@vendure/dashboard 3.5.0-minor-202510071456 → 3.5.0-minor-202510201346

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 (204) hide show
  1. package/dist/plugin/dashboard.plugin.js +1 -1
  2. package/dist/vite/utils/ast-utils.spec.js +3 -3
  3. package/dist/vite/vite-plugin-hmr.d.ts +8 -0
  4. package/dist/vite/vite-plugin-hmr.js +34 -0
  5. package/dist/vite/vite-plugin-theme.js +6 -6
  6. package/dist/vite/vite-plugin-transform-index.js +6 -1
  7. package/dist/vite/vite-plugin-vendure-dashboard.d.ts +31 -4
  8. package/dist/vite/vite-plugin-vendure-dashboard.js +89 -34
  9. package/package.json +17 -5
  10. package/src/app/app-providers.tsx +4 -1
  11. package/src/app/common/map-faceted-filter-fields.ts +21 -0
  12. package/src/app/main.tsx +3 -1
  13. package/src/app/routes/_authenticated/_administrators/administrators.graphql.ts +2 -2
  14. package/src/app/routes/_authenticated/_administrators/administrators.tsx +13 -3
  15. package/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx +6 -13
  16. package/src/app/routes/_authenticated/_administrators/components/role-permissions-display.tsx +1 -1
  17. package/src/app/routes/_authenticated/_assets/assets.tsx +17 -1
  18. package/src/app/routes/_authenticated/_collections/collections.graphql.ts +1 -0
  19. package/src/app/routes/_authenticated/_collections/collections.tsx +5 -0
  20. package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +0 -1
  21. package/src/app/routes/_authenticated/_customers/customers.tsx +9 -5
  22. package/src/app/routes/_authenticated/_facets/components/facet-bulk-actions.tsx +0 -6
  23. package/src/app/routes/_authenticated/_facets/components/facet-value-bulk-actions.tsx +16 -0
  24. package/src/app/routes/_authenticated/_facets/components/facet-values-table.tsx +43 -12
  25. package/src/app/routes/_authenticated/_facets/facets_.$facetId.values_.$id.tsx +14 -5
  26. package/src/app/routes/_authenticated/_orders/components/edit-order-table.tsx +117 -92
  27. package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +1 -1
  28. package/src/app/routes/_authenticated/_orders/components/order-modification-summary.tsx +2 -1
  29. package/src/app/routes/_authenticated/_orders/components/order-table-totals.tsx +26 -27
  30. package/src/app/routes/_authenticated/_orders/components/order-table.tsx +5 -3
  31. package/src/app/routes/_authenticated/_orders/components/state-transition-control.tsx +6 -9
  32. package/src/app/routes/_authenticated/_orders/orders.graphql.ts +17 -1
  33. package/src/app/routes/_authenticated/_orders/orders.tsx +2 -0
  34. package/src/app/routes/_authenticated/_orders/orders_.$id_.modify.tsx +48 -281
  35. package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +59 -40
  36. package/src/app/routes/_authenticated/_orders/utils/order-utils.ts +73 -0
  37. package/src/app/routes/_authenticated/_orders/utils/use-modify-order.ts +312 -0
  38. package/src/app/routes/_authenticated/_payment-methods/payment-methods.graphql.ts +2 -2
  39. package/src/app/routes/_authenticated/_payment-methods/payment-methods.tsx +4 -0
  40. package/src/app/routes/_authenticated/_product-variants/product-variants.tsx +2 -0
  41. package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +0 -6
  42. package/src/app/routes/_authenticated/_products/products.tsx +6 -2
  43. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$productOptionGroupId.options_.$id.tsx +4 -8
  44. package/src/app/routes/_authenticated/_promotions/components/promotion-bulk-actions.tsx +0 -10
  45. package/src/app/routes/_authenticated/_promotions/promotions.graphql.ts +2 -2
  46. package/src/app/routes/_authenticated/_promotions/promotions.tsx +12 -0
  47. package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +6 -2
  48. package/src/app/routes/_authenticated/_sellers/sellers.graphql.ts +2 -2
  49. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.graphql.ts +2 -2
  50. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.tsx +4 -0
  51. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +4 -10
  52. package/src/app/routes/_authenticated/_stock-locations/stock-locations.graphql.ts +2 -2
  53. package/src/app/routes/_authenticated/_tax-categories/tax-categories.graphql.ts +2 -2
  54. package/src/app/routes/_authenticated/_tax-rates/tax-rates.tsx +9 -0
  55. package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +1 -0
  56. package/src/app/routes/_authenticated/_zones/zones.graphql.ts +2 -2
  57. package/src/app/routes/login.tsx +2 -2
  58. package/src/i18n/locales/ar.po +420 -289
  59. package/src/i18n/locales/cs.po +420 -289
  60. package/src/i18n/locales/de.po +420 -289
  61. package/src/i18n/locales/en.po +420 -289
  62. package/src/i18n/locales/es.po +420 -289
  63. package/src/i18n/locales/fa.po +420 -289
  64. package/src/i18n/locales/fr.po +468 -337
  65. package/src/i18n/locales/he.po +420 -289
  66. package/src/i18n/locales/hr.po +420 -289
  67. package/src/i18n/locales/it.po +420 -289
  68. package/src/i18n/locales/ja.po +420 -289
  69. package/src/i18n/locales/nb.po +420 -289
  70. package/src/i18n/locales/ne.po +420 -289
  71. package/src/i18n/locales/pl.po +420 -289
  72. package/src/i18n/locales/pt_BR.po +420 -289
  73. package/src/i18n/locales/pt_PT.po +420 -289
  74. package/src/i18n/locales/ru.po +420 -289
  75. package/src/i18n/locales/sv.po +420 -289
  76. package/src/i18n/locales/tr.po +420 -289
  77. package/src/i18n/locales/uk.po +420 -289
  78. package/src/i18n/locales/zh_Hans.po +420 -289
  79. package/src/i18n/locales/zh_Hant.po +420 -289
  80. package/src/lib/components/data-input/affixed-input.stories.tsx +93 -0
  81. package/src/lib/components/data-input/affixed-input.tsx +5 -2
  82. package/src/lib/components/data-input/boolean-input.stories.tsx +102 -0
  83. package/src/lib/components/data-input/checkbox-input.stories.tsx +61 -0
  84. package/src/lib/components/data-input/datetime-input.stories.tsx +62 -0
  85. package/src/lib/components/data-input/datetime-input.tsx +27 -13
  86. package/src/lib/components/data-input/default-relation-input.tsx +18 -12
  87. package/src/lib/components/data-input/money-input.stories.tsx +88 -0
  88. package/src/lib/components/data-input/number-input.stories.tsx +103 -0
  89. package/src/lib/components/data-input/number-input.tsx +10 -4
  90. package/src/lib/components/data-input/password-form-input.stories.tsx +65 -0
  91. package/src/lib/components/data-input/{password-input.tsx → password-form-input.tsx} +1 -1
  92. package/src/lib/components/data-input/rich-text-input.stories.tsx +92 -0
  93. package/src/lib/components/data-input/slug-input.stories.tsx +232 -0
  94. package/src/lib/components/data-input/slug-input.tsx +9 -10
  95. package/src/lib/components/data-input/text-input.stories.tsx +52 -0
  96. package/src/lib/components/data-input/textarea-input.stories.tsx +55 -0
  97. package/src/lib/components/data-table/add-filter-menu.tsx +6 -1
  98. package/src/lib/components/data-table/column-header-wrapper.tsx +106 -0
  99. package/src/lib/components/data-table/data-table-bulk-action-item.tsx +11 -9
  100. package/src/lib/components/data-table/data-table-bulk-actions.tsx +4 -4
  101. package/src/lib/components/data-table/data-table-column-header.tsx +17 -14
  102. package/src/lib/components/data-table/data-table-faceted-filter.tsx +33 -11
  103. package/src/lib/components/data-table/data-table-filter-badge-editable.tsx +35 -0
  104. package/src/lib/components/data-table/data-table-filter-badge.tsx +23 -16
  105. package/src/lib/components/data-table/data-table-filter-dialog.tsx +28 -8
  106. package/src/lib/components/data-table/data-table-pagination.tsx +23 -7
  107. package/src/lib/components/data-table/data-table.stories.tsx +249 -0
  108. package/src/lib/components/data-table/data-table.tsx +37 -9
  109. package/src/lib/components/data-table/filters/data-table-datetime-filter.tsx +79 -34
  110. package/src/lib/components/data-table/use-generated-columns.tsx +55 -27
  111. package/src/lib/components/layout/nav-user.tsx +19 -13
  112. package/src/lib/components/login/login-form.tsx +39 -123
  113. package/src/lib/components/shared/alerts.tsx +29 -17
  114. package/src/lib/components/shared/asset/asset-bulk-actions.tsx +3 -3
  115. package/src/lib/components/shared/asset/asset-gallery.stories.tsx +76 -0
  116. package/src/lib/components/shared/asset/asset-gallery.tsx +147 -113
  117. package/src/lib/components/shared/asset/asset-picker-dialog.stories.tsx +58 -0
  118. package/src/lib/components/shared/customer-group-selector.tsx +5 -2
  119. package/src/lib/components/shared/detail-page-button.stories.tsx +52 -0
  120. package/src/lib/components/shared/facet-value-selector.stories.tsx +48 -0
  121. package/src/lib/components/shared/facet-value-selector.tsx +130 -34
  122. package/src/lib/components/shared/paginated-list-data-table.stories.tsx +212 -0
  123. package/src/lib/components/shared/paginated-list-data-table.tsx +12 -12
  124. package/src/lib/components/shared/permission-guard.stories.tsx +46 -0
  125. package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +2 -0
  126. package/src/lib/components/shared/rich-text-editor/responsive-toolbar.tsx +8 -4
  127. package/src/lib/components/shared/rich-text-editor/rich-text-editor.tsx +1 -0
  128. package/src/lib/components/shared/table-cell/order-table-cell-components.tsx +40 -0
  129. package/src/lib/components/shared/vendure-image.stories.tsx +167 -0
  130. package/src/lib/components/shared/vendure-image.tsx +6 -7
  131. package/src/lib/components/ui/accordion.stories.tsx +33 -0
  132. package/src/lib/components/ui/alert-dialog.stories.tsx +48 -0
  133. package/src/lib/components/ui/alert.stories.tsx +35 -0
  134. package/src/lib/components/ui/aspect-ratio.stories.tsx +28 -0
  135. package/src/lib/components/ui/badge.stories.tsx +28 -0
  136. package/src/lib/components/ui/breadcrumb.stories.tsx +41 -0
  137. package/src/lib/components/ui/button.stories.tsx +38 -0
  138. package/src/lib/components/ui/calendar.stories.tsx +22 -0
  139. package/src/lib/components/ui/card.stories.tsx +28 -0
  140. package/src/lib/components/ui/carousel.stories.tsx +34 -0
  141. package/src/lib/components/ui/checkbox.stories.tsx +31 -0
  142. package/src/lib/components/ui/collapsible.stories.tsx +39 -0
  143. package/src/lib/components/ui/command.stories.tsx +44 -0
  144. package/src/lib/components/ui/context-menu.stories.tsx +38 -0
  145. package/src/lib/components/ui/dialog.stories.tsx +52 -0
  146. package/src/lib/components/ui/drawer.stories.tsx +50 -0
  147. package/src/lib/components/ui/dropdown-menu.stories.tsx +41 -0
  148. package/src/lib/components/ui/hover-card.stories.tsx +38 -0
  149. package/src/lib/components/ui/input-group.tsx +148 -0
  150. package/src/lib/components/ui/input-otp.stories.tsx +30 -0
  151. package/src/lib/components/ui/input.stories.tsx +38 -0
  152. package/src/lib/components/ui/label.stories.tsx +24 -0
  153. package/src/lib/components/ui/menubar.stories.tsx +53 -0
  154. package/src/lib/components/ui/navigation-menu.stories.tsx +54 -0
  155. package/src/lib/components/ui/pagination.stories.tsx +51 -0
  156. package/src/lib/components/ui/password-input.stories.tsx +32 -0
  157. package/src/lib/components/ui/password-input.tsx +29 -0
  158. package/src/lib/components/ui/popover.stories.tsx +33 -0
  159. package/src/lib/components/ui/progress.stories.tsx +27 -0
  160. package/src/lib/components/ui/radio-group.stories.tsx +34 -0
  161. package/src/lib/components/ui/resizable.stories.tsx +32 -0
  162. package/src/lib/components/ui/scroll-area.stories.tsx +31 -0
  163. package/src/lib/components/ui/select.stories.tsx +36 -0
  164. package/src/lib/components/ui/separator.stories.tsx +35 -0
  165. package/src/lib/components/ui/sheet.stories.tsx +50 -0
  166. package/src/lib/components/ui/sidebar-context.ts +16 -0
  167. package/src/lib/components/ui/sidebar.tsx +2 -13
  168. package/src/lib/components/ui/skeleton.stories.tsx +26 -0
  169. package/src/lib/components/ui/slider.stories.tsx +37 -0
  170. package/src/lib/components/ui/switch.stories.tsx +31 -0
  171. package/src/lib/components/ui/table.stories.tsx +52 -0
  172. package/src/lib/components/ui/tabs.stories.tsx +29 -0
  173. package/src/lib/components/ui/textarea.stories.tsx +32 -0
  174. package/src/lib/components/ui/toggle-group.stories.tsx +31 -0
  175. package/src/lib/components/ui/toggle.stories.tsx +39 -0
  176. package/src/lib/components/ui/tooltip.stories.tsx +30 -0
  177. package/src/lib/components/ui/tooltip.tsx +2 -2
  178. package/src/lib/framework/alert/alert-extensions.tsx +0 -11
  179. package/src/lib/framework/alert/alert-item.tsx +14 -19
  180. package/src/lib/framework/alert/alerts-indicator.tsx +14 -15
  181. package/src/lib/framework/alert/search-index-buffer-alert/search-index-buffer-alert.ts +41 -0
  182. package/src/lib/framework/component-registry/component-registry.tsx +3 -14
  183. package/src/lib/framework/dashboard-widget/base-widget.tsx +18 -9
  184. package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +12 -11
  185. package/src/lib/framework/defaults.ts +9 -13
  186. package/src/lib/framework/extension-api/input-component-extensions.tsx +8 -3
  187. package/src/lib/framework/extension-api/logic/alerts.ts +3 -2
  188. package/src/lib/framework/extension-api/types/alerts.ts +12 -6
  189. package/src/lib/framework/extension-api/types/data-table.ts +5 -2
  190. package/src/lib/framework/extension-api/types/login.ts +0 -21
  191. package/src/lib/framework/layout-engine/custom-form-page.stories.tsx +344 -0
  192. package/src/lib/framework/layout-engine/page-layout.tsx +11 -9
  193. package/src/lib/framework/layout-engine/page.stories.tsx +275 -0
  194. package/src/lib/framework/nav-menu/nav-menu-extensions.ts +32 -19
  195. package/src/lib/framework/page/detail-page.stories.tsx +151 -0
  196. package/src/lib/framework/page/list-page.stories.tsx +217 -0
  197. package/src/lib/framework/page/list-page.tsx +8 -1
  198. package/src/lib/graphql/api.ts +18 -1
  199. package/src/lib/graphql/graphql-env.d.ts +1 -1
  200. package/src/lib/hooks/use-alerts.ts +84 -0
  201. package/src/lib/hooks/use-floating-bulk-actions.ts +2 -3
  202. package/src/lib/index.ts +14 -1
  203. package/src/lib/providers/alerts-provider.tsx +60 -0
  204. package/src/lib/providers/theme-provider.tsx +6 -3
@@ -151,7 +151,7 @@ let DashboardPlugin = DashboardPlugin_1 = class DashboardPlugin {
151
151
  createStaticServer(dashboardPath) {
152
152
  const limiter = (0, express_rate_limit_1.rateLimit)({
153
153
  windowMs: 60 * 1000,
154
- limit: process.env.NODE_ENV === 'production' ? 500 : 2000,
154
+ limit: process.env.NODE_ENV === 'production' ? 500 : 10000,
155
155
  standardHeaders: true,
156
156
  legacyHeaders: false,
157
157
  });
@@ -2,7 +2,7 @@ import ts from 'typescript';
2
2
  import { describe, expect, it } from 'vitest';
3
3
  import { findConfigExport } from './ast-utils.js';
4
4
  describe('findConfigExport', () => {
5
- it('should return undefined when no VendureConfig export is found', () => {
5
+ it('should return undefined when no VendureConfig export is found', { timeout: 30000 }, () => {
6
6
  const sourceText = `
7
7
  export const notConfig = {
8
8
  some: 'value'
@@ -12,7 +12,7 @@ describe('findConfigExport', () => {
12
12
  const result = findConfigExport(sourceFile);
13
13
  expect(result).toBeUndefined();
14
14
  });
15
- it('should find exported variable with VendureConfig type', () => {
15
+ it('should find exported variable with VendureConfig type', { timeout: 30000 }, () => {
16
16
  const sourceText = `
17
17
  import { VendureConfig } from '@vendure/core';
18
18
 
@@ -26,7 +26,7 @@ describe('findConfigExport', () => {
26
26
  const result = findConfigExport(sourceFile);
27
27
  expect(result).toBe('config');
28
28
  });
29
- it('should find exported variable with VendureConfig type among other exports', () => {
29
+ it('should find exported variable with VendureConfig type among other exports', { timeout: 30000 }, () => {
30
30
  const sourceText = `
31
31
  import { VendureConfig } from '@vendure/core';
32
32
 
@@ -0,0 +1,8 @@
1
+ import { Plugin } from 'vite';
2
+ /**
3
+ * @description
4
+ * This plugin enables kind-of HMR for when dashboard extension files change.
5
+ * It is not true HMR because it triggers a page reload. Making real HMR work is very
6
+ * tricky in this case due to the way we load extension files via virtual modules.
7
+ */
8
+ export declare function hmrPlugin(): Plugin;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @description
3
+ * This plugin enables kind-of HMR for when dashboard extension files change.
4
+ * It is not true HMR because it triggers a page reload. Making real HMR work is very
5
+ * tricky in this case due to the way we load extension files via virtual modules.
6
+ */
7
+ export function hmrPlugin() {
8
+ let viteRoot;
9
+ return {
10
+ name: 'vendure:hmr',
11
+ configResolved(config) {
12
+ viteRoot = config.root;
13
+ },
14
+ handleHotUpdate({ server, modules, timestamp, file }) {
15
+ const invalidatedModules = new Set();
16
+ for (const mod of modules) {
17
+ server.moduleGraph.invalidateModule(mod, invalidatedModules, timestamp, true);
18
+ // Check if this is a file outside the Vite root (e.g., dashboard extensions)
19
+ const isOutsideRoot = mod.file && !mod.file.startsWith(viteRoot);
20
+ if (isOutsideRoot) {
21
+ // For files outside root, trigger a full page reload
22
+ // This ensures all extension code is fresh
23
+ server.ws.send({
24
+ type: 'full-reload',
25
+ path: '*',
26
+ });
27
+ return [];
28
+ }
29
+ }
30
+ // Let Vite handle normal HMR for files inside root
31
+ return undefined;
32
+ },
33
+ };
34
+ }
@@ -7,16 +7,16 @@ const defaultVariables = {
7
7
  popover: 'oklch(1.0000 0 0)',
8
8
  'popover-foreground': 'oklch(0.2103 0.0059 285.8852)',
9
9
  primary: 'oklch(0.7613 0.1503 231.1314)',
10
- 'primary-foreground': 'oklch(0.1408 0.0044 285.8229)',
10
+ 'primary-foreground': 'oklch(0.261 0.043 218.379)',
11
11
  secondary: 'oklch(0.9674 0.0013 286.3752)',
12
12
  'secondary-foreground': 'oklch(0.2103 0.0059 285.8852)',
13
13
  muted: 'oklch(0.9674 0.0013 286.3752)',
14
14
  'muted-foreground': 'oklch(0.5517 0.0138 285.9385)',
15
15
  accent: 'oklch(0.9674 0.0013 286.3752)',
16
16
  'accent-foreground': 'oklch(0.2103 0.0059 285.8852)',
17
- destructive: 'oklch(0.5771 0.2152 27.3250)',
17
+ destructive: 'oklch(0.505 0.188 27.325)',
18
18
  'destructive-foreground': 'oklch(0.9851 0 0)',
19
- success: 'hsl(100, 81%, 35%)',
19
+ success: 'hsl(99deg 67.25% 33.2%)',
20
20
  'success-foreground': 'hsl(0 0% 98%)',
21
21
  'dev-mode': 'hsl(204, 76%, 62%)',
22
22
  'dev-mode-foreground': 'hsl(0 0% 98%)',
@@ -58,9 +58,9 @@ const defaultVariables = {
58
58
  'muted-foreground': 'oklch(0.7118 0.0129 286.0665)',
59
59
  accent: 'oklch(0.2739 0.0055 286.0326)',
60
60
  'accent-foreground': 'oklch(0.9851 0 0)',
61
- destructive: 'oklch(0.6368 0.2078 25.3313)',
61
+ destructive: 'oklch(0.4 0.15 27.11)',
62
62
  'destructive-foreground': 'oklch(0.9851 0 0)',
63
- success: 'hsl(100, 100%, 35%)',
63
+ success: 'hsl(100 76.42% 22.21%)',
64
64
  'success-foreground': 'hsl(0 0% 98%)',
65
65
  'dev-mode': 'hsl(204, 86%, 53%)',
66
66
  'dev-mode-foreground': 'hsl(0 0% 98%)',
@@ -72,7 +72,7 @@ const defaultVariables = {
72
72
  'chart-3': 'oklch(0.6450 0.2154 16.4393)',
73
73
  'chart-4': 'oklch(0.7686 0.1647 70.0804)',
74
74
  'chart-5': 'oklch(0.7227 0.1920 149.5793)',
75
- sidebar: 'oklch(0.1408 0.0044 285.8229)',
75
+ sidebar: 'oklch(0.2 0 0)',
76
76
  'sidebar-foreground': 'oklch(0.9851 0 0)',
77
77
  'sidebar-primary': 'oklch(0.7613 0.1503 231.1314)',
78
78
  'sidebar-primary-foreground': 'oklch(0.1408 0.0044 285.8229)',
@@ -17,7 +17,12 @@ export function transformIndexHtmlPlugin() {
17
17
  },
18
18
  // Only apply this plugin during the build phase
19
19
  apply: 'build',
20
- transformIndexHtml(html) {
20
+ transformIndexHtml(html, ctx) {
21
+ // Don't transform Storybook HTML files
22
+ if (ctx.filename &&
23
+ (ctx.filename.includes('iframe.html') || ctx.filename.includes('storybook'))) {
24
+ return html;
25
+ }
21
26
  if (config.base && config.base !== '/') {
22
27
  // Remove the base path from hrefs and srcs
23
28
  const basePath = config.base.replace(/\/$/, ''); // Remove trailing slash
@@ -73,11 +73,38 @@ export type VitePluginVendureDashboardOptions = {
73
73
  * the location based on the location of the `@vendure/core` package.
74
74
  */
75
75
  pluginPackageScanner?: PackageScannerConfig;
76
+ /**
77
+ * @description
78
+ * Allows you to selectively disable individual plugins.
79
+ * @example
80
+ * ```ts
81
+ * vendureDashboardPlugin({
82
+ * vendureConfigPath: './config.ts',
83
+ * disablePlugins: {
84
+ * react: true,
85
+ * lingui: true,
86
+ * }
87
+ * })
88
+ * ```
89
+ */
90
+ disablePlugins?: {
91
+ tanstackRouter?: boolean;
92
+ react?: boolean;
93
+ lingui?: boolean;
94
+ themeVariables?: boolean;
95
+ tailwindSource?: boolean;
96
+ tailwindcss?: boolean;
97
+ configLoader?: boolean;
98
+ viteConfig?: boolean;
99
+ adminApiSchema?: boolean;
100
+ dashboardMetadata?: boolean;
101
+ uiConfig?: boolean;
102
+ gqlTada?: boolean;
103
+ transformIndexHtml?: boolean;
104
+ translations?: boolean;
105
+ hmr?: boolean;
106
+ };
76
107
  } & UiConfigPluginOptions & ThemeVariablesPluginOptions;
77
- /**
78
- * @description
79
- * This is a Vite plugin which configures a set of plugins required to build the Vendure Dashboard.
80
- */
81
108
  export declare function vendureDashboardPlugin(options: VitePluginVendureDashboardOptions): PluginOption[];
82
109
  /**
83
110
  * Get the normalized path to the Vendure config file given either a string or URL.
@@ -8,60 +8,115 @@ import { configLoaderPlugin } from './vite-plugin-config-loader.js';
8
8
  import { viteConfigPlugin } from './vite-plugin-config.js';
9
9
  import { dashboardMetadataPlugin } from './vite-plugin-dashboard-metadata.js';
10
10
  import { gqlTadaPlugin } from './vite-plugin-gql-tada.js';
11
+ import { hmrPlugin } from './vite-plugin-hmr.js';
11
12
  import { dashboardTailwindSourcePlugin } from './vite-plugin-tailwind-source.js';
12
13
  import { themeVariablesPlugin } from './vite-plugin-theme.js';
13
14
  import { transformIndexHtmlPlugin } from './vite-plugin-transform-index.js';
14
15
  import { translationsPlugin } from './vite-plugin-translations.js';
15
16
  import { uiConfigPlugin } from './vite-plugin-ui-config.js';
16
- /**
17
- * @description
18
- * This is a Vite plugin which configures a set of plugins required to build the Vendure Dashboard.
19
- */
20
17
  export function vendureDashboardPlugin(options) {
21
- var _a;
18
+ var _a, _b;
22
19
  const tempDir = (_a = options.tempCompilationDir) !== null && _a !== void 0 ? _a : path.join(import.meta.dirname, './.vendure-dashboard-temp');
23
20
  const normalizedVendureConfigPath = getNormalizedVendureConfigPath(options.vendureConfigPath);
24
21
  const packageRoot = getDashboardPackageRoot();
25
22
  const linguiConfigPath = path.join(packageRoot, 'lingui.config.js');
23
+ const disabled = (_b = options.disablePlugins) !== null && _b !== void 0 ? _b : {};
26
24
  if (process.env.IS_LOCAL_DEV !== 'true') {
27
25
  process.env.LINGUI_CONFIG = linguiConfigPath;
28
26
  }
29
- return [
30
- ...(options.disableTansStackRouterPlugin
31
- ? []
32
- : [
27
+ const pluginMap = [
28
+ {
29
+ key: 'tanstackRouter',
30
+ plugin: () => !options.disableTansStackRouterPlugin &&
33
31
  tanstackRouter({
34
32
  autoCodeSplitting: true,
35
33
  routeFileIgnorePattern: '.graphql.ts|components|hooks|utils',
36
34
  routesDirectory: path.join(packageRoot, 'src/app/routes'),
37
35
  generatedRouteTree: path.join(packageRoot, 'src/app/routeTree.gen.ts'),
38
36
  }),
39
- ]),
40
- react({
41
- plugins: [['@lingui/swc-plugin', {}]],
42
- }),
43
- lingui({}),
44
- themeVariablesPlugin({ theme: options.theme }),
45
- dashboardTailwindSourcePlugin(),
46
- tailwindcss(),
47
- configLoaderPlugin({
48
- vendureConfigPath: normalizedVendureConfigPath,
49
- outputPath: tempDir,
50
- pathAdapter: options.pathAdapter,
51
- pluginPackageScanner: options.pluginPackageScanner,
52
- }),
53
- viteConfigPlugin({ packageRoot }),
54
- adminApiSchemaPlugin(),
55
- dashboardMetadataPlugin(),
56
- uiConfigPlugin(options),
57
- ...(options.gqlOutputPath
58
- ? [gqlTadaPlugin({ gqlTadaOutputPath: options.gqlOutputPath, tempDir, packageRoot })]
59
- : []),
60
- transformIndexHtmlPlugin(),
61
- translationsPlugin({
62
- packageRoot,
63
- }),
37
+ },
38
+ {
39
+ key: 'react',
40
+ plugin: () => react({
41
+ plugins: [['@lingui/swc-plugin', {}]],
42
+ }),
43
+ },
44
+ {
45
+ key: 'lingui',
46
+ plugin: () => lingui({}),
47
+ },
48
+ {
49
+ key: 'themeVariables',
50
+ plugin: () => themeVariablesPlugin({ theme: options.theme }),
51
+ },
52
+ {
53
+ key: 'tailwindSource',
54
+ plugin: () => dashboardTailwindSourcePlugin(),
55
+ },
56
+ {
57
+ key: 'tailwindcss',
58
+ plugin: () => tailwindcss(),
59
+ },
60
+ {
61
+ key: 'configLoader',
62
+ plugin: () => configLoaderPlugin({
63
+ vendureConfigPath: normalizedVendureConfigPath,
64
+ outputPath: tempDir,
65
+ pathAdapter: options.pathAdapter,
66
+ pluginPackageScanner: options.pluginPackageScanner,
67
+ }),
68
+ },
69
+ {
70
+ key: 'viteConfig',
71
+ plugin: () => viteConfigPlugin({ packageRoot }),
72
+ },
73
+ {
74
+ key: 'adminApiSchema',
75
+ plugin: () => adminApiSchemaPlugin(),
76
+ },
77
+ {
78
+ key: 'dashboardMetadata',
79
+ plugin: () => dashboardMetadataPlugin(),
80
+ },
81
+ {
82
+ key: 'uiConfig',
83
+ plugin: () => uiConfigPlugin(options),
84
+ },
85
+ {
86
+ key: 'gqlTada',
87
+ plugin: () => options.gqlOutputPath &&
88
+ gqlTadaPlugin({ gqlTadaOutputPath: options.gqlOutputPath, tempDir, packageRoot }),
89
+ },
90
+ {
91
+ key: 'transformIndexHtml',
92
+ plugin: () => transformIndexHtmlPlugin(),
93
+ },
94
+ {
95
+ key: 'translations',
96
+ plugin: () => translationsPlugin({
97
+ packageRoot,
98
+ }),
99
+ },
100
+ {
101
+ key: 'hmr',
102
+ plugin: () => hmrPlugin(),
103
+ },
64
104
  ];
105
+ const plugins = [];
106
+ for (const entry of pluginMap) {
107
+ if (!disabled[entry.key]) {
108
+ const plugin = entry.plugin();
109
+ if (plugin) {
110
+ if (Array.isArray(plugin)) {
111
+ plugins.push(...plugin);
112
+ }
113
+ else {
114
+ plugins.push(plugin);
115
+ }
116
+ }
117
+ }
118
+ }
119
+ return plugins;
65
120
  }
66
121
  /**
67
122
  * @description
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vendure/dashboard",
3
3
  "private": false,
4
- "version": "3.5.0-minor-202510071456",
4
+ "version": "3.5.0-minor-202510201346",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
@@ -24,7 +24,10 @@
24
24
  "preview": "vite preview",
25
25
  "generate-index": "node scripts/generate-index.js",
26
26
  "i18n:extract": "lingui extract && node ./scripts/translate/i18n-tool.js extract",
27
- "i18n:apply": "node ./scripts/translate/i18n-tool.js apply"
27
+ "i18n:apply": "node ./scripts/translate/i18n-tool.js apply",
28
+ "storybook": "storybook dev -p 6006",
29
+ "storybook:build": "storybook build",
30
+ "storybook:deploy": "npm run build --prefix ../common && npm run build --prefix ../core && npm run build:vite && storybook build"
28
31
  },
29
32
  "module": "./src/lib/index.ts",
30
33
  "main": "./src/lib/index.ts",
@@ -146,19 +149,28 @@
146
149
  },
147
150
  "devDependencies": {
148
151
  "@eslint/js": "^9.19.0",
152
+ "@storybook/addon-a11y": "^10.0.0-beta.9",
153
+ "@storybook/addon-docs": "^10.0.0-beta.9",
154
+ "@storybook/addon-vitest": "^10.0.0-beta.9",
155
+ "@storybook/react-vite": "^10.0.0-beta.9",
149
156
  "@types/node": "^22.13.4",
150
- "@vendure/common": "^3.5.0-minor-202510071456",
151
- "@vendure/core": "^3.5.0-minor-202510071456",
157
+ "@vendure/common": "^3.5.0-minor-202510201346",
158
+ "@vendure/core": "^3.5.0-minor-202510201346",
159
+ "@vitest/browser": "^3.2.4",
160
+ "@vitest/coverage-v8": "^3.2.4",
152
161
  "eslint": "^9.19.0",
153
162
  "eslint-plugin-react": "^7.37.4",
154
163
  "eslint-plugin-react-hooks": "^5.0.0",
155
164
  "eslint-plugin-react-refresh": "^0.4.18",
165
+ "eslint-plugin-storybook": "^10.0.0-beta.9",
156
166
  "globals": "^15.14.0",
167
+ "playwright": "^1.55.1",
168
+ "storybook": "^10.0.0-beta.9",
157
169
  "vite-plugin-dts": "^4.5.4"
158
170
  },
159
171
  "optionalDependencies": {
160
172
  "lightningcss-linux-arm64-musl": "^1.29.3",
161
173
  "lightningcss-linux-x64-musl": "^1.29.1"
162
174
  },
163
- "gitHead": "a0d7f3f10de46e0ab1825b412baf42093dbd9ebf"
175
+ "gitHead": "6701c9ee1a7f79763fc710486a60d6fd5529c16b"
164
176
  }
@@ -1,3 +1,4 @@
1
+ import { AlertsProvider } from '@/vdb/providers/alerts-provider.js';
1
2
  import { AuthProvider } from '@/vdb/providers/auth.js';
2
3
  import { ChannelProvider } from '@/vdb/providers/channel-provider.js';
3
4
  import { I18nProvider } from '@/vdb/providers/i18n-provider.js';
@@ -17,7 +18,9 @@ export function AppProviders({ children }: { children: React.ReactNode }) {
17
18
  <ThemeProvider defaultTheme="system">
18
19
  <AuthProvider>
19
20
  <ServerConfigProvider>
20
- <ChannelProvider>{children}</ChannelProvider>
21
+ <ChannelProvider>
22
+ <AlertsProvider>{children}</AlertsProvider>
23
+ </ChannelProvider>
21
24
  </ServerConfigProvider>
22
25
  </AuthProvider>
23
26
  </ThemeProvider>
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Maps filter fields to their corresponding ID fields in faceted filters.
3
+ * For example, transforms { category: '5' } to { categoryId: { eq: '5' } }
4
+ *
5
+ * @param facetedFilters - Array of filter objects to transform
6
+ * @param fieldMapping - Record mapping source field names to target field names
7
+ */
8
+ export function mapFacetedFilterFields(
9
+ facetedFilters: Array<Record<string, any>>,
10
+ fieldMapping: Record<string, string>,
11
+ ) {
12
+ for (const [index, filter] of Object.entries(facetedFilters)) {
13
+ for (const [sourceField, targetField] of Object.entries(fieldMapping)) {
14
+ if (filter[sourceField]) {
15
+ facetedFilters[index as unknown as number] = {
16
+ [targetField]: filter[sourceField],
17
+ };
18
+ }
19
+ }
20
+ }
21
+ }
package/src/app/main.tsx CHANGED
@@ -38,7 +38,9 @@ const routerOptions: RouterOptions<AnyRoute, any> = {
38
38
  auth: undefined!, // This will be set after we wrap the app in an AuthProvider
39
39
  queryClient,
40
40
  },
41
- defaultErrorComponent: ({ error }: { error: Error }) => <div>Uh Oh!!! {error.message}</div>,
41
+ defaultErrorComponent: ({ error }: { error: Error }) => (
42
+ <div className="text-destructive p-6">An error occurred: {error.message}</div>
43
+ ),
42
44
  };
43
45
 
44
46
  // Create a type-only router instance for TypeScript type registration
@@ -29,8 +29,8 @@ export const administratorItemFragment = graphql(`
29
29
 
30
30
  export const administratorListDocument = graphql(
31
31
  `
32
- query AdministratorList {
33
- administrators {
32
+ query AdministratorList($options: AdministratorListOptions) {
33
+ administrators(options: $options) {
34
34
  items {
35
35
  ...AdministratorItem
36
36
  }
@@ -24,10 +24,20 @@ function AdministratorListPage() {
24
24
  listQuery={administratorListDocument}
25
25
  route={Route}
26
26
  onSearchTermChange={searchTerm => {
27
+ return searchTerm
28
+ ? {
29
+ firstName: { contains: searchTerm },
30
+ lastName: { contains: searchTerm },
31
+ emailAddress: { contains: searchTerm },
32
+ }
33
+ : {};
34
+ }}
35
+ transformVariables={variables => {
27
36
  return {
28
- firstName: { contains: searchTerm },
29
- lastName: { contains: searchTerm },
30
- emailAddress: { contains: searchTerm },
37
+ options: {
38
+ ...variables.options,
39
+ filterOperator: 'OR',
40
+ },
31
41
  };
32
42
  }}
33
43
  additionalColumns={{
@@ -75,11 +75,9 @@ function AdministratorDetailPage() {
75
75
  params: { id: params.id },
76
76
  onSuccess: async data => {
77
77
  toast(
78
- i18n.t(
79
- creatingNewEntity
80
- ? 'Successfully created administrator'
81
- : 'Successfully updated administrator',
82
- ),
78
+ creatingNewEntity
79
+ ? t`Successfully created administrator`
80
+ : t`Successfully updated administrator`,
83
81
  );
84
82
  resetForm();
85
83
  if (creatingNewEntity) {
@@ -87,14 +85,9 @@ function AdministratorDetailPage() {
87
85
  }
88
86
  },
89
87
  onError: err => {
90
- toast(
91
- i18n.t(
92
- creatingNewEntity ? 'Failed to create administrator' : 'Failed to update administrator',
93
- ),
94
- {
95
- description: err instanceof Error ? err.message : 'Unknown error',
96
- },
97
- );
88
+ toast(creatingNewEntity ? t`Failed to create administrator` : t`Failed to update administrator`, {
89
+ description: err instanceof Error ? err.message : 'Unknown error',
90
+ });
98
91
  },
99
92
  });
100
93
 
@@ -29,7 +29,7 @@ interface RolePermissionsDisplayProps {
29
29
  }
30
30
 
31
31
  export function RolePermissionsDisplay({ value = [] }: Readonly<RolePermissionsDisplayProps>) {
32
- const { t } = useLingui();
32
+ const { i18n } = useLingui();
33
33
  const groupedPermissions = useGroupedPermissions();
34
34
 
35
35
  const { data } = useQuery({
@@ -1,15 +1,29 @@
1
1
  import { AssetGallery } from '@/vdb/components/shared/asset/asset-gallery.js';
2
2
  import { Page, PageBlock, PageTitle } from '@/vdb/framework/layout-engine/page-layout.js';
3
3
  import { Trans } from '@lingui/react/macro';
4
- import { createFileRoute } from '@tanstack/react-router';
4
+ import { createFileRoute, useNavigate } from '@tanstack/react-router';
5
5
  import { DeleteAssetsBulkAction } from './components/asset-bulk-actions.js';
6
6
 
7
7
  export const Route = createFileRoute('/_authenticated/_assets/assets')({
8
8
  component: RouteComponent,
9
9
  loader: () => ({ breadcrumb: () => <Trans>Assets</Trans> }),
10
+ validateSearch: (search: Record<string, unknown>) => {
11
+ return {
12
+ perPage: (search.perPage as number) || 24,
13
+ };
14
+ },
10
15
  });
11
16
 
12
17
  function RouteComponent() {
18
+ const navigate = useNavigate({ from: Route.fullPath });
19
+ const { perPage } = Route.useSearch();
20
+
21
+ const handlePageSizeChange = (newPageSize: number) => {
22
+ navigate({
23
+ search: (prev: any) => ({ ...prev, perPage: newPageSize }),
24
+ });
25
+ };
26
+
13
27
  return (
14
28
  <Page pageId="asset-list">
15
29
  <PageTitle>
@@ -19,6 +33,8 @@ function RouteComponent() {
19
33
  <AssetGallery
20
34
  selectable={true}
21
35
  multiSelect="manual"
36
+ pageSize={perPage}
37
+ onPageSizeChange={handlePageSizeChange}
22
38
  bulkActions={[
23
39
  {
24
40
  order: 10,
@@ -20,6 +20,7 @@ export const collectionListDocument = graphql(
20
20
  }
21
21
  name
22
22
  slug
23
+ description
23
24
  breadcrumbs {
24
25
  id
25
26
  name
@@ -13,6 +13,7 @@ import { ResultOf } from 'gql.tada';
13
13
  import { Folder, FolderOpen, PlusIcon } from 'lucide-react';
14
14
  import { useState } from 'react';
15
15
 
16
+ import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
16
17
  import { Badge } from '@/vdb/components/ui/badge.js';
17
18
  import { collectionListDocument } from './collections.graphql.js';
18
19
  import {
@@ -123,6 +124,9 @@ function CollectionListPage() {
123
124
  );
124
125
  },
125
126
  },
127
+ description: {
128
+ cell: RichTextDescriptionCell,
129
+ },
126
130
  breadcrumbs: {
127
131
  cell: ({ cell }) => {
128
132
  const value = cell.getValue();
@@ -204,6 +208,7 @@ function CollectionListPage() {
204
208
  position: false,
205
209
  parentId: false,
206
210
  children: false,
211
+ description: false,
207
212
  }}
208
213
  onSearchTermChange={searchTerm => {
209
214
  return {
@@ -68,7 +68,6 @@ export const DuplicateCollectionsBulkAction: BulkActionComponent<any> = ({ selec
68
68
  <DuplicateBulkAction
69
69
  entityType="Collection"
70
70
  duplicatorCode="collection-duplicator"
71
- duplicatorArguments={[]}
72
71
  requiredPermissions={['UpdateCatalog', 'UpdateCollection']}
73
72
  entityName="Collection"
74
73
  selection={selection}
@@ -51,11 +51,15 @@ function CustomerListPage() {
51
51
  },
52
52
  groups: {
53
53
  cell: ({ row }) => {
54
- return row.original.groups?.map(g => (
55
- <Badge variant="secondary" key={g.id}>
56
- {g.name}
57
- </Badge>
58
- ));
54
+ return (
55
+ <div className="flex flex-wrap gap-1">
56
+ {row.original.groups?.map(g => (
57
+ <Badge variant="secondary" key={g.id}>
58
+ {g.name}
59
+ </Badge>
60
+ ))}
61
+ </div>
62
+ );
59
63
  },
60
64
  },
61
65
  }}
@@ -90,12 +90,6 @@ export const DuplicateFacetsBulkAction: BulkActionComponent<any> = ({ selection,
90
90
  <DuplicateBulkAction
91
91
  entityType="Facet"
92
92
  duplicatorCode="facet-duplicator"
93
- duplicatorArguments={[
94
- {
95
- name: 'includeValues',
96
- value: 'true',
97
- },
98
- ]}
99
93
  requiredPermissions={['UpdateCatalog', 'UpdateFacet']}
100
94
  entityName="Facet"
101
95
  selection={selection}
@@ -0,0 +1,16 @@
1
+ import { BulkActionComponent } from '@/vdb/framework/extension-api/types/data-table.js';
2
+ import { DeleteBulkAction } from '../../../../common/delete-bulk-action.js';
3
+
4
+ import { deleteFacetValuesDocument } from '../facets.graphql.js';
5
+
6
+ export const DeleteFacetValuesBulkAction: BulkActionComponent<any> = ({ selection, table }) => {
7
+ return (
8
+ <DeleteBulkAction
9
+ mutationDocument={deleteFacetValuesDocument}
10
+ entityName="facets"
11
+ requiredPermissions={['DeleteCatalog', 'DeleteFacet']}
12
+ selection={selection}
13
+ table={table}
14
+ />
15
+ );
16
+ };