All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Removed console.log statements from FilePreview and ObjectForm components for cleaner code. - Replaced console.log with loglevel in KeyboardShortcut for better logging management. - Updated ID handling in ObjectForm, ObjectTable, PrinterMiscPanel, PrinterPositionPanel, and PrinterTemperaturePanel components to ensure IDs are consistently converted to lowercase, enhancing data integrity.
580 lines
18 KiB
JavaScript
580 lines
18 KiB
JavaScript
import { useContext, useState, useEffect } from 'react'
|
|
import {
|
|
Typography,
|
|
Spin,
|
|
Flex,
|
|
Space,
|
|
Collapse,
|
|
InputNumber,
|
|
Descriptions,
|
|
Button,
|
|
Divider
|
|
} from 'antd'
|
|
import { LoadingOutlined, CaretRightOutlined } from '@ant-design/icons'
|
|
import { ApiServerContext } from '../context/ApiServerContext'
|
|
import styled from 'styled-components'
|
|
import PropTypes from 'prop-types'
|
|
import BoolDisplay from './BoolDisplay'
|
|
import merge from 'lodash/merge'
|
|
import { round } from '../utils/Utils'
|
|
const { Text } = Typography
|
|
|
|
const CustomCollapse = styled(Collapse)`
|
|
.ant-collapse-header {
|
|
padding: 0 !important;
|
|
}
|
|
.ant-collapse-content-box {
|
|
padding-left: 0 !important;
|
|
padding-right: 0 !important;
|
|
padding-bottom: 0 !important;
|
|
}
|
|
`
|
|
|
|
const controlLabelStyle = {
|
|
whiteSpace: 'nowrap',
|
|
flexShrink: 0,
|
|
minWidth: '120px'
|
|
}
|
|
|
|
const controlInputStyle = {
|
|
flex: 1,
|
|
minWidth: 0
|
|
}
|
|
|
|
const PrinterPositionPanel = ({
|
|
id,
|
|
showControls = true,
|
|
showMoreInfo = true,
|
|
disabled = false,
|
|
offline = true
|
|
}) => {
|
|
const { subscribeToObjectEvent, connected, sendObjectAction } =
|
|
useContext(ApiServerContext)
|
|
const controlsDisabled = disabled || !connected
|
|
const [positionData, setPositionData] = useState({
|
|
speedFactor: 1.0,
|
|
speed: 100,
|
|
extrudeFactor: 1.0,
|
|
absoluteCoordinates: true,
|
|
absoluteExtrude: false,
|
|
homingOrigin: [0.0, 0.0, 0.0, 0.0],
|
|
toolheadPosition: [0.0, 0.0, 0.0, 0.0],
|
|
gcodePosition: [0.0, 0.0, 0.0, 0.0],
|
|
livePosition: [0.0, 0.0, 0.0, 0.0],
|
|
maxVelocity: 1000,
|
|
maxAcceleration: 1000,
|
|
squareCornerVelocity: 100,
|
|
minCruiseRatio: 0
|
|
})
|
|
|
|
useEffect(() => {
|
|
if (offline) {
|
|
setPositionData({
|
|
speedFactor: 1.0,
|
|
speed: 100,
|
|
extrudeFactor: 1.0,
|
|
absoluteCoordinates: true,
|
|
absoluteExtrude: false,
|
|
homingOrigin: [0.0, 0.0, 0.0, 0.0],
|
|
toolheadPosition: [0.0, 0.0, 0.0, 0.0],
|
|
gcodePosition: [0.0, 0.0, 0.0, 0.0],
|
|
livePosition: [0.0, 0.0, 0.0, 0.0],
|
|
maxVelocity: 1000,
|
|
maxAcceleration: 1000,
|
|
squareCornerVelocity: 100,
|
|
minCruiseRatio: 0
|
|
})
|
|
}
|
|
}, [offline])
|
|
|
|
useEffect(() => {
|
|
if (id && connected == true) {
|
|
const motionEventUnsubscribe = subscribeToObjectEvent(
|
|
id?.toLowerCase(),
|
|
'printer',
|
|
'motion',
|
|
(event) => {
|
|
setPositionData((prev) => {
|
|
const merged = merge({}, prev, event.data)
|
|
return merged
|
|
})
|
|
}
|
|
)
|
|
return () => {
|
|
if (motionEventUnsubscribe) motionEventUnsubscribe()
|
|
}
|
|
}
|
|
}, [id, connected, subscribeToObjectEvent])
|
|
|
|
const [speedFactor, setSpeedFactor] = useState(positionData.speedFactor)
|
|
const [extrudeFactor, setExtrudeFactor] = useState(positionData.extrudeFactor)
|
|
const [maxVelocity, setMaxVelocity] = useState(positionData.maxVelocity)
|
|
const [maxAcceleration, setMaxAcceleration] = useState(
|
|
positionData.maxAcceleration
|
|
)
|
|
const [squareCornerVelocity, setSquareCornerVelocity] = useState(
|
|
positionData.squareCornerVelocity
|
|
)
|
|
const [minCruiseRatio, setMinCruiseRatio] = useState(
|
|
positionData.minCruiseRatio
|
|
)
|
|
|
|
useEffect(() => {
|
|
if (positionData.speedFactor !== undefined) {
|
|
setSpeedFactor(positionData.speedFactor)
|
|
}
|
|
if (positionData.extrudeFactor !== undefined) {
|
|
setExtrudeFactor(positionData.extrudeFactor)
|
|
}
|
|
if (positionData.maxVelocity !== undefined) {
|
|
setMaxVelocity(positionData.maxVelocity)
|
|
}
|
|
if (positionData.maxAcceleration !== undefined) {
|
|
setMaxAcceleration(positionData.maxAcceleration)
|
|
}
|
|
if (positionData.squareCornerVelocity !== undefined) {
|
|
setSquareCornerVelocity(positionData.squareCornerVelocity)
|
|
}
|
|
if (positionData.minCruiseRatio !== undefined) {
|
|
setMinCruiseRatio(positionData.minCruiseRatio)
|
|
}
|
|
}, [
|
|
positionData.speedFactor,
|
|
positionData.extrudeFactor,
|
|
positionData.maxVelocity,
|
|
positionData.maxAcceleration,
|
|
positionData.squareCornerVelocity,
|
|
positionData.minCruiseRatio
|
|
])
|
|
|
|
const handleSetSpeedFactor = () => {
|
|
if (id && connected == true) {
|
|
sendObjectAction(id, 'printer', {
|
|
type: 'setSpeedFactor',
|
|
data: {
|
|
speedFactor: speedFactor * 100
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleSetExtrudeFactor = () => {
|
|
if (id && connected == true) {
|
|
sendObjectAction(id, 'printer', {
|
|
type: 'setExtrudeFactor',
|
|
data: {
|
|
extrudeFactor: extrudeFactor * 100
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleSetMaxVelocity = () => {
|
|
if (id && connected == true) {
|
|
sendObjectAction(id, 'printer', {
|
|
type: 'setMaxVelocity',
|
|
data: {
|
|
maxVelocity: maxVelocity
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleSetMaxAcceleration = () => {
|
|
if (id && connected == true) {
|
|
sendObjectAction(id, 'printer', {
|
|
type: 'setMaxAcceleration',
|
|
data: {
|
|
maxAcceleration: maxAcceleration
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleSetSquareCornerVelocity = () => {
|
|
if (id && connected == true) {
|
|
sendObjectAction(id, 'printer', {
|
|
type: 'setSquareCornerVelocity',
|
|
data: {
|
|
squareCornerVelocity: squareCornerVelocity
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleSetMinCruiseRatio = () => {
|
|
if (id && connected == true) {
|
|
sendObjectAction(id, 'printer', {
|
|
type: 'setMinCruiseRatio',
|
|
data: {
|
|
minCruiseRatio: minCruiseRatio
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const moreInfoItems = [
|
|
{
|
|
key: '1',
|
|
label: 'More Position Data',
|
|
children: (
|
|
<>
|
|
<Divider style={{ margin: '0 0 12px 0' }} />
|
|
<Flex vertical gap={'middle'}>
|
|
<Text>GCode Position:</Text>
|
|
<Descriptions
|
|
column={1}
|
|
size='small'
|
|
bordered
|
|
styles={{ label: { width: '40px' } }}
|
|
>
|
|
<Descriptions.Item label='X'>
|
|
{' '}
|
|
{round(positionData.gcodePosition[0], 2)}mm
|
|
</Descriptions.Item>
|
|
|
|
<Descriptions.Item label='Y'>
|
|
{round(positionData.gcodePosition[1], 2)}mm
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Z'>
|
|
{round(positionData.gcodePosition[2], 2)}mm
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='E'>
|
|
{round(positionData.gcodePosition[3], 2)}mm
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
{showControls && (
|
|
<>
|
|
<Flex vertical gap='small' style={{ width: '100%' }}>
|
|
<Flex align='center' style={{ width: '100%' }}>
|
|
<Text style={{ ...controlLabelStyle, minWidth: '91px' }}>
|
|
Max Velocity:
|
|
</Text>
|
|
<Space.Compact
|
|
block
|
|
size='small'
|
|
style={{ flex: 1, minWidth: 0 }}
|
|
>
|
|
<InputNumber
|
|
value={round(maxVelocity, 2)}
|
|
min={1}
|
|
max={10000}
|
|
step={5}
|
|
style={controlInputStyle}
|
|
suffix='mm/s'
|
|
onChange={(value) => setMaxVelocity(value)}
|
|
onPressEnter={handleSetMaxVelocity}
|
|
size='small'
|
|
disabled={controlsDisabled}
|
|
/>
|
|
<Button
|
|
type='default'
|
|
style={{ width: 40 }}
|
|
onClick={handleSetMaxVelocity}
|
|
disabled={controlsDisabled}
|
|
>
|
|
Set
|
|
</Button>
|
|
</Space.Compact>
|
|
</Flex>
|
|
|
|
<Flex align='center' style={{ width: '100%' }}>
|
|
<Text style={{ ...controlLabelStyle, minWidth: '120px' }}>
|
|
Max Acceleration:
|
|
</Text>
|
|
<Space.Compact
|
|
block
|
|
size='small'
|
|
style={{ flex: 1, minWidth: 0 }}
|
|
>
|
|
<InputNumber
|
|
value={round(maxAcceleration, 2)}
|
|
min={1}
|
|
max={10000}
|
|
step={5}
|
|
style={controlInputStyle}
|
|
suffix='mm/s²'
|
|
onChange={(value) => setMaxAcceleration(value)}
|
|
onPressEnter={handleSetMaxAcceleration}
|
|
size='small'
|
|
disabled={controlsDisabled}
|
|
/>
|
|
<Button
|
|
type='default'
|
|
style={{ width: 40 }}
|
|
onClick={handleSetMaxAcceleration}
|
|
disabled={controlsDisabled}
|
|
>
|
|
Set
|
|
</Button>
|
|
</Space.Compact>
|
|
</Flex>
|
|
|
|
<Flex align='center' style={{ width: '100%' }}>
|
|
<Text style={{ ...controlLabelStyle, minWidth: '102px' }}>
|
|
Sqr Corner Vel:
|
|
</Text>
|
|
<Space.Compact
|
|
block
|
|
size='small'
|
|
style={{ flex: 1, minWidth: 0 }}
|
|
>
|
|
<InputNumber
|
|
value={round(squareCornerVelocity, 2) || 0}
|
|
min={0.1}
|
|
max={1000}
|
|
step={0.1}
|
|
style={controlInputStyle}
|
|
suffix='mm/s'
|
|
onChange={(value) => setSquareCornerVelocity(value)}
|
|
onPressEnter={handleSetSquareCornerVelocity}
|
|
size='small'
|
|
disabled={controlsDisabled}
|
|
/>
|
|
<Button
|
|
type='default'
|
|
style={{ width: 40 }}
|
|
onClick={handleSetSquareCornerVelocity}
|
|
disabled={controlsDisabled}
|
|
>
|
|
Set
|
|
</Button>
|
|
</Space.Compact>
|
|
</Flex>
|
|
|
|
<Flex align='center' style={{ width: '100%' }}>
|
|
<Text style={{ ...controlLabelStyle, minWidth: '114px' }}>
|
|
Min Cruise Ratio:
|
|
</Text>
|
|
<Space.Compact
|
|
block
|
|
size='small'
|
|
style={{ flex: 1, minWidth: 0 }}
|
|
>
|
|
<InputNumber
|
|
value={round(minCruiseRatio * 100, 2) || 0}
|
|
min={0}
|
|
max={100}
|
|
step={1}
|
|
suffix='%'
|
|
style={controlInputStyle}
|
|
onChange={(value) => setMinCruiseRatio(value / 100)}
|
|
onPressEnter={handleSetMinCruiseRatio}
|
|
size='small'
|
|
disabled={controlsDisabled}
|
|
/>
|
|
<Button
|
|
type='default'
|
|
style={{ width: 40 }}
|
|
onClick={handleSetMinCruiseRatio}
|
|
disabled={controlsDisabled}
|
|
>
|
|
Set
|
|
</Button>
|
|
</Space.Compact>
|
|
</Flex>
|
|
</Flex>
|
|
</>
|
|
)}
|
|
<Text>Homing Origin:</Text>
|
|
<Descriptions
|
|
column={1}
|
|
size='small'
|
|
bordered
|
|
style={{ flexGrow: 1 }}
|
|
styles={{ label: { width: '40px' } }}
|
|
>
|
|
<Descriptions.Item label='X' span={1}>
|
|
{round(positionData.homingOrigin[0], 2)}mm
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Y' span={1}>
|
|
{round(positionData.homingOrigin[1], 2)}mm
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Z' span={1}>
|
|
{round(positionData.homingOrigin[2], 2)}mm
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='E'>
|
|
{round(positionData.homingOrigin[3], 2)}mm
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
</Flex>
|
|
</>
|
|
)
|
|
}
|
|
]
|
|
|
|
return (
|
|
<div style={{ minWidth: 190 }}>
|
|
{positionData ? (
|
|
<Flex vertical gap='middle'>
|
|
<Flex vertical gap={'middle'}>
|
|
<Descriptions
|
|
column={1}
|
|
size='small'
|
|
bordered
|
|
styles={{ label: { width: '40px' } }}
|
|
>
|
|
<Descriptions.Item label='X'>
|
|
<Space>
|
|
<Text>{round(positionData.livePosition[0], 2)}mm</Text>
|
|
<Text type='secondary'>
|
|
{round(positionData.toolheadPosition[0], 2)}mm
|
|
</Text>
|
|
</Space>
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Y'>
|
|
<Space>
|
|
<Text>{round(positionData.livePosition[1], 2)}mm</Text>
|
|
<Text type='secondary'>
|
|
{round(positionData.toolheadPosition[1], 2)}mm
|
|
</Text>
|
|
</Space>
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Z'>
|
|
<Space>
|
|
<Text>{round(positionData.livePosition[2], 2)}mm</Text>
|
|
<Text type='secondary'>
|
|
{round(positionData.toolheadPosition[2], 2)}mm
|
|
</Text>
|
|
</Space>
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='E'>
|
|
<Space>
|
|
<Text>{round(positionData.livePosition[3], 2)}mm</Text>
|
|
<Text type='secondary'>
|
|
{round(positionData.toolheadPosition[3], 2)}mm
|
|
</Text>
|
|
</Space>
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
{showControls && (
|
|
<>
|
|
<Flex vertical gap='small' style={{ width: '100%' }}>
|
|
<Flex align='center' style={{ width: '100%' }}>
|
|
<Text style={{ ...controlLabelStyle, minWidth: '96px' }}>
|
|
Speed Factor:
|
|
</Text>
|
|
<Space.Compact
|
|
block
|
|
size='small'
|
|
style={{ flex: 1, minWidth: 0 }}
|
|
>
|
|
<InputNumber
|
|
value={round(speedFactor, 2)}
|
|
min={0.1}
|
|
max={2}
|
|
step={0.1}
|
|
style={controlInputStyle}
|
|
suffix='%'
|
|
onChange={(value) => setSpeedFactor(value)}
|
|
onPressEnter={handleSetSpeedFactor}
|
|
size='small'
|
|
disabled={controlsDisabled}
|
|
/>
|
|
<Button
|
|
type='default'
|
|
style={{ width: 40 }}
|
|
onClick={handleSetSpeedFactor}
|
|
disabled={controlsDisabled}
|
|
>
|
|
Set
|
|
</Button>
|
|
</Space.Compact>
|
|
</Flex>
|
|
|
|
<Flex align='center' style={{ width: '100%' }}>
|
|
<Text style={{ ...controlLabelStyle, minWidth: '105px' }}>
|
|
Extrude Factor:
|
|
</Text>
|
|
<Space.Compact
|
|
block
|
|
size='small'
|
|
style={{ flex: 1, minWidth: 0 }}
|
|
>
|
|
<InputNumber
|
|
value={round(extrudeFactor, 2)}
|
|
min={0.1}
|
|
max={2}
|
|
step={0.1}
|
|
style={controlInputStyle}
|
|
suffix='%'
|
|
onChange={(value) => setExtrudeFactor(value)}
|
|
onPressEnter={handleSetExtrudeFactor}
|
|
size='small'
|
|
disabled={controlsDisabled}
|
|
/>
|
|
<Button
|
|
type='default'
|
|
style={{ width: 40 }}
|
|
onClick={handleSetExtrudeFactor}
|
|
disabled={controlsDisabled}
|
|
>
|
|
Set
|
|
</Button>
|
|
</Space.Compact>
|
|
</Flex>
|
|
</Flex>
|
|
</>
|
|
)}
|
|
<Descriptions
|
|
column={1}
|
|
size='small'
|
|
bordered
|
|
styles={{ label: { width: '125px' } }}
|
|
>
|
|
<Descriptions.Item label='Speed'>
|
|
{round(positionData.speed, 2)}mm/s
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Abs Coor'>
|
|
{positionData ? (
|
|
<BoolDisplay
|
|
value={positionData.absoluteCoordinates}
|
|
yesNo={true}
|
|
/>
|
|
) : (
|
|
<Text>n/a</Text>
|
|
)}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label='Abs Extrude'>
|
|
{positionData ? (
|
|
<BoolDisplay
|
|
value={positionData.absoluteExtrude}
|
|
yesNo={true}
|
|
/>
|
|
) : (
|
|
<Text>n/a</Text>
|
|
)}
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
</Flex>
|
|
|
|
{showMoreInfo && (
|
|
<CustomCollapse
|
|
ghost
|
|
size='small'
|
|
items={moreInfoItems}
|
|
expandIcon={({ isActive }) => (
|
|
<CaretRightOutlined rotate={isActive ? 90 : 0} />
|
|
)}
|
|
/>
|
|
)}
|
|
</Flex>
|
|
) : (
|
|
<Flex justify='centre'>
|
|
<Spin indicator={<LoadingOutlined spin />} size='large' />
|
|
</Flex>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
PrinterPositionPanel.propTypes = {
|
|
id: PropTypes.string.isRequired,
|
|
showControls: PropTypes.bool,
|
|
showMoreInfo: PropTypes.bool,
|
|
disabled: PropTypes.bool,
|
|
offline: PropTypes.bool
|
|
}
|
|
|
|
export default PrinterPositionPanel
|