@pega/sdk 0.0.13 → 0.0.15

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 (139) hide show
  1. package/README.md +46 -6
  2. package/dist/index.js +50 -24
  3. package/package.json +42 -3
  4. package/templates/angular-sdk-reference/extra-webpack.config.cjs +23 -0
  5. package/templates/angular-sdk-reference/index.html +12 -0
  6. package/templates/angular-sdk-reference/src/app/pconnect-renderer.component.ts +153 -0
  7. package/templates/angular-sdk-reference/src/components/component-map.ts +90 -0
  8. package/templates/angular-sdk-reference/src/components/fields/auto-complete/auto-complete.component.ts +304 -0
  9. package/templates/angular-sdk-reference/src/components/fields/checkbox/checkbox.component.ts +89 -0
  10. package/templates/angular-sdk-reference/src/components/fields/currency/currency.component.ts +112 -0
  11. package/templates/angular-sdk-reference/src/components/fields/date-input/date-input.component.ts +101 -0
  12. package/templates/angular-sdk-reference/src/components/fields/dropdown/dropdown.component.ts +118 -0
  13. package/templates/angular-sdk-reference/src/components/fields/email/email.component.ts +104 -0
  14. package/templates/angular-sdk-reference/src/components/fields/integer/integer.component.ts +106 -0
  15. package/templates/angular-sdk-reference/src/components/fields/phone/phone.component.ts +104 -0
  16. package/templates/angular-sdk-reference/src/components/fields/radio-buttons/radio-buttons.component.ts +113 -0
  17. package/templates/angular-sdk-reference/src/components/fields/text-area/text-area.component.ts +111 -0
  18. package/templates/angular-sdk-reference/src/components/fields/text-input/text-input.component.ts +110 -0
  19. package/templates/angular-sdk-reference/src/components/fields/url-input/url-input.component.ts +113 -0
  20. package/templates/angular-sdk-reference/src/components/helpers/sdk-helpers.ts +93 -0
  21. package/templates/angular-sdk-reference/src/components/infra/assignment/assignment.component.ts +206 -0
  22. package/templates/angular-sdk-reference/src/components/infra/case-summary/case-summary.component.ts +75 -0
  23. package/templates/angular-sdk-reference/src/components/infra/case-view/case-view.component.ts +126 -0
  24. package/templates/angular-sdk-reference/src/components/infra/flow-container/flow-container.component.ts +411 -0
  25. package/templates/angular-sdk-reference/src/components/infra/reference/reference.component.ts +158 -0
  26. package/templates/angular-sdk-reference/src/components/infra/region/region.component.ts +39 -0
  27. package/templates/angular-sdk-reference/src/components/infra/root-container/root-container.component.ts +199 -0
  28. package/templates/angular-sdk-reference/src/components/infra/stages/stages.component.ts +89 -0
  29. package/templates/angular-sdk-reference/src/components/infra/view/view.component.ts +144 -0
  30. package/templates/angular-sdk-reference/src/components/infra/view-container/view-container.component.ts +191 -0
  31. package/templates/angular-sdk-reference/src/components/templates/default-form/default-form.component.ts +105 -0
  32. package/templates/angular-sdk-reference/src/components/templates/narrow-wide/narrow-wide.component.ts +37 -0
  33. package/templates/angular-sdk-reference/src/components/templates/one-column/one-column.component.ts +37 -0
  34. package/templates/angular-sdk-reference/src/components/templates/two-column/two-column.component.ts +37 -0
  35. package/templates/angular-sdk-reference/src/components/templates/wide-narrow/wide-narrow.component.ts +37 -0
  36. package/templates/angular-sdk-reference/tsconfig.app.json +13 -0
  37. package/templates/react-sdk-reference/.ai-common/agents/embedded-flow-expert.md +75 -34
  38. package/templates/react-sdk-reference/.ai-common/agents/implementation-expert.md +74 -38
  39. package/templates/react-sdk-reference/.ai-common/global/ai-agent-instructions-embedded.md +33 -1
  40. package/templates/react-sdk-reference/.ai-common/global/ai-agent-instructions.md +57 -22
  41. package/templates/react-sdk-reference/.ai-common/instructions/embedded-component.md +25 -10
  42. package/templates/react-sdk-reference/.ai-common/prompts/add-component.md +40 -19
  43. package/templates/react-sdk-reference/.ai-common/prompts/component-manifest.json +62 -1
  44. package/templates/react-sdk-reference/.ai-common/prompts/embedded-component-manifest.md +26 -4
  45. package/templates/react-sdk-reference/.ai-common/prompts/generate-all-components.md +84 -33
  46. package/templates/react-sdk-reference/.ai-common/prompts/generate-dse-components.md +46 -26
  47. package/templates/react-sdk-reference/.ai-common/prompts/generate-embedded-components.md +28 -15
  48. package/templates/react-sdk-reference/.ai-common/prompts/generate-field-components.md +24 -6
  49. package/templates/react-sdk-reference/.ai-common/prompts/generate-infra-components.md +24 -6
  50. package/templates/react-sdk-reference/.ai-common/prompts/generate-template-components.md +24 -6
  51. package/templates/react-sdk-reference/.ai-common/prompts/generate-widget-components.md +24 -6
  52. package/templates/react-sdk-reference/.ai-common/prompts/identify-components.md +2 -0
  53. package/templates/react-sdk-reference/.ai-common/prompts/replace-design-system.md +44 -17
  54. package/templates/react-sdk-reference/.ai-common/skills/connect-pega-server.md +14 -1
  55. package/templates/react-sdk-reference/.ai-common/skills/design-system-extension-skills/AssignmentHeader.md +79 -0
  56. package/templates/react-sdk-reference/.ai-common/skills/design-system-extension-skills/Toast.md +96 -0
  57. package/templates/react-sdk-reference/.ai-common/skills/design-system-extension.md +56 -35
  58. package/templates/react-sdk-reference/.ai-common/skills/embedded-flow/analyze-customer-repo.md +29 -3
  59. package/templates/react-sdk-reference/.ai-common/skills/embedded-flow/run-and-verify-integration.md +97 -37
  60. package/templates/react-sdk-reference/.ai-common/skills/embedded-flow/wire-integration.md +91 -60
  61. package/templates/react-sdk-reference/.ai-common/skills/field-components.md +88 -30
  62. package/templates/react-sdk-reference/.ai-common/skills/field-skills/AutoComplete.md +133 -101
  63. package/templates/react-sdk-reference/.ai-common/skills/field-skills/EmbeddedData.md +385 -0
  64. package/templates/react-sdk-reference/.ai-common/skills/field-skills/EmbeddedDataMulti.md +506 -0
  65. package/templates/react-sdk-reference/.ai-common/skills/field-skills/ObjectReference.md +549 -86
  66. package/templates/react-sdk-reference/.ai-common/skills/field-skills/UserReference.md +181 -83
  67. package/templates/react-sdk-reference/.ai-common/skills/infra-components.md +13 -1
  68. package/templates/react-sdk-reference/.ai-common/skills/portal-flow/run-and-verify-portal.md +290 -0
  69. package/templates/react-sdk-reference/.ai-common/skills/template-components.md +13 -1
  70. package/templates/react-sdk-reference/.ai-common/skills/template-skills/ListView.md +125 -153
  71. package/templates/react-sdk-reference/.ai-common/skills/template-skills/SimpleTable.md +90 -81
  72. package/templates/react-sdk-reference/.ai-common/skills/widget-components.md +13 -1
  73. package/templates/react-sdk-reference/assets/icons/trash.svg +3 -0
  74. package/templates/react-sdk-reference/index.html +0 -1
  75. package/templates/react-sdk-reference/package.json +2 -2
  76. package/templates/react-sdk-reference/package.minimal.json +2 -2
  77. package/templates/react-sdk-reference/sdk-config.json +3 -3
  78. package/templates/react-sdk-reference/src/FallbackComponent.tsx +1 -1
  79. package/templates/react-sdk-reference/src/MashupApp.tsx +33 -78
  80. package/templates/react-sdk-reference/src/PortalApp.tsx +23 -100
  81. package/templates/react-sdk-reference/src/components/component-map.ts +15 -1
  82. package/templates/react-sdk-reference/src/components/designSystemExtension/AssignmentHeader/AssignmentHeader.tsx +15 -0
  83. package/templates/react-sdk-reference/src/components/designSystemExtension/AssignmentHeader/index.tsx +1 -0
  84. package/templates/react-sdk-reference/src/components/designSystemExtension/FieldGroup/FieldGroup.tsx +1 -1
  85. package/templates/react-sdk-reference/src/components/designSystemExtension/FieldGroupList/FieldGroupList.tsx +1 -1
  86. package/templates/react-sdk-reference/src/components/designSystemExtension/FieldValueList/FieldValueList.tsx +16 -4
  87. package/templates/react-sdk-reference/src/components/designSystemExtension/ModalDialog/ModalDialog.tsx +26 -0
  88. package/templates/react-sdk-reference/src/components/designSystemExtension/ModalDialog/index.tsx +1 -0
  89. package/templates/react-sdk-reference/src/components/designSystemExtension/Toast/Toast.tsx +35 -0
  90. package/templates/react-sdk-reference/src/components/designSystemExtension/Toast/index.tsx +1 -0
  91. package/templates/react-sdk-reference/src/components/field/AutoComplete/AutoComplete.tsx +362 -24
  92. package/templates/react-sdk-reference/src/components/field/CancelAlert/CancelAlert.tsx +1 -1
  93. package/templates/react-sdk-reference/src/components/field/Checkbox/Checkbox.tsx +3 -1
  94. package/templates/react-sdk-reference/src/components/field/Currency/Currency.tsx +6 -3
  95. package/templates/react-sdk-reference/src/components/field/Date/Date.tsx +2 -1
  96. package/templates/react-sdk-reference/src/components/field/DateTime/DateTime.tsx +2 -1
  97. package/templates/react-sdk-reference/src/components/field/Decimal/Decimal.tsx +4 -3
  98. package/templates/react-sdk-reference/src/components/field/Dropdown/Dropdown.tsx +2 -0
  99. package/templates/react-sdk-reference/src/components/field/Email/Email.tsx +2 -1
  100. package/templates/react-sdk-reference/src/components/field/EmbeddedDataMulti/EmbeddedDataMulti.tsx +121 -0
  101. package/templates/react-sdk-reference/src/components/field/EmbeddedDataMulti/config-ext.json +7 -0
  102. package/templates/react-sdk-reference/src/components/field/EmbeddedDataMulti/index.tsx +1 -0
  103. package/templates/react-sdk-reference/src/components/field/Integer/Integer.tsx +2 -1
  104. package/templates/react-sdk-reference/src/components/field/Location/Location.tsx +1 -1
  105. package/templates/react-sdk-reference/src/components/field/Multiselect/Multiselect.tsx +40 -20
  106. package/templates/react-sdk-reference/src/components/field/ObjectReference/ObjectReference.tsx +554 -49
  107. package/templates/react-sdk-reference/src/components/field/ObjectReference/utils.ts +111 -20
  108. package/templates/react-sdk-reference/src/components/field/Percentage/Percentage.tsx +4 -3
  109. package/templates/react-sdk-reference/src/components/field/Phone/Phone.tsx +2 -1
  110. package/templates/react-sdk-reference/src/components/field/SelectableCard/SelectableCard.tsx +2 -1
  111. package/templates/react-sdk-reference/src/components/field/TextArea/TextArea.tsx +2 -1
  112. package/templates/react-sdk-reference/src/components/field/TextInput/TextInput.tsx +2 -1
  113. package/templates/react-sdk-reference/src/components/field/Time/Time.tsx +2 -1
  114. package/templates/react-sdk-reference/src/components/field/URL/URL.tsx +2 -1
  115. package/templates/react-sdk-reference/src/components/field/UserReference/UserReference.tsx +1 -1
  116. package/templates/react-sdk-reference/src/components/helpers/field-utils.ts +44 -0
  117. package/templates/react-sdk-reference/src/components/helpers/simpleTableHelpers.ts +19 -7
  118. package/templates/react-sdk-reference/src/components/infra/ModalViewContainer/DataViewActionButtons/DataViewActionButtons.tsx +97 -0
  119. package/templates/react-sdk-reference/src/components/infra/ModalViewContainer/DataViewActionButtons/index.tsx +1 -0
  120. package/templates/react-sdk-reference/src/components/infra/ModalViewContainer/ListViewActionButtons/ListViewActionButtons.tsx +53 -0
  121. package/templates/react-sdk-reference/src/components/infra/ModalViewContainer/ListViewActionButtons/index.tsx +1 -0
  122. package/templates/react-sdk-reference/src/components/template/AdvancedSearch/SearchGroups/SearchGroups.tsx +2 -2
  123. package/templates/react-sdk-reference/src/components/template/CaseSummary/CaseSummary.tsx +3 -1
  124. package/templates/react-sdk-reference/src/components/template/DataReference/SearchForm.tsx +4 -4
  125. package/templates/react-sdk-reference/src/components/template/HierarchicalForm/HierarchicalForm.tsx +2 -2
  126. package/templates/react-sdk-reference/src/components/template/InlineDashboard/InlineDashboard.tsx +1 -1
  127. package/templates/react-sdk-reference/src/components/template/ListView/ListView.tsx +7 -3
  128. package/templates/react-sdk-reference/src/components/template/SimpleTable/SimpleTableManual/SimpleTableManual.tsx +173 -99
  129. package/templates/react-sdk-reference/src/components/template/SimpleTable/SimpleTableSelect/SimpleTableSelect.tsx +63 -56
  130. package/templates/react-sdk-reference/src/components/widget/ToDo/ToDo.tsx +1 -1
  131. package/templates/react-sdk-reference/vite.config.ts +26 -4
  132. package/templates/react-sdk-reference/.ai-common/instructions/dse-component.md +0 -47
  133. package/templates/react-sdk-reference/.ai-common/instructions/field-component.md +0 -50
  134. package/templates/react-sdk-reference/.ai-common/instructions/infra-component.md +0 -76
  135. package/templates/react-sdk-reference/.ai-common/instructions/template-component.md +0 -43
  136. package/templates/react-sdk-reference/.ai-common/instructions/widget-component.md +0 -45
  137. package/templates/react-sdk-reference/.ai-common/skills/embedded-flow/authenticate.md +0 -311
  138. package/templates/react-sdk-reference/pega-constellationjs-0.26.3-local.tgz +0 -0
  139. package/templates/react-sdk-reference/pega-sdk-react-0.1.0.tgz +0 -0
@@ -0,0 +1,506 @@
1
+ # Skill: EmbeddedDataMulti
2
+
3
+ List of embedded records stored directly on the case — rendered as a table, repeating groups, tabs, or a read-only value list.
4
+
5
+ > **Prerequisite skill:** [`field-components.md`](../field-components.md) — covers architecture, input contract, display modes, event handling, the shared Condition Encoding contract, and registration patterns common to ALL field components.
6
+
7
+ > **Sibling skill:** [`EmbeddedData.md`](./EmbeddedData.md) — the same Pega field type configured to hold a **single** record. It compiles to different node types and different components; see the Node Type Matrix below.
8
+
9
+ ---
10
+
11
+ ## Component Purpose
12
+
13
+ Renders a list of records that is **owned by the case** rather than referenced from elsewhere. An embedded list has no data page behind it: the records live on the case's own page structure. That single fact separates this field type from every reference field, and it removes an entire category of configuration — there is no datasource, no parameters, no search, and no selection of existing records.
14
+
15
+ This component draws no input control of its own. It inspects its configuration, decides which component should present the list, resolves that component from the project's registry, and hands it a derived configuration. Almost everything it does is _deciding_ rather than _drawing_.
16
+
17
+ The surface is large: five presentations, two modes, two edit mechanisms, and two different structures under one configuration key. Read the Rendering Decision Tree as an ordered procedure — several conditions overlap, and the first match wins.
18
+
19
+ ## Pega Metadata
20
+
21
+ - **Pega Name:** `EmbeddedDataMulti`
22
+ - **Type / Subtype:** `Field` / `EmbeddedData`
23
+ - **Registration key:** `EmbeddedDataMulti` (in the project's component map)
24
+ - **Shown in the configuration UI as:** `Embedded Data`, with a subtitle reading "list of records" and naming the target class
25
+
26
+ ### Node Type Matrix
27
+
28
+ One Pega field type compiles to three different node types. The type is **not** carried in a configuration key — it is the node's own type.
29
+
30
+ | Options | Display as | Node type | Component |
31
+ | --------------- | ------------------------------------------------ | ------------------- | ------------------------------------------- |
32
+ | Single record | `Form` | `reference` | none — the runtime's generic reference path |
33
+ | Single record | `Combo-box` | `EmbeddedData` | see the sibling skill |
34
+ | List of records | `Table`, `Repeating view`, and the read-only set | `EmbeddedDataMulti` | **this component** |
35
+
36
+ Establish the node type before reading any configuration key. A node of type `reference` or `EmbeddedData` is not this component's concern, and treating the three as presentation variants of one component produces the wrong component or none.
37
+
38
+ Note also that a field type's presentation control does not always map to a configuration key. Across Pega field types this mechanism varies — some carry the presentation in a `displayAs` key, some in a `componentType` key, and some change the node type itself. Embedded data does **both**. Never generalise one field type's mechanism to another.
39
+
40
+ ### Configuration Surfaces
41
+
42
+ There are **three** separate surfaces, with different lifetimes. Keep them distinct.
43
+
44
+ **Surface 1 — the per-view field dialog.** Settings stored per view, reached from the field within a view. For a list field it offers only: Label, Required, Disabled, Visibility, Test ID. Its Visibility control omits the "if not blank" and "if not zero" conveniences, because a list has no single scalar value to test.
45
+
46
+ **Surface 2 — the field-definition screen.** Settings stored on the field definition, shared by every view that uses the field. This is where the mode, the presentation, and everything associated with them live. Its control set changes completely with the mode and the presentation; see the per-presentation tables below.
47
+
48
+ **Surface 3 — the per-descriptor dialog.** Every entry in a `columns` list has its own dialog. It is the ordinary editable-field dialog — display as, label, edit mode, placeholder, helper text, the three conditions, test id — plus two extras specific to columns: a show-additional-details toggle and a column width. It omits the field-input-warning control that the in-view field dialog offers. Because these are ordinary fields, the whole Condition Encoding contract applies to them recursively.
49
+
50
+ ### Config Keys — always present
51
+
52
+ | Configuration control | Emitted config key(s) | Value shape and notes |
53
+ | ------------------------------------------ | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
54
+ | (platform-emitted) | `pagelistValue` | The path to the case's own list of embedded records. This is the **only** key in the list presentations that keeps its property marker |
55
+ | Display as / Mode | `displayAs` | The presentation — see the Presentation Matrix |
56
+ | Mode | `readOnly` | Present and true when the mode is read-only; absent when editable |
57
+ | (platform-emitted) | `targetObjectClass` | The class of each embedded record. Read it verbatim; never derive or normalise a class name |
58
+ | Label | `label` + `labelOption` | `labelOption` is the default value when the field's own name is kept, and the label is then **plain text with no marker**; it is the custom value when text is supplied, and the label then carries the localization marker. Always render the resolved label; never branch on `labelOption` |
59
+ | Add label | `targetClassLabel` + `targetClassLabelOption` | A display label for the record class, following the same default/custom pattern — but **always carrying the localization marker, in both states**, unlike the field label. There is no separate add-label key; this pair is reused for it, and it supplies the add affordance's caption |
60
+ | Required / Disabled / Visibility / Test ID | `required` / `disabled` / `visibility` / `testId` | See the shared Condition Encoding contract; `testId` is a plain, non-localized string |
61
+
62
+ There is **no** `targetObjectType` key. Embedded data has no data-versus-case distinction, so any logic written for reference fields that branches on such a key does not apply.
63
+
64
+ Equally, there is **no** `referenceList` and **no** `parameters`. A component that goes looking for a datasource will find none. This is the single biggest structural difference from the reference fields, and the easiest thing to get wrong by pattern-matching against them.
65
+
66
+ ### Presentation Matrix
67
+
68
+ The **Mode** control offers editable or read-only, and the **Display as** options depend on it. This asymmetry is important: three presentations exist only in read-only mode.
69
+
70
+ | `displayAs` | Available in | Presents as |
71
+ | --------------- | ------------------- | ------------------------------------------------ |
72
+ | `table` | editable, read-only | A data table, one row per record |
73
+ | `simpleTable` | **read-only only** | A simplified table |
74
+ | `repeatingView` | editable, read-only | A repeated group of fields, one group per record |
75
+ | `readonly` | **read-only only** | A read-only list of one display value per record |
76
+ | `tabs` | **read-only only** | One tab per record, each holding a view |
77
+
78
+ In editable mode the table style is chosen by a **separate** control that emits its own `tableFormat` key; in read-only mode that control disappears and the style becomes a `displayAs` value instead. So the same visual result is encoded two different ways depending on mode.
79
+
80
+ **Rule:** the SDK renders the table and simple-table presentations as one and the same table, so the style distinction is out of scope. Treat `displayAs` values `table` and `simpleTable` identically, and ignore `tableFormat` in every mode. The two keys frequently coexist and can contradict each other, because `tableFormat` is not cleared when the presentation changes — one more reason never to branch on it.
81
+
82
+ A component whose presentation list is derived from the editable mode alone will silently fail on three of the five.
83
+
84
+ ### Config Keys — table presentations (`table` and `simpleTable`)
85
+
86
+ | Configuration control | Emitted config key(s) | Notes |
87
+ | --------------------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
88
+ | Table format | `tableFormat` | Absent for the standard style; a simple value otherwise. Editable mode only — see the rule above |
89
+ | Columns | `columns` | Two incompatible structures under one key — see Column Definitions |
90
+ | Column to take up remaining width | `fillAvailableSpace` on **each** descriptor | Not a field-level key. Once set, every descriptor gains the key, false on all but the chosen one. Absent from all descriptors until the control is touched |
91
+ | Add/edit records in… | `editMode` | A modal value or a table-rows value; the latter means inline row editing |
92
+ | Use View or Action | `editType` | A view value or an action value |
93
+ | View for add/edit | `addEditView` | A view **rule name** |
94
+ | Use separate View for edit | `useSeparateViewForEdit` | Boolean |
95
+ | View for edit modal | `editView` | A view rule name, meaningful only when the separate-view flag is set |
96
+ | User Action | `addEditAction` | An action rule name |
97
+ | Use separate User Action for editing | `useSeparateActionForEdit` | Boolean |
98
+ | (paired with the above) | `editAction` | An action rule name, meaningful only when the separate-action flag is set |
99
+ | (platform-emitted, inline editing only) | `uniqueField` | A bare property path used to give each row an identity — see Row Identity |
100
+
101
+ **A trap in the edit keys.** `editAction` is emitted even when no separate edit action was configured — it simply mirrors `addEditAction`. The same holds for the view form. So the presence of `editView` or `editAction` never means a separate edit target was chosen. Decide from `useSeparateViewForEdit` and `useSeparateActionForEdit`, and fall back to the add/edit target when the flag is not set.
102
+
103
+ ### Config Keys — repeating view presentation
104
+
105
+ | Configuration control | Emitted config key(s) | Notes |
106
+ | --------------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------- |
107
+ | Collapse behavior | `collapseOnLoad` | A none value, an expanded value, or a collapsed value |
108
+ | Record label source | `repeatingViewHeadingSource` | A constant value or a property-reference value |
109
+ | Record label value / Property reference | `repeatingViewHeading` | **One key, two shapes** — see below |
110
+ | Record view | `repeatingView` | A view **rule name** |
111
+ | Start in empty state | `allowEmptyInitialState` | Boolean. When true the list must start with no rows rather than auto-creating a first one |
112
+ | (read-only only) | `repeatingViewHeadingField` | A **single complete field descriptor** for the heading property — see below |
113
+ | (platform-emitted) | `uniqueField` | See Row Identity |
114
+
115
+ **The heading is polymorphic.** The configuration UI shows a free-text box for a constant and a property picker for a property reference, but both write the same key. When the source is the constant value the heading is localized text carrying the localization marker. When the source is the property-reference value the heading is a **bare property path with no marker at all**. Discriminate on `repeatingViewHeadingSource` — never by inspecting the heading string for a marker.
116
+
117
+ When the heading is a property reference, read each record's value for that property, stripping the path's leading separator to get the property name, and fall back to a positional label such as the record's ordinal when a record has no value for it.
118
+
119
+ **The heading descriptor.** In read-only mode with a property-reference heading, an additional key carries a complete field descriptor — a node with its own type and configuration — for the heading property. Its purpose is formatting: a currency or date heading should be rendered through that descriptor rather than emitted as a raw value. It is a single object, not a list. It has not been observed for every property type, so treat it as optional and fall back to the raw value when absent.
120
+
121
+ ### Config Keys — tabs presentation
122
+
123
+ Structurally a parallel of the repeating view, with its own key prefix. Treat the two as one contract with two prefixes rather than implementing them separately.
124
+
125
+ | Configuration control | Emitted config key(s) | Notes |
126
+ | ------------------------------------ | ----------------------- | ----------------------------------------------------------------------- |
127
+ | Tab orientation | `tabsOrientation` | Absent for horizontal; a vertical value otherwise |
128
+ | Tab label source | `tabsViewHeadingSource` | A constant value or a property-reference value |
129
+ | Tab label value / Property reference | `tabsViewHeading` | Same two shapes as the repeating view heading, same discrimination rule |
130
+ | Tab view | `tabsView` | A view **rule name** |
131
+ | (platform-emitted) | `uniqueField` | See Row Identity |
132
+
133
+ A heading descriptor key by analogy with the repeating view has **not** been observed here. Render the raw heading value when none is present.
134
+
135
+ ### Config Keys — read-only field presentation
136
+
137
+ The smallest presentation. It carries only `displayField` — a **bare** property path, no marker — naming the single property to show for each record. No columns are emitted at all, not even the system column described under Row Identity.
138
+
139
+ ### Conditions
140
+
141
+ Two groups, and the distinction between them is not cosmetic.
142
+
143
+ | Group | Configuration control | Key | Options |
144
+ | ------------ | ---------------------- | ---------------- | ------------------------------------------- |
145
+ | Field-level | Allow adding | `allowAdd` | never, always, custom condition, When Rule |
146
+ | Field-level | Allow editing | `allowEdit` | the same four |
147
+ | Field-level | Allow deleting | `allowDelete` | the same four |
148
+ | Field-level | Allow row re-ordering | `allowDragDrop` | the same four; **table presentations only** |
149
+ | Record-level | Allow deleting records | `allowRowDelete` | never, always, custom condition — **three** |
150
+ | Record-level | Allow editing records | `allowRowEdit` | never, always, custom condition — **three** |
151
+
152
+ Field-level settings follow the ordinary Condition Encoding contract and arrive resolved to a boolean. **Record-level settings do not** — they are the exception described in the prerequisite skill. They govern an individual record, must be read from the raw configuration, and must be evaluated per record. The When-Rule option is absent from them for exactly that reason.
153
+
154
+ All six default to allowed and emit no key at that default. Choosing never emits an explicit false. In read-only mode the whole conditions surface disappears and **all six keys are cleared** — so their absence must never be read as "allowed" when the field is read-only. State the precedence plainly: read-only wins over every allow setting.
155
+
156
+ ### Raw and Resolved Configuration
157
+
158
+ The runtime hands the component its inputs after replacing every marker with its current value, and a property-reference marker becomes _the current value of that property_. That is right for text and conditions, and wrong for anything that names a property, a view or a column.
159
+
160
+ - Read from the **resolved inputs**: `label`, `readOnly`, `displayMode`, `hideLabel`, `testId`, and the field-level allow settings, which arrive resolved.
161
+ - Read from the **raw configuration**, `getPConnect().getRawMetadata().config`: `pagelistValue`, `columns`, `displayAs`, `displayField`, `uniqueField`, every edit-target key, every heading key, `targetObjectClass`, `targetClassLabel`, and the record-level conditions `allowRowEdit` and `allowRowDelete`, which must stay unresolved so they can be evaluated per record. Every value in Child Construction is read here.
162
+
163
+ Hand markers on to the child unchanged: the child is built with `getPConnect().createComponent`, and the runtime resolves its configuration against the child's own context.
164
+
165
+ ### Annotation Prefixes
166
+
167
+ The markers the raw configuration can carry:
168
+
169
+ A **property reference** marker points at a property. A **localization** marker precedes user-facing text. A **locale reference** marker identifies the view's localization bundle. A **field label** marker resolves a property's configured label. A **user reference** marker identifies an operator-valued property. An **associated datasource** marker points at an associated list. A **field metadata** marker points at a field's own metadata. An **attachment** marker identifies an attachment-valued property. A **class context** marker names a class. An **expression** marker precedes a computed condition. A **When Rule** marker names a decision rule.
170
+
171
+ Three rules about markers, all of which were observed to break naive assumptions:
172
+
173
+ **Marker use is level-dependent.** Keys consumed directly by this component are emitted bare — the display field, the row heading when it is a property reference, and the unique field. Only `pagelistValue` keeps its marker. Keys inside nested descriptors, which the runtime resolves as ordinary fields, do carry markers. Never normalise one rule across both levels, and never test for a marker to decide what a value means.
174
+
175
+ **A marked value may be empty.** A localization or field-label marker followed by nothing at all is a real, observed value. Handle it as empty text rather than as the literal marker.
176
+
177
+ **The same setting may be marked in one payload and plain in another.** A column's label has been observed both as already-resolved plain text and as a field-label marker pointing at the property, with the identical label option in both cases — and both shapes coexisting within one payload. Pass column descriptors through unchanged and let the table resolve each label; make no assumption about which shape produced it.
178
+
179
+ Finally: wherever a configuration picker shows a friendly description — of a view, a decision rule, or a class — the stored value is the underlying **rule name**. The two are unrelated strings. Do not assume a naming convention either: within one payload, one view's stored name matched its displayed label exactly while another's did not.
180
+
181
+ ### Preview Metadata Hazards
182
+
183
+ View metadata captured from the configuration UI is _preview_ metadata and substitutes placeholder values. Two consequences matter here, because tooling that discovers components by walking view metadata will read placeholders as real.
184
+
185
+ **Placeholder property paths are named for a field type, not a field.** Two different column descriptors of the same type therefore share one identical bound path, distinguished only by their labels. Never use a bound path as an identity, a key, or a de-duplication criterion for descriptors.
186
+
187
+ **A placeholder path is not even stable for one field.** The same property has been observed emitting different placeholder paths depending on how its presentation was configured, with extra deferred-loading keys appearing and disappearing alongside.
188
+
189
+ ### Key Lifecycle Rules
190
+
191
+ This field type clears keys inconsistently, and five distinct behaviours have been observed — often several within a single change:
192
+
193
+ 1. A control that disappears may leave its key behind carrying the old value.
194
+ 2. A control that disappears may instead have its key cleared.
195
+ 3. Both happen in the **same** transition. Switching presentation has been seen to clear seven keys while leaving another untouched, with no way to predict which.
196
+ 4. A key cleared by one change may reappear later carrying a **re-seeded default** rather than the value last configured for it — so a deliberate configuration can be silently replaced by a default.
197
+ 5. Keys may be re-seeded even for controls that are not visible in the current mode.
198
+
199
+ One key in particular has been observed surviving nine consecutive presentation changes, including several in which its control did not exist.
200
+
201
+ The single rule that follows: **decide which settings are active from the mode and `displayAs` — never from key presence, and never from a key's value.**
202
+
203
+ ### Generation Rules
204
+
205
+ 1. Establish the node type before anything else. This component handles only the list node type; the two single-record node types belong to the sibling skill or to the runtime.
206
+ 2. Never read a datasource or parameters. Embedded records live on the case.
207
+ 3. Read the list binding from `pagelistValue`, and remember it is the only list key that keeps its marker.
208
+ 4. Handle all five `displayAs` values, including the three that exist only in read-only mode. Do not pass an unmapped presentation name to the registry — an unresolved name degrades to a blank render rather than raising an error.
209
+ 5. Treat the table and simple-table presentations as one: ignore `tableFormat` and `fillAvailableSpace`.
210
+ 6. Honour the per-presentation active-key set. Ignore any key whose control does not exist in the current presentation, however plausible its value.
211
+ 7. Support both shapes of `columns`, and resolve a referenced view by name when the second shape appears.
212
+ 8. Render every column descriptor through the component registry using the descriptor's own type. Descriptors are ordinary fields with their own full configuration, and may themselves be reference or embedded fields.
213
+ 9. Honour the hidden flag on a column descriptor. Some columns are generated by the platform and must never be displayed.
214
+ 10. Treat field-level and record-level conditions differently, per the prerequisite skill. Read record-level ones from the raw configuration and evaluate them per record.
215
+ 11. Apply mode precedence: while the field is read-only, ignore every allow setting and every edit-target setting, present or absent.
216
+ 12. Implement the settings listed under Implementation Status rather than reproducing the gaps.
217
+ 13. Confirm every registry dependency exists before relying on it — see Registry Dependency Prerequisite.
218
+
219
+ ## Inputs (component-specific)
220
+
221
+ > Extends the project's field input contract but omits `value`, because a list field has no single bound scalar.
222
+
223
+ For every input below, an absent value means the stated default. An empty string means the setting was never given a value and must be treated exactly like an absent one. A key belonging to a presentation other than the active one is stale and must be ignored regardless of its value.
224
+
225
+ | Input | Type | Default | Description |
226
+ | ---------------------------- | -------------------- | ---------- | ---------------------------------------------------------------------------------------- |
227
+ | `getPConnect` | `any` | — | The PConnect accessor |
228
+ | `pagelistValue` | `string` | — | Marked path to the case's list of embedded records |
229
+ | `displayAs` | `string` | — | The presentation; see the Presentation Matrix |
230
+ | `readOnly` | `boolean` (optional) | `false` | True when the mode is read-only |
231
+ | `targetObjectClass` | `string` | — | Class of each embedded record |
232
+ | `targetClassLabel` | `string` (optional) | — | Display label for that class, already resolved; also supplies the add-affordance caption |
233
+ | `targetClassLabelOption` | `string` (optional) | default | Informational only |
234
+ | `tableFormat` | `string` (optional) | — | Table style; editable mode only, and frequently stale |
235
+ | `columns` | `array` (optional) | — | Either descriptors or a single view reference — see Column Definitions |
236
+ | `uniqueField` | `string` (optional) | — | Bare property path giving each record an identity |
237
+ | `displayField` | `string` (optional) | — | Bare property path; the read-only field presentation only |
238
+ | `editMode` | `string` (optional) | — | Modal or inline row editing |
239
+ | `editType` | `string` (optional) | — | View-driven or action-driven |
240
+ | `addEditView` | `string` (optional) | — | View rule name for add and edit |
241
+ | `editView` | `string` (optional) | — | View rule name for edit; meaningful only with the separate-view flag |
242
+ | `useSeparateViewForEdit` | `boolean` (optional) | `false` | |
243
+ | `addEditAction` | `string` (optional) | — | Action rule name for add and edit |
244
+ | `editAction` | `string` (optional) | — | Action rule name for edit; meaningful only with the separate-action flag |
245
+ | `useSeparateActionForEdit` | `boolean` (optional) | `false` | |
246
+ | `collapseOnLoad` | `string` (optional) | none | Repeating view — none, expanded, or collapsed |
247
+ | `repeatingView` | `string` (optional) | — | Repeating view — view rule name for each group |
248
+ | `repeatingViewHeading` | `string` (optional) | — | Repeating view — localized text or a bare property path |
249
+ | `repeatingViewHeadingSource` | `string` (optional) | — | Repeating view — which shape the heading takes |
250
+ | `repeatingViewHeadingField` | `object` (optional) | — | Repeating view, read-only — a field descriptor for formatting the heading |
251
+ | `allowEmptyInitialState` | `boolean` (optional) | `false` | Repeating view — start with no rows |
252
+ | `tabsOrientation` | `string` (optional) | horizontal | Tabs — absent for horizontal |
253
+ | `tabsView` | `string` (optional) | — | Tabs — view rule name for each tab |
254
+ | `tabsViewHeading` | `string` (optional) | — | Tabs — localized text or a bare property path |
255
+ | `tabsViewHeadingSource` | `string` (optional) | — | Tabs — which shape the heading takes |
256
+ | `allowAdd` | `boolean` (optional) | `true` | Field-level; already-resolved boolean |
257
+ | `allowEdit` | `boolean` (optional) | `true` | Field-level; already-resolved boolean |
258
+ | `allowDelete` | `boolean` (optional) | `true` | Field-level; already-resolved boolean |
259
+ | `allowDragDrop` | `boolean` (optional) | `true` | Field-level; table presentations only |
260
+ | `allowRowDelete` | `any` (optional) | `true` | **Record-level — unresolved.** Read from raw configuration; evaluate per record |
261
+ | `allowRowEdit` | `any` (optional) | `true` | **Record-level — unresolved.** Read from raw configuration; evaluate per record |
262
+ | `label` | `string` (optional) | `''` | Already resolved |
263
+ | `labelOption` | `string` (optional) | default | Informational only |
264
+ | `required` | `boolean` (optional) | `false` | Already-resolved boolean |
265
+ | `disabled` | `boolean` (optional) | `false` | Already-resolved boolean |
266
+ | `visibility` | `boolean` (optional) | `true` | Already-resolved boolean; the component is normally not rendered at all when false |
267
+ | `hideLabel` | `boolean` (optional) | `false` | |
268
+ | `testId` | `string` (optional) | `''` | Test identifier |
269
+ | `displayMode` | `string` (optional) | — | Supplied by the surrounding view; a display-only value forces a read-only presentation |
270
+
271
+ ## Implementation Structure
272
+
273
+ An orchestrator. It resolves one presenting component, derives a configuration for it, and renders it inside a single full-width container. It draws no control of its own.
274
+
275
+ ### Registry Dependency Prerequisite
276
+
277
+ > **Check this before writing the component.** Because this component only orchestrates others, it cannot work unless its dependencies are already generated and registered.
278
+
279
+ Tooling that discovers components by walking a case's view metadata will not find most of these, because they never appear there as fields — they are building blocks reached for at runtime. A discovery-driven generation pass can therefore produce this component while silently omitting everything it depends on, and a registry lookup that finds nothing degrades to a blank render rather than raising an error.
280
+
281
+ The registry keys this component reaches for: the table router (`SimpleTable`), the manually-fed editable table it delegates to (`SimpleTableManual`), the repeating-group template (`FieldGroupTemplate`) and the two design-system components beneath it (`FieldGroup` and `FieldGroupList`), and the modal container together with its action buttons for the add-and-edit flow. The table and group components are template components; their skills live alongside the template skills rather than the field skills, and `FieldGroup` and `FieldGroupList` live with the design-system-extension skills.
282
+
283
+ The dependency is **transitive**. Every column descriptor is rendered through the registry using its own type, so any field type appearing in a configured column is also a dependency — including reference fields and other embedded fields. Enumerate the descriptor types actually present in your metadata and check those too.
284
+
285
+ Before finishing: confirm each required key is registered or was generated earlier in the session; generate and register anything missing from its own skill file; only then wire up the lookups.
286
+
287
+ **Module Setup:** The component depends on the project's component registry, on the platform APIs listed below, and on a local helper that resolves a primary-fields view and merges its descriptors into a column list. Define the input contract as an extension of the project's field input contract, omitting `value` and adding every input in the table above.
288
+
289
+ **Main Component Logic** — in order:
290
+
291
+ 1. **Registry lookups.** Resolve the presenting components you may need. See the prerequisite above.
292
+ 2. **Receive inputs,** each defaulted as documented. Read the **raw** configuration as well: several keys must be consumed unresolved, and if the raw configuration is unavailable the component should render nothing rather than a broken table.
293
+ 3. **Derive the render mode** from `readOnly` and from the surrounding view's display mode — a read-only mode and an editable mode.
294
+ 4. **Derive a context path** from `pagelistValue` by stripping its marker, and a name from that path by stripping its leading separator.
295
+ 5. **Resolve the presentation** by following the Rendering Decision Tree.
296
+ 6. **Build the child configuration** as described under Child Construction, create the child with `getPConnect().createComponent`, and render it inside a single full-width container.
297
+
298
+ ## Behavioral Contract
299
+
300
+ ### Rendering decision tree
301
+
302
+ Evaluate in this order and stop at the first match.
303
+
304
+ 1. **The surrounding view is display-only, or the field is read-only.** Force a read-only render mode, and ignore every allow setting and every edit-target setting from here on. Then continue into the presentation tests — read-only affects the mode, not the choice of presentation.
305
+ 2. **Repeating view presentation.** Build a region holding a reference to the view named by `repeatingView`, and render the repeating-group template. Supply the resolved list, the heading contract described below, the collapse behaviour, and the empty-initial-state flag.
306
+ 3. **Tabs presentation.** As above but with the tabs key prefix, rendering one tab per record, each containing the view named by `tabsView`, laid out according to `tabsOrientation`.
307
+ 4. **Read-only field presentation.** Render one value per record, taking the property named by `displayField`. No columns participate.
308
+ 5. **Table or simple-table presentation.** Create the table child described under Child Construction, which wraps `columns` as a region named `Columns` and hands over the resolved list, the render mode, the edit configuration and the allow settings. Both values render the same manually-fed table: `tableFormat` and `fillAvailableSpace` are out of scope and must be ignored.
309
+
310
+ A presentation value outside this set must not be passed to the registry unchanged. Map it to something you provide, or render nothing — an unmatched name resolves to no component and produces a silent blank.
311
+
312
+ ### Child Construction
313
+
314
+ The table and repeating-view presentations are not rendered directly. Create one child with `getPConnect().createComponent`, a node of type `View` whose configuration asks for the `SimpleTable` template; the runtime resolves that configuration for the child, and the table router then chooses the table or the repeating group. Every value below is read from the **raw** configuration, `getPConnect().getRawMetadata().config`; render nothing when it is unavailable.
315
+
316
+ The node's configuration holds:
317
+
318
+ - `template` set to `SimpleTable`, and `type` set to `multirecordlist`;
319
+ - `authorContext` set to `pagelistValue` with its property-reference marker removed — `@P .Expenses` becomes `.Expenses` — and `name` set to that path without its leading separator;
320
+ - `referenceList` set to the raw `pagelistValue`, marker included, so the child receives the resolved list of records;
321
+ - `renderMode` set to `ReadOnly` or `Editable`, from the Rendering Decision Tree;
322
+ - `multiRecordDisplayAs` and `displayAs` both set to `fieldGroup` for the repeating view, and otherwise to `displayAs` unchanged;
323
+ - `contextClass` set to `targetObjectClass`, and `label`, `displayField`, `uniqueField`, `targetClassLabel` and `targetClassLabelOption`;
324
+ - `editMode`, and `editModeConfig` holding `editType`, `defaultView` set to `addEditView`, `defaultAction` set to `addEditAction`, `useSeparateViewForEdit`, `useSeparateActionForEdit`, `editView` and `editAction`;
325
+ - `fieldHeader` set to `repeatingViewHeadingSource`, and `heading` set to `repeatingViewHeading`;
326
+ - `allowActions` holding `allowAdd`, `allowEdit`, `allowDelete` and `allowDragDrop`, each true when absent; and `allowRowDelete` and `allowRowEdit`, each true when absent and otherwise passed raw, so an expression-marked row condition reaches the table unresolved and is evaluated per row;
327
+ - for the table and simple-table presentations only, `children` holding one region named `Columns` whose children are the raw `columns`, unchanged.
328
+
329
+ For the repeating view only, the node itself gets one child: a region named `view` holding a reference node whose configuration has `type` set to `view` and `name` set to `repeatingView`.
330
+
331
+ The table router renders the repeating-group template for `fieldGroup`, and otherwise the manually-fed table. It hides the add, delete and edit affordances whose allow flag is false, and passes the row-level edit flag through. See the SimpleTable skill for what the manually-fed table does with each of these values.
332
+
333
+ The tabs and read-only-field presentations have no branch in the table router: sent there, they fall through to the manually-fed table. Implement them as this skill describes instead of creating the `View` node for them.
334
+
335
+ ### Column definitions
336
+
337
+ The name `columns` denotes two incompatible structures, plus a system-generated entry that can appear in either.
338
+
339
+ | Shape | Where it appears | How to consume it |
340
+ | ---------------------------------------------------- | ------------------------------------------------ | --------------------------------------------------- |
341
+ | A single view reference naming a primary-fields view | The default state, before columns are configured | Resolve the named view and use its descriptors |
342
+ | A list of component descriptors | Once columns are configured explicitly | Render each through the registry using its own type |
343
+
344
+ Configuring columns explicitly replaces the first shape with the second **and removes the referenced view from the payload**. Both shapes must be supported under the same key.
345
+
346
+ **Resolving the primary-fields reference.** The reference entry carries both a name and a value, and both hold the same view name. The **value** is the lookup key — locate the entry whose value matches the primary-fields view name, allowing for a namespace-qualified form of that name as well. Resolve that view by name, select the returned view whose class matches the embedded record's class — the resolution may return more than one — and take the descriptors from its first region. Splice them into the column list in place of the reference entry, then de-duplicate the combined list by each descriptor's bound path.
347
+
348
+ **A caution about filtering.** A reference implementation filters primary-fields descriptors against a fixed list of supported field types and silently discards anything outside it, while leaving explicitly configured columns unfiltered. That asymmetry means a column can vanish with no error depending only on how it was configured. Do not reproduce it; render every descriptor through the registry and let an unregistered type be the thing you report.
349
+
350
+ **The system-generated hidden column.** When records need an identity — see Row Identity — the platform prepends a column descriptor carrying a hidden flag, a property bound to the record identity, and its own type. It never appears in the configuration UI. Honour the hidden flag: this column must not be displayed. It appears even in presentations that display no columns at all, so the presence of a `columns` list never implies a table presentation.
351
+
352
+ ### Row identity
353
+
354
+ A `uniqueField` key naming a bare property path is emitted whenever individual records need to be identified — that is, for inline row editing, for the repeating view, and for the tabs presentation. It is **absent** when records are added and edited through a modal, because the modal commits a whole record at a time.
355
+
356
+ When it is present, generate a fresh identifier for that property on each newly inserted record, and include it in the instructions sent to the store. The platform's system-generated hidden column carries the same property.
357
+
358
+ ### Add, edit, and delete
359
+
360
+ The flow depends on `editMode`.
361
+
362
+ **Modal.** When `editType` is the view value, open a modal containing the view named by `addEditView` for a new record, and — when `useSeparateViewForEdit` is set — the view named by `editView` for an existing one. When `editType` is the action value, do the same with `addEditAction` and `editAction`. In both cases, indicate whether the modal is creating or updating. The modal's own footer commits or discards through the platform's embedded-data modal actions; do not write the record directly.
363
+
364
+ **Inline row editing.** Insert an empty record at the end of the list, generating a record identity as described above, and render the row's cells as editable controls.
365
+
366
+ **Deletion and reordering** act on the list directly through the platform's list actions, addressed by index.
367
+
368
+ The add affordance's caption is built from `targetClassLabel` — an "add" verb followed by the class label. When no class label is available, use the verb alone.
369
+
370
+ ### Repeating view and tabs — one contract, two prefixes
371
+
372
+ Both present one view per record and share an identical key structure. Implement them once, parameterised by prefix.
373
+
374
+ For each record: determine the group or tab label. When the heading source is the constant value, use the heading as localized text, the same for every record. When it is the property-reference value, read that property from the record, stripping the path's leading separator, and fall back to a positional label when the record has no value. When a heading descriptor is present, render the value through it so that typed values are formatted; otherwise render the raw value.
375
+
376
+ For the repeating view specifically: when the list is empty and adding is allowed, a first record is normally created automatically so the user has something to fill in — but `allowEmptyInitialState` reverses that, and must be honoured. In a read-only render mode, present each record as a static group and do not offer add or delete affordances.
377
+
378
+ ### View references and loading
379
+
380
+ Three mechanisms reference another view, and they differ in whether that view arrives with the payload.
381
+
382
+ | Mechanism | Referenced view delivered? | Resolution |
383
+ | ----------------------------------------------- | -------------------------------------------- | ------------------------------- |
384
+ | `repeatingView` and `tabsView` | yes, together with everything they reference | eagerly, from the payload |
385
+ | A primary-fields view referenced from `columns` | yes | eagerly, by name |
386
+ | `addEditView` and `editView` | **no** | on demand, when the modal opens |
387
+
388
+ So the add and edit modal views are the only deferred ones. Everything else is present in the payload and can be resolved without a fetch.
389
+
390
+ ## Worked Traces
391
+
392
+ Three walkthroughs. Each names the active keys, the resolved presenting component, and what is handed down.
393
+
394
+ **Table with a modal driven by a view.** `displayAs` is the table value and the field is editable. Active keys: `pagelistValue`, `columns`, `editMode`, `editType`, `addEditView`, `useSeparateViewForEdit`, `editView`, `tableFormat`, the four field-level allow settings, the two record-level ones, and `targetClassLabel`. There is no `uniqueField` — records are committed whole through the modal. Resolve the list by stripping the marker from `pagelistValue`. If `columns` holds a view reference, resolve that view by name and use its descriptors; otherwise render the descriptors directly. Render the table with an add affordance captioned from `targetClassLabel`, opening the view named by `addEditView`. Use `editView` for editing **only** if the separate-view flag is set — otherwise reuse `addEditView`, because `editView` is emitted regardless. Evaluate the two record-level settings per record from the raw configuration. Ignore any `repeatingView` or tabs keys that happen to be present; they belong to other presentations.
395
+
396
+ **Repeating view, editable, with a constant record label.** `displayAs` is the repeating-view value. Active keys: `pagelistValue`, `repeatingView`, `repeatingViewHeading`, `repeatingViewHeadingSource`, `collapseOnLoad`, `allowEmptyInitialState`, `uniqueField`, the three field-level allow settings that remain, the two record-level ones, and a `columns` list containing only the system hidden column. There is no `allowDragDrop` — that control does not exist for this presentation. Build a region holding a reference to the view named by `repeatingView` and render the repeating-group template. Because the heading source is the constant value, every group carries the same localized label. Generate an identity for `uniqueField` on each inserted record. Honour `allowEmptyInitialState` rather than auto-creating a first record. Ignore `tableFormat` if present; it is stale.
397
+
398
+ **Read-only tabs with a property-reference label.** `displayAs` is the tabs value and `readOnly` is true. Active keys: `pagelistValue`, `readOnly`, `tabsView`, `tabsViewHeading`, `tabsViewHeadingSource`, `tabsOrientation`, `uniqueField`, and a `columns` list containing only the system hidden column. Force the read-only render mode and ignore every allow setting — all six were cleared, and their absence does not mean "allowed". Render one tab per record, each containing the view named by `tabsView`, laid out per `tabsOrientation`. Because the heading source is the property-reference value, read each record's value for the bare path in `tabsViewHeading` and use it as that tab's label, falling back to a positional label where a record has no value. Render no columns — the only entry is hidden. Ignore `displayField` and `tableFormat` if present; both are stale here, and `tableFormat` in particular has been observed surviving many unrelated changes.
399
+
400
+ ## Display Mode Rendering
401
+
402
+ Display mode reaches this component from the surrounding view and is not the same thing as the field's own read-only mode. Either forces a read-only presentation, and both must be checked.
403
+
404
+ Once a read-only render mode is established it propagates to the presenting component, which is responsible for suppressing every affordance that would change data. This component contributes nothing of its own beyond setting the mode and withholding the edit configuration.
405
+
406
+ Read-only is also the only mode in which three of the five presentations exist at all.
407
+
408
+ ## Visual Specifications
409
+
410
+ This component contributes only a single full-width container holding one child. Everything visible is produced by the presenting component.
411
+
412
+ | Property | Value |
413
+ | ---------- | ------------------------------------------------ |
414
+ | Container | Full width, single column, no padding of its own |
415
+ | Appearance | Entirely delegated to the presenting component |
416
+
417
+ The presentations themselves map as follows, with detailed specifications living in the corresponding template skills: a table presentation is a data table with one row per record and affordances for add, edit, delete, and reorder; a simplified table is the same with reduced chrome; a repeating view is a stack of labelled, optionally collapsible groups; a tabs presentation is a tab strip, horizontal or vertical, each tab holding a full view; a read-only field presentation is a plain list of values.
418
+
419
+ ## Edge Cases & Special Logic
420
+
421
+ - **There is no datasource.** Any logic that looks for a data page or parameters is inapplicable.
422
+ - **`pagelistValue` is the only key that keeps its marker.** Everything else consumed directly by this component is bare.
423
+ - **The presence of `columns` does not imply a table.** Every presentation that needs record identity carries a system hidden column in that list.
424
+ - **The same visual result has two encodings.** A simple table is a `displayAs` value in read-only mode and a `tableFormat` value in editable mode.
425
+ - **`editView` and `editAction` are always emitted.** Their presence never means a separate edit target was configured.
426
+ - **Stale keys are pervasive and look valid.** One key has been observed surviving nine consecutive presentation changes, including several where its control did not exist.
427
+ - **A cleared key may return as a default,** not as the value previously configured. A key's value is as untrustworthy as its presence.
428
+ - **Read-only clears every allow setting,** so their absence must not be read as "allowed". Apply read-only precedence explicitly rather than relying on defaults — defaulting an absent allow setting to true would otherwise re-enable every affordance in a read-only field.
429
+ - **Record-level conditions are not resolved.** Typing them as booleans loses per-record behaviour; truthiness-checking them makes the action always available.
430
+ - **`allowDragDrop` does not exist for the repeating view.** Its control is absent there and the key is cleared.
431
+ - **An empty marked string is a real value.** Treat it as empty text.
432
+ - **A missing registry entry degrades silently.** An omitted dependency looks like a styling problem, not an error.
433
+ - **The configuration is read from the component's own raw metadata,** which several presentations then modify before handing it on. Derive a fresh configuration for the child rather than modifying shared metadata in place.
434
+
435
+ ## Implementation Status
436
+
437
+ Some settings the configuration UI can produce are not honoured by the reference implementation. They are genuine options, so **implement them** rather than reproducing the gap.
438
+
439
+ | Setting or presentation | Reference behaviour | What a generated component should do |
440
+ | --------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------- |
441
+ | `readonly` presentation | Falls through to the table path and renders a table | Render one value per record from `displayField` |
442
+ | `tabs` presentation | Falls through to the table path and renders an empty table | Render one tab per record, honouring orientation and the heading contract |
443
+ | `collapseOnLoad` | Not read, although a collapse mechanism exists elsewhere in the project | Wire the existing collapse behaviour to this key |
444
+ | `allowEmptyInitialState` | Not read; a first record is always created when the list is empty | Suppress the automatic first record when the flag is set |
445
+ | `repeatingViewHeadingField` | Not read; headings render as raw values | Render the heading through the descriptor so typed values are formatted |
446
+ | Primary-fields filtering | Descriptors outside a fixed type list are silently discarded | Render every descriptor; report an unregistered type instead of dropping it |
447
+
448
+ ## Dependencies
449
+
450
+ > Every registry dependency must be generated and registered before this component can render — see Registry Dependency Prerequisite.
451
+
452
+ - The project's component registry, resolving the table router, the manually-fed table, the repeating-group template and its two design-system components, the modal container and its action buttons, and the type of every column descriptor present in the metadata.
453
+ - A local helper that resolves a primary-fields view and merges its descriptors into a column list.
454
+ - The Pega Platform APIs listed below.
455
+
456
+ ## Pega Platform APIs
457
+
458
+ All of these are reached through the global `PCore` object, which the SDK runtime installs before any component renders. Never import them from a package — read them off `PCore` at the point of use.
459
+
460
+ **`PCore.getAnnotationUtils().getPropertyName(value)`** — takes a marker-prefixed property path and returns the bare property name. Use it wherever a stored path must become a property name, instead of trimming a marker yourself.
461
+
462
+ **`PCore.getMetadataUtils().resolveView(viewName)`** — takes a view name and returns that view's metadata, which may be a single view or a list of views for different classes. Used to resolve a primary-fields view referenced from `columns`; when a list is returned, select the entry whose class matches the embedded record's class.
463
+
464
+ **`PCore.getNameSpaceUtils().getDefaultQualifiedName(name)`** — takes a view name and returns its namespace-qualified form. A primary-fields reference may carry either form, so compare against both.
465
+
466
+ **`PCore.getExpressionEngine().evaluate(expression, recordData)`** — takes an expression with its marker removed, and the data of a single record. Returns a boolean. This is how a record-level condition is applied per record. Treat a failure as permitting the action rather than blocking it.
467
+
468
+ **`getPConnect().getListActions()`** — provides the list operations: inserting a record at an index, deleting an entry by index, reordering entries, and initialising the default instructions for a list. All of them address the list resolved from `pagelistValue`.
469
+
470
+ **`getPConnect().getActionsApi().openEmbeddedDataModal(...)`** — opens the add-or-edit modal. It takes the view to show, the component's own accessor, the resolved list path, the index at which the record sits, whether the operation is a creation or an update, the class label, the edit type, and the action identifier when the flow is action-driven.
471
+
472
+ **`getPConnect().getActionsApi().submitEmbeddedDataModal(context)`** and **`getPConnect().getActionsApi().cancelDataObject(context)`** — commit or discard the record being edited in that modal. Both take the current context name.
473
+
474
+ **`getPConnect().getRawMetadata()`** and **`getPConnect().getComponentConfig()`** — return the component's configuration **before** markers are resolved. Required for the keys that must be consumed unresolved: the record-level conditions, and the column descriptors whose bound paths are needed as property names.
475
+
476
+ **`getPConnect().createComponent(...)`** — builds the presenting child from a derived configuration. The context name, the page reference, and the change handler all come from the PConnect accessor rather than from `PCore`.
477
+
478
+ ## Design System Mapping
479
+
480
+ **UI control type:** Embedded record list — an orchestrator that delegates to a table, a group list, a tab strip, or a value list.
481
+
482
+ When implementing in a specific design system, map the following:
483
+
484
+ - **Table and simple-table presentations** → a data table with per-row affordances for edit and delete, a list-level add affordance, and drag handles when reordering is allowed
485
+ - **Repeating view presentation** → a stack of labelled groups, collapsible when the collapse behaviour requests it, each group holding a full view, with add and delete affordances in the editable mode
486
+ - **Tabs presentation** → the design system's tab strip, oriented horizontally or vertically, one tab per record
487
+ - **Read-only field presentation** → the design system's read-only value display, one value per record
488
+ - **Add affordance caption** → an "add" verb combined with the resolved class label
489
+ - **Container** → a plain full-width wrapper; add no styling of your own
490
+
491
+ ## Generation Self-Check
492
+
493
+ Before considering the component finished, confirm each of the following.
494
+
495
+ - The node type is established before any presentation logic, and only the list node type is handled here.
496
+ - No datasource or parameter lookup exists anywhere in the component.
497
+ - All five `displayAs` values are handled, including the three that exist only in read-only mode, and none is passed to the registry unchanged.
498
+ - The table and simple-table presentations produce the same child, and neither `tableFormat` nor `fillAvailableSpace` is read.
499
+ - Both shapes of `columns` are supported, a primary-fields view is resolved by its value key and matched on class, and the hidden flag is honoured.
500
+ - Column descriptors are rendered through the registry by their own type, with no type-based filtering.
501
+ - Record identity is generated for every presentation that carries `uniqueField`.
502
+ - The separate-view and separate-action flags decide the edit target, not the presence of `editView` or `editAction`.
503
+ - Field-level and record-level conditions are handled differently, and record-level ones are evaluated per record from the raw configuration.
504
+ - Read-only precedence is applied explicitly, overriding every allow setting whether present or absent.
505
+ - The heading contract is implemented once and shared by the repeating view and the tabs presentation.
506
+ - Every registry key the component reaches for is registered, including the types of all column descriptors.