@wilshop/dashboard 3.5.5 → 3.5.7

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 (133) hide show
  1. package/dist/plugin/dashboard.plugin.d.ts +1 -1
  2. package/dist/plugin/dashboard.plugin.js +1 -1
  3. package/dist/vite/utils/compiler.js +50 -24
  4. package/dist/vite/utils/path-transformer.d.ts +20 -0
  5. package/dist/vite/utils/path-transformer.js +116 -0
  6. package/dist/vite/utils/plugin-discovery.js +3 -2
  7. package/dist/vite/utils/ui-config.js +15 -1
  8. package/dist/vite/vite-plugin-lingui-babel.d.ts +15 -2
  9. package/dist/vite/vite-plugin-lingui-babel.js +92 -17
  10. package/dist/vite/vite-plugin-translations.js +2 -2
  11. package/dist/vite/vite-plugin-ui-config.d.ts +31 -0
  12. package/package.json +10 -6
  13. package/src/app/common/delete-bulk-action.tsx +1 -1
  14. package/src/app/common/duplicate-bulk-action.tsx +1 -1
  15. package/src/app/routes/_authenticated/_collections/collections.graphql.ts +1 -3
  16. package/src/app/routes/_authenticated/_collections/collections.tsx +169 -48
  17. package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +36 -5
  18. package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +1 -1
  19. package/src/app/routes/_authenticated/_collections/components/collection-filters-selector.tsx +7 -1
  20. package/src/app/routes/_authenticated/_customers/components/customer-history/default-customer-history-components.tsx +31 -29
  21. package/src/app/routes/_authenticated/_customers/customers.graphql.ts +1 -0
  22. package/src/app/routes/_authenticated/_customers/customers.tsx +3 -0
  23. package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +1 -1
  24. package/src/app/routes/_authenticated/_orders/components/draft-order-status.tsx +48 -0
  25. package/src/app/routes/_authenticated/_orders/components/fulfill-order-dialog.tsx +8 -5
  26. package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +79 -54
  27. package/src/app/routes/_authenticated/_orders/components/order-history/default-order-history-components.tsx +43 -3
  28. package/src/app/routes/_authenticated/_orders/components/order-history/order-history-utils.tsx +19 -3
  29. package/src/app/routes/_authenticated/_orders/components/order-table.tsx +1 -0
  30. package/src/app/routes/_authenticated/_orders/components/refund-order-dialog.tsx +372 -0
  31. package/src/app/routes/_authenticated/_orders/hooks/use-refund-order.ts +345 -0
  32. package/src/app/routes/_authenticated/_orders/orders.graphql.ts +41 -0
  33. package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +22 -6
  34. package/src/app/routes/_authenticated/_orders/utils/order-utils.ts +51 -0
  35. package/src/app/routes/_authenticated/_orders/utils/refund-utils.ts +100 -0
  36. package/src/app/routes/_authenticated/_orders/utils/use-modify-order.ts +1 -1
  37. package/src/app/routes/_authenticated/_payment-methods/components/payment-eligibility-checker-selector.tsx +4 -1
  38. package/src/app/routes/_authenticated/_payment-methods/components/payment-handler-selector.tsx +7 -1
  39. package/src/app/routes/_authenticated/_payment-methods/payment-methods_.$id.tsx +18 -2
  40. package/src/app/routes/_authenticated/_product-variants/components/product-variant-bulk-actions.tsx +1 -1
  41. package/src/app/routes/_authenticated/_product-variants/components/variant-price-detail.tsx +6 -2
  42. package/src/app/routes/_authenticated/_product-variants/product-variants.graphql.ts +9 -3
  43. package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +49 -30
  44. package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +1 -1
  45. package/src/app/routes/_authenticated/_profile/profile.graphql.ts +7 -0
  46. package/src/app/routes/_authenticated/_profile/profile.tsx +25 -1
  47. package/src/app/routes/_authenticated/_promotions/components/promotion-actions-selector.tsx +7 -1
  48. package/src/app/routes/_authenticated/_promotions/components/promotion-conditions-selector.tsx +7 -1
  49. package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +18 -2
  50. package/src/app/routes/_authenticated/_shipping-methods/components/shipping-calculator-selector.tsx +7 -1
  51. package/src/app/routes/_authenticated/_shipping-methods/components/shipping-eligibility-checker-selector.tsx +4 -1
  52. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +14 -2
  53. package/src/i18n/common-strings.ts +7 -0
  54. package/src/i18n/locales/ar.po +669 -399
  55. package/src/i18n/locales/bg.po +1889 -46
  56. package/src/i18n/locales/cs.po +676 -406
  57. package/src/i18n/locales/de.po +676 -406
  58. package/src/i18n/locales/en.po +669 -399
  59. package/src/i18n/locales/es.po +676 -406
  60. package/src/i18n/locales/fa.po +676 -406
  61. package/src/i18n/locales/fr.po +676 -406
  62. package/src/i18n/locales/he.po +676 -406
  63. package/src/i18n/locales/hr.po +676 -406
  64. package/src/i18n/locales/it.po +676 -406
  65. package/src/i18n/locales/ja.po +676 -406
  66. package/src/i18n/locales/nb.po +676 -406
  67. package/src/i18n/locales/ne.po +676 -406
  68. package/src/i18n/locales/pl.po +676 -406
  69. package/src/i18n/locales/pt_BR.po +676 -406
  70. package/src/i18n/locales/pt_PT.po +676 -406
  71. package/src/i18n/locales/ru.po +676 -406
  72. package/src/i18n/locales/sv.po +676 -406
  73. package/src/i18n/locales/tr.po +676 -406
  74. package/src/i18n/locales/uk.po +676 -406
  75. package/src/i18n/locales/zh_Hans.po +676 -406
  76. package/src/i18n/locales/zh_Hant.po +676 -406
  77. package/src/lib/components/data-input/facet-value-input.tsx +2 -2
  78. package/src/lib/components/data-input/index.ts +1 -0
  79. package/src/lib/components/data-input/select-with-options.tsx +23 -7
  80. package/src/lib/components/data-input/struct-form-input.tsx +53 -21
  81. package/src/lib/components/data-input/text-input.tsx +1 -1
  82. package/src/lib/components/data-table/data-table-bulk-actions.tsx +2 -1
  83. package/src/lib/components/data-table/data-table-context.tsx +2 -10
  84. package/src/lib/components/data-table/data-table-utils.ts +34 -12
  85. package/src/lib/components/data-table/data-table.tsx +68 -30
  86. package/src/lib/components/data-table/global-views-bar.tsx +1 -1
  87. package/src/lib/components/data-table/my-views-button.tsx +1 -1
  88. package/src/lib/components/data-table/save-view-button.tsx +1 -1
  89. package/src/lib/components/data-table/use-generated-columns.tsx +9 -2
  90. package/src/lib/components/data-table/views-sheet.tsx +1 -1
  91. package/src/lib/components/layout/channel-switcher.tsx +16 -17
  92. package/src/lib/components/layout/manage-languages-dialog.tsx +1 -1
  93. package/src/lib/components/shared/assign-to-channel-bulk-action.tsx +1 -1
  94. package/src/lib/components/shared/configurable-operation-input.tsx +23 -0
  95. package/src/lib/components/shared/configurable-operation-multi-selector.tsx +45 -0
  96. package/src/lib/components/shared/configurable-operation-selector.tsx +5 -0
  97. package/src/lib/components/shared/paginated-list-context.ts +10 -0
  98. package/src/lib/components/shared/paginated-list-data-table.tsx +6 -32
  99. package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +1 -1
  100. package/src/lib/components/ui/alert.tsx +2 -0
  101. package/src/lib/constants.ts +7 -319
  102. package/src/lib/framework/dashboard-widget/base-widget.tsx +3 -12
  103. package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +1 -1
  104. package/src/lib/framework/dashboard-widget/metrics-widget/chart.tsx +1 -1
  105. package/src/lib/framework/dashboard-widget/metrics-widget/index.tsx +1 -1
  106. package/src/lib/framework/dashboard-widget/orders-summary/index.tsx +1 -1
  107. package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +2 -20
  108. package/src/lib/framework/extension-api/input-component-extensions.tsx +4 -0
  109. package/src/lib/framework/form-engine/custom-form-component.tsx +13 -3
  110. package/src/lib/framework/form-engine/form-engine-types.ts +3 -5
  111. package/src/lib/framework/form-engine/form-schema-tools.ts +4 -1
  112. package/src/lib/framework/form-engine/use-generated-form.tsx +6 -2
  113. package/src/lib/framework/form-engine/utils.spec.ts +129 -2
  114. package/src/lib/framework/form-engine/utils.ts +36 -9
  115. package/src/lib/framework/form-engine/value-transformers.ts +6 -0
  116. package/src/lib/framework/page/detail-page-route-loader.tsx +6 -4
  117. package/src/lib/framework/page/detail-page.tsx +22 -37
  118. package/src/lib/framework/page/list-page.stories.tsx +41 -2
  119. package/src/lib/framework/page/list-page.tsx +8 -0
  120. package/src/lib/graphql/graphql-env.d.ts +33 -16
  121. package/src/lib/graphql/schema-enums.ts +13 -0
  122. package/src/lib/hooks/use-alerts-context.ts +10 -0
  123. package/src/lib/hooks/use-alerts.ts +1 -1
  124. package/src/lib/hooks/use-data-table-context.ts +11 -0
  125. package/src/lib/hooks/use-dynamic-translations.ts +7 -0
  126. package/src/lib/hooks/use-job-queue-polling.ts +160 -0
  127. package/src/lib/hooks/use-paginated-list.ts +28 -0
  128. package/src/lib/hooks/use-widget-dimensions.ts +12 -0
  129. package/src/lib/hooks/use-widget-filters.ts +21 -0
  130. package/src/lib/index.ts +12 -0
  131. package/src/lib/providers/alerts-provider.tsx +3 -11
  132. package/src/lib/virtual.d.ts +5 -0
  133. package/src/lib/utils/global-languages.ts +0 -268
@@ -42,7 +42,7 @@ export interface DashboardPluginOptions {
42
42
  * ## Usage
43
43
  *
44
44
  * First you need to set up compilation of the Dashboard, using the Vite configuration
45
- * described in the [Dashboard Getting Started Guide](/guides/extending-the-dashboard/getting-started/)
45
+ * described in the [Dashboard Getting Started Guide](/extending-the-dashboard/getting-started/)
46
46
  *
47
47
  * ## Development vs Production
48
48
  *
@@ -69,7 +69,7 @@ const metrics_service_js_1 = require("./service/metrics.service.js");
69
69
  * ## Usage
70
70
  *
71
71
  * First you need to set up compilation of the Dashboard, using the Vite configuration
72
- * described in the [Dashboard Getting Started Guide](/guides/extending-the-dashboard/getting-started/)
72
+ * described in the [Dashboard Getting Started Guide](/extending-the-dashboard/getting-started/)
73
73
  *
74
74
  * ## Development vs Production
75
75
  *
@@ -5,6 +5,7 @@ import * as ts from 'typescript';
5
5
  import { pathToFileURL } from 'url';
6
6
  import { findConfigExport } from './ast-utils.js';
7
7
  import { noopLogger } from './logger.js';
8
+ import { createPathTransformer } from './path-transformer.js';
8
9
  import { discoverPlugins } from './plugin-discovery.js';
9
10
  import { findTsConfigPaths } from './tsconfig-utils.js';
10
11
  const defaultPathAdapter = {
@@ -16,7 +17,7 @@ const defaultPathAdapter = {
16
17
  * and in node_modules.
17
18
  */
18
19
  export async function compile(options) {
19
- var _a, _b, _c;
20
+ var _a, _b, _c, _d;
20
21
  const { vendureConfigPath, outputPath, pathAdapter, logger = noopLogger, pluginPackageScanner } = options;
21
22
  const getCompiledConfigPath = (_a = pathAdapter === null || pathAdapter === void 0 ? void 0 : pathAdapter.getCompiledConfigPath) !== null && _a !== void 0 ? _a : defaultPathAdapter.getCompiledConfigPath;
22
23
  const transformTsConfigPathMappings = (_b = pathAdapter === null || pathAdapter === void 0 ? void 0 : pathAdapter.transformTsConfigPathMappings) !== null && _b !== void 0 ? _b : defaultPathAdapter.transformTsConfigPathMappings;
@@ -70,7 +71,8 @@ export async function compile(options) {
70
71
  config = await import(compiledConfigFilePath).then(m => m[exportedSymbolName]);
71
72
  }
72
73
  catch (e) {
73
- logger.error(`Error loading config: ${e instanceof Error ? e.message : String(e)}`);
74
+ const errorMessage = e instanceof Error ? `${e.message}\n${(_d = e.stack) !== null && _d !== void 0 ? _d : ''}` : JSON.stringify(e, null, 2);
75
+ logger.error(`Error loading config: ${errorMessage}`);
74
76
  }
75
77
  if (!config) {
76
78
  throw new Error(`Could not find a variable exported as VendureConfig with the name "${exportedSymbolName}".`);
@@ -84,8 +86,11 @@ export async function compile(options) {
84
86
  async function compileTypeScript({ inputPath, outputPath, logger, transformTsConfigPathMappings, module, }) {
85
87
  var _a;
86
88
  await fs.ensureDir(outputPath);
87
- // Find tsconfig paths first
88
- const tsConfigInfo = await findTsConfigPaths(inputPath, logger, 'compiling', transformTsConfigPathMappings);
89
+ // Find tsconfig paths - we need BOTH original and transformed versions
90
+ // Original paths: Used by TypeScript for module resolution during compilation
91
+ // Transformed paths: Used by the path transformer for rewriting output imports
92
+ const originalTsConfigInfo = await findTsConfigPaths(inputPath, logger, 'compiling', ({ patterns }) => patterns);
93
+ const transformedTsConfigInfo = await findTsConfigPaths(inputPath, logger, 'compiling', transformTsConfigPathMappings);
89
94
  const compilerOptions = {
90
95
  target: ts.ScriptTarget.ES2020,
91
96
  module: module === 'esm' ? ts.ModuleKind.ESNext : ts.ModuleKind.CommonJS,
@@ -110,30 +115,51 @@ async function compileTypeScript({ inputPath, outputPath, logger, transformTsCon
110
115
  outDir: outputPath,
111
116
  };
112
117
  logger.debug(`Compiling ${inputPath} to ${outputPath} using TypeScript...`);
113
- // Add path mappings if found
114
- if (tsConfigInfo) {
118
+ // Add path mappings if found - use ORIGINAL paths for TypeScript module resolution
119
+ if (originalTsConfigInfo) {
115
120
  // We need to set baseUrl and paths for TypeScript to resolve the imports
116
- compilerOptions.baseUrl = tsConfigInfo.baseUrl;
117
- compilerOptions.paths = tsConfigInfo.paths;
121
+ compilerOptions.baseUrl = originalTsConfigInfo.baseUrl;
122
+ compilerOptions.paths = originalTsConfigInfo.paths;
118
123
  // This is critical - it tells TypeScript to preserve the paths in the output
119
- // compilerOptions.rootDir = tsConfigInfo.baseUrl;
124
+ // compilerOptions.rootDir = originalTsConfigInfo.baseUrl;
125
+ }
126
+ logger.debug(`tsConfig original paths: ${JSON.stringify(originalTsConfigInfo === null || originalTsConfigInfo === void 0 ? void 0 : originalTsConfigInfo.paths, null, 2)}`);
127
+ logger.debug(`tsConfig transformed paths: ${JSON.stringify(transformedTsConfigInfo === null || transformedTsConfigInfo === void 0 ? void 0 : transformedTsConfigInfo.paths, null, 2)}`);
128
+ logger.debug(`tsConfig baseUrl: ${(_a = originalTsConfigInfo === null || originalTsConfigInfo === void 0 ? void 0 : originalTsConfigInfo.baseUrl) !== null && _a !== void 0 ? _a : 'UNKNOWN'}`);
129
+ // Build custom transformers
130
+ const afterTransformers = [];
131
+ // Add path transformer for ESM mode when there are path mappings
132
+ // This is necessary because tsconfig-paths.register() only works for CommonJS require(),
133
+ // not for ESM import(). We need to transform the import paths during compilation.
134
+ //
135
+ // IMPORTANT: We use 'after' transformers because:
136
+ // 1. 'before' runs before TypeScript resolves modules - changing paths there breaks resolution
137
+ // 2. 'after' runs after module resolution but before emit - paths are transformed in output only
138
+ //
139
+ // We use ORIGINAL (untransformed) paths here because the transformer resolves aliases
140
+ // relative to the source file's directory using path.relative(). Since TypeScript preserves
141
+ // directory nesting in output, the relative relationships between source files are the same
142
+ // in both the source and output trees.
143
+ if (module === 'esm' && originalTsConfigInfo) {
144
+ logger.debug('Adding path transformer for ESM mode');
145
+ afterTransformers.push(createPathTransformer({
146
+ baseUrl: originalTsConfigInfo.baseUrl,
147
+ paths: originalTsConfigInfo.paths,
148
+ }));
120
149
  }
121
- logger.debug(`tsConfig paths: ${JSON.stringify(tsConfigInfo === null || tsConfigInfo === void 0 ? void 0 : tsConfigInfo.paths, null, 2)}`);
122
- logger.debug(`tsConfig baseUrl: ${(_a = tsConfigInfo === null || tsConfigInfo === void 0 ? void 0 : tsConfigInfo.baseUrl) !== null && _a !== void 0 ? _a : 'UNKNOWN'}`);
123
- // Create a custom transformer to rewrite the output paths
150
+ // Add the existing transformer for non-entry-point files
151
+ afterTransformers.push(context => {
152
+ return sourceFile => {
153
+ // Only transform files that are not the entry point
154
+ if (sourceFile.fileName === inputPath) {
155
+ return sourceFile;
156
+ }
157
+ sourceFile.fileName = path.join(outputPath, path.basename(sourceFile.fileName));
158
+ return sourceFile;
159
+ };
160
+ });
124
161
  const customTransformers = {
125
- after: [
126
- context => {
127
- return sourceFile => {
128
- // Only transform files that are not the entry point
129
- if (sourceFile.fileName === inputPath) {
130
- return sourceFile;
131
- }
132
- sourceFile.fileName = path.join(outputPath, path.basename(sourceFile.fileName));
133
- return sourceFile;
134
- };
135
- },
136
- ],
162
+ after: afterTransformers,
137
163
  };
138
164
  const program = ts.createProgram([inputPath], compilerOptions);
139
165
  const emitResult = program.emit(undefined, undefined, undefined, undefined, customTransformers);
@@ -0,0 +1,20 @@
1
+ import * as ts from 'typescript';
2
+ export interface PathTransformerOptions {
3
+ baseUrl: string;
4
+ paths: Record<string, string[]>;
5
+ }
6
+ /**
7
+ * Creates a TypeScript custom transformer that rewrites import/export paths
8
+ * from tsconfig path aliases to their resolved relative paths.
9
+ *
10
+ * This is necessary for ESM mode where tsconfig-paths.register() doesn't work
11
+ * because it only hooks into CommonJS require(), not ESM import().
12
+ *
13
+ * The transformer uses the source file's location and the tsconfig baseUrl to
14
+ * compute correct relative paths, even for files in nested directories.
15
+ *
16
+ * Known limitations:
17
+ * - Only the first path target is used when multiple fallbacks are configured
18
+ * - `require()` calls via `createRequire` are not transformed
19
+ */
20
+ export declare function createPathTransformer(options: PathTransformerOptions): ts.TransformerFactory<ts.SourceFile>;
@@ -0,0 +1,116 @@
1
+ import * as path from 'node:path';
2
+ import * as ts from 'typescript';
3
+ /**
4
+ * Creates a TypeScript custom transformer that rewrites import/export paths
5
+ * from tsconfig path aliases to their resolved relative paths.
6
+ *
7
+ * This is necessary for ESM mode where tsconfig-paths.register() doesn't work
8
+ * because it only hooks into CommonJS require(), not ESM import().
9
+ *
10
+ * The transformer uses the source file's location and the tsconfig baseUrl to
11
+ * compute correct relative paths, even for files in nested directories.
12
+ *
13
+ * Known limitations:
14
+ * - Only the first path target is used when multiple fallbacks are configured
15
+ * - `require()` calls via `createRequire` are not transformed
16
+ */
17
+ export function createPathTransformer(options) {
18
+ const { baseUrl, paths } = options;
19
+ // Compile the path patterns into matchers
20
+ const pathMatchers = Object.entries(paths).map(([pattern, targets]) => {
21
+ const hasWildcard = pattern.includes('*');
22
+ // Escape special regex chars, then replace * with capture group
23
+ const regexStr = pattern
24
+ .replace(/[.+?^${}()|[\]\\]/g, String.raw `\$&`)
25
+ .split('*')
26
+ .join('(.*)');
27
+ const regex = new RegExp('^' + regexStr + '$');
28
+ return { pattern, regex, targets, hasWildcard };
29
+ });
30
+ return context => {
31
+ return sourceFile => {
32
+ const sourceDir = path.dirname(sourceFile.fileName);
33
+ const visitor = node => {
34
+ // Handle import declarations: import { X } from 'module';
35
+ if (ts.isImportDeclaration(node) &&
36
+ node.moduleSpecifier &&
37
+ ts.isStringLiteral(node.moduleSpecifier)) {
38
+ const resolvedPath = resolvePathAlias(node.moduleSpecifier.text, pathMatchers, baseUrl, sourceDir);
39
+ if (resolvedPath) {
40
+ return context.factory.updateImportDeclaration(node, node.modifiers, node.importClause, context.factory.createStringLiteral(resolvedPath), node.attributes);
41
+ }
42
+ }
43
+ // Handle export declarations: export { X } from 'module';
44
+ if (ts.isExportDeclaration(node) &&
45
+ node.moduleSpecifier &&
46
+ ts.isStringLiteral(node.moduleSpecifier)) {
47
+ const resolvedPath = resolvePathAlias(node.moduleSpecifier.text, pathMatchers, baseUrl, sourceDir);
48
+ if (resolvedPath) {
49
+ return context.factory.updateExportDeclaration(node, node.modifiers, node.isTypeOnly, node.exportClause, context.factory.createStringLiteral(resolvedPath), node.attributes);
50
+ }
51
+ }
52
+ // Handle dynamic imports: import('module')
53
+ if (ts.isCallExpression(node) &&
54
+ node.expression.kind === ts.SyntaxKind.ImportKeyword &&
55
+ node.arguments.length > 0 &&
56
+ ts.isStringLiteral(node.arguments[0])) {
57
+ const resolvedPath = resolvePathAlias(node.arguments[0].text, pathMatchers, baseUrl, sourceDir);
58
+ if (resolvedPath) {
59
+ return context.factory.updateCallExpression(node, node.expression, node.typeArguments, [context.factory.createStringLiteral(resolvedPath), ...node.arguments.slice(1)]);
60
+ }
61
+ }
62
+ return ts.visitEachChild(node, visitor, context);
63
+ };
64
+ return ts.visitNode(sourceFile, visitor);
65
+ };
66
+ };
67
+ }
68
+ /**
69
+ * Resolves a path alias to its actual path, computed relative to the source file's directory.
70
+ * Returns undefined if the module specifier doesn't match any path alias.
71
+ */
72
+ function resolvePathAlias(moduleSpecifier, pathMatchers, baseUrl, sourceDir) {
73
+ if (moduleSpecifier.startsWith('.') || moduleSpecifier.startsWith('/')) {
74
+ return undefined;
75
+ }
76
+ for (const { regex, targets, hasWildcard } of pathMatchers) {
77
+ const match = regex.exec(moduleSpecifier);
78
+ if (match) {
79
+ const target = targets[0];
80
+ const resolved = hasWildcard && match[1] ? target.split('*').join(match[1]) : target;
81
+ // Compute absolute target path from baseUrl, then get relative path from source dir
82
+ const absoluteTarget = path.resolve(baseUrl, resolved);
83
+ let relativePath = path.relative(sourceDir, absoluteTarget);
84
+ // Normalize path separators to forward slashes
85
+ relativePath = relativePath.split('\\').join('/');
86
+ // Ensure relative path has ./ or ../ prefix
87
+ if (!relativePath.startsWith('.')) {
88
+ relativePath = './' + relativePath;
89
+ }
90
+ // Convert TypeScript extensions to JavaScript equivalents for ESM
91
+ return convertExtension(relativePath);
92
+ }
93
+ }
94
+ return undefined;
95
+ }
96
+ /**
97
+ * Converts TypeScript extensions to JavaScript equivalents for ESM.
98
+ * .ts -> .js, .tsx -> .js, .mts -> .mjs, .cts -> .cjs
99
+ */
100
+ function convertExtension(filePath) {
101
+ if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
102
+ return filePath.replace(/\.tsx?$/, '.js');
103
+ }
104
+ if (filePath.endsWith('.mts')) {
105
+ return filePath.replace(/\.mts$/, '.mjs');
106
+ }
107
+ if (filePath.endsWith('.cts')) {
108
+ return filePath.replace(/\.cts$/, '.cjs');
109
+ }
110
+ // No extension - assume directory import, add /index.js
111
+ if (!/\.\w+$/.test(filePath)) {
112
+ return `${filePath}/index.js`;
113
+ }
114
+ // Files with other extensions (.json, .js, etc.) are left as-is
115
+ return filePath;
116
+ }
@@ -323,8 +323,9 @@ export async function findVendurePluginFiles({ outputPath, vendureConfigPath, lo
323
323
  const globStart = Date.now();
324
324
  const files = await glob(patterns, {
325
325
  ignore: [
326
- // Standard test & doc files
327
- '**/node_modules/**/node_modules/**',
326
+ // Skip nested node_modules (transitive deps) but not .pnpm or .bun directories.
327
+ // [!.] excludes paths starting with . since pnpm and bun store packages there.
328
+ '**/node_modules/[!.]*/**/node_modules/**',
328
329
  '**/*.spec.js',
329
330
  '**/*.test.js',
330
331
  ],
@@ -1,7 +1,7 @@
1
1
  import { ADMIN_API_PATH, DEFAULT_AUTH_TOKEN_HEADER_KEY, DEFAULT_CHANNEL_TOKEN_KEY, } from '@vendure/common/lib/shared-constants';
2
2
  import { defaultAvailableLanguages, defaultAvailableLocales, defaultLanguage, defaultLocale, } from '../constants.js';
3
3
  export function getUiConfig(config, pluginOptions) {
4
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
4
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
5
5
  const { authOptions, apiOptions } = config;
6
6
  // Merge API configuration with defaults
7
7
  const api = {
@@ -23,8 +23,22 @@ export function getUiConfig(config, pluginOptions) {
23
23
  ? pluginOptions.i18n.availableLocales
24
24
  : defaultAvailableLocales,
25
25
  };
26
+ // Merge orders configuration with defaults
27
+ // Default labels are identifiers that get translated via getTranslatedRefundReason()
28
+ const orders = {
29
+ refundReasons: ((_x = pluginOptions.orders) === null || _x === void 0 ? void 0 : _x.refundReasons) && pluginOptions.orders.refundReasons.length > 0
30
+ ? pluginOptions.orders.refundReasons
31
+ : [
32
+ { value: 'customer-request', label: 'CustomerRequest' },
33
+ { value: 'not-available', label: 'NotAvailable' },
34
+ { value: 'damaged-shipping', label: 'DamagedInShipping' },
35
+ { value: 'wrong-item', label: 'WrongItem' },
36
+ { value: 'other', label: 'Other' },
37
+ ],
38
+ };
26
39
  return {
27
40
  api,
28
41
  i18n,
42
+ orders,
29
43
  };
30
44
  }
@@ -1,4 +1,14 @@
1
1
  import type { Plugin } from 'vite';
2
+ /**
3
+ * Options for the linguiBabelPlugin.
4
+ */
5
+ export interface LinguiBabelPluginOptions {
6
+ /**
7
+ * For testing: manually specify package paths that should have Lingui macros transformed.
8
+ * In production, these are automatically discovered from the VendureConfig plugins.
9
+ */
10
+ additionalPackagePaths?: string[];
11
+ }
2
12
  /**
3
13
  * @description
4
14
  * A custom Vite plugin that transforms Lingui macros in files using Babel instead of SWC.
@@ -17,11 +27,14 @@ import type { Plugin } from 'vite';
17
27
  * - `@vendure/dashboard/src` files (in node_modules for external projects)
18
28
  * - `packages/dashboard/src` files (in monorepo development)
19
29
  * - User's dashboard extension files (e.g., custom plugins using Lingui)
30
+ * - Third-party npm packages that provide dashboard extensions (discovered automatically)
20
31
  *
21
32
  * Files NOT processed:
22
- * - Other node_modules packages (they shouldn't contain Lingui macros)
33
+ * - Files that don't contain Lingui macro imports (fast check via string matching)
34
+ * - Non-JS/TS files
35
+ * - node_modules packages that are not discovered as Vendure plugins
23
36
  *
24
37
  * @see https://github.com/vendurehq/vendure/issues/3929
25
38
  * @see https://github.com/lingui/swc-plugin/issues/179
26
39
  */
27
- export declare function linguiBabelPlugin(): Plugin;
40
+ export declare function linguiBabelPlugin(options?: LinguiBabelPluginOptions): Plugin;
@@ -1,4 +1,5 @@
1
1
  import * as babel from '@babel/core';
2
+ import { getConfigLoaderApi } from './vite-plugin-config-loader.js';
2
3
  /**
3
4
  * @description
4
5
  * A custom Vite plugin that transforms Lingui macros in files using Babel instead of SWC.
@@ -17,19 +18,40 @@ import * as babel from '@babel/core';
17
18
  * - `@vendure/dashboard/src` files (in node_modules for external projects)
18
19
  * - `packages/dashboard/src` files (in monorepo development)
19
20
  * - User's dashboard extension files (e.g., custom plugins using Lingui)
21
+ * - Third-party npm packages that provide dashboard extensions (discovered automatically)
20
22
  *
21
23
  * Files NOT processed:
22
- * - Other node_modules packages (they shouldn't contain Lingui macros)
24
+ * - Files that don't contain Lingui macro imports (fast check via string matching)
25
+ * - Non-JS/TS files
26
+ * - node_modules packages that are not discovered as Vendure plugins
23
27
  *
24
28
  * @see https://github.com/vendurehq/vendure/issues/3929
25
29
  * @see https://github.com/lingui/swc-plugin/issues/179
26
30
  */
27
- export function linguiBabelPlugin() {
31
+ export function linguiBabelPlugin(options) {
32
+ var _a;
33
+ // Paths of npm packages that should have Lingui macros transformed.
34
+ // This is populated from plugin discovery when transform is first called.
35
+ const allowedNodeModulesPackages = new Set((_a = options === null || options === void 0 ? void 0 : options.additionalPackagePaths) !== null && _a !== void 0 ? _a : []);
36
+ // API reference to the config loader plugin (set in configResolved)
37
+ let configLoaderApi;
38
+ // Cached result from config loader (set on first transform that needs it)
39
+ let configResult;
28
40
  return {
29
41
  name: 'vendure:lingui-babel',
30
42
  // Run BEFORE @vitejs/plugin-react so the macros are already transformed
31
43
  // when the react plugin processes the file
32
44
  enforce: 'pre',
45
+ configResolved({ plugins }) {
46
+ // Get reference to the config loader API.
47
+ // This doesn't load the config yet - that happens lazily in transform.
48
+ try {
49
+ configLoaderApi = getConfigLoaderApi(plugins);
50
+ }
51
+ catch (_a) {
52
+ // configLoaderPlugin not available (e.g., plugin used standalone for testing)
53
+ }
54
+ },
33
55
  async transform(code, id) {
34
56
  // Strip query params for path matching (Vite adds ?v=xxx for cache busting)
35
57
  const cleanId = id.split('?')[0];
@@ -42,22 +64,42 @@ export function linguiBabelPlugin() {
42
64
  if (!code.includes('@lingui/') || !code.includes('/macro')) {
43
65
  return null;
44
66
  }
45
- // Skip node_modules files EXCEPT for @wilshop/dashboard source
46
- // This ensures:
47
- // 1. Dashboard source files get transformed (both in monorepo and external projects)
48
- // 2. User's extension files get transformed (not in node_modules)
49
- // 3. Other node_modules packages are left alone
67
+ // Check if this file should be transformed
50
68
  if (cleanId.includes('node_modules')) {
51
- const isDashboard =
52
- // Check for YOUR custom name
53
- cleanId.includes('@wilshop/dashboard/src') ||
54
- // CRITICAL: Keep checking for the original name too!
55
- // If you use "npm:@wilshop/dashboard" alias, the folder is still named "@vendure"
56
- cleanId.includes('@vendure/dashboard/src') ||
57
- // Check for local monorepo path
58
- cleanId.includes('packages/dashboard/src');
59
- if (!isDashboard) {
60
- return null;
69
+ // Always allow @vendure/dashboard source files
70
+ const isVendureDashboard = cleanId.includes('@vendure/dashboard/src') || cleanId.includes('packages/dashboard/src');
71
+ if (!isVendureDashboard) {
72
+ // Load discovered plugins on first need (lazy loading with caching)
73
+ if (configLoaderApi && !configResult) {
74
+ try {
75
+ configResult = await configLoaderApi.getVendureConfig();
76
+ // Extract package paths from discovered npm plugins
77
+ for (const plugin of configResult.pluginInfo) {
78
+ if (!plugin.sourcePluginPath && plugin.pluginPath.includes('node_modules')) {
79
+ const packagePath = extractPackagePath(plugin.pluginPath);
80
+ if (packagePath) {
81
+ allowedNodeModulesPackages.add(packagePath);
82
+ }
83
+ }
84
+ }
85
+ }
86
+ catch (error) {
87
+ // Log but continue - will use only manually specified paths
88
+ // eslint-disable-next-line no-console
89
+ console.warn('[vendure:lingui-babel] Failed to load plugin config:', error);
90
+ }
91
+ }
92
+ // Check if this is from a discovered Vendure plugin package
93
+ let isDiscoveredPlugin = false;
94
+ for (const pkgPath of allowedNodeModulesPackages) {
95
+ if (cleanId.includes(pkgPath)) {
96
+ isDiscoveredPlugin = true;
97
+ break;
98
+ }
99
+ }
100
+ if (!isDiscoveredPlugin) {
101
+ return null;
102
+ }
61
103
  }
62
104
  }
63
105
  try {
@@ -91,3 +133,36 @@ export function linguiBabelPlugin() {
91
133
  },
92
134
  };
93
135
  }
136
+ /**
137
+ * Extracts the npm package name from a full file path.
138
+ *
139
+ * Examples:
140
+ * - /path/to/node_modules/@vendure-ee/plugin/dist/index.js -> @vendure-ee/plugin
141
+ * - /path/to/node_modules/some-plugin/lib/index.js -> some-plugin
142
+ * - /path/to/node_modules/.pnpm/@vendure-ee+plugin@1.0.0/node_modules/@vendure-ee/plugin/dist/index.js -> @vendure-ee/plugin
143
+ */
144
+ function extractPackagePath(filePath) {
145
+ // Normalize path separators
146
+ const normalizedPath = filePath.replace(/\\/g, '/');
147
+ // Find the last occurrence of node_modules (handles pnpm structure)
148
+ const lastNodeModulesIndex = normalizedPath.lastIndexOf('node_modules/');
149
+ if (lastNodeModulesIndex === -1) {
150
+ return undefined;
151
+ }
152
+ const afterNodeModules = normalizedPath.slice(lastNodeModulesIndex + 'node_modules/'.length);
153
+ // Handle scoped packages (@scope/package)
154
+ if (afterNodeModules.startsWith('@')) {
155
+ const parts = afterNodeModules.split('/');
156
+ if (parts.length >= 2) {
157
+ return `${parts[0]}/${parts[1]}`;
158
+ }
159
+ }
160
+ else {
161
+ // Unscoped package
162
+ const parts = afterNodeModules.split('/');
163
+ if (parts.length >= 1) {
164
+ return parts[0];
165
+ }
166
+ }
167
+ return undefined;
168
+ }
@@ -91,8 +91,8 @@ async function getPluginTranslations(pluginInfo) {
91
91
  const poPatterns = path.join(dashboardPath, '**/*.po');
92
92
  const translations = await glob(poPatterns, {
93
93
  ignore: [
94
- // Standard test & doc files
95
- '**/node_modules/**/node_modules/**',
94
+ // Skip nested node_modules (transitive deps) but not .pnpm or .bun directories.
95
+ '**/node_modules/[!.]*/**/node_modules/**',
96
96
  '**/*.spec.js',
97
97
  '**/*.test.js',
98
98
  ],
@@ -103,6 +103,27 @@ export interface I18nConfig {
103
103
  */
104
104
  availableLocales?: string[];
105
105
  }
106
+ /**
107
+ * @description
108
+ * Options used by the {@link vendureDashboardPlugin} to configure order-related
109
+ * Dashboard UI behaviour.
110
+ *
111
+ * @docsCategory vite-plugin
112
+ * @docsPage vendureDashboardPlugin
113
+ * @since 3.4.0
114
+ */
115
+ export interface OrdersConfig {
116
+ /**
117
+ * @description
118
+ * An array of refund reasons to display in the refund order dialog.
119
+ * Each reason has a `value` (used as the identifier) and a `label` (displayed to the user).
120
+ * If not provided, default reasons will be used.
121
+ */
122
+ refundReasons?: Array<{
123
+ value: string;
124
+ label: string;
125
+ }>;
126
+ }
106
127
  /**
107
128
  * @description
108
129
  * Options used by the {@link vendureDashboardPlugin} to configure aspects of the
@@ -123,6 +144,11 @@ export interface UiConfigPluginOptions {
123
144
  * Configuration for internationalization settings
124
145
  */
125
146
  i18n?: I18nConfig;
147
+ /**
148
+ * @description
149
+ * Configuration for order-related settings
150
+ */
151
+ orders?: OrdersConfig;
126
152
  }
127
153
  /**
128
154
  * @description
@@ -141,6 +167,11 @@ export interface ResolvedUiConfig {
141
167
  * Note: defaultLocale remains optional as it can be undefined.
142
168
  */
143
169
  i18n: Required<Omit<I18nConfig, 'defaultLocale'>> & Pick<I18nConfig, 'defaultLocale'>;
170
+ /**
171
+ * @description
172
+ * Order-related settings with all defaults applied
173
+ */
174
+ orders: Required<OrdersConfig>;
144
175
  }
145
176
  /**
146
177
  * This Vite plugin scans the configured plugins for any dashboard extensions and dynamically
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wilshop/dashboard",
3
3
  "private": false,
4
- "version": "3.5.5",
4
+ "version": "3.5.7",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
@@ -26,7 +26,10 @@
26
26
  "generate-index": "node scripts/generate-index.js",
27
27
  "i18n:extract": "lingui extract && node ./scripts/translate/i18n-tool.js extract",
28
28
  "i18n:apply": "node ./scripts/translate/i18n-tool.js apply",
29
+ "i18n:check": "node ./scripts/translate/check-translations.js",
29
30
  "storybook": "storybook dev -p 6006",
31
+ "e2e:pw": "playwright test --config e2e/playwright.config.ts",
32
+ "e2e:ui": "playwright test --config e2e/playwright.config.ts --ui",
30
33
  "storybook:build": "storybook build",
31
34
  "storybook:deploy": "npm run build --prefix ../common && npm run build --prefix ../core && npm run build:vite && storybook build"
32
35
  },
@@ -99,10 +102,10 @@
99
102
  "@tanstack/eslint-plugin-query": "^5.66.1",
100
103
  "@tanstack/react-query": "^5.66.7",
101
104
  "@tanstack/react-query-devtools": "^5.68.0",
102
- "@tanstack/react-router": "^1.105.0",
105
+ "@tanstack/react-router": "^1.154.0",
103
106
  "@tanstack/react-table": "^8.21.2",
104
- "@tanstack/router-devtools": "^1.105.0",
105
- "@tanstack/router-plugin": "^1.105.0",
107
+ "@tanstack/router-devtools": "^1.154.0",
108
+ "@tanstack/router-plugin": "^1.154.0",
106
109
  "@tiptap/extension-floating-menu": "^3.4.4",
107
110
  "@tiptap/extension-image": "^3.4.4",
108
111
  "@tiptap/extension-table": "^3.4.4",
@@ -152,13 +155,14 @@
152
155
  },
153
156
  "devDependencies": {
154
157
  "@eslint/js": "^9.19.0",
158
+ "@playwright/test": "^1.58.2",
155
159
  "@storybook/addon-a11y": "^10.0.0-beta.9",
156
160
  "@storybook/addon-docs": "^10.0.0-beta.9",
157
161
  "@storybook/addon-vitest": "^10.0.0-beta.9",
158
162
  "@storybook/react-vite": "^10.0.0-beta.9",
159
163
  "@types/node": "^22.13.4",
160
- "@vendure/common": "3.5.2",
161
- "@vendure/core": "3.5.2",
164
+ "@vendure/common": "3.5.3",
165
+ "@vendure/core": "3.5.3",
162
166
  "@vitest/browser": "^3.2.4",
163
167
  "@vitest/coverage-v8": "^3.2.4",
164
168
  "eslint": "^9.19.0",
@@ -3,7 +3,7 @@ import { TrashIcon } from 'lucide-react';
3
3
  import { toast } from 'sonner';
4
4
 
5
5
  import { DataTableBulkActionItem } from '@/vdb/components/data-table/data-table-bulk-action-item.js';
6
- import { usePaginatedList } from '@/vdb/components/shared/paginated-list-data-table.js';
6
+ import { usePaginatedList } from '@/vdb/hooks/use-paginated-list.js';
7
7
  import { getMutationName } from '@/vdb/framework/document-introspection/get-document-structure.js';
8
8
  import { api } from '@/vdb/graphql/api.js';
9
9
  import { Trans, useLingui } from '@lingui/react/macro';
@@ -5,7 +5,7 @@ import { useState } from 'react';
5
5
  import { toast } from 'sonner';
6
6
 
7
7
  import { DataTableBulkActionItem } from '@/vdb/components/data-table/data-table-bulk-action-item.js';
8
- import { usePaginatedList } from '@/vdb/components/shared/paginated-list-data-table.js';
8
+ import { usePaginatedList } from '@/vdb/hooks/use-paginated-list.js';
9
9
  import { api } from '@/vdb/graphql/api.js';
10
10
  import { duplicateEntityDocument } from '@/vdb/graphql/common-operations.js';
11
11
  import { Trans, useLingui } from '@lingui/react/macro';
@@ -33,9 +33,7 @@ export const collectionListDocument = graphql(
33
33
  position
34
34
  isPrivate
35
35
  parentId
36
- productVariants {
37
- totalItems
38
- }
36
+ productVariantCount
39
37
  }
40
38
  totalItems
41
39
  }