@vendure/dashboard 3.3.6-master-202507020234 → 3.3.6-master-202507020959

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 (24) hide show
  1. package/package.json +4 -4
  2. package/src/lib/framework/component-registry/component-registry.tsx +31 -47
  3. package/src/lib/framework/extension-api/define-dashboard-extension.ts +29 -95
  4. package/src/lib/framework/extension-api/display-component-extensions.tsx +69 -0
  5. package/src/lib/framework/extension-api/extension-api-types.ts +18 -160
  6. package/src/lib/framework/extension-api/input-component-extensions.tsx +69 -0
  7. package/src/lib/framework/extension-api/logic/alerts.ts +10 -0
  8. package/src/lib/framework/extension-api/logic/data-table.ts +60 -0
  9. package/src/lib/framework/extension-api/logic/detail-forms.ts +48 -0
  10. package/src/lib/framework/extension-api/logic/form-components.ts +13 -0
  11. package/src/lib/framework/extension-api/logic/index.ts +8 -0
  12. package/src/lib/framework/extension-api/logic/layout.ts +22 -0
  13. package/src/lib/framework/extension-api/logic/navigation.ts +37 -0
  14. package/src/lib/framework/extension-api/logic/widgets.ts +10 -0
  15. package/src/lib/framework/extension-api/types/alerts.ts +54 -0
  16. package/src/lib/framework/extension-api/types/data-table.ts +64 -0
  17. package/src/lib/framework/extension-api/types/detail-forms.ts +81 -0
  18. package/src/lib/framework/extension-api/types/form-components.ts +32 -0
  19. package/src/lib/framework/extension-api/types/index.ts +8 -0
  20. package/src/lib/framework/extension-api/types/layout.ts +78 -0
  21. package/src/lib/framework/extension-api/types/navigation.ts +19 -0
  22. package/src/lib/framework/extension-api/types/widgets.ts +94 -0
  23. package/src/lib/framework/page/detail-page.tsx +48 -3
  24. package/src/lib/framework/registry/registry-types.ts +3 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vendure/dashboard",
3
3
  "private": false,
4
- "version": "3.3.6-master-202507020234",
4
+ "version": "3.3.6-master-202507020959",
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.6-master-202507020234",
90
- "@vendure/core": "^3.3.6-master-202507020234",
89
+ "@vendure/common": "^3.3.6-master-202507020959",
90
+ "@vendure/core": "^3.3.6-master-202507020959",
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": "1ebfbfe0c8cc2a8f545987f52fd06b7f9a1f3089"
133
+ "gitHead": "5ee07181c993fe6edee6c000fe4cd90ffcba852f"
134
134
  }
@@ -1,70 +1,54 @@
1
- import { BooleanDisplayBadge, BooleanDisplayCheckbox } from '@/components/data-display/boolean.js';
2
- import { DateTime } from '@/components/data-display/date-time.js';
3
- import { Money } from '@/components/data-display/money.js';
4
- import { DateTimeInput } from '@/components/data-input/datetime-input.js';
5
- import { FacetValueInput } from '@/components/data-input/facet-value-input.js';
6
- import { MoneyInput } from '@/components/data-input/money-input.js';
7
- import { VendureImage } from '@/components/shared/vendure-image.js';
8
- import { Checkbox } from '@/components/ui/checkbox.js';
9
- import { Input } from '@/components/ui/input.js';
10
1
  import * as React from 'react';
2
+ import { addDisplayComponent, getDisplayComponent } from '../extension-api/display-component-extensions.js';
3
+ import { addInputComponent, getInputComponent } from '../extension-api/input-component-extensions.js';
11
4
 
12
5
  export interface ComponentRegistryEntry<Props extends Record<string, any>> {
13
6
  component: React.ComponentType<Props>;
14
7
  }
15
8
 
16
9
  // Basic component types
17
- export type DataDisplayComponent = React.ComponentType<{ value: any; [key: string]: any }>;
18
- export type DataInputComponent = React.ComponentType<{ value: any; onChange: (value: any) => void; [key: string]: any }>;
19
10
 
20
- // Simple component registry
21
- interface ComponentRegistry {
22
- dataDisplay: Record<string, DataDisplayComponent>;
23
- dataInput: Record<string, DataInputComponent>;
11
+ export interface DataDisplayComponentProps {
12
+ value: any;
13
+ [key: string]: any;
24
14
  }
25
15
 
26
- export const COMPONENT_REGISTRY: ComponentRegistry = {
27
- dataDisplay: {
28
- 'vendure:booleanCheckbox': BooleanDisplayCheckbox,
29
- 'vendure:booleanBadge': BooleanDisplayBadge,
30
- 'vendure:dateTime': DateTime,
31
- 'vendure:asset': ({value}) => <VendureImage asset={value} preset="tiny" />,
32
- 'vendure:money': Money,
33
- },
34
- dataInput: {
35
- 'vendure:moneyInput': MoneyInput,
36
- 'vendure:textInput': (props) => <Input {...props} onChange={e => props.onChange(e.target.value)} />,
37
- 'vendure:numberInput': (props) => <Input {...props} onChange={e => props.onChange(e.target.value)} type="number" />,
38
- 'vendure:dateTimeInput': DateTimeInput,
39
- 'vendure:checkboxInput': (props) => <Checkbox {...props} checked={props.value === 'true' || props.value === true} onCheckedChange={value => props.onChange(value)} />,
40
- 'vendure:facetValueInput': FacetValueInput,
41
- }
42
- };
16
+ export interface DataInputComponentProps {
17
+ value: any;
18
+ onChange: (value: any) => void;
19
+ [key: string]: any;
20
+ }
21
+
22
+ export type DataDisplayComponent = React.ComponentType<DataDisplayComponentProps>;
23
+ export type DataInputComponent = React.ComponentType<DataInputComponentProps>;
43
24
 
44
- // Simplified implementation - replace with actual implementation
25
+ // Component registry hook that uses the global registry
45
26
  export function useComponentRegistry() {
46
27
  return {
47
28
  getDisplayComponent: (id: string): DataDisplayComponent | undefined => {
48
- // This is a placeholder implementation
49
- return COMPONENT_REGISTRY.dataDisplay[id];
29
+ return getDisplayComponent(id);
50
30
  },
51
31
  getInputComponent: (id: string): DataInputComponent | undefined => {
52
- // This is a placeholder implementation
53
- return COMPONENT_REGISTRY.dataInput[id];
32
+ return getInputComponent(id);
54
33
  },
55
34
  };
56
35
  }
57
36
 
58
- export function registerInputComponent(id: string, component: DataInputComponent) {
59
- if (COMPONENT_REGISTRY.dataInput[id]) {
60
- throw new Error(`Input component with id ${id} already registered`);
61
- }
62
- COMPONENT_REGISTRY.dataInput[id] = component;
37
+ // Legacy registration functions - these now delegate to the global registry
38
+ export function registerInputComponent(
39
+ pageId: string,
40
+ blockId: string,
41
+ field: string,
42
+ component: DataInputComponent,
43
+ ) {
44
+ addInputComponent({ pageId, blockId, field, component });
63
45
  }
64
46
 
65
- export function registerDisplayComponent(id: string, component: DataDisplayComponent) {
66
- if (COMPONENT_REGISTRY.dataDisplay[id]) {
67
- throw new Error(`Display component with id ${id} already registered`);
68
- }
69
- COMPONENT_REGISTRY.dataDisplay[id] = component;
47
+ export function registerDisplayComponent(
48
+ pageId: string,
49
+ blockId: string,
50
+ field: string,
51
+ component: DataDisplayComponent,
52
+ ) {
53
+ addDisplayComponent({ pageId, blockId, field, component });
70
54
  }
@@ -1,20 +1,15 @@
1
- import { addBulkAction, addListQueryDocument } from '@/framework/data-table/data-table-extensions.js';
2
- import { parse } from 'graphql';
3
-
4
- import { registerDashboardWidget } from '../dashboard-widget/widget-extensions.js';
5
- import {
6
- addCustomFormComponent,
7
- addDetailQueryDocument,
8
- } from '../form-engine/custom-form-component-extensions.js';
9
- import {
10
- registerDashboardActionBarItem,
11
- registerDashboardPageBlock,
12
- } from '../layout-engine/layout-extensions.js';
13
- import { addNavMenuItem, addNavMenuSection, NavMenuItem } from '../nav-menu/nav-menu-extensions.js';
14
- import { registerRoute } from '../page/page-api.js';
15
1
  import { globalRegistry } from '../registry/global-registry.js';
16
2
 
17
3
  import { DashboardExtension } from './extension-api-types.js';
4
+ import {
5
+ registerAlertExtensions,
6
+ registerDataTableExtensions,
7
+ registerDetailFormExtensions,
8
+ registerFormComponentExtensions,
9
+ registerLayoutExtensions,
10
+ registerNavigationExtensions,
11
+ registerWidgetExtensions,
12
+ } from './logic/index.js';
18
13
 
19
14
  globalRegistry.register('extensionSourceChangeCallbacks', new Set<() => void>());
20
15
  globalRegistry.register('registerDashboardExtensionCallbacks', new Set<() => void>());
@@ -41,89 +36,28 @@ export function executeDashboardExtensionCallbacks() {
41
36
  */
42
37
  export function defineDashboardExtension(extension: DashboardExtension) {
43
38
  globalRegistry.get('registerDashboardExtensionCallbacks').add(() => {
44
- if (extension.navSections) {
45
- for (const section of extension.navSections) {
46
- addNavMenuSection({
47
- ...section,
48
- placement: 'top',
49
- order: section.order ?? 999,
50
- items: [],
51
- });
52
- }
53
- }
54
- if (extension.routes) {
55
- for (const route of extension.routes) {
56
- if (route.navMenuItem) {
57
- // Add the nav menu item
58
- const item: NavMenuItem = {
59
- url: route.navMenuItem.url ?? route.path,
60
- id: route.navMenuItem.id ?? route.path,
61
- title: route.navMenuItem.title ?? route.path,
62
- };
63
- addNavMenuItem(item, route.navMenuItem.sectionId);
64
- }
65
- if (route.path) {
66
- // Configure a list page
67
- registerRoute(route);
68
- }
69
- }
70
- }
71
- if (extension.actionBarItems) {
72
- for (const item of extension.actionBarItems) {
73
- registerDashboardActionBarItem(item);
74
- }
75
- }
76
- if (extension.pageBlocks) {
77
- for (const block of extension.pageBlocks) {
78
- registerDashboardPageBlock(block);
79
- }
80
- }
81
- if (extension.widgets) {
82
- for (const widget of extension.widgets) {
83
- registerDashboardWidget(widget);
84
- }
85
- }
86
- if (extension.customFormComponents) {
87
- for (const component of extension.customFormComponents) {
88
- addCustomFormComponent(component);
89
- }
90
- }
91
- if (extension.dataTables) {
92
- for (const dataTable of extension.dataTables) {
93
- if (dataTable.bulkActions?.length) {
94
- for (const action of dataTable.bulkActions) {
95
- addBulkAction(dataTable.pageId, dataTable.blockId, action);
96
- }
97
- }
98
- if (dataTable.extendListDocument) {
99
- const document =
100
- typeof dataTable.extendListDocument === 'function'
101
- ? dataTable.extendListDocument()
102
- : dataTable.extendListDocument;
39
+ // Register navigation extensions (nav sections and routes)
40
+ registerNavigationExtensions(extension.navSections, extension.routes);
103
41
 
104
- addListQueryDocument(
105
- dataTable.pageId,
106
- dataTable.blockId,
107
- typeof document === 'string' ? parse(document) : document,
108
- );
109
- }
110
- }
111
- }
112
- if (extension.detailForms) {
113
- for (const detailForm of extension.detailForms) {
114
- if (detailForm.extendDetailDocument) {
115
- const document =
116
- typeof detailForm.extendDetailDocument === 'function'
117
- ? detailForm.extendDetailDocument()
118
- : detailForm.extendDetailDocument;
42
+ // Register layout extensions (action bar items and page blocks)
43
+ registerLayoutExtensions(extension.actionBarItems, extension.pageBlocks);
119
44
 
120
- addDetailQueryDocument(
121
- detailForm.pageId,
122
- typeof document === 'string' ? parse(document) : document,
123
- );
124
- }
125
- }
126
- }
45
+ // Register widget extensions
46
+ registerWidgetExtensions(extension.widgets);
47
+
48
+ // Register form component extensions (custom form components, input components, and display components)
49
+ registerFormComponentExtensions(extension.customFormComponents);
50
+
51
+ // Register data table extensions
52
+ registerDataTableExtensions(extension.dataTables);
53
+
54
+ // Register detail form extensions
55
+ registerDetailFormExtensions(extension.detailForms);
56
+
57
+ // Register alert extensions
58
+ registerAlertExtensions(extension.alerts);
59
+
60
+ // Execute extension source change callbacks
127
61
  const callbacks = globalRegistry.get('extensionSourceChangeCallbacks');
128
62
  if (callbacks.size) {
129
63
  for (const callback of callbacks) {
@@ -0,0 +1,69 @@
1
+ import { BooleanDisplayBadge, BooleanDisplayCheckbox } from '@/components/data-display/boolean.js';
2
+ import { DateTime } from '@/components/data-display/date-time.js';
3
+ import { Money } from '@/components/data-display/money.js';
4
+ import { VendureImage } from '@/components/shared/vendure-image.js';
5
+ import { DataDisplayComponent } from '../component-registry/component-registry.js';
6
+ import { globalRegistry } from '../registry/global-registry.js';
7
+
8
+ globalRegistry.register('displayComponents', new Map<string, DataDisplayComponent>());
9
+
10
+ // Create component function for asset display
11
+ const AssetDisplay: DataDisplayComponent = ({ value }) => <VendureImage asset={value} preset="tiny" />;
12
+
13
+ // Register built-in display components
14
+ const displayComponents = globalRegistry.get('displayComponents');
15
+ displayComponents.set('vendure:booleanCheckbox', BooleanDisplayCheckbox);
16
+ displayComponents.set('vendure:booleanBadge', BooleanDisplayBadge);
17
+ displayComponents.set('vendure:dateTime', DateTime);
18
+ displayComponents.set('vendure:asset', AssetDisplay);
19
+ displayComponents.set('vendure:money', Money);
20
+
21
+ export function getDisplayComponent(id: string): DataDisplayComponent | undefined {
22
+ return globalRegistry.get('displayComponents').get(id);
23
+ }
24
+
25
+ /**
26
+ * @description
27
+ * Gets a display component using the targeting properties.
28
+ * Uses the same key pattern as registration: pageId_blockId_fieldName
29
+ */
30
+ export function getTargetedDisplayComponent(
31
+ pageId: string,
32
+ blockId: string,
33
+ field: string,
34
+ ): DataDisplayComponent | undefined {
35
+ const key = generateDisplayComponentKey(pageId, blockId, field);
36
+ return globalRegistry.get('displayComponents').get(key);
37
+ }
38
+
39
+ /**
40
+ * @description
41
+ * Generates a display component key based on the targeting properties.
42
+ * Follows the existing pattern: pageId_blockId_fieldName
43
+ */
44
+ export function generateDisplayComponentKey(pageId: string, blockId: string, field: string): string {
45
+ return `${pageId}_${blockId}_${field}`;
46
+ }
47
+
48
+ export function addDisplayComponent({
49
+ pageId,
50
+ blockId,
51
+ field,
52
+ component,
53
+ }: {
54
+ pageId: string;
55
+ blockId: string;
56
+ field: string;
57
+ component: React.ComponentType<{ value: any; [key: string]: any }>;
58
+ }) {
59
+ const displayComponents = globalRegistry.get('displayComponents');
60
+
61
+ // Generate the key using the helper function
62
+ const key = generateDisplayComponentKey(pageId, blockId, field);
63
+
64
+ if (displayComponents.has(key)) {
65
+ // eslint-disable-next-line no-console
66
+ console.warn(`Display component with key "${key}" is already registered and will be overwritten.`);
67
+ }
68
+ displayComponents.set(key, component);
69
+ }
@@ -1,161 +1,18 @@
1
- import { PageContextValue } from '@/framework/layout-engine/page-provider.js';
2
- import { AnyRoute, RouteOptions } from '@tanstack/react-router';
3
- import { DocumentNode } from 'graphql';
4
- import { LucideIcon } from 'lucide-react';
5
- import type React from 'react';
1
+ // Import all domain-specific types
2
+ export * from './types/index.js';
6
3
 
7
- import { DashboardAlertDefinition } from '../alert/types.js';
8
- import { DashboardWidgetDefinition } from '../dashboard-widget/types.js';
9
- import { BulkAction } from '../data-table/data-table-types.js';
10
- import { CustomFormComponentInputProps } from '../form-engine/custom-form-component.js';
11
- import { NavMenuItem } from '../nav-menu/nav-menu-extensions.js';
12
-
13
- /**
14
- * @description
15
- * Allows you to define custom form components for custom fields in the dashboard.
16
- *
17
- * @docsCategory extensions
18
- * @since 3.4.0
19
- */
20
- export interface DashboardCustomFormComponent {
21
- id: string;
22
- component: React.FunctionComponent<CustomFormComponentInputProps>;
23
- }
24
-
25
- export interface DashboardRouteDefinition {
26
- component: (route: AnyRoute) => React.ReactNode;
27
- path: string;
28
- navMenuItem?: Partial<NavMenuItem> & { sectionId: string };
29
- loader?: RouteOptions['loader'];
30
- }
31
-
32
- export interface ActionBarButtonState {
33
- disabled: boolean;
34
- visible: boolean;
35
- }
36
-
37
- export interface DashboardNavSectionDefinition {
38
- id: string;
39
- title: string;
40
- icon?: LucideIcon;
41
- order?: number;
42
- }
43
-
44
- /**
45
- * @description
46
- * **Status: Developer Preview**
47
- *
48
- * Allows you to define custom action bar items for any page in the dashboard.
49
- *
50
- * @docsCategory extensions
51
- * @since 3.3.0
52
- */
53
- export interface DashboardActionBarItem {
54
- /**
55
- * @description
56
- * The ID of the page where the action bar item should be displayed.
57
- */
58
- pageId: string;
59
- /**
60
- * @description
61
- * A React component that will be rendered in the action bar.
62
- */
63
- component: React.FunctionComponent<{ context: PageContextValue }>;
64
- /**
65
- * @description
66
- * Any permissions that are required to display this action bar item.
67
- */
68
- requiresPermission?: string | string[];
69
- }
70
-
71
- export interface DashboardActionBarDropdownMenuItem {
72
- locationId: string;
73
- component: React.FunctionComponent<{ context: PageContextValue }>;
74
- requiresPermission?: string | string[];
75
- }
76
-
77
- export type PageBlockPosition = { blockId: string; order: 'before' | 'after' | 'replace' };
78
-
79
- /**
80
- * @description
81
- * **Status: Developer Preview**
82
- *
83
- * The location of a page block in the dashboard. The location can be found by turning on
84
- * "developer mode" in the dashboard user menu (bottom left corner) and then
85
- * clicking the `< />` icon when hovering over a page block.
86
- *
87
- * @docsCategory extensions
88
- * @since 3.3.0
89
- */
90
- export type PageBlockLocation = {
91
- pageId: string;
92
- position: PageBlockPosition;
93
- column: 'main' | 'side';
94
- };
95
-
96
- /**
97
- * @description
98
- * **Status: Developer Preview**
99
- *
100
- * This allows you to insert a custom component into a specific location
101
- * on any page in the dashboard.
102
- *
103
- * @docsCategory extensions
104
- * @since 3.3.0
105
- */
106
- export interface DashboardPageBlockDefinition {
107
- id: string;
108
- title?: React.ReactNode;
109
- location: PageBlockLocation;
110
- component: React.FunctionComponent<{ context: PageContextValue }>;
111
- requiresPermission?: string | string[];
112
- }
113
-
114
- /**
115
- * @description
116
- * **Status: Developer Preview**
117
- *
118
- * This allows you to customize aspects of existing data tables in the dashboard.
119
- *
120
- * @docsCategory extensions
121
- * @since 3.4.0
122
- */
123
- export interface DashboardDataTableExtensionDefinition {
124
- /**
125
- * @description
126
- * The ID of the page where the data table is located, e.g. `'product-list'`, `'order-list'`.
127
- */
128
- pageId: string;
129
- /**
130
- * @description
131
- * The ID of the data table block. Defaults to `'list-table'`, which is the default blockId
132
- * for the standard list pages. However, some other pages may use a different blockId,
133
- * such as `'product-variants-table'` on the `'product-detail'` page.
134
- */
135
- blockId?: string;
136
- /**
137
- * @description
138
- * An array of additional bulk actions that will be available on the data table.
139
- */
140
- bulkActions?: BulkAction[];
141
- /**
142
- * @description
143
- * Allows you to extend the list document for the data table.
144
- */
145
- extendListDocument?: string | DocumentNode | (() => DocumentNode | string);
146
- }
147
-
148
- export interface DashboardDetailFormExtensionDefinition {
149
- /**
150
- * @description
151
- * The ID of the page where the detail form is located, e.g. `'product-detail'`, `'order-detail'`.
152
- */
153
- pageId: string;
154
- /**
155
- * @description
156
- */
157
- extendDetailDocument?: string | DocumentNode | (() => DocumentNode | string);
158
- }
4
+ // Import types for the main interface
5
+ import {
6
+ DashboardActionBarItem,
7
+ DashboardAlertDefinition,
8
+ DashboardCustomFormComponents,
9
+ DashboardDataTableExtensionDefinition,
10
+ DashboardDetailFormExtensionDefinition,
11
+ DashboardNavSectionDefinition,
12
+ DashboardPageBlockDefinition,
13
+ DashboardRouteDefinition,
14
+ DashboardWidgetDefinition,
15
+ } from './types/index.js';
159
16
 
160
17
  /**
161
18
  * @description
@@ -189,7 +46,7 @@ export interface DashboardExtension {
189
46
  actionBarItems?: DashboardActionBarItem[];
190
47
  /**
191
48
  * @description
192
- * Not yet implemented
49
+ * Allows you to define custom alerts that can be displayed in the dashboard.
193
50
  */
194
51
  alerts?: DashboardAlertDefinition[];
195
52
  /**
@@ -200,9 +57,10 @@ export interface DashboardExtension {
200
57
  widgets?: DashboardWidgetDefinition[];
201
58
  /**
202
59
  * @description
203
- * Allows you to define custom form components for custom fields in the dashboard.
60
+ * Unified registration for custom form components including custom field components,
61
+ * input components, and display components.
204
62
  */
205
- customFormComponents?: DashboardCustomFormComponent[];
63
+ customFormComponents?: DashboardCustomFormComponents;
206
64
  /**
207
65
  * @description
208
66
  * Allows you to customize aspects of existing data tables in the dashboard.
@@ -0,0 +1,69 @@
1
+ import { DateTimeInput } from '@/components/data-input/datetime-input.js';
2
+ import { FacetValueInput } from '@/components/data-input/facet-value-input.js';
3
+ import { MoneyInput } from '@/components/data-input/money-input.js';
4
+ import { Checkbox } from '@/components/ui/checkbox.js';
5
+ import { Input } from '@/components/ui/input.js';
6
+ import { DataInputComponent } from '../component-registry/component-registry.js';
7
+ import { globalRegistry } from '../registry/global-registry.js';
8
+
9
+ globalRegistry.register('inputComponents', new Map<string, DataInputComponent>());
10
+
11
+ // Create component functions for built-in components
12
+ const TextInput: DataInputComponent = props => (
13
+ <Input {...props} onChange={e => props.onChange(e.target.value)} />
14
+ );
15
+ const NumberInput: DataInputComponent = props => (
16
+ <Input {...props} onChange={e => props.onChange(e.target.valueAsNumber)} type="number" />
17
+ );
18
+ const CheckboxInput: DataInputComponent = props => (
19
+ <Checkbox
20
+ {...props}
21
+ checked={props.value === 'true' || props.value === true}
22
+ onCheckedChange={value => props.onChange(value)}
23
+ />
24
+ );
25
+
26
+ // Register built-in input components
27
+ const inputComponents = globalRegistry.get('inputComponents');
28
+ inputComponents.set('vendure:moneyInput', MoneyInput);
29
+ inputComponents.set('vendure:textInput', TextInput);
30
+ inputComponents.set('vendure:numberInput', NumberInput);
31
+ inputComponents.set('vendure:dateTimeInput', DateTimeInput);
32
+ inputComponents.set('vendure:checkboxInput', CheckboxInput);
33
+ inputComponents.set('vendure:facetValueInput', FacetValueInput);
34
+
35
+ export function getInputComponent(id: string): DataInputComponent | undefined {
36
+ return globalRegistry.get('inputComponents').get(id);
37
+ }
38
+
39
+ /**
40
+ * @description
41
+ * Generates a component key based on the targeting properties.
42
+ * Follows the existing pattern: pageId_blockId_fieldName
43
+ */
44
+ export function generateInputComponentKey(pageId: string, blockId: string, field: string): string {
45
+ return `${pageId}_${blockId}_${field}`;
46
+ }
47
+
48
+ export function addInputComponent({
49
+ pageId,
50
+ blockId,
51
+ field,
52
+ component,
53
+ }: {
54
+ pageId: string;
55
+ blockId: string;
56
+ field: string;
57
+ component: React.ComponentType<{ value: any; onChange: (value: any) => void; [key: string]: any }>;
58
+ }) {
59
+ const inputComponents = globalRegistry.get('inputComponents');
60
+
61
+ // Generate the key using the helper function
62
+ const key = generateInputComponentKey(pageId, blockId, field);
63
+
64
+ if (inputComponents.has(key)) {
65
+ // eslint-disable-next-line no-console
66
+ console.warn(`Input component with key "${key}" is already registered and will be overwritten.`);
67
+ }
68
+ inputComponents.set(key, component);
69
+ }
@@ -0,0 +1,10 @@
1
+ import { globalRegistry } from '../../registry/global-registry.js';
2
+ import { DashboardAlertDefinition } from '../types/alerts.js';
3
+
4
+ export function registerAlertExtensions(alerts?: DashboardAlertDefinition[]) {
5
+ if (alerts) {
6
+ for (const alert of alerts) {
7
+ globalRegistry.get('dashboardAlertRegistry').set(alert.id, alert);
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,60 @@
1
+ import { parse } from 'graphql';
2
+
3
+ import { addBulkAction, addListQueryDocument } from '../../data-table/data-table-extensions.js';
4
+ import { addDisplayComponent } from '../display-component-extensions.js';
5
+ import { DashboardDataTableExtensionDefinition } from '../types/index.js';
6
+
7
+ /**
8
+ * @description
9
+ * Generates a data table display component key based on the pageId and column name.
10
+ * Uses the pattern: pageId_columnName
11
+ */
12
+ export function generateDataTableDisplayComponentKey(pageId: string, column: string): string {
13
+ return `${pageId}_${column}`;
14
+ }
15
+
16
+ /**
17
+ * @description
18
+ * Adds a display component for a specific column in a data table.
19
+ */
20
+ export function addDataTableDisplayComponent(
21
+ pageId: string,
22
+ column: string,
23
+ component: React.ComponentType<{ value: any; [key: string]: any }>,
24
+ ) {
25
+ const key = generateDataTableDisplayComponentKey(pageId, column);
26
+ addDisplayComponent({ pageId, blockId: 'list-table', field: column, component });
27
+ }
28
+
29
+ export function registerDataTableExtensions(dataTables?: DashboardDataTableExtensionDefinition[]) {
30
+ if (dataTables) {
31
+ for (const dataTable of dataTables) {
32
+ if (dataTable.bulkActions?.length) {
33
+ for (const action of dataTable.bulkActions) {
34
+ addBulkAction(dataTable.pageId, dataTable.blockId, action);
35
+ }
36
+ }
37
+ if (dataTable.extendListDocument) {
38
+ const document =
39
+ typeof dataTable.extendListDocument === 'function'
40
+ ? dataTable.extendListDocument()
41
+ : dataTable.extendListDocument;
42
+
43
+ addListQueryDocument(
44
+ dataTable.pageId,
45
+ dataTable.blockId,
46
+ typeof document === 'string' ? parse(document) : document,
47
+ );
48
+ }
49
+ if (dataTable.displayComponents?.length) {
50
+ for (const displayComponent of dataTable.displayComponents) {
51
+ addDataTableDisplayComponent(
52
+ dataTable.pageId,
53
+ displayComponent.column,
54
+ displayComponent.component,
55
+ );
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }