@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,63 @@
1
+ <script setup lang="ts">
2
+ import TextFilter from "./inputs/TextFilter.vue";
3
+ import NumericRangeFilter from "./inputs/NumericRangeFilter.vue";
4
+ import BooleanFilter from "./inputs/BooleanFilter.vue";
5
+ import DateRangeFilter from "./inputs/DateRangeFilter.vue";
6
+ import PicklistField from "./PicklistField.vue";
7
+ import type { FilterFieldConfig } from "../../utils/filterUtils";
8
+ import type { SObjectSourceConfig } from "../../types";
9
+
10
+ defineProps<{ filter: FilterFieldConfig; source: SObjectSourceConfig }>();
11
+ </script>
12
+
13
+ <template>
14
+ <TextFilter
15
+ v-if="filter.type === 'text'"
16
+ :field="filter.field"
17
+ :label="filter.label"
18
+ :placeholder="filter.placeholder"
19
+ :help-text="filter.helpText"
20
+ />
21
+ <PicklistField
22
+ v-else-if="filter.type === 'picklist'"
23
+ :filter="filter"
24
+ :source="source"
25
+ :multi="false"
26
+ />
27
+ <PicklistField
28
+ v-else-if="filter.type === 'multipicklist'"
29
+ :filter="filter"
30
+ :source="source"
31
+ :multi="true"
32
+ />
33
+ <NumericRangeFilter
34
+ v-else-if="filter.type === 'numeric'"
35
+ :field="filter.field"
36
+ :label="filter.label"
37
+ :help-text="filter.helpText"
38
+ :min="filter.min"
39
+ :max="filter.max"
40
+ />
41
+ <BooleanFilter
42
+ v-else-if="filter.type === 'boolean'"
43
+ :field="filter.field"
44
+ :label="filter.label"
45
+ :help-text="filter.helpText"
46
+ />
47
+ <DateRangeFilter
48
+ v-else-if="filter.type === 'date' || filter.type === 'daterange'"
49
+ :field="filter.field"
50
+ :label="filter.label"
51
+ :help-text="filter.helpText"
52
+ filter-type="daterange"
53
+ :mode="filter.dateMode"
54
+ />
55
+ <DateRangeFilter
56
+ v-else-if="filter.type === 'datetime' || filter.type === 'datetimerange'"
57
+ :field="filter.field"
58
+ :label="filter.label"
59
+ :help-text="filter.helpText"
60
+ filter-type="datetimerange"
61
+ :mode="filter.dateMode"
62
+ />
63
+ </template>
@@ -0,0 +1,31 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Default filter panel used when no custom filters are supplied for a source.
4
+ *
5
+ * Renders one input per entry in `source.filterBy`, picking the right
6
+ * component for each `FilterFieldType`:
7
+ *
8
+ * - text -> TextFilter
9
+ * - picklist -> SelectFilter (inline options or auto-fetched)
10
+ * - multipicklist -> MultiSelectFilter (inline options or auto-fetched)
11
+ * - numeric -> NumericRangeFilter
12
+ * - boolean -> BooleanFilter
13
+ * - date / daterange / datetime / datetimerange -> DateRangeFilter
14
+ * (its Between / After / Before chrome is chosen by `filter.dateMode`)
15
+ */
16
+ import type { SObjectSourceConfig } from "../../types";
17
+ import DefaultFilterField from "./DefaultFilterField.vue";
18
+
19
+ defineProps<{ source: SObjectSourceConfig }>();
20
+ </script>
21
+
22
+ <template>
23
+ <template v-if="(source.filterBy ?? []).length > 0">
24
+ <DefaultFilterField
25
+ v-for="filter in source.filterBy"
26
+ :key="filter.field"
27
+ :filter="filter"
28
+ :source="source"
29
+ />
30
+ </template>
31
+ </template>
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Filter context for custom filter UIs. `<FilterProvider>` provides the active
3
+ * filters plus change/remove/reset callbacks; `useFilterField` and
4
+ * `useFilterPanel` read them from any descendant.
5
+ */
6
+ import {
7
+ computed,
8
+ inject,
9
+ toValue,
10
+ type ComputedRef,
11
+ type InjectionKey,
12
+ type MaybeRefOrGetter,
13
+ } from "vue";
14
+ import type { ActiveFilterValue } from "../../utils/filterUtils";
15
+
16
+ export interface FilterContextValue {
17
+ filters: ComputedRef<ActiveFilterValue[]>;
18
+ onFilterChange: (field: string, value: ActiveFilterValue | undefined) => void;
19
+ onFilterRemove: (field: string) => void;
20
+ onReset: () => void;
21
+ }
22
+
23
+ export const FILTER_CONTEXT_KEY: InjectionKey<FilterContextValue> = Symbol("search-filter-context");
24
+
25
+ function useFilterContext(): FilterContextValue {
26
+ const ctx = inject(FILTER_CONTEXT_KEY, null);
27
+ if (!ctx) throw new Error("useFilterField must be used within a FilterProvider");
28
+ return ctx;
29
+ }
30
+
31
+ export function useFilterField(field: MaybeRefOrGetter<string>) {
32
+ const { filters, onFilterChange, onFilterRemove } = useFilterContext();
33
+ const value = computed(() => filters.value.find((f) => f.field === toValue(field)));
34
+ const onChange = (next: ActiveFilterValue | undefined) => {
35
+ const name = toValue(field);
36
+ if (next) onFilterChange(name, next);
37
+ else onFilterRemove(name);
38
+ };
39
+ return { value, onChange };
40
+ }
41
+
42
+ export function useFilterPanel() {
43
+ const { filters, onReset } = useFilterContext();
44
+ return { hasActiveFilters: computed(() => filters.value.length > 0), resetAll: onReset };
45
+ }
@@ -0,0 +1,23 @@
1
+ <script setup lang="ts">
2
+ import { computed, provide } from "vue";
3
+ import type { ActiveFilterValue } from "../../utils/filterUtils";
4
+ import { FILTER_CONTEXT_KEY } from "./FilterContext";
5
+
6
+ const props = defineProps<{ filters: ActiveFilterValue[] }>();
7
+ const emit = defineEmits<{
8
+ filterChange: [field: string, value: ActiveFilterValue | undefined];
9
+ filterRemove: [field: string];
10
+ reset: [];
11
+ }>();
12
+
13
+ provide(FILTER_CONTEXT_KEY, {
14
+ filters: computed(() => props.filters),
15
+ onFilterChange: (field, value) => emit("filterChange", field, value),
16
+ onFilterRemove: (field) => emit("filterRemove", field),
17
+ onReset: () => emit("reset"),
18
+ });
19
+ </script>
20
+
21
+ <template>
22
+ <slot />
23
+ </template>
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import { Button } from "../../../../components/ui/button";
3
+ import { useFilterPanel } from "./FilterContext";
4
+
5
+ const { hasActiveFilters, resetAll } = useFilterPanel();
6
+ </script>
7
+
8
+ <template>
9
+ <Button
10
+ v-if="hasActiveFilters"
11
+ aria-label="Reset filters"
12
+ variant="destructive"
13
+ @click="resetAll"
14
+ >
15
+ <slot>Reset</slot>
16
+ </Button>
17
+ </template>
@@ -0,0 +1,35 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Resolves picklist options from inline config first; falls back to fetching
4
+ * distinct values from the GraphQL aggregate API.
5
+ */
6
+ import { computed } from "vue";
7
+ import { useDistinctValues } from "../../composables/useDistinctValues";
8
+ import SelectFilter from "./inputs/SelectFilter.vue";
9
+ import MultiSelectFilter from "./inputs/MultiSelectFilter.vue";
10
+ import type { FilterFieldConfig } from "../../utils/filterUtils";
11
+ import type { SObjectSourceConfig } from "../../types";
12
+
13
+ const props = defineProps<{
14
+ filter: FilterFieldConfig;
15
+ source: SObjectSourceConfig;
16
+ multi: boolean;
17
+ }>();
18
+
19
+ const fetched = useDistinctValues(() =>
20
+ props.filter.options
21
+ ? null
22
+ : { objectName: props.source.objectName, fieldName: props.filter.field },
23
+ );
24
+ const options = computed(() => props.filter.options ?? fetched.value ?? []);
25
+ </script>
26
+
27
+ <template>
28
+ <component
29
+ :is="multi ? MultiSelectFilter : SelectFilter"
30
+ :field="filter.field"
31
+ :label="filter.label"
32
+ :options="options"
33
+ :help-text="filter.helpText"
34
+ />
35
+ </template>
@@ -0,0 +1,47 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ Select,
4
+ SelectContent,
5
+ SelectItem,
6
+ SelectTrigger,
7
+ SelectValue,
8
+ } from "../../../../../components/ui/select";
9
+ import { useFilterField } from "../FilterContext";
10
+ import FilterFieldWrapper from "./FilterFieldWrapper.vue";
11
+
12
+ const ANY_VALUE = "__any__";
13
+
14
+ const props = withDefaults(
15
+ defineProps<{
16
+ field: string;
17
+ label: string;
18
+ trueLabel?: string;
19
+ falseLabel?: string;
20
+ helpText?: string;
21
+ }>(),
22
+ { trueLabel: "Yes", falseLabel: "No" },
23
+ );
24
+
25
+ const { value, onChange } = useFilterField(() => props.field);
26
+ const id = `filter-${props.field}`;
27
+
28
+ const onValueChange = (v: unknown) => {
29
+ if (v === ANY_VALUE) onChange(undefined);
30
+ else onChange({ field: props.field, label: props.label, type: "boolean", value: String(v) });
31
+ };
32
+ </script>
33
+
34
+ <template>
35
+ <FilterFieldWrapper :label="label" :html-for="id" :help-text="helpText">
36
+ <Select :model-value="value?.value ?? ANY_VALUE" @update:model-value="onValueChange">
37
+ <SelectTrigger :id="id" class="w-full">
38
+ <SelectValue />
39
+ </SelectTrigger>
40
+ <SelectContent>
41
+ <SelectItem :value="ANY_VALUE">Any</SelectItem>
42
+ <SelectItem value="true">{{ trueLabel }}</SelectItem>
43
+ <SelectItem value="false">{{ falseLabel }}</SelectItem>
44
+ </SelectContent>
45
+ </Select>
46
+ </FilterFieldWrapper>
47
+ </template>
@@ -0,0 +1,144 @@
1
+ <script setup lang="ts">
2
+ import { ref } from "vue";
3
+ import { Input } from "../../../../../components/ui/input";
4
+ import {
5
+ Select,
6
+ SelectContent,
7
+ SelectItem,
8
+ SelectTrigger,
9
+ SelectValue,
10
+ } from "../../../../../components/ui/select";
11
+ import { useFilterField } from "../FilterContext";
12
+ import FilterFieldWrapper from "./FilterFieldWrapper.vue";
13
+ import type {
14
+ ActiveFilterValue,
15
+ DateFilterMode,
16
+ FilterFieldType,
17
+ } from "../../../utils/filterUtils";
18
+
19
+ /**
20
+ * A date constraint whose chrome is driven by `mode`:
21
+ * - "range": a single Between control (two date inputs).
22
+ * - "comparison" (default): an After / Before selector with one input.
23
+ * - "both": a Between / After / Before selector spanning the two.
24
+ * They map onto the `min`/`max` bounds the query builder understands
25
+ * (after -> min only, before -> max only, between -> both).
26
+ */
27
+ type DateOperator = "between" | "after" | "before";
28
+
29
+ const props = withDefaults(
30
+ defineProps<{
31
+ field: string;
32
+ label: string;
33
+ helpText?: string;
34
+ /** "daterange" (Date scalar) or "datetimerange" (DateTime scalar). */
35
+ filterType?: Extract<FilterFieldType, "daterange" | "datetimerange">;
36
+ /** Which comparison chrome to show. See DateFilterMode. */
37
+ mode?: DateFilterMode;
38
+ }>(),
39
+ { filterType: "daterange", mode: "comparison" },
40
+ );
41
+
42
+ const OPERATOR_LABELS: Record<DateOperator, string> = {
43
+ between: "Between",
44
+ after: "After",
45
+ before: "Before",
46
+ };
47
+
48
+ const MODE_OPERATORS: Record<DateFilterMode, DateOperator[]> = {
49
+ range: ["between"],
50
+ comparison: ["after", "before"],
51
+ both: ["between", "after", "before"],
52
+ };
53
+
54
+ /** Pick the operator implied by an already-active filter (e.g. restored from the URL). */
55
+ function operatorFor(value: ActiveFilterValue | undefined): DateOperator {
56
+ const hasMin = !!value?.min;
57
+ const hasMax = !!value?.max;
58
+ if (hasMax && !hasMin) return "before";
59
+ if (hasMin && !hasMax) return "after";
60
+ return "between";
61
+ }
62
+
63
+ const { value, onChange } = useFilterField(() => props.field);
64
+ const operators = MODE_OPERATORS[props.mode];
65
+
66
+ // Operator is local UI state: it must survive a moment where no date is yet
67
+ // entered (which clears the active filter), so it can't be derived from `value`.
68
+ const restored = operatorFor(value.value);
69
+ const operator = ref<DateOperator>(operators.includes(restored) ? restored : operators[0]);
70
+
71
+ const emitValue = (nextMin: string | undefined, nextMax: string | undefined) => {
72
+ if (!nextMin && !nextMax) onChange(undefined);
73
+ else
74
+ onChange({
75
+ field: props.field,
76
+ label: props.label,
77
+ type: props.filterType,
78
+ min: nextMin,
79
+ max: nextMax,
80
+ });
81
+ };
82
+
83
+ const changeOperator = (next: unknown) => {
84
+ const op = next as DateOperator;
85
+ operator.value = op;
86
+ // Re-emit, keeping only the bound(s) the new operator uses.
87
+ if (op === "after") emitValue(value.value?.min, undefined);
88
+ else if (op === "before") emitValue(undefined, value.value?.max);
89
+ else emitValue(value.value?.min, value.value?.max);
90
+ };
91
+
92
+ const str = (v: string | number | undefined) =>
93
+ v === undefined || v === "" ? undefined : String(v);
94
+ const operatorId = `filter-${props.field}-op`;
95
+ // A lone "between" operator (mode="range") needs no selector — it can't change.
96
+ const showSelector = operators.length > 1;
97
+ </script>
98
+
99
+ <template>
100
+ <FilterFieldWrapper :label="label" :help-text="helpText">
101
+ <div class="flex flex-col gap-2">
102
+ <Select v-if="showSelector" :model-value="operator" @update:model-value="changeOperator">
103
+ <SelectTrigger :id="operatorId" class="w-full" :aria-label="`${label} comparison`">
104
+ <SelectValue />
105
+ </SelectTrigger>
106
+ <SelectContent>
107
+ <SelectItem v-for="op in operators" :key="op" :value="op">{{
108
+ OPERATOR_LABELS[op]
109
+ }}</SelectItem>
110
+ </SelectContent>
111
+ </Select>
112
+
113
+ <div v-if="operator === 'between'" class="flex items-center gap-2">
114
+ <Input
115
+ type="date"
116
+ :model-value="value?.min ?? ''"
117
+ :aria-label="`${label} from`"
118
+ @update:model-value="(v) => emitValue(str(v), value?.max)"
119
+ />
120
+ <span class="text-sm text-muted-foreground">–</span>
121
+ <Input
122
+ type="date"
123
+ :model-value="value?.max ?? ''"
124
+ :aria-label="`${label} to`"
125
+ @update:model-value="(v) => emitValue(value?.min, str(v))"
126
+ />
127
+ </div>
128
+ <Input
129
+ v-else-if="operator === 'after'"
130
+ type="date"
131
+ :model-value="value?.min ?? ''"
132
+ :aria-label="`${label} after`"
133
+ @update:model-value="(v) => emitValue(str(v), undefined)"
134
+ />
135
+ <Input
136
+ v-else
137
+ type="date"
138
+ :model-value="value?.max ?? ''"
139
+ :aria-label="`${label} before`"
140
+ @update:model-value="(v) => emitValue(undefined, str(v))"
141
+ />
142
+ </div>
143
+ </FilterFieldWrapper>
144
+ </template>
@@ -0,0 +1,23 @@
1
+ <script setup lang="ts">
2
+ import { Label } from "../../../../../components/ui/label";
3
+
4
+ defineProps<{
5
+ label: string;
6
+ htmlFor?: string;
7
+ errorId?: string;
8
+ helpText?: string;
9
+ error?: string;
10
+ class?: string;
11
+ }>();
12
+ </script>
13
+
14
+ <template>
15
+ <div :class="['space-y-1', $props.class]">
16
+ <Label :for="htmlFor">{{ label }}</Label>
17
+ <slot />
18
+ <div class="min-h-4">
19
+ <p v-if="error" :id="errorId" role="alert" class="text-xs text-destructive">{{ error }}</p>
20
+ <p v-else-if="helpText" class="text-xs text-muted-foreground">{{ helpText }}</p>
21
+ </div>
22
+ </div>
23
+ </template>
@@ -0,0 +1,95 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+ import { ChevronDown } from "@lucide/vue";
4
+ import { Button } from "../../../../../components/ui/button";
5
+ import { Checkbox } from "../../../../../components/ui/checkbox";
6
+ import { Label } from "../../../../../components/ui/label";
7
+ import {
8
+ Popover,
9
+ PopoverContent,
10
+ PopoverTrigger,
11
+ } from "../../../../../components/ui/popover";
12
+ import { useFilterField } from "../FilterContext";
13
+ import FilterFieldWrapper from "./FilterFieldWrapper.vue";
14
+
15
+ const props = defineProps<{
16
+ field: string;
17
+ label: string;
18
+ options: Array<{ value: string; label: string }>;
19
+ helpText?: string;
20
+ }>();
21
+
22
+ const { value, onChange } = useFilterField(() => props.field);
23
+ const selected = computed(
24
+ () => new Set(value.value?.value ? value.value.value.split(",").filter(Boolean) : []),
25
+ );
26
+
27
+ const toggle = (v: string, on: boolean) => {
28
+ const next = new Set(selected.value);
29
+ if (on) next.add(v);
30
+ else next.delete(v);
31
+ const joined = Array.from(next).join(",");
32
+ if (joined === "") onChange(undefined);
33
+ else onChange({ field: props.field, label: props.label, type: "multipicklist", value: joined });
34
+ };
35
+
36
+ // Summarize the selection on the collapsed trigger: the sole label when one is
37
+ // picked, a count when several are, and a placeholder when none.
38
+ const summary = computed(() => {
39
+ const size = selected.value.size;
40
+ if (size === 0) return `Select ${props.label.toLowerCase()}`;
41
+ if (size === 1) {
42
+ return props.options.find((o) => selected.value.has(o.value))?.label ?? `${size} selected`;
43
+ }
44
+ return `${size} selected`;
45
+ });
46
+ const triggerId = `filter-${props.field}`;
47
+ </script>
48
+
49
+ <template>
50
+ <FilterFieldWrapper :label="label" :html-for="triggerId" :help-text="helpText">
51
+ <Popover>
52
+ <PopoverTrigger as-child>
53
+ <Button
54
+ :id="triggerId"
55
+ variant="outline"
56
+ class="w-full justify-between font-normal"
57
+ :aria-label="`${label}: ${summary}`"
58
+ >
59
+ <span :class="['truncate', selected.size === 0 ? 'text-foreground/70' : '']">{{
60
+ summary
61
+ }}</span>
62
+ <ChevronDown class="ml-2 size-4 shrink-0 opacity-50" aria-hidden="true" />
63
+ </Button>
64
+ </PopoverTrigger>
65
+ <PopoverContent
66
+ align="start"
67
+ :aria-label="label"
68
+ class="w-(--reka-popover-trigger-width) max-h-72 overflow-y-auto"
69
+ >
70
+ <div role="group" class="flex flex-col gap-1">
71
+ <p v-if="options.length === 0" class="px-1 py-2 text-sm text-muted-foreground">
72
+ No options available.
73
+ </p>
74
+ <template v-else>
75
+ <div v-for="opt in options" :key="opt.value" class="flex items-center gap-2">
76
+ <Checkbox
77
+ :id="`filter-${field}-${opt.value}`"
78
+ :model-value="selected.has(opt.value)"
79
+ @update:model-value="
80
+ (checked: boolean | 'indeterminate') => toggle(opt.value, checked === true)
81
+ "
82
+ />
83
+ <Label
84
+ :for="`filter-${field}-${opt.value}`"
85
+ class="text-sm font-normal cursor-pointer"
86
+ >
87
+ {{ opt.label }}
88
+ </Label>
89
+ </div>
90
+ </template>
91
+ </div>
92
+ </PopoverContent>
93
+ </Popover>
94
+ </FilterFieldWrapper>
95
+ </template>
@@ -0,0 +1,117 @@
1
+ <script setup lang="ts">
2
+ import { computed, ref, useId, watch } from "vue";
3
+ import { Input } from "../../../../../components/ui/input";
4
+ import { useFilterField } from "../FilterContext";
5
+ import FilterFieldWrapper from "./FilterFieldWrapper.vue";
6
+ import { debounce, FILTER_DEBOUNCE_MS } from "../../../utils/debounce";
7
+
8
+ const props = defineProps<{
9
+ field: string;
10
+ label: string;
11
+ helpText?: string;
12
+ min?: number;
13
+ max?: number;
14
+ }>();
15
+
16
+ const { value, onChange } = useFilterField(() => props.field);
17
+ const errorId = useId();
18
+ const draftMin = ref<string>(value.value?.min ?? "");
19
+ const draftMax = ref<string>(value.value?.max ?? "");
20
+
21
+ const emitDebounced = debounce((nextMin: string, nextMax: string) => {
22
+ if (!nextMin && !nextMax) onChange(undefined);
23
+ else
24
+ onChange({
25
+ field: props.field,
26
+ label: props.label,
27
+ type: "numeric",
28
+ min: nextMin || undefined,
29
+ max: nextMax || undefined,
30
+ });
31
+ }, FILTER_DEBOUNCE_MS);
32
+
33
+ watch(
34
+ () => [value.value?.min, value.value?.max],
35
+ ([nextMin, nextMax]) => {
36
+ draftMin.value = nextMin ?? "";
37
+ draftMax.value = nextMax ?? "";
38
+ },
39
+ );
40
+
41
+ const isOutOfBounds = (v: string) => {
42
+ if (v === "") return false;
43
+ const n = Number(v);
44
+ return (props.min != null && n < props.min) || (props.max != null && n > props.max);
45
+ };
46
+ const minOutOfBounds = computed(() => isOutOfBounds(draftMin.value));
47
+ const maxOutOfBounds = computed(() => isOutOfBounds(draftMax.value));
48
+ const isRangeInverted = computed(
49
+ () =>
50
+ draftMin.value !== "" &&
51
+ draftMax.value !== "" &&
52
+ Number(draftMin.value) > Number(draftMax.value),
53
+ );
54
+ const hasError = computed(
55
+ () => minOutOfBounds.value || maxOutOfBounds.value || isRangeInverted.value,
56
+ );
57
+
58
+ const boundsLabel = computed(() => {
59
+ const { min, max } = props;
60
+ if (min != null && max != null) return `${min}–${max}`;
61
+ if (min != null) return `${min} or more`;
62
+ if (max != null) return `${max} or less`;
63
+ return null;
64
+ });
65
+
66
+ const errorMessage = computed(() => {
67
+ if (isRangeInverted.value) return "Min must not exceed max";
68
+ if ((minOutOfBounds.value || maxOutOfBounds.value) && boundsLabel.value) {
69
+ return `Value must be between ${boundsLabel.value}`;
70
+ }
71
+ return undefined;
72
+ });
73
+
74
+ const onMin = (v: string | number | undefined) => {
75
+ draftMin.value = String(v ?? "");
76
+ emitDebounced(draftMin.value, draftMax.value);
77
+ };
78
+ const onMax = (v: string | number | undefined) => {
79
+ draftMax.value = String(v ?? "");
80
+ emitDebounced(draftMin.value, draftMax.value);
81
+ };
82
+ </script>
83
+
84
+ <template>
85
+ <FilterFieldWrapper
86
+ :label="label"
87
+ :help-text="helpText"
88
+ :error="errorMessage"
89
+ :error-id="errorId"
90
+ >
91
+ <div class="flex items-center gap-2">
92
+ <Input
93
+ type="number"
94
+ placeholder="Min"
95
+ :min="min"
96
+ :max="max"
97
+ :model-value="draftMin"
98
+ :aria-label="`${label} minimum`"
99
+ :aria-invalid="hasError || undefined"
100
+ :aria-describedby="hasError ? errorId : undefined"
101
+ @update:model-value="onMin"
102
+ />
103
+ <span class="text-sm text-muted-foreground">–</span>
104
+ <Input
105
+ type="number"
106
+ placeholder="Max"
107
+ :min="min"
108
+ :max="max"
109
+ :model-value="draftMax"
110
+ :aria-label="`${label} maximum`"
111
+ :aria-invalid="hasError || undefined"
112
+ :aria-describedby="hasError ? errorId : undefined"
113
+ @update:model-value="onMax"
114
+ />
115
+ </div>
116
+ </FilterFieldWrapper>
117
+ </template>