Add Filament and Printer Profile components with associated functionality
- Introduced FilamentProfiles and PrinterProfiles components for managing filament and printer profiles, respectively. - Implemented modal dialogs for creating and editing profiles, enhancing user interaction. - Added ObjectTable for displaying profiles with action handling for edit and delete operations. - Integrated context for API server interactions and improved state management for profile visibility and actions. - Created detailed info components for both filament and printer profiles, allowing for comprehensive data management and display.
This commit is contained in:
parent
830cf5224a
commit
def9b9aefb
144
src/components/Dashboard/Production/FilamentProfiles.jsx
Normal file
144
src/components/Dashboard/Production/FilamentProfiles.jsx
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
import { useContext, useRef, useState } from 'react'
|
||||||
|
import { Button, Dropdown, Flex, Modal, Space } from 'antd'
|
||||||
|
import NewFilamentProfile, {
|
||||||
|
EditFilamentProfile
|
||||||
|
} from './FilamentProfiles/NewFilamentProfile'
|
||||||
|
import ColumnViewButton from '../common/ColumnViewButton'
|
||||||
|
import ExportListButton from '../common/ExportListButton'
|
||||||
|
import FilterSidebarButton from '../common/FilterSidebarButton'
|
||||||
|
import ObjectTable from '../common/ObjectTable'
|
||||||
|
import ObjectTableViewButton from '../common/ObjectTableViewButton'
|
||||||
|
import { ApiServerContext } from '../context/ApiServerContext'
|
||||||
|
import PlusIcon from '../../Icons/PlusIcon'
|
||||||
|
import ReloadIcon from '../../Icons/ReloadIcon'
|
||||||
|
import useColumnVisibility from '../hooks/useColumnVisibility'
|
||||||
|
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
|
||||||
|
import useViewMode from '../hooks/useViewMode'
|
||||||
|
|
||||||
|
const FilamentProfiles = () => {
|
||||||
|
const { deleteObject } = useContext(ApiServerContext)
|
||||||
|
const [profileModal, setProfileModal] = useState({
|
||||||
|
open: false,
|
||||||
|
profileId: null
|
||||||
|
})
|
||||||
|
const tableRef = useRef()
|
||||||
|
const [viewMode, setViewMode] = useViewMode('FilamentProfiles')
|
||||||
|
const [columnVisibility, setColumnVisibility] =
|
||||||
|
useColumnVisibility('filamentProfile')
|
||||||
|
const [showFilterSidebar, setShowFilterSidebar] =
|
||||||
|
useFilterSidebarVisibility('FilamentProfiles')
|
||||||
|
|
||||||
|
const actionItems = {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: 'New Filament Profile',
|
||||||
|
key: 'newFilamentProfile',
|
||||||
|
icon: <PlusIcon />
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
label: 'Reload List',
|
||||||
|
key: 'reloadList',
|
||||||
|
icon: <ReloadIcon />
|
||||||
|
}
|
||||||
|
],
|
||||||
|
onClick: ({ key }) => {
|
||||||
|
if (key === 'reloadList') {
|
||||||
|
tableRef.current?.reload()
|
||||||
|
} else if (key === 'newFilamentProfile') {
|
||||||
|
setProfileModal({ open: true, profileId: null })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRowAction = (action, profile) => {
|
||||||
|
if (action.name === 'edit') {
|
||||||
|
setProfileModal({ open: true, profileId: profile._id })
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.name === 'delete') {
|
||||||
|
Modal.confirm({
|
||||||
|
title: 'Delete filament profile?',
|
||||||
|
content: `This will permanently delete ${profile.name || profile._reference}.`,
|
||||||
|
okText: 'Delete',
|
||||||
|
okType: 'danger',
|
||||||
|
onOk: async () => {
|
||||||
|
await deleteObject(profile._id, 'filamentProfile')
|
||||||
|
await tableRef.current?.reload()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Flex vertical={'true'} gap='large' className='h-100'>
|
||||||
|
<Flex justify={'space-between'}>
|
||||||
|
<Space>
|
||||||
|
<Dropdown menu={actionItems}>
|
||||||
|
<Button>Actions</Button>
|
||||||
|
</Dropdown>
|
||||||
|
<ColumnViewButton
|
||||||
|
type='filamentProfile'
|
||||||
|
visibleState={columnVisibility}
|
||||||
|
updateVisibleState={setColumnVisibility}
|
||||||
|
/>
|
||||||
|
<ExportListButton objectType='filamentProfile' />
|
||||||
|
</Space>
|
||||||
|
<Space>
|
||||||
|
<FilterSidebarButton
|
||||||
|
active={showFilterSidebar}
|
||||||
|
onClick={() => setShowFilterSidebar(!showFilterSidebar)}
|
||||||
|
/>
|
||||||
|
<ObjectTableViewButton
|
||||||
|
viewMode={viewMode}
|
||||||
|
setViewMode={setViewMode}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<ObjectTable
|
||||||
|
ref={tableRef}
|
||||||
|
type='filamentProfile'
|
||||||
|
cards={viewMode === 'cards'}
|
||||||
|
visibleColumns={columnVisibility}
|
||||||
|
showFilterSidebar={showFilterSidebar}
|
||||||
|
expandHeight={true}
|
||||||
|
onRowAction={handleRowAction}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
open={profileModal.open}
|
||||||
|
footer={null}
|
||||||
|
width={800}
|
||||||
|
onCancel={() => setProfileModal({ open: false, profileId: null })}
|
||||||
|
destroyOnHidden
|
||||||
|
>
|
||||||
|
{profileModal.open &&
|
||||||
|
(profileModal.profileId ? (
|
||||||
|
<EditFilamentProfile
|
||||||
|
profileId={profileModal.profileId}
|
||||||
|
onOk={() => {
|
||||||
|
setProfileModal({ open: false, profileId: null })
|
||||||
|
tableRef.current?.reload()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<NewFilamentProfile
|
||||||
|
onOk={() => {
|
||||||
|
setProfileModal({ open: false, profileId: null })
|
||||||
|
tableRef.current?.reload()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FilamentProfiles
|
||||||
@ -0,0 +1,529 @@
|
|||||||
|
import { useRef, useState } from 'react'
|
||||||
|
import { useLocation } from 'react-router-dom'
|
||||||
|
import { Card, Flex, Space } from 'antd'
|
||||||
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
|
import ActionHandler from '../../common/ActionHandler'
|
||||||
|
import AuditLogIcon from '../../../Icons/AuditLogIcon'
|
||||||
|
import DocumentPrintButton from '../../common/DocumentPrintButton'
|
||||||
|
import EditButtons from '../../common/EditButtons'
|
||||||
|
import FilamentIcon from '../../../Icons/FilamentIcon'
|
||||||
|
import GCodeFileIcon from '../../../Icons/GCodeFileIcon'
|
||||||
|
import HotEndIcon from '../../../Icons/HotEndIcon'
|
||||||
|
import InfoCircleIcon from '../../../Icons/InfoCircleIcon'
|
||||||
|
import InfoCollapse from '../../common/InfoCollapse'
|
||||||
|
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder'
|
||||||
|
import LockIndicator from '../../common/LockIndicator'
|
||||||
|
import MultiMotionIcon from '../../../Icons/MultiMotionIcon'
|
||||||
|
import NoteIcon from '../../../Icons/NoteIcon'
|
||||||
|
import NotesPanel from '../../common/NotesPanel'
|
||||||
|
import ObjectActions from '../../common/ObjectActions'
|
||||||
|
import ObjectForm from '../../common/ObjectForm'
|
||||||
|
import ObjectInfo from '../../common/ObjectInfo'
|
||||||
|
import ObjectTable from '../../common/ObjectTable'
|
||||||
|
import RulerIcon from '../../../Icons/RulerIcon'
|
||||||
|
import ScrollBox from '../../common/ScrollBox'
|
||||||
|
import SettingsIcon from '../../../Icons/SettingsIcon'
|
||||||
|
import UserNotifierToggle from '../../common/UserNotifierToggle'
|
||||||
|
import ViewButton from '../../common/ViewButton'
|
||||||
|
import useCollapseState from '../../hooks/useCollapseState'
|
||||||
|
import {
|
||||||
|
FILAMENT_PROFILE_BED_TEMPERATURE_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_COMPATIBILITY_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_COOLING_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_EXHAUST_FAN_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_FLOW_PRESSURE_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_GCODE_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_LOADING_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_MATERIAL_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_RETRACTION_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_SHRINKAGE_DRYING_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_SPEED_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_TEMPERATURE_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_WIPE_TOWER_PROPERTIES
|
||||||
|
} from '../../../../database/models/FilamentProfile'
|
||||||
|
|
||||||
|
const toVisibleProperties = (propertyNames) =>
|
||||||
|
Object.fromEntries(propertyNames.map((name) => [name, true]))
|
||||||
|
|
||||||
|
const FilamentProfileInfo = () => {
|
||||||
|
const location = useLocation()
|
||||||
|
const objectFormRef = useRef(null)
|
||||||
|
const actionHandlerRef = useRef(null)
|
||||||
|
const filamentProfileId = new URLSearchParams(location.search).get(
|
||||||
|
'filamentProfileId'
|
||||||
|
)
|
||||||
|
const [collapseState, updateCollapseState] = useCollapseState(
|
||||||
|
'FilamentProfileInfo',
|
||||||
|
{
|
||||||
|
info: true,
|
||||||
|
material: true,
|
||||||
|
flowPressure: true,
|
||||||
|
temperature: true,
|
||||||
|
bedTemperature: true,
|
||||||
|
speed: true,
|
||||||
|
cooling: true,
|
||||||
|
exhaustFan: true,
|
||||||
|
retraction: true,
|
||||||
|
loading: true,
|
||||||
|
wipeTower: true,
|
||||||
|
gCodeSettings: true,
|
||||||
|
compatibility: true,
|
||||||
|
shrinkageDrying: true,
|
||||||
|
notes: true,
|
||||||
|
auditLogs: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const [objectFormState, setObjectFormState] = useState({
|
||||||
|
isEditing: false,
|
||||||
|
editLoading: false,
|
||||||
|
formValid: false,
|
||||||
|
lock: null,
|
||||||
|
loading: false,
|
||||||
|
objectData: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
edit: () => {
|
||||||
|
objectFormRef.current?.startEditing?.()
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
cancelEdit: () => {
|
||||||
|
objectFormRef.current?.cancelEditing?.()
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
finishEdit: () => {
|
||||||
|
objectFormRef.current?.handleUpdate?.()
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
delete: () => {
|
||||||
|
objectFormRef.current?.handleDelete?.()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
gap='large'
|
||||||
|
vertical='true'
|
||||||
|
style={{ maxHeight: '100%', minHeight: 0 }}
|
||||||
|
>
|
||||||
|
<Flex justify='space-between'>
|
||||||
|
<Space size='middle'>
|
||||||
|
<Space size='small'>
|
||||||
|
<ObjectActions
|
||||||
|
type='filamentProfile'
|
||||||
|
id={filamentProfileId}
|
||||||
|
disabled={objectFormState.loading}
|
||||||
|
objectData={objectFormState.objectData}
|
||||||
|
/>
|
||||||
|
<ViewButton
|
||||||
|
disabled={objectFormState.loading}
|
||||||
|
items={[
|
||||||
|
{ key: 'info', label: 'Filament Profile Information' },
|
||||||
|
{ key: 'material', label: 'Material' },
|
||||||
|
{ key: 'flowPressure', label: 'Flow & Pressure' },
|
||||||
|
{ key: 'temperature', label: 'Temperature' },
|
||||||
|
{ key: 'bedTemperature', label: 'Bed Temperatures' },
|
||||||
|
{ key: 'speed', label: 'Speed' },
|
||||||
|
{ key: 'cooling', label: 'Part Cooling Fan' },
|
||||||
|
{ key: 'exhaustFan', label: 'Exhaust Fan' },
|
||||||
|
{ key: 'retraction', label: 'Retraction Overrides' },
|
||||||
|
{ key: 'loading', label: 'Loading & Multi-tool' },
|
||||||
|
{ key: 'wipeTower', label: 'Wipe Tower & Flushing' },
|
||||||
|
{ key: 'gCodeSettings', label: 'G-Code Settings' },
|
||||||
|
{ key: 'compatibility', label: 'Compatibility' },
|
||||||
|
{ key: 'shrinkageDrying', label: 'Shrinkage & Drying' },
|
||||||
|
{ key: 'notes', label: 'Notes' },
|
||||||
|
{ key: 'auditLogs', label: 'Audit Logs' }
|
||||||
|
]}
|
||||||
|
visibleState={collapseState}
|
||||||
|
updateVisibleState={updateCollapseState}
|
||||||
|
/>
|
||||||
|
<UserNotifierToggle
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectFormState.objectData}
|
||||||
|
disabled={objectFormState.loading}
|
||||||
|
/>
|
||||||
|
<DocumentPrintButton
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectFormState.objectData}
|
||||||
|
disabled={objectFormState.loading}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
|
</Space>
|
||||||
|
<EditButtons
|
||||||
|
isEditing={objectFormState.isEditing}
|
||||||
|
handleUpdate={() => actionHandlerRef.current.callAction('finishEdit')}
|
||||||
|
cancelEditing={() =>
|
||||||
|
actionHandlerRef.current.callAction('cancelEdit')
|
||||||
|
}
|
||||||
|
startEditing={() => actionHandlerRef.current.callAction('edit')}
|
||||||
|
editLoading={objectFormState.editLoading}
|
||||||
|
formValid={objectFormState.formValid}
|
||||||
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
|
loading={objectFormState.editLoading}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<ScrollBox>
|
||||||
|
<Flex vertical gap='large'>
|
||||||
|
<ActionHandler
|
||||||
|
actions={actions}
|
||||||
|
loading={objectFormState.loading}
|
||||||
|
ref={actionHandlerRef}
|
||||||
|
>
|
||||||
|
<ObjectForm
|
||||||
|
id={filamentProfileId}
|
||||||
|
type='filamentProfile'
|
||||||
|
ref={objectFormRef}
|
||||||
|
onStateChange={(state) =>
|
||||||
|
setObjectFormState((current) => ({ ...current, ...state }))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{({ loading, isEditing, objectData }) => (
|
||||||
|
<Flex vertical gap='large'>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Filament Profile Information'
|
||||||
|
icon={<InfoCircleIcon />}
|
||||||
|
active={collapseState.info}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('info', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='info'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='140px'
|
||||||
|
visibleProperties={{
|
||||||
|
_id: true,
|
||||||
|
name: true,
|
||||||
|
_reference: true,
|
||||||
|
filamentType: true,
|
||||||
|
filament: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Material'
|
||||||
|
icon={<FilamentIcon />}
|
||||||
|
active={collapseState.material}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('material', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='material'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='220px'
|
||||||
|
visibleProperties={toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_MATERIAL_PROPERTIES
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Flow & Pressure'
|
||||||
|
icon={<SettingsIcon />}
|
||||||
|
active={collapseState.flowPressure}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('flowPressure', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='flowPressure'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='325px'
|
||||||
|
visibleProperties={toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_FLOW_PRESSURE_PROPERTIES
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Temperature'
|
||||||
|
icon={<HotEndIcon />}
|
||||||
|
active={collapseState.temperature}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('temperature', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='temperature'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='280px'
|
||||||
|
visibleProperties={toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_TEMPERATURE_PROPERTIES
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Bed Temperatures'
|
||||||
|
icon={<RulerIcon />}
|
||||||
|
active={collapseState.bedTemperature}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('bedTemperature', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='bedTemperature'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='280px'
|
||||||
|
visibleProperties={toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_BED_TEMPERATURE_PROPERTIES
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Speed'
|
||||||
|
icon={<MultiMotionIcon />}
|
||||||
|
active={collapseState.speed}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('speed', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='speed'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='265px'
|
||||||
|
visibleProperties={toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_SPEED_PROPERTIES
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Part Cooling Fan'
|
||||||
|
icon={<SettingsIcon />}
|
||||||
|
active={collapseState.cooling}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('cooling', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='cooling'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='350px'
|
||||||
|
visibleProperties={toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_COOLING_PROPERTIES
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Exhaust Fan'
|
||||||
|
icon={<SettingsIcon />}
|
||||||
|
active={collapseState.exhaustFan}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('exhaustFan', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='exhaustFan'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='285px'
|
||||||
|
visibleProperties={toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_EXHAUST_FAN_PROPERTIES
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Retraction Overrides'
|
||||||
|
icon={<SettingsIcon />}
|
||||||
|
active={collapseState.retraction}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('retraction', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='retraction'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='250px'
|
||||||
|
visibleProperties={toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_RETRACTION_PROPERTIES
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Loading & Multi-tool'
|
||||||
|
icon={<FilamentIcon />}
|
||||||
|
active={collapseState.loading}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('loading', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='loading'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='220px'
|
||||||
|
visibleProperties={toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_LOADING_PROPERTIES
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Wipe Tower & Flushing'
|
||||||
|
icon={<SettingsIcon />}
|
||||||
|
active={collapseState.wipeTower}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('wipeTower', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='wipeTower'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='330px'
|
||||||
|
visibleProperties={toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_WIPE_TOWER_PROPERTIES
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='G-Code Settings'
|
||||||
|
icon={<GCodeFileIcon />}
|
||||||
|
active={collapseState.gCodeSettings}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('gCodeSettings', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='gCodeSettings'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='270px'
|
||||||
|
visibleProperties={toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_GCODE_PROPERTIES
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Compatibility'
|
||||||
|
icon={<SettingsIcon />}
|
||||||
|
active={collapseState.compatibility}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('compatibility', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='compatibility'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='270px'
|
||||||
|
visibleProperties={toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_COMPATIBILITY_PROPERTIES
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Shrinkage & Drying'
|
||||||
|
icon={<SettingsIcon />}
|
||||||
|
active={collapseState.shrinkageDrying}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('shrinkageDrying', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='shrinkageDrying'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='filamentProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='340px'
|
||||||
|
visibleProperties={{
|
||||||
|
...toVisibleProperties(
|
||||||
|
FILAMENT_PROFILE_SHRINKAGE_DRYING_PROPERTIES
|
||||||
|
),
|
||||||
|
filamentNotes: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</ObjectForm>
|
||||||
|
</ActionHandler>
|
||||||
|
|
||||||
|
<InfoCollapse
|
||||||
|
title='Notes'
|
||||||
|
icon={<NoteIcon />}
|
||||||
|
active={collapseState.notes}
|
||||||
|
onToggle={(expanded) => updateCollapseState('notes', expanded)}
|
||||||
|
collapseKey='notes'
|
||||||
|
>
|
||||||
|
<Card>
|
||||||
|
<NotesPanel _id={filamentProfileId} type='filamentProfile' />
|
||||||
|
</Card>
|
||||||
|
</InfoCollapse>
|
||||||
|
|
||||||
|
<InfoCollapse
|
||||||
|
title='Audit Logs'
|
||||||
|
icon={<AuditLogIcon />}
|
||||||
|
active={collapseState.auditLogs}
|
||||||
|
onToggle={(expanded) => updateCollapseState('auditLogs', expanded)}
|
||||||
|
collapseKey='auditLogs'
|
||||||
|
>
|
||||||
|
{objectFormState.loading ? (
|
||||||
|
<InfoCollapsePlaceholder />
|
||||||
|
) : (
|
||||||
|
<ObjectTable
|
||||||
|
type='auditLog'
|
||||||
|
masterFilter={{ 'parent._id': filamentProfileId }}
|
||||||
|
visibleColumns={{ _id: false, 'parent._id': false }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</InfoCollapse>
|
||||||
|
</Flex>
|
||||||
|
</ScrollBox>
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FilamentProfileInfo
|
||||||
@ -0,0 +1,420 @@
|
|||||||
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import NewObjectForm from '../../common/NewObjectForm'
|
||||||
|
import ObjectForm from '../../common/ObjectForm'
|
||||||
|
import ObjectInfo from '../../common/ObjectInfo'
|
||||||
|
import WizardView from '../../common/WizardView'
|
||||||
|
import {
|
||||||
|
FILAMENT_PROFILE_BED_TEMPERATURE_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_COMPATIBILITY_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_COOLING_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_EXHAUST_FAN_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_FLOW_PRESSURE_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_MATERIAL_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_SPEED_PROPERTIES,
|
||||||
|
FILAMENT_PROFILE_TEMPERATURE_PROPERTIES
|
||||||
|
} from '../../../../database/models/FilamentProfile'
|
||||||
|
|
||||||
|
const PRUSA_GENERIC_PETG_DEFAULTS = {
|
||||||
|
filamentType: 'filament',
|
||||||
|
filamentIsSupport: false,
|
||||||
|
filamentSoluble: false,
|
||||||
|
filamentPrintable: 3,
|
||||||
|
filamentAdhesivenessCategory: 0,
|
||||||
|
temperatureVitrification: 80,
|
||||||
|
idleTemperature: 0,
|
||||||
|
pelletFlowCoefficient: 0.4157,
|
||||||
|
requiredNozzleHrc: 0,
|
||||||
|
filamentFlowRatio: 0.98,
|
||||||
|
enablePressureAdvance: false,
|
||||||
|
pressureAdvance: 0.02,
|
||||||
|
adaptivePressureAdvance: false,
|
||||||
|
adaptivePressureAdvanceBridges: false,
|
||||||
|
adaptivePressureAdvanceOverhangs: false,
|
||||||
|
adaptivePressureAdvanceModel: '0,0,0\n0,0,0',
|
||||||
|
activateChamberTempControl: false,
|
||||||
|
chamberTemperature: 0,
|
||||||
|
chamberMinimalTemperature: 0,
|
||||||
|
nozzleTemperatureInitialLayer: 230,
|
||||||
|
nozzleTemperature: 240,
|
||||||
|
nozzleTemperatureRangeLow: 220,
|
||||||
|
nozzleTemperatureRangeHigh: 260,
|
||||||
|
hotPlateTempInitialLayer: 85,
|
||||||
|
hotPlateTemp: 85,
|
||||||
|
coolPlateTempInitialLayer: 60,
|
||||||
|
coolPlateTemp: 60,
|
||||||
|
engPlateTempInitialLayer: 0,
|
||||||
|
engPlateTemp: 0,
|
||||||
|
texturedPlateTempInitialLayer: 45,
|
||||||
|
texturedPlateTemp: 45,
|
||||||
|
texturedCoolPlateTempInitialLayer: 40,
|
||||||
|
texturedCoolPlateTemp: 40,
|
||||||
|
supertackPlateTempInitialLayer: 35,
|
||||||
|
supertackPlateTemp: 35,
|
||||||
|
filamentAdaptiveVolumetricSpeed: false,
|
||||||
|
filamentMaxVolumetricSpeed: 8,
|
||||||
|
volumetricSpeedCoefficients: '',
|
||||||
|
closeFanTheFirstXLayers: 3,
|
||||||
|
fullFanSpeedLayer: 0,
|
||||||
|
fanMinSpeed: 40,
|
||||||
|
fanMaxSpeed: 90,
|
||||||
|
reduceFanStopStartFreq: true,
|
||||||
|
slowDownForLayerCooling: true,
|
||||||
|
dontSlowDownOuterWall: false,
|
||||||
|
slowDownMinSpeed: 10,
|
||||||
|
slowDownLayerTime: 8,
|
||||||
|
fanCoolingLayerTime: 30,
|
||||||
|
enableOverhangBridgeFan: true,
|
||||||
|
overhangFanThreshold: '25%',
|
||||||
|
overhangFanSpeed: 90,
|
||||||
|
internalBridgeFanSpeed: -1,
|
||||||
|
supportMaterialInterfaceFanSpeed: -1,
|
||||||
|
ironingFanSpeed: -1,
|
||||||
|
initialLayerFanSpeed: -1,
|
||||||
|
firstXLayerFanSpeed: 0,
|
||||||
|
additionalCoolingFanSpeed: 0,
|
||||||
|
additionalFanFullSpeedLayer: 0,
|
||||||
|
closeAdditionalFanFirstXLayers: true,
|
||||||
|
activateAirFiltration: false,
|
||||||
|
activateAirFiltrationDuringPrint: true,
|
||||||
|
activateAirFiltrationOnCompletion: true,
|
||||||
|
duringPrintExhaustFanSpeed: 60,
|
||||||
|
completePrintExhaustFanSpeed: 80,
|
||||||
|
filamentLoadingSpeed: 28,
|
||||||
|
filamentLoadingSpeedStart: 3,
|
||||||
|
filamentUnloadingSpeed: 90,
|
||||||
|
filamentUnloadingSpeedStart: 100,
|
||||||
|
filamentChangeLength: 10,
|
||||||
|
filamentChangeLengthNc: 10,
|
||||||
|
filamentToolchangeDelay: 0,
|
||||||
|
filamentExtruderCompatibility: 0,
|
||||||
|
filamentExtruderVariant: 'Direct Drive Standard',
|
||||||
|
filamentMultitoolRamming: false,
|
||||||
|
filamentMultitoolRammingFlow: 10,
|
||||||
|
filamentMultitoolRammingVolume: 10,
|
||||||
|
filamentRammingParameters:
|
||||||
|
'120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6',
|
||||||
|
filamentRammingTravelTime: 0,
|
||||||
|
filamentRammingTravelTimeNc: 0,
|
||||||
|
filamentRammingVolumetricSpeed: -1,
|
||||||
|
filamentRammingVolumetricSpeedNc: -1,
|
||||||
|
filamentMinimalPurgeOnWipeTower: 15,
|
||||||
|
filamentTowerInterfacePreExtrusionDist: 10,
|
||||||
|
filamentTowerInterfacePreExtrusionLength: 0,
|
||||||
|
filamentTowerInterfacePrintTemp: -1,
|
||||||
|
filamentTowerInterfacePurgeVolume: 20,
|
||||||
|
filamentTowerIroningArea: 4,
|
||||||
|
filamentCoolingBeforeTower: 10,
|
||||||
|
filamentCoolingInitialSpeed: 2.2,
|
||||||
|
filamentCoolingFinalSpeed: 3.4,
|
||||||
|
filamentCoolingMoves: 4,
|
||||||
|
filamentFlushTemp: 0,
|
||||||
|
filamentFlushTempFast: 0,
|
||||||
|
filamentFlushVolumetricSpeed: 0,
|
||||||
|
filamentPreCoolingTemperature: 0,
|
||||||
|
filamentPreCoolingTemperatureNc: 0,
|
||||||
|
filamentPreheatTemperatureDelta: 0,
|
||||||
|
filamentPrimeVolumeNc: 60,
|
||||||
|
filamentStampingDistance: 0,
|
||||||
|
filamentStampingLoadingSpeed: 0,
|
||||||
|
longRetractionsWhenEc: false,
|
||||||
|
retractionDistancesWhenEc: 10,
|
||||||
|
filamentStartGcode:
|
||||||
|
'; filament start gcode\nM900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.08{endif} ; Filament gcode LA 1.5',
|
||||||
|
filamentEndGcode: '; filament end gcode \n',
|
||||||
|
filamentChangeExtrusionRoleGcode: '',
|
||||||
|
filamentShrink: '100%',
|
||||||
|
filamentShrinkageCompensationZ: '100%',
|
||||||
|
compatiblePrinters: [],
|
||||||
|
compatiblePrintersCondition: '',
|
||||||
|
compatiblePrints: [],
|
||||||
|
compatiblePrintsCondition: '',
|
||||||
|
filamentNotes: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const REQUIRED_PROPERTIES = ['name', 'filamentType', 'filament']
|
||||||
|
|
||||||
|
const SUMMARY_PROPERTIES = [
|
||||||
|
...REQUIRED_PROPERTIES,
|
||||||
|
...FILAMENT_PROFILE_MATERIAL_PROPERTIES,
|
||||||
|
...FILAMENT_PROFILE_FLOW_PRESSURE_PROPERTIES,
|
||||||
|
...FILAMENT_PROFILE_TEMPERATURE_PROPERTIES,
|
||||||
|
...FILAMENT_PROFILE_BED_TEMPERATURE_PROPERTIES,
|
||||||
|
...FILAMENT_PROFILE_SPEED_PROPERTIES,
|
||||||
|
...FILAMENT_PROFILE_COOLING_PROPERTIES,
|
||||||
|
...FILAMENT_PROFILE_EXHAUST_FAN_PROPERTIES
|
||||||
|
]
|
||||||
|
|
||||||
|
const FilamentProfileWizard = ({
|
||||||
|
objectData,
|
||||||
|
formValid,
|
||||||
|
loading,
|
||||||
|
onSubmit,
|
||||||
|
editing,
|
||||||
|
filamentId = null
|
||||||
|
}) => {
|
||||||
|
const visibleProperties = useMemo(() => {
|
||||||
|
if (!filamentId) return undefined
|
||||||
|
return { filament: false, 'filament._id': false }
|
||||||
|
}, [filamentId])
|
||||||
|
|
||||||
|
const steps = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
title: 'Required',
|
||||||
|
key: 'required',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='filamentProfile'
|
||||||
|
properties={REQUIRED_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
labelWidth='110px'
|
||||||
|
required={true}
|
||||||
|
objectData={objectData}
|
||||||
|
visibleProperties={visibleProperties}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Material',
|
||||||
|
key: 'material',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='filamentProfile'
|
||||||
|
properties={FILAMENT_PROFILE_MATERIAL_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
labelWidth='210px'
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Flow & Pressure',
|
||||||
|
key: 'flowPressure',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='filamentProfile'
|
||||||
|
properties={FILAMENT_PROFILE_FLOW_PRESSURE_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
labelWidth='290px'
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Temperature',
|
||||||
|
key: 'temperature',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='filamentProfile'
|
||||||
|
properties={[
|
||||||
|
...FILAMENT_PROFILE_TEMPERATURE_PROPERTIES,
|
||||||
|
...FILAMENT_PROFILE_BED_TEMPERATURE_PROPERTIES
|
||||||
|
]}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
labelWidth='250px'
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Speed',
|
||||||
|
key: 'speed',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='filamentProfile'
|
||||||
|
properties={FILAMENT_PROFILE_SPEED_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
labelWidth='220px'
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Cooling',
|
||||||
|
key: 'cooling',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='filamentProfile'
|
||||||
|
properties={FILAMENT_PROFILE_COOLING_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
labelWidth='320px'
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Exhaust Fan',
|
||||||
|
key: 'exhaustFan',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='filamentProfile'
|
||||||
|
properties={FILAMENT_PROFILE_EXHAUST_FAN_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
labelWidth='270px'
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Compatibility',
|
||||||
|
key: 'compatibility',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='filamentProfile'
|
||||||
|
properties={FILAMENT_PROFILE_COMPATIBILITY_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
labelWidth='270px'
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Summary',
|
||||||
|
key: 'summary',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='filamentProfile'
|
||||||
|
properties={SUMMARY_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing={false}
|
||||||
|
labelWidth='250px'
|
||||||
|
objectData={objectData}
|
||||||
|
visibleProperties={visibleProperties}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[objectData, visibleProperties]
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WizardView
|
||||||
|
sizeBarWidth='185px'
|
||||||
|
steps={steps}
|
||||||
|
loading={loading}
|
||||||
|
formValid={formValid}
|
||||||
|
title={editing ? 'Edit Filament Profile' : 'New Filament Profile'}
|
||||||
|
submitText={editing ? 'Save' : 'Create'}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
FilamentProfileWizard.propTypes = {
|
||||||
|
objectData: PropTypes.object,
|
||||||
|
formValid: PropTypes.bool.isRequired,
|
||||||
|
loading: PropTypes.bool,
|
||||||
|
onSubmit: PropTypes.func.isRequired,
|
||||||
|
editing: PropTypes.bool,
|
||||||
|
filamentId: PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
const NewFilamentProfile = ({ onOk, filamentId = null }) => (
|
||||||
|
<NewObjectForm
|
||||||
|
type='filamentProfile'
|
||||||
|
defaultValues={{
|
||||||
|
...PRUSA_GENERIC_PETG_DEFAULTS,
|
||||||
|
...(filamentId ? { filamentType: 'filament', filament: filamentId } : {})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({ handleSubmit, submitLoading, objectData, formValid }) => (
|
||||||
|
<FilamentProfileWizard
|
||||||
|
objectData={objectData}
|
||||||
|
formValid={formValid}
|
||||||
|
loading={submitLoading}
|
||||||
|
filamentId={filamentId}
|
||||||
|
onSubmit={async () => {
|
||||||
|
const result = await handleSubmit()
|
||||||
|
if (result?._id) onOk(result)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</NewObjectForm>
|
||||||
|
)
|
||||||
|
|
||||||
|
NewFilamentProfile.propTypes = {
|
||||||
|
onOk: PropTypes.func.isRequired,
|
||||||
|
filamentId: PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EditFilamentProfile = ({ profileId, onOk, filamentId = null }) => {
|
||||||
|
const formRef = useRef(null)
|
||||||
|
const startedEditingRef = useRef(false)
|
||||||
|
const saveRequestedRef = useRef(false)
|
||||||
|
const stateRef = useRef({})
|
||||||
|
const [formState, setFormState] = useState({
|
||||||
|
loading: true,
|
||||||
|
editLoading: false,
|
||||||
|
formValid: false,
|
||||||
|
isEditing: false,
|
||||||
|
objectData: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
!formState.loading &&
|
||||||
|
!formState.isEditing &&
|
||||||
|
!startedEditingRef.current
|
||||||
|
) {
|
||||||
|
startedEditingRef.current = true
|
||||||
|
formRef.current?.startEditing()
|
||||||
|
}
|
||||||
|
}, [formState.isEditing, formState.loading])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ObjectForm
|
||||||
|
id={profileId}
|
||||||
|
type='filamentProfile'
|
||||||
|
ref={formRef}
|
||||||
|
onStateChange={(nextState) => {
|
||||||
|
stateRef.current = { ...stateRef.current, ...nextState }
|
||||||
|
setFormState((current) => ({ ...current, ...nextState }))
|
||||||
|
|
||||||
|
if (saveRequestedRef.current && nextState.isEditing === false) {
|
||||||
|
saveRequestedRef.current = false
|
||||||
|
onOk(stateRef.current.objectData)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({ objectData, formValid, editLoading, handleUpdate }) => (
|
||||||
|
<FilamentProfileWizard
|
||||||
|
editing
|
||||||
|
objectData={objectData}
|
||||||
|
formValid={formValid}
|
||||||
|
loading={formState.loading || editLoading}
|
||||||
|
filamentId={filamentId}
|
||||||
|
onSubmit={() => {
|
||||||
|
saveRequestedRef.current = true
|
||||||
|
handleUpdate()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ObjectForm>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
EditFilamentProfile.propTypes = {
|
||||||
|
profileId: PropTypes.string.isRequired,
|
||||||
|
onOk: PropTypes.func.isRequired,
|
||||||
|
filamentId: PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NewFilamentProfile
|
||||||
143
src/components/Dashboard/Production/PrinterProfiles.jsx
Normal file
143
src/components/Dashboard/Production/PrinterProfiles.jsx
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import { useContext, useRef, useState } from 'react'
|
||||||
|
import { Button, Dropdown, Flex, Modal, Space } from 'antd'
|
||||||
|
import NewPrinterProfile, {
|
||||||
|
EditPrinterProfile
|
||||||
|
} from './PrinterProfiles/NewPrinterProfile'
|
||||||
|
import ColumnViewButton from '../common/ColumnViewButton'
|
||||||
|
import ExportListButton from '../common/ExportListButton'
|
||||||
|
import FilterSidebarButton from '../common/FilterSidebarButton'
|
||||||
|
import ObjectTable from '../common/ObjectTable'
|
||||||
|
import ObjectTableViewButton from '../common/ObjectTableViewButton'
|
||||||
|
import { ApiServerContext } from '../context/ApiServerContext'
|
||||||
|
import PlusIcon from '../../Icons/PlusIcon'
|
||||||
|
import ReloadIcon from '../../Icons/ReloadIcon'
|
||||||
|
import useColumnVisibility from '../hooks/useColumnVisibility'
|
||||||
|
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
|
||||||
|
import useViewMode from '../hooks/useViewMode'
|
||||||
|
const PrinterProfiles = () => {
|
||||||
|
const { deleteObject } = useContext(ApiServerContext)
|
||||||
|
const [profileModal, setProfileModal] = useState({
|
||||||
|
open: false,
|
||||||
|
profileId: null
|
||||||
|
})
|
||||||
|
const tableRef = useRef()
|
||||||
|
const [viewMode, setViewMode] = useViewMode('PrinterProfiles')
|
||||||
|
const [columnVisibility, setColumnVisibility] =
|
||||||
|
useColumnVisibility('printerProfile')
|
||||||
|
const [showFilterSidebar, setShowFilterSidebar] =
|
||||||
|
useFilterSidebarVisibility('PrinterProfiles')
|
||||||
|
|
||||||
|
const actionItems = {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: 'New Printer Profile',
|
||||||
|
key: 'newPrinterProfile',
|
||||||
|
icon: <PlusIcon />
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
label: 'Reload List',
|
||||||
|
key: 'reloadList',
|
||||||
|
icon: <ReloadIcon />
|
||||||
|
}
|
||||||
|
],
|
||||||
|
onClick: ({ key }) => {
|
||||||
|
if (key === 'reloadList') {
|
||||||
|
tableRef.current?.reload()
|
||||||
|
} else if (key === 'newPrinterProfile') {
|
||||||
|
setProfileModal({ open: true, profileId: null })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRowAction = (action, profile) => {
|
||||||
|
if (action.name === 'edit') {
|
||||||
|
setProfileModal({ open: true, profileId: profile._id })
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.name === 'delete') {
|
||||||
|
Modal.confirm({
|
||||||
|
title: 'Delete printer profile?',
|
||||||
|
content: `This will permanently delete ${profile.name || profile._reference}.`,
|
||||||
|
okText: 'Delete',
|
||||||
|
okType: 'danger',
|
||||||
|
onOk: async () => {
|
||||||
|
await deleteObject(profile._id, 'printerProfile')
|
||||||
|
await tableRef.current?.reload()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Flex vertical={'true'} gap='large' className='h-100'>
|
||||||
|
<Flex justify={'space-between'}>
|
||||||
|
<Space>
|
||||||
|
<Dropdown menu={actionItems}>
|
||||||
|
<Button>Actions</Button>
|
||||||
|
</Dropdown>
|
||||||
|
<ColumnViewButton
|
||||||
|
type='printerProfile'
|
||||||
|
visibleState={columnVisibility}
|
||||||
|
updateVisibleState={setColumnVisibility}
|
||||||
|
/>
|
||||||
|
<ExportListButton objectType='printerProfile' />
|
||||||
|
</Space>
|
||||||
|
<Space>
|
||||||
|
<FilterSidebarButton
|
||||||
|
active={showFilterSidebar}
|
||||||
|
onClick={() => setShowFilterSidebar(!showFilterSidebar)}
|
||||||
|
/>
|
||||||
|
<ObjectTableViewButton
|
||||||
|
viewMode={viewMode}
|
||||||
|
setViewMode={setViewMode}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<ObjectTable
|
||||||
|
ref={tableRef}
|
||||||
|
type='printerProfile'
|
||||||
|
cards={viewMode === 'cards'}
|
||||||
|
visibleColumns={columnVisibility}
|
||||||
|
showFilterSidebar={showFilterSidebar}
|
||||||
|
expandHeight={true}
|
||||||
|
onRowAction={handleRowAction}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
open={profileModal.open}
|
||||||
|
footer={null}
|
||||||
|
width={800}
|
||||||
|
onCancel={() => setProfileModal({ open: false, profileId: null })}
|
||||||
|
destroyOnHidden
|
||||||
|
>
|
||||||
|
{profileModal.open &&
|
||||||
|
(profileModal.profileId ? (
|
||||||
|
<EditPrinterProfile
|
||||||
|
profileId={profileModal.profileId}
|
||||||
|
onOk={() => {
|
||||||
|
setProfileModal({ open: false, profileId: null })
|
||||||
|
tableRef.current?.reload()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<NewPrinterProfile
|
||||||
|
onOk={() => {
|
||||||
|
setProfileModal({ open: false, profileId: null })
|
||||||
|
tableRef.current?.reload()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PrinterProfiles
|
||||||
@ -0,0 +1,372 @@
|
|||||||
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import NewObjectForm from '../../common/NewObjectForm'
|
||||||
|
import ObjectForm from '../../common/ObjectForm'
|
||||||
|
import ObjectInfo from '../../common/ObjectInfo'
|
||||||
|
import WizardView from '../../common/WizardView'
|
||||||
|
|
||||||
|
const DEFAULT_EXTRUDER = {
|
||||||
|
nozzleDiameter: 0.4,
|
||||||
|
nozzleVolume: 0,
|
||||||
|
nozzleType: 'hardened_steel',
|
||||||
|
minLayerHeight: 0.05,
|
||||||
|
maxLayerHeight: 0.3,
|
||||||
|
positionOffsetX: 0,
|
||||||
|
positionOffsetY: 0,
|
||||||
|
retractionLength: 0.8,
|
||||||
|
retractionExtraLengthOnRestart: 0,
|
||||||
|
retractionSpeed: 35,
|
||||||
|
deretractionSpeed: 0,
|
||||||
|
retractionTravelDistanceThreshold: 2,
|
||||||
|
retractOnLayerChange: false,
|
||||||
|
wipeWhileRetracting: false,
|
||||||
|
wipeDistance: 1,
|
||||||
|
retractAmountBeforeWipe: 70,
|
||||||
|
retractAmountAfterWipe: 0,
|
||||||
|
zHopOnSurfaces: 'All Surfaces',
|
||||||
|
zHopType: 'Auto',
|
||||||
|
zHopHeight: 0,
|
||||||
|
zHopTravelingAngle: 0,
|
||||||
|
zHopOnlyLiftZAbove: 0,
|
||||||
|
zHopOnlyLiftZBelow: 0,
|
||||||
|
materialSwitchRetractionLength: 10,
|
||||||
|
materialSwitchExtraLengthOnRestart: 0,
|
||||||
|
longRetractionWhenCut: false
|
||||||
|
}
|
||||||
|
|
||||||
|
const PRUSA_MK3S_PROFILE_DEFAULTS = {
|
||||||
|
extruders: [{ ...DEFAULT_EXTRUDER }],
|
||||||
|
printBedWidth: 250,
|
||||||
|
printBedHeight: 210,
|
||||||
|
originX: 0,
|
||||||
|
originY: 0,
|
||||||
|
bedExcludeArea: [{ x: 0, y: 0 }],
|
||||||
|
printableHeight: 210,
|
||||||
|
supportMultiBedTypes: false,
|
||||||
|
bestObjectPositionX: 125,
|
||||||
|
bestObjectPositionY: 105,
|
||||||
|
zOffset: 0,
|
||||||
|
preferredOrientation: 0,
|
||||||
|
machineMaxAccelerationRetracting: { min: 2500, max: 2500 },
|
||||||
|
machineMaxSpeedE: { min: 120, max: 120 },
|
||||||
|
machineMaxSpeedX: { min: 200, max: 200 },
|
||||||
|
machineMaxSpeedY: { min: 200, max: 200 },
|
||||||
|
machinePauseGcode: 'M601',
|
||||||
|
machineStartGcode: `M862.1 P[nozzle_diameter] ; nozzle diameter check
|
||||||
|
M115 U3.13.0 ; tell printer latest fw version
|
||||||
|
G90 ; use absolute coordinates
|
||||||
|
M83 ; extruder relative mode
|
||||||
|
M104 S[first_layer_temperature] ; set extruder temp
|
||||||
|
M140 S[first_layer_bed_temperature] ; set bed temp
|
||||||
|
M190 S[first_layer_bed_temperature] ; wait for bed temp
|
||||||
|
M109 S[first_layer_temperature] ; wait for extruder temp
|
||||||
|
G28 W ; home all without mesh bed level
|
||||||
|
G80 ; mesh bed leveling
|
||||||
|
G1 Z0.3 F720
|
||||||
|
G1 Y-3 F1000 ; go outside print area
|
||||||
|
G92 E0
|
||||||
|
G1 X60 E9 F1000 ; intro line
|
||||||
|
G1 X100 E9 F1000 ; intro line
|
||||||
|
{else}
|
||||||
|
G1 Z0.2 F720
|
||||||
|
G1 Y-3 F1000 ; go outside print area
|
||||||
|
G92 E0
|
||||||
|
G1 X60 E9 F1000 ; intro line
|
||||||
|
G1 X100 E12.5 F1000 ; intro line
|
||||||
|
{endif}
|
||||||
|
G92 E0
|
||||||
|
M221 S{if layer_height<0.075}100{else}95{endif}`,
|
||||||
|
machineEndGcode: `{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}
|
||||||
|
G1 X0 Y200 F3600 ; park
|
||||||
|
{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+49, max_print_height)} F720 ; Move print head further up{endif}
|
||||||
|
G4 ; wait
|
||||||
|
M221 S100 ; reset flow
|
||||||
|
M900 K0 ; reset LA
|
||||||
|
M104 S0 ; turn off temperature
|
||||||
|
M140 S0 ; turn off heatbed
|
||||||
|
M107 ; turn off fan
|
||||||
|
M84 ; disable motors
|
||||||
|
; max_layer_z = [max_layer_z]`,
|
||||||
|
layerChangeGcode: `;AFTER_LAYER_CHANGE
|
||||||
|
;[layer_z]`,
|
||||||
|
beforeLayerChangeGcode: `;BEFORE_LAYER_CHANGE
|
||||||
|
;[layer_z]
|
||||||
|
G92 E0
|
||||||
|
`,
|
||||||
|
printerNotes: `Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.
|
||||||
|
PRINTER_VENDOR_PRUSA3D
|
||||||
|
PRINTER_MODEL_MK3
|
||||||
|
`,
|
||||||
|
scanFirstLayer: false,
|
||||||
|
machineLoadFilamentTime: 17,
|
||||||
|
machineUnloadFilamentTime: 16,
|
||||||
|
thumbnails: [{ width: 160, height: 120 }],
|
||||||
|
auxiliaryFan: false,
|
||||||
|
machineMaxJunctionDeviation: { min: 0.02, max: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
const REQUIRED_PROPERTIES = ['name', 'printer']
|
||||||
|
|
||||||
|
const DIMENSION_PROPERTIES = [
|
||||||
|
'printBedWidth',
|
||||||
|
'printBedHeight',
|
||||||
|
'originX',
|
||||||
|
'originY',
|
||||||
|
'printableHeight',
|
||||||
|
'supportMultiBedTypes',
|
||||||
|
'bestObjectPositionX',
|
||||||
|
'bestObjectPositionY',
|
||||||
|
'zOffset',
|
||||||
|
'preferredOrientation'
|
||||||
|
]
|
||||||
|
|
||||||
|
const EXTRUDER_STEP_PROPERTIES = ['extruders']
|
||||||
|
|
||||||
|
const MOTION_PROPERTIES = [
|
||||||
|
'machineMaxAccelerationRetracting',
|
||||||
|
'machineMaxSpeedE',
|
||||||
|
'machineMaxSpeedX',
|
||||||
|
'machineMaxSpeedY',
|
||||||
|
'machineMaxJunctionDeviation'
|
||||||
|
]
|
||||||
|
|
||||||
|
const OPTIONAL_PROPERTIES = [
|
||||||
|
'scanFirstLayer',
|
||||||
|
'machineLoadFilamentTime',
|
||||||
|
'machineUnloadFilamentTime',
|
||||||
|
'auxiliaryFan'
|
||||||
|
]
|
||||||
|
|
||||||
|
const SUMMARY_PROPERTIES = [
|
||||||
|
...REQUIRED_PROPERTIES,
|
||||||
|
...DIMENSION_PROPERTIES,
|
||||||
|
...MOTION_PROPERTIES,
|
||||||
|
...OPTIONAL_PROPERTIES
|
||||||
|
]
|
||||||
|
|
||||||
|
const PrinterProfileWizard = ({
|
||||||
|
objectData,
|
||||||
|
formValid,
|
||||||
|
loading,
|
||||||
|
onSubmit,
|
||||||
|
editing,
|
||||||
|
printerId = null
|
||||||
|
}) => {
|
||||||
|
const visibleProperties = useMemo(() => {
|
||||||
|
if (!printerId) return undefined
|
||||||
|
return { printer: false, 'printer._id': false }
|
||||||
|
}, [printerId])
|
||||||
|
|
||||||
|
const steps = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
title: 'Required',
|
||||||
|
key: 'required',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='printerProfile'
|
||||||
|
properties={REQUIRED_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
labelWidth='75px'
|
||||||
|
required={true}
|
||||||
|
objectData={objectData}
|
||||||
|
visibleProperties={visibleProperties}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Dimensions',
|
||||||
|
key: 'dimensions',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='printerProfile'
|
||||||
|
properties={DIMENSION_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
labelWidth='190px'
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Extruders',
|
||||||
|
key: 'extruders',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='printerProfile'
|
||||||
|
properties={EXTRUDER_STEP_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
showLabels={false}
|
||||||
|
labelWidth='90px'
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Motion',
|
||||||
|
key: 'motion',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='printerProfile'
|
||||||
|
properties={MOTION_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
labelWidth='185px'
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Optional',
|
||||||
|
key: 'optional',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='printerProfile'
|
||||||
|
properties={OPTIONAL_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
labelWidth='170px'
|
||||||
|
bordered={false}
|
||||||
|
isEditing
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Summary',
|
||||||
|
key: 'summary',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='printerProfile'
|
||||||
|
properties={SUMMARY_PROPERTIES}
|
||||||
|
column={1}
|
||||||
|
bordered={false}
|
||||||
|
isEditing={false}
|
||||||
|
labelWidth='210px'
|
||||||
|
objectData={objectData}
|
||||||
|
visibleProperties={visibleProperties}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[objectData, visibleProperties]
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WizardView
|
||||||
|
sizeBarWidth='160px'
|
||||||
|
steps={steps}
|
||||||
|
loading={loading}
|
||||||
|
formValid={formValid}
|
||||||
|
title={editing ? 'Edit Printer Profile' : 'New Printer Profile'}
|
||||||
|
submitText={editing ? 'Save' : 'Create'}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
PrinterProfileWizard.propTypes = {
|
||||||
|
objectData: PropTypes.object,
|
||||||
|
formValid: PropTypes.bool.isRequired,
|
||||||
|
loading: PropTypes.bool,
|
||||||
|
onSubmit: PropTypes.func.isRequired,
|
||||||
|
editing: PropTypes.bool,
|
||||||
|
printerId: PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
const NewPrinterProfile = ({ onOk, printerId = null }) => (
|
||||||
|
<NewObjectForm
|
||||||
|
type='printerProfile'
|
||||||
|
defaultValues={{
|
||||||
|
...PRUSA_MK3S_PROFILE_DEFAULTS,
|
||||||
|
...(printerId ? { printer: printerId } : {})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({ handleSubmit, submitLoading, objectData, formValid }) => (
|
||||||
|
<PrinterProfileWizard
|
||||||
|
objectData={objectData}
|
||||||
|
formValid={formValid}
|
||||||
|
loading={submitLoading}
|
||||||
|
printerId={printerId}
|
||||||
|
onSubmit={async () => {
|
||||||
|
const result = await handleSubmit()
|
||||||
|
if (result?._id) onOk(result)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</NewObjectForm>
|
||||||
|
)
|
||||||
|
|
||||||
|
NewPrinterProfile.propTypes = {
|
||||||
|
onOk: PropTypes.func.isRequired,
|
||||||
|
printerId: PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EditPrinterProfile = ({ profileId, onOk, printerId = null }) => {
|
||||||
|
const formRef = useRef(null)
|
||||||
|
const startedEditingRef = useRef(false)
|
||||||
|
const saveRequestedRef = useRef(false)
|
||||||
|
const stateRef = useRef({})
|
||||||
|
const [formState, setFormState] = useState({
|
||||||
|
loading: true,
|
||||||
|
editLoading: false,
|
||||||
|
formValid: false,
|
||||||
|
isEditing: false,
|
||||||
|
objectData: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
!formState.loading &&
|
||||||
|
!formState.isEditing &&
|
||||||
|
!startedEditingRef.current
|
||||||
|
) {
|
||||||
|
startedEditingRef.current = true
|
||||||
|
formRef.current?.startEditing()
|
||||||
|
}
|
||||||
|
}, [formState.isEditing, formState.loading])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ObjectForm
|
||||||
|
id={profileId}
|
||||||
|
type='printerProfile'
|
||||||
|
ref={formRef}
|
||||||
|
onStateChange={(nextState) => {
|
||||||
|
stateRef.current = { ...stateRef.current, ...nextState }
|
||||||
|
setFormState((current) => ({ ...current, ...nextState }))
|
||||||
|
|
||||||
|
if (saveRequestedRef.current && nextState.isEditing === false) {
|
||||||
|
saveRequestedRef.current = false
|
||||||
|
onOk(stateRef.current.objectData)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({ objectData, formValid, editLoading, handleUpdate }) => (
|
||||||
|
<PrinterProfileWizard
|
||||||
|
editing
|
||||||
|
objectData={objectData}
|
||||||
|
formValid={formValid}
|
||||||
|
loading={formState.loading || editLoading}
|
||||||
|
printerId={printerId}
|
||||||
|
onSubmit={() => {
|
||||||
|
saveRequestedRef.current = true
|
||||||
|
handleUpdate()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ObjectForm>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
EditPrinterProfile.propTypes = {
|
||||||
|
profileId: PropTypes.string.isRequired,
|
||||||
|
onOk: PropTypes.func.isRequired,
|
||||||
|
printerId: PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NewPrinterProfile
|
||||||
@ -0,0 +1,381 @@
|
|||||||
|
import { useRef, useState } from 'react'
|
||||||
|
import { useLocation } from 'react-router-dom'
|
||||||
|
import { Card, Flex, Space } from 'antd'
|
||||||
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
|
import ActionHandler from '../../common/ActionHandler'
|
||||||
|
import AuditLogIcon from '../../../Icons/AuditLogIcon'
|
||||||
|
import DocumentPrintButton from '../../common/DocumentPrintButton'
|
||||||
|
import EditButtons from '../../common/EditButtons'
|
||||||
|
import HotEndIcon from '../../../Icons/HotEndIcon'
|
||||||
|
import InfoCircleIcon from '../../../Icons/InfoCircleIcon'
|
||||||
|
import MultiMotionIcon from '../../../Icons/MultiMotionIcon'
|
||||||
|
import PictureIcon from '../../../Icons/PictureIcon'
|
||||||
|
import RulerIcon from '../../../Icons/RulerIcon'
|
||||||
|
import InfoCollapse from '../../common/InfoCollapse'
|
||||||
|
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder'
|
||||||
|
import LockIndicator from '../../common/LockIndicator'
|
||||||
|
import NoteIcon from '../../../Icons/NoteIcon'
|
||||||
|
import NotesPanel from '../../common/NotesPanel'
|
||||||
|
import ObjectActions from '../../common/ObjectActions'
|
||||||
|
import ObjectForm from '../../common/ObjectForm'
|
||||||
|
import ObjectInfo from '../../common/ObjectInfo'
|
||||||
|
import ObjectTable from '../../common/ObjectTable'
|
||||||
|
import ScrollBox from '../../common/ScrollBox'
|
||||||
|
import UserNotifierToggle from '../../common/UserNotifierToggle'
|
||||||
|
import ViewButton from '../../common/ViewButton'
|
||||||
|
import useCollapseState from '../../hooks/useCollapseState'
|
||||||
|
import ObjectProperty from '../../common/ObjectProperty'
|
||||||
|
import { getModelProperty } from '../../../../database/ObjectModels'
|
||||||
|
import GCodeFileIcon from '../../../Icons/GCodeFileIcon'
|
||||||
|
import SettingsIcon from '../../../Icons/SettingsIcon'
|
||||||
|
import ExclamationOctagonIcon from '../../../Icons/ExclamationOctagonIcon'
|
||||||
|
|
||||||
|
const PrinterProfileInfo = () => {
|
||||||
|
const location = useLocation()
|
||||||
|
const objectFormRef = useRef(null)
|
||||||
|
const actionHandlerRef = useRef(null)
|
||||||
|
const printerProfileId = new URLSearchParams(location.search).get(
|
||||||
|
'printerProfileId'
|
||||||
|
)
|
||||||
|
const [collapseState, updateCollapseState] = useCollapseState(
|
||||||
|
'PrinterProfileInfo',
|
||||||
|
{
|
||||||
|
info: true,
|
||||||
|
dimensions: true,
|
||||||
|
bedExcludeArea: true,
|
||||||
|
extruders: true,
|
||||||
|
motion: true,
|
||||||
|
gCodeSettings: true,
|
||||||
|
optional: true,
|
||||||
|
thumbnails: true,
|
||||||
|
notes: true,
|
||||||
|
auditLogs: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const [objectFormState, setObjectFormState] = useState({
|
||||||
|
isEditing: false,
|
||||||
|
editLoading: false,
|
||||||
|
formValid: false,
|
||||||
|
lock: null,
|
||||||
|
loading: false,
|
||||||
|
objectData: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
edit: () => {
|
||||||
|
objectFormRef.current?.startEditing?.()
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
cancelEdit: () => {
|
||||||
|
objectFormRef.current?.cancelEditing?.()
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
finishEdit: () => {
|
||||||
|
objectFormRef.current?.handleUpdate?.()
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
delete: () => {
|
||||||
|
objectFormRef.current?.handleDelete?.()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
gap='large'
|
||||||
|
vertical='true'
|
||||||
|
style={{ maxHeight: '100%', minHeight: 0 }}
|
||||||
|
>
|
||||||
|
<Flex justify='space-between'>
|
||||||
|
<Space size='middle'>
|
||||||
|
<Space size='small'>
|
||||||
|
<ObjectActions
|
||||||
|
type='printerProfile'
|
||||||
|
id={printerProfileId}
|
||||||
|
disabled={objectFormState.loading}
|
||||||
|
objectData={objectFormState.objectData}
|
||||||
|
/>
|
||||||
|
<ViewButton
|
||||||
|
disabled={objectFormState.loading}
|
||||||
|
items={[
|
||||||
|
{ key: 'info', label: 'Printer Profile Information' },
|
||||||
|
{ key: 'dimensions', label: 'Dimensions' },
|
||||||
|
{ key: 'bedExcludeArea', label: 'Excluded Bed Area' },
|
||||||
|
{ key: 'extruders', label: 'Extruders' },
|
||||||
|
{ key: 'motion', label: 'Motion' },
|
||||||
|
{ key: 'gCodeSettings', label: 'G-Code Settings' },
|
||||||
|
{ key: 'miscellaneous', label: 'Miscellaneous' },
|
||||||
|
{ key: 'thumbnails', label: 'Thumbnail Sizes' },
|
||||||
|
{ key: 'notes', label: 'Notes' },
|
||||||
|
{ key: 'auditLogs', label: 'Audit Logs' }
|
||||||
|
]}
|
||||||
|
visibleState={collapseState}
|
||||||
|
updateVisibleState={updateCollapseState}
|
||||||
|
/>
|
||||||
|
<UserNotifierToggle
|
||||||
|
type='printerProfile'
|
||||||
|
objectData={objectFormState.objectData}
|
||||||
|
disabled={objectFormState.loading}
|
||||||
|
/>
|
||||||
|
<DocumentPrintButton
|
||||||
|
type='printerProfile'
|
||||||
|
objectData={objectFormState.objectData}
|
||||||
|
disabled={objectFormState.loading}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
|
</Space>
|
||||||
|
<EditButtons
|
||||||
|
isEditing={objectFormState.isEditing}
|
||||||
|
handleUpdate={() => actionHandlerRef.current.callAction('finishEdit')}
|
||||||
|
cancelEditing={() =>
|
||||||
|
actionHandlerRef.current.callAction('cancelEdit')
|
||||||
|
}
|
||||||
|
startEditing={() => actionHandlerRef.current.callAction('edit')}
|
||||||
|
editLoading={objectFormState.editLoading}
|
||||||
|
formValid={objectFormState.formValid}
|
||||||
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
|
loading={objectFormState.editLoading}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<ScrollBox>
|
||||||
|
<Flex vertical gap='large'>
|
||||||
|
<ActionHandler
|
||||||
|
actions={actions}
|
||||||
|
loading={objectFormState.loading}
|
||||||
|
ref={actionHandlerRef}
|
||||||
|
>
|
||||||
|
<ObjectForm
|
||||||
|
id={printerProfileId}
|
||||||
|
type='printerProfile'
|
||||||
|
ref={objectFormRef}
|
||||||
|
onStateChange={(state) =>
|
||||||
|
setObjectFormState((current) => ({ ...current, ...state }))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{({ loading, isEditing, objectData }) => (
|
||||||
|
<Flex vertical gap='large'>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Printer Profile Information'
|
||||||
|
icon={<InfoCircleIcon />}
|
||||||
|
active={collapseState.info}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('info', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='info'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='printerProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='140px'
|
||||||
|
visibleProperties={{
|
||||||
|
_id: true,
|
||||||
|
name: true,
|
||||||
|
_reference: true,
|
||||||
|
printer: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Dimensions'
|
||||||
|
icon={<RulerIcon />}
|
||||||
|
active={collapseState.dimensions}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('dimensions', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='dimensions'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='printerProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='230px'
|
||||||
|
visibleProperties={{
|
||||||
|
printBedWidth: true,
|
||||||
|
printBedHeight: true,
|
||||||
|
originX: true,
|
||||||
|
originY: true,
|
||||||
|
printableHeight: true,
|
||||||
|
supportMultiBedTypes: true,
|
||||||
|
bestObjectPositionX: true,
|
||||||
|
bestObjectPositionY: true,
|
||||||
|
zOffset: true,
|
||||||
|
preferredOrientation: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Excluded Bed Area'
|
||||||
|
icon={<ExclamationOctagonIcon />}
|
||||||
|
active={collapseState.bedExcludeArea}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('bedExcludeArea', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='bedExcludeArea'
|
||||||
|
>
|
||||||
|
<ObjectProperty
|
||||||
|
{...getModelProperty('printerProfile', 'bedExcludeArea')}
|
||||||
|
isEditing={isEditing}
|
||||||
|
objectData={objectData}
|
||||||
|
loading={loading}
|
||||||
|
size='medium'
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Extruders'
|
||||||
|
icon={<HotEndIcon />}
|
||||||
|
active={collapseState.extruders}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('extruders', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='extruders'
|
||||||
|
>
|
||||||
|
<ObjectProperty
|
||||||
|
{...getModelProperty('printerProfile', 'extruders')}
|
||||||
|
isEditing={isEditing}
|
||||||
|
objectData={objectData}
|
||||||
|
loading={loading}
|
||||||
|
size='medium'
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Motion'
|
||||||
|
icon={<MultiMotionIcon />}
|
||||||
|
active={collapseState.motion}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('motion', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='motion'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='printerProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='225px'
|
||||||
|
visibleProperties={{
|
||||||
|
machineMaxAccelerationRetracting: true,
|
||||||
|
machineMaxSpeedE: true,
|
||||||
|
machineMaxSpeedX: true,
|
||||||
|
machineMaxSpeedY: true,
|
||||||
|
machineMaxJunctionDeviation: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='G-Code Settings'
|
||||||
|
icon={<GCodeFileIcon />}
|
||||||
|
active={collapseState.gCodeSettings}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('gCodeSettings', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='gCodeSettings'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='printerProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='240px'
|
||||||
|
visibleProperties={{
|
||||||
|
machinePauseGcode: true,
|
||||||
|
machineStartGcode: true,
|
||||||
|
machineEndGcode: true,
|
||||||
|
layerChangeGcode: true,
|
||||||
|
beforeLayerChangeGcode: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Miscellaneous'
|
||||||
|
icon={<SettingsIcon />}
|
||||||
|
active={collapseState.miscellaneous}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('miscellaneous', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='miscellaneous'
|
||||||
|
>
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
indicator={<LoadingOutlined />}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='printerProfile'
|
||||||
|
objectData={objectData}
|
||||||
|
labelWidth='210px'
|
||||||
|
visibleProperties={{
|
||||||
|
printerNotes: true,
|
||||||
|
scanFirstLayer: true,
|
||||||
|
machineLoadFilamentTime: true,
|
||||||
|
machineUnloadFilamentTime: true,
|
||||||
|
auxiliaryFan: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Thumbnail Sizes'
|
||||||
|
icon={<PictureIcon />}
|
||||||
|
active={collapseState.thumbnails}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('thumbnails', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='thumbnails'
|
||||||
|
>
|
||||||
|
<ObjectProperty
|
||||||
|
{...getModelProperty('printerProfile', 'thumbnails')}
|
||||||
|
isEditing={isEditing}
|
||||||
|
objectData={objectData}
|
||||||
|
loading={loading}
|
||||||
|
size='medium'
|
||||||
|
/>
|
||||||
|
</InfoCollapse>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</ObjectForm>
|
||||||
|
</ActionHandler>
|
||||||
|
|
||||||
|
<InfoCollapse
|
||||||
|
title='Notes'
|
||||||
|
icon={<NoteIcon />}
|
||||||
|
active={collapseState.notes}
|
||||||
|
onToggle={(expanded) => updateCollapseState('notes', expanded)}
|
||||||
|
collapseKey='notes'
|
||||||
|
>
|
||||||
|
<Card>
|
||||||
|
<NotesPanel _id={printerProfileId} type='printerProfile' />
|
||||||
|
</Card>
|
||||||
|
</InfoCollapse>
|
||||||
|
|
||||||
|
<InfoCollapse
|
||||||
|
title='Audit Logs'
|
||||||
|
icon={<AuditLogIcon />}
|
||||||
|
active={collapseState.auditLogs}
|
||||||
|
onToggle={(expanded) => updateCollapseState('auditLogs', expanded)}
|
||||||
|
collapseKey='auditLogs'
|
||||||
|
>
|
||||||
|
{objectFormState.loading ? (
|
||||||
|
<InfoCollapsePlaceholder />
|
||||||
|
) : (
|
||||||
|
<ObjectTable
|
||||||
|
type='auditLog'
|
||||||
|
masterFilter={{ 'parent._id': printerProfileId }}
|
||||||
|
visibleColumns={{ _id: false, 'parent._id': false }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</InfoCollapse>
|
||||||
|
</Flex>
|
||||||
|
</ScrollBox>
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PrinterProfileInfo
|
||||||
1464
src/database/models/FilamentProfile.js
Normal file
1464
src/database/models/FilamentProfile.js
Normal file
File diff suppressed because it is too large
Load Diff
665
src/database/models/PrinterProfile.js
Normal file
665
src/database/models/PrinterProfile.js
Normal file
@ -0,0 +1,665 @@
|
|||||||
|
import PrinterProfileIcon from '../../components/Icons/PrinterProfileIcon'
|
||||||
|
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
|
||||||
|
import EditIcon from '../../components/Icons/EditIcon'
|
||||||
|
import CheckIcon from '../../components/Icons/CheckIcon'
|
||||||
|
import XMarkIcon from '../../components/Icons/XMarkIcon'
|
||||||
|
import BinIcon from '../../components/Icons/BinIcon'
|
||||||
|
|
||||||
|
const THUMBNAIL_PROPERTIES = [
|
||||||
|
{
|
||||||
|
name: 'width',
|
||||||
|
label: 'Width',
|
||||||
|
type: 'number',
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'height',
|
||||||
|
label: 'Height',
|
||||||
|
type: 'number',
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 120
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const BED_EXCLUDE_AREA_PROPERTIES = [
|
||||||
|
{
|
||||||
|
name: 'x',
|
||||||
|
label: 'X',
|
||||||
|
type: 'number',
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'y',
|
||||||
|
label: 'Y',
|
||||||
|
type: 'number',
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 120
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const EXTRUDER_PROPERTIES = [
|
||||||
|
{
|
||||||
|
name: 'nozzleDiameter',
|
||||||
|
label: 'Nozzle Diameter',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.05,
|
||||||
|
columnWidth: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'nozzleVolume',
|
||||||
|
label: 'Nozzle Volume',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm³',
|
||||||
|
min: 0,
|
||||||
|
step: 0.1,
|
||||||
|
columnWidth: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'nozzleType',
|
||||||
|
label: 'Nozzle Type',
|
||||||
|
type: 'text',
|
||||||
|
columnWidth: 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'minLayerHeight',
|
||||||
|
label: 'Min Layer Height',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 180
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'maxLayerHeight',
|
||||||
|
label: 'Max Layer Height',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 180
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'positionOffsetX',
|
||||||
|
label: 'Extruder Offset X',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 180
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'positionOffsetY',
|
||||||
|
label: 'Extruder Offset Y',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 180
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'retractionLength',
|
||||||
|
label: 'Retraction Length',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.1,
|
||||||
|
columnWidth: 170
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'retractionExtraLengthOnRestart',
|
||||||
|
label: 'Extra Length on Restart',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.1,
|
||||||
|
columnWidth: 210
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'retractionSpeed',
|
||||||
|
label: 'Retraction Speed',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm/s',
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 170
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'deretractionSpeed',
|
||||||
|
label: 'Deretraction Speed',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm/s',
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 180
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'retractionTravelDistanceThreshold',
|
||||||
|
label: 'Travel Distance Threshold',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.1,
|
||||||
|
columnWidth: 220
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'retractOnLayerChange',
|
||||||
|
label: 'Retract on Layer Change',
|
||||||
|
type: 'bool',
|
||||||
|
columnWidth: 210
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'wipeWhileRetracting',
|
||||||
|
label: 'Wipe While Retracting',
|
||||||
|
type: 'bool',
|
||||||
|
columnWidth: 190
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'wipeDistance',
|
||||||
|
label: 'Wipe Distance',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.1,
|
||||||
|
columnWidth: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'retractAmountBeforeWipe',
|
||||||
|
label: 'Retract Amount Before Wipe',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.1,
|
||||||
|
columnWidth: 230
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'retractAmountAfterWipe',
|
||||||
|
label: 'Retract Amount After Wipe',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.1,
|
||||||
|
columnWidth: 230
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'zHopOnSurfaces',
|
||||||
|
label: 'Z-Hop On Surfaces',
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: 'All Surfaces', value: 'All Surfaces' },
|
||||||
|
{ label: 'Top Only', value: 'Top Only' },
|
||||||
|
{ label: 'Bottom Only', value: 'Bottom Only' },
|
||||||
|
{ label: 'None', value: 'None' }
|
||||||
|
],
|
||||||
|
columnWidth: 170
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'zHopType',
|
||||||
|
label: 'Z-Hop Type',
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: 'Auto', value: 'Auto' },
|
||||||
|
{ label: 'Normal', value: 'Normal' },
|
||||||
|
{ label: 'Spiral', value: 'Spiral' },
|
||||||
|
{ label: 'Slope', value: 'Slope' }
|
||||||
|
],
|
||||||
|
columnWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'zHopHeight',
|
||||||
|
label: 'Z-Hop Height',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'zHopTravelingAngle',
|
||||||
|
label: 'Traveling Angle',
|
||||||
|
type: 'number',
|
||||||
|
suffix: '°',
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'zHopOnlyLiftZAbove',
|
||||||
|
label: 'Only Lift Z Above',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 170
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'zHopOnlyLiftZBelow',
|
||||||
|
label: 'Only Lift Z Below',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 170
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'materialSwitchRetractionLength',
|
||||||
|
label: 'Material Switch Retraction Length',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.1,
|
||||||
|
columnWidth: 250
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'materialSwitchExtraLengthOnRestart',
|
||||||
|
label: 'Material Switch Extra Length on Restart',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.1,
|
||||||
|
columnWidth: 290
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'longRetractionWhenCut',
|
||||||
|
label: 'Long Retraction When Cut (beta)',
|
||||||
|
type: 'bool',
|
||||||
|
columnWidth: 240
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const PrinterProfile = {
|
||||||
|
name: 'printerProfile',
|
||||||
|
label: 'Printer Profile',
|
||||||
|
labelPlural: 'Printer Profiles',
|
||||||
|
url: '/dashboard/production/printerprofiles',
|
||||||
|
prefix: 'PPF',
|
||||||
|
icon: PrinterProfileIcon,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
name: 'info',
|
||||||
|
label: 'Info',
|
||||||
|
default: true,
|
||||||
|
row: true,
|
||||||
|
icon: InfoCircleIcon,
|
||||||
|
url: (_id) =>
|
||||||
|
`/dashboard/production/printerprofiles/info?printerProfileId=${_id}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'edit',
|
||||||
|
label: 'Edit',
|
||||||
|
row: true,
|
||||||
|
icon: EditIcon,
|
||||||
|
url: (_id) =>
|
||||||
|
`/dashboard/production/printerprofiles/info?printerProfileId=${_id}&action=edit`,
|
||||||
|
visible: (objectData) => !objectData?._isEditing
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'finishEdit',
|
||||||
|
label: 'Save Edits',
|
||||||
|
icon: CheckIcon,
|
||||||
|
url: (_id) =>
|
||||||
|
`/dashboard/production/printerprofiles/info?printerProfileId=${_id}&action=finishEdit`,
|
||||||
|
visible: (objectData) => objectData?._isEditing === true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cancelEdit',
|
||||||
|
label: 'Cancel Edits',
|
||||||
|
icon: XMarkIcon,
|
||||||
|
url: (_id) =>
|
||||||
|
`/dashboard/production/printerprofiles/info?printerProfileId=${_id}&action=cancelEdit`,
|
||||||
|
visible: (objectData) => objectData?._isEditing === true
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
name: 'delete',
|
||||||
|
label: 'Delete',
|
||||||
|
row: true,
|
||||||
|
icon: BinIcon,
|
||||||
|
danger: true,
|
||||||
|
url: (_id) =>
|
||||||
|
`/dashboard/production/printerprofiles/info?printerProfileId=${_id}&action=delete`
|
||||||
|
}
|
||||||
|
],
|
||||||
|
columns: [
|
||||||
|
'_reference',
|
||||||
|
'name',
|
||||||
|
'printer',
|
||||||
|
'printBedWidth',
|
||||||
|
'printBedHeight',
|
||||||
|
'printableHeight',
|
||||||
|
'extruders.0.nozzleDiameter',
|
||||||
|
'extruders.0.nozzleType',
|
||||||
|
'zOffset',
|
||||||
|
'scanFirstLayer',
|
||||||
|
'auxiliaryFan',
|
||||||
|
'updatedAt'
|
||||||
|
],
|
||||||
|
filters: ['_id', 'name', 'printer'],
|
||||||
|
sorters: [
|
||||||
|
'name',
|
||||||
|
'printBedWidth',
|
||||||
|
'printBedHeight',
|
||||||
|
'printableHeight',
|
||||||
|
'zOffset',
|
||||||
|
'createdAt',
|
||||||
|
'updatedAt'
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
name: '_id',
|
||||||
|
label: 'ID',
|
||||||
|
type: 'id',
|
||||||
|
objectType: 'printerProfile',
|
||||||
|
showCopy: true,
|
||||||
|
readOnly: true,
|
||||||
|
columnWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'createdAt',
|
||||||
|
label: 'Created At',
|
||||||
|
type: 'dateTime',
|
||||||
|
readOnly: true,
|
||||||
|
columnWidth: 175
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '_reference',
|
||||||
|
label: 'Reference',
|
||||||
|
type: 'reference',
|
||||||
|
objectType: 'printerProfile',
|
||||||
|
showCopy: true,
|
||||||
|
readOnly: true,
|
||||||
|
columnFixed: 'left',
|
||||||
|
columnWidth: 180
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'updatedAt',
|
||||||
|
label: 'Updated At',
|
||||||
|
type: 'dateTime',
|
||||||
|
readOnly: true,
|
||||||
|
columnWidth: 175
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
label: 'Name',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
columnFixed: 'left',
|
||||||
|
columnWidth: 220,
|
||||||
|
value: (objectData) => {
|
||||||
|
if (objectData?.name == undefined) {
|
||||||
|
return objectData?.printer?.name
|
||||||
|
}
|
||||||
|
return objectData?.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'printer',
|
||||||
|
label: 'Printer',
|
||||||
|
type: 'object',
|
||||||
|
objectType: 'printer',
|
||||||
|
required: true,
|
||||||
|
showHyperlink: true,
|
||||||
|
columnWidth: 220
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'printBedWidth',
|
||||||
|
label: 'Print Bed Width',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 170
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'printBedHeight',
|
||||||
|
label: 'Print Bed Height',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 170
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'originX',
|
||||||
|
label: 'Origin X',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'originY',
|
||||||
|
label: 'Origin Y',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'bestObjectPositionX',
|
||||||
|
label: 'Best Object Position X',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'bestObjectPositionY',
|
||||||
|
label: 'Best Object Position Y',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'bedExcludeArea',
|
||||||
|
label: 'Excluded Bed Area',
|
||||||
|
type: 'objectChildren',
|
||||||
|
canAddRemove: true,
|
||||||
|
span: 2,
|
||||||
|
columns: ['x', 'y'],
|
||||||
|
properties: BED_EXCLUDE_AREA_PROPERTIES
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'printableHeight',
|
||||||
|
label: 'Printable Height',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 170
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'supportMultiBedTypes',
|
||||||
|
label: 'Support Multi Bed Types',
|
||||||
|
type: 'bool',
|
||||||
|
columnWidth: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'zOffset',
|
||||||
|
label: 'Z Offset',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'preferredOrientation',
|
||||||
|
label: 'Preferred Orientation',
|
||||||
|
type: 'number',
|
||||||
|
suffix: '°',
|
||||||
|
min: 0,
|
||||||
|
max: 360,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 190
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'extruders.0.nozzleDiameter',
|
||||||
|
label: 'Nozzle Diameter',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.05,
|
||||||
|
readOnly: true,
|
||||||
|
columnWidth: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'extruders.0.nozzleType',
|
||||||
|
label: 'Nozzle Type',
|
||||||
|
type: 'text',
|
||||||
|
readOnly: true,
|
||||||
|
columnWidth: 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'extruders',
|
||||||
|
label: 'Extruders',
|
||||||
|
type: 'objectChildren',
|
||||||
|
canAddRemove: true,
|
||||||
|
span: 2,
|
||||||
|
columns: [
|
||||||
|
'nozzleDiameter',
|
||||||
|
'nozzleType',
|
||||||
|
'nozzleVolume',
|
||||||
|
'minLayerHeight',
|
||||||
|
'maxLayerHeight',
|
||||||
|
'positionOffsetX',
|
||||||
|
'positionOffsetY'
|
||||||
|
],
|
||||||
|
hiddenPropertyWidth: 330,
|
||||||
|
properties: EXTRUDER_PROPERTIES
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'machineMaxAccelerationRetracting',
|
||||||
|
label: 'Max Retracting Accel',
|
||||||
|
type: 'minMax',
|
||||||
|
suffix: ' mm/s²',
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 260
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'machineMaxSpeedE',
|
||||||
|
label: 'Max Extruder Speed',
|
||||||
|
type: 'minMax',
|
||||||
|
suffix: ' mm/s',
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 220
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'machineMaxSpeedX',
|
||||||
|
label: 'Max X Speed',
|
||||||
|
type: 'minMax',
|
||||||
|
suffix: ' mm/s',
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 190
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'machineMaxSpeedY',
|
||||||
|
label: 'Max Y Speed',
|
||||||
|
type: 'minMax',
|
||||||
|
suffix: ' mm/s',
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
columnWidth: 190
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'machinePauseGcode',
|
||||||
|
label: 'Pause G-code',
|
||||||
|
type: 'codeBlock',
|
||||||
|
language: 'gcode',
|
||||||
|
height: '180px',
|
||||||
|
span: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'machineStartGcode',
|
||||||
|
label: 'Start G-code',
|
||||||
|
type: 'codeBlock',
|
||||||
|
language: 'gcode',
|
||||||
|
height: '240px',
|
||||||
|
span: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'machineEndGcode',
|
||||||
|
label: 'End G-code',
|
||||||
|
type: 'codeBlock',
|
||||||
|
language: 'gcode',
|
||||||
|
height: '240px',
|
||||||
|
span: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'layerChangeGcode',
|
||||||
|
label: 'Layer Change G-code',
|
||||||
|
type: 'codeBlock',
|
||||||
|
language: 'gcode',
|
||||||
|
height: '180px',
|
||||||
|
span: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'beforeLayerChangeGcode',
|
||||||
|
label: 'Before Layer Change G-code',
|
||||||
|
type: 'codeBlock',
|
||||||
|
language: 'gcode',
|
||||||
|
height: '180px',
|
||||||
|
span: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'machineLoadFilamentTime',
|
||||||
|
label: 'Filament Load Time',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' s',
|
||||||
|
min: 0,
|
||||||
|
step: 0.1,
|
||||||
|
columnWidth: 180
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'scanFirstLayer',
|
||||||
|
label: 'Scan First Layer',
|
||||||
|
type: 'bool',
|
||||||
|
columnWidth: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'machineUnloadFilamentTime',
|
||||||
|
label: 'Filament Unload Time',
|
||||||
|
type: 'number',
|
||||||
|
suffix: ' s',
|
||||||
|
min: 0,
|
||||||
|
step: 0.1,
|
||||||
|
columnWidth: 190
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'thumbnails',
|
||||||
|
label: 'Thumbnail Sizes',
|
||||||
|
type: 'objectChildren',
|
||||||
|
canAddRemove: true,
|
||||||
|
span: 2,
|
||||||
|
columns: ['width', 'height'],
|
||||||
|
properties: THUMBNAIL_PROPERTIES
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'auxiliaryFan',
|
||||||
|
label: 'Auxiliary Fan',
|
||||||
|
type: 'bool',
|
||||||
|
columnWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'printerNotes',
|
||||||
|
label: 'Printer Notes',
|
||||||
|
type: 'markdown',
|
||||||
|
span: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'machineMaxJunctionDeviation',
|
||||||
|
label: 'Max Junction Deviation',
|
||||||
|
type: 'minMax',
|
||||||
|
suffix: ' mm',
|
||||||
|
min: 0,
|
||||||
|
step: 0.01,
|
||||||
|
columnWidth: 240
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user