@salesforce/templates 66.17.5 → 66.18.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 (277) hide show
  1. package/lib/generators/projectGenerator.js +1 -0
  2. package/lib/generators/projectGenerator.js.map +1 -1
  3. package/lib/templates/project/angularextapp/_p_/_m_/_w_/_a_/package-lock.json +165 -165
  4. package/lib/templates/project/angularintapp/CHANGELOG.md +8 -0
  5. package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/eslint.config.js +2 -1
  6. package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/package-lock.json +169 -169
  7. package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/package.json +4 -4
  8. package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/src/app/components/ui/icon/icon.ts +44 -0
  9. package/lib/templates/project/angularintapp/package.json +1 -1
  10. package/lib/templates/project/reactexternalapp/CHANGELOG.md +8 -0
  11. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/eslint.config.js +8 -12
  12. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/package-lock.json +136 -136
  13. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/package.json +5 -5
  14. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/components/ui/button.tsx +1 -1
  15. package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/components/ui/sonner.tsx +7 -1
  16. package/lib/templates/project/reactexternalapp/package.json +1 -1
  17. package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/package-lock.json +131 -131
  18. package/lib/templates/project/vueinternalapp/.forceignore +15 -0
  19. package/lib/templates/project/vueinternalapp/.husky/pre-commit +4 -0
  20. package/lib/templates/project/vueinternalapp/.prettierignore +11 -0
  21. package/lib/templates/project/vueinternalapp/.prettierrc +17 -0
  22. package/lib/templates/project/vueinternalapp/CHANGELOG.md +5375 -0
  23. package/lib/templates/project/vueinternalapp/PRD.md +35 -0
  24. package/lib/templates/project/vueinternalapp/README.md +125 -0
  25. package/lib/templates/project/vueinternalapp/_p_/_m_/_ps_/vueinternalapp_Access.permissionset-meta.xml +13 -0
  26. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/.forceignore +15 -0
  27. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/.graphqlrc.yml +2 -0
  28. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/.prettierignore +9 -0
  29. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/.prettierrc +11 -0
  30. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/README.md +35 -0
  31. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/codegen.yml +95 -0
  32. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/components.json +19 -0
  33. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/e2e/app.spec.ts +17 -0
  34. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/eslint.config.js +124 -0
  35. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/index.html +12 -0
  36. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/package-lock.json +15530 -0
  37. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/package.json +73 -0
  38. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/playwright.config.ts +24 -0
  39. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/scripts/get-graphql-schema.mjs +71 -0
  40. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/scripts/rewrite-e2e-assets.mjs +23 -0
  41. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/App.vue +5 -0
  42. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/apiUtils.ts +56 -0
  43. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/orgApiVersionService.ts +37 -0
  44. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/searchableContentTypesService.ts +119 -0
  45. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/channelResolver.ts +40 -0
  46. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/cmsQueryFragment.ts +108 -0
  47. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/composables/useSearchableContentTypes.ts +132 -0
  48. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/contentTypeSessionCache.ts +134 -0
  49. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/contentTypeUtils.ts +40 -0
  50. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/index.ts +55 -0
  51. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/parseResponse.ts +65 -0
  52. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/searchChannel.ts +31 -0
  53. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/types.ts +66 -0
  54. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/registry.ts +38 -0
  55. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/index.ts +19 -0
  56. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/parseResponse.ts +55 -0
  57. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/queryFragment.ts +141 -0
  58. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/types.ts +103 -0
  59. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/api/distinctValuesService.ts +81 -0
  60. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/api/searchService.ts +136 -0
  61. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/GlobalSearchBox.types.ts +18 -0
  62. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/GlobalSearchBox.vue +73 -0
  63. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/MergedSearchResults.types.ts +24 -0
  64. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/MergedSearchResults.vue +263 -0
  65. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/Search.vue +200 -0
  66. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SearchResults.vue +99 -0
  67. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SourceSection.vue +204 -0
  68. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/PaginationControls.vue +180 -0
  69. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/ScopeSelector.vue +91 -0
  70. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/SearchBar.vue +56 -0
  71. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/SortControl.vue +55 -0
  72. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/ActiveFilters.vue +59 -0
  73. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/DefaultFilterField.vue +63 -0
  74. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/DefaultFilterPanel.vue +31 -0
  75. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/FilterContext.ts +45 -0
  76. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/FilterProvider.vue +23 -0
  77. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/FilterResetButton.vue +17 -0
  78. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/PicklistField.vue +35 -0
  79. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/BooleanFilter.vue +47 -0
  80. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/DateRangeFilter.vue +144 -0
  81. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/FilterFieldWrapper.vue +23 -0
  82. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/MultiSelectFilter.vue +95 -0
  83. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/NumericRangeFilter.vue +117 -0
  84. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/SelectFilter.vue +44 -0
  85. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/TextFilter.vue +49 -0
  86. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/CmsResultRow.vue +160 -0
  87. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/DefaultResultRow.vue +102 -0
  88. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/RenderVNode.ts +10 -0
  89. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/resolveResultRenderer.ts +41 -0
  90. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/composables/useAsyncData.ts +66 -0
  91. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/composables/useDistinctValues.ts +67 -0
  92. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/composables/useSearch.ts +906 -0
  93. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/config.json +88 -0
  94. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/constants.ts +8 -0
  95. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/index.ts +115 -0
  96. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/loadConfig.ts +14 -0
  97. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/queryBuilder.ts +100 -0
  98. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/types.ts +375 -0
  99. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/debounce.ts +17 -0
  100. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/fieldUtils.ts +14 -0
  101. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/filterUtils.ts +304 -0
  102. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/sortUtils.ts +34 -0
  103. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/api/account/query/getAccountDetail.graphql +121 -0
  104. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/api/graphqlClient.ts +44 -0
  105. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/appLayout.vue +153 -0
  106. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/AgentforceConversationClient.vue +76 -0
  107. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/account/AccountDetailContent.vue +124 -0
  108. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/account/AccountDetailError.vue +28 -0
  109. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/account/AccountDetailNotFound.vue +22 -0
  110. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/account/AccountDetailSkeleton.vue +57 -0
  111. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/account/DetailSection.vue +25 -0
  112. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/account/FieldItem.vue +17 -0
  113. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/account/FieldRow.vue +5 -0
  114. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/account/SkeletonFieldRow.vue +12 -0
  115. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/account/TelephoneField.vue +7 -0
  116. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/account/types.ts +42 -0
  117. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/alerts/status-alert.vue +59 -0
  118. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/layouts/card-layout.vue +30 -0
  119. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/alert/Alert.vue +21 -0
  120. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/alert/AlertAction.vue +17 -0
  121. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/alert/AlertDescription.vue +22 -0
  122. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/alert/AlertTitle.vue +22 -0
  123. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/alert/index.ts +25 -0
  124. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/avatar/Avatar.vue +23 -0
  125. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/avatar/AvatarFallback.vue +31 -0
  126. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/avatar/AvatarImage.vue +16 -0
  127. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/avatar/index.ts +3 -0
  128. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/button/Button.vue +33 -0
  129. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/button/index.ts +43 -0
  130. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/card/Card.vue +29 -0
  131. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/card/CardAction.vue +22 -0
  132. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/card/CardContent.vue +17 -0
  133. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/card/CardDescription.vue +17 -0
  134. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/card/CardFooter.vue +22 -0
  135. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/card/CardHeader.vue +22 -0
  136. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/card/CardTitle.vue +22 -0
  137. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/card/index.ts +7 -0
  138. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/checkbox/Checkbox.vue +43 -0
  139. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/checkbox/index.ts +1 -0
  140. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/collapsible/Collapsible.vue +19 -0
  141. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/collapsible/CollapsibleContent.vue +12 -0
  142. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/collapsible/CollapsibleTrigger.vue +12 -0
  143. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/collapsible/index.ts +3 -0
  144. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dialog/Dialog.vue +15 -0
  145. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dialog/DialogClose.vue +12 -0
  146. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dialog/DialogContent.vue +59 -0
  147. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dialog/DialogDescription.vue +31 -0
  148. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dialog/DialogFooter.vue +33 -0
  149. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dialog/DialogHeader.vue +17 -0
  150. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dialog/DialogOverlay.vue +31 -0
  151. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dialog/DialogPortal.vue +12 -0
  152. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dialog/DialogTitle.vue +26 -0
  153. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dialog/DialogTrigger.vue +12 -0
  154. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dialog/index.ts +10 -0
  155. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenu.vue +19 -0
  156. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +51 -0
  157. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuContent.vue +47 -0
  158. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
  159. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuItem.vue +44 -0
  160. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +30 -0
  161. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuPortal.vue +12 -0
  162. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +21 -0
  163. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +52 -0
  164. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +26 -0
  165. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +19 -0
  166. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
  167. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +37 -0
  168. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +38 -0
  169. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +17 -0
  170. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/dropdown-menu/index.ts +15 -0
  171. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/field/Field.vue +27 -0
  172. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/field/FieldContent.vue +22 -0
  173. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/field/FieldDescription.vue +24 -0
  174. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/field/FieldError.vue +48 -0
  175. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/field/FieldGroup.vue +22 -0
  176. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/field/FieldLabel.vue +24 -0
  177. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/field/FieldLegend.vue +29 -0
  178. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/field/FieldSeparator.vue +31 -0
  179. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/field/FieldSet.vue +22 -0
  180. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/field/FieldTitle.vue +22 -0
  181. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/field/index.ts +33 -0
  182. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/index.ts +115 -0
  183. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/input/Input.vue +30 -0
  184. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/input/index.ts +1 -0
  185. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/label/Label.vue +29 -0
  186. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/label/index.ts +1 -0
  187. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/pagination/Pagination.vue +17 -0
  188. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/pagination/PaginationContent.vue +15 -0
  189. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/pagination/PaginationEllipsis.vue +23 -0
  190. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/pagination/PaginationItem.vue +7 -0
  191. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/pagination/PaginationLink.vue +31 -0
  192. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/pagination/PaginationNext.vue +29 -0
  193. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/pagination/PaginationPrevious.vue +29 -0
  194. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/pagination/index.ts +7 -0
  195. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/popover/Popover.vue +15 -0
  196. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/popover/PopoverAnchor.vue +12 -0
  197. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/popover/PopoverContent.vue +44 -0
  198. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/popover/PopoverDescription.vue +17 -0
  199. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/popover/PopoverHeader.vue +17 -0
  200. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/popover/PopoverTitle.vue +14 -0
  201. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/popover/PopoverTrigger.vue +12 -0
  202. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/popover/index.ts +7 -0
  203. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/select/Select.vue +15 -0
  204. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/select/SelectContent.vue +65 -0
  205. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/select/SelectGroup.vue +26 -0
  206. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/select/SelectItem.vue +41 -0
  207. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/select/SelectLabel.vue +26 -0
  208. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/select/SelectScrollDownButton.vue +32 -0
  209. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/select/SelectScrollUpButton.vue +32 -0
  210. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/select/SelectSeparator.vue +24 -0
  211. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/select/SelectTrigger.vue +45 -0
  212. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/select/SelectValue.vue +12 -0
  213. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/select/index.ts +10 -0
  214. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/separator/Separator.vue +33 -0
  215. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/separator/index.ts +1 -0
  216. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/skeleton/Skeleton.vue +15 -0
  217. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/skeleton/index.ts +1 -0
  218. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/sonner/Sonner.vue +29 -0
  219. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/sonner/index.ts +3 -0
  220. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/spinner/Spinner.vue +17 -0
  221. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/components/ui/spinner/index.ts +1 -0
  222. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/composables/useAsyncData.ts +69 -0
  223. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/index.ts +10 -0
  224. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/lib/utils.ts +6 -0
  225. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/main.ts +6 -0
  226. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/pages/AccountObjectDetailPage.vue +98 -0
  227. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/pages/Home.vue +20 -0
  228. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/pages/NotFound.vue +28 -0
  229. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/pages/SearchPage.vue +17 -0
  230. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/router-utils.ts +32 -0
  231. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/router.ts +51 -0
  232. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/styles/global.css +134 -0
  233. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/test/setup.ts +1 -0
  234. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/types/conversation.ts +54 -0
  235. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/types/globals.d.ts +13 -0
  236. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/src/utils/accountFields.ts +25 -0
  237. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/tsconfig.json +45 -0
  238. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/tsconfig.node.json +13 -0
  239. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/tsconfig.tsbuildinfo +1 -0
  240. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/ui-bundle.json +7 -0
  241. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/vite-env.d.ts +14 -0
  242. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/vite.config.ts +106 -0
  243. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/vitest-env.d.ts +2 -0
  244. package/lib/templates/project/vueinternalapp/_p_/_m_/_w_/_a_/vueinternalapp.uibundle-meta.xml +8 -0
  245. package/lib/templates/project/vueinternalapp/_p_/_m_/applications/vueinternalapp.app-meta.xml +17 -0
  246. package/lib/templates/project/vueinternalapp/config/project-scratch-def.json +13 -0
  247. package/lib/templates/project/vueinternalapp/eslint.config.js +7 -0
  248. package/lib/templates/project/vueinternalapp/jest.config.js +6 -0
  249. package/lib/templates/project/vueinternalapp/package.json +46 -0
  250. package/lib/templates/project/vueinternalapp/scripts/apex/hello.apex +10 -0
  251. package/lib/templates/project/vueinternalapp/scripts/gitignore-templates.json +4 -0
  252. package/lib/templates/project/vueinternalapp/scripts/graphql-search.sh +191 -0
  253. package/lib/templates/project/vueinternalapp/scripts/network-senders.mjs +84 -0
  254. package/lib/templates/project/vueinternalapp/scripts/org-setup-config-schema.mjs +132 -0
  255. package/lib/templates/project/vueinternalapp/scripts/org-setup-dev.mjs +114 -0
  256. package/lib/templates/project/vueinternalapp/scripts/org-setup-url.mjs +108 -0
  257. package/lib/templates/project/vueinternalapp/scripts/org-setup-utils.mjs +569 -0
  258. package/lib/templates/project/vueinternalapp/scripts/org-setup-xml.mjs +283 -0
  259. package/lib/templates/project/vueinternalapp/scripts/org-setup.config.json +9 -0
  260. package/lib/templates/project/vueinternalapp/scripts/org-setup.mjs +2545 -0
  261. package/lib/templates/project/vueinternalapp/scripts/sf-project-setup.mjs +103 -0
  262. package/lib/templates/project/vueinternalapp/scripts/soql/account.soql +6 -0
  263. package/lib/templates/project/vueinternalapp/scripts/validate-org-setup-config.mjs +38 -0
  264. package/lib/templates/project/vueinternalapp/sfdx-project.json +12 -0
  265. package/lib/templates/uiBundles/angularbasic/package-lock.json +165 -165
  266. package/lib/templates/uiBundles/reactbasic/eslint.config.js +8 -12
  267. package/lib/templates/uiBundles/reactbasic/package-lock.json +136 -136
  268. package/lib/templates/uiBundles/reactbasic/package.json +5 -5
  269. package/lib/templates/uiBundles/reactbasic/src/components/ui/button.tsx +1 -1
  270. package/lib/templates/uiBundles/reactbasic/src/components/ui/sonner.tsx +7 -1
  271. package/lib/templates/uiBundles/vuebasic/eslint.config.js +6 -1
  272. package/lib/templates/uiBundles/vuebasic/package-lock.json +143 -143
  273. package/lib/templates/uiBundles/vuebasic/package.json +5 -5
  274. package/lib/utils/types.d.ts +1 -1
  275. package/lib/utils/uiBundleTemplateUtils.js +5 -0
  276. package/lib/utils/uiBundleTemplateUtils.js.map +1 -1
  277. package/package.json +7 -6
@@ -0,0 +1,141 @@
1
+ /**
2
+ * SObject fragment builder.
3
+ *
4
+ * Extracted verbatim from `queryBuilder.ts`: `buildSelectionBody`,
5
+ * `renderField`, `buildSourceWhere`, `assertValidKey`, `KEY_PATTERN`, and the
6
+ * per-source variable/selection assembly. Emits one `QueryFragmentContribution`
7
+ * with `placement: "uiapi.query"` — the `${key}: ${objectName}(...) { … }`
8
+ * selection, its 4 per-source variable declarations, and their 4 values.
9
+ *
10
+ * Behaviour is byte-for-byte equivalent to the original inline logic; this is a
11
+ * move, not a rewrite.
12
+ *
13
+ * Selection sets are generated from `displayFields`:
14
+ * - string `"Name"` → `Name @optional { value displayValue }`
15
+ * - `{ name, raw: true }` → `Name`
16
+ * - `{ name, subfields }` → nested `Name @optional { ... }`
17
+ *
18
+ * The `idField` (default "Id") is always emitted; it is **not** wrapped
19
+ * because uiapi's Id is a scalar.
20
+ */
21
+
22
+ import {
23
+ buildFilter,
24
+ buildGlobalQueryClause,
25
+ type ActiveFilterValue,
26
+ } from "../../utils/filterUtils";
27
+ import { buildOrderBy } from "../../utils/sortUtils";
28
+ import type { DisplayField, SObjectSourceConfig } from "../../types";
29
+ import type { QueryFragmentContribution, SourceRequest } from "../types";
30
+
31
+ const KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
32
+
33
+ function assertValidKey(key: string): void {
34
+ if (!KEY_PATTERN.test(key)) {
35
+ throw new Error(
36
+ `Invalid source key "${key}". Must match /^[A-Za-z_][A-Za-z0-9_]*$/ to be a valid GraphQL alias and variable prefix.`,
37
+ );
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Combines a per-source structured-filter clause with the global-q `or` clause.
43
+ * Returns `undefined` when neither side has any constraints.
44
+ */
45
+ function buildSourceWhere(
46
+ source: SObjectSourceConfig,
47
+ q: string,
48
+ filters: ActiveFilterValue[],
49
+ ): unknown {
50
+ const clauses: unknown[] = [];
51
+ const globalClause = buildGlobalQueryClause(q, source.searchableFields);
52
+ if (globalClause) clauses.push(globalClause);
53
+ const structured = buildFilter(filters, source.filterBy ?? []);
54
+ if (structured) clauses.push(structured);
55
+ if (clauses.length === 0) return undefined;
56
+ if (clauses.length === 1) return clauses[0];
57
+ return { and: clauses };
58
+ }
59
+
60
+ function buildSelectionBody(source: SObjectSourceConfig): string {
61
+ const idField = source.idField ?? "Id";
62
+ const fieldLines = [` ${idField}`];
63
+ for (const field of source.displayFields) {
64
+ fieldLines.push(...renderField(field, " "));
65
+ }
66
+ return [
67
+ ` edges { node {`,
68
+ ...fieldLines,
69
+ ` } }`,
70
+ ` pageInfo { hasNextPage hasPreviousPage startCursor endCursor }`,
71
+ ` totalCount`,
72
+ ].join("\n");
73
+ }
74
+
75
+ function renderField(field: DisplayField, indentStr: string): string[] {
76
+ if (typeof field === "string") {
77
+ return [`${indentStr}${field} @optional { value displayValue }`];
78
+ }
79
+ if ("raw" in field) {
80
+ return [`${indentStr}${field.name}`];
81
+ }
82
+ const lines = [`${indentStr}${field.name} @optional {`];
83
+ for (const sub of field.subfields) {
84
+ lines.push(...renderField(sub, indentStr + " "));
85
+ }
86
+ lines.push(`${indentStr}}`);
87
+ return lines;
88
+ }
89
+
90
+ /**
91
+ * Builds one SObject source's `QueryFragmentContribution`.
92
+ *
93
+ * The fragment is the `${key}: ${objectName}(...) { … }` selection that lives
94
+ * inside `uiapi.query`; the 4 declarations/values are the per-source
95
+ * `first / after / where / orderBy` variables. Output matches the original
96
+ * inline builder exactly.
97
+ */
98
+ export function buildSObjectFragment(
99
+ request: SourceRequest<SObjectSourceConfig>,
100
+ ): QueryFragmentContribution {
101
+ const { source } = request;
102
+ assertValidKey(source.key);
103
+
104
+ const firstVar = `${source.key}_first`;
105
+ const afterVar = `${source.key}_after`;
106
+ const whereVar = `${source.key}_where`;
107
+ const orderByVar = `${source.key}_orderBy`;
108
+ const whereType = source.whereTypeName ?? `${source.objectName}_Filter`;
109
+ const orderByType = source.orderByTypeName ?? `${source.objectName}_OrderBy`;
110
+
111
+ const variableDeclarations = [
112
+ `$${firstVar}: Int`,
113
+ `$${afterVar}: String`,
114
+ `$${whereVar}: ${whereType}`,
115
+ `$${orderByVar}: ${orderByType}`,
116
+ ];
117
+
118
+ const fragment =
119
+ `${source.key}: ${source.objectName}(` +
120
+ `first: $${firstVar}, ` +
121
+ `after: $${afterVar}, ` +
122
+ `where: $${whereVar}, ` +
123
+ `orderBy: $${orderByVar}` +
124
+ `) {\n` +
125
+ buildSelectionBody(source) +
126
+ `\n}`;
127
+
128
+ const variables: Record<string, unknown> = {
129
+ [firstVar]: request.pageSize,
130
+ [afterVar]: request.afterCursor ?? null,
131
+ [whereVar]: buildSourceWhere(source, request.q, request.filters) ?? null,
132
+ [orderByVar]: buildOrderBy(request.sort) ?? null,
133
+ };
134
+
135
+ return {
136
+ variableDeclarations,
137
+ variables,
138
+ placement: "uiapi.query",
139
+ fragment,
140
+ };
141
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Kind-agnostic adapter contracts for unified (multi-source) search.
3
+ *
4
+ * Every searchable backend ("sobject", "cms", …) is fronted by a
5
+ * {@link SourceAdapter}. The core query builder and result parser are
6
+ * completely kind-agnostic: they dispatch to the adapter registered for a
7
+ * source's `kind`, so a new backend plugs in by adding a `kind` + an adapter,
8
+ * never by touching the common builder/parser or any consumer.
9
+ *
10
+ * - {@link SourceAdapter.buildRequest} contributes a {@link QueryFragmentContribution}
11
+ * (its GraphQL fragment, variable declarations, and variable values) that the
12
+ * builder assembles into one combined document.
13
+ * - {@link SourceAdapter.parseResponse} receives the full response `data` root
14
+ * and extracts this source's `SourceResult`, returning `null` (never
15
+ * throwing) when its own subtree is absent or errored — this is what lets
16
+ * sources fail independently (partial-failure resilience).
17
+ */
18
+
19
+ import type { SourceConfig, SourceResult } from "../types";
20
+ import type { ActiveFilterValue } from "../utils/filterUtils";
21
+ import type { SortState } from "../utils/sortUtils";
22
+
23
+ /**
24
+ * One source's contribution to the combined GraphQL document.
25
+ *
26
+ * The builder concatenates every source's `variableDeclarations` into the
27
+ * `query Search(...)` header and merges every source's `variables` into one
28
+ * flat map. Fragments are placed by `placement`:
29
+ * - `"uiapi.query"` → inside the shared `uiapi { query { … } }` block.
30
+ * - `"root"` → a sibling of `uiapi` at the document root (e.g. the CMS
31
+ * `managed_content { … }` block).
32
+ *
33
+ * A contribution MAY declare zero extra variables (e.g. the CMS bootstrap call
34
+ * omits `$cmsContentTypeFQNs` entirely). The builder handles declaration lists of
35
+ * differing lengths, so an unused/undeclared variable is never emitted.
36
+ */
37
+ export interface QueryFragmentContribution {
38
+ /** Namespaced GraphQL variable declarations, e.g. `"$cmsKeyword: String!"`. */
39
+ variableDeclarations: string[];
40
+ /** Values for the declared variables, keyed by (unprefixed) variable name. */
41
+ variables: Record<string, unknown>;
42
+ /** Where the `fragment` is spliced into the combined document. */
43
+ placement: "uiapi.query" | "root";
44
+ /** The GraphQL selection fragment (unindented; the builder indents it). */
45
+ fragment: string;
46
+ }
47
+
48
+ /**
49
+ * A per-source search request. Generic over the source config so an adapter can
50
+ * narrow to its own config kind (e.g. `SourceRequest<CmsSourceConfig>`).
51
+ *
52
+ * The base fields (`source`/`q`/`filters`/`sort`/`pageSize`/`afterCursor`) are
53
+ * kind-agnostic. The trailing fields are optional and only populated for the
54
+ * kinds that need them; the sync query builder never resolves async values, so
55
+ * anything async (e.g. the CMS UIBundle id) is resolved by the caller and
56
+ * threaded in here.
57
+ */
58
+ export interface SourceRequest<T extends SourceConfig = SourceConfig> {
59
+ /** The config for the source this request targets. */
60
+ source: T;
61
+ /** The global search term, broadcast to every source. */
62
+ q: string;
63
+ /** Active structured filters (SObject-relevant; other kinds may ignore). */
64
+ filters: ActiveFilterValue[];
65
+ /** Active sort (SObject-relevant; other kinds may ignore). */
66
+ sort: SortState | null;
67
+ /** Page size for this fetch (validated against `pageSizeOptions` upstream). */
68
+ pageSize: number;
69
+ /** Opaque forward cursor for this fetch (CMS decodes it to an offset). */
70
+ afterCursor: string | undefined;
71
+ /**
72
+ * CMS-only, optional. Present (non-null, non-empty) only when content types
73
+ * are known/selected; absent on the bootstrap call so the CMS adapter omits
74
+ * `$cmsContentTypeFQNs` entirely.
75
+ */
76
+ contentTypes?: string[] | null;
77
+ /**
78
+ * CMS-only, optional. The resolved UIBundle id fed into the CMS search
79
+ * query. Resolved by the caller (async `getUIBundleId()`) BEFORE the sync
80
+ * query builder runs, then threaded in here so `buildRequest` stays
81
+ * synchronous. Ignored by non-CMS adapters.
82
+ */
83
+ uiBundleId?: string;
84
+ /** CMS-only, optional. The current user's language tag fed to the CMS search `language` argument. */
85
+ language?: string;
86
+ }
87
+
88
+ /**
89
+ * Runtime adapter for one source `kind`. Bridges a kind-agnostic
90
+ * {@link SourceRequest} to a GraphQL fragment and back to a {@link SourceResult}.
91
+ */
92
+ export interface SourceAdapter<T extends SourceConfig = SourceConfig> {
93
+ /** The `kind` discriminator this adapter handles. */
94
+ readonly kind: T["kind"];
95
+ /** Build this source's fragment/variables contribution for the combined doc. */
96
+ buildRequest(request: SourceRequest<T>): QueryFragmentContribution;
97
+ /**
98
+ * Extract this source's result from the full response `data` root. Returns
99
+ * `null` when the source's own subtree is absent or errored — never throws
100
+ * for a partial failure.
101
+ */
102
+ parseResponse(root: Record<string, unknown>, request: SourceRequest<T>): SourceResult | null;
103
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Fetches distinct values for a picklist field via the uiapi aggregate
3
+ * `groupBy` query.
4
+ *
5
+ * Used by the auto-render pathway when a picklist filter does not declare
6
+ * inline `options`. Each call hits the GraphQL endpoint once and returns the
7
+ * sorted set of distinct values plus their display labels.
8
+ */
9
+
10
+ import { createDataSDK } from "@salesforce/platform-sdk";
11
+
12
+ export interface PicklistOption {
13
+ value: string;
14
+ label: string;
15
+ }
16
+
17
+ const KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
18
+
19
+ function assertValidIdentifier(name: string, kind: string): void {
20
+ if (!KEY_PATTERN.test(name)) {
21
+ throw new Error(
22
+ `Invalid ${kind} "${name}". Must match /^[A-Za-z_][A-Za-z0-9_]*$/ to be a valid GraphQL identifier.`,
23
+ );
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Builds and executes a `uiapi.aggregate.<objectName>(groupBy: { <field>: { group: true } })`
29
+ * query and extracts the distinct values.
30
+ */
31
+ export async function fetchDistinctValues(
32
+ objectName: string,
33
+ fieldName: string,
34
+ ): Promise<PicklistOption[]> {
35
+ assertValidIdentifier(objectName, "objectName");
36
+ assertValidIdentifier(fieldName, "fieldName");
37
+
38
+ const document = `query DistinctValues {
39
+ uiapi {
40
+ aggregate {
41
+ ${objectName}(groupBy: { ${fieldName}: { group: true } }) {
42
+ edges {
43
+ node {
44
+ aggregate @optional {
45
+ ${fieldName} @optional {
46
+ value
47
+ displayValue
48
+ label
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
56
+ }`;
57
+
58
+ const data = await createDataSDK();
59
+ const response = await data.graphql!.query<unknown>({ query: document });
60
+
61
+ if (response.errors?.length) {
62
+ throw new Error(response.errors.map((e) => e.message).join("; "));
63
+ }
64
+
65
+ const root = response.data as Record<string, unknown> | undefined;
66
+ const aggregate = (root?.uiapi as Record<string, unknown> | undefined)?.aggregate as
67
+ Record<string, unknown> | undefined;
68
+ const objectAgg = aggregate?.[objectName] as
69
+ { edges?: Array<{ node?: { aggregate?: Record<string, unknown> } }> } | undefined;
70
+ const edges = objectAgg?.edges ?? [];
71
+
72
+ return edges
73
+ .map((edge) => {
74
+ const field = edge?.node?.aggregate?.[fieldName] as
75
+ { value?: string | null; displayValue?: string | null; label?: string | null } | undefined;
76
+ const value = field?.value;
77
+ if (value == null || value === "") return null;
78
+ return { value, label: field?.label ?? field?.displayValue ?? value };
79
+ })
80
+ .filter((opt): opt is PicklistOption => opt !== null);
81
+ }
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Executes a combined search request and parses each source's subtree via its
3
+ * adapter, with partial-failure resilience.
4
+ *
5
+ * The combined GraphQL response can carry BOTH partial `data` AND `errors`
6
+ * (`uiapi` and CMS `managed_content` are independent roots). Rather than
7
+ * throwing on `response.errors`, we parse each source through
8
+ * `getAdapter(kind).parseResponse(root, req)`:
9
+ * - a `SourceResult` → recorded in `results[key]`.
10
+ * - `null` (subtree absent/errored) → the source produced no data; if the
11
+ * request as a whole reported GraphQL errors, an attributed message is
12
+ * recorded in `errors[key]` so the UI can show a per-source error while
13
+ * sibling sources still render.
14
+ *
15
+ * Only a whole-request failure — the SDK call rejecting, or a response with no
16
+ * `data` at all — throws, so `useSearch` surfaces it as a page-level error
17
+ * (preserving the original network-failure behaviour).
18
+ */
19
+
20
+ import { createDataSDK } from "@salesforce/platform-sdk";
21
+ import { buildSearchQuery } from "../queryBuilder";
22
+ import { getAdapter } from "../adapters/registry";
23
+ import type { SourceRequest } from "../adapters/types";
24
+ import type { SourceResult } from "../types";
25
+
26
+ /**
27
+ * The outcome of a combined `runSearch`: successfully-parsed results plus a
28
+ * per-source error map. `errors` is keyed by `source.key` and only carries an
29
+ * entry for a source that failed to produce data (its subtree was absent or
30
+ * errored). A source appears in at most one of `results` / `errors`.
31
+ */
32
+ export interface RunSearchOutcome {
33
+ results: Record<string, SourceResult>;
34
+ errors: Record<string, string>;
35
+ }
36
+
37
+ /** Minimal shape of a GraphQL error we can attribute to a source by path. */
38
+ interface GraphQLErrorLike {
39
+ message?: string | null;
40
+ path?: Array<string | number> | null;
41
+ }
42
+
43
+ /**
44
+ * Attributes GraphQL errors to a source by matching the error `path` against
45
+ * the source's location in the document:
46
+ * - SObject aliases live under `uiapi.query.<key>`.
47
+ * - CMS lives under the root `managed_content` block.
48
+ *
49
+ * Returns the joined messages whose `path` matches `request`. When NO path
50
+ * matches (or paths are absent), returns a GENERIC per-source message rather
51
+ * than echoing unrelated sources' messages — otherwise one source could display
52
+ * another's error text (over-broad cross-attribution). The whole-request
53
+ * (`data == null`) path still joins ALL error messages; that lives in
54
+ * `runSearch` and is unaffected.
55
+ */
56
+ function attributeError(request: SourceRequest, errors: GraphQLErrorLike[]): string {
57
+ const kind = request.source.kind;
58
+ const key = request.source.key;
59
+
60
+ const matched = errors.filter((e) => {
61
+ const path = e.path;
62
+ if (!path || path.length === 0) return false;
63
+ if (kind === "cms") {
64
+ return path[0] === "managed_content";
65
+ }
66
+ // SObject: uiapi -> query -> <key>
67
+ return path[0] === "uiapi" && path[1] === "query" && path[2] === key;
68
+ });
69
+
70
+ // No path matched this source: don't leak sibling sources' messages — fall
71
+ // back to a generic per-source explanation.
72
+ if (matched.length === 0) {
73
+ return "Search failed for this source.";
74
+ }
75
+
76
+ const message = matched
77
+ .map((e) => e.message)
78
+ .filter((m): m is string => !!m)
79
+ .join("; ");
80
+ return message || "Search failed for this source.";
81
+ }
82
+
83
+ /**
84
+ * Runs one combined multi-source GraphQL request. Returns `{ results, errors }`
85
+ * (never throws on partial GraphQL errors); throws only on a whole-request /
86
+ * network failure.
87
+ */
88
+ export async function runSearch(requests: SourceRequest[]): Promise<RunSearchOutcome> {
89
+ const { document, variables } = buildSearchQuery(requests);
90
+
91
+ const data = await createDataSDK();
92
+ const response = await data.graphql!.query<unknown, Record<string, unknown>>({
93
+ query: document,
94
+ variables,
95
+ });
96
+
97
+ const root = response.data as Record<string, unknown> | undefined;
98
+ const gqlErrors = (response.errors ?? []) as GraphQLErrorLike[];
99
+
100
+ // Whole-request failure: no data at all. Surface as a page-level error
101
+ // (preserves the original network-failure behaviour).
102
+ if (root == null) {
103
+ const message = gqlErrors
104
+ .map((e) => e.message)
105
+ .filter((m): m is string => !!m)
106
+ .join("; ");
107
+ throw new Error(message || "Unified search failed");
108
+ }
109
+
110
+ const results: Record<string, SourceResult> = {};
111
+ const errors: Record<string, string> = {};
112
+
113
+ for (const request of requests) {
114
+ const key = request.source.key;
115
+ let parsed: SourceResult | null = null;
116
+ try {
117
+ parsed = getAdapter(request.source.kind).parseResponse(root, request);
118
+ } catch {
119
+ // An adapter that throws while parsing its own subtree is a
120
+ // per-source failure, not a page-level one.
121
+ parsed = null;
122
+ }
123
+
124
+ if (parsed != null) {
125
+ results[key] = parsed;
126
+ } else if (gqlErrors.length > 0) {
127
+ // No data for this source AND the request reported errors — attribute
128
+ // a message so the UI can show a per-source error.
129
+ errors[key] = attributeError(request, gqlErrors);
130
+ }
131
+ // else: no data and no errors — the source simply returned nothing;
132
+ // leave it absent from both maps (empty result, no error).
133
+ }
134
+
135
+ return { results, errors };
136
+ }
@@ -0,0 +1,18 @@
1
+ /** Props for `<GlobalSearchBox>` (kept in a .ts module so plain `tsc` can import the type). */
2
+ export interface GlobalSearchBoxProps {
3
+ /** Optional CSS class for container styling/placement. */
4
+ class?: string;
5
+ /** Placeholder text for the search input. */
6
+ placeholder?: string;
7
+ /** Whether the input should autofocus on mount. */
8
+ autoFocus?: boolean;
9
+ /** Accessible (screen-reader) label for the input. Exposed for localization. */
10
+ label?: string;
11
+ /** Visible text for the submit button. Exposed for localization. */
12
+ submitLabel?: string;
13
+ /**
14
+ * Minimum length of keyword required by search. `{min}` is replaced with
15
+ * MIN_QUERY_LENGTH. Exposed for localization.
16
+ */
17
+ minLengthHint?: string;
18
+ }
@@ -0,0 +1,73 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * GlobalSearchBox — pure launcher component for global search.
4
+ *
5
+ * A self-contained search input + button that navigates to `/search?q=...`
6
+ * when the user submits a query of at least MIN_QUERY_LENGTH characters.
7
+ *
8
+ * Props are purely cosmetic (class, placeholder, autoFocus, localization
9
+ * strings) — all behavior (the gate, the route, the query key) is owned by this
10
+ * component, not the caller.
11
+ *
12
+ * Usage:
13
+ * <GlobalSearchBox class="mb-8" placeholder="Search everything..." />
14
+ */
15
+ import { computed, onMounted, ref, useId, useTemplateRef } from "vue";
16
+ import { useRouter } from "vue-router";
17
+ import { Search } from "@lucide/vue";
18
+ import { Input } from "../../../components/ui/input";
19
+ import { Button } from "../../../components/ui/button";
20
+ import { GLOBAL_QUERY_KEY } from "../utils/filterUtils";
21
+ import { MIN_QUERY_LENGTH } from "../constants";
22
+ import type { GlobalSearchBoxProps } from "./GlobalSearchBox.types";
23
+
24
+ const props = withDefaults(defineProps<GlobalSearchBoxProps>(), {
25
+ placeholder: "Search…",
26
+ label: "Search",
27
+ submitLabel: "Search",
28
+ minLengthHint: "Enter at least {min} characters to search.",
29
+ });
30
+
31
+ const router = useRouter();
32
+ const text = ref("");
33
+ const inputId = useId();
34
+ const hintId = useId();
35
+ const inputRef = useTemplateRef<{ $el: HTMLInputElement }>("inputRef");
36
+
37
+ onMounted(() => {
38
+ if (props.autoFocus) inputRef.value?.$el?.focus();
39
+ });
40
+
41
+ const canSearch = computed(() => text.value.trim().length >= MIN_QUERY_LENGTH);
42
+ const hintText = computed(() => props.minLengthHint.replace("{min}", String(MIN_QUERY_LENGTH)));
43
+
44
+ const handleSubmit = () => {
45
+ if (!canSearch.value) return;
46
+ void router.push(`/search?${GLOBAL_QUERY_KEY}=${encodeURIComponent(text.value.trim())}`);
47
+ };
48
+ </script>
49
+
50
+ <template>
51
+ <form :class="$props.class" role="search" @submit.prevent="handleSubmit">
52
+ <label :for="inputId" class="sr-only">{{ label }}</label>
53
+ <div class="flex gap-2">
54
+ <div class="relative flex-1">
55
+ <Search
56
+ aria-hidden="true"
57
+ class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"
58
+ />
59
+ <Input
60
+ :id="inputId"
61
+ ref="inputRef"
62
+ v-model="text"
63
+ type="text"
64
+ :placeholder="placeholder"
65
+ class="pl-9"
66
+ :aria-describedby="hintId"
67
+ />
68
+ </div>
69
+ <Button type="submit" :disabled="!canSearch">{{ submitLabel }}</Button>
70
+ </div>
71
+ <p :id="hintId" class="sr-only">{{ hintText }}</p>
72
+ </form>
73
+ </template>
@@ -0,0 +1,24 @@
1
+ /** Props for `<MergedSearchResults>` (kept in a .ts module so plain `tsc` can import the type). */
2
+ import type { SearchHandle } from "../types";
3
+ import type { ResultRenderer } from "./results/resolveResultRenderer";
4
+
5
+ export interface MergedSearchResultsProps {
6
+ handle: SearchHandle;
7
+ /**
8
+ * Per source key: how to render one node in the merged grid. Falls back to
9
+ * the built-in default row for any source without an entry. Pass `false` to
10
+ * skip a source's cards entirely. The `#result` scoped slot is the
11
+ * alternative for all sources.
12
+ */
13
+ renderResult?: Record<string, ResultRenderer>;
14
+ /** Message shown when there are no results. Defaults to "No results found." */
15
+ emptyMessage?: string;
16
+ /** Message shown when the query is below MIN_QUERY_LENGTH. Defaults to "Start your search…" */
17
+ shortQueryMessage?: string;
18
+ /** Number of skeleton placeholders to show while loading. Defaults to `pageSize`. */
19
+ skeletonCount?: number;
20
+ /** Extra classes on the grid container. Defaults to a responsive 1/2/3-column grid. */
21
+ gridClassName?: string;
22
+ /** Extra classes on the outer wrapper. */
23
+ class?: string;
24
+ }