@pega/custom-dx-components 26.1.11 → 26.1.12-alpha-0.1
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.
- package/README.md +6 -2
- package/package.json +44 -61
- package/src/ai/README.md +44 -0
- package/src/ai/catalog/README.md +133 -0
- package/src/ai/catalog/best-practices/README.md +24 -0
- package/src/ai/catalog/best-practices/accessibility-for-async-components.md +53 -0
- package/src/ai/catalog/best-practices/error-handling-and-resiliency.md +116 -0
- package/src/ai/catalog/best-practices/genai-assistant-integration-patterns.md +49 -0
- package/src/ai/catalog/best-practices/performance-and-efficiency.md +109 -0
- package/src/ai/catalog/best-practices/security-considerations.md +93 -0
- package/src/ai/catalog/best-practices/testing-pconnect-components.md +245 -0
- package/src/ai/catalog/best-practices/troubleshooting-common-pitfalls.md +132 -0
- package/src/ai/catalog/pconnect-assignment-lifecycle/SKILL.md +44 -0
- package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/README.md +39 -0
- package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/approval-workflow-decision.md +47 -0
- package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/attachment-upload.md +45 -0
- package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/bulk-action-submit.md +50 -0
- package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/confirm-before-destructive-action.md +43 -0
- package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/create-and-stage-new-case.md +45 -0
- package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/graceful-submit-failure.md +39 -0
- package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/modal-assignment-submit.md +58 -0
- package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/multi-step-wizard.md +44 -0
- package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/resolve-or-ignore-duplicate.md +47 -0
- package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/safe-case-deletion.md +36 -0
- package/src/ai/catalog/pconnect-case-collaboration/SKILL.md +42 -0
- package/src/ai/catalog/pconnect-case-collaboration/cookbooks/README.md +36 -0
- package/src/ai/catalog/pconnect-case-collaboration/cookbooks/look-up-user-details.md +43 -0
- package/src/ai/catalog/pconnect-case-collaboration/cookbooks/manage-case-attachments.md +51 -0
- package/src/ai/catalog/pconnect-case-collaboration/cookbooks/manage-case-participants.md +52 -0
- package/src/ai/catalog/pconnect-case-collaboration/cookbooks/participant-and-follower.md +40 -0
- package/src/ai/catalog/pconnect-case-collaboration/cookbooks/post-and-manage-feed.md +50 -0
- package/src/ai/catalog/pconnect-case-collaboration/cookbooks/relate-cases.md +35 -0
- package/src/ai/catalog/pconnect-case-collaboration/cookbooks/tag-case-and-find-related.md +44 -0
- package/src/ai/catalog/pconnect-data-subscriptions/SKILL.md +42 -0
- package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/README.md +35 -0
- package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/data-page-subscription-cleanup.md +41 -0
- package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/publish-and-subscribe-events.md +40 -0
- package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/pubsub-cleanup.md +38 -0
- package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/query-paginated-list-data.md +44 -0
- package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/realtime-case-subscription.md +46 -0
- package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/refresh-and-update-data.md +41 -0
- package/src/ai/catalog/pconnect-forms-and-fields/SKILL.md +44 -0
- package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/README.md +36 -0
- package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/autosave-tracking.md +45 -0
- package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/cascading-dependent-fields.md +51 -0
- package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/collect-form-changes-for-manual-save.md +45 -0
- package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/custom-field-validators.md +44 -0
- package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/discard-changes-and-reset-form.md +41 -0
- package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/full-form-validation.md +38 -0
- package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/persist-widget-ui-state.md +41 -0
- package/src/ai/catalog/pconnect-lists-and-views/SKILL.md +44 -0
- package/src/ai/catalog/pconnect-lists-and-views/cookbooks/README.md +35 -0
- package/src/ai/catalog/pconnect-lists-and-views/cookbooks/activate-and-switch-container-items.md +52 -0
- package/src/ai/catalog/pconnect-lists-and-views/cookbooks/container-item-lifecycle.md +61 -0
- package/src/ai/catalog/pconnect-lists-and-views/cookbooks/insert-delete-list-rows.md +40 -0
- package/src/ai/catalog/pconnect-lists-and-views/cookbooks/reorder-list-rows.md +39 -0
- package/src/ai/catalog/pconnect-lists-and-views/cookbooks/repeating-row-edit.md +39 -0
- package/src/ai/catalog/pconnect-lists-and-views/cookbooks/view-personalization.md +60 -0
- package/src/ai/catalog/pconnect-navigation-locale-genai/SKILL.md +45 -0
- package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/README.md +35 -0
- package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/agent-conversation-for-tasks.md +54 -0
- package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/bookmarkable-filter-state.md +40 -0
- package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/deep-link-semantic-url.md +39 -0
- package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/genai-assistant-conversation.md +43 -0
- package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/locale-switch-and-relocalize.md +38 -0
- package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/persist-operator-preferences.md +40 -0
- package/src/ai/catalog/references/architecture-overview.md +52 -0
- package/src/ai/catalog/references/pconnect-actions-api.md +948 -0
- package/src/ai/catalog/references/pconnect-case-info-data-info-localization.md +618 -0
- package/src/ai/catalog/references/pconnect-case-validation-utilities.md +238 -0
- package/src/ai/catalog/references/pconnect-container-manager.md +215 -0
- package/src/ai/catalog/references/pconnect-list-actions.md +250 -0
- package/src/ai/catalog/references/pconnect-misc-suggestions-creation.md +231 -0
- package/src/ai/catalog/references/pconnect-reference-context-component.md +471 -0
- package/src/ai/catalog/references/pconnect-state-config.md +316 -0
- package/src/ai/catalog/references/pconnect-validation-api.md +45 -0
- package/src/ai/catalog/references/pcore-analytics-genai-details.md +50 -0
- package/src/ai/catalog/references/pcore-bootstrap-init-details.md +121 -0
- package/src/ai/catalog/references/pcore-bootstrap-registry-routing.md +253 -0
- package/src/ai/catalog/references/pcore-case-collaboration-details.md +191 -0
- package/src/ai/catalog/references/pcore-case-collaboration-genai.md +264 -0
- package/src/ai/catalog/references/pcore-environment-info-details.md +96 -0
- package/src/ai/catalog/references/pcore-environment-locale-namespace.md +175 -0
- package/src/ai/catalog/references/pcore-messaging-details.md +99 -0
- package/src/ai/catalog/references/pcore-misc-details.md +207 -0
- package/src/ai/catalog/references/pcore-misc-utilities.md +325 -0
- package/src/ai/catalog/references/pcore-rest-data-details.md +164 -0
- package/src/ai/catalog/references/pcore-rest-data-messaging.md +308 -0
- package/src/ai/catalog/references/pcore-store-context-details.md +40 -0
- package/src/ai/catalog/references/pcore-store-context-state.md +130 -0
- package/src/ai/index.js +154 -0
- package/src/ai/project/.claude/skills/boolean/SKILL.md +43 -0
- package/src/ai/project/.claude/skills/case/SKILL.md +58 -0
- package/src/ai/project/.claude/skills/create-dx-component/SKILL.md +98 -0
- package/src/ai/project/.claude/skills/create-dx-component/assets/PConnProps.d.ts +24 -0
- package/src/ai/project/.claude/skills/create-dx-component/assets/create-nonce.ts +5 -0
- package/src/ai/project/.claude/skills/create-dx-component/assets/event-utils.ts +18 -0
- package/src/ai/project/.claude/skills/create-dx-component/assets/styles.ts +7 -0
- package/src/ai/project/.claude/skills/create-dx-component/cookbooks/README.md +28 -0
- package/src/ai/project/.claude/skills/create-dx-component/cookbooks/build-a-data-widget.md +281 -0
- package/src/ai/project/.claude/skills/create-dx-component/cookbooks/field-with-limits-and-validation.md +156 -0
- package/src/ai/project/.claude/skills/create-dx-component/cookbooks/status-badge-field.md +97 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/accessibility.md +71 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/choosing-type-and-subtype.md +79 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/cli-workflow.md +125 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/component-patterns.md +241 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/config-schema.md +296 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/cosmos-components.md +137 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/field-behavior.md +155 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/field-essentials.md +90 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/field-subtypes-extra.md +68 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/localization.md +30 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/pcore-pconnect-apis.md +77 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/presentation-essentials.md +57 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/props-contract.md +182 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/state-matrix.md +102 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/storybook-pattern.md +262 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/styles-pattern.md +54 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/template-essentials.md +87 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/template-patterns.md +131 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/test-pattern.md +215 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/ui-gallery-reuse.md +93 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/widget-essentials.md +84 -0
- package/src/ai/project/.claude/skills/create-dx-component/references/widget-patterns.md +164 -0
- package/src/ai/project/.claude/skills/currency/SKILL.md +46 -0
- package/src/ai/project/.claude/skills/date/SKILL.md +46 -0
- package/src/ai/project/.claude/skills/decimal/SKILL.md +49 -0
- package/src/ai/project/.claude/skills/details/SKILL.md +60 -0
- package/src/ai/project/.claude/skills/email/SKILL.md +42 -0
- package/src/ai/project/.claude/skills/field/SKILL.md +68 -0
- package/src/ai/project/.claude/skills/form/SKILL.md +51 -0
- package/src/ai/project/.claude/skills/generate-component-set/SKILL.md +80 -0
- package/src/ai/project/.claude/skills/generate-component-set/component-manifest.json +161 -0
- package/src/ai/project/.claude/skills/identify-components/SKILL.md +76 -0
- package/src/ai/project/.claude/skills/integer/SKILL.md +45 -0
- package/src/ai/project/.claude/skills/page/SKILL.md +60 -0
- package/src/ai/project/.claude/skills/page-widget/SKILL.md +55 -0
- package/src/ai/project/.claude/skills/percentage/SKILL.md +52 -0
- package/src/ai/project/.claude/skills/phone/SKILL.md +44 -0
- package/src/ai/project/.claude/skills/picklist/SKILL.md +50 -0
- package/src/ai/project/.claude/skills/plan-dx-component/SKILL.md +51 -0
- package/src/ai/project/.claude/skills/plan-dx-component/references/design-system-mapping.md +108 -0
- package/src/ai/project/.claude/skills/plan-dx-component/references/intake.md +146 -0
- package/src/ai/project/.claude/skills/plan-dx-component/references/plan-template.md +76 -0
- package/src/ai/project/.claude/skills/plan-dx-component/references/requirements-template.md +88 -0
- package/src/ai/project/.claude/skills/presentation/SKILL.md +61 -0
- package/src/ai/project/.claude/skills/publish-library/SKILL.md +106 -0
- package/src/ai/project/.claude/skills/radiobuttons/SKILL.md +51 -0
- package/src/ai/project/.claude/skills/review-component/SKILL.md +49 -0
- package/src/ai/project/.claude/skills/review-component/references/checklist.md +77 -0
- package/src/ai/project/.claude/skills/template/SKILL.md +60 -0
- package/src/ai/project/.claude/skills/text/SKILL.md +45 -0
- package/src/ai/project/.claude/skills/update-dx-component/SKILL.md +56 -0
- package/src/ai/project/.claude/skills/update-dx-component/references/maintenance.md +43 -0
- package/src/ai/project/.claude/skills/url/SKILL.md +46 -0
- package/src/ai/project/.claude/skills/validate-component/SKILL.md +78 -0
- package/src/ai/project/.claude/skills/validate-component/references/runtime-troubleshooting.md +56 -0
- package/src/ai/project/.claude/skills/validate-component/scripts/check-component.mjs +327 -0
- package/src/ai/project/.claude/skills/widget/SKILL.md +59 -0
- package/src/ai/project/.gemini/settings.json +5 -0
- package/src/ai/project/AGENTS.md +74 -0
- package/src/ai/readme-section.md +91 -0
- package/src/cli.js +48 -7
- package/src/constants.js +54 -53
- package/src/internal-tests.js +27 -0
- package/src/tasks/ai-toggle/index.js +46 -0
- package/src/tasks/authenticate/helper.js +38 -38
- package/src/tasks/authenticate/index.js +17 -15
- package/src/tasks/build-all/helper.js +4 -4
- package/src/tasks/build-all/index.js +7 -7
- package/src/tasks/build-comp/helper.js +17 -17
- package/src/tasks/build-comp/index.js +10 -10
- package/src/tasks/build-jest-assets/index.js +7 -9
- package/src/tasks/build-lib/helper.js +8 -8
- package/src/tasks/build-lib/index.js +8 -8
- package/src/tasks/bundle/builder/index.js +9 -12
- package/src/tasks/bundle/builder/modules.js +8 -9
- package/src/tasks/bundle/builder/paths.js +2 -19
- package/src/tasks/bundle/builder/webpack.config.js +60 -77
- package/src/tasks/bundle/index.js +8 -8
- package/src/tasks/create/index.js +35 -35
- package/src/tasks/create/templates/Constellation/Field/Boolean/index.tsx.mustache +1 -36
- package/src/tasks/create/templates/Constellation/Field/Date/date.ts.mustache +2 -2
- package/src/tasks/create/templates/Constellation/Field/Date/index.tsx.mustache +2 -27
- package/src/tasks/create/templates/Constellation/Field/DateTime/date-utils.ts.mustache +2 -2
- package/src/tasks/create/templates/Constellation/Field/DateTime/date.ts.mustache +2 -2
- package/src/tasks/create/templates/Constellation/Field/DateTime/index.tsx.mustache +2 -35
- package/src/tasks/create/templates/Constellation/Field/Decimal/index.tsx.mustache +3 -36
- package/src/tasks/create/templates/Constellation/Field/Decimal-Currency/index.tsx.mustache +4 -39
- package/src/tasks/create/templates/Constellation/Field/Decimal-Percentage/index.tsx.mustache +4 -53
- package/src/tasks/create/templates/Constellation/Field/Icon-Button-URL/index.tsx.mustache +5 -5
- package/src/tasks/create/templates/Constellation/Field/Integer/index.tsx.mustache +3 -36
- package/src/tasks/create/templates/Constellation/Field/Picklist/index.tsx.mustache +7 -42
- package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/component-constants.ts +1 -1
- package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/date.ts.mustache +0 -2
- package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/embed-utils.ts.mustache +1 -1
- package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/index.tsx.mustache +11 -11
- package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/repeat-utils.ts.mustache +3 -13
- package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/textformat-utils.tsx.mustache +2 -3
- package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/utils.ts.mustache +28 -28
- package/src/tasks/create/templates/Constellation/Field/Picklist-RadioButtons/index.tsx.mustache +2 -2
- package/src/tasks/create/templates/Constellation/Field/Picklist-RadioButtons/textformat-utils.tsx.mustache +2 -3
- package/src/tasks/create/templates/Constellation/Field/Text/index.tsx.mustache +4 -33
- package/src/tasks/create/templates/Constellation/Field/Text-Email/index.tsx.mustache +3 -33
- package/src/tasks/create/templates/Constellation/Field/Text-Input/index.tsx.mustache +3 -31
- package/src/tasks/create/templates/Constellation/Field/Text-Paragraph/index.tsx.mustache +3 -31
- package/src/tasks/create/templates/Constellation/Field/Text-Phone/index.tsx.mustache +3 -35
- package/src/tasks/create/templates/Constellation/Field/Text-URL/index.tsx.mustache +3 -33
- package/src/tasks/create/templates/Constellation/Field/Text-URL/text-url.tsx.mustache +2 -3
- package/src/tasks/create/templates/Constellation/Field/TimeofDay/index.tsx.mustache +2 -35
- package/src/tasks/create/templates/Constellation/Field/TimeofDay/time-of-day.ts.mustache +2 -2
- package/src/tasks/create/templates/Constellation/Template/DETAILS/Avatar.tsx.mustache +19 -15
- package/src/tasks/create/templates/Constellation/Template/DETAILS/Operator.tsx.mustache +6 -6
- package/src/tasks/create/templates/Constellation/Template/DETAILS/demo.stories.tsx.mustache +1 -1
- package/src/tasks/create/templates/Constellation/Template/DETAILS/index.tsx.mustache +4 -8
- package/src/tasks/create/templates/Constellation/Template/DETAILS/mock.ts.mustache +9 -9
- package/src/tasks/create/templates/Constellation/Template/DETAILS/utils.js.mustache +4 -8
- package/src/tasks/create/templates/Constellation/Template/DETAILS-region/Avatar.tsx.mustache +19 -15
- package/src/tasks/create/templates/Constellation/Template/DETAILS-region/Operator.tsx.mustache +6 -6
- package/src/tasks/create/templates/Constellation/Template/DETAILS-region/demo.stories.tsx.mustache +1 -1
- package/src/tasks/create/templates/Constellation/Template/DETAILS-region/index.tsx.mustache +1 -1
- package/src/tasks/create/templates/Constellation/Template/DETAILS-region/mock.ts.mustache +9 -9
- package/src/tasks/create/templates/Constellation/Template/DETAILS-region/utils.ts.mustache +4 -8
- package/src/tasks/create/templates/Constellation/Template/FORM/demo.stories.tsx.mustache +8 -8
- package/src/tasks/create/templates/Constellation/Template/FORM-region/demo.stories.tsx.mustache +8 -8
- package/src/tasks/create/templates/Constellation/Template/PAGE/utils.ts.mustache +4 -9
- package/src/tasks/create/templates/Constellation/Widget/CASE/demo.test.tsx.mustache +3 -3
- package/src/tasks/create/templates/Constellation/Widget/PAGE-CASE/Avatar.tsx.mustache +19 -14
- package/src/tasks/create/templates/Constellation/Widget/PAGE-CASE/Operator.tsx.mustache +6 -6
- package/src/tasks/create/templates/Constellation/Widget/PAGE-CASE/index.tsx.mustache +1 -1
- package/src/tasks/create/templates/Constellation/Widget/PAGE-CASE/mock.ts.mustache +1 -1
- package/src/tasks/create/templates/Launchpad/Field/Icon-Button-URL/index.tsx.mustache +5 -5
- package/src/tasks/create/templates/Launchpad/Field/Text-Phone/index.tsx.mustache +3 -35
- package/src/tasks/create/templates/Launchpad/Field/__components.md +1 -1
- package/src/tasks/create/templates/Launchpad/Template/FORM/demo.stories.tsx.mustache +8 -8
- package/src/tasks/create/templates/Launchpad/Template/FORM-region/demo.stories.tsx.mustache +8 -8
- package/src/tasks/create/templates/Launchpad/Widget/CASE/demo.test.tsx.mustache +3 -3
- package/src/tasks/create/templates/Launchpad/Widget/PAGE-CASE/index.tsx.mustache +1 -1
- package/src/tasks/create/templates/Launchpad/Widget/PAGE-CASE/mock.ts.mustache +1 -1
- package/src/tasks/create-all/index.js +42 -41
- package/src/tasks/create-lib/helper.js +13 -13
- package/src/tasks/create-lib/index.js +5 -5
- package/src/tasks/create-version/helper.js +10 -10
- package/src/tasks/create-version/index.js +3 -4
- package/src/tasks/delete/helper.js +20 -19
- package/src/tasks/delete/index.js +2 -2
- package/src/tasks/delete-all/helper.js +26 -25
- package/src/tasks/delete-all/index.js +2 -2
- package/src/tasks/delete-lib/helper.js +6 -6
- package/src/tasks/delete-lib/index.js +6 -6
- package/src/tasks/delete-pub/helper.js +18 -18
- package/src/tasks/delete-pub/index.js +8 -8
- package/src/tasks/delete-version/index.js +2 -2
- package/src/tasks/dev-server/index.js +1 -1
- package/src/tasks/export-archive/helper.js +21 -21
- package/src/tasks/export-archive/index.js +27 -40
- package/src/tasks/export-rc/helper.js +34 -34
- package/src/tasks/export-rc/index.js +21 -31
- package/src/tasks/import-archive/helper.js +39 -39
- package/src/tasks/import-archive/index.js +69 -89
- package/src/tasks/import-comp/helper.js +8 -8
- package/src/tasks/import-comp/index.js +30 -42
- package/src/tasks/index.js +5 -0
- package/src/tasks/init/Node.gitignore +149 -0
- package/src/tasks/init/helper.js +15 -8
- package/src/tasks/init/index.js +115 -35
- package/src/tasks/init/template/.prettierrc.json +4 -1
- package/src/tasks/init/template/.storybook/main.ts +1 -4
- package/src/tasks/init/template/.storybook/manager.ts +1 -1
- package/src/tasks/init/template/.storybook/preview.tsx +2 -2
- package/src/tasks/init/template/.storybook/theme.js +1 -1
- package/src/tasks/init/template/.vscode/extensions.json +0 -1
- package/src/tasks/init/template/README.md +2 -2
- package/src/tasks/init/template/eslint.config.mjs +13 -155
- package/src/tasks/init/template/jest.config.cjs +2 -0
- package/src/tasks/init/template/package-lock.json +26864 -0
- package/src/tasks/init/template/package.json.mustache +19 -74
- package/src/tasks/init/template/setupTests.ts +10 -4
- package/src/tasks/init/template/tsconfig.json +14 -6
- package/src/tasks/internal-test/index.js +21 -0
- package/src/tasks/internal-test-full/index.js +15 -0
- package/src/tasks/internal-test-functional/index.js +15 -0
- package/src/tasks/internal-test-unit/index.js +13 -0
- package/src/tasks/linter/index.js +2 -2
- package/src/tasks/list/helper.js +41 -40
- package/src/tasks/list/index.js +3 -3
- package/src/tasks/list-lib/helper.js +5 -5
- package/src/tasks/list-lib/index.js +8 -8
- package/src/tasks/list-pub/helper.js +23 -16
- package/src/tasks/list-pub/index.js +24 -21
- package/src/tasks/move/helper.js +8 -8
- package/src/tasks/move/index.js +19 -23
- package/src/tasks/promote-webpack/index.js +4 -4
- package/src/tasks/promote-webpack/webpack.config.js +62 -93
- package/src/tasks/publish/helper.js +21 -21
- package/src/tasks/publish/index.js +16 -16
- package/src/tasks/publish-all/helper.js +20 -20
- package/src/tasks/publish-all/index.js +11 -12
- package/src/tasks/publish-archive/helper.js +9 -9
- package/src/tasks/publish-archive/index.js +12 -14
- package/src/tasks/publish-lib/helper.js +3 -3
- package/src/tasks/publish-lib/index.js +28 -34
- package/src/tasks/quarantine/index.js +8 -8
- package/src/tasks/rename/index.js +26 -30
- package/src/tasks/rename-lib/index.js +21 -25
- package/src/tasks/restore/index.js +8 -8
- package/src/tasks/restore-config/index.js +3 -5
- package/src/tasks/set-perm/index.js +8 -8
- package/src/tasks/show-help/index.js +17 -9
- package/src/tasks/show-status/index.js +2 -2
- package/src/tasks/store/index.js +8 -8
- package/src/tasks/switch-lib/helper.js +7 -7
- package/src/tasks/switch-lib/index.js +7 -7
- package/src/tasks/switch-version/helper.js +6 -6
- package/src/tasks/switch-version/index.js +7 -7
- package/src/tasks/update/index.js +1 -1
- package/src/tasks/upgrade/index.js +7 -7
- package/src/tasks/validator/index.js +49 -203
- package/src/util.js +169 -186
- package/src/rules/no-pcore-pconnect-in-presentation.js +0 -103
- package/src/tasks/init/template/.stylelintrc.json +0 -4
- package/src/tasks/init/template/babel.config.cjs +0 -22
- package/src/tasks/init/template/cspell.json +0 -14
package/README.md
CHANGED
|
@@ -37,9 +37,13 @@ Ensure you have access to the following in your system:
|
|
|
37
37
|
|
|
38
38
|
- Git version 2.30 or later
|
|
39
39
|
|
|
40
|
-
- System node version >= 24.
|
|
40
|
+
- System node version >= 24.22.1
|
|
41
41
|
|
|
42
|
-
- System npm version 11.
|
|
42
|
+
- System npm version 11.19.1
|
|
43
|
+
|
|
44
|
+
## AI-assisted component development
|
|
45
|
+
|
|
46
|
+
Projects created with DX Component Builder include AI skills and project rules that work in **GitHub Copilot, Claude Code, Cursor, Codex CLI and Gemini CLI**: 32 skills covering every component type, the CLI workflow, and an exhaustive PCore/PConnect API catalog, installed once at `init` with no extra package or setup. It is optional: answer "No" to the "Enable AI-assisted component development?" prompt during `init`, or run `init --noAi`, to create a project without any of it, and switch it off or on later with `npm run disableAi` / `npm run enableAi`. See the generated project's `README.md` for details.
|
|
43
47
|
|
|
44
48
|
## Latest Documentation
|
|
45
49
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pega/custom-dx-components",
|
|
3
|
-
"version": "26.1.
|
|
3
|
+
"version": "26.1.12-alpha-0.1",
|
|
4
4
|
"description": "Utility for building custom UI components",
|
|
5
5
|
"bin": {
|
|
6
6
|
"custom-dx-components": "./bin/index.js"
|
|
@@ -20,87 +20,70 @@
|
|
|
20
20
|
"author": "Custom component dev",
|
|
21
21
|
"sideEffects": false,
|
|
22
22
|
"type": "module",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=24.20.0"
|
|
25
|
+
},
|
|
23
26
|
"scripts": {
|
|
24
|
-
"lint:es": "eslint --color --cache --cache-location node_modules/.cache/eslint/ \"src/**\"",
|
|
27
|
+
"lint:es": "eslint --no-config-lookup -c eslint.config.mjs --color --cache --cache-location node_modules/.cache/eslint/ \"src/**\"",
|
|
25
28
|
"lint:format": "prettier -c \"src/**\"",
|
|
26
29
|
"lint:spelling": "cspell **/*",
|
|
27
|
-
"fix:es": "eslint --fix .",
|
|
30
|
+
"fix:es": "eslint --no-config-lookup -c eslint.config.mjs --fix .",
|
|
28
31
|
"fix:format": "prettier -w \"src/**\"",
|
|
29
32
|
"test:unit:local": "node --input-type=module --experimental-vm-modules node_modules/jest/bin/jest.js --runInBand --coverage=false /tests/unit",
|
|
30
33
|
"test:functional:local": "jest --runInBand /tests/functional --detectOpenHandles --coverage"
|
|
31
34
|
},
|
|
32
35
|
"dependencies": {
|
|
33
|
-
"@
|
|
34
|
-
"@
|
|
35
|
-
"@
|
|
36
|
-
"@pega/auth": "^0.2.37",
|
|
37
|
-
"@pega/constellation-dx-components-build-utils": "^2.0.11",
|
|
38
|
-
"@pega/inquirer-fuzzy-path": "^3.0.0",
|
|
36
|
+
"@pega/auth": "^1.0.0",
|
|
37
|
+
"@pega/constellation-dx-components-build-utils": "^2.0.17",
|
|
38
|
+
"@pega/inquirer-fuzzy-path": "^4.0.0",
|
|
39
39
|
"ajv": "^8.17.1",
|
|
40
|
-
"ajv-keywords": "^5.1.0",
|
|
41
40
|
"archiver": "^7.0.1",
|
|
42
41
|
"arg": "^5.0.2",
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"eslint": "^9.36.0",
|
|
50
|
-
"execa": "^9.6.0",
|
|
42
|
+
"chalk": "^6.0.1",
|
|
43
|
+
"compression-webpack-plugin": "^12.0.0",
|
|
44
|
+
"css-loader": "7.1.5",
|
|
45
|
+
"css-minimizer-webpack-plugin": "^8.0.0",
|
|
46
|
+
"eslint": "^10.11.0",
|
|
47
|
+
"execa": "^10.0.1",
|
|
51
48
|
"file-loader": "6.2.0",
|
|
52
|
-
"
|
|
53
|
-
"gitignore": "^0.7.0",
|
|
54
|
-
"inquirer": "^9.3.7",
|
|
49
|
+
"inquirer": "^9.3.8",
|
|
55
50
|
"jwt-decode": "^4.0.0",
|
|
56
|
-
"listr2": "^
|
|
57
|
-
"mini-css-extract-plugin": "2.
|
|
51
|
+
"listr2": "^11.1.0",
|
|
52
|
+
"mini-css-extract-plugin": "2.10.2",
|
|
58
53
|
"mustache": "^4.2.0",
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"node-stream-zip": "^1.15.0",
|
|
62
|
-
"ora": "^8.2.0",
|
|
54
|
+
"node-stream-zip": "^1.16.0",
|
|
55
|
+
"ora": "^9.4.1",
|
|
63
56
|
"pascalcase": "^2.0.0",
|
|
64
57
|
"postcss": "^8.5.6",
|
|
65
|
-
"postcss-loader": "8.
|
|
66
|
-
"postcss-preset-env": "
|
|
67
|
-
"prop-types": "^15.8.1",
|
|
68
|
-
"react": "^18.2.0",
|
|
58
|
+
"postcss-loader": "8.2.1",
|
|
59
|
+
"postcss-preset-env": "11.5.4",
|
|
69
60
|
"react-dev-utils": "^12.0.1",
|
|
70
|
-
"resolve": "1.22.10",
|
|
71
61
|
"resolve-url-loader": "^5.0.0",
|
|
72
|
-
"sass-loader": "^
|
|
73
|
-
"terser-webpack-plugin": "5.
|
|
74
|
-
"ts-loader": "^9.
|
|
75
|
-
"typescript": "~5.
|
|
62
|
+
"sass-loader": "^17.0.1",
|
|
63
|
+
"terser-webpack-plugin": "5.6.1",
|
|
64
|
+
"ts-loader": "^9.6.2",
|
|
65
|
+
"typescript": "~5.9.3",
|
|
76
66
|
"unarchive": "^1.1.3",
|
|
77
|
-
"undici": "^7.
|
|
67
|
+
"undici": "^7.30.0",
|
|
78
68
|
"url-loader": "4.1.1",
|
|
79
|
-
"webpack": "5.
|
|
80
|
-
|
|
69
|
+
"webpack": "5.111.1"
|
|
70
|
+
},
|
|
71
|
+
"overrides": {
|
|
72
|
+
"glob": "^13.0.0",
|
|
73
|
+
"serialize-javascript": "^7.0.5",
|
|
74
|
+
"webpack": "$webpack"
|
|
81
75
|
},
|
|
82
76
|
"devDependencies": {
|
|
83
|
-
"@babel/preset-env": "^7.
|
|
84
|
-
"@
|
|
85
|
-
"@
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"eslint
|
|
94
|
-
"eslint-plugin-prettier": "^5.5.4",
|
|
95
|
-
"eslint-plugin-react": "^7.33.2",
|
|
96
|
-
"eslint-plugin-react-hooks": "^4.6.0",
|
|
97
|
-
"eslint-plugin-sonarjs": "^0.23.0",
|
|
98
|
-
"eslint-plugin-storybook": "^0.6.15",
|
|
99
|
-
"jest": "^29.7.0",
|
|
100
|
-
"jest-environment-jsdom": "^29.7.0",
|
|
101
|
-
"jest-junit": "^16.0.0",
|
|
102
|
-
"prettier": "3.6.2",
|
|
103
|
-
"ts-jest": "^29.4.0",
|
|
104
|
-
"typescript-eslint": "^8.44.1"
|
|
77
|
+
"@babel/preset-env": "^7.29.7",
|
|
78
|
+
"@eslint/js": "^10.0.1",
|
|
79
|
+
"@types/jest": "^30.0.0",
|
|
80
|
+
"babel-jest": "^30.5.2",
|
|
81
|
+
"cspell": "^10.3.5",
|
|
82
|
+
"globals": "^17.12.0",
|
|
83
|
+
"jest": "^30.5.2",
|
|
84
|
+
"jest-environment-jsdom": "^30.5.2",
|
|
85
|
+
"jest-junit": "^17.0.0",
|
|
86
|
+
"prettier": "^3.9.9",
|
|
87
|
+
"typescript-eslint": "^8.71.0"
|
|
105
88
|
}
|
|
106
89
|
}
|
package/src/ai/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# AI assets (maintainer notes)
|
|
2
|
+
|
|
3
|
+
Everything the CLI ships for AI coding tools lives here. Nothing in this folder is copied to customers except `project/`, `catalog/` and `readme-section.md`; this file stays in the CLI repo.
|
|
4
|
+
|
|
5
|
+
| Path | What it is | Installed to |
|
|
6
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
|
|
7
|
+
| `project/` | Mirrors the project root: `AGENTS.md`, `.gemini/`, and the component skills in `.claude/skills/` | The project root |
|
|
8
|
+
| `catalog/` | The PCore/PConnect skills, `references/` and `best-practices/` | `.claude/skills/` (and `.agents/skills`, a link) |
|
|
9
|
+
| `readme-section.md` | The README section describing the AI setup, between `ai-agents` marker comments | Inserted before `## Latest Documentation` |
|
|
10
|
+
| `index.js` | `enableAgentFiles`, `removeAgentFiles`, `hasAgentFiles`, used by `init`, `enableAi` and `disableAi`. It also adds and removes a marked block in the project's `.prettierignore` | |
|
|
11
|
+
|
|
12
|
+
The install and remove file lists are derived from these folders, so adding a skill means adding a folder and nothing else. Skill folders must be one level deep and uniquely named (Claude Code only scans one level); `tests/unit/ai-assets.test.js` enforces this, along with valid frontmatter, working links and manifest paths.
|
|
13
|
+
|
|
14
|
+
## Adding or changing a component skill
|
|
15
|
+
|
|
16
|
+
Edit `project/.claude/skills/<name>/`. If it is a new component subtype, also add it to `project/.claude/skills/generate-component-set/component-manifest.json` (with its `cliSubtype` and skill path) and to the routing list in `project/AGENTS.md`. Run `npm run test:unit:local`.
|
|
17
|
+
|
|
18
|
+
## Where rules live
|
|
19
|
+
|
|
20
|
+
Keep `SKILL.md` files free of inline code: they hold instructions, routing and pointers, and a unit test fails if one carries more than a few fenced lines. Code skeletons, handler shapes and snippets belong in `references/`, `cookbooks/` or `assets/`, and config properties are listed as tables. Write each rule once, in a skill reference under `project/.claude/skills/create-dx-component/references/`, because every AI tool reads skills. `project/AGENTS.md` loads on every request, so it carries only repo-wide rules and compact routing; keep it under about 9 KB. There are no tool-specific instruction files, Copilot prompt files or custom agents: batch generation and design analysis are skills (`generate-component-set`, `identify-components`) so they work in every tool.
|
|
21
|
+
|
|
22
|
+
Generation speed depends mostly on how much an agent must read before writing code. Each type has one `*-essentials.md` reference (field, widget, template, presentation) with the must-follow rules for every component file and a closing table of when to open a deeper reference. Agents read the essentials file instead of the deep references. When you add or change a must-follow rule in a deep reference, update the matching essentials file too, and keep each one under about 9 KB. The type skills (`field`, `widget`, `template`, `presentation`) hold only routing, the contract items, the scaffold command and a pointer to their essentials file.
|
|
23
|
+
|
|
24
|
+
## Re-syncing the catalog from corejs
|
|
25
|
+
|
|
26
|
+
`catalog/` is a snapshot of `packages/corejs/skills` in the constellation-frontend repo. It is not generated, so re-syncing is manual, and **a plain copy over `catalog/` loses fixes**:
|
|
27
|
+
|
|
28
|
+
- The snapshot was type-checked against `@pega/pcore-pconnect-typedefs`. Roughly 30 documented signatures and payloads were corrected (for example `loadView`, `openEmbeddedDataModal`, `refreshCaseView`, `acceptSuggestion`, tag, participant and follower payloads, conversation IDs). Those corrections do not exist in corejs unless they were ported back.
|
|
29
|
+
- Monorepo-only references were removed, and each `pconnect-*` skill carries `metadata.verified-against`.
|
|
30
|
+
|
|
31
|
+
To re-sync:
|
|
32
|
+
|
|
33
|
+
1. Diff corejs against `catalog/` (`diff -r`) and read the diff before copying anything. Take new or changed content; keep the local corrections or port them upstream first.
|
|
34
|
+
2. Keep customer-facing text free of monorepo paths and internal terms.
|
|
35
|
+
3. Keep custom frontmatter keys under `metadata:`. The shared Agent Skills format that Claude Code, Copilot and Cursor read does not allow bare custom keys.
|
|
36
|
+
4. Type-check every fenced TypeScript block in the changed docs against the installed typedefs, and compare each documented method signature (required and optional parameters) with the typedefs. Fix mismatches in the docs.
|
|
37
|
+
5. Update `metadata.verified-against` only for skills you re-verified.
|
|
38
|
+
6. Run `npm run test:unit:local`, `npx prettier -c "src/**"` and `npx cspell "**/*"`. Allow-list new domain words in `cspell.json`.
|
|
39
|
+
|
|
40
|
+
Existing customer projects are not updated when the catalog changes: `enableAi` restores missing files but never overwrites existing ones.
|
|
41
|
+
|
|
42
|
+
## Supporting another AI tool
|
|
43
|
+
|
|
44
|
+
Check where the tool reads skills and project instructions before adding anything. Today: Claude Code, Copilot and Cursor read `.claude/skills`; Codex and Gemini read `.agents/skills` (a link to it); Gemini needs `.gemini/settings.json` to load `AGENTS.md`. If the tool reads one of those, nothing needs to be added. Never add a second copy of the skills.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: PCore / PConnect API Reference Skills
|
|
3
|
+
description: 'Index of the six PCore/PConnect skills, their shared method-by-method reference catalog, and cross-cutting testing/security/performance/error-handling/accessibility/GenAI-integration/troubleshooting guidance, for building Pega Constellation custom components.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PCore / PConnect API Reference Skills
|
|
7
|
+
|
|
8
|
+
This directory contains **six focused skills**, one per workflow area, plus a **shared reference catalog** (`references/`) that all six draw from. Splitting by workflow keeps each skill's `SKILL.md` narrowly scoped and loadable on its own, while the shared catalog avoids duplicating method-signature facts across skills.
|
|
9
|
+
|
|
10
|
+
Every API documented here was verified against the latest 26.x release.
|
|
11
|
+
|
|
12
|
+
Each skill is self-contained — it does not assume access to Pega's internal source code, only the public runtime APIs available to any component at runtime. Only the documented public API surface is covered; methods marked internal, private, or unstable in Pega's own API documentation are intentionally excluded — treat anything not listed here as unsupported and subject to change without notice.
|
|
13
|
+
|
|
14
|
+
## The Six Skills
|
|
15
|
+
|
|
16
|
+
| Skill | Covers |
|
|
17
|
+
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
18
|
+
| [pconnect-assignment-lifecycle/SKILL.md](./pconnect-assignment-lifecycle/SKILL.md) | Opening, validating, submitting, and deleting assignments/cases; attachments; destructive-action confirmation |
|
|
19
|
+
| [pconnect-forms-and-fields/SKILL.md](./pconnect-forms-and-fields/SKILL.md) | Form/field validation, cascading dependent fields, autosave tracking, persisting custom widget UI state |
|
|
20
|
+
| [pconnect-data-subscriptions/SKILL.md](./pconnect-data-subscriptions/SKILL.md) | Data page subscriptions, application-wide pub/sub, real-time server-pushed case updates |
|
|
21
|
+
| [pconnect-case-collaboration/SKILL.md](./pconnect-case-collaboration/SKILL.md) | Participants, followers, related cases, tags |
|
|
22
|
+
| [pconnect-lists-and-views/SKILL.md](./pconnect-lists-and-views/SKILL.md) | Repeating row edits, saved list view personalization, non-assignment container item lifecycle |
|
|
23
|
+
| [pconnect-navigation-locale-genai/SKILL.md](./pconnect-navigation-locale-genai/SKILL.md) | Deep links/semantic URLs, locale switching, GenAI Assistant conversations |
|
|
24
|
+
|
|
25
|
+
Each skill's `SKILL.md` covers its own file-listing table and cookbook index. Start with the skill whose topic matches your task; consult [Architecture at a Glance](./references/architecture-overview.md) first if you're new to PCore/PConnect.
|
|
26
|
+
|
|
27
|
+
## Shared Reference Catalog
|
|
28
|
+
|
|
29
|
+
[`references/`](./references/) contains method-by-method reference files shared by all six skills above — each file documents a group of methods with a **signature**, a **purpose**, and a minimal **example**.
|
|
30
|
+
|
|
31
|
+
### PCore APIs
|
|
32
|
+
|
|
33
|
+
| File | Covers |
|
|
34
|
+
| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
35
|
+
| [references/pcore-bootstrap-registry-routing.md](./references/pcore-bootstrap-registry-routing.md) | Bootstrap lifecycle, component/module registration, routing, view resources |
|
|
36
|
+
| [references/pcore-store-context-state.md](./references/pcore-store-context-state.md) | Redux-backed store access, context tree, state machines, object diffing |
|
|
37
|
+
| [references/pcore-environment-locale-namespace.md](./references/pcore-environment-locale-namespace.md) | Environment info, locale switching, namespace utilities, auth, network status |
|
|
38
|
+
| [references/pcore-rest-data-messaging.md](./references/pcore-rest-data-messaging.md) | REST client, data pages/views, cascade, messaging, pub/sub, events, refresh, expressions |
|
|
39
|
+
| [references/pcore-case-collaboration-genai.md](./references/pcore-case-collaboration-genai.md) | Containers, attachments, feed, tags, stakeholders, user, related cases, GenAI, analytics, personalization |
|
|
40
|
+
| [references/pcore-misc-utilities.md](./references/pcore-misc-utilities.md) | Constants, behavior overrides, error handling, forms, autosave, debug, mashup bridge, field/annotation utilities, asset loader, navigation |
|
|
41
|
+
|
|
42
|
+
### PConnect APIs
|
|
43
|
+
|
|
44
|
+
| File | Covers |
|
|
45
|
+
| ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
|
|
46
|
+
| [references/pconnect-state-config.md](./references/pconnect-state-config.md) | State & configuration management, data access & property manipulation |
|
|
47
|
+
| [references/pconnect-reference-context-component.md](./references/pconnect-reference-context-component.md) | Page/view reference, context & container management, component information |
|
|
48
|
+
| [references/pconnect-case-validation-utilities.md](./references/pconnect-case-validation-utilities.md) | Case & data info accessors, validation/condition checks, sub-API access points |
|
|
49
|
+
| [references/pconnect-misc-suggestions-creation.md](./references/pconnect-misc-suggestions-creation.md) | Utilities & services, suggestions handling, component creation |
|
|
50
|
+
|
|
51
|
+
### Sub-API Deep Dives
|
|
52
|
+
|
|
53
|
+
| File | Class | Obtained via |
|
|
54
|
+
| -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------ |
|
|
55
|
+
| [references/pconnect-actions-api.md](./references/pconnect-actions-api.md) | `ActionsApi` | `pConn.getActionsApi()` |
|
|
56
|
+
| [references/pconnect-validation-api.md](./references/pconnect-validation-api.md) | `ValidationApi` | `pConn.getValidationApi()` |
|
|
57
|
+
| [references/pconnect-container-manager.md](./references/pconnect-container-manager.md) | `ContainerManager` | `pConn.getContainerManager()` |
|
|
58
|
+
| [references/pconnect-case-info-data-info-localization.md](./references/pconnect-case-info-data-info-localization.md) | `CaseInfo`, `DataInfo`, `LocalizationService` | `pConn.getCaseInfo()`, `pConn.getDataInfo()`, `pConn.getLocalizationService()` |
|
|
59
|
+
| [references/pconnect-list-actions.md](./references/pconnect-list-actions.md) | `ListActions` | `pConn.getListActions()` |
|
|
60
|
+
|
|
61
|
+
### PCore Sub-API Method Details
|
|
62
|
+
|
|
63
|
+
The files above cover each `PCore.get*()` accessor's own signature. The files below catalog the methods on the _objects those accessors return_ (for example, what you can call on the `EnvironmentInfo` object returned by `PCore.getEnvironmentInfo()`).
|
|
64
|
+
|
|
65
|
+
| File | Covers |
|
|
66
|
+
| -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
67
|
+
| [references/pcore-environment-info-details.md](./references/pcore-environment-info-details.md) | `EnvironmentInfo`, `LocaleUtils`, `AuthUtils` |
|
|
68
|
+
| [references/pcore-rest-data-details.md](./references/pcore-rest-data-details.md) | `RestClient`, `DataApi`, `DataApiUtils`, `DataPageUtils`, `DataTypeUtils`, `CascadeManager`, `MashupApi` |
|
|
69
|
+
| [references/pcore-messaging-details.md](./references/pcore-messaging-details.md) | `SemanticUrlUtils`, `MessageManager`, `PubSubUtils`, `Events`, `MessagingServiceManager` |
|
|
70
|
+
| [references/pcore-case-collaboration-details.md](./references/pcore-case-collaboration-details.md) | `ContainerUtils`, `AttachmentUtils`, `FeedUtils`, `TagUtils`, `StakeholderUtils`, `UserApi`, `CaseFollowerApi`, `CaseUtils`, `RelatedCasesApi` |
|
|
71
|
+
| [references/pcore-analytics-genai-details.md](./references/pcore-analytics-genai-details.md) | `AnalyticsUtils`, `GenAIAssistantUtils` |
|
|
72
|
+
| [references/pcore-bootstrap-init-details.md](./references/pcore-bootstrap-init-details.md) | `ComponentsRegistry`, `Initialiser`, `BootstrapUtils` (mostly portal-shell/SDK-bridge internals) |
|
|
73
|
+
| [references/pcore-store-context-details.md](./references/pcore-store-context-details.md) | `StateUtils`, `ContextTreeManager` |
|
|
74
|
+
| [references/pcore-misc-details.md](./references/pcore-misc-details.md) | `ErrorHandler`, `FormUtils`, `AutosaveUtils`, `MashupBridge`, `ConfirmDialogService`, `FieldDefaultUtils`, `AssetLoader`, `NavigationUtils` |
|
|
75
|
+
|
|
76
|
+
## Cross-Cutting Best Practices
|
|
77
|
+
|
|
78
|
+
[`best-practices/`](./best-practices/) holds guidance that applies across all six skills rather than to one topic: how to test a component that calls these APIs, security considerations when rendering/uploading/linking with them, performance patterns (debouncing, caching, cancellation), a deliberate error-handling/resiliency strategy, accessibility for async/API-driven state, GenAI Assistant integration patterns, and a symptom-indexed troubleshooting guide for the handful of mistakes that recur across every topic area.
|
|
79
|
+
|
|
80
|
+
| File | Use when |
|
|
81
|
+
| ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
|
|
82
|
+
| [best-practices/testing-pconnect-components.md](./best-practices/testing-pconnect-components.md) | Writing or reviewing a Jest/React Testing Library test for a component that calls `PCore.*` or `pConn.*` |
|
|
83
|
+
| [best-practices/security-considerations.md](./best-practices/security-considerations.md) | Rendering feed/comment/GenAI content, building deep links, handling uploads, authenticating, or logging errors |
|
|
84
|
+
| [best-practices/performance-and-efficiency.md](./best-practices/performance-and-efficiency.md) | Debouncing input, caching/invalidating data pages, canceling stale requests, or avoiding redundant subscriptions |
|
|
85
|
+
| [best-practices/error-handling-and-resiliency.md](./best-practices/error-handling-and-resiliency.md) | Deciding how a failed call should behave (recover/retry/degrade/block), or containing a failure so it doesn't spread |
|
|
86
|
+
| [best-practices/accessibility-for-async-components.md](./best-practices/accessibility-for-async-components.md) | Announcing loading/success/error states, managing focus after navigation, or localizing status text |
|
|
87
|
+
| [best-practices/genai-assistant-integration-patterns.md](./best-practices/genai-assistant-integration-patterns.md) | Starting/continuing a GenAI Assistant or Agent conversation, streaming responses, or handling `rewriteText` results |
|
|
88
|
+
| [best-practices/troubleshooting-common-pitfalls.md](./best-practices/troubleshooting-common-pitfalls.md) | A method is called correctly per its signature but the behavior is still wrong — search by symptom, not method name |
|
|
89
|
+
|
|
90
|
+
## Finding a Specific Method Fast
|
|
91
|
+
|
|
92
|
+
Don't guess which file covers a method by category alone — search for it directly, using the method's exact name:
|
|
93
|
+
|
|
94
|
+
- Every top-level `PCore.*` / `pConn.*` method is a markdown heading in the form `` `methodName(params)` ``.
|
|
95
|
+
- Every method on a _sub-API_ (an object returned by another method — for example, what `PCore.getEnvironmentInfo()` returns) is a row in a `| Method | Signature | Purpose |` table, with the method name as the first cell, still wrapped in backticks.
|
|
96
|
+
- Both forms are plain text and consistently backtick-wrapped, so a literal (non-regex) full-text search for the bare method name — for example `getDebouncedSubject` or `isFormValid` — across `references/*.md` will find it regardless of which file or which form (heading vs. table row) it's in. Do not restrict a search to `^## ` headings only, or sub-API table methods will be missed.
|
|
97
|
+
- If you only know the class name (e.g. `FormUtils`, `EnvironmentInfo`), search for `` (via `PCore.get...` `` or check the "PCore Sub-API Method Details" / "Sub-API Deep Dives" tables above, which map every class to its file.
|
|
98
|
+
- If the question is about **order, sequencing, cleanup, or combining more than one method** to complete a task (rather than a single method's signature), check the relevant skill's `cookbooks/README.md` first — see the table above for which skill covers which topic — before assembling your own sequence from individual reference files.
|
|
99
|
+
|
|
100
|
+
## Conventions Used Across These Skills
|
|
101
|
+
|
|
102
|
+
- Examples use `pConn` for a `PConnect` instance and `getPConnect` for the prop function that returns one — the standard naming convention in Constellation component code.
|
|
103
|
+
- Examples are minimal and illustrative, written directly from each method's documented signature and behavior — they demonstrate the calling pattern, not a specific production implementation.
|
|
104
|
+
- A method's return type notes whether it resolves a `Promise` — always handle the rejection case for any API that returns one.
|
|
105
|
+
- Only publicly documented, supported methods are included. If you find a method on `PCore` or `pConn` at runtime that isn't listed here, treat it as unsupported and avoid depending on it.
|
|
106
|
+
|
|
107
|
+
## Coverage Roadmap
|
|
108
|
+
|
|
109
|
+
### Documented across these skills
|
|
110
|
+
|
|
111
|
+
- PCore top-level APIs (`PCore.*`) and PConnect / component-context APIs (`pConn.*`).
|
|
112
|
+
- Sub-API deep dives: `ActionsApi`, `ValidationApi`, `ContainerManager`, `CaseInfo`, `DataInfo`, `LocalizationService`, `ListActions`.
|
|
113
|
+
- Every sub-API class reachable from a documented `PCore.get*()` accessor now has its own methods cataloged (see the "PCore Sub-API Method Details" table above): `EnvironmentInfo`, `LocaleUtils`, `AuthUtils`, `NamespaceUtils`, `NetworkStatusManager`, `RestClient`, `DataApi`, `DataApiUtils`, `DataPageUtils`, `DataTypeUtils`, `CascadeManager`, `MashupApi`, `SemanticUrlUtils`, `MessageManager`, `PubSubUtils`, `Events`, `MessagingServiceManager`, `ExpressionEngine`, `ContainerUtils`, `AttachmentUtils`, `FeedUtils`, `TagUtils`, `StakeholderUtils`, `UserApi`, `CaseFollowerApi`, `CaseUtils`, `RelatedCasesApi`, `AnalyticsUtils`, `GenAIAssistantUtils`, `GenAIUtils`, `PersonalizationUtils`, `AsynchronousUtils`, `ComponentsRegistry`, `ViewResources`, `Initialiser`, `BootstrapUtils`, `StateUtils`, `ContextTreeManager`, `ErrorHandler`, `FormUtils`, `AutosaveUtils`, `MashupBridge`, `ConfirmDialogService`, `FieldUtils`, `FieldDefaultUtils`, `AnnotationUtils`, `AssetLoader`, `NavigationUtils`.
|
|
114
|
+
- Some large classes (`EnvironmentInfo`, `ContainerUtils`, `CaseUtils`, `DataApi`, `AssetLoader`, `DataApiUtils`, `DataPageUtils`) are documented as a **curated subset** — methods that are purely internal framework plumbing (low-level query builders, container bookkeeping used only by the framework itself, and so on) are intentionally omitted to keep the signal-to-noise ratio high for component authors.
|
|
115
|
+
- Composed, multi-method recipes for common real-world tasks (see each skill's `cookbooks/README.md`) — these chain together methods already cataloged elsewhere and call out ordering/cleanup pitfalls.
|
|
116
|
+
- Cross-cutting testing, security, performance, error-handling, accessibility, GenAI-integration, and troubleshooting guidance (see [`best-practices/`](./best-practices/)) that applies across all six skills rather than to one topic.
|
|
117
|
+
|
|
118
|
+
### Permanently out of scope
|
|
119
|
+
|
|
120
|
+
The following classes are only reachable through a `PCore.get*()` accessor that is itself unsupported/private, so there is no supported way to obtain them — they are intentionally not documented anywhere in these skills: `RuntimeParamsAPI`, `RemoteCase`, `MetadataUtils`, `Debugger`, `DeferLoadManager`, `RefreshManager`, `AccessPrivilege`, `ObjectTransformer`, `RoutingUtils`, `CoexistenceManager`.
|
|
121
|
+
|
|
122
|
+
## Related Documentation
|
|
123
|
+
|
|
124
|
+
- [Using PCore and PConnect public APIs](https://docs.pega.com/bundle/pcore-pconnect/page/pcore-pconnect-public-apis/api/using-pcore-pconnect-public-apis.html) — official entry point for the public API spec.
|
|
125
|
+
- [Accessing APIs from the PCore object](https://docs.pega.com/bundle/pcore-pconnect/page/pcore-pconnect-public-apis/api/accessing-apis-pcore-object.html)
|
|
126
|
+
- [Accessing APIs from the PConnect object](https://docs.pega.com/bundle/pcore-pconnect/page/pcore-pconnect-public-apis/api/accessing-apis-pconnect-object.html)
|
|
127
|
+
- [Working with Containers](https://docs.pega.com/bundle/pcore-pconnect/page/pcore-pconnect-public-apis/api/working-containers.html)
|
|
128
|
+
- [Working with Messaging Service](https://docs.pega.com/bundle/pcore-pconnect/page/pcore-pconnect-public-apis/api/working-messaging-service.html)
|
|
129
|
+
- [Initializing the Constellation environment](https://docs.pega.com/bundle/pcore-pconnect/page/pcore-pconnect-public-apis/api/initializing-constellation-environment.html)
|
|
130
|
+
- [Caching and invalidating data pages](https://docs.pega.com/bundle/pcore-pconnect/page/pcore-pconnect-public-apis/api/caching-invalidating-constellation-data-pages.html)
|
|
131
|
+
- [Invoking a savable data page](https://docs.pega.com/bundle/pcore-pconnect/page/pcore-pconnect-public-apis/api/invoking-savable-data-page.html)
|
|
132
|
+
- [Using type definitions for PCore and PConnect APIs](https://docs.pega.com/bundle/pcore-pconnect/page/pcore-pconnect-public-apis/api/using-type-definitions-pcore-pconnect-apis.html)
|
|
133
|
+
- [Pega Academy: PCore and PConnect APIs in Constellation DX components](https://academy.pega.com/topic/pcore-and-pconnect-apis-constellation-dx-components/v1)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Cross-Cutting Best Practices — Index
|
|
3
|
+
description: Testing, security, performance, error-handling, accessibility, GenAI-integration, and troubleshooting guidance that applies across all the PCore/PConnect skills, indexed by topic and symptom for AI/RAG retrieval.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cross-Cutting Best Practices
|
|
7
|
+
|
|
8
|
+
> Shared by all the skills in the [skills index](../README.md).
|
|
9
|
+
|
|
10
|
+
The skills and their `references/`/`cookbooks/` folders document individual methods and multi-method recipes. This folder is different: it covers practices that apply **regardless of which topic you're working in** — how to test a component that calls these APIs, how to use them without introducing a security or accessibility issue, how to integrate GenAI Assistant conversations specifically, and how to recognize/fix the same handful of mistakes that show up across every topic area.
|
|
11
|
+
|
|
12
|
+
## Guides
|
|
13
|
+
|
|
14
|
+
| Guide | Use when |
|
|
15
|
+
| ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
16
|
+
| [Testing components that use PCore/PConnect](./testing-pconnect-components.md) | Writing or reviewing a Jest/React Testing Library test for a component that calls `PCore.*` or `pConn.*` |
|
|
17
|
+
| [Security considerations](./security-considerations.md) | Rendering feed/comment/GenAI content, building deep links, handling uploads, authenticating, or logging errors |
|
|
18
|
+
| [Performance & efficiency](./performance-and-efficiency.md) | Debouncing input, caching/invalidating data pages, canceling stale requests, or avoiding redundant subscriptions |
|
|
19
|
+
| [Error handling & resiliency](./error-handling-and-resiliency.md) | Deciding how a failed call should behave (recover/retry/degrade/block), or containing a failure so it doesn't spread |
|
|
20
|
+
| [Accessibility for async, API-driven components](./accessibility-for-async-components.md) | Announcing loading/success/error states, managing focus after navigation, or localizing status text |
|
|
21
|
+
| [GenAI Assistant integration patterns](./genai-assistant-integration-patterns.md) | Starting/continuing a GenAI Assistant or Agent conversation, streaming responses, or handling `rewriteText` results |
|
|
22
|
+
| [Troubleshooting common pitfalls](./troubleshooting-common-pitfalls.md) | Something calls the documented method correctly but the behavior is still wrong — search by symptom, not method name |
|
|
23
|
+
|
|
24
|
+
Nothing in this folder introduces a new API — every recommendation composes methods already cataloged in [`../references/`](../references/) or sequenced in a skill's `cookbooks/`. Use the reference/cookbook links inside each guide for exact signatures and call order.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Accessibility for Async, API-Driven Components
|
|
3
|
+
description: How to announce loading/success/error states, manage focus after navigation, and localize status text for components driven by PCore/PConnect calls, aligned with WCAG 2.2 AA.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Accessibility for Async, API-Driven Components
|
|
7
|
+
|
|
8
|
+
> Part of [Cross-Cutting Best Practices](./README.md).
|
|
9
|
+
|
|
10
|
+
Every state transition covered elsewhere in these guides — a pending `Promise`, a resolved success/empty/error result, a navigation to a new view — is also a moment a screen reader or keyboard-only user can silently miss if it isn't announced or focused correctly. This guide covers where WCAG 2.2 AA requirements intersect with PCore/PConnect usage specifically; it isn't a general accessibility reference.
|
|
11
|
+
|
|
12
|
+
## Announce Async State Changes With a Live Region, Not Just a Visual Change
|
|
13
|
+
|
|
14
|
+
The four states covered in [Testing: the four states of an API-driven component](./testing-pconnect-components.md#test-the-four-states-of-an-api-driven-component) (loading, success, empty, error) are all status messages under WCAG 4.1.3 Status Messages. A spinner that only changes visually, or an error message that only appears in the DOM without the right role, is invisible to a screen reader user unless focus already happens to be there:
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
return (
|
|
18
|
+
<>
|
|
19
|
+
{isLoading && <span role='status'>Loading case details…</span>}
|
|
20
|
+
{error && <span role='alert'>{userFacingErrorMessage}</span>}
|
|
21
|
+
</>
|
|
22
|
+
);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Use `role="status"` (equivalent to `aria-live="polite"`) for routine completions and `role="alert"` (equivalent to `aria-live="assertive"`) only for genuinely urgent failures — reserve `alert` the same way the [Error Handling & Resiliency](./error-handling-and-resiliency.md#choose-a-deliberate-strategy-recover-retry-degrade-or-block) guide reserves the "block" strategy, for failures that actually need immediate attention. The live region container should already exist in the DOM before the async call resolves; don't inject the container and its message at the same time — a live region added to the DOM at the same moment as its content is often not announced.
|
|
26
|
+
|
|
27
|
+
## Localize Status Text, Don't Just Make It Announceable
|
|
28
|
+
|
|
29
|
+
A correctly-roled status message that's hardcoded in one language is still an accessibility (and localization) gap for users on a different locale. Pull status/error copy through `pConn.getLocalizationService().getLocalizedText(...)`/`getLocalizedMessage(...)` (see [pconnect-case-info-data-info-localization.md](../references/pconnect-case-info-data-info-localization.md)) the same way any other user-facing string in these components must be — never hardcode display text. This applies doubly to async status text, since it's easy to hardcode a "quick" loading/error string and forget it needs the same localization treatment as the rest of the view.
|
|
30
|
+
|
|
31
|
+
## Move Focus After a Navigation-Driven View Change
|
|
32
|
+
|
|
33
|
+
When a component navigates to a new view or case — via `SemanticUrlUtils.getResolvedSemanticURL`/a container item open, or after `PCore.switchLocale` re-renders localized content — the resulting DOM change is a route change under WCAG 2.4.3 Focus Order: focus must be set to an appropriate element (typically the new view's heading, or a confirmation message for an in-place save) after the update, rather than being left on a now-stale or removed trigger element:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
const headingRef = useRef<HTMLHeadingElement>(null);
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (viewHasLoaded) headingRef.current?.focus();
|
|
40
|
+
}, [viewHasLoaded]);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Don't Let a Loading Overlay Trap or Skip Keyboard Focus
|
|
44
|
+
|
|
45
|
+
A full-panel loading overlay shown while a `Promise` is pending should either disable focus on the content underneath it (so Tab doesn't silently move focus to now-hidden controls) or, if it's a true modal overlay, provide a documented keyboard exit (for example, Escape) as required by WCAG 2.1.2 No Keyboard Trap for any intentional focus trap. An overlay that visually covers content but leaves the covered controls still tab-reachable is a common, easy-to-miss defect specific to async loading states.
|
|
46
|
+
|
|
47
|
+
## Checklist
|
|
48
|
+
|
|
49
|
+
- Every loading/success/empty/error transition has a corresponding `role="status"`/`role="alert"` live region, not just a visual change.
|
|
50
|
+
- Live region containers exist in the DOM before the async result that populates them arrives.
|
|
51
|
+
- Status and error text is localized through `LocalizationService`, not hardcoded.
|
|
52
|
+
- Focus moves to the new view's heading (or a confirmation message) after a navigation or in-place content swap, rather than staying on a stale trigger.
|
|
53
|
+
- A loading overlay either disables the controls it covers or provides a documented keyboard exit if it's an intentional modal trap.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Error Handling & Resiliency
|
|
3
|
+
description: How to choose a deliberate recover/retry/degrade/block strategy for PCore/PConnect failures, avoid silent failures, and contain them so one broken call doesn't take down a whole view.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Error Handling & Resiliency
|
|
7
|
+
|
|
8
|
+
> Part of [Cross-Cutting Best Practices](./README.md).
|
|
9
|
+
|
|
10
|
+
Nearly every method in these skills that crosses the network returns a `Promise` that can reject. This guide covers how to handle that rejection deliberately, rather than leaving it to whatever the default behavior happens to be.
|
|
11
|
+
|
|
12
|
+
## Choose a Deliberate Strategy: Recover, Retry, Degrade, or Block
|
|
13
|
+
|
|
14
|
+
Every call that can fail should have an intentional answer to "what happens when this rejects" — picked at the time you write the call, not left to be discovered later. Four broad strategies, roughly in order of how disruptive they are to the user:
|
|
15
|
+
|
|
16
|
+
| Strategy | When to use it | Example |
|
|
17
|
+
| ----------- | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
18
|
+
| **Recover** | The failure has an obvious, safe fallback value. | An optional lookup data page fails — render the field without the enrichment instead of blocking. |
|
|
19
|
+
| **Retry** | The failure is likely transient (network blip) and the operation is safe to repeat. | A read-only data page fetch fails once — retry it, not a non-idempotent submit (see below). |
|
|
20
|
+
| **Degrade** | Part of the view can still be useful without the failed piece. | A GenAI Assistant suggestion fails to load — show the rest of the form, omit the suggestion panel. |
|
|
21
|
+
| **Block** | The failure means continuing would be incorrect or unsafe (e.g. an assignment submit or case delete). | `ActionsApi.finishAssignment` fails — stop, surface the error, do not proceed as if it succeeded. |
|
|
22
|
+
|
|
23
|
+
Pick the strategy deliberately for each call; don't let every failure default to the same generic error message regardless of how disruptive the underlying failure actually is.
|
|
24
|
+
|
|
25
|
+
## Never Fail Silently
|
|
26
|
+
|
|
27
|
+
An empty `catch` block, or a rejected promise nobody attaches a handler to, hides the failure from both the user and anyone debugging it later. Every failure path needs an observable outcome: a visible error state in the UI, a call to `ErrorHandler`, or at minimum a re-thrown/logged error — never a silent no-op.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
// Avoid: the user has no idea the save failed, and nothing is logged.
|
|
31
|
+
saveChanges().catch(() => {});
|
|
32
|
+
|
|
33
|
+
// Prefer: the failure is visible, and the strategy (recover/retry/degrade/block) is explicit.
|
|
34
|
+
try {
|
|
35
|
+
await saveChanges();
|
|
36
|
+
} catch (error) {
|
|
37
|
+
setErrorState('Your changes could not be saved. Please try again.');
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Idempotency Before Retrying a Submit
|
|
42
|
+
|
|
43
|
+
Retrying is only safe when repeating the call can't cause a duplicate effect. A read (`getPageDataAsync`, `getData`) is generally safe to retry. A write that isn't idempotent — `ActionsApi.finishAssignment`, `deleteWork`, `AttachmentUtils.uploadAttachment` — is not automatically safe to retry blindly: if the first attempt actually succeeded server-side and only the client-side confirmation was lost (e.g. a network drop after the request was sent), a naive retry can duplicate the submit or the upload. See [graceful-submit-failure](../pconnect-assignment-lifecycle/cookbooks/graceful-submit-failure.md) for the documented pattern — confirm the actual outcome (e.g. re-check case/assignment state) before assuming a retry is safe, rather than resubmitting on every failure by default.
|
|
44
|
+
|
|
45
|
+
## Distinguish Cancellation From Failure
|
|
46
|
+
|
|
47
|
+
A request canceled on purpose (because a newer one superseded it, or the component unmounted) is not an error and shouldn't be shown as one. Check `RestClient.isRequestCanceled(error)` (see [pcore-rest-data-details.md](../references/pcore-rest-data-details.md)) before running your failure-handling path:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
invokeRestApi(routeKey, payload).catch((error) => {
|
|
51
|
+
if (PCore.getRestClient().isRequestCanceled(error)) return; // intentional — not a failure
|
|
52
|
+
showErrorState(error);
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Degrade Gracefully When Offline
|
|
57
|
+
|
|
58
|
+
`NetworkUtils.isOnline()`/`onStatusChange(callback)` (see [pcore-environment-locale-namespace.md](../references/pcore-environment-locale-namespace.md)) let a component know about connectivity changes rather than discovering them only via a failed request. When offline, prefer disabling/queuing calls that require the network (submits, uploads) with a clear "you're offline" state, over letting each one fail individually and showing a wall of unrelated error messages for what is really one underlying cause.
|
|
59
|
+
|
|
60
|
+
## Contain Failures With Boundaries
|
|
61
|
+
|
|
62
|
+
A single custom component throwing during render shouldn't be able to blank out an entire page around it. Wrap custom widget rendering in a React error boundary so a failure in one component degrades to an error state for that component's region, not the whole view — this is standard React practice and applies directly here since a rejected `Promise` mishandled inside a component (e.g. an unhandled rejection that triggers a render-time throw) is a common way for one bad API call to take down an unrelated part of the page.
|
|
63
|
+
|
|
64
|
+
## Give Users an Actionable Message, Not a Stack Trace
|
|
65
|
+
|
|
66
|
+
`ErrorHandler.setGenericFailedMessage(message)`/`getGenericFailedMessage()` (see [pcore-misc-details.md](../references/pcore-misc-details.md)) control the fallback message shown when a component fails to render. Set this to something a user can act on ("Something went wrong loading this section. Try refreshing the page.") rather than leaving a default that isn't meaningful to an end user — and prefer a specific, component-level error message over the generic fallback whenever the component knows what actually failed. Never surface the raw rejection value, an internal error code, or a stack trace to the user (see [Security Considerations](./security-considerations.md#dont-leak-sensitive-details-through-error-handling)).
|
|
67
|
+
|
|
68
|
+
## Distinguish a Validation Rejection From a System Failure
|
|
69
|
+
|
|
70
|
+
`ValidationApi.validate(value, propertyName?)`/`validateEmail(value, options?)` (see [pconnect-validation-api.md](../references/pconnect-validation-api.md)) return a result object describing _why the input was invalid_ — this is not the same category of failure as a rejected `Promise` from a network call, and the two need different handling. A validation result belongs inline, next to the field, worded around what the user should fix; a system/network failure belongs in a broader error state and is worded around what went wrong with the operation, not the input. Don't route both through the same generic error-message path — collapsing them makes a simple "enter a valid email" correction look as alarming as a failed save, and makes a real system failure easy to dismiss as "just a typo."
|
|
71
|
+
|
|
72
|
+
## Retry With a Backoff and a Limit, Never Forever
|
|
73
|
+
|
|
74
|
+
When a retry strategy is appropriate (see the table above), retrying immediately and indefinitely can turn a transient blip into a self-inflicted flood of requests against a server that's already struggling. Space retries out (for example, doubling the delay each attempt) and cap the number of attempts, surfacing the failure state once the cap is reached instead of retrying silently forever:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
async function fetchWithRetry(fn: () => Promise<unknown>, attempts = 3, delayMs = 500): Promise<unknown> {
|
|
78
|
+
try {
|
|
79
|
+
return await fn();
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (attempts <= 1) throw error;
|
|
82
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
83
|
+
return fetchWithRetry(fn, attempts - 1, delayMs * 2);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Handle a Case Locked or Changed by Another User as an Expected Outcome
|
|
89
|
+
|
|
90
|
+
A submit, save, or field update can fail specifically because another user (or another tab/session for the same user) modified or locked the same case/assignment first — this is a distinct, expected failure mode in a collaborative system, not the same as a generic network error. Recognize it from the specific failure the call surfaces and give the user a clear next step ("This case was updated by someone else — refresh to see the latest version before continuing") rather than the generic failed-save message, and don't silently overwrite the other change by blindly retrying the original submit.
|
|
91
|
+
|
|
92
|
+
## Guard Against a Call That Never Resolves
|
|
93
|
+
|
|
94
|
+
A `Promise` that neither resolves nor rejects (a hung request, a subscription callback that never fires) leaves a loading state on screen indefinitely with no path to an error state. For a call where the framework doesn't already provide a timeout, wrap it with your own bound so the UI can fall back to a visible error/timeout state instead of spinning forever:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
|
|
98
|
+
return Promise.race([promise, new Promise<T>((_, reject) => setTimeout(() => reject(new Error('timed out')), ms))]);
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Prefer this only as a defensive fallback around calls with no first-class cancellation, not as a substitute for `RestClient.getCancelTokenSource()` (see [Performance & Efficiency: cancel requests that are no longer needed](./performance-and-efficiency.md#cancel-requests-that-are-no-longer-needed)) where that's available — an explicit cancel also stops the server from doing wasted work, where a client-side timeout alone does not.
|
|
103
|
+
|
|
104
|
+
## Checklist
|
|
105
|
+
|
|
106
|
+
- Decide recover/retry/degrade/block for each call at the time you write it, not by default.
|
|
107
|
+
- Never leave a rejected promise unhandled or a `catch` block empty — every failure needs an observable outcome.
|
|
108
|
+
- Only retry idempotent operations automatically; confirm actual outcome before retrying a non-idempotent submit/upload/delete.
|
|
109
|
+
- Check `isRequestCanceled` before treating a canceled request as a failure.
|
|
110
|
+
- Use `NetworkUtils` to detect offline state proactively rather than reacting to a pile of individually failed requests.
|
|
111
|
+
- Wrap custom component rendering in an error boundary so one failure doesn't blank the whole page.
|
|
112
|
+
- Show a clear, actionable, generic message to the user; never a raw error object or stack trace.
|
|
113
|
+
- Route validation results and system failures through different UI treatments — don't make a field-level typo look like a broken save.
|
|
114
|
+
- Space out and cap any automatic retry loop; never retry immediately and indefinitely.
|
|
115
|
+
- Give a case-locked/changed-by-another-user failure its own clear message and next step, instead of the generic failed-save path.
|
|
116
|
+
- Guard a call with no built-in cancellation/timeout so a hung request can't leave a loading state on screen forever.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: GenAI Assistant Integration Patterns
|
|
3
|
+
description: Conversation lifecycle, state rehydration, streaming, feedback, and safety-gate patterns for building custom components on top of GenAIAssistantUtils and GenAIUtils.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GenAI Assistant Integration Patterns
|
|
7
|
+
|
|
8
|
+
> Part of [Cross-Cutting Best Practices](./README.md).
|
|
9
|
+
|
|
10
|
+
`GenAIAssistantUtils` and `GenAIUtils` (see [pcore-analytics-genai-details.md](../references/pcore-analytics-genai-details.md) and [pcore-case-collaboration-genai.md](../references/pcore-case-collaboration-genai.md)) let a custom component start and continue a conversation with a GenAI Assistant or Agent, and rewrite text. This guide covers the integration patterns specific to these APIs — for content-safety concerns (prompt injection, sanitizing model output), see [Security Considerations](./security-considerations.md); for the general async-state and mocking patterns, see [Testing](./testing-pconnect-components.md#testing-genai-assistant-conversations) and [Error Handling & Resiliency](./error-handling-and-resiliency.md).
|
|
11
|
+
|
|
12
|
+
## Gate on `isGenAIEnabled()` Before Rendering Any GenAI Affordance
|
|
13
|
+
|
|
14
|
+
Not every environment has GenAI enabled. Check `PCore.getEnvironmentInfo().isGenAIEnabled()` before rendering a GenAI-dependent button, panel, or suggestion — and treat "disabled" as an expected, silent state (simply don't render the affordance), not an error condition to surface to the user:
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
const genAIEnabled = PCore.getEnvironmentInfo().isGenAIEnabled();
|
|
18
|
+
|
|
19
|
+
if (!genAIEnabled) return null; // no GenAI affordance in this environment — not an error
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Rehydrate Conversation History Instead of Trusting Local State Alone
|
|
23
|
+
|
|
24
|
+
`createConversation`/`createConversationForAgent` start a conversation that's tracked server-side; `getMessages`/`getMessagesForAgent` and the paginated `getConversations`/`getConversationsForAgent` retrieve what's already there. Local component state built up as the user sends/receives messages in the current session is a convenient cache, but it is not the source of truth — on mount (or when reopening a previously started conversation), call `getMessages(assistantID, conversationID, context)` to rehydrate rather than assuming a fresh component instance starts with no history (see [Troubleshooting: a GenAI Assistant conversation's history is empty after a page reload](./troubleshooting-common-pitfalls.md#a-genai-assistant-conversations-history-is-empty-after-a-page-reload)).
|
|
25
|
+
|
|
26
|
+
## Render Incrementally When `enableStreaming` Is Used
|
|
27
|
+
|
|
28
|
+
`sendMessage` supports an `enableStreaming` option for a more responsive, incremental reply rather than waiting for the full response. If a component uses streaming, render the partial response as it arrives (with its own visible "in progress" indicator distinct from a fully-loaded message) rather than buffering the whole thing client-side and only rendering once — buffering defeats the purpose of requesting streaming in the first place and leaves the user staring at nothing for longer than necessary.
|
|
29
|
+
|
|
30
|
+
## Handle `GenAIUtils.rewriteText`'s Discriminated Result Explicitly
|
|
31
|
+
|
|
32
|
+
`rewriteText({ originalText, rewriteAction })` resolves an object shaped as either `{ success: true, rewrittenText }` or a failure shape — it does not reject on a model-side failure the way a network error would. Check `result.success` explicitly and handle both branches (see [Testing: testing GenAI Assistant conversations](./testing-pconnect-components.md#testing-genai-assistant-conversations)); a component that only reads `result.rewrittenText` without checking `success` first will render `undefined` on failure instead of a clear fallback message.
|
|
33
|
+
|
|
34
|
+
## Use the Like/Unlike Feedback Loop, Don't Build a Parallel One
|
|
35
|
+
|
|
36
|
+
`likeAgentMessage`/`unLikeAgentMessage(agentID, conversationID, messageID, context, feedbackText?)` are the documented mechanism for capturing a user's reaction to an Agent's message, including optional free-text feedback on removal of a like. Route thumbs-up/thumbs-down UI through these calls rather than inventing a separate feedback-collection mechanism — this keeps feedback attached to the same conversation/message record the platform already tracks, rather than living in a disconnected system nobody correlates back to the conversation.
|
|
37
|
+
|
|
38
|
+
## Treat a Long-Running Conversation Call Like Any Other Async Operation
|
|
39
|
+
|
|
40
|
+
Nothing about `sendMessage`/`sendMessageForAgent` exempts it from the general patterns elsewhere in this folder: it's a `Promise` that can reject (see [Error Handling & Resiliency](./error-handling-and-resiliency.md)), a user can trigger a new message before a previous one resolves (consider whether to disable the input or track/cancel the stale one, per [Performance & Efficiency: cancel requests that are no longer needed](./performance-and-efficiency.md#cancel-requests-that-are-no-longer-needed)), and its pending/success/error states need the same live-region treatment as any other async UI (see [Accessibility for Async, API-Driven Components](./accessibility-for-async-components.md)).
|
|
41
|
+
|
|
42
|
+
## Checklist
|
|
43
|
+
|
|
44
|
+
- Check `PCore.getEnvironmentInfo().isGenAIEnabled()` before rendering any GenAI-dependent UI; treat "disabled" as a silent no-render, not an error.
|
|
45
|
+
- Rehydrate conversation history via `getMessages`/`getConversations` on mount rather than relying only on in-session local state.
|
|
46
|
+
- Render streamed responses incrementally, not buffered until fully complete, when `enableStreaming` is used.
|
|
47
|
+
- Explicitly branch on `rewriteText`'s `success` field rather than assuming the happy-path shape.
|
|
48
|
+
- Route message feedback through `likeAgentMessage`/`unLikeAgentMessage` instead of a separate, disconnected mechanism.
|
|
49
|
+
- Apply the same async-state, cancellation, and accessibility patterns used elsewhere in these guides to conversation calls — they aren't a special case.
|