@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
@@ -7,10 +7,11 @@ import {
7
7
  DropdownMenuItem,
8
8
  DropdownMenuTrigger,
9
9
  } from '@/vdb/components/ui/dropdown-menu.js';
10
- import { Trans } from '@/vdb/lib/trans.js';
11
- import { camelCaseToTitleCase } from '@/vdb/lib/utils.js';
10
+ import { Tooltip, TooltipContent, TooltipTrigger } from '@/vdb/components/ui/tooltip.js';
11
+ import { useDynamicTranslations } from '@/vdb/hooks/use-dynamic-translations.js';
12
+ import { Trans } from '@lingui/react/macro';
12
13
  import { Column, ColumnDef } from '@tanstack/react-table';
13
- import { PlusCircle } from 'lucide-react';
14
+ import { FilterIcon } from 'lucide-react';
14
15
  import { useState } from 'react';
15
16
 
16
17
  export interface AddFilterMenuProps {
@@ -20,18 +21,24 @@ export interface AddFilterMenuProps {
20
21
  export function AddFilterMenu({ columns }: Readonly<AddFilterMenuProps>) {
21
22
  const [selectedColumn, setSelectedColumn] = useState<ColumnDef<any> | null>(null);
22
23
  const [isDialogOpen, setIsDialogOpen] = useState(false);
23
-
24
+ const { getTranslatedFieldName } = useDynamicTranslations();
24
25
  const filterableColumns = columns.filter(column => column.getCanFilter());
25
26
 
26
27
  return (
27
28
  <Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
28
29
  <DropdownMenu>
29
- <DropdownMenuTrigger asChild>
30
- <Button variant="outline" size="sm" className="h-8 border-dashed">
31
- <PlusCircle className="mr-2 h-4 w-4" />
30
+ <Tooltip>
31
+ <TooltipTrigger asChild>
32
+ <DropdownMenuTrigger asChild>
33
+ <Button variant="outline" size="icon">
34
+ <FilterIcon />
35
+ </Button>
36
+ </DropdownMenuTrigger>
37
+ </TooltipTrigger>
38
+ <TooltipContent>
32
39
  <Trans>Add filter</Trans>
33
- </Button>
34
- </DropdownMenuTrigger>
40
+ </TooltipContent>
41
+ </Tooltip>
35
42
  <DropdownMenuContent align="end" className="w-[200px]">
36
43
  {filterableColumns.map(column => (
37
44
  <DropdownMenuItem
@@ -41,7 +48,7 @@ export function AddFilterMenu({ columns }: Readonly<AddFilterMenuProps>) {
41
48
  setIsDialogOpen(true);
42
49
  }}
43
50
  >
44
- {camelCaseToTitleCase(column.id)}
51
+ {getTranslatedFieldName(column.id)}
45
52
  </DropdownMenuItem>
46
53
  ))}
47
54
  </DropdownMenuContent>
@@ -1,5 +1,5 @@
1
1
  import { usePermissions } from '@/vdb/hooks/use-permissions.js';
2
- import { Trans } from '@/vdb/lib/trans.js';
2
+ import { Trans } from '@lingui/react/macro';
3
3
  import { cn } from '@/vdb/lib/utils.js';
4
4
  import { LucideIcon } from 'lucide-react';
5
5
  import { useState } from 'react';
@@ -16,6 +16,13 @@ import {
16
16
  } from '../ui/alert-dialog.js';
17
17
  import { DropdownMenuItem } from '../ui/dropdown-menu.js';
18
18
 
19
+ /**
20
+ * @description
21
+ *
22
+ * @docsCategory list-views
23
+ * @docsPage bulk-actions
24
+ * @since 3.4.0
25
+ */
19
26
  export interface DataTableBulkActionItemProps {
20
27
  label: React.ReactNode;
21
28
  icon?: LucideIcon;
@@ -25,14 +32,44 @@ export interface DataTableBulkActionItemProps {
25
32
  requiresPermission?: string[];
26
33
  }
27
34
 
35
+ /**
36
+ * @description
37
+ * A component that should be used to implement any bulk actions for list pages & data tables.
38
+ *
39
+ * @example
40
+ * ```tsx
41
+ * import { DataTableBulkActionItem, Trans } from '\@vendure/dashboard';
42
+ * import { Check } from 'lucide-react';
43
+ *
44
+ * export const MyBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
45
+ *
46
+ * return (
47
+ * <DataTableBulkActionItem
48
+ * requiresPermission={['ReadMyCustomEntity']}
49
+ * onClick={() => {
50
+ * console.log('Selected items:', selection);
51
+ * }}
52
+ * label={<Trans>Delete</Trans>}
53
+ * confirmationText={<Trans>Are you sure?</Trans>}
54
+ * icon={Check}
55
+ * className="text-destructive"
56
+ * />
57
+ * );
58
+ * }
59
+ * ```
60
+ *
61
+ * @docsCategory list-views
62
+ * @docsPage bulk-actions
63
+ * @since 3.4.0
64
+ */
28
65
  export function DataTableBulkActionItem({
29
- label,
30
- icon: Icon,
31
- confirmationText,
32
- className,
33
- onClick,
34
- requiresPermission,
35
- }: DataTableBulkActionItemProps) {
66
+ label,
67
+ icon: Icon,
68
+ confirmationText,
69
+ className,
70
+ onClick,
71
+ requiresPermission,
72
+ }: Readonly<DataTableBulkActionItemProps>) {
36
73
  const [isOpen, setIsOpen] = useState(false);
37
74
  const { hasPermissions } = usePermissions();
38
75
  const userHasPermission = hasPermissions(requiresPermission ?? []);
@@ -8,7 +8,7 @@ import {
8
8
  } from '@/vdb/components/ui/dropdown-menu.js';
9
9
  import { BulkAction } from '@/vdb/framework/extension-api/types/index.js';
10
10
  import { useFloatingBulkActions } from '@/vdb/hooks/use-floating-bulk-actions.js';
11
- import { Trans } from '@/vdb/lib/trans.js';
11
+ import { Trans } from '@lingui/react/macro';
12
12
  import { Table } from '@tanstack/react-table';
13
13
  import { ChevronDown } from 'lucide-react';
14
14
  import { useRef } from 'react';
@@ -19,9 +19,9 @@ interface DataTableBulkActionsProps<TData> {
19
19
  }
20
20
 
21
21
  export function DataTableBulkActions<TData>({
22
- table,
23
- bulkActions,
24
- }: Readonly<DataTableBulkActionsProps<TData>>) {
22
+ table,
23
+ bulkActions,
24
+ }: Readonly<DataTableBulkActionsProps<TData>>) {
25
25
  const allBulkActions = useAllBulkActions(bulkActions);
26
26
 
27
27
  // Cache to store selected items across page changes
@@ -1,7 +1,8 @@
1
1
  import { Button } from '@/vdb/components/ui/button.js';
2
- import { camelCaseToTitleCase } from '@/vdb/lib/utils.js';
2
+ import { useDynamicTranslations } from '@/vdb/hooks/use-dynamic-translations.js';
3
3
  import { ColumnDef, HeaderContext } from '@tanstack/table-core';
4
4
  import { ArrowDown, ArrowUp, ArrowUpDown } from 'lucide-react';
5
+ import { useMemo } from 'react';
5
6
 
6
7
  export interface DataTableColumnHeaderProps {
7
8
  customConfig: Partial<ColumnDef<any>>;
@@ -11,14 +12,18 @@ export interface DataTableColumnHeaderProps {
11
12
  export function DataTableColumnHeader({ headerContext, customConfig }: Readonly<DataTableColumnHeaderProps>) {
12
13
  const { column } = headerContext;
13
14
  const isSortable = column.getCanSort();
15
+ const { getTranslatedFieldName } = useDynamicTranslations();
14
16
 
15
- const customHeader = customConfig.header;
16
- let display = camelCaseToTitleCase(column.id);
17
- if (typeof customHeader === 'function') {
18
- display = customHeader(headerContext);
19
- } else if (typeof customHeader === 'string') {
20
- display = customHeader;
21
- }
17
+ const display = useMemo(() => {
18
+ const customHeader = customConfig.header;
19
+ let result = getTranslatedFieldName(column.id);
20
+ if (typeof customHeader === 'function') {
21
+ result = customHeader(headerContext);
22
+ } else if (typeof customHeader === 'string') {
23
+ result = customHeader;
24
+ }
25
+ return result;
26
+ }, [customConfig.header, column.id, getTranslatedFieldName]);
22
27
 
23
28
  const columSort = column.getIsSorted();
24
29
  const nextSort = columSort === 'asc' ? true : columSort === 'desc' ? undefined : false;
@@ -0,0 +1,91 @@
1
+ 'use client';
2
+
3
+ import { ColumnFiltersState, SortingState, Table } from '@tanstack/react-table';
4
+ import React, { createContext, ReactNode, useContext } from 'react';
5
+
6
+ interface DataTableContextValue {
7
+ columnFilters: ColumnFiltersState;
8
+ setColumnFilters: React.Dispatch<React.SetStateAction<ColumnFiltersState>>;
9
+ searchTerm: string;
10
+ setSearchTerm: React.Dispatch<React.SetStateAction<string>>;
11
+ sorting: SortingState;
12
+ setSorting: React.Dispatch<React.SetStateAction<SortingState>>;
13
+ pageId?: string;
14
+ onFilterChange?: (table: Table<any>, filters: ColumnFiltersState) => void;
15
+ onSearchTermChange?: (searchTerm: string) => void;
16
+ onRefresh?: () => void;
17
+ isLoading?: boolean;
18
+ table?: Table<any>;
19
+ handleApplyView: (filters: ColumnFiltersState, searchTerm?: string) => void;
20
+ }
21
+
22
+ const DataTableContext = createContext<DataTableContextValue | undefined>(undefined);
23
+
24
+ export interface DataTableProviderProps {
25
+ children: ReactNode;
26
+ columnFilters: ColumnFiltersState;
27
+ setColumnFilters: React.Dispatch<React.SetStateAction<ColumnFiltersState>>;
28
+ searchTerm: string;
29
+ setSearchTerm: React.Dispatch<React.SetStateAction<string>>;
30
+ sorting: SortingState;
31
+ setSorting: React.Dispatch<React.SetStateAction<SortingState>>;
32
+ pageId?: string;
33
+ onFilterChange?: (table: Table<any>, filters: ColumnFiltersState) => void;
34
+ onSearchTermChange?: (searchTerm: string) => void;
35
+ onRefresh?: () => void;
36
+ isLoading?: boolean;
37
+ table?: Table<any>;
38
+ }
39
+
40
+ export function DataTableProvider({
41
+ children,
42
+ columnFilters,
43
+ setColumnFilters,
44
+ searchTerm,
45
+ setSearchTerm,
46
+ sorting,
47
+ setSorting,
48
+ pageId,
49
+ onFilterChange,
50
+ onSearchTermChange,
51
+ onRefresh,
52
+ isLoading,
53
+ table,
54
+ }: DataTableProviderProps) {
55
+ const handleApplyView = (filters: ColumnFiltersState, viewSearchTerm?: string) => {
56
+ setColumnFilters(filters);
57
+ if (viewSearchTerm !== undefined && onSearchTermChange) {
58
+ setSearchTerm(viewSearchTerm);
59
+ onSearchTermChange(viewSearchTerm);
60
+ }
61
+ if (onFilterChange && table) {
62
+ onFilterChange(table, filters);
63
+ }
64
+ };
65
+
66
+ const value: DataTableContextValue = {
67
+ columnFilters,
68
+ setColumnFilters,
69
+ searchTerm,
70
+ setSearchTerm,
71
+ sorting,
72
+ setSorting,
73
+ pageId,
74
+ onFilterChange,
75
+ onSearchTermChange,
76
+ onRefresh,
77
+ isLoading,
78
+ table,
79
+ handleApplyView,
80
+ };
81
+
82
+ return <DataTableContext.Provider value={value}>{children}</DataTableContext.Provider>;
83
+ }
84
+
85
+ export function useDataTableContext() {
86
+ const context = useContext(DataTableContext);
87
+ if (context === undefined) {
88
+ throw new Error('useDataTableContext must be used within a DataTableProvider');
89
+ }
90
+ return context;
91
+ }
@@ -16,6 +16,7 @@ import {
16
16
  import { Popover, PopoverContent, PopoverTrigger } from '@/vdb/components/ui/popover.js';
17
17
  import { Separator } from '@/vdb/components/ui/separator.js';
18
18
  import { cn } from '@/vdb/lib/utils.js';
19
+ import { Trans } from '@lingui/react/macro';
19
20
 
20
21
  export interface DataTableFacetedFilterOption {
21
22
  label: string;
@@ -159,7 +160,7 @@ export function DataTableFacetedFilter<TData, TValue>({
159
160
  onSelect={() => column?.setFilterValue(undefined)}
160
161
  className="justify-center text-center"
161
162
  >
162
- Clear filters
163
+ <Trans>Clear filters</Trans>
163
164
  </CommandItem>
164
165
  </CommandGroup>
165
166
  </>
@@ -1,5 +1,5 @@
1
1
  import { useLocalFormat } from '@/vdb/hooks/use-local-format.js';
2
- import { CircleX, Filter } from 'lucide-react';
2
+ import { Filter, XIcon } from 'lucide-react';
3
3
  import { Badge } from '../ui/badge.js';
4
4
  import { HumanReadableOperator, Operator } from './human-readable-operator.js';
5
5
  import { ColumnDataType } from './types.js';
@@ -17,16 +17,20 @@ export function DataTableFilterBadge({
17
17
  }) {
18
18
  const [operator, value] = Object.entries(filter.value as Record<string, unknown>)[0];
19
19
  return (
20
- <Badge key={filter.id} className="flex gap-1 items-center" variant="secondary">
20
+ <Badge
21
+ key={filter.id}
22
+ className="flex gap-1 items-center font-mono cursor-pointer "
23
+ variant="outline"
24
+ onClick={() => onRemove(filter)}
25
+ >
21
26
  <Filter size="12" className="opacity-50" />
22
27
  <div>{filter.id}</div>
23
28
  <div className="text-muted-foreground">
24
29
  <HumanReadableOperator operator={operator as Operator} mode="short" />
25
30
  </div>
26
31
  <FilterValue value={value} dataType={dataType} currencyCode={currencyCode} />
27
- <button className="cursor-pointer" onClick={() => onRemove(filter)}>
28
- <CircleX size="14" />
29
- </button>
32
+
33
+ <XIcon className="h-4" />
30
34
  </Badge>
31
35
  );
32
36
  }
@@ -7,7 +7,7 @@ import {
7
7
  DialogHeader,
8
8
  DialogTitle,
9
9
  } from '@/vdb/components/ui/dialog.js';
10
- import { Trans } from '@/vdb/lib/trans.js';
10
+ import { Trans } from '@lingui/react/macro';
11
11
  import { Column } from '@tanstack/react-table';
12
12
  import { useState } from 'react';
13
13
  import { DataTableBooleanFilter } from './filters/data-table-boolean-filter.js';
@@ -1,4 +1,5 @@
1
- import { FieldInfo } from '@/vdb/framework/document-introspection/get-document-structure.js';
1
+ import { AccessorFnColumnDef } from '@tanstack/react-table';
2
+ import { AccessorKeyColumnDef } from '@tanstack/table-core';
2
3
 
3
4
  /**
4
5
  * Returns the default column visibility configuration.
@@ -13,7 +14,7 @@ import { FieldInfo } from '@/vdb/framework/document-introspection/get-document-s
13
14
  * ```
14
15
  */
15
16
  export function getColumnVisibility(
16
- fields: FieldInfo[],
17
+ columns: Array<AccessorKeyColumnDef<any> | AccessorFnColumnDef<any>>,
17
18
  defaultVisibility?: Record<string, boolean | undefined>,
18
19
  customFieldColumnNames?: string[],
19
20
  ): Record<string, boolean> {
@@ -23,12 +24,28 @@ export function getColumnVisibility(
23
24
  id: false,
24
25
  createdAt: false,
25
26
  updatedAt: false,
26
- ...(allDefaultsTrue ? { ...Object.fromEntries(fields.map(f => [f.name, false])) } : {}),
27
- ...(allDefaultsFalse ? { ...Object.fromEntries(fields.map(f => [f.name, true])) } : {}),
27
+ ...(allDefaultsTrue ? { ...Object.fromEntries(columns.map(f => [f.id, false])) } : {}),
28
+ ...(allDefaultsFalse ? { ...Object.fromEntries(columns.map(f => [f.id, true])) } : {}),
28
29
  // Make custom fields hidden by default unless overridden
29
30
  ...(customFieldColumnNames
30
31
  ? { ...Object.fromEntries(customFieldColumnNames.map(f => [f, false])) }
31
32
  : {}),
32
33
  ...defaultVisibility,
34
+ selection: true,
35
+ actions: true,
33
36
  };
34
37
  }
38
+
39
+ /**
40
+ * Ensures that the default column order always starts with `id`, `createdAt`, `deletedAt`
41
+ */
42
+ export function getStandardizedDefaultColumnOrder<T extends string | number | symbol>(
43
+ defaultColumnOrder?: T[],
44
+ ): T[] {
45
+ const standardFirstColumns = new Set(['id', 'createdAt', 'updatedAt']);
46
+ if (!defaultColumnOrder) {
47
+ return [...standardFirstColumns] as T[];
48
+ }
49
+ const rest = defaultColumnOrder.filter(c => !standardFirstColumns.has(c as string));
50
+ return [...standardFirstColumns, ...rest] as T[];
51
+ }
@@ -17,9 +17,11 @@ import {
17
17
  DropdownMenuTrigger,
18
18
  } from '@/vdb/components/ui/dropdown-menu.js';
19
19
  import { ScrollArea } from '@/vdb/components/ui/scroll-area.js';
20
+ import { Tooltip, TooltipContent, TooltipTrigger } from '@/vdb/components/ui/tooltip.js';
21
+ import { useDynamicTranslations } from '@/vdb/hooks/use-dynamic-translations.js';
20
22
  import { usePage } from '@/vdb/hooks/use-page.js';
21
23
  import { useUserSettings } from '@/vdb/hooks/use-user-settings.js';
22
- import { Trans } from '@/vdb/lib/trans.js';
24
+ import { Trans } from '@lingui/react/macro';
23
25
 
24
26
  interface DataTableViewOptionsProps<TData> {
25
27
  table: Table<TData>;
@@ -45,6 +47,7 @@ function SortableItem({ id, children }: { id: string; children: React.ReactNode
45
47
 
46
48
  export function DataTableViewOptions<TData>({ table }: DataTableViewOptionsProps<TData>) {
47
49
  const { setTableSettings } = useUserSettings();
50
+ const { getTranslatedFieldName } = useDynamicTranslations();
48
51
  const page = usePage();
49
52
  const columns = table
50
53
  .getAllColumns()
@@ -78,12 +81,18 @@ export function DataTableViewOptions<TData>({ table }: DataTableViewOptionsProps
78
81
  return (
79
82
  <div className="flex items-center gap-2">
80
83
  <DropdownMenu modal={false}>
81
- <DropdownMenuTrigger asChild>
82
- <Button variant="ghost" size="sm" className="ml-auto hidden h-8 lg:flex">
83
- <Settings2 />
84
- <Trans>Columns</Trans>
85
- </Button>
86
- </DropdownMenuTrigger>
84
+ <Tooltip>
85
+ <TooltipTrigger asChild>
86
+ <DropdownMenuTrigger asChild>
87
+ <Button variant="outline" size="sm" className="ml-auto hidden h-8 lg:flex">
88
+ <Settings2 />
89
+ </Button>
90
+ </DropdownMenuTrigger>
91
+ </TooltipTrigger>
92
+ <TooltipContent>
93
+ <Trans>Column settings</Trans>
94
+ </TooltipContent>
95
+ </Tooltip>
87
96
  <DropdownMenuContent align="end" className="overflow-auto">
88
97
  <ScrollArea className="max-h-[60vh]" type="always">
89
98
  <DndContext
@@ -100,17 +109,19 @@ export function DataTableViewOptions<TData>({ table }: DataTableViewOptionsProps
100
109
  <DropdownMenuCheckboxItem
101
110
  className="capitalize"
102
111
  checked={column.getIsVisible()}
103
- onCheckedChange={value => column.toggleVisibility(!!value)}
112
+ onCheckedChange={value => column.toggleVisibility(value)}
104
113
  onSelect={e => e.preventDefault()}
105
114
  >
106
- {column.id}
115
+ {getTranslatedFieldName(column.id)}
107
116
  </DropdownMenuCheckboxItem>
108
117
  </SortableItem>
109
118
  ))}
110
119
  </SortableContext>
111
120
  </DndContext>
112
121
  <DropdownMenuSeparator />
113
- <DropdownMenuItem onClick={handleReset}>Reset</DropdownMenuItem>
122
+ <DropdownMenuItem onClick={handleReset}>
123
+ <Trans>Reset</Trans>
124
+ </DropdownMenuItem>
114
125
  </ScrollArea>
115
126
  </DropdownMenuContent>
116
127
  </DropdownMenu>