From 358d31c3841ff30703cfcff66a1fb0d683011613 Mon Sep 17 00:00:00 2001 From: manasa Date: Wed, 1 Jul 2026 15:51:54 +0530 Subject: [PATCH 1/2] Added fixes for SimpleTable sorting and filtering issues --- .../SimpleTableManual/SimpleTableManual.tsx | 155 +++++++++++------- 1 file changed, 93 insertions(+), 62 deletions(-) diff --git a/packages/react-sdk-components/src/components/template/SimpleTable/SimpleTableManual/SimpleTableManual.tsx b/packages/react-sdk-components/src/components/template/SimpleTable/SimpleTableManual/SimpleTableManual.tsx index 4ddb2e42..07fecb8f 100644 --- a/packages/react-sdk-components/src/components/template/SimpleTable/SimpleTableManual/SimpleTableManual.tsx +++ b/packages/react-sdk-components/src/components/template/SimpleTable/SimpleTableManual/SimpleTableManual.tsx @@ -102,9 +102,6 @@ let menuColumnId = ''; let menuColumnType = ''; let menuColumnLabel = ''; -const filterByColumns: any[] = []; -let myRows: any[]; - export default function SimpleTableManual(props: PropsWithChildren) { const classes = useStyles(); const { @@ -133,7 +130,7 @@ export default function SimpleTableManual(props: PropsWithChildren[]>([]); + const [rowData, setRowData] = useState([]); const [elements, setElementsData] = useState([]); const [order, setOrder] = useState('asc'); const [orderBy, setOrderBy] = useState(''); @@ -150,6 +147,8 @@ export default function SimpleTableManual(props: PropsWithChildren('notequal'); const [displayDialogDateValue, setDisplayDialogDateValue] = useState(''); const selectedRowIndex: any = useRef(null); + const myRowsRef = useRef([]); + const filterByColumnsRef = useRef([]); const localizedVal = PCore.getLocaleUtils().getLocaleValue; const localeCategory = 'SimpleTable'; const parameters = fieldMetadata?.datasource?.parameters; @@ -202,7 +201,9 @@ export default function SimpleTableManual(props: PropsWithChildren { - buildElementsForTable(); + if (!(readOnlyMode && dataPageName)) { + buildElementsForTable(); + } if (readOnlyMode || allowEditingInModal) { generateRowsData(); } @@ -230,7 +231,8 @@ export default function SimpleTableManual(props: PropsWithChildren item.name).map(item => item.name) + // Temporary filter for attachments to align with constellation payload behavior. + fieldDefs.filter(item => item.name && item.meta?.type !== 'Attachment').map(item => item.name) ); } else { // @ts-expect-error - An argument for 'fields' was not provided @@ -242,8 +244,6 @@ export default function SimpleTableManual(props: PropsWithChildren col !== 'DeleteIcon'); - const getFormattedValue = (val, key) => { const rawField = fieldsWithPropNames.find(item => item.propName === key); let options = {}; @@ -266,8 +266,10 @@ export default function SimpleTableManual(props: PropsWithChildren { if (!data) return {}; - return data.map(item => { - return dataColumns.reduce((dataForRow, colKey) => { - dataForRow[colKey] = getRowValue(item, colKey); - return dataForRow; - }, {}); + return data.map((item, idx) => { + const dataForRow = displayedColumns.reduce((acc, colKey) => { + acc[colKey] = getRowValue(item, colKey); + return acc; + }, {} as any); + dataForRow.__originalIndex = idx; + return dataForRow; }); }; function generateRowsData() { + myRowsRef.current = []; // if referenceList is empty and dataPageName property value exists then make a datapage fetch call and get the list of data. if (dataPageName) { getDataPage(dataPageName, parameters, context) .then(listData => { const data = formatRowsData(listData); - myRows = data; + myRowsRef.current = data || []; setRowData(data); + // Build elements from fetched data since referenceList may be empty for data page tables + if (readOnlyMode) { + buildElementsFromData(listData as any[]); + } }) .catch(e => { console.log(e); @@ -300,16 +309,19 @@ export default function SimpleTableManual(props: PropsWithChildren { + const dataForRow: any = {}; + for (const col of displayedColumns) { const colKey: string = col; const theVal = getRowValue(row, colKey); dataForRow[colKey] = theVal || ''; } + // Preserve the original position so stableSort can look up the right + // entry in `elements` even after filtering shrinks rowData. + dataForRow.__originalIndex = idx; data.push(dataForRow); - myRows = data; - } + }); + myRowsRef.current = data; setRowData(data); } } @@ -390,13 +402,14 @@ export default function SimpleTableManual(props: PropsWithChildren { + const data: any = []; + rawFields.forEach(item => { + if (!item.config.hide) { + const propName = item.config.value.replace('@P .', ''); + const val = getRowValue(element, propName); + data.push(createElement('span', { key: `${index}-${propName}` }, val ?? '---')); + } + }); + eleData.push(data); + }); + setElementsData(eleData); + } + const handleRequestSort = (event: React.MouseEvent, property: keyof any) => { const isAsc = orderBy === property && order === 'asc'; setOrder(isAsc ? 'desc' : 'asc'); @@ -448,7 +477,7 @@ export default function SimpleTableManual(props: PropsWithChildren el[0]); + return stabilizedThis.map(([el]) => el); } function _menuClick(event, columnId: string, columnType: string, labelValue: string) { @@ -474,7 +503,7 @@ export default function SimpleTableManual(props: PropsWithChildren @@ -668,7 +697,7 @@ export default function SimpleTableManual(props: PropsWithChildren - {row.map((item, childIndex) => { + {row?.map((item, childIndex) => { const theColKey = `data-${index}-${childIndex}`; return ( @@ -695,41 +724,43 @@ export default function SimpleTableManual(props: PropsWithChildren 0 && - stableSort(rowData, getComparator(order, orderBy)) - .slice(0) - .map((row, index) => { - return ( - - {Object.keys(row).map(colKey => { - return ( - - {row[colKey] || '---'} - - ); - })} - {showDeleteButton && ( - -
- { - editMenuClick(event, index); - }} - /> - - editRecord()}>Edit - deleteRecord()}>Delete - -
+ stableSort(rowData, getComparator(order, orderBy)).map((row: any, displayIndex) => { + const originalIndex = row.__originalIndex; + return ( + + {(elements as any[])[originalIndex]?.map((item, childIndex) => { + const theColKey = displayedColumns[childIndex]; + return ( + + {item} - )} - - ); - })} + ); + })} + {showDeleteButton && ( + +
+ { + editMenuClick(event, originalIndex); + }} + /> + + editRecord()}>Edit + deleteRecord()}>Delete + +
+
+ )} +
+ ); + })} - {((readOnlyMode && (!rowData || rowData?.length === 0)) || (editableMode && (!referenceList || referenceList?.length === 0))) && ( + {((readOnlyMode && (!rowData || rowData?.length === 0)) || + (editableMode && (!referenceList || referenceList?.length === 0)) || + (allowEditingInModal && (!rowData || rowData?.length === 0))) && (
{getGenericFieldsLocalizedValue('COSMOSFIELDS.lists', 'No records found.')}
From 94ef650194e62b2aa9b496a42442aa418713784d Mon Sep 17 00:00:00 2001 From: manasa Date: Fri, 24 Jul 2026 17:11:20 +0530 Subject: [PATCH 2/2] DataRef API call fix --- .../field/ObjectReference/ObjectReference.tsx | 1 + .../components/template/ListView/ListView.tsx | 19 ++++-- .../src/components/template/ListView/hooks.ts | 65 ++++++++++++++++++- 3 files changed, 80 insertions(+), 5 deletions(-) diff --git a/packages/react-sdk-components/src/components/field/ObjectReference/ObjectReference.tsx b/packages/react-sdk-components/src/components/field/ObjectReference/ObjectReference.tsx index d18f4407..c09dd30e 100644 --- a/packages/react-sdk-components/src/components/field/ObjectReference/ObjectReference.tsx +++ b/packages/react-sdk-components/src/components/field/ObjectReference/ObjectReference.tsx @@ -316,6 +316,7 @@ export default function ObjectReference(props: ObjectReferenceProps) { referenceList: rawViewMetadata.config.referenceList, referenceType, rowHeader: rawViewMetadata.config.rowHeader, + parameters: rawViewMetadata.config.parameters, selectionList: contextPageValue, selectionMode: mode, showPromotedFilters: false, diff --git a/packages/react-sdk-components/src/components/template/ListView/ListView.tsx b/packages/react-sdk-components/src/components/template/ListView/ListView.tsx index 263f7eac..7edd29e7 100644 --- a/packages/react-sdk-components/src/components/template/ListView/ListView.tsx +++ b/packages/react-sdk-components/src/components/template/ListView/ListView.tsx @@ -41,6 +41,7 @@ import { getGenericFieldsLocalizedValue } from '../../helpers/common-utils'; import { format } from '../../helpers/formatters'; import useInit from './hooks'; +import { useCascadeAndUpdate } from './hooks'; import type { PConnProps } from '../../../types/PConnProps'; interface ListViewProps extends PConnProps { @@ -77,6 +78,7 @@ let sortColumnId: any; const filterByColumns: any[] = []; export default function ListView(props: ListViewProps) { + console.log('ListView props', props); const { getPConnect, bInForm = true } = props; const { globalSearch, @@ -459,7 +461,7 @@ export default function ListView(props: ListViewProps) { fetchDataFromServer(); } - function fetchAllData(fields): any { + function fetchAllData(fields, overrideParams?: any): any { if (displayAs === 'advancedSearch' && !showRecords) { return Promise.resolve({ data: null }); } @@ -479,12 +481,13 @@ export default function ListView(props: ListViewProps) { query = filterPayload.current?.query; } const context = getPConnect().getContextName(); + const resolvedParams = overrideParams ?? dataViewParameters; // getDataAsync isn't returning correct data for the Page(i.e. ListView within a page) case return !bInForm ? // @ts-ignore - 3rd parameter "context" should be optional in getData method PCore.getDataApiUtils().getData(referenceList, payload) : // @ts-ignore - Argument of type 'null' is not assignable to parameter of type 'object' - PCore.getDataPageUtils().getDataAsync(referenceList, context, payload ? payload.dataViewParameters : dataViewParameters, null, query); + PCore.getDataPageUtils().getDataAsync(referenceList, context, payload ? payload.dataViewParameters : resolvedParams, null, query); } const buildSelect = (fieldDefs, colId, patchQueryFields = [], compositeKeys = []) => { @@ -557,12 +560,12 @@ export default function ListView(props: ListViewProps) { return fieldsMap; }; - async function fetchDataFromServer() { + async function fetchDataFromServer(overrideParams?: any) { let bCallSetRowsColumns = true; const { fieldDefs, itemKey, patchQueryFields } = meta; let listFields = fieldDefs ? buildSelect(fieldDefs, undefined, patchQueryFields, compositeKeys) : []; listFields = addItemKeyInSelect(fieldDefs, itemKey, listFields, compositeKeys); - const workListJSON = await fetchAllData(listFields); + const workListJSON = await fetchAllData(listFields, overrideParams); // this is an unresovled version of this.fields$, need unresolved, so can get the property reference const columnFields = componentConfig.presets[0].children[0].children; @@ -652,6 +655,14 @@ export default function ListView(props: ListViewProps) { }, {}); } + useCascadeAndUpdate({ + getPConnect, + listContext, + referenceList, + parameters, + fetchDataFromServer + }); + useEffect(() => { if (listContext.meta) { const identifier = `promoted-filters-queryable-${uniqueId}`; diff --git a/packages/react-sdk-components/src/components/template/ListView/hooks.ts b/packages/react-sdk-components/src/components/template/ListView/hooks.ts index 69431341..9b96afc1 100644 --- a/packages/react-sdk-components/src/components/template/ListView/hooks.ts +++ b/packages/react-sdk-components/src/components/template/ListView/hooks.ts @@ -1,7 +1,70 @@ -import { useEffect } from 'react'; +import { useEffect, useRef } from 'react'; import { getContext, readContextResponse } from './utils'; +/** + * Hook that subscribes to parameter field changes and triggers a data re-fetch + * when the parameters change. This mirrors the useCascadeAndUpdate hook from + * the constellation-frontend codebase. + */ +export function useCascadeAndUpdate({ getPConnect, listContext, referenceList, parameters, fetchDataFromServer }) { + const isParametersOverride = !!parameters; + const fetchRef = useRef(fetchDataFromServer); + fetchRef.current = fetchDataFromServer; + + useEffect(() => { + if (Object.keys(listContext).length === 0) return; + + const fieldChangeCallback = () => { + if (listContext.meta) { + // Resolve fresh parameters at callback time since the subscription fires + // before React re-renders with updated props + const { parameters: freshParams } = getPConnect().getConfigProps(); + fetchRef.current(freshParams); + } + }; + + const rawViewParameters = getPConnect().getComponentConfig?.()?.parameters; + const subscriptionId = crypto.randomUUID(); + + const overriddenParamFields: string[] = []; + + // Collect overridden parameter fields that are property references + if (rawViewParameters && isParametersOverride) { + Object.keys(rawViewParameters).forEach(paramKey => { + const paramField = rawViewParameters[paramKey]; + if (PCore.getAnnotationUtils().isProperty(paramField)) { + overriddenParamFields.push(`.${PCore.getAnnotationUtils().getPropertyName(paramField)}`); + } + }); + } + + // Subscribe to parameter field changes when parameters are overridden on the view + if (overriddenParamFields.length !== 0) { + PCore.getDataPageUtils().subscribeToUpdate( + referenceList, + overriddenParamFields, + getPConnect().getContextName(), + getPConnect().getPageReference(), + fieldChangeCallback, + `${subscriptionId}-override-params` + ); + } + + return function cleanup() { + if (overriddenParamFields.length !== 0) { + PCore.getDataPageUtils().unsubscribe( + referenceList, + overriddenParamFields, + getPConnect().getContextName(), + getPConnect().getPageReference(), + `${subscriptionId}-override-params` + ); + } + }; + }, [listContext]); +} + export default function useInit(props) { const { referenceList,