Compare commits

..

No commits in common. "d982b8dfb362a7311322cf9941c69ae626c77ccd" and "6ea5f2848ad7824cf5143c3bb0529845a1bbade8" have entirely different histories.

15 changed files with 277 additions and 531 deletions

View File

@ -34,7 +34,6 @@ import AuthCallback from './components/App/AuthCallback.jsx'
import EmailNotificationTemplate from './components/Email/EmailNotificationTemplate.jsx'
import MarketplaceAuthCallback from './components/Dashboard/Sales/Marketplaces/MarketplaceAuthCallback.jsx'
import AuthLaunch from './components/App/AppLaunch.jsx'
import { TableStateProvider } from './components/Dashboard/context/TableStateContext.jsx'
const SlicerIntegration = lazy(
() =>
import('./components/Dashboard/Production/Printers/SlicerIntegration.jsx')
@ -87,78 +86,76 @@ const AppContent = () => {
<NotificationProvider>
<SpotlightProvider>
<ActionsModalProvider>
<TableStateProvider>
<Routes>
<Route
path='/applaunch'
element={<AuthLaunch />}
/>
<Route
path='/dashboard/electron/spotlightcontent'
element={
<PrivateRoute
component={() => (
<ElectronSpotlightContentPage />
)}
/>
}
/>
<Route
path='/'
element={
<PrivateRoute
component={() => (
<Navigate
to='/dashboard/production/overview'
replace
/>
)}
/>
}
/>
<Route
path='/auth/callback'
element={<AuthCallback />}
/>
<Route
path='/auth/marketplace/callback'
element={<MarketplaceAuthCallback />}
/>
<Route
path='/email/notification'
element={<EmailNotificationTemplate />}
/>
<Route
path='/slicer'
element={<SlicerIntegration />}
/>
<Routes>
<Route
path='/applaunch'
element={<AuthLaunch />}
/>
<Route
path='/dashboard/electron/spotlightcontent'
element={
<PrivateRoute
component={() => (
<ElectronSpotlightContentPage />
)}
/>
}
/>
<Route
path='/'
element={
<PrivateRoute
component={() => (
<Navigate
to='/dashboard/production/overview'
replace
/>
)}
/>
}
/>
<Route
path='/auth/callback'
element={<AuthCallback />}
/>
<Route
path='/auth/marketplace/callback'
element={<MarketplaceAuthCallback />}
/>
<Route
path='/email/notification'
element={<EmailNotificationTemplate />}
/>
<Route
path='/slicer'
element={<SlicerIntegration />}
/>
<Route
path='/dashboard'
element={
<PrivateRoute
component={() => <Dashboard />}
/>
}
>
{ProductionRoutes}
{InventoryRoutes}
{FinanceRoutes}
{SalesRoutes}
{ManagementRoutes}
{DeveloperRoutes}
</Route>
<Route
path='*'
element={
<AppError
message='Error 404. Page not found.'
showRefresh={false}
/>
}
/>
</Routes>
</TableStateProvider>
<Route
path='/dashboard'
element={
<PrivateRoute
component={() => <Dashboard />}
/>
}
>
{ProductionRoutes}
{InventoryRoutes}
{FinanceRoutes}
{SalesRoutes}
{ManagementRoutes}
{DeveloperRoutes}
</Route>
<Route
path='*'
element={
<AppError
message='Error 404. Page not found.'
showRefresh={false}
/>
}
/>
</Routes>
</ActionsModalProvider>
</SpotlightProvider>
</NotificationProvider>

View File

@ -12,6 +12,7 @@ import DashboardBreadcrumb from './common/DashboardBreadcrumb'
import DeveloperSidebar from './Developer/DeveloperSidebar'
import { useThemeContext } from './context/ThemeContext'
import { MessageProvider } from './context/MessageContext'
import { TableStateProvider } from './context/TableStateContext'
const { Content } = Layout
@ -28,40 +29,42 @@ const DashboardLayout = ({ children }) => {
return (
<MessageProvider>
<Layout
style={{ height: 'var(--unit-100vh)' }}
className={isDarkMode ? 'dark-mode' : 'light-mode'}
>
<DashboardNavigation />
<Layout>
{isProduction ? (
<ProductionSidebar />
) : isInventory ? (
<InventorySidebar />
) : isFinance ? (
<FinanceSidebar />
) : isSales ? (
<SalesSidebar />
) : isManagement ? (
<ManagementSidebar />
) : isDeveloper ? (
<DeveloperSidebar />
) : (
<ProductionSidebar /> // Default to production sidebar
)}
<Layout style={{ padding: '24px' }}>
<Content>
<Flex vertical style={{ height: '100%' }} gap='20px'>
<Flex justify='space-between'>
<DashboardBreadcrumb style={{ margin: '16px 0' }} />
</Flex>
<TableStateProvider>
<Layout
style={{ height: 'var(--unit-100vh)' }}
className={isDarkMode ? 'dark-mode' : 'light-mode'}
>
<DashboardNavigation />
<Layout>
{isProduction ? (
<ProductionSidebar />
) : isInventory ? (
<InventorySidebar />
) : isFinance ? (
<FinanceSidebar />
) : isSales ? (
<SalesSidebar />
) : isManagement ? (
<ManagementSidebar />
) : isDeveloper ? (
<DeveloperSidebar />
) : (
<ProductionSidebar /> // Default to production sidebar
)}
<Layout style={{ padding: '24px' }}>
<Content>
<Flex vertical style={{ height: '100%' }} gap='20px'>
<Flex justify='space-between'>
<DashboardBreadcrumb style={{ margin: '16px 0' }} />
</Flex>
{children}
</Flex>
</Content>
{children}
</Flex>
</Content>
</Layout>
</Layout>
</Layout>
</Layout>
</TableStateProvider>
</MessageProvider>
)
}

View File

@ -33,7 +33,6 @@ import LoadFilamentStock from '../../Inventory/FilamentStocks/LoadFilamentStock.
import UnloadFilamentStock from '../../Inventory/FilamentStocks/UnloadFilamentStock.jsx'
import ScrollBox from '../../common/ScrollBox.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx'
import PrinterControlButtons from '../../common/PrinterControlButtons.jsx'
const log = loglevel.getLogger('ControlPrinter')
log.setLevel(config.logLevel)
@ -183,7 +182,6 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
>
<PrinterTemperaturePanel
id={printerId}
offline={!objectFormState.objectData?.online}
disabled={
!objectFormState.objectData?.online || objectFormState.loading
}
@ -245,7 +243,6 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
>
<PrinterMiscPanel
id={printerId}
offline={!objectFormState.objectData?.online}
disabled={
!objectFormState.objectData?.online || objectFormState.loading
}
@ -275,8 +272,7 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
visibleActions={{
edit: false,
info: !slicerIntegration,
control: !slicerIntegration,
newPrinterProfile: !slicerIntegration
control: !slicerIntegration
}}
objectData={objectFormState.objectData}
/>
@ -322,26 +318,11 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
/>
</Space>
</Space>
<Flex gap='small'>
<PrinterControlButtons
callAction={(action) =>
actionHandlerRef.current?.callAction(action)
}
objectData={objectFormState.objectData}
disabled={
!objectFormState.objectData?.online || objectFormState.loading
}
loading={objectFormState.loading}
/>
{!slicerIntegration && (
<ObjectTableNavigationButtons
showEndingDivider={true}
disabled={objectFormState.loading}
_id={printerId}
objectType='printer'
/>
)}
</Flex>
<ObjectTableNavigationButtons
disabled={objectFormState.loading}
_id={printerId}
objectType='printer'
/>
</Flex>
<AlertsDisplay

View File

@ -36,6 +36,8 @@ const FilePreview = ({ file, style = {} }) => {
}
}, [file._id, file?.type, fetchPreview, token])
console.log(file)
if (loading == true || !file?.type) {
return <LoadingPlaceholder message={'Loading file preview...'} />
}

View File

@ -1,10 +1,6 @@
import { useEffect, useRef, cloneElement, useMemo } from 'react'
import PropTypes from 'prop-types'
import { Popover, Typography } from 'antd'
import loglevel from 'loglevel'
import config from '../../../config'
const logger = loglevel.getLogger('ApiServerContext')
logger.setLevel(config.logLevel)
const MODIFIER_ALIASES = {
cmd: 'meta',
@ -63,9 +59,7 @@ const KeyboardShortcut = ({
}
if (log) {
logger.info('Key Down:', key, 'Pressed Keys:', [
...pressedKeysRef.current
])
console.log('Key Down:', key, 'Pressed Keys:', [...pressedKeysRef.current])
}
if (

View File

@ -37,95 +37,54 @@ function filterActionsByVisibility(actions, visibleActions) {
})
}
function cleanDividers(items) {
if (!Array.isArray(items) || items.length === 0) return []
const cleaned = []
for (const item of items) {
if (!item) continue
if (item.type === 'divider') {
if (cleaned.length === 0) continue
if (cleaned[cleaned.length - 1]?.type === 'divider') continue
cleaned.push(item)
continue
}
if (item.children && Array.isArray(item.children)) {
const children = cleanDividers(item.children)
if (children.length === 0) continue
cleaned.push({ ...item, children })
continue
}
cleaned.push(item)
}
if (cleaned[cleaned.length - 1]?.type === 'divider') {
cleaned.pop()
}
return cleaned
}
// Recursively map actions to AntD Dropdown items
function mapActionsToMenuItems(
actions,
currentUrlWithActions,
id,
objectData,
userProfile
) {
return cleanDividers(
actions.map((action) => {
if (action.type === 'divider') {
return { type: 'divider' }
}
const actionUrl = action.url ? action.url(id) : undefined
function mapActionsToMenuItems(actions, currentUrlWithActions, id, objectData) {
return actions.map((action) => {
if (action.type === 'divider') {
return { type: 'divider' }
}
const actionUrl = action.url ? action.url(id) : undefined
var disabled = actionUrl && actionUrl === currentUrlWithActions
var visible = true
var disabled = actionUrl && actionUrl === currentUrlWithActions
var visible = true
if (action.disabled) {
if (typeof action.disabled === 'function') {
disabled = action.disabled({ ...objectData, _user: userProfile })
} else {
disabled = action.disabled
}
}
const { userProfile } = useContext(AuthContext)
if (action.visible) {
if (typeof action.visible === 'function') {
visible = action.visible(objectData)
} else {
visible = action.visible
}
if (action.disabled) {
if (typeof action.disabled === 'function') {
disabled = action.disabled({ ...objectData, _user: userProfile })
} else {
disabled = action.disabled
}
}
if (visible != true) {
return null
if (action.visible) {
if (typeof action.visible === 'function') {
visible = action.visible(objectData)
} else {
visible = action.visible
}
}
const item = {
key: action.key || action.name,
label: action.label,
danger: action?.danger || false,
icon: action.icon ? createElement(action.icon) : undefined,
disabled
}
if (action.children && Array.isArray(action.children)) {
item.children = mapActionsToMenuItems(
action.children,
currentUrlWithActions,
id,
objectData,
userProfile
)
}
const item = {
key: action.key || action.name,
label: action.label,
danger: action?.danger || false,
icon: action.icon ? createElement(action.icon) : undefined,
disabled
}
if (action.children && Array.isArray(action.children)) {
item.children = mapActionsToMenuItems(
action.children,
currentUrlWithActions,
id,
objectData
)
}
if (visible == true) {
return item
})
)
}
})
}
const stripActionParam = (pathname, search) => {
@ -149,7 +108,6 @@ const ObjectActions = ({
const navigate = useNavigate()
const location = useLocation()
const { showActionsModal } = useActionsModal()
const { userProfile } = useContext(AuthContext)
// Get current url without 'action' param
const currentUrlWithoutActions = stripActionParam(
location.pathname,
@ -162,13 +120,10 @@ const ObjectActions = ({
visibleActions
)
const filteredActions = cleanDividers(
visibilityFilteredActions.filter(
(action) =>
action.type === 'divider' ||
typeof action.url !== 'function' ||
action.url(id) !== currentUrlWithoutActions
)
const filteredActions = visibilityFilteredActions.filter(
(action) =>
typeof action.url !== 'function' ||
action.url(id) !== currentUrlWithoutActions
)
const currentUrlWithActions = location.pathname + location.search
@ -179,8 +134,7 @@ const ObjectActions = ({
filteredActions,
currentUrlWithActions,
id,
objectData,
userProfile
objectData
),
onClick: (info) => {
// Find the action by key

View File

@ -127,6 +127,8 @@ const ObjectForm = forwardRef(
searchParams.delete(actionParam)
const newSearch = searchParams.toString()
console.log('newSearch', newSearch)
console.log('location.pathname', location.pathname)
const newPath = location.pathname + (newSearch ? `?${newSearch}` : '')
navigate(newPath, { replace: true })
},
@ -535,7 +537,7 @@ const ObjectForm = forwardRef(
}
const activityUnsubscribe = subscribeToObjectActivity(
id?.toLowerCase(),
id,
type,
activityHandler
)
@ -563,7 +565,7 @@ const ObjectForm = forwardRef(
}
const objectUpdatesUnsubscribe = subscribeToObjectUpdates(
id?.toLowerCase(),
id,
type,
objectUpdateHandler
)

View File

@ -693,7 +693,7 @@ const ObjectTable = forwardRef(
// Subscribe to new items only
newItemIds.forEach((itemId) => {
const unsubscribe = subscribeToObjectUpdates(
itemId?.toLowerCase(),
itemId,
type,
(updateData) => {
updateEventHandlerRef.current(itemId, updateData)

View File

@ -1,89 +0,0 @@
import { createElement, useContext } from 'react'
import { Button, Space } from 'antd'
import PropTypes from 'prop-types'
import { getModelByName } from '../../../database/ObjectModels'
import { AuthContext } from '../context/AuthContext'
import PlayCircleIcon from '../../Icons/PlayCircleIcon'
import PauseCircleIcon from '../../Icons/PauseCircleIcon'
import StopCircleIcon from '../../Icons/StopCircleIcon'
const findAction = (actions, name) => {
for (const action of actions) {
if (action.name === name) return action
if (action.children) {
const found = findAction(action.children, name)
if (found) return found
}
}
return null
}
const isActionDisabled = (action, objectData, userProfile, disabled) => {
if (disabled) return true
if (!action?.disabled) return false
if (typeof action.disabled === 'function') {
return action.disabled({ ...objectData, _user: userProfile })
}
return action.disabled
}
const PrinterControlButtons = ({ callAction, objectData, disabled }) => {
const { userProfile } = useContext(AuthContext)
const model = getModelByName('printer')
const startQueueAction = findAction(model.actions, 'startQueue')
const pauseJobAction = findAction(model.actions, 'pauseJob')
const resumeJobAction = findAction(model.actions, 'resumeJob')
const cancelJobAction = findAction(model.actions, 'cancelJob')
const isPaused = objectData?.state?.type === 'paused'
const startAction = isPaused ? resumeJobAction : startQueueAction
const startActionName = isPaused ? 'resumeJob' : 'startQueue'
return (
<Space size='small'>
<Button
icon={createElement(PlayCircleIcon)}
onClick={() => callAction(startActionName)}
disabled={isActionDisabled(
startAction,
objectData,
userProfile,
disabled
)}
title={startAction?.label}
/>
<Button
icon={createElement(PauseCircleIcon)}
onClick={() => callAction('pauseJob')}
disabled={isActionDisabled(
pauseJobAction,
objectData,
userProfile,
disabled
)}
title={pauseJobAction?.label}
/>
<Button
icon={createElement(StopCircleIcon)}
onClick={() => callAction('cancelJob')}
disabled={isActionDisabled(
cancelJobAction,
objectData,
userProfile,
disabled
)}
title={cancelJobAction?.label}
danger
/>
</Space>
)
}
PrinterControlButtons.propTypes = {
callAction: PropTypes.func.isRequired,
objectData: PropTypes.object.isRequired,
disabled: PropTypes.bool,
loading: PropTypes.bool
}
export default PrinterControlButtons

View File

@ -7,12 +7,7 @@ import merge from 'lodash/merge'
const { Text } = Typography
const PrinterMiscPanel = ({
id,
showControls = true,
disabled = false,
offline = true
}) => {
const PrinterMiscPanel = ({ id, showControls = true, disabled = false }) => {
const { subscribeToObjectEvent, connected, sendObjectAction } =
useContext(ApiServerContext)
const controlsDisabled = disabled || !connected
@ -40,22 +35,10 @@ const PrinterMiscPanel = ({
const [lcdBrightness, setLcdBrightness] = useState(0)
const [beeperValue, setBeeperValue] = useState(0)
useEffect(() => {
if (offline) {
setMiscData({
fan: { speed: 0, target: 0 },
lcdBacklight: { brightness: 0 },
beeper: { value: 0 },
filamentSensor: { enabled: false, filamentDetected: false },
coolingFan: { speed: 0 }
})
}
}, [offline])
useEffect(() => {
if (id && connected == true) {
const miscEventUnsubscribe = subscribeToObjectEvent(
id?.toLowerCase(),
id,
'printer',
'misc',
(event) => {
@ -210,8 +193,7 @@ const PrinterMiscPanel = ({
PrinterMiscPanel.propTypes = {
id: PropTypes.string.isRequired,
showControls: PropTypes.bool,
disabled: PropTypes.bool,
offline: PropTypes.bool
disabled: PropTypes.bool
}
export default PrinterMiscPanel

View File

@ -30,23 +30,11 @@ const CustomCollapse = styled(Collapse)`
}
`
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
disabled = false
}) => {
const { subscribeToObjectEvent, connected, sendObjectAction } =
useContext(ApiServerContext)
@ -67,30 +55,10 @@ const PrinterPositionPanel = ({
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(),
id,
'printer',
'motion',
(event) => {
@ -105,7 +73,6 @@ const PrinterPositionPanel = ({
}
}
}, [id, connected, subscribeToObjectEvent])
const [speedFactor, setSpeedFactor] = useState(positionData.speedFactor)
const [extrudeFactor, setExtrudeFactor] = useState(positionData.extrudeFactor)
const [maxVelocity, setMaxVelocity] = useState(positionData.maxVelocity)
@ -245,22 +212,16 @@ const PrinterPositionPanel = ({
</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 }}
>
<Space direction='vertical' style={{ width: '100%' }}>
<Space direction='horizontal'>
<Text>Max Velocity:</Text>
<Space.Compact block size='small'>
<InputNumber
value={round(maxVelocity, 2)}
min={1}
max={10000}
step={5}
style={controlInputStyle}
style={{ width: '125px' }}
suffix='mm/s'
onChange={(value) => setMaxVelocity(value)}
onPressEnter={handleSetMaxVelocity}
@ -276,104 +237,92 @@ const PrinterPositionPanel = ({
Set
</Button>
</Space.Compact>
</Flex>
</Space>
<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>
<Space direction='vertical' style={{ width: '100%' }}>
<Space direction='horizontal'>
<Text>Max Acceleration:</Text>
<Space.Compact block size='small'>
<InputNumber
value={round(maxAcceleration, 2)}
min={1}
max={10000}
step={5}
style={{ width: '125px' }}
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>
</Space>
</Space>
<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>
<Space direction='vertical' style={{ width: '100%' }}>
<Space direction='horizontal'>
<Text>Sqr Corner Vel:</Text>
<Space.Compact block size='small'>
<InputNumber
value={round(squareCornerVelocity, 2) || 0}
min={0.1}
max={1000}
step={0.1}
suffix='mm/s'
style={{ width: '125px' }}
onChange={(value) => setSquareCornerVelocity(value)}
onPressEnter={handleSetSquareCornerVelocity}
size='small'
disabled={controlsDisabled}
/>
<Button
type='default'
style={{ width: 40 }}
onClick={handleSetSquareCornerVelocity}
disabled={controlsDisabled}
>
Set
</Button>
</Space.Compact>
</Space>
</Space>
<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>
<Space direction='vertical' style={{ width: '100%' }}>
<Space direction='horizontal'>
<Text>Min Cruise Ratio:</Text>
<Space.Compact block size='small'>
<InputNumber
value={round(minCruiseRatio * 100, 2) || 0}
min={0}
max={100}
step={1}
suffix='%'
style={{ width: '125px' }}
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>
</Space>
</Space>
</Space>
</>
)}
<Text>Homing Origin:</Text>
@ -449,22 +398,16 @@ const PrinterPositionPanel = ({
</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 }}
>
<Space direction='vertical' style={{ width: '100%' }}>
<Space direction='horizontal'>
<Text>Speed Factor:</Text>
<Space.Compact block size='small'>
<InputNumber
value={round(speedFactor, 2)}
min={0.1}
max={2}
step={0.1}
style={controlInputStyle}
style={{ width: '125px' }}
suffix='%'
onChange={(value) => setSpeedFactor(value)}
onPressEnter={handleSetSpeedFactor}
@ -480,23 +423,17 @@ const PrinterPositionPanel = ({
Set
</Button>
</Space.Compact>
</Flex>
</Space>
<Flex align='center' style={{ width: '100%' }}>
<Text style={{ ...controlLabelStyle, minWidth: '105px' }}>
Extrude Factor:
</Text>
<Space.Compact
block
size='small'
style={{ flex: 1, minWidth: 0 }}
>
<Space direction='horizontal'>
<Text>Extrude Factor:</Text>
<Space.Compact block size='small'>
<InputNumber
value={round(extrudeFactor, 2)}
min={0.1}
max={2}
step={0.1}
style={controlInputStyle}
style={{ width: '125px' }}
suffix='%'
onChange={(value) => setExtrudeFactor(value)}
onPressEnter={handleSetExtrudeFactor}
@ -512,8 +449,8 @@ const PrinterPositionPanel = ({
Set
</Button>
</Space.Compact>
</Flex>
</Flex>
</Space>
</Space>
</>
)}
<Descriptions
@ -572,8 +509,7 @@ PrinterPositionPanel.propTypes = {
id: PropTypes.string.isRequired,
showControls: PropTypes.bool,
showMoreInfo: PropTypes.bool,
disabled: PropTypes.bool,
offline: PropTypes.bool
disabled: PropTypes.bool
}
export default PrinterPositionPanel

View File

@ -38,8 +38,7 @@ const PrinterTemperaturePanel = ({
showExtruder = true,
showBed = true,
showMoreInfo = true,
disabled = false,
offline = true
disabled = false
}) => {
const [temperatureData, setTemperatureData] = useState({
extruder: {
@ -56,17 +55,6 @@ const PrinterTemperaturePanel = ({
ambiant: 0
})
useEffect(() => {
if (offline) {
setTemperatureData({
extruder: { current: 0, target: 0, power: 0 },
bed: { current: 0, target: 0, power: 0 },
pinda: 0,
ambiant: 0
})
}
}, [offline])
const { subscribeToObjectEvent, connected, sendObjectAction } =
useContext(ApiServerContext)
const controlsDisabled = disabled || !connected
@ -84,9 +72,9 @@ const PrinterTemperaturePanel = ({
}, [temperatureData.bed?.target])
useEffect(() => {
if (id && connected == true && offline == false) {
if (id && connected == true) {
const temperatureEventUnsubscribe = subscribeToObjectEvent(
id?.toLowerCase(),
id,
'printer',
'temperature',
(event) => {
@ -100,7 +88,7 @@ const PrinterTemperaturePanel = ({
if (temperatureEventUnsubscribe) temperatureEventUnsubscribe()
}
}
}, [id, connected, subscribeToObjectEvent, offline])
}, [id, connected, subscribeToObjectEvent])
const [extruderTarget, setExtruderTarget] = useState(0)
const [bedTarget, setBedTarget] = useState(0)
@ -189,7 +177,7 @@ const PrinterTemperaturePanel = ({
value={extruderTarget}
min={0}
max={300}
style={{ width: '140px' }}
style={{ width: '120px' }}
addonAfter='°C'
onChange={(value) => setExtruderTarget(value || 0)}
onPressEnter={() =>
@ -253,7 +241,7 @@ const PrinterTemperaturePanel = ({
value={bedTarget}
min={0}
max={300}
style={{ width: '140px' }}
style={{ width: '120px' }}
addonAfter='°C'
onChange={(value) => setBedTarget(value || 0)}
onPressEnter={() =>
@ -321,8 +309,7 @@ PrinterTemperaturePanel.propTypes = {
showBed: PropTypes.bool,
showMoreInfo: PropTypes.bool,
shouldUnsubscribe: PropTypes.bool,
disabled: PropTypes.bool,
offline: PropTypes.bool
disabled: PropTypes.bool
}
export default PrinterTemperaturePanel

View File

@ -42,6 +42,7 @@ const Thumbnail = function Thumbnail({
borderRadius: '5px',
width: size,
height: size,
border: 'none',
...style
}
@ -150,7 +151,7 @@ const Thumbnail = function Thumbnail({
<Card
className={className}
style={cardStyle}
styles={{ body: { padding: 0, height: '100%', width: style?.width } }}
styles={{ body: { padding: 0, height: '100%' } }}
>
<Flex justify='center' align='center' style={{ height: '100%' }}>
{fallback || (

View File

@ -1510,7 +1510,7 @@ const ApiServerProvider = ({ children }) => {
}
}
const fetchFileThumbnail = async (file, size, show404Error = false) => {
const fetchFileThumbnail = async (file, size) => {
try {
const response = await axios.get(
`${config.backendUrl}/files/${file._id}/thumbnail`,
@ -1528,9 +1528,6 @@ const ApiServerProvider = ({ children }) => {
})
return window.URL.createObjectURL(blob)
} catch (err) {
if (err.response.status === 404 && show404Error == false) {
return null
}
console.error(err)
showError(err, () => {
fetchFileThumbnail(file, size)

View File

@ -164,7 +164,6 @@ export const GCodeFile = {
showPreview: false,
showHyperlink: true,
masterFilter: ['.gcode', '.g'],
thumbnail: true,
columnWidth: 200
},
{