Compare commits

..

9 Commits

8 changed files with 198 additions and 58 deletions

View File

@ -80,12 +80,20 @@
font-size: 95%;
}
.object-display-tag {
.ant-select-selection-item .country-display {
margin-left: 1px !important;
}
.object-display-tag,
.object-type-display-tag,
.country-display {
opacity: 1;
transition: opacity 0.15s ease-in-out;
}
.ant-select-focused .object-display-tag {
.object-select.ant-select-focused .object-display-tag,
.ant-select-focused .object-type-display-tag,
.ant-select-focused .country-display {
opacity: 0.5;
}
@ -379,7 +387,7 @@ body {
margin-right: 1px !important;
}
.ant-select-selection-item .object-display-tag {
.object-select .ant-select-selection-item .object-display-tag {
top: 1.5px;
}
@ -621,11 +629,20 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
right 0.15s ease-in-out;
}
.sidebar-scroll .simplebar-track.simplebar-vertical {
border-radius: 0 0 6.5px 0;
}
.sidebar-scroll.dark .simplebar-track.simplebar-vertical {
background-color: #141414;
border-inline-end: 1px solid rgba(253, 253, 253, 0.12);
border-bottom: 1px solid rgba(253, 253, 253, 0.12);
border-radius: 0 0 6.5px 0;
}
.sidebar-scroll.light .simplebar-track.simplebar-vertical {
background-color: #ffffff;
border-inline-end: 1px solid rgba(5, 5, 5, 0.06);
border-bottom: 1px solid rgba(5, 5, 5, 0.06);
}
.sidebar-scroll.simplebar-scrolling .simplebar-track.simplebar-vertical {

View File

@ -57,7 +57,7 @@ const NewDocumentJob = ({ onOk, defaultValues = {} }) => {
disabled={downloading}
sideBarGrow={true}
sideBar={
<div style={{ minHeight: '500px', flexGrow: 1 }}>
<div style={{ minHeight: '760px', flexGrow: 1 }}>
<TemplatePreview
objectData={objectData?.object}
documentTemplate={objectData?.documentTemplate}

View File

@ -13,7 +13,7 @@ const CountryDisplay = ({ countryCode }) => {
}
return (
<Flex gap={'small'} align='center'>
<Flex gap={'small'} align='center' className='country-display'>
<Flag
code={country.code}
size='middle'

View File

@ -28,7 +28,7 @@ const CountrySelect = ({
value: country.code,
name: country.name,
label: (
<Flex gap='small' align='center'>
<Flex gap='small' align='center' className='country-display'>
<Flag code={country.code} size='small' borderRadius={3} />
<Text elipsis>{country.name}</Text>
</Flex>

View File

@ -1,5 +1,12 @@
import PropTypes from 'prop-types'
import { useState, useEffect, useContext, useCallback, useMemo, useRef } from 'react'
import {
useState,
useEffect,
useContext,
useCallback,
useMemo,
useRef
} from 'react'
// import { getModelByName } from '../../../database/ObjectModels'
import DocumentPrinterIcon from '../../Icons/DocumentPrinterIcon'
import { Button, Dropdown, Modal } from 'antd'

View File

@ -60,6 +60,7 @@ const ObjectSelect = ({
const [objectList, setObjectList] = useState([])
const [treeSelectValue, setTreeSelectValue] = useState(null)
const [initialLoading, setInitialLoading] = useState(true)
const [delayedInitialLoading, setDelayedInitalLoading] = useState(true)
const [expandedKeys, setExpandedKeys] = useState([])
const [treeVersion, setTreeVersion] = useState(0)
const [isSearching, setIsSearching] = useState(false)
@ -358,7 +359,7 @@ const ObjectSelect = ({
const onTreeSelectChange = useCallback(
(value) => {
// Mark this as an internal change
setIsSearching(false)
if (!multiple) setIsSearching(false)
isInternalChangeRef.current = true
// value can be a string (single) or array (multiple)
@ -367,7 +368,7 @@ const ObjectSelect = ({
let selectedObjects = []
if (Array.isArray(value)) {
selectedObjects = value
.map((id) => objectList.find((obj) => obj._id === id))
.map((id) => objectList.find((obj) => areValuesEqual(obj._id, id)))
.filter(Boolean)
}
setTreeSelectValue(value)
@ -399,14 +400,32 @@ const ObjectSelect = ({
if (requestId !== searchRequestIdRef.current) return
if (!Array.isArray(data)) return
setTreeData(buildTreeData(data, properties.length))
const searchData =
multiple && Array.isArray(treeSelectValue)
? [
...data,
...objectList.filter((object) =>
treeSelectValue.some((id) => areValuesEqual(object._id, id))
)
].filter(
(object, index, objects) =>
objects.findIndex((item) =>
areValuesEqual(item._id, object._id)
) === index
)
: data
setTreeData(buildTreeData(searchData, properties.length))
},
[
searchObjects,
type,
buildTreeData,
objectPropertiesTree,
properties.length
properties.length,
multiple,
treeSelectValue,
objectList
]
)
@ -421,12 +440,29 @@ const ObjectSelect = ({
e.preventDefault()
e.stopPropagation()
onTreeSelectChange(
multiple ? [firstLeaf.value] : firstLeaf.value
multiple
? [
...(Array.isArray(treeSelectValue) ? treeSelectValue : []),
firstLeaf.value
].filter(
(item, index, values) =>
values.findIndex((value) => areValuesEqual(value, item)) ===
index
)
: firstLeaf.value
)
setSearchValue('')
onSearch('')
},
[treeSelectProps, isSearching, treeData, multiple, onTreeSelectChange, onSearch]
[
treeSelectProps,
isSearching,
treeData,
treeSelectValue,
multiple,
onTreeSelectChange,
onSearch
]
)
// Update treeData when objectPropertiesTree changes
useEffect(() => {
@ -444,6 +480,60 @@ const ObjectSelect = ({
useEffect(() => {
const handleValue = async () => {
if (
multiple &&
Array.isArray(value) &&
getValueIdentity(valueRef.current) !== getValueIdentity(value) &&
type != 'unknown'
) {
valueRef.current = value
const fullValues = await Promise.all(value.map(fetchFullObjectIfNeeded))
const pathKeys = []
if (fullValues.length === 0) {
handleFetchObjectsProperties()
} else {
fullValues.forEach((fullValue) => {
const valueFilter = { ...filter }
const parentKeys = []
properties.forEach((prop) => {
if (!Object.prototype.hasOwnProperty.call(fullValue, prop)) return
const filterValue = fullValue[prop]
let valueString = filterValue
if (
filterValue &&
typeof filterValue === 'object' &&
filterValue._id
) {
valueString = filterValue._id
} else if (filterValue?.name) {
valueString = filterValue.name
} else if (Array.isArray(filterValue)) {
valueString = filterValue.join(',')
}
valueFilter[prop] = valueString
pathKeys.push(
parentKeys.concat(prop + ':' + valueString).join('-')
)
parentKeys.push(valueString)
})
handleFetchObjectsProperties(valueFilter)
})
}
setExpandedKeys([...new Set(pathKeys)])
setTreeSelectValue(
value
.map((item) => (item && typeof item === 'object' ? item._id : item))
.filter((id) => id != null)
)
setInitialized(true)
return
}
if (
value &&
typeof value === 'object' &&
@ -527,7 +617,8 @@ const ObjectSelect = ({
fetchFullObjectIfNeeded,
type,
connected,
getValueIdentity
getValueIdentity,
multiple
])
const prevValuesRef = useRef({ type, masterFilter })
@ -583,6 +674,16 @@ const ObjectSelect = ({
}
}, [value, getValueIdentity, type, masterFilter])
useEffect(() => {
if (initialLoading == false) {
setTimeout(() => {
setDelayedInitalLoading(false)
}, 100)
} else {
setDelayedInitalLoading(true)
}
}, [initialLoading])
const placeholder = useMemo(
() =>
type == 'unknown' || type == undefined
@ -609,34 +710,48 @@ const ObjectSelect = ({
)
}
if (initialLoading) {
return <TreeSelect disabled loading placeholder='Loading...' />
}
// --- Main TreeSelect UI ---
return (
<TreeSelect
key={treeVersion}
treeDataSimpleMode={false}
treeDefaultExpandAll={true}
treeExpandedKeys={expandedKeys}
onTreeExpand={setExpandedKeys}
treeData={treeData}
showSearch={showSearch}
filterTreeNode={() => true}
multiple={multiple}
loadData={isSearching ? undefined : loadData}
showCheckedStrategy={SHOW_CHILD}
placeholder={placeholder}
{...treeSelectProps}
{...rest}
value={treeSelectValue}
onChange={onTreeSelectChange}
onSearch={onSearch}
onInputKeyDown={onInputKeyDown}
searchValue={searchValue}
disabled={disabled || type == 'unknown' || type == undefined}
/>
<div>
<TreeSelect
key={treeVersion}
treeDataSimpleMode={false}
treeDefaultExpandAll={true}
treeExpandedKeys={expandedKeys}
onTreeExpand={setExpandedKeys}
treeData={treeData}
showSearch={showSearch}
filterTreeNode={() => true}
multiple={multiple}
loadData={isSearching ? undefined : loadData}
showCheckedStrategy={SHOW_CHILD}
placeholder={placeholder}
{...treeSelectProps}
{...rest}
value={treeSelectValue}
onChange={onTreeSelectChange}
onSearch={onSearch}
onInputKeyDown={onInputKeyDown}
searchValue={searchValue}
disabled={disabled || type == 'unknown' || type == undefined}
style={{ opacity: delayedInitialLoading ? 0 : 1 }}
className={multiple ? 'object-select-multiple' : 'object-select'}
/>
{delayedInitialLoading && (
<TreeSelect
disabled
loading
placeholder='Loading...'
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0
}}
/>
)}
</div>
)
}

View File

@ -28,6 +28,7 @@ const ObjectTypeDisplay = ({
color={color}
style={{ margin: 0, ...style }}
icon={showIcon && Icon ? <Icon /> : undefined}
className='object-type-display-tag'
>
{showLabel && model.label && model.label}
</Tag>

View File

@ -131,6 +131,13 @@ export const Product = {
readOnly: true,
columnWidth: 180
},
{
name: 'updatedAt',
label: 'Updated At',
type: 'dateTime',
readOnly: true,
columnWidth: 175
},
{
name: 'name',
label: 'Name',
@ -139,31 +146,15 @@ export const Product = {
columnWidth: 200,
columnFixed: 'left'
},
{
name: 'updatedAt',
label: 'Updated At',
type: 'dateTime',
readOnly: true,
columnWidth: 175
},
{
name: 'productCategory',
label: 'Product Category',
label: 'Category',
required: true,
type: 'object',
objectType: 'productCategory',
showHyperlink: true,
columnWidth: 200
},
{
name: 'vendor',
label: 'Vendor',
required: true,
type: 'object',
objectType: 'vendor',
showHyperlink: true,
columnWidth: 200
},
{
name: 'version',
label: 'Version',
@ -171,6 +162,15 @@ export const Product = {
type: 'text',
columnWidth: 120
},
{
name: 'vendor',
label: 'Vendor',
required: true,
type: 'object',
objectType: 'vendor',
showHyperlink: true,
columnWidth: 200
},
{
name: 'tags',
label: 'Tags',