@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
@@ -0,0 +1,40 @@
1
+ import { useUserSettings } from './use-user-settings.js';
2
+
3
+ const rtlLanguageCodes = ['ar', 'he', 'fa', 'ur', 'ps'];
4
+
5
+ /**
6
+ * @description
7
+ * Returns information about the current display language & region.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * const {
12
+ * bcp47Tag,
13
+ * humanReadableLanguageAndLocale,
14
+ * humanReadableLanguage,
15
+ * isRTL,
16
+ * } = useDisplayLocale();
17
+ *
18
+ * console.log(bcp47Tag) // "en-GB"
19
+ * console.log(humanReadableLanguage) // "English"
20
+ * console.log(humanReadableLanguageAndLocale) // "British English"
21
+ * console.log(isRTL) // false
22
+ * ```
23
+ *
24
+ * @docsCategory hooks
25
+ * @docsPage useDisplayLocale
26
+ */
27
+ export function useDisplayLocale() {
28
+ const { settings } = useUserSettings();
29
+ const language = settings.displayLanguage.replace(/[_-]/, '-');
30
+ const locale = settings.displayLocale;
31
+ const bcp47Tag = language.match(/[_-]/)
32
+ ? language.replace(/[_-]/, '-')
33
+ : [language, locale].filter(x => !!x).join('-');
34
+ const humanReadableLanguageAndLocale = new Intl.DisplayNames([bcp47Tag], { type: 'language' }).of(
35
+ bcp47Tag,
36
+ );
37
+ const isRTL = rtlLanguageCodes.includes(language);
38
+ const humanReadableLanguage = new Intl.DisplayNames([bcp47Tag], { type: 'language' }).of(language);
39
+ return { bcp47Tag, humanReadableLanguageAndLocale, humanReadableLanguage, isRTL };
40
+ }
@@ -0,0 +1,46 @@
1
+ import { camelCaseToTitleCase } from '@/vdb/lib/utils.js';
2
+ import { useLingui } from '@lingui/react';
3
+
4
+ export function useDynamicTranslations() {
5
+ const { i18n } = useLingui();
6
+
7
+ const getTranslatedFieldName = (fieldId: string) => {
8
+ const fieldNameTranslationId = `fieldName.${fieldId}`;
9
+ const translatedDisplay = i18n.t(fieldNameTranslationId);
10
+ return translatedDisplay !== fieldNameTranslationId
11
+ ? translatedDisplay
12
+ : camelCaseToTitleCase(fieldId);
13
+ };
14
+
15
+ const getTranslatedOrderState = (state: string) => {
16
+ const stateTranslationId = `orderState.${state}`;
17
+ const translatedDisplay = i18n.t(stateTranslationId);
18
+ return translatedDisplay !== stateTranslationId ? translatedDisplay : camelCaseToTitleCase(state);
19
+ };
20
+
21
+ const getTranslatedFulfillmentState = (state: string) => {
22
+ const stateTranslationId = `fulfillmentState.${state}`;
23
+ const translatedDisplay = i18n.t(stateTranslationId);
24
+ return translatedDisplay !== stateTranslationId ? translatedDisplay : camelCaseToTitleCase(state);
25
+ };
26
+
27
+ const getTranslatedPaymentState = (state: string) => {
28
+ const stateTranslationId = `paymentState.${state}`;
29
+ const translatedDisplay = i18n.t(stateTranslationId);
30
+ return translatedDisplay !== stateTranslationId ? translatedDisplay : camelCaseToTitleCase(state);
31
+ };
32
+
33
+ const getTranslatedRefundState = (state: string) => {
34
+ const stateTranslationId = `refundState.${state}`;
35
+ const translatedDisplay = i18n.t(stateTranslationId);
36
+ return translatedDisplay !== stateTranslationId ? translatedDisplay : camelCaseToTitleCase(state);
37
+ };
38
+
39
+ return {
40
+ getTranslatedFieldName,
41
+ getTranslatedOrderState,
42
+ getTranslatedFulfillmentState,
43
+ getTranslatedPaymentState,
44
+ getTranslatedRefundState,
45
+ };
46
+ }
@@ -1,5 +1,5 @@
1
1
  import { extendDetailFormQuery } from '@/vdb/framework/document-extension/extend-detail-form-query.js';
2
- import { useLingui } from '@/vdb/lib/trans.js';
2
+ import { useLingui } from '@lingui/react/macro';
3
3
  import { DocumentNode } from 'graphql';
4
4
  import { useEffect, useMemo, useRef } from 'react';
5
5
  import { toast } from 'sonner';
@@ -1,6 +1,6 @@
1
1
  import { getListQueryDocuments } from '@/vdb/framework/data-table/data-table-extensions.js';
2
2
  import { extendDocument } from '@/vdb/framework/document-extension/extend-document.js';
3
- import { useLingui } from '@/vdb/lib/trans.js';
3
+ import { useLingui } from '@lingui/react/macro';
4
4
  import { DocumentNode } from 'graphql';
5
5
  import { useEffect, useMemo, useRef } from 'react';
6
6
  import { toast } from 'sonner';
@@ -8,6 +8,11 @@ import { toast } from 'sonner';
8
8
  import { usePageBlock } from './use-page-block.js';
9
9
  import { usePage } from './use-page.js';
10
10
 
11
+ /**
12
+ * @description
13
+ * Extends the given list query document with additional fields that can be
14
+ * supplied via the Dashboard Extension API.
15
+ */
11
16
  export function useExtendedListQuery<T extends DocumentNode>(listQuery: T) {
12
17
  const { pageId } = usePage();
13
18
  const { blockId } = usePageBlock() ?? {};
@@ -1,5 +1,6 @@
1
1
  import { useCallback, useMemo } from 'react';
2
2
 
3
+ import { useDisplayLocale } from './use-display-locale.js';
3
4
  import { useServerConfig } from './use-server-config.js';
4
5
 
5
6
  /**
@@ -26,7 +27,8 @@ import { useServerConfig } from './use-server-config.js';
26
27
  export function useLocalFormat() {
27
28
  const { moneyStrategyPrecision } = useServerConfig() ?? { moneyStrategyPrecision: 2 };
28
29
  const precisionFactor = useMemo(() => Math.pow(10, moneyStrategyPrecision), [moneyStrategyPrecision]);
29
- const locale = 'en';
30
+ const { bcp47Tag } = useDisplayLocale();
31
+ const locale = bcp47Tag;
30
32
 
31
33
  const toMajorUnits = useCallback(
32
34
  (value: number): number => {
@@ -119,6 +121,17 @@ export function useLocalFormat() {
119
121
  [locale],
120
122
  );
121
123
 
124
+ const formatRegionName = useCallback(
125
+ (value: string): string => {
126
+ try {
127
+ return new Intl.DisplayNames([locale], { type: 'region' }).of(value) ?? value;
128
+ } catch (e: any) {
129
+ return value;
130
+ }
131
+ },
132
+ [locale],
133
+ );
134
+
122
135
  const formatCurrencyName = useCallback(
123
136
  (currencyCode: string, display: 'full' | 'symbol' | 'name' = 'full'): string => {
124
137
  if (!currencyCode) return '';
@@ -154,6 +167,7 @@ export function useLocalFormat() {
154
167
  formatDate,
155
168
  formatRelativeDate,
156
169
  formatLanguageName,
170
+ formatRegionName,
157
171
  formatCurrencyName,
158
172
  toMajorUnits,
159
173
  toMinorUnits,
@@ -0,0 +1,230 @@
1
+ import { api } from '@/vdb/graphql/api.js';
2
+ import {
3
+ getSettingsStoreValueDocument,
4
+ setSettingsStoreValueDocument,
5
+ } from '@/vdb/graphql/settings-store-operations.js';
6
+ import { SavedView, SavedViewsStore, SaveViewInput, UpdateViewInput } from '@/vdb/types/saved-views.js';
7
+ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
8
+ import { ColumnFiltersState } from '@tanstack/react-table';
9
+
10
+ import { usePageBlock } from './use-page-block.js';
11
+ import { usePage } from './use-page.js';
12
+ import { usePermissions } from './use-permissions.js';
13
+
14
+ const generateId = () => {
15
+ const array = new Uint32Array(2);
16
+ crypto.getRandomValues(array);
17
+ return array[0].toString(36) + array[1].toString(36);
18
+ };
19
+
20
+ export function useSavedViews() {
21
+ const queryClient = useQueryClient();
22
+ const { pageId } = usePage();
23
+ const pageBlock = usePageBlock({ optional: true });
24
+ const blockId = pageBlock?.blockId || 'default';
25
+
26
+ if (!pageId) {
27
+ throw new Error('useSavedViews must be used within a Page context');
28
+ }
29
+
30
+ const userViewsKey = 'vendure.dashboard.userSavedViews';
31
+ const globalViewsKey = 'vendure.dashboard.globalSavedViews';
32
+
33
+ // Query for user views
34
+ const { data: userViewsData, isLoading: userViewsLoading } = useQuery({
35
+ queryKey: ['saved-views-user', pageId, blockId],
36
+ queryFn: async () => {
37
+ const result = await api.query(getSettingsStoreValueDocument, { key: userViewsKey });
38
+ const allUserViews = (result?.getSettingsStoreValue as SavedViewsStore) || {};
39
+ return allUserViews[pageId]?.[blockId] || [];
40
+ },
41
+ });
42
+
43
+ // Query for global views
44
+ const { data: globalViewsData, isLoading: globalViewsLoading } = useQuery({
45
+ queryKey: ['saved-views-global', pageId, blockId],
46
+ queryFn: async () => {
47
+ const result = await api.query(getSettingsStoreValueDocument, { key: globalViewsKey });
48
+ const allGlobalViews = (result?.getSettingsStoreValue as SavedViewsStore) || {};
49
+ return allGlobalViews[pageId]?.[blockId] || [];
50
+ },
51
+ });
52
+
53
+ // Save user view mutation
54
+ const saveUserViewMutation = useMutation({
55
+ mutationFn: async (views: SavedView[]) => {
56
+ // Get current data first
57
+ const result = await api.query(getSettingsStoreValueDocument, { key: userViewsKey });
58
+ const allUserViews = (result?.getSettingsStoreValue as SavedViewsStore) || {};
59
+
60
+ // Update the specific page and block
61
+ const updatedViews = {
62
+ ...allUserViews,
63
+ [pageId]: {
64
+ ...allUserViews[pageId],
65
+ [blockId]: views,
66
+ },
67
+ };
68
+
69
+ return api.mutate(setSettingsStoreValueDocument, {
70
+ input: { key: userViewsKey, value: updatedViews },
71
+ });
72
+ },
73
+ onSuccess: () => {
74
+ void queryClient.invalidateQueries({ queryKey: ['saved-views-user', pageId, blockId] });
75
+ },
76
+ });
77
+
78
+ // Save global view mutation
79
+ const saveGlobalViewMutation = useMutation({
80
+ mutationFn: async (views: SavedView[]) => {
81
+ // Get current data first
82
+ const result = await api.query(getSettingsStoreValueDocument, { key: globalViewsKey });
83
+ const allGlobalViews = (result?.getSettingsStoreValue as SavedViewsStore) || {};
84
+
85
+ // Update the specific page and block
86
+ const updatedViews = {
87
+ ...allGlobalViews,
88
+ [pageId]: {
89
+ ...allGlobalViews[pageId],
90
+ [blockId]: views,
91
+ },
92
+ };
93
+
94
+ return api.mutate(setSettingsStoreValueDocument, {
95
+ input: { key: globalViewsKey, value: updatedViews },
96
+ });
97
+ },
98
+ onSuccess: () => {
99
+ void queryClient.invalidateQueries({ queryKey: ['saved-views-global', pageId, blockId] });
100
+ },
101
+ });
102
+
103
+ const saveView = async (input: SaveViewInput) => {
104
+ const newView: SavedView = {
105
+ id: generateId(),
106
+ name: input.name,
107
+ scope: input.scope,
108
+ filters: input.filters,
109
+ searchTerm: input.searchTerm,
110
+ pageId,
111
+ blockId: blockId === 'default' ? undefined : blockId,
112
+ createdAt: new Date().toISOString(),
113
+ updatedAt: new Date().toISOString(),
114
+ };
115
+
116
+ if (input.scope === 'user') {
117
+ const currentViews = userViewsData || [];
118
+ await saveUserViewMutation.mutateAsync([...currentViews, newView]);
119
+ } else {
120
+ const currentViews = globalViewsData || [];
121
+ await saveGlobalViewMutation.mutateAsync([...currentViews, newView]);
122
+ }
123
+
124
+ return newView;
125
+ };
126
+
127
+ const updateView = async (input: UpdateViewInput) => {
128
+ const userViews = userViewsData || [];
129
+ const globalViews = globalViewsData || [];
130
+
131
+ const viewInUserViews = userViews.find(v => v.id === input.id);
132
+ const viewInGlobalViews = globalViews.find(v => v.id === input.id);
133
+
134
+ if (viewInUserViews) {
135
+ const updatedViews = userViews.map(v =>
136
+ v.id === input.id
137
+ ? {
138
+ ...v,
139
+ name: input.name ?? v.name,
140
+ filters: input.filters ?? v.filters,
141
+ searchTerm: input.searchTerm !== undefined ? input.searchTerm : v.searchTerm,
142
+ updatedAt: new Date().toISOString(),
143
+ }
144
+ : v,
145
+ );
146
+ await saveUserViewMutation.mutateAsync(updatedViews);
147
+ } else if (viewInGlobalViews) {
148
+ const updatedViews = globalViews.map(v =>
149
+ v.id === input.id
150
+ ? {
151
+ ...v,
152
+ name: input.name ?? v.name,
153
+ filters: input.filters ?? v.filters,
154
+ searchTerm: input.searchTerm !== undefined ? input.searchTerm : v.searchTerm,
155
+ updatedAt: new Date().toISOString(),
156
+ }
157
+ : v,
158
+ );
159
+ await saveGlobalViewMutation.mutateAsync(updatedViews);
160
+ }
161
+ };
162
+
163
+ const deleteView = async (viewId: string) => {
164
+ const userViews = userViewsData || [];
165
+ const globalViews = globalViewsData || [];
166
+
167
+ if (userViews.some(v => v.id === viewId)) {
168
+ const updatedViews = userViews.filter(v => v.id !== viewId);
169
+ await saveUserViewMutation.mutateAsync(updatedViews);
170
+ } else if (globalViews.some(v => v.id === viewId)) {
171
+ const updatedViews = globalViews.filter(v => v.id !== viewId);
172
+ await saveGlobalViewMutation.mutateAsync(updatedViews);
173
+ }
174
+ };
175
+
176
+ const duplicateView = async (viewId: string, newScope: 'user' | 'global') => {
177
+ const allViews = [...(userViewsData || []), ...(globalViewsData || [])];
178
+ const viewToDuplicate = allViews.find(v => v.id === viewId);
179
+
180
+ if (viewToDuplicate) {
181
+ const newView: SavedView = {
182
+ ...viewToDuplicate,
183
+ id: generateId(),
184
+ name: `${viewToDuplicate.name} (Copy)`,
185
+ scope: newScope,
186
+ pageId,
187
+ blockId: blockId === 'default' ? undefined : blockId,
188
+ createdAt: new Date().toISOString(),
189
+ updatedAt: new Date().toISOString(),
190
+ };
191
+
192
+ if (newScope === 'user') {
193
+ const currentViews = userViewsData || [];
194
+ await saveUserViewMutation.mutateAsync([...currentViews, newView]);
195
+ } else {
196
+ const currentViews = globalViewsData || [];
197
+ await saveGlobalViewMutation.mutateAsync([...currentViews, newView]);
198
+ }
199
+
200
+ return newView;
201
+ }
202
+ };
203
+
204
+ const applyView = (
205
+ view: SavedView,
206
+ setFilters: (filters: ColumnFiltersState) => void,
207
+ setSearchTerm?: (term: string) => void,
208
+ ) => {
209
+ setFilters(view.filters);
210
+ if (setSearchTerm && view.searchTerm !== undefined) {
211
+ setSearchTerm(view.searchTerm);
212
+ }
213
+ };
214
+
215
+ // Use UpdateSettings permission for managing global views
216
+ const { hasPermissions } = usePermissions();
217
+ const canManageGlobalViews = hasPermissions(['WriteDashboardGlobalViews']);
218
+
219
+ return {
220
+ userViews: userViewsData || [],
221
+ globalViews: globalViewsData || [],
222
+ isLoading: userViewsLoading || globalViewsLoading,
223
+ saveView,
224
+ updateView,
225
+ deleteView,
226
+ duplicateView,
227
+ applyView,
228
+ canManageGlobalViews,
229
+ };
230
+ }
@@ -0,0 +1,30 @@
1
+ import { loadI18nMessages } from '@/vdb/lib/load-i18n-messages.js';
2
+ import { useLingui } from '@lingui/react/macro';
3
+
4
+ let currentlyLoading: string | null = null;
5
+
6
+ /**
7
+ * @description
8
+ * Loads the UI translations for the given locale and activates it
9
+ * with the Lingui I18nProvider. Generally this is used internally
10
+ * when the display language is set via the user > language dialog.
11
+ *
12
+ * @docsCategory hooks
13
+ * @docsPage useUiLanguageLoader
14
+ */
15
+ export function useUiLanguageLoader() {
16
+ const { i18n } = useLingui();
17
+
18
+ async function loadAndActivateLocale(locale: string) {
19
+ if (currentlyLoading === locale) {
20
+ return;
21
+ }
22
+ currentlyLoading = locale;
23
+ const messages = await loadI18nMessages(locale);
24
+ i18n.load(locale, messages);
25
+ i18n.activate(locale);
26
+ currentlyLoading = null;
27
+ }
28
+
29
+ return { loadAndActivateLocale };
30
+ }
package/src/lib/index.ts CHANGED
@@ -22,6 +22,7 @@ export * from './components/data-input/relation-input.js';
22
22
  export * from './components/data-input/relation-selector.js';
23
23
  export * from './components/data-input/rich-text-input.js';
24
24
  export * from './components/data-input/select-with-options.js';
25
+ export * from './components/data-input/slug-input.js';
25
26
  export * from './components/data-input/struct-form-input.js';
26
27
  export * from './components/data-input/text-input.js';
27
28
  export * from './components/data-input/textarea-input.js';
@@ -29,6 +30,7 @@ export * from './components/data-table/add-filter-menu.js';
29
30
  export * from './components/data-table/data-table-bulk-action-item.js';
30
31
  export * from './components/data-table/data-table-bulk-actions.js';
31
32
  export * from './components/data-table/data-table-column-header.js';
33
+ export * from './components/data-table/data-table-context.js';
32
34
  export * from './components/data-table/data-table-faceted-filter.js';
33
35
  export * from './components/data-table/data-table-filter-badge.js';
34
36
  export * from './components/data-table/data-table-filter-dialog.js';
@@ -41,11 +43,20 @@ export * from './components/data-table/filters/data-table-datetime-filter.js';
41
43
  export * from './components/data-table/filters/data-table-id-filter.js';
42
44
  export * from './components/data-table/filters/data-table-number-filter.js';
43
45
  export * from './components/data-table/filters/data-table-string-filter.js';
46
+ export * from './components/data-table/global-views-bar.js';
47
+ export * from './components/data-table/global-views-sheet.js';
44
48
  export * from './components/data-table/human-readable-operator.js';
49
+ export * from './components/data-table/manage-global-views-button.js';
50
+ export * from './components/data-table/my-views-button.js';
45
51
  export * from './components/data-table/refresh-button.js';
52
+ export * from './components/data-table/save-view-button.js';
53
+ export * from './components/data-table/save-view-dialog.js';
46
54
  export * from './components/data-table/types.js';
47
55
  export * from './components/data-table/use-all-bulk-actions.js';
48
56
  export * from './components/data-table/use-generated-columns.js';
57
+ export * from './components/data-table/user-views-sheet.js';
58
+ export * from './components/data-table/views-sheet.js';
59
+ export * from './components/date-range-picker.js';
49
60
  export * from './components/labeled-data.js';
50
61
  export * from './components/layout/app-layout.js';
51
62
  export * from './components/layout/app-sidebar.js';
@@ -98,9 +109,11 @@ export * from './components/shared/form-field-wrapper.js';
98
109
  export * from './components/shared/history-timeline/history-entry-date.js';
99
110
  export * from './components/shared/history-timeline/history-note-checkbox.js';
100
111
  export * from './components/shared/history-timeline/history-note-editor.js';
112
+ export * from './components/shared/history-timeline/history-note-entry.js';
101
113
  export * from './components/shared/history-timeline/history-note-input.js';
102
114
  export * from './components/shared/history-timeline/history-timeline-with-grouping.js';
103
115
  export * from './components/shared/history-timeline/history-timeline.js';
116
+ export * from './components/shared/history-timeline/use-history-note-editor.js';
104
117
  export * from './components/shared/icon-mark.js';
105
118
  export * from './components/shared/language-selector.js';
106
119
  export * from './components/shared/logo-mark.js';
@@ -183,6 +196,7 @@ export * from './framework/dashboard-widget/metrics-widget/chart.js';
183
196
  export * from './framework/dashboard-widget/metrics-widget/metrics-widget.graphql.js';
184
197
  export * from './framework/dashboard-widget/orders-summary/order-summary-widget.graphql.js';
185
198
  export * from './framework/dashboard-widget/widget-extensions.js';
199
+ export * from './framework/dashboard-widget/widget-filters-context.js';
186
200
  export * from './framework/data-table/data-table-extensions.js';
187
201
  export * from './framework/defaults.js';
188
202
  export * from './framework/document-extension/extend-detail-form-query.js';
@@ -259,6 +273,7 @@ export * from './hooks/use-mobile.js';
259
273
  export * from './hooks/use-page-block.js';
260
274
  export * from './hooks/use-page.js';
261
275
  export * from './hooks/use-permissions.js';
276
+ export * from './hooks/use-saved-views.js';
262
277
  export * from './hooks/use-server-config.js';
263
278
  export * from './hooks/use-theme.js';
264
279
  export * from './hooks/use-user-settings.js';
@@ -0,0 +1,17 @@
1
+ import { Messages } from '@lingui/core';
2
+
3
+ export async function loadI18nMessages(locale: string): Promise<Messages> {
4
+ if (import.meta.env.PROD) {
5
+ // We add the vite-ignore directive because we do not want to transform and
6
+ // bundle this dynamic import. Instead, we actually want to load it at runtime
7
+ // as a normal dynamic JS import.
8
+ // These i18n JS files are generated during build by the `translationsPlugin` in the
9
+ // vite-plugin-translations.ts file.
10
+ const { messages } = await import(/* @vite-ignore */ `./i18n/${locale}.js`);
11
+ return messages;
12
+ } else {
13
+ // In dev mode we allow the dynamic import behaviour
14
+ const { messages } = await import(`../../i18n/locales/${locale}.po`);
15
+ return messages;
16
+ }
17
+ }
@@ -1,16 +1,20 @@
1
+ // export { Trans } from '@lingui/react/macro';
2
+ // export { useLingui } from '@lingui/react';
3
+
4
+
1
5
  /**
2
6
  * This is a temporary work-around because the Lingui macros do not
3
7
  * currently work when the dashboard is packaged in an npm
4
8
  * module. Related issue: https://github.com/kentcdodds/babel-plugin-macros/issues/87
5
9
  */
6
- export function Trans({ children }: Readonly<{ children: React.ReactNode; context?: string }>) {
7
- return <>{children}</>;
8
- }
9
-
10
- export function useLingui() {
11
- return {
12
- i18n: {
13
- t: (key: string) => key,
14
- },
15
- };
16
- }
10
+ // export function Trans({ children }: Readonly<{ children: React.ReactNode; context?: string }>) {
11
+ // return <>{children}</>;
12
+ // }
13
+ //
14
+ // export function useLingui() {
15
+ // return {
16
+ // i18n: {
17
+ // t: (key: string) => key,
18
+ // },
19
+ // };
20
+ // }
@@ -1,11 +1,8 @@
1
+ import { loadI18nMessages } from '@/vdb/lib/load-i18n-messages.js';
2
+ import { i18n } from '@lingui/core';
3
+ import { I18nProvider as LinguiI18nProvider } from '@lingui/react';
1
4
  import React from 'react';
2
- // import { i18n } from '@lingui/core';
3
- // import { I18nProvider as LinguiI18nProvider } from '@lingui/react';
4
5
 
5
- export const locales = {
6
- en: 'English',
7
- de: 'Deutsch',
8
- };
9
6
  export const defaultLocale = 'en';
10
7
 
11
8
  /**
@@ -13,16 +10,12 @@ export const defaultLocale = 'en';
13
10
  * @param locale any locale string
14
11
  */
15
12
  export async function dynamicActivate(locale: string, onActivate?: () => void) {
16
- // Temporarily disabled because Lingui macros do not work when the dashboard is packaged in an npm module.
17
- // Related issue: https://github.com/kentcdodds/babel-plugin-macros/issues/87
18
-
19
- // const { messages } = await import(`../../i18n/locales/${locale}.po`);
20
- // i18n.load(locale, messages);
21
- // i18n.activate(locale);
13
+ const messages = await loadI18nMessages(locale);
14
+ i18n.load(locale, messages);
15
+ i18n.activate(locale);
22
16
  onActivate?.();
23
17
  }
24
18
 
25
19
  export function I18nProvider({ children }: { children: React.ReactNode }) {
26
- // return <LinguiI18nProvider i18n={i18n}>{children}</LinguiI18nProvider>;
27
- return <>{children}</>;
20
+ return <LinguiI18nProvider i18n={i18n}>{children}</LinguiI18nProvider>;
28
21
  }
@@ -0,0 +1,39 @@
1
+ import { ColumnFiltersState } from '@tanstack/react-table';
2
+
3
+ export interface SavedView {
4
+ id: string;
5
+ name: string;
6
+ scope: 'user' | 'global';
7
+ filters: ColumnFiltersState;
8
+ searchTerm?: string;
9
+ pageId?: string;
10
+ blockId?: string;
11
+ createdAt: string; // ISO timestamp string
12
+ updatedAt: string; // ISO timestamp string
13
+ createdBy?: string;
14
+ }
15
+
16
+ export interface SavedViewsData {
17
+ userViews: SavedView[];
18
+ globalViews: SavedView[];
19
+ }
20
+
21
+ export interface SavedViewsStore {
22
+ [pageId: string]: {
23
+ [blockId: string]: SavedView[];
24
+ };
25
+ }
26
+
27
+ export interface SaveViewInput {
28
+ name: string;
29
+ scope: 'user' | 'global';
30
+ filters: ColumnFiltersState;
31
+ searchTerm?: string;
32
+ }
33
+
34
+ export interface UpdateViewInput {
35
+ id: string;
36
+ name?: string;
37
+ filters?: ColumnFiltersState;
38
+ searchTerm?: string;
39
+ }
@@ -0,0 +1,40 @@
1
+ import { ColumnFiltersState } from '@tanstack/react-table';
2
+
3
+ import { SavedView } from '../types/saved-views.js';
4
+
5
+ /**
6
+ * Checks if the current filters and search term match any of the provided saved views
7
+ * @param currentFilters - The current column filters
8
+ * @param currentSearchTerm - The current search term
9
+ * @param views - Array of saved views to check against
10
+ * @returns The matching saved view if found, undefined otherwise
11
+ */
12
+ export function findMatchingSavedView(
13
+ currentFilters: ColumnFiltersState,
14
+ currentSearchTerm: string,
15
+ views: SavedView[],
16
+ ): SavedView | undefined {
17
+ return views.find(view => {
18
+ const filtersMatch = JSON.stringify(view.filters) === JSON.stringify(currentFilters);
19
+ const searchMatch = (view.searchTerm || '') === currentSearchTerm;
20
+ return filtersMatch && searchMatch;
21
+ });
22
+ }
23
+
24
+ /**
25
+ * Checks if the current filters match any saved view (user or global)
26
+ * @param currentFilters - The current column filters
27
+ * @param currentSearchTerm - The current search term
28
+ * @param userViews - Array of user saved views
29
+ * @param globalViews - Array of global saved views
30
+ * @returns true if a matching view is found, false otherwise
31
+ */
32
+ export function isMatchingSavedView(
33
+ currentFilters: ColumnFiltersState,
34
+ currentSearchTerm: string,
35
+ userViews: SavedView[],
36
+ globalViews: SavedView[],
37
+ ): boolean {
38
+ const allViews = [...userViews, ...globalViews];
39
+ return findMatchingSavedView(currentFilters, currentSearchTerm, allViews) !== undefined;
40
+ }