@salesforce/ui-bundle-template-app-angular-template-b2x 11.30.0

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 (211) hide show
  1. package/LICENSE.txt +82 -0
  2. package/dist/.forceignore +15 -0
  3. package/dist/.husky/pre-commit +4 -0
  4. package/dist/.prettierignore +11 -0
  5. package/dist/.prettierrc +17 -0
  6. package/dist/CHANGELOG.md +3966 -0
  7. package/dist/README.md +77 -0
  8. package/dist/config/project-scratch-def.json +13 -0
  9. package/dist/eslint.config.js +7 -0
  10. package/dist/force-app/main/default/classes/UIBundleAuthUtils.cls +68 -0
  11. package/dist/force-app/main/default/classes/UIBundleAuthUtils.cls-meta.xml +5 -0
  12. package/dist/force-app/main/default/classes/UIBundleChangePassword.cls +77 -0
  13. package/dist/force-app/main/default/classes/UIBundleChangePassword.cls-meta.xml +5 -0
  14. package/dist/force-app/main/default/classes/UIBundleForgotPassword.cls +71 -0
  15. package/dist/force-app/main/default/classes/UIBundleForgotPassword.cls-meta.xml +5 -0
  16. package/dist/force-app/main/default/classes/UIBundleLogin.cls +105 -0
  17. package/dist/force-app/main/default/classes/UIBundleLogin.cls-meta.xml +5 -0
  18. package/dist/force-app/main/default/classes/UIBundleRegistration.cls +162 -0
  19. package/dist/force-app/main/default/classes/UIBundleRegistration.cls-meta.xml +5 -0
  20. package/dist/force-app/main/default/digitalExperienceConfigs/angularexternalapp1.digitalExperienceConfig-meta.xml +8 -0
  21. package/dist/force-app/main/default/digitalExperiences/site/angularexternalapp1/angularexternalapp1.digitalExperience-meta.xml +11 -0
  22. package/dist/force-app/main/default/digitalExperiences/site/angularexternalapp1/sfdc_cms__site/angularexternalapp1/_meta.json +5 -0
  23. package/dist/force-app/main/default/digitalExperiences/site/angularexternalapp1/sfdc_cms__site/angularexternalapp1/content.json +10 -0
  24. package/dist/force-app/main/default/networks/angularexternalapp.network-meta.xml +60 -0
  25. package/dist/force-app/main/default/package.xml +24 -0
  26. package/dist/force-app/main/default/permissionsets/angularexternalapp_Guest_User_Api_Access.permissionset-meta.xml +9 -0
  27. package/dist/force-app/main/default/sites/angularexternalapp.site-meta.xml +31 -0
  28. package/dist/force-app/main/default/uiBundles/angularexternalapp/.forceignore +15 -0
  29. package/dist/force-app/main/default/uiBundles/angularexternalapp/.postcssrc.json +5 -0
  30. package/dist/force-app/main/default/uiBundles/angularexternalapp/.prettierignore +8 -0
  31. package/dist/force-app/main/default/uiBundles/angularexternalapp/.prettierrc +12 -0
  32. package/dist/force-app/main/default/uiBundles/angularexternalapp/CHANGELOG.md +4 -0
  33. package/dist/force-app/main/default/uiBundles/angularexternalapp/README.md +85 -0
  34. package/dist/force-app/main/default/uiBundles/angularexternalapp/angular.json +98 -0
  35. package/dist/force-app/main/default/uiBundles/angularexternalapp/angularexternalapp.uibundle-meta.xml +8 -0
  36. package/dist/force-app/main/default/uiBundles/angularexternalapp/e2e/app.spec.ts +15 -0
  37. package/dist/force-app/main/default/uiBundles/angularexternalapp/esbuild/api-version.mjs +17 -0
  38. package/dist/force-app/main/default/uiBundles/angularexternalapp/eslint.config.js +60 -0
  39. package/dist/force-app/main/default/uiBundles/angularexternalapp/middleware/html.mjs +3 -0
  40. package/dist/force-app/main/default/uiBundles/angularexternalapp/middleware/proxy.mjs +12 -0
  41. package/dist/force-app/main/default/uiBundles/angularexternalapp/package.json +56 -0
  42. package/dist/force-app/main/default/uiBundles/angularexternalapp/playwright.config.ts +25 -0
  43. package/dist/force-app/main/default/uiBundles/angularexternalapp/public/favicon.ico +0 -0
  44. package/dist/force-app/main/default/uiBundles/angularexternalapp/scripts/rewrite-e2e-assets.mjs +30 -0
  45. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/account/account-search.service.ts +196 -0
  46. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/account/distinctAccountIndustries.ts +26 -0
  47. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/account/distinctAccountTypes.ts +26 -0
  48. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/account/getAccountDetail.ts +128 -0
  49. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/account/searchAccounts.ts +58 -0
  50. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/data-client.service.spec.ts +184 -0
  51. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/data-client.service.ts +74 -0
  52. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/user-profile.service.ts +126 -0
  53. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/app.config.ts +22 -0
  54. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/app.html +1 -0
  55. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/app.routes.ts +77 -0
  56. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/app.spec.ts +18 -0
  57. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/app.ts +15 -0
  58. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/layout/app-layout/app-layout.component.html +53 -0
  59. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/layout/app-layout/app-layout.component.spec.ts +89 -0
  60. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/layout/app-layout/app-layout.component.ts +81 -0
  61. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/_field-size.scss +42 -0
  62. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/alert/alert.component.html +31 -0
  63. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/alert/alert.component.ts +53 -0
  64. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/button/button.component.html +18 -0
  65. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/button/button.component.scss +112 -0
  66. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/button/button.component.ts +57 -0
  67. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/card/card.component.scss +34 -0
  68. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/card/card.component.ts +110 -0
  69. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/collapsible/collapsible.component.html +10 -0
  70. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/collapsible/collapsible.component.ts +26 -0
  71. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/date-picker/date-picker.component.html +25 -0
  72. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/date-picker/date-picker.component.scss +36 -0
  73. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/date-picker/date-picker.component.ts +41 -0
  74. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/date-range-picker/date-range-picker.component.html +34 -0
  75. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/date-range-picker/date-range-picker.component.scss +33 -0
  76. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/date-range-picker/date-range-picker.component.ts +66 -0
  77. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/dialog/dialog.component.html +37 -0
  78. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/dialog/dialog.component.ts +55 -0
  79. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/field/field.component.html +21 -0
  80. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/field/field.component.ts +36 -0
  81. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/field-size.ts +8 -0
  82. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/input/input.component.html +19 -0
  83. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/input/input.component.scss +35 -0
  84. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/input/input.component.ts +36 -0
  85. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/label/label.component.html +3 -0
  86. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/label/label.component.ts +17 -0
  87. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/paginator/paginator.component.html +10 -0
  88. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/paginator/paginator.component.ts +37 -0
  89. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/popover/popover.component.html +41 -0
  90. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/popover/popover.component.ts +40 -0
  91. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/select/select.component.html +24 -0
  92. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/select/select.component.scss +35 -0
  93. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/select/select.component.ts +72 -0
  94. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/separator/separator.component.html +1 -0
  95. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/separator/separator.component.scss +23 -0
  96. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/separator/separator.component.ts +56 -0
  97. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/skeleton/skeleton.component.html +1 -0
  98. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/skeleton/skeleton.component.scss +28 -0
  99. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/skeleton/skeleton.component.ts +24 -0
  100. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/spinner/spinner.component.ts +35 -0
  101. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/auth/auth.guard.ts +50 -0
  102. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/auth/auth.service.ts +126 -0
  103. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/components/status-alert/status-alert.component.html +7 -0
  104. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/components/status-alert/status-alert.component.ts +52 -0
  105. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/config/authentication.config.ts +75 -0
  106. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/auth-form/auth-form.component.html +38 -0
  107. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/auth-form/auth-form.component.ts +94 -0
  108. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/footer-link/footer-link.component.html +11 -0
  109. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/footer-link/footer-link.component.ts +26 -0
  110. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/reactive-form-page.base.ts +50 -0
  111. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/submit-button/submit-button.component.html +8 -0
  112. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/submit-button/submit-button.component.scss +17 -0
  113. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/submit-button/submit-button.component.ts +35 -0
  114. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/layouts/auth-app-layout/auth-app-layout.component.html +2 -0
  115. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/layouts/auth-app-layout/auth-app-layout.component.ts +30 -0
  116. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/layouts/card-layout/card-layout.component.html +17 -0
  117. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/layouts/card-layout/card-layout.component.ts +40 -0
  118. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/menu/auth-menu/auth-menu.component.html +26 -0
  119. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/menu/auth-menu/auth-menu.component.ts +46 -0
  120. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/session-timeout/session-time-servlet.ts +130 -0
  121. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/session-timeout/session-timeout-validator/session-timeout-validator.component.html +57 -0
  122. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/session-timeout/session-timeout-validator/session-timeout-validator.component.ts +205 -0
  123. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/session-timeout/session-timeout.config.ts +83 -0
  124. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/session-timeout/session-timeout.service.ts +201 -0
  125. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/utils/auth-helpers.ts +68 -0
  126. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/utils/auth-validators.ts +72 -0
  127. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/utils/helpers.ts +85 -0
  128. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/active-filters/active-filters.component.html +23 -0
  129. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/active-filters/active-filters.component.ts +78 -0
  130. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/date-filter/date-filter.component.html +18 -0
  131. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/date-filter/date-filter.component.ts +137 -0
  132. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/date-range-filter/date-range-filter.component.html +11 -0
  133. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/date-range-filter/date-range-filter.component.ts +69 -0
  134. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/filter-field-wrapper/filter-field-wrapper.component.html +11 -0
  135. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/filter-field-wrapper/filter-field-wrapper.component.ts +36 -0
  136. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/multi-select-filter/multi-select-filter.component.html +10 -0
  137. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/multi-select-filter/multi-select-filter.component.ts +58 -0
  138. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/numeric-range-filter/numeric-range-filter.component.html +22 -0
  139. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/numeric-range-filter/numeric-range-filter.component.ts +146 -0
  140. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/search-filter/search-filter.component.html +8 -0
  141. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/search-filter/search-filter.component.ts +82 -0
  142. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/select-filter/select-filter.component.html +12 -0
  143. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/select-filter/select-filter.component.ts +65 -0
  144. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/text-filter/text-filter.component.html +12 -0
  145. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/text-filter/text-filter.component.ts +90 -0
  146. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/object-breadcrumb/object-breadcrumb.component.html +55 -0
  147. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/object-breadcrumb/object-breadcrumb.component.ts +40 -0
  148. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/pagination-controls/pagination-controls.component.html +8 -0
  149. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/pagination-controls/pagination-controls.component.ts +61 -0
  150. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/search-bar/search-bar.component.html +59 -0
  151. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/search-bar/search-bar.component.ts +108 -0
  152. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/sort-control/sort-control.component.html +50 -0
  153. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/sort-control/sort-control.component.ts +72 -0
  154. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/object-search-state.service.ts +232 -0
  155. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/utils/debounce.ts +31 -0
  156. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/utils/field-utils.ts +54 -0
  157. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/utils/filter-utils.ts +354 -0
  158. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/utils/index.ts +12 -0
  159. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/utils/sort-utils.ts +46 -0
  160. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/account-detail/account-detail-page.component.html +174 -0
  161. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/account-detail/account-detail-page.component.scss +7 -0
  162. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/account-detail/account-detail-page.component.ts +199 -0
  163. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/account-search/account-search-page.component.html +111 -0
  164. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/account-search/account-search-page.component.ts +217 -0
  165. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/change-password/change-password-page.component.html +68 -0
  166. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/change-password/change-password-page.component.ts +82 -0
  167. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/forgot-password/forgot-password-page.component.html +35 -0
  168. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/forgot-password/forgot-password-page.component.ts +87 -0
  169. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/home/home-page.component.html +18 -0
  170. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/home/home-page.component.ts +47 -0
  171. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/home/home.component.html +6 -0
  172. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/home/home.component.spec.ts +23 -0
  173. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/home/home.component.ts +13 -0
  174. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/login/login-page.component.html +47 -0
  175. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/login/login-page.component.ts +89 -0
  176. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/not-found/not-found.component.html +12 -0
  177. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/not-found/not-found.component.spec.ts +33 -0
  178. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/not-found/not-found.component.ts +15 -0
  179. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/profile/profile-page.component.html +126 -0
  180. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/profile/profile-page.component.ts +194 -0
  181. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/register/register-page.component.html +80 -0
  182. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/register/register-page.component.ts +93 -0
  183. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/reset-password/reset-password-page.component.html +60 -0
  184. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/reset-password/reset-password-page.component.ts +96 -0
  185. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/utils/async-data.ts +99 -0
  186. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/index.html +14 -0
  187. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/main.ts +5 -0
  188. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/styles.scss +170 -0
  189. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/theme.scss +39 -0
  190. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/types/sf-globals.d.ts +9 -0
  191. package/dist/force-app/main/default/uiBundles/angularexternalapp/tsconfig.app.json +11 -0
  192. package/dist/force-app/main/default/uiBundles/angularexternalapp/tsconfig.json +33 -0
  193. package/dist/force-app/main/default/uiBundles/angularexternalapp/tsconfig.spec.json +10 -0
  194. package/dist/force-app/main/default/uiBundles/angularexternalapp/ui-bundle.json +7 -0
  195. package/dist/jest.config.js +6 -0
  196. package/dist/package-lock.json +10066 -0
  197. package/dist/package.json +46 -0
  198. package/dist/scripts/apex/hello.apex +10 -0
  199. package/dist/scripts/gitignore-templates.json +4 -0
  200. package/dist/scripts/graphql-search.sh +191 -0
  201. package/dist/scripts/org-setup-config-schema.mjs +103 -0
  202. package/dist/scripts/org-setup-dev.mjs +87 -0
  203. package/dist/scripts/org-setup-utils.mjs +369 -0
  204. package/dist/scripts/org-setup-xml.mjs +182 -0
  205. package/dist/scripts/org-setup.config.json +9 -0
  206. package/dist/scripts/org-setup.mjs +1702 -0
  207. package/dist/scripts/sf-project-setup.mjs +103 -0
  208. package/dist/scripts/soql/account.soql +6 -0
  209. package/dist/scripts/validate-org-setup-config.mjs +38 -0
  210. package/dist/sfdx-project.json +12 -0
  211. package/package.json +40 -0
@@ -0,0 +1,11 @@
1
+ <app-filter-field-wrapper [label]="config().label" [helpText]="config().helpText">
2
+ <app-date-range-picker
3
+ class="w-full"
4
+ startPlaceholder="Start"
5
+ endPlaceholder="End"
6
+ [readonly]="true"
7
+ [max]="maxDate()"
8
+ [value]="range()"
9
+ (valueChange)="onRangeChange($event)"
10
+ />
11
+ </app-filter-field-wrapper>
@@ -0,0 +1,69 @@
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, inject, input } from "@angular/core";
7
+ // Base-app UI wrapper, inherited (not recreated) by this feature. Post-compose
8
+ // it lands at uiBundles/<target>/src/app/components/ui/date-range-picker/..., three levels up.
9
+ import {
10
+ DateRange,
11
+ DateRangePickerComponent,
12
+ } from "../../../../../components/ui/date-range-picker/date-range-picker.component";
13
+ import { ObjectSearchStateService } from "../../../object-search-state.service";
14
+ import type { FilterFieldConfig, FilterFieldType } from "../../../utils/filter-utils";
15
+ import { toDate, toDateString } from "../date-filter/date-filter.component";
16
+ import { FilterFieldWrapperComponent } from "../filter-field-wrapper/filter-field-wrapper.component";
17
+
18
+ /**
19
+ * Date range filter — a single two-ended range picker. Emits a `daterange`
20
+ * (or `datetimerange`) filter with `min` / `max` as `YYYY-MM-DD` strings; the
21
+ * filter builder wires each end into a `gte` / `lte` clause.
22
+ *
23
+ * Thin bridge over the base `app-date-range-picker` (Material's
24
+ * `mat-date-range-picker`): it maps the picker's `DateRange<Date>` value to and
25
+ * from the `min` / `max` string split the filter state stores.
26
+ */
27
+ @Component({
28
+ selector: "app-date-range-filter",
29
+ changeDetection: ChangeDetectionStrategy.OnPush,
30
+ imports: [DateRangePickerComponent, FilterFieldWrapperComponent],
31
+ templateUrl: "./date-range-filter.component.html",
32
+ })
33
+ export class DateRangeFilterComponent {
34
+ private readonly state = inject(ObjectSearchStateService);
35
+
36
+ /** Field config: `field`, `label`, `helpText`, ... */
37
+ readonly config = input.required<FilterFieldConfig>();
38
+ /** Underlying filter type — `'daterange'` (default) or `'datetimerange'`. */
39
+ readonly filterType = input<FilterFieldType>("daterange");
40
+
41
+ private readonly active = computed(() => this.state.filterFor(this.config().field));
42
+
43
+ /** The active filter's `min` / `max` strings surfaced as a picker range. */
44
+ protected readonly range = computed<DateRange<Date>>(
45
+ () => new DateRange(toDate(this.active()?.min), toDate(this.active()?.max)),
46
+ );
47
+
48
+ /** Cap the picker at today when the field can't hold a future date. */
49
+ protected readonly maxDate = computed<Date | null>(() =>
50
+ this.config().disableFuture ? new Date() : null,
51
+ );
52
+
53
+ protected onRangeChange(range: DateRange<Date> | null): void {
54
+ const cfg = this.config();
55
+ const from = range?.start ?? null;
56
+ const to = range?.end ?? null;
57
+ if (!from && !to) {
58
+ this.state.removeFilter(cfg.field);
59
+ return;
60
+ }
61
+ this.state.setFilter(cfg.field, {
62
+ field: cfg.field,
63
+ label: cfg.label,
64
+ type: this.filterType(),
65
+ min: toDateString(from),
66
+ max: toDateString(to),
67
+ });
68
+ }
69
+ }
@@ -0,0 +1,11 @@
1
+ <div class="space-y-1">
2
+ <app-label [for]="htmlFor()">{{ label() }}</app-label>
3
+ <ng-content />
4
+ <div class="min-h-4">
5
+ @if (error(); as err) {
6
+ <p class="text-xs text-red-600" role="alert">{{ err }}</p>
7
+ } @else if (helpText(); as help) {
8
+ <p class="text-xs text-gray-500">{{ help }}</p>
9
+ }
10
+ </div>
11
+ </div>
@@ -0,0 +1,36 @@
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
+ // Base-app UI wrapper, inherited (not recreated) by this feature. Post-compose
8
+ // it lands at uiBundles/<target>/src/app/components/ui/label/..., three levels up from this
9
+ // filter folder (app/object-search/components/filters/ -> app/components/ui/).
10
+ import { LabelComponent } from "../../../../../components/ui/label/label.component";
11
+
12
+ /**
13
+ * Standard label + control + help/error scaffold shared by every filter
14
+ * component (the Angular analogue of the React `FilterFieldWrapper`).
15
+ *
16
+ * The control itself is content-projected so each filter can supply the
17
+ * primitive that fits its data type (input, select, popover, date picker, ...)
18
+ * while the wrapper keeps the layout, label, and error/help affordances
19
+ * consistent across the search page.
20
+ */
21
+ @Component({
22
+ selector: "app-filter-field-wrapper",
23
+ changeDetection: ChangeDetectionStrategy.OnPush,
24
+ imports: [LabelComponent],
25
+ templateUrl: "./filter-field-wrapper.component.html",
26
+ })
27
+ export class FilterFieldWrapperComponent {
28
+ /** Visible field label rendered above the control. */
29
+ readonly label = input.required<string>();
30
+ /** Optional `for` attribute forwarded to the underlying `<label>`. */
31
+ readonly htmlFor = input<string | null>(null);
32
+ /** Advisory copy rendered below the control when there is no error. */
33
+ readonly helpText = input<string | undefined>(undefined);
34
+ /** Validation message; when set, replaces the help text. */
35
+ readonly error = input<string | undefined>(undefined);
36
+ }
@@ -0,0 +1,10 @@
1
+ <app-filter-field-wrapper [label]="config().label" [helpText]="config().helpText">
2
+ <app-select
3
+ multiple
4
+ [size]="size()"
5
+ [options]="config().options ?? []"
6
+ [placeholder]="placeholder()"
7
+ [values]="selected()"
8
+ (valuesChange)="onSelectionChange($event)"
9
+ />
10
+ </app-filter-field-wrapper>
@@ -0,0 +1,58 @@
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, inject, input } from "@angular/core";
7
+ import type { AppFieldSize } from "../../../../../components/ui/field-size";
8
+ import { SelectComponent } from "../../../../../components/ui/select/select.component";
9
+ import { ObjectSearchStateService } from "../../../object-search-state.service";
10
+ import type { FilterFieldConfig } from "../../../utils/filter-utils";
11
+ import { FilterFieldWrapperComponent } from "../filter-field-wrapper/filter-field-wrapper.component";
12
+
13
+ /**
14
+ * Multi-select picklist filter. All presentation (checkbox options, trigger
15
+ * summary, height) lives in `app-select multiple`; this component only bridges
16
+ * the UI's `string[]` selection to the object-search state, serializing it into
17
+ * the comma-joined string the `type: 'multipicklist'` contract expects
18
+ * (`buildSingleFilter` maps that to `{ eq }` for one value, `{ in: [...] }` for
19
+ * many).
20
+ */
21
+ @Component({
22
+ selector: "app-multi-select-filter",
23
+ changeDetection: ChangeDetectionStrategy.OnPush,
24
+ imports: [SelectComponent, FilterFieldWrapperComponent],
25
+ templateUrl: "./multi-select-filter.component.html",
26
+ })
27
+ export class MultiSelectFilterComponent {
28
+ private readonly state = inject(ObjectSearchStateService);
29
+
30
+ /** Field config: `field`, `label`, `options`, `helpText`, ... */
31
+ readonly config = input.required<FilterFieldConfig>();
32
+
33
+ /** Field height: `sm` = 24px, `default` = 32px, `lg` = 40px. */
34
+ readonly size = input<AppFieldSize>("default");
35
+
36
+ /** Currently selected option values (parsed back from the comma-joined string). */
37
+ protected readonly selected = computed<string[]>(() => {
38
+ const raw = this.state.filterFor(this.config().field)?.value;
39
+ return raw ? raw.split(",") : [];
40
+ });
41
+
42
+ /** Placeholder shown on the trigger when nothing is selected. */
43
+ protected readonly placeholder = computed(() => `Select ${this.config().label.toLowerCase()}`);
44
+
45
+ protected onSelectionChange(next: readonly string[]): void {
46
+ const cfg = this.config();
47
+ if (next.length === 0) {
48
+ this.state.removeFilter(cfg.field);
49
+ } else {
50
+ this.state.setFilter(cfg.field, {
51
+ field: cfg.field,
52
+ label: cfg.label,
53
+ type: "multipicklist",
54
+ value: next.join(","),
55
+ });
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,22 @@
1
+ <app-filter-field-wrapper
2
+ [label]="config().label"
3
+ [helpText]="config().helpText"
4
+ [error]="errorMessage()"
5
+ >
6
+ <div class="flex gap-2">
7
+ <app-input
8
+ class="flex-1"
9
+ type="number"
10
+ placeholder="Min"
11
+ [value]="localMin()"
12
+ (valueChange)="onMinChange($event)"
13
+ />
14
+ <app-input
15
+ class="flex-1"
16
+ type="number"
17
+ placeholder="Max"
18
+ [value]="localMax()"
19
+ (valueChange)="onMaxChange($event)"
20
+ />
21
+ </div>
22
+ </app-filter-field-wrapper>
@@ -0,0 +1,146 @@
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
+ computed,
11
+ effect,
12
+ inject,
13
+ input,
14
+ signal,
15
+ } from "@angular/core";
16
+ import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
17
+ import { Subject } from "rxjs";
18
+ import { debounceTime } from "rxjs/operators";
19
+ import { MatInputModule } from "@angular/material/input";
20
+ import { MatFormFieldModule } from "@angular/material/form-field";
21
+ import { FormsModule } from "@angular/forms";
22
+ // Base-app UI wrapper, inherited (not recreated) by this feature. Post-compose
23
+ // it lands at uiBundles/<target>/src/app/components/ui/input/..., three levels up.
24
+ import { InputComponent } from "../../../../../components/ui/input/input.component";
25
+ import { ObjectSearchStateService } from "../../../object-search-state.service";
26
+ import { FILTER_DEBOUNCE_MS } from "../../../utils/debounce";
27
+ import type { FilterFieldConfig } from "../../../utils/filter-utils";
28
+ import { FilterFieldWrapperComponent } from "../filter-field-wrapper/filter-field-wrapper.component";
29
+
30
+ /**
31
+ * Numeric range filter — paired `min` / `max` inputs whose committed values are
32
+ * written as strings on a `type: 'numeric'` filter (numeric coercion happens
33
+ * in `buildSingleFilter`).
34
+ *
35
+ * Local signals drive the inputs immediately; a trailing debounce commits the
36
+ * pair, but only when the range is self-consistent (`min <= max`) and within
37
+ * `boundMin` / `boundMax` if provided — an inverted or out-of-bounds pair
38
+ * shows the same inline error the React reference renders and skips the write.
39
+ */
40
+ @Component({
41
+ selector: "app-numeric-range-filter",
42
+ changeDetection: ChangeDetectionStrategy.OnPush,
43
+ imports: [
44
+ InputComponent,
45
+ FilterFieldWrapperComponent,
46
+ FormsModule,
47
+ MatFormFieldModule,
48
+ MatInputModule,
49
+ ],
50
+ templateUrl: "./numeric-range-filter.component.html",
51
+ })
52
+ export class NumericRangeFilterComponent {
53
+ private readonly state = inject(ObjectSearchStateService);
54
+ private readonly destroyRef = inject(DestroyRef);
55
+
56
+ /** Field config: `field`, `label`, `helpText`, ... */
57
+ readonly config = input.required<FilterFieldConfig>();
58
+ /** Optional lower bound accepted by the field (used for validation only). */
59
+ readonly boundMin = input<number | undefined>(undefined);
60
+ /** Optional upper bound accepted by the field (used for validation only). */
61
+ readonly boundMax = input<number | undefined>(undefined);
62
+
63
+ protected readonly localMin = signal<string>("");
64
+ protected readonly localMax = signal<string>("");
65
+
66
+ private readonly commit$ = new Subject<{ min: string; max: string }>();
67
+
68
+ constructor() {
69
+ this.commit$
70
+ .pipe(debounceTime(FILTER_DEBOUNCE_MS), takeUntilDestroyed(this.destroyRef))
71
+ .subscribe(({ min, max }) => this.commit(min, max));
72
+
73
+ // Sync local inputs from shared state (URL restore / reset-all).
74
+ effect(() => {
75
+ const cfg = this.config();
76
+ const active = this.state.filterFor(cfg.field);
77
+ this.localMin.set(active?.min ?? "");
78
+ this.localMax.set(active?.max ?? "");
79
+ });
80
+ }
81
+
82
+ protected readonly minOutOfBounds = computed(() => this.isOutOfBounds(this.localMin()));
83
+ protected readonly maxOutOfBounds = computed(() => this.isOutOfBounds(this.localMax()));
84
+ protected readonly isRangeInverted = computed(() => {
85
+ const lo = this.localMin();
86
+ const hi = this.localMax();
87
+ return lo !== "" && hi !== "" && Number(lo) > Number(hi);
88
+ });
89
+ protected readonly hasError = computed(
90
+ () => this.minOutOfBounds() || this.maxOutOfBounds() || this.isRangeInverted(),
91
+ );
92
+
93
+ protected readonly errorMessage = computed<string | undefined>(() => {
94
+ if (this.isRangeInverted()) return "Min must not exceed max";
95
+ if (!this.minOutOfBounds() && !this.maxOutOfBounds()) return undefined;
96
+ const lo = this.boundMin();
97
+ const hi = this.boundMax();
98
+ if (lo != null && hi != null) return `Value must be between ${lo}–${hi}`;
99
+ if (lo != null) return `Value must be ${lo} or more`;
100
+ if (hi != null) return `Value must be ${hi} or less`;
101
+ return undefined;
102
+ });
103
+
104
+ protected onMinChange(v: string): void {
105
+ this.localMin.set(v);
106
+ this.commit$.next({ min: v, max: this.localMax() });
107
+ }
108
+
109
+ protected onMaxChange(v: string): void {
110
+ this.localMax.set(v);
111
+ this.commit$.next({ min: this.localMin(), max: v });
112
+ }
113
+
114
+ private isOutOfBounds(v: string): boolean {
115
+ if (v === "") return false;
116
+ const n = Number(v);
117
+ const lo = this.boundMin();
118
+ const hi = this.boundMax();
119
+ return (lo != null && n < lo) || (hi != null && n > hi);
120
+ }
121
+
122
+ private commit(min: string, max: string): void {
123
+ const cfg = this.config();
124
+ if (!min && !max) {
125
+ this.state.removeFilter(cfg.field);
126
+ return;
127
+ }
128
+ const minNum = min !== "" ? Number(min) : null;
129
+ const maxNum = max !== "" ? Number(max) : null;
130
+ // Skip writes that would produce an inverted or out-of-bounds clause;
131
+ // the UI keeps the input contents so the user can correct in place.
132
+ if (minNum != null && maxNum != null && minNum > maxNum) return;
133
+ const lo = this.boundMin();
134
+ const hi = this.boundMax();
135
+ if (minNum != null && ((lo != null && minNum < lo) || (hi != null && minNum > hi))) return;
136
+ if (maxNum != null && ((lo != null && maxNum < lo) || (hi != null && maxNum > hi))) return;
137
+
138
+ this.state.setFilter(cfg.field, {
139
+ field: cfg.field,
140
+ label: cfg.label,
141
+ type: "numeric",
142
+ min,
143
+ max,
144
+ });
145
+ }
146
+ }
@@ -0,0 +1,8 @@
1
+ <app-filter-field-wrapper [label]="config().label" [htmlFor]="inputId()">
2
+ <app-input
3
+ type="search"
4
+ [placeholder]="config().placeholder ?? 'Search...'"
5
+ [value]="localValue()"
6
+ (valueChange)="onValueChange($event)"
7
+ />
8
+ </app-filter-field-wrapper>
@@ -0,0 +1,82 @@
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
+ input,
13
+ signal,
14
+ } from "@angular/core";
15
+ import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
16
+ import { Subject } from "rxjs";
17
+ import { debounceTime } from "rxjs/operators";
18
+ // Base-app UI wrapper, inherited (not recreated) by this feature. Post-compose
19
+ // it lands at uiBundles/<target>/src/app/components/ui/input/..., three levels up.
20
+ import { InputComponent } from "../../../../../components/ui/input/input.component";
21
+ import { ObjectSearchStateService } from "../../../object-search-state.service";
22
+ import { FILTER_DEBOUNCE_MS } from "../../../utils/debounce";
23
+ import type { FilterFieldConfig } from "../../../utils/filter-utils";
24
+ import { FilterFieldWrapperComponent } from "../filter-field-wrapper/filter-field-wrapper.component";
25
+
26
+ /**
27
+ * Multi-field search filter — a debounced input whose value is applied via
28
+ * `like %value%` across every field named in `config.searchFields` (combined
29
+ * with a top-level `or`, see {@link buildFilter}).
30
+ *
31
+ * Shape mirrors {@link TextFilterComponent} but emits a `type: 'search'`
32
+ * {@link ActiveFilterValue} so `filter-utils` picks the multi-field path.
33
+ */
34
+ @Component({
35
+ selector: "app-search-filter",
36
+ changeDetection: ChangeDetectionStrategy.OnPush,
37
+ imports: [InputComponent, FilterFieldWrapperComponent],
38
+ templateUrl: "./search-filter.component.html",
39
+ })
40
+ export class SearchFilterComponent {
41
+ private readonly state = inject(ObjectSearchStateService);
42
+ private readonly destroyRef = inject(DestroyRef);
43
+
44
+ /** Field config: `field`, `label`, `placeholder`, `searchFields`, ... */
45
+ readonly config = input.required<FilterFieldConfig>();
46
+
47
+ protected readonly localValue = signal<string>("");
48
+ protected readonly inputId = signal<string>("");
49
+ private readonly commit$ = new Subject<string>();
50
+
51
+ constructor() {
52
+ this.commit$
53
+ .pipe(debounceTime(FILTER_DEBOUNCE_MS), takeUntilDestroyed(this.destroyRef))
54
+ .subscribe((v) => this.commit(v));
55
+
56
+ effect(() => {
57
+ const cfg = this.config();
58
+ this.inputId.set(`filter-${cfg.field}`);
59
+ const external = this.state.filterFor(cfg.field)?.value ?? "";
60
+ this.localValue.set(external);
61
+ });
62
+ }
63
+
64
+ protected onValueChange(v: string): void {
65
+ this.localValue.set(v);
66
+ this.commit$.next(v);
67
+ }
68
+
69
+ private commit(v: string): void {
70
+ const cfg = this.config();
71
+ if (v) {
72
+ this.state.setFilter(cfg.field, {
73
+ field: cfg.field,
74
+ label: cfg.label,
75
+ type: "search",
76
+ value: v,
77
+ });
78
+ } else {
79
+ this.state.removeFilter(cfg.field);
80
+ }
81
+ }
82
+ }
@@ -0,0 +1,12 @@
1
+ <app-filter-field-wrapper
2
+ [label]="config().label"
3
+ [htmlFor]="inputId()"
4
+ [helpText]="config().helpText"
5
+ >
6
+ <app-select
7
+ [placeholder]="'Select ' + config().label.toLowerCase()"
8
+ [options]="options()"
9
+ [value]="currentValue()"
10
+ (valueChange)="onValueChange($event)"
11
+ />
12
+ </app-filter-field-wrapper>
@@ -0,0 +1,65 @@
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, inject, input } from "@angular/core";
7
+ // Base-app UI wrapper, inherited (not recreated) by this feature. Post-compose
8
+ // it lands at uiBundles/<target>/src/app/components/ui/select/..., three levels up.
9
+ import {
10
+ SelectComponent,
11
+ type AppSelectOption,
12
+ } from "../../../../../components/ui/select/select.component";
13
+ import { ObjectSearchStateService } from "../../../object-search-state.service";
14
+ import type { FilterFieldConfig } from "../../../utils/filter-utils";
15
+ import { FilterFieldWrapperComponent } from "../filter-field-wrapper/filter-field-wrapper.component";
16
+
17
+ /**
18
+ * Single-value picklist filter — a select rendered from `config.options` with
19
+ * a leading "All" entry (empty value) that clears the filter.
20
+ *
21
+ * Emits a `type: 'picklist'` filter which `buildSingleFilter` maps to
22
+ * `{ [field]: { eq: value } }`.
23
+ */
24
+ const ALL_VALUE = "";
25
+
26
+ @Component({
27
+ selector: "app-select-filter",
28
+ changeDetection: ChangeDetectionStrategy.OnPush,
29
+ imports: [SelectComponent, FilterFieldWrapperComponent],
30
+ templateUrl: "./select-filter.component.html",
31
+ })
32
+ export class SelectFilterComponent {
33
+ private readonly state = inject(ObjectSearchStateService);
34
+
35
+ /** Field config: `field`, `label`, `options`, `helpText`, ... */
36
+ readonly config = input.required<FilterFieldConfig>();
37
+
38
+ /** DOM id shared by the wrapper label and the underlying control. */
39
+ protected readonly inputId = computed(() => `filter-${this.config().field}`);
40
+
41
+ /** Options rendered in the select, with an "All" (clear) sentinel prepended. */
42
+ protected readonly options = computed<readonly AppSelectOption[]>(() => [
43
+ { value: ALL_VALUE, label: "All" },
44
+ ...(this.config().options ?? []),
45
+ ]);
46
+
47
+ /** Current selection, reading through to shared state so URL changes reflect. */
48
+ protected readonly currentValue = computed(
49
+ () => this.state.filterFor(this.config().field)?.value ?? ALL_VALUE,
50
+ );
51
+
52
+ protected onValueChange(v: string): void {
53
+ const cfg = this.config();
54
+ if (v === ALL_VALUE) {
55
+ this.state.removeFilter(cfg.field);
56
+ } else {
57
+ this.state.setFilter(cfg.field, {
58
+ field: cfg.field,
59
+ label: cfg.label,
60
+ type: "picklist",
61
+ value: v,
62
+ });
63
+ }
64
+ }
65
+ }
@@ -0,0 +1,12 @@
1
+ <app-filter-field-wrapper
2
+ [label]="config().label"
3
+ [htmlFor]="inputId()"
4
+ [helpText]="config().helpText"
5
+ >
6
+ <app-input
7
+ type="text"
8
+ [placeholder]="config().placeholder ?? 'Filter by ' + config().label.toLowerCase() + '...'"
9
+ [value]="localValue()"
10
+ (valueChange)="onValueChange($event)"
11
+ />
12
+ </app-filter-field-wrapper>
@@ -0,0 +1,90 @@
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
+ input,
13
+ signal,
14
+ } from "@angular/core";
15
+ import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
16
+ import { Subject } from "rxjs";
17
+ import { debounceTime } from "rxjs/operators";
18
+ // Base-app UI wrapper, inherited (not recreated) by this feature. Post-compose
19
+ // it lands at uiBundles/<target>/src/app/components/ui/input/..., three levels up.
20
+ import { InputComponent } from "../../../../../components/ui/input/input.component";
21
+ import { ObjectSearchStateService } from "../../../object-search-state.service";
22
+ import { FILTER_DEBOUNCE_MS } from "../../../utils/debounce";
23
+ import type { FilterFieldConfig } from "../../../utils/filter-utils";
24
+ import { FilterFieldWrapperComponent } from "../filter-field-wrapper/filter-field-wrapper.component";
25
+
26
+ /**
27
+ * Text filter — free-text input that writes a `like %value%` clause via
28
+ * {@link ObjectSearchStateService.setFilter}. Keystrokes update the local
29
+ * signal immediately (for a responsive UI) and flush to shared state on a
30
+ * {@link FILTER_DEBOUNCE_MS}ms trailing debounce (to avoid a query per key).
31
+ *
32
+ * Reads the current value from `state.filterFor(config.field)` so URL /
33
+ * reset-all changes reflect back into the input.
34
+ */
35
+ @Component({
36
+ selector: "app-text-filter",
37
+ changeDetection: ChangeDetectionStrategy.OnPush,
38
+ imports: [InputComponent, FilterFieldWrapperComponent],
39
+ templateUrl: "./text-filter.component.html",
40
+ })
41
+ export class TextFilterComponent {
42
+ private readonly state = inject(ObjectSearchStateService);
43
+ private readonly destroyRef = inject(DestroyRef);
44
+
45
+ /** Field config: `field`, `label`, `placeholder`, `helpText`, ... */
46
+ readonly config = input.required<FilterFieldConfig>();
47
+
48
+ /** Local (uncommitted) value that drives the input while the user is typing. */
49
+ protected readonly localValue = signal<string>("");
50
+
51
+ /** DOM id shared by the wrapper label and the underlying input. */
52
+ protected readonly inputId = signal<string>("");
53
+
54
+ /** Coalesces rapid keystrokes into one shared-state write. */
55
+ private readonly commit$ = new Subject<string>();
56
+
57
+ constructor() {
58
+ this.commit$
59
+ .pipe(debounceTime(FILTER_DEBOUNCE_MS), takeUntilDestroyed(this.destroyRef))
60
+ .subscribe((v) => this.commit(v));
61
+
62
+ // Sync the input with the shared state (URL restore, reset-all, ...).
63
+ // Mirrors the React "reset local when external changes" pattern.
64
+ effect(() => {
65
+ const cfg = this.config();
66
+ this.inputId.set(`filter-${cfg.field}`);
67
+ const external = this.state.filterFor(cfg.field)?.value ?? "";
68
+ this.localValue.set(external);
69
+ });
70
+ }
71
+
72
+ protected onValueChange(v: string): void {
73
+ this.localValue.set(v);
74
+ this.commit$.next(v);
75
+ }
76
+
77
+ private commit(v: string): void {
78
+ const cfg = this.config();
79
+ if (v) {
80
+ this.state.setFilter(cfg.field, {
81
+ field: cfg.field,
82
+ label: cfg.label,
83
+ type: "text",
84
+ value: v,
85
+ });
86
+ } else {
87
+ this.state.removeFilter(cfg.field);
88
+ }
89
+ }
90
+ }