@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.
Files changed (295) hide show
  1. package/LICENSE.txt +82 -0
  2. package/README.md +130 -0
  3. package/dist/.forceignore +15 -0
  4. package/dist/.husky/pre-commit +4 -0
  5. package/dist/.prettierignore +11 -0
  6. package/dist/.prettierrc +17 -0
  7. package/dist/CHANGELOG.md +5238 -0
  8. package/dist/README.md +77 -0
  9. package/dist/config/project-scratch-def.json +13 -0
  10. package/dist/eslint.config.js +7 -0
  11. package/dist/force-app/main/default/classes/UIBundleAuthUtils.cls +68 -0
  12. package/dist/force-app/main/default/classes/UIBundleAuthUtils.cls-meta.xml +5 -0
  13. package/dist/force-app/main/default/classes/UIBundleChangePassword.cls +77 -0
  14. package/dist/force-app/main/default/classes/UIBundleChangePassword.cls-meta.xml +5 -0
  15. package/dist/force-app/main/default/classes/UIBundleForgotPassword.cls +71 -0
  16. package/dist/force-app/main/default/classes/UIBundleForgotPassword.cls-meta.xml +5 -0
  17. package/dist/force-app/main/default/classes/UIBundleLogin.cls +105 -0
  18. package/dist/force-app/main/default/classes/UIBundleLogin.cls-meta.xml +5 -0
  19. package/dist/force-app/main/default/classes/UIBundleRegistration.cls +162 -0
  20. package/dist/force-app/main/default/classes/UIBundleRegistration.cls-meta.xml +5 -0
  21. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/.forceignore +15 -0
  22. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/.graphqlrc.yml +2 -0
  23. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/.postcssrc.json +5 -0
  24. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/.prettierignore +8 -0
  25. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/.prettierrc +12 -0
  26. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/CHANGELOG.md +4 -0
  27. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/README.md +85 -0
  28. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/angular.json +98 -0
  29. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/codegen.yml +95 -0
  30. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/components.json +6 -0
  31. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/e2e/app.spec.ts +15 -0
  32. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/esbuild/api-version.mjs +17 -0
  33. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/esbuild/graphql-codegen.mjs +13 -0
  34. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/eslint-plugin-angular-graphql.js +148 -0
  35. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/eslint.config.js +76 -0
  36. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/feature-angular-authentication.uibundle-meta.xml +7 -0
  37. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/middleware/html.mjs +3 -0
  38. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/middleware/proxy.mjs +12 -0
  39. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/package.json +69 -0
  40. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/playwright.config.ts +25 -0
  41. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/public/favicon.ico +0 -0
  42. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/scripts/get-graphql-schema.mjs +69 -0
  43. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/scripts/rewrite-e2e-assets.mjs +30 -0
  44. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/api/data-client.service.spec.ts +184 -0
  45. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/api/data-client.service.ts +74 -0
  46. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/api/user-profile.service.ts +126 -0
  47. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/app.config.ts +20 -0
  48. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/app.html +1 -0
  49. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/app.routes.ts +66 -0
  50. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/app.spec.ts +18 -0
  51. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/app.ts +15 -0
  52. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/layout/app-layout/app-layout.html +51 -0
  53. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/layout/app-layout/app-layout.spec.ts +63 -0
  54. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/layout/app-layout/app-layout.ts +27 -0
  55. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/alert/alert.html +27 -0
  56. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/alert/alert.ts +41 -0
  57. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/button/button.html +27 -0
  58. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/button/button.ts +66 -0
  59. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/card/card.ts +100 -0
  60. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/collapsible/collapsible.html +38 -0
  61. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/collapsible/collapsible.ts +21 -0
  62. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/date-picker/date-picker.html +20 -0
  63. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/date-picker/date-picker.ts +49 -0
  64. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/date-range-picker/date-range-picker.html +20 -0
  65. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/date-range-picker/date-range-picker.ts +69 -0
  66. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/dialog/dialog.html +20 -0
  67. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/dialog/dialog.ts +40 -0
  68. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/dropdown-menu/dropdown-menu.html +20 -0
  69. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/dropdown-menu/dropdown-menu.ts +100 -0
  70. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/field/field.html +15 -0
  71. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/field/field.ts +28 -0
  72. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/field-appearance.ts +8 -0
  73. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/field-size.ts +8 -0
  74. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/icon/icon.ts +68 -0
  75. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/input/input.html +34 -0
  76. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/input/input.ts +79 -0
  77. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/label/label.ts +21 -0
  78. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/paginator/paginator.html +74 -0
  79. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/paginator/paginator.ts +93 -0
  80. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/paginator/types.ts +13 -0
  81. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/popover/popover.html +13 -0
  82. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/popover/popover.ts +37 -0
  83. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/select/select.html +36 -0
  84. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/select/select.ts +63 -0
  85. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/separator/separator.ts +31 -0
  86. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/skeleton/skeleton.ts +20 -0
  87. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/components/ui/spinner/spinner.ts +28 -0
  88. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/auth/auth.guard.ts +50 -0
  89. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/auth/auth.service.ts +158 -0
  90. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/auth-form/auth-form.html +33 -0
  91. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/auth-form/auth-form.ts +94 -0
  92. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/auth-layout/auth-layout.html +2 -0
  93. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/auth-layout/auth-layout.ts +30 -0
  94. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/card-layout/card-layout.html +16 -0
  95. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/card-layout/card-layout.ts +40 -0
  96. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/config/authentication.config.ts +75 -0
  97. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/footer-link/footer-link.html +9 -0
  98. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/footer-link/footer-link.ts +26 -0
  99. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/menu/auth-menu/auth-menu.html +36 -0
  100. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/menu/auth-menu/auth-menu.ts +34 -0
  101. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/reactive-form-page.base.ts +50 -0
  102. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/session/session.html +55 -0
  103. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/session/session.ts +205 -0
  104. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/status-alert/status-alert.html +5 -0
  105. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/status-alert/status-alert.ts +52 -0
  106. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/submit-button/submit-button.html +9 -0
  107. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/submit-button/submit-button.ts +23 -0
  108. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/utils/auth-helpers.ts +68 -0
  109. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/utils/auth-validators.ts +72 -0
  110. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/utils/helpers.ts +85 -0
  111. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/utils/session-time-servlet.ts +130 -0
  112. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/utils/session-timeout.config.ts +83 -0
  113. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/features/authentication/utils/session-timeout.service.ts +201 -0
  114. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/change-password/change-password-page.html +68 -0
  115. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/change-password/change-password-page.ts +82 -0
  116. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/forgot-password/forgot-password-page.html +35 -0
  117. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/forgot-password/forgot-password-page.ts +87 -0
  118. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/home/home.html +6 -0
  119. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/home/home.spec.ts +23 -0
  120. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/home/home.ts +13 -0
  121. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/login/login-page.html +47 -0
  122. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/login/login-page.ts +89 -0
  123. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/not-found/not-found.html +12 -0
  124. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/not-found/not-found.spec.ts +33 -0
  125. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/not-found/not-found.ts +15 -0
  126. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/profile/profile-page.html +116 -0
  127. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/profile/profile-page.ts +194 -0
  128. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/register/register-page.html +80 -0
  129. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/register/register-page.ts +93 -0
  130. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/reset-password/reset-password-page.html +60 -0
  131. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/pages/reset-password/reset-password-page.ts +96 -0
  132. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/alert/hlm-alert-action.ts +14 -0
  133. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/alert/hlm-alert-description.ts +17 -0
  134. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/alert/hlm-alert-title.ts +17 -0
  135. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/alert/hlm-alert.ts +35 -0
  136. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/alert/index.ts +16 -0
  137. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/button/hlm-button.token.ts +22 -0
  138. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/button/hlm-button.ts +72 -0
  139. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/button/index.ts +6 -0
  140. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/calendar/hlm-calendar-multi.ts +195 -0
  141. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/calendar/hlm-calendar-range.ts +194 -0
  142. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/calendar/hlm-calendar.ts +189 -0
  143. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/calendar/hlm-month-year-calendar.ts +119 -0
  144. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/calendar/index.ts +16 -0
  145. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-action.ts +12 -0
  146. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-avatar.ts +14 -0
  147. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-content.ts +12 -0
  148. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-description.ts +12 -0
  149. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-footer.ts +12 -0
  150. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-header.ts +15 -0
  151. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card-title.ts +12 -0
  152. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card.token.ts +19 -0
  153. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/hlm-card.ts +22 -0
  154. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/card/index.ts +28 -0
  155. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/collapsible/hlm-collapsible-content.ts +14 -0
  156. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/collapsible/hlm-collapsible-trigger.ts +9 -0
  157. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/collapsible/hlm-collapsible.ts +15 -0
  158. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/collapsible/index.ts +13 -0
  159. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-multi-input.ts +104 -0
  160. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker-anchor.ts +23 -0
  161. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker-input.ts +118 -0
  162. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker-multi.token.ts +109 -0
  163. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker-multi.ts +220 -0
  164. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker-trigger.ts +104 -0
  165. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker.token.ts +69 -0
  166. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-picker.ts +203 -0
  167. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-range-input.ts +120 -0
  168. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-range-picker.token.ts +86 -0
  169. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-date-range-picker.ts +252 -0
  170. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-month-year-input.ts +105 -0
  171. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-month-year-picker.token.ts +89 -0
  172. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/hlm-month-year-picker.ts +196 -0
  173. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/date-picker/index.ts +38 -0
  174. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-close.ts +9 -0
  175. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-content.ts +74 -0
  176. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-description.ts +17 -0
  177. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-footer.ts +15 -0
  178. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-header.ts +12 -0
  179. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-overlay.ts +27 -0
  180. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-portal.ts +8 -0
  181. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-title.ts +14 -0
  182. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog-trigger.ts +14 -0
  183. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog.service.ts +46 -0
  184. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/hlm-dialog.ts +24 -0
  185. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dialog/index.ts +35 -0
  186. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-checkbox-indicator.ts +21 -0
  187. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-checkbox.ts +54 -0
  188. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-focus-on-hover.ts +35 -0
  189. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-group.ts +14 -0
  190. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-item-sub-indicator.ts +19 -0
  191. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-item.ts +42 -0
  192. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-label.ts +20 -0
  193. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-radio-indicator.ts +21 -0
  194. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-radio.ts +49 -0
  195. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-separator.ts +12 -0
  196. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-shortcut.ts +15 -0
  197. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-sub-trigger.ts +52 -0
  198. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-sub.ts +53 -0
  199. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-token.ts +26 -0
  200. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu-trigger.ts +46 -0
  201. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/hlm-dropdown-menu.ts +57 -0
  202. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/dropdown-menu/index.ts +49 -0
  203. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-content.ts +12 -0
  204. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-description.ts +53 -0
  205. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-error.ts +100 -0
  206. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-group.ts +15 -0
  207. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-label.ts +17 -0
  208. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-legend.ts +19 -0
  209. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-separator.ts +24 -0
  210. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-set.ts +15 -0
  211. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field-title.ts +15 -0
  212. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/hlm-field.ts +47 -0
  213. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/field/index.ts +34 -0
  214. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input/hlm-input.ts +21 -0
  215. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input/index.ts +5 -0
  216. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input-group/hlm-input-group-addon.ts +40 -0
  217. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input-group/hlm-input-group-button.ts +47 -0
  218. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input-group/hlm-input-group-input.ts +17 -0
  219. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input-group/hlm-input-group-text.ts +14 -0
  220. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input-group/hlm-input-group.ts +18 -0
  221. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/input-group/index.ts +19 -0
  222. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/label/hlm-label.ts +17 -0
  223. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/label/index.ts +5 -0
  224. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/label/label.html +11 -0
  225. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-numbered-pagination-query-params.ts +191 -0
  226. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-numbered-pagination.ts +290 -0
  227. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination-content.ts +12 -0
  228. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination-ellipsis.ts +27 -0
  229. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination-item.ts +7 -0
  230. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination-link.ts +51 -0
  231. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination-next.ts +65 -0
  232. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination-previous.ts +65 -0
  233. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/hlm-pagination.ts +19 -0
  234. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/pagination/index.ts +31 -0
  235. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover-content.ts +25 -0
  236. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover-description.ts +12 -0
  237. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover-header.ts +12 -0
  238. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover-portal.ts +8 -0
  239. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover-title.ts +12 -0
  240. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover-trigger.ts +14 -0
  241. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/hlm-popover.ts +23 -0
  242. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/popover/index.ts +25 -0
  243. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-content.ts +44 -0
  244. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-group.ts +14 -0
  245. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-item.ts +36 -0
  246. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-label.ts +14 -0
  247. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-multiple.ts +37 -0
  248. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-placeholder.ts +17 -0
  249. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-portal.ts +8 -0
  250. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-scroll-down.ts +22 -0
  251. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-scroll-up.ts +22 -0
  252. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-separator.ts +14 -0
  253. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-trigger.ts +59 -0
  254. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-value-template.ts +5 -0
  255. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-value.ts +18 -0
  256. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-values-content.ts +9 -0
  257. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select-values.ts +5 -0
  258. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/hlm-select.ts +37 -0
  259. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/select/index.ts +52 -0
  260. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/separator/hlm-separator.ts +19 -0
  261. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/separator/index.ts +5 -0
  262. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/skeleton/hlm-skeleton.ts +14 -0
  263. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/skeleton/index.ts +5 -0
  264. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/spinner/hlm-spinner.ts +26 -0
  265. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/spinner/index.ts +5 -0
  266. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/utils/hlm.ts +313 -0
  267. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/utils/index.ts +2 -0
  268. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/shared/utils/provide-spartan-hlm.ts +34 -0
  269. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/app/utils/async-data.ts +99 -0
  270. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/index.html +13 -0
  271. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/main.ts +5 -0
  272. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/styles.css +139 -0
  273. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/src/types/sf-globals.d.ts +9 -0
  274. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/tsconfig.app.json +11 -0
  275. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/tsconfig.json +36 -0
  276. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/tsconfig.spec.json +10 -0
  277. package/dist/force-app/main/default/uiBundles/feature-angular-authentication/ui-bundle.json +7 -0
  278. package/dist/jest.config.js +6 -0
  279. package/dist/package-lock.json +12554 -0
  280. package/dist/package.json +46 -0
  281. package/dist/scripts/apex/hello.apex +10 -0
  282. package/dist/scripts/gitignore-templates.json +4 -0
  283. package/dist/scripts/graphql-search.sh +191 -0
  284. package/dist/scripts/org-setup-config-schema.mjs +132 -0
  285. package/dist/scripts/org-setup-dev.mjs +114 -0
  286. package/dist/scripts/org-setup-url.mjs +108 -0
  287. package/dist/scripts/org-setup-utils.mjs +569 -0
  288. package/dist/scripts/org-setup-xml.mjs +278 -0
  289. package/dist/scripts/org-setup.config.json +5 -0
  290. package/dist/scripts/org-setup.mjs +2537 -0
  291. package/dist/scripts/sf-project-setup.mjs +103 -0
  292. package/dist/scripts/soql/account.soql +6 -0
  293. package/dist/scripts/validate-org-setup-config.mjs +38 -0
  294. package/dist/sfdx-project.json +12 -0
  295. 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,5 @@
1
+ <app-alert [title]="title()" [class]="toneClass()">
2
+ @if (message()) { {{ message() }} } @else {
3
+ <ng-content />
4
+ }
5
+ </app-alert>
@@ -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,9 @@
1
+ <app-button
2
+ type="submit"
3
+ class="w-full"
4
+ [loading]="submitting()"
5
+ [loadingLabel]="loadingLabel()"
6
+ [disabled]="disabled()"
7
+ >
8
+ {{ label() }}
9
+ </app-button>
@@ -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
+ }