@vendure/dashboard 3.5.0-minor-202509261210 → 3.5.0-minor-202510031341

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 (263) hide show
  1. package/README.md +4 -0
  2. package/dist/plugin/dashboard.plugin.d.ts +25 -6
  3. package/dist/plugin/dashboard.plugin.js +184 -27
  4. package/dist/plugin/default-page.html +188 -0
  5. package/dist/vite/vite-plugin-config.js +13 -9
  6. package/dist/vite/vite-plugin-translations.d.ts +22 -0
  7. package/dist/vite/vite-plugin-translations.js +66 -0
  8. package/dist/vite/vite-plugin-vendure-dashboard.js +8 -6
  9. package/lingui.config.js +25 -2
  10. package/package.json +159 -156
  11. package/src/app/app-providers.tsx +0 -4
  12. package/src/app/common/delete-bulk-action.tsx +6 -5
  13. package/src/app/common/duplicate-bulk-action.tsx +4 -5
  14. package/src/app/common/duplicate-entity-dialog.tsx +1 -1
  15. package/src/app/common/set-document-direction.ts +7 -0
  16. package/src/app/main.tsx +50 -17
  17. package/src/app/routes/_authenticated/_administrators/administrators.tsx +8 -6
  18. package/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx +17 -6
  19. package/src/app/routes/_authenticated/_administrators/components/role-permissions-display.tsx +2 -2
  20. package/src/app/routes/_authenticated/_assets/assets.tsx +1 -1
  21. package/src/app/routes/_authenticated/_assets/assets_.$id.tsx +4 -4
  22. package/src/app/routes/_authenticated/_assets/components/asset-bulk-actions.tsx +8 -6
  23. package/src/app/routes/_authenticated/_assets/components/asset-tag-filter.tsx +1 -1
  24. package/src/app/routes/_authenticated/_assets/components/asset-tags-editor.tsx +1 -1
  25. package/src/app/routes/_authenticated/_assets/components/manage-tags-dialog.tsx +3 -8
  26. package/src/app/routes/_authenticated/_channels/channels.tsx +3 -6
  27. package/src/app/routes/_authenticated/_channels/channels_.$id.tsx +5 -5
  28. package/src/app/routes/_authenticated/_collections/collections.tsx +3 -4
  29. package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +4 -6
  30. package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +1 -1
  31. package/src/app/routes/_authenticated/_collections/components/collection-contents-sheet.tsx +1 -1
  32. package/src/app/routes/_authenticated/_collections/components/move-collections-dialog.tsx +6 -6
  33. package/src/app/routes/_authenticated/_countries/countries.graphql.ts +2 -0
  34. package/src/app/routes/_authenticated/_countries/countries.tsx +2 -3
  35. package/src/app/routes/_authenticated/_countries/countries_.$id.tsx +4 -4
  36. package/src/app/routes/_authenticated/_customer-groups/components/customer-group-members-sheet.tsx +1 -1
  37. package/src/app/routes/_authenticated/_customer-groups/components/customer-group-members-table.tsx +4 -4
  38. package/src/app/routes/_authenticated/_customer-groups/customer-groups.tsx +2 -4
  39. package/src/app/routes/_authenticated/_customer-groups/customer-groups_.$id.tsx +13 -6
  40. package/src/app/routes/_authenticated/_customers/components/customer-address-card.tsx +8 -8
  41. package/src/app/routes/_authenticated/_customers/components/customer-address-form.tsx +3 -3
  42. package/src/app/routes/_authenticated/_customers/components/customer-history/customer-history-container.tsx +1 -1
  43. package/src/app/routes/_authenticated/_customers/components/customer-history/customer-history-utils.tsx +1 -1
  44. package/src/app/routes/_authenticated/_customers/components/customer-history/default-customer-history-components.tsx +1 -1
  45. package/src/app/routes/_authenticated/_customers/components/customer-history/use-customer-history.ts +1 -1
  46. package/src/app/routes/_authenticated/_customers/components/customer-status-badge.tsx +1 -1
  47. package/src/app/routes/_authenticated/_customers/customers.graphql.ts +4 -0
  48. package/src/app/routes/_authenticated/_customers/customers.tsx +23 -11
  49. package/src/app/routes/_authenticated/_customers/customers_.$id.tsx +10 -8
  50. package/src/app/routes/_authenticated/_facets/components/edit-facet-value.tsx +1 -1
  51. package/src/app/routes/_authenticated/_facets/components/facet-bulk-actions.tsx +6 -5
  52. package/src/app/routes/_authenticated/_facets/components/facet-values-sheet.tsx +1 -1
  53. package/src/app/routes/_authenticated/_facets/components/facet-values-table.tsx +1 -1
  54. package/src/app/routes/_authenticated/_facets/facets.tsx +5 -5
  55. package/src/app/routes/_authenticated/_facets/facets_.$facetId.values_.$id.tsx +7 -5
  56. package/src/app/routes/_authenticated/_facets/facets_.$id.tsx +4 -4
  57. package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +5 -5
  58. package/src/app/routes/_authenticated/_orders/components/add-manual-payment-dialog.tsx +19 -21
  59. package/src/app/routes/_authenticated/_orders/components/customer-address-selector.tsx +1 -1
  60. package/src/app/routes/_authenticated/_orders/components/edit-order-table.tsx +22 -22
  61. package/src/app/routes/_authenticated/_orders/components/fulfill-order-dialog.tsx +6 -6
  62. package/src/app/routes/_authenticated/_orders/components/fulfillment-details.tsx +15 -9
  63. package/src/app/routes/_authenticated/_orders/components/order-address.tsx +1 -1
  64. package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +11 -9
  65. package/src/app/routes/_authenticated/_orders/components/order-history/default-order-history-components.tsx +1 -1
  66. package/src/app/routes/_authenticated/_orders/components/order-history/order-history-container.tsx +1 -1
  67. package/src/app/routes/_authenticated/_orders/components/order-history/order-history-utils.tsx +1 -1
  68. package/src/app/routes/_authenticated/_orders/components/order-history/use-order-history.ts +1 -1
  69. package/src/app/routes/_authenticated/_orders/components/order-line-custom-fields-form.tsx +1 -1
  70. package/src/app/routes/_authenticated/_orders/components/order-modification-preview-dialog.tsx +4 -4
  71. package/src/app/routes/_authenticated/_orders/components/order-modification-summary.tsx +1 -1
  72. package/src/app/routes/_authenticated/_orders/components/order-table-totals.tsx +27 -27
  73. package/src/app/routes/_authenticated/_orders/components/order-table.tsx +2 -2
  74. package/src/app/routes/_authenticated/_orders/components/order-tax-summary.tsx +1 -1
  75. package/src/app/routes/_authenticated/_orders/components/payment-details.tsx +26 -20
  76. package/src/app/routes/_authenticated/_orders/components/seller-orders-card.tsx +3 -1
  77. package/src/app/routes/_authenticated/_orders/components/settle-refund-dialog.tsx +6 -6
  78. package/src/app/routes/_authenticated/_orders/components/shipping-method-selector.tsx +1 -1
  79. package/src/app/routes/_authenticated/_orders/components/state-transition-control.tsx +1 -1
  80. package/src/app/routes/_authenticated/_orders/components/use-transition-order-to-state.tsx +3 -2
  81. package/src/app/routes/_authenticated/_orders/orders.tsx +5 -9
  82. package/src/app/routes/_authenticated/_orders/orders_.$aggregateOrderId_.seller-orders.$sellerOrderId.tsx +1 -1
  83. package/src/app/routes/_authenticated/_orders/orders_.$id.tsx +1 -1
  84. package/src/app/routes/_authenticated/_orders/orders_.$id_.modify.tsx +4 -4
  85. package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +17 -17
  86. package/src/app/routes/_authenticated/_orders/utils/order-detail-loaders.tsx +1 -1
  87. package/src/app/routes/_authenticated/_payment-methods/payment-methods.tsx +5 -6
  88. package/src/app/routes/_authenticated/_payment-methods/payment-methods_.$id.tsx +13 -6
  89. package/src/app/routes/_authenticated/_product-variants/components/product-variant-bulk-actions.tsx +1 -1
  90. package/src/app/routes/_authenticated/_product-variants/components/variant-price-detail.tsx +1 -1
  91. package/src/app/routes/_authenticated/_product-variants/product-variants.tsx +9 -2
  92. package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +13 -6
  93. package/src/app/routes/_authenticated/_products/components/add-option-group-dialog.tsx +5 -5
  94. package/src/app/routes/_authenticated/_products/components/add-product-variant-dialog.tsx +5 -5
  95. package/src/app/routes/_authenticated/_products/components/assign-facet-values-dialog.tsx +5 -4
  96. package/src/app/routes/_authenticated/_products/components/create-product-options-dialog.tsx +9 -12
  97. package/src/app/routes/_authenticated/_products/components/create-product-variants-dialog.tsx +1 -1
  98. package/src/app/routes/_authenticated/_products/components/create-product-variants.tsx +4 -4
  99. package/src/app/routes/_authenticated/_products/components/option-groups-editor.tsx +1 -1
  100. package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +1 -1
  101. package/src/app/routes/_authenticated/_products/components/product-option-select.tsx +3 -3
  102. package/src/app/routes/_authenticated/_products/components/product-options-table.tsx +9 -6
  103. package/src/app/routes/_authenticated/_products/products.graphql.ts +31 -31
  104. package/src/app/routes/_authenticated/_products/products.tsx +11 -6
  105. package/src/app/routes/_authenticated/_products/products_.$id.tsx +4 -4
  106. package/src/app/routes/_authenticated/_products/products_.$id_.variants.tsx +11 -11
  107. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$id.tsx +8 -12
  108. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$productOptionGroupId.options_.$id.tsx +2 -2
  109. package/src/app/routes/_authenticated/_profile/profile.tsx +4 -4
  110. package/src/app/routes/_authenticated/_promotions/promotions.tsx +2 -4
  111. package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +16 -9
  112. package/src/app/routes/_authenticated/_roles/components/permissions-table-grid.tsx +1 -1
  113. package/src/app/routes/_authenticated/_roles/roles.tsx +3 -6
  114. package/src/app/routes/_authenticated/_roles/roles_.$id.tsx +4 -6
  115. package/src/app/routes/_authenticated/_sellers/sellers.tsx +3 -4
  116. package/src/app/routes/_authenticated/_sellers/sellers_.$id.tsx +4 -4
  117. package/src/app/routes/_authenticated/_shipping-methods/components/price-display.tsx +5 -5
  118. package/src/app/routes/_authenticated/_shipping-methods/components/shipping-method-test-result-wrapper.tsx +1 -1
  119. package/src/app/routes/_authenticated/_shipping-methods/components/test-address-form.tsx +4 -3
  120. package/src/app/routes/_authenticated/_shipping-methods/components/test-order-builder.tsx +4 -3
  121. package/src/app/routes/_authenticated/_shipping-methods/components/test-shipping-methods-result.tsx +8 -8
  122. package/src/app/routes/_authenticated/_shipping-methods/components/test-shipping-methods-sheet.tsx +1 -1
  123. package/src/app/routes/_authenticated/_shipping-methods/components/test-single-method-result.tsx +8 -8
  124. package/src/app/routes/_authenticated/_shipping-methods/components/test-single-shipping-method-sheet.tsx +4 -4
  125. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.tsx +2 -3
  126. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +2 -2
  127. package/src/app/routes/_authenticated/_stock-locations/stock-locations.tsx +3 -4
  128. package/src/app/routes/_authenticated/_stock-locations/stock-locations_.$id.tsx +13 -6
  129. package/src/app/routes/_authenticated/_system/healthchecks.tsx +10 -4
  130. package/src/app/routes/_authenticated/_system/job-queue.tsx +10 -13
  131. package/src/app/routes/_authenticated/_system/scheduled-tasks.tsx +18 -16
  132. package/src/app/routes/_authenticated/_tax-categories/tax-categories.tsx +2 -4
  133. package/src/app/routes/_authenticated/_tax-categories/tax-categories_.$id.tsx +13 -6
  134. package/src/app/routes/_authenticated/_tax-rates/tax-rates.tsx +8 -12
  135. package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +6 -4
  136. package/src/app/routes/_authenticated/_zones/zones.tsx +4 -4
  137. package/src/app/routes/_authenticated/_zones/zones_.$id.tsx +8 -5
  138. package/src/app/routes/_authenticated/index.tsx +6 -2
  139. package/src/app/styles.css +4 -0
  140. package/src/i18n/common-strings.ts +111 -0
  141. package/src/i18n/locales/ar.po +4777 -0
  142. package/src/i18n/locales/cs.po +4777 -0
  143. package/src/i18n/locales/de.po +4299 -1101
  144. package/src/i18n/locales/en.po +3857 -659
  145. package/src/i18n/locales/es.po +4777 -0
  146. package/src/i18n/locales/fa.po +4777 -0
  147. package/src/i18n/locales/fr.po +4777 -0
  148. package/src/i18n/locales/he.po +4777 -0
  149. package/src/i18n/locales/hr.po +4777 -0
  150. package/src/i18n/locales/it.po +4777 -0
  151. package/src/i18n/locales/ja.po +4777 -0
  152. package/src/i18n/locales/ko.po +4628 -0
  153. package/src/i18n/locales/nb.po +4777 -0
  154. package/src/i18n/locales/ne.po +4777 -0
  155. package/src/i18n/locales/nl.po +4628 -0
  156. package/src/i18n/locales/pl.po +4777 -0
  157. package/src/i18n/locales/pt_BR.po +4777 -0
  158. package/src/i18n/locales/pt_PT.po +4777 -0
  159. package/src/i18n/locales/ru.po +4777 -0
  160. package/src/i18n/locales/sv.po +4777 -0
  161. package/src/i18n/locales/tr.po +4777 -0
  162. package/src/i18n/locales/uk.po +4777 -0
  163. package/src/i18n/locales/zh_Hans.po +4777 -0
  164. package/src/i18n/locales/zh_Hant.po +4777 -0
  165. package/src/lib/components/data-input/combination-mode-input.tsx +1 -1
  166. package/src/lib/components/data-input/custom-field-list-input.tsx +11 -7
  167. package/src/lib/components/data-input/customer-group-input.tsx +27 -33
  168. package/src/lib/components/data-input/datetime-input.tsx +40 -1
  169. package/src/lib/components/data-input/default-relation-input.tsx +5 -4
  170. package/src/lib/components/data-input/product-multi-selector-input.tsx +14 -14
  171. package/src/lib/components/data-input/relation-selector.tsx +1 -1
  172. package/src/lib/components/data-input/select-with-options.tsx +1 -1
  173. package/src/lib/components/data-input/slug-input.tsx +9 -15
  174. package/src/lib/components/data-table/add-filter-menu.tsx +4 -4
  175. package/src/lib/components/data-table/data-table-bulk-action-item.tsx +8 -8
  176. package/src/lib/components/data-table/data-table-bulk-actions.tsx +4 -4
  177. package/src/lib/components/data-table/data-table-column-header.tsx +13 -8
  178. package/src/lib/components/data-table/data-table-faceted-filter.tsx +2 -1
  179. package/src/lib/components/data-table/data-table-filter-dialog.tsx +1 -1
  180. package/src/lib/components/data-table/data-table-utils.ts +21 -4
  181. package/src/lib/components/data-table/data-table-view-options.tsx +4 -2
  182. package/src/lib/components/data-table/data-table.tsx +3 -3
  183. package/src/lib/components/data-table/filters/data-table-boolean-filter.tsx +4 -4
  184. package/src/lib/components/data-table/global-views-bar.tsx +1 -1
  185. package/src/lib/components/data-table/human-readable-operator.tsx +1 -1
  186. package/src/lib/components/data-table/manage-global-views-button.tsx +1 -1
  187. package/src/lib/components/data-table/my-views-button.tsx +13 -13
  188. package/src/lib/components/data-table/refresh-button.tsx +1 -1
  189. package/src/lib/components/data-table/save-view-button.tsx +11 -11
  190. package/src/lib/components/data-table/use-generated-columns.tsx +10 -7
  191. package/src/lib/components/data-table/views-sheet.tsx +79 -71
  192. package/src/lib/components/date-range-picker.tsx +36 -34
  193. package/src/lib/components/layout/app-sidebar.tsx +3 -1
  194. package/src/lib/components/layout/channel-switcher.tsx +8 -10
  195. package/src/lib/components/layout/dev-mode-indicator.tsx +1 -1
  196. package/src/lib/components/layout/generated-breadcrumbs.tsx +10 -8
  197. package/src/lib/components/layout/language-dialog.tsx +34 -13
  198. package/src/lib/components/layout/manage-languages-dialog.tsx +1 -1
  199. package/src/lib/components/layout/nav-main.tsx +23 -13
  200. package/src/lib/components/layout/nav-user.tsx +19 -23
  201. package/src/lib/components/login/login-form.tsx +1 -1
  202. package/src/lib/components/shared/asset/asset-bulk-actions.tsx +4 -4
  203. package/src/lib/components/shared/asset/asset-focal-point-editor.tsx +1 -1
  204. package/src/lib/components/shared/asset/asset-gallery.tsx +15 -14
  205. package/src/lib/components/shared/assign-to-channel-bulk-action.tsx +11 -11
  206. package/src/lib/components/shared/assign-to-channel-dialog.tsx +6 -5
  207. package/src/lib/components/shared/channel-code-label.tsx +1 -1
  208. package/src/lib/components/shared/channel-selector.tsx +4 -4
  209. package/src/lib/components/shared/configurable-operation-multi-selector.tsx +16 -14
  210. package/src/lib/components/shared/configurable-operation-selector.tsx +1 -1
  211. package/src/lib/components/shared/confirmation-dialog.tsx +8 -8
  212. package/src/lib/components/shared/country-selector.tsx +1 -1
  213. package/src/lib/components/shared/currency-selector.tsx +4 -4
  214. package/src/lib/components/shared/custom-fields-form.tsx +8 -24
  215. package/src/lib/components/shared/customer-address-form.tsx +3 -3
  216. package/src/lib/components/shared/customer-group-selector.tsx +1 -1
  217. package/src/lib/components/shared/customer-selector.tsx +1 -1
  218. package/src/lib/components/shared/error-page.tsx +1 -1
  219. package/src/lib/components/shared/facet-value-selector.tsx +10 -10
  220. package/src/lib/components/shared/history-timeline/history-note-checkbox.tsx +1 -1
  221. package/src/lib/components/shared/history-timeline/history-note-editor.tsx +1 -1
  222. package/src/lib/components/shared/history-timeline/history-note-entry.tsx +1 -1
  223. package/src/lib/components/shared/language-selector.tsx +4 -4
  224. package/src/lib/components/shared/navigation-confirmation.tsx +1 -1
  225. package/src/lib/components/shared/paginated-list-data-table.tsx +21 -18
  226. package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +6 -5
  227. package/src/lib/components/shared/rich-text-editor/image-dialog.tsx +1 -1
  228. package/src/lib/components/shared/rich-text-editor/link-dialog.tsx +1 -1
  229. package/src/lib/components/shared/rich-text-editor/responsive-toolbar.tsx +1 -1
  230. package/src/lib/components/shared/rich-text-editor/table-edit-icons.tsx +1 -1
  231. package/src/lib/components/shared/role-code-label.tsx +1 -1
  232. package/src/lib/components/shared/role-selector.tsx +4 -4
  233. package/src/lib/components/shared/seller-selector.tsx +1 -1
  234. package/src/lib/components/shared/stock-level-label.tsx +3 -5
  235. package/src/lib/components/shared/table-cell/order-table-cell-components.tsx +3 -1
  236. package/src/lib/components/shared/tax-category-selector.tsx +1 -1
  237. package/src/lib/components/shared/translatable-form-field.tsx +15 -15
  238. package/src/lib/components/shared/zone-selector.tsx +1 -1
  239. package/src/lib/constants.ts +10 -0
  240. package/src/lib/framework/dashboard-widget/base-widget.tsx +11 -9
  241. package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +6 -4
  242. package/src/lib/framework/dashboard-widget/metrics-widget/index.tsx +8 -5
  243. package/src/lib/framework/dashboard-widget/orders-summary/index.tsx +7 -4
  244. package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +3 -1
  245. package/src/lib/framework/defaults.ts +34 -63
  246. package/src/lib/framework/layout-engine/page-layout.tsx +36 -36
  247. package/src/lib/framework/page/detail-page.tsx +10 -10
  248. package/src/lib/framework/page/use-extended-router.tsx +48 -23
  249. package/src/lib/graphql/api.ts +22 -7
  250. package/src/lib/graphql/graphql-env.d.ts +13 -25
  251. package/src/lib/hooks/use-display-locale.ts +40 -0
  252. package/src/lib/hooks/use-dynamic-translations.ts +46 -0
  253. package/src/lib/hooks/use-extended-detail-query.ts +1 -1
  254. package/src/lib/hooks/use-extended-list-query.ts +1 -1
  255. package/src/lib/hooks/use-local-format.ts +15 -1
  256. package/src/lib/hooks/use-saved-views.ts +7 -0
  257. package/src/lib/hooks/use-ui-language-loader.ts +30 -0
  258. package/src/lib/lib/load-i18n-messages.ts +17 -0
  259. package/src/lib/lib/trans.tsx +15 -11
  260. package/src/lib/providers/auth.tsx +2 -2
  261. package/src/lib/providers/channel-provider.tsx +3 -2
  262. package/src/lib/providers/i18n-provider.tsx +7 -14
  263. package/src/lib/providers/user-settings.tsx +46 -5
@@ -1,5 +1,5 @@
1
1
  import { DashboardFormComponentProps } from '@/vdb/framework/form-engine/form-engine-types.js';
2
- import { Trans } from '@/vdb/lib/trans.js';
2
+ import { Trans } from '@lingui/react/macro';
3
3
 
4
4
  export type CombinationModeInputProps = DashboardFormComponentProps & {
5
5
  position?: number;
@@ -1,6 +1,5 @@
1
1
  import { Button } from '@/vdb/components/ui/button.js';
2
2
  import { DashboardFormComponentProps } from '@/vdb/framework/form-engine/form-engine-types.js';
3
- import { useLingui } from '@/vdb/lib/trans.js';
4
3
  import {
5
4
  closestCenter,
6
5
  DndContext,
@@ -18,6 +17,7 @@ import {
18
17
  verticalListSortingStrategy,
19
18
  } from '@dnd-kit/sortable';
20
19
  import { CSS } from '@dnd-kit/utilities';
20
+ import { useLingui } from '@lingui/react/macro';
21
21
  import { GripVertical, Plus, X } from 'lucide-react';
22
22
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
23
23
  import { ControllerRenderProps } from 'react-hook-form';
@@ -53,7 +53,7 @@ function SortableItem({
53
53
  field,
54
54
  isFullWidth = false,
55
55
  }: Readonly<SortableItemProps>) {
56
- const { i18n } = useLingui();
56
+ const { t } = useLingui();
57
57
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
58
58
  id: itemWithId._id,
59
59
  disabled,
@@ -69,7 +69,7 @@ function SortableItem({
69
69
  {...attributes}
70
70
  {...listeners}
71
71
  className="cursor-move text-muted-foreground hover:text-foreground transition-colors"
72
- title={i18n.t('Drag to reorder')}
72
+ title={t`Drag to reorder`}
73
73
  >
74
74
  <GripVertical className="h-4 w-4" />
75
75
  </div>
@@ -82,7 +82,7 @@ function SortableItem({
82
82
  size="sm"
83
83
  onClick={() => onRemove(itemWithId._id)}
84
84
  className="h-6 w-6 p-0 text-muted-foreground hover:text-destructive transition-colors opacity-0 group-hover:opacity-100"
85
- title={i18n.t('Remove item')}
85
+ title={t`Remove item`}
86
86
  >
87
87
  <X className="h-3 w-3" />
88
88
  </Button>
@@ -169,9 +169,13 @@ function convertToFlatArray(itemsWithIds: ListItemWithId[]): any[] {
169
169
  return itemsWithIds.map(item => item.value);
170
170
  }
171
171
 
172
- export const CustomFieldListInput = ({ renderInput, defaultValue, ...fieldProps }: CustomFieldListInputProps) => {
172
+ export const CustomFieldListInput = ({
173
+ renderInput,
174
+ defaultValue,
175
+ ...fieldProps
176
+ }: CustomFieldListInputProps) => {
173
177
  const { value, onChange, disabled } = fieldProps;
174
- const { i18n } = useLingui();
178
+ const { t } = useLingui();
175
179
  const sensors = useSensors(
176
180
  useSensor(PointerSensor),
177
181
  useSensor(KeyboardSensor, {
@@ -282,7 +286,7 @@ export const CustomFieldListInput = ({ renderInput, defaultValue, ...fieldProps
282
286
  {!disabled && (
283
287
  <Button type="button" variant="outline" size="sm" onClick={handleAddItem} className="w-full">
284
288
  <Plus className="h-4 w-4 mr-2" />
285
- {i18n.t('Add item')}
289
+ {t`Add item`}
286
290
  </Button>
287
291
  )}
288
292
  </div>
@@ -6,13 +6,11 @@ import { CustomerGroupSelector } from '../shared/customer-group-selector.js';
6
6
 
7
7
  import { DashboardFormComponentProps } from '@/vdb/framework/form-engine/form-engine-types.js';
8
8
 
9
- const customerGroupsDocument = graphql(`
10
- query GetCustomerGroups($options: CustomerGroupListOptions) {
11
- customerGroups(options: $options) {
12
- items {
13
- id
14
- name
15
- }
9
+ const customerGroupDocument = graphql(`
10
+ query GetCustomerGroup($id: ID!) {
11
+ customerGroup(id: $id) {
12
+ id
13
+ name
16
14
  }
17
15
  }
18
16
  `);
@@ -22,47 +20,43 @@ export interface CustomerGroup {
22
20
  name: string;
23
21
  }
24
22
 
25
- export function CustomerGroupInput({ value, onChange, disabled }: Readonly<DashboardFormComponentProps>) {
26
- const ids = decodeIds(value);
27
- const { data: groups } = useQuery({
28
- queryKey: ['customerGroups', ids],
23
+ export function CustomerGroupInput({
24
+ value,
25
+ onChange,
26
+ disabled,
27
+ fieldDef,
28
+ }: Readonly<DashboardFormComponentProps>) {
29
+ console.log(fieldDef);
30
+ const { data } = useQuery({
31
+ queryKey: ['customerGroups', value],
29
32
  queryFn: () =>
30
- api.query(customerGroupsDocument, {
31
- options: {
32
- filter: {
33
- id: { in: ids },
34
- },
35
- },
33
+ api.query(customerGroupDocument, {
34
+ id: value,
36
35
  }),
36
+ enabled: !!value,
37
37
  });
38
38
 
39
39
  const onValueSelectHandler = (value: CustomerGroup) => {
40
- const newIds = new Set([...ids, value.id]);
41
- onChange(JSON.stringify(Array.from(newIds)));
40
+ onChange(value.id);
42
41
  };
43
42
 
44
- const onValueRemoveHandler = (id: string) => {
45
- const newIds = new Set(ids.filter(existingId => existingId !== id));
46
- onChange(JSON.stringify(Array.from(newIds)));
43
+ const onValueRemoveHandler = () => {
44
+ onChange(null);
47
45
  };
48
46
 
49
47
  return (
50
48
  <div>
51
49
  <div className="flex flex-wrap gap-2 mb-2">
52
- {groups?.customerGroups.items.map(group => (
53
- <CustomerGroupChip key={group.id} group={group} onRemove={onValueRemoveHandler} />
54
- ))}
50
+ {data?.customerGroup ? (
51
+ <CustomerGroupChip
52
+ key={data.customerGroup.id}
53
+ group={data.customerGroup}
54
+ onRemove={onValueRemoveHandler}
55
+ />
56
+ ) : null}
55
57
  </div>
56
58
 
57
59
  <CustomerGroupSelector onSelect={onValueSelectHandler} readOnly={disabled} />
58
60
  </div>
59
61
  );
60
62
  }
61
-
62
- function decodeIds(idsString: string): string[] {
63
- try {
64
- return JSON.parse(idsString);
65
- } catch (error) {
66
- return [];
67
- }
68
- }
@@ -2,15 +2,34 @@
2
2
 
3
3
  import { format } from 'date-fns';
4
4
  import * as React from 'react';
5
+ import { useEffect, useState } from 'react';
5
6
 
6
7
  import { Button } from '@/vdb/components/ui/button.js';
7
8
  import { Calendar } from '@/vdb/components/ui/calendar.js';
8
9
  import { Popover, PopoverContent, PopoverTrigger } from '@/vdb/components/ui/popover.js';
9
10
  import { ScrollArea, ScrollBar } from '@/vdb/components/ui/scroll-area.js';
10
11
  import { DashboardFormComponentProps } from '@/vdb/framework/form-engine/form-engine-types.js';
12
+ import { isReadonlyField } from '@/vdb/framework/form-engine/utils.js';
13
+ import { useDisplayLocale } from '@/vdb/hooks/use-display-locale.js';
11
14
  import { cn } from '@/vdb/lib/utils.js';
15
+ import type { Locale } from 'date-fns/locale';
12
16
  import { CalendarClock } from 'lucide-react';
13
- import { isReadonlyField } from '@/vdb/framework/form-engine/utils.js';
17
+
18
+ /**
19
+ * @description
20
+ * Returns a `Locale` object that can be passed to the react-day-picker
21
+ * `locale` prop.
22
+ */
23
+ export function useDayPickerLocale() {
24
+ const { bcp47Tag } = useDisplayLocale();
25
+ const [calendarLocale, setCalendarLocale] = useState<Locale | undefined>(undefined);
26
+ useEffect(() => {
27
+ import('react-day-picker/locale').then(mod => {
28
+ setCalendarLocale(bcpTagToDatePickerLocale(bcp47Tag, mod));
29
+ });
30
+ }, [bcp47Tag]);
31
+ return calendarLocale;
32
+ }
14
33
 
15
34
  /**
16
35
  * @description
@@ -21,6 +40,7 @@ import { isReadonlyField } from '@/vdb/framework/form-engine/utils.js';
21
40
  */
22
41
  export function DateTimeInput({ value, onChange, fieldDef }: Readonly<DashboardFormComponentProps>) {
23
42
  const readOnly = isReadonlyField(fieldDef);
43
+ const locale = useDayPickerLocale();
24
44
  const date = value && value instanceof Date ? value.toISOString() : (value ?? '');
25
45
  const [isOpen, setIsOpen] = React.useState(false);
26
46
 
@@ -65,6 +85,7 @@ export function DateTimeInput({ value, onChange, fieldDef }: Readonly<DashboardF
65
85
  <div className="sm:flex">
66
86
  <Calendar
67
87
  mode="single"
88
+ locale={locale}
68
89
  selected={new Date(date)}
69
90
  onSelect={handleDateSelect}
70
91
  initialFocus
@@ -137,3 +158,21 @@ export function DateTimeInput({ value, onChange, fieldDef }: Readonly<DashboardF
137
158
  </Popover>
138
159
  );
139
160
  }
161
+
162
+ function bcpTagToDatePickerLocale(
163
+ tag: string,
164
+ module: typeof import('react-day-picker/locale'),
165
+ ): Locale | undefined {
166
+ switch (tag) {
167
+ case 'zh-Hans':
168
+ return module.zhCN;
169
+ case 'zh-Hant':
170
+ return module.zhTW;
171
+ case 'pt-BR':
172
+ return module.ptBR;
173
+ default: {
174
+ const lang = tag.split('-').at(0);
175
+ return lang ? module[lang as keyof typeof module] : undefined;
176
+ }
177
+ }
178
+ }
@@ -1,5 +1,5 @@
1
1
  import { graphql } from '@/vdb/graphql/graphql.js';
2
- import { Trans, useLingui } from '@/vdb/lib/trans.js';
2
+ import { Trans, useLingui } from '@lingui/react/macro';
3
3
  import { RelationCustomFieldConfig } from '@vendure/common/lib/generated-types';
4
4
  import { ControllerRenderProps } from 'react-hook-form';
5
5
  import { MultiRelationInput, SingleRelationInput } from './relation-input.js';
@@ -100,10 +100,11 @@ function createBaseEntityConfig(
100
100
  labelKey: 'name' | 'code' | 'emailAddress' = 'name',
101
101
  searchField: string = 'name',
102
102
  ) {
103
+ const entityNameLower = entityName.toLowerCase();
103
104
  return {
104
105
  idKey: 'id',
105
106
  labelKey,
106
- placeholder: i18n.t(`Search ${entityName.toLowerCase()}s...`),
107
+ placeholder: i18n`Search ${entityNameLower}...`,
107
108
  buildSearchFilter: (term: string) => ({
108
109
  [searchField]: { contains: term },
109
110
  }),
@@ -563,12 +564,12 @@ export function DefaultRelationInput({
563
564
  ref,
564
565
  disabled,
565
566
  }: Readonly<DashboardFormComponentProps>) {
566
- const { i18n } = useLingui();
567
+ const { t } = useLingui();
567
568
  if (!fieldDef || !isRelationCustomFieldConfig(fieldDef)) {
568
569
  return null;
569
570
  }
570
571
  const entityName = fieldDef.entity;
571
- const ENTITY_CONFIGS = createEntityConfigs(i18n);
572
+ const ENTITY_CONFIGS = createEntityConfigs(t);
572
573
  const config = ENTITY_CONFIGS[entityName as keyof typeof ENTITY_CONFIGS];
573
574
 
574
575
  if (!config) {
@@ -13,7 +13,7 @@ import { Input } from '@/vdb/components/ui/input.js';
13
13
  import { DashboardFormComponent } from '@/vdb/framework/form-engine/form-engine-types.js';
14
14
  import { api } from '@/vdb/graphql/api.js';
15
15
  import { graphql } from '@/vdb/graphql/graphql.js';
16
- import { Trans } from '@/vdb/lib/trans.js';
16
+ import { Trans } from '@lingui/react/macro';
17
17
  import { useQuery } from '@tanstack/react-query';
18
18
  import { useDebounce } from '@uidotdev/usehooks';
19
19
  import { Plus, X } from 'lucide-react';
@@ -93,13 +93,13 @@ function EmptyState() {
93
93
  }
94
94
 
95
95
  function ProductList({
96
- items,
97
- mode,
98
- selectedIds,
99
- getItemId,
100
- getItemName,
101
- toggleSelection,
102
- }: Readonly<{
96
+ items,
97
+ mode,
98
+ selectedIds,
99
+ getItemId,
100
+ getItemName,
101
+ toggleSelection,
102
+ }: Readonly<{
103
103
  items: SearchItem[];
104
104
  mode: 'product' | 'variant';
105
105
  selectedIds: Set<string>;
@@ -163,12 +163,12 @@ function ProductList({
163
163
  }
164
164
 
165
165
  function ProductMultiSelectorDialog({
166
- mode,
167
- initialSelectionIds = [],
168
- onSelectionChange,
169
- open,
170
- onOpenChange,
171
- }: Readonly<ProductMultiSelectorProps>) {
166
+ mode,
167
+ initialSelectionIds = [],
168
+ onSelectionChange,
169
+ open,
170
+ onOpenChange,
171
+ }: Readonly<ProductMultiSelectorProps>) {
172
172
  const [searchTerm, setSearchTerm] = useState('');
173
173
  const [selectedItems, setSelectedItems] = useState<SearchItem[]>([]);
174
174
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
@@ -10,7 +10,7 @@ import {
10
10
  import { Popover, PopoverContent, PopoverTrigger } from '@/vdb/components/ui/popover.js';
11
11
  import { getQueryName } from '@/vdb/framework/document-introspection/get-document-structure.js';
12
12
  import { api } from '@/vdb/graphql/api.js';
13
- import { Trans } from '@/vdb/lib/trans.js';
13
+ import { Trans } from '@lingui/react/macro';
14
14
  import { cn } from '@/vdb/lib/utils.js';
15
15
  import { useInfiniteQuery } from '@tanstack/react-query';
16
16
  import { useDebounce } from '@uidotdev/usehooks';
@@ -6,7 +6,7 @@ import {
6
6
  } from '@/vdb/framework/form-engine/form-engine-types.js';
7
7
  import { isReadonlyField, isStringFieldWithOptions } from '@/vdb/framework/form-engine/utils.js';
8
8
  import { useUserSettings } from '@/vdb/hooks/use-user-settings.js';
9
- import { Trans } from '@/vdb/lib/trans.js';
9
+ import { Trans } from '@lingui/react/macro';
10
10
  import React from 'react';
11
11
  import { MultiSelect } from '../shared/multi-select.js';
12
12
 
@@ -5,8 +5,8 @@ import { isReadonlyField } from '@/vdb/framework/form-engine/utils.js';
5
5
  import { api } from '@/vdb/graphql/api.js';
6
6
  import { graphql } from '@/vdb/graphql/graphql.js';
7
7
  import { useUserSettings } from '@/vdb/hooks/use-user-settings.js';
8
- import { useLingui } from '@/vdb/lib/trans.js';
9
8
  import { cn } from '@/vdb/lib/utils.js';
9
+ import { useLingui } from '@lingui/react/macro';
10
10
  import { useQuery } from '@tanstack/react-query';
11
11
  import { useDebounce } from '@uidotdev/usehooks';
12
12
  import { Edit, Lock, RefreshCw } from 'lucide-react';
@@ -147,7 +147,7 @@ export function SlugInput({
147
147
  name,
148
148
  ...props
149
149
  }: SlugInputProps) {
150
- const { i18n } = useLingui();
150
+ const { t } = useLingui();
151
151
  const form = useFormContext();
152
152
  const { contentLanguage } = useUserSettings().settings;
153
153
  const isFormReadonly = isReadonlyField(fieldDef);
@@ -234,9 +234,9 @@ export function SlugInput({
234
234
  placeholder={
235
235
  isReadonly
236
236
  ? value
237
- ? i18n.t('Slug is set')
238
- : i18n.t('Slug will be generated automatically...')
239
- : i18n.t('Enter slug manually')
237
+ ? t`Slug is set`
238
+ : t`Slug will be generated automatically...`
239
+ : t`Enter slug manually`
240
240
  }
241
241
  className={cn(
242
242
  'pr-8',
@@ -262,8 +262,8 @@ export function SlugInput({
262
262
  size="sm"
263
263
  onClick={handleRegenerate}
264
264
  className="shrink-0"
265
- title={i18n.t('Regenerate slug from source field')}
266
- aria-label={i18n.t('Regenerate slug from source field')}
265
+ title={t`Regenerate slug from source field`}
266
+ aria-label={t`Regenerate slug from source field`}
267
267
  disabled={!watchedValue || isLoading}
268
268
  >
269
269
  <RefreshCw className="h-4 w-4" />
@@ -276,15 +276,9 @@ export function SlugInput({
276
276
  size="sm"
277
277
  onClick={toggleReadonly}
278
278
  className="shrink-0"
279
- title={
280
- isManuallyReadonly
281
- ? i18n.t('Edit slug manually')
282
- : i18n.t('Generate slug automatically')
283
- }
279
+ title={isManuallyReadonly ? t`Edit slug manually` : t`Generate slug automatically`}
284
280
  aria-label={
285
- isManuallyReadonly
286
- ? i18n.t('Edit slug manually')
287
- : i18n.t('Generate slug automatically')
281
+ isManuallyReadonly ? t`Edit slug manually` : t`Generate slug automatically`
288
282
  }
289
283
  >
290
284
  {isManuallyReadonly ? <Edit className="h-4 w-4" /> : <Lock className="h-4 w-4" />}
@@ -8,8 +8,8 @@ import {
8
8
  DropdownMenuTrigger,
9
9
  } from '@/vdb/components/ui/dropdown-menu.js';
10
10
  import { Tooltip, TooltipContent, TooltipTrigger } from '@/vdb/components/ui/tooltip.js';
11
- import { Trans } from '@/vdb/lib/trans.js';
12
- import { camelCaseToTitleCase } from '@/vdb/lib/utils.js';
11
+ import { useDynamicTranslations } from '@/vdb/hooks/use-dynamic-translations.js';
12
+ import { Trans } from '@lingui/react/macro';
13
13
  import { Column, ColumnDef } from '@tanstack/react-table';
14
14
  import { FilterIcon } from 'lucide-react';
15
15
  import { useState } from 'react';
@@ -21,7 +21,7 @@ export interface AddFilterMenuProps {
21
21
  export function AddFilterMenu({ columns }: Readonly<AddFilterMenuProps>) {
22
22
  const [selectedColumn, setSelectedColumn] = useState<ColumnDef<any> | null>(null);
23
23
  const [isDialogOpen, setIsDialogOpen] = useState(false);
24
-
24
+ const { getTranslatedFieldName } = useDynamicTranslations();
25
25
  const filterableColumns = columns.filter(column => column.getCanFilter());
26
26
 
27
27
  return (
@@ -48,7 +48,7 @@ export function AddFilterMenu({ columns }: Readonly<AddFilterMenuProps>) {
48
48
  setIsDialogOpen(true);
49
49
  }}
50
50
  >
51
- {camelCaseToTitleCase(column.id)}
51
+ {getTranslatedFieldName(column.id)}
52
52
  </DropdownMenuItem>
53
53
  ))}
54
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';
@@ -63,13 +63,13 @@ export interface DataTableBulkActionItemProps {
63
63
  * @since 3.4.0
64
64
  */
65
65
  export function DataTableBulkActionItem({
66
- label,
67
- icon: Icon,
68
- confirmationText,
69
- className,
70
- onClick,
71
- requiresPermission,
72
- }: Readonly<DataTableBulkActionItemProps>) {
66
+ label,
67
+ icon: Icon,
68
+ confirmationText,
69
+ className,
70
+ onClick,
71
+ requiresPermission,
72
+ }: Readonly<DataTableBulkActionItemProps>) {
73
73
  const [isOpen, setIsOpen] = useState(false);
74
74
  const { hasPermissions } = usePermissions();
75
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;
@@ -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
  </>
@@ -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
+ }
@@ -18,9 +18,10 @@ import {
18
18
  } from '@/vdb/components/ui/dropdown-menu.js';
19
19
  import { ScrollArea } from '@/vdb/components/ui/scroll-area.js';
20
20
  import { Tooltip, TooltipContent, TooltipTrigger } from '@/vdb/components/ui/tooltip.js';
21
+ import { useDynamicTranslations } from '@/vdb/hooks/use-dynamic-translations.js';
21
22
  import { usePage } from '@/vdb/hooks/use-page.js';
22
23
  import { useUserSettings } from '@/vdb/hooks/use-user-settings.js';
23
- import { Trans } from '@/vdb/lib/trans.js';
24
+ import { Trans } from '@lingui/react/macro';
24
25
 
25
26
  interface DataTableViewOptionsProps<TData> {
26
27
  table: Table<TData>;
@@ -46,6 +47,7 @@ function SortableItem({ id, children }: { id: string; children: React.ReactNode
46
47
 
47
48
  export function DataTableViewOptions<TData>({ table }: DataTableViewOptionsProps<TData>) {
48
49
  const { setTableSettings } = useUserSettings();
50
+ const { getTranslatedFieldName } = useDynamicTranslations();
49
51
  const page = usePage();
50
52
  const columns = table
51
53
  .getAllColumns()
@@ -110,7 +112,7 @@ export function DataTableViewOptions<TData>({ table }: DataTableViewOptionsProps
110
112
  onCheckedChange={value => column.toggleVisibility(value)}
111
113
  onSelect={e => e.preventDefault()}
112
114
  >
113
- {column.id}
115
+ {getTranslatedFieldName(column.id)}
114
116
  </DropdownMenuCheckboxItem>
115
117
  </SortableItem>
116
118
  ))}
@@ -14,7 +14,7 @@ import { BulkAction } from '@/vdb/framework/extension-api/types/index.js';
14
14
  import { useChannel } from '@/vdb/hooks/use-channel.js';
15
15
  import { usePage } from '@/vdb/hooks/use-page.js';
16
16
  import { useSavedViews } from '@/vdb/hooks/use-saved-views.js';
17
- import { Trans, useLingui } from '@/vdb/lib/trans.js';
17
+ import { Trans, useLingui } from '@lingui/react/macro';
18
18
  import {
19
19
  ColumnDef,
20
20
  ColumnFilter,
@@ -119,7 +119,7 @@ export function DataTable<TData>({
119
119
  const { pageId } = usePage();
120
120
  const savedViewsResult = useSavedViews();
121
121
  const globalViews = pageId && onFilterChange ? savedViewsResult.globalViews : [];
122
- const { i18n } = useLingui();
122
+ const { t } = useLingui();
123
123
  const [pagination, setPagination] = React.useState<PaginationState>({
124
124
  pageIndex: (page ?? 1) - 1,
125
125
  pageSize: itemsPerPage ?? 10,
@@ -214,7 +214,7 @@ export function DataTable<TData>({
214
214
  <div className="flex items-center gap-2">
215
215
  {onSearchTermChange && (
216
216
  <Input
217
- placeholder={i18n.t('Filter...')}
217
+ placeholder={t`Filter...`}
218
218
  value={searchTerm}
219
219
  onChange={event => handleSearchChange(event.target.value)}
220
220
  className="w-64"