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