diff --git a/src/components/Dashboard/common/ObjectChildTable.jsx b/src/components/Dashboard/common/ObjectChildTable.jsx index 9aa43c4..c58b9ba 100644 --- a/src/components/Dashboard/common/ObjectChildTable.jsx +++ b/src/components/Dashboard/common/ObjectChildTable.jsx @@ -3,8 +3,11 @@ import PropTypes from 'prop-types' import { Table, Skeleton, Card, Button, Flex, Typography, Modal } from 'antd' import PlusIcon from '../../Icons/PlusIcon' import ObjectProperty from './ObjectProperty' +import ObjectInfo from './ObjectInfo' import { LoadingOutlined } from '@ant-design/icons' import BinIcon from '../../Icons/BinIcon' +import EyeIcon from '../../Icons/EyeIcon' +import EditIcon from '../../Icons/EditIcon' const { Text, Link, Title } = Typography const DEFAULT_COLUMN_WIDTHS = { @@ -64,6 +67,7 @@ const ObjectChildTable = ({ value = [], rollups = [], onChange, + hiddenPropertyWidth = '300px', minimal = false, label = '', ...tableProps @@ -73,6 +77,9 @@ const ObjectChildTable = ({ const generatedRowKeysRef = useRef(new WeakMap()) const generatedRowKeyCountRef = useRef(0) const [minimalModelOpen, setMinimalModelOpen] = useState(false) + const [detailModalOpen, setDetailModalOpen] = useState(false) + const [detailModalRecord, setDetailModalRecord] = useState(null) + const [detailModalIndex, setDetailModalIndex] = useState(null) const getFallbackRowKey = (record) => { if (!record || typeof record !== 'object') { return `object-child-table-row-${String(record)}` @@ -124,15 +131,14 @@ const ObjectChildTable = ({ }, [columns, properties]) const resolvedProperties = useMemo(() => { - const explicit = orderedPropertyNames - .map((name) => propertyMap.get(name)) - .filter(Boolean) + const baseProperties = + columns && columns.length > 0 + ? orderedPropertyNames + .map((name) => propertyMap.get(name)) + .filter(Boolean) + : properties - const remaining = properties.filter( - (property) => !orderedPropertyNames.includes(property.name) - ) - - return [...explicit, ...remaining].filter((property) => { + return baseProperties.filter((property) => { if (!property?.name) return false if ( visibleColumns && @@ -142,13 +148,87 @@ const ObjectChildTable = ({ } return true }) - }, [orderedPropertyNames, propertyMap, properties, visibleColumns]) + }, [columns, orderedPropertyNames, propertyMap, properties, visibleColumns]) + + const hasHiddenProperties = useMemo(() => { + return ( + Array.isArray(columns) && + columns.length > 0 && + Array.isArray(properties) && + columns.length < properties.length + ) + }, [columns, properties]) // When used inside antd Form.Item without Form.List, `value` will be the controlled array. const itemsSource = useMemo(() => { return value ?? [] }, [value]) + const handleRemoveItem = useCallback( + (record, index) => { + const currentItems = Array.isArray(itemsSource) ? itemsSource : [] + + let newItems + if (typeof rowKey === 'string' && record[rowKey] != null) { + newItems = currentItems.filter( + (item) => item[rowKey] !== record[rowKey] + ) + } else if (typeof rowKey === 'function') { + const recordKey = getResolvedRecordKey(record) + newItems = currentItems.filter((item) => { + const itemKey = getResolvedRecordKey(item) + return itemKey !== recordKey + }) + } else { + newItems = currentItems.filter((_, i) => i !== index) + } + + if (typeof onChange === 'function') { + onChange(newItems) + } + }, + [itemsSource, onChange, rowKey, getResolvedRecordKey] + ) + + const handleOpenDetailModal = useCallback((record, index) => { + setDetailModalRecord({ ...record }) + setDetailModalIndex(index) + setDetailModalOpen(true) + }, []) + + const handleDetailPropertyChange = useCallback( + (propName, newVal) => { + const property = propertyMap.get(propName) + const resolved = resolveChangeValue(newVal, property?.type) + + setDetailModalRecord((prev) => + prev ? { ...prev, [propName]: resolved } : prev + ) + + if (detailModalIndex == null) return + + const currentItems = Array.isArray(itemsSource) ? [...itemsSource] : [] + const existingRowKey = + currentItems[detailModalIndex] != null + ? getResolvedRecordKey(currentItems[detailModalIndex]) + : null + const updatedItem = { + ...currentItems[detailModalIndex], + [propName]: resolved + } + + if (existingRowKey) { + generatedRowKeysRef.current.set(updatedItem, existingRowKey) + } + + currentItems[detailModalIndex] = updatedItem + if (typeof onChange === 'function') { + onChange(currentItems) + } + }, + [propertyMap, detailModalIndex, itemsSource, onChange, getResolvedRecordKey] + ) + const tableColumns = useMemo(() => { const propertyColumns = resolvedProperties.map((property) => ({ title: property.label || property.name, @@ -197,54 +277,44 @@ const ObjectChildTable = ({ } })) - const deleteColumn = - isEditing && canAddRemove + const actionsColumn = + hasHiddenProperties || (isEditing && canAddRemove) ? { title: '', - key: 'delete', - width: 10, + key: 'actions', + width: hasHiddenProperties && isEditing && canAddRemove ? 70 : 40, fixed: 'right', render: (_text, record, index) => { if (record?.isSkeleton) { return null } + return ( - + <> + + + + - {canAddRemove && ( -