@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.
- package/README.md +6 -2
- package/package.json +48 -64
- 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
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Troubleshooting Common Pitfalls
|
|
3
|
+
description: Symptom-indexed guide to the handful of mistakes that recur across all the PCore/PConnect skills — search by what's going wrong, not by method name.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Troubleshooting Common Pitfalls
|
|
7
|
+
|
|
8
|
+
> Part of [Cross-Cutting Best Practices](./README.md).
|
|
9
|
+
|
|
10
|
+
The reference files document what each method does; this guide documents what tends to go wrong even when a method is called correctly according to its signature. Search this page by symptom before assuming a method is broken or under-documented.
|
|
11
|
+
|
|
12
|
+
## Systematic Diagnosis Checklist
|
|
13
|
+
|
|
14
|
+
Before assuming a documented method is broken, work through this order — most "the API doesn't work" reports turn out to be one of these:
|
|
15
|
+
|
|
16
|
+
1. **Check the browser console for the actual error.** A `TypeError`, a rejected-promise stack, or a validation warning almost always names the real problem more precisely than the symptom you started with.
|
|
17
|
+
2. **Re-read the exact signature in the relevant `references/` file.** A missing/misordered required parameter is the single most common root cause — verify argument order and required vs. optional parameters before suspecting the method itself.
|
|
18
|
+
3. **Confirm the method exists in the version you're running against.** If it's a recently-documented method, check whether the runtime/mock you're testing against is old enough to not implement it yet (see the entry below on this exact symptom).
|
|
19
|
+
4. **Check subscribe/unsubscribe and async ordering.** A large share of "state is stale" or "still running after unmount" bugs are a missing cleanup or an out-of-order async resolution, not a wrong method call — see the dedicated entries below.
|
|
20
|
+
5. **If it's failing only in a test, check the mock, not the component.** A test mock can drift out of sync with the real method's shape; confirm the failure reproduces against the real API (or a fresh mock built directly from the reference file) before debugging the component itself.
|
|
21
|
+
|
|
22
|
+
## `TypeError: pConn.someMethod is not a function` (or the same for `PCore.someMethod`)
|
|
23
|
+
|
|
24
|
+
**Cause:** the method exists in a newer platform version than the one the current mock, test, or runtime is on. This is especially common right after a new `PConnect`/`PCore` method is added — existing Jest mocks of `pConn`/`PCore` across the codebase don't automatically gain new methods.
|
|
25
|
+
|
|
26
|
+
**Fix:** call new/optional methods with optional chaining, `pConn.someMethod?.()`, rather than assuming every method is always present. Don't remove the optional chaining just because it works locally — other call sites or older mocks may not implement the method yet.
|
|
27
|
+
|
|
28
|
+
## `MessageManager.clearMessages(...)` runs without error, but the message is still shown
|
|
29
|
+
|
|
30
|
+
**Cause:** `type` was omitted from the options object. The underlying filter only removes messages whose `type` matches what you passed — omitting it means nothing matches, so nothing is removed, silently.
|
|
31
|
+
|
|
32
|
+
**Fix:** always pass the `type` that matches the message you're clearing (for example, `'error'`), alongside `category`/`context`, when calling `PCore.getMessageManager().clearMessages(...)` (see [pcore-messaging-details.md](../references/pcore-messaging-details.md)).
|
|
33
|
+
|
|
34
|
+
## Deleting a case throws, or deletes the wrong thing
|
|
35
|
+
|
|
36
|
+
**Cause:** `ActionsApi.deleteWork` and `ActionsApi.deleteCaseInCreateStage` are not interchangeable — one is for a case that has already left its create stage (persisted, has a confirmed ID), the other is for a case still being created.
|
|
37
|
+
|
|
38
|
+
**Fix:** branch on the case's stage before choosing which method to call — see [safe-case-deletion](../pconnect-assignment-lifecycle/cookbooks/safe-case-deletion.md).
|
|
39
|
+
|
|
40
|
+
## Subscription callback keeps firing after the component unmounts
|
|
41
|
+
|
|
42
|
+
**Cause:** the unsubscribe/cancel function returned by `subscribe` (data page, `PubSubUtils`, or `MessagingServiceManager`) was never called. This can also surface as a React warning about updating state on an unmounted component.
|
|
43
|
+
|
|
44
|
+
**Fix:** always store and invoke the returned unsubscribe handle in a cleanup function (e.g. a `useEffect` cleanup) — see [data-page-subscription-cleanup](../pconnect-data-subscriptions/cookbooks/data-page-subscription-cleanup.md), [pubsub-cleanup](../pconnect-data-subscriptions/cookbooks/pubsub-cleanup.md), and [realtime-case-subscription](../pconnect-data-subscriptions/cookbooks/realtime-case-subscription.md).
|
|
45
|
+
|
|
46
|
+
## Locale switched, but already-rendered labels didn't update
|
|
47
|
+
|
|
48
|
+
**Cause:** `PCore.switchLocale(locale)` changes the active locale going forward — it does not retroactively re-resolve strings that a component already fetched and stored (e.g. in state) before the switch.
|
|
49
|
+
|
|
50
|
+
**Fix:** re-call `pConn.getLocalizationService().getLocalizedText(...)`/`getLocalizedMessage(...)` after the locale switch resolves, for any string held in component state — see [locale-switch-and-relocalize](../pconnect-navigation-locale-genai/cookbooks/locale-switch-and-relocalize.md).
|
|
51
|
+
|
|
52
|
+
## Two users' (or two components') personalization saves overwrite each other
|
|
53
|
+
|
|
54
|
+
**Cause:** `PersonalizationUtils` saves are keyed by `listComponentID` — if two different components/instances reuse the same ID, their saves collide, last write wins.
|
|
55
|
+
|
|
56
|
+
**Fix:** make `listComponentID` unique and stable per component instance (max 32 chars) — see [view-personalization](../pconnect-lists-and-views/cookbooks/view-personalization.md).
|
|
57
|
+
|
|
58
|
+
## A cascading dependent field doesn't refresh after the field it depends on changes
|
|
59
|
+
|
|
60
|
+
**Cause:** the dependent field's cascade subscription wasn't set up before the source field's change was dispatched, or the subscription's cleanup fired too early.
|
|
61
|
+
|
|
62
|
+
**Fix:** follow the subscribe-before-trigger ordering in [cascading-dependent-fields](../pconnect-forms-and-fields/cookbooks/cascading-dependent-fields.md).
|
|
63
|
+
|
|
64
|
+
## `ContainerUtils.closeContainerItem` doesn't behave like `ContainerManager.removeContainerItem`
|
|
65
|
+
|
|
66
|
+
**Cause:** these two methods are not interchangeable. `closeContainerItem` performs a dirty-state check before closing (part of `ContainerUtils`); `removeContainerItem` (part of `ContainerManager`) removes an item from the container's item list without that check.
|
|
67
|
+
|
|
68
|
+
**Fix:** use the one that matches your intent — see [container-item-lifecycle](../pconnect-lists-and-views/cookbooks/container-item-lifecycle.md).
|
|
69
|
+
|
|
70
|
+
## A data page still shows old data right after a save
|
|
71
|
+
|
|
72
|
+
**Cause:** data page results are cached; saving a record through a different call doesn't automatically invalidate a data page instance that already cached the old result.
|
|
73
|
+
|
|
74
|
+
**Fix:** call `DataPageUtils.markDataInstanceDirty(dataPageName, parameters)` after the save, or re-fetch with the `{ invalidateCache: true }` option, before reading the data page again — see [pcore-rest-data-details.md](../references/pcore-rest-data-details.md). See also [Performance & Efficiency: cache deliberately](./performance-and-efficiency.md#cache-data-pages-but-invalidate-deliberately).
|
|
75
|
+
|
|
76
|
+
## A typeahead/search field hammers the server on every keystroke
|
|
77
|
+
|
|
78
|
+
**Cause:** the field's `fetchData`/REST call is wired directly to the input's `onChange`, with no debouncing or buffering.
|
|
79
|
+
|
|
80
|
+
**Fix:** debounce with `AsynchronousUtils.getDebouncedSubject(delay)` or configure `DataApi.registerForBufferedCall({ waitTime, maxSize })` before fetching — see [Performance & Efficiency: debounce and buffer](./performance-and-efficiency.md#debounce-or-buffer-user-triggered-calls).
|
|
81
|
+
|
|
82
|
+
## The UI shows "online" right after the network actually dropped (or vice versa)
|
|
83
|
+
|
|
84
|
+
**Cause:** the component reads `navigator.onLine` directly or adds its own `window` `online`/`offline` listeners instead of using the platform's own connectivity tracking, and misses an edge case the platform already handles.
|
|
85
|
+
|
|
86
|
+
**Fix:** use `PCore.getNetworkUtils().isOnline()`/`onStatusChange(callback)` instead — see [pcore-environment-locale-namespace.md](../references/pcore-environment-locale-namespace.md).
|
|
87
|
+
|
|
88
|
+
## An older async response overwrites a newer one (a fast-typed search shows results for an earlier query)
|
|
89
|
+
|
|
90
|
+
**Cause:** two overlapping requests were in flight (e.g. triggered by two keystrokes) and the one that started first happened to resolve last, and nothing discarded the stale response.
|
|
91
|
+
|
|
92
|
+
**Fix:** cancel the superseded request with `RestClient.getCancelTokenSource()`/check `isRequestCanceled(error)` before treating a rejection as a real error, or otherwise tag each request and ignore a resolution that isn't for the latest one — see [pcore-rest-data-details.md](../references/pcore-rest-data-details.md) and [Error Handling & Resiliency: distinguish cancellation from failure](./error-handling-and-resiliency.md#distinguish-cancellation-from-failure).
|
|
93
|
+
|
|
94
|
+
## The same generic error message shows for every failure, which makes triage hard
|
|
95
|
+
|
|
96
|
+
**Cause:** `ErrorHandler`'s generic failure message (shown when a component fails to render) hasn't been customized, so every unrelated failure looks identical to the user/tester.
|
|
97
|
+
|
|
98
|
+
**Fix:** call `PCore.getErrorHandler().setGenericFailedMessage(message)` with a clearer default, and prefer surfacing a specific, component-level error state over relying solely on the generic fallback — see [pcore-misc-details.md](../references/pcore-misc-details.md).
|
|
99
|
+
|
|
100
|
+
## A field's validation error message won't clear even after the value is fixed
|
|
101
|
+
|
|
102
|
+
**Cause:** `ValidationApi.validate(value, propertyName?)` (see [pconnect-validation-api.md](../references/pconnect-validation-api.md)) both validates and writes the result to application state — if the corrected value is never re-passed through `validate()` (for example, a fix applied programmatically rather than through the field's own change handler), the stale message stays in state because nothing told it to re-evaluate.
|
|
103
|
+
|
|
104
|
+
**Fix:** re-run `validate()` with the corrected value through the same path a normal user edit would take, rather than only updating the underlying value and assuming the displayed message updates itself.
|
|
105
|
+
|
|
106
|
+
## An attachment upload appears stuck and never resolves
|
|
107
|
+
|
|
108
|
+
**Cause:** `AttachmentUtils.uploadAttachment` (see [pcore-case-collaboration-details.md](../references/pcore-case-collaboration-details.md)) rejected or the resolved promise's status was never checked, and nothing surfaces a stuck/failed state to the user — the UI is left showing a permanent "uploading" indicator instead of an error.
|
|
109
|
+
|
|
110
|
+
**Fix:** always attach a `.catch`/handle the rejection path for `uploadAttachment` (see [Error Handling & Resiliency: never fail silently](./error-handling-and-resiliency.md#never-fail-silently)), and pair it with a reasonable timeout guard (see [Error Handling & Resiliency: guard against a call that never resolves](./error-handling-and-resiliency.md#guard-against-a-call-that-never-resolves)) so a genuinely hung request doesn't leave the indicator spinning forever.
|
|
111
|
+
|
|
112
|
+
## A GenAI Assistant conversation's history is empty after a page reload
|
|
113
|
+
|
|
114
|
+
**Cause:** `GenAIAssistantUtils.createConversation`/`sendMessage` (see [pcore-analytics-genai-details.md](../references/pcore-analytics-genai-details.md)) manage the conversation server-side, but the component only reads messages from its own local state (populated as the user sends/receives messages in that session) rather than re-fetching the conversation on mount.
|
|
115
|
+
|
|
116
|
+
**Fix:** on mount, call `getMessages(assistantID, conversationID, context)`/`getConversations(...)` to rehydrate history from the server instead of assuming local state is the source of truth — local state should be treated as a cache of what `getMessages` would return, not the only copy.
|
|
117
|
+
|
|
118
|
+
## The autosave indicator stays "unsaved" after a successful save
|
|
119
|
+
|
|
120
|
+
**Cause:** a change was made through a path that doesn't call `AutosaveUtils.notifyChange(context, propReference, value)` (see [pcore-misc-details.md](../references/pcore-misc-details.md)) — for example, a value set directly via a lower-level state update instead of the field's normal change handler — so the autosave engine never learns the edit happened, and its status subscription never transitions out of the stale state.
|
|
121
|
+
|
|
122
|
+
**Fix:** route every user-facing edit path through the same mechanism a normal field edit uses, so `notifyChange` fires consistently; don't bypass it for "programmatic" updates that are still meant to be autosaved.
|
|
123
|
+
|
|
124
|
+
## A buffered/typeahead call never fires, even though the user kept typing
|
|
125
|
+
|
|
126
|
+
**Cause:** `DataApi.registerForBufferedCall({ waitTime, maxSize })` (see [pcore-rest-data-details.md](../references/pcore-rest-data-details.md)) batches calls until either `waitTime` elapses with no new input or `maxSize` queued calls are reached — if `waitTime` is set too high relative to how the component's lifecycle unmounts/resets between keystrokes (for example, the component re-creates the `DataApi` instance on every render instead of reusing one), the buffer can be discarded before it ever fires.
|
|
127
|
+
|
|
128
|
+
**Fix:** create the buffered `DataApi` instance once (not on every render) and confirm `waitTime` is tuned to the input's actual typing cadence — see [Performance & Efficiency: debounce or buffer user-triggered calls](./performance-and-efficiency.md#debounce-or-buffer-user-triggered-calls).
|
|
129
|
+
|
|
130
|
+
## Still stuck?
|
|
131
|
+
|
|
132
|
+
If the symptom isn't listed above, first re-check the exact signature in the relevant `references/` file — many "the method doesn't work" reports turn out to be a missed required parameter, not a bug. If the method genuinely isn't documented anywhere in these skills, treat it as unsupported rather than assuming it exists at runtime.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pconnect-assignment-lifecycle
|
|
3
|
+
description: 'Reference catalog and cookbook for PCore/PConnect APIs governing assignment and case submission lifecycle — ActionsApi, ContainerManager, ValidationApi, AttachmentUtils, ErrorHandler, and ConfirmDialogService — with recipes for opening an assignment in a modal, multi-step wizard navigation, bulk action submit, safe case deletion, custom destructive-action confirmation, attachment upload, graceful submit-failure handling, creating a case and jumping to a stage, approving/rejecting a case, and resolving/ignoring a duplicate case. Use when you need the exact signature for these APIs, or the correct order to call them to open, validate, submit, or delete an assignment/case.'
|
|
4
|
+
user-invocable: true
|
|
5
|
+
argument-hint: 'Use when opening, validating, submitting, or deleting an assignment/case, confirming a destructive action, or uploading an attachment — for the exact ActionsApi/ContainerManager/ValidationApi signature, or the correct call order.'
|
|
6
|
+
metadata:
|
|
7
|
+
verified-against: 'latest 26.x'
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Assignment & Submission Lifecycle — PCore/PConnect Skill
|
|
11
|
+
|
|
12
|
+
This skill covers the PCore/PConnect APIs and recipes for the **assignment and case submission lifecycle**: opening an assignment, validating it, submitting it, deleting a case, confirming a destructive action, and handling attachments. 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 an `ActionsApi`, `ContainerManager`, `ValidationApi`, `AttachmentUtils`, `ErrorHandler`, or `ConfirmDialogService` method.
|
|
19
|
+
- You're opening an assignment in a modal/container, submitting it, or deleting a case, and need the correct call order.
|
|
20
|
+
- You're building a custom confirmation dialog before a destructive action, or handling a failed submit without losing user edits.
|
|
21
|
+
|
|
22
|
+
If your task is about form/field validation state, cascading fields, or autosave rather than the submit/delete lifecycle itself, see [pconnect-forms-and-fields](../pconnect-forms-and-fields/SKILL.md) instead.
|
|
23
|
+
|
|
24
|
+
New to PCore/PConnect? Start with [Architecture at a Glance](../references/architecture-overview.md).
|
|
25
|
+
|
|
26
|
+
## Key Reference Files
|
|
27
|
+
|
|
28
|
+
| File | Class(es) | Obtained via |
|
|
29
|
+
| ------------------------------------------------------------------------------------------------------ | --------------------------------------------------- | ----------------------------- |
|
|
30
|
+
| [../references/pconnect-actions-api.md](../references/pconnect-actions-api.md) | `ActionsApi` | `pConn.getActionsApi()` |
|
|
31
|
+
| [../references/pconnect-container-manager.md](../references/pconnect-container-manager.md) | `ContainerManager` | `pConn.getContainerManager()` |
|
|
32
|
+
| [../references/pconnect-validation-api.md](../references/pconnect-validation-api.md) | `ValidationApi` | `pConn.getValidationApi()` |
|
|
33
|
+
| [../references/pcore-case-collaboration-details.md](../references/pcore-case-collaboration-details.md) | `AttachmentUtils` | `PCore.getAttachmentUtils()` |
|
|
34
|
+
| [../references/pcore-misc-details.md](../references/pcore-misc-details.md) | `ErrorHandler`, `FormUtils`, `ConfirmDialogService` | `PCore.get*()` |
|
|
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): modal assignment submit, multi-step wizard navigation, bulk action submit, safe case deletion, custom destructive-action confirmation, attachment upload, graceful submit-failure handling, creating a case and jumping to a target stage, approving or rejecting a case, and resolving or ignoring a duplicate case.
|
|
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 (attachment uploads, destructive-action confirmation), idempotent/resilient retry and cancellation handling for submits, accessible loading/error states during a submit, or troubleshooting a call that isn't behaving as documented, see [Cross-Cutting Best Practices](../best-practices/README.md).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Assignment & Submission Lifecycle Cookbook — Recipe Index
|
|
3
|
+
description: Multi-method recipes for opening, validating, submitting, and deleting assignments/cases, indexed by symptom/keyword and primary method for AI/RAG retrieval.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cookbook: Assignment & Submission Lifecycle
|
|
7
|
+
|
|
8
|
+
> Part of the [Assignment & Submission Lifecycle 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
|
+
| [Modal assignment submit](./modal-assignment-submit.md) | modal, dialog, submit, close, validate before submit, containerItemID | `ContainerManager`, `ActionsApi`, `ValidationApi` |
|
|
27
|
+
| [Multi-step wizard](./multi-step-wizard.md) | stepper, process flow, next/previous, save between steps, finish on last step | `ActionsApi` |
|
|
28
|
+
| [Bulk action submit](./bulk-action-submit.md) | select all, checkbox, mass update, multiple cases | `ListActions`, `ActionsApi` |
|
|
29
|
+
| [Graceful submit failure handling](./graceful-submit-failure.md) | error handling, failed submit, generic error message, rollback | `ErrorHandler`, `FormUtils`, `ActionsApi` |
|
|
30
|
+
| [Custom confirm before a destructive action](./confirm-before-destructive-action.md) | confirm dialog, are you sure, destructive action, custom modal | `ConfirmDialogService` |
|
|
31
|
+
| [Safe case deletion](./safe-case-deletion.md) | delete case, cancel case, remove work object, create stage | `ActionsApi` |
|
|
32
|
+
| [Attachment upload](./attachment-upload.md) | file upload, attach, progress, cancel, category | `AttachmentUtils` |
|
|
33
|
+
| [Create a case and jump to a target stage](./create-and-stage-new-case.md) | create case, new case wizard, skip stage, jump to stage | `ActionsApi` |
|
|
34
|
+
| [Approve or reject a case](./approval-workflow-decision.md) | approval, reject, approve case, sign-off, decision step | `ActionsApi`, `ConfirmDialogService` |
|
|
35
|
+
| [Resolve or ignore a duplicate case](./resolve-or-ignore-duplicate.md) | duplicate case, duplicate detection, merge case, ignore duplicate | `ActionsApi`, `RelatedCasesApi` |
|
|
36
|
+
|
|
37
|
+
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.
|
|
38
|
+
|
|
39
|
+
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,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Approve or reject a case in an approval step
|
|
3
|
+
keywords: [approval, reject, approve case, sign-off, decision step]
|
|
4
|
+
primary_methods: [ActionsApi.approveCase, ActionsApi.rejectCase]
|
|
5
|
+
related: [confirm-before-destructive-action, graceful-submit-failure]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Recipe: Approve or reject a case in an approval step
|
|
9
|
+
|
|
10
|
+
> Part of the [Assignment & Submission Lifecycle cookbook](./README.md) — [skill overview](../SKILL.md).
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
An approval assignment presents two outcomes — approve or reject — and the reject path should ask for confirmation first since it is harder to walk back than an approval.
|
|
15
|
+
|
|
16
|
+
## Solution
|
|
17
|
+
|
|
18
|
+
Uses [`ActionsApi`](../../references/pconnect-actions-api.md) and, for the confirmation step, [`ConfirmDialogService`](../../references/pcore-misc-details.md).
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
async function approve(containerItemID) {
|
|
22
|
+
// approveCase both records the decision and finishes the assignment — do not call finishAssignment afterward.
|
|
23
|
+
await pConn.getActionsApi().approveCase(containerItemID);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function rejectWithConfirmation(containerItemID) {
|
|
27
|
+
const confirmed = await PCore.getConfirmDialogService().confirm(
|
|
28
|
+
'This case will be sent back and cannot be re-approved from this step. Continue?'
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
if (!confirmed) return;
|
|
32
|
+
|
|
33
|
+
// rejectCase also finishes the assignment on its own.
|
|
34
|
+
await pConn.getActionsApi().rejectCase(containerItemID);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Discussion
|
|
39
|
+
|
|
40
|
+
**MUST NOT** call `finishAssignment` after `approveCase`/`rejectCase` — both methods already finish the assignment as part of recording the decision; calling `finishAssignment` again submits an already-finished assignment.
|
|
41
|
+
|
|
42
|
+
**SHOULD** gate the reject path behind an explicit confirmation (see [Custom confirm before a destructive action](./confirm-before-destructive-action.md)) since rejection is typically harder to reverse than approval, but treat this as a UX choice, not a requirement of the API itself — the API applies no such distinction.
|
|
43
|
+
|
|
44
|
+
## Related recipes
|
|
45
|
+
|
|
46
|
+
- [Custom confirm before a destructive action](./confirm-before-destructive-action.md)
|
|
47
|
+
- [Graceful submit failure handling](./graceful-submit-failure.md)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Upload a file, attach it to a case, and handle a failed upload
|
|
3
|
+
keywords: [file upload, attach, progress, cancel, category]
|
|
4
|
+
primary_methods:
|
|
5
|
+
[AttachmentUtils.uploadAttachment, AttachmentUtils.linkAttachmentsToCase, AttachmentUtils.cancelRequest]
|
|
6
|
+
related: [graceful-submit-failure]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Recipe: Upload a file, attach it to a case, and handle a failed upload
|
|
10
|
+
|
|
11
|
+
> Part of the [Assignment & Submission Lifecycle cookbook](./README.md) — [skill overview](../SKILL.md).
|
|
12
|
+
|
|
13
|
+
## Problem
|
|
14
|
+
|
|
15
|
+
A file must be uploaded and linked to a case, with the upload and link steps failing independently and needing different recovery.
|
|
16
|
+
|
|
17
|
+
## Solution
|
|
18
|
+
|
|
19
|
+
Uses `PCore.getAttachmentUtils()` (see [pcore-case-collaboration-details.md](../../references/pcore-case-collaboration-details.md)).
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
const { uploadAttachment, linkAttachmentsToCase, cancelRequest } = PCore.getAttachmentUtils();
|
|
23
|
+
|
|
24
|
+
let uploadedFile;
|
|
25
|
+
try {
|
|
26
|
+
uploadedFile = await uploadAttachment(file, onUploadProgress, onUploadError, context);
|
|
27
|
+
} catch {
|
|
28
|
+
// The upload itself failed (network error, size/type rejection) — do not attempt to link.
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
await linkAttachmentsToCase(caseID, [uploadedFile], 'File', context);
|
|
34
|
+
} catch {
|
|
35
|
+
// The file uploaded but failed to link — offer a retry for linking only, don't re-upload.
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Discussion
|
|
40
|
+
|
|
41
|
+
**MUST** call `cancelRequest(fileID)` if the user navigates away or cancels mid-upload, to stop the in-flight request rather than letting it complete and silently discarding the result.
|
|
42
|
+
|
|
43
|
+
## Related recipes
|
|
44
|
+
|
|
45
|
+
- [Handle a failed submit gracefully](./graceful-submit-failure.md)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Bulk-submit selected rows from a list
|
|
3
|
+
keywords: [select all, checkbox, mass update, multiple cases, modal]
|
|
4
|
+
primary_methods: [ListActions.getSelectedRows, ActionsApi.openBulkAction, ListActions.clearSelectedRows]
|
|
5
|
+
related: [repeating-row-edit]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Recipe: Bulk-submit selected rows from a list
|
|
9
|
+
|
|
10
|
+
> Part of the [Assignment & Submission Lifecycle cookbook](./README.md) — [skill overview](../SKILL.md).
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
A user has selected several rows in a list and needs to submit a bulk action against exactly those rows, then clear the selection.
|
|
15
|
+
|
|
16
|
+
## Solution
|
|
17
|
+
|
|
18
|
+
Uses [`ListActions`](../../references/pconnect-list-actions.md) and [`ActionsApi`](../../references/pconnect-actions-api.md).
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// The typedefs type the result as a bare `object`; with `withPayload` false it is the array of selected row keys.
|
|
22
|
+
const selectedKeys = (await pConn.getListActions().getSelectedRows(false)) as string[];
|
|
23
|
+
// getCaseSummary() is typed `any`; its documented keys are caseID, ID (assignment ID), caseClass, name, urgency, routedTo.
|
|
24
|
+
// Confirm which keys your runtime returns for the bulk context before relying on these names.
|
|
25
|
+
const { ID: bulkContextID, caseTypeID: bulkContextType } = pConn.getCaseSummary();
|
|
26
|
+
|
|
27
|
+
await pConn.getActionsApi().openBulkAction(actionID, {
|
|
28
|
+
selectedList: selectedKeys,
|
|
29
|
+
containerName: 'modal',
|
|
30
|
+
bulkContextID,
|
|
31
|
+
bulkContextType,
|
|
32
|
+
callbacks: {
|
|
33
|
+
submit: async () => {
|
|
34
|
+
await pConn.getListActions().clearSelectedRows();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Discussion
|
|
41
|
+
|
|
42
|
+
`getSelectedRows(false)` resolves to a `string[]` of selected row keys, not row objects — pass it straight through as `selectedList`.
|
|
43
|
+
|
|
44
|
+
**NEVER** call `submitBulkAction` directly with the selected keys — `openBulkAction` opens the bulk-action modal and registers `submitBulkAction`/`submitBulkActionAsync` on its own submit button internally, and `submitBulkAction` only accepts a single `containerItemID` string established by the opened bulk-action context.
|
|
45
|
+
|
|
46
|
+
**MUST** clear the selection inside the `submit` callback, which only fires once the platform confirms the bulk action was submitted.
|
|
47
|
+
|
|
48
|
+
## Related recipes
|
|
49
|
+
|
|
50
|
+
- [Edit a repeating row with validation, then save](../../pconnect-lists-and-views/cookbooks/repeating-row-edit.md)
|
package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/confirm-before-destructive-action.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Show a custom confirmation dialog before a destructive action
|
|
3
|
+
keywords: [confirm dialog, are you sure, destructive action, custom modal, delete attachment, remove participant]
|
|
4
|
+
primary_methods: [ConfirmDialogService.registerConfirmHandler, ConfirmDialogService.confirm]
|
|
5
|
+
related: [safe-case-deletion, graceful-submit-failure]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Recipe: Show a custom confirmation dialog before a destructive action
|
|
9
|
+
|
|
10
|
+
> Part of the [Assignment & Submission Lifecycle cookbook](./README.md) — [skill overview](../SKILL.md).
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
An action like deleting an attachment or removing a participant has no built-in confirmation prompt, and the app wants its own styled confirm dialog — not the native browser `confirm()` — shown consistently before that action runs.
|
|
15
|
+
|
|
16
|
+
## Solution
|
|
17
|
+
|
|
18
|
+
Uses `ConfirmDialogService` (via `PCore.getConfirmDialogService()`, see [pcore-misc-details.md](../../references/pcore-misc-details.md)).
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// Register once, near app bootstrap.
|
|
22
|
+
PCore.getConfirmDialogService().registerConfirmHandler((message) => showCustomConfirmModal(message));
|
|
23
|
+
|
|
24
|
+
// At the call site of the destructive action:
|
|
25
|
+
async function onRemoveAttachment(attachmentID: string, context: string) {
|
|
26
|
+
const confirmed = await PCore.getConfirmDialogService().confirm(
|
|
27
|
+
'This attachment will be permanently removed. Continue?'
|
|
28
|
+
);
|
|
29
|
+
if (!confirmed) return;
|
|
30
|
+
await PCore.getAttachmentUtils().deleteAttachment(attachmentID, context);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Discussion
|
|
35
|
+
|
|
36
|
+
`registerConfirmHandler` is global and last-write-wins. **NEVER** register it per-component — registering a second handler elsewhere in the app (for example, from another custom component) silently replaces the first. **ALWAYS** register it once during bootstrap instead.
|
|
37
|
+
|
|
38
|
+
If no handler is ever registered, `confirm()` falls back to the native browser `confirm()` dialog — a missing registration won't crash the destructive action, but it does surface an inconsistent, unstyled prompt instead of failing loudly.
|
|
39
|
+
|
|
40
|
+
## Related recipes
|
|
41
|
+
|
|
42
|
+
- [Delete a case safely (create stage vs. an existing work object)](./safe-case-deletion.md)
|
|
43
|
+
- [Handle a failed submit gracefully](./graceful-submit-failure.md)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Create a new case and jump directly to a target stage
|
|
3
|
+
keywords: [create case, new case wizard, skip stage, jump to stage, case creation]
|
|
4
|
+
primary_methods: [ActionsApi.createWork, ActionsApi.openStage, ActionsApi.finishAssignment]
|
|
5
|
+
related: [multi-step-wizard, modal-assignment-submit]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Recipe: Create a new case and jump directly to a target stage
|
|
9
|
+
|
|
10
|
+
> Part of the [Assignment & Submission Lifecycle cookbook](./README.md) — [skill overview](../SKILL.md).
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
A "create case" affordance needs to create the case with some starting field values already known (for example, a case created from a picklist selection), then skip straight to a later stage instead of showing the case's default first stage.
|
|
15
|
+
|
|
16
|
+
## Solution
|
|
17
|
+
|
|
18
|
+
Uses [`ActionsApi`](../../references/pconnect-actions-api.md).
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
async function createCaseAtStage(className, startingFields, targetStageID) {
|
|
22
|
+
await pConn.getActionsApi().createWork(className, {
|
|
23
|
+
containerName: 'primary',
|
|
24
|
+
startingFields
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Only call openStage if the target stage differs from the case's default starting stage.
|
|
28
|
+
await pConn.getActionsApi().openStage(targetStageID);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function finishCurrentStageAssignment(containerItemID) {
|
|
32
|
+
await pConn.getActionsApi().finishAssignment(containerItemID);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Discussion
|
|
37
|
+
|
|
38
|
+
**MUST NOT** assume `createWork` alone lands the user on the desired stage — it always opens the case's configured first assignment. Call `openStage` afterward only when the target stage is known to differ from that default; calling it unconditionally on every creation adds a redundant navigation round trip.
|
|
39
|
+
|
|
40
|
+
**MUST** treat `openStage` as a navigation call only — it does not submit or skip validation for stages in between. Any stage-entry data still needs to be collected and submitted through its own assignment(s).
|
|
41
|
+
|
|
42
|
+
## Related recipes
|
|
43
|
+
|
|
44
|
+
- [Multi-step wizard navigation with per-step save and final submit](./multi-step-wizard.md)
|
|
45
|
+
- [Open an assignment in a modal, edit, validate, submit, and close](./modal-assignment-submit.md)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Handle a failed submit gracefully
|
|
3
|
+
keywords: [error handling, failed submit, generic error message, rollback]
|
|
4
|
+
primary_methods: [ErrorHandler.setGenericFailedMessage, ActionsApi.finishAssignment, FormUtils.getChanges]
|
|
5
|
+
related: [modal-assignment-submit, attachment-upload]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Recipe: Handle a failed submit gracefully
|
|
9
|
+
|
|
10
|
+
> Part of the [Assignment & Submission Lifecycle cookbook](./README.md) — [skill overview](../SKILL.md).
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
A submit call can fail server-side, and the user's in-progress edits must not be lost or silently discarded when that happens.
|
|
15
|
+
|
|
16
|
+
## Solution
|
|
17
|
+
|
|
18
|
+
Uses `ErrorHandler` and `FormUtils` (both via `PCore.get*()`, see [pcore-misc-details.md](../../references/pcore-misc-details.md)) together with [`ActionsApi`](../../references/pconnect-actions-api.md).
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
PCore.getErrorHandler().setGenericFailedMessage('We could not save your changes. Please try again.');
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
await pConn.getActionsApi().finishAssignment(containerItemID);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
// The assignment stays open and dirty — surface the changed fields so the user doesn't lose them.
|
|
27
|
+
const changedFields = PCore.getFormUtils().getChanges(context);
|
|
28
|
+
showRetryBanner(changedFields);
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Discussion
|
|
33
|
+
|
|
34
|
+
**NEVER** remove the container item or navigate away in the `catch` block — the whole point of leaving the assignment open is so the user's in-progress edits (tracked via `getChanges`) are not lost.
|
|
35
|
+
|
|
36
|
+
## Related recipes
|
|
37
|
+
|
|
38
|
+
- [Open an assignment in a modal, edit, validate, submit, and close](./modal-assignment-submit.md)
|
|
39
|
+
- [Upload a file, attach it to a case, and handle a failed upload](./attachment-upload.md)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Open an assignment in a modal, edit, validate, submit, and close
|
|
3
|
+
keywords: [modal, dialog, submit, close, validate before submit, containerItemID]
|
|
4
|
+
primary_methods:
|
|
5
|
+
[
|
|
6
|
+
ContainerManager.addContainerItem,
|
|
7
|
+
ActionsApi.openAssignment,
|
|
8
|
+
ValidationApi.validateEmail,
|
|
9
|
+
ActionsApi.finishAssignment,
|
|
10
|
+
ContainerManager.removeContainerItem
|
|
11
|
+
]
|
|
12
|
+
related: [full-form-validation, multi-step-wizard, graceful-submit-failure, safe-case-deletion]
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Recipe: Open an assignment in a modal, edit, validate, submit, and close
|
|
16
|
+
|
|
17
|
+
> Part of the [Assignment & Submission Lifecycle cookbook](./README.md) — [skill overview](../SKILL.md).
|
|
18
|
+
|
|
19
|
+
## Problem
|
|
20
|
+
|
|
21
|
+
An assignment needs to open in a modal region, let the user edit a field, and only submit (and close the modal) once that field is valid.
|
|
22
|
+
|
|
23
|
+
## Solution
|
|
24
|
+
|
|
25
|
+
Uses [`ContainerManager`](../../references/pconnect-container-manager.md), [`ValidationApi`](../../references/pconnect-validation-api.md), and [`ActionsApi`](../../references/pconnect-actions-api.md).
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
const containerManager = pConn.getContainerManager();
|
|
29
|
+
|
|
30
|
+
// 1. Add a container item to host the assignment in a modal region. addContainerItem's promise
|
|
31
|
+
// resolves with null, not the container item — pass an explicit ID so it can be reused below.
|
|
32
|
+
const containerItemID = `modalAssignment_${assignmentID}`;
|
|
33
|
+
await containerManager.addContainerItem({ containerItemID, context, semanticURL: '' });
|
|
34
|
+
|
|
35
|
+
// 2. Load the assignment into that container item.
|
|
36
|
+
await pConn.getActionsApi().openAssignment(assignmentID, className, { containerName: 'modal' });
|
|
37
|
+
|
|
38
|
+
// 3. Validate a field before allowing submission.
|
|
39
|
+
const emailCheck = pConn.getValidationApi().validateEmail(emailValue);
|
|
40
|
+
if (emailCheck.status === 'failure') {
|
|
41
|
+
// Surface emailCheck.message next to the field and stop here.
|
|
42
|
+
} else {
|
|
43
|
+
// 4. Submit and close the modal.
|
|
44
|
+
await pConn.getActionsApi().finishAssignment(containerItemID);
|
|
45
|
+
await containerManager.removeContainerItem({ containerItemID });
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Discussion
|
|
50
|
+
|
|
51
|
+
**MUST:** call `finishAssignment` before `removeContainerItem`. `finishAssignment` submits server-side; NEVER remove the container item first — doing so closes the modal before you know whether the submission succeeded.
|
|
52
|
+
|
|
53
|
+
## Related recipes
|
|
54
|
+
|
|
55
|
+
- [Validate an entire form before allowing submit](../../pconnect-forms-and-fields/cookbooks/full-form-validation.md)
|
|
56
|
+
- [Multi-step wizard navigation with per-step save and final submit](./multi-step-wizard.md)
|
|
57
|
+
- [Handle a failed submit gracefully](./graceful-submit-failure.md)
|
|
58
|
+
- [Delete a case safely (create stage vs. an existing work object)](./safe-case-deletion.md)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Multi-step wizard navigation with per-step save and final submit
|
|
3
|
+
keywords: [stepper, process flow, next/previous, save between steps, finish on last step]
|
|
4
|
+
primary_methods: [ActionsApi.saveAssignment, ActionsApi.finishAssignment, ActionsApi.navigateToStep]
|
|
5
|
+
related: [modal-assignment-submit, full-form-validation]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Recipe: Multi-step wizard navigation with per-step save and final submit
|
|
9
|
+
|
|
10
|
+
> Part of the [Assignment & Submission Lifecycle cookbook](./README.md) — [skill overview](../SKILL.md).
|
|
11
|
+
|
|
12
|
+
## Problem
|
|
13
|
+
|
|
14
|
+
A multi-step process needs to persist each step's data as the user advances, but only actually submit the assignment on the final step.
|
|
15
|
+
|
|
16
|
+
## Solution
|
|
17
|
+
|
|
18
|
+
Uses [`ActionsApi`](../../references/pconnect-actions-api.md).
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
async function goToNextStep(containerItemID, stepID, isLastStep) {
|
|
22
|
+
// Persist the current step's data before moving on, without submitting the assignment.
|
|
23
|
+
await pConn.getActionsApi().saveAssignment(containerItemID);
|
|
24
|
+
|
|
25
|
+
if (isLastStep) {
|
|
26
|
+
await pConn.getActionsApi().finishAssignment(containerItemID);
|
|
27
|
+
} else {
|
|
28
|
+
await pConn.getActionsApi().navigateToStep(stepID, containerItemID);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function goToPreviousStep(containerItemID) {
|
|
33
|
+
await pConn.getActionsApi().navigateToStep('previous', containerItemID);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Discussion
|
|
38
|
+
|
|
39
|
+
**NEVER** call `finishAssignment` on every step — it MUST only be called on the last step; intermediate steps MUST save (`saveAssignment`) without submitting.
|
|
40
|
+
|
|
41
|
+
## Related recipes
|
|
42
|
+
|
|
43
|
+
- [Open an assignment in a modal, edit, validate, submit, and close](./modal-assignment-submit.md)
|
|
44
|
+
- [Validate an entire form before allowing submit](../../pconnect-forms-and-fields/cookbooks/full-form-validation.md)
|