@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
@@ -4,7 +4,7 @@ import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
4
4
  import { Button } from '@/vdb/components/ui/button.js';
5
5
  import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
6
6
  import { ListPage } from '@/vdb/framework/page/list-page.js';
7
- import { Trans } from '@/vdb/lib/trans.js';
7
+ import { Trans, useLingui } from '@lingui/react/macro';
8
8
  import { createFileRoute, Link } from '@tanstack/react-router';
9
9
  import { PlusIcon } from 'lucide-react';
10
10
  import {
@@ -20,12 +20,13 @@ export const Route = createFileRoute('/_authenticated/_payment-methods/payment-m
20
20
  });
21
21
 
22
22
  function PaymentMethodListPage() {
23
+ const { t } = useLingui();
23
24
  return (
24
25
  <ListPage
25
26
  pageId="payment-method-list"
26
27
  listQuery={paymentMethodListQuery}
27
28
  route={Route}
28
- title="Payment Methods"
29
+ title={<Trans>Payment Methods</Trans>}
29
30
  defaultVisibility={{
30
31
  name: true,
31
32
  code: true,
@@ -38,7 +39,7 @@ function PaymentMethodListPage() {
38
39
  }}
39
40
  facetedFilters={{
40
41
  enabled: {
41
- title: 'Enabled',
42
+ title: t`Enabled`,
42
43
  options: [
43
44
  { label: 'Enabled', value: true },
44
45
  { label: 'Disabled', value: false },
@@ -47,11 +48,9 @@ function PaymentMethodListPage() {
47
48
  }}
48
49
  customizeColumns={{
49
50
  name: {
50
- header: 'Name',
51
51
  cell: ({ row }) => <DetailPageButton id={row.original.id} label={row.original.name} />,
52
52
  },
53
53
  enabled: {
54
- header: 'Enabled',
55
54
  cell: ({ row }) => <BooleanDisplayBadge value={row.original.enabled} />,
56
55
  },
57
56
  }}
@@ -75,7 +74,7 @@ function PaymentMethodListPage() {
75
74
  <Button asChild>
76
75
  <Link to="./new">
77
76
  <PlusIcon className="mr-2 h-4 w-4" />
78
- New Payment Method
77
+ <Trans>New Payment Method</Trans>
79
78
  </Link>
80
79
  </Button>
81
80
  </PermissionGuard>
@@ -19,7 +19,7 @@ import {
19
19
  } from '@/vdb/framework/layout-engine/page-layout.js';
20
20
  import { detailPageRouteLoader } from '@/vdb/framework/page/detail-page-route-loader.js';
21
21
  import { useDetailPage } from '@/vdb/framework/page/use-detail-page.js';
22
- import { Trans, useLingui } from '@/vdb/lib/trans.js';
22
+ import { Trans, useLingui } from '@lingui/react/macro';
23
23
  import { createFileRoute, useNavigate } from '@tanstack/react-router';
24
24
  import { toast } from 'sonner';
25
25
  import { PaymentEligibilityCheckerSelector } from './components/payment-eligibility-checker-selector.js';
@@ -51,7 +51,7 @@ function PaymentMethodDetailPage() {
51
51
  const params = Route.useParams();
52
52
  const navigate = useNavigate();
53
53
  const creatingNewEntity = params.id === NEW_ENTITY_PATH;
54
- const { i18n } = useLingui();
54
+ const { t } = useLingui();
55
55
 
56
56
  const { form, submitHandler, entity, isPending, resetForm } = useDetailPage({
57
57
  pageId,
@@ -95,16 +95,23 @@ function PaymentMethodDetailPage() {
95
95
  },
96
96
  params: { id: params.id },
97
97
  onSuccess: async data => {
98
- toast.success(i18n.t(creatingNewEntity ? 'Successfully created payment method' : 'Successfully updated payment method'));
98
+ toast.success(
99
+ creatingNewEntity
100
+ ? t`Successfully created payment method`
101
+ : t`Successfully updated payment method`,
102
+ );
99
103
  resetForm();
100
104
  if (creatingNewEntity) {
101
105
  await navigate({ to: `../$id`, params: { id: data.id } });
102
106
  }
103
107
  },
104
108
  onError: err => {
105
- toast.error(i18n.t(creatingNewEntity ? 'Failed to create payment method' : 'Failed to update payment method'), {
106
- description: err instanceof Error ? err.message : 'Unknown error',
107
- });
109
+ toast.error(
110
+ creatingNewEntity ? t`Failed to create payment method` : t`Failed to update payment method`,
111
+ {
112
+ description: err instanceof Error ? err.message : 'Unknown error',
113
+ },
114
+ );
108
115
  },
109
116
  });
110
117
 
@@ -9,7 +9,7 @@ import { RemoveFromChannelBulkAction } from '@/vdb/components/shared/remove-from
9
9
  import { BulkActionComponent } from '@/vdb/framework/extension-api/types/data-table.js';
10
10
  import { api } from '@/vdb/graphql/api.js';
11
11
  import { useChannel } from '@/vdb/hooks/use-channel.js';
12
- import { Trans } from '@/vdb/lib/trans.js';
12
+ import { Trans } from '@lingui/react/macro';
13
13
  import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
14
14
 
15
15
  import { AssignFacetValuesDialog } from '../../_products/components/assign-facet-values-dialog.js';
@@ -2,7 +2,7 @@ import { Money } from '@/vdb/components/data-display/money.js';
2
2
  import { api } from '@/vdb/graphql/api.js';
3
3
  import { graphql } from '@/vdb/graphql/graphql.js';
4
4
  import { useChannel } from '@/vdb/hooks/use-channel.js';
5
- import { Trans } from '@/vdb/lib/trans.js';
5
+ import { Trans } from '@lingui/react/macro';
6
6
  import { useQuery } from '@tanstack/react-query';
7
7
  import { useEffect, useState } from 'react';
8
8
 
@@ -60,6 +60,16 @@ export const productVariantDetailDocument = graphql(
60
60
  name
61
61
  }
62
62
  }
63
+ options {
64
+ id
65
+ name
66
+ code
67
+ group {
68
+ id
69
+ name
70
+ code
71
+ }
72
+ }
63
73
  translations {
64
74
  id
65
75
  languageCode
@@ -3,7 +3,7 @@ import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js'
3
3
  import { StockLevelLabel } from '@/vdb/components/shared/stock-level-label.js';
4
4
  import { ListPage } from '@/vdb/framework/page/list-page.js';
5
5
  import { useLocalFormat } from '@/vdb/hooks/use-local-format.js';
6
- import { Trans } from '@/vdb/lib/trans.js';
6
+ import { Trans } from '@lingui/react/macro';
7
7
  import { createFileRoute } from '@tanstack/react-router';
8
8
  import {
9
9
  AssignFacetValuesToProductVariantsBulkAction,
@@ -25,6 +25,14 @@ function ProductListPage() {
25
25
  pageId="product-variant-list"
26
26
  title={<Trans>Product Variants</Trans>}
27
27
  listQuery={productVariantListDocument}
28
+ defaultVisibility={{
29
+ featuredAsset: true,
30
+ name: true,
31
+ sku: true,
32
+ priceWithTax: true,
33
+ enabled: true,
34
+ stockLevels: true,
35
+ }}
28
36
  bulkActions={[
29
37
  {
30
38
  component: AssignProductVariantsToChannelBulkAction,
@@ -45,7 +53,6 @@ function ProductListPage() {
45
53
  ]}
46
54
  customizeColumns={{
47
55
  name: {
48
- header: 'Product Name',
49
56
  cell: ({ row: { original } }) => (
50
57
  <DetailPageButton id={original.id} label={original.name} />
51
58
  ),
@@ -25,7 +25,7 @@ import {
25
25
  import { detailPageRouteLoader } from '@/vdb/framework/page/detail-page-route-loader.js';
26
26
  import { useDetailPage } from '@/vdb/framework/page/use-detail-page.js';
27
27
  import { useChannel } from '@/vdb/hooks/use-channel.js';
28
- import { Trans, useLingui } from '@/vdb/lib/trans.js';
28
+ import { Trans, useLingui } from '@lingui/react/macro';
29
29
  import { createFileRoute, useNavigate } from '@tanstack/react-router';
30
30
  import { Fragment } from 'react/jsx-runtime';
31
31
  import { toast } from 'sonner';
@@ -61,7 +61,7 @@ function ProductVariantDetailPage() {
61
61
  const params = Route.useParams();
62
62
  const navigate = useNavigate();
63
63
  const creatingNewEntity = params.id === NEW_ENTITY_PATH;
64
- const { i18n } = useLingui();
64
+ const { t } = useLingui();
65
65
  const { activeChannel } = useChannel();
66
66
 
67
67
  const { form, submitHandler, entity, isPending, resetForm } = useDetailPage({
@@ -97,16 +97,23 @@ function ProductVariantDetailPage() {
97
97
  },
98
98
  params: { id: params.id },
99
99
  onSuccess: data => {
100
- toast.success(i18n.t(creatingNewEntity ? 'Successfully created product variant' : 'Successfully updated product variant'));
100
+ toast.success(
101
+ creatingNewEntity
102
+ ? t`Successfully created product variant`
103
+ : t`Successfully updated product variant`,
104
+ );
101
105
  resetForm();
102
106
  if (creatingNewEntity) {
103
107
  navigate({ to: `../${(data as any)?.[0]?.id}`, from: Route.id });
104
108
  }
105
109
  },
106
110
  onError: err => {
107
- toast.error(i18n.t(creatingNewEntity ? 'Failed to create product variant' : 'Failed to update product variant'), {
108
- description: err instanceof Error ? err.message : 'Unknown error',
109
- });
111
+ toast.error(
112
+ creatingNewEntity ? t`Failed to create product variant` : t`Failed to update product variant`,
113
+ {
114
+ description: err instanceof Error ? err.message : 'Unknown error',
115
+ },
116
+ );
110
117
  },
111
118
  });
112
119
 
@@ -9,8 +9,8 @@ import {
9
9
  } from '@/vdb/components/ui/dialog.js';
10
10
  import { Form } from '@/vdb/components/ui/form.js';
11
11
  import { api } from '@/vdb/graphql/api.js';
12
- import { Trans, useLingui } from '@/vdb/lib/trans.js';
13
12
  import { zodResolver } from '@hookform/resolvers/zod';
13
+ import { Trans, useLingui } from '@lingui/react/macro';
14
14
  import { useMutation } from '@tanstack/react-query';
15
15
  import { Plus, Save } from 'lucide-react';
16
16
  import { useState } from 'react';
@@ -27,7 +27,7 @@ export function AddOptionGroupDialog({
27
27
  onSuccess?: () => void;
28
28
  }>) {
29
29
  const [open, setOpen] = useState(false);
30
- const { i18n } = useLingui();
30
+ const { t } = useLingui();
31
31
 
32
32
  const form = useForm<OptionGroup>({
33
33
  resolver: zodResolver(optionGroupSchema),
@@ -79,12 +79,12 @@ export function AddOptionGroupDialog({
79
79
  });
80
80
  }
81
81
 
82
- toast.success(i18n.t('Successfully created option group'));
82
+ toast.success(t`Successfully created option group`);
83
83
  setOpen(false);
84
84
  onSuccess?.();
85
85
  } catch (error) {
86
- toast.error(i18n.t('Failed to create option group'), {
87
- description: error instanceof Error ? error.message : i18n.t('Unknown error'),
86
+ toast.error(t`Failed to create option group`, {
87
+ description: error instanceof Error ? error.message : t`Unknown error`,
88
88
  });
89
89
  }
90
90
  };
@@ -14,8 +14,8 @@ import { Input } from '@/vdb/components/ui/input.js';
14
14
  import { api } from '@/vdb/graphql/api.js';
15
15
  import { graphql, ResultOf, VariablesOf } from '@/vdb/graphql/graphql.js';
16
16
  import { useChannel } from '@/vdb/hooks/use-channel.js';
17
- import { Trans, useLingui } from '@/vdb/lib/trans.js';
18
17
  import { zodResolver } from '@hookform/resolvers/zod';
18
+ import { Trans, useLingui } from '@lingui/react/macro';
19
19
  import { useMutation, useQuery } from '@tanstack/react-query';
20
20
  import { Plus } from 'lucide-react';
21
21
  import { useCallback, useEffect, useState } from 'react';
@@ -83,7 +83,7 @@ export function AddProductVariantDialog({
83
83
  }) {
84
84
  const [open, setOpen] = useState(false);
85
85
  const { activeChannel } = useChannel();
86
- const { i18n } = useLingui();
86
+ const { t } = useLingui();
87
87
  const [duplicateVariantError, setDuplicateVariantError] = useState<string | null>(null);
88
88
  const [nameTouched, setNameTouched] = useState(false);
89
89
 
@@ -166,13 +166,13 @@ export function AddProductVariantDialog({
166
166
  const createProductVariantMutation = useMutation({
167
167
  mutationFn: api.mutate(createProductVariantDocument),
168
168
  onSuccess: (result: ResultOf<typeof createProductVariantDocument>) => {
169
- toast.success(i18n.t('Successfully created product variant'));
169
+ toast.success(t`Successfully created product variant`);
170
170
  setOpen(false);
171
171
  onSuccess?.();
172
172
  },
173
173
  onError: error => {
174
- toast.error(i18n.t('Failed to create product variant'), {
175
- description: error instanceof Error ? error.message : i18n.t('Unknown error'),
174
+ toast.error(t`Failed to create product variant`, {
175
+ description: error instanceof Error ? error.message : t`Unknown error`,
176
176
  });
177
177
  },
178
178
  });
@@ -14,7 +14,7 @@ import {
14
14
  DialogTitle,
15
15
  } from '@/vdb/components/ui/dialog.js';
16
16
  import { ResultOf } from '@/vdb/graphql/graphql.js';
17
- import { Trans, useLingui } from '@/vdb/lib/trans.js';
17
+ import { Trans, useLingui } from '@lingui/react/macro';
18
18
 
19
19
  import { getDetailQueryOptions } from '@/vdb/framework/page/use-detail-page.js';
20
20
 
@@ -55,11 +55,12 @@ export function AssignFacetValuesDialog({
55
55
  detailDocument,
56
56
  onSuccess,
57
57
  }: AssignFacetValuesDialogProps) {
58
- const { i18n } = useLingui();
58
+ const { t } = useLingui();
59
59
  const [selectedValues, setSelectedValues] = useState<FacetValue[]>([]);
60
60
  const [facetValuesRemoved, setFacetValuesRemoved] = useState(false);
61
61
  const [removedFacetValues, setRemovedFacetValues] = useState<Set<string>>(new Set());
62
62
  const queryClient = useQueryClient();
63
+ const entityIdsLength = entityIds.length;
63
64
 
64
65
  // Fetch existing facet values for the entities
65
66
  const { data: entitiesData, isLoading } = useQuery({
@@ -71,7 +72,7 @@ export function AssignFacetValuesDialog({
71
72
  const { mutate, isPending } = useMutation({
72
73
  mutationFn,
73
74
  onSuccess: () => {
74
- toast.success(i18n.t(`Successfully updated facet values for ${entityIds.length} ${entityType}`));
75
+ toast.success(t`Successfully updated facet values for ${entityIdsLength} ${entityType}`);
75
76
  onSuccess?.();
76
77
  onOpenChange(false);
77
78
  // Reset state
@@ -84,7 +85,7 @@ export function AssignFacetValuesDialog({
84
85
  });
85
86
  },
86
87
  onError: () => {
87
- toast.error(`Failed to update facet values for ${entityIds.length} ${entityType}`);
88
+ toast.error(`Failed to update facet values for ${entityIdsLength} ${entityType}`);
88
89
  },
89
90
  });
90
91
 
@@ -12,8 +12,8 @@ import { Form } from '@/vdb/components/ui/form.js';
12
12
  import { Input } from '@/vdb/components/ui/input.js';
13
13
  import { api } from '@/vdb/graphql/api.js';
14
14
  import { graphql } from '@/vdb/graphql/graphql.js';
15
- import { Trans, useLingui } from '@/vdb/lib/trans.js';
16
15
  import { zodResolver } from '@hookform/resolvers/zod';
16
+ import { Trans, useLingui } from '@lingui/react/macro';
17
17
  import { useMutation, useQuery } from '@tanstack/react-query';
18
18
  import { Plus, Trash2 } from 'lucide-react';
19
19
  import { useState } from 'react';
@@ -90,7 +90,7 @@ export function CreateProductOptionsDialog({
90
90
  onSuccess?: () => void;
91
91
  }) {
92
92
  const [open, setOpen] = useState(false);
93
- const { i18n } = useLingui();
93
+ const { t } = useLingui();
94
94
 
95
95
  const { data: productData } = useQuery({
96
96
  queryKey: ['product', productId],
@@ -116,13 +116,13 @@ export function CreateProductOptionsDialog({
116
116
  const updateProductVariantMutation = useMutation({
117
117
  mutationFn: api.mutate(updateProductVariantDocument),
118
118
  onSuccess: () => {
119
- toast.success(i18n.t('Successfully created product options'));
119
+ toast.success(t`Successfully created product options`);
120
120
  setOpen(false);
121
121
  onSuccess?.();
122
122
  },
123
123
  onError: error => {
124
- toast.error(i18n.t('Failed to create product options'), {
125
- description: error instanceof Error ? error.message : i18n.t('Unknown error'),
124
+ toast.error(t`Failed to create product options`, {
125
+ description: error instanceof Error ? error.message : t`Unknown error`,
126
126
  });
127
127
  },
128
128
  });
@@ -206,8 +206,8 @@ export function CreateProductOptionsDialog({
206
206
  });
207
207
  }
208
208
  } catch (error) {
209
- toast.error(i18n.t('Failed to create product options'), {
210
- description: error instanceof Error ? error.message : i18n.t('Unknown error'),
209
+ toast.error(t`Failed to create product options`, {
210
+ description: error instanceof Error ? error.message : t`Unknown error`,
211
211
  });
212
212
  }
213
213
  };
@@ -266,7 +266,7 @@ export function CreateProductOptionsDialog({
266
266
  name={`optionGroups.${groupIndex}.name`}
267
267
  label={<Trans>Option group name</Trans>}
268
268
  render={({ field }) => (
269
- <Input {...field} placeholder={i18n.t('e.g. Size')} />
269
+ <Input {...field} placeholder={t`e.g. Size`} />
270
270
  )}
271
271
  />
272
272
  {groupIndex > 0 && (
@@ -287,10 +287,7 @@ export function CreateProductOptionsDialog({
287
287
  name={`optionGroups.${groupIndex}.options.${optionIndex}`}
288
288
  label={<Trans>Option name</Trans>}
289
289
  render={({ field }) => (
290
- <Input
291
- {...field}
292
- placeholder={i18n.t('e.g. Small')}
293
- />
290
+ <Input {...field} placeholder={t`e.g. Small`} />
294
291
  )}
295
292
  />
296
293
  {optionIndex > 0 && (
@@ -10,7 +10,7 @@ import {
10
10
  } from '@/vdb/components/ui/dialog.js';
11
11
  import { api } from '@/vdb/graphql/api.js';
12
12
  import { useChannel } from '@/vdb/hooks/use-channel.js';
13
- import { Trans } from '@/vdb/lib/trans.js';
13
+ import { Trans } from '@lingui/react/macro';
14
14
  import { normalizeString } from '@/vdb/lib/utils.js';
15
15
  import { useMutation } from '@tanstack/react-query';
16
16
  import { Plus } from 'lucide-react';
@@ -5,7 +5,7 @@ import { Input } from '@/vdb/components/ui/input.js';
5
5
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/vdb/components/ui/table.js';
6
6
  import { api } from '@/vdb/graphql/api.js';
7
7
  import { graphql } from '@/vdb/graphql/graphql.js';
8
- import { Trans } from '@/vdb/lib/trans.js';
8
+ import { Trans } from '@lingui/react/macro';
9
9
  import { zodResolver } from '@hookform/resolvers/zod';
10
10
  import { useQuery } from '@tanstack/react-query';
11
11
  import { useEffect, useMemo, useState } from 'react';
@@ -83,9 +83,9 @@ interface CreateProductVariantsProps {
83
83
  }
84
84
 
85
85
  export function CreateProductVariants({
86
- currencyCode = 'USD',
87
- onChange,
88
- }: Readonly<CreateProductVariantsProps>) {
86
+ currencyCode = 'USD',
87
+ onChange,
88
+ }: Readonly<CreateProductVariantsProps>) {
89
89
  const { data: stockLocationsResult } = useQuery({
90
90
  queryKey: ['stockLocations'],
91
91
  queryFn: () => api.query(getStockLocationsDocument, { options: { take: 100 } }),
@@ -2,7 +2,7 @@ import { FormFieldWrapper } from '@/vdb/components/shared/form-field-wrapper.js'
2
2
  import { Button } from '@/vdb/components/ui/button.js';
3
3
  import { Form } from '@/vdb/components/ui/form.js';
4
4
  import { Input } from '@/vdb/components/ui/input.js';
5
- import { Trans } from '@/vdb/lib/trans.js';
5
+ import { Trans } from '@lingui/react/macro';
6
6
  import { zodResolver } from '@hookform/resolvers/zod';
7
7
  import { Plus, Trash2 } from 'lucide-react';
8
8
  import { useEffect } from 'react';
@@ -9,7 +9,7 @@ import { RemoveFromChannelBulkAction } from '@/vdb/components/shared/remove-from
9
9
  import { BulkActionComponent } from '@/vdb/framework/extension-api/types/data-table.js';
10
10
  import { api } from '@/vdb/graphql/api.js';
11
11
  import { useChannel } from '@/vdb/hooks/use-channel.js';
12
- import { Trans } from '@/vdb/lib/trans.js';
12
+ import { Trans } from '@lingui/react/macro';
13
13
  import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
14
14
  import { DuplicateBulkAction } from '../../../../common/duplicate-bulk-action.js';
15
15
  import {
@@ -0,0 +1,19 @@
1
+ import { Badge } from '@/vdb/components/ui/badge.js';
2
+ import { Link } from '@tanstack/react-router';
3
+ import { Edit2 } from 'lucide-react';
4
+
5
+ interface ProductOptionGroupBadgeProps {
6
+ id: string;
7
+ name: string;
8
+ }
9
+
10
+ export function ProductOptionGroupBadge({ id, name }: ProductOptionGroupBadgeProps) {
11
+ return (
12
+ <Badge variant="secondary" className="text-xs">
13
+ <span>{name}</span>
14
+ <Link to={`option-groups/${id}`} className="ml-1.5 inline-flex">
15
+ <Edit2 className="h-3 w-3" />
16
+ </Link>
17
+ </Badge>
18
+ );
19
+ }
@@ -8,8 +8,8 @@ import {
8
8
  CommandItem,
9
9
  } from '@/vdb/components/ui/command.js';
10
10
  import { Popover, PopoverContent, PopoverTrigger } from '@/vdb/components/ui/popover.js';
11
- import { Trans, useLingui } from '@/vdb/lib/trans.js';
12
11
  import { cn } from '@/vdb/lib/utils.js';
12
+ import { Trans, useLingui } from '@lingui/react/macro';
13
13
  import { Check, ChevronsUpDown, Plus } from 'lucide-react';
14
14
  import { useState } from 'react';
15
15
 
@@ -41,7 +41,7 @@ export function ProductOptionSelect({
41
41
  }: Readonly<ProductOptionSelectProps>) {
42
42
  const [open, setOpen] = useState(false);
43
43
  const [newOptionInput, setNewOptionInput] = useState('');
44
- const { i18n } = useLingui();
44
+ const { t } = useLingui();
45
45
 
46
46
  return (
47
47
  <FormFieldWrapper
@@ -63,7 +63,7 @@ export function ProductOptionSelect({
63
63
  <PopoverContent className="w-full p-0">
64
64
  <Command>
65
65
  <CommandInput
66
- placeholder={i18n.t('Search {name}...').replace('{name}', group.name)}
66
+ placeholder={t`Search {name}...`.replace('{name}', group.name)}
67
67
  onValueChange={setNewOptionInput}
68
68
  />
69
69
  <CommandEmpty className="py-2">
@@ -0,0 +1,114 @@
1
+ import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js';
2
+ import { PaginatedListDataTable } from '@/vdb/components/shared/paginated-list-data-table.js';
3
+ import { Button } from '@/vdb/components/ui/button.js';
4
+ import { graphql } from '@/vdb/graphql/graphql.js';
5
+ import { Trans } from '@lingui/react/macro';
6
+ import { Link } from '@tanstack/react-router';
7
+ import { ColumnFiltersState, SortingState, VisibilityState } from '@tanstack/react-table';
8
+ import { PlusIcon } from 'lucide-react';
9
+ import { useRef, useState } from 'react';
10
+ import { deleteProductOptionDocument } from '../product-option-groups.graphql.js';
11
+
12
+ export const productOptionListDocument = graphql(`
13
+ query ProductOptionList($options: ProductOptionListOptions, $groupId: ID) {
14
+ productOptions(options: $options, groupId: $groupId) {
15
+ items {
16
+ id
17
+ createdAt
18
+ updatedAt
19
+ name
20
+ code
21
+ }
22
+ totalItems
23
+ }
24
+ }
25
+ `);
26
+
27
+ export interface ProductOptionsTableProps {
28
+ productOptionGroupId: string;
29
+ registerRefresher?: (refresher: () => void) => void;
30
+ }
31
+
32
+ export function ProductOptionsTable({
33
+ productOptionGroupId,
34
+ registerRefresher,
35
+ }: Readonly<ProductOptionsTableProps>) {
36
+ const [sorting, setSorting] = useState<SortingState>([]);
37
+ const [page, setPage] = useState(1);
38
+ const [pageSize, setPageSize] = useState(10);
39
+ const [filters, setFilters] = useState<ColumnFiltersState>([]);
40
+ const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({
41
+ name: true,
42
+ code: true,
43
+ });
44
+ const refreshRef = useRef<() => void>(() => {});
45
+
46
+ return (
47
+ <>
48
+ <PaginatedListDataTable
49
+ listQuery={productOptionListDocument}
50
+ deleteMutation={deleteProductOptionDocument}
51
+ page={page}
52
+ itemsPerPage={pageSize}
53
+ sorting={sorting}
54
+ columnFilters={filters}
55
+ onPageChange={(_, page, perPage) => {
56
+ setPage(page);
57
+ setPageSize(perPage);
58
+ }}
59
+ onSortChange={(_, sorting) => {
60
+ setSorting(sorting);
61
+ }}
62
+ onColumnVisibilityChange={(_, value) => setColumnVisibility(value)}
63
+ onFilterChange={(_, filters) => {
64
+ setFilters(filters);
65
+ }}
66
+ registerRefresher={refresher => {
67
+ refreshRef.current = refresher;
68
+ registerRefresher?.(refresher);
69
+ }}
70
+ transformVariables={variables => {
71
+ const filter = variables.options?.filter ?? {};
72
+ return {
73
+ options: {
74
+ filter: {
75
+ ...filter,
76
+ groupId: { eq: productOptionGroupId },
77
+ },
78
+ sort: variables.options?.sort,
79
+ take: pageSize,
80
+ skip: (page - 1) * pageSize,
81
+ },
82
+ };
83
+ }}
84
+ onSearchTermChange={searchTerm => {
85
+ return {
86
+ name: {
87
+ contains: searchTerm,
88
+ },
89
+ };
90
+ }}
91
+ defaultVisibility={columnVisibility}
92
+ customizeColumns={{
93
+ name: {
94
+ cell: ({ row }) => (
95
+ <DetailPageButton
96
+ id={row.original.id}
97
+ label={row.original.name}
98
+ href={`options/${row.original.id}`}
99
+ />
100
+ ),
101
+ },
102
+ }}
103
+ />
104
+ <div className="mt-4">
105
+ <Button asChild variant="outline">
106
+ <Link to="./options/new">
107
+ <PlusIcon />
108
+ <Trans>Add product option</Trans>
109
+ </Link>
110
+ </Button>
111
+ </div>
112
+ </>
113
+ );
114
+ }