@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,69 @@
1
+ /**
2
+ * Downloads the full GraphQL schema from a connected Salesforce org via introspection.
3
+ *
4
+ * Usage:
5
+ * npm run graphql:schema
6
+ * node scripts/get-graphql-schema.mjs [output-path]
7
+ *
8
+ * The default output path matches the schema location expected by codegen.yml
9
+ * and .graphqlrc.yml so that codegen and IDE tooling resolve it automatically.
10
+ */
11
+ import { writeFileSync } from 'node:fs';
12
+ import { resolve } from 'node:path';
13
+ import { getOrgInfo } from '@salesforce/ui-bundle/app';
14
+ import { buildClientSchema, getIntrospectionQuery, printSchema } from 'graphql';
15
+ import { pruneSchema } from '@graphql-tools/utils';
16
+
17
+ const DEFAULT_SCHEMA_PATH = '../../../../../schema.graphql';
18
+ const TARGET_ORG = process.env.SF_TARGET_ORG || undefined;
19
+
20
+ async function executeSalesforceGraphQLQuery(query, variables, operationName) {
21
+ const orgInfo = await getOrgInfo(TARGET_ORG);
22
+ if (!orgInfo) {
23
+ throw new Error('Could not resolve a Salesforce org. Set SF_TARGET_ORG or a default org.');
24
+ }
25
+ const { rawInstanceUrl: instanceUrl, apiVersion, accessToken } = orgInfo;
26
+
27
+ const targetUrl = `${instanceUrl}/services/data/v${apiVersion}/graphql`;
28
+
29
+ console.log(`Executing introspection query against ${targetUrl}`);
30
+ const response = await fetch(targetUrl, {
31
+ method: 'POST',
32
+ headers: {
33
+ Authorization: `Bearer ${accessToken}`,
34
+ 'Content-Type': 'application/json',
35
+ 'X-Chatter-Entity-Encoding': 'false',
36
+ },
37
+ body: JSON.stringify({ query, variables, operationName }),
38
+ });
39
+
40
+ if (!response.ok) {
41
+ const errorText = await response.text();
42
+ throw new Error(
43
+ `Salesforce GraphQL request failed: ${response.status} ${response.statusText} - ${errorText}`,
44
+ );
45
+ }
46
+
47
+ return response.json();
48
+ }
49
+
50
+ try {
51
+ const outputPath = resolve(process.argv[2] || DEFAULT_SCHEMA_PATH);
52
+
53
+ const introspectionResult = await executeSalesforceGraphQLQuery(
54
+ getIntrospectionQuery(),
55
+ {},
56
+ 'IntrospectionQuery',
57
+ );
58
+
59
+ const schema = buildClientSchema(introspectionResult.data);
60
+ const prunedSchema = pruneSchema(schema);
61
+ const sdl = printSchema(prunedSchema);
62
+
63
+ writeFileSync(outputPath, sdl);
64
+
65
+ console.log(`Schema saved to ${outputPath}`);
66
+ } catch (error) {
67
+ console.error('Error:', error.message);
68
+ process.exit(1);
69
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Prepares dist/ for e2e: root-relative asset paths + SPA fallback for serve.
3
+ *
4
+ * angular.json sets deployUrl: "./", so the built index.html references
5
+ * scripts/styles with a relative "./" prefix (e.g. ./main-HASH.js). When the
6
+ * SPA fallback serves index.html for a deep route like /non-existent-route,
7
+ * those "./" paths resolve against the wrong base and 404, so the app never
8
+ * boots. Rewrite them to root-relative "/" paths.
9
+ */
10
+ import { readFileSync, writeFileSync } from 'node:fs';
11
+ import { join, dirname } from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
15
+ // angular.json outputPath: { base: "dist", browser: "" } -> files land in dist/
16
+ const distDir = join(__dirname, '..', 'dist');
17
+
18
+ // Rewrite index.html so asset paths are root-relative (./main-x.js -> /main-x.js)
19
+ const indexPath = join(distDir, 'index.html');
20
+ let html = readFileSync(indexPath, 'utf8');
21
+ html = html.replace(/(src|href)="\.\//g, '$1="/');
22
+ writeFileSync(indexPath, html);
23
+
24
+ // SPA fallback so /non-existent-route etc. serve index.html
25
+ writeFileSync(
26
+ join(distDir, 'serve.json'),
27
+ JSON.stringify({
28
+ rewrites: [{ source: '**', destination: '/index.html' }],
29
+ }),
30
+ );
@@ -0,0 +1,184 @@
1
+ import { TestBed } from '@angular/core/testing';
2
+ import { DataClient } from './data-client.service';
3
+ import { createDataSDK } from '@salesforce/platform-sdk';
4
+
5
+ vi.mock('@salesforce/platform-sdk', () => ({
6
+ createDataSDK: vi.fn(),
7
+ }));
8
+
9
+ describe('DataClient', () => {
10
+ let service: DataClient;
11
+ let mockGraphqlQuery: ReturnType<typeof vi.fn>;
12
+ let mockGraphqlMutate: ReturnType<typeof vi.fn>;
13
+ let mockFetch: ReturnType<typeof vi.fn>;
14
+
15
+ beforeEach(async () => {
16
+ mockGraphqlQuery = vi.fn();
17
+ mockGraphqlMutate = vi.fn();
18
+ mockFetch = vi.fn();
19
+
20
+ vi.mocked(createDataSDK).mockResolvedValue({
21
+ graphql: {
22
+ query: mockGraphqlQuery,
23
+ mutate: mockGraphqlMutate,
24
+ },
25
+ fetch: mockFetch,
26
+ } as any);
27
+
28
+ await TestBed.configureTestingModule({
29
+ providers: [DataClient],
30
+ }).compileComponents();
31
+
32
+ service = TestBed.inject(DataClient);
33
+ });
34
+
35
+ afterEach(() => {
36
+ vi.clearAllMocks();
37
+ });
38
+
39
+ it('should create the service', () => {
40
+ expect(service).toBeTruthy();
41
+ expect(service).toBeInstanceOf(DataClient);
42
+ });
43
+
44
+ it('should route plain query operations to graphql.query and return result.data', async () => {
45
+ const operation = 'query { user { id name } }';
46
+ const expectedData = { user: { id: '123', name: 'Test User' } };
47
+ mockGraphqlQuery.mockResolvedValue({ data: expectedData });
48
+
49
+ const result = await service.execute(operation);
50
+
51
+ expect(mockGraphqlQuery).toHaveBeenCalledWith({ query: operation, variables: undefined });
52
+ expect(mockGraphqlMutate).not.toHaveBeenCalled();
53
+ expect(result).toEqual(expectedData);
54
+ });
55
+
56
+ it('should route anonymous query operations to graphql.query', async () => {
57
+ const operation = '{ user { id name } }';
58
+ const expectedData = { user: { id: '456', name: 'Anonymous User' } };
59
+ mockGraphqlQuery.mockResolvedValue({ data: expectedData });
60
+
61
+ const result = await service.execute(operation);
62
+
63
+ expect(mockGraphqlQuery).toHaveBeenCalledWith({ query: operation, variables: undefined });
64
+ expect(mockGraphqlMutate).not.toHaveBeenCalled();
65
+ expect(result).toEqual(expectedData);
66
+ });
67
+
68
+ it('should route mutation operations to graphql.mutate', async () => {
69
+ const operation = 'mutation { updateUser(id: "123", name: "New Name") { id name } }';
70
+ const expectedData = { updateUser: { id: '123', name: 'New Name' } };
71
+ mockGraphqlMutate.mockResolvedValue({ data: expectedData });
72
+
73
+ const result = await service.execute(operation);
74
+
75
+ expect(mockGraphqlMutate).toHaveBeenCalledWith({ mutation: operation, variables: undefined });
76
+ expect(mockGraphqlQuery).not.toHaveBeenCalled();
77
+ expect(result).toEqual(expectedData);
78
+ });
79
+
80
+ it('should detect mutation with leading GraphQL comment and route to graphql.mutate', async () => {
81
+ const operation = '# This is a comment\nmutation { deleteUser(id: "123") { success } }';
82
+ const expectedData = { deleteUser: { success: true } };
83
+ mockGraphqlMutate.mockResolvedValue({ data: expectedData });
84
+
85
+ const result = await service.execute(operation);
86
+
87
+ expect(mockGraphqlMutate).toHaveBeenCalledWith({ mutation: operation, variables: undefined });
88
+ expect(mockGraphqlQuery).not.toHaveBeenCalled();
89
+ expect(result).toEqual(expectedData);
90
+ });
91
+
92
+ it('should not treat query as mutation when comment contains "mutation" word', async () => {
93
+ const operation = '# this is not a mutation, just a query\nquery { user { id } }';
94
+ const expectedData = { user: { id: '789' } };
95
+ mockGraphqlQuery.mockResolvedValue({ data: expectedData });
96
+
97
+ const result = await service.execute(operation);
98
+
99
+ expect(mockGraphqlQuery).toHaveBeenCalledWith({ query: operation, variables: undefined });
100
+ expect(mockGraphqlMutate).not.toHaveBeenCalled();
101
+ expect(result).toEqual(expectedData);
102
+ });
103
+
104
+ it('should throw error when result.errors contains errors', async () => {
105
+ const operation = 'query { user { id } }';
106
+ mockGraphqlQuery.mockResolvedValue({
107
+ data: null,
108
+ errors: [{ message: 'Field not found' }, { message: 'Permission denied' }],
109
+ });
110
+
111
+ await expect(service.execute(operation)).rejects.toThrow(
112
+ 'GraphQL Error: Field not found; Permission denied',
113
+ );
114
+ });
115
+
116
+ it('should throw error when result.errors contains a single error', async () => {
117
+ const operation = 'query { user { id } }';
118
+ mockGraphqlQuery.mockResolvedValue({
119
+ data: null,
120
+ errors: [{ message: 'Unauthorized' }],
121
+ });
122
+
123
+ await expect(service.execute(operation)).rejects.toThrow('GraphQL Error: Unauthorized');
124
+ });
125
+
126
+ it('should throw error when result.data is null with no errors', async () => {
127
+ const operation = 'query { user { id } }';
128
+ mockGraphqlQuery.mockResolvedValue({ data: null });
129
+
130
+ await expect(service.execute(operation)).rejects.toThrow('GraphQL response data is null');
131
+ });
132
+
133
+ it('should pass variables through to graphql.query', async () => {
134
+ const operation = 'query GetUser($id: ID!) { user(id: $id) { id name } }';
135
+ const variables = { id: '999' };
136
+ const expectedData = { user: { id: '999', name: 'Variable User' } };
137
+ mockGraphqlQuery.mockResolvedValue({ data: expectedData });
138
+
139
+ const result = await service.execute(operation, variables);
140
+
141
+ expect(mockGraphqlQuery).toHaveBeenCalledWith({ query: operation, variables });
142
+ expect(result).toEqual(expectedData);
143
+ });
144
+
145
+ it('should pass variables through to graphql.mutate', async () => {
146
+ const operation =
147
+ 'mutation UpdateUser($id: ID!, $name: String!) { updateUser(id: $id, name: $name) { id name } }';
148
+ const variables = { id: '888', name: 'Updated Name' };
149
+ const expectedData = { updateUser: { id: '888', name: 'Updated Name' } };
150
+ mockGraphqlMutate.mockResolvedValue({ data: expectedData });
151
+
152
+ const result = await service.execute(operation, variables);
153
+
154
+ expect(mockGraphqlMutate).toHaveBeenCalledWith({ mutation: operation, variables });
155
+ expect(result).toEqual(expectedData);
156
+ });
157
+
158
+ it('should proxy fetch to sdk.fetch and return the raw Response', async () => {
159
+ const url = '/services/apexrest/auth/login';
160
+ const init: RequestInit = {
161
+ method: 'POST',
162
+ body: JSON.stringify({ email: 'a@b.com' }),
163
+ headers: { 'Content-Type': 'application/json' },
164
+ };
165
+ const expectedResponse = { ok: true, status: 200 } as Response;
166
+ mockFetch.mockResolvedValue(expectedResponse);
167
+
168
+ const response = await service.fetch(url, init);
169
+
170
+ expect(mockFetch).toHaveBeenCalledWith(url, init);
171
+ expect(response).toBe(expectedResponse);
172
+ });
173
+
174
+ it('should call fetch with no init when omitted', async () => {
175
+ const url = '/services/data/v64.0/chatter/users/me';
176
+ const expectedResponse = { ok: true, status: 200 } as Response;
177
+ mockFetch.mockResolvedValue(expectedResponse);
178
+
179
+ const response = await service.fetch(url);
180
+
181
+ expect(mockFetch).toHaveBeenCalledWith(url, undefined);
182
+ expect(response).toBe(expectedResponse);
183
+ });
184
+ });
@@ -0,0 +1,74 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { createDataSDK } from '@salesforce/platform-sdk';
3
+
4
+ /**
5
+ * True when the operation's first definition is a `mutation`. Strips GraphQL
6
+ * comments first so a leading `# ...` line can't mask the keyword. Queries
7
+ * (named or anonymous `{ ... }` shorthand) and subscriptions fall through to
8
+ * query().
9
+ */
10
+ function isMutation(operation: string): boolean {
11
+ return /^\s*mutation\b/.test(operation.replace(/#[^\n\r]*/g, ''));
12
+ }
13
+
14
+ /**
15
+ * The single data-access client for the app — a thin wrapper over
16
+ * `createDataSDK` that centralizes both of the SDK's surfaces:
17
+ *
18
+ * - `execute()` for GraphQL (routes mutations to `sdk.graphql.mutate` and
19
+ * everything else to `sdk.graphql.query`, with centralized error handling).
20
+ * Use with gql-tagged queries and generated operation types for type-safe
21
+ * calls.
22
+ * - `fetch()` for REST (proxies `sdk.fetch`, returning the raw `Response` so
23
+ * callers keep full control over response parsing / error shaping).
24
+ *
25
+ * Consumers inject this instead of calling `createDataSDK` directly, so the SDK
26
+ * bootstrap lives in exactly one place. Feature packages consume it via an
27
+ * `__inherit__data-client.service` stub (base wins at compose).
28
+ */
29
+ @Injectable({ providedIn: 'root' })
30
+ export class DataClient {
31
+ /**
32
+ * Executes a GraphQL operation and returns its `data`, throwing on GraphQL
33
+ * errors or a null payload.
34
+ */
35
+ async execute<TData, TVariables = Record<string, unknown>>(
36
+ operation: string,
37
+ variables?: TVariables,
38
+ ): Promise<TData> {
39
+ const data = await createDataSDK();
40
+ const result = isMutation(operation)
41
+ ? await data.graphql!.mutate<TData, TVariables>({
42
+ mutation: operation,
43
+ variables,
44
+ })
45
+ : await data.graphql!.query<TData, TVariables>({
46
+ query: operation,
47
+ variables,
48
+ });
49
+
50
+ if (result.errors?.length) {
51
+ const msg = result.errors.map((e) => e.message).join('; ');
52
+ throw new Error(`GraphQL Error: ${msg}`);
53
+ }
54
+
55
+ if (result.data == null) {
56
+ throw new Error('GraphQL response data is null');
57
+ }
58
+
59
+ return result.data;
60
+ }
61
+
62
+ /**
63
+ * Performs a REST request through the SDK's authenticated `fetch`, returning
64
+ * the raw `Response`. Callers parse the body / shape errors themselves (e.g.
65
+ * via `handleApiResponse`).
66
+ *
67
+ * @param input - The request URL (e.g. an Apex REST route).
68
+ * @param init - Standard `fetch` options (method, headers, body, …).
69
+ */
70
+ async fetch(input: string, init?: RequestInit): Promise<Response> {
71
+ const sdk = await createDataSDK();
72
+ return sdk.fetch!(input, init);
73
+ }
74
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ import { Injectable, inject } from "@angular/core";
7
+ // DataClient is provided by the base-angular-app. Consumed via the
8
+ // `__inherit__` stub in this same folder (app/api/); post-compose patches-cli
9
+ // strips the prefix so it resolves to the seeded base file at
10
+ // app/api/data-client.service.ts.
11
+ import { DataClient } from "./data-client.service";
12
+ import { flattenGraphQLRecord } from "../features/authentication/utils/helpers";
13
+
14
+ // ---------------------------------------------------------------------------
15
+ // Hand-written GraphQL query/mutation strings + wire types. Codegen is PARKED
16
+ // for the Angular port (same decision as object-search). The field selection,
17
+ // query/mutation shape, and variable structure mirror the React
18
+ // `userProfileApi.ts` byte-for-byte so behavior is identical.
19
+ // ---------------------------------------------------------------------------
20
+
21
+ const USER_PROFILE_FIELDS_FULL = `
22
+ Id
23
+ FirstName @optional { value }
24
+ LastName @optional { value }
25
+ Email @optional { value }
26
+ Phone @optional { value }
27
+ Street @optional { value }
28
+ City @optional { value }
29
+ State @optional { value }
30
+ PostalCode @optional { value }
31
+ Country @optional { value }`;
32
+
33
+ const USER_CONTACT_FIELDS = `
34
+ Id
35
+ ContactId @optional { value }`;
36
+
37
+ function getUserProfileQuery(fields: string): string {
38
+ return `
39
+ query GetUserProfile($userId: ID) {
40
+ uiapi {
41
+ query {
42
+ User(where: { Id: { eq: $userId } }) {
43
+ edges {
44
+ node {${fields}}
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }`;
50
+ }
51
+
52
+ function getUserProfileMutation(fields: string): string {
53
+ return `
54
+ mutation UpdateUserProfile($input: UserUpdateInput!) {
55
+ uiapi {
56
+ UserUpdate(input: $input) {
57
+ Record {${fields}}
58
+ }
59
+ }
60
+ }`;
61
+ }
62
+
63
+ /** Wire shape for the GetUserProfile query. */
64
+ interface GetUserProfileData {
65
+ uiapi: {
66
+ query: {
67
+ User: { edges: Array<{ node: Record<string, unknown> } | null> | null } | null;
68
+ };
69
+ };
70
+ }
71
+
72
+ /** Wire shape for the UpdateUserProfile mutation. */
73
+ interface UpdateUserProfileData {
74
+ uiapi: {
75
+ UserUpdate: { Record: Record<string, unknown> | null } | null;
76
+ };
77
+ }
78
+
79
+ /**
80
+ * Extensible user-profile fetching and updating via UI API GraphQL — the
81
+ * Angular port of the React `userProfileApi.ts` module.
82
+ *
83
+ * Uses the base app's `DataClient` (which centralizes GraphQL error handling
84
+ * and routes mutations vs queries), matching the object-search feature's
85
+ * data-access idiom. Responses are flattened via `flattenGraphQLRecord` for
86
+ * straightforward form binding.
87
+ */
88
+ @Injectable({ providedIn: "root" })
89
+ export class UserProfileService {
90
+ private readonly client = inject(DataClient);
91
+
92
+ /**
93
+ * Fetches the user profile via GraphQL and returns a flattened record.
94
+ * @param userId - The Salesforce User Id.
95
+ * @param fields - GraphQL field selection (defaults to the full profile).
96
+ */
97
+ async fetchUserProfile<T>(userId: string, fields: string = USER_PROFILE_FIELDS_FULL): Promise<T> {
98
+ const data = await this.client.execute<GetUserProfileData, { userId: string }>(
99
+ getUserProfileQuery(fields),
100
+ { userId },
101
+ );
102
+ return flattenGraphQLRecord<T>(data.uiapi?.query?.User?.edges?.[0]?.node);
103
+ }
104
+
105
+ /**
106
+ * Fetches the user's associated contact record ID via GraphQL and returns a
107
+ * flattened record.
108
+ * @param userId - The Salesforce User Id.
109
+ */
110
+ async fetchUserContact<T>(userId: string): Promise<T> {
111
+ return this.fetchUserProfile<T>(userId, USER_CONTACT_FIELDS);
112
+ }
113
+
114
+ /**
115
+ * Updates the user profile via GraphQL and returns the flattened updated record.
116
+ * @param userId - The Salesforce User Id.
117
+ * @param values - The field values to update.
118
+ */
119
+ async updateUserProfile<T>(userId: string, values: Record<string, unknown>): Promise<T> {
120
+ const data = await this.client.execute<UpdateUserProfileData, { input: unknown }>(
121
+ getUserProfileMutation(USER_PROFILE_FIELDS_FULL),
122
+ { input: { Id: userId, User: { ...values } } },
123
+ );
124
+ return flattenGraphQLRecord<T>(data.uiapi?.UserUpdate?.Record);
125
+ }
126
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
7
+ import { provideRouter } from '@angular/router';
8
+ import { provideNativeDateAdapter as provideBrnNativeDateAdapter } from '@spartan-ng/brain/date-time';
9
+ import { provideNgIconsConfig } from '@ng-icons/core';
10
+
11
+ import { routes } from './app.routes';
12
+
13
+ export const appConfig: ApplicationConfig = {
14
+ providers: [
15
+ provideBrowserGlobalErrorListeners(),
16
+ provideRouter(routes),
17
+ provideBrnNativeDateAdapter(),
18
+ provideNgIconsConfig({ size: '1rem' }),
19
+ ],
20
+ };
@@ -0,0 +1,66 @@
1
+ import { Routes } from '@angular/router';
2
+ import { HomeComponent } from './pages/home/home';
3
+ import { NotFoundComponent } from './pages/not-found/not-found';
4
+ import { AuthAppLayoutComponent } from "./features/authentication/auth-layout/auth-layout";
5
+ import { authGuard } from "./features/authentication/auth/auth.guard";
6
+ import { LoginPageComponent } from "./pages/login/login-page";
7
+ import { RegisterPageComponent } from "./pages/register/register-page";
8
+ import { ForgotPasswordPageComponent } from "./pages/forgot-password/forgot-password-page";
9
+ import { ResetPasswordPageComponent } from "./pages/reset-password/reset-password-page";
10
+ import { ProfilePageComponent } from "./pages/profile/profile-page";
11
+ import { ChangePasswordPageComponent } from "./pages/change-password/change-password-page";
12
+
13
+ export const routes: Routes = [
14
+ {
15
+ path: "",
16
+ component: AuthAppLayoutComponent,
17
+ children: [
18
+ {
19
+ path: '',
20
+ component: HomeComponent
21
+ },
22
+ {
23
+ path: "login",
24
+ component: LoginPageComponent,
25
+ title: "Login | MyApp",
26
+ data: { showInNavigation: false, label: "Login" }
27
+ },
28
+ {
29
+ path: "register",
30
+ component: RegisterPageComponent,
31
+ title: "Create Account | MyApp",
32
+ data: { showInNavigation: false }
33
+ },
34
+ {
35
+ path: "forgot-password",
36
+ component: ForgotPasswordPageComponent,
37
+ title: "Recover Password | MyApp",
38
+ data: { showInNavigation: false }
39
+ },
40
+ {
41
+ path: "reset-password",
42
+ component: ResetPasswordPageComponent,
43
+ title: "Reset Password | MyApp",
44
+ data: { showInNavigation: false }
45
+ },
46
+ {
47
+ path: "profile",
48
+ component: ProfilePageComponent,
49
+ canActivate: [authGuard],
50
+ title: "My Profile | MyApp",
51
+ data: { showInNavigation: false, label: "Profile" }
52
+ },
53
+ {
54
+ path: "change-password",
55
+ component: ChangePasswordPageComponent,
56
+ canActivate: [authGuard],
57
+ title: "Change Password | MyApp",
58
+ data: { showInNavigation: false }
59
+ },
60
+ {
61
+ path: '**',
62
+ component: NotFoundComponent
63
+ }
64
+ ]
65
+ }
66
+ ];
@@ -0,0 +1,18 @@
1
+ import { TestBed } from '@angular/core/testing';
2
+ import { provideRouter } from '@angular/router';
3
+ import { App } from './app';
4
+
5
+ describe('App', () => {
6
+ beforeEach(async () => {
7
+ await TestBed.configureTestingModule({
8
+ imports: [App],
9
+ providers: [provideRouter([])],
10
+ }).compileComponents();
11
+ });
12
+
13
+ it('should create the app', () => {
14
+ const fixture = TestBed.createComponent(App);
15
+ const app = fixture.componentInstance;
16
+ expect(app).toBeTruthy();
17
+ });
18
+ });
@@ -0,0 +1,15 @@
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 } from '@angular/core';
7
+ import { RouterOutlet } from '@angular/router';
8
+
9
+ @Component({
10
+ selector: 'app-root',
11
+ changeDetection: ChangeDetectionStrategy.OnPush,
12
+ imports: [RouterOutlet],
13
+ templateUrl: './app.html',
14
+ })
15
+ export class App {}
@@ -0,0 +1,51 @@
1
+ <nav class="bg-white border-b border-gray-200">
2
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
3
+ <div class="flex justify-between items-center h-16">
4
+ <a routerLink="/" class="text-xl font-semibold text-gray-900"> Angular App </a>
5
+ <button
6
+ (click)="toggleMenu()"
7
+ class="p-2 rounded-md text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
8
+ aria-label="Toggle menu"
9
+ aria-controls="app-layout-nav-menu"
10
+ [attr.aria-expanded]="isOpen()"
11
+ >
12
+ <div class="w-6 h-6 flex flex-col justify-center space-y-1.5">
13
+ <span
14
+ class="block h-0.5 w-6 bg-current transition-all"
15
+ [class.rotate-45]="isOpen()"
16
+ [class.translate-y-2]="isOpen()"
17
+ ></span>
18
+ <span
19
+ class="block h-0.5 w-6 bg-current transition-all"
20
+ [class.opacity-0]="isOpen()"
21
+ ></span>
22
+ <span
23
+ class="block h-0.5 w-6 bg-current transition-all"
24
+ [class.-rotate-45]="isOpen()"
25
+ [class.-translate-y-2]="isOpen()"
26
+ ></span>
27
+ </div>
28
+ </button>
29
+ </div>
30
+ @if (isOpen()) {
31
+ <div id="app-layout-nav-menu" class="pb-4">
32
+ <ul class="flex flex-col space-y-2 list-none">
33
+ @for (item of navigationItems; track item.path) {
34
+ <li>
35
+ <a
36
+ [routerLink]="item.path"
37
+ routerLinkActive="bg-blue-100 text-blue-700"
38
+ [routerLinkActiveOptions]="{ exact: true }"
39
+ (click)="closeMenu()"
40
+ class="block px-3 py-2 rounded-md text-sm font-medium transition-colors text-gray-700 hover:bg-gray-100"
41
+ >
42
+ {{ item.label }}
43
+ </a>
44
+ </li>
45
+ }
46
+ </ul>
47
+ </div>
48
+ }
49
+ </div>
50
+ </nav>
51
+ <router-outlet />