Compare commits

..

8 Commits

Author SHA1 Message Date
f55a09ff1f Refactor TemplateEditor to Improve Loading State Handling
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Wrapped the TemplatePreview component in a Spin component to provide a loading indicator while content is being loaded.
- Enhanced the structure of the TemplatePreview component by ensuring proper style and props are passed, improving user experience during loading states.
2026-08-21 23:15:47 +01:00
53d488011b Add Pan Icon and Pan Filled Icon Components for Template Preview
- Introduced new PanIcon and PanFilledIcon components to enhance the TemplatePreview functionality.
- Implemented panning feature in TemplatePreview, allowing users to navigate through content more intuitively.
- Updated TemplatePreview to toggle panning mode with visual feedback using the new icons.
- Enhanced user experience by managing pointer events and cursor styles during panning.
2026-08-21 23:15:41 +01:00
fede8af6aa Enhance TemplatePreview Component with Scroll and Iframe Resizing Features
- Refactored the TemplatePreview component to improve iframe content size handling and scrolling behavior.
- Introduced a new ScrollBox component to manage scroll position and enhance user experience.
- Implemented a ResizeObserver to dynamically adjust iframe size based on content, ensuring better display of HTML previews.
- Added cleanup logic for the observer to prevent memory leaks during component unmounting.
2026-08-21 23:06:11 +01:00
699e178fa1 Refactor JavaScript Completion Support for Enhanced Autocomplete Functionality
- Renamed the javascriptCompletionSources function to javascriptCompletionSupport for clarity.
- Updated the implementation to utilize CodeMirror's built-in support for JavaScript, improving the handling of autocomplete sources.
- Streamlined the integration of completion sources for mixed languages, ensuring better performance and user experience.
2026-08-21 22:49:08 +01:00
56b9ad9e1a Enhance Document Size Configuration with New Padding Options
- Updated the NewDocumentSize component to include additional default values for print padding and padding dimensions (left, right, top, bottom).
- Modified the ApiServerProvider to pass padding parameters in API requests, ensuring consistent handling of new padding options.
- Expanded the DocumentSize model to incorporate new fields for print padding and padding dimensions, enhancing the document size configuration capabilities.
2026-08-21 22:39:11 +01:00
12b963a887 Refactor FilterInput Component for Improved Width Handling
- Adjusted the layout of the FilterInput component by wrapping the SimplePropertyFilter in a div with a max-width of 100%, ensuring better responsiveness and alignment.
- Removed the fixed width style to enhance flexibility across different screen sizes, improving overall user experience.
2026-08-21 21:51:50 +01:00
a6a40128e3 Add Background Color to Code Block Editor
- Introduced a new CSS rule to set the background color for the code block editor, enhancing visual distinction and user experience.
- This change improves the overall aesthetics of the editor interface, aligning it with the application's design standards.
2026-08-21 21:51:38 +01:00
ef79c881e4 Refactor FilterInput Component for Improved Layout and Styling
- Updated the FilterInput component to enhance its layout by applying a new class and adjusting styles for better responsiveness.
- Modified the ScrollBox and inner div styles to ensure proper sizing and alignment, improving the overall user interface.
- Added CSS rules to support the new layout, ensuring consistent behavior across different screen sizes.
2026-08-21 21:42:24 +01:00
13 changed files with 450 additions and 86 deletions

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.935415,0,0,0.935415,2.292349,1.999999)">
<path d="M23.559,56.897C33.746,67.068 47.027,66.068 56.324,56.787C62.652,50.459 64.606,43.662 62.965,35.615C62.027,29.131 57.996,21.49 55.684,17.1C54.012,13.865 51.918,9.693 50.762,8.178C49.465,6.443 47.402,6.068 45.73,7.318C43.809,8.709 43.543,10.803 44.496,13.521L48.309,23.537C48.621,24.365 48.574,24.818 48.262,25.131C47.934,25.443 47.48,25.521 46.84,24.881L23.199,1.209C21.559,-0.4 19.137,-0.4 17.527,1.193C15.934,2.803 15.934,5.256 17.543,6.865L35.215,24.537C34.512,24.896 33.809,25.271 33.09,25.74L12.824,5.475C11.199,3.834 8.777,3.834 7.168,5.475C5.559,7.084 5.559,9.521 7.168,11.131L27.199,31.162C26.684,31.787 26.152,32.443 25.684,33.084L7.246,14.631C5.637,13.037 3.199,13.021 1.574,14.615C-0.004,16.225 -0.004,18.678 1.59,20.287L21.574,40.256C21.23,41.131 20.996,41.975 20.762,42.803L6.84,28.881C5.246,27.24 2.809,27.24 1.184,28.834C-0.395,30.475 -0.395,32.912 1.184,34.537L23.559,56.897Z" style="fill-rule:nonzero;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

7
assets/icons/panicon.svg Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.89584,0,0,0.89584,2.323959,1.951688)">
<path d="M58.333,59.078C67.13,50.281 68.599,39.468 62.739,27.046L55.505,11.796C54.911,10.546 54.208,9.531 53.38,8.734C50.583,5.921 46.38,5.843 43.489,8.718C41.864,10.343 41.536,12.781 42.083,15.265L43.192,17.953C43.224,18.062 43.224,18.156 43.177,18.234C43.067,18.343 42.942,18.281 42.864,18.203L27.052,2.39C23.927,-0.766 19.692,-0.704 16.552,2.453C15.802,3.171 15.333,4.078 15.099,5.046C12.271,3.484 9.239,3.953 6.817,6.359C4.521,8.64 4.083,11.765 5.521,14.546C4.63,14.718 3.817,15.171 3.161,15.828C0.239,18.734 0.224,22.812 3.192,25.765L4.536,27.125C3.692,27.265 2.833,27.687 2.146,28.359C-0.776,31.312 -0.714,35.593 2.333,38.593L22.224,58.515C33.458,69.765 47.614,69.781 58.333,59.078ZM53.302,54.328C45.224,62.406 35.177,62.281 26.411,53.484L7.505,34.562C6.833,33.89 6.802,32.984 7.458,32.343C8.099,31.703 9.036,31.687 9.724,32.359L21.239,43.874C22.395,45.031 24.192,44.968 25.302,43.859C26.427,42.734 26.505,40.937 25.349,39.765L8.005,22.406C7.317,21.734 7.286,20.843 7.958,20.218C8.567,19.546 9.505,19.562 10.192,20.218L26.349,36.39C27.505,37.546 29.317,37.468 30.442,36.359C31.536,35.234 31.614,33.406 30.474,32.265L11.411,13.218C10.724,12.546 10.724,11.624 11.364,10.968C11.989,10.343 12.927,10.328 13.599,10.999L31.974,29.39C33.114,30.5 34.911,30.468 36.036,29.343C37.177,28.25 37.224,26.39 36.083,25.265L20.599,9.781C19.942,9.109 19.927,8.234 20.567,7.578C21.208,6.921 22.13,6.921 22.786,7.593L45.27,30.031C46.802,31.593 48.755,31.39 49.974,30.109C50.989,29.078 51.474,27.562 50.77,25.75L46.802,15.374C46.38,14.343 46.817,13.531 47.567,13.187C48.411,12.828 49.208,13.187 49.677,14.187L56.864,29.843C61.536,40.093 60.067,47.546 53.302,54.328Z" style="fill-rule:nonzero;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -1680,3 +1680,7 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
margin: 0;
font-size: 95%;
}
.code-block-editor .simplebar-content-wrapper {
background-color: var(--layout-modal-bg);
}

View File

@ -9,7 +9,7 @@ import {
import { styleTags, tags as t } from '@lezer/highlight'
import { parseMixed } from '@lezer/common'
import { javascriptLanguage } from '@codemirror/lang-javascript'
import { javascriptCompletionSources } from '../javascriptLang'
import { javascriptCompletionSupport } from '../javascriptLang'
import {
xmlLanguage,
completeFromSchema,
@ -105,8 +105,6 @@ export function fcTemplateLang(options = {}) {
)
}),
autoCloseTags,
javascriptLanguage.data.of({
autocomplete: javascriptCompletionSources(jsScope)
})
...javascriptCompletionSupport(jsScope)
])
}

View File

@ -1,10 +1,7 @@
import { completeFromList } from '@codemirror/autocomplete'
import {
javascript,
javascriptLanguage,
localCompletionSource,
scopeCompletionSource,
snippets
scopeCompletionSource
} from '@codemirror/lang-javascript'
import { nodeJsScope } from './nodeScope.js'
@ -31,14 +28,20 @@ export function nodeScopeCompletionSource(autoCompleteObject) {
}
/**
* Completions for mixed languages that mount `javascriptLanguage`
* without `javascript()` (snippets + locals + Node globals).
* Support extensions for mixed languages that mount
* `javascriptLanguage` without `javascript()` itself (snippets,
* keywords, locals, and Node globals).
*
* Each source must be a separate `languageData` entry. CodeMirror
* treats an `autocomplete` *array* as `completeFromList` options, not
* as multiple completion sources.
*/
export function javascriptCompletionSources(autoCompleteObject) {
export function javascriptCompletionSupport(autoCompleteObject) {
return [
completeFromList(snippets),
localCompletionSource,
nodeScopeCompletionSource(autoCompleteObject)
javascript().support,
javascriptLanguage.data.of({
autocomplete: nodeScopeCompletionSource(autoCompleteObject)
})
]
}

View File

@ -7,7 +7,15 @@ const NewDocumentSize = ({ onOk, defaultValues }) => {
return (
<NewObjectForm
type={'documentSize'}
defaultValues={{ infiniteHeight: false, ...defaultValues }}
defaultValues={{
infiniteHeight: false,
printPadding: false,
paddingLeft: 0,
paddingRight: 0,
paddingTop: 0,
paddingBottom: 0,
...defaultValues
}}
>
{({ handleSubmit, submitLoading, objectData, formValid }) => {
const steps = [

View File

@ -868,16 +868,35 @@ const FilterInput = ({
// Keep the input focused while interacting with the popover.
event.preventDefault()
}}
style={{ width: 280, height: 220, margin: -4 }}
className='filter-input-property-filter'
style={{
display: 'inline-block',
maxWidth: 280,
maxHeight: 220,
margin: -4,
verticalAlign: 'top'
}}
>
<ScrollBox inner smallPadding>
<div style={{ padding: '12px 16px', minWidth: 0 }}>
<SimplePropertyFilter
modelType={propertyFilter.modelType}
propertyName={propertyFilter.propertyName}
value={propertyFilterValue}
onChange={handlePropertyFilterChange}
/>
<ScrollBox
inner
smallPadding
style={{ height: 'auto', maxHeight: 220, maxWidth: 280 }}
>
<div
style={{
padding: '12px 16px',
maxWidth: 280,
boxSizing: 'border-box'
}}
>
<div style={{ width: 'max-content', maxWidth: '100%' }}>
<SimplePropertyFilter
modelType={propertyFilter.modelType}
propertyName={propertyFilter.propertyName}
value={propertyFilterValue}
onChange={handlePropertyFilterChange}
/>
</div>
</div>
</ScrollBox>
</div>
@ -1014,6 +1033,12 @@ const FilterInput = ({
display: none;
height: 0;
}
.filter-input-property-filter .simplebar-content-wrapper {
max-width: none;
}
.filter-input-property-filter .simplebar-content {
display: inline-block;
}
`}</style>
{showPlaceholder && (
<span

View File

@ -187,22 +187,24 @@ const TemplateEditor = ({
<Splitter className={'farmcontrol-splitter'} vertical={true}>
{collapseState.preview == true && (
<Splitter.Panel style={{ height: '100%' }}>
<Card
spinning={loading}
style={style}
styles={{ body: { height: '100%', padding: '22px' } }}
>
<TemplatePreview
objectData={objectData?.testObject}
documentTemplate={objectData}
loading={loading}
isEditing={isEditing}
<Spin spinning={loading} indicator={<LoadingOutlined />}>
<Card
spinning={loading}
style={style}
onTestObjectOpen={() => setTestObjectOpen(true)}
onPreviewMessage={handlePreviewMessage}
showTestObject={true}
/>
</Card>
styles={{ body: { height: '100%', padding: '22px' } }}
>
<TemplatePreview
objectData={objectData?.testObject}
documentTemplate={objectData}
loading={loading}
isEditing={isEditing}
style={style}
onTestObjectOpen={() => setTestObjectOpen(true)}
onPreviewMessage={handlePreviewMessage}
showTestObject={true}
/>
</Card>
</Spin>
</Splitter.Panel>
)}
{collapseState.editor == true && (

View File

@ -1,10 +1,20 @@
import { useState, useContext, useEffect, useRef, useCallback } from 'react'
import {
useState,
useContext,
useEffect,
useLayoutEffect,
useRef,
useCallback
} from 'react'
import PropTypes from 'prop-types'
import { Flex, Button, Input, Select } from 'antd'
import PlusIcon from '../../Icons/PlusIcon.jsx'
import MinusIcon from '../../Icons/MinusIcon.jsx'
import InfoCircleIcon from '../../Icons/InfoCircleIcon.jsx'
import PanIcon from '../../Icons/PanIcon.jsx'
import PanFilledIcon from '../../Icons/PanFilledIcon.jsx'
import ObjectProperty from '../common/ObjectProperty.jsx'
import ScrollBox from './ScrollBox.jsx'
import { ApiServerContext } from '../context/ApiServerContext.jsx'
const noop = () => {}
@ -20,6 +30,9 @@ const TemplatePreview = ({
showPreviewSwitch = true
}) => {
const iframeRef = useRef(null)
const scrollElementRef = useRef(null)
const savedScrollRef = useRef({ top: 0, left: 0 })
const iframeSizeObserverRef = useRef(null)
const previewRequestIdRef = useRef(0)
const { fetchTemplatePreview, fetchTemplatePDF } =
useContext(ApiServerContext)
@ -28,23 +41,115 @@ const TemplatePreview = ({
const [reloadLoading, setReloadLoading] = useState(false)
const [previewScale, setPreviewScale] = useState(1)
const [previewType, setPreviewType] = useState('HTML')
const [panMode, setPanMode] = useState(false)
const [isPanning, setIsPanning] = useState(false)
const panStartRef = useRef({ x: 0, y: 0, scrollLeft: 0, scrollTop: 0 })
const [iframeSize, setIframeSize] = useState({
width: '100%',
height: 'auto'
})
const applyIframeContentSize = useCallback(() => {
const iframe = iframeRef.current
const doc = iframe?.contentDocument
if (!iframe || !doc?.documentElement) {
return
}
const documentEl =
doc.querySelector('.previewDocument') ||
doc.querySelector('.previewWrapper') ||
doc.body
const container = doc.querySelector('.previewContainer')
const wrapper = doc.querySelector('.previewWrapper')
const visual = documentEl.getBoundingClientRect()
if (visual.width <= 0 && visual.height <= 0) {
return
}
if (wrapper) {
wrapper.style.width = `${visual.width}px`
wrapper.style.height = `${visual.height}px`
}
let padX = 0
let padY = 0
if (container) {
const containerStyle = doc.defaultView.getComputedStyle(container)
padX =
parseFloat(containerStyle.paddingLeft) +
parseFloat(containerStyle.paddingRight)
padY =
parseFloat(containerStyle.paddingTop) +
parseFloat(containerStyle.paddingBottom)
}
const contentWidth = Math.ceil(visual.width + padX)
const contentHeight = Math.ceil(visual.height + padY)
if (!doc.head?.querySelector('style[data-preview-outer-scroll]')) {
const styleEl = doc.createElement('style')
styleEl.setAttribute('data-preview-outer-scroll', 'true')
styleEl.textContent =
'html, body { overflow: hidden !important; height: auto !important; }'
doc.head?.appendChild(styleEl)
}
setIframeSize((prev) => {
const width = `${contentWidth}px`
const height = `${contentHeight}px`
if (prev.width === width && prev.height === height) {
return prev
}
return { width, height }
})
}, [])
const restoreScrollPosition = useCallback(() => {
const scrollEl = scrollElementRef.current
if (!scrollEl) {
return
}
scrollEl.scrollTo(savedScrollRef.current.left, savedScrollRef.current.top)
}, [])
const handleIframeLoad = useCallback(() => {
iframeSizeObserverRef.current?.disconnect()
iframeSizeObserverRef.current = null
if (previewType != 'HTML') {
return
}
applyIframeContentSize()
const doc = iframeRef.current?.contentDocument
const observed =
doc?.querySelector('.previewDocument') ||
doc?.querySelector('.previewContainer') ||
doc?.body
if (observed && typeof ResizeObserver === 'function') {
const observer = new ResizeObserver(() => {
applyIframeContentSize()
})
observer.observe(observed)
iframeSizeObserverRef.current = observer
}
}, [applyIframeContentSize, previewType])
useLayoutEffect(() => {
restoreScrollPosition()
}, [iframeSize, restoreScrollPosition])
const updatePreviewContentHTML = (html) => {
if (iframeRef.current) {
// Save current scroll position
const scrollY = iframeRef.current.contentWindow.scrollY
const scrollX = iframeRef.current.contentWindow.scrollX
// Update srcDoc
setPreviewContentHTML(html)
// Restore scroll position after iframe loads new content
const handleLoad = () => {
iframeRef.current.contentWindow.scrollTo(scrollX, scrollY)
iframeRef.current.removeEventListener('load', handleLoad)
const scrollEl = scrollElementRef.current
if (scrollEl) {
savedScrollRef.current = {
top: scrollEl.scrollTop,
left: scrollEl.scrollLeft
}
iframeRef.current.addEventListener('load', handleLoad)
}
setPreviewContentHTML(html)
}
const reloadPreviewPDF = useCallback(
@ -84,24 +189,18 @@ const TemplatePreview = ({
const requestId = ++previewRequestIdRef.current
setReloadLoading(true)
fetchTemplatePreview(
templateId,
content,
testObject,
scale,
(result) => {
if (requestId !== previewRequestIdRef.current) {
return
}
setReloadLoading(false)
if (result?.error) {
onPreviewMessage(result.error, true)
} else {
updatePreviewContentHTML(result.html)
onPreviewMessage('No issues found.', false)
}
fetchTemplatePreview(templateId, content, testObject, scale, (result) => {
if (requestId !== previewRequestIdRef.current) {
return
}
)
setReloadLoading(false)
if (result?.error) {
onPreviewMessage(result.error, true)
} else {
updatePreviewContentHTML(result.html)
onPreviewMessage('No issues found.', false)
}
})
},
[fetchTemplatePreview, onPreviewMessage, documentTemplate?._id]
)
@ -136,6 +235,80 @@ const TemplatePreview = ({
reloadPreviewPDF
])
useEffect(() => {
return () => {
iframeSizeObserverRef.current?.disconnect()
}
}, [])
useEffect(() => {
if (!panMode) {
setIsPanning(false)
}
}, [panMode])
useEffect(() => {
const scrollEl = scrollElementRef.current
if (!panMode || !scrollEl || previewType != 'HTML') {
return
}
const handlePointerDown = (event) => {
if (event.pointerType === 'mouse' && event.button !== 0) {
return
}
event.preventDefault()
panStartRef.current = {
x: event.clientX,
y: event.clientY,
scrollLeft: scrollEl.scrollLeft,
scrollTop: scrollEl.scrollTop
}
setIsPanning(true)
}
scrollEl.addEventListener('pointerdown', handlePointerDown)
return () => {
scrollEl.removeEventListener('pointerdown', handlePointerDown)
}
}, [panMode, previewType])
useEffect(() => {
if (!isPanning) {
return
}
const previousCursor = document.body.style.cursor
const previousUserSelect = document.body.style.userSelect
document.body.style.cursor = 'grabbing'
document.body.style.userSelect = 'none'
const handlePointerMove = (event) => {
const scrollEl = scrollElementRef.current
if (!scrollEl) {
return
}
const { x, y, scrollLeft, scrollTop } = panStartRef.current
scrollEl.scrollLeft = scrollLeft - (event.clientX - x)
scrollEl.scrollTop = scrollTop - (event.clientY - y)
}
const handlePointerUp = () => {
setIsPanning(false)
}
window.addEventListener('pointermove', handlePointerMove)
window.addEventListener('pointerup', handlePointerUp)
window.addEventListener('pointercancel', handlePointerUp)
return () => {
document.body.style.cursor = previousCursor
document.body.style.userSelect = previousUserSelect
window.removeEventListener('pointermove', handlePointerMove)
window.removeEventListener('pointerup', handlePointerUp)
window.removeEventListener('pointercancel', handlePointerUp)
}
}, [isPanning])
return (
<Flex vertical gap={'middle'} style={{ height: '100%' }}>
<Flex gap={'small'}>
@ -149,6 +322,7 @@ const TemplatePreview = ({
objectData={objectData}
disabled={!isEditing || objectData?.global}
type={'object'}
style={{ minWidth: 0 }}
/>
) : (
<div style={{ flexGrow: 1 }}>
@ -165,6 +339,19 @@ const TemplatePreview = ({
</>
) : null}
<Button
icon={
panMode ? (
<PanFilledIcon style={{ color: 'var(--color-primary)' }} />
) : (
<PanIcon />
)
}
disabled={loading || reloadLoading || previewType == 'PDF'}
onClick={() => {
setPanMode((prev) => !prev)
}}
/>
<Button
icon={<PlusIcon />}
onClick={() => {
@ -205,18 +392,62 @@ const TemplatePreview = ({
) : null}
</Flex>
<iframe
ref={iframeRef}
srcDoc={previewType == 'HTML' ? previewContentHTML : undefined}
src={previewType == 'PDF' ? pdfBlob : undefined}
frameBorder='0'
<div
style={{
width: '100%',
flexGrow: 1,
border: '1px solid #85858541',
overflow: 'auto'
flex: '1 1 auto',
minHeight: 0,
border: '1px solid #85858541'
}}
/>
>
{previewType == 'HTML' ? (
<ScrollBox
scrollableNodeProps={{ ref: scrollElementRef }}
style={{
cursor: panMode ? (isPanning ? 'grabbing' : 'grab') : undefined,
touchAction: panMode ? 'none' : undefined
}}
>
<div
style={{
width: iframeSize.width,
height: iframeSize.height,
cursor: panMode
? isPanning
? 'grabbing'
: 'grab'
: undefined
}}
>
<iframe
ref={iframeRef}
srcDoc={previewContentHTML}
onLoad={handleIframeLoad}
scrolling='no'
frameBorder='0'
style={{
width: '100%',
height: iframeSize.height === 'auto' ? 150 : '100%',
display: 'block',
border: 0,
overflow: 'hidden',
pointerEvents: panMode ? 'none' : undefined
}}
/>
</div>
</ScrollBox>
) : (
<iframe
ref={iframeRef}
src={pdfBlob}
frameBorder='0'
style={{
width: '100%',
height: '100%',
border: 0
}}
/>
)}
</div>
</Flex>
)
}

View File

@ -1854,7 +1854,8 @@ const ApiServerProvider = ({ children }) => {
{
content,
testObject,
scale
scale,
padding: true
},
{
headers: {
@ -1886,7 +1887,7 @@ const ApiServerProvider = ({ children }) => {
object
},
{
params: { type },
params: { type, padding: true },
responseType: 'arraybuffer',
headers: {
Authorization: `Bearer ${token}`

View File

@ -0,0 +1,8 @@
import Icon from '@ant-design/icons'
import CustomIconSvg from '../../../assets/icons/panfilledicon.svg?react'
const PanFilledIcon = (props) => (
<Icon component={CustomIconSvg} {...props} />
)
export default PanFilledIcon

View File

@ -0,0 +1,6 @@
import Icon from '@ant-design/icons'
import CustomIconSvg from '../../../assets/icons/panicon.svg?react'
const PanIcon = (props) => <Icon component={CustomIconSvg} {...props} />
export default PanIcon

View File

@ -1,10 +1,12 @@
import { createElement, lazy } from 'react'
const DocumentSizeInfo = lazy(
() => import('../../components/Dashboard/Management/DocumentSizes/DocumentSizeInfo')
() =>
import('../../components/Dashboard/Management/DocumentSizes/DocumentSizeInfo')
)
const NewDocumentSize = lazy(
() => import('../../components/Dashboard/Management/DocumentSizes/NewDocumentSize')
() =>
import('../../components/Dashboard/Management/DocumentSizes/NewDocumentSize')
)
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import PlusIcon from '../../components/Icons/PlusIcon'
@ -30,7 +32,11 @@ export const DocumentSize = {
label: 'New Document Size',
icon: PlusIcon,
content: (objectData, { onOk } = {}) => {
return createElement(NewDocumentSize, { defaultValues: objectData, onOk, reset: true })
return createElement(NewDocumentSize, {
defaultValues: objectData,
onOk,
reset: true
})
}
},
{
@ -79,7 +85,7 @@ export const DocumentSize = {
visible: (objectData) => {
return objectData?._isEditing && objectData?._isEditing == true
}
},
}
],
pages: [
{
@ -93,6 +99,11 @@ export const DocumentSize = {
'width',
'height',
'infiniteHeight',
'printPadding',
'paddingLeft',
'paddingRight',
'paddingTop',
'paddingBottom',
'createdAt',
'updatedAt'
],
@ -100,6 +111,11 @@ export const DocumentSize = {
'name',
'width',
'height',
'printPadding',
'paddingLeft',
'paddingRight',
'paddingTop',
'paddingBottom',
'createdAt',
'updatedAt',
'_reference'
@ -109,6 +125,11 @@ export const DocumentSize = {
'width',
'height',
'infiniteHeight',
'printPadding',
'paddingLeft',
'paddingRight',
'paddingTop',
'paddingBottom',
'createdAt',
'updatedAt'
],
@ -178,6 +199,49 @@ export const DocumentSize = {
visible: (objectData) => {
return !objectData.infiniteHeight
}
},
{
name: 'printPadding',
label: 'Print Padding',
required: true,
columnWidth: 160,
type: 'bool'
},
{
name: 'paddingLeft',
label: 'Padding Left',
required: true,
columnWidth: 150,
type: 'number',
suffix: 'mm',
min: 0
},
{
name: 'paddingRight',
label: 'Padding Right',
required: true,
columnWidth: 162,
type: 'number',
suffix: 'mm',
min: 0
},
{
name: 'paddingTop',
label: 'Padding Top',
required: true,
columnWidth: 155,
type: 'number',
suffix: 'mm',
min: 0
},
{
name: 'paddingBottom',
label: 'Padding Bottom',
required: true,
columnWidth: 180,
type: 'number',
suffix: 'mm',
min: 0
}
]
}