@pega/custom-dx-components 26.1.11 → 26.1.12-alpha.0.2

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 (323) hide show
  1. package/README.md +6 -2
  2. package/package.json +48 -64
  3. package/src/ai/README.md +44 -0
  4. package/src/ai/catalog/README.md +133 -0
  5. package/src/ai/catalog/best-practices/README.md +24 -0
  6. package/src/ai/catalog/best-practices/accessibility-for-async-components.md +53 -0
  7. package/src/ai/catalog/best-practices/error-handling-and-resiliency.md +116 -0
  8. package/src/ai/catalog/best-practices/genai-assistant-integration-patterns.md +49 -0
  9. package/src/ai/catalog/best-practices/performance-and-efficiency.md +109 -0
  10. package/src/ai/catalog/best-practices/security-considerations.md +93 -0
  11. package/src/ai/catalog/best-practices/testing-pconnect-components.md +245 -0
  12. package/src/ai/catalog/best-practices/troubleshooting-common-pitfalls.md +132 -0
  13. package/src/ai/catalog/pconnect-assignment-lifecycle/SKILL.md +44 -0
  14. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/README.md +39 -0
  15. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/approval-workflow-decision.md +47 -0
  16. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/attachment-upload.md +45 -0
  17. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/bulk-action-submit.md +50 -0
  18. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/confirm-before-destructive-action.md +43 -0
  19. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/create-and-stage-new-case.md +45 -0
  20. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/graceful-submit-failure.md +39 -0
  21. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/modal-assignment-submit.md +58 -0
  22. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/multi-step-wizard.md +44 -0
  23. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/resolve-or-ignore-duplicate.md +47 -0
  24. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/safe-case-deletion.md +36 -0
  25. package/src/ai/catalog/pconnect-case-collaboration/SKILL.md +42 -0
  26. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/README.md +36 -0
  27. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/look-up-user-details.md +43 -0
  28. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/manage-case-attachments.md +51 -0
  29. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/manage-case-participants.md +52 -0
  30. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/participant-and-follower.md +40 -0
  31. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/post-and-manage-feed.md +50 -0
  32. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/relate-cases.md +35 -0
  33. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/tag-case-and-find-related.md +44 -0
  34. package/src/ai/catalog/pconnect-data-subscriptions/SKILL.md +42 -0
  35. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/README.md +35 -0
  36. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/data-page-subscription-cleanup.md +41 -0
  37. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/publish-and-subscribe-events.md +40 -0
  38. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/pubsub-cleanup.md +38 -0
  39. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/query-paginated-list-data.md +44 -0
  40. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/realtime-case-subscription.md +46 -0
  41. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/refresh-and-update-data.md +41 -0
  42. package/src/ai/catalog/pconnect-forms-and-fields/SKILL.md +44 -0
  43. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/README.md +36 -0
  44. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/autosave-tracking.md +45 -0
  45. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/cascading-dependent-fields.md +51 -0
  46. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/collect-form-changes-for-manual-save.md +45 -0
  47. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/custom-field-validators.md +44 -0
  48. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/discard-changes-and-reset-form.md +41 -0
  49. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/full-form-validation.md +38 -0
  50. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/persist-widget-ui-state.md +41 -0
  51. package/src/ai/catalog/pconnect-lists-and-views/SKILL.md +44 -0
  52. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/README.md +35 -0
  53. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/activate-and-switch-container-items.md +52 -0
  54. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/container-item-lifecycle.md +61 -0
  55. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/insert-delete-list-rows.md +40 -0
  56. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/reorder-list-rows.md +39 -0
  57. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/repeating-row-edit.md +39 -0
  58. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/view-personalization.md +60 -0
  59. package/src/ai/catalog/pconnect-navigation-locale-genai/SKILL.md +45 -0
  60. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/README.md +35 -0
  61. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/agent-conversation-for-tasks.md +54 -0
  62. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/bookmarkable-filter-state.md +40 -0
  63. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/deep-link-semantic-url.md +39 -0
  64. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/genai-assistant-conversation.md +43 -0
  65. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/locale-switch-and-relocalize.md +38 -0
  66. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/persist-operator-preferences.md +40 -0
  67. package/src/ai/catalog/references/architecture-overview.md +52 -0
  68. package/src/ai/catalog/references/pconnect-actions-api.md +948 -0
  69. package/src/ai/catalog/references/pconnect-case-info-data-info-localization.md +618 -0
  70. package/src/ai/catalog/references/pconnect-case-validation-utilities.md +238 -0
  71. package/src/ai/catalog/references/pconnect-container-manager.md +215 -0
  72. package/src/ai/catalog/references/pconnect-list-actions.md +250 -0
  73. package/src/ai/catalog/references/pconnect-misc-suggestions-creation.md +231 -0
  74. package/src/ai/catalog/references/pconnect-reference-context-component.md +471 -0
  75. package/src/ai/catalog/references/pconnect-state-config.md +316 -0
  76. package/src/ai/catalog/references/pconnect-validation-api.md +45 -0
  77. package/src/ai/catalog/references/pcore-analytics-genai-details.md +50 -0
  78. package/src/ai/catalog/references/pcore-bootstrap-init-details.md +121 -0
  79. package/src/ai/catalog/references/pcore-bootstrap-registry-routing.md +253 -0
  80. package/src/ai/catalog/references/pcore-case-collaboration-details.md +191 -0
  81. package/src/ai/catalog/references/pcore-case-collaboration-genai.md +264 -0
  82. package/src/ai/catalog/references/pcore-environment-info-details.md +96 -0
  83. package/src/ai/catalog/references/pcore-environment-locale-namespace.md +175 -0
  84. package/src/ai/catalog/references/pcore-messaging-details.md +99 -0
  85. package/src/ai/catalog/references/pcore-misc-details.md +207 -0
  86. package/src/ai/catalog/references/pcore-misc-utilities.md +325 -0
  87. package/src/ai/catalog/references/pcore-rest-data-details.md +164 -0
  88. package/src/ai/catalog/references/pcore-rest-data-messaging.md +308 -0
  89. package/src/ai/catalog/references/pcore-store-context-details.md +40 -0
  90. package/src/ai/catalog/references/pcore-store-context-state.md +130 -0
  91. package/src/ai/index.js +154 -0
  92. package/src/ai/project/.claude/skills/boolean/SKILL.md +43 -0
  93. package/src/ai/project/.claude/skills/case/SKILL.md +58 -0
  94. package/src/ai/project/.claude/skills/create-dx-component/SKILL.md +98 -0
  95. package/src/ai/project/.claude/skills/create-dx-component/assets/PConnProps.d.ts +24 -0
  96. package/src/ai/project/.claude/skills/create-dx-component/assets/create-nonce.ts +5 -0
  97. package/src/ai/project/.claude/skills/create-dx-component/assets/event-utils.ts +18 -0
  98. package/src/ai/project/.claude/skills/create-dx-component/assets/styles.ts +7 -0
  99. package/src/ai/project/.claude/skills/create-dx-component/cookbooks/README.md +28 -0
  100. package/src/ai/project/.claude/skills/create-dx-component/cookbooks/build-a-data-widget.md +281 -0
  101. package/src/ai/project/.claude/skills/create-dx-component/cookbooks/field-with-limits-and-validation.md +156 -0
  102. package/src/ai/project/.claude/skills/create-dx-component/cookbooks/status-badge-field.md +97 -0
  103. package/src/ai/project/.claude/skills/create-dx-component/references/accessibility.md +71 -0
  104. package/src/ai/project/.claude/skills/create-dx-component/references/choosing-type-and-subtype.md +79 -0
  105. package/src/ai/project/.claude/skills/create-dx-component/references/cli-workflow.md +125 -0
  106. package/src/ai/project/.claude/skills/create-dx-component/references/component-patterns.md +241 -0
  107. package/src/ai/project/.claude/skills/create-dx-component/references/config-schema.md +296 -0
  108. package/src/ai/project/.claude/skills/create-dx-component/references/cosmos-components.md +137 -0
  109. package/src/ai/project/.claude/skills/create-dx-component/references/field-behavior.md +155 -0
  110. package/src/ai/project/.claude/skills/create-dx-component/references/field-essentials.md +90 -0
  111. package/src/ai/project/.claude/skills/create-dx-component/references/field-subtypes-extra.md +68 -0
  112. package/src/ai/project/.claude/skills/create-dx-component/references/localization.md +30 -0
  113. package/src/ai/project/.claude/skills/create-dx-component/references/pcore-pconnect-apis.md +77 -0
  114. package/src/ai/project/.claude/skills/create-dx-component/references/presentation-essentials.md +57 -0
  115. package/src/ai/project/.claude/skills/create-dx-component/references/props-contract.md +182 -0
  116. package/src/ai/project/.claude/skills/create-dx-component/references/state-matrix.md +102 -0
  117. package/src/ai/project/.claude/skills/create-dx-component/references/storybook-pattern.md +262 -0
  118. package/src/ai/project/.claude/skills/create-dx-component/references/styles-pattern.md +54 -0
  119. package/src/ai/project/.claude/skills/create-dx-component/references/template-essentials.md +87 -0
  120. package/src/ai/project/.claude/skills/create-dx-component/references/template-patterns.md +131 -0
  121. package/src/ai/project/.claude/skills/create-dx-component/references/test-pattern.md +215 -0
  122. package/src/ai/project/.claude/skills/create-dx-component/references/ui-gallery-reuse.md +93 -0
  123. package/src/ai/project/.claude/skills/create-dx-component/references/widget-essentials.md +84 -0
  124. package/src/ai/project/.claude/skills/create-dx-component/references/widget-patterns.md +164 -0
  125. package/src/ai/project/.claude/skills/currency/SKILL.md +46 -0
  126. package/src/ai/project/.claude/skills/date/SKILL.md +46 -0
  127. package/src/ai/project/.claude/skills/decimal/SKILL.md +49 -0
  128. package/src/ai/project/.claude/skills/details/SKILL.md +60 -0
  129. package/src/ai/project/.claude/skills/email/SKILL.md +42 -0
  130. package/src/ai/project/.claude/skills/field/SKILL.md +68 -0
  131. package/src/ai/project/.claude/skills/form/SKILL.md +51 -0
  132. package/src/ai/project/.claude/skills/generate-component-set/SKILL.md +80 -0
  133. package/src/ai/project/.claude/skills/generate-component-set/component-manifest.json +161 -0
  134. package/src/ai/project/.claude/skills/identify-components/SKILL.md +76 -0
  135. package/src/ai/project/.claude/skills/integer/SKILL.md +45 -0
  136. package/src/ai/project/.claude/skills/page/SKILL.md +60 -0
  137. package/src/ai/project/.claude/skills/page-widget/SKILL.md +55 -0
  138. package/src/ai/project/.claude/skills/percentage/SKILL.md +52 -0
  139. package/src/ai/project/.claude/skills/phone/SKILL.md +44 -0
  140. package/src/ai/project/.claude/skills/picklist/SKILL.md +50 -0
  141. package/src/ai/project/.claude/skills/plan-dx-component/SKILL.md +51 -0
  142. package/src/ai/project/.claude/skills/plan-dx-component/references/design-system-mapping.md +108 -0
  143. package/src/ai/project/.claude/skills/plan-dx-component/references/intake.md +146 -0
  144. package/src/ai/project/.claude/skills/plan-dx-component/references/plan-template.md +76 -0
  145. package/src/ai/project/.claude/skills/plan-dx-component/references/requirements-template.md +88 -0
  146. package/src/ai/project/.claude/skills/presentation/SKILL.md +61 -0
  147. package/src/ai/project/.claude/skills/publish-library/SKILL.md +106 -0
  148. package/src/ai/project/.claude/skills/radiobuttons/SKILL.md +51 -0
  149. package/src/ai/project/.claude/skills/review-component/SKILL.md +49 -0
  150. package/src/ai/project/.claude/skills/review-component/references/checklist.md +77 -0
  151. package/src/ai/project/.claude/skills/template/SKILL.md +60 -0
  152. package/src/ai/project/.claude/skills/text/SKILL.md +45 -0
  153. package/src/ai/project/.claude/skills/update-dx-component/SKILL.md +56 -0
  154. package/src/ai/project/.claude/skills/update-dx-component/references/maintenance.md +43 -0
  155. package/src/ai/project/.claude/skills/url/SKILL.md +46 -0
  156. package/src/ai/project/.claude/skills/validate-component/SKILL.md +78 -0
  157. package/src/ai/project/.claude/skills/validate-component/references/runtime-troubleshooting.md +56 -0
  158. package/src/ai/project/.claude/skills/validate-component/scripts/check-component.mjs +327 -0
  159. package/src/ai/project/.claude/skills/widget/SKILL.md +59 -0
  160. package/src/ai/project/.gemini/settings.json +5 -0
  161. package/src/ai/project/AGENTS.md +74 -0
  162. package/src/ai/readme-section.md +91 -0
  163. package/src/cli.js +48 -7
  164. package/src/constants.js +54 -53
  165. package/src/internal-tests.js +27 -0
  166. package/src/tasks/ai-toggle/index.js +46 -0
  167. package/src/tasks/authenticate/helper.js +38 -38
  168. package/src/tasks/authenticate/index.js +17 -15
  169. package/src/tasks/build-all/helper.js +4 -4
  170. package/src/tasks/build-all/index.js +7 -7
  171. package/src/tasks/build-comp/helper.js +17 -17
  172. package/src/tasks/build-comp/index.js +10 -10
  173. package/src/tasks/build-jest-assets/index.js +7 -9
  174. package/src/tasks/build-lib/helper.js +8 -8
  175. package/src/tasks/build-lib/index.js +8 -8
  176. package/src/tasks/bundle/builder/index.js +9 -12
  177. package/src/tasks/bundle/builder/modules.js +8 -9
  178. package/src/tasks/bundle/builder/paths.js +2 -19
  179. package/src/tasks/bundle/builder/webpack.config.js +60 -77
  180. package/src/tasks/bundle/index.js +8 -8
  181. package/src/tasks/create/index.js +35 -35
  182. package/src/tasks/create/templates/Constellation/Field/Boolean/index.tsx.mustache +1 -36
  183. package/src/tasks/create/templates/Constellation/Field/Date/date.ts.mustache +2 -2
  184. package/src/tasks/create/templates/Constellation/Field/Date/index.tsx.mustache +2 -27
  185. package/src/tasks/create/templates/Constellation/Field/DateTime/date-utils.ts.mustache +2 -2
  186. package/src/tasks/create/templates/Constellation/Field/DateTime/date.ts.mustache +2 -2
  187. package/src/tasks/create/templates/Constellation/Field/DateTime/index.tsx.mustache +2 -35
  188. package/src/tasks/create/templates/Constellation/Field/Decimal/index.tsx.mustache +3 -36
  189. package/src/tasks/create/templates/Constellation/Field/Decimal-Currency/index.tsx.mustache +4 -39
  190. package/src/tasks/create/templates/Constellation/Field/Decimal-Percentage/index.tsx.mustache +4 -53
  191. package/src/tasks/create/templates/Constellation/Field/Icon-Button-URL/index.tsx.mustache +5 -5
  192. package/src/tasks/create/templates/Constellation/Field/Integer/index.tsx.mustache +3 -36
  193. package/src/tasks/create/templates/Constellation/Field/Picklist/index.tsx.mustache +7 -42
  194. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/component-constants.ts +1 -1
  195. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/date.ts.mustache +0 -2
  196. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/embed-utils.ts.mustache +1 -1
  197. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/index.tsx.mustache +11 -11
  198. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/repeat-utils.ts.mustache +3 -13
  199. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/textformat-utils.tsx.mustache +2 -3
  200. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/utils.ts.mustache +28 -28
  201. package/src/tasks/create/templates/Constellation/Field/Picklist-RadioButtons/index.tsx.mustache +2 -2
  202. package/src/tasks/create/templates/Constellation/Field/Picklist-RadioButtons/textformat-utils.tsx.mustache +2 -3
  203. package/src/tasks/create/templates/Constellation/Field/Text/index.tsx.mustache +4 -33
  204. package/src/tasks/create/templates/Constellation/Field/Text-Email/index.tsx.mustache +3 -33
  205. package/src/tasks/create/templates/Constellation/Field/Text-Input/index.tsx.mustache +3 -31
  206. package/src/tasks/create/templates/Constellation/Field/Text-Paragraph/index.tsx.mustache +3 -31
  207. package/src/tasks/create/templates/Constellation/Field/Text-Phone/index.tsx.mustache +3 -35
  208. package/src/tasks/create/templates/Constellation/Field/Text-URL/index.tsx.mustache +3 -33
  209. package/src/tasks/create/templates/Constellation/Field/Text-URL/text-url.tsx.mustache +2 -3
  210. package/src/tasks/create/templates/Constellation/Field/TimeofDay/index.tsx.mustache +2 -35
  211. package/src/tasks/create/templates/Constellation/Field/TimeofDay/time-of-day.ts.mustache +2 -2
  212. package/src/tasks/create/templates/Constellation/Template/DETAILS/Avatar.tsx.mustache +19 -15
  213. package/src/tasks/create/templates/Constellation/Template/DETAILS/Operator.tsx.mustache +6 -6
  214. package/src/tasks/create/templates/Constellation/Template/DETAILS/demo.stories.tsx.mustache +1 -1
  215. package/src/tasks/create/templates/Constellation/Template/DETAILS/index.tsx.mustache +4 -8
  216. package/src/tasks/create/templates/Constellation/Template/DETAILS/mock.ts.mustache +9 -9
  217. package/src/tasks/create/templates/Constellation/Template/DETAILS/utils.js.mustache +4 -8
  218. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/Avatar.tsx.mustache +19 -15
  219. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/Operator.tsx.mustache +6 -6
  220. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/demo.stories.tsx.mustache +1 -1
  221. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/index.tsx.mustache +1 -1
  222. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/mock.ts.mustache +9 -9
  223. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/utils.ts.mustache +4 -8
  224. package/src/tasks/create/templates/Constellation/Template/FORM/demo.stories.tsx.mustache +8 -8
  225. package/src/tasks/create/templates/Constellation/Template/FORM-region/demo.stories.tsx.mustache +8 -8
  226. package/src/tasks/create/templates/Constellation/Template/PAGE/utils.ts.mustache +4 -9
  227. package/src/tasks/create/templates/Constellation/Widget/CASE/demo.test.tsx.mustache +3 -3
  228. package/src/tasks/create/templates/Constellation/Widget/PAGE-CASE/Avatar.tsx.mustache +19 -14
  229. package/src/tasks/create/templates/Constellation/Widget/PAGE-CASE/Operator.tsx.mustache +6 -6
  230. package/src/tasks/create/templates/Constellation/Widget/PAGE-CASE/index.tsx.mustache +1 -1
  231. package/src/tasks/create/templates/Constellation/Widget/PAGE-CASE/mock.ts.mustache +1 -1
  232. package/src/tasks/create/templates/Launchpad/Field/Icon-Button-URL/index.tsx.mustache +5 -5
  233. package/src/tasks/create/templates/Launchpad/Field/Text-Phone/index.tsx.mustache +3 -35
  234. package/src/tasks/create/templates/Launchpad/Field/__components.md +1 -1
  235. package/src/tasks/create/templates/Launchpad/Template/FORM/demo.stories.tsx.mustache +8 -8
  236. package/src/tasks/create/templates/Launchpad/Template/FORM-region/demo.stories.tsx.mustache +8 -8
  237. package/src/tasks/create/templates/Launchpad/Widget/CASE/demo.test.tsx.mustache +3 -3
  238. package/src/tasks/create/templates/Launchpad/Widget/PAGE-CASE/index.tsx.mustache +1 -1
  239. package/src/tasks/create/templates/Launchpad/Widget/PAGE-CASE/mock.ts.mustache +1 -1
  240. package/src/tasks/create-all/index.js +42 -41
  241. package/src/tasks/create-lib/helper.js +13 -13
  242. package/src/tasks/create-lib/index.js +5 -5
  243. package/src/tasks/create-version/helper.js +10 -10
  244. package/src/tasks/create-version/index.js +3 -4
  245. package/src/tasks/delete/helper.js +20 -19
  246. package/src/tasks/delete/index.js +2 -2
  247. package/src/tasks/delete-all/helper.js +26 -25
  248. package/src/tasks/delete-all/index.js +2 -2
  249. package/src/tasks/delete-lib/helper.js +6 -6
  250. package/src/tasks/delete-lib/index.js +6 -6
  251. package/src/tasks/delete-pub/helper.js +18 -18
  252. package/src/tasks/delete-pub/index.js +8 -8
  253. package/src/tasks/delete-version/index.js +2 -2
  254. package/src/tasks/dev-server/index.js +1 -1
  255. package/src/tasks/export-archive/helper.js +21 -21
  256. package/src/tasks/export-archive/index.js +27 -40
  257. package/src/tasks/export-rc/helper.js +34 -34
  258. package/src/tasks/export-rc/index.js +21 -31
  259. package/src/tasks/import-archive/helper.js +39 -39
  260. package/src/tasks/import-archive/index.js +69 -89
  261. package/src/tasks/import-comp/helper.js +8 -8
  262. package/src/tasks/import-comp/index.js +30 -42
  263. package/src/tasks/index.js +5 -0
  264. package/src/tasks/init/Node.gitignore +149 -0
  265. package/src/tasks/init/helper.js +15 -8
  266. package/src/tasks/init/index.js +115 -35
  267. package/src/tasks/init/template/.prettierrc.json +4 -1
  268. package/src/tasks/init/template/.storybook/main.ts +1 -4
  269. package/src/tasks/init/template/.storybook/manager.ts +1 -1
  270. package/src/tasks/init/template/.storybook/preview.tsx +2 -2
  271. package/src/tasks/init/template/.storybook/theme.js +1 -1
  272. package/src/tasks/init/template/.vscode/extensions.json +0 -1
  273. package/src/tasks/init/template/README.md +2 -2
  274. package/src/tasks/init/template/eslint.config.mjs +13 -155
  275. package/src/tasks/init/template/jest.config.cjs +2 -0
  276. package/src/tasks/init/template/package-lock.json +26864 -0
  277. package/src/tasks/init/template/package.json.mustache +19 -74
  278. package/src/tasks/init/template/setupTests.ts +10 -4
  279. package/src/tasks/init/template/tsconfig.json +14 -6
  280. package/src/tasks/internal-test/index.js +21 -0
  281. package/src/tasks/internal-test-full/index.js +15 -0
  282. package/src/tasks/internal-test-functional/index.js +15 -0
  283. package/src/tasks/internal-test-unit/index.js +13 -0
  284. package/src/tasks/linter/index.js +2 -2
  285. package/src/tasks/list/helper.js +41 -40
  286. package/src/tasks/list/index.js +3 -3
  287. package/src/tasks/list-lib/helper.js +5 -5
  288. package/src/tasks/list-lib/index.js +8 -8
  289. package/src/tasks/list-pub/helper.js +23 -16
  290. package/src/tasks/list-pub/index.js +24 -21
  291. package/src/tasks/move/helper.js +8 -8
  292. package/src/tasks/move/index.js +19 -23
  293. package/src/tasks/promote-webpack/index.js +4 -4
  294. package/src/tasks/promote-webpack/webpack.config.js +62 -93
  295. package/src/tasks/publish/helper.js +21 -21
  296. package/src/tasks/publish/index.js +16 -16
  297. package/src/tasks/publish-all/helper.js +20 -20
  298. package/src/tasks/publish-all/index.js +11 -12
  299. package/src/tasks/publish-archive/helper.js +9 -9
  300. package/src/tasks/publish-archive/index.js +12 -14
  301. package/src/tasks/publish-lib/helper.js +3 -3
  302. package/src/tasks/publish-lib/index.js +28 -34
  303. package/src/tasks/quarantine/index.js +8 -8
  304. package/src/tasks/rename/index.js +26 -30
  305. package/src/tasks/rename-lib/index.js +21 -25
  306. package/src/tasks/restore/index.js +8 -8
  307. package/src/tasks/restore-config/index.js +3 -5
  308. package/src/tasks/set-perm/index.js +8 -8
  309. package/src/tasks/show-help/index.js +17 -9
  310. package/src/tasks/show-status/index.js +2 -2
  311. package/src/tasks/store/index.js +8 -8
  312. package/src/tasks/switch-lib/helper.js +7 -7
  313. package/src/tasks/switch-lib/index.js +7 -7
  314. package/src/tasks/switch-version/helper.js +6 -6
  315. package/src/tasks/switch-version/index.js +7 -7
  316. package/src/tasks/update/index.js +1 -1
  317. package/src/tasks/upgrade/index.js +7 -7
  318. package/src/tasks/validator/index.js +49 -203
  319. package/src/util.js +169 -186
  320. package/src/rules/no-pcore-pconnect-in-presentation.js +0 -103
  321. package/src/tasks/init/template/.stylelintrc.json +0 -4
  322. package/src/tasks/init/template/babel.config.cjs +0 -22
  323. package/src/tasks/init/template/cspell.json +0 -14
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: Publish a custom application-wide event for other components to react to
3
+ keywords: [event bus, publish, custom event, cross-component communication, broadcast]
4
+ primary_methods: [PubSubUtils.publish, PubSubUtils.subscribeOnce]
5
+ related: [pubsub-cleanup]
6
+ ---
7
+
8
+ # Recipe: Publish a custom application-wide event for other components to react to
9
+
10
+ > Part of the [Data Subscriptions & Real-time cookbook](./README.md) — [skill overview](../SKILL.md).
11
+
12
+ ## Problem
13
+
14
+ A component completes an action (for example, "review submitted") that several unrelated components elsewhere in the page need to react to, without wiring them together directly through props or a shared parent.
15
+
16
+ ## Solution
17
+
18
+ Uses `PCore.getPubSubUtils()` (see [pcore-messaging-details.md](../../references/pcore-messaging-details.md)). This is the publisher side of the pattern documented from the subscriber side in [Publish/subscribe between unrelated components, with cleanup](./pubsub-cleanup.md).
19
+
20
+ ```typescript
21
+ const CUSTOM_EVENT = 'my-app:review-submitted';
22
+
23
+ // Publisher — fires after the action completes.
24
+ function onReviewSubmitted(caseID) {
25
+ PCore.getPubSubUtils().publish(CUSTOM_EVENT, { caseID });
26
+ }
27
+
28
+ // A subscriber that only needs to react the next time this happens, not every time.
29
+ PCore.getPubSubUtils().subscribeOnce(CUSTOM_EVENT, ({ caseID }) => refreshSummaryPanel(caseID), 'summary-panel-once');
30
+ ```
31
+
32
+ ## Discussion
33
+
34
+ **SHOULD** namespace custom event names (for example, `my-app:review-submitted`) rather than a bare string like `reviewSubmitted` — `PubSubUtils` is a single, application-wide bus shared by every component, and an unnamespaced string can collide with another component's event.
35
+
36
+ **MUST** use `subscribeOnce` (not `subscribe` followed by a manual `unsubscribe` inside the handler) when a listener genuinely only needs to fire one time — it self-removes after the first invocation, which is easy to get wrong by hand.
37
+
38
+ ## Related recipes
39
+
40
+ - [Publish/subscribe between unrelated components, with cleanup](./pubsub-cleanup.md)
@@ -0,0 +1,38 @@
1
+ ---
2
+ title: Publish/subscribe between unrelated components, with cleanup
3
+ keywords: [event bus, publish, subscribe, cross-component communication, orphaned handler]
4
+ primary_methods: [PubSubUtils.subscribe, PubSubUtils.unsubscribe, Events.getCaseEvent]
5
+ related: [data-page-subscription-cleanup, cascading-dependent-fields]
6
+ ---
7
+
8
+ # Recipe: Publish/subscribe between unrelated components, with cleanup
9
+
10
+ > Part of the [Data Subscriptions & Real-time cookbook](./README.md) — [skill overview](../SKILL.md).
11
+
12
+ ## Problem
13
+
14
+ Two components that don't share a parent/child relationship need to communicate through an application-wide event, without leaving a stale handler registered after either unmounts.
15
+
16
+ ## Solution
17
+
18
+ Uses `PCore.getPubSubUtils()` (see [pcore-messaging-details.md](../../references/pcore-messaging-details.md)).
19
+
20
+ ```typescript
21
+ useEffect(() => {
22
+ const { subscribe, unsubscribe } = PCore.getPubSubUtils();
23
+ const handlerName = 'my-widget-stage-listener';
24
+
25
+ subscribe(PCore.getEvents().getCaseEvent().CREATE_STAGE_DONE, onStageCreated, handlerName);
26
+
27
+ return () => unsubscribe(PCore.getEvents().getCaseEvent().CREATE_STAGE_DONE, handlerName);
28
+ }, []);
29
+ ```
30
+
31
+ ## Discussion
32
+
33
+ **MUST** use the same `name` for `subscribe`/`unsubscribe`. **NEVER** mismatch them (for example, unsubscribing with a different string) — doing so silently leaves the original handler active.
34
+
35
+ ## Related recipes
36
+
37
+ - [Subscribe to a data page and clean up on unmount](./data-page-subscription-cleanup.md)
38
+ - [Register cascading/dependent fields and clean them up](../../pconnect-forms-and-fields/cookbooks/cascading-dependent-fields.md)
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Query a paginated, filterable list data view
3
+ keywords: [list query, pagination, filter, sort, data view, search results]
4
+ primary_methods: [DataApiUtils.getData, DataApiUtils.getListCount, DataApiUtils.getDataViewMetadata]
5
+ related: [refresh-and-update-data]
6
+ ---
7
+
8
+ # Recipe: Query a paginated, filterable list data view
9
+
10
+ > Part of the [Data Subscriptions & Real-time cookbook](./README.md) — [skill overview](../SKILL.md).
11
+
12
+ ## Problem
13
+
14
+ A grid/table needs to fetch a page of results from a list data view with filters and sorting applied, show a total record count for the pager, and know which columns are filterable/sortable ahead of rendering filter controls.
15
+
16
+ ## Solution
17
+
18
+ Uses `PCore.getDataApiUtils()` (see [pcore-rest-data-details.md](../../references/pcore-rest-data-details.md)).
19
+
20
+ ```typescript
21
+ const { getData, getListCount, getDataViewMetadata } = PCore.getDataApiUtils();
22
+
23
+ // Render filter controls from the data view's own field metadata rather than hardcoding column config.
24
+ const metadata = await getDataViewMetadata('D_CaseSearchResults', context);
25
+
26
+ const payload = {
27
+ paging: { pageSize: 20, pageNumber: 1 },
28
+ sortBy: [{ field: 'pxCreateDateTime', direction: 'DESC' }],
29
+ filters: [{ field: 'pyStatusWork', operator: 'IN', values: ['Open'] }]
30
+ };
31
+
32
+ const { data } = await getData('D_CaseSearchResults', payload, context);
33
+ const { data: count } = await getListCount('D_CaseSearchResults', payload, context);
34
+ ```
35
+
36
+ ## Discussion
37
+
38
+ **SHOULD** call `getDataViewMetadata` once (and cache the result) to discover which fields are actually queryable/sortable, rather than assuming every visible column supports server-side filtering — an unsupported filter field is silently ignored by some data views rather than raising an error.
39
+
40
+ **MUST** pass the identical `payload` (filters and paging) to both `getData` and `getListCount` — a mismatched payload returns a total count that doesn't correspond to the rows actually shown, breaking the pager.
41
+
42
+ ## Related recipes
43
+
44
+ - [Force-refresh a stale cached data page on demand](./refresh-and-update-data.md)
@@ -0,0 +1,46 @@
1
+ ---
2
+ title: Subscribe to real-time case updates pushed from the server
3
+ keywords: [WebSocket, server push, real-time update, live case status, messaging service]
4
+ primary_methods:
5
+ [MessagingServiceManager.subscribe, MessagingServiceManager.unsubscribe, MessagingServiceManager.getCaseSubscription]
6
+ related: [pubsub-cleanup, data-page-subscription-cleanup]
7
+ ---
8
+
9
+ # Recipe: Subscribe to real-time case updates pushed from the server
10
+
11
+ > Part of the [Data Subscriptions & Real-time cookbook](./README.md) — [skill overview](../SKILL.md).
12
+
13
+ ## Problem
14
+
15
+ A component needs to reflect another user's changes to the same case in near-real-time (for example, a live "someone else updated this case" banner), which requires a server-pushed message rather than a purely local, same-tab event.
16
+
17
+ ## Solution
18
+
19
+ Uses `MessagingServiceManager` (via `PCore.getMessagingServiceManager()`, see [pcore-messaging-details.md](../../references/pcore-messaging-details.md)).
20
+
21
+ ```typescript
22
+ useEffect(() => {
23
+ const manager = PCore.getMessagingServiceManager();
24
+
25
+ // The filter is { matcher, criteria }: 'CASE' with the case ID selects server pushes for that case.
26
+ // caseID is the case ID string (the same value as pConn.getCaseSummary().caseID; the typedef examples use
27
+ // 'Approval-Request A-101'). Do not use getCaseSummary().ID: that is the assignment ID.
28
+ const subscriptionId = manager.subscribe(
29
+ { matcher: 'CASE', criteria: { caseId: caseID } },
30
+ (payload: unknown) => showLiveUpdateBanner(payload),
31
+ pConn.getContextName()
32
+ );
33
+
34
+ // subscribe returns the subscription id (a string), not an unsubscribe function.
35
+ return () => manager.unsubscribe(subscriptionId);
36
+ }, [caseID]);
37
+ ```
38
+
39
+ ## Discussion
40
+
41
+ `MessagingServiceManager` is a distinct transport from `PubSubUtils`: this `subscribe` reacts to server-pushed WebSocket messages describing changes made in other sessions, while `PubSubUtils.subscribe` (see [Publish/subscribe between unrelated components](./pubsub-cleanup.md)) only reacts to events published locally within the same browser tab. **NEVER** expect `PubSubUtils` to notice another user's edit. **MUST** apply the same unsubscribe-on-unmount discipline here — an orphaned `MessagingServiceManager` subscription keeps a live socket handler registered for a component that no longer exists.
42
+
43
+ ## Related recipes
44
+
45
+ - [Publish/subscribe between unrelated components, with cleanup](./pubsub-cleanup.md)
46
+ - [Subscribe to a data page and clean up on unmount](./data-page-subscription-cleanup.md)
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Force-refresh a stale cached data page on demand
3
+ keywords: [refresh, stale cache, cache invalidation, force reload, refresh button]
4
+ primary_methods: [DataPageUtils.markDataInstanceDirty, DataPageUtils.getDataAsync]
5
+ related: [data-page-subscription-cleanup]
6
+ ---
7
+
8
+ # Recipe: Force-refresh a stale cached data page on demand
9
+
10
+ > Part of the [Data Subscriptions & Real-time cookbook](./README.md) — [skill overview](../SKILL.md).
11
+
12
+ ## Problem
13
+
14
+ A component caches a data page result, but the user clicks an explicit "Refresh" affordance (or the component knows the underlying data changed some other way) and needs the next read to hit the server instead of returning the cached value.
15
+
16
+ ## Solution
17
+
18
+ Uses `PCore.getDataPageUtils()` (see [pcore-rest-data-details.md](../../references/pcore-rest-data-details.md)).
19
+
20
+ ```typescript
21
+ async function onRefreshClick(dataPageName, parameters, context) {
22
+ const { markDataInstanceDirty, getDataAsync } = PCore.getDataPageUtils();
23
+
24
+ // Marks the cached instance stale; it does NOT itself trigger a re-fetch.
25
+ markDataInstanceDirty(dataPageName, parameters);
26
+
27
+ // The next getDataAsync call — with the same parameters — now goes to the server instead of the cache.
28
+ const refreshed = await getDataAsync(dataPageName, context, parameters);
29
+ return refreshed;
30
+ }
31
+ ```
32
+
33
+ ## Discussion
34
+
35
+ **MUST** call `getDataAsync` (or otherwise re-request the page) after `markDataInstanceDirty` — marking a page dirty does not by itself cause any subscriber to re-render with new data; it only changes what the _next_ fetch returns.
36
+
37
+ **MUST** pass the exact same `parameters` to `markDataInstanceDirty` and the follow-up `getDataAsync` call — the cache key includes parameters, so marking one parameter combination dirty does not invalidate a differently-parameterized cached instance of the same data page.
38
+
39
+ ## Related recipes
40
+
41
+ - [Subscribe to a data page and clean up on unmount](./data-page-subscription-cleanup.md)
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: pconnect-forms-and-fields
3
+ description: "Reference catalog and cookbook for PCore/PConnect APIs governing form and field behavior — FormUtils, CascadeManager, AutosaveUtils, NavigationUtils component state, and ValidationApi — with recipes for full-form validation before submit, cascading/dependent fields, autosave status tracking, persisting a custom widget's UI state across navigation, collecting changed/submittable data for a manual save, discarding changes and resetting a form, and registering a custom cross-field validator. Use when you need the exact signature for these APIs, or the correct order to call them to validate, cascade, or persist form/field state."
4
+ user-invocable: true
5
+ argument-hint: "Use when validating a whole form, wiring cascading/dependent fields, tracking autosave status, or persisting a custom widget's UI state across navigation — for the exact FormUtils/CascadeManager/AutosaveUtils/NavigationUtils signature, or the correct call order."
6
+ metadata:
7
+ verified-against: 'latest 26.x'
8
+ ---
9
+
10
+ # Forms & Field Behavior — PCore/PConnect Skill
11
+
12
+ This skill covers the PCore/PConnect APIs and recipes for **form and field behavior**: whole-form validation, cascading/dependent fields, autosave tracking, and persisting custom widget UI state. It is one of the PCore/PConnect API skills — see the [skills index](../README.md) for the full method catalog, architecture primer, and the other five skills.
13
+
14
+ ## When to Use This Skill
15
+
16
+ Load this skill when:
17
+
18
+ - You need the exact parameters, return type, or purpose of a `FormUtils`, `CascadeManager`, `AutosaveUtils`, or `NavigationUtils` (component state) method.
19
+ - You're disabling/enabling a Submit button based on whole-form validity and dirty state, rather than a single field.
20
+ - You're wiring one field's change to reset or reload a dependent field, or tracking/notifying autosave status.
21
+ - You're persisting a custom component's UI state (for example, a selected tab) across navigation/unmount.
22
+
23
+ If your task is actually about submitting or deleting the assignment/case itself, see [pconnect-assignment-lifecycle](../pconnect-assignment-lifecycle/SKILL.md) instead.
24
+
25
+ New to PCore/PConnect? Start with [Architecture at a Glance](../references/architecture-overview.md).
26
+
27
+ ## Key Reference Files
28
+
29
+ | File | Class(es) | Obtained via |
30
+ | ------------------------------------------------------------------------------------ | ----------------------------------------------- | --------------------------- |
31
+ | [../references/pcore-misc-details.md](../references/pcore-misc-details.md) | `FormUtils`, `AutosaveUtils`, `NavigationUtils` | `PCore.get*()` |
32
+ | [../references/pcore-rest-data-details.md](../references/pcore-rest-data-details.md) | `CascadeManager` | `PCore.getCascadeManager()` |
33
+ | [../references/pconnect-validation-api.md](../references/pconnect-validation-api.md) | `ValidationApi` | `pConn.getValidationApi()` |
34
+ | [../references/pconnect-actions-api.md](../references/pconnect-actions-api.md) | `ActionsApi` | `pConn.getActionsApi()` |
35
+
36
+ See the [full reference index](../README.md) for every other PCore/PConnect method not directly related to this skill's topic.
37
+
38
+ ## Cookbooks
39
+
40
+ Multi-method, ordering/cleanup recipes for this skill's topic live in [cookbooks/README.md](./cookbooks/README.md): full-form validation before submit, cascading/dependent fields, autosave status tracking, persisting a custom widget's UI state, collecting changed/submittable data for a manual save action, discarding changes and resetting a form, and registering a custom field validator.
41
+
42
+ Use the reference files above for a single method's signature. Use the cookbook index when you need the **order** multiple methods should be called in to complete a task.
43
+
44
+ For testing components that call these APIs, security considerations, performance (debouncing cascades/autosave), error-handling strategy for a failed validation/autosave call, accessibly announcing validation/autosave status, or troubleshooting a call that isn't behaving as documented, see [Cross-Cutting Best Practices](../best-practices/README.md).
@@ -0,0 +1,36 @@
1
+ ---
2
+ title: Forms & Field Behavior Cookbook — Recipe Index
3
+ description: Multi-method recipes for form/field validation, cascading fields, autosave, and persisted UI state, indexed by symptom/keyword and primary method for AI/RAG retrieval.
4
+ ---
5
+
6
+ # Cookbook: Forms & Field Behavior
7
+
8
+ > Part of the [Forms & Field Behavior skill](../SKILL.md).
9
+
10
+ Every file in [`../../references/`](../../references/) documents one method at a time. Each file in this folder shows how to **chain multiple documented methods together** to complete one common real-world task. Every recipe only uses methods already cataloged in `references/` — follow the links in each recipe for full signatures. Nothing here invents a new API; every call is a direct composition of already-documented methods.
11
+
12
+ Each recipe is a single, self-contained file with:
13
+
14
+ - YAML frontmatter (`keywords`, `primary_methods`, `related`) for structured/metadata search.
15
+ - A **Problem** statement — what you're trying to accomplish, in plain language.
16
+ - A **Solution** — the minimal correct code, linking to the individual reference files for each method used.
17
+ - A **Discussion** — the ordering/cleanup/gotcha pitfall that makes this worth documenting as a recipe instead of assembling from scratch.
18
+ - **Related recipes** — links to recipes that share a pattern (lifecycle, cleanup, error handling, etc.), including recipes in sibling skills.
19
+
20
+ ## Recipe Index
21
+
22
+ Search by symptom or keyword before assembling a sequence of calls from scratch — there is a good chance the ordering/cleanup pitfalls have already been worked out below.
23
+
24
+ | Recipe | Keywords | Primary methods |
25
+ | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ---------------------------- |
26
+ | [Full-form validation before submit](./full-form-validation.md) | validate all fields, disable submit button, dirty check, unsaved changes | `FormUtils`, `ActionsApi` |
27
+ | [Cascading dependent fields](./cascading-dependent-fields.md) | dependent dropdown, country/state, cascade, dynamic field reset | `CascadeManager` |
28
+ | [Autosave status tracking](./autosave-tracking.md) | autosave, draft, in-progress edits, save indicator | `AutosaveUtils` |
29
+ | [Persist widget UI state](./persist-widget-ui-state.md) | persist UI state, remember selected tab, navigation cache, survive remount | `NavigationUtils` |
30
+ | [Collect form changes for a manual save](./collect-form-changes-for-manual-save.md) | manual save, save draft, changed fields, submit payload, custom save button | `FormUtils` |
31
+ | [Discard changes and reset a form](./discard-changes-and-reset-form.md) | discard changes, reset form, clear validation errors, cancel edit, revert | `FormUtils` |
32
+ | [Register a custom field validator](./custom-field-validators.md) | custom validator, business rule validation, cross-field validation | `FormUtils`, `ValidationApi` |
33
+
34
+ Use the individual reference files in [`../../references/`](../../references/) to look up a single method's exact signature. Use a recipe here when you need to know the **order** multiple methods should be called in to complete a task.
35
+
36
+ As more cookbooks are added, add one file per recipe (not more content to an existing recipe file) and a row here — see any existing recipe file for the expected frontmatter/structure.
@@ -0,0 +1,45 @@
1
+ ---
2
+ title: Track autosave status while editing a form
3
+ keywords: [autosave, draft, in-progress edits, save indicator]
4
+ primary_methods:
5
+ [AutosaveUtils.isAutosaveEnabledForContext, AutosaveUtils.subscribeAutosaveStatus, AutosaveUtils.notifyChange]
6
+ related: [data-page-subscription-cleanup, full-form-validation]
7
+ ---
8
+
9
+ # Recipe: Track autosave status while editing a form
10
+
11
+ > Part of the [Forms & Field Behavior cookbook](./README.md) — [skill overview](../SKILL.md).
12
+
13
+ ## Problem
14
+
15
+ A component needs to show an autosave indicator and tell the autosave engine about in-progress edits, without leaking the status subscription after unmount.
16
+
17
+ ## Solution
18
+
19
+ Uses `AutosaveUtils` (via `PCore.getAutosaveUtils()`, see [pcore-misc-details.md](../../references/pcore-misc-details.md)).
20
+
21
+ ```typescript
22
+ useEffect(() => {
23
+ if (!PCore.getAutosaveUtils().isAutosaveEnabledForContext(context)) return undefined;
24
+
25
+ const unsubscribe = PCore.getAutosaveUtils().subscribeAutosaveStatus(itemKey, (status) => {
26
+ setAutosaveStatus(status);
27
+ });
28
+
29
+ return unsubscribe;
30
+ }, [context, itemKey]);
31
+
32
+ const onFieldChange = (propReference, value) => {
33
+ // Tell the autosave engine about the edit so it can debounce/save it, separately from field-level state.
34
+ PCore.getAutosaveUtils().notifyChange(context, propReference, value);
35
+ };
36
+ ```
37
+
38
+ ## Discussion
39
+
40
+ **MUST** check `isAutosaveEnabledForContext` before subscribing. **NEVER** subscribe unconditionally — it wires up a listener that never fires on a context where autosave is off, which is a silent no-op that's easy to mistake for a bug elsewhere.
41
+
42
+ ## Related recipes
43
+
44
+ - [Subscribe to a data page and clean up on unmount](../../pconnect-data-subscriptions/cookbooks/data-page-subscription-cleanup.md)
45
+ - [Validate an entire form before allowing submit](./full-form-validation.md)
@@ -0,0 +1,51 @@
1
+ ---
2
+ title: Register cascading/dependent fields and clean them up
3
+ keywords: [dependent dropdown, country/state, cascade, dynamic field reset]
4
+ primary_methods: [CascadeManager.registerFields, CascadeManager.unRegisterFields]
5
+ related: [data-page-subscription-cleanup, pubsub-cleanup]
6
+ ---
7
+
8
+ # Recipe: Register cascading/dependent fields and clean them up
9
+
10
+ > Part of the [Forms & Field Behavior cookbook](./README.md) — [skill overview](../SKILL.md).
11
+
12
+ ## Problem
13
+
14
+ Changing one field (for example, Country) needs to reset or reload a dependent field (for example, State), and the listener must not keep firing after the component unmounts.
15
+
16
+ ## Solution
17
+
18
+ Uses `PCore.getCascadeManager()` (see [pcore-rest-data-messaging.md](../../references/pcore-rest-data-messaging.md)).
19
+
20
+ ```typescript
21
+ useEffect(() => {
22
+ const context = pConn.getContextName();
23
+ const pageReference = pConn.getPageReference();
24
+ const subscriberId = 'country-state-cascade';
25
+ // Register the field being WATCHED (the one whose change should trigger the reload), not the dependent field.
26
+ const watchedProps = ['.Country'];
27
+
28
+ const onCountryChanged = () => {
29
+ pConn.getActionsApi().updateFieldValue('.State', ''); // clear the dependent value
30
+ reloadStateOptions(); // load the options for the new country
31
+ };
32
+
33
+ PCore.getCascadeManager().registerFields(context, pageReference, watchedProps, onCountryChanged, subscriberId);
34
+
35
+ return () => {
36
+ // Always pair registerFields with unRegisterFields, or the callback keeps firing after unmount.
37
+ PCore.getCascadeManager().unRegisterFields(context, pageReference, watchedProps, subscriberId);
38
+ };
39
+ }, []);
40
+ ```
41
+
42
+ The typedef's own example registers field names without a leading dot (`['firstName', 'lastName']`) with an explicit page reference (`'caseInfo.content'`). Use the form your runtime resolves and confirm it in a running app; the call compiles either way.
43
+
44
+ ## Discussion
45
+
46
+ **MUST** pass the exact same `context`, `pageReference`, `watchedProps`, and `subscriberId` to both `registerFields` and `unRegisterFields`. **NEVER** let them drift apart — a mismatch silently fails the cleanup, and the original callback keeps firing after unmount.
47
+
48
+ ## Related recipes
49
+
50
+ - [Subscribe to a data page and clean up on unmount](../../pconnect-data-subscriptions/cookbooks/data-page-subscription-cleanup.md)
51
+ - [Publish/subscribe between unrelated components, with cleanup](../../pconnect-data-subscriptions/cookbooks/pubsub-cleanup.md)
@@ -0,0 +1,45 @@
1
+ ---
2
+ title: Collect changed or submittable form data for a manual save action
3
+ keywords: [manual save, save draft, changed fields, submit payload, custom save button]
4
+ primary_methods: [FormUtils.getChanges, FormUtils.getSubmitData]
5
+ related: [autosave-tracking, full-form-validation]
6
+ ---
7
+
8
+ # Recipe: Collect changed or submittable form data for a manual save action
9
+
10
+ > Part of the [Forms & Field Behavior cookbook](./README.md) — [skill overview](../SKILL.md).
11
+
12
+ ## Problem
13
+
14
+ A custom "Save Draft" button — distinct from both autosave and the final assignment submit — needs to package up either just the fields the user changed, or the full submittable payload, to send to a custom endpoint.
15
+
16
+ ## Solution
17
+
18
+ Uses `FormUtils` (via `PCore.getFormUtils()`, see [pcore-misc-details.md](../../references/pcore-misc-details.md)).
19
+
20
+ ```typescript
21
+ const { getChanges, getSubmitData } = PCore.getFormUtils();
22
+
23
+ function onSaveDraftClick(context) {
24
+ // Only the properties the user actually touched since the last save.
25
+ const changedFields = getChanges(context);
26
+ return saveDraftToCustomEndpoint(changedFields);
27
+ }
28
+
29
+ function onSaveFullSnapshotClick(context) {
30
+ // The complete submittable payload, as if the form were being submitted now.
31
+ const fullPayload = getSubmitData(context, { onlyChangedData: false });
32
+ return saveDraftToCustomEndpoint(fullPayload);
33
+ }
34
+ ```
35
+
36
+ ## Discussion
37
+
38
+ **MUST** choose `getChanges` vs. `getSubmitData({ onlyChangedData: true })` deliberately rather than interchangeably — `getChanges` returns the raw changed-properties list, while `getSubmitData` shapes the data the way an actual submit would, including any fields the form's own submit-time logic would add. Prefer `getSubmitData` when the draft will later be replayed through the same submit path.
39
+
40
+ **SHOULD** pass `{ includeDisabledFields: false }` (the default) unless the custom save endpoint specifically needs disabled-field values — including them can leak data the user never had a chance to edit or even see.
41
+
42
+ ## Related recipes
43
+
44
+ - [Track autosave status while editing a form](./autosave-tracking.md)
45
+ - [Validate an entire form before allowing submit](./full-form-validation.md)
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Register a custom validator for business-rule field validation
3
+ keywords: [custom validator, business rule validation, cross-field validation, register validator]
4
+ primary_methods: [FormUtils.setCustomValidator, ValidationApi.validate]
5
+ related: [full-form-validation]
6
+ ---
7
+
8
+ # Recipe: Register a custom validator for business-rule field validation
9
+
10
+ > Part of the [Forms & Field Behavior cookbook](./README.md) — [skill overview](../SKILL.md).
11
+
12
+ ## Problem
13
+
14
+ A field needs validation logic beyond what's configured on the field itself — for example, a business rule that compares two fields' values — and that logic should run through the same validation pipeline as built-in validators rather than being wired up ad hoc in the component.
15
+
16
+ ## Solution
17
+
18
+ Uses `FormUtils` and `ValidationApi` (`FormUtils` via `PCore.getFormUtils()`, see [pcore-misc-details.md](../../references/pcore-misc-details.md); `ValidationApi` via `pConn.getValidationApi()`, see [pconnect-validation-api.md](../../references/pconnect-validation-api.md)).
19
+
20
+ ```typescript
21
+ // Register once, near app bootstrap — not per component instance.
22
+ PCore.getFormUtils().setCustomValidator('endDateAfterStartDate', (value, context) => {
23
+ const startDate = PCore.getStoreValue('.StartDate', 'caseInfo.content', context);
24
+ return value > startDate ? undefined : 'End date must be after the start date';
25
+ });
26
+ ```
27
+
28
+ ```typescript
29
+ // At the field, run validation the same way as any other field.
30
+ const result = pConn.getValidationApi().validate(endDateValue, 'EndDate');
31
+ if (!result.status) {
32
+ // result.message reflects whichever validator (built-in or custom) failed
33
+ }
34
+ ```
35
+
36
+ ## Discussion
37
+
38
+ **MUST** register a given validator `type` name once — registering the same type name a second time (for example, from another component that also calls `setCustomValidator` with the same string) silently replaces the first registration, the same last-write-wins hazard as `ConfirmDialogService.registerConfirmHandler`.
39
+
40
+ **SHOULD** keep custom validator functions pure and side-effect-free — they can run on every keystroke depending on the field's validation trigger, so anything beyond a synchronous check (a network call, for example) belongs in `validateEmail`-style pre-submit validation instead, not a custom validator.
41
+
42
+ ## Related recipes
43
+
44
+ - [Validate an entire form before allowing submit](./full-form-validation.md)
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Discard changes and reset a form to its pristine state
3
+ keywords: [discard changes, reset form, clear validation errors, cancel edit, revert]
4
+ primary_methods: [FormUtils.clearChangedProperties, FormUtils.resetComplexObjectDirtyStatus]
5
+ related: [collect-form-changes-for-manual-save, full-form-validation]
6
+ ---
7
+
8
+ # Recipe: Discard changes and reset a form to its pristine state
9
+
10
+ > Part of the [Forms & Field Behavior cookbook](./README.md) — [skill overview](../SKILL.md).
11
+
12
+ ## Problem
13
+
14
+ A "Discard changes" / "Cancel edit" affordance needs to clear the form's changed-properties tracking and dirty-status flags so the form no longer reports unsaved changes, without a full page reload.
15
+
16
+ ## Solution
17
+
18
+ Uses `FormUtils` (via `PCore.getFormUtils()`, see [pcore-misc-details.md](../../references/pcore-misc-details.md)).
19
+
20
+ ```typescript
21
+ function onDiscardChangesClick(context) {
22
+ const { clearChangedProperties, resetComplexObjectDirtyStatus } = PCore.getFormUtils();
23
+
24
+ clearChangedProperties(context);
25
+ resetComplexObjectDirtyStatus(context);
26
+
27
+ // Field values themselves are not reset by either call — reload/re-fetch the underlying
28
+ // page/case data if the visible field values must also revert to their last-saved values.
29
+ }
30
+ ```
31
+
32
+ ## Discussion
33
+
34
+ **MUST NOT** assume `clearChangedProperties`/`resetComplexObjectDirtyStatus` revert field values — they only clear the _tracking_ of what changed and whether a complex object is dirty. If the UI must show the last-saved values again, re-fetch or restore them separately (for example, by re-opening the assignment).
35
+
36
+ **SHOULD** call both together when fully resetting a form's dirty state — `clearChangedProperties` covers simple properties, while `resetComplexObjectDirtyStatus` covers the dirty flag on nested/complex objects; using only one can leave the other half of the form still reporting as dirty.
37
+
38
+ ## Related recipes
39
+
40
+ - [Collect changed or submittable form data for a manual save action](./collect-form-changes-for-manual-save.md)
41
+ - [Validate an entire form before allowing submit](./full-form-validation.md)
@@ -0,0 +1,38 @@
1
+ ---
2
+ title: Validate an entire form before allowing submit
3
+ keywords: [validate all fields, disable submit button, dirty check, unsaved changes]
4
+ primary_methods: [FormUtils.isFormValid, FormUtils.isStateModified, ActionsApi.finishAssignment]
5
+ related: [modal-assignment-submit, multi-step-wizard, autosave-tracking]
6
+ ---
7
+
8
+ # Recipe: Validate an entire form before allowing submit
9
+
10
+ > Part of the [Forms & Field Behavior cookbook](./README.md) — [skill overview](../SKILL.md).
11
+
12
+ ## Problem
13
+
14
+ A Submit button must stay disabled until every field on the view is valid and the user has actually changed something — not just one field, as in the modal recipe.
15
+
16
+ ## Solution
17
+
18
+ Uses `PCore.getFormUtils()` (see [pcore-misc-details.md](../../references/pcore-misc-details.md)) together with [`ActionsApi`](../../references/pconnect-actions-api.md).
19
+
20
+ ```typescript
21
+ const canSubmit = PCore.getFormUtils().isFormValid(context) && PCore.getFormUtils().isStateModified(context);
22
+
23
+ if (canSubmit) {
24
+ await pConn.getActionsApi().finishAssignment(containerItemID);
25
+ } else {
26
+ // Keep the Submit button disabled; individual field errors are already shown by the framework.
27
+ }
28
+ ```
29
+
30
+ ## Discussion
31
+
32
+ **MUST** combine `isStateModified` with `isFormValid` — checking validity alone allows submitting an assignment the user never actually changed.
33
+
34
+ ## Related recipes
35
+
36
+ - [Open an assignment in a modal, edit, validate, submit, and close](../../pconnect-assignment-lifecycle/cookbooks/modal-assignment-submit.md)
37
+ - [Multi-step wizard navigation with per-step save and final submit](../../pconnect-assignment-lifecycle/cookbooks/multi-step-wizard.md)
38
+ - [Track autosave status while editing a form](./autosave-tracking.md)
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Persist a custom widget's UI state across navigation
3
+ keywords: [persist UI state, remember selected tab, navigation cache, component cache, survive remount]
4
+ primary_methods:
5
+ [NavigationUtils.getComponentState, NavigationUtils.setComponentState, NavigationUtils.getComponentCache]
6
+ related: [autosave-tracking]
7
+ ---
8
+
9
+ # Recipe: Persist a custom widget's UI state across navigation
10
+
11
+ > Part of the [Forms & Field Behavior cookbook](./README.md) — [skill overview](../SKILL.md).
12
+
13
+ ## Problem
14
+
15
+ A custom component (for example, a tab strip or collapsible panel) needs to remember which sub-view the user had open, surviving a full unmount when the user navigates away and back — plain React state resets on remount.
16
+
17
+ ## Solution
18
+
19
+ Uses `NavigationUtils` (via `PCore.getNavigationUtils()`, see [pcore-misc-details.md](../../references/pcore-misc-details.md)).
20
+
21
+ ```typescript
22
+ const stateKey = `my-widget-${pConn.getContextName()}`;
23
+
24
+ const [selectedTab, setSelectedTab] = useState(
25
+ () => PCore.getNavigationUtils().getComponentState(stateKey) ?? 'overview'
26
+ );
27
+
28
+ useEffect(() => {
29
+ PCore.getNavigationUtils().setComponentState(stateKey, selectedTab);
30
+ }, [selectedTab]);
31
+ ```
32
+
33
+ ## Discussion
34
+
35
+ **MUST** scope `stateKey` to the component's own context (`pConn.getContextName()`) rather than a hardcoded literal. **NEVER** use a shared key across multiple instances of the same widget — it collides across instances open in different containers, so one instance's tab selection silently overwrites another's.
36
+
37
+ `setComponentState` (persisted navigation state) and `setComponentCache` (in-memory cache) are not the same durability tier — reach for `setComponentCache` for cheap, short-lived memoization that's fine to lose, and reserve `setComponentState` for values that genuinely need to survive a full unmount/remount.
38
+
39
+ ## Related recipes
40
+
41
+ - [Track autosave status while editing a form](./autosave-tracking.md)