@pega/sdk 0.0.13 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/package.json +1 -1
  2. package/templates/angular-sdk-reference/angular.json +2 -1
  3. package/templates/angular-sdk-reference/package.json +1 -0
  4. package/templates/angular-sdk-reference/pega-constellationjs-0.26.3-local.tgz +0 -0
  5. package/templates/angular-sdk-reference/src/app/app.component.ts +232 -15
  6. package/templates/angular-sdk-reference/src/components/component-map.ts +90 -0
  7. package/templates/angular-sdk-reference/src/components/fields/auto-complete/auto-complete.component.ts +267 -0
  8. package/templates/angular-sdk-reference/src/components/fields/checkbox/checkbox.component.ts +84 -0
  9. package/templates/angular-sdk-reference/src/components/fields/currency/currency.component.ts +97 -0
  10. package/templates/angular-sdk-reference/src/components/fields/date-input/date-input.component.ts +88 -0
  11. package/templates/angular-sdk-reference/src/components/fields/dropdown/dropdown.component.ts +101 -0
  12. package/templates/angular-sdk-reference/src/components/fields/email/email.component.ts +91 -0
  13. package/templates/angular-sdk-reference/src/components/fields/integer/integer.component.ts +93 -0
  14. package/templates/angular-sdk-reference/src/components/fields/phone/phone.component.ts +91 -0
  15. package/templates/angular-sdk-reference/src/components/fields/radio-buttons/radio-buttons.component.ts +102 -0
  16. package/templates/angular-sdk-reference/src/components/fields/text-area/text-area.component.ts +98 -0
  17. package/templates/angular-sdk-reference/src/components/fields/text-input/text-input.component.ts +97 -0
  18. package/templates/angular-sdk-reference/src/components/fields/url-input/url-input.component.ts +94 -0
  19. package/templates/angular-sdk-reference/src/components/infra/assignment/assignment.component.ts +206 -0
  20. package/templates/angular-sdk-reference/src/components/infra/case-summary/case-summary.component.ts +76 -0
  21. package/templates/angular-sdk-reference/src/components/infra/case-view/case-view.component.ts +114 -0
  22. package/templates/angular-sdk-reference/src/components/infra/flow-container/flow-container.component.ts +411 -0
  23. package/templates/angular-sdk-reference/src/components/infra/reference/reference.component.ts +158 -0
  24. package/templates/angular-sdk-reference/src/components/infra/region/region.component.ts +39 -0
  25. package/templates/angular-sdk-reference/src/components/infra/root-container/root-container.component.ts +193 -0
  26. package/templates/angular-sdk-reference/src/components/infra/stages/stages.component.ts +78 -0
  27. package/templates/angular-sdk-reference/src/components/infra/view/view.component.ts +139 -0
  28. package/templates/angular-sdk-reference/src/components/infra/view-container/view-container.component.ts +191 -0
  29. package/templates/angular-sdk-reference/src/components/templates/default-form/default-form.component.ts +101 -0
  30. package/templates/angular-sdk-reference/src/components/templates/narrow-wide/narrow-wide.component.ts +37 -0
  31. package/templates/angular-sdk-reference/src/components/templates/one-column/one-column.component.ts +37 -0
  32. package/templates/angular-sdk-reference/src/components/templates/two-column/two-column.component.ts +37 -0
  33. package/templates/angular-sdk-reference/src/components/templates/wide-narrow/wide-narrow.component.ts +37 -0
  34. package/templates/angular-sdk-reference/src/helpers/event-utils.ts +18 -0
  35. package/templates/angular-sdk-reference/src/helpers/utils.ts +38 -0
  36. package/templates/angular-sdk-reference/src/helpers/versionHelpers.ts +14 -0
  37. package/templates/angular-sdk-reference/tsconfig.json +5 -2
  38. package/templates/react-sdk-reference/.ai-common/agents/embedded-flow-expert.md +11 -4
  39. package/templates/react-sdk-reference/.ai-common/prompts/component-manifest.json +7 -0
  40. package/templates/react-sdk-reference/.ai-common/prompts/generate-all-components.md +3 -1
  41. package/templates/react-sdk-reference/.ai-common/skills/field-components.md +75 -29
  42. package/templates/react-sdk-reference/.ai-common/skills/field-skills/AutoComplete.md +133 -101
  43. package/templates/react-sdk-reference/.ai-common/skills/field-skills/EmbeddedData.md +385 -0
  44. package/templates/react-sdk-reference/.ai-common/skills/field-skills/EmbeddedDataMulti.md +506 -0
  45. package/templates/react-sdk-reference/.ai-common/skills/field-skills/ObjectReference.md +549 -86
  46. package/templates/react-sdk-reference/.ai-common/skills/field-skills/UserReference.md +181 -83
  47. package/templates/react-sdk-reference/.ai-common/skills/template-skills/ListView.md +125 -153
  48. package/templates/react-sdk-reference/.ai-common/skills/template-skills/SimpleTable.md +90 -81
@@ -0,0 +1,114 @@
1
+ /**
2
+ * CaseView — renders the full case view with header, actions menu, and tabs/content.
3
+ *
4
+ * Simplified version that shows heading, status, and renders children.
5
+ *
6
+ * Pattern reference: angular-sdk-components CaseViewComponent + sdk-react CaseView
7
+ */
8
+
9
+ /* eslint-disable @typescript-eslint/no-explicit-any */
10
+ import { Component, Input, ChangeDetectorRef, NgZone } from '@angular/core';
11
+ import type { OnInit, OnDestroy } from '@angular/core';
12
+ import { CommonModule } from '@angular/common';
13
+ import type { Unsubscribe } from '@pega/sdk-angular';
14
+ import { PConnectBridgeComponent } from '@pega/sdk-angular';
15
+
16
+ @Component({
17
+ selector: 'pega-case-view',
18
+ standalone: true,
19
+ imports: [CommonModule, PConnectBridgeComponent],
20
+ template: `
21
+ <div>
22
+ <div *ngIf="heading" style="font-size: 1.25rem; font-weight: 600; margin-bottom: 0.5rem;">
23
+ {{ heading }}
24
+ </div>
25
+ <div *ngIf="id" style="font-size: 0.75rem; color: #6b7280; margin-bottom: 1rem;">
26
+ {{ id }}
27
+ </div>
28
+
29
+ <!-- Case summary -->
30
+ <div *ngIf="caseSummaryGetPConnect">
31
+ <pconnect-bridge [getPConnect]="caseSummaryGetPConnect"></pconnect-bridge>
32
+ </div>
33
+
34
+ <!-- Children (tabs, stages, etc.) -->
35
+ <div *ngFor="let getter of childGetters">
36
+ <pconnect-bridge [getPConnect]="getter"></pconnect-bridge>
37
+ </div>
38
+ </div>
39
+ `,
40
+ })
41
+ export class CaseViewComponent implements OnInit, OnDestroy {
42
+ @Input() props: any;
43
+
44
+ heading = '';
45
+ id = '';
46
+ status = '';
47
+ caseSummaryGetPConnect: (() => typeof PConnect) | null = null;
48
+ childGetters: Array<() => typeof PConnect> = [];
49
+
50
+ private pConn: any;
51
+ private observable: any;
52
+ private storeUnsub: Unsubscribe | undefined;
53
+
54
+ constructor(
55
+ private ngZone: NgZone,
56
+ private cdr: ChangeDetectorRef,
57
+ ) {}
58
+
59
+ ngOnInit(): void {
60
+ this.pConn = this.props.getPConnect();
61
+
62
+ // @ts-ignore
63
+ const { PConnectObservable } = PCore.getInitialiser().getSdkCore() as any;
64
+ this.observable = new PConnectObservable(this.pConn);
65
+ this.updateSelf();
66
+
67
+ this.storeUnsub = this.observable.subscribe(() => {
68
+ this.updateSelf();
69
+ });
70
+ }
71
+
72
+ ngOnDestroy(): void {
73
+ this.storeUnsub?.();
74
+ this.observable?.destroy();
75
+ }
76
+
77
+ private updateSelf(): void {
78
+ const configProps = this.pConn.resolveConfigProps(this.pConn.getConfigProps());
79
+
80
+ this.heading = configProps.header ?? '';
81
+ this.id = configProps.subheader ?? '';
82
+
83
+ const children = this.pConn.getChildren?.() ?? [];
84
+
85
+ // First child is typically the case summary (if applicable)
86
+ if (children.length > 0) {
87
+ const firstChild = children[0];
88
+ const firstPConn = firstChild.getPConnect?.() ?? firstChild;
89
+ const firstCompName = firstPConn.getComponentName?.() ?? '';
90
+
91
+ if (firstCompName === 'CaseSummary' || firstCompName === 'CaseSummaryFields') {
92
+ this.caseSummaryGetPConnect = firstChild.getPConnect ?? (() => firstChild);
93
+ this.childGetters = children.slice(1).map((child: any) => {
94
+ return child.getPConnect ?? (() => child);
95
+ });
96
+ } else {
97
+ this.caseSummaryGetPConnect = null;
98
+ this.childGetters = children.map((child: any) => {
99
+ return child.getPConnect ?? (() => child);
100
+ });
101
+ }
102
+ } else {
103
+ this.childGetters = [];
104
+ this.caseSummaryGetPConnect = null;
105
+ }
106
+
107
+ // Update okToInitFlowContainer
108
+ sessionStorage.setItem('okToInitFlowContainer', 'true');
109
+
110
+ this.ngZone.run(() => {
111
+ this.cdr.detectChanges();
112
+ });
113
+ }
114
+ }
@@ -0,0 +1,411 @@
1
+ /**
2
+ * FlowContainer — manages the case execution lifecycle.
3
+ *
4
+ * Key flow:
5
+ * 1. initContainer: checks getActiveContainerItemName, calls initializeContainers + addContainerItem
6
+ * 2. Store subscription drives updateSelf on every Redux change
7
+ * 3. updateSelf reads routingInfo from populateAdditionalProps, creates PConnect for active item
8
+ * 4. Renders the assignment form via PConnectBridgeComponent
9
+ * 5. sessionStorage('okToInitFlowContainer') gate for re-init on cancel
10
+ *
11
+ * Pattern reference: angular-sdk-components FlowContainerComponent
12
+ */
13
+
14
+ /* eslint-disable @typescript-eslint/no-explicit-any */
15
+ import { Component, Input, ChangeDetectorRef, NgZone } from '@angular/core';
16
+ import type { OnInit, OnDestroy } from '@angular/core';
17
+ import { CommonModule } from '@angular/common';
18
+ import { AssignmentComponent } from '../assignment/assignment.component';
19
+
20
+ @Component({
21
+ selector: 'pega-flow-container',
22
+ standalone: true,
23
+ imports: [CommonModule, AssignmentComponent],
24
+ template: `
25
+ <div [id]="buildName" style="text-align: left;">
26
+ <!-- Confirmation banner -->
27
+ <div
28
+ *ngIf="bShowConfirm"
29
+ style="padding: 1rem; background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 0.5rem; margin-bottom: 1rem;"
30
+ >
31
+ <p style="color: #166534;">{{ caseMessages }}</p>
32
+ </div>
33
+
34
+ <!-- Assignment view (perform mode) -->
35
+ <div *ngIf="!bShowConfirm && !showTodo && arChildren.length > 0">
36
+ <div
37
+ *ngIf="containerName"
38
+ style="font-size: 0.875rem; font-weight: 500; margin-bottom: 0.5rem; padding: 0 0.5rem;"
39
+ >
40
+ {{ containerName }}
41
+ </div>
42
+ <!-- Render Assignment explicitly — it wraps children with action buttons.
43
+ Matches reference pattern: FlowContainer -> Assignment -> view children -->
44
+ <pega-assignment [props]="assignmentProps"></pega-assignment>
45
+ </div>
46
+
47
+ <!-- Todo/review mode placeholder -->
48
+ <div
49
+ *ngIf="!bShowConfirm && showTodo"
50
+ style="padding: 1rem; text-align: center; color: #64748b;"
51
+ >
52
+ Case is in review mode
53
+ </div>
54
+ </div>
55
+ `,
56
+ })
57
+ export class FlowContainerComponent implements OnInit, OnDestroy {
58
+ @Input() props: any;
59
+
60
+ buildName = '';
61
+ containerName = '';
62
+ showTodo = false;
63
+ bShowConfirm = false;
64
+ caseMessages = '';
65
+ itemKey = '';
66
+ arChildren: Array<{ getPConnect: () => typeof PConnect }> = [];
67
+ assignmentProps: Record<string, unknown> = {};
68
+
69
+ private pConn: any;
70
+ private storeUnsub: (() => void) | undefined;
71
+ private localizedVal: any;
72
+ private bReInit = false;
73
+
74
+ constructor(
75
+ private cdr: ChangeDetectorRef,
76
+ private ngZone: NgZone,
77
+ ) {}
78
+
79
+ ngOnInit(): void {
80
+ this.pConn = this.props.getPConnect();
81
+ this.localizedVal = PCore.getLocaleUtils().getLocaleValue;
82
+
83
+ // Load children from pConn
84
+ this.arChildren = (this.pConn.getChildren?.() ?? []).map((child: any) => ({
85
+ getPConnect: child.getPConnect ?? (() => child),
86
+ }));
87
+
88
+ this.initComponent();
89
+
90
+ // Build initial assignment props for the Assignment component
91
+ this.updateAssignmentProps();
92
+
93
+ // Initialize the container (matching withSimpleViewContainerRenderer pattern from sdk-react)
94
+ this.ensureContainerInitialized();
95
+
96
+ // Add container item if initialized but no items yet (matching sdk-react useEffect pattern)
97
+ this.ensureContainerItem();
98
+
99
+ // Subscribe to store for routing changes
100
+ this.storeUnsub = PCore.getStore().subscribe(() => {
101
+ // Re-check container initialization on every store change
102
+ this.ensureContainerInitialized();
103
+ this.ensureContainerItem();
104
+ this.updateSelf();
105
+ });
106
+
107
+ // Subscribe to cancel events
108
+ PCore.getPubSubUtils().subscribe(
109
+ (PCore.getConstants() as any).PUB_SUB_EVENTS.EVENT_CANCEL,
110
+ () => {
111
+ // cancel happened — allow re-init of flow container
112
+ this.bReInit = true;
113
+ },
114
+ 'cancelAssignment',
115
+ );
116
+ }
117
+
118
+ ngOnDestroy(): void {
119
+ this.storeUnsub?.();
120
+
121
+ PCore.getPubSubUtils().unsubscribe(
122
+ (PCore.getConstants() as any).PUB_SUB_EVENTS.EVENT_CANCEL,
123
+ 'cancelAssignment',
124
+ );
125
+ }
126
+
127
+ /**
128
+ * Ensure the container is initialized.
129
+ * Matches the useContainerInitializer pattern from sdk-react's
130
+ * withSimpleViewContainerRenderer HOC.
131
+ */
132
+ private ensureContainerInitialized(): void {
133
+ const context = this.pConn.getContextName();
134
+ const containerName = this.pConn.getContainerName();
135
+ const containerMgr = this.pConn.getContainerManager();
136
+
137
+ const isInitialized = (
138
+ PCore.getContainerUtils() as any
139
+ ).isContainerInitialized(context, containerName);
140
+
141
+ if (!isInitialized) {
142
+ containerMgr.initializeContainers({
143
+ type: 'single',
144
+ name: containerName,
145
+ });
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Add a container item if the container is initialized but has no items.
151
+ * Matches the sdk-react FlowContainer's useEffect + addContainerItem helper.
152
+ */
153
+ private ensureContainerItem(): void {
154
+ const context = this.pConn.getContextName();
155
+ const containerName = this.pConn.getContainerName();
156
+ const containerPath = `${context}/${containerName}`;
157
+
158
+ const isInitialized = (
159
+ PCore.getContainerUtils() as any
160
+ ).isContainerInitialized(context, containerName);
161
+ const hasItems = (PCore.getContainerUtils() as any).hasContainerItems(
162
+ containerPath,
163
+ );
164
+ const hasMetadataChildren = !!this.pConn.getMetadata?.()?.children;
165
+
166
+ if (isInitialized && hasMetadataChildren && !hasItems) {
167
+ this.addContainerItemWithContext();
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Adds a container item with full context — matches sdk-react's addContainerItem helper.
173
+ * Passes key, flowName, caseViewMode, resourceType, and data so PCore can properly
174
+ * populate the workarea container.
175
+ */
176
+ private addContainerItemWithContext(): void {
177
+ const containerMgr = this.pConn.getContainerManager();
178
+ const contextName = this.pConn.getContextName();
179
+ const caseViewMode = this.pConn.getValue('context_data.caseViewMode');
180
+
181
+ let key: string | undefined;
182
+ let flowName: string | undefined;
183
+
184
+ if (caseViewMode !== 'review') {
185
+ const target = contextName.substring(0, contextName.lastIndexOf('_'));
186
+ const activeContainerItemID = (
187
+ PCore.getContainerUtils() as any
188
+ ).getActiveContainerItemName(target);
189
+ const containerItemData = (
190
+ PCore.getContainerUtils() as any
191
+ ).getContainerItemData(target, activeContainerItemID);
192
+
193
+ if (containerItemData) {
194
+ ({ key, flowName } = containerItemData);
195
+ }
196
+ }
197
+
198
+ containerMgr.addContainerItem({
199
+ semanticURL: '',
200
+ key,
201
+ flowName,
202
+ caseViewMode: 'perform',
203
+ resourceType: 'ASSIGNMENT',
204
+ data: this.pConn.getDataObject(contextName),
205
+ });
206
+ }
207
+
208
+ /**
209
+ * Initialize component state from pConn — name, children, todo visibility.
210
+ */
211
+ private initComponent(): void {
212
+ const baseContext = this.pConn.getContextName();
213
+ const acName = this.pConn.getContainerName();
214
+
215
+ if (this.itemKey === '') {
216
+ this.itemKey = `${baseContext}/${acName}`;
217
+ }
218
+
219
+ this.pConn.isBoundToState();
220
+ this.buildName = this.getBuildName();
221
+ this.showTodo = this.getTodoVisibility();
222
+
223
+ // Get container/assignment name
224
+ if (this.arChildren.length > 0) {
225
+ const oWorkItem = this.arChildren[0].getPConnect() as any;
226
+ const oWorkData = oWorkItem.getDataObject?.();
227
+ if (oWorkData) {
228
+ this.containerName = this.localizedVal(
229
+ oWorkData.caseInfo?.assignments?.[0]?.name,
230
+ undefined,
231
+ this.pConn.getCaseLocaleReference?.(),
232
+ );
233
+ }
234
+ }
235
+ }
236
+
237
+ private getTodoVisibility(): boolean {
238
+ const caseViewMode = this.pConn.getValue('context_data.caseViewMode');
239
+ if (caseViewMode && caseViewMode === 'review') {
240
+ return true;
241
+ }
242
+ return !(caseViewMode && caseViewMode === 'perform');
243
+ }
244
+
245
+ /**
246
+ * Called on every store change — reads routingInfo, creates new PConnect,
247
+ * and updates arChildren to render the assignment form.
248
+ */
249
+ private updateSelf(): void {
250
+ const caseViewMode = this.pConn.getValue('context_data.caseViewMode');
251
+
252
+ if (caseViewMode === 'review') {
253
+ this.showTodo = true;
254
+ if (this.bReInit) {
255
+ this.bReInit = false;
256
+ this.ensureContainerInitialized();
257
+ this.ensureContainerItem();
258
+ }
259
+ this.cdr.detectChanges();
260
+ return;
261
+ }
262
+
263
+ if (caseViewMode === 'perform') {
264
+ this.showTodo = false;
265
+ if (this.bReInit) {
266
+ this.bReInit = false;
267
+ this.ensureContainerInitialized();
268
+ this.ensureContainerItem();
269
+ }
270
+ }
271
+
272
+ // Check for case completion messages
273
+ this.showCaseMessages();
274
+
275
+ // Update children from routingInfo
276
+ this.updateFlowContainerChildren();
277
+ }
278
+
279
+ private showCaseMessages(): void {
280
+ const theCaseMessages = this.pConn.getValue('caseMessages');
281
+ const hasAssignments = this.checkHasAssignments();
282
+
283
+ if (!hasAssignments) {
284
+ this.bShowConfirm = true;
285
+ this.caseMessages =
286
+ this.localizedVal(theCaseMessages, 'Messages') ||
287
+ this.localizedVal(
288
+ 'Thank you! The next step in this case has been routed appropriately.',
289
+ 'Messages',
290
+ );
291
+ } else {
292
+ this.bShowConfirm = false;
293
+ }
294
+ }
295
+
296
+ private checkHasAssignments(): boolean {
297
+ const { CASE_INFO } = PCore.getConstants() as any;
298
+ const assignments = this.pConn.getValue(
299
+ CASE_INFO.D_CASE_ASSIGNMENTS_RESULTS,
300
+ );
301
+ const childCases = this.pConn.getValue(CASE_INFO.CHILD_ASSIGNMENTS);
302
+
303
+ return (
304
+ (assignments && assignments.length > 0) ||
305
+ (childCases && childCases.length > 0)
306
+ );
307
+ }
308
+
309
+ /**
310
+ * Reads routingInfo from Redux props, creates PConnect for active container item,
311
+ * and updates arChildren to render the assignment form components.
312
+ */
313
+ private updateFlowContainerChildren(): void {
314
+ // routingInfo is populated by PConnectObservable.resolveState() which calls
315
+ // populateAdditionalProps — it arrives via this.props (set by the bridge),
316
+ // NOT from pConn.getComponentProps() which skips populateAdditionalProps.
317
+ const routingInfo = this.props?.routingInfo;
318
+ if (!routingInfo) return;
319
+
320
+ const { accessedOrder, items, type } = routingInfo;
321
+ if (!accessedOrder || !items) return;
322
+
323
+ const key = accessedOrder[accessedOrder.length - 1];
324
+ if (key && key !== '') {
325
+ this.itemKey = key;
326
+ }
327
+
328
+ if (
329
+ accessedOrder.length > 0 &&
330
+ items[key]?.view &&
331
+ type === 'single' &&
332
+ Object.keys(items[key].view).length > 0
333
+ ) {
334
+ this.addPConnectAndUpdateChildren(items[key], key);
335
+ }
336
+ }
337
+
338
+ /**
339
+ * Creates a new PConnect from the routing item's view metadata,
340
+ * and replaces arChildren so the template renders the new assignment form.
341
+ */
342
+ private addPConnectAndUpdateChildren(currentItem: any, key: string): void {
343
+ const localPConn =
344
+ this.arChildren.length > 0
345
+ ? (this.arChildren[0].getPConnect() as any)
346
+ : this.pConn;
347
+
348
+ const rootView = currentItem.view;
349
+ const { context, name: viewName } = rootView.config;
350
+
351
+ // Don't proceed if View doesn't exist
352
+ if (!viewName) return;
353
+
354
+ const config: any = { meta: rootView };
355
+ config.options = {
356
+ context: currentItem.context,
357
+ pageReference: context || localPConn.getPageReference(),
358
+ hasForm: true,
359
+ isFlowContainer: true,
360
+ containerName: localPConn.getContainerName(),
361
+ containerItemName: key,
362
+ parentPageReference: localPConn.getPageReference(),
363
+ };
364
+
365
+ const configObject = PCore.createPConnect(config) as any;
366
+
367
+ this.ngZone.run(() => {
368
+ this.buildName = this.getBuildName();
369
+ this.arChildren = [
370
+ {
371
+ getPConnect:
372
+ configObject.getPConnect ?? (() => configObject.getPConnect()),
373
+ },
374
+ ];
375
+
376
+ // Update container/assignment name
377
+ const oWorkItem = configObject.getPConnect();
378
+ const oWorkData = oWorkItem.getDataObject?.();
379
+ if (oWorkData) {
380
+ this.containerName = this.localizedVal(
381
+ oWorkData.caseInfo?.assignments?.[0]?.name,
382
+ undefined,
383
+ this.pConn.getCaseLocaleReference?.(),
384
+ );
385
+ }
386
+
387
+ // Update assignment props so Assignment component gets new children + itemKey
388
+ this.updateAssignmentProps();
389
+
390
+ this.cdr.detectChanges();
391
+ });
392
+ }
393
+
394
+ private getBuildName(): string {
395
+ const sContext = this.pConn.getContextName?.() ?? '';
396
+ const sName = this.pConn.getContainerName?.() ?? '';
397
+ return `${sContext.toUpperCase()}/${sName.toUpperCase()}`;
398
+ }
399
+
400
+ /**
401
+ * Update assignmentProps passed to the Assignment component.
402
+ * Must be called whenever arChildren, itemKey, or pConn changes.
403
+ */
404
+ private updateAssignmentProps(): void {
405
+ this.assignmentProps = {
406
+ getPConnect: () => this.pConn,
407
+ arChildren: this.arChildren,
408
+ itemKey: this.itemKey,
409
+ };
410
+ }
411
+ }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Reference — resolves a 'reference' PConnect to its actual referenced view
3
+ * and renders it via PConnectBridge.
4
+ *
5
+ * Pattern reference: angular-sdk-components ReferenceComponent + sdk-react Reference
6
+ */
7
+
8
+ /* eslint-disable @typescript-eslint/no-explicit-any */
9
+ import { Component, Input } from '@angular/core';
10
+ import type { OnInit } from '@angular/core';
11
+ import { CommonModule } from '@angular/common';
12
+ import { PConnectBridgeComponent } from '@pega/sdk-angular';
13
+
14
+ @Component({
15
+ selector: 'pega-reference',
16
+ standalone: true,
17
+ imports: [CommonModule, PConnectBridgeComponent],
18
+ template: `
19
+ <div *ngIf="viewGetPConnect">
20
+ <pconnect-bridge [getPConnect]="viewGetPConnect"></pconnect-bridge>
21
+ </div>
22
+ `,
23
+ })
24
+ export class ReferenceComponent implements OnInit {
25
+ @Input() props: any;
26
+
27
+ viewGetPConnect: (() => typeof PConnect) | null = null;
28
+
29
+ ngOnInit(): void {
30
+ const pConn = this.props.getPConnect();
31
+ const {
32
+ visibility = true,
33
+ context = '',
34
+ readOnly = false,
35
+ displayMode = '',
36
+ } = this.props;
37
+
38
+ const referenceConfig: any = { ...pConn.getComponentConfig() };
39
+ delete referenceConfig?.name;
40
+ delete referenceConfig?.type;
41
+ delete referenceConfig?.visibility;
42
+
43
+ const viewMetadata = pConn.getReferencedView();
44
+ if (!viewMetadata) return;
45
+
46
+ const viewObject = {
47
+ ...viewMetadata,
48
+ config: {
49
+ ...viewMetadata.config,
50
+ ...referenceConfig,
51
+ },
52
+ };
53
+
54
+ const viewComponent = pConn.createComponent(viewObject, null, null, {
55
+ pageReference: context && context.startsWith('@CLASS') ? '' : context,
56
+ });
57
+
58
+ if (referenceConfig.inheritedProps?.length > 0) {
59
+ const inheritedProps = pConn.getInheritedProps();
60
+ referenceConfig.inheritedProps = Object.keys(inheritedProps).map(
61
+ (prop) => ({ prop, value: inheritedProps[prop] }),
62
+ );
63
+ }
64
+
65
+ const newPConnect =
66
+ viewComponent.getPConnect?.() ?? viewComponent.props?.getPConnect?.();
67
+ if (newPConnect) {
68
+ newPConnect.setInheritedConfig({
69
+ ...referenceConfig,
70
+ readOnly,
71
+ displayMode,
72
+ });
73
+ }
74
+
75
+ if (visibility !== false) {
76
+ const getter =
77
+ viewComponent.getPConnect ?? (() => newPConnect ?? viewComponent);
78
+ this.viewGetPConnect = getter;
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Static utility: normalizes a PConnect that might be a 'reference' into
84
+ * its dereferenced view. Returns the input unchanged if not a reference.
85
+ */
86
+ static normalizePConn(inPConn: any): any {
87
+ if (!inPConn) return inPConn;
88
+
89
+ const hasGetPConnect = !!inPConn.getPConnect;
90
+ const componentName = hasGetPConnect
91
+ ? inPConn.getPConnect().getComponentName()
92
+ : inPConn.getComponentName?.();
93
+
94
+ if (componentName === 'reference') {
95
+ const pConn = hasGetPConnect ? inPConn.getPConnect() : inPConn;
96
+ const referenceConfig: any = { ...pConn.getComponentConfig() };
97
+ delete referenceConfig?.name;
98
+ delete referenceConfig?.type;
99
+ delete referenceConfig?.visibility;
100
+
101
+ const viewMetadata = pConn.getReferencedView();
102
+ if (!viewMetadata) return null;
103
+
104
+ const viewObject = {
105
+ ...viewMetadata,
106
+ config: { ...viewMetadata.config, ...referenceConfig },
107
+ };
108
+
109
+ const resolvedConfigProps = pConn.resolveConfigProps(
110
+ pConn.getConfigProps(),
111
+ );
112
+ const {
113
+ visibility = true,
114
+ context,
115
+ readOnly = false,
116
+ displayMode = '',
117
+ } = resolvedConfigProps;
118
+
119
+ const viewComponent = pConn.createComponent(viewObject, null, null, {
120
+ pageReference: context && context.startsWith('@CLASS') ? '' : context,
121
+ });
122
+
123
+ if (referenceConfig.inheritedProps?.length > 0) {
124
+ const inheritedProps = pConn.getInheritedProps();
125
+ referenceConfig.inheritedProps = Object.keys(inheritedProps).map(
126
+ (prop: string) => ({ prop, value: inheritedProps[prop] }),
127
+ );
128
+ }
129
+
130
+ const newPConnect = viewComponent.getPConnect?.();
131
+ if (newPConnect) {
132
+ newPConnect.setInheritedConfig({
133
+ ...referenceConfig,
134
+ readOnly,
135
+ displayMode,
136
+ });
137
+ }
138
+
139
+ if (visibility !== false) {
140
+ return hasGetPConnect ? viewComponent : newPConnect;
141
+ }
142
+ return null;
143
+ }
144
+
145
+ return inPConn;
146
+ }
147
+
148
+ /**
149
+ * Static utility: normalizes an array of PConnect objects, replacing any
150
+ * 'reference' components with their resolved views.
151
+ */
152
+ static normalizePConnArray(inArray: any[]): any[] {
153
+ if (!inArray?.length) return inArray ?? [];
154
+ return inArray
155
+ .map((child) => ReferenceComponent.normalizePConn(child))
156
+ .filter(Boolean);
157
+ }
158
+ }