@salesforce/ui-bundle-template-feature-angular-authentication 12.5.4
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/LICENSE.txt +82 -0
- package/README.md +130 -0
- package/dist/.forceignore +15 -0
- package/dist/.husky/pre-commit +4 -0
- package/dist/.prettierignore +11 -0
- package/dist/.prettierrc +17 -0
- package/dist/CHANGELOG.md +5238 -0
- package/dist/README.md +77 -0
- package/dist/config/project-scratch-def.json +13 -0
- package/dist/eslint.config.js +7 -0
- package/dist/force-app/main/default/classes/UIBundleAuthUtils.cls +68 -0
- package/dist/force-app/main/default/classes/UIBundleAuthUtils.cls-meta.xml +5 -0
- package/dist/force-app/main/default/classes/UIBundleChangePassword.cls +77 -0
- package/dist/force-app/main/default/classes/UIBundleChangePassword.cls-meta.xml +5 -0
- package/dist/force-app/main/default/classes/UIBundleForgotPassword.cls +71 -0
- package/dist/force-app/main/default/classes/UIBundleForgotPassword.cls-meta.xml +5 -0
- package/dist/force-app/main/default/classes/UIBundleLogin.cls +105 -0
- package/dist/force-app/main/default/classes/UIBundleLogin.cls-meta.xml +5 -0
- package/dist/force-app/main/default/classes/UIBundleRegistration.cls +162 -0
- package/dist/force-app/main/default/classes/UIBundleRegistration.cls-meta.xml +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/.forceignore +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/.graphqlrc.yml +2 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/.postcssrc.json +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/.prettierignore +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/.prettierrc +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/CHANGELOG.md +4 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/README.md +85 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/angular.json +98 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/codegen.yml +95 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/components.json +6 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/e2e/app.spec.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/esbuild/api-version.mjs +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/esbuild/graphql-codegen.mjs +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/eslint-plugin-angular-graphql.js +148 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/eslint.config.js +76 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/feature-angular-authentication.uibundle-meta.xml +7 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/middleware/html.mjs +3 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/middleware/proxy.mjs +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/package.json +69 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/playwright.config.ts +25 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/public/favicon.ico +0 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/scripts/get-graphql-schema.mjs +69 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/scripts/rewrite-e2e-assets.mjs +30 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/api/data-client.service.spec.ts +184 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/api/data-client.service.ts +74 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/api/user-profile.service.ts +126 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/app.config.ts +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/app.html +1 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/app.routes.ts +66 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/app.spec.ts +18 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/app.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/layout/app-layout/app-layout.html +51 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/layout/app-layout/app-layout.spec.ts +63 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/layout/app-layout/app-layout.ts +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/alert/alert.html +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/alert/alert.ts +41 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/button/button.html +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/button/button.ts +66 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/card/card.ts +100 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/collapsible/collapsible.html +38 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/collapsible/collapsible.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/date-picker/date-picker.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/date-picker/date-picker.ts +49 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/date-range-picker/date-range-picker.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/date-range-picker/date-range-picker.ts +69 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/dialog/dialog.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/dialog/dialog.ts +40 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/dropdown-menu/dropdown-menu.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/dropdown-menu/dropdown-menu.ts +100 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/field/field.html +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/field/field.ts +28 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/field-appearance.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/field-size.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/icon/icon.ts +68 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/input/input.html +34 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/input/input.ts +79 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/label/label.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/paginator/paginator.html +74 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/paginator/paginator.ts +93 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/paginator/types.ts +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/popover/popover.html +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/popover/popover.ts +37 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/select/select.html +36 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/select/select.ts +63 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/separator/separator.ts +31 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/skeleton/skeleton.ts +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/spinner/spinner.ts +28 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/auth/auth.guard.ts +50 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/auth/auth.service.ts +158 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/auth-form/auth-form.html +33 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/auth-form/auth-form.ts +94 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/auth-layout/auth-layout.html +2 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/auth-layout/auth-layout.ts +30 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/card-layout/card-layout.html +16 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/card-layout/card-layout.ts +40 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/config/authentication.config.ts +75 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/footer-link/footer-link.html +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/footer-link/footer-link.ts +26 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/menu/auth-menu/auth-menu.html +36 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/menu/auth-menu/auth-menu.ts +34 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/reactive-form-page.base.ts +50 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/session/session.html +55 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/session/session.ts +205 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/status-alert/status-alert.html +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/status-alert/status-alert.ts +52 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/submit-button/submit-button.html +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/submit-button/submit-button.ts +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/utils/auth-helpers.ts +68 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/utils/auth-validators.ts +72 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/utils/helpers.ts +85 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/utils/session-time-servlet.ts +130 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/utils/session-timeout.config.ts +83 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/utils/session-timeout.service.ts +201 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/change-password/change-password-page.html +68 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/change-password/change-password-page.ts +82 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/forgot-password/forgot-password-page.html +35 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/forgot-password/forgot-password-page.ts +87 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/home/home.html +6 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/home/home.spec.ts +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/home/home.ts +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/login/login-page.html +47 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/login/login-page.ts +89 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/not-found/not-found.html +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/not-found/not-found.spec.ts +33 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/not-found/not-found.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/profile/profile-page.html +116 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/profile/profile-page.ts +194 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/register/register-page.html +80 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/register/register-page.ts +93 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/reset-password/reset-password-page.html +60 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/reset-password/reset-password-page.ts +96 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/alert/hlm-alert-action.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/alert/hlm-alert-description.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/alert/hlm-alert-title.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/alert/hlm-alert.ts +35 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/alert/index.ts +16 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/button/hlm-button.token.ts +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/button/hlm-button.ts +72 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/button/index.ts +6 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/calendar/hlm-calendar-multi.ts +195 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/calendar/hlm-calendar-range.ts +194 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/calendar/hlm-calendar.ts +189 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/calendar/hlm-month-year-calendar.ts +119 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/calendar/index.ts +16 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-action.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-avatar.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-content.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-description.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-footer.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-header.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-title.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card.token.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card.ts +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/index.ts +28 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/collapsible/hlm-collapsible-content.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/collapsible/hlm-collapsible-trigger.ts +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/collapsible/hlm-collapsible.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/collapsible/index.ts +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-multi-input.ts +104 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker-anchor.ts +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker-input.ts +118 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker-multi.token.ts +109 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker-multi.ts +220 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker-trigger.ts +104 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker.token.ts +69 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker.ts +203 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-range-input.ts +120 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-range-picker.token.ts +86 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-range-picker.ts +252 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-month-year-input.ts +105 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-month-year-picker.token.ts +89 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-month-year-picker.ts +196 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/index.ts +38 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-close.ts +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-content.ts +74 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-description.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-footer.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-header.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-overlay.ts +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-portal.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-title.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-trigger.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog.service.ts +46 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog.ts +24 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/index.ts +35 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-checkbox-indicator.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-checkbox.ts +54 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-focus-on-hover.ts +35 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-group.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-item-sub-indicator.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-item.ts +42 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-label.ts +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-radio-indicator.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-radio.ts +49 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-separator.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-shortcut.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-sub-trigger.ts +52 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-sub.ts +53 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-token.ts +26 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-trigger.ts +46 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu.ts +57 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/index.ts +49 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-content.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-description.ts +53 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-error.ts +100 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-group.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-label.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-legend.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-separator.ts +24 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-set.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-title.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field.ts +47 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/index.ts +34 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input/hlm-input.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input-group/hlm-input-group-addon.ts +40 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input-group/hlm-input-group-button.ts +47 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input-group/hlm-input-group-input.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input-group/hlm-input-group-text.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input-group/hlm-input-group.ts +18 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input-group/index.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/label/hlm-label.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/label/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/label/label.html +11 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-numbered-pagination-query-params.ts +191 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-numbered-pagination.ts +290 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination-content.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination-ellipsis.ts +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination-item.ts +7 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination-link.ts +51 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination-next.ts +65 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination-previous.ts +65 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/index.ts +31 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover-content.ts +25 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover-description.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover-header.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover-portal.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover-title.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover-trigger.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover.ts +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/index.ts +25 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-content.ts +44 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-group.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-item.ts +36 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-label.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-multiple.ts +37 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-placeholder.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-portal.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-scroll-down.ts +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-scroll-up.ts +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-separator.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-trigger.ts +59 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-value-template.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-value.ts +18 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-values-content.ts +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-values.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select.ts +37 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/index.ts +52 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/separator/hlm-separator.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/separator/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/skeleton/hlm-skeleton.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/skeleton/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/spinner/hlm-spinner.ts +26 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/spinner/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/utils/hlm.ts +313 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/utils/index.ts +2 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/utils/provide-spartan-hlm.ts +34 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/utils/async-data.ts +99 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/index.html +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/main.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/styles.css +139 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/types/sf-globals.d.ts +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/tsconfig.app.json +11 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/tsconfig.json +36 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/tsconfig.spec.json +10 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-authentication/ui-bundle.json +7 -0
- package/dist/jest.config.js +6 -0
- package/dist/package-lock.json +12554 -0
- package/dist/package.json +46 -0
- package/dist/scripts/apex/hello.apex +10 -0
- package/dist/scripts/gitignore-templates.json +4 -0
- package/dist/scripts/graphql-search.sh +191 -0
- package/dist/scripts/org-setup-config-schema.mjs +132 -0
- package/dist/scripts/org-setup-dev.mjs +114 -0
- package/dist/scripts/org-setup-url.mjs +108 -0
- package/dist/scripts/org-setup-utils.mjs +569 -0
- package/dist/scripts/org-setup-xml.mjs +278 -0
- package/dist/scripts/org-setup.config.json +5 -0
- package/dist/scripts/org-setup.mjs +2537 -0
- package/dist/scripts/sf-project-setup.mjs +103 -0
- package/dist/scripts/soql/account.soql +6 -0
- package/dist/scripts/validate-org-setup-config.mjs +38 -0
- package/dist/sfdx-project.json +12 -0
- package/package.json +45 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { ChangeDetectionStrategy, Component, input } from "@angular/core";
|
|
7
|
+
import { RouterLink } from "@angular/router";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Footer navigation link under an auth form — the Angular port of the React
|
|
11
|
+
* `FooterLink`. Renders an optional prefix text followed by a `routerLink`.
|
|
12
|
+
*/
|
|
13
|
+
@Component({
|
|
14
|
+
selector: "app-footer-link",
|
|
15
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
16
|
+
imports: [RouterLink],
|
|
17
|
+
templateUrl: "./footer-link.html",
|
|
18
|
+
})
|
|
19
|
+
export class FooterLinkComponent {
|
|
20
|
+
/** Link text prefix (e.g., "Don't have an account?"). */
|
|
21
|
+
readonly text = input<string>("");
|
|
22
|
+
/** Router path to navigate to. */
|
|
23
|
+
readonly to = input.required<string>();
|
|
24
|
+
/** Link label (e.g., "Sign up"). */
|
|
25
|
+
readonly linkText = input.required<string>();
|
|
26
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
@if (loading()) {
|
|
2
|
+
<app-skeleton class="size-8 rounded-full" />
|
|
3
|
+
} @else {
|
|
4
|
+
<app-dropdown-menu
|
|
5
|
+
align="end"
|
|
6
|
+
aria-label="User menu"
|
|
7
|
+
triggerClass="inline-flex size-8 items-center justify-center rounded-full hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
|
8
|
+
>
|
|
9
|
+
<app-icon trigger name="person" size="24" />
|
|
10
|
+
|
|
11
|
+
<ng-template appDropdownMenuContent>
|
|
12
|
+
@if (isAuthenticated()) {
|
|
13
|
+
<app-dropdown-menu-label class="truncate">{{ user()?.name }}</app-dropdown-menu-label>
|
|
14
|
+
<app-dropdown-menu-separator />
|
|
15
|
+
<a appDropdownMenuItem [routerLink]="routes.PROFILE.PATH">
|
|
16
|
+
<app-icon name="editProfile" />
|
|
17
|
+
<span>Edit Profile</span>
|
|
18
|
+
</a>
|
|
19
|
+
<ng-content select="[menuItems]" />
|
|
20
|
+
<button appDropdownMenuItem type="button" (triggered)="onLogout()">
|
|
21
|
+
<app-icon name="logout" />
|
|
22
|
+
<span>Sign Out</span>
|
|
23
|
+
</button>
|
|
24
|
+
} @else {
|
|
25
|
+
<a appDropdownMenuItem [routerLink]="routes.LOGIN.PATH">
|
|
26
|
+
<app-icon name="login" />
|
|
27
|
+
<span>Log In</span>
|
|
28
|
+
</a>
|
|
29
|
+
<a appDropdownMenuItem [routerLink]="routes.REGISTER.PATH">
|
|
30
|
+
<app-icon name="personAdd" />
|
|
31
|
+
<span>Register</span>
|
|
32
|
+
</a>
|
|
33
|
+
}
|
|
34
|
+
</ng-template>
|
|
35
|
+
</app-dropdown-menu>
|
|
36
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { ChangeDetectionStrategy, Component, inject } from "@angular/core";
|
|
7
|
+
import { RouterLink } from "@angular/router";
|
|
8
|
+
import { DropdownMenuImports } from "../../../../components/ui/dropdown-menu/dropdown-menu";
|
|
9
|
+
import { IconComponent } from "../../../../components/ui/icon/icon";
|
|
10
|
+
import { SkeletonComponent } from "../../../../components/ui/skeleton/skeleton";
|
|
11
|
+
import { AuthService } from "../../auth/auth.service";
|
|
12
|
+
import { ROUTES } from "../../config/authentication.config";
|
|
13
|
+
|
|
14
|
+
// Header dropdown: shows the user's name + Edit Profile / Sign Out, or Log In
|
|
15
|
+
// / Register for guests. Shows a skeleton avatar while auth state is loading.
|
|
16
|
+
// Extra items can be inserted before Sign Out via [menuItems] projection.
|
|
17
|
+
@Component({
|
|
18
|
+
selector: "app-auth-menu",
|
|
19
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
20
|
+
imports: [RouterLink, IconComponent, SkeletonComponent, ...DropdownMenuImports],
|
|
21
|
+
templateUrl: "./auth-menu.html",
|
|
22
|
+
})
|
|
23
|
+
export class AuthMenuComponent {
|
|
24
|
+
private readonly authService = inject(AuthService);
|
|
25
|
+
|
|
26
|
+
protected readonly routes = ROUTES;
|
|
27
|
+
protected readonly user = this.authService.user;
|
|
28
|
+
protected readonly isAuthenticated = this.authService.isAuthenticated;
|
|
29
|
+
protected readonly loading = this.authService.loading;
|
|
30
|
+
|
|
31
|
+
protected onLogout(): void {
|
|
32
|
+
this.authService.logout();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { Directive } from "@angular/core";
|
|
7
|
+
import { FormGroup } from "@angular/forms";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Shared helpers for the auth form pages.
|
|
11
|
+
*
|
|
12
|
+
* The base `app-input` primitive exposes a two-way `[(value)]` model rather than
|
|
13
|
+
* a ControlValueAccessor, so neither `formControlName` nor `[formGroup]` can bind
|
|
14
|
+
* to it directly. These pages therefore keep a Reactive Forms `FormGroup` as the
|
|
15
|
+
* validation + submit source of truth (with no `[formGroup]` on the template
|
|
16
|
+
* `<form>`) and bridge each field manually with `[value]` / `(valueChange)`:
|
|
17
|
+
* <app-input [value]="form.controls.x.value" (valueChange)="setControl('x', $event)" />
|
|
18
|
+
*
|
|
19
|
+
* `setControl` pushes edits back into the control (marking it touched/dirty so
|
|
20
|
+
* validation surfaces), and `controlError` reads a specific error message for
|
|
21
|
+
* display once the control has been touched — mirroring the React forms, which
|
|
22
|
+
* showed field errors after interaction.
|
|
23
|
+
*
|
|
24
|
+
* Kept as an abstract base (not injectable) so each page owns its own typed
|
|
25
|
+
* `form`. Not an Angular component/service; no DI.
|
|
26
|
+
*/
|
|
27
|
+
@Directive()
|
|
28
|
+
export abstract class ReactiveFormPageBase {
|
|
29
|
+
protected abstract readonly form: FormGroup;
|
|
30
|
+
|
|
31
|
+
/** Push an edited value into the named control and mark it touched/dirty. */
|
|
32
|
+
protected setControl(name: string, value: string): void {
|
|
33
|
+
const control = this.form.get(name);
|
|
34
|
+
if (!control) return;
|
|
35
|
+
control.setValue(value);
|
|
36
|
+
control.markAsDirty();
|
|
37
|
+
control.markAsTouched();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Returns the message for the named error key on the control, but only once
|
|
42
|
+
* the control has been touched (so pristine fields don't show errors).
|
|
43
|
+
*/
|
|
44
|
+
protected controlError(name: string, errorKey: string): string | null {
|
|
45
|
+
const control = this.form.get(name);
|
|
46
|
+
if (!control || !control.touched) return null;
|
|
47
|
+
const message = control.errors?.[errorKey];
|
|
48
|
+
return typeof message === "string" ? message : null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
@if (showWarningModal()) {
|
|
2
|
+
<app-dialog [open]="true" [closeOnBackdrop]="false">
|
|
3
|
+
<div
|
|
4
|
+
class="max-w-md"
|
|
5
|
+
role="alertdialog"
|
|
6
|
+
aria-labelledby="session-warning-title"
|
|
7
|
+
aria-describedby="session-warning-description"
|
|
8
|
+
>
|
|
9
|
+
<h2 id="session-warning-title" class="text-lg font-semibold">
|
|
10
|
+
{{ labels.sessionWarningTitle }}
|
|
11
|
+
</h2>
|
|
12
|
+
<p id="session-warning-description" class="text-sm text-muted-foreground mt-1">
|
|
13
|
+
{{ labels.sessionWarningMessage }}
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<div class="flex flex-col items-center gap-4 py-6">
|
|
17
|
+
<time
|
|
18
|
+
[attr.datetime]="isoTime()"
|
|
19
|
+
role="timer"
|
|
20
|
+
aria-live="off"
|
|
21
|
+
aria-atomic="true"
|
|
22
|
+
aria-describedby="session-warning-description"
|
|
23
|
+
class="text-5xl font-bold text-center tabular-nums text-destructive"
|
|
24
|
+
>
|
|
25
|
+
{{ formattedTime() }}
|
|
26
|
+
</time>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div class="flex gap-4 justify-end">
|
|
30
|
+
<app-button appearance="outlined" (clicked)="onLogoutClick()">
|
|
31
|
+
{{ labels.logoutButton }}
|
|
32
|
+
</app-button>
|
|
33
|
+
<app-button appearance="filled" (clicked)="onContinue()">
|
|
34
|
+
{{ labels.continueButton }}
|
|
35
|
+
</app-button>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</app-dialog>
|
|
39
|
+
} @if (showExpiredAlert()) {
|
|
40
|
+
<div class="fixed top-4 left-1/2 -translate-x-1/2 z-50 w-full max-w-md px-4">
|
|
41
|
+
<app-status-alert
|
|
42
|
+
variant="error"
|
|
43
|
+
[title]="labels.sessionWarningTitle"
|
|
44
|
+
[message]="labels.invalidSessionMessage"
|
|
45
|
+
/>
|
|
46
|
+
<button
|
|
47
|
+
type="button"
|
|
48
|
+
class="sr-only"
|
|
49
|
+
[attr.aria-label]="labels.closeLabel"
|
|
50
|
+
(click)="onDismissAlert()"
|
|
51
|
+
>
|
|
52
|
+
{{ labels.closeLabel }}
|
|
53
|
+
</button>
|
|
54
|
+
</div>
|
|
55
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import {
|
|
7
|
+
ChangeDetectionStrategy,
|
|
8
|
+
Component,
|
|
9
|
+
DestroyRef,
|
|
10
|
+
effect,
|
|
11
|
+
inject,
|
|
12
|
+
OnInit,
|
|
13
|
+
signal,
|
|
14
|
+
} from "@angular/core";
|
|
15
|
+
import { Router } from "@angular/router";
|
|
16
|
+
import { DialogComponent } from "../../../components/ui/dialog/dialog";
|
|
17
|
+
import { StatusAlertComponent } from "../status-alert/status-alert";
|
|
18
|
+
import { ButtonComponent } from "../../../components/ui/button/button";
|
|
19
|
+
import { AuthService } from "../auth/auth.service";
|
|
20
|
+
import { SessionTimeoutService } from "../utils/session-timeout.service";
|
|
21
|
+
import { LABELS, STORAGE_KEYS } from "../utils/session-timeout.config";
|
|
22
|
+
import { ROUTES } from "../config/authentication.config";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Session-timeout validator — the Angular port of the React
|
|
26
|
+
* `SessionTimeoutValidator`. Rendered app-wide by `AuthAppLayoutComponent` so
|
|
27
|
+
* the warning modal is available on every route (exactly like React).
|
|
28
|
+
*
|
|
29
|
+
* Responsibilities (all mirrored from React):
|
|
30
|
+
* - Starts polling via `SessionTimeoutService` on init, skipping guest users.
|
|
31
|
+
* - Shows a non-dismissable warning modal with a live countdown when the session
|
|
32
|
+
* nears expiry; "Continue" extends the session, "Log Out" logs out.
|
|
33
|
+
* - When the countdown reaches 0 it re-checks the server before logging out
|
|
34
|
+
* (prevents premature logout).
|
|
35
|
+
* - On expiry it sets the `showSessionMessage` sessionStorage flag then calls
|
|
36
|
+
* `AuthService.logout(window.location.pathname)` (hard nav).
|
|
37
|
+
* - On the login page, if the flag is set, shows the session-expired alert once
|
|
38
|
+
* (lazily read at init, since the expiry logout hard-navigates and this
|
|
39
|
+
* component always remounts fresh on login).
|
|
40
|
+
*
|
|
41
|
+
* `SessionTimeoutService` is provided here so its timers are scoped to this
|
|
42
|
+
* component's lifetime (mirrors the hook's unmount cleanup).
|
|
43
|
+
*/
|
|
44
|
+
@Component({
|
|
45
|
+
selector: "app-session-timeout-validator",
|
|
46
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
47
|
+
providers: [SessionTimeoutService],
|
|
48
|
+
imports: [DialogComponent, StatusAlertComponent, ButtonComponent],
|
|
49
|
+
templateUrl: "./session.html",
|
|
50
|
+
})
|
|
51
|
+
export class SessionTimeoutValidatorComponent implements OnInit {
|
|
52
|
+
private readonly authService = inject(AuthService);
|
|
53
|
+
private readonly session = inject(SessionTimeoutService);
|
|
54
|
+
private readonly destroyRef = inject(DestroyRef);
|
|
55
|
+
private readonly router = inject(Router);
|
|
56
|
+
|
|
57
|
+
protected readonly labels = LABELS;
|
|
58
|
+
|
|
59
|
+
// Community base path. React hard-codes "" here (root-relative); kept identical.
|
|
60
|
+
private readonly basePath = "";
|
|
61
|
+
|
|
62
|
+
// -- Exposed session state (from the service) ----------------------------
|
|
63
|
+
protected readonly showWarningModal = this.session.showWarningModal;
|
|
64
|
+
protected readonly timeLeftInSession = this.session.timeLeftInSession;
|
|
65
|
+
|
|
66
|
+
// -- Session-expired alert (lazy, read once at init) ---------------------
|
|
67
|
+
protected readonly showExpiredAlert = signal<boolean>(false);
|
|
68
|
+
|
|
69
|
+
// -- Countdown state (mirrors useCountdownTimer) -------------------------
|
|
70
|
+
protected readonly countdownSeconds = signal<number>(0);
|
|
71
|
+
private countdownIntervalId: ReturnType<typeof setInterval> | null = null;
|
|
72
|
+
private countdownEndTime = 0;
|
|
73
|
+
private lastModalOpen = false;
|
|
74
|
+
|
|
75
|
+
constructor() {
|
|
76
|
+
// React's SessionWarningModal resets+starts the countdown when the modal
|
|
77
|
+
// opens and stops it when it closes. This effect mirrors that: it reacts to
|
|
78
|
+
// the warning-modal signal and (re)starts the countdown from the latest
|
|
79
|
+
// remaining time whenever the modal is open.
|
|
80
|
+
effect(() => {
|
|
81
|
+
const open = this.showWarningModal();
|
|
82
|
+
const remaining = this.timeLeftInSession() ?? 0;
|
|
83
|
+
if (open) {
|
|
84
|
+
this.startCountdown(remaining);
|
|
85
|
+
} else if (this.lastModalOpen) {
|
|
86
|
+
this.stopCountdown();
|
|
87
|
+
}
|
|
88
|
+
this.lastModalOpen = open;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Auto-logout when the countdown/poll reports the session is expired and the
|
|
92
|
+
// user is not a guest (mirrors the React expiry `useEffect`).
|
|
93
|
+
effect(() => {
|
|
94
|
+
const timeLeft = this.timeLeftInSession();
|
|
95
|
+
if (timeLeft !== null && timeLeft <= 0 && !this.isGuest()) {
|
|
96
|
+
this.handleLogout();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
ngOnInit(): void {
|
|
102
|
+
// Session-expired alert: checked once at init via a lazy read. The expiry
|
|
103
|
+
// handler triggers a hard navigation, so this component always mounts fresh
|
|
104
|
+
// on the login page after expiry.
|
|
105
|
+
//
|
|
106
|
+
// Compare against the router's parsed URL (base-href/community-path stripped)
|
|
107
|
+
// rather than `window.location.pathname`: the raw browser path includes any
|
|
108
|
+
// base href (e.g. `/sfsites/c/.../login`) and would never equal `/login`,
|
|
109
|
+
// silently hiding the banner. `router.url` is router-relative, matching the
|
|
110
|
+
// React `useLocation().pathname` behavior. Strip the query/fragment before
|
|
111
|
+
// comparing.
|
|
112
|
+
const routerPath = this.router.url.split(/[?#]/)[0];
|
|
113
|
+
const isLoginPage = routerPath === ROUTES.LOGIN.PATH;
|
|
114
|
+
const shouldShow =
|
|
115
|
+
isLoginPage && sessionStorage.getItem(STORAGE_KEYS.SHOW_SESSION_MESSAGE) === "true";
|
|
116
|
+
if (shouldShow) {
|
|
117
|
+
sessionStorage.removeItem(STORAGE_KEYS.SHOW_SESSION_MESSAGE);
|
|
118
|
+
this.showExpiredAlert.set(true);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Start monitoring (service skips guests internally).
|
|
122
|
+
this.session.start(this.basePath, this.isGuest());
|
|
123
|
+
|
|
124
|
+
this.destroyRef.onDestroy(() => {
|
|
125
|
+
this.session.stop();
|
|
126
|
+
this.stopCountdown();
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private isGuest(): boolean {
|
|
131
|
+
return !this.authService.isAuthenticated();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// -- Countdown ------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
private startCountdown(seconds: number): void {
|
|
137
|
+
this.stopCountdown();
|
|
138
|
+
this.countdownSeconds.set(seconds);
|
|
139
|
+
this.countdownEndTime = Date.now() + seconds * 1000;
|
|
140
|
+
this.countdownIntervalId = setInterval(() => {
|
|
141
|
+
const remainingMs = this.countdownEndTime - Date.now();
|
|
142
|
+
const newTime = Math.max(0, Math.ceil(remainingMs / 1000));
|
|
143
|
+
this.countdownSeconds.set(newTime);
|
|
144
|
+
if (newTime <= 0) {
|
|
145
|
+
this.stopCountdown();
|
|
146
|
+
// Re-check with the server before logging out (React onCountdownExpire).
|
|
147
|
+
void this.session.checkSession();
|
|
148
|
+
}
|
|
149
|
+
}, 100);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private stopCountdown(): void {
|
|
153
|
+
if (this.countdownIntervalId) {
|
|
154
|
+
clearInterval(this.countdownIntervalId);
|
|
155
|
+
this.countdownIntervalId = null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** MM:SS formatted countdown (mirrors useCountdownTimer.formattedTime). */
|
|
160
|
+
protected formattedTime(): string {
|
|
161
|
+
const total = this.countdownSeconds();
|
|
162
|
+
const minutes = Math.floor(total / 60);
|
|
163
|
+
const secs = total % 60;
|
|
164
|
+
const pad = (n: number) => n.toString().padStart(2, "0");
|
|
165
|
+
return `${pad(minutes)}:${pad(secs)}`;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** ISO 8601 duration for the <time> element (mirrors isoTime). */
|
|
169
|
+
protected isoTime(): string {
|
|
170
|
+
const total = this.countdownSeconds();
|
|
171
|
+
const minutes = Math.floor(total / 60);
|
|
172
|
+
const secs = total % 60;
|
|
173
|
+
return `PT${minutes}M${secs}S`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// -- Actions --------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
/** "Continue" — stop countdown and extend the session. */
|
|
179
|
+
protected onContinue(): void {
|
|
180
|
+
this.stopCountdown();
|
|
181
|
+
void this.session.extendSession();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** "Log Out" button in the warning modal. */
|
|
185
|
+
protected onLogoutClick(): void {
|
|
186
|
+
this.stopCountdown();
|
|
187
|
+
this.handleLogout();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Dismiss the session-expired alert. */
|
|
191
|
+
protected onDismissAlert(): void {
|
|
192
|
+
this.showExpiredAlert.set(false);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Set the session-message flag, stop monitoring, then hand off to the
|
|
197
|
+
* centralized logout (hard nav). Passes the current pathname as the return
|
|
198
|
+
* URL. Mirrors the React `handleLogout`.
|
|
199
|
+
*/
|
|
200
|
+
private handleLogout(): void {
|
|
201
|
+
sessionStorage.setItem(STORAGE_KEYS.SHOW_SESSION_MESSAGE, "true");
|
|
202
|
+
this.session.stop();
|
|
203
|
+
this.authService.logout(window.location.pathname);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { ChangeDetectionStrategy, Component, computed, input } from "@angular/core";
|
|
7
|
+
import { AlertComponent } from "../../../components/ui/alert/alert";
|
|
8
|
+
|
|
9
|
+
/** Status banner variant conveying the tone of the message. */
|
|
10
|
+
export type AppStatusAlertVariant = "error" | "success" | "info" | "warning";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Status / error banner — a feature-owned composition over the base `app-alert`
|
|
14
|
+
* ui primitive (not a base-template component). Adds a four-way `variant` with a
|
|
15
|
+
* colour treatment, mirroring the React `components/alerts/status-alert`.
|
|
16
|
+
*
|
|
17
|
+
* Supply the copy via the `message` input, or content-project richer markup
|
|
18
|
+
* (lists, links) as the default slot. Consumed by the authentication
|
|
19
|
+
* login-error / success / session-expired banners.
|
|
20
|
+
*/
|
|
21
|
+
@Component({
|
|
22
|
+
selector: "app-status-alert",
|
|
23
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
24
|
+
imports: [AlertComponent],
|
|
25
|
+
templateUrl: "./status-alert.html",
|
|
26
|
+
host: {
|
|
27
|
+
"data-slot": "status-alert",
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
export class StatusAlertComponent {
|
|
31
|
+
readonly variant = input<AppStatusAlertVariant>("info");
|
|
32
|
+
|
|
33
|
+
/** Optional title rendered above the message / projected content. */
|
|
34
|
+
readonly title = input<string>("");
|
|
35
|
+
|
|
36
|
+
/** Message copy; may be omitted in favour of projected content. */
|
|
37
|
+
readonly message = input<string>("");
|
|
38
|
+
|
|
39
|
+
/** Colour utilities applied to the banner for the current variant. */
|
|
40
|
+
protected readonly toneClass = computed(() => {
|
|
41
|
+
switch (this.variant()) {
|
|
42
|
+
case "error":
|
|
43
|
+
return "text-destructive";
|
|
44
|
+
case "success":
|
|
45
|
+
return "text-emerald-700";
|
|
46
|
+
case "warning":
|
|
47
|
+
return "text-amber-700";
|
|
48
|
+
default:
|
|
49
|
+
return "text-sky-700";
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { ChangeDetectionStrategy, Component, input } from "@angular/core";
|
|
7
|
+
import { ButtonComponent } from "../../../components/ui/button/button";
|
|
8
|
+
|
|
9
|
+
// Submit button reflecting form submission state: the parent passes its
|
|
10
|
+
// submitting flag via [submitting]. While submitting the base button is
|
|
11
|
+
// disabled and shows a spinner with the loading label (prevents double-submit).
|
|
12
|
+
@Component({
|
|
13
|
+
selector: "app-submit-button",
|
|
14
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
15
|
+
imports: [ButtonComponent],
|
|
16
|
+
templateUrl: "./submit-button.html",
|
|
17
|
+
})
|
|
18
|
+
export class SubmitButtonComponent {
|
|
19
|
+
readonly label = input.required<string>();
|
|
20
|
+
readonly loadingLabel = input<string>("Submitting…");
|
|
21
|
+
readonly submitting = input<boolean>(false);
|
|
22
|
+
readonly disabled = input<boolean>(false);
|
|
23
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { AUTH_REDIRECT_PARAM } from "../config/authentication.config";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Extracts the startUrl from the current query params, defaulting to '/'.
|
|
10
|
+
*
|
|
11
|
+
* SECURITY NOTE: This function strictly validates the URL to prevent Open
|
|
12
|
+
* Redirect vulnerabilities. It allows only relative paths.
|
|
13
|
+
*
|
|
14
|
+
* Direct port of the React `getStartUrl`. The React version takes a
|
|
15
|
+
* `URLSearchParams`; Angular's `ParamMap` exposes the same `get(key)` contract,
|
|
16
|
+
* so this accepts a minimal `{ get(name): string | null }` shape and works with
|
|
17
|
+
* both an `ActivatedRoute` `ParamMap` and a `URLSearchParams`.
|
|
18
|
+
*
|
|
19
|
+
* @param params - The query-param map (e.g. ActivatedRoute.snapshot.queryParamMap).
|
|
20
|
+
* @returns The start URL for post-authentication redirect.
|
|
21
|
+
*/
|
|
22
|
+
export function getStartUrl(params: { get(name: string): string | null }): string {
|
|
23
|
+
const url = params.get(AUTH_REDIRECT_PARAM);
|
|
24
|
+
if (url && isValidRedirect(url)) {
|
|
25
|
+
return url;
|
|
26
|
+
}
|
|
27
|
+
return "/";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Security: Validates that the redirect URL is a relative path to prevent Open
|
|
32
|
+
* Redirect vulnerabilities.
|
|
33
|
+
*
|
|
34
|
+
* Security Checks:
|
|
35
|
+
* 1. Rejects protocol-relative URLs (//)
|
|
36
|
+
* 2. Rejects backslash usage which some browsers treat as slashes (/\)
|
|
37
|
+
* 3. Rejects control characters
|
|
38
|
+
*
|
|
39
|
+
* Ported from the React `isValidRedirect`, with one intentional hardening: the
|
|
40
|
+
* character-range ceiling is tightened from the React source's U+00FF to the
|
|
41
|
+
* printable-ASCII bound U+007E (~) so DEL / C1 controls / NBSP are rejected in
|
|
42
|
+
* line with check #3. Do not relax any of these checks without security review.
|
|
43
|
+
*/
|
|
44
|
+
export function isValidRedirect(url: string): boolean {
|
|
45
|
+
// Basic structure check
|
|
46
|
+
if (!url.startsWith("/") || url.startsWith("//")) return false;
|
|
47
|
+
// Security: Reject backslashes to prevent /\example.com bypasses
|
|
48
|
+
if (url.includes("\\")) return false;
|
|
49
|
+
// Robustness: Ensure it doesn't contain whitespace/control characters.
|
|
50
|
+
// Allowed range is the printable-ASCII band U+0021 (!) through U+007E (~).
|
|
51
|
+
// This deliberately tightens the React reference's U+00FF ceiling, which
|
|
52
|
+
// admitted U+007F (DEL), the C1 control block (U+0080-U+009F, incl. NEL),
|
|
53
|
+
// and U+00A0 (NBSP) - all of which contradict the "reject control
|
|
54
|
+
// characters" contract and are open-redirect / request-splitting vectors.
|
|
55
|
+
if (/[^!-~]/.test(url)) return false;
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Shared response type for authentication endpoints (login/register). Success
|
|
61
|
+
* responses contain `success: true` and `redirectUrl`. Error responses contain
|
|
62
|
+
* an `errors` array.
|
|
63
|
+
*/
|
|
64
|
+
export interface AuthResponse {
|
|
65
|
+
success?: boolean;
|
|
66
|
+
redirectUrl?: string | null;
|
|
67
|
+
errors?: string[];
|
|
68
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Angular Reactive Forms validators that mirror the React feature's zod schemas
|
|
10
|
+
* (`authHelpers.ts`). The React port dropped zod in favour of native Angular
|
|
11
|
+
* validators; these reproduce the same rules and messages so the UX is
|
|
12
|
+
* identical. Each validator returns `{ <key>: message }` on failure and `null`
|
|
13
|
+
* on success; templates read the first message via `control.errors`.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Mirrors zod `emailSchema`: trimmed, valid email. */
|
|
17
|
+
export const emailValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
|
|
18
|
+
const value = (control.value ?? "").toString().trim();
|
|
19
|
+
if (value === "") {
|
|
20
|
+
return { email: "Please enter a valid email address" };
|
|
21
|
+
}
|
|
22
|
+
// Same intent as zod's email check: a single @ with non-empty local/domain
|
|
23
|
+
// parts and a dotted domain. Kept deliberately permissive, like zod.
|
|
24
|
+
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
25
|
+
return emailPattern.test(value) ? null : { email: "Please enter a valid email address" };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** Mirrors zod `passwordSchema`: minimum 8 characters. */
|
|
29
|
+
export const passwordMinValidator: ValidatorFn = (
|
|
30
|
+
control: AbstractControl,
|
|
31
|
+
): ValidationErrors | null => {
|
|
32
|
+
const value = (control.value ?? "").toString();
|
|
33
|
+
return value.length >= 8 ? null : { password: "Password must be at least 8 characters" };
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** A required-with-custom-message validator (mirrors zod `min(1, message)`). */
|
|
37
|
+
export function requiredWithMessage(message: string): ValidatorFn {
|
|
38
|
+
return (control: AbstractControl): ValidationErrors | null => {
|
|
39
|
+
const value = (control.value ?? "").toString().trim();
|
|
40
|
+
return value.length >= 1 ? null : { required: message };
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Cross-field validator mirroring the `newPasswordSchema` refine: the
|
|
46
|
+
* `confirmPassword` control must equal the `newPassword` control. Attach to the
|
|
47
|
+
* FormGroup; sets `{ passwordMismatch: '...' }` on the confirm control (matching
|
|
48
|
+
* the zod `path: ['confirmPassword']`) so the error renders under that field.
|
|
49
|
+
*/
|
|
50
|
+
export function passwordsMatchValidator(
|
|
51
|
+
passwordKey = "newPassword",
|
|
52
|
+
confirmKey = "confirmPassword",
|
|
53
|
+
): ValidatorFn {
|
|
54
|
+
return (group: AbstractControl): ValidationErrors | null => {
|
|
55
|
+
const password = group.get(passwordKey);
|
|
56
|
+
const confirm = group.get(confirmKey);
|
|
57
|
+
if (!password || !confirm) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
if (confirm.value !== password.value) {
|
|
61
|
+
const existing = confirm.errors ?? {};
|
|
62
|
+
confirm.setErrors({ ...existing, passwordMismatch: "Passwords do not match" });
|
|
63
|
+
return { passwordMismatch: "Passwords do not match" };
|
|
64
|
+
}
|
|
65
|
+
// Clear only our own error, preserving any other errors on the control.
|
|
66
|
+
if (confirm.errors) {
|
|
67
|
+
const { passwordMismatch: _removed, ...rest } = confirm.errors;
|
|
68
|
+
confirm.setErrors(Object.keys(rest).length ? rest : null);
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
};
|
|
72
|
+
}
|