@comet/admin-generator 9.0.0-canary-20250915134805 → 9.0.0-canary-20251002064922
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/lib/commands/generate/generate-command.d.ts +63 -45
- package/lib/commands/generate/generateForm/asyncSelect/generateAsyncSelect.d.ts +14 -1
- package/lib/commands/generate/generateForm/asyncSelect/generateAsyncSelect.js +79 -19
- package/lib/commands/generate/generateForm/formField/options.d.ts +1 -1
- package/lib/commands/generate/generateForm/formField/options.js +5 -3
- package/lib/commands/generate/generateForm/generateForm.js +2 -11
- package/lib/commands/generate/generateForm/generateFormField.js +58 -24
- package/lib/commands/generate/generateForm/generateFormLayout.js +1 -1
- package/lib/commands/generate/generateForm/generateFragmentByFormFragmentFields.d.ts +11 -0
- package/lib/commands/generate/generateForm/generateFragmentByFormFragmentFields.js +62 -0
- package/lib/commands/generate/generateGrid/generateGrid.js +8 -1
- package/lib/commands/generate/utils/isFieldOptional.js +1 -1
- package/package.json +6 -6
|
@@ -15,18 +15,6 @@ type Icon = IconName | IconObject | ComponentType;
|
|
|
15
15
|
export type Adornment = string | {
|
|
16
16
|
icon: Icon;
|
|
17
17
|
};
|
|
18
|
-
type SingleFileFormFieldConfig = {
|
|
19
|
-
type: "fileUpload";
|
|
20
|
-
multiple?: false;
|
|
21
|
-
maxFiles?: 1;
|
|
22
|
-
download?: boolean;
|
|
23
|
-
} & Pick<Partial<FinalFormFileUploadProps<false>>, "maxFileSize" | "readOnly" | "layout" | "accept">;
|
|
24
|
-
type MultiFileFormFieldConfig = {
|
|
25
|
-
type: "fileUpload";
|
|
26
|
-
multiple: true;
|
|
27
|
-
maxFiles?: number;
|
|
28
|
-
download?: boolean;
|
|
29
|
-
} & Pick<Partial<FinalFormFileUploadProps<true>>, "maxFileSize" | "readOnly" | "layout" | "accept">;
|
|
30
18
|
type InputBaseFieldConfig = {
|
|
31
19
|
startAdornment?: Adornment;
|
|
32
20
|
endAdornment?: Adornment;
|
|
@@ -39,73 +27,103 @@ export type StaticSelectValue = {
|
|
|
39
27
|
value: string;
|
|
40
28
|
label: string;
|
|
41
29
|
} | string;
|
|
30
|
+
type AsyncSelectFilter = {
|
|
31
|
+
/**
|
|
32
|
+
* Filter by value of field in current form
|
|
33
|
+
*/
|
|
34
|
+
type: "field";
|
|
35
|
+
/**
|
|
36
|
+
* Name of the field in current form, that will be used to filter the query
|
|
37
|
+
*/
|
|
38
|
+
formFieldName: string;
|
|
39
|
+
/**
|
|
40
|
+
* Name of the graphql argument the prop will be applied to. Defaults to propdName.
|
|
41
|
+
*
|
|
42
|
+
* Root Argument or filter argument are supported.
|
|
43
|
+
*/
|
|
44
|
+
rootQueryArg?: string;
|
|
45
|
+
} | {
|
|
46
|
+
/**
|
|
47
|
+
* Filter by a prop passed into the form, this prop will be generated
|
|
48
|
+
*/
|
|
49
|
+
type: "formProp";
|
|
50
|
+
/**
|
|
51
|
+
* Name of the prop generated for this form
|
|
52
|
+
*/
|
|
53
|
+
propName: string;
|
|
54
|
+
/**
|
|
55
|
+
* Name of the graphql argument the prop will be applied to. Defaults to propdName.
|
|
56
|
+
*
|
|
57
|
+
* Root Argument or filter argument are supported.
|
|
58
|
+
*/
|
|
59
|
+
rootQueryArg?: string;
|
|
60
|
+
};
|
|
42
61
|
export type FormFieldConfig<T> = (({
|
|
43
62
|
type: "text";
|
|
63
|
+
name: keyof T;
|
|
44
64
|
multiline?: boolean;
|
|
45
65
|
} & InputBaseFieldConfig) | ({
|
|
46
66
|
type: "number";
|
|
67
|
+
name: keyof T;
|
|
47
68
|
decimals?: number;
|
|
48
69
|
} & InputBaseFieldConfig) | ({
|
|
49
70
|
type: "numberRange";
|
|
71
|
+
name: keyof T;
|
|
50
72
|
minValue: number;
|
|
51
73
|
maxValue: number;
|
|
52
74
|
disableSlider?: boolean;
|
|
53
75
|
} & InputBaseFieldConfig) | {
|
|
54
76
|
type: "boolean";
|
|
77
|
+
name: keyof T;
|
|
55
78
|
} | ({
|
|
56
79
|
type: "date";
|
|
80
|
+
name: keyof T;
|
|
57
81
|
} & InputBaseFieldConfig) | ({
|
|
58
82
|
type: "dateTime";
|
|
83
|
+
name: keyof T;
|
|
59
84
|
} & InputBaseFieldConfig) | ({
|
|
60
85
|
type: "staticSelect";
|
|
86
|
+
name: keyof T;
|
|
61
87
|
values?: StaticSelectValue[];
|
|
62
88
|
inputType?: "select" | "radio";
|
|
63
89
|
} & Omit<InputBaseFieldConfig, "endAdornment">) | ({
|
|
64
90
|
type: "asyncSelect";
|
|
91
|
+
name: keyof T;
|
|
65
92
|
rootQuery: string;
|
|
66
93
|
labelField?: string;
|
|
67
94
|
/**
|
|
68
95
|
* filter for query, passed as variable to graphql query
|
|
69
96
|
*/
|
|
70
|
-
filter?:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
*
|
|
82
|
-
* Root Argument or filter argument are supported.
|
|
83
|
-
*/
|
|
84
|
-
rootQueryArg?: string;
|
|
85
|
-
} | {
|
|
86
|
-
/**
|
|
87
|
-
* Filter by a prop passed into the form, this prop will be generated
|
|
88
|
-
*/
|
|
89
|
-
type: "formProp";
|
|
90
|
-
/**
|
|
91
|
-
* Name of the prop generated for this form
|
|
92
|
-
*/
|
|
93
|
-
propName: string;
|
|
94
|
-
/**
|
|
95
|
-
* Name of the graphql argument the prop will be applied to. Defaults to propdName.
|
|
96
|
-
*
|
|
97
|
-
* Root Argument or filter argument are supported.
|
|
98
|
-
*/
|
|
99
|
-
rootQueryArg?: string;
|
|
100
|
-
};
|
|
97
|
+
filter?: AsyncSelectFilter;
|
|
98
|
+
} & Omit<InputBaseFieldConfig, "endAdornment">) | ({
|
|
99
|
+
type: "asyncSelectFilter";
|
|
100
|
+
name: string;
|
|
101
|
+
loadValueQueryField: string;
|
|
102
|
+
rootQuery: string;
|
|
103
|
+
labelField?: string;
|
|
104
|
+
/**
|
|
105
|
+
* filter for query, passed as variable to graphql query
|
|
106
|
+
*/
|
|
107
|
+
filter?: AsyncSelectFilter;
|
|
101
108
|
} & Omit<InputBaseFieldConfig, "endAdornment">) | {
|
|
102
109
|
type: "block";
|
|
110
|
+
name: keyof T;
|
|
103
111
|
block: BlockInterface;
|
|
104
|
-
} |
|
|
112
|
+
} | ({
|
|
113
|
+
type: "fileUpload";
|
|
114
|
+
multiple?: false;
|
|
115
|
+
name: keyof T;
|
|
116
|
+
maxFiles?: 1;
|
|
117
|
+
download?: boolean;
|
|
118
|
+
} & Pick<Partial<FinalFormFileUploadProps<false>>, "maxFileSize" | "readOnly" | "layout" | "accept">) | ({
|
|
119
|
+
type: "fileUpload";
|
|
120
|
+
multiple: true;
|
|
105
121
|
name: keyof T;
|
|
122
|
+
maxFiles?: number;
|
|
123
|
+
download?: boolean;
|
|
124
|
+
} & Pick<Partial<FinalFormFileUploadProps<true>>, "maxFileSize" | "readOnly" | "layout" | "accept">)) & {
|
|
106
125
|
label?: string;
|
|
107
126
|
required?: boolean;
|
|
108
|
-
virtual?: boolean;
|
|
109
127
|
validate?: FieldValidator<unknown>;
|
|
110
128
|
helperText?: string;
|
|
111
129
|
readOnly?: boolean;
|
|
@@ -1,11 +1,24 @@
|
|
|
1
|
-
import { type IntrospectionQuery } from "graphql";
|
|
1
|
+
import { type IntrospectionObjectType, type IntrospectionQuery } from "graphql";
|
|
2
2
|
import { type FormConfig, type FormFieldConfig } from "../../generate-command";
|
|
3
3
|
import { type GenerateFieldsReturn } from "../generateFields";
|
|
4
|
+
/**
|
|
5
|
+
* Helper that returns the introspection object type for a given form field config, supporting the special case for asyncSelectFilter
|
|
6
|
+
*/
|
|
7
|
+
export declare function findIntrospectionObjectType({ config, gqlIntrospection, gqlType, }: {
|
|
8
|
+
config: FormFieldConfig<any>;
|
|
9
|
+
gqlIntrospection: IntrospectionQuery;
|
|
10
|
+
gqlType: string;
|
|
11
|
+
}): {
|
|
12
|
+
multiple: boolean;
|
|
13
|
+
objectType: IntrospectionObjectType;
|
|
14
|
+
};
|
|
4
15
|
export declare function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, formConfig, gqlType, namePrefix, }: {
|
|
5
16
|
gqlIntrospection: IntrospectionQuery;
|
|
6
17
|
baseOutputFilename: string;
|
|
7
18
|
config: Extract<FormFieldConfig<any>, {
|
|
8
19
|
type: "asyncSelect";
|
|
20
|
+
} | {
|
|
21
|
+
type: "asyncSelectFilter";
|
|
9
22
|
}>;
|
|
10
23
|
formConfig: FormConfig<any>;
|
|
11
24
|
gqlType: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findIntrospectionObjectType = findIntrospectionObjectType;
|
|
3
4
|
exports.generateAsyncSelect = generateAsyncSelect;
|
|
4
5
|
const generate_command_1 = require("../../generate-command");
|
|
5
6
|
const findQueryType_1 = require("../../utils/findQueryType");
|
|
@@ -56,28 +57,69 @@ function buildTypeInfo(arg, gqlIntrospection) {
|
|
|
56
57
|
inputType,
|
|
57
58
|
};
|
|
58
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Helper that returns the introspection object type for a given form field config, supporting the special case for asyncSelectFilter
|
|
62
|
+
*/
|
|
63
|
+
function findIntrospectionObjectType({ config, gqlIntrospection, gqlType, }) {
|
|
64
|
+
const name = String(config.name);
|
|
65
|
+
const introspectionObject = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === gqlType);
|
|
66
|
+
if (!introspectionObject)
|
|
67
|
+
throw new Error(`didn't find object ${gqlType} in gql introspection`);
|
|
68
|
+
function findIntrospectionField(introspectionObject, name) {
|
|
69
|
+
const introspectionField = introspectionObject.fields.find((field) => field.name === name);
|
|
70
|
+
if (!introspectionField)
|
|
71
|
+
throw new Error(`didn't find field ${name} in gql introspection type ${gqlType}`);
|
|
72
|
+
let introspectionFieldType = introspectionField.type.kind === "NON_NULL" ? introspectionField.type.ofType : introspectionField.type;
|
|
73
|
+
const multiple = (introspectionFieldType === null || introspectionFieldType === void 0 ? void 0 : introspectionFieldType.kind) === "LIST";
|
|
74
|
+
if ((introspectionFieldType === null || introspectionFieldType === void 0 ? void 0 : introspectionFieldType.kind) === "LIST") {
|
|
75
|
+
introspectionFieldType =
|
|
76
|
+
introspectionFieldType.ofType.kind === "NON_NULL" ? introspectionFieldType.ofType.ofType : introspectionFieldType.ofType;
|
|
77
|
+
}
|
|
78
|
+
if (introspectionFieldType.kind !== "OBJECT")
|
|
79
|
+
throw new Error(`asyncSelect only supports OBJECT types`);
|
|
80
|
+
const objectType = gqlIntrospection.__schema.types.find((t) => t.kind === "OBJECT" && t.name === introspectionFieldType.name);
|
|
81
|
+
if (!objectType)
|
|
82
|
+
throw new Error(`Object type ${introspectionFieldType.name} not found for field ${name}`);
|
|
83
|
+
return { multiple, objectType };
|
|
84
|
+
}
|
|
85
|
+
if (config.type === "asyncSelectFilter") {
|
|
86
|
+
//for a filter select the field is "virtual", and it's ObjectType is defined by the path in config.loadValueQueryField
|
|
87
|
+
return {
|
|
88
|
+
multiple: false,
|
|
89
|
+
objectType: config.loadValueQueryField.split(".").reduce((acc, fieldName) => {
|
|
90
|
+
const introspectionField = findIntrospectionField(acc, fieldName);
|
|
91
|
+
if (introspectionField.multiple)
|
|
92
|
+
throw new Error(`asyncSelectFilter does not support list fields in loadValueQueryField`);
|
|
93
|
+
return introspectionField.objectType;
|
|
94
|
+
}, introspectionObject),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
//for a standard select we just find the field directly (no nested path to follow, name can be only one level deep)
|
|
99
|
+
return findIntrospectionField(introspectionObject, name);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
59
102
|
function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, formConfig, gqlType, namePrefix, }) {
|
|
60
103
|
var _a, _b;
|
|
61
104
|
const imports = [];
|
|
62
105
|
const formProps = [];
|
|
63
|
-
const { name, fieldLabel,
|
|
106
|
+
const { name, fieldLabel, startAdornment,
|
|
64
107
|
//endAdornment,
|
|
65
108
|
imports: optionsImports, } = (0, options_1.buildFormFieldOptions)({ config, formConfig, gqlIntrospection, gqlType });
|
|
66
109
|
imports.push(...optionsImports);
|
|
67
110
|
const nameWithPrefix = `${namePrefix ? `${namePrefix}.` : ``}${name}`;
|
|
68
111
|
const required = !(0, isFieldOptional_1.isFieldOptional)({ config, gqlIntrospection, gqlType });
|
|
69
|
-
const
|
|
70
|
-
destructFromFormValues: config.
|
|
112
|
+
const formValueConfig = {
|
|
113
|
+
destructFromFormValues: config.type == "asyncSelectFilter" ? name : undefined,
|
|
71
114
|
};
|
|
72
|
-
const formValuesConfig = [defaultFormValuesConfig]; // FormFields should only contain one entry
|
|
73
115
|
let finalFormConfig;
|
|
74
116
|
let code = "";
|
|
75
117
|
let formValueToGqlInputCode = "";
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
118
|
+
const { objectType, multiple } = findIntrospectionObjectType({
|
|
119
|
+
config,
|
|
120
|
+
gqlIntrospection,
|
|
121
|
+
gqlType,
|
|
122
|
+
});
|
|
81
123
|
//find labelField: 1. as configured
|
|
82
124
|
let labelField = config.labelField;
|
|
83
125
|
//find labelField: 2. common names (name or title)
|
|
@@ -105,7 +147,13 @@ function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, for
|
|
|
105
147
|
const rootQuery = config.rootQuery; //TODO we should infer a default value from the gql schema
|
|
106
148
|
const queryName = `${rootQuery[0].toUpperCase() + rootQuery.substring(1)}Select`;
|
|
107
149
|
const rootQueryType = (0, findQueryType_1.findQueryTypeOrThrow)(rootQuery, gqlIntrospection);
|
|
108
|
-
|
|
150
|
+
let formFragmentFields;
|
|
151
|
+
if (config.type == "asyncSelectFilter") {
|
|
152
|
+
formFragmentFields = [`${config.loadValueQueryField}.id`, `${config.loadValueQueryField}.${labelField}`];
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
formFragmentFields = [`${name}.id`, `${name}.${labelField}`];
|
|
156
|
+
}
|
|
109
157
|
const filterConfig = config.filter
|
|
110
158
|
? (() => {
|
|
111
159
|
var _a;
|
|
@@ -118,9 +166,9 @@ function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, for
|
|
|
118
166
|
throw new Error(`Field ${String(config.name)}: No field with name "${config.filter.formFieldName}" referenced as filter.formFieldName found in form-config.`);
|
|
119
167
|
}
|
|
120
168
|
if (!(0, generate_command_1.isFormFieldConfig)(filterField)) {
|
|
121
|
-
throw new Error(`Field ${String(config.name)}: Field with name "${config.filter.formFieldName}" referenced as filter.
|
|
169
|
+
throw new Error(`Field ${String(config.name)}: Field with name "${config.filter.formFieldName}" referenced as filter.formFieldName is no FormField.`);
|
|
122
170
|
}
|
|
123
|
-
filterVar = `values.${filterField.type === "asyncSelect" ? `${String(filterField.name)}?.id` : String(filterField.name)}`;
|
|
171
|
+
filterVar = `values.${filterField.type === "asyncSelect" || filterField.type === "asyncSelectFilter" ? `${String(filterField.name)}?.id` : String(filterField.name)}`;
|
|
124
172
|
if (!rootQueryArg) {
|
|
125
173
|
rootQueryArg = config.filter.formFieldName;
|
|
126
174
|
}
|
|
@@ -194,7 +242,7 @@ function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, for
|
|
|
194
242
|
}
|
|
195
243
|
}
|
|
196
244
|
else {
|
|
197
|
-
throw new Error(`Neither filter-prop nor root-prop with name: ${rootQueryArg} for asyncSelect-query not found. Consider setting
|
|
245
|
+
throw new Error(`Neither filter-prop nor root-prop with name: ${rootQueryArg} for asyncSelect-query not found. Consider setting filterField.gqlVarName explicitly.`);
|
|
198
246
|
}
|
|
199
247
|
}
|
|
200
248
|
if (config.filter.type === "formProp") {
|
|
@@ -216,12 +264,17 @@ function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, for
|
|
|
216
264
|
imports.push({ name: "OnChangeField", importPath: "@comet/admin" });
|
|
217
265
|
finalFormConfig = { subscription: { values: true }, renderProps: { values: true, form: true } };
|
|
218
266
|
}
|
|
219
|
-
if (
|
|
220
|
-
if (!
|
|
221
|
-
|
|
267
|
+
if (config.type != "asyncSelectFilter") {
|
|
268
|
+
if (!multiple) {
|
|
269
|
+
if (!required) {
|
|
270
|
+
formValueToGqlInputCode = `${name}: formValues.${name} ? formValues.${name}.id : null,`;
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
formValueToGqlInputCode = `${name}: formValues.${name}?.id,`;
|
|
274
|
+
}
|
|
222
275
|
}
|
|
223
276
|
else {
|
|
224
|
-
formValueToGqlInputCode = `${name}: formValues.${name}
|
|
277
|
+
formValueToGqlInputCode = `${name}: formValues.${name}.map((item) => item.id),`;
|
|
225
278
|
}
|
|
226
279
|
}
|
|
227
280
|
imports.push({
|
|
@@ -232,11 +285,18 @@ function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, for
|
|
|
232
285
|
name: `GQL${queryName}QueryVariables`,
|
|
233
286
|
importPath: `./${baseOutputFilename}.generated`,
|
|
234
287
|
});
|
|
288
|
+
const instanceGqlType = gqlType[0].toLowerCase() + gqlType.substring(1);
|
|
289
|
+
if (config.type == "asyncSelectFilter") {
|
|
290
|
+
// add (in the gql schema) non existing value for virtual filter field
|
|
291
|
+
formValueConfig.typeCode = `${name}?: { id: string; ${labelField}: string };`;
|
|
292
|
+
formValueConfig.initializationCode = `${name}: data.${instanceGqlType}.${config.loadValueQueryField.replace(/\./g, "?.")}`;
|
|
293
|
+
}
|
|
235
294
|
code = `<AsyncSelectField
|
|
236
295
|
${required ? "required" : ""}
|
|
237
296
|
variant="horizontal"
|
|
238
297
|
fullWidth
|
|
239
298
|
${config.readOnly ? "readOnly disabled" : ""}
|
|
299
|
+
${multiple ? "multiple" : ""}
|
|
240
300
|
name="${nameWithPrefix}"
|
|
241
301
|
label={${fieldLabel}}
|
|
242
302
|
${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
@@ -270,11 +330,11 @@ function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, for
|
|
|
270
330
|
code,
|
|
271
331
|
hooksCode: "",
|
|
272
332
|
formValueToGqlInputCode,
|
|
273
|
-
formFragmentFields
|
|
333
|
+
formFragmentFields,
|
|
274
334
|
gqlDocuments: {},
|
|
275
335
|
imports,
|
|
276
336
|
formProps,
|
|
277
|
-
formValuesConfig,
|
|
337
|
+
formValuesConfig: [formValueConfig],
|
|
278
338
|
finalFormConfig,
|
|
279
339
|
};
|
|
280
340
|
}
|
|
@@ -23,6 +23,6 @@ export declare function buildFormFieldOptions({ config, formConfig, gqlIntrospec
|
|
|
23
23
|
startAdornment: AdornmentData;
|
|
24
24
|
endAdornment: AdornmentData;
|
|
25
25
|
imports: Imports;
|
|
26
|
-
introspectionFieldType: import("graphql").IntrospectionNamedTypeRef<import("graphql").IntrospectionOutputType> | import("graphql").IntrospectionListTypeRef<import("graphql").IntrospectionOutputTypeRef
|
|
26
|
+
introspectionFieldType: import("graphql").IntrospectionNamedTypeRef<import("graphql").IntrospectionOutputType> | import("graphql").IntrospectionListTypeRef<import("graphql").IntrospectionOutputTypeRef> | undefined;
|
|
27
27
|
};
|
|
28
28
|
export {};
|
|
@@ -62,9 +62,11 @@ function buildFormFieldOptions({ config, formConfig, gqlIntrospection, gqlType,
|
|
|
62
62
|
if (!introspectionObject)
|
|
63
63
|
throw new Error(`didn't find object ${gqlType} in gql introspection`);
|
|
64
64
|
const introspectionField = introspectionObject.fields.find((field) => field.name === name);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
const introspectionFieldType = introspectionField
|
|
66
|
+
? introspectionField.type.kind === "NON_NULL"
|
|
67
|
+
? introspectionField.type.ofType
|
|
68
|
+
: introspectionField.type
|
|
69
|
+
: undefined;
|
|
68
70
|
const imports = [];
|
|
69
71
|
let startAdornment = { adornmentString: "" };
|
|
70
72
|
let endAdornment = { adornmentString: "" };
|
|
@@ -18,6 +18,7 @@ const findMutationType_1 = require("../utils/findMutationType");
|
|
|
18
18
|
const generateImportsCode_1 = require("../utils/generateImportsCode");
|
|
19
19
|
const runtimeTypeGuards_1 = require("../utils/runtimeTypeGuards");
|
|
20
20
|
const generateFields_1 = require("./generateFields");
|
|
21
|
+
const generateFragmentByFormFragmentFields_1 = require("./generateFragmentByFormFragmentFields");
|
|
21
22
|
const getForwardedGqlArgs_1 = require("./getForwardedGqlArgs");
|
|
22
23
|
function generateFormPropsCode(props) {
|
|
23
24
|
if (!props.length)
|
|
@@ -141,10 +142,6 @@ config) {
|
|
|
141
142
|
const fileFields = formFields.filter((field) => field.type == "fileUpload");
|
|
142
143
|
if (fileFields.length > 0) {
|
|
143
144
|
imports.push({ name: "GQLFinalFormFileUploadFragment", importPath: "@comet/cms-admin" });
|
|
144
|
-
}
|
|
145
|
-
// Unnecessary field.type == "fileUpload" check to make TypeScript happy
|
|
146
|
-
const downloadableFileFields = fileFields.filter((field) => field.type == "fileUpload" && field.download);
|
|
147
|
-
if (fileFields.length > 0) {
|
|
148
145
|
imports.push({ name: "GQLFinalFormFileUploadDownloadableFragment", importPath: "@comet/cms-admin" });
|
|
149
146
|
}
|
|
150
147
|
let hooksCode = "";
|
|
@@ -173,13 +170,7 @@ config) {
|
|
|
173
170
|
formValuesConfig.push(...generatedFields.formValuesConfig);
|
|
174
171
|
const { formPropsTypeCode, formPropsParamsCode } = generateFormPropsCode(formProps);
|
|
175
172
|
gqlDocuments[`${instanceGqlType}FormFragment`] = {
|
|
176
|
-
document:
|
|
177
|
-
fragment ${formFragmentName} on ${gqlType} {
|
|
178
|
-
${formFragmentFields.join("\n")}
|
|
179
|
-
}
|
|
180
|
-
${fileFields.length > 0 && fileFields.length !== downloadableFileFields.length ? "${finalFormFileUploadFragment}" : ""}
|
|
181
|
-
${downloadableFileFields.length > 0 ? "${finalFormFileUploadDownloadableFragment}" : ""}
|
|
182
|
-
`,
|
|
173
|
+
document: (0, generateFragmentByFormFragmentFields_1.generateFragmentByFormFragmentFields)({ formFragmentName, gqlType, formFragmentFields }),
|
|
183
174
|
export: editMode,
|
|
184
175
|
};
|
|
185
176
|
if (editMode) {
|
|
@@ -8,13 +8,14 @@ const runtimeTypeGuards_1 = require("../utils/runtimeTypeGuards");
|
|
|
8
8
|
const generateAsyncSelect_1 = require("./asyncSelect/generateAsyncSelect");
|
|
9
9
|
const options_1 = require("./formField/options");
|
|
10
10
|
function generateFormField({ gqlIntrospection, baseOutputFilename, config, formConfig, gqlType, namePrefix, }) {
|
|
11
|
-
if (config.type == "asyncSelect") {
|
|
11
|
+
if (config.type == "asyncSelect" || config.type == "asyncSelectFilter") {
|
|
12
12
|
return (0, generateAsyncSelect_1.generateAsyncSelect)({ gqlIntrospection, baseOutputFilename, config, formConfig, gqlType, namePrefix });
|
|
13
13
|
}
|
|
14
14
|
const imports = [];
|
|
15
15
|
const formProps = [];
|
|
16
|
-
const { name, formattedMessageRootId, fieldLabel,
|
|
16
|
+
const { name, formattedMessageRootId, fieldLabel, startAdornment, endAdornment, imports: optionsImports, } = (0, options_1.buildFormFieldOptions)({ config, formConfig, gqlType, gqlIntrospection });
|
|
17
17
|
imports.push(...optionsImports);
|
|
18
|
+
let { introspectionFieldType } = (0, options_1.buildFormFieldOptions)({ config, formConfig, gqlType, gqlIntrospection });
|
|
18
19
|
const nameWithPrefix = `${namePrefix ? `${namePrefix}.` : ``}${name}`;
|
|
19
20
|
const rootGqlType = formConfig.gqlType;
|
|
20
21
|
const dataRootName = rootGqlType[0].toLowerCase() + rootGqlType.substring(1); // TODO should probably be deteced via query
|
|
@@ -23,10 +24,7 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
23
24
|
const endAdornmentWithLockIconProp = `endAdornment={<InputAdornment position="end"><Lock /></InputAdornment>}`;
|
|
24
25
|
const readOnlyProps = `readOnly disabled`;
|
|
25
26
|
const readOnlyPropsWithLock = `${readOnlyProps} ${endAdornmentWithLockIconProp}`;
|
|
26
|
-
|
|
27
|
-
destructFromFormValues: config.virtual ? name : undefined,
|
|
28
|
-
};
|
|
29
|
-
let formValuesConfig = [defaultFormValuesConfig]; // FormFields should only contain one entry
|
|
27
|
+
let formValuesConfig = [{}]; // FormFields should only contain one entry
|
|
30
28
|
const gqlDocuments = {};
|
|
31
29
|
const hooksCode = "";
|
|
32
30
|
let finalFormConfig;
|
|
@@ -43,7 +41,7 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
43
41
|
}
|
|
44
42
|
let code = "";
|
|
45
43
|
let formValueToGqlInputCode = "";
|
|
46
|
-
let
|
|
44
|
+
let formFragmentFields = [name];
|
|
47
45
|
if (config.type == "text") {
|
|
48
46
|
const TextInputComponent = config.multiline ? "TextAreaField" : "TextField";
|
|
49
47
|
code = `
|
|
@@ -63,7 +61,7 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
63
61
|
: ""}
|
|
64
62
|
${validateCode}
|
|
65
63
|
/>`;
|
|
66
|
-
if (!
|
|
64
|
+
if (!required && !config.readOnly) {
|
|
67
65
|
formValueToGqlInputCode = `${name}: formValues.${name} ?? null,`;
|
|
68
66
|
}
|
|
69
67
|
}
|
|
@@ -91,17 +89,17 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
91
89
|
if ((0, isFieldOptional_1.isFieldOptional)({ config, gqlIntrospection: gqlIntrospection, gqlType: gqlType })) {
|
|
92
90
|
assignment = `formValues.${nameWithPrefix} ? ${assignment} : null`;
|
|
93
91
|
}
|
|
94
|
-
formValueToGqlInputCode =
|
|
92
|
+
formValueToGqlInputCode = `${name}: ${assignment},`;
|
|
95
93
|
let initializationAssignment = `String(data.${dataRootName}.${nameWithPrefix})`;
|
|
96
94
|
if (!required) {
|
|
97
95
|
initializationAssignment = `data.${dataRootName}.${nameWithPrefix} ? ${initializationAssignment} : undefined`;
|
|
98
96
|
}
|
|
99
97
|
formValuesConfig = [
|
|
100
|
-
|
|
98
|
+
{
|
|
101
99
|
omitFromFragmentType: name,
|
|
102
100
|
typeCode: `${name}${!required ? `?` : ``}: string;`,
|
|
103
101
|
initializationCode: `${name}: ${initializationAssignment}`,
|
|
104
|
-
}
|
|
102
|
+
},
|
|
105
103
|
];
|
|
106
104
|
}
|
|
107
105
|
else if (config.type === "numberRange") {
|
|
@@ -126,7 +124,7 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
126
124
|
: ""}
|
|
127
125
|
${validateCode}
|
|
128
126
|
/>`;
|
|
129
|
-
|
|
127
|
+
formFragmentFields = [`${name}.min`, `${name}.max`];
|
|
130
128
|
}
|
|
131
129
|
else if (config.type == "boolean") {
|
|
132
130
|
code = `<CheckboxField
|
|
@@ -143,9 +141,9 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
143
141
|
${validateCode}
|
|
144
142
|
/>`;
|
|
145
143
|
formValuesConfig = [
|
|
146
|
-
|
|
144
|
+
{
|
|
147
145
|
defaultInitializationCode: `${name}: false`,
|
|
148
|
-
}
|
|
146
|
+
},
|
|
149
147
|
];
|
|
150
148
|
}
|
|
151
149
|
else if (config.type == "date") {
|
|
@@ -170,9 +168,16 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
170
168
|
: ""}
|
|
171
169
|
${validateCode}
|
|
172
170
|
/>`;
|
|
171
|
+
if (!required && !config.readOnly) {
|
|
172
|
+
formValueToGqlInputCode = `${name}: formValues.${name} ?? null,`;
|
|
173
|
+
}
|
|
173
174
|
}
|
|
174
175
|
else if (config.type == "dateTime") {
|
|
175
|
-
|
|
176
|
+
imports.push({
|
|
177
|
+
name: "Future_DateTimePickerField as DateTimePickerField",
|
|
178
|
+
importPath: "@comet/admin",
|
|
179
|
+
});
|
|
180
|
+
code = `<DateTimePickerField
|
|
176
181
|
${required ? "required" : ""}
|
|
177
182
|
${config.readOnly ? readOnlyPropsWithLock : ""}
|
|
178
183
|
variant="horizontal"
|
|
@@ -189,13 +194,13 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
189
194
|
${validateCode}
|
|
190
195
|
/>`;
|
|
191
196
|
formValuesConfig = [
|
|
192
|
-
|
|
197
|
+
{
|
|
193
198
|
initializationCode: `${name}: data.${dataRootName}.${nameWithPrefix} ? new Date(data.${dataRootName}.${nameWithPrefix}) : undefined`,
|
|
194
199
|
omitFromFragmentType: name,
|
|
195
200
|
typeCode: `${name}${!required ? "?" : ""}: Date${!required ? " | null" : ""};`,
|
|
196
|
-
}
|
|
201
|
+
},
|
|
197
202
|
];
|
|
198
|
-
if (!config.
|
|
203
|
+
if (!config.readOnly) {
|
|
199
204
|
formValueToGqlInputCode = required
|
|
200
205
|
? `${name}: formValues.${name}.toISOString(),`
|
|
201
206
|
: `${name}: formValues.${name} ? formValues.${name}.toISOString() : null,`;
|
|
@@ -205,13 +210,13 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
205
210
|
code = `<Field name="${nameWithPrefix}" isEqual={isEqual} label={${fieldLabel}} variant="horizontal" fullWidth>
|
|
206
211
|
{createFinalFormBlock(rootBlocks.${String(config.name)})}
|
|
207
212
|
</Field>`;
|
|
208
|
-
formValueToGqlInputCode =
|
|
213
|
+
formValueToGqlInputCode = `${name}: rootBlocks.${name}.state2Output(formValues.${nameWithPrefix}),`;
|
|
209
214
|
formValuesConfig = [
|
|
210
|
-
|
|
215
|
+
{
|
|
211
216
|
typeCode: `${name}: BlockState<typeof rootBlocks.${name}>;`,
|
|
212
217
|
initializationCode: `${name}: rootBlocks.${name}.input2State(data.${dataRootName}.${nameWithPrefix})`,
|
|
213
218
|
defaultInitializationCode: `${name}: rootBlocks.${name}.defaultValues()`,
|
|
214
|
-
}
|
|
219
|
+
},
|
|
215
220
|
];
|
|
216
221
|
}
|
|
217
222
|
else if (config.type === "fileUpload") {
|
|
@@ -231,9 +236,14 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
231
236
|
else {
|
|
232
237
|
formValueToGqlInputCode = `${name}: formValues.${name} ? formValues.${name}.id : null,`;
|
|
233
238
|
}
|
|
234
|
-
|
|
239
|
+
formFragmentFields = [`${name} { ...${config.download ? "FinalFormFileUploadDownloadable" : "FinalFormFileUpload"} }`];
|
|
235
240
|
}
|
|
236
241
|
else if (config.type == "staticSelect") {
|
|
242
|
+
const multiple = (introspectionFieldType === null || introspectionFieldType === void 0 ? void 0 : introspectionFieldType.kind) === "LIST";
|
|
243
|
+
if ((introspectionFieldType === null || introspectionFieldType === void 0 ? void 0 : introspectionFieldType.kind) === "LIST") {
|
|
244
|
+
introspectionFieldType =
|
|
245
|
+
introspectionFieldType.ofType.kind === "NON_NULL" ? introspectionFieldType.ofType.ofType : introspectionFieldType.ofType;
|
|
246
|
+
}
|
|
237
247
|
const enumType = gqlIntrospection.__schema.types.find((t) => t.kind === "ENUM" && t.name === introspectionFieldType.name);
|
|
238
248
|
if (!enumType)
|
|
239
249
|
throw new Error(`Enum type ${introspectionFieldType.name} not found for field ${name}`);
|
|
@@ -248,7 +258,30 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
248
258
|
return value;
|
|
249
259
|
}
|
|
250
260
|
});
|
|
251
|
-
|
|
261
|
+
let inputType = config.inputType;
|
|
262
|
+
if (!inputType) {
|
|
263
|
+
if (!required || multiple) {
|
|
264
|
+
// radio is not clearable, render always as select if not required
|
|
265
|
+
// radio doesn't support multiple
|
|
266
|
+
inputType = "select";
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
// auto select/radio based on number of values
|
|
270
|
+
if (values.length <= 5) {
|
|
271
|
+
inputType = "radio";
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
inputType = "select";
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (inputType === "radio" && multiple) {
|
|
279
|
+
throw new Error(`${name}: inputType=radio doesn't support multiple`);
|
|
280
|
+
}
|
|
281
|
+
if (inputType === "radio" && !required) {
|
|
282
|
+
throw new Error(`${name}: inputType=radio must be required as it doesn't support clearable`);
|
|
283
|
+
}
|
|
284
|
+
const renderAsRadio = inputType === "radio";
|
|
252
285
|
if (renderAsRadio) {
|
|
253
286
|
code = `<RadioGroupField
|
|
254
287
|
${required ? "required" : ""}
|
|
@@ -286,6 +319,7 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
286
319
|
: ""}
|
|
287
320
|
${validateCode}
|
|
288
321
|
${config.readOnly ? readOnlyPropsWithLock : ""}
|
|
322
|
+
${multiple ? "multiple" : ""}
|
|
289
323
|
options={[${values.map((value) => {
|
|
290
324
|
const id = `${formattedMessageRootId}.${name}.${value.value.charAt(0).toLowerCase() + value.value.slice(1)}`;
|
|
291
325
|
return `{
|
|
@@ -303,7 +337,7 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
303
337
|
code,
|
|
304
338
|
hooksCode,
|
|
305
339
|
formValueToGqlInputCode,
|
|
306
|
-
formFragmentFields
|
|
340
|
+
formFragmentFields,
|
|
307
341
|
gqlDocuments,
|
|
308
342
|
imports,
|
|
309
343
|
formProps,
|
|
@@ -88,7 +88,7 @@ function generateFormLayout({ gqlIntrospection, baseOutputFilename, config, form
|
|
|
88
88
|
namePrefix: name,
|
|
89
89
|
});
|
|
90
90
|
hooksCode += generatedFields.hooksCode;
|
|
91
|
-
formFragmentFields.push(
|
|
91
|
+
formFragmentFields.push(...generatedFields.formFragmentFields.map((field) => `${name}.${field}`));
|
|
92
92
|
for (const name in generatedFields.gqlDocuments) {
|
|
93
93
|
gqlDocuments[name] = generatedFields.gqlDocuments[name];
|
|
94
94
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function that generates a GraphQL fragment from form fragment fields (array of dot.separated.fields).
|
|
3
|
+
*
|
|
4
|
+
* - Fragments are supported as "foo { ...FragmentName }"
|
|
5
|
+
* - for FinalFormFileUpload and FinalFormFileUploadDownloadable the needed variable is added automatically
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateFragmentByFormFragmentFields({ formFragmentName, gqlType, formFragmentFields, }: {
|
|
8
|
+
formFragmentName: string;
|
|
9
|
+
gqlType: string;
|
|
10
|
+
formFragmentFields: string[];
|
|
11
|
+
}): string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateFragmentByFormFragmentFields = generateFragmentByFormFragmentFields;
|
|
7
|
+
const object_path_1 = __importDefault(require("object-path"));
|
|
8
|
+
/**
|
|
9
|
+
* Helper function that generates a GraphQL fragment from form fragment fields (array of dot.separated.fields).
|
|
10
|
+
*
|
|
11
|
+
* - Fragments are supported as "foo { ...FragmentName }"
|
|
12
|
+
* - for FinalFormFileUpload and FinalFormFileUploadDownloadable the needed variable is added automatically
|
|
13
|
+
*/
|
|
14
|
+
function generateFragmentByFormFragmentFields({ formFragmentName, gqlType, formFragmentFields, }) {
|
|
15
|
+
// 1. create tree out of dot separated fields
|
|
16
|
+
const fieldsObject = formFragmentFields.reduce((acc, field) => {
|
|
17
|
+
const fragmentMatch = field.match(/(.*)({.*?})/); // keep { ... } parts as they are, contains eg. fragments
|
|
18
|
+
if (fragmentMatch) {
|
|
19
|
+
object_path_1.default.set(acc, fragmentMatch[1].trim(), fragmentMatch[2]);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
object_path_1.default.set(acc, field, true);
|
|
23
|
+
}
|
|
24
|
+
return acc;
|
|
25
|
+
}, {});
|
|
26
|
+
// 2. create fragment string out of tree
|
|
27
|
+
const recursiveStringify = (obj) => {
|
|
28
|
+
let ret = "";
|
|
29
|
+
let prefixField = "";
|
|
30
|
+
for (const key in obj) {
|
|
31
|
+
const value = obj[key];
|
|
32
|
+
if (typeof value === "boolean") {
|
|
33
|
+
ret += `${prefixField}${key}`;
|
|
34
|
+
}
|
|
35
|
+
else if (typeof value === "string") {
|
|
36
|
+
ret += `${prefixField}${key} ${value}`;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
ret += `${prefixField}${key} { ${recursiveStringify(value)} }`;
|
|
40
|
+
}
|
|
41
|
+
prefixField = " ";
|
|
42
|
+
}
|
|
43
|
+
return ret;
|
|
44
|
+
};
|
|
45
|
+
let fragmentCode = `
|
|
46
|
+
fragment ${formFragmentName} on ${gqlType} {
|
|
47
|
+
${recursiveStringify(fieldsObject)}
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
50
|
+
// 3. add fragment instance variables when fragments are used
|
|
51
|
+
// this only works for hardcoded special cases, and the imports are also not handled here - if there would be more, this needs improvement
|
|
52
|
+
const fragments = {
|
|
53
|
+
"...FinalFormFileUpload": "${finalFormFileUploadFragment}",
|
|
54
|
+
"...FinalFormFileUploadDownloadable": "${finalFormFileUploadDownloadableFragment}",
|
|
55
|
+
};
|
|
56
|
+
for (const [fragmentName, fragmentVar] of Object.entries(fragments)) {
|
|
57
|
+
if (fragmentCode.match(`${fragmentName.replace(".", "\\.")}\\b`) && !fragmentCode.includes(fragmentVar)) {
|
|
58
|
+
fragmentCode += `\n${fragmentVar}`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return fragmentCode;
|
|
62
|
+
}
|
|
@@ -308,6 +308,7 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
|
|
|
308
308
|
let gridColumnType = undefined;
|
|
309
309
|
let renderCell = undefined;
|
|
310
310
|
let valueFormatter = undefined;
|
|
311
|
+
let valueGetter = name.includes(".") ? `(params, row) => row.${name.replace(/\./g, "?.")}` : undefined;
|
|
311
312
|
let gridType;
|
|
312
313
|
let filterOperators;
|
|
313
314
|
if (column.type != "virtual" && column.filterOperators) {
|
|
@@ -321,9 +322,15 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
|
|
|
321
322
|
}
|
|
322
323
|
if (type == "dateTime") {
|
|
323
324
|
gridColumnType = "...dataGridDateTimeColumn,";
|
|
325
|
+
valueGetter = name.includes(".")
|
|
326
|
+
? `(params, row) => row.${name.replace(/\./g, "?.")} && new Date(row.${name.replace(/\./g, "?.")})`
|
|
327
|
+
: undefined;
|
|
324
328
|
}
|
|
325
329
|
else if (type == "date") {
|
|
326
330
|
gridColumnType = "...dataGridDateColumn,";
|
|
331
|
+
valueGetter = name.includes(".")
|
|
332
|
+
? `(params, row) => row.${name.replace(/\./g, "?.")} && new Date(row.${name.replace(/\./g, "?.")})`
|
|
333
|
+
: undefined;
|
|
327
334
|
}
|
|
328
335
|
else if (type == "number") {
|
|
329
336
|
gridType = "number";
|
|
@@ -458,7 +465,7 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
|
|
|
458
465
|
gridType,
|
|
459
466
|
columnType: gridColumnType,
|
|
460
467
|
renderCell,
|
|
461
|
-
valueGetter
|
|
468
|
+
valueGetter,
|
|
462
469
|
filterOperators: filterOperators,
|
|
463
470
|
valueFormatter,
|
|
464
471
|
width: column.width,
|
|
@@ -15,7 +15,7 @@ const isFieldOptional = ({ config, gqlIntrospection, gqlType, }) => {
|
|
|
15
15
|
throw new Error(`kind of ${gqlType} is not object, but should be.`); // this should not happen
|
|
16
16
|
const fieldDef = schemaEntity.fields.find((field) => field.name === String(config.name));
|
|
17
17
|
if (!fieldDef)
|
|
18
|
-
|
|
18
|
+
return false;
|
|
19
19
|
return fieldDef.type.kind !== "NON_NULL";
|
|
20
20
|
};
|
|
21
21
|
exports.isFieldOptional = isFieldOptional;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@comet/admin-generator",
|
|
3
|
-
"version": "9.0.0-canary-
|
|
3
|
+
"version": "9.0.0-canary-20251002064922",
|
|
4
4
|
"description": "Comet Admin Generator CLI tool",
|
|
5
5
|
"repository": {
|
|
6
6
|
"directory": "packages/admin/admin-generator",
|
|
@@ -40,17 +40,17 @@
|
|
|
40
40
|
"eslint": "^9.30.1",
|
|
41
41
|
"final-form": "^4.20.10",
|
|
42
42
|
"jest": "^29.7.0",
|
|
43
|
-
"npm-run-all2": "^
|
|
43
|
+
"npm-run-all2": "^8.0.0",
|
|
44
44
|
"prettier": "^3.6.2",
|
|
45
45
|
"react": "^18.3.1",
|
|
46
46
|
"react-intl": "^7.1.11",
|
|
47
47
|
"rimraf": "^6.0.1",
|
|
48
48
|
"ts-jest": "^29.4.0",
|
|
49
49
|
"typescript": "5.8.3",
|
|
50
|
-
"@comet/admin": "9.0.0-canary-
|
|
51
|
-
"@comet/admin-icons": "9.0.0-canary-
|
|
52
|
-
"@comet/cms-admin": "9.0.0-canary-
|
|
53
|
-
"@comet/eslint-config": "9.0.0-canary-
|
|
50
|
+
"@comet/admin": "9.0.0-canary-20251002064922",
|
|
51
|
+
"@comet/admin-icons": "9.0.0-canary-20251002064922",
|
|
52
|
+
"@comet/cms-admin": "9.0.0-canary-20251002064922",
|
|
53
|
+
"@comet/eslint-config": "9.0.0-canary-20251002064922"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
56
56
|
"node": ">=22.0.0"
|