@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
@@ -2,12 +2,19 @@
2
2
 
3
3
  import { DataTablePagination } from '@/vdb/components/data-table/data-table-pagination.js';
4
4
  import { DataTableViewOptions } from '@/vdb/components/data-table/data-table-view-options.js';
5
+ import { GlobalViewsBar } from '@/vdb/components/data-table/global-views-bar.js';
6
+ import { MyViewsButton } from '@/vdb/components/data-table/my-views-button.js';
5
7
  import { RefreshButton } from '@/vdb/components/data-table/refresh-button.js';
8
+ import { SaveViewButton } from '@/vdb/components/data-table/save-view-button.js';
9
+ import { Button } from '@/vdb/components/ui/button.js';
6
10
  import { Input } from '@/vdb/components/ui/input.js';
7
11
  import { Skeleton } from '@/vdb/components/ui/skeleton.js';
8
12
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/vdb/components/ui/table.js';
9
13
  import { BulkAction } from '@/vdb/framework/extension-api/types/index.js';
10
14
  import { useChannel } from '@/vdb/hooks/use-channel.js';
15
+ import { usePage } from '@/vdb/hooks/use-page.js';
16
+ import { useSavedViews } from '@/vdb/hooks/use-saved-views.js';
17
+ import { Trans, useLingui } from '@lingui/react/macro';
11
18
  import {
12
19
  ColumnDef,
13
20
  ColumnFilter,
@@ -25,6 +32,7 @@ import { RowSelectionState, TableOptions } from '@tanstack/table-core';
25
32
  import React, { Suspense, useEffect } from 'react';
26
33
  import { AddFilterMenu } from './add-filter-menu.js';
27
34
  import { DataTableBulkActions } from './data-table-bulk-actions.js';
35
+ import { DataTableProvider } from './data-table-context.js';
28
36
  import { DataTableFacetedFilter, DataTableFacetedFilterOption } from './data-table-faceted-filter.js';
29
37
  import { DataTableFilterBadge } from './data-table-filter-badge.js';
30
38
 
@@ -106,7 +114,12 @@ export function DataTable<TData>({
106
114
  }: Readonly<DataTableProps<TData>>) {
107
115
  const [sorting, setSorting] = React.useState<SortingState>(sortingInitialState || []);
108
116
  const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(filtersInitialState || []);
117
+ const [searchTerm, setSearchTerm] = React.useState<string>('');
109
118
  const { activeChannel } = useChannel();
119
+ const { pageId } = usePage();
120
+ const savedViewsResult = useSavedViews();
121
+ const globalViews = pageId && onFilterChange ? savedViewsResult.globalViews : [];
122
+ const { t } = useLingui();
110
123
  const [pagination, setPagination] = React.useState<PaginationState>({
111
124
  pageIndex: (page ?? 1) - 1,
112
125
  pageSize: itemsPerPage ?? 10,
@@ -175,19 +188,37 @@ export function DataTable<TData>({
175
188
  }, [columnVisibility]);
176
189
 
177
190
  const visibleColumnCount = Object.values(columnVisibility).filter(Boolean).length;
191
+
192
+ const handleSearchChange = (value: string) => {
193
+ setSearchTerm(value);
194
+ onSearchTermChange?.(value);
195
+ };
196
+
178
197
  return (
179
- <>
180
- <div className="flex justify-between items-start">
181
- <div className="flex flex-col space-y-2">
182
- <div className="flex items-center justify-start gap-2">
198
+ <DataTableProvider
199
+ columnFilters={columnFilters}
200
+ setColumnFilters={setColumnFilters}
201
+ searchTerm={searchTerm}
202
+ setSearchTerm={setSearchTerm}
203
+ sorting={sorting}
204
+ setSorting={setSorting}
205
+ pageId={pageId}
206
+ onFilterChange={onFilterChange}
207
+ onSearchTermChange={onSearchTermChange}
208
+ onRefresh={onRefresh}
209
+ isLoading={isLoading}
210
+ table={table}
211
+ >
212
+ <div className="space-y-2">
213
+ <div className="flex items-center justify-between gap-2">
214
+ <div className="flex items-center gap-2">
183
215
  {onSearchTermChange && (
184
- <div className="flex items-center">
185
- <Input
186
- placeholder="Filter..."
187
- onChange={event => onSearchTermChange(event.target.value)}
188
- className="max-w-sm w-md"
189
- />
190
- </div>
216
+ <Input
217
+ placeholder={t`Filter...`}
218
+ value={searchTerm}
219
+ onChange={event => handleSearchChange(event.target.value)}
220
+ className="w-64"
221
+ />
191
222
  )}
192
223
  <Suspense>
193
224
  {Object.entries(facetedFilters ?? {}).map(([key, filter]) => (
@@ -201,99 +232,120 @@ export function DataTable<TData>({
201
232
  ))}
202
233
  </Suspense>
203
234
  {onFilterChange && <AddFilterMenu columns={table.getAllColumns()} />}
235
+ {pageId && onFilterChange && <MyViewsButton />}
204
236
  </div>
205
- <div className="flex gap-1">
206
- {columnFilters
207
- .filter(f => !facetedFilters?.[f.id])
208
- .map(f => {
209
- const column = table.getColumn(f.id);
210
- const currency = activeChannel?.defaultCurrencyCode ?? 'USD';
211
- return (
212
- <DataTableFilterBadge
213
- key={f.id}
214
- filter={f}
215
- currencyCode={currency}
216
- dataType={
217
- (column?.columnDef.meta as any)?.fieldInfo?.type ?? 'String'
218
- }
219
- onRemove={() =>
220
- setColumnFilters(old => old.filter(x => x.id !== f.id))
221
- }
222
- />
223
- );
224
- })}
237
+ <div className="flex items-center gap-2">
238
+ {pageId && onFilterChange && <SaveViewButton />}
239
+ {!disableViewOptions && <DataTableViewOptions table={table} />}
240
+ {onRefresh && <RefreshButton onRefresh={onRefresh} isLoading={isLoading ?? false} />}
225
241
  </div>
226
242
  </div>
227
- <div className="flex items-center justify-start gap-2">
228
- {!disableViewOptions && <DataTableViewOptions table={table} />}
229
- {onRefresh && <RefreshButton onRefresh={onRefresh} isLoading={isLoading ?? false} />}
230
- </div>
231
- </div>
232
243
 
233
- <div className="rounded-md border my-2 relative">
234
- <Table>
235
- <TableHeader>
236
- {table.getHeaderGroups().map(headerGroup => (
237
- <TableRow key={headerGroup.id}>
238
- {headerGroup.headers.map(header => {
244
+ {(pageId && onFilterChange && globalViews.length > 0) ||
245
+ columnFilters.filter(f => !facetedFilters?.[f.id]).length > 0 ? (
246
+ <div className="flex items-center justify-between bg-muted/40 rounded border border-border p-2">
247
+ <div className="flex items-center">
248
+ {pageId && onFilterChange && <GlobalViewsBar />}
249
+ </div>
250
+ <div className="flex gap-1 items-center">
251
+ {columnFilters
252
+ .filter(f => !facetedFilters?.[f.id])
253
+ .map(f => {
254
+ const column = table.getColumn(f.id);
255
+ const currency = activeChannel?.defaultCurrencyCode ?? 'USD';
239
256
  return (
240
- <TableHead key={header.id}>
241
- {header.isPlaceholder
242
- ? null
243
- : flexRender(
244
- header.column.columnDef.header,
245
- header.getContext(),
246
- )}
247
- </TableHead>
257
+ <DataTableFilterBadge
258
+ key={f.id}
259
+ filter={f}
260
+ currencyCode={currency}
261
+ dataType={
262
+ (column?.columnDef.meta as any)?.fieldInfo?.type ?? 'String'
263
+ }
264
+ onRemove={() =>
265
+ setColumnFilters(old => old.filter(x => x.id !== f.id))
266
+ }
267
+ />
248
268
  );
249
269
  })}
250
- </TableRow>
251
- ))}
252
- </TableHeader>
253
- <TableBody>
254
- {isLoading && !data?.length ? (
255
- Array.from({ length: pagination.pageSize }).map((_, index) => (
256
- <TableRow
257
- key={`skeleton-${index}`}
258
- className="animate-in fade-in duration-100"
270
+ {columnFilters.filter(f => !facetedFilters?.[f.id]).length > 0 && (
271
+ <Button
272
+ variant="ghost"
273
+ size="sm"
274
+ onClick={() => setColumnFilters([])}
275
+ className="text-xs opacity-60 hover:opacity-100"
259
276
  >
260
- {Array.from({ length: visibleColumnCount }).map((_, cellIndex) => (
261
- <TableCell
262
- key={`skeleton-cell-${index}-${cellIndex}`}
263
- className="h-12"
264
- >
265
- <Skeleton className="h-4 my-2 w-full" />
266
- </TableCell>
267
- ))}
277
+ <Trans>Clear all</Trans>
278
+ </Button>
279
+ )}
280
+ </div>
281
+ </div>
282
+ ) : null}
283
+
284
+ <div className="rounded-md border my-2 relative shadow-sm">
285
+ <Table>
286
+ <TableHeader className="bg-muted/50">
287
+ {table.getHeaderGroups().map(headerGroup => (
288
+ <TableRow key={headerGroup.id}>
289
+ {headerGroup.headers.map(header => {
290
+ return (
291
+ <TableHead key={header.id}>
292
+ {header.isPlaceholder
293
+ ? null
294
+ : flexRender(
295
+ header.column.columnDef.header,
296
+ header.getContext(),
297
+ )}
298
+ </TableHead>
299
+ );
300
+ })}
268
301
  </TableRow>
269
- ))
270
- ) : table.getRowModel().rows?.length ? (
271
- table.getRowModel().rows.map(row => (
272
- <TableRow
273
- key={row.id}
274
- data-state={row.getIsSelected() && 'selected'}
275
- className="animate-in fade-in duration-100"
276
- >
277
- {row.getVisibleCells().map(cell => (
278
- <TableCell key={cell.id} className="h-12">
279
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
280
- </TableCell>
281
- ))}
302
+ ))}
303
+ </TableHeader>
304
+ <TableBody>
305
+ {isLoading && !data?.length ? (
306
+ Array.from({ length: pagination.pageSize }).map((_, index) => (
307
+ <TableRow
308
+ key={`skeleton-${index}`}
309
+ className="animate-in fade-in duration-100"
310
+ >
311
+ {Array.from({ length: visibleColumnCount }).map((_, cellIndex) => (
312
+ <TableCell
313
+ key={`skeleton-cell-${index}-${cellIndex}`}
314
+ className="h-12"
315
+ >
316
+ <Skeleton className="h-4 my-2 w-full" />
317
+ </TableCell>
318
+ ))}
319
+ </TableRow>
320
+ ))
321
+ ) : table.getRowModel().rows?.length ? (
322
+ table.getRowModel().rows.map(row => (
323
+ <TableRow
324
+ key={row.id}
325
+ data-state={row.getIsSelected() && 'selected'}
326
+ className="animate-in fade-in duration-100"
327
+ >
328
+ {row.getVisibleCells().map(cell => (
329
+ <TableCell key={cell.id} className="h-12">
330
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
331
+ </TableCell>
332
+ ))}
333
+ </TableRow>
334
+ ))
335
+ ) : (
336
+ <TableRow className="animate-in fade-in duration-100">
337
+ <TableCell colSpan={columns.length} className="h-24 text-center">
338
+ <Trans>No results</Trans>
339
+ </TableCell>
282
340
  </TableRow>
283
- ))
284
- ) : (
285
- <TableRow className="animate-in fade-in duration-100">
286
- <TableCell colSpan={columns.length} className="h-24 text-center">
287
- No results.
288
- </TableCell>
289
- </TableRow>
290
- )}
291
- {children}
292
- </TableBody>
293
- </Table>
294
- <DataTableBulkActions bulkActions={bulkActions ?? []} table={table} />
341
+ )}
342
+ {children}
343
+ </TableBody>
344
+ </Table>
345
+ <DataTableBulkActions bulkActions={bulkActions ?? []} table={table} />
346
+ </div>
347
+ {onPageChange && totalItems != null && <DataTablePagination table={table} />}
295
348
  </div>
296
- {onPageChange && totalItems != null && <DataTablePagination table={table} />}
297
- </>
349
+ </DataTableProvider>
298
350
  );
299
351
  }
@@ -1,4 +1,4 @@
1
- import { Trans } from '@/vdb/lib/trans.js';
1
+ import { Trans } from '@lingui/react/macro';
2
2
 
3
3
  import { Select, SelectItem, SelectTrigger, SelectValue } from '@/vdb/components/ui/select.js';
4
4
 
@@ -14,9 +14,9 @@ export interface DataTableBooleanFilterProps {
14
14
  export const BOOLEAN_OPERATORS = ['eq', 'isNull'] as const;
15
15
 
16
16
  export function DataTableBooleanFilter({
17
- value: incomingValue,
18
- onChange,
19
- }: Readonly<DataTableBooleanFilterProps>) {
17
+ value: incomingValue,
18
+ onChange,
19
+ }: Readonly<DataTableBooleanFilterProps>) {
20
20
  const initialOperator = incomingValue ? (Object.keys(incomingValue)[0] ?? 'eq') : 'eq';
21
21
  const initialValue = incomingValue ? Object.values(incomingValue)[0] : true;
22
22
  const [operator, setOperator] = useState<string>(initialOperator ?? 'eq');
@@ -0,0 +1,97 @@
1
+ import { Trans } from '@lingui/react/macro';
2
+ import { ChevronDown } from 'lucide-react';
3
+ import React from 'react';
4
+ import { useSavedViews } from '../../hooks/use-saved-views.js';
5
+ import { SavedView } from '../../types/saved-views.js';
6
+ import { findMatchingSavedView } from '../../utils/saved-views-utils.js';
7
+ import { PermissionGuard } from '../shared/permission-guard.js';
8
+ import { Button } from '../ui/button.js';
9
+ import {
10
+ DropdownMenu,
11
+ DropdownMenuContent,
12
+ DropdownMenuItem,
13
+ DropdownMenuTrigger,
14
+ } from '../ui/dropdown-menu.js';
15
+ import { useDataTableContext } from './data-table-context.js';
16
+ import { ManageGlobalViewsButton } from './manage-global-views-button.js';
17
+
18
+ export const GlobalViewsBar: React.FC = () => {
19
+ const { globalViews, canManageGlobalViews } = useSavedViews();
20
+ const { columnFilters, searchTerm, handleApplyView } = useDataTableContext();
21
+
22
+ if (globalViews.length === 0) {
23
+ return null;
24
+ }
25
+
26
+ const sortedViews = [...globalViews].sort(
27
+ (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(),
28
+ );
29
+
30
+ const handleViewClick = (view: SavedView) => {
31
+ handleApplyView(view.filters, view.searchTerm);
32
+ };
33
+
34
+ const isViewActive = (view: SavedView) => {
35
+ return findMatchingSavedView(columnFilters, searchTerm, [view]) !== undefined;
36
+ };
37
+
38
+ if (sortedViews.length <= 3) {
39
+ // Show all views as buttons
40
+ return (
41
+ <div className="flex items-center gap-1">
42
+ {sortedViews.map(view => (
43
+ <Button
44
+ key={view.id}
45
+ variant={isViewActive(view) ? 'default' : 'outline'}
46
+ size="sm"
47
+ onClick={() => handleViewClick(view)}
48
+ >
49
+ {view.name}
50
+ </Button>
51
+ ))}
52
+ {canManageGlobalViews && <ManageGlobalViewsButton />}
53
+ </div>
54
+ );
55
+ }
56
+
57
+ // Show first 3 as buttons, rest in dropdown
58
+ const visibleViews = sortedViews.slice(0, 3);
59
+ const dropdownViews = sortedViews.slice(3);
60
+
61
+ return (
62
+ <div className="flex items-center gap-1">
63
+ {visibleViews.map(view => (
64
+ <Button
65
+ key={view.id}
66
+ variant={isViewActive(view) ? 'default' : 'outline'}
67
+ size="sm"
68
+ onClick={() => handleViewClick(view)}
69
+ >
70
+ {view.name}
71
+ </Button>
72
+ ))}
73
+ <DropdownMenu>
74
+ <DropdownMenuTrigger asChild>
75
+ <Button variant="outline" size="sm">
76
+ <Trans>More views</Trans>
77
+ <ChevronDown className="h-3 w-3" />
78
+ </Button>
79
+ </DropdownMenuTrigger>
80
+ <DropdownMenuContent align="start">
81
+ {dropdownViews.map(view => (
82
+ <DropdownMenuItem
83
+ key={view.id}
84
+ onClick={() => handleViewClick(view)}
85
+ className={isViewActive(view) ? 'bg-primary' : ''}
86
+ >
87
+ {view.name}
88
+ </DropdownMenuItem>
89
+ ))}
90
+ </DropdownMenuContent>
91
+ </DropdownMenu>
92
+ <PermissionGuard requires={['WriteDashboardGlobalViews']}>
93
+ {canManageGlobalViews && <ManageGlobalViewsButton />}
94
+ </PermissionGuard>
95
+ </div>
96
+ );
97
+ };
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import { ViewsSheet } from './views-sheet.js';
3
+
4
+ interface GlobalViewsSheetProps {
5
+ open: boolean;
6
+ onOpenChange: (open: boolean) => void;
7
+ }
8
+
9
+ export const GlobalViewsSheet: React.FC<GlobalViewsSheetProps> = ({ open, onOpenChange }) => {
10
+ return <ViewsSheet open={open} onOpenChange={onOpenChange} type="global" />;
11
+ };
@@ -1,4 +1,4 @@
1
- import { Trans } from '@/vdb/lib/trans.js';
1
+ import { Trans } from '@lingui/react/macro';
2
2
  import { BOOLEAN_OPERATORS } from './filters/data-table-boolean-filter.js';
3
3
  import { DATETIME_OPERATORS } from './filters/data-table-datetime-filter.js';
4
4
  import { ID_OPERATORS } from './filters/data-table-id-filter.js';
@@ -0,0 +1,26 @@
1
+ import { Settings } from 'lucide-react';
2
+ import React, { useState } from 'react';
3
+ import { Button } from '../ui/button.js';
4
+ import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip.js';
5
+ import { Trans } from '@lingui/react/macro';
6
+ import { GlobalViewsSheet } from './global-views-sheet.js';
7
+
8
+ export const ManageGlobalViewsButton: React.FC = () => {
9
+ const [sheetOpen, setSheetOpen] = useState(false);
10
+
11
+ return (
12
+ <>
13
+ <Tooltip>
14
+ <TooltipTrigger asChild>
15
+ <Button variant="outline" size="icon-sm" onClick={() => setSheetOpen(true)}>
16
+ <Settings />
17
+ </Button>
18
+ </TooltipTrigger>
19
+ <TooltipContent>
20
+ <Trans>Manage global views</Trans>
21
+ </TooltipContent>
22
+ </Tooltip>
23
+ <GlobalViewsSheet open={sheetOpen} onOpenChange={setSheetOpen} />
24
+ </>
25
+ );
26
+ };
@@ -0,0 +1,47 @@
1
+ import { Bookmark } from 'lucide-react';
2
+ import React, { useState, useMemo } from 'react';
3
+ import { Button } from '../ui/button.js';
4
+ import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip.js';
5
+ import { Trans } from '@lingui/react/macro';
6
+ import { UserViewsSheet } from './user-views-sheet.js';
7
+ import { useSavedViews } from '../../hooks/use-saved-views.js';
8
+ import { findMatchingSavedView } from '../../utils/saved-views-utils.js';
9
+ import { useDataTableContext } from './data-table-context.js';
10
+
11
+ export const MyViewsButton: React.FC = () => {
12
+ const [sheetOpen, setSheetOpen] = useState(false);
13
+ const { userViews } = useSavedViews();
14
+ const { columnFilters, searchTerm, handleApplyView } = useDataTableContext();
15
+
16
+ // Find the active view using centralized utility
17
+ const activeView = useMemo(() => {
18
+ return findMatchingSavedView(columnFilters, searchTerm, userViews);
19
+ }, [userViews, columnFilters, searchTerm]);
20
+
21
+ return (
22
+ <>
23
+ <div className="flex items-center gap-2">
24
+ <Tooltip>
25
+ <TooltipTrigger asChild>
26
+ <Button
27
+ variant={activeView ? 'default' : 'outline'}
28
+ size="icon"
29
+ onClick={() => setSheetOpen(true)}
30
+ >
31
+ <Bookmark />
32
+ </Button>
33
+ </TooltipTrigger>
34
+ <TooltipContent>
35
+ <Trans>My saved views</Trans>
36
+ </TooltipContent>
37
+ </Tooltip>
38
+ {activeView && (
39
+ <span className="text-sm text-muted-foreground">
40
+ {activeView.name}
41
+ </span>
42
+ )}
43
+ </div>
44
+ <UserViewsSheet open={sheetOpen} onOpenChange={setSheetOpen} />
45
+ </>
46
+ );
47
+ };
@@ -1,4 +1,6 @@
1
1
  import { Button } from '@/vdb/components/ui/button.js';
2
+ import { Tooltip, TooltipContent, TooltipTrigger } from '@/vdb/components/ui/tooltip.js';
3
+ import { Trans } from '@lingui/react/macro';
2
4
  import { RefreshCw } from 'lucide-react';
3
5
  import { useEffect, useState } from 'react';
4
6
 
@@ -33,8 +35,15 @@ export function RefreshButton({
33
35
  };
34
36
 
35
37
  return (
36
- <Button variant="ghost" size="sm" onClick={handleClick} disabled={delayedLoading}>
37
- <RefreshCw className={delayedLoading ? 'animate-rotate' : ''} />
38
- </Button>
38
+ <Tooltip>
39
+ <TooltipTrigger asChild>
40
+ <Button variant="outline" size="sm" onClick={handleClick} disabled={delayedLoading}>
41
+ <RefreshCw className={delayedLoading ? 'animate-rotate' : ''} />
42
+ </Button>
43
+ </TooltipTrigger>
44
+ <TooltipContent>
45
+ <Trans>Refresh data</Trans>
46
+ </TooltipContent>
47
+ </Tooltip>
39
48
  );
40
49
  }
@@ -0,0 +1,41 @@
1
+ import { Trans } from '@lingui/react/macro';
2
+ import { BookmarkPlus } from 'lucide-react';
3
+ import React, { useState } from 'react';
4
+ import { useSavedViews } from '../../hooks/use-saved-views.js';
5
+ import { isMatchingSavedView } from '../../utils/saved-views-utils.js';
6
+ import { Button } from '../ui/button.js';
7
+ import { useDataTableContext } from './data-table-context.js';
8
+ import { SaveViewDialog } from './save-view-dialog.js';
9
+
10
+ interface SaveViewButtonProps {
11
+ disabled?: boolean;
12
+ }
13
+
14
+ export const SaveViewButton: React.FC<SaveViewButtonProps> = ({ disabled }) => {
15
+ const [dialogOpen, setDialogOpen] = useState(false);
16
+ const { userViews, globalViews } = useSavedViews();
17
+ const { columnFilters, searchTerm } = useDataTableContext();
18
+
19
+ const hasFilters = columnFilters.length > 0 || (searchTerm && searchTerm.length > 0);
20
+ const matchesExistingView = isMatchingSavedView(columnFilters, searchTerm || '', userViews, globalViews);
21
+
22
+ // Don't show the button if there are no filters or if filters match an existing saved view
23
+ if (!hasFilters || matchesExistingView) {
24
+ return null;
25
+ }
26
+
27
+ return (
28
+ <>
29
+ <Button variant="outline" size="sm" onClick={() => setDialogOpen(true)} disabled={disabled}>
30
+ <BookmarkPlus className="h-4 w-4 mr-1" />
31
+ <Trans>Save View</Trans>
32
+ </Button>
33
+ <SaveViewDialog
34
+ open={dialogOpen}
35
+ onOpenChange={setDialogOpen}
36
+ filters={columnFilters}
37
+ searchTerm={searchTerm}
38
+ />
39
+ </>
40
+ );
41
+ };