@vendure/dashboard 3.4.3-master-202509260228 → 3.5.0-minor-202510012036

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/README.md +4 -0
  2. package/dist/plugin/api/api-extensions.js +11 -14
  3. package/dist/plugin/api/metrics.resolver.d.ts +2 -2
  4. package/dist/plugin/api/metrics.resolver.js +2 -2
  5. package/dist/plugin/config/metrics-strategies.d.ts +9 -9
  6. package/dist/plugin/config/metrics-strategies.js +6 -6
  7. package/dist/plugin/constants.d.ts +2 -0
  8. package/dist/plugin/constants.js +3 -1
  9. package/dist/plugin/dashboard.plugin.js +13 -0
  10. package/dist/plugin/service/metrics.service.d.ts +3 -3
  11. package/dist/plugin/service/metrics.service.js +37 -53
  12. package/dist/plugin/types.d.ts +9 -12
  13. package/dist/plugin/types.js +7 -11
  14. package/dist/vite/vite-plugin-config.js +13 -9
  15. package/dist/vite/vite-plugin-translations.d.ts +22 -0
  16. package/dist/vite/vite-plugin-translations.js +66 -0
  17. package/dist/vite/vite-plugin-vendure-dashboard.js +10 -8
  18. package/lingui.config.js +25 -2
  19. package/package.json +159 -156
  20. package/src/app/app-providers.tsx +0 -4
  21. package/src/app/common/delete-bulk-action.tsx +6 -5
  22. package/src/app/common/duplicate-bulk-action.tsx +4 -5
  23. package/src/app/common/duplicate-entity-dialog.tsx +1 -1
  24. package/src/app/common/set-document-direction.ts +7 -0
  25. package/src/app/main.tsx +50 -17
  26. package/src/app/routes/_authenticated/_administrators/administrators.tsx +8 -6
  27. package/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx +17 -6
  28. package/src/app/routes/_authenticated/_administrators/components/role-permissions-display.tsx +2 -2
  29. package/src/app/routes/_authenticated/_assets/assets.tsx +1 -1
  30. package/src/app/routes/_authenticated/_assets/assets_.$id.tsx +4 -4
  31. package/src/app/routes/_authenticated/_assets/components/asset-bulk-actions.tsx +8 -6
  32. package/src/app/routes/_authenticated/_assets/components/asset-tag-filter.tsx +1 -1
  33. package/src/app/routes/_authenticated/_assets/components/asset-tags-editor.tsx +1 -1
  34. package/src/app/routes/_authenticated/_assets/components/manage-tags-dialog.tsx +3 -8
  35. package/src/app/routes/_authenticated/_channels/channels.tsx +3 -6
  36. package/src/app/routes/_authenticated/_channels/channels_.$id.tsx +5 -5
  37. package/src/app/routes/_authenticated/_collections/collections.tsx +10 -6
  38. package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +16 -5
  39. package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +1 -1
  40. package/src/app/routes/_authenticated/_collections/components/collection-contents-sheet.tsx +1 -1
  41. package/src/app/routes/_authenticated/_collections/components/move-collections-dialog.tsx +6 -6
  42. package/src/app/routes/_authenticated/_countries/countries.graphql.ts +2 -0
  43. package/src/app/routes/_authenticated/_countries/countries.tsx +2 -3
  44. package/src/app/routes/_authenticated/_countries/countries_.$id.tsx +4 -4
  45. package/src/app/routes/_authenticated/_customer-groups/components/customer-group-members-sheet.tsx +1 -1
  46. package/src/app/routes/_authenticated/_customer-groups/components/customer-group-members-table.tsx +4 -4
  47. package/src/app/routes/_authenticated/_customer-groups/customer-groups.tsx +2 -4
  48. package/src/app/routes/_authenticated/_customer-groups/customer-groups_.$id.tsx +13 -6
  49. package/src/app/routes/_authenticated/_customers/components/customer-address-card.tsx +8 -8
  50. package/src/app/routes/_authenticated/_customers/components/customer-address-form.tsx +3 -3
  51. package/src/app/routes/_authenticated/_customers/components/customer-history/customer-history-container.tsx +1 -1
  52. package/src/app/routes/_authenticated/_customers/components/customer-history/customer-history-utils.tsx +1 -1
  53. package/src/app/routes/_authenticated/_customers/components/customer-history/default-customer-history-components.tsx +1 -1
  54. package/src/app/routes/_authenticated/_customers/components/customer-history/use-customer-history.ts +1 -1
  55. package/src/app/routes/_authenticated/_customers/components/customer-status-badge.tsx +1 -1
  56. package/src/app/routes/_authenticated/_customers/customers.graphql.ts +4 -0
  57. package/src/app/routes/_authenticated/_customers/customers.tsx +23 -11
  58. package/src/app/routes/_authenticated/_customers/customers_.$id.tsx +10 -8
  59. package/src/app/routes/_authenticated/_facets/components/edit-facet-value.tsx +1 -1
  60. package/src/app/routes/_authenticated/_facets/components/facet-bulk-actions.tsx +6 -5
  61. package/src/app/routes/_authenticated/_facets/components/facet-values-sheet.tsx +1 -1
  62. package/src/app/routes/_authenticated/_facets/components/facet-values-table.tsx +1 -1
  63. package/src/app/routes/_authenticated/_facets/facets.tsx +5 -5
  64. package/src/app/routes/_authenticated/_facets/facets_.$facetId.values_.$id.tsx +7 -5
  65. package/src/app/routes/_authenticated/_facets/facets_.$id.tsx +18 -6
  66. package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +5 -5
  67. package/src/app/routes/_authenticated/_orders/components/add-manual-payment-dialog.tsx +19 -21
  68. package/src/app/routes/_authenticated/_orders/components/customer-address-selector.tsx +1 -1
  69. package/src/app/routes/_authenticated/_orders/components/edit-order-table.tsx +22 -22
  70. package/src/app/routes/_authenticated/_orders/components/fulfill-order-dialog.tsx +6 -6
  71. package/src/app/routes/_authenticated/_orders/components/fulfillment-details.tsx +15 -9
  72. package/src/app/routes/_authenticated/_orders/components/order-address.tsx +1 -1
  73. package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +11 -9
  74. package/src/app/routes/_authenticated/_orders/components/order-history/default-order-history-components.tsx +1 -1
  75. package/src/app/routes/_authenticated/_orders/components/order-history/order-history-container.tsx +1 -1
  76. package/src/app/routes/_authenticated/_orders/components/order-history/order-history-utils.tsx +1 -1
  77. package/src/app/routes/_authenticated/_orders/components/order-history/use-order-history.ts +1 -1
  78. package/src/app/routes/_authenticated/_orders/components/order-line-custom-fields-form.tsx +1 -1
  79. package/src/app/routes/_authenticated/_orders/components/order-modification-preview-dialog.tsx +4 -4
  80. package/src/app/routes/_authenticated/_orders/components/order-modification-summary.tsx +1 -1
  81. package/src/app/routes/_authenticated/_orders/components/order-table-totals.tsx +27 -27
  82. package/src/app/routes/_authenticated/_orders/components/order-table.tsx +2 -2
  83. package/src/app/routes/_authenticated/_orders/components/order-tax-summary.tsx +1 -1
  84. package/src/app/routes/_authenticated/_orders/components/payment-details.tsx +26 -20
  85. package/src/app/routes/_authenticated/_orders/components/seller-orders-card.tsx +3 -1
  86. package/src/app/routes/_authenticated/_orders/components/settle-refund-dialog.tsx +6 -6
  87. package/src/app/routes/_authenticated/_orders/components/shipping-method-selector.tsx +1 -1
  88. package/src/app/routes/_authenticated/_orders/components/state-transition-control.tsx +1 -1
  89. package/src/app/routes/_authenticated/_orders/components/use-transition-order-to-state.tsx +3 -2
  90. package/src/app/routes/_authenticated/_orders/orders.tsx +5 -9
  91. package/src/app/routes/_authenticated/_orders/orders_.$aggregateOrderId_.seller-orders.$sellerOrderId.tsx +1 -1
  92. package/src/app/routes/_authenticated/_orders/orders_.$id.tsx +1 -1
  93. package/src/app/routes/_authenticated/_orders/orders_.$id_.modify.tsx +4 -4
  94. package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +17 -17
  95. package/src/app/routes/_authenticated/_orders/utils/order-detail-loaders.tsx +1 -1
  96. package/src/app/routes/_authenticated/_payment-methods/payment-methods.tsx +5 -6
  97. package/src/app/routes/_authenticated/_payment-methods/payment-methods_.$id.tsx +13 -6
  98. package/src/app/routes/_authenticated/_product-variants/components/product-variant-bulk-actions.tsx +1 -1
  99. package/src/app/routes/_authenticated/_product-variants/components/variant-price-detail.tsx +1 -1
  100. package/src/app/routes/_authenticated/_product-variants/product-variants.graphql.ts +10 -0
  101. package/src/app/routes/_authenticated/_product-variants/product-variants.tsx +9 -2
  102. package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +13 -6
  103. package/src/app/routes/_authenticated/_products/components/add-option-group-dialog.tsx +5 -5
  104. package/src/app/routes/_authenticated/_products/components/add-product-variant-dialog.tsx +5 -5
  105. package/src/app/routes/_authenticated/_products/components/assign-facet-values-dialog.tsx +5 -4
  106. package/src/app/routes/_authenticated/_products/components/create-product-options-dialog.tsx +9 -12
  107. package/src/app/routes/_authenticated/_products/components/create-product-variants-dialog.tsx +1 -1
  108. package/src/app/routes/_authenticated/_products/components/create-product-variants.tsx +4 -4
  109. package/src/app/routes/_authenticated/_products/components/option-groups-editor.tsx +1 -1
  110. package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +1 -1
  111. package/src/app/routes/_authenticated/_products/components/product-option-group-badge.tsx +19 -0
  112. package/src/app/routes/_authenticated/_products/components/product-option-select.tsx +3 -3
  113. package/src/app/routes/_authenticated/_products/components/product-options-table.tsx +114 -0
  114. package/src/app/routes/_authenticated/_products/product-option-groups.graphql.ts +103 -0
  115. package/src/app/routes/_authenticated/_products/products.graphql.ts +44 -32
  116. package/src/app/routes/_authenticated/_products/products.tsx +34 -5
  117. package/src/app/routes/_authenticated/_products/products_.$id.tsx +29 -12
  118. package/src/app/routes/_authenticated/_products/products_.$id_.variants.tsx +11 -11
  119. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$id.tsx +177 -0
  120. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$productOptionGroupId.options_.$id.tsx +208 -0
  121. package/src/app/routes/_authenticated/_profile/profile.tsx +4 -4
  122. package/src/app/routes/_authenticated/_promotions/promotions.tsx +2 -4
  123. package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +16 -9
  124. package/src/app/routes/_authenticated/_roles/components/permissions-table-grid.tsx +1 -1
  125. package/src/app/routes/_authenticated/_roles/roles.tsx +3 -6
  126. package/src/app/routes/_authenticated/_roles/roles_.$id.tsx +4 -6
  127. package/src/app/routes/_authenticated/_sellers/sellers.tsx +3 -4
  128. package/src/app/routes/_authenticated/_sellers/sellers_.$id.tsx +4 -4
  129. package/src/app/routes/_authenticated/_shipping-methods/components/price-display.tsx +5 -5
  130. package/src/app/routes/_authenticated/_shipping-methods/components/shipping-method-test-result-wrapper.tsx +1 -1
  131. package/src/app/routes/_authenticated/_shipping-methods/components/test-address-form.tsx +11 -11
  132. package/src/app/routes/_authenticated/_shipping-methods/components/test-order-builder.tsx +1 -1
  133. package/src/app/routes/_authenticated/_shipping-methods/components/test-shipping-methods-result.tsx +8 -8
  134. package/src/app/routes/_authenticated/_shipping-methods/components/test-shipping-methods-sheet.tsx +1 -1
  135. package/src/app/routes/_authenticated/_shipping-methods/components/test-single-method-result.tsx +8 -8
  136. package/src/app/routes/_authenticated/_shipping-methods/components/test-single-shipping-method-sheet.tsx +4 -4
  137. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.tsx +2 -3
  138. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +2 -2
  139. package/src/app/routes/_authenticated/_stock-locations/stock-locations.tsx +3 -4
  140. package/src/app/routes/_authenticated/_stock-locations/stock-locations_.$id.tsx +13 -6
  141. package/src/app/routes/_authenticated/_system/healthchecks.tsx +10 -4
  142. package/src/app/routes/_authenticated/_system/job-queue.tsx +10 -13
  143. package/src/app/routes/_authenticated/_system/scheduled-tasks.tsx +18 -16
  144. package/src/app/routes/_authenticated/_tax-categories/tax-categories.tsx +2 -4
  145. package/src/app/routes/_authenticated/_tax-categories/tax-categories_.$id.tsx +13 -6
  146. package/src/app/routes/_authenticated/_tax-rates/tax-rates.tsx +8 -12
  147. package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +6 -4
  148. package/src/app/routes/_authenticated/_zones/components/zone-countries-sheet.tsx +4 -1
  149. package/src/app/routes/_authenticated/_zones/zones.tsx +4 -4
  150. package/src/app/routes/_authenticated/_zones/zones_.$id.tsx +8 -5
  151. package/src/app/routes/_authenticated/index.tsx +46 -25
  152. package/src/app/styles.css +4 -0
  153. package/src/i18n/common-strings.ts +111 -0
  154. package/src/i18n/locales/ar.po +4777 -0
  155. package/src/i18n/locales/cs.po +4777 -0
  156. package/src/i18n/locales/de.po +4299 -1101
  157. package/src/i18n/locales/en.po +3857 -659
  158. package/src/i18n/locales/es.po +4777 -0
  159. package/src/i18n/locales/fa.po +4777 -0
  160. package/src/i18n/locales/fr.po +4777 -0
  161. package/src/i18n/locales/he.po +4777 -0
  162. package/src/i18n/locales/hr.po +4777 -0
  163. package/src/i18n/locales/it.po +4777 -0
  164. package/src/i18n/locales/ja.po +4777 -0
  165. package/src/i18n/locales/ko.po +4628 -0
  166. package/src/i18n/locales/nb.po +4777 -0
  167. package/src/i18n/locales/ne.po +4777 -0
  168. package/src/i18n/locales/nl.po +4628 -0
  169. package/src/i18n/locales/pl.po +4777 -0
  170. package/src/i18n/locales/pt_BR.po +4777 -0
  171. package/src/i18n/locales/pt_PT.po +4777 -0
  172. package/src/i18n/locales/ru.po +4777 -0
  173. package/src/i18n/locales/sv.po +4777 -0
  174. package/src/i18n/locales/tr.po +4777 -0
  175. package/src/i18n/locales/uk.po +4777 -0
  176. package/src/i18n/locales/zh_Hans.po +4777 -0
  177. package/src/i18n/locales/zh_Hant.po +4777 -0
  178. package/src/lib/components/data-display/json.tsx +16 -1
  179. package/src/lib/components/data-input/combination-mode-input.tsx +1 -1
  180. package/src/lib/components/data-input/custom-field-list-input.tsx +11 -7
  181. package/src/lib/components/data-input/customer-group-input.tsx +27 -33
  182. package/src/lib/components/data-input/datetime-input.tsx +40 -1
  183. package/src/lib/components/data-input/default-relation-input.tsx +5 -4
  184. package/src/lib/components/data-input/index.ts +3 -0
  185. package/src/lib/components/data-input/product-multi-selector-input.tsx +14 -14
  186. package/src/lib/components/data-input/relation-selector.tsx +1 -1
  187. package/src/lib/components/data-input/select-with-options.tsx +1 -1
  188. package/src/lib/components/data-input/slug-input.tsx +290 -0
  189. package/src/lib/components/data-table/add-filter-menu.tsx +17 -10
  190. package/src/lib/components/data-table/data-table-bulk-action-item.tsx +45 -8
  191. package/src/lib/components/data-table/data-table-bulk-actions.tsx +4 -4
  192. package/src/lib/components/data-table/data-table-column-header.tsx +13 -8
  193. package/src/lib/components/data-table/data-table-context.tsx +91 -0
  194. package/src/lib/components/data-table/data-table-faceted-filter.tsx +2 -1
  195. package/src/lib/components/data-table/data-table-filter-badge.tsx +9 -5
  196. package/src/lib/components/data-table/data-table-filter-dialog.tsx +1 -1
  197. package/src/lib/components/data-table/data-table-utils.ts +21 -4
  198. package/src/lib/components/data-table/data-table-view-options.tsx +21 -10
  199. package/src/lib/components/data-table/data-table.tsx +146 -94
  200. package/src/lib/components/data-table/filters/data-table-boolean-filter.tsx +4 -4
  201. package/src/lib/components/data-table/global-views-bar.tsx +97 -0
  202. package/src/lib/components/data-table/global-views-sheet.tsx +11 -0
  203. package/src/lib/components/data-table/human-readable-operator.tsx +1 -1
  204. package/src/lib/components/data-table/manage-global-views-button.tsx +26 -0
  205. package/src/lib/components/data-table/my-views-button.tsx +47 -0
  206. package/src/lib/components/data-table/refresh-button.tsx +12 -3
  207. package/src/lib/components/data-table/save-view-button.tsx +41 -0
  208. package/src/lib/components/data-table/save-view-dialog.tsx +113 -0
  209. package/src/lib/components/data-table/use-generated-columns.tsx +13 -8
  210. package/src/lib/components/data-table/user-views-sheet.tsx +11 -0
  211. package/src/lib/components/data-table/views-sheet.tsx +305 -0
  212. package/src/lib/components/date-range-picker.tsx +186 -0
  213. package/src/lib/components/layout/app-sidebar.tsx +3 -1
  214. package/src/lib/components/layout/channel-switcher.tsx +8 -10
  215. package/src/lib/components/layout/dev-mode-indicator.tsx +1 -1
  216. package/src/lib/components/layout/generated-breadcrumbs.tsx +10 -8
  217. package/src/lib/components/layout/language-dialog.tsx +34 -13
  218. package/src/lib/components/layout/manage-languages-dialog.tsx +1 -1
  219. package/src/lib/components/layout/nav-main.tsx +23 -13
  220. package/src/lib/components/layout/nav-user.tsx +19 -23
  221. package/src/lib/components/login/login-form.tsx +1 -1
  222. package/src/lib/components/shared/asset/asset-bulk-actions.tsx +4 -4
  223. package/src/lib/components/shared/asset/asset-focal-point-editor.tsx +1 -1
  224. package/src/lib/components/shared/asset/asset-gallery.tsx +15 -14
  225. package/src/lib/components/shared/assign-to-channel-bulk-action.tsx +11 -11
  226. package/src/lib/components/shared/assign-to-channel-dialog.tsx +6 -5
  227. package/src/lib/components/shared/channel-code-label.tsx +1 -1
  228. package/src/lib/components/shared/channel-selector.tsx +4 -4
  229. package/src/lib/components/shared/configurable-operation-multi-selector.tsx +16 -14
  230. package/src/lib/components/shared/configurable-operation-selector.tsx +1 -1
  231. package/src/lib/components/shared/confirmation-dialog.tsx +8 -8
  232. package/src/lib/components/shared/country-selector.tsx +1 -1
  233. package/src/lib/components/shared/currency-selector.tsx +4 -4
  234. package/src/lib/components/shared/custom-fields-form.tsx +8 -24
  235. package/src/lib/components/shared/customer-address-form.tsx +3 -3
  236. package/src/lib/components/shared/customer-group-selector.tsx +1 -1
  237. package/src/lib/components/shared/customer-selector.tsx +1 -1
  238. package/src/lib/components/shared/error-page.tsx +1 -1
  239. package/src/lib/components/shared/facet-value-selector.tsx +10 -10
  240. package/src/lib/components/shared/history-timeline/history-note-checkbox.tsx +1 -1
  241. package/src/lib/components/shared/history-timeline/history-note-editor.tsx +1 -1
  242. package/src/lib/components/shared/history-timeline/history-note-entry.tsx +1 -1
  243. package/src/lib/components/shared/language-selector.tsx +4 -4
  244. package/src/lib/components/shared/navigation-confirmation.tsx +1 -1
  245. package/src/lib/components/shared/paginated-list-data-table.tsx +64 -34
  246. package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +6 -5
  247. package/src/lib/components/shared/rich-text-editor/image-dialog.tsx +1 -1
  248. package/src/lib/components/shared/rich-text-editor/link-dialog.tsx +1 -1
  249. package/src/lib/components/shared/rich-text-editor/responsive-toolbar.tsx +1 -1
  250. package/src/lib/components/shared/rich-text-editor/table-edit-icons.tsx +1 -1
  251. package/src/lib/components/shared/role-code-label.tsx +1 -1
  252. package/src/lib/components/shared/role-selector.tsx +4 -4
  253. package/src/lib/components/shared/seller-selector.tsx +1 -1
  254. package/src/lib/components/shared/stock-level-label.tsx +3 -5
  255. package/src/lib/components/shared/table-cell/order-table-cell-components.tsx +3 -1
  256. package/src/lib/components/shared/tax-category-selector.tsx +1 -1
  257. package/src/lib/components/shared/translatable-form-field.tsx +15 -15
  258. package/src/lib/components/shared/zone-selector.tsx +1 -1
  259. package/src/lib/components/ui/button.tsx +1 -1
  260. package/src/lib/framework/dashboard-widget/base-widget.tsx +11 -9
  261. package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +35 -6
  262. package/src/lib/framework/dashboard-widget/metrics-widget/index.tsx +18 -12
  263. package/src/lib/framework/dashboard-widget/metrics-widget/metrics-widget.graphql.ts +9 -3
  264. package/src/lib/framework/dashboard-widget/orders-summary/index.tsx +26 -79
  265. package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +35 -0
  266. package/src/lib/framework/defaults.ts +34 -63
  267. package/src/lib/framework/document-introspection/add-custom-fields.spec.ts +319 -9
  268. package/src/lib/framework/document-introspection/add-custom-fields.ts +60 -31
  269. package/src/lib/framework/document-introspection/get-document-structure.spec.ts +1 -159
  270. package/src/lib/framework/document-introspection/include-only-selected-list-fields.spec.ts +1840 -0
  271. package/src/lib/framework/document-introspection/include-only-selected-list-fields.ts +940 -0
  272. package/src/lib/framework/document-introspection/testing-utils.ts +161 -0
  273. package/src/lib/framework/extension-api/display-component-extensions.tsx +2 -0
  274. package/src/lib/framework/extension-api/types/data-table.ts +62 -4
  275. package/src/lib/framework/extension-api/types/navigation.ts +16 -0
  276. package/src/lib/framework/form-engine/utils.ts +34 -0
  277. package/src/lib/framework/layout-engine/page-layout.tsx +36 -36
  278. package/src/lib/framework/page/detail-page.tsx +10 -10
  279. package/src/lib/framework/page/list-page.tsx +289 -4
  280. package/src/lib/framework/page/use-extended-router.tsx +101 -34
  281. package/src/lib/graphql/api.ts +6 -2
  282. package/src/lib/graphql/graphql-env.d.ts +38 -26
  283. package/src/lib/hooks/use-display-locale.ts +40 -0
  284. package/src/lib/hooks/use-dynamic-translations.ts +46 -0
  285. package/src/lib/hooks/use-extended-detail-query.ts +1 -1
  286. package/src/lib/hooks/use-extended-list-query.ts +6 -1
  287. package/src/lib/hooks/use-local-format.ts +15 -1
  288. package/src/lib/hooks/use-saved-views.ts +230 -0
  289. package/src/lib/hooks/use-ui-language-loader.ts +30 -0
  290. package/src/lib/index.ts +15 -0
  291. package/src/lib/lib/load-i18n-messages.ts +17 -0
  292. package/src/lib/lib/trans.tsx +15 -11
  293. package/src/lib/providers/i18n-provider.tsx +7 -14
  294. package/src/lib/types/saved-views.ts +39 -0
  295. package/src/lib/utils/saved-views-utils.ts +40 -0
@@ -17,7 +17,6 @@ import { ColumnFiltersState, SortingState, Table } from '@tanstack/react-table';
17
17
  import { TableOptions } from '@tanstack/table-core';
18
18
 
19
19
  import { BulkAction } from '@/vdb/framework/extension-api/types/index.js';
20
- import { addCustomFields } from '../document-introspection/add-custom-fields.js';
21
20
  import { FullWidthPageBlock, Page, PageActionBar, PageLayout, PageTitle } from '../layout-engine/page-layout.js';
22
21
 
23
22
  /**
@@ -34,9 +33,62 @@ export interface ListPageProps<
34
33
  V extends ListQueryOptionsShape,
35
34
  AC extends AdditionalColumns<T>,
36
35
  > {
36
+ /**
37
+ * @description
38
+ * A unique identifier for the list page. This is important to support
39
+ * customization functionality that relies on page IDs and makes your
40
+ * component extensible.
41
+ */
37
42
  pageId?: string;
43
+ /**
44
+ @description
45
+ * The Tanstack Router `Route` object, which will be defined in the component file.
46
+ */
38
47
  route: AnyRoute | (() => AnyRoute);
48
+ /**
49
+ @description
50
+ * The page title, which will display in the header area.
51
+ */
39
52
  title: string | React.ReactElement;
53
+ /**
54
+ * @description
55
+ * This DocumentNode of the list query, i.e. a query that fetches
56
+ * PaginatedList data with "items" and "totalItems", such as:
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * export const collectionListDocument = graphql(`
61
+ * query CollectionList($options: CollectionListOptions) {
62
+ * collections(options: $options) {
63
+ * items {
64
+ * id
65
+ * createdAt
66
+ * updatedAt
67
+ * name
68
+ * slug
69
+ * breadcrumbs {
70
+ * id
71
+ * name
72
+ * slug
73
+ * }
74
+ * children {
75
+ * id
76
+ * name
77
+ * }
78
+ * # ... etc
79
+ * }
80
+ * totalItems
81
+ * }
82
+ * }
83
+ * `);
84
+ * // ...
85
+ * <ListPage
86
+ * pageId="collection-list"
87
+ * listQuery={collectionListDocument}
88
+ * // ...
89
+ * />
90
+ * ```
91
+ */
40
92
  listQuery: T;
41
93
  /**
42
94
  * @description
@@ -46,20 +98,255 @@ export interface ListPageProps<
46
98
  * will be added to the action column dropdown already.
47
99
  */
48
100
  deleteMutation?: TypedDocumentNode<any, { id: string }>;
101
+ /**
102
+ * @description
103
+ * This prop can be used to intercept and transform the list query variables before they are
104
+ * sent to the Admin API.
105
+ *
106
+ * This allows you to implement specific logic that differs from the standard filter/sort
107
+ * handling.
108
+ *
109
+ * @example
110
+ * ```tsx
111
+ * <ListPage
112
+ * pageId="collection-list"
113
+ * title="Collections"
114
+ * listQuery={collectionListDocument}
115
+ * transformVariables={input => {
116
+ * const filterTerm = input.options?.filter?.name?.contains;
117
+ * // If there is a filter term set
118
+ * // we want to return all results. Else
119
+ * // we only want top-level Collections
120
+ * const isFiltering = !!filterTerm;
121
+ * return {
122
+ * options: {
123
+ * ...input.options,
124
+ * topLevelOnly: !isFiltering,
125
+ * },
126
+ * };
127
+ * }}
128
+ * />
129
+ * ```
130
+ */
49
131
  transformVariables?: (variables: V) => V;
132
+ /**
133
+ * @description
134
+ * Allows you to customize how the search term is used in the list query options.
135
+ * For instance, when you want the term to filter on specific fields.
136
+ *
137
+ * @example
138
+ * ```tsx
139
+ * <ListPage
140
+ * pageId="administrator-list"
141
+ * title="Administrators"
142
+ * listQuery={administratorListDocument}
143
+ * onSearchTermChange={searchTerm => {
144
+ * return {
145
+ * firstName: { contains: searchTerm },
146
+ * lastName: { contains: searchTerm },
147
+ * emailAddress: { contains: searchTerm },
148
+ * };
149
+ * }}
150
+ * />
151
+ * @param searchTerm
152
+ */
50
153
  onSearchTermChange?: (searchTerm: string) => NonNullable<V['options']>['filter'];
154
+ /**
155
+ * @description
156
+ * Allows you to customize the rendering and other aspects of individual columns.
157
+ *
158
+ * By default, an appropriate component will be chosen to render the column data
159
+ * based on the data type of the field. However, in many cases you want to have
160
+ * more control over how the column data is rendered.
161
+ *
162
+ * @example
163
+ * ```tsx
164
+ * <ListPage
165
+ * pageId="collection-list"
166
+ * listQuery={collectionListDocument}
167
+ * customizeColumns={{
168
+ * // The key "name" matches one of the top-level fields of the
169
+ * // list query type (Collection, in this example)
170
+ * name: {
171
+ * meta: {
172
+ * // The Dashboard optimizes the list query `collectionListDocument` to
173
+ * // only select field that are actually visible in the ListPage table.
174
+ * // However, sometimes you want to render data from other fields, i.e.
175
+ * // this column has a data dependency on the "children" and "breadcrumbs"
176
+ * // fields in order to correctly render the "name" field.
177
+ * // In this case, we can declare those data dependencies which means whenever
178
+ * // the "name" column is visible, it will ensure the "children" and "breadcrumbs"
179
+ * // fields are also selected in the query.
180
+ * dependencies: ['children', 'breadcrumbs'],
181
+ * },
182
+ * header: 'Collection Name',
183
+ * cell: ({ row }) => {
184
+ * const isExpanded = row.getIsExpanded();
185
+ * const hasChildren = !!row.original.children?.length;
186
+ * return (
187
+ * <div
188
+ * style={{ marginLeft: (row.original.breadcrumbs?.length - 2) * 20 + 'px' }}
189
+ * className="flex gap-2 items-center"
190
+ * >
191
+ * <Button
192
+ * size="icon"
193
+ * variant="secondary"
194
+ * onClick={row.getToggleExpandedHandler()}
195
+ * disabled={!hasChildren}
196
+ * className={!hasChildren ? 'opacity-20' : ''}
197
+ * >
198
+ * {isExpanded ? <FolderOpen /> : <Folder />}
199
+ * </Button>
200
+ * <DetailPageButton id={row.original.id} label={row.original.name} />
201
+ * </div>
202
+ * );
203
+ * },
204
+ * },
205
+ * ```
206
+ */
51
207
  customizeColumns?: CustomizeColumnConfig<T>;
208
+ /**
209
+ * @description
210
+ * Allows you to define extra columns that are not related to actual fields returned in
211
+ * the query result.
212
+ *
213
+ * For example, in the Administrator list, we define an additional "name" column composed
214
+ * of the `firstName` and `lastName` fields.
215
+ *
216
+ * @example
217
+ * ```tsx
218
+ * <ListPage
219
+ * pageId="administrator-list"
220
+ * title="Administrators"
221
+ * listQuery={administratorListDocument}
222
+ * additionalColumns={{
223
+ * name: {
224
+ * header: 'Name',
225
+ * cell: ({ row }) => (
226
+ * <DetailPageButton
227
+ * id={row.original.id}
228
+ * label={`${row.original.firstName} ${row.original.lastName}`}
229
+ * />
230
+ * ),
231
+ * },
232
+ * />
233
+ * ```
234
+ */
52
235
  additionalColumns?: AC;
236
+ /**
237
+ * @description
238
+ * Allows you to specify the default order of columns in the table. When not defined, the
239
+ * order of fields in the list query document will be used.
240
+ */
53
241
  defaultColumnOrder?: (keyof ListQueryFields<T> | keyof AC | CustomFieldKeysOfItem<ListQueryFields<T>>)[];
242
+ /**
243
+ * @description
244
+ * Allows you to specify the default sorting applied to the table.
245
+ *
246
+ * @example
247
+ * ```tsx
248
+ * defaultSort={[{ id: 'orderPlacedAt', desc: true }]}
249
+ * ```
250
+ */
54
251
  defaultSort?: SortingState;
252
+ /**
253
+ * @description
254
+ * Allows you to specify the default columns that are visible in the table.
255
+ * If you set them to `true`, then only those will show by default. If you set them to `false`,
256
+ * then _all other_ columns will be visible by default.
257
+ *
258
+ * @example
259
+ * ```tsx
260
+ * <ListPage
261
+ * pageId="country-list"
262
+ * listQuery={countriesListQuery}
263
+ * title="Countries"
264
+ * defaultVisibility={{
265
+ * name: true,
266
+ * code: true,
267
+ * enabled: true,
268
+ * }}
269
+ * />
270
+ * ```
271
+ */
55
272
  defaultVisibility?: Partial<
56
273
  Record<keyof ListQueryFields<T> | keyof AC | CustomFieldKeysOfItem<ListQueryFields<T>>, boolean>
57
274
  >;
58
275
  children?: React.ReactNode;
276
+ /**
277
+ * @description
278
+ * Allows you to define pre-set filters based on an array of possible selections
279
+ *
280
+ * @example
281
+ * ```tsx
282
+ * <ListPage
283
+ * pageId="payment-method-list"
284
+ * listQuery={paymentMethodListQuery}
285
+ * title="Payment Methods"
286
+ * facetedFilters={{
287
+ * enabled: {
288
+ * title: 'Enabled',
289
+ * options: [
290
+ * { label: 'Enabled', value: true },
291
+ * { label: 'Disabled', value: false },
292
+ * ],
293
+ * },
294
+ * }}
295
+ * />
296
+ * ```
297
+ */
59
298
  facetedFilters?: FacetedFilterConfig<T>;
299
+ /**
300
+ * @description
301
+ * Allows you to specify additional "actions" that will be made available in the "actions" column.
302
+ * By default, the actions column includes all bulk actions defined in the `bulkActions` prop.
303
+ */
60
304
  rowActions?: RowAction<ListQueryFields<T>>[];
305
+ /**
306
+ * @description
307
+ * Allows the returned list query data to be transformed in some way. This is an advanced feature
308
+ * that is not often required.
309
+ */
61
310
  transformData?: (data: any[]) => any[];
311
+ /**
312
+ * @description
313
+ * Allows you to directly manipulate the Tanstack Table `TableOptions` object before the
314
+ * table is created. And advanced option that is not often required.
315
+ */
62
316
  setTableOptions?: (table: TableOptions<any>) => TableOptions<any>;
317
+ /**
318
+ * @description
319
+ * Bulk actions are actions that can be applied to one or more table rows, and include things like
320
+ *
321
+ * - Deleting the rows
322
+ * - Assigning the rows to another channel
323
+ * - Bulk editing some aspect of the rows
324
+ *
325
+ * See the {@link BulkAction} docs for an example of how to build the component.
326
+ *
327
+ * @example
328
+ * ```tsx
329
+ * <ListPage
330
+ * pageId="product-list"
331
+ * listQuery={productListDocument}
332
+ * title="Products"
333
+ * bulkActions={[
334
+ * {
335
+ * component: AssignProductsToChannelBulkAction,
336
+ * order: 100,
337
+ * },
338
+ * {
339
+ * component: RemoveProductsFromChannelBulkAction,
340
+ * order: 200,
341
+ * },
342
+ * {
343
+ * component: DeleteProductsBulkAction,
344
+ * order: 300,
345
+ * },
346
+ * ]}
347
+ * />
348
+ * ```
349
+ */
63
350
  bulkActions?: BulkAction[];
64
351
  /**
65
352
  * @description
@@ -242,8 +529,6 @@ export function ListPage<
242
529
  });
243
530
  }
244
531
 
245
- const listQueryWithCustomFields = addCustomFields(listQuery);
246
-
247
532
  return (
248
533
  <Page pageId={pageId}>
249
534
  <PageTitle>{title}</PageTitle>
@@ -251,7 +536,7 @@ export function ListPage<
251
536
  <PageLayout>
252
537
  <FullWidthPageBlock blockId="list-table">
253
538
  <PaginatedListDataTable
254
- listQuery={listQueryWithCustomFields}
539
+ listQuery={listQuery}
255
540
  deleteMutation={deleteMutation}
256
541
  transformVariables={transformVariables}
257
542
  customizeColumns={customizeColumns as any}
@@ -1,4 +1,4 @@
1
- import { AnyRoute, createRoute, Router } from '@tanstack/react-router';
1
+ import { AnyRoute, createRoute, createRouter, RouterOptions } from '@tanstack/react-router';
2
2
  import { useMemo } from 'react';
3
3
  import { ErrorPage } from '../../components/shared/error-page.js';
4
4
  import { AUTHENTICATED_ROUTE_PREFIX } from '../../constants.js';
@@ -6,63 +6,130 @@ import { useDashboardExtensions } from '../extension-api/use-dashboard-extension
6
6
  import { extensionRoutes } from './page-api.js';
7
7
 
8
8
  /**
9
- * Extends the TanStack Router with additional routes for each dashboard
10
- * extension.
9
+ * Creates a TanStack Router with the base route tree extended with additional
10
+ * routes from dashboard extensions.
11
11
  */
12
- export const useExtendedRouter = (router: Router<AnyRoute, any, any>) => {
12
+ export const useExtendedRouter = (
13
+ baseRouteTree: AnyRoute,
14
+ routerOptions: Omit<RouterOptions<AnyRoute, any>, 'routeTree'>,
15
+ ) => {
13
16
  const { extensionsLoaded } = useDashboardExtensions();
14
17
 
15
18
  return useMemo(() => {
19
+ // Start with the base route tree
20
+ let routeTree = baseRouteTree;
21
+
22
+ // Only extend if extensions are loaded
16
23
  if (!extensionsLoaded) {
17
- return router;
24
+ return createRouter({
25
+ ...routerOptions,
26
+ routeTree,
27
+ });
18
28
  }
19
29
 
20
- const authenticatedRouteIndex = router.routeTree.children.findIndex(
30
+ const authenticatedRouteIndex = routeTree.children.findIndex(
21
31
  (r: AnyRoute) => r.id === AUTHENTICATED_ROUTE_PREFIX,
22
32
  );
23
33
 
24
34
  if (authenticatedRouteIndex === -1) {
25
- return router;
35
+ // No authenticated route found, return router with base tree
36
+ return createRouter({
37
+ ...routerOptions,
38
+ routeTree,
39
+ });
26
40
  }
27
41
 
28
- let authenticatedRoute: AnyRoute = router.routeTree.children[authenticatedRouteIndex];
42
+ let authenticatedRoute: AnyRoute = routeTree.children[authenticatedRouteIndex];
43
+
44
+ const newAuthenticatedRoutes: AnyRoute[] = [];
45
+ const newRootRoutes: AnyRoute[] = [];
29
46
 
30
- const newRoutes: AnyRoute[] = [];
31
47
  // Create new routes for each extension
32
48
  for (const [path, config] of extensionRoutes.entries()) {
33
49
  const pathWithoutLeadingSlash = path.startsWith('/') ? path.slice(1) : path;
34
- if (
35
- authenticatedRoute.children.findIndex((r: AnyRoute) => r.path === pathWithoutLeadingSlash) >
36
- -1
37
- ) {
38
- // Skip if the route already exists
39
- continue;
50
+
51
+ // Check if route should be authenticated (default is true)
52
+ const isAuthenticated = config.authenticated !== false;
53
+
54
+ if (isAuthenticated) {
55
+ // Check if the route already exists under authenticated route
56
+ if (
57
+ authenticatedRoute.children.findIndex(
58
+ (r: AnyRoute) => r.path === pathWithoutLeadingSlash,
59
+ ) > -1
60
+ ) {
61
+ // Skip if the route already exists
62
+ continue;
63
+ }
64
+
65
+ const newRoute: AnyRoute = createRoute({
66
+ path: `/${pathWithoutLeadingSlash}`,
67
+ getParentRoute: () => authenticatedRoute,
68
+ loader: config.loader,
69
+ validateSearch: config.validateSearch,
70
+ component: () => config.component(newRoute),
71
+ errorComponent: ({ error }) => <ErrorPage message={error.message} />,
72
+ });
73
+ newAuthenticatedRoutes.push(newRoute);
74
+ } else {
75
+ // Check if the route already exists at the root level
76
+ // Check both by path and by id (which includes the leading slash)
77
+ const routeExists =
78
+ routeTree.children.some(
79
+ (r: AnyRoute) =>
80
+ r.path === `/${pathWithoutLeadingSlash}` ||
81
+ r.path === pathWithoutLeadingSlash ||
82
+ r.id === `/${pathWithoutLeadingSlash}`,
83
+ ) ||
84
+ newRootRoutes.some(
85
+ (r: AnyRoute) =>
86
+ r.path === `/${pathWithoutLeadingSlash}` ||
87
+ r.id === `/${pathWithoutLeadingSlash}`,
88
+ );
89
+
90
+ if (routeExists) {
91
+ // Skip if the route already exists
92
+ continue;
93
+ }
94
+
95
+ const newRoute: AnyRoute = createRoute({
96
+ path: `/${pathWithoutLeadingSlash}`,
97
+ getParentRoute: () => routeTree,
98
+ loader: config.loader,
99
+ validateSearch: config.validateSearch,
100
+ component: () => config.component(newRoute),
101
+ errorComponent: ({ error }) => <ErrorPage message={error.message} />,
102
+ });
103
+ newRootRoutes.push(newRoute);
40
104
  }
105
+ }
41
106
 
42
- const newRoute: AnyRoute = createRoute({
43
- path: `/${pathWithoutLeadingSlash}`,
44
- getParentRoute: () => authenticatedRoute,
45
- loader: config.loader,
46
- component: () => config.component(newRoute),
47
- errorComponent: ({ error }) => <ErrorPage message={error.message} />,
107
+ // Only extend the tree if we have new routes to add
108
+ if (newAuthenticatedRoutes.length === 0 && newRootRoutes.length === 0) {
109
+ return createRouter({
110
+ ...routerOptions,
111
+ routeTree,
48
112
  });
49
- newRoutes.push(newRoute);
50
113
  }
51
114
 
52
- const childrenWithoutAuthenticated = router.routeTree.children.filter(
115
+ const childrenWithoutAuthenticated = routeTree.children.filter(
53
116
  (r: AnyRoute) => r.id !== AUTHENTICATED_ROUTE_PREFIX,
54
117
  );
55
118
 
56
- // Create a new router with the modified route tree
57
- const newRouter = new Router({
58
- routeTree: router.routeTree.addChildren([
59
- ...childrenWithoutAuthenticated,
60
- authenticatedRoute.addChildren([...authenticatedRoute.children, ...newRoutes]),
61
- ]),
62
- basepath: router.basepath,
63
- defaultPreload: router.options.defaultPreload,
64
- defaultPreloadDelay: router.options.defaultPreloadDelay,
119
+ const updatedAuthenticatedRoute = authenticatedRoute.addChildren([
120
+ ...authenticatedRoute.children,
121
+ ...newAuthenticatedRoutes,
122
+ ]);
123
+
124
+ const extendedRouteTree: AnyRoute = routeTree.addChildren([
125
+ ...childrenWithoutAuthenticated,
126
+ updatedAuthenticatedRoute,
127
+ ...newRootRoutes,
128
+ ]);
129
+
130
+ return createRouter({
131
+ ...routerOptions,
132
+ routeTree: extendedRouteTree,
65
133
  });
66
- return newRouter;
67
- }, [router, extensionsLoaded]);
134
+ }, [baseRouteTree, routerOptions, extensionsLoaded]);
68
135
  };
@@ -3,9 +3,13 @@ import { AwesomeGraphQLClient } from 'awesome-graphql-client';
3
3
  import { DocumentNode, print } from 'graphql';
4
4
  import { uiConfig } from 'virtual:vendure-ui-config';
5
5
 
6
+ const host =
7
+ uiConfig.api.host !== 'auto'
8
+ ? uiConfig.api.host
9
+ : `${window.location.protocol}//${window.location.hostname}`;
6
10
  const API_URL =
7
- (uiConfig.api.host !== "auto" ? uiConfig.api.host : `${window.location.protocol}//${window.location.hostname}`) +
8
- `:${(uiConfig.api.port !== 'auto' ? uiConfig.api.port : window.location.port)}` +
11
+ host +
12
+ `:${uiConfig.api.port !== 'auto' ? uiConfig.api.port : window.location.port}` +
9
13
  `/${uiConfig.api.adminApiPath}`;
10
14
 
11
15
  export const SELECTED_CHANNEL_TOKEN_KEY = 'vendure-selected-channel-token';