Tom Butcher def9b9aefb 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.
2026-07-20 02:10:41 +01:00

421 lines
12 KiB
JavaScript

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