Compare commits
2 Commits
39f1b31ac8
...
3e86170e5c
| Author | SHA1 | Date | |
|---|---|---|---|
| 3e86170e5c | |||
| 90d9ed286d |
@ -680,9 +680,11 @@ body {
|
||||
border-radius: 0px !important;
|
||||
}
|
||||
|
||||
.ant-select-selection-item .object-display-tag,
|
||||
.ant-select-tree-title .object-display-tag {
|
||||
.ant-select-selection-item .ant-tag.object-display-tag,
|
||||
.ant-select-tree-title .ant-tag.object-display-tag,
|
||||
.ant-select-dropdown .ant-tag.object-display-tag {
|
||||
background: transparent !important;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin-right: 1px !important;
|
||||
}
|
||||
@ -710,7 +712,11 @@ body {
|
||||
.ant-select-selection-item
|
||||
.object-display-tag
|
||||
.ant-flex {
|
||||
margin-top: -0.75px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ant-select-tree-node-content-wrapper .object-display-tag > .ant-flex {
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.object-info-descriptions table {
|
||||
@ -1304,7 +1310,8 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
width: auto;
|
||||
overflow: hidden;
|
||||
overflow-y: hidden;
|
||||
overflow-x: visible;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
flex-basis: auto;
|
||||
@ -1686,6 +1693,12 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
|
||||
font-size: 95%;
|
||||
}
|
||||
|
||||
.ant-tag.object-display-tag,
|
||||
.object-select-multiple.ant-select-outlined.ant-select-multiple
|
||||
.ant-select-selection-item {
|
||||
border: 1px solid color-mix(in srgb, var(--color-text) 5%, transparent);
|
||||
}
|
||||
|
||||
.code-block-editor .simplebar-content-wrapper {
|
||||
background-color: var(--layout-modal-bg);
|
||||
}
|
||||
|
||||
@ -73,6 +73,7 @@ const NewDocumentJob = ({ onOk, defaultValues = {} }) => {
|
||||
// Capture initial default values so later prop changes don't re-initialize the form
|
||||
const defaultValuesRef = useRef({
|
||||
objectType: 'documentJob',
|
||||
quantity: 1,
|
||||
...defaultValues,
|
||||
saveToFile: false
|
||||
})
|
||||
|
||||
@ -34,6 +34,8 @@ import { ApiServerContext } from '../../context/ApiServerContext.jsx'
|
||||
import ScrollBox from '../../common/ScrollBox.jsx'
|
||||
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx'
|
||||
import PrinterControlButtons from '../../common/PrinterControlButtons.jsx'
|
||||
import PrinterQueue from '../../common/PrinterQueue.jsx'
|
||||
import ListIcon from '../../../Icons/ListIcon.jsx'
|
||||
|
||||
const log = loglevel.getLogger('ControlPrinter')
|
||||
log.setLevel(config.logLevel)
|
||||
@ -50,6 +52,7 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
|
||||
printer: true,
|
||||
job: true,
|
||||
subjob: true,
|
||||
queue: true,
|
||||
filamentStock: true,
|
||||
temperature: true,
|
||||
position: true,
|
||||
@ -271,7 +274,7 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
|
||||
<Space size='small'>
|
||||
<ObjectActions
|
||||
type='printer'
|
||||
pageName='info'
|
||||
pageName='info'
|
||||
id={printerId}
|
||||
disabled={objectFormState.loading}
|
||||
visibleActions={{
|
||||
@ -297,6 +300,10 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
|
||||
key: 'subJob',
|
||||
label: 'Sub Job'
|
||||
},
|
||||
{
|
||||
key: 'queue',
|
||||
label: 'Queue'
|
||||
},
|
||||
{
|
||||
key: 'filamentStock',
|
||||
label: 'Filament Stock'
|
||||
@ -401,6 +408,7 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
|
||||
'currentJob._id': false,
|
||||
currentSubJob: false,
|
||||
'currentSubJob._id': false,
|
||||
queue: false,
|
||||
createdAt: false,
|
||||
updatedAt: false,
|
||||
state: !slicerIntegration,
|
||||
@ -418,6 +426,29 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
|
||||
}}
|
||||
</ObjectForm>
|
||||
</InfoCollapse>
|
||||
<InfoCollapse
|
||||
title={'Queue'}
|
||||
icon={<ListIcon />}
|
||||
collapseKey='queue'
|
||||
active={collapseState.queue}
|
||||
onToggle={(expanded) =>
|
||||
updateCollapseState('queue', expanded)
|
||||
}
|
||||
>
|
||||
<Card
|
||||
style={{
|
||||
backgroundColor: 'transparent',
|
||||
border: '1px solid var(--color-descriptions-border)'
|
||||
}}
|
||||
>
|
||||
<PrinterQueue
|
||||
queue={objectFormState.objectData?.queue}
|
||||
currentSubJob={
|
||||
objectFormState.objectData?.currentSubJob
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
</InfoCollapse>
|
||||
<InfoCollapse
|
||||
title={'Job'}
|
||||
icon={<JobIcon />}
|
||||
@ -459,7 +490,9 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
|
||||
) : (
|
||||
<MissingPlaceholder
|
||||
message={'No job.'}
|
||||
padding='24px'
|
||||
hasBackground={false}
|
||||
mutedBorder={true}
|
||||
/>
|
||||
)}
|
||||
</InfoCollapse>
|
||||
@ -507,7 +540,9 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
|
||||
) : (
|
||||
<MissingPlaceholder
|
||||
message={'No sub job.'}
|
||||
padding='24px'
|
||||
hasBackground={false}
|
||||
mutedBorder={true}
|
||||
/>
|
||||
)}
|
||||
</InfoCollapse>
|
||||
@ -552,7 +587,9 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
|
||||
) : (
|
||||
<MissingPlaceholder
|
||||
message={'No filament stock.'}
|
||||
padding='24px'
|
||||
hasBackground={false}
|
||||
mutedBorder={true}
|
||||
/>
|
||||
)}
|
||||
</InfoCollapse>
|
||||
|
||||
@ -7,19 +7,27 @@ const { Text } = Typography
|
||||
const MissingPlaceholder = ({
|
||||
message,
|
||||
hasBackground = true,
|
||||
hasBorder = true
|
||||
hasBorder = true,
|
||||
mutedBorder = false,
|
||||
padding = '16px'
|
||||
}) => {
|
||||
var border = undefined
|
||||
if (hasBorder == false) {
|
||||
border = 'none'
|
||||
} else if (mutedBorder == true && hasBorder == true) {
|
||||
border = '1px solid var(--color-descriptions-border)'
|
||||
}
|
||||
return (
|
||||
<Card
|
||||
size='small'
|
||||
style={{
|
||||
background: hasBackground == false ? 'transparent' : undefined,
|
||||
border:
|
||||
hasBorder == false
|
||||
? 'none'
|
||||
: hasBackground == false
|
||||
? '1px solid rgb(0 0 0 / 7%)'
|
||||
: undefined
|
||||
border: border
|
||||
}}
|
||||
styles={{
|
||||
body: {
|
||||
padding: padding
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
@ -42,7 +50,9 @@ const MissingPlaceholder = ({
|
||||
MissingPlaceholder.propTypes = {
|
||||
message: PropTypes.string.isRequired,
|
||||
hasBackground: PropTypes.bool,
|
||||
hasBorder: PropTypes.bool
|
||||
hasBorder: PropTypes.bool,
|
||||
mutedBorder: PropTypes.bool,
|
||||
padding: PropTypes.string
|
||||
}
|
||||
|
||||
export default MissingPlaceholder
|
||||
|
||||
@ -13,7 +13,7 @@ import ElipsisText from './ElipsisText'
|
||||
import SpotlightTooltip from './SpotlightTooltip'
|
||||
import StateTag from './StateTag'
|
||||
|
||||
const { Text, Link } = Typography
|
||||
const { Text } = Typography
|
||||
|
||||
const ObjectDisplay = ({
|
||||
object,
|
||||
@ -159,7 +159,6 @@ const ObjectDisplay = ({
|
||||
<Tag
|
||||
style={{
|
||||
margin: 0,
|
||||
border: 'none',
|
||||
minWidth: 0,
|
||||
maxWidth: '100%'
|
||||
}}
|
||||
@ -187,7 +186,7 @@ const ObjectDisplay = ({
|
||||
hyperlink = buildActionUrl(model, defaultModelActions[0], objectId, '', '')
|
||||
}
|
||||
|
||||
// Render name with hyperlink/spotlight support
|
||||
// Render name with spotlight support
|
||||
const renderNameDisplay = () => {
|
||||
if (!objectData?.name) return null
|
||||
|
||||
@ -195,36 +194,6 @@ const ObjectDisplay = ({
|
||||
<ElipsisText style={{ lineHeight: '1' }}>{objectData.name}</ElipsisText>
|
||||
)
|
||||
|
||||
// If hyperlink is enabled
|
||||
if (showHyperlink && hyperlink != null) {
|
||||
const linkElement = (
|
||||
<Link onClick={() => navigate(hyperlink)} ellipsis>
|
||||
{textElement}
|
||||
</Link>
|
||||
)
|
||||
|
||||
if (showSpotlight && objectId) {
|
||||
return (
|
||||
<Popover
|
||||
content={
|
||||
<SpotlightTooltip
|
||||
query={prefix + ':' + objectId}
|
||||
type={objectType}
|
||||
/>
|
||||
}
|
||||
trigger={['hover', 'click']}
|
||||
placement='topLeft'
|
||||
arrow={false}
|
||||
style={{ padding: 0 }}
|
||||
>
|
||||
{linkElement}
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
return linkElement
|
||||
}
|
||||
|
||||
// If hyperlink is disabled
|
||||
if (showSpotlight && objectId) {
|
||||
return (
|
||||
<Popover
|
||||
@ -237,6 +206,7 @@ const ObjectDisplay = ({
|
||||
trigger={['hover', 'click']}
|
||||
placement='topLeft'
|
||||
arrow={false}
|
||||
style={{ padding: 0 }}
|
||||
>
|
||||
{textElement}
|
||||
</Popover>
|
||||
@ -245,20 +215,23 @@ const ObjectDisplay = ({
|
||||
return textElement
|
||||
}
|
||||
|
||||
const canNavigate = showHyperlink && hyperlink != null
|
||||
|
||||
return (
|
||||
<Tag
|
||||
style={{
|
||||
margin: 0,
|
||||
border: 'none',
|
||||
minWidth: 0,
|
||||
maxWidth: '100%'
|
||||
maxWidth: '100%',
|
||||
cursor: canNavigate ? 'pointer' : undefined
|
||||
}}
|
||||
className='object-display-tag'
|
||||
onClick={canNavigate ? () => navigate(hyperlink) : undefined}
|
||||
>
|
||||
<Flex
|
||||
gap={objectData?.color || objectData?.state ? 'small' : '5px'}
|
||||
align='center'
|
||||
style={{ minWidth: 0, height: '24px' }}
|
||||
style={{ minWidth: 0, height: '22px' }}
|
||||
>
|
||||
<Icon />
|
||||
<Flex gap={'small'} align='center' style={{ minWidth: 0, flex: 1 }}>
|
||||
@ -285,7 +258,7 @@ const ObjectDisplay = ({
|
||||
type={objectType}
|
||||
longId={false}
|
||||
showCopy={false}
|
||||
showHyperlink={showHyperlink}
|
||||
showHyperlink={false}
|
||||
showSpotlight={showSpotlight}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@ -17,7 +17,15 @@ const ObjectList = ({
|
||||
}
|
||||
|
||||
const listContents = (
|
||||
<Flex gap={'4px'} wrap={!scrollHorizontal} style={style} justify={'start'}>
|
||||
<Flex
|
||||
gap={'4px'}
|
||||
wrap={!scrollHorizontal}
|
||||
style={{
|
||||
...style,
|
||||
width: 'fit-content'
|
||||
}}
|
||||
justify={'start'}
|
||||
>
|
||||
{value.map((item) => (
|
||||
<div key={item._id} style={{ flexShrink: 0 }}>
|
||||
<ObjectDisplay
|
||||
@ -31,7 +39,11 @@ const ObjectList = ({
|
||||
)
|
||||
|
||||
if (scrollHorizontal) {
|
||||
return <ScrollBox horizontalBottomPadding={10}>{listContents}</ScrollBox>
|
||||
return (
|
||||
<ScrollBox horizontalBottomPadding={9}>
|
||||
{listContents}
|
||||
</ScrollBox>
|
||||
)
|
||||
} else {
|
||||
return listContents
|
||||
}
|
||||
|
||||
@ -944,6 +944,11 @@ const ObjectTable = forwardRef(
|
||||
if (connected !== true) return
|
||||
if (subscribedTypeRef.current === type) return
|
||||
|
||||
console.log(
|
||||
'subscribing to object type updates',
|
||||
type,
|
||||
subscriptionFilterRef.current
|
||||
)
|
||||
const unsubscribe = subscribeToObjectTypeUpdatesFnRef.current(
|
||||
type,
|
||||
subscriptionFilterRef.current,
|
||||
|
||||
65
src/components/Dashboard/common/PrinterQueue.jsx
Normal file
65
src/components/Dashboard/common/PrinterQueue.jsx
Normal file
@ -0,0 +1,65 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import ObjectDisplay from './ObjectDisplay'
|
||||
import { Steps } from 'antd'
|
||||
import MissingPlaceholder from './MissingPlaceholder'
|
||||
|
||||
const getId = (item) => {
|
||||
if (!item) return null
|
||||
if (typeof item === 'string') return item
|
||||
if (typeof item._id === 'string') return item._id
|
||||
if (typeof item._id === 'object' && item._id?._id) return item._id._id
|
||||
return null
|
||||
}
|
||||
|
||||
const toObject = (item) => {
|
||||
if (!item) return null
|
||||
if (typeof item === 'string') return { _id: item }
|
||||
return item
|
||||
}
|
||||
|
||||
const PrinterQueue = ({ queue, currentSubJob }) => {
|
||||
const queueItems = Array.isArray(queue)
|
||||
? queue.map(toObject).filter(Boolean)
|
||||
: []
|
||||
const current = toObject(currentSubJob)
|
||||
const currentId = getId(current)
|
||||
|
||||
const items = []
|
||||
if (current && !queueItems.some((item) => getId(item) === currentId)) {
|
||||
items.push(current)
|
||||
}
|
||||
items.push(...queueItems)
|
||||
|
||||
if (items.length === 0) {
|
||||
return (
|
||||
<MissingPlaceholder
|
||||
message='No sub jobs in queue.'
|
||||
hasBackground={false}
|
||||
hasBorder={false}
|
||||
padding={0}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const currentIndex = currentId
|
||||
? items.findIndex((item) => getId(item) === currentId)
|
||||
: -1
|
||||
|
||||
return (
|
||||
<Steps
|
||||
current={currentIndex}
|
||||
direction='vertical'
|
||||
size='small'
|
||||
items={items.map((item) => ({
|
||||
title: <ObjectDisplay object={item} objectType='subJob' showHyperlink />
|
||||
}))}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
PrinterQueue.propTypes = {
|
||||
queue: PropTypes.array,
|
||||
currentSubJob: PropTypes.oneOfType([PropTypes.object, PropTypes.string])
|
||||
}
|
||||
|
||||
export default PrinterQueue
|
||||
@ -9,6 +9,7 @@ const ScrollBox = ({
|
||||
verticalRightPadding = 16,
|
||||
inner = false,
|
||||
smallPadding = false,
|
||||
className = '',
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
@ -19,7 +20,7 @@ const ScrollBox = ({
|
||||
'--scrollbox-vertical-right-padding': `${verticalRightPadding}px`,
|
||||
'--scrollbox-horizontal-bottom-padding': `${horizontalBottomPadding}px`
|
||||
}}
|
||||
className={`${inner ? 'scrollbox-inner' : ''} ${smallPadding ? 'scrollbox-inner-small-padding' : ''}`}
|
||||
className={`${inner ? 'scrollbox-inner' : ''} ${smallPadding ? 'scrollbox-inner-small-padding' : ''} ${className}`}
|
||||
>
|
||||
<SimpleBar style={{ height: '100%', ...style }} {...rest}>
|
||||
{children}
|
||||
@ -34,7 +35,8 @@ ScrollBox.propTypes = {
|
||||
horizontalBottomPadding: PropTypes.number,
|
||||
verticalRightPadding: PropTypes.number,
|
||||
inner: PropTypes.bool,
|
||||
smallPadding: PropTypes.bool
|
||||
smallPadding: PropTypes.bool,
|
||||
className: PropTypes.string
|
||||
}
|
||||
|
||||
export default ScrollBox
|
||||
|
||||
@ -157,6 +157,10 @@ export const ThemeProvider = ({ children }) => {
|
||||
isDarkMode ? '#1f1f1f' : '#ffffff'
|
||||
)
|
||||
root.style.setProperty('--color-text', isDarkMode ? '#ffffff' : '#000000')
|
||||
root.style.setProperty(
|
||||
'--color-descriptions-border',
|
||||
isDarkMode ? 'rgba(253,253,253,0.12)' : 'rgba(5,5,5,0.06)'
|
||||
)
|
||||
}, [isDarkMode, primaryColorOverride])
|
||||
|
||||
const themeConfig = {
|
||||
|
||||
@ -88,9 +88,10 @@ export const DocumentJob = {
|
||||
content: () => createElement(DocumentJobInfo)
|
||||
}
|
||||
],
|
||||
columns: ['_reference', 'name', 'state', 'createdAt', 'updatedAt'],
|
||||
columns: ['_reference', 'name', 'quantity', 'state', 'createdAt', 'updatedAt'],
|
||||
filters: [
|
||||
'name',
|
||||
'quantity',
|
||||
'width',
|
||||
'height',
|
||||
'state',
|
||||
@ -98,7 +99,7 @@ export const DocumentJob = {
|
||||
'updatedAt',
|
||||
'_reference'
|
||||
],
|
||||
sorters: ['name', 'state', 'createdAt', 'updatedAt'],
|
||||
sorters: ['name', 'quantity', 'state', 'createdAt', 'updatedAt'],
|
||||
properties: [
|
||||
{
|
||||
name: '_id',
|
||||
@ -203,6 +204,20 @@ export const DocumentJob = {
|
||||
online: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'quantity',
|
||||
label: 'Quantity',
|
||||
type: 'number',
|
||||
required: true,
|
||||
min: 1,
|
||||
step: 1,
|
||||
columnWidth: 125,
|
||||
value: (objectData) => {
|
||||
if (objectData?.createdAt == undefined && objectData?.quantity == null) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user