Enhance ObjectSelect component to support additional filtering and improved data handling

- Introduced a new 'masterFilter' prop to allow for more complex filtering scenarios.
- Updated data fetching logic to handle both array and object responses from the API, ensuring robust data management.
- Improved tree data handling by refining how children nodes are built and updated.
- Added a 'disabled' prop to control the component's interactivity.
- Enhanced prop types for better type checking and documentation clarity.
This commit is contained in:
Tom Butcher 2025-08-18 01:02:27 +01:00
parent 08dbbefada
commit e423f32493

View File

@ -9,6 +9,7 @@ import PropTypes from 'prop-types'
import { TreeSelect, Space, Button, Input } from 'antd' import { TreeSelect, Space, Button, Input } from 'antd'
import ReloadIcon from '../../Icons/ReloadIcon' import ReloadIcon from '../../Icons/ReloadIcon'
import { ApiServerContext } from '../context/ApiServerContext' import { ApiServerContext } from '../context/ApiServerContext'
import { AuthContext } from '../context/AuthContext'
import ObjectProperty from './ObjectProperty' import ObjectProperty from './ObjectProperty'
import { getModelByName } from '../../../database/ObjectModels' import { getModelByName } from '../../../database/ObjectModels'
import merge from 'lodash/merge' import merge from 'lodash/merge'
@ -20,10 +21,13 @@ const ObjectSelect = ({
multiple = false, multiple = false,
treeSelectProps = {}, treeSelectProps = {},
filter = {}, filter = {},
masterFilter = {},
value, value,
disabled = false,
...rest ...rest
}) => { }) => {
const { fetchObjectsByProperty } = useContext(ApiServerContext) const { fetchObjectsByProperty } = useContext(ApiServerContext)
const { token } = useContext(AuthContext)
// --- State --- // --- State ---
const [treeData, setTreeData] = useState([]) const [treeData, setTreeData] = useState([])
const [objectPropertiesTree, setObjectPropertiesTree] = useState({}) const [objectPropertiesTree, setObjectPropertiesTree] = useState({})
@ -40,9 +44,15 @@ const ObjectSelect = ({
try { try {
const data = await fetchObjectsByProperty(type, { const data = await fetchObjectsByProperty(type, {
properties: properties, properties: properties,
filter: customFilter filter: customFilter,
masterFilter
}) })
if (Array.isArray(data)) {
setObjectPropertiesTree((prev) => merge([], prev, data))
} else {
setObjectPropertiesTree((prev) => merge({}, prev, data)) setObjectPropertiesTree((prev) => merge({}, prev, data))
}
setInitialLoading(false) setInitialLoading(false)
setError(false) setError(false)
return data return data
@ -86,6 +96,7 @@ const ObjectSelect = ({
} }
}) })
} }
if (typeof data == 'object') { if (typeof data == 'object') {
const property = properties[pIdx] || null const property = properties[pIdx] || null
return Object.entries(data) return Object.entries(data)
@ -97,7 +108,7 @@ const ObjectSelect = ({
value: key, value: key,
key: parentKeys.concat(key).join(':'), key: parentKeys.concat(key).join(':'),
property, property,
parentKeys: parentKeys.concat(key), parentKeys: parentKeys.concat(key || ':'),
filterPath: newFilterPath, filterPath: newFilterPath,
selectable: false, selectable: false,
children: buildTreeData( children: buildTreeData(
@ -120,6 +131,7 @@ const ObjectSelect = ({
const loadData = async (node) => { const loadData = async (node) => {
// node.property is the property name, node.value is the value // node.property is the property name, node.value is the value
if (!node.property) return if (!node.property) return
// Build filter for this node by merging all parent property-value pairs // Build filter for this node by merging all parent property-value pairs
const customFilter = { ...filter } const customFilter = { ...filter }
if (Array.isArray(node.filterPath)) { if (Array.isArray(node.filterPath)) {
@ -128,12 +140,21 @@ const ObjectSelect = ({
}) })
} }
customFilter[node.property] = node.value customFilter[node.property] = node.value
// Fetch children for this node // Fetch children for this node
const data = await handleFetchObjectsProperties(customFilter) const data = await handleFetchObjectsProperties(customFilter)
if (!data) return if (!data) return
// Build new children
// Extract only the children for the specific node that was expanded
let nodeSpecificData = data
if (typeof data === 'object' && !Array.isArray(data)) {
// If the API returns an object with multiple keys, get only the data for this node
nodeSpecificData = data[node.value] || {}
}
// Build new children only for this specific node
const children = buildTreeData( const children = buildTreeData(
data, nodeSpecificData,
properties.indexOf(node.property) + 1, properties.indexOf(node.property) + 1,
node.parentKeys || [], node.parentKeys || [],
(node.filterPath || []).concat({ (node.filterPath || []).concat({
@ -141,7 +162,8 @@ const ObjectSelect = ({
value: node.value value: node.value
}) })
) )
// Update treeData with new children for this node
// Update treeData with new children for this node only
setTreeData((prevTreeData) => { setTreeData((prevTreeData) => {
// Helper to recursively update the correct node // Helper to recursively update the correct node
const updateNode = (nodes) => const updateNode = (nodes) =>
@ -195,11 +217,12 @@ const ObjectSelect = ({
// Build a new filter from value's properties that are in the properties list // Build a new filter from value's properties that are in the properties list
const valueFilter = { ...filter } const valueFilter = { ...filter }
properties.forEach((prop) => { properties.forEach((prop) => {
console.log('prop', prop)
if (Object.prototype.hasOwnProperty.call(value, prop)) { if (Object.prototype.hasOwnProperty.call(value, prop)) {
const filterValue = value[prop] const filterValue = value[prop]
if (filterValue?.name) { if (filterValue?.name) {
valueFilter[prop] = filterValue.name valueFilter[prop] = filterValue.name
} else if (Array.isArray(filterValue)) {
valueFilter[prop] = filterValue.join(',')
} else { } else {
valueFilter[prop] = filterValue valueFilter[prop] = filterValue
} }
@ -211,7 +234,7 @@ const ObjectSelect = ({
setInitialized(true) setInitialized(true)
return return
} }
if (!initialized) { if (!initialized && token != null) {
handleFetchObjectsProperties() handleFetchObjectsProperties()
setInitialized(true) setInitialized(true)
} }
@ -254,6 +277,7 @@ const ObjectSelect = ({
{...rest} {...rest}
value={treeSelectValue} value={treeSelectValue}
onChange={onTreeSelectChange} onChange={onTreeSelectChange}
disabled={disabled}
/> />
) )
} }
@ -261,13 +285,15 @@ const ObjectSelect = ({
ObjectSelect.propTypes = { ObjectSelect.propTypes = {
properties: PropTypes.arrayOf(PropTypes.string).isRequired, properties: PropTypes.arrayOf(PropTypes.string).isRequired,
filter: PropTypes.object, filter: PropTypes.object,
masterFilter: PropTypes.object,
useFilter: PropTypes.bool, useFilter: PropTypes.bool,
value: PropTypes.any, value: PropTypes.any,
onChange: PropTypes.func, onChange: PropTypes.func,
showSearch: PropTypes.bool, showSearch: PropTypes.bool,
multiple: PropTypes.bool, multiple: PropTypes.bool,
treeSelectProps: PropTypes.object, treeSelectProps: PropTypes.object,
type: PropTypes.string.isRequired type: PropTypes.string.isRequired,
disabled: PropTypes.bool
} }
export default ObjectSelect export default ObjectSelect