@vendure/dashboard 3.4.1-master-202508210231 → 3.4.1
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.
- package/package.json +152 -152
- package/src/app/routes/_authenticated/_orders/components/order-modification-preview-dialog.tsx +2 -1
- package/src/app/routes/_authenticated/_products/components/add-product-variant-dialog.tsx +1 -0
- package/src/lib/components/data-input/affixed-input.tsx +19 -5
- package/src/lib/components/data-input/boolean-input.tsx +9 -0
- package/src/lib/components/data-input/checkbox-input.tsx +8 -0
- package/src/lib/components/data-input/combination-mode-input.tsx +11 -2
- package/src/lib/components/data-input/configurable-operation-list-input.tsx +26 -401
- package/src/lib/components/data-input/custom-field-list-input.tsx +18 -25
- package/src/lib/components/data-input/customer-group-input.tsx +7 -11
- package/src/lib/components/data-input/datetime-input.tsx +9 -13
- package/src/lib/components/data-input/default-relation-input.tsx +29 -9
- package/src/lib/components/data-input/facet-value-input.tsx +15 -13
- package/src/lib/components/data-input/index.ts +2 -2
- package/src/lib/components/data-input/money-input.tsx +27 -20
- package/src/lib/components/data-input/number-input.tsx +48 -0
- package/src/lib/components/data-input/password-input.tsx +16 -0
- package/src/lib/components/data-input/{product-multi-selector.tsx → product-multi-selector-input.tsx} +8 -15
- package/src/lib/components/data-input/relation-input.tsx +7 -6
- package/src/lib/components/data-input/rich-text-input.tsx +10 -13
- package/src/lib/components/data-input/select-with-options.tsx +29 -17
- package/src/lib/components/data-input/struct-form-input.tsx +54 -59
- package/src/lib/components/data-input/text-input.tsx +9 -0
- package/src/lib/components/data-input/textarea-input.tsx +16 -0
- package/src/lib/components/data-table/filters/data-table-number-filter.tsx +3 -0
- package/src/lib/components/data-table/use-generated-columns.tsx +16 -5
- package/src/lib/components/shared/configurable-operation-arg-input.tsx +3 -10
- package/src/lib/components/shared/configurable-operation-input.tsx +1 -6
- package/src/lib/components/shared/configurable-operation-multi-selector.tsx +8 -5
- package/src/lib/components/shared/configurable-operation-selector.tsx +5 -5
- package/src/lib/components/shared/custom-fields-form.tsx +20 -49
- package/src/lib/components/shared/multi-select.tsx +1 -1
- package/src/lib/framework/component-registry/component-registry.tsx +9 -32
- package/src/lib/framework/component-registry/display-component.tsx +28 -0
- package/src/lib/framework/extension-api/display-component-extensions.tsx +0 -14
- package/src/lib/framework/extension-api/input-component-extensions.tsx +52 -34
- package/src/lib/framework/extension-api/logic/data-table.ts +4 -27
- package/src/lib/framework/extension-api/logic/form-components.ts +3 -2
- package/src/lib/framework/extension-api/types/detail-forms.ts +2 -38
- package/src/lib/framework/extension-api/types/form-components.ts +2 -4
- package/src/lib/framework/form-engine/custom-form-component-extensions.ts +0 -23
- package/src/lib/framework/form-engine/custom-form-component.tsx +8 -25
- package/src/lib/framework/form-engine/default-input-for-type.tsx +35 -0
- package/src/lib/framework/form-engine/form-control-adapter.tsx +192 -0
- package/src/lib/framework/form-engine/form-engine-types.ts +163 -0
- package/src/lib/framework/form-engine/form-schema-tools.ts +55 -71
- package/src/lib/framework/form-engine/overridden-form-component.tsx +2 -2
- package/src/lib/framework/form-engine/utils.ts +223 -0
- package/src/lib/{components/shared → framework/form-engine}/value-transformers.ts +9 -9
- package/src/lib/framework/registry/registry-types.ts +3 -5
- package/src/lib/graphql/graphql-env.d.ts +11 -7
- package/src/lib/index.ts +28 -1
- package/src/lib/providers/server-config.tsx +1 -0
- package/src/lib/components/shared/direct-form-component-map.tsx +0 -393
- package/src/lib/components/shared/universal-field-definition.ts +0 -118
- package/src/lib/components/shared/universal-form-input.tsx +0 -175
- package/src/lib/components/shared/universal-input-components.tsx +0 -291
- package/src/lib/framework/component-registry/dynamic-component.tsx +0 -58
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ControllerRenderProps } from 'react-hook-form';
|
|
3
|
-
|
|
4
|
-
import { AffixedInput } from '../data-input/affixed-input.js';
|
|
5
|
-
import { DateTimeInput } from '../data-input/datetime-input.js';
|
|
6
|
-
import { DefaultRelationInput } from '../data-input/default-relation-input.js';
|
|
7
|
-
import { SelectWithOptions } from '../data-input/select-with-options.js';
|
|
8
|
-
import { Input } from '../ui/input.js';
|
|
9
|
-
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select.js';
|
|
10
|
-
import { Switch } from '../ui/switch.js';
|
|
11
|
-
import { Textarea } from '../ui/textarea.js';
|
|
12
|
-
import { UniversalFieldDefinition } from './universal-field-definition.js';
|
|
13
|
-
import { ValueMode, transformValue } from './value-transformers.js';
|
|
14
|
-
|
|
15
|
-
export interface UniversalInputComponentProps {
|
|
16
|
-
fieldDef: UniversalFieldDefinition;
|
|
17
|
-
field: ControllerRenderProps<any, any>;
|
|
18
|
-
valueMode: ValueMode;
|
|
19
|
-
disabled?: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Component renderer interface for cleaner separation
|
|
23
|
-
interface ComponentRendererProps {
|
|
24
|
-
fieldDef: UniversalFieldDefinition;
|
|
25
|
-
field: ControllerRenderProps<any, any>;
|
|
26
|
-
valueMode: ValueMode;
|
|
27
|
-
isReadonly: boolean;
|
|
28
|
-
transformedValue: any;
|
|
29
|
-
handleChange: (value: any) => void;
|
|
30
|
-
handleNumericChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
31
|
-
handleRegularNumericChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
32
|
-
handleTextareaChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
|
|
33
|
-
handleTextChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Renders relation input component
|
|
38
|
-
*/
|
|
39
|
-
function renderRelationInput({ fieldDef, field, transformedValue, handleChange, isReadonly }: ComponentRendererProps) {
|
|
40
|
-
if (fieldDef.type !== 'relation' || !fieldDef.entity) return null;
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<DefaultRelationInput
|
|
44
|
-
fieldDef={{
|
|
45
|
-
entity: fieldDef.entity,
|
|
46
|
-
list: fieldDef.list,
|
|
47
|
-
} as any}
|
|
48
|
-
field={{
|
|
49
|
-
...field,
|
|
50
|
-
value: transformedValue,
|
|
51
|
-
onChange: handleChange,
|
|
52
|
-
}}
|
|
53
|
-
disabled={isReadonly}
|
|
54
|
-
/>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Renders string field with options as select dropdown
|
|
60
|
-
*/
|
|
61
|
-
function renderSelectInput({ fieldDef, valueMode, transformedValue, handleChange, isReadonly, field }: ComponentRendererProps) {
|
|
62
|
-
if (fieldDef.type !== 'string' || !fieldDef.ui?.options) return null;
|
|
63
|
-
|
|
64
|
-
if (valueMode === 'json-string') {
|
|
65
|
-
return (
|
|
66
|
-
<Select value={transformedValue || ''} onValueChange={handleChange} disabled={isReadonly}>
|
|
67
|
-
<SelectTrigger className="bg-background mb-0">
|
|
68
|
-
<SelectValue placeholder="Select an option..." />
|
|
69
|
-
</SelectTrigger>
|
|
70
|
-
<SelectContent>
|
|
71
|
-
{fieldDef.ui.options.map((option) => (
|
|
72
|
-
<SelectItem key={option.value} value={option.value}>
|
|
73
|
-
{typeof option.label === 'string'
|
|
74
|
-
? option.label
|
|
75
|
-
: Array.isArray(option.label)
|
|
76
|
-
? option.label[0]?.value || option.value
|
|
77
|
-
: option.value}
|
|
78
|
-
</SelectItem>
|
|
79
|
-
))}
|
|
80
|
-
</SelectContent>
|
|
81
|
-
</Select>
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return (
|
|
86
|
-
<SelectWithOptions
|
|
87
|
-
field={{
|
|
88
|
-
...field,
|
|
89
|
-
value: transformedValue,
|
|
90
|
-
onChange: handleChange,
|
|
91
|
-
}}
|
|
92
|
-
options={fieldDef.ui.options as any}
|
|
93
|
-
disabled={isReadonly}
|
|
94
|
-
isListField={fieldDef.list}
|
|
95
|
-
/>
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Renders numeric input components (int/float)
|
|
101
|
-
*/
|
|
102
|
-
function renderNumericInput({ fieldDef, valueMode, transformedValue, handleNumericChange, handleRegularNumericChange, isReadonly, field }: ComponentRendererProps) {
|
|
103
|
-
if (fieldDef.type !== 'int' && fieldDef.type !== 'float') return null;
|
|
104
|
-
|
|
105
|
-
const isFloat = fieldDef.type === 'float';
|
|
106
|
-
const min = fieldDef.ui?.min;
|
|
107
|
-
const max = fieldDef.ui?.max;
|
|
108
|
-
const step = fieldDef.ui?.step || (isFloat ? 0.01 : 1);
|
|
109
|
-
const prefix = fieldDef.ui?.prefix;
|
|
110
|
-
const suffix = fieldDef.ui?.suffix;
|
|
111
|
-
|
|
112
|
-
const shouldUseAffixedInput = prefix || suffix || valueMode === 'json-string';
|
|
113
|
-
|
|
114
|
-
if (shouldUseAffixedInput) {
|
|
115
|
-
const numericValue = transformedValue !== undefined && transformedValue !== ''
|
|
116
|
-
? (typeof transformedValue === 'number' ? transformedValue : parseFloat(transformedValue) || '')
|
|
117
|
-
: '';
|
|
118
|
-
|
|
119
|
-
return (
|
|
120
|
-
<AffixedInput
|
|
121
|
-
type="number"
|
|
122
|
-
value={numericValue}
|
|
123
|
-
onChange={handleNumericChange}
|
|
124
|
-
disabled={isReadonly}
|
|
125
|
-
min={min}
|
|
126
|
-
max={max}
|
|
127
|
-
step={step}
|
|
128
|
-
prefix={prefix}
|
|
129
|
-
suffix={suffix}
|
|
130
|
-
className="bg-background"
|
|
131
|
-
/>
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return (
|
|
136
|
-
<Input
|
|
137
|
-
type="number"
|
|
138
|
-
value={transformedValue ?? ''}
|
|
139
|
-
onChange={handleRegularNumericChange}
|
|
140
|
-
onBlur={field.onBlur}
|
|
141
|
-
name={field.name}
|
|
142
|
-
disabled={isReadonly}
|
|
143
|
-
min={min}
|
|
144
|
-
max={max}
|
|
145
|
-
step={step}
|
|
146
|
-
/>
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Renders boolean input as switch
|
|
152
|
-
*/
|
|
153
|
-
function renderBooleanInput({ fieldDef, valueMode, transformedValue, handleChange, isReadonly }: ComponentRendererProps) {
|
|
154
|
-
if (fieldDef.type !== 'boolean') return null;
|
|
155
|
-
|
|
156
|
-
const boolValue = valueMode === 'json-string'
|
|
157
|
-
? (transformedValue === true || transformedValue === 'true')
|
|
158
|
-
: transformedValue;
|
|
159
|
-
|
|
160
|
-
return (
|
|
161
|
-
<Switch
|
|
162
|
-
checked={boolValue}
|
|
163
|
-
onCheckedChange={handleChange}
|
|
164
|
-
disabled={isReadonly}
|
|
165
|
-
/>
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Renders datetime input
|
|
171
|
-
*/
|
|
172
|
-
function renderDateTimeInput({ fieldDef, transformedValue, handleChange, isReadonly }: ComponentRendererProps) {
|
|
173
|
-
if (fieldDef.type !== 'datetime') return null;
|
|
174
|
-
|
|
175
|
-
return (
|
|
176
|
-
<DateTimeInput
|
|
177
|
-
value={transformedValue}
|
|
178
|
-
onChange={handleChange}
|
|
179
|
-
disabled={isReadonly}
|
|
180
|
-
/>
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Renders textarea for specific config args
|
|
186
|
-
*/
|
|
187
|
-
function renderTextareaInput({ fieldDef, valueMode, transformedValue, handleTextareaChange, isReadonly }: ComponentRendererProps) {
|
|
188
|
-
if (valueMode !== 'json-string' || fieldDef.ui?.component !== 'textarea-form-input') return null;
|
|
189
|
-
|
|
190
|
-
return (
|
|
191
|
-
<Textarea
|
|
192
|
-
value={transformedValue || ''}
|
|
193
|
-
onChange={handleTextareaChange}
|
|
194
|
-
disabled={isReadonly}
|
|
195
|
-
spellCheck={fieldDef.ui?.spellcheck ?? true}
|
|
196
|
-
placeholder="Enter text..."
|
|
197
|
-
rows={4}
|
|
198
|
-
className="bg-background"
|
|
199
|
-
/>
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Renders default text input
|
|
205
|
-
*/
|
|
206
|
-
function renderTextInput({ valueMode, transformedValue, handleTextChange, isReadonly, field }: ComponentRendererProps) {
|
|
207
|
-
return (
|
|
208
|
-
<Input
|
|
209
|
-
type="text"
|
|
210
|
-
value={transformedValue ?? ''}
|
|
211
|
-
onChange={handleTextChange}
|
|
212
|
-
onBlur={field.onBlur}
|
|
213
|
-
name={field.name}
|
|
214
|
-
disabled={isReadonly}
|
|
215
|
-
placeholder={valueMode === 'json-string' ? "Enter value..." : undefined}
|
|
216
|
-
className={valueMode === 'json-string' ? "bg-background" : undefined}
|
|
217
|
-
/>
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Consolidated input component for rendering form inputs based on field type
|
|
223
|
-
* This replaces the duplicate implementations in custom fields and config args
|
|
224
|
-
*/
|
|
225
|
-
export function UniversalInputComponent({
|
|
226
|
-
fieldDef,
|
|
227
|
-
field,
|
|
228
|
-
valueMode,
|
|
229
|
-
disabled = false,
|
|
230
|
-
}: Readonly<UniversalInputComponentProps>) {
|
|
231
|
-
const isReadonly = disabled || fieldDef.readonly;
|
|
232
|
-
|
|
233
|
-
// Transform the field value for the component
|
|
234
|
-
const transformedValue = React.useMemo(() => {
|
|
235
|
-
return valueMode === 'json-string'
|
|
236
|
-
? transformValue(field.value, fieldDef, valueMode, 'parse')
|
|
237
|
-
: field.value;
|
|
238
|
-
}, [field.value, fieldDef, valueMode]);
|
|
239
|
-
|
|
240
|
-
// Transform onChange handler for the component
|
|
241
|
-
const handleChange = React.useCallback((newValue: any) => {
|
|
242
|
-
const serializedValue = valueMode === 'json-string'
|
|
243
|
-
? transformValue(newValue, fieldDef, valueMode, 'serialize')
|
|
244
|
-
: newValue;
|
|
245
|
-
field.onChange(serializedValue);
|
|
246
|
-
}, [field.onChange, fieldDef, valueMode]);
|
|
247
|
-
|
|
248
|
-
// Pre-define all change handlers at the top level to follow Rules of Hooks
|
|
249
|
-
const handleNumericChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
|
250
|
-
const val = e.target.valueAsNumber;
|
|
251
|
-
handleChange(isNaN(val) ? (valueMode === 'json-string' ? '' : undefined) : val);
|
|
252
|
-
}, [handleChange, valueMode]);
|
|
253
|
-
|
|
254
|
-
const handleRegularNumericChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
|
255
|
-
const val = e.target.valueAsNumber;
|
|
256
|
-
handleChange(isNaN(val) ? undefined : val);
|
|
257
|
-
}, [handleChange]);
|
|
258
|
-
|
|
259
|
-
const handleTextareaChange = React.useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
260
|
-
handleChange(e.target.value);
|
|
261
|
-
}, [handleChange]);
|
|
262
|
-
|
|
263
|
-
const handleTextChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
|
264
|
-
handleChange(e.target.value);
|
|
265
|
-
}, [handleChange]);
|
|
266
|
-
|
|
267
|
-
// Create props object for all renderers
|
|
268
|
-
const rendererProps: ComponentRendererProps = {
|
|
269
|
-
fieldDef,
|
|
270
|
-
field,
|
|
271
|
-
valueMode,
|
|
272
|
-
isReadonly,
|
|
273
|
-
transformedValue,
|
|
274
|
-
handleChange,
|
|
275
|
-
handleNumericChange,
|
|
276
|
-
handleRegularNumericChange,
|
|
277
|
-
handleTextareaChange,
|
|
278
|
-
handleTextChange,
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
// Try each renderer in order, return the first match
|
|
282
|
-
return (
|
|
283
|
-
renderRelationInput(rendererProps) ||
|
|
284
|
-
renderSelectInput(rendererProps) ||
|
|
285
|
-
renderNumericInput(rendererProps) ||
|
|
286
|
-
renderBooleanInput(rendererProps) ||
|
|
287
|
-
renderDateTimeInput(rendererProps) ||
|
|
288
|
-
renderTextareaInput(rendererProps) ||
|
|
289
|
-
renderTextInput(rendererProps)
|
|
290
|
-
);
|
|
291
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { useComponentRegistry } from "./component-registry.js";
|
|
3
|
-
|
|
4
|
-
export type DisplayComponentProps<
|
|
5
|
-
T extends keyof (typeof COMPONENT_REGISTRY)['dataDisplay'] | string,
|
|
6
|
-
> = {
|
|
7
|
-
id: T;
|
|
8
|
-
value: any;
|
|
9
|
-
// rest of the props are passed to the component
|
|
10
|
-
[key: string]: any;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export type InputComponentProps<
|
|
15
|
-
T extends keyof (typeof COMPONENT_REGISTRY)['dataInput'] | string,
|
|
16
|
-
> = {
|
|
17
|
-
id: T;
|
|
18
|
-
value: any;
|
|
19
|
-
// rest of the props are passed to the component
|
|
20
|
-
[key: string]: any;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @description
|
|
25
|
-
* This component is used to delegate the rendering of a component to the component registry.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```ts
|
|
29
|
-
* <Delegate component="money.display.default" value={100} />
|
|
30
|
-
* ```
|
|
31
|
-
*
|
|
32
|
-
* @returns
|
|
33
|
-
*/
|
|
34
|
-
export function DisplayComponent<
|
|
35
|
-
T extends keyof (typeof COMPONENT_REGISTRY)['dataDisplay'] | string,
|
|
36
|
-
>(props: Readonly<DisplayComponentProps<T>>): React.ReactNode {
|
|
37
|
-
const { getDisplayComponent } = useComponentRegistry();
|
|
38
|
-
const Component = getDisplayComponent(props.id);
|
|
39
|
-
if (!Component) {
|
|
40
|
-
throw new Error(`Component with id ${props.id} not found`);
|
|
41
|
-
}
|
|
42
|
-
const { value, ...rest } = props;
|
|
43
|
-
return <Component value={value} {...rest} />;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function InputComponent<
|
|
47
|
-
T extends keyof (typeof COMPONENT_REGISTRY)['dataInput'] | string,
|
|
48
|
-
>(props: Readonly<InputComponentProps<T>>): React.ReactNode {
|
|
49
|
-
const { getInputComponent } = useComponentRegistry();
|
|
50
|
-
const Component = getInputComponent(props.id);
|
|
51
|
-
if (!Component) {
|
|
52
|
-
throw new Error(`Component with id ${props.id} not found`);
|
|
53
|
-
}
|
|
54
|
-
const { value, onChange, ...rest } = props;
|
|
55
|
-
return <Component value={value} onChange={onChange} {...rest} />;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|