From 46fd3b0c8e8f4731f2f94d6d51221daa1d5b7b19 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Mon, 20 Jul 2026 02:06:40 +0100 Subject: [PATCH] Enhance ObjectProperty component by adding support for min/max value handling and array input/display functionality. Introduce new MinMaxDisplay, MinMaxInput, ArrayDisplay, and ArrayInput components, improving data entry and visualization capabilities. Update validation logic for min/max and list inputs to ensure data integrity. --- .../Dashboard/common/ObjectProperty.jsx | 147 +++++++++++++++++- 1 file changed, 142 insertions(+), 5 deletions(-) diff --git a/src/components/Dashboard/common/ObjectProperty.jsx b/src/components/Dashboard/common/ObjectProperty.jsx index 3a6ba35..33a15bf 100644 --- a/src/components/Dashboard/common/ObjectProperty.jsx +++ b/src/components/Dashboard/common/ObjectProperty.jsx @@ -27,6 +27,8 @@ import { getPropertyValue } from '../../../database/ObjectModels' import PropertyChanges from './PropertyChanges' import NetGrossDisplay from './NetGrossDisplay' import NetGrossInput from './NetGrossInput' +import MinMaxDisplay from './MinMaxDisplay' +import MinMaxInput from './MinMaxInput' import InputNumberCal from './InputNumberCal' import ObjectList from './ObjectList' import VarianceDisplay from './VarianceDisplay' @@ -47,10 +49,35 @@ import FileList from './FileList' import ObjectChildTable from './ObjectChildTable' import MiscId from './MiscId' import AddressDisplay from './AddressDisplay' +import ArrayDisplay from './ArrayDisplay' +import ArrayInput from './ArrayInput' import { round } from '../utils/Utils' const { Text } = Typography +const getTextValue = (value) => { + if (value == null || typeof value === 'string' || typeof value === 'number') { + return value + } + + if (typeof value === 'object') { + if (typeof value._id === 'string') { + return value._id + } + if (typeof value._id?._id === 'string') { + return value._id._id + } + + try { + return JSON.stringify(value) + } catch { + return String(value) + } + } + + return String(value) +} + const timeEditFormItemProps = { getValueProps: (v) => ({ value: v ? dayjs(v) : null }) } @@ -97,7 +124,10 @@ const ObjectProperty = ({ loading = false, rollups = [], showCard = true, + showDownload = true, + columns = [], style = {}, + hiddenPropertyWidth = '100px', ...rest }) => { if (value && typeof value == 'function' && objectData) { @@ -152,7 +182,11 @@ const ObjectProperty = ({ type = type(objectData, parentData) } - if (!value) { + if (columns && typeof columns == 'function' && objectData) { + columns = columns(objectData, parentData) + } + + if (value == null) { value = getPropertyValue(objectData, name) } @@ -183,6 +217,15 @@ const ObjectProperty = ({ return ( ) + case 'minMax': + return ( + + ) case 'secret': if (value != null) { return @@ -313,6 +356,9 @@ const ObjectProperty = ({ ) } } + case 'numberList': + case 'stringList': + return case 'variance': { if (value != null) { return ( @@ -331,7 +377,7 @@ const ObjectProperty = ({ return ( {prefix} - {value} + {getTextValue(value)} {suffix} ) @@ -432,8 +478,10 @@ const ObjectProperty = ({ loading={loading} rollups={rollups} size={size} + hiddenPropertyWidth={hiddenPropertyWidth} minimal={minimal} label={label} + columns={columns} canAddRemove={canAddRemove} /> ) @@ -571,6 +619,7 @@ const ObjectProperty = ({ defaultPreviewOpen={previewOpen} showPreview={showPreview} showInfo={showHyperlink} + showDownload={showDownload} /> ) } @@ -588,8 +637,8 @@ const ObjectProperty = ({ ) } default: { - if (value) { - return {value} + if (value != null && value !== '') { + return {getTextValue(value)} } else { return ( @@ -620,6 +669,59 @@ const ObjectProperty = ({ } mergedFormItemProps.rules = rules } + if (type === 'minMax' && disabled == false) { + const rules = [...(mergedFormItemProps.rules || [])] + rules.push({ + validator: (_, range) => { + if (range == null) return Promise.resolve() + if (typeof range !== 'object' || Array.isArray(range)) { + return Promise.reject(new Error('Value must be a min/max range')) + } + + const values = [range.min, range.max].filter((item) => item != null) + const valid = values.every( + (item) => + typeof item === 'number' && + Number.isFinite(item) && + (min == null || item >= min) && + (max == null || item <= max) + ) + + return valid + ? Promise.resolve() + : Promise.reject(new Error('Enter valid min and max values')) + } + }) + mergedFormItemProps.rules = rules + } + if ((type === 'numberList' || type === 'stringList') && disabled == false) { + const rules = [...(mergedFormItemProps.rules || [])] + rules.push({ + validator: (_, items) => { + if (items == null) return Promise.resolve() + if (!Array.isArray(items)) { + return Promise.reject(new Error('Value must be a list')) + } + + const valid = items.every((item) => { + if (type === 'numberList') { + return ( + typeof item === 'number' && + Number.isFinite(item) && + (min == null || item >= min) && + (max == null || item <= max) + ) + } + return typeof item === 'string' && item.trim().length > 0 + }) + + return valid + ? Promise.resolve() + : Promise.reject(new Error('Complete or remove empty list items')) + } + }) + mergedFormItemProps.rules = rules + } // Remove name from mergedFormItemProps if present if (mergedFormItemProps.name) { delete mergedFormItemProps.name @@ -657,6 +759,17 @@ const ObjectProperty = ({ {...inputProps} /> ) + case 'minMax': + return ( + + ) case 'secret': return ( ) + case 'numberList': + return ( + + ) + case 'stringList': + return ( + + ) case 'text': return case 'codeBlock': @@ -831,9 +964,11 @@ const ObjectProperty = ({