From a31d78567dee8c86667d6a3a2368749ca4dc06a2 Mon Sep 17 00:00:00 2001 From: Sharma Date: Wed, 23 Sep 2026 15:59:31 +0530 Subject: [PATCH 1/2] feat(simple-table): add support for primary fields in EmbeddedData and query params for refreshFor --- .../infra/assignment/assignment.component.ts | 12 +++-- .../template/simple-table-manual/helpers.ts | 31 ++++++++++-- .../simple-table-manual.component.scss | 4 ++ .../simple-table-manual.component.ts | 49 +++++++++++++------ 4 files changed, 71 insertions(+), 25 deletions(-) diff --git a/packages/angular-sdk-components/src/lib/_components/infra/assignment/assignment.component.ts b/packages/angular-sdk-components/src/lib/_components/infra/assignment/assignment.component.ts index 36a2f6f4..d94c565b 100644 --- a/packages/angular-sdk-components/src/lib/_components/infra/assignment/assignment.component.ts +++ b/packages/angular-sdk-components/src/lib/_components/infra/assignment/assignment.component.ts @@ -509,10 +509,14 @@ export class AssignmentComponent implements OnInit, OnDestroy, OnChanges { refreshProps.forEach(prop => { PCore.getRefreshManager().registerForRefresh( 'PROP_CHANGE', - this.pConn$.getActionsApi().refreshCaseView.bind(this.pConn$.getActionsApi(), caseKey, '', pageReference, { - ...refreshOptions, - refreshFor: prop[0] - }), + // The registered prop is an authored pattern with an empty list index (ex: ".Addons().Type"), + // which the server rejects. The refresh manager hands back the concrete path that changed. + (matchedPath?: string) => { + this.pConn$.getActionsApi().refreshCaseView(caseKey, '', pageReference, { + ...refreshOptions, + refreshFor: matchedPath || prop[0] + }); + }, `${pageReference}.${prop[1]}`, `${context}/${pageReference}`, context diff --git a/packages/angular-sdk-components/src/lib/_components/template/simple-table-manual/helpers.ts b/packages/angular-sdk-components/src/lib/_components/template/simple-table-manual/helpers.ts index 68f55dc1..aeabbd0b 100644 --- a/packages/angular-sdk-components/src/lib/_components/template/simple-table-manual/helpers.ts +++ b/packages/angular-sdk-components/src/lib/_components/template/simple-table-manual/helpers.ts @@ -148,12 +148,33 @@ const SUPPORTED_FIELD_TYPES = [ 'RichText' ]; +// PCore.getNameSpaceUtils() exists at runtime but is missing from the pcore typedefs. +export const getQualifiedPrimaryFieldsName = (): string => + (PCore as any).getNameSpaceUtils?.()?.getDefaultQualifiedName(PRIMARY_FIELDS) ?? PRIMARY_FIELDS; + +export const isPrimaryFieldsValue = (value): boolean => value === PRIMARY_FIELDS || value === getQualifiedPrimaryFieldsName(); + +/** + * Strips annotation prefixes (ex: "@P .FirstName") and the leading dot from a raw config value. + */ +export const getPropertyNameFromConfigValue = (configValue): string => { + let name = configValue ?? ''; + if (name.startsWith('@')) { + name = name.substring(name.indexOf(' ') + 1); + } + if (name.startsWith('.')) { + name = name.substring(1); + } + return name; +}; + export const getConfigFields = (rawFields, contextClass, primaryFieldsViewIndex) => { let primaryFields: any = []; let configFields: any = []; + const safeRawFields = rawFields || []; if (primaryFieldsViewIndex > -1) { - let primaryFieldVMD: any = PCore.getMetadataUtils().resolveView(PRIMARY_FIELDS); + let primaryFieldVMD: any = PCore.getMetadataUtils().resolveView(getQualifiedPrimaryFieldsName()); if (Array.isArray(primaryFieldVMD)) { primaryFieldVMD = primaryFieldVMD.find(primaryFieldView => primaryFieldView.classID === contextClass); primaryFields = primaryFieldVMD?.children?.[0]?.children || []; @@ -166,7 +187,7 @@ export const getConfigFields = (rawFields, contextClass, primaryFieldsViewIndex) } } - configFields = [...rawFields.slice(0, primaryFieldsViewIndex), ...primaryFields, ...rawFields.slice(primaryFieldsViewIndex + 1)]; + configFields = [...safeRawFields.slice(0, primaryFieldsViewIndex), ...primaryFields, ...safeRawFields.slice(primaryFieldsViewIndex + 1)]; // filter duplicate fields after combining raw fields and primary fields return configFields.filter((field, index) => configFields.findIndex(_field => field.config?.value === _field.config?.value) === index); }; @@ -200,7 +221,7 @@ export const updateFieldLabels = (fields, configFields, primaryFieldsViewIndex, const { columnsRawConfig = [] } = options; fields.forEach((field, idx) => { const rawColumnConfig = columnsRawConfig[idx]?.config; - if (field.config.value === PRIMARY_FIELDS) { + if (isPrimaryFieldsValue(field.config.value)) { labelsOfFields.push(''); } else if (isFLProperty(rawColumnConfig?.label ?? rawColumnConfig?.caption)) { labelsOfFields.push(getFieldLabel(rawColumnConfig) || field.config.label || field.config.caption); @@ -247,7 +268,7 @@ export const buildFieldsForTable = (configFields, pConnect, showActionColumn, op label: fieldsLabels[index], fillAvailableSpace: !!field.config.fillAvailableSpace, id: `${index}`, - name: field.config.value.substr(4), + name: getPropertyNameFromConfigValue(field.config.value), cellRenderer: TABLE_CELL, sort: false, noContextMenu: true, @@ -256,7 +277,7 @@ export const buildFieldsForTable = (configFields, pConnect, showActionColumn, op ...field }, // BUG-615253: Workaround for autosize in table with lazy loading components - width: getFieldWidth(field, fields[index].config.label) + width: getFieldWidth(field, fieldsLabels[index]) }; }); diff --git a/packages/angular-sdk-components/src/lib/_components/template/simple-table-manual/simple-table-manual.component.scss b/packages/angular-sdk-components/src/lib/_components/template/simple-table-manual/simple-table-manual.component.scss index 407c4392..3afa4c02 100644 --- a/packages/angular-sdk-components/src/lib/_components/template/simple-table-manual/simple-table-manual.component.scss +++ b/packages/angular-sdk-components/src/lib/_components/template/simple-table-manual/simple-table-manual.component.scss @@ -165,6 +165,10 @@ tr.mat-mdc-header-row { text-align: center; border: 1px solid var(--mat-sys-outline-variant); border-top: none; + + td.mat-cell { + text-align: center; + } } .psdk-utility-card-action-svg-icon { diff --git a/packages/angular-sdk-components/src/lib/_components/template/simple-table-manual/simple-table-manual.component.ts b/packages/angular-sdk-components/src/lib/_components/template/simple-table-manual/simple-table-manual.component.ts index 026a8014..ef81d2ad 100755 --- a/packages/angular-sdk-components/src/lib/_components/template/simple-table-manual/simple-table-manual.component.ts +++ b/packages/angular-sdk-components/src/lib/_components/template/simple-table-manual/simple-table-manual.component.ts @@ -17,7 +17,7 @@ import { ComponentMapperComponent } from '../../../_bridge/component-mapper/comp import { AngularPConnectData, AngularPConnectService } from '../../../_bridge/angular-pconnect'; import { DatapageService } from '../../../_services/datapage.service'; import { getReferenceList } from '../../../_helpers/field-group-utils'; -import { buildFieldsForTable, filterDataByCommonFields, filterDataByDate, getContext } from './helpers'; +import { buildFieldsForTable, filterDataByCommonFields, filterDataByDate, getConfigFields, getContext, isPrimaryFieldsValue } from './helpers'; import { evaluateAllowRowAction } from '../utils'; import { Utils } from '../../../_helpers/utils'; import { getSeconds } from '../../../_helpers/common'; @@ -48,6 +48,7 @@ interface SimpleTableManualProps { useSeparateViewForEdit: any; viewForEditModal: any; targetClassLabel?: string; + uniqueField?: string; } class Group { @@ -115,6 +116,9 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy { elementsData: MatTableDataSource; originalElementsData: MatTableDataSource; rawFields: any; + configFields: any[] = []; + uniqueField?: string; + normalizedUniqueField?: string; label?: string = ''; searchIcon$: string; @@ -262,9 +266,15 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy { displayMode, useSeparateViewForEdit, viewForEditModal, - targetClassLabel + targetClassLabel, + uniqueField } = this.configProps$; + // uniqueField is authored as a property reference (ex: ".EmbedListUUID__"); page instructions expect it + // with the leading dot while the inserted row payload expects the bare property name. + this.uniqueField = uniqueField; + this.normalizedUniqueField = uniqueField?.startsWith('.') ? uniqueField.substring(1) : uniqueField; + const simpleTableManualProps: any = {}; if (this.checkIfAllowActionsOrRowEditingExist(allowActions) && editMode) { simpleTableManualProps.hideAddRow = allowActions?.allowAdd === false; @@ -335,9 +345,14 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy { this.defaultActionId = this.editType === 'action' ? editModeConfig?.defaultAction : undefined; this.editActionId = this.editType === 'action' && editModeConfig?.useSeparateActionForEdit ? editModeConfig?.editAction : editModeConfig?.defaultAction; - const primaryFieldsViewIndex = resolvedFields.findIndex(field => field.config.value === 'pyPrimaryFields'); + const primaryFieldsViewIndex = resolvedFields?.findIndex(field => isPrimaryFieldsValue(field.config.value)) ?? -1; // const showDeleteButton = !this.readOnlyMode && !hideDeleteRow; + // "pyPrimaryFields" is a single authored column that expands into several real columns, so the + // resolved/raw children can no longer be used directly - configFields is the expanded column list. + const configFields = getConfigFields(rawFields, contextClass, primaryFieldsViewIndex); + this.configFields = configFields.filter(field => !(field?.config?.hide === true)); + // Nebula has other handling for isReadOnlyMode but has Cosmos-specific code // so ignoring that for now... // fieldDefs will be an array where each entry will have a "name" which will be the @@ -346,7 +361,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy { // Nebula does). It will also have the "label", and "meta" contains the original, // unchanged config info. For now, much of the info here is carried over from // Nebula and we may not end up using it all. - this.fieldDefs = buildFieldsForTable(rawFields, this.pConn$, this.showActionColumn, { + this.fieldDefs = buildFieldsForTable(configFields, this.pConn$, this.showActionColumn, { primaryFieldsViewIndex, fields: resolvedFields }); @@ -362,7 +377,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy { return field.name ? field.name : field.cellRenderer; }); - // And now we can process the resolvedFields to add in the "name" + // And now we can process the configFields to add in the "name" // from from the fieldDefs. This "name" is the value that // we'll share to connect things together in the table. @@ -370,12 +385,9 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy { return { ...acc, [curr.name]: curr.label }; }, {}); - this.processedFields = []; - - this.processedFields = resolvedFields.map((field, i) => { - field.config.name = this.displayedColumns[i]; // .config["value"].replace(/ ./g,"_"); // replace space dot with underscore - field.config.label = labelsMap[field.config.name] || field.config.label; - return field; + this.processedFields = this.configFields.map((field, i) => { + const name = this.displayedColumns[i]; + return { ...field, config: { ...field.config, name, label: labelsMap[name] || field.config.label } }; }); // for adding rows to table when editable and not modal view @@ -421,11 +433,12 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy { this.pConn$.getListActions().initDefaultPageInstructions( this.pConn$.getReferenceList(), // Temporary filter for attachments to align with constellation payload behavior. - this.fieldDefs.filter(item => item.name && item.meta?.type !== 'Attachment').map(item => item.name) + this.fieldDefs.filter(item => item.name && item.meta?.type !== 'Attachment').map(item => item.name), + this.uniqueField ); } else { - // @ts-ignore - An argument for 'propertyNames' was not provided. - this.pConn$.getListActions().initDefaultPageInstructions(this.pConn$.getReferenceList()); + // @ts-ignore - 'propertyNames' is optional at runtime; uniqueField is passed as the 3rd argument. + this.pConn$.getListActions().initDefaultPageInstructions(this.pConn$.getReferenceList(), undefined, this.uniqueField); } } @@ -1032,7 +1045,11 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy { this.defaultActionId ); } else { - this.pConn$.getListActions().insert({ classID: this.contextClass }, this.referenceList.length); + const payload: any = { classID: this.contextClass }; + if (this.normalizedUniqueField) { + payload[this.normalizedUniqueField] = crypto.randomUUID(); + } + this.pConn$.getListActions().insert(payload, this.referenceList.length); } this.pConn$.clearErrorMessages({ @@ -1084,7 +1101,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy { const isRowEditable = evaluateAllowRowAction(allowRowEdit, element); const data: any = []; data.__originalIndex = index; - this.rawFields?.forEach(item => { + this.configFields?.forEach(item => { if (!item?.config?.hide) { item = { ...item, From 9008ed0d951c36631a4d8585ec8a1356b45efbf1 Mon Sep 17 00:00:00 2001 From: Sharma Date: Wed, 23 Sep 2026 18:21:25 +0530 Subject: [PATCH 2/2] feat(simple-table): update the changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb81f7b1..a0428c6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ * Github: [PR-576](https://github.com/pegasystems/angular-sdk-components/pull/576) * **Added support for Data Object actions in the case view, and Submit/Cancel controls in the Data Object modal.** * Github: [PR-577](https://github.com/pegasystems/angular-sdk-components/pull/577) +* **Added support for primary fields in EmbeddedData and query params for refreshFor action.** + * Github: [PR-584](https://github.com/pegasystems/angular-sdk-components/pull/584) ### **Bug fixes** * **Fixed DataReference not making an api call on state change.**