@vendure/dashboard 3.3.5-master-202506250629 → 3.3.5-master-202506250727

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 (37) hide show
  1. package/dist/plugin/tests/barrel-exports/my-plugin/index.d.ts +1 -0
  2. package/dist/plugin/tests/barrel-exports/my-plugin/index.js +17 -0
  3. package/dist/plugin/tests/barrel-exports/my-plugin/src/my.plugin.d.ts +2 -0
  4. package/dist/plugin/tests/barrel-exports/my-plugin/src/my.plugin.js +20 -0
  5. package/dist/plugin/tests/barrel-exports/vendure-config.d.ts +2 -0
  6. package/dist/plugin/tests/barrel-exports/vendure-config.js +19 -0
  7. package/dist/plugin/tests/barrel-exports.spec.d.ts +1 -0
  8. package/dist/plugin/tests/barrel-exports.spec.js +14 -0
  9. package/dist/plugin/utils/config-loader.js +8 -2
  10. package/package.json +4 -4
  11. package/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx +1 -1
  12. package/src/app/routes/_authenticated/_assets/assets_.$id.tsx +43 -34
  13. package/src/app/routes/_authenticated/_channels/channels_.$id.tsx +1 -1
  14. package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +1 -1
  15. package/src/app/routes/_authenticated/_countries/countries_.$id.tsx +1 -1
  16. package/src/app/routes/_authenticated/_customer-groups/customer-groups_.$id.tsx +1 -1
  17. package/src/app/routes/_authenticated/_customers/customers_.$id.tsx +1 -1
  18. package/src/app/routes/_authenticated/_facets/facets_.$id.tsx +1 -1
  19. package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +1 -1
  20. package/src/app/routes/_authenticated/_orders/orders_.$id.tsx +2 -5
  21. package/src/app/routes/_authenticated/_payment-methods/payment-methods_.$id.tsx +1 -1
  22. package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +1 -1
  23. package/src/app/routes/_authenticated/_products/products_.$id.tsx +11 -8
  24. package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +1 -1
  25. package/src/app/routes/_authenticated/_roles/roles_.$id.tsx +1 -1
  26. package/src/app/routes/_authenticated/_sellers/sellers_.$id.tsx +1 -1
  27. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +1 -1
  28. package/src/app/routes/_authenticated/_stock-locations/stock-locations_.$id.tsx +1 -1
  29. package/src/app/routes/_authenticated/_tax-categories/tax-categories_.$id.tsx +1 -1
  30. package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +1 -1
  31. package/src/app/routes/_authenticated/_zones/zones_.$id.tsx +1 -1
  32. package/vite/tests/barrel-exports/my-plugin/index.ts +1 -0
  33. package/vite/tests/barrel-exports/my-plugin/src/my.plugin.ts +8 -0
  34. package/vite/tests/barrel-exports/package.json +6 -0
  35. package/vite/tests/barrel-exports/vendure-config.ts +19 -0
  36. package/vite/tests/barrel-exports.spec.ts +17 -0
  37. package/vite/utils/config-loader.ts +10 -2
@@ -0,0 +1 @@
1
+ export * from './src/my.plugin';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./src/my.plugin"), exports);
@@ -0,0 +1,2 @@
1
+ export declare class MyPlugin {
2
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.MyPlugin = void 0;
10
+ const core_1 = require("@vendure/core");
11
+ let MyPlugin = class MyPlugin {
12
+ };
13
+ exports.MyPlugin = MyPlugin;
14
+ exports.MyPlugin = MyPlugin = __decorate([
15
+ (0, core_1.VendurePlugin)({
16
+ imports: [core_1.PluginCommonModule],
17
+ providers: [],
18
+ dashboard: './dashboard/index.tsx',
19
+ })
20
+ ], MyPlugin);
@@ -0,0 +1,2 @@
1
+ import { VendureConfig } from '@vendure/core';
2
+ export declare const config: VendureConfig;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.config = void 0;
4
+ const my_plugin_1 = require("./my-plugin");
5
+ exports.config = {
6
+ apiOptions: {
7
+ port: 3000,
8
+ },
9
+ authOptions: {
10
+ tokenMethod: 'bearer',
11
+ },
12
+ dbConnectionOptions: {
13
+ type: 'postgres',
14
+ },
15
+ paymentOptions: {
16
+ paymentMethodHandlers: [],
17
+ },
18
+ plugins: [my_plugin_1.MyPlugin],
19
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { join } from 'path';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { loadVendureConfig } from '../utils/config-loader.js';
4
+ describe('detecting plugins in barrel exports', () => {
5
+ it('should detect plugins in barrel exports', async () => {
6
+ const result = await loadVendureConfig({
7
+ tempDir: join(__dirname, './__temp'),
8
+ vendureConfigPath: join(__dirname, 'barrel-exports', 'vendure-config.ts'),
9
+ });
10
+ expect(result.pluginInfo).toHaveLength(1);
11
+ expect(result.pluginInfo[0].name).toBe('MyPlugin');
12
+ expect(result.pluginInfo[0].dashboardEntryPath).toBe('./dashboard/index.tsx');
13
+ });
14
+ });
@@ -157,11 +157,14 @@ export async function compileFile({ inputRootDir, inputPath, outputDir, transfor
157
157
  }
158
158
  }
159
159
  async function collectImports(node) {
160
- if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
160
+ if ((ts.isExportDeclaration(node) || ts.isImportDeclaration(node)) &&
161
+ node.moduleSpecifier &&
162
+ ts.isStringLiteral(node.moduleSpecifier)) {
161
163
  const importPath = node.moduleSpecifier.text;
162
164
  // Handle relative imports
163
165
  if (importPath.startsWith('.')) {
164
166
  const resolvedPath = path.resolve(path.dirname(absoluteInputPath), importPath);
167
+ // TODO: does this handle index files correctly?
165
168
  let resolvedTsPath = resolvedPath + '.ts';
166
169
  // Also check for .tsx if .ts doesn't exist
167
170
  if (!(await fs.pathExists(resolvedTsPath))) {
@@ -209,7 +212,9 @@ export async function compileFile({ inputRootDir, inputPath, outputDir, transfor
209
212
  continue;
210
213
  const potentialPathBase = path.resolve(tsConfigInfo.baseUrl, patternPrefix);
211
214
  const resolvedPath = path.join(potentialPathBase, remainingImportPath);
212
- let resolvedTsPath = resolvedPath + '.ts';
215
+ let resolvedTsPath = resolvedPath.endsWith('.ts')
216
+ ? resolvedPath
217
+ : resolvedPath + '.ts';
213
218
  // Similar existence checks as relative paths
214
219
  if (!(await fs.pathExists(resolvedTsPath))) {
215
220
  const resolvedTsxPath = resolvedPath + '.tsx';
@@ -258,6 +263,7 @@ export async function compileFile({ inputRootDir, inputPath, outputDir, transfor
258
263
  ts.isModuleBlock(child) ||
259
264
  ts.isModuleDeclaration(child) ||
260
265
  ts.isImportDeclaration(child) ||
266
+ ts.isExportDeclaration(child) ||
261
267
  child.kind === ts.SyntaxKind.SyntaxList) {
262
268
  await collectImports(child);
263
269
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vendure/dashboard",
3
3
  "private": false,
4
- "version": "3.3.5-master-202506250629",
4
+ "version": "3.3.5-master-202506250727",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
@@ -86,8 +86,8 @@
86
86
  "@types/react-dom": "^19.0.4",
87
87
  "@types/react-grid-layout": "^1.3.5",
88
88
  "@uidotdev/usehooks": "^2.4.1",
89
- "@vendure/common": "^3.3.5-master-202506250629",
90
- "@vendure/core": "^3.3.5-master-202506250629",
89
+ "@vendure/common": "^3.3.5-master-202506250727",
90
+ "@vendure/core": "^3.3.5-master-202506250727",
91
91
  "@vitejs/plugin-react": "^4.3.4",
92
92
  "awesome-graphql-client": "^2.1.0",
93
93
  "class-variance-authority": "^0.7.1",
@@ -130,5 +130,5 @@
130
130
  "lightningcss-linux-arm64-musl": "^1.29.3",
131
131
  "lightningcss-linux-x64-musl": "^1.29.1"
132
132
  },
133
- "gitHead": "4b7f357c29755911b3b825081711c1c97b570083"
133
+ "gitHead": "a1b6b57cbb9b65a63e88cf06e0e65d5a5dd0a87f"
134
134
  }
@@ -87,7 +87,7 @@ function AdministratorDetailPage() {
87
87
  const roleIds = form.watch('roleIds');
88
88
 
89
89
  return (
90
- <Page pageId="administrator-detail" form={form} submitHandler={submitHandler}>
90
+ <Page pageId="administrator-detail" form={form} submitHandler={submitHandler} entity={entity}>
91
91
  <PageTitle>{creatingNewEntity ? <Trans>New administrator</Trans> : name}</PageTitle>
92
92
 
93
93
  <PageActionBar>
@@ -1,23 +1,30 @@
1
- import { AssetPreview } from '@/components/shared/asset/asset-preview.js'
2
- import { detailPageRouteLoader } from '@/framework/page/detail-page-route-loader.js';
3
- import { createFileRoute } from '@tanstack/react-router'
4
- import { assetDetailDocument, assetUpdateDocument } from './assets.graphql.js';
5
- import { Trans, useLingui } from '@/lib/trans.js';
6
- import { ErrorPage } from '@/components/shared/error-page.js';
7
- import { toast } from 'sonner';
8
- import { Page, PageTitle, PageActionBar, PageActionBarRight, PageBlock, PageLayout, CustomFieldsPageBlock } from '@/framework/layout-engine/page-layout.js'
9
- import { useDetailPage } from '@/framework/page/use-detail-page.js';
10
- import { PermissionGuard } from '@/components/shared/permission-guard.js';
11
- import { Button } from '@/components/ui/button.js';
12
- import { VendureImage } from '@/components/shared/vendure-image.js';
13
- import { useState, useRef } from 'react';
14
- import { PreviewPreset } from '@/components/shared/asset/asset-preview.js';
1
+ import { AssetFocalPointEditor } from '@/components/shared/asset/asset-focal-point-editor.js';
15
2
  import { AssetPreviewSelector } from '@/components/shared/asset/asset-preview-selector.js';
3
+ import { PreviewPreset } from '@/components/shared/asset/asset-preview.js';
16
4
  import { AssetProperties } from '@/components/shared/asset/asset-properties.js';
17
- import { AssetFocalPointEditor } from '@/components/shared/asset/asset-focal-point-editor.js';
18
- import { FocusIcon } from 'lucide-react';
19
5
  import { Point } from '@/components/shared/asset/focal-point-control.js';
6
+ import { ErrorPage } from '@/components/shared/error-page.js';
7
+ import { PermissionGuard } from '@/components/shared/permission-guard.js';
8
+ import { VendureImage } from '@/components/shared/vendure-image.js';
9
+ import { Button } from '@/components/ui/button.js';
20
10
  import { Label } from '@/components/ui/label.js';
11
+ import {
12
+ CustomFieldsPageBlock,
13
+ Page,
14
+ PageActionBar,
15
+ PageActionBarRight,
16
+ PageBlock,
17
+ PageLayout,
18
+ PageTitle,
19
+ } from '@/framework/layout-engine/page-layout.js';
20
+ import { detailPageRouteLoader } from '@/framework/page/detail-page-route-loader.js';
21
+ import { useDetailPage } from '@/framework/page/use-detail-page.js';
22
+ import { Trans, useLingui } from '@/lib/trans.js';
23
+ import { createFileRoute } from '@tanstack/react-router';
24
+ import { FocusIcon } from 'lucide-react';
25
+ import { useRef, useState } from 'react';
26
+ import { toast } from 'sonner';
27
+ import { assetDetailDocument, assetUpdateDocument } from './assets.graphql.js';
21
28
  export const Route = createFileRoute('/_authenticated/_assets/assets_/$id')({
22
29
  component: AssetDetailPage,
23
30
  loader: detailPageRouteLoader({
@@ -25,7 +32,7 @@ export const Route = createFileRoute('/_authenticated/_assets/assets_/$id')({
25
32
  breadcrumb(isNew, entity) {
26
33
  return [
27
34
  { path: '/assets', label: 'Assets' },
28
- isNew ? <Trans>New asset</Trans> : entity?.name ?? '',
35
+ isNew ? <Trans>New asset</Trans> : (entity?.name ?? ''),
29
36
  ];
30
37
  },
31
38
  }),
@@ -79,17 +86,14 @@ function AssetDetailPage() {
79
86
  return null;
80
87
  }
81
88
  return (
82
- <Page pageId="asset-detail" form={form} submitHandler={submitHandler}>
89
+ <Page pageId="asset-detail" form={form} submitHandler={submitHandler} entity={entity}>
83
90
  <PageTitle>
84
91
  <Trans>Edit asset</Trans>
85
92
  </PageTitle>
86
93
  <PageActionBar>
87
94
  <PageActionBarRight>
88
95
  <PermissionGuard requires={['UpdateChannel']}>
89
- <Button
90
- type="submit"
91
- disabled={!form.formState.isDirty || isPending}
92
- >
96
+ <Button type="submit" disabled={!form.formState.isDirty || isPending}>
93
97
  <Trans>Update</Trans>
94
98
  </Button>
95
99
  </PermissionGuard>
@@ -103,7 +107,7 @@ function AssetDetailPage() {
103
107
  height={height}
104
108
  settingFocalPoint={settingFocalPoint}
105
109
  focalPoint={form.getValues().focalPoint ?? { x: 0.5, y: 0.5 }}
106
- onFocalPointChange={(point) => {
110
+ onFocalPointChange={point => {
107
111
  form.setValue('focalPoint.x', point.x, { shouldDirty: true });
108
112
  form.setValue('focalPoint.y', point.y, { shouldDirty: true });
109
113
  setSettingFocalPoint(false);
@@ -124,11 +128,7 @@ function AssetDetailPage() {
124
128
  </AssetFocalPointEditor>
125
129
  </div>
126
130
  </PageBlock>
127
- <CustomFieldsPageBlock
128
- column="main"
129
- entityType={'Asset'}
130
- control={form.control}
131
- />
131
+ <CustomFieldsPageBlock column="main" entityType={'Asset'} control={form.control} />
132
132
  <PageBlock column="side" blockId="asset-properties">
133
133
  <AssetProperties asset={entity} />
134
134
  </PageBlock>
@@ -136,15 +136,24 @@ function AssetDetailPage() {
136
136
  <div className="flex flex-col gap-2">
137
137
  <AssetPreviewSelector size={size} setSize={setSize} width={width} height={height} />
138
138
  <div className="flex items-center gap-2">
139
- <Button type='button' variant="outline" size="icon" onClick={() => setSettingFocalPoint(true)}>
139
+ <Button
140
+ type="button"
141
+ variant="outline"
142
+ size="icon"
143
+ onClick={() => setSettingFocalPoint(true)}
144
+ >
140
145
  <FocusIcon className="h-4 w-4" />
141
146
  </Button>
142
147
  <div className="text-sm text-muted-foreground">
143
- <Label><Trans>Focal Point</Trans></Label>
148
+ <Label>
149
+ <Trans>Focal Point</Trans>
150
+ </Label>
144
151
  <div className="text-sm text-muted-foreground">
145
- {form.getValues().focalPoint?.x && form.getValues().focalPoint?.y
146
- ? `${form.getValues().focalPoint?.x.toFixed(2)}, ${form.getValues().focalPoint?.y.toFixed(2)}`
147
- : <Trans>Not set</Trans>}
152
+ {form.getValues().focalPoint?.x && form.getValues().focalPoint?.y ? (
153
+ `${form.getValues().focalPoint?.x.toFixed(2)}, ${form.getValues().focalPoint?.y.toFixed(2)}`
154
+ ) : (
155
+ <Trans>Not set</Trans>
156
+ )}
148
157
  </div>
149
158
  </div>
150
159
  </div>
@@ -152,5 +161,5 @@ function AssetDetailPage() {
152
161
  </PageBlock>
153
162
  </PageLayout>
154
163
  </Page>
155
- )
164
+ );
156
165
  }
@@ -100,7 +100,7 @@ function ChannelDetailPage() {
100
100
  const codeIsDefault = entity?.code === DEFAULT_CHANNEL_CODE;
101
101
 
102
102
  return (
103
- <Page pageId="channel-detail" form={form} submitHandler={submitHandler}>
103
+ <Page pageId="channel-detail" form={form} submitHandler={submitHandler} entity={entity}>
104
104
  <PageTitle>
105
105
  {creatingNewEntity ? (
106
106
  <Trans>New channel</Trans>
@@ -105,7 +105,7 @@ function CollectionDetailPage() {
105
105
  const currentInheritFiltersValue = form.watch('inheritFilters');
106
106
 
107
107
  return (
108
- <Page pageId="collection-detail" form={form} submitHandler={submitHandler}>
108
+ <Page pageId="collection-detail" form={form} submitHandler={submitHandler} entity={entity}>
109
109
  <PageTitle>{creatingNewEntity ? <Trans>New collection</Trans> : (entity?.name ?? '')}</PageTitle>
110
110
  <PageActionBar>
111
111
  <PageActionBarRight>
@@ -71,7 +71,7 @@ function CountryDetailPage() {
71
71
  });
72
72
 
73
73
  return (
74
- <Page pageId="country-detail" form={form} submitHandler={submitHandler}>
74
+ <Page pageId="country-detail" form={form} submitHandler={submitHandler} entity={entity}>
75
75
  <PageTitle>{creatingNewEntity ? <Trans>New country</Trans> : (entity?.name ?? '')}</PageTitle>
76
76
  <PageActionBar>
77
77
  <PageActionBarRight>
@@ -72,7 +72,7 @@ function CustomerGroupDetailPage() {
72
72
  });
73
73
 
74
74
  return (
75
- <Page pageId="customer-group-detail" form={form} submitHandler={submitHandler}>
75
+ <Page pageId="customer-group-detail" form={form} submitHandler={submitHandler} entity={entity}>
76
76
  <PageTitle>
77
77
  {creatingNewEntity ? <Trans>New customer group</Trans> : (entity?.name ?? '')}
78
78
  </PageTitle>
@@ -137,7 +137,7 @@ function CustomerDetailPage() {
137
137
  const customerName = entity ? `${entity.firstName} ${entity.lastName}` : '';
138
138
 
139
139
  return (
140
- <Page pageId="customer-detail" form={form} submitHandler={submitHandler}>
140
+ <Page pageId="customer-detail" form={form} submitHandler={submitHandler} entity={entity}>
141
141
  <PageTitle>{creatingNewEntity ? <Trans>New customer</Trans> : customerName}</PageTitle>
142
142
  <PageActionBar>
143
143
  <PageActionBarRight>
@@ -82,7 +82,7 @@ function FacetDetailPage() {
82
82
  });
83
83
 
84
84
  return (
85
- <Page pageId="facet-detail" form={form} submitHandler={submitHandler}>
85
+ <Page pageId="facet-detail" form={form} submitHandler={submitHandler} entity={entity}>
86
86
  <PageTitle>{creatingNewEntity ? <Trans>New facet</Trans> : (entity?.name ?? '')}</PageTitle>
87
87
  <PageActionBar>
88
88
  <PageActionBarRight>
@@ -78,7 +78,7 @@ function GlobalSettingsPage() {
78
78
  });
79
79
 
80
80
  return (
81
- <Page pageId="global-settings" form={form} submitHandler={submitHandler}>
81
+ <Page pageId="global-settings" form={form} submitHandler={submitHandler} entity={entity}>
82
82
  <PageTitle>
83
83
  <Trans>Global settings</Trans>
84
84
  </PageTitle>
@@ -27,10 +27,7 @@ import { orderDetailDocument } from './orders.graphql.js';
27
27
 
28
28
  export const Route = createFileRoute('/_authenticated/_orders/orders_/$id')({
29
29
  component: OrderDetailPage,
30
- loader: async ({
31
- context,
32
- params,
33
- }) => {
30
+ loader: async ({ context, params }) => {
34
31
  if (!params.id) {
35
32
  throw new Error('ID param is required');
36
33
  }
@@ -86,7 +83,7 @@ function OrderDetailPage() {
86
83
  }
87
84
 
88
85
  return (
89
- <Page pageId="order-detail" form={form} submitHandler={submitHandler}>
86
+ <Page pageId="order-detail" form={form} submitHandler={submitHandler} entity={entity}>
90
87
  <PageTitle>{entity?.code ?? ''}</PageTitle>
91
88
  <PageActionBar>
92
89
  <PageActionBarRight>
@@ -102,7 +102,7 @@ function PaymentMethodDetailPage() {
102
102
  });
103
103
 
104
104
  return (
105
- <Page pageId="payment-method-detail" form={form} submitHandler={submitHandler}>
105
+ <Page pageId="payment-method-detail" form={form} submitHandler={submitHandler} entity={entity}>
106
106
  <PageTitle>
107
107
  {creatingNewEntity ? <Trans>New payment method</Trans> : (entity?.name ?? '')}
108
108
  </PageTitle>
@@ -102,7 +102,7 @@ function ProductVariantDetailPage() {
102
102
  const [price, taxCategoryId] = form.watch(['price', 'taxCategoryId']);
103
103
 
104
104
  return (
105
- <Page pageId="product-variant-detail" form={form} submitHandler={submitHandler}>
105
+ <Page pageId="product-variant-detail" form={form} submitHandler={submitHandler} entity={entity}>
106
106
  <PageTitle>
107
107
  {creatingNewEntity ? <Trans>New product variant</Trans> : (entity?.name ?? '')}
108
108
  </PageTitle>
@@ -24,12 +24,12 @@ import { detailPageRouteLoader } from '@/framework/page/detail-page-route-loader
24
24
  import { useDetailPage } from '@/framework/page/use-detail-page.js';
25
25
  import { Trans, useLingui } from '@/lib/trans.js';
26
26
  import { createFileRoute, useNavigate } from '@tanstack/react-router';
27
+ import { useRef } from 'react';
27
28
  import { toast } from 'sonner';
29
+ import { AddProductVariantDialog } from './components/add-product-variant-dialog.js';
28
30
  import { CreateProductVariantsDialog } from './components/create-product-variants-dialog.js';
29
31
  import { ProductVariantsTable } from './components/product-variants-table.js';
30
- import { AddProductVariantDialog } from './components/add-product-variant-dialog.js';
31
32
  import { createProductDocument, productDetailDocument, updateProductDocument } from './products.graphql.js';
32
- import { useRef } from 'react';
33
33
 
34
34
  export const Route = createFileRoute('/_authenticated/_products/products_/$id')({
35
35
  component: ProductDetailPage,
@@ -88,9 +88,9 @@ function ProductDetailPage() {
88
88
  });
89
89
  },
90
90
  });
91
-
91
+
92
92
  return (
93
- <Page pageId="product-detail" entity={entity} form={form} submitHandler={submitHandler}>
93
+ <Page pageId="product-detail" form={form} submitHandler={submitHandler} entity={entity}>
94
94
  <PageTitle>{creatingNewEntity ? <Trans>New product</Trans> : (entity?.name ?? '')}</PageTitle>
95
95
  <PageActionBar>
96
96
  <PageActionBarRight>
@@ -142,10 +142,13 @@ function ProductDetailPage() {
142
142
  <CustomFieldsPageBlock column="main" entityType="Product" control={form.control} />
143
143
  {entity && entity.variantList.totalItems > 0 && (
144
144
  <PageBlock column="main" blockId="product-variants-table">
145
- <ProductVariantsTable productId={params.id} registerRefresher={refresher => {
146
- refreshRef.current = refresher;
147
- }} />
148
- <div className="mt-4">
145
+ <ProductVariantsTable
146
+ productId={params.id}
147
+ registerRefresher={refresher => {
148
+ refreshRef.current = refresher;
149
+ }}
150
+ />
151
+ <div className="mt-4">
149
152
  <AddProductVariantDialog
150
153
  productId={params.id}
151
154
  onSuccess={() => {
@@ -114,7 +114,7 @@ function PromotionDetailPage() {
114
114
  });
115
115
 
116
116
  return (
117
- <Page pageId="promotion-detail" form={form} submitHandler={submitHandler}>
117
+ <Page pageId="promotion-detail" form={form} submitHandler={submitHandler} entity={entity}>
118
118
  <PageTitle>{creatingNewEntity ? <Trans>New promotion</Trans> : (entity?.name ?? '')}</PageTitle>
119
119
  <PageActionBar>
120
120
  <PageActionBarRight>
@@ -71,7 +71,7 @@ function RoleDetailPage() {
71
71
  });
72
72
 
73
73
  return (
74
- <Page pageId="role-detail" form={form} submitHandler={submitHandler}>
74
+ <Page pageId="role-detail" form={form} submitHandler={submitHandler} entity={entity}>
75
75
  <PageTitle>{creatingNewEntity ? <Trans>New role</Trans> : (entity?.description ?? '')}</PageTitle>
76
76
  <PageActionBar>
77
77
  <PageActionBarRight>
@@ -65,7 +65,7 @@ function SellerDetailPage() {
65
65
  });
66
66
 
67
67
  return (
68
- <Page pageId="seller-detail" form={form} submitHandler={submitHandler}>
68
+ <Page pageId="seller-detail" form={form} submitHandler={submitHandler} entity={entity}>
69
69
  <PageTitle>{creatingNewEntity ? <Trans>New seller</Trans> : (entity?.name ?? '')}</PageTitle>
70
70
  <PageActionBar>
71
71
  <PageActionBarRight>
@@ -94,7 +94,7 @@ function ShippingMethodDetailPage() {
94
94
  });
95
95
 
96
96
  return (
97
- <Page pageId="shipping-method-detail" form={form} submitHandler={submitHandler}>
97
+ <Page pageId="shipping-method-detail" form={form} submitHandler={submitHandler} entity={entity}>
98
98
  <PageTitle>
99
99
  {creatingNewEntity ? <Trans>New shipping method</Trans> : (entity?.name ?? '')}
100
100
  </PageTitle>
@@ -74,7 +74,7 @@ function StockLocationDetailPage() {
74
74
  });
75
75
 
76
76
  return (
77
- <Page pageId="stock-location-detail" form={form} submitHandler={submitHandler}>
77
+ <Page pageId="stock-location-detail" form={form} submitHandler={submitHandler} entity={entity}>
78
78
  <PageTitle>
79
79
  {creatingNewEntity ? <Trans>New stock location</Trans> : (entity?.name ?? '')}
80
80
  </PageTitle>
@@ -73,7 +73,7 @@ function TaxCategoryDetailPage() {
73
73
  });
74
74
 
75
75
  return (
76
- <Page pageId="tax-category-detail" form={form} submitHandler={submitHandler}>
76
+ <Page pageId="tax-category-detail" form={form} submitHandler={submitHandler} entity={entity}>
77
77
  <PageTitle>
78
78
  {creatingNewEntity ? <Trans>New tax category</Trans> : (entity?.name ?? '')}
79
79
  </PageTitle>
@@ -77,7 +77,7 @@ function TaxRateDetailPage() {
77
77
  });
78
78
 
79
79
  return (
80
- <Page pageId="tax-rate-detail" form={form} submitHandler={submitHandler}>
80
+ <Page pageId="tax-rate-detail" form={form} submitHandler={submitHandler} entity={entity}>
81
81
  <PageTitle>{creatingNewEntity ? <Trans>New tax rate</Trans> : (entity?.name ?? '')}</PageTitle>
82
82
  <PageActionBar>
83
83
  <PageActionBarRight>
@@ -66,7 +66,7 @@ function ZoneDetailPage() {
66
66
  });
67
67
 
68
68
  return (
69
- <Page pageId="zone-detail" form={form} submitHandler={submitHandler}>
69
+ <Page pageId="zone-detail" form={form} submitHandler={submitHandler} entity={entity}>
70
70
  <PageTitle>{creatingNewEntity ? <Trans>New zone</Trans> : (entity?.name ?? '')}</PageTitle>
71
71
  <PageActionBar>
72
72
  <PageActionBarRight>
@@ -0,0 +1 @@
1
+ export * from './src/my.plugin';
@@ -0,0 +1,8 @@
1
+ import { PluginCommonModule, VendurePlugin } from '@vendure/core';
2
+
3
+ @VendurePlugin({
4
+ imports: [PluginCommonModule],
5
+ providers: [],
6
+ dashboard: './dashboard/index.tsx',
7
+ })
8
+ export class MyPlugin {}
@@ -0,0 +1,6 @@
1
+ {
2
+ "type": "commonjs",
3
+ "name": "barrel-exports",
4
+ "version": "0.0.1",
5
+ "main": "index.ts"
6
+ }
@@ -0,0 +1,19 @@
1
+ import { VendureConfig } from '@vendure/core';
2
+
3
+ import { MyPlugin } from './my-plugin';
4
+
5
+ export const config: VendureConfig = {
6
+ apiOptions: {
7
+ port: 3000,
8
+ },
9
+ authOptions: {
10
+ tokenMethod: 'bearer',
11
+ },
12
+ dbConnectionOptions: {
13
+ type: 'postgres',
14
+ },
15
+ paymentOptions: {
16
+ paymentMethodHandlers: [],
17
+ },
18
+ plugins: [MyPlugin],
19
+ };
@@ -0,0 +1,17 @@
1
+ import { join } from 'path';
2
+ import { describe, expect, it } from 'vitest';
3
+
4
+ import { loadVendureConfig } from '../utils/config-loader.js';
5
+
6
+ describe('detecting plugins in barrel exports', () => {
7
+ it('should detect plugins in barrel exports', async () => {
8
+ const result = await loadVendureConfig({
9
+ tempDir: join(__dirname, './__temp'),
10
+ vendureConfigPath: join(__dirname, 'barrel-exports', 'vendure-config.ts'),
11
+ });
12
+
13
+ expect(result.pluginInfo).toHaveLength(1);
14
+ expect(result.pluginInfo[0].name).toBe('MyPlugin');
15
+ expect(result.pluginInfo[0].dashboardEntryPath).toBe('./dashboard/index.tsx');
16
+ });
17
+ });
@@ -328,12 +328,17 @@ export async function compileFile({
328
328
  }
329
329
 
330
330
  async function collectImports(node: ts.Node) {
331
- if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
331
+ if (
332
+ (ts.isExportDeclaration(node) || ts.isImportDeclaration(node)) &&
333
+ node.moduleSpecifier &&
334
+ ts.isStringLiteral(node.moduleSpecifier)
335
+ ) {
332
336
  const importPath = node.moduleSpecifier.text;
333
337
 
334
338
  // Handle relative imports
335
339
  if (importPath.startsWith('.')) {
336
340
  const resolvedPath = path.resolve(path.dirname(absoluteInputPath), importPath);
341
+ // TODO: does this handle index files correctly?
337
342
  let resolvedTsPath = resolvedPath + '.ts';
338
343
  // Also check for .tsx if .ts doesn't exist
339
344
  if (!(await fs.pathExists(resolvedTsPath))) {
@@ -384,7 +389,9 @@ export async function compileFile({
384
389
  const potentialPathBase = path.resolve(tsConfigInfo.baseUrl, patternPrefix);
385
390
  const resolvedPath = path.join(potentialPathBase, remainingImportPath);
386
391
 
387
- let resolvedTsPath = resolvedPath + '.ts';
392
+ let resolvedTsPath = resolvedPath.endsWith('.ts')
393
+ ? resolvedPath
394
+ : resolvedPath + '.ts';
388
395
  // Similar existence checks as relative paths
389
396
  if (!(await fs.pathExists(resolvedTsPath))) {
390
397
  const resolvedTsxPath = resolvedPath + '.tsx';
@@ -429,6 +436,7 @@ export async function compileFile({
429
436
  ts.isModuleBlock(child) ||
430
437
  ts.isModuleDeclaration(child) ||
431
438
  ts.isImportDeclaration(child) ||
439
+ ts.isExportDeclaration(child) ||
432
440
  child.kind === ts.SyntaxKind.SyntaxList
433
441
  ) {
434
442
  await collectImports(child);