@salesforce/templates 66.13.5 → 66.13.7

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 (281) hide show
  1. package/lib/templates/project/angularextapp/CHANGELOG.md +258 -0
  2. package/lib/templates/project/angularextapp/_p_/_m_/_w_/_a_/angular.json +1 -1
  3. package/lib/templates/project/angularextapp/_p_/_m_/_w_/_a_/eslint-plugin-angular-graphql.js +148 -0
  4. package/lib/templates/project/angularextapp/_p_/_m_/_w_/_a_/eslint.config.js +9 -1
  5. package/lib/templates/project/angularextapp/_p_/_m_/_w_/_a_/package-lock.json +680 -408
  6. package/lib/templates/project/angularextapp/_p_/_m_/_w_/_a_/package.json +2 -2
  7. package/lib/templates/project/angularextapp/package.json +1 -1
  8. package/lib/templates/project/angularextapp/scripts/org-setup-config-schema.mjs +17 -0
  9. package/lib/templates/project/angularextapp/scripts/org-setup-utils.mjs +33 -3
  10. package/lib/templates/project/angularextapp/scripts/org-setup.mjs +535 -3
  11. package/lib/templates/project/angularintapp/CHANGELOG.md +266 -0
  12. package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/angular.json +1 -1
  13. package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/eslint-plugin-angular-graphql.js +148 -0
  14. package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/eslint.config.js +9 -1
  15. package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/package-lock.json +690 -418
  16. package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/package.json +2 -2
  17. package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/src/app/features/agentforce/agentforce-embed.service.ts +6 -1
  18. package/lib/templates/project/angularintapp/package.json +1 -1
  19. package/lib/templates/project/angularintapp/scripts/org-setup-config-schema.mjs +17 -0
  20. package/lib/templates/project/angularintapp/scripts/org-setup-utils.mjs +33 -3
  21. package/lib/templates/project/angularintapp/scripts/org-setup.mjs +535 -3
  22. package/lib/templates/project/reactexternalapp/CHANGELOG.md +1409 -0
  23. package/lib/templates/project/reactexternalapp/PRD.md +38 -0
  24. package/lib/templates/project/reactexternalapp/README.md +14 -10
  25. package/lib/templates/project/reactexternalapp/_p_/_m_/_ps_/reactexternalapp_Guest_User_Api_Access.permissionset-meta.xml +25 -0
  26. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/package-lock.json +953 -714
  27. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/package.json +9 -7
  28. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/scripts/get-graphql-schema.mjs +8 -5
  29. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_ls_/LanguageSwitcher.tsx +116 -0
  30. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_ls_/__examples__/language-switcher-example.tsx +36 -0
  31. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_ls_/__examples__/vite-config-site-example.ts +44 -0
  32. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_ls_/buildLanguageUrl.ts +158 -0
  33. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_ls_/index.ts +28 -0
  34. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_ls_/languages.ts +46 -0
  35. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/authentication/components/SocialLogin.tsx +141 -0
  36. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/authentication/pages/Login.tsx +2 -0
  37. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/README.md +246 -0
  38. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/apiUtils.ts +56 -0
  39. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/orgApiVersionService.ts +37 -0
  40. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/searchableContentTypesService.ts +116 -0
  41. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/channelResolver.ts +40 -0
  42. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/cmsQueryFragment.ts +97 -0
  43. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/contentTypeSessionCache.ts +134 -0
  44. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/contentTypeUtils.ts +38 -0
  45. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/hooks/useSearchableContentTypes.ts +128 -0
  46. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/index.ts +54 -0
  47. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/parseResponse.ts +65 -0
  48. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/searchChannel.ts +15 -0
  49. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/types.ts +66 -0
  50. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/registry.ts +38 -0
  51. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/index.ts +19 -0
  52. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/parseResponse.ts +56 -0
  53. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/queryFragment.ts +141 -0
  54. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/types.ts +101 -0
  55. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/api/distinctValuesService.ts +84 -0
  56. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/api/searchService.ts +136 -0
  57. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/GlobalSearchBox.tsx +98 -0
  58. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/MergedSearchResults.tsx +294 -0
  59. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/Search.tsx +203 -0
  60. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SearchResults.tsx +88 -0
  61. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SourceSection.tsx +187 -0
  62. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/PaginationControls.tsx +185 -0
  63. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/ScopeSelector.tsx +107 -0
  64. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/SearchBar.tsx +55 -0
  65. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/SortControl.tsx +62 -0
  66. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/ActiveFilters.tsx +61 -0
  67. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/DefaultFilterPanel.tsx +125 -0
  68. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/{_os_/components → search/components/filters}/FilterContext.tsx +7 -20
  69. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/BooleanFilter.tsx +50 -0
  70. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/DateRangeFilter.tsx +160 -0
  71. package/lib/templates/project/{reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters → reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs}/FilterFieldWrapper.tsx +11 -6
  72. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/MultiSelectFilter.tsx +89 -0
  73. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/NumericRangeFilter.tsx +108 -0
  74. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/SelectFilter.tsx +46 -0
  75. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/TextFilter.tsx +52 -0
  76. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/CmsResultRow.tsx +101 -0
  77. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/DefaultResultRow.tsx +109 -0
  78. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/resolveResultRenderer.ts +49 -0
  79. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/config.json +88 -0
  80. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/constants.ts +8 -0
  81. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/{_os_ → search}/hooks/useAsyncData.ts +3 -10
  82. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/hooks/useDistinctValues.ts +59 -0
  83. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/hooks/useSearch.ts +966 -0
  84. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/index.ts +115 -0
  85. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/loadConfig.ts +14 -0
  86. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/queryBuilder.ts +100 -0
  87. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/types.ts +376 -0
  88. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/debounce.ts +17 -0
  89. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/fieldUtils.ts +14 -0
  90. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/filterUtils.ts +285 -0
  91. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/sortUtils.ts +34 -0
  92. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/api/graphqlClient.ts +24 -8
  93. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/appLayout.tsx +7 -0
  94. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/components/CustomerWebClientChat.tsx +74 -0
  95. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/{_f_/_os_/components → components}/ObjectBreadcrumb.tsx +7 -2
  96. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/components/ui/button.tsx +1 -1
  97. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/components/ui/datePicker.tsx +2 -2
  98. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/components/ui/table.tsx +9 -2
  99. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/index.ts +8 -0
  100. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/pages/AccountObjectDetailPage.tsx +53 -18
  101. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/pages/Home.tsx +3 -27
  102. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/pages/TestChatPage.tsx +26 -0
  103. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/routes.tsx +21 -8
  104. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/types/chat.ts +36 -0
  105. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/types/globals.d.ts +23 -0
  106. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/{_f_/_os_/utils/fieldUtils.ts → utils/accountFields.ts} +9 -0
  107. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/tsconfig.json +2 -2
  108. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/tsconfig.tsbuildinfo +1 -0
  109. package/lib/templates/project/reactexternalapp/_p_/_m_/classes/UIBundleSocialLoginConfig.cls +133 -0
  110. package/lib/templates/project/reactexternalapp/_p_/_m_/classes/UIBundleSocialLoginConfig.cls-meta.xml +5 -0
  111. package/lib/templates/project/reactexternalapp/_p_/_m_/classes/UIBundleSocialLoginConfig_Test.cls +101 -0
  112. package/lib/templates/project/reactexternalapp/_p_/_m_/classes/UIBundleSocialLoginConfig_Test.cls-meta.xml +5 -0
  113. package/lib/templates/project/reactexternalapp/_p_/_m_/package.xml +4 -0
  114. package/lib/templates/project/reactexternalapp/package.json +8 -2
  115. package/lib/templates/project/reactexternalapp/scripts/org-setup-config-schema.mjs +120 -0
  116. package/lib/templates/project/reactexternalapp/scripts/org-setup-dev.mjs +87 -0
  117. package/lib/templates/project/reactexternalapp/scripts/org-setup-utils.mjs +569 -0
  118. package/lib/templates/project/reactexternalapp/scripts/org-setup-xml.mjs +182 -0
  119. package/lib/templates/project/reactexternalapp/scripts/org-setup.config.json +6 -2
  120. package/lib/templates/project/reactexternalapp/scripts/org-setup.mjs +1509 -328
  121. package/lib/templates/project/reactexternalapp/scripts/validate-org-setup-config.mjs +38 -0
  122. package/lib/templates/project/reactinternalapp/CHANGELOG.md +1223 -0
  123. package/lib/templates/project/reactinternalapp/PRD.md +35 -0
  124. package/lib/templates/project/reactinternalapp/README.md +14 -10
  125. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/package-lock.json +813 -538
  126. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/package.json +10 -9
  127. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/README.md +246 -0
  128. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/apiUtils.ts +56 -0
  129. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/orgApiVersionService.ts +37 -0
  130. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/searchableContentTypesService.ts +116 -0
  131. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/channelResolver.ts +40 -0
  132. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/cmsQueryFragment.ts +97 -0
  133. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/contentTypeSessionCache.ts +134 -0
  134. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/contentTypeUtils.ts +38 -0
  135. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/hooks/useSearchableContentTypes.ts +128 -0
  136. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/index.ts +54 -0
  137. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/parseResponse.ts +65 -0
  138. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/searchChannel.ts +15 -0
  139. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/types.ts +66 -0
  140. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/registry.ts +38 -0
  141. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/index.ts +19 -0
  142. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/parseResponse.ts +56 -0
  143. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/queryFragment.ts +141 -0
  144. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/types.ts +101 -0
  145. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/api/distinctValuesService.ts +84 -0
  146. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/api/searchService.ts +136 -0
  147. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/GlobalSearchBox.tsx +98 -0
  148. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/MergedSearchResults.tsx +294 -0
  149. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/Search.tsx +203 -0
  150. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SearchResults.tsx +88 -0
  151. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SourceSection.tsx +187 -0
  152. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/PaginationControls.tsx +185 -0
  153. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/ScopeSelector.tsx +107 -0
  154. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/SearchBar.tsx +55 -0
  155. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/SortControl.tsx +62 -0
  156. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/ActiveFilters.tsx +61 -0
  157. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/DefaultFilterPanel.tsx +125 -0
  158. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/{_os_/components → search/components/filters}/FilterContext.tsx +7 -20
  159. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/BooleanFilter.tsx +50 -0
  160. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/DateRangeFilter.tsx +160 -0
  161. package/lib/templates/project/{reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters → reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs}/FilterFieldWrapper.tsx +11 -6
  162. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/MultiSelectFilter.tsx +89 -0
  163. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/NumericRangeFilter.tsx +108 -0
  164. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/SelectFilter.tsx +46 -0
  165. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/TextFilter.tsx +52 -0
  166. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/CmsResultRow.tsx +101 -0
  167. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/DefaultResultRow.tsx +109 -0
  168. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/resolveResultRenderer.ts +49 -0
  169. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/config.json +88 -0
  170. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/constants.ts +8 -0
  171. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/{_os_ → search}/hooks/useAsyncData.ts +3 -10
  172. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/hooks/useDistinctValues.ts +59 -0
  173. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/hooks/useSearch.ts +966 -0
  174. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/index.ts +115 -0
  175. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/loadConfig.ts +14 -0
  176. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/queryBuilder.ts +100 -0
  177. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/types.ts +376 -0
  178. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/debounce.ts +17 -0
  179. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/fieldUtils.ts +14 -0
  180. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/filterUtils.ts +285 -0
  181. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/sortUtils.ts +34 -0
  182. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/components/AgentforceConversationClient.tsx +16 -132
  183. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/{_f_/_os_/components → components}/ObjectBreadcrumb.tsx +7 -2
  184. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/components/ui/button.tsx +1 -1
  185. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/components/ui/datePicker.tsx +2 -2
  186. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/components/ui/table.tsx +9 -2
  187. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/pages/AccountObjectDetailPage.tsx +49 -16
  188. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/pages/Home.tsx +3 -27
  189. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/routes.tsx +12 -5
  190. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/{_f_/_os_/utils/fieldUtils.ts → utils/accountFields.ts} +9 -0
  191. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/tsconfig.json +2 -2
  192. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/tsconfig.tsbuildinfo +1 -0
  193. package/lib/templates/project/reactinternalapp/package.json +4 -2
  194. package/lib/templates/project/reactinternalapp/scripts/org-setup-config-schema.mjs +24 -0
  195. package/lib/templates/project/reactinternalapp/scripts/org-setup-dev.mjs +87 -0
  196. package/lib/templates/project/reactinternalapp/scripts/org-setup-utils.mjs +569 -0
  197. package/lib/templates/project/reactinternalapp/scripts/org-setup-xml.mjs +182 -0
  198. package/lib/templates/project/reactinternalapp/scripts/org-setup.mjs +1162 -214
  199. package/lib/templates/uiBundles/angularbasic/angular.json +1 -1
  200. package/lib/templates/uiBundles/angularbasic/eslint-plugin-angular-graphql.js +148 -0
  201. package/lib/templates/uiBundles/angularbasic/eslint.config.js +9 -1
  202. package/lib/templates/uiBundles/angularbasic/package-lock.json +680 -408
  203. package/lib/templates/uiBundles/angularbasic/package.json +2 -2
  204. package/lib/templates/uiBundles/reactbasic/package-lock.json +738 -440
  205. package/lib/utils/template-placeholders.js +14 -0
  206. package/lib/utils/template-placeholders.js.map +1 -1
  207. package/lib/utils/uiBundleTemplateUtils.d.ts +5 -1
  208. package/lib/utils/uiBundleTemplateUtils.js +7 -1
  209. package/lib/utils/uiBundleTemplateUtils.js.map +1 -1
  210. package/package.json +7 -7
  211. package/lib/templates/project/reactexternalapp/AGENT.md +0 -252
  212. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/accountSearchService.ts +0 -46
  213. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/distinctAccountIndustries.graphql +0 -19
  214. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/distinctAccountTypes.graphql +0 -19
  215. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/getAccountDetail.graphql +0 -121
  216. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/searchAccounts.graphql +0 -51
  217. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/pages/AccountObjectDetailPage.tsx +0 -355
  218. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/pages/AccountSearch.tsx +0 -304
  219. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/pages/Home.tsx +0 -34
  220. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/api/objectSearchService.ts +0 -82
  221. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/ActiveFilters.tsx +0 -89
  222. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/PaginationControls.tsx +0 -109
  223. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/SearchBar.tsx +0 -41
  224. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/SortControl.tsx +0 -143
  225. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/BooleanFilter.tsx +0 -78
  226. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/DateFilter.tsx +0 -128
  227. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/DateRangeFilter.tsx +0 -70
  228. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/MultiSelectFilter.tsx +0 -97
  229. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/NumericRangeFilter.tsx +0 -167
  230. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/SearchFilter.tsx +0 -52
  231. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/SelectFilter.tsx +0 -97
  232. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/TextFilter.tsx +0 -93
  233. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/hooks/useDebouncedCallback.ts +0 -34
  234. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/hooks/useObjectSearchParams.ts +0 -254
  235. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/utils/debounce.ts +0 -25
  236. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/utils/filterUtils.ts +0 -404
  237. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/utils/sortUtils.ts +0 -38
  238. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/api/account/accountSearchService.ts +0 -46
  239. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/api/account/query/distinctAccountIndustries.graphql +0 -19
  240. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/api/account/query/distinctAccountTypes.graphql +0 -19
  241. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/api/account/query/searchAccounts.graphql +0 -51
  242. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/api/graphql-operations-types.ts +0 -11260
  243. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/pages/AccountSearch.tsx +0 -297
  244. package/lib/templates/project/reactexternalapp/scripts/prepare-import-unique-fields.js +0 -122
  245. package/lib/templates/project/reactinternalapp/AGENT.md +0 -252
  246. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/accountSearchService.ts +0 -46
  247. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/distinctAccountIndustries.graphql +0 -19
  248. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/distinctAccountTypes.graphql +0 -19
  249. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/getAccountDetail.graphql +0 -121
  250. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/searchAccounts.graphql +0 -51
  251. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/pages/AccountObjectDetailPage.tsx +0 -355
  252. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/pages/AccountSearch.tsx +0 -304
  253. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/pages/Home.tsx +0 -34
  254. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/api/objectSearchService.ts +0 -82
  255. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/ActiveFilters.tsx +0 -89
  256. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/PaginationControls.tsx +0 -109
  257. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/SearchBar.tsx +0 -41
  258. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/SortControl.tsx +0 -143
  259. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/BooleanFilter.tsx +0 -78
  260. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/DateFilter.tsx +0 -128
  261. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/DateRangeFilter.tsx +0 -70
  262. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/MultiSelectFilter.tsx +0 -97
  263. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/NumericRangeFilter.tsx +0 -167
  264. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/SearchFilter.tsx +0 -52
  265. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/SelectFilter.tsx +0 -97
  266. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/TextFilter.tsx +0 -93
  267. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/hooks/useDebouncedCallback.ts +0 -34
  268. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/hooks/useObjectSearchParams.ts +0 -254
  269. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/utils/debounce.ts +0 -25
  270. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/utils/filterUtils.ts +0 -404
  271. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/utils/sortUtils.ts +0 -38
  272. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/api/account/accountSearchService.ts +0 -46
  273. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/api/account/query/distinctAccountIndustries.graphql +0 -19
  274. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/api/account/query/distinctAccountTypes.graphql +0 -19
  275. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/api/account/query/searchAccounts.graphql +0 -51
  276. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/api/graphql-operations-types.ts +0 -11260
  277. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/pages/AccountSearch.tsx +0 -297
  278. package/lib/templates/project/reactinternalapp/scripts/prepare-import-unique-fields.js +0 -122
  279. /package/lib/templates/project/angularextapp/_p_/_m_/{permissionsets → _ps_}/angularextapp_Guest_User_Api_Access.permissionset-meta.xml +0 -0
  280. /package/lib/templates/project/angularintapp/_p_/_m_/{permissionsets → _ps_}/angularintapp_Access.permissionset-meta.xml +0 -0
  281. /package/lib/templates/project/reactinternalapp/_p_/_m_/{permissionsets → _ps_}/reactinternalapp_Access.permissionset-meta.xml +0 -0
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Filter primitives for search.
3
+ *
4
+ * Two responsibilities:
5
+ * 1. Build a GraphQL `where` clause from a list of active filter values.
6
+ * 2. Serialize/deserialize active filters to/from URLSearchParams under a
7
+ * per-source namespace prefix (so multiple sources can coexist on one URL).
8
+ *
9
+ * The URL helpers are namespaced: each source declares its key, and filter
10
+ * params are written as `s.<key>.f.<field>=...`. Sort uses
11
+ * `s.<key>.sort=<field>&s.<key>.dir=ASC|DESC`. Page size and page index use
12
+ * `s.<key>.ps=<size>` and `s.<key>.page=<n>`.
13
+ *
14
+ * The global search term `q=...` is **not** scoped to a source — it's broadcast
15
+ * to every source's `searchableFields` by the query builder.
16
+ */
17
+
18
+ import type { SortState } from "./sortUtils";
19
+
20
+ export type FilterFieldType =
21
+ | "text"
22
+ | "picklist"
23
+ | "numeric"
24
+ | "boolean"
25
+ | "date"
26
+ | "daterange"
27
+ | "datetime"
28
+ | "datetimerange"
29
+ | "multipicklist";
30
+
31
+ /**
32
+ * Which comparison UI a date/datetime filter exposes:
33
+ * - `"range"`: a single Between control (two date inputs, lower–upper bound).
34
+ * - `"comparison"`: an After / Before selector with one date input.
35
+ * - `"both"`: a Between / After / Before selector that switches between the two.
36
+ *
37
+ * Applies only to the date-family `type`s (`date`, `daterange`, `datetime`,
38
+ * `datetimerange`); ignored for other field types. Defaults to `"comparison"`.
39
+ */
40
+ export type DateFilterMode = "range" | "comparison" | "both";
41
+
42
+ export type FilterFieldConfig<TFieldName extends string = string> = {
43
+ field: TFieldName;
44
+ label: string;
45
+ type: FilterFieldType;
46
+ placeholder?: string;
47
+ /** Required for picklist / multipicklist. */
48
+ options?: Array<{ value: string; label: string }>;
49
+ /** Date-family only — see {@link DateFilterMode}. Defaults to `"comparison"`. */
50
+ dateMode?: DateFilterMode;
51
+ helpText?: string;
52
+ };
53
+
54
+ export type ActiveFilterValue<TFieldName extends string = string> = {
55
+ field: TFieldName;
56
+ label: string;
57
+ type: FilterFieldType;
58
+ value?: string;
59
+ min?: string;
60
+ max?: string;
61
+ };
62
+
63
+ // ---------------------------------------------------------------------------
64
+ // URL serialization (per-source namespace)
65
+ // ---------------------------------------------------------------------------
66
+
67
+ const SOURCE_PREFIX = "s.";
68
+ const FILTER_INFIX = ".f.";
69
+ const SORT_SUFFIX = ".sort";
70
+ const DIR_SUFFIX = ".dir";
71
+ const PAGE_SIZE_SUFFIX = ".ps";
72
+ const PAGE_SUFFIX = ".page";
73
+
74
+ /** Global search term key (not source-scoped). */
75
+ export const GLOBAL_QUERY_KEY = "q";
76
+
77
+ function filterKey(sourceKey: string, field: string, suffix?: string) {
78
+ return `${SOURCE_PREFIX}${sourceKey}${FILTER_INFIX}${field}${suffix ? `.${suffix}` : ""}`;
79
+ }
80
+
81
+ /**
82
+ * The source's own default sort / page size. When a source's current state
83
+ * matches these, the corresponding URL params are omitted so the query string
84
+ * only ever reflects an *explicit* user choice — resetting filters or returning
85
+ * a source to its defaults yields a clean URL instead of one littered with the
86
+ * defaults. The read path falls back to these same defaults when the params are
87
+ * absent, so the round-trip is lossless.
88
+ */
89
+ export interface SourceParamDefaults {
90
+ sort?: SortState | null;
91
+ pageSize?: number;
92
+ }
93
+
94
+ function sortMatchesDefault(sort: SortState, defaultSort: SortState | null | undefined): boolean {
95
+ return (
96
+ !!defaultSort && sort.field === defaultSort.field && sort.direction === defaultSort.direction
97
+ );
98
+ }
99
+
100
+ export function writeSourceParams(
101
+ params: URLSearchParams,
102
+ sourceKey: string,
103
+ filters: ActiveFilterValue[],
104
+ sort: SortState | null,
105
+ pageSize?: number,
106
+ pageIndex?: number,
107
+ defaults?: SourceParamDefaults,
108
+ ): void {
109
+ for (const filter of filters) {
110
+ if (filter.value !== undefined && filter.value !== "") {
111
+ params.set(filterKey(sourceKey, filter.field), filter.value);
112
+ }
113
+ if (filter.min !== undefined && filter.min !== "") {
114
+ params.set(filterKey(sourceKey, filter.field, "min"), filter.min);
115
+ }
116
+ if (filter.max !== undefined && filter.max !== "") {
117
+ params.set(filterKey(sourceKey, filter.field, "max"), filter.max);
118
+ }
119
+ }
120
+ // Only serialize sort when it differs from the source default — otherwise
121
+ // the URL would carry the default the user never chose.
122
+ if (sort && !sortMatchesDefault(sort, defaults?.sort)) {
123
+ params.set(`${SOURCE_PREFIX}${sourceKey}${SORT_SUFFIX}`, sort.field);
124
+ params.set(`${SOURCE_PREFIX}${sourceKey}${DIR_SUFFIX}`, sort.direction);
125
+ }
126
+ if (pageSize !== undefined && pageSize !== defaults?.pageSize) {
127
+ params.set(`${SOURCE_PREFIX}${sourceKey}${PAGE_SIZE_SUFFIX}`, String(pageSize));
128
+ }
129
+ if (pageIndex !== undefined && pageIndex > 0) {
130
+ params.set(`${SOURCE_PREFIX}${sourceKey}${PAGE_SUFFIX}`, String(pageIndex + 1));
131
+ }
132
+ }
133
+
134
+ export interface ReadSourceParamsResult {
135
+ filters: ActiveFilterValue[];
136
+ sort: SortState | null;
137
+ pageSize: number | undefined;
138
+ pageIndex: number;
139
+ }
140
+
141
+ export function readSourceParams(
142
+ params: URLSearchParams,
143
+ sourceKey: string,
144
+ configs: FilterFieldConfig[],
145
+ ): ReadSourceParamsResult {
146
+ const filters: ActiveFilterValue[] = [];
147
+ for (const config of configs) {
148
+ const { field, label, type } = config;
149
+ const value = params.get(filterKey(sourceKey, field)) ?? undefined;
150
+ const min = params.get(filterKey(sourceKey, field, "min")) ?? undefined;
151
+ const max = params.get(filterKey(sourceKey, field, "max")) ?? undefined;
152
+
153
+ const hasValue = value !== undefined && value !== "";
154
+ const hasRange = (min !== undefined && min !== "") || (max !== undefined && max !== "");
155
+ if (hasValue || hasRange) {
156
+ filters.push({ field, label, type, value, min, max });
157
+ }
158
+ }
159
+
160
+ let sort: SortState | null = null;
161
+ const sortField = params.get(`${SOURCE_PREFIX}${sourceKey}${SORT_SUFFIX}`);
162
+ const sortDir = params.get(`${SOURCE_PREFIX}${sourceKey}${DIR_SUFFIX}`);
163
+ if (sortField) {
164
+ sort = { field: sortField, direction: sortDir === "DESC" ? "DESC" : "ASC" };
165
+ }
166
+
167
+ const pageSizeRaw = params.get(`${SOURCE_PREFIX}${sourceKey}${PAGE_SIZE_SUFFIX}`);
168
+ const pageSize = pageSizeRaw ? parseInt(pageSizeRaw, 10) : undefined;
169
+ const pageRaw = params.get(`${SOURCE_PREFIX}${sourceKey}${PAGE_SUFFIX}`);
170
+ const page = pageRaw ? parseInt(pageRaw, 10) : 1;
171
+ const pageIndex = !isNaN(page) && page > 1 ? page - 1 : 0;
172
+
173
+ return {
174
+ filters,
175
+ sort,
176
+ pageSize: pageSize && !isNaN(pageSize) ? pageSize : undefined,
177
+ pageIndex,
178
+ };
179
+ }
180
+
181
+ // ---------------------------------------------------------------------------
182
+ // GraphQL filter building
183
+ // ---------------------------------------------------------------------------
184
+
185
+ /**
186
+ * Combines active filter values into a GraphQL `where` clause for one source.
187
+ * Returns `undefined` when no constraints are active.
188
+ */
189
+ export function buildFilter(filters: ActiveFilterValue[], configs: FilterFieldConfig[]): unknown {
190
+ const configMap = new Map(configs.map((c) => [c.field, c]));
191
+ const clauses: unknown[] = [];
192
+ for (const filter of filters) {
193
+ const clause = buildSingleFilter(filter, configMap.get(filter.field));
194
+ if (clause) clauses.push(clause);
195
+ }
196
+ if (clauses.length === 0) return undefined;
197
+ if (clauses.length === 1) return clauses[0];
198
+ return { and: clauses };
199
+ }
200
+
201
+ function toStartOfDay(d: string) {
202
+ return `${d}T00:00:00.000Z`;
203
+ }
204
+ function toEndOfDay(d: string) {
205
+ return `${d}T23:59:59.999Z`;
206
+ }
207
+
208
+ function buildSingleFilter(filter: ActiveFilterValue, _config?: FilterFieldConfig): unknown {
209
+ const { field, type, value, min, max } = filter;
210
+ switch (type) {
211
+ case "text": {
212
+ if (!value) return null;
213
+ return { [field]: { like: `%${value}%` } };
214
+ }
215
+ case "picklist": {
216
+ if (!value) return null;
217
+ return { [field]: { eq: value } };
218
+ }
219
+ case "numeric": {
220
+ if (!min && !max) return null;
221
+ const ops: Record<string, number> = {};
222
+ if (min) ops.gte = Number(min);
223
+ if (max) ops.lte = Number(max);
224
+ return { [field]: ops };
225
+ }
226
+ case "boolean": {
227
+ if (value === undefined || value === "") return null;
228
+ return { [field]: { eq: value === "true" } };
229
+ }
230
+ case "multipicklist": {
231
+ if (!value) return null;
232
+ const values = value.split(",").filter(Boolean);
233
+ if (values.length === 0) return null;
234
+ if (values.length === 1) return { [field]: { eq: values[0] } };
235
+ return { [field]: { in: values } };
236
+ }
237
+ case "date": {
238
+ if (!min && !max) return null;
239
+ const op = min ? "gte" : "lte";
240
+ const dateStr = min ?? max;
241
+ return { [field]: { [op]: { value: dateStr } } };
242
+ }
243
+ case "daterange": {
244
+ if (!min && !max) return null;
245
+ const clauses: unknown[] = [];
246
+ if (min) clauses.push({ [field]: { gte: { value: min } } });
247
+ if (max) clauses.push({ [field]: { lte: { value: max } } });
248
+ return clauses.length === 1 ? clauses[0] : { and: clauses };
249
+ }
250
+ case "datetime": {
251
+ if (!min && !max) return null;
252
+ const op = min ? "gte" : "lte";
253
+ const dateStr = min ?? max;
254
+ const isoStr = op === "gte" ? toStartOfDay(dateStr!) : toEndOfDay(dateStr!);
255
+ return { [field]: { [op]: { value: isoStr } } };
256
+ }
257
+ case "datetimerange": {
258
+ if (!min && !max) return null;
259
+ const clauses: unknown[] = [];
260
+ if (min) clauses.push({ [field]: { gte: { value: toStartOfDay(min) } } });
261
+ if (max) clauses.push({ [field]: { lte: { value: toEndOfDay(max) } } });
262
+ return clauses.length === 1 ? clauses[0] : { and: clauses };
263
+ }
264
+ default:
265
+ return null;
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Builds a global-q `or` clause across the source's searchable fields.
271
+ * Returns `undefined` when q is empty or the source has no searchable fields.
272
+ */
273
+ export function buildGlobalQueryClause(q: string, searchableFields: string[]): unknown {
274
+ const trimmed = q.trim();
275
+ if (!trimmed || searchableFields.length === 0) return undefined;
276
+ const clauses = searchableFields.map((path) => {
277
+ const parts = path.split(".");
278
+ let clause: Record<string, unknown> = { like: `%${trimmed}%` };
279
+ for (let i = parts.length - 1; i >= 0; i--) {
280
+ clause = { [parts[i]]: clause };
281
+ }
282
+ return clause;
283
+ });
284
+ return clauses.length === 1 ? clauses[0] : { or: clauses };
285
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Sort state and order-by builder for search.
3
+ *
4
+ * The order-by output shape matches the Salesforce uiapi GraphQL convention:
5
+ * { [field]: { order: ASC|DESC, nulls: LAST } }
6
+ *
7
+ * The constants are stringly-typed here (rather than imported from codegen)
8
+ * because search builds its query at runtime and isn't tied to a
9
+ * specific generated schema.
10
+ */
11
+
12
+ export type SortFieldConfig<TFieldName extends string = string> = {
13
+ field: TFieldName;
14
+ label: string;
15
+ };
16
+
17
+ export type SortState<TFieldName extends string = string> = {
18
+ field: TFieldName;
19
+ direction: "ASC" | "DESC";
20
+ };
21
+
22
+ const ORDER_ASC = "ASC";
23
+ const ORDER_DESC = "DESC";
24
+ const NULLS_LAST = "LAST";
25
+
26
+ export function buildOrderBy(sort: SortState | null): unknown {
27
+ if (!sort) return undefined;
28
+ return {
29
+ [sort.field]: {
30
+ order: sort.direction === "ASC" ? ORDER_ASC : ORDER_DESC,
31
+ nulls: NULLS_LAST,
32
+ },
33
+ };
34
+ }
@@ -1,19 +1,35 @@
1
1
  /**
2
- * Thin GraphQL client: createDataSDK + sdk.graphql.query with centralized
3
- * error handling. Use with gql-tagged queries and generated operation types
4
- * for type-safe calls.
2
+ * Thin GraphQL client: createDataSDK + sdk.graphql with centralized error
3
+ * handling. Mutations are routed to sdk.graphql.mutate and everything else to
4
+ * sdk.graphql.query (the SDK rejects an operation sent to the wrong method).
5
+ * Use with gql-tagged queries and generated operation types for type-safe calls.
5
6
  */
6
7
  import { createDataSDK } from '@salesforce/platform-sdk';
7
8
 
9
+ /**
10
+ * True when the operation's first definition is a `mutation`. Strips GraphQL
11
+ * comments first so a leading `# ...` line can't mask the keyword. Queries
12
+ * (named or anonymous `{ ... }` shorthand) and subscriptions fall through to
13
+ * query().
14
+ */
15
+ function isMutation(operation: string): boolean {
16
+ return /^\s*mutation\b/.test(operation.replace(/#[^\n\r]*/g, ''));
17
+ }
18
+
8
19
  export async function executeGraphQL<TData, TVariables>(
9
- query: string,
20
+ operation: string,
10
21
  variables?: TVariables
11
22
  ): Promise<TData> {
12
23
  const data = await createDataSDK();
13
- const result = await data.graphql!.query<TData, TVariables>({
14
- query: query,
15
- variables: variables,
16
- });
24
+ const result = isMutation(operation)
25
+ ? await data.graphql!.mutate<TData, TVariables>({
26
+ mutation: operation,
27
+ variables: variables,
28
+ })
29
+ : await data.graphql!.query<TData, TVariables>({
30
+ query: operation,
31
+ variables: variables,
32
+ });
17
33
 
18
34
  if (result.errors?.length) {
19
35
  const msg = result.errors.map(e => e.message).join('; ');
@@ -3,6 +3,7 @@ import { getAllRoutes } from "./router-utils";
3
3
  import { useState } from "react";
4
4
  import { AuthMenu } from "./features/authentication/menu/AuthMenu";
5
5
  import { Button } from "./components/ui/button";
6
+ import CustomerWebClientChat from "./components/CustomerWebClientChat";
6
7
 
7
8
  export default function AppLayout() {
8
9
  const [isOpen, setIsOpen] = useState(false);
@@ -83,6 +84,12 @@ export default function AppLayout() {
83
84
  </div>
84
85
  </nav>
85
86
  <Outlet />
87
+ <CustomerWebClientChat
88
+ orgId="<ORG_ID_15_OR_18_CHAR_00D...>"
89
+ deploymentName="<EMBEDDED_SERVICE_DEPLOYMENT_NAME>"
90
+ siteURL="<SITE_URL>"
91
+ scrt2URL="<SCRT2_URL>"
92
+ />
86
93
  </>
87
94
  );
88
95
  }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+
7
+ import { useEffect } from "react";
8
+ import type { CustomerWebClientChatProps, WindowWithCwcProperties } from "../types/chat";
9
+
10
+ /**
11
+ * React wrapper that embeds the Customer Web Client (Embedded Messaging) chat
12
+ * widget into an external site. It dynamically loads the site's
13
+ * `embeddedservice_bootstrap` script and calls `init` with the org, deployment,
14
+ * site, and SCRT2 configuration. Renders nothing itself — the chat UI is a
15
+ * floating widget injected by the bootstrap script.
16
+ */
17
+ export function CustomerWebClientChat({
18
+ orgId,
19
+ deploymentName,
20
+ siteURL,
21
+ scrt2URL,
22
+ language = "en",
23
+ devMode = false,
24
+ }: CustomerWebClientChatProps) {
25
+ useEffect(() => {
26
+ if (typeof window === "undefined") return;
27
+ if (
28
+ !orgId ||
29
+ !deploymentName ||
30
+ !siteURL ||
31
+ !scrt2URL ||
32
+ !(orgId.length === 15 || orgId.length === 18)
33
+ ) {
34
+ console.warn("[CustomerWebClientChat] missing required config; skipping init");
35
+ return;
36
+ }
37
+
38
+ const win = window as WindowWithCwcProperties;
39
+ const bootstrapSrc = `${siteURL}/assets/js/bootstrap.js`;
40
+ const existing = document.querySelector<HTMLScriptElement>(`script[src="${bootstrapSrc}"]`);
41
+ const script: HTMLScriptElement = existing ?? document.createElement("script");
42
+
43
+ const init = () => {
44
+ try {
45
+ if (!win.embeddedservice_bootstrap) return;
46
+ win.embeddedservice_bootstrap.settings.language = language;
47
+ if (devMode) win.embeddedservice_bootstrap.settings.devMode = true;
48
+ win.embeddedservice_bootstrap.init(orgId, deploymentName, siteURL, {
49
+ scrt2URL,
50
+ });
51
+ } catch (err) {
52
+ console.error("Error loading Embedded Messaging: ", err);
53
+ }
54
+ };
55
+
56
+ if (existing) {
57
+ if (win.embeddedservice_bootstrap) init();
58
+ else existing.addEventListener("load", init, { once: true });
59
+ } else {
60
+ script.type = "text/javascript";
61
+ script.src = bootstrapSrc;
62
+ script.addEventListener("load", init, { once: true });
63
+ document.body.appendChild(script);
64
+ }
65
+
66
+ return () => {
67
+ script.removeEventListener("load", init);
68
+ };
69
+ }, [orgId, deploymentName, siteURL, scrt2URL, language, devMode]);
70
+
71
+ return null;
72
+ }
73
+
74
+ export default CustomerWebClientChat;
@@ -6,9 +6,14 @@ import {
6
6
  BreadcrumbLink,
7
7
  BreadcrumbSeparator,
8
8
  BreadcrumbPage,
9
- } from "../../../components/ui/breadcrumb";
10
- import { Skeleton } from "../../../components/ui/skeleton";
9
+ } from "./ui/breadcrumb";
10
+ import { Skeleton } from "./ui/skeleton";
11
11
 
12
+ /**
13
+ * Home → List → Record breadcrumb for object pages. Previously imported from
14
+ * feature-react-object-search; inlined here so the app no longer depends on
15
+ * that feature.
16
+ */
12
17
  interface ObjectBreadcrumbProps {
13
18
  listPath: string;
14
19
  listLabel: string;
@@ -17,7 +17,7 @@ const buttonVariants = cva(
17
17
  ghost:
18
18
  'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',
19
19
  destructive:
20
- 'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',
20
+ 'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-red-700 dark:text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',
21
21
  link: 'text-primary underline-offset-4 hover:underline',
22
22
  },
23
23
  size: {
@@ -38,7 +38,7 @@ function DatePickerTrigger({
38
38
  data-slot="date-picker-trigger"
39
39
  data-empty={!date}
40
40
  className={cn(
41
- 'w-[280px] justify-start text-left font-normal data-[empty=true]:text-muted-foreground',
41
+ 'w-[280px] justify-start text-left font-normal data-[empty=true]:text-gray-600',
42
42
  className
43
43
  )}
44
44
  {...props}
@@ -87,7 +87,7 @@ function DatePickerRangeTrigger({
87
87
  data-slot="date-picker-range-trigger"
88
88
  data-empty={!hasDate}
89
89
  className={cn(
90
- 'justify-start text-left font-normal data-[empty=true]:text-muted-foreground',
90
+ 'justify-start text-left font-normal data-[empty=true]:text-gray-600',
91
91
  className
92
92
  )}
93
93
  {...props}
@@ -2,11 +2,18 @@ import * as React from 'react';
2
2
 
3
3
  import { cn } from '../../lib/utils';
4
4
 
5
- function Table({ className, ...props }: React.ComponentProps<'table'>) {
5
+ function Table({
6
+ className,
7
+ 'aria-label': ariaLabel = 'Table',
8
+ ...props
9
+ }: React.ComponentProps<'table'>) {
6
10
  return (
7
11
  <div
8
12
  data-slot="table-container"
9
- className="relative w-full overflow-x-auto"
13
+ role="region"
14
+ aria-label={ariaLabel}
15
+ tabIndex={0}
16
+ className="relative w-full overflow-x-auto focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-purple"
10
17
  >
11
18
  <table
12
19
  data-slot="table"
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+
7
+ /** Package entry point — re-exports the language switcher public API. */
8
+ export * from "./features/language-switcher/index";
@@ -3,18 +3,10 @@ import { useParams, useNavigate } from "react-router";
3
3
  import { createDataSDK } from "@salesforce/platform-sdk";
4
4
  import { AlertCircle, ChevronDown, ChevronRight, FileQuestion } from "lucide-react";
5
5
  import GET_ACCOUNT_DETAIL from "../api/account/query/getAccountDetail.graphql?raw";
6
- import type {
7
- GetAccountDetailQuery,
8
- GetAccountDetailQueryVariables,
9
- } from "../api/graphql-operations-types";
10
6
  import { Alert, AlertTitle, AlertDescription } from "../components/ui/alert";
11
7
  import { Button } from "../components/ui/button";
12
8
  import { Card, CardContent } from "../components/ui/card";
13
- import {
14
- fieldValue,
15
- getAddressFieldLines,
16
- formatDateTimeField,
17
- } from "../features/object-search/utils/fieldUtils";
9
+ import { fieldValue, getAddressFieldLines, formatDateTimeField } from "../utils/accountFields";
18
10
  import {
19
11
  Collapsible,
20
12
  CollapsibleTrigger,
@@ -23,17 +15,58 @@ import {
23
15
  import { Separator } from "../components/ui/separator";
24
16
  import { Skeleton } from "../components/ui/skeleton";
25
17
  import { useAsyncData } from "../hooks/useAsyncData";
26
- import { ObjectBreadcrumb } from "../features/object-search/components/ObjectBreadcrumb";
18
+ import { ObjectBreadcrumb } from "../components/ObjectBreadcrumb";
19
+
20
+ /**
21
+ * A uiapi scalar field as returned with `@optional { value displayValue }`.
22
+ * Typed locally so this page no longer depends on the generated
23
+ * `graphql-operations-types` that shipped with feature-react-object-search.
24
+ */
25
+ type FieldValue = { value?: unknown; displayValue?: string | null } | null;
26
+ type NameHolder = { Name?: FieldValue } | null;
27
+
28
+ interface AccountNode {
29
+ Id?: string;
30
+ Name?: FieldValue;
31
+ Owner?: NameHolder;
32
+ Phone?: FieldValue;
33
+ Fax?: FieldValue;
34
+ Parent?: NameHolder;
35
+ Website?: FieldValue;
36
+ Type?: FieldValue;
37
+ NumberOfEmployees?: FieldValue;
38
+ Industry?: FieldValue;
39
+ AnnualRevenue?: FieldValue;
40
+ Description?: FieldValue;
41
+ BillingStreet?: FieldValue;
42
+ BillingCity?: FieldValue;
43
+ BillingState?: FieldValue;
44
+ BillingPostalCode?: FieldValue;
45
+ BillingCountry?: FieldValue;
46
+ ShippingStreet?: FieldValue;
47
+ ShippingCity?: FieldValue;
48
+ ShippingState?: FieldValue;
49
+ ShippingPostalCode?: FieldValue;
50
+ ShippingCountry?: FieldValue;
51
+ CreatedBy?: NameHolder;
52
+ CreatedDate?: FieldValue;
53
+ LastModifiedBy?: NameHolder;
54
+ LastModifiedDate?: FieldValue;
55
+ }
27
56
 
28
- type AccountNode = NonNullable<
29
- NonNullable<
30
- NonNullable<NonNullable<GetAccountDetailQuery["uiapi"]["query"]["Account"]>["edges"]>[number]
31
- >["node"]
32
- >;
57
+ interface GetAccountDetailResponse {
58
+ uiapi?: {
59
+ query?: {
60
+ Account?: {
61
+ edges?: Array<{ node?: AccountNode } | null> | null;
62
+ } | null;
63
+ } | null;
64
+ } | null;
65
+ }
33
66
 
34
67
  async function fetchAccountDetail(recordId: string): Promise<AccountNode | null | undefined> {
35
68
  const data = await createDataSDK();
36
- const result = await data.graphql!.query<GetAccountDetailQuery, GetAccountDetailQueryVariables>({
69
+ const result = await data.graphql!.query<GetAccountDetailResponse, { id: string }>({
37
70
  query: GET_ACCOUNT_DETAIL,
38
71
  variables: { id: recordId },
39
72
  });
@@ -156,7 +189,9 @@ function AccountDetailContent({ account }: { account: AccountNode }) {
156
189
  <FieldItem label="Industry">{fieldValue(account.Industry)}</FieldItem>
157
190
  <FieldItem label="Annual Revenue">{fieldValue(account.AnnualRevenue)}</FieldItem>
158
191
  </FieldRow>
159
- <FieldItem label="Description">{fieldValue(account.Description)}</FieldItem>
192
+ <dl>
193
+ <FieldItem label="Description">{fieldValue(account.Description)}</FieldItem>
194
+ </dl>
160
195
  </Section>
161
196
 
162
197
  <Separator />
@@ -216,7 +251,7 @@ function FieldItem({ label, children }: { label: string; children: React.ReactNo
216
251
  }
217
252
 
218
253
  function FieldRow({ children }: { children: React.ReactNode }) {
219
- return <div className="grid grid-cols-2 gap-x-8 gap-y-4">{children}</div>;
254
+ return <dl className="grid grid-cols-2 gap-x-8 gap-y-4">{children}</dl>;
220
255
  }
221
256
 
222
257
  function Section({ title, children }: { title: string; children: React.ReactNode }) {
@@ -1,34 +1,10 @@
1
- import { useState } from "react";
2
- import { useNavigate } from "react-router";
3
- import { SearchBar } from "../features/object-search/components/SearchBar";
4
- import { Button } from "../components/ui/button";
1
+ import { GlobalSearchBox } from "../features/search";
5
2
 
6
3
  export default function HomePage() {
7
- const navigate = useNavigate();
8
- const [text, setText] = useState("");
9
-
10
- const handleSubmit = (e: React.SyntheticEvent<HTMLFormElement>) => {
11
- e.preventDefault();
12
- const params = text ? `?q=${encodeURIComponent(text)}` : "";
13
- navigate(`/accounts${params}`);
14
- };
15
-
16
4
  return (
17
5
  <div className="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
18
- <div className="flex items-center gap-6 mb-6">
19
- <h1 className="text-2xl font-bold">Account Search</h1>
20
- <Button variant="outline" size="sm" onClick={() => navigate("/accounts")}>
21
- Browse All Accounts
22
- </Button>
23
- </div>
24
- <form onSubmit={handleSubmit} className="flex gap-2">
25
- <SearchBar
26
- placeholder="Search by name, phone, or industry..."
27
- value={text}
28
- handleChange={setText}
29
- />
30
- <Button type="submit">Search</Button>
31
- </form>
6
+ <h1 className="text-2xl font-bold mb-6">Home</h1>
7
+ <GlobalSearchBox placeholder="Search accounts, contacts, opportunities..." />
32
8
  </div>
33
9
  );
34
10
  }