@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
@@ -0,0 +1,48 @@
1
+ import { addDetailQueryDocument } from '@/framework/form-engine/custom-form-component-extensions.js';
2
+ import { parse } from 'graphql';
3
+
4
+ import { addDisplayComponent } from '../display-component-extensions.js';
5
+ import { addInputComponent } from '../input-component-extensions.js';
6
+ import { DashboardDetailFormExtensionDefinition } from '../types/detail-forms.js';
7
+
8
+ export function registerDetailFormExtensions(detailForms?: DashboardDetailFormExtensionDefinition[]) {
9
+ if (detailForms) {
10
+ for (const detailForm of detailForms) {
11
+ if (detailForm.extendDetailDocument) {
12
+ const document =
13
+ typeof detailForm.extendDetailDocument === 'function'
14
+ ? detailForm.extendDetailDocument()
15
+ : detailForm.extendDetailDocument;
16
+
17
+ addDetailQueryDocument(
18
+ detailForm.pageId,
19
+ typeof document === 'string' ? parse(document) : document,
20
+ );
21
+ }
22
+
23
+ // Register input components for this detail form
24
+ if (detailForm.inputs) {
25
+ for (const inputComponent of detailForm.inputs) {
26
+ addInputComponent({
27
+ pageId: detailForm.pageId,
28
+ blockId: inputComponent.blockId,
29
+ field: inputComponent.field,
30
+ component: inputComponent.component,
31
+ });
32
+ }
33
+ }
34
+
35
+ // Register display components for this detail form
36
+ if (detailForm.displays) {
37
+ for (const displayComponent of detailForm.displays) {
38
+ addDisplayComponent({
39
+ pageId: detailForm.pageId,
40
+ blockId: displayComponent.blockId,
41
+ field: displayComponent.field,
42
+ component: displayComponent.component,
43
+ });
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,13 @@
1
+ import { addCustomFormComponent } from '../../form-engine/custom-form-component-extensions.js';
2
+ import { DashboardCustomFormComponents } from '../types/form-components.js';
3
+
4
+ export function registerFormComponentExtensions(customFormComponents?: DashboardCustomFormComponents) {
5
+ if (customFormComponents) {
6
+ // Handle custom field components
7
+ if (customFormComponents.customFields) {
8
+ for (const component of customFormComponents.customFields) {
9
+ addCustomFormComponent(component);
10
+ }
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,8 @@
1
+ // Re-export all domain-specific logic functions
2
+ export * from './alerts.js';
3
+ export * from './data-table.js';
4
+ export * from './detail-forms.js';
5
+ export * from './form-components.js';
6
+ export * from './layout.js';
7
+ export * from './navigation.js';
8
+ export * from './widgets.js';
@@ -0,0 +1,22 @@
1
+ import {
2
+ registerDashboardActionBarItem,
3
+ registerDashboardPageBlock,
4
+ } from '../../layout-engine/layout-extensions.js';
5
+ import { DashboardActionBarItem, DashboardPageBlockDefinition } from '../types/layout.js';
6
+
7
+ export function registerLayoutExtensions(
8
+ actionBarItems?: DashboardActionBarItem[],
9
+ pageBlocks?: DashboardPageBlockDefinition[],
10
+ ) {
11
+ if (actionBarItems) {
12
+ for (const item of actionBarItems) {
13
+ registerDashboardActionBarItem(item);
14
+ }
15
+ }
16
+
17
+ if (pageBlocks) {
18
+ for (const block of pageBlocks) {
19
+ registerDashboardPageBlock(block);
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,37 @@
1
+ import { addNavMenuItem, addNavMenuSection, NavMenuItem } from '../../nav-menu/nav-menu-extensions.js';
2
+ import { registerRoute } from '../../page/page-api.js';
3
+ import { DashboardNavSectionDefinition, DashboardRouteDefinition } from '../types/navigation.js';
4
+
5
+ export function registerNavigationExtensions(
6
+ navSections?: DashboardNavSectionDefinition[],
7
+ routes?: DashboardRouteDefinition[],
8
+ ) {
9
+ if (navSections) {
10
+ for (const section of navSections) {
11
+ addNavMenuSection({
12
+ ...section,
13
+ placement: 'top',
14
+ order: section.order ?? 999,
15
+ items: [],
16
+ });
17
+ }
18
+ }
19
+
20
+ if (routes) {
21
+ for (const route of routes) {
22
+ if (route.navMenuItem) {
23
+ // Add the nav menu item
24
+ const item: NavMenuItem = {
25
+ url: route.navMenuItem.url ?? route.path,
26
+ id: route.navMenuItem.id ?? route.path,
27
+ title: route.navMenuItem.title ?? route.path,
28
+ };
29
+ addNavMenuItem(item, route.navMenuItem.sectionId);
30
+ }
31
+ if (route.path) {
32
+ // Configure a list page
33
+ registerRoute(route);
34
+ }
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,10 @@
1
+ import { registerDashboardWidget } from '../../dashboard-widget/widget-extensions.js';
2
+ import { DashboardWidgetDefinition } from '../types/index.js';
3
+
4
+ export function registerWidgetExtensions(widgets?: DashboardWidgetDefinition[]) {
5
+ if (widgets) {
6
+ for (const widget of widgets) {
7
+ registerDashboardWidget(widget);
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @description
3
+ * **Status: Developer Preview**
4
+ *
5
+ * Allows you to define custom alerts that can be displayed in the dashboard.
6
+ *
7
+ * @docsCategory extensions
8
+ * @since 3.3.0
9
+ */
10
+ export interface DashboardAlertDefinition<TResponse = any> {
11
+ /**
12
+ * @description
13
+ * A unique identifier for the alert.
14
+ */
15
+ id: string;
16
+ /**
17
+ * @description
18
+ * The title of the alert. Can be a string or a function that returns a string based on the response data.
19
+ */
20
+ title: string | ((data: TResponse) => string);
21
+ /**
22
+ * @description
23
+ * The description of the alert. Can be a string or a function that returns a string based on the response data.
24
+ */
25
+ description?: string | ((data: TResponse) => string);
26
+ /**
27
+ * @description
28
+ * The severity level of the alert.
29
+ */
30
+ severity: 'info' | 'warning' | 'error';
31
+ /**
32
+ * @description
33
+ * A function that checks the condition and returns the response data.
34
+ */
35
+ check: () => Promise<TResponse> | TResponse;
36
+ /**
37
+ * @description
38
+ * The interval in milliseconds to recheck the condition.
39
+ */
40
+ recheckInterval?: number;
41
+ /**
42
+ * @description
43
+ * A function that determines whether the alert should be shown based on the response data.
44
+ */
45
+ shouldShow?: (data: TResponse) => boolean;
46
+ /**
47
+ * @description
48
+ * Optional actions that can be performed when the alert is shown.
49
+ */
50
+ actions?: Array<{
51
+ label: string;
52
+ onClick: (data: TResponse) => void;
53
+ }>;
54
+ }
@@ -0,0 +1,64 @@
1
+ import { DocumentNode } from 'graphql';
2
+
3
+ import { BulkAction } from '../../data-table/data-table-types.js';
4
+
5
+ /**
6
+ * @description
7
+ * Allows you to define custom display components for specific columns in data tables.
8
+ * The pageId is already defined in the data table extension, so only the column name is needed.
9
+ *
10
+ * @docsCategory extensions
11
+ * @since 3.4.0
12
+ */
13
+ export interface DashboardDataTableDisplayComponent {
14
+ /**
15
+ * @description
16
+ * The name of the column where this display component should be used.
17
+ */
18
+ column: string;
19
+ /**
20
+ * @description
21
+ * The React component that will be rendered as the display.
22
+ * It should accept `value` and other standard display props.
23
+ */
24
+ component: React.ComponentType<{ value: any; [key: string]: any }>;
25
+ }
26
+
27
+ /**
28
+ * @description
29
+ * **Status: Developer Preview**
30
+ *
31
+ * This allows you to customize aspects of existing data tables in the dashboard.
32
+ *
33
+ * @docsCategory extensions
34
+ * @since 3.4.0
35
+ */
36
+ export interface DashboardDataTableExtensionDefinition {
37
+ /**
38
+ * @description
39
+ * The ID of the page where the data table is located, e.g. `'product-list'`, `'order-list'`.
40
+ */
41
+ pageId: string;
42
+ /**
43
+ * @description
44
+ * The ID of the data table block. Defaults to `'list-table'`, which is the default blockId
45
+ * for the standard list pages. However, some other pages may use a different blockId,
46
+ * such as `'product-variants-table'` on the `'product-detail'` page.
47
+ */
48
+ blockId?: string;
49
+ /**
50
+ * @description
51
+ * An array of additional bulk actions that will be available on the data table.
52
+ */
53
+ bulkActions?: BulkAction[];
54
+ /**
55
+ * @description
56
+ * Allows you to extend the list document for the data table.
57
+ */
58
+ extendListDocument?: string | DocumentNode | (() => DocumentNode | string);
59
+ /**
60
+ * @description
61
+ * Custom display components for specific columns in the data table.
62
+ */
63
+ displayComponents?: DashboardDataTableDisplayComponent[];
64
+ }
@@ -0,0 +1,81 @@
1
+ import {
2
+ DataDisplayComponent,
3
+ DataInputComponent,
4
+ } from '@/framework/component-registry/component-registry.js';
5
+ import { DocumentNode } from 'graphql';
6
+
7
+ /**
8
+ * @description
9
+ * Allows you to define custom input components for specific fields in detail forms.
10
+ * The pageId is already defined in the detail form extension, so only the blockId and field are needed.
11
+ *
12
+ * @docsCategory extensions
13
+ * @since 3.4.0
14
+ */
15
+ export interface DashboardDetailFormInputComponent {
16
+ /**
17
+ * @description
18
+ * The ID of the block where this input component should be used.
19
+ */
20
+ blockId: string;
21
+ /**
22
+ * @description
23
+ * The name of the field where this input component should be used.
24
+ */
25
+ field: string;
26
+ /**
27
+ * @description
28
+ * The React component that will be rendered as the input.
29
+ * It should accept `value`, `onChange`, and other standard input props.
30
+ */
31
+ component: DataInputComponent;
32
+ }
33
+
34
+ /**
35
+ * @description
36
+ * Allows you to define custom display components for specific fields in detail forms.
37
+ * The pageId is already defined in the detail form extension, so only the blockId and field are needed.
38
+ *
39
+ * @docsCategory extensions
40
+ * @since 3.4.0
41
+ */
42
+ export interface DashboardDetailFormDisplayComponent {
43
+ /**
44
+ * @description
45
+ * The ID of the block where this display component should be used.
46
+ */
47
+ blockId: string;
48
+ /**
49
+ * @description
50
+ * The name of the field where this display component should be used.
51
+ */
52
+ field: string;
53
+ /**
54
+ * @description
55
+ * The React component that will be rendered as the display.
56
+ * It should accept `value` and other standard display props.
57
+ */
58
+ component: DataDisplayComponent;
59
+ }
60
+
61
+ export interface DashboardDetailFormExtensionDefinition {
62
+ /**
63
+ * @description
64
+ * The ID of the page where the detail form is located, e.g. `'product-detail'`, `'order-detail'`.
65
+ */
66
+ pageId: string;
67
+ /**
68
+ * @description
69
+ */
70
+ extendDetailDocument?: string | DocumentNode | (() => DocumentNode | string);
71
+ /**
72
+ * @description
73
+ * Custom input components for specific fields in the detail form.
74
+ */
75
+ inputs?: DashboardDetailFormInputComponent[];
76
+ /**
77
+ * @description
78
+ * Custom display components for specific fields in the detail form.
79
+ */
80
+ displays?: DashboardDetailFormDisplayComponent[];
81
+ }
@@ -0,0 +1,32 @@
1
+ import type React from 'react';
2
+
3
+ import { CustomFormComponentInputProps } from '../../form-engine/custom-form-component.js';
4
+
5
+ /**
6
+ * @description
7
+ * Allows you to define custom form components for custom fields in the dashboard.
8
+ *
9
+ * @docsCategory extensions
10
+ * @since 3.4.0
11
+ */
12
+ export interface DashboardCustomFormComponent {
13
+ id: string;
14
+ component: React.FunctionComponent<CustomFormComponentInputProps>;
15
+ }
16
+
17
+ /**
18
+ * @description
19
+ * Interface for registering custom field components in the dashboard.
20
+ * For input and display components, use the co-located approach with detailForms.
21
+ *
22
+ * @docsCategory extensions
23
+ * @since 3.4.0
24
+ */
25
+ export interface DashboardCustomFormComponents {
26
+ /**
27
+ * @description
28
+ * Custom form components for custom fields. These are used when rendering
29
+ * custom fields in forms.
30
+ */
31
+ customFields?: DashboardCustomFormComponent[];
32
+ }
@@ -0,0 +1,8 @@
1
+ // Re-export all domain-specific types
2
+ export * from './alerts.js';
3
+ export * from './data-table.js';
4
+ export * from './detail-forms.js';
5
+ export * from './form-components.js';
6
+ export * from './layout.js';
7
+ export * from './navigation.js';
8
+ export * from './widgets.js';
@@ -0,0 +1,78 @@
1
+ import type React from 'react';
2
+
3
+ import { PageContextValue } from '../../layout-engine/page-provider.js';
4
+
5
+ export interface ActionBarButtonState {
6
+ disabled: boolean;
7
+ visible: boolean;
8
+ }
9
+
10
+ /**
11
+ * @description
12
+ * **Status: Developer Preview**
13
+ *
14
+ * Allows you to define custom action bar items for any page in the dashboard.
15
+ *
16
+ * @docsCategory extensions
17
+ * @since 3.3.0
18
+ */
19
+ export interface DashboardActionBarItem {
20
+ /**
21
+ * @description
22
+ * The ID of the page where the action bar item should be displayed.
23
+ */
24
+ pageId: string;
25
+ /**
26
+ * @description
27
+ * A React component that will be rendered in the action bar.
28
+ */
29
+ component: React.FunctionComponent<{ context: PageContextValue }>;
30
+ /**
31
+ * @description
32
+ * Any permissions that are required to display this action bar item.
33
+ */
34
+ requiresPermission?: string | string[];
35
+ }
36
+
37
+ export interface DashboardActionBarDropdownMenuItem {
38
+ locationId: string;
39
+ component: React.FunctionComponent<{ context: PageContextValue }>;
40
+ requiresPermission?: string | string[];
41
+ }
42
+
43
+ export type PageBlockPosition = { blockId: string; order: 'before' | 'after' | 'replace' };
44
+
45
+ /**
46
+ * @description
47
+ * **Status: Developer Preview**
48
+ *
49
+ * The location of a page block in the dashboard. The location can be found by turning on
50
+ * "developer mode" in the dashboard user menu (bottom left corner) and then
51
+ * clicking the `< />` icon when hovering over a page block.
52
+ *
53
+ * @docsCategory extensions
54
+ * @since 3.3.0
55
+ */
56
+ export type PageBlockLocation = {
57
+ pageId: string;
58
+ position: PageBlockPosition;
59
+ column: 'main' | 'side';
60
+ };
61
+
62
+ /**
63
+ * @description
64
+ * **Status: Developer Preview**
65
+ *
66
+ * This allows you to insert a custom component into a specific location
67
+ * on any page in the dashboard.
68
+ *
69
+ * @docsCategory extensions
70
+ * @since 3.3.0
71
+ */
72
+ export interface DashboardPageBlockDefinition {
73
+ id: string;
74
+ title?: React.ReactNode;
75
+ location: PageBlockLocation;
76
+ component: React.FunctionComponent<{ context: PageContextValue }>;
77
+ requiresPermission?: string | string[];
78
+ }
@@ -0,0 +1,19 @@
1
+ import { AnyRoute, RouteOptions } from '@tanstack/react-router';
2
+ import { LucideIcon } from 'lucide-react';
3
+ import type React from 'react';
4
+
5
+ import { NavMenuItem } from '../../nav-menu/nav-menu-extensions.js';
6
+
7
+ export interface DashboardRouteDefinition {
8
+ component: (route: AnyRoute) => React.ReactNode;
9
+ path: string;
10
+ navMenuItem?: Partial<NavMenuItem> & { sectionId: string };
11
+ loader?: RouteOptions['loader'];
12
+ }
13
+
14
+ export interface DashboardNavSectionDefinition {
15
+ id: string;
16
+ title: string;
17
+ icon?: LucideIcon;
18
+ order?: number;
19
+ }
@@ -0,0 +1,94 @@
1
+ import type React from 'react';
2
+
3
+ /**
4
+ * @description
5
+ * **Status: Developer Preview**
6
+ *
7
+ * Base props interface for dashboard widgets.
8
+ *
9
+ * @docsCategory extensions
10
+ * @since 3.3.0
11
+ */
12
+ export interface DashboardBaseWidgetProps {
13
+ widgetId: string;
14
+ config?: Record<string, unknown>;
15
+ }
16
+
17
+ /**
18
+ * @description
19
+ * **Status: Developer Preview**
20
+ *
21
+ * Represents an instance of a dashboard widget with its layout and configuration.
22
+ *
23
+ * @docsCategory extensions
24
+ * @since 3.3.0
25
+ */
26
+ export type DashboardWidgetInstance = {
27
+ /**
28
+ * @description
29
+ * A unique identifier for the widget instance.
30
+ */
31
+ id: string;
32
+ /**
33
+ * @description
34
+ * The ID of the widget definition this instance is based on.
35
+ */
36
+ widgetId: string;
37
+ /**
38
+ * @description
39
+ * The layout configuration for the widget.
40
+ */
41
+ layout: {
42
+ x: number;
43
+ y: number;
44
+ w: number;
45
+ h: number;
46
+ };
47
+ /**
48
+ * @description
49
+ * Optional configuration data for the widget.
50
+ */
51
+ config?: Record<string, unknown>;
52
+ };
53
+
54
+ /**
55
+ * @description
56
+ * **Status: Developer Preview**
57
+ *
58
+ * Defines a dashboard widget that can be added to the dashboard.
59
+ *
60
+ * @docsCategory extensions
61
+ * @since 3.3.0
62
+ */
63
+ export type DashboardWidgetDefinition = {
64
+ /**
65
+ * @description
66
+ * A unique identifier for the widget.
67
+ */
68
+ id: string;
69
+ /**
70
+ * @description
71
+ * The display name of the widget.
72
+ */
73
+ name: string;
74
+ /**
75
+ * @description
76
+ * The React component that renders the widget.
77
+ */
78
+ component: React.ComponentType<DashboardBaseWidgetProps>;
79
+ /**
80
+ * @description
81
+ * The default size and position of the widget.
82
+ */
83
+ defaultSize: { w: number; h: number; x?: number; y?: number };
84
+ /**
85
+ * @description
86
+ * The minimum size constraints for the widget.
87
+ */
88
+ minSize?: { w: number; h: number };
89
+ /**
90
+ * @description
91
+ * The maximum size constraints for the widget.
92
+ */
93
+ maxSize?: { w: number; h: number };
94
+ };
@@ -11,11 +11,15 @@ import { AnyRoute, useNavigate } from '@tanstack/react-router';
11
11
  import { ResultOf, VariablesOf } from 'gql.tada';
12
12
  import { toast } from 'sonner';
13
13
  import {
14
+ FieldInfo,
14
15
  getEntityName,
15
16
  getOperationVariablesFields,
16
17
  } from '../document-introspection/get-document-structure.js';
17
18
 
18
19
  import { TranslatableFormFieldWrapper } from '@/components/shared/translatable-form-field.js';
20
+ import { ControllerRenderProps, FieldPath, FieldValues } from 'react-hook-form';
21
+ import { useComponentRegistry } from '../component-registry/component-registry.js';
22
+ import { generateInputComponentKey } from '../extension-api/input-component-extensions.js';
19
23
  import {
20
24
  CustomFieldsPageBlock,
21
25
  DetailFormGrid,
@@ -85,10 +89,37 @@ export interface DetailPageProps<
85
89
  setValuesForUpdate: (entity: ResultOf<T>[EntityField]) => VariablesOf<U>['input'];
86
90
  }
87
91
 
92
+ export interface DetailPageFieldProps<
93
+ TFieldValues extends FieldValues = FieldValues,
94
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
95
+ > {
96
+ fieldInfo: FieldInfo;
97
+ field: ControllerRenderProps<TFieldValues, TName>;
98
+ blockId: string;
99
+ pageId: string;
100
+ }
101
+
88
102
  /**
89
103
  * Renders form input components based on field type
90
104
  */
91
- function renderFieldInput(fieldInfo: { type: string }, field: any) {
105
+ function FieldInputRenderer<
106
+ TFieldValues extends FieldValues = FieldValues,
107
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
108
+ >({ fieldInfo, field, blockId, pageId }: DetailPageFieldProps<TFieldValues, TName>) {
109
+ const componentRegistry = useComponentRegistry();
110
+ const customInputComponentKey = generateInputComponentKey(pageId, blockId, fieldInfo.name);
111
+
112
+ const DisplayComponent = componentRegistry.getDisplayComponent(customInputComponentKey);
113
+ const InputComponent = componentRegistry.getInputComponent(customInputComponentKey);
114
+
115
+ if (DisplayComponent) {
116
+ return <DisplayComponent {...field} />;
117
+ }
118
+
119
+ if (InputComponent) {
120
+ return <InputComponent {...field} />;
121
+ }
122
+
92
123
  switch (fieldInfo.type) {
93
124
  case 'Int':
94
125
  case 'Float':
@@ -196,7 +227,14 @@ export function DetailPage<
196
227
  control={form.control}
197
228
  name={fieldInfo.name as never}
198
229
  label={fieldInfo.name}
199
- render={({ field }) => renderFieldInput(fieldInfo, field)}
230
+ render={({ field }) => (
231
+ <FieldInputRenderer
232
+ fieldInfo={fieldInfo}
233
+ field={field}
234
+ blockId="main-form"
235
+ pageId={pageId}
236
+ />
237
+ )}
200
238
  />
201
239
  );
202
240
  })}
@@ -211,7 +249,14 @@ export function DetailPage<
211
249
  control={form.control}
212
250
  name={fieldInfo.name as never}
213
251
  label={fieldInfo.name}
214
- render={({ field }) => renderFieldInput(fieldInfo, field)}
252
+ render={({ field }) => (
253
+ <FieldInputRenderer
254
+ fieldInfo={fieldInfo}
255
+ field={field}
256
+ blockId="main-form"
257
+ pageId={pageId}
258
+ />
259
+ )}
215
260
  />
216
261
  );
217
262
  })}
@@ -2,6 +2,7 @@ import { DocumentNode } from 'graphql';
2
2
  import React from 'react';
3
3
 
4
4
  import { DashboardAlertDefinition } from '../alert/types.js';
5
+ import { DataDisplayComponent, DataInputComponent } from '../component-registry/component-registry.js';
5
6
  import { DashboardWidgetDefinition } from '../dashboard-widget/types.js';
6
7
  import { BulkAction } from '../data-table/data-table-types.js';
7
8
  import {
@@ -20,6 +21,8 @@ export interface GlobalRegistryContents {
20
21
  dashboardWidgetRegistry: Map<string, DashboardWidgetDefinition>;
21
22
  dashboardAlertRegistry: Map<string, DashboardAlertDefinition>;
22
23
  customFormComponents: Map<string, React.FunctionComponent<CustomFormComponentInputProps>>;
24
+ inputComponents: Map<string, DataInputComponent>;
25
+ displayComponents: Map<string, DataDisplayComponent>;
23
26
  bulkActionsRegistry: Map<string, BulkAction[]>;
24
27
  listQueryDocumentRegistry: Map<string, DocumentNode[]>;
25
28
  detailQueryDocumentRegistry: Map<string, DocumentNode[]>;