diff --git a/src/components/Dashboard/Production/FilamentProfiles.jsx b/src/components/Dashboard/Production/FilamentProfiles.jsx
new file mode 100644
index 0000000..bc0a275
--- /dev/null
+++ b/src/components/Dashboard/Production/FilamentProfiles.jsx
@@ -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:
+ },
+ { type: 'divider' },
+ {
+ label: 'Reload List',
+ key: 'reloadList',
+ icon:
+ }
+ ],
+ 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 (
+ <>
+
+
+
+
+
+
+
+
+
+
+ setShowFilterSidebar(!showFilterSidebar)}
+ />
+
+
+
+
+
+
+
+ setProfileModal({ open: false, profileId: null })}
+ destroyOnHidden
+ >
+ {profileModal.open &&
+ (profileModal.profileId ? (
+ {
+ setProfileModal({ open: false, profileId: null })
+ tableRef.current?.reload()
+ }}
+ />
+ ) : (
+ {
+ setProfileModal({ open: false, profileId: null })
+ tableRef.current?.reload()
+ }}
+ />
+ ))}
+
+ >
+ )
+}
+
+export default FilamentProfiles
diff --git a/src/components/Dashboard/Production/FilamentProfiles/FilamentProfileInfo.jsx b/src/components/Dashboard/Production/FilamentProfiles/FilamentProfileInfo.jsx
new file mode 100644
index 0000000..4e2900d
--- /dev/null
+++ b/src/components/Dashboard/Production/FilamentProfiles/FilamentProfileInfo.jsx
@@ -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 (
+
+
+
+
+
+
+
+
+
+
+
+ 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}
+ />
+
+
+
+
+
+
+ setObjectFormState((current) => ({ ...current, ...state }))
+ }
+ >
+ {({ loading, isEditing, objectData }) => (
+
+ }
+ active={collapseState.info}
+ onToggle={(expanded) =>
+ updateCollapseState('info', expanded)
+ }
+ collapseKey='info'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='140px'
+ visibleProperties={{
+ _id: true,
+ name: true,
+ _reference: true,
+ filamentType: true,
+ filament: true,
+ createdAt: true,
+ updatedAt: true
+ }}
+ />
+
+ }
+ active={collapseState.material}
+ onToggle={(expanded) =>
+ updateCollapseState('material', expanded)
+ }
+ collapseKey='material'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='220px'
+ visibleProperties={toVisibleProperties(
+ FILAMENT_PROFILE_MATERIAL_PROPERTIES
+ )}
+ />
+
+ }
+ active={collapseState.flowPressure}
+ onToggle={(expanded) =>
+ updateCollapseState('flowPressure', expanded)
+ }
+ collapseKey='flowPressure'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='325px'
+ visibleProperties={toVisibleProperties(
+ FILAMENT_PROFILE_FLOW_PRESSURE_PROPERTIES
+ )}
+ />
+
+ }
+ active={collapseState.temperature}
+ onToggle={(expanded) =>
+ updateCollapseState('temperature', expanded)
+ }
+ collapseKey='temperature'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='280px'
+ visibleProperties={toVisibleProperties(
+ FILAMENT_PROFILE_TEMPERATURE_PROPERTIES
+ )}
+ />
+
+ }
+ active={collapseState.bedTemperature}
+ onToggle={(expanded) =>
+ updateCollapseState('bedTemperature', expanded)
+ }
+ collapseKey='bedTemperature'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='280px'
+ visibleProperties={toVisibleProperties(
+ FILAMENT_PROFILE_BED_TEMPERATURE_PROPERTIES
+ )}
+ />
+
+ }
+ active={collapseState.speed}
+ onToggle={(expanded) =>
+ updateCollapseState('speed', expanded)
+ }
+ collapseKey='speed'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='265px'
+ visibleProperties={toVisibleProperties(
+ FILAMENT_PROFILE_SPEED_PROPERTIES
+ )}
+ />
+
+ }
+ active={collapseState.cooling}
+ onToggle={(expanded) =>
+ updateCollapseState('cooling', expanded)
+ }
+ collapseKey='cooling'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='350px'
+ visibleProperties={toVisibleProperties(
+ FILAMENT_PROFILE_COOLING_PROPERTIES
+ )}
+ />
+
+ }
+ active={collapseState.exhaustFan}
+ onToggle={(expanded) =>
+ updateCollapseState('exhaustFan', expanded)
+ }
+ collapseKey='exhaustFan'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='285px'
+ visibleProperties={toVisibleProperties(
+ FILAMENT_PROFILE_EXHAUST_FAN_PROPERTIES
+ )}
+ />
+
+ }
+ active={collapseState.retraction}
+ onToggle={(expanded) =>
+ updateCollapseState('retraction', expanded)
+ }
+ collapseKey='retraction'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='250px'
+ visibleProperties={toVisibleProperties(
+ FILAMENT_PROFILE_RETRACTION_PROPERTIES
+ )}
+ />
+
+ }
+ active={collapseState.loading}
+ onToggle={(expanded) =>
+ updateCollapseState('loading', expanded)
+ }
+ collapseKey='loading'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='220px'
+ visibleProperties={toVisibleProperties(
+ FILAMENT_PROFILE_LOADING_PROPERTIES
+ )}
+ />
+
+ }
+ active={collapseState.wipeTower}
+ onToggle={(expanded) =>
+ updateCollapseState('wipeTower', expanded)
+ }
+ collapseKey='wipeTower'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='330px'
+ visibleProperties={toVisibleProperties(
+ FILAMENT_PROFILE_WIPE_TOWER_PROPERTIES
+ )}
+ />
+
+ }
+ active={collapseState.gCodeSettings}
+ onToggle={(expanded) =>
+ updateCollapseState('gCodeSettings', expanded)
+ }
+ collapseKey='gCodeSettings'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='270px'
+ visibleProperties={toVisibleProperties(
+ FILAMENT_PROFILE_GCODE_PROPERTIES
+ )}
+ />
+
+ }
+ active={collapseState.compatibility}
+ onToggle={(expanded) =>
+ updateCollapseState('compatibility', expanded)
+ }
+ collapseKey='compatibility'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='270px'
+ visibleProperties={toVisibleProperties(
+ FILAMENT_PROFILE_COMPATIBILITY_PROPERTIES
+ )}
+ />
+
+ }
+ active={collapseState.shrinkageDrying}
+ onToggle={(expanded) =>
+ updateCollapseState('shrinkageDrying', expanded)
+ }
+ collapseKey='shrinkageDrying'
+ >
+ }
+ isEditing={isEditing}
+ type='filamentProfile'
+ objectData={objectData}
+ labelWidth='340px'
+ visibleProperties={{
+ ...toVisibleProperties(
+ FILAMENT_PROFILE_SHRINKAGE_DRYING_PROPERTIES
+ ),
+ filamentNotes: true
+ }}
+ />
+
+
+ )}
+
+
+
+ }
+ active={collapseState.notes}
+ onToggle={(expanded) => updateCollapseState('notes', expanded)}
+ collapseKey='notes'
+ >
+
+
+
+
+
+ }
+ active={collapseState.auditLogs}
+ onToggle={(expanded) => updateCollapseState('auditLogs', expanded)}
+ collapseKey='auditLogs'
+ >
+ {objectFormState.loading ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ )
+}
+
+export default FilamentProfileInfo
diff --git a/src/components/Dashboard/Production/FilamentProfiles/NewFilamentProfile.jsx b/src/components/Dashboard/Production/FilamentProfiles/NewFilamentProfile.jsx
new file mode 100644
index 0000000..67419ca
--- /dev/null
+++ b/src/components/Dashboard/Production/FilamentProfiles/NewFilamentProfile.jsx
@@ -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: (
+
+ )
+ },
+ {
+ title: 'Material',
+ key: 'material',
+ content: (
+
+ )
+ },
+ {
+ title: 'Flow & Pressure',
+ key: 'flowPressure',
+ content: (
+
+ )
+ },
+ {
+ title: 'Temperature',
+ key: 'temperature',
+ content: (
+
+ )
+ },
+ {
+ title: 'Speed',
+ key: 'speed',
+ content: (
+
+ )
+ },
+ {
+ title: 'Cooling',
+ key: 'cooling',
+ content: (
+
+ )
+ },
+ {
+ title: 'Exhaust Fan',
+ key: 'exhaustFan',
+ content: (
+
+ )
+ },
+ {
+ title: 'Compatibility',
+ key: 'compatibility',
+ content: (
+
+ )
+ },
+ {
+ title: 'Summary',
+ key: 'summary',
+ content: (
+
+ )
+ }
+ ],
+ [objectData, visibleProperties]
+ )
+
+ return (
+
+ )
+}
+
+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 }) => (
+
+ {({ handleSubmit, submitLoading, objectData, formValid }) => (
+ {
+ const result = await handleSubmit()
+ if (result?._id) onOk(result)
+ }}
+ />
+ )}
+
+)
+
+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 (
+ {
+ 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 }) => (
+ {
+ saveRequestedRef.current = true
+ handleUpdate()
+ }}
+ />
+ )}
+
+ )
+}
+
+EditFilamentProfile.propTypes = {
+ profileId: PropTypes.string.isRequired,
+ onOk: PropTypes.func.isRequired,
+ filamentId: PropTypes.string
+}
+
+export default NewFilamentProfile
diff --git a/src/components/Dashboard/Production/PrinterProfiles.jsx b/src/components/Dashboard/Production/PrinterProfiles.jsx
new file mode 100644
index 0000000..260c0ea
--- /dev/null
+++ b/src/components/Dashboard/Production/PrinterProfiles.jsx
@@ -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:
+ },
+ { type: 'divider' },
+ {
+ label: 'Reload List',
+ key: 'reloadList',
+ icon:
+ }
+ ],
+ 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 (
+ <>
+
+
+
+
+
+
+
+
+
+
+ setShowFilterSidebar(!showFilterSidebar)}
+ />
+
+
+
+
+
+
+
+ setProfileModal({ open: false, profileId: null })}
+ destroyOnHidden
+ >
+ {profileModal.open &&
+ (profileModal.profileId ? (
+ {
+ setProfileModal({ open: false, profileId: null })
+ tableRef.current?.reload()
+ }}
+ />
+ ) : (
+ {
+ setProfileModal({ open: false, profileId: null })
+ tableRef.current?.reload()
+ }}
+ />
+ ))}
+
+ >
+ )
+}
+
+export default PrinterProfiles
diff --git a/src/components/Dashboard/Production/PrinterProfiles/NewPrinterProfile.jsx b/src/components/Dashboard/Production/PrinterProfiles/NewPrinterProfile.jsx
new file mode 100644
index 0000000..9960a13
--- /dev/null
+++ b/src/components/Dashboard/Production/PrinterProfiles/NewPrinterProfile.jsx
@@ -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: (
+
+ )
+ },
+ {
+ title: 'Dimensions',
+ key: 'dimensions',
+ content: (
+
+ )
+ },
+ {
+ title: 'Extruders',
+ key: 'extruders',
+ content: (
+
+ )
+ },
+ {
+ title: 'Motion',
+ key: 'motion',
+ content: (
+
+ )
+ },
+ {
+ title: 'Optional',
+ key: 'optional',
+ content: (
+
+ )
+ },
+ {
+ title: 'Summary',
+ key: 'summary',
+ content: (
+
+ )
+ }
+ ],
+ [objectData, visibleProperties]
+ )
+
+ return (
+
+ )
+}
+
+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 }) => (
+
+ {({ handleSubmit, submitLoading, objectData, formValid }) => (
+ {
+ const result = await handleSubmit()
+ if (result?._id) onOk(result)
+ }}
+ />
+ )}
+
+)
+
+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 (
+ {
+ 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 }) => (
+ {
+ saveRequestedRef.current = true
+ handleUpdate()
+ }}
+ />
+ )}
+
+ )
+}
+
+EditPrinterProfile.propTypes = {
+ profileId: PropTypes.string.isRequired,
+ onOk: PropTypes.func.isRequired,
+ printerId: PropTypes.string
+}
+
+export default NewPrinterProfile
diff --git a/src/components/Dashboard/Production/PrinterProfiles/PrinterProfileInfo.jsx b/src/components/Dashboard/Production/PrinterProfiles/PrinterProfileInfo.jsx
new file mode 100644
index 0000000..c5b282d
--- /dev/null
+++ b/src/components/Dashboard/Production/PrinterProfiles/PrinterProfileInfo.jsx
@@ -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 (
+
+
+
+
+
+
+
+
+
+
+
+ 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}
+ />
+
+
+
+
+
+
+ setObjectFormState((current) => ({ ...current, ...state }))
+ }
+ >
+ {({ loading, isEditing, objectData }) => (
+
+ }
+ active={collapseState.info}
+ onToggle={(expanded) =>
+ updateCollapseState('info', expanded)
+ }
+ collapseKey='info'
+ >
+ }
+ isEditing={isEditing}
+ type='printerProfile'
+ objectData={objectData}
+ labelWidth='140px'
+ visibleProperties={{
+ _id: true,
+ name: true,
+ _reference: true,
+ printer: true,
+ createdAt: true,
+ updatedAt: true
+ }}
+ />
+
+ }
+ active={collapseState.dimensions}
+ onToggle={(expanded) =>
+ updateCollapseState('dimensions', expanded)
+ }
+ collapseKey='dimensions'
+ >
+ }
+ 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
+ }}
+ />
+
+ }
+ active={collapseState.bedExcludeArea}
+ onToggle={(expanded) =>
+ updateCollapseState('bedExcludeArea', expanded)
+ }
+ collapseKey='bedExcludeArea'
+ >
+
+
+ }
+ active={collapseState.extruders}
+ onToggle={(expanded) =>
+ updateCollapseState('extruders', expanded)
+ }
+ collapseKey='extruders'
+ >
+
+
+ }
+ active={collapseState.motion}
+ onToggle={(expanded) =>
+ updateCollapseState('motion', expanded)
+ }
+ collapseKey='motion'
+ >
+ }
+ isEditing={isEditing}
+ type='printerProfile'
+ objectData={objectData}
+ labelWidth='225px'
+ visibleProperties={{
+ machineMaxAccelerationRetracting: true,
+ machineMaxSpeedE: true,
+ machineMaxSpeedX: true,
+ machineMaxSpeedY: true,
+ machineMaxJunctionDeviation: true
+ }}
+ />
+
+ }
+ active={collapseState.gCodeSettings}
+ onToggle={(expanded) =>
+ updateCollapseState('gCodeSettings', expanded)
+ }
+ collapseKey='gCodeSettings'
+ >
+ }
+ isEditing={isEditing}
+ type='printerProfile'
+ objectData={objectData}
+ labelWidth='240px'
+ visibleProperties={{
+ machinePauseGcode: true,
+ machineStartGcode: true,
+ machineEndGcode: true,
+ layerChangeGcode: true,
+ beforeLayerChangeGcode: true
+ }}
+ />
+
+ }
+ active={collapseState.miscellaneous}
+ onToggle={(expanded) =>
+ updateCollapseState('miscellaneous', expanded)
+ }
+ collapseKey='miscellaneous'
+ >
+ }
+ isEditing={isEditing}
+ type='printerProfile'
+ objectData={objectData}
+ labelWidth='210px'
+ visibleProperties={{
+ printerNotes: true,
+ scanFirstLayer: true,
+ machineLoadFilamentTime: true,
+ machineUnloadFilamentTime: true,
+ auxiliaryFan: true
+ }}
+ />
+
+ }
+ active={collapseState.thumbnails}
+ onToggle={(expanded) =>
+ updateCollapseState('thumbnails', expanded)
+ }
+ collapseKey='thumbnails'
+ >
+
+
+
+ )}
+
+
+
+ }
+ active={collapseState.notes}
+ onToggle={(expanded) => updateCollapseState('notes', expanded)}
+ collapseKey='notes'
+ >
+
+
+
+
+
+ }
+ active={collapseState.auditLogs}
+ onToggle={(expanded) => updateCollapseState('auditLogs', expanded)}
+ collapseKey='auditLogs'
+ >
+ {objectFormState.loading ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ )
+}
+
+export default PrinterProfileInfo
diff --git a/src/database/models/FilamentProfile.js b/src/database/models/FilamentProfile.js
new file mode 100644
index 0000000..97af3f9
--- /dev/null
+++ b/src/database/models/FilamentProfile.js
@@ -0,0 +1,1464 @@
+import FilamentProfileIcon from '../../components/Icons/FilamentProfileIcon'
+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'
+
+export const FilamentProfile = {
+ name: 'filamentProfile',
+ label: 'Filament Profile',
+ labelPlural: 'Filament Profiles',
+ url: '/dashboard/production/filamentprofiles',
+ prefix: 'FPF',
+ icon: FilamentProfileIcon,
+ actions: [
+ {
+ name: 'info',
+ label: 'Info',
+ default: true,
+ row: true,
+ icon: InfoCircleIcon,
+ url: (_id) =>
+ `/dashboard/production/filamentprofiles/info?filamentProfileId=${_id}`
+ },
+ {
+ name: 'edit',
+ label: 'Edit',
+ row: true,
+ icon: EditIcon,
+ url: (_id) =>
+ `/dashboard/production/filamentprofiles/info?filamentProfileId=${_id}&action=edit`,
+ visible: (objectData) => !objectData?._isEditing
+ },
+ {
+ name: 'finishEdit',
+ label: 'Save Edits',
+ icon: CheckIcon,
+ url: (_id) =>
+ `/dashboard/production/filamentprofiles/info?filamentProfileId=${_id}&action=finishEdit`,
+ visible: (objectData) => objectData?._isEditing === true
+ },
+ {
+ name: 'cancelEdit',
+ label: 'Cancel Edits',
+ icon: XMarkIcon,
+ url: (_id) =>
+ `/dashboard/production/filamentprofiles/info?filamentProfileId=${_id}&action=cancelEdit`,
+ visible: (objectData) => objectData?._isEditing === true
+ },
+ { type: 'divider' },
+ {
+ name: 'delete',
+ label: 'Delete',
+ row: true,
+ icon: BinIcon,
+ danger: true,
+ url: (_id) =>
+ `/dashboard/production/filamentprofiles/info?filamentProfileId=${_id}&action=delete`
+ }
+ ],
+ columns: ['_reference', 'name', 'filamentType', 'filament', 'updatedAt'],
+ filters: ['_id', 'name', 'filamentType', 'filament'],
+ sorters: ['name', 'createdAt', 'updatedAt'],
+ properties: [
+ {
+ name: '_id',
+ label: 'ID',
+ type: 'id',
+ objectType: 'filamentProfile',
+ showCopy: true,
+ readOnly: true,
+ columnWidth: 140
+ },
+ {
+ name: 'createdAt',
+ label: 'Created At',
+ type: 'dateTime',
+ readOnly: true,
+ columnWidth: 175
+ },
+ {
+ name: '_reference',
+ label: 'Reference',
+ type: 'reference',
+ objectType: 'filamentProfile',
+ 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 &&
+ objectData?.filamentType == 'filament' &&
+ objectData?.filament != undefined
+ ) {
+ return objectData?.filament?.name
+ }
+ if (
+ objectData?.name == undefined &&
+ objectData?.filamentType == 'filamentSku' &&
+ objectData?.filament?.filament != undefined
+ ) {
+ return (
+ objectData?.filament?.filament?.name +
+ ' - ' +
+ objectData?.filament?.name
+ )
+ }
+ return objectData?.name
+ }
+ },
+ {
+ name: 'filamentType',
+ label: 'Filament Type',
+ type: 'objectType',
+ masterFilter: ['filament', 'filamentSku'],
+ required: true,
+ columnWidth: 150
+ },
+ {
+ name: 'filament',
+ label: 'Filament',
+ type: 'object',
+ objectType: (objectData) => objectData?.filamentType,
+ required: true,
+ showHyperlink: true,
+ columnWidth: 220
+ },
+ {
+ name: 'filamentIsSupport',
+ label: 'Is Support Material',
+ type: 'bool',
+ columnWidth: 170
+ },
+ {
+ name: 'filamentSoluble',
+ label: 'Soluble',
+ type: 'bool',
+ columnWidth: 110
+ },
+ {
+ name: 'filamentPrintable',
+ label: 'Printable',
+ type: 'number',
+ min: 0,
+ step: 1,
+ columnWidth: 120
+ },
+ {
+ name: 'filamentAdhesivenessCategory',
+ label: 'Adhesiveness Category',
+ type: 'number',
+ min: 0,
+ step: 1,
+ columnWidth: 190
+ },
+ {
+ name: 'temperatureVitrification',
+ label: 'Temperature Vitrification',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 200
+ },
+ {
+ name: 'idleTemperature',
+ label: 'Idle Temperature',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 160
+ },
+ {
+ name: 'pelletFlowCoefficient',
+ label: 'Pellet Flow Coefficient',
+ type: 'number',
+ min: 0,
+ step: 0.0001,
+ columnWidth: 190
+ },
+ {
+ name: 'requiredNozzleHrc',
+ label: 'Required Nozzle HRC',
+ type: 'number',
+ min: 0,
+ step: 1,
+ columnWidth: 180
+ },
+ {
+ name: 'filamentFlowRatio',
+ label: 'Flow Ratio',
+ type: 'number',
+ min: 0,
+ step: 0.01,
+ columnWidth: 130
+ },
+ {
+ name: 'enablePressureAdvance',
+ label: 'Enable Pressure Advance',
+ type: 'bool',
+ columnWidth: 200
+ },
+ {
+ name: 'pressureAdvance',
+ label: 'Pressure Advance',
+ type: 'number',
+ min: 0,
+ step: 0.001,
+ columnWidth: 160,
+ visible: (objectData) => objectData?.enablePressureAdvance
+ },
+ {
+ name: 'adaptivePressureAdvance',
+ label: 'Enable Adaptive Pressure Advance (beta)',
+ type: 'bool',
+ columnWidth: 290,
+ visible: (objectData) => objectData?.enablePressureAdvance
+ },
+ {
+ name: 'adaptivePressureAdvanceBridges',
+ label: 'Adaptive Pressure Advance Bridges',
+ type: 'bool',
+ columnWidth: 260,
+ visible: (objectData) => objectData?.adaptivePressureAdvance
+ },
+ {
+ name: 'adaptivePressureAdvanceOverhangs',
+ label: 'Adaptive Pressure Advance Overhangs',
+ type: 'bool',
+ columnWidth: 280,
+ visible: (objectData) => objectData?.adaptivePressureAdvance
+ },
+ {
+ name: 'adaptivePressureAdvanceModel',
+ label: 'Adaptive Pressure Advance Model',
+ type: 'text',
+ span: 2,
+ columnWidth: 260,
+ visible: (objectData) => objectData?.adaptivePressureAdvance
+ },
+ {
+ name: 'activateChamberTempControl',
+ label: 'Activate Temperature Control',
+ type: 'bool',
+ columnWidth: 220
+ },
+ {
+ name: 'chamberTemperature',
+ label: 'Chamber Temperature Target',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 220,
+ visible: (objectData) => objectData?.activateChamberTempControl
+ },
+ {
+ name: 'chamberMinimalTemperature',
+ label: 'Chamber Temperature Minimal',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 230,
+ visible: (objectData) => objectData?.activateChamberTempControl
+ },
+ {
+ name: 'nozzleTemperatureInitialLayer',
+ label: 'Nozzle Temperature First Layer',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 240,
+ visible: (objectData) => objectData?.activateChamberTempControl
+ },
+ {
+ name: 'nozzleTemperature',
+ label: 'Nozzle Temperature Other Layers',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 250
+ },
+ {
+ name: 'nozzleTemperatureRangeLow',
+ label: 'Nozzle Temperature Range Low',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 240
+ },
+ {
+ name: 'nozzleTemperatureRangeHigh',
+ label: 'Nozzle Temperature Range High',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 250
+ },
+ {
+ name: 'hotPlateTempInitialLayer',
+ label: 'Hot Plate First Layer',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 180
+ },
+ {
+ name: 'hotPlateTemp',
+ label: 'Hot Plate Other Layers',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 190
+ },
+ {
+ name: 'coolPlateTempInitialLayer',
+ label: 'Cool Plate First Layer',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 180
+ },
+ {
+ name: 'coolPlateTemp',
+ label: 'Cool Plate Other Layers',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 190
+ },
+ {
+ name: 'engPlateTempInitialLayer',
+ label: 'Engineering Plate First Layer',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 220
+ },
+ {
+ name: 'engPlateTemp',
+ label: 'Engineering Plate Other Layers',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 230
+ },
+ {
+ name: 'texturedPlateTempInitialLayer',
+ label: 'Textured Plate First Layer',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 200
+ },
+ {
+ name: 'texturedPlateTemp',
+ label: 'Textured Plate Other Layers',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 210
+ },
+ {
+ name: 'texturedCoolPlateTempInitialLayer',
+ label: 'Textured Cool Plate First Layer',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 240
+ },
+ {
+ name: 'texturedCoolPlateTemp',
+ label: 'Textured Cool Plate Other Layers',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 250
+ },
+ {
+ name: 'supertackPlateTempInitialLayer',
+ label: 'Supertack Plate First Layer',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 210
+ },
+ {
+ name: 'supertackPlateTemp',
+ label: 'Supertack Plate Other Layers',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 220
+ },
+ {
+ name: 'filamentAdaptiveVolumetricSpeed',
+ label: 'Adaptive Volumetric Speed',
+ type: 'bool',
+ columnWidth: 220
+ },
+ {
+ name: 'filamentMaxVolumetricSpeed',
+ label: 'Max Volumetric Speed',
+ type: 'number',
+ suffix: ' mm³/s',
+ min: 0,
+ step: 0.1,
+ columnWidth: 200
+ },
+ {
+ name: 'volumetricSpeedCoefficients',
+ label: 'Volumetric Speed Coefficients',
+ type: 'text',
+ span: 2,
+ columnWidth: 240,
+ visible: (objectData) => objectData?.filamentAdaptiveVolumetricSpeed
+ },
+ {
+ name: 'closeFanTheFirstXLayers',
+ label: 'No Cooling for the First Layers',
+ type: 'number',
+ min: 0,
+ step: 1,
+ columnWidth: 250
+ },
+ {
+ name: 'fullFanSpeedLayer',
+ label: 'Full Fan Speed at Layer',
+ type: 'number',
+ min: 0,
+ step: 1,
+ columnWidth: 200
+ },
+ {
+ name: 'fanMinSpeed',
+ label: 'Min Fan Speed Threshold',
+ type: 'number',
+ suffix: ' %',
+ min: 0,
+ max: 100,
+ step: 1,
+ columnWidth: 200
+ },
+ {
+ name: 'fanMaxSpeed',
+ label: 'Max Fan Speed Threshold',
+ type: 'number',
+ suffix: ' %',
+ min: 0,
+ max: 100,
+ step: 1,
+ columnWidth: 200
+ },
+ {
+ name: 'reduceFanStopStartFreq',
+ label: 'Keep Fan Always On',
+ type: 'bool',
+ columnWidth: 180
+ },
+ {
+ name: 'slowDownForLayerCooling',
+ label: 'Slow Printing Down for Better Layer Cooling',
+ type: 'bool',
+ columnWidth: 320
+ },
+ {
+ name: 'dontSlowDownOuterWall',
+ label: "Don't Slow Down Outer Walls",
+ type: 'bool',
+ columnWidth: 220,
+ visible: (objectData) => objectData?.slowDownForLayerCooling
+ },
+ {
+ name: 'slowDownMinSpeed',
+ label: 'Min Print Speed',
+ type: 'number',
+ suffix: ' mm/s',
+ min: 0,
+ step: 1,
+ columnWidth: 150,
+ visible: (objectData) => objectData?.slowDownForLayerCooling
+ },
+ {
+ name: 'slowDownLayerTime',
+ label: 'Slow Down Layer Time',
+ type: 'number',
+ suffix: ' s',
+ min: 0,
+ step: 0.1,
+ columnWidth: 190,
+ visible: (objectData) => objectData?.slowDownForLayerCooling
+ },
+ {
+ name: 'fanCoolingLayerTime',
+ label: 'Fan Cooling Layer Time',
+ type: 'number',
+ suffix: ' s',
+ min: 0,
+ step: 0.1,
+ columnWidth: 200,
+ visible: (objectData) => objectData?.slowDownForLayerCooling
+ },
+ {
+ name: 'enableOverhangBridgeFan',
+ label: 'Force Cooling for Overhangs and Bridges',
+ type: 'bool',
+ columnWidth: 300
+ },
+ {
+ name: 'overhangFanThreshold',
+ label: 'Overhang Cooling Activation Threshold',
+ type: 'text',
+ columnWidth: 280,
+ visible: (objectData) => objectData?.enableOverhangBridgeFan
+ },
+ {
+ name: 'overhangFanSpeed',
+ label: 'Overhangs and External Bridges Fan Speed',
+ type: 'number',
+ suffix: ' %',
+ min: 0,
+ max: 100,
+ step: 1,
+ columnWidth: 310,
+ visible: (objectData) => objectData?.enableOverhangBridgeFan
+ },
+ {
+ name: 'internalBridgeFanSpeed',
+ label: 'Internal Bridges Fan Speed',
+ type: 'number',
+ suffix: ' %',
+ min: -1,
+ max: 100,
+ step: 1,
+ columnWidth: 220,
+ visible: (objectData) => objectData?.enableOverhangBridgeFan
+ },
+ {
+ name: 'supportMaterialInterfaceFanSpeed',
+ label: 'Support Interface Fan Speed',
+ type: 'number',
+ suffix: ' %',
+ min: -1,
+ max: 100,
+ step: 1,
+ columnWidth: 230
+ },
+ {
+ name: 'ironingFanSpeed',
+ label: 'Ironing Fan Speed',
+ type: 'number',
+ suffix: ' %',
+ min: -1,
+ max: 100,
+ step: 1,
+ columnWidth: 180
+ },
+ {
+ name: 'initialLayerFanSpeed',
+ label: 'Initial Layer Fan Speed',
+ type: 'number',
+ suffix: ' %',
+ min: -1,
+ max: 100,
+ step: 1,
+ columnWidth: 200
+ },
+ {
+ name: 'firstXLayerFanSpeed',
+ label: 'First X Layer Fan Speed',
+ type: 'number',
+ suffix: ' %',
+ min: 0,
+ max: 100,
+ step: 1,
+ columnWidth: 200
+ },
+ {
+ name: 'additionalCoolingFanSpeed',
+ label: 'Additional Cooling Fan Speed',
+ type: 'number',
+ suffix: ' %',
+ min: 0,
+ max: 100,
+ step: 1,
+ columnWidth: 230
+ },
+ {
+ name: 'additionalFanFullSpeedLayer',
+ label: 'Additional Fan Full Speed Layer',
+ type: 'number',
+ min: 0,
+ step: 1,
+ columnWidth: 250,
+ visible: (objectData) => objectData?.additionalCoolingFanSpeed > 0
+ },
+ {
+ name: 'closeAdditionalFanFirstXLayers',
+ label: 'Close Additional Fan First X Layers',
+ type: 'bool',
+ columnWidth: 280,
+ visible: (objectData) => objectData?.additionalCoolingFanSpeed > 0
+ },
+ {
+ name: 'activateAirFiltration',
+ label: 'Activate Air Filtration',
+ type: 'bool',
+ columnWidth: 200
+ },
+ {
+ name: 'activateAirFiltrationDuringPrint',
+ label: 'During Print',
+ type: 'bool',
+ columnWidth: 140,
+ visible: (objectData) => objectData?.activateAirFiltration
+ },
+ {
+ name: 'activateAirFiltrationOnCompletion',
+ label: 'Complete Print',
+ type: 'bool',
+ columnWidth: 150,
+ visible: (objectData) => objectData?.activateAirFiltration
+ },
+ {
+ name: 'duringPrintExhaustFanSpeed',
+ label: 'During Print Exhaust Fan Speed',
+ type: 'number',
+ suffix: ' %',
+ min: 0,
+ max: 100,
+ step: 1,
+ columnWidth: 260,
+ visible: (objectData) => objectData?.activateAirFiltration
+ },
+ {
+ name: 'completePrintExhaustFanSpeed',
+ label: 'Complete Print Exhaust Fan Speed',
+ type: 'number',
+ suffix: ' %',
+ min: 0,
+ max: 100,
+ step: 1,
+ columnWidth: 270,
+ visible: (objectData) => objectData?.activateAirFiltration
+ },
+ {
+ name: 'filamentRetractionLength',
+ label: 'Retraction Length',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 170
+ },
+ {
+ name: 'filamentRetractionSpeed',
+ label: 'Retraction Speed',
+ type: 'number',
+ suffix: ' mm/s',
+ min: 0,
+ step: 1,
+ columnWidth: 170
+ },
+ {
+ name: 'filamentDeretractionSpeed',
+ label: 'Deretraction Speed',
+ type: 'number',
+ suffix: ' mm/s',
+ min: 0,
+ step: 1,
+ columnWidth: 180
+ },
+ {
+ name: 'filamentRetractionMinimumTravel',
+ label: 'Minimum Travel',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 160
+ },
+ {
+ name: 'filamentRetractWhenChangingLayer',
+ label: 'Retract When Changing Layer',
+ type: 'bool',
+ columnWidth: 220
+ },
+ {
+ name: 'filamentRetractBeforeWipe',
+ label: 'Retract Before Wipe',
+ type: 'number',
+ suffix: ' %',
+ min: 0,
+ step: 1,
+ columnWidth: 180
+ },
+ {
+ name: 'filamentRetractAfterWipe',
+ label: 'Retract After Wipe',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 170
+ },
+ {
+ name: 'filamentRetractRestartExtra',
+ label: 'Restart Extra Length',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 190
+ },
+ {
+ name: 'filamentRetractLiftAbove',
+ label: 'Lift Above',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.01,
+ columnWidth: 130
+ },
+ {
+ name: 'filamentRetractLiftBelow',
+ label: 'Lift Below',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.01,
+ columnWidth: 130
+ },
+ {
+ name: 'filamentRetractLiftEnforce',
+ label: 'Lift Enforce',
+ type: 'text',
+ columnWidth: 140
+ },
+ {
+ name: 'filamentWipe',
+ label: 'Wipe',
+ type: 'bool',
+ columnWidth: 90
+ },
+ {
+ name: 'filamentWipeDistance',
+ label: 'Wipe Distance',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 150,
+ visible: (objectData) => objectData?.filamentWipe
+ },
+ {
+ name: 'filamentZHop',
+ label: 'Z Hop',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.01,
+ columnWidth: 110
+ },
+ {
+ name: 'filamentZHopTypes',
+ label: 'Z Hop Types',
+ type: 'text',
+ columnWidth: 130
+ },
+ {
+ name: 'filamentLongRetractionsWhenCut',
+ label: 'Long Retractions When Cut',
+ type: 'bool',
+ columnWidth: 220
+ },
+ {
+ name: 'filamentRetractionDistancesWhenCut',
+ label: 'Retraction Distances When Cut',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 250,
+ visible: (objectData) => objectData?.filamentLongRetractionsWhenCut
+ },
+ {
+ name: 'longRetractionsWhenEc',
+ label: 'Long Retractions When EC',
+ type: 'bool',
+ columnWidth: 220
+ },
+ {
+ name: 'retractionDistancesWhenEc',
+ label: 'Retraction Distances When EC',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 240,
+ visible: (objectData) => objectData?.longRetractionsWhenEc
+ },
+ {
+ name: 'filamentLoadingSpeed',
+ label: 'Loading Speed',
+ type: 'number',
+ suffix: ' mm/s',
+ min: 0,
+ step: 1,
+ columnWidth: 150
+ },
+ {
+ name: 'filamentLoadingSpeedStart',
+ label: 'Loading Speed Start',
+ type: 'number',
+ suffix: ' mm/s',
+ min: 0,
+ step: 1,
+ columnWidth: 170
+ },
+ {
+ name: 'filamentUnloadingSpeed',
+ label: 'Unloading Speed',
+ type: 'number',
+ suffix: ' mm/s',
+ min: 0,
+ step: 1,
+ columnWidth: 160
+ },
+ {
+ name: 'filamentUnloadingSpeedStart',
+ label: 'Unloading Speed Start',
+ type: 'number',
+ suffix: ' mm/s',
+ min: 0,
+ step: 1,
+ columnWidth: 180
+ },
+ {
+ name: 'filamentChangeLength',
+ label: 'Change Length',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 150
+ },
+ {
+ name: 'filamentChangeLengthNc',
+ label: 'Change Length NC',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 170
+ },
+ {
+ name: 'filamentToolchangeDelay',
+ label: 'Toolchange Delay',
+ type: 'number',
+ suffix: ' s',
+ min: 0,
+ step: 0.1,
+ columnWidth: 170
+ },
+ {
+ name: 'filamentExtruderCompatibility',
+ label: 'Extruder Compatibility',
+ type: 'number',
+ min: 0,
+ step: 1,
+ columnWidth: 190
+ },
+ {
+ name: 'filamentExtruderVariant',
+ label: 'Extruder Variant',
+ type: 'text',
+ columnWidth: 170
+ },
+ {
+ name: 'filamentMultitoolRamming',
+ label: 'Multitool Ramming',
+ type: 'bool',
+ columnWidth: 170
+ },
+ {
+ name: 'filamentMultitoolRammingFlow',
+ label: 'Multitool Ramming Flow',
+ type: 'number',
+ min: 0,
+ step: 0.1,
+ columnWidth: 200,
+ visible: (objectData) => objectData?.filamentMultitoolRamming
+ },
+ {
+ name: 'filamentMultitoolRammingVolume',
+ label: 'Multitool Ramming Volume',
+ type: 'number',
+ min: 0,
+ step: 0.1,
+ columnWidth: 220,
+ visible: (objectData) => objectData?.filamentMultitoolRamming
+ },
+ {
+ name: 'filamentRammingParameters',
+ label: 'Ramming Parameters',
+ type: 'text',
+ span: 2,
+ columnWidth: 200,
+ visible: (objectData) => objectData?.filamentMultitoolRamming
+ },
+ {
+ name: 'filamentRammingTravelTime',
+ label: 'Ramming Travel Time',
+ type: 'number',
+ suffix: ' s',
+ min: 0,
+ step: 0.1,
+ columnWidth: 190,
+ visible: (objectData) => objectData?.filamentMultitoolRamming
+ },
+ {
+ name: 'filamentRammingTravelTimeNc',
+ label: 'Ramming Travel Time NC',
+ type: 'number',
+ suffix: ' s',
+ min: 0,
+ step: 0.1,
+ columnWidth: 210,
+ visible: (objectData) => objectData?.filamentMultitoolRamming
+ },
+ {
+ name: 'filamentRammingVolumetricSpeed',
+ label: 'Ramming Volumetric Speed',
+ type: 'number',
+ suffix: ' mm³/s',
+ step: 0.1,
+ columnWidth: 220,
+ visible: (objectData) => objectData?.filamentMultitoolRamming
+ },
+ {
+ name: 'filamentRammingVolumetricSpeedNc',
+ label: 'Ramming Volumetric Speed NC',
+ type: 'number',
+ suffix: ' mm³/s',
+ step: 0.1,
+ columnWidth: 250,
+ visible: (objectData) => objectData?.filamentMultitoolRamming
+ },
+ {
+ name: 'filamentMinimalPurgeOnWipeTower',
+ label: 'Minimal Purge on Wipe Tower',
+ type: 'number',
+ suffix: ' mm³',
+ min: 0,
+ step: 0.1,
+ columnWidth: 230
+ },
+ {
+ name: 'filamentTowerInterfacePreExtrusionDist',
+ label: 'Tower Interface Pre-Extrusion Distance',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 290
+ },
+ {
+ name: 'filamentTowerInterfacePreExtrusionLength',
+ label: 'Tower Interface Pre-Extrusion Length',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 280
+ },
+ {
+ name: 'filamentTowerInterfacePrintTemp',
+ label: 'Tower Interface Print Temperature',
+ type: 'number',
+ suffix: ' °C',
+ step: 1,
+ columnWidth: 270
+ },
+ {
+ name: 'filamentTowerInterfacePurgeVolume',
+ label: 'Tower Interface Purge Volume',
+ type: 'number',
+ suffix: ' mm³',
+ min: 0,
+ step: 0.1,
+ columnWidth: 250
+ },
+ {
+ name: 'filamentTowerIroningArea',
+ label: 'Tower Ironing Area',
+ type: 'number',
+ min: 0,
+ step: 0.1,
+ columnWidth: 180
+ },
+ {
+ name: 'filamentCoolingBeforeTower',
+ label: 'Cooling Before Tower',
+ type: 'number',
+ suffix: ' s',
+ min: 0,
+ step: 0.1,
+ columnWidth: 200
+ },
+ {
+ name: 'filamentCoolingInitialSpeed',
+ label: 'Cooling Initial Speed',
+ type: 'number',
+ suffix: ' mm/s',
+ min: 0,
+ step: 0.1,
+ columnWidth: 200
+ },
+ {
+ name: 'filamentCoolingFinalSpeed',
+ label: 'Cooling Final Speed',
+ type: 'number',
+ suffix: ' mm/s',
+ min: 0,
+ step: 0.1,
+ columnWidth: 190
+ },
+ {
+ name: 'filamentCoolingMoves',
+ label: 'Cooling Moves',
+ type: 'number',
+ min: 0,
+ step: 1,
+ columnWidth: 150
+ },
+ {
+ name: 'filamentFlushTemp',
+ label: 'Flush Temperature',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 170
+ },
+ {
+ name: 'filamentFlushTempFast',
+ label: 'Flush Temperature Fast',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 190
+ },
+ {
+ name: 'filamentFlushVolumetricSpeed',
+ label: 'Flush Volumetric Speed',
+ type: 'number',
+ suffix: ' mm³/s',
+ min: 0,
+ step: 0.1,
+ columnWidth: 210
+ },
+ {
+ name: 'filamentPreCoolingTemperature',
+ label: 'Pre-Cooling Temperature',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 200
+ },
+ {
+ name: 'filamentPreCoolingTemperatureNc',
+ label: 'Pre-Cooling Temperature NC',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 220
+ },
+ {
+ name: 'filamentPreheatTemperatureDelta',
+ label: 'Preheat Temperature Delta',
+ type: 'number',
+ suffix: ' °C',
+ step: 1,
+ columnWidth: 220
+ },
+ {
+ name: 'filamentPrimeVolumeNc',
+ label: 'Prime Volume NC',
+ type: 'number',
+ suffix: ' mm³',
+ min: 0,
+ step: 0.1,
+ columnWidth: 160
+ },
+ {
+ name: 'filamentRetractLengthNc',
+ label: 'Retract Length NC',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 170
+ },
+ {
+ name: 'filamentStampingDistance',
+ label: 'Stamping Distance',
+ type: 'number',
+ suffix: ' mm',
+ min: 0,
+ step: 0.1,
+ columnWidth: 170
+ },
+ {
+ name: 'filamentStampingLoadingSpeed',
+ label: 'Stamping Loading Speed',
+ type: 'number',
+ suffix: ' mm/s',
+ min: 0,
+ step: 1,
+ columnWidth: 210
+ },
+ {
+ name: 'filamentStartGcode',
+ label: 'Start G-code',
+ type: 'codeBlock',
+ language: 'gcode',
+ height: '200px',
+ span: 2
+ },
+ {
+ name: 'filamentEndGcode',
+ label: 'End G-code',
+ type: 'codeBlock',
+ language: 'gcode',
+ height: '160px',
+ span: 2
+ },
+ {
+ name: 'filamentChangeExtrusionRoleGcode',
+ label: 'Change Extrusion Role G-code',
+ type: 'codeBlock',
+ language: 'gcode',
+ height: '160px',
+ span: 2
+ },
+ {
+ name: 'compatiblePrinters',
+ label: 'Compatible Printer Profiles',
+ type: 'objectList',
+ objectType: 'printerProfile',
+ span: 2,
+ columnWidth: 220
+ },
+ {
+ name: 'compatiblePrintersCondition',
+ label: 'Compatible Printers Condition',
+ type: 'text',
+ span: 2,
+ columnWidth: 240
+ },
+ {
+ name: 'compatiblePrints',
+ label: 'Compatible Prints',
+ type: 'stringList',
+ span: 2,
+ columnWidth: 200
+ },
+ {
+ name: 'compatiblePrintsCondition',
+ label: 'Compatible Prints Condition',
+ type: 'text',
+ span: 2,
+ columnWidth: 230
+ },
+ {
+ name: 'filamentShrink',
+ label: 'Shrinkage XY',
+ type: 'text',
+ columnWidth: 140
+ },
+ {
+ name: 'filamentShrinkageCompensationZ',
+ label: 'Shrinkage Compensation Z',
+ type: 'text',
+ columnWidth: 220
+ },
+ {
+ name: 'filamentDevAmsDryingTemperature',
+ label: 'AMS Drying Temperature',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 210
+ },
+ {
+ name: 'filamentDevAmsDryingTime',
+ label: 'AMS Drying Time',
+ type: 'number',
+ suffix: ' h',
+ min: 0,
+ step: 0.1,
+ columnWidth: 170
+ },
+ {
+ name: 'filamentDevAmsDryingHeatDistortionTemperature',
+ label: 'AMS Drying Heat Distortion Temperature',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 310
+ },
+ {
+ name: 'filamentDevAmsDryingAmsLimitations',
+ label: 'AMS Drying Limitations',
+ type: 'text',
+ span: 2,
+ columnWidth: 210
+ },
+ {
+ name: 'filamentDevChamberDryingBedTemperature',
+ label: 'Chamber Drying Bed Temperature',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 260
+ },
+ {
+ name: 'filamentDevChamberDryingTime',
+ label: 'Chamber Drying Time',
+ type: 'number',
+ suffix: ' h',
+ min: 0,
+ step: 0.1,
+ columnWidth: 200
+ },
+ {
+ name: 'filamentDevDryingCoolingTemperature',
+ label: 'Drying Cooling Temperature',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 240
+ },
+ {
+ name: 'filamentDevDryingSofteningTemperature',
+ label: 'Drying Softening Temperature',
+ type: 'number',
+ suffix: ' °C',
+ min: 0,
+ step: 1,
+ columnWidth: 260
+ },
+ {
+ name: 'filamentNotes',
+ label: 'Filament Notes',
+ type: 'markdown',
+ span: 2
+ }
+ ]
+}
+
+export const FILAMENT_PROFILE_MATERIAL_PROPERTIES = [
+ 'filamentIsSupport',
+ 'filamentSoluble',
+ 'filamentPrintable',
+ 'filamentAdhesivenessCategory',
+ 'temperatureVitrification',
+ 'idleTemperature',
+ 'pelletFlowCoefficient',
+ 'requiredNozzleHrc'
+]
+export const FILAMENT_PROFILE_FLOW_PRESSURE_PROPERTIES = [
+ 'filamentFlowRatio',
+ 'enablePressureAdvance',
+ 'pressureAdvance',
+ 'adaptivePressureAdvance',
+ 'adaptivePressureAdvanceBridges',
+ 'adaptivePressureAdvanceOverhangs',
+ 'adaptivePressureAdvanceModel'
+]
+export const FILAMENT_PROFILE_TEMPERATURE_PROPERTIES = [
+ 'activateChamberTempControl',
+ 'chamberTemperature',
+ 'chamberMinimalTemperature',
+ 'nozzleTemperatureInitialLayer',
+ 'nozzleTemperature',
+ 'nozzleTemperatureRangeLow',
+ 'nozzleTemperatureRangeHigh'
+]
+export const FILAMENT_PROFILE_BED_TEMPERATURE_PROPERTIES = [
+ 'hotPlateTempInitialLayer',
+ 'hotPlateTemp',
+ 'coolPlateTempInitialLayer',
+ 'coolPlateTemp',
+ 'engPlateTempInitialLayer',
+ 'engPlateTemp',
+ 'texturedPlateTempInitialLayer',
+ 'texturedPlateTemp',
+ 'texturedCoolPlateTempInitialLayer',
+ 'texturedCoolPlateTemp',
+ 'supertackPlateTempInitialLayer',
+ 'supertackPlateTemp'
+]
+export const FILAMENT_PROFILE_SPEED_PROPERTIES = [
+ 'filamentAdaptiveVolumetricSpeed',
+ 'filamentMaxVolumetricSpeed',
+ 'volumetricSpeedCoefficients'
+]
+export const FILAMENT_PROFILE_COOLING_PROPERTIES = [
+ 'closeFanTheFirstXLayers',
+ 'fullFanSpeedLayer',
+ 'fanMinSpeed',
+ 'fanMaxSpeed',
+ 'reduceFanStopStartFreq',
+ 'slowDownForLayerCooling',
+ 'dontSlowDownOuterWall',
+ 'slowDownMinSpeed',
+ 'slowDownLayerTime',
+ 'fanCoolingLayerTime',
+ 'enableOverhangBridgeFan',
+ 'overhangFanThreshold',
+ 'overhangFanSpeed',
+ 'internalBridgeFanSpeed',
+ 'supportMaterialInterfaceFanSpeed',
+ 'ironingFanSpeed',
+ 'initialLayerFanSpeed',
+ 'firstXLayerFanSpeed',
+ 'additionalCoolingFanSpeed',
+ 'additionalFanFullSpeedLayer',
+ 'closeAdditionalFanFirstXLayers'
+]
+export const FILAMENT_PROFILE_EXHAUST_FAN_PROPERTIES = [
+ 'activateAirFiltration',
+ 'activateAirFiltrationDuringPrint',
+ 'activateAirFiltrationOnCompletion',
+ 'duringPrintExhaustFanSpeed',
+ 'completePrintExhaustFanSpeed'
+]
+export const FILAMENT_PROFILE_RETRACTION_PROPERTIES = [
+ 'filamentRetractionLength',
+ 'filamentRetractionSpeed',
+ 'filamentDeretractionSpeed',
+ 'filamentRetractionMinimumTravel',
+ 'filamentRetractWhenChangingLayer',
+ 'filamentRetractBeforeWipe',
+ 'filamentRetractAfterWipe',
+ 'filamentRetractRestartExtra',
+ 'filamentRetractLiftAbove',
+ 'filamentRetractLiftBelow',
+ 'filamentRetractLiftEnforce',
+ 'filamentWipe',
+ 'filamentWipeDistance',
+ 'filamentZHop',
+ 'filamentZHopTypes',
+ 'filamentLongRetractionsWhenCut',
+ 'filamentRetractionDistancesWhenCut',
+ 'longRetractionsWhenEc',
+ 'retractionDistancesWhenEc'
+]
+export const FILAMENT_PROFILE_LOADING_PROPERTIES = [
+ 'filamentLoadingSpeed',
+ 'filamentLoadingSpeedStart',
+ 'filamentUnloadingSpeed',
+ 'filamentUnloadingSpeedStart',
+ 'filamentChangeLength',
+ 'filamentChangeLengthNc',
+ 'filamentToolchangeDelay',
+ 'filamentExtruderCompatibility',
+ 'filamentExtruderVariant',
+ 'filamentMultitoolRamming',
+ 'filamentMultitoolRammingFlow',
+ 'filamentMultitoolRammingVolume',
+ 'filamentRammingParameters',
+ 'filamentRammingTravelTime',
+ 'filamentRammingTravelTimeNc',
+ 'filamentRammingVolumetricSpeed',
+ 'filamentRammingVolumetricSpeedNc'
+]
+export const FILAMENT_PROFILE_WIPE_TOWER_PROPERTIES = [
+ 'filamentMinimalPurgeOnWipeTower',
+ 'filamentTowerInterfacePreExtrusionDist',
+ 'filamentTowerInterfacePreExtrusionLength',
+ 'filamentTowerInterfacePrintTemp',
+ 'filamentTowerInterfacePurgeVolume',
+ 'filamentTowerIroningArea',
+ 'filamentCoolingBeforeTower',
+ 'filamentCoolingInitialSpeed',
+ 'filamentCoolingFinalSpeed',
+ 'filamentCoolingMoves',
+ 'filamentFlushTemp',
+ 'filamentFlushTempFast',
+ 'filamentFlushVolumetricSpeed',
+ 'filamentPreCoolingTemperature',
+ 'filamentPreCoolingTemperatureNc',
+ 'filamentPreheatTemperatureDelta',
+ 'filamentPrimeVolumeNc',
+ 'filamentRetractLengthNc',
+ 'filamentStampingDistance',
+ 'filamentStampingLoadingSpeed'
+]
+export const FILAMENT_PROFILE_GCODE_PROPERTIES = [
+ 'filamentStartGcode',
+ 'filamentEndGcode',
+ 'filamentChangeExtrusionRoleGcode'
+]
+export const FILAMENT_PROFILE_COMPATIBILITY_PROPERTIES = [
+ 'compatiblePrinters',
+ 'compatiblePrintersCondition',
+ 'compatiblePrints',
+ 'compatiblePrintsCondition'
+]
+export const FILAMENT_PROFILE_SHRINKAGE_DRYING_PROPERTIES = [
+ 'filamentShrink',
+ 'filamentShrinkageCompensationZ',
+ 'filamentDevAmsDryingTemperature',
+ 'filamentDevAmsDryingTime',
+ 'filamentDevAmsDryingHeatDistortionTemperature',
+ 'filamentDevAmsDryingAmsLimitations',
+ 'filamentDevChamberDryingBedTemperature',
+ 'filamentDevChamberDryingTime',
+ 'filamentDevDryingCoolingTemperature',
+ 'filamentDevDryingSofteningTemperature'
+]
diff --git a/src/database/models/PrinterProfile.js b/src/database/models/PrinterProfile.js
new file mode 100644
index 0000000..18ba492
--- /dev/null
+++ b/src/database/models/PrinterProfile.js
@@ -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
+ }
+ ]
+}