@comet/admin-generator 8.7.0-canary-20251112090955 → 8.7.0-canary-20251113072631
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 +13 -13
- package/lib/commands/generate/generateForm/asyncSelect/generateAsyncSelect.js +8 -9
- package/lib/commands/generate/generateForm/formField/findIntrospectionFieldType.d.ts +6 -0
- package/lib/commands/generate/generateForm/formField/findIntrospectionFieldType.js +22 -0
- package/lib/commands/generate/generateForm/formField/options.d.ts +1 -5
- package/lib/commands/generate/generateForm/formField/options.js +2 -11
- package/lib/commands/generate/generateForm/generateComponentFormField.js +0 -1
- package/lib/commands/generate/generateForm/generateFields.d.ts +9 -4
- package/lib/commands/generate/generateForm/generateFields.js +0 -3
- package/lib/commands/generate/generateForm/generateForm.js +8 -4
- package/lib/commands/generate/generateForm/generateFormField.js +33 -43
- package/lib/commands/generate/generateForm/generateFormLayout.js +23 -44
- package/lib/commands/generate/generateForm/generateFormValues.d.ts +29 -8
- package/lib/commands/generate/generateForm/generateFormValues.js +191 -51
- package/lib/commands/generate/generateForm/getForwardedGqlArgs.js +8 -3
- package/lib/commands/generate/generateGrid/usableFields.d.ts +6 -1
- package/package.json +5 -5
|
@@ -6,7 +6,7 @@ import { type GridCellParams, type GridFilterItem, type GridFilterOperator, type
|
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import { type FieldValidator } from "final-form";
|
|
8
8
|
import { type ComponentType } from "react";
|
|
9
|
-
import { type UsableFields } from "./generateGrid/usableFields";
|
|
9
|
+
import { type UsableFields, type UsableFormFields } from "./generateGrid/usableFields";
|
|
10
10
|
import { type ColumnVisibleOption } from "./utils/columnVisibility";
|
|
11
11
|
type IconObject = Pick<IconProps, "color" | "fontSize"> & {
|
|
12
12
|
name: IconName;
|
|
@@ -60,35 +60,35 @@ type AsyncSelectFilter = {
|
|
|
60
60
|
};
|
|
61
61
|
export type FormFieldConfig<T> = (({
|
|
62
62
|
type: "text";
|
|
63
|
-
name:
|
|
63
|
+
name: UsableFormFields<T>;
|
|
64
64
|
multiline?: boolean;
|
|
65
65
|
} & InputBaseFieldConfig) | ({
|
|
66
66
|
type: "number";
|
|
67
|
-
name:
|
|
67
|
+
name: UsableFormFields<T>;
|
|
68
68
|
decimals?: number;
|
|
69
69
|
} & InputBaseFieldConfig) | ({
|
|
70
70
|
type: "numberRange";
|
|
71
|
-
name:
|
|
71
|
+
name: UsableFormFields<T>;
|
|
72
72
|
minValue: number;
|
|
73
73
|
maxValue: number;
|
|
74
74
|
disableSlider?: boolean;
|
|
75
75
|
} & InputBaseFieldConfig) | {
|
|
76
76
|
type: "boolean";
|
|
77
|
-
name:
|
|
77
|
+
name: UsableFormFields<T>;
|
|
78
78
|
} | ({
|
|
79
79
|
type: "date";
|
|
80
|
-
name:
|
|
80
|
+
name: UsableFormFields<T>;
|
|
81
81
|
} & InputBaseFieldConfig) | ({
|
|
82
82
|
type: "dateTime";
|
|
83
|
-
name:
|
|
83
|
+
name: UsableFormFields<T>;
|
|
84
84
|
} & InputBaseFieldConfig) | ({
|
|
85
85
|
type: "staticSelect";
|
|
86
|
-
name:
|
|
86
|
+
name: UsableFormFields<T>;
|
|
87
87
|
values?: StaticSelectValue[];
|
|
88
88
|
inputType?: "select" | "radio";
|
|
89
89
|
} & Omit<InputBaseFieldConfig, "endAdornment">) | ({
|
|
90
90
|
type: "asyncSelect";
|
|
91
|
-
name:
|
|
91
|
+
name: UsableFormFields<T>;
|
|
92
92
|
rootQuery: string;
|
|
93
93
|
labelField?: string;
|
|
94
94
|
/** Whether Autocomplete or Select should be used.
|
|
@@ -117,18 +117,18 @@ export type FormFieldConfig<T> = (({
|
|
|
117
117
|
filter?: AsyncSelectFilter;
|
|
118
118
|
} & Omit<InputBaseFieldConfig, "endAdornment">) | {
|
|
119
119
|
type: "block";
|
|
120
|
-
name:
|
|
120
|
+
name: UsableFormFields<T>;
|
|
121
121
|
block: BlockInterface;
|
|
122
122
|
} | ({
|
|
123
123
|
type: "fileUpload";
|
|
124
124
|
multiple?: false;
|
|
125
|
-
name:
|
|
125
|
+
name: UsableFormFields<T>;
|
|
126
126
|
maxFiles?: 1;
|
|
127
127
|
download?: boolean;
|
|
128
128
|
} & Pick<Partial<FinalFormFileUploadProps<false>>, "maxFileSize" | "readOnly" | "layout" | "accept">) | ({
|
|
129
129
|
type: "fileUpload";
|
|
130
130
|
multiple: true;
|
|
131
|
-
name:
|
|
131
|
+
name: UsableFormFields<T>;
|
|
132
132
|
maxFiles?: number;
|
|
133
133
|
download?: boolean;
|
|
134
134
|
} & Pick<Partial<FinalFormFileUploadProps<true>>, "maxFileSize" | "readOnly" | "layout" | "accept">)) & {
|
|
@@ -141,7 +141,7 @@ export type FormFieldConfig<T> = (({
|
|
|
141
141
|
export declare function isFormFieldConfig<T>(arg: any): arg is FormFieldConfig<T>;
|
|
142
142
|
type OptionalNestedFieldsConfig<T> = {
|
|
143
143
|
type: "optionalNestedFields";
|
|
144
|
-
name:
|
|
144
|
+
name: UsableFormFields<T>;
|
|
145
145
|
checkboxLabel?: string;
|
|
146
146
|
fields: FormFieldConfig<any>[];
|
|
147
147
|
};
|
|
@@ -106,16 +106,16 @@ function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, for
|
|
|
106
106
|
const formProps = [];
|
|
107
107
|
const { name, fieldLabel, startAdornment,
|
|
108
108
|
//endAdornment,
|
|
109
|
-
imports: optionsImports, } = (0, options_1.buildFormFieldOptions)({ config, formConfig
|
|
109
|
+
imports: optionsImports, } = (0, options_1.buildFormFieldOptions)({ config, formConfig });
|
|
110
110
|
imports.push(...optionsImports);
|
|
111
111
|
const nameWithPrefix = `${namePrefix ? `${namePrefix}.` : ``}${name}`;
|
|
112
112
|
const required = !(0, isFieldOptional_1.isFieldOptional)({ config, gqlIntrospection, gqlType });
|
|
113
113
|
const formValueConfig = {
|
|
114
|
-
|
|
114
|
+
fieldName: name,
|
|
115
|
+
destructFromFormValues: config.type == "asyncSelectFilter",
|
|
115
116
|
};
|
|
116
117
|
let finalFormConfig;
|
|
117
118
|
let code = "";
|
|
118
|
-
let formValueToGqlInputCode = "";
|
|
119
119
|
const { objectType, multiple } = findIntrospectionObjectType({
|
|
120
120
|
config,
|
|
121
121
|
gqlIntrospection,
|
|
@@ -278,14 +278,14 @@ function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, for
|
|
|
278
278
|
if (config.type != "asyncSelectFilter") {
|
|
279
279
|
if (!multiple) {
|
|
280
280
|
if (!required) {
|
|
281
|
-
formValueToGqlInputCode = `$
|
|
281
|
+
formValueConfig.formValueToGqlInputCode = `$fieldName ? $fieldName.id : null`;
|
|
282
282
|
}
|
|
283
283
|
else {
|
|
284
|
-
formValueToGqlInputCode = `$
|
|
284
|
+
formValueConfig.formValueToGqlInputCode = `$fieldName?.id`;
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
287
|
else {
|
|
288
|
-
formValueToGqlInputCode = `$
|
|
288
|
+
formValueConfig.formValueToGqlInputCode = `$fieldName.map((item) => item.id)`;
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
291
|
imports.push({
|
|
@@ -305,8 +305,8 @@ function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, for
|
|
|
305
305
|
const instanceGqlType = gqlType[0].toLowerCase() + gqlType.substring(1);
|
|
306
306
|
if (config.type == "asyncSelectFilter") {
|
|
307
307
|
// add (in the gql schema) non existing value for virtual filter field
|
|
308
|
-
formValueConfig.typeCode =
|
|
309
|
-
formValueConfig.initializationCode =
|
|
308
|
+
formValueConfig.typeCode = { nullable: true, type: `{ id: string; ${labelField}: string }` };
|
|
309
|
+
formValueConfig.initializationCode = `data.${instanceGqlType}.${config.loadValueQueryField.replace(/\./g, "?.")}`;
|
|
310
310
|
}
|
|
311
311
|
code = `<${useAutocomplete ? "AsyncAutocompleteField" : "AsyncSelectField"}
|
|
312
312
|
${required ? "required" : ""}
|
|
@@ -354,7 +354,6 @@ function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, for
|
|
|
354
354
|
return {
|
|
355
355
|
code,
|
|
356
356
|
hooksCode: "",
|
|
357
|
-
formValueToGqlInputCode,
|
|
358
357
|
formFragmentFields,
|
|
359
358
|
gqlDocuments: {},
|
|
360
359
|
imports,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type IntrospectionQuery } from "graphql";
|
|
2
|
+
export declare function findIntrospectionFieldType({ name, gqlType, gqlIntrospection, }: {
|
|
3
|
+
name: string;
|
|
4
|
+
gqlType: string;
|
|
5
|
+
gqlIntrospection: IntrospectionQuery;
|
|
6
|
+
}): import("graphql").IntrospectionNamedTypeRef<import("graphql").IntrospectionOutputType> | import("graphql").IntrospectionListTypeRef<import("graphql").IntrospectionOutputTypeRef> | undefined;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findIntrospectionFieldType = findIntrospectionFieldType;
|
|
4
|
+
function findIntrospectionFieldType({ name, gqlType, gqlIntrospection, }) {
|
|
5
|
+
let introspectionFieldType;
|
|
6
|
+
for (const namePart of name.split(".")) {
|
|
7
|
+
const introspectionObject = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === gqlType);
|
|
8
|
+
if (!introspectionObject)
|
|
9
|
+
throw new Error(`didn't find object ${gqlType} in gql introspection`);
|
|
10
|
+
const introspectionField = introspectionObject.fields.find((field) => field.name === namePart);
|
|
11
|
+
introspectionFieldType = introspectionField
|
|
12
|
+
? introspectionField.type.kind === "NON_NULL"
|
|
13
|
+
? introspectionField.type.ofType
|
|
14
|
+
: introspectionField.type
|
|
15
|
+
: undefined;
|
|
16
|
+
if ((introspectionFieldType === null || introspectionFieldType === void 0 ? void 0 : introspectionFieldType.kind) === "OBJECT") {
|
|
17
|
+
// for next loop iteration (nested fields)
|
|
18
|
+
gqlType = introspectionFieldType.name;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return introspectionFieldType;
|
|
22
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type IntrospectionQuery } from "graphql";
|
|
2
1
|
import { type FormConfig, type FormFieldConfig } from "../../generate-command";
|
|
3
2
|
import { type Imports } from "../../utils/generateImportsCode";
|
|
4
3
|
type AdornmentData = {
|
|
@@ -11,11 +10,9 @@ type AdornmentData = {
|
|
|
11
10
|
/**
|
|
12
11
|
* Helper function that builds various options needed for generating form fields.
|
|
13
12
|
*/
|
|
14
|
-
export declare function buildFormFieldOptions({ config, formConfig,
|
|
13
|
+
export declare function buildFormFieldOptions({ config, formConfig, }: {
|
|
15
14
|
config: FormFieldConfig<any>;
|
|
16
15
|
formConfig: FormConfig<any>;
|
|
17
|
-
gqlIntrospection: IntrospectionQuery;
|
|
18
|
-
gqlType: string;
|
|
19
16
|
}): {
|
|
20
17
|
name: string;
|
|
21
18
|
formattedMessageRootId: any;
|
|
@@ -23,6 +20,5 @@ export declare function buildFormFieldOptions({ config, formConfig, gqlIntrospec
|
|
|
23
20
|
startAdornment: AdornmentData;
|
|
24
21
|
endAdornment: AdornmentData;
|
|
25
22
|
imports: Imports;
|
|
26
|
-
introspectionFieldType: import("graphql").IntrospectionNamedTypeRef<import("graphql").IntrospectionOutputType> | import("graphql").IntrospectionListTypeRef<import("graphql").IntrospectionOutputTypeRef> | undefined;
|
|
27
23
|
};
|
|
28
24
|
export {};
|
|
@@ -51,22 +51,13 @@ const buildAdornmentData = ({ adornmentData }) => {
|
|
|
51
51
|
/**
|
|
52
52
|
* Helper function that builds various options needed for generating form fields.
|
|
53
53
|
*/
|
|
54
|
-
function buildFormFieldOptions({ config, formConfig,
|
|
54
|
+
function buildFormFieldOptions({ config, formConfig, }) {
|
|
55
55
|
var _a;
|
|
56
56
|
const rootGqlType = formConfig.gqlType;
|
|
57
57
|
const name = String(config.name);
|
|
58
58
|
const label = (_a = config.label) !== null && _a !== void 0 ? _a : (0, camelCaseToHumanReadable_1.camelCaseToHumanReadable)(name);
|
|
59
59
|
const formattedMessageRootId = rootGqlType[0].toLowerCase() + rootGqlType.substring(1);
|
|
60
60
|
const fieldLabel = `<FormattedMessage id="${formattedMessageRootId}.${name}" defaultMessage="${label}" />`;
|
|
61
|
-
const introspectionObject = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === gqlType);
|
|
62
|
-
if (!introspectionObject)
|
|
63
|
-
throw new Error(`didn't find object ${gqlType} in gql introspection`);
|
|
64
|
-
const introspectionField = introspectionObject.fields.find((field) => field.name === name);
|
|
65
|
-
const introspectionFieldType = introspectionField
|
|
66
|
-
? introspectionField.type.kind === "NON_NULL"
|
|
67
|
-
? introspectionField.type.ofType
|
|
68
|
-
: introspectionField.type
|
|
69
|
-
: undefined;
|
|
70
61
|
const imports = [];
|
|
71
62
|
let startAdornment = { adornmentString: "" };
|
|
72
63
|
let endAdornment = { adornmentString: "" };
|
|
@@ -86,5 +77,5 @@ function buildFormFieldOptions({ config, formConfig, gqlIntrospection, gqlType,
|
|
|
86
77
|
imports.push(endAdornment.adornmentImport);
|
|
87
78
|
}
|
|
88
79
|
}
|
|
89
|
-
return { name, formattedMessageRootId, fieldLabel, startAdornment, endAdornment, imports
|
|
80
|
+
return { name, formattedMessageRootId, fieldLabel, startAdornment, endAdornment, imports };
|
|
90
81
|
}
|
|
@@ -6,14 +6,19 @@ export type GenerateFieldsReturn = GeneratorReturn & {
|
|
|
6
6
|
imports: Imports;
|
|
7
7
|
hooksCode: string;
|
|
8
8
|
formFragmentFields: string[];
|
|
9
|
-
formValueToGqlInputCode: string;
|
|
10
9
|
formProps: Prop[];
|
|
11
10
|
formValuesConfig: {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
fieldName: string;
|
|
12
|
+
omitFromFragmentType?: boolean;
|
|
13
|
+
destructFromFormValues?: boolean;
|
|
14
|
+
typeCode?: {
|
|
15
|
+
nullable: boolean;
|
|
16
|
+
type: string;
|
|
17
|
+
};
|
|
15
18
|
initializationCode?: string;
|
|
16
19
|
defaultInitializationCode?: string;
|
|
20
|
+
formValueToGqlInputCode?: string;
|
|
21
|
+
wrapFormValueToGqlInputCode?: string;
|
|
17
22
|
}[];
|
|
18
23
|
finalFormConfig?: {
|
|
19
24
|
subscription?: {
|
|
@@ -22,7 +22,6 @@ function findFieldByName(name, fields) {
|
|
|
22
22
|
function generateFields({ gqlIntrospection, baseOutputFilename, fields, formFragmentName, formConfig, gqlType, namePrefix, }) {
|
|
23
23
|
const gqlDocuments = {};
|
|
24
24
|
let hooksCode = "";
|
|
25
|
-
let formValueToGqlInputCode = "";
|
|
26
25
|
const formFragmentFields = [];
|
|
27
26
|
const imports = [];
|
|
28
27
|
const formProps = [];
|
|
@@ -68,7 +67,6 @@ function generateFields({ gqlIntrospection, baseOutputFilename, fields, formFrag
|
|
|
68
67
|
imports.push(...generated.imports);
|
|
69
68
|
formProps.push(...generated.formProps);
|
|
70
69
|
hooksCode += generated.hooksCode;
|
|
71
|
-
formValueToGqlInputCode += generated.formValueToGqlInputCode;
|
|
72
70
|
formFragmentFields.push(...generated.formFragmentFields);
|
|
73
71
|
formValuesConfig.push(...generated.formValuesConfig);
|
|
74
72
|
finalFormConfig.subscription = Object.assign(Object.assign({}, finalFormConfig.subscription), (_a = generated.finalFormConfig) === null || _a === void 0 ? void 0 : _a.subscription);
|
|
@@ -79,7 +77,6 @@ function generateFields({ gqlIntrospection, baseOutputFilename, fields, formFrag
|
|
|
79
77
|
return {
|
|
80
78
|
code,
|
|
81
79
|
hooksCode,
|
|
82
|
-
formValueToGqlInputCode,
|
|
83
80
|
formFragmentFields,
|
|
84
81
|
gqlDocuments,
|
|
85
82
|
imports,
|
|
@@ -288,7 +288,7 @@ config) {
|
|
|
288
288
|
|
|
289
289
|
${customFilterByFragment}
|
|
290
290
|
|
|
291
|
-
${(0, generateFormValues_1.generateFormValuesType)({
|
|
291
|
+
${(0, generateFormValues_1.generateFormValuesType)({ formValuesConfig, filterByFragmentType, gqlIntrospection, gqlType })}
|
|
292
292
|
|
|
293
293
|
${formPropsTypeCode}
|
|
294
294
|
|
|
@@ -308,7 +308,7 @@ config) {
|
|
|
308
308
|
`
|
|
309
309
|
: ""}
|
|
310
310
|
|
|
311
|
-
${(0, generateFormValues_1.generateInitialValues)({
|
|
311
|
+
${(0, generateFormValues_1.generateInitialValues)({ mode, formValuesConfig, filterByFragmentType, gqlIntrospection, gqlType })}
|
|
312
312
|
|
|
313
313
|
|
|
314
314
|
${editMode
|
|
@@ -326,9 +326,13 @@ config) {
|
|
|
326
326
|
`
|
|
327
327
|
: ""}
|
|
328
328
|
|
|
329
|
-
const handleSubmit = async (${(0, generateFormValues_1.generateDestructFormValueForInput)({
|
|
329
|
+
const handleSubmit = async (${(0, generateFormValues_1.generateDestructFormValueForInput)({
|
|
330
|
+
formValuesConfig,
|
|
331
|
+
gqlIntrospection,
|
|
332
|
+
gqlType,
|
|
333
|
+
})}: FormValues, form: FormApi<FormValues>${addMode ? `, event: FinalFormSubmitEvent` : ""}) => {
|
|
330
334
|
${editMode ? `if (await saveConflict.checkForConflicts()) throw new Error("Conflicts detected");` : ""}
|
|
331
|
-
${(0, generateFormValues_1.generateFormValuesToGqlInput)({
|
|
335
|
+
${(0, generateFormValues_1.generateFormValuesToGqlInput)({ formValuesConfig, gqlIntrospection, gqlType })}
|
|
332
336
|
|
|
333
337
|
${mode == "all" ? `if (mode === "edit") {` : ""}
|
|
334
338
|
${editMode
|
|
@@ -6,6 +6,7 @@ const convertConfigImport_1 = require("../utils/convertConfigImport");
|
|
|
6
6
|
const isFieldOptional_1 = require("../utils/isFieldOptional");
|
|
7
7
|
const runtimeTypeGuards_1 = require("../utils/runtimeTypeGuards");
|
|
8
8
|
const generateAsyncSelect_1 = require("./asyncSelect/generateAsyncSelect");
|
|
9
|
+
const findIntrospectionFieldType_1 = require("./formField/findIntrospectionFieldType");
|
|
9
10
|
const options_1 = require("./formField/options");
|
|
10
11
|
function generateFormField({ gqlIntrospection, baseOutputFilename, config, formConfig, gqlType, namePrefix, }) {
|
|
11
12
|
if (config.type == "asyncSelect" || config.type == "asyncSelectFilter") {
|
|
@@ -13,9 +14,9 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
13
14
|
}
|
|
14
15
|
const imports = [];
|
|
15
16
|
const formProps = [];
|
|
16
|
-
const { name, formattedMessageRootId, fieldLabel, startAdornment, endAdornment, imports: optionsImports, } = (0, options_1.buildFormFieldOptions)({ config, formConfig
|
|
17
|
+
const { name, formattedMessageRootId, fieldLabel, startAdornment, endAdornment, imports: optionsImports, } = (0, options_1.buildFormFieldOptions)({ config, formConfig });
|
|
17
18
|
imports.push(...optionsImports);
|
|
18
|
-
let
|
|
19
|
+
let introspectionFieldType = (0, findIntrospectionFieldType_1.findIntrospectionFieldType)({ name, gqlIntrospection, gqlType });
|
|
19
20
|
const nameWithPrefix = `${namePrefix ? `${namePrefix}.` : ``}${name}`;
|
|
20
21
|
const rootGqlType = formConfig.gqlType;
|
|
21
22
|
const dataRootName = rootGqlType[0].toLowerCase() + rootGqlType.substring(1); // TODO should probably be deteced via query
|
|
@@ -24,7 +25,9 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
24
25
|
const endAdornmentWithLockIconProp = `endAdornment={<InputAdornment position="end"><Lock /></InputAdornment>}`;
|
|
25
26
|
const readOnlyProps = `readOnly disabled`;
|
|
26
27
|
const readOnlyPropsWithLock = `${readOnlyProps} ${endAdornmentWithLockIconProp}`;
|
|
27
|
-
|
|
28
|
+
const formValueConfig = {
|
|
29
|
+
fieldName: nameWithPrefix,
|
|
30
|
+
};
|
|
28
31
|
const gqlDocuments = {};
|
|
29
32
|
const hooksCode = "";
|
|
30
33
|
let finalFormConfig;
|
|
@@ -40,7 +43,6 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
45
|
let code = "";
|
|
43
|
-
let formValueToGqlInputCode = "";
|
|
44
46
|
let formFragmentFields = [name];
|
|
45
47
|
if (config.type == "text") {
|
|
46
48
|
const TextInputComponent = config.multiline ? "TextAreaField" : "TextField";
|
|
@@ -62,7 +64,7 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
62
64
|
${validateCode}
|
|
63
65
|
/>`;
|
|
64
66
|
if (!required && !config.readOnly) {
|
|
65
|
-
formValueToGqlInputCode = `$
|
|
67
|
+
formValueConfig.formValueToGqlInputCode = `$fieldName ?? null`;
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
else if (config.type == "number") {
|
|
@@ -85,22 +87,21 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
85
87
|
${validateCode}
|
|
86
88
|
/>`;
|
|
87
89
|
//TODO MUI suggest not using type=number https://mui.com/material-ui/react-text-field/#type-quot-number-quot
|
|
88
|
-
let assignment = `parseFloat(
|
|
90
|
+
let assignment = `parseFloat($fieldName)`;
|
|
89
91
|
if ((0, isFieldOptional_1.isFieldOptional)({ config, gqlIntrospection: gqlIntrospection, gqlType: gqlType })) {
|
|
90
|
-
assignment =
|
|
92
|
+
assignment = `$fieldName ? ${assignment} : null`;
|
|
91
93
|
}
|
|
92
|
-
formValueToGqlInputCode = `${
|
|
94
|
+
formValueConfig.formValueToGqlInputCode = `${assignment}`;
|
|
93
95
|
let initializationAssignment = `String(data.${dataRootName}.${nameWithPrefix})`;
|
|
94
96
|
if (!required) {
|
|
95
97
|
initializationAssignment = `data.${dataRootName}.${nameWithPrefix} ? ${initializationAssignment} : undefined`;
|
|
96
98
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
];
|
|
99
|
+
formValueConfig.omitFromFragmentType = true;
|
|
100
|
+
formValueConfig.typeCode = {
|
|
101
|
+
nullable: !required,
|
|
102
|
+
type: "string",
|
|
103
|
+
};
|
|
104
|
+
formValueConfig.initializationCode = `${initializationAssignment}`;
|
|
104
105
|
}
|
|
105
106
|
else if (config.type === "numberRange") {
|
|
106
107
|
code = `
|
|
@@ -140,11 +141,7 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
140
141
|
: ""}
|
|
141
142
|
${validateCode}
|
|
142
143
|
/>`;
|
|
143
|
-
|
|
144
|
-
{
|
|
145
|
-
defaultInitializationCode: `${name}: false`,
|
|
146
|
-
},
|
|
147
|
-
];
|
|
144
|
+
formValueConfig.defaultInitializationCode = `false`;
|
|
148
145
|
}
|
|
149
146
|
else if (config.type == "date") {
|
|
150
147
|
imports.push({
|
|
@@ -169,7 +166,7 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
169
166
|
${validateCode}
|
|
170
167
|
/>`;
|
|
171
168
|
if (!required && !config.readOnly) {
|
|
172
|
-
formValueToGqlInputCode = `$
|
|
169
|
+
formValueConfig.formValueToGqlInputCode = `$fieldName ?? null`;
|
|
173
170
|
}
|
|
174
171
|
}
|
|
175
172
|
else if (config.type == "dateTime") {
|
|
@@ -193,31 +190,25 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
193
190
|
: ""}
|
|
194
191
|
${validateCode}
|
|
195
192
|
/>`;
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
];
|
|
193
|
+
formValueConfig.initializationCode = `data.${dataRootName}.${nameWithPrefix} ? new Date(data.${dataRootName}.${nameWithPrefix}) : undefined`;
|
|
194
|
+
formValueConfig.omitFromFragmentType = true;
|
|
195
|
+
formValueConfig.typeCode = {
|
|
196
|
+
nullable: !required,
|
|
197
|
+
type: `Date${!required ? " | null" : ""}`,
|
|
198
|
+
};
|
|
203
199
|
if (!config.readOnly) {
|
|
204
|
-
formValueToGqlInputCode = required
|
|
205
|
-
? `${name}: formValues.${name}.toISOString(),`
|
|
206
|
-
: `${name}: formValues.${name} ? formValues.${name}.toISOString() : null,`;
|
|
200
|
+
formValueConfig.formValueToGqlInputCode = required ? `$fieldName.toISOString()` : `$fieldName ? $fieldName.toISOString() : null`;
|
|
207
201
|
}
|
|
208
202
|
}
|
|
209
203
|
else if (config.type == "block") {
|
|
210
204
|
code = `<Field name="${nameWithPrefix}" isEqual={isEqual} label={${fieldLabel}} variant="horizontal" fullWidth>
|
|
211
205
|
{createFinalFormBlock(rootBlocks.${String(config.name)})}
|
|
212
206
|
</Field>`;
|
|
213
|
-
formValueToGqlInputCode =
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
defaultInitializationCode: `${name}: rootBlocks.${name}.defaultValues()`,
|
|
219
|
-
},
|
|
220
|
-
];
|
|
207
|
+
formValueConfig.formValueToGqlInputCode = `rootBlocks.${name}.state2Output($fieldName)`;
|
|
208
|
+
formValueConfig.omitFromFragmentType = true;
|
|
209
|
+
formValueConfig.typeCode = { nullable: false, type: `BlockState<typeof rootBlocks.${name}>` };
|
|
210
|
+
formValueConfig.initializationCode = `rootBlocks.${name}.input2State(data.${dataRootName}.${nameWithPrefix})`;
|
|
211
|
+
formValueConfig.defaultInitializationCode = `rootBlocks.${name}.defaultValues()`;
|
|
221
212
|
}
|
|
222
213
|
else if (config.type === "fileUpload") {
|
|
223
214
|
const multiple = config.multiple || (typeof config.maxFiles === "number" && config.maxFiles > 1);
|
|
@@ -231,10 +222,10 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
231
222
|
${config.accept ? `accept="${config.accept}"` : ""}
|
|
232
223
|
/>`;
|
|
233
224
|
if (multiple) {
|
|
234
|
-
formValueToGqlInputCode = `$
|
|
225
|
+
formValueConfig.formValueToGqlInputCode = `$fieldName?.map(({ id }) => id)`;
|
|
235
226
|
}
|
|
236
227
|
else {
|
|
237
|
-
formValueToGqlInputCode = `$
|
|
228
|
+
formValueConfig.formValueToGqlInputCode = `$fieldName ? $fieldName.id : null`;
|
|
238
229
|
}
|
|
239
230
|
formFragmentFields = [`${name}...${config.download ? "FinalFormFileUploadDownloadable" : "FinalFormFileUpload"}`];
|
|
240
231
|
}
|
|
@@ -336,12 +327,11 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
|
|
|
336
327
|
return {
|
|
337
328
|
code,
|
|
338
329
|
hooksCode,
|
|
339
|
-
formValueToGqlInputCode,
|
|
340
330
|
formFragmentFields,
|
|
341
331
|
gqlDocuments,
|
|
342
332
|
imports,
|
|
343
333
|
formProps,
|
|
344
|
-
formValuesConfig,
|
|
334
|
+
formValuesConfig: [formValueConfig],
|
|
345
335
|
finalFormConfig,
|
|
346
336
|
};
|
|
347
337
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateFormLayout = generateFormLayout;
|
|
4
4
|
const camelCaseToHumanReadable_1 = require("../utils/camelCaseToHumanReadable");
|
|
5
|
+
const findIntrospectionFieldType_1 = require("./formField/findIntrospectionFieldType");
|
|
5
6
|
const generateFields_1 = require("./generateFields");
|
|
6
7
|
function generateFormLayout({ gqlIntrospection, baseOutputFilename, config, formFragmentName, formConfig, gqlType, namePrefix, }) {
|
|
7
8
|
var _a, _b, _c, _d, _e;
|
|
@@ -10,7 +11,6 @@ function generateFormLayout({ gqlIntrospection, baseOutputFilename, config, form
|
|
|
10
11
|
const dataRootName = rootGqlType[0].toLowerCase() + rootGqlType.substring(1); // TODO should probably be deteced via query
|
|
11
12
|
let code = "";
|
|
12
13
|
let hooksCode = "";
|
|
13
|
-
let formValueToGqlInputCode = "";
|
|
14
14
|
const formFragmentFields = [];
|
|
15
15
|
const gqlDocuments = {};
|
|
16
16
|
const imports = [];
|
|
@@ -29,7 +29,6 @@ function generateFormLayout({ gqlIntrospection, baseOutputFilename, config, form
|
|
|
29
29
|
namePrefix,
|
|
30
30
|
});
|
|
31
31
|
hooksCode += generatedFields.hooksCode;
|
|
32
|
-
formValueToGqlInputCode += generatedFields.formValueToGqlInputCode;
|
|
33
32
|
formFragmentFields.push(...generatedFields.formFragmentFields);
|
|
34
33
|
for (const name in generatedFields.gqlDocuments) {
|
|
35
34
|
gqlDocuments[name] = generatedFields.gqlDocuments[name];
|
|
@@ -66,16 +65,10 @@ function generateFormLayout({ gqlIntrospection, baseOutputFilename, config, form
|
|
|
66
65
|
}
|
|
67
66
|
else if (config.type === "optionalNestedFields") {
|
|
68
67
|
const name = String(config.name);
|
|
69
|
-
const
|
|
70
|
-
if (!
|
|
71
|
-
throw new Error(`
|
|
72
|
-
|
|
73
|
-
if (!introspectionField)
|
|
74
|
-
throw new Error(`didn't find field ${name} in gql introspection type ${gqlType}`);
|
|
75
|
-
if (introspectionField.type.kind === "NON_NULL") {
|
|
76
|
-
throw new Error(`field ${name} in gql introspection type ${gqlType} must not be required to be usable with optionalNestedFields`);
|
|
77
|
-
}
|
|
78
|
-
if (introspectionField.type.kind !== "OBJECT")
|
|
68
|
+
const introspectionFieldType = (0, findIntrospectionFieldType_1.findIntrospectionFieldType)({ name, gqlType, gqlIntrospection });
|
|
69
|
+
if (!introspectionFieldType)
|
|
70
|
+
throw new Error(`field ${name} in gql introspection type ${gqlType} not found`);
|
|
71
|
+
if (introspectionFieldType.kind !== "OBJECT")
|
|
79
72
|
throw new Error(`field ${name} in gql introspection type ${gqlType} has to be OBJECT`);
|
|
80
73
|
const checkboxLabel = (_e = config.checkboxLabel) !== null && _e !== void 0 ? _e : `Enable ${(0, camelCaseToHumanReadable_1.camelCaseToHumanReadable)(String(config.name))}`;
|
|
81
74
|
const generatedFields = (0, generateFields_1.generateFields)({
|
|
@@ -84,7 +77,7 @@ function generateFormLayout({ gqlIntrospection, baseOutputFilename, config, form
|
|
|
84
77
|
fields: config.fields,
|
|
85
78
|
formFragmentName,
|
|
86
79
|
formConfig,
|
|
87
|
-
gqlType:
|
|
80
|
+
gqlType: introspectionFieldType.name,
|
|
88
81
|
namePrefix: name,
|
|
89
82
|
});
|
|
90
83
|
hooksCode += generatedFields.hooksCode;
|
|
@@ -93,39 +86,26 @@ function generateFormLayout({ gqlIntrospection, baseOutputFilename, config, form
|
|
|
93
86
|
gqlDocuments[name] = generatedFields.gqlDocuments[name];
|
|
94
87
|
}
|
|
95
88
|
imports.push(...generatedFields.imports);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
.map((config) => config.initializationCode);
|
|
114
|
-
if (subfieldsFormValuesInitCode.length) {
|
|
115
|
-
wrappingFormValuesConfig.initializationCode = `${wrappingFormValuesConfig.initializationCode},
|
|
116
|
-
${name}: data.${dataRootName}.${name} ? { ${subfieldsFormValuesInitCode.join(", ")}} : undefined `;
|
|
117
|
-
}
|
|
118
|
-
const subfieldsFormValuesDefaultInitCode = generatedFields.formValuesConfig
|
|
119
|
-
.filter((config) => !!config.defaultInitializationCode)
|
|
120
|
-
.map((config) => config.defaultInitializationCode);
|
|
121
|
-
if (subfieldsFormValuesDefaultInitCode.length) {
|
|
122
|
-
wrappingFormValuesConfig.defaultInitializationCode = `${name}: { ${subfieldsFormValuesDefaultInitCode.join(", ")}}`;
|
|
123
|
-
}
|
|
124
|
-
formValuesConfig.push(wrappingFormValuesConfig);
|
|
89
|
+
formValuesConfig.push(...generatedFields.formValuesConfig);
|
|
90
|
+
// first field is the "enabled" checkbox
|
|
91
|
+
formValuesConfig.push({
|
|
92
|
+
fieldName: `${name}Enabled`,
|
|
93
|
+
omitFromFragmentType: false,
|
|
94
|
+
destructFromFormValues: true,
|
|
95
|
+
typeCode: {
|
|
96
|
+
nullable: false,
|
|
97
|
+
type: "boolean",
|
|
98
|
+
},
|
|
99
|
+
initializationCode: `!!data.${dataRootName}.${name}`,
|
|
100
|
+
});
|
|
101
|
+
// second field is the nested object, which is not a final-form field itself
|
|
102
|
+
formValuesConfig.push({
|
|
103
|
+
fieldName: `${name}`,
|
|
104
|
+
wrapFormValueToGqlInputCode: `${name.split(".").pop()}Enabled && $fieldName ? $inner : null`,
|
|
105
|
+
});
|
|
125
106
|
imports.push({ name: "FinalFormSwitch", importPath: "@comet/admin" });
|
|
126
107
|
imports.push({ name: "messages", importPath: "@comet/admin" });
|
|
127
108
|
imports.push({ name: "FormControlLabel", importPath: "@mui/material" });
|
|
128
|
-
formValueToGqlInputCode += `${String(config.name)}: ${String(config.name)}Enabled && formValues.${String(config.name)} ? {${generatedFields.formValueToGqlInputCode}} : null,`;
|
|
129
109
|
code = `<Field
|
|
130
110
|
fullWidth
|
|
131
111
|
name="${String(config.name)}Enabled"
|
|
@@ -155,7 +135,6 @@ function generateFormLayout({ gqlIntrospection, baseOutputFilename, config, form
|
|
|
155
135
|
return {
|
|
156
136
|
code,
|
|
157
137
|
hooksCode,
|
|
158
|
-
formValueToGqlInputCode,
|
|
159
138
|
formFragmentFields,
|
|
160
139
|
gqlDocuments,
|
|
161
140
|
imports,
|
|
@@ -1,18 +1,39 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type IntrospectionQuery } from "graphql";
|
|
2
2
|
import { type GenerateFieldsReturn } from "./generateFields";
|
|
3
|
-
|
|
4
|
-
config
|
|
3
|
+
type FormValuesConfigTreeNode = {
|
|
4
|
+
config?: GenerateFieldsReturn["formValuesConfig"][0];
|
|
5
|
+
nullable?: boolean;
|
|
6
|
+
children: FormValuesConfigTree;
|
|
7
|
+
};
|
|
8
|
+
type FormValuesConfigTree = {
|
|
9
|
+
[key: string]: FormValuesConfigTreeNode;
|
|
10
|
+
};
|
|
11
|
+
export declare function formValuesConfigToTree({ formValuesConfig, gqlIntrospection, gqlType, }: {
|
|
12
|
+
formValuesConfig: GenerateFieldsReturn["formValuesConfig"];
|
|
13
|
+
gqlIntrospection: IntrospectionQuery;
|
|
14
|
+
gqlType: string;
|
|
15
|
+
}): FormValuesConfigTree;
|
|
16
|
+
export declare function generateFormValuesType({ formValuesConfig, filterByFragmentType, gqlIntrospection, gqlType, }: {
|
|
5
17
|
formValuesConfig: GenerateFieldsReturn["formValuesConfig"];
|
|
6
18
|
filterByFragmentType: string;
|
|
19
|
+
gqlIntrospection: IntrospectionQuery;
|
|
20
|
+
gqlType: string;
|
|
7
21
|
}): string;
|
|
8
|
-
export declare function generateInitialValues({
|
|
9
|
-
|
|
22
|
+
export declare function generateInitialValues({ mode, formValuesConfig, filterByFragmentType, gqlIntrospection, gqlType, }: {
|
|
23
|
+
mode: "all" | "edit" | "add";
|
|
10
24
|
formValuesConfig: GenerateFieldsReturn["formValuesConfig"];
|
|
11
25
|
filterByFragmentType: string;
|
|
26
|
+
gqlIntrospection: IntrospectionQuery;
|
|
27
|
+
gqlType: string;
|
|
12
28
|
}): string;
|
|
13
|
-
export declare function generateDestructFormValueForInput({ formValuesConfig }: {
|
|
29
|
+
export declare function generateDestructFormValueForInput({ formValuesConfig, gqlIntrospection, gqlType, }: {
|
|
14
30
|
formValuesConfig: GenerateFieldsReturn["formValuesConfig"];
|
|
31
|
+
gqlIntrospection: IntrospectionQuery;
|
|
32
|
+
gqlType: string;
|
|
15
33
|
}): string;
|
|
16
|
-
export declare function generateFormValuesToGqlInput({
|
|
17
|
-
|
|
34
|
+
export declare function generateFormValuesToGqlInput({ formValuesConfig, gqlIntrospection, gqlType, }: {
|
|
35
|
+
formValuesConfig: GenerateFieldsReturn["formValuesConfig"];
|
|
36
|
+
gqlIntrospection: IntrospectionQuery;
|
|
37
|
+
gqlType: string;
|
|
18
38
|
}): string;
|
|
39
|
+
export {};
|
|
@@ -1,77 +1,217 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formValuesConfigToTree = formValuesConfigToTree;
|
|
3
4
|
exports.generateFormValuesType = generateFormValuesType;
|
|
4
5
|
exports.generateInitialValues = generateInitialValues;
|
|
5
6
|
exports.generateDestructFormValueForInput = generateDestructFormValueForInput;
|
|
6
7
|
exports.generateFormValuesToGqlInput = generateFormValuesToGqlInput;
|
|
7
|
-
|
|
8
|
-
function
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
.
|
|
29
|
-
|
|
30
|
-
|
|
8
|
+
// internal represenstation of formValuesConfig as tree to allow recursive processing
|
|
9
|
+
function formValuesConfigToTree({ formValuesConfig, gqlIntrospection, gqlType, }) {
|
|
10
|
+
const treeRoot = { children: {} };
|
|
11
|
+
for (const formValueConfig of formValuesConfig) {
|
|
12
|
+
const fieldName = formValueConfig.fieldName;
|
|
13
|
+
let currentTreeNode = treeRoot;
|
|
14
|
+
let currentGqlType = gqlType;
|
|
15
|
+
for (const part of fieldName.split(".")) {
|
|
16
|
+
const introspectionObject = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === currentGqlType);
|
|
17
|
+
if (!introspectionObject)
|
|
18
|
+
throw new Error(`didn't find object ${gqlType} in gql introspection`);
|
|
19
|
+
const introspectionField = introspectionObject.fields.find((field) => field.name === part);
|
|
20
|
+
const introspectionFieldType = introspectionField
|
|
21
|
+
? introspectionField.type.kind === "NON_NULL"
|
|
22
|
+
? introspectionField.type.ofType
|
|
23
|
+
: introspectionField.type
|
|
24
|
+
: undefined;
|
|
25
|
+
if ((introspectionFieldType === null || introspectionFieldType === void 0 ? void 0 : introspectionFieldType.kind) === "OBJECT") {
|
|
26
|
+
// for next loop iteration (nested fields)
|
|
27
|
+
currentGqlType = introspectionFieldType.name;
|
|
28
|
+
}
|
|
29
|
+
if (!currentTreeNode.children[part]) {
|
|
30
|
+
currentTreeNode.children[part] = { children: {} };
|
|
31
|
+
}
|
|
32
|
+
currentTreeNode.children[part].nullable = (introspectionField === null || introspectionField === void 0 ? void 0 : introspectionField.type.kind) !== "NON_NULL";
|
|
33
|
+
currentTreeNode = currentTreeNode.children[part];
|
|
34
|
+
}
|
|
35
|
+
currentTreeNode.config = formValueConfig;
|
|
36
|
+
}
|
|
37
|
+
return treeRoot.children;
|
|
31
38
|
}
|
|
32
|
-
function
|
|
39
|
+
function generateFormValuesTypeFromTree(tree, currentTypeName, currentIsNullable) {
|
|
40
|
+
var _a, _b, _c;
|
|
41
|
+
const omitKeys = [];
|
|
42
|
+
let appendCode = "";
|
|
43
|
+
for (const [key, value] of Object.entries(tree)) {
|
|
44
|
+
if (Object.keys(value.children).length > 0) {
|
|
45
|
+
let childRootType = `${currentTypeName}["${key}"]`;
|
|
46
|
+
if (currentIsNullable) {
|
|
47
|
+
childRootType = `NonNullable<${currentTypeName}>["${key}"]`;
|
|
48
|
+
}
|
|
49
|
+
const childOmit = generateFormValuesTypeFromTree(value.children, childRootType, (_a = value.nullable) !== null && _a !== void 0 ? _a : false);
|
|
50
|
+
if (childOmit !== childRootType) {
|
|
51
|
+
appendCode += `${key}: ${childOmit}`;
|
|
52
|
+
omitKeys.push(key);
|
|
53
|
+
}
|
|
54
|
+
if ((_b = value.config) === null || _b === void 0 ? void 0 : _b.typeCode) {
|
|
55
|
+
throw new Error("Field has both subfields and direct typeCode, which is not supported.");
|
|
56
|
+
}
|
|
57
|
+
if ((_c = value.config) === null || _c === void 0 ? void 0 : _c.omitFromFragmentType) {
|
|
58
|
+
throw new Error("Field has both subfields and direct omitFromFragmentType, which is not supported.");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (value.config) {
|
|
62
|
+
if (value.config.typeCode) {
|
|
63
|
+
appendCode += `${key}${value.config.typeCode.nullable ? "?" : ""}: ${value.config.typeCode.type}; `;
|
|
64
|
+
}
|
|
65
|
+
if (value.config.omitFromFragmentType) {
|
|
66
|
+
omitKeys.push(key);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
let code = omitKeys.length
|
|
71
|
+
? `Omit<${currentIsNullable ? `NonNullable<` : ""}${currentTypeName}${currentIsNullable ? `>` : ""}, ${omitKeys.map((k) => `"${k}"`).join(" | ")}>`
|
|
72
|
+
: currentTypeName;
|
|
73
|
+
if (appendCode.length) {
|
|
74
|
+
code += ` & { ${appendCode} }`;
|
|
75
|
+
}
|
|
76
|
+
return code;
|
|
77
|
+
}
|
|
78
|
+
function generateFormValuesType({ formValuesConfig, filterByFragmentType, gqlIntrospection, gqlType, }) {
|
|
79
|
+
const tree = formValuesConfigToTree({ formValuesConfig, gqlIntrospection, gqlType });
|
|
80
|
+
return `type FormValues = ${generateFormValuesTypeFromTree(tree, filterByFragmentType, false)};`;
|
|
81
|
+
}
|
|
82
|
+
function generateInitialValuesFromTree(tree, dataObject, generationType) {
|
|
33
83
|
var _a;
|
|
34
|
-
|
|
84
|
+
let code = "";
|
|
85
|
+
for (const [key, value] of Object.entries(tree)) {
|
|
86
|
+
if (Object.keys(value.children).length > 0) {
|
|
87
|
+
let childCode = generateInitialValuesFromTree(value.children, `${dataObject}.${key}`, generationType);
|
|
88
|
+
if (childCode.length) {
|
|
89
|
+
if (generationType == "initializationCode") {
|
|
90
|
+
childCode = `{ ...${dataObject}.${key}, ${childCode} }`;
|
|
91
|
+
if (value.nullable) {
|
|
92
|
+
code += `${key}: ${dataObject}.${key} ? ${childCode} : undefined, `;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
code += `${key}: ${childCode}, `;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
code += `${key}: { ${childCode} }, `;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if ((_a = value.config) === null || _a === void 0 ? void 0 : _a[generationType]) {
|
|
103
|
+
throw new Error("Field has both subfields and direct initialization code, which is not supported.");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (value.config) {
|
|
107
|
+
if (value.config[generationType]) {
|
|
108
|
+
code += `${key}: ${value.config[generationType]}, `;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return code;
|
|
113
|
+
}
|
|
114
|
+
function generateInitialValues({ mode, formValuesConfig, filterByFragmentType, gqlIntrospection, gqlType, }) {
|
|
35
115
|
const instanceGqlType = gqlType[0].toLowerCase() + gqlType.substring(1);
|
|
36
|
-
const mode = (_a = config.mode) !== null && _a !== void 0 ? _a : "all";
|
|
37
116
|
const editMode = mode === "edit" || mode == "all";
|
|
117
|
+
const tree = formValuesConfigToTree({ formValuesConfig, gqlIntrospection, gqlType });
|
|
38
118
|
if (editMode) {
|
|
39
119
|
return `const initialValues = useMemo<Partial<FormValues>>(() => data?.${instanceGqlType}
|
|
40
120
|
? {
|
|
41
121
|
...filterByFragment<${filterByFragmentType}>(${instanceGqlType}FormFragment, data.${instanceGqlType}),
|
|
42
|
-
${
|
|
43
|
-
.filter((config) => !!config.initializationCode)
|
|
44
|
-
.map((config) => config.initializationCode)
|
|
45
|
-
.join(",\n")}
|
|
122
|
+
${generateInitialValuesFromTree(tree, `data.${instanceGqlType}`, "initializationCode")}
|
|
46
123
|
}
|
|
47
124
|
: {
|
|
48
|
-
${
|
|
49
|
-
.filter((config) => !!config.defaultInitializationCode)
|
|
50
|
-
.map((config) => config.defaultInitializationCode)
|
|
51
|
-
.join(",\n")}
|
|
125
|
+
${generateInitialValuesFromTree(tree, `data.${instanceGqlType}`, "defaultInitializationCode")}
|
|
52
126
|
}
|
|
53
127
|
, [data]);`;
|
|
54
128
|
}
|
|
55
129
|
else {
|
|
56
130
|
return `const initialValues = {
|
|
57
|
-
${
|
|
58
|
-
.filter((config) => !!config.defaultInitializationCode)
|
|
59
|
-
.map((config) => config.defaultInitializationCode)
|
|
60
|
-
.join(",\n")}
|
|
131
|
+
${generateInitialValuesFromTree(tree, `data.${instanceGqlType}`, "defaultInitializationCode")}
|
|
61
132
|
};`;
|
|
62
133
|
}
|
|
63
134
|
}
|
|
64
|
-
function
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
.
|
|
69
|
-
.
|
|
70
|
-
|
|
135
|
+
function generateDestructFormValueForInputFromTree(tree, restObject) {
|
|
136
|
+
let code = "";
|
|
137
|
+
for (const [key, value] of Object.entries(tree)) {
|
|
138
|
+
if (Object.keys(value.children).length > 0) {
|
|
139
|
+
const childCode = generateDestructFormValueForInputFromTree(value.children, `${restObject}${key.substring(0, 1).toUpperCase()}${key.substring(1)}`);
|
|
140
|
+
if (childCode.length) {
|
|
141
|
+
code += `${key}: { ${childCode} }, `;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else if (value.config) {
|
|
145
|
+
if (value.config.destructFromFormValues) {
|
|
146
|
+
code += `${key}, `;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (code.length) {
|
|
151
|
+
code += `...${restObject}Rest`;
|
|
152
|
+
return code;
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
return "";
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function generateDestructFormValueForInput({ formValuesConfig, gqlIntrospection, gqlType, }) {
|
|
159
|
+
const tree = formValuesConfigToTree({ formValuesConfig, gqlIntrospection, gqlType });
|
|
160
|
+
const code = generateDestructFormValueForInputFromTree(tree, "formValues");
|
|
161
|
+
return code.length ? `{ ${code} }` : "formValues";
|
|
162
|
+
}
|
|
163
|
+
function generateFormValuesToGqlInputFromTree(tree, dataObject, restObject) {
|
|
164
|
+
var _a, _b;
|
|
165
|
+
let code = "";
|
|
166
|
+
for (const [key, value] of Object.entries(tree)) {
|
|
167
|
+
if (Object.keys(value.children).length > 0) {
|
|
168
|
+
const childRestObject = `${restObject.replace(/Rest$/, "")}${key.substring(0, 1).toUpperCase()}${key.substring(1)}Rest`;
|
|
169
|
+
const hasChildDestruct = hasChildDestructTree(value.children);
|
|
170
|
+
let childCode = generateFormValuesToGqlInputFromTree(value.children, hasChildDestruct ? childRestObject : `${dataObject}.${key}`, childRestObject);
|
|
171
|
+
if (childCode.length || hasChildDestruct) {
|
|
172
|
+
childCode = `{ ...${hasChildDestruct ? childRestObject : `${dataObject}.${key}`}, ${childCode} }`;
|
|
173
|
+
if ((_a = value.config) === null || _a === void 0 ? void 0 : _a.wrapFormValueToGqlInputCode) {
|
|
174
|
+
childCode = value.config.wrapFormValueToGqlInputCode
|
|
175
|
+
.replaceAll("$fieldName", `${dataObject}.${key}`)
|
|
176
|
+
.replaceAll("$inner", childCode);
|
|
177
|
+
}
|
|
178
|
+
code += `${key}: ${childCode}, `;
|
|
179
|
+
}
|
|
180
|
+
if ((_b = value.config) === null || _b === void 0 ? void 0 : _b.formValueToGqlInputCode) {
|
|
181
|
+
throw new Error("Field has both subfields and direct formValueToGqlInputCode, which is not supported.");
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else if (value.config) {
|
|
185
|
+
if (value.config.formValueToGqlInputCode) {
|
|
186
|
+
code += `${key}: ${value.config.formValueToGqlInputCode.replaceAll("$fieldName", `${dataObject}.${key}`)}, `;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return code;
|
|
191
|
+
}
|
|
192
|
+
function hasChildDestructTree(tree) {
|
|
193
|
+
return Object.values(tree).some((childValue) => {
|
|
194
|
+
var _a;
|
|
195
|
+
if ((_a = childValue.config) === null || _a === void 0 ? void 0 : _a.destructFromFormValues) {
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
if (Object.keys(childValue.children).length > 0) {
|
|
199
|
+
return hasChildDestructTree(childValue.children);
|
|
200
|
+
}
|
|
201
|
+
return false;
|
|
202
|
+
});
|
|
71
203
|
}
|
|
72
|
-
function generateFormValuesToGqlInput({
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
204
|
+
function generateFormValuesToGqlInput({ formValuesConfig, gqlIntrospection, gqlType, }) {
|
|
205
|
+
const tree = formValuesConfigToTree({ formValuesConfig, gqlIntrospection, gqlType });
|
|
206
|
+
const hasChildDestruct = hasChildDestructTree(tree);
|
|
207
|
+
const code = generateFormValuesToGqlInputFromTree(tree, hasChildDestruct ? "formValuesRest" : "formValues", hasChildDestruct ? "formValuesRest" : "formValues");
|
|
208
|
+
if (code.length) {
|
|
209
|
+
return `const output = { ...${hasChildDestruct ? "formValuesRest" : "formValues"}, ${code} };`;
|
|
210
|
+
}
|
|
211
|
+
else if (hasChildDestruct) {
|
|
212
|
+
return `const output = formValuesRest;`;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
return `const output = formValues;`;
|
|
216
|
+
}
|
|
77
217
|
}
|
|
@@ -3,10 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getForwardedGqlArgs = getForwardedGqlArgs;
|
|
4
4
|
function getForwardedGqlArgs({ fields, gqlOperation, gqlIntrospection, }) {
|
|
5
5
|
const ret = [];
|
|
6
|
-
const skipGqlInputArgFields = fields.map((field) => String(field.name));
|
|
7
6
|
getArgsIncludingInputArgSubfields(gqlOperation, gqlIntrospection).forEach((arg) => {
|
|
8
|
-
if (arg.isInputArgSubfield
|
|
9
|
-
|
|
7
|
+
if (arg.isInputArgSubfield) {
|
|
8
|
+
if (fields.some((field) => {
|
|
9
|
+
return field.name === arg.name || field.name.startsWith(`${arg.name}.`);
|
|
10
|
+
})) {
|
|
11
|
+
// there is a field (or subfield) in this form, no need to forward this arg
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
10
15
|
let prop;
|
|
11
16
|
const imports = [];
|
|
12
17
|
if (arg.type === "ID" || arg.type === "String" || arg.type === "DateTime") {
|
|
@@ -2,8 +2,13 @@ type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
|
2
2
|
type GqlLeaves<T, FollowArrays extends boolean = false, Depth extends number = 5> = [Depth] extends [never] ? never : T extends any ? T extends Array<infer ArrayType> ? FollowArrays extends true ? GqlLeaves<ArrayType, FollowArrays, Prev[Depth]> : never : "__typename" extends keyof T ? {
|
|
3
3
|
[K in keyof T as K extends "__typename" ? never : K]-?: GqlLeaves<T[K], FollowArrays, Prev[Depth]>;
|
|
4
4
|
} : never : never;
|
|
5
|
+
type IfExplicitAny<T, Y, N> = T extends never ? Y : N;
|
|
5
6
|
type FieldNames<T> = {
|
|
6
7
|
[K in keyof T]: `${Exclude<K, symbol>}${FieldNames<T[K]> extends never ? "" : `.${FieldNames<T[K]>}`}`;
|
|
7
8
|
}[keyof T];
|
|
8
|
-
export type UsableFields<T, FollowArrays extends boolean = false> = FieldNames<GqlLeaves<T, FollowArrays
|
|
9
|
+
export type UsableFields<T, FollowArrays extends boolean = false> = IfExplicitAny<T, any, FieldNames<GqlLeaves<T, FollowArrays>>>;
|
|
10
|
+
type FormFieldNames<T> = {
|
|
11
|
+
[K in keyof T]: `${Exclude<K, symbol>}` | (FormFieldNames<T[K]> extends never ? never : `${Exclude<K, symbol>}.${FormFieldNames<T[K]>}`);
|
|
12
|
+
}[keyof T];
|
|
13
|
+
export type UsableFormFields<T> = IfExplicitAny<T, any, FormFieldNames<GqlLeaves<T, false>>>;
|
|
9
14
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@comet/admin-generator",
|
|
3
|
-
"version": "8.7.0-canary-
|
|
3
|
+
"version": "8.7.0-canary-20251113072631",
|
|
4
4
|
"description": "Comet Admin Generator CLI tool",
|
|
5
5
|
"repository": {
|
|
6
6
|
"directory": "packages/admin/admin-generator",
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
"rimraf": "^6.0.1",
|
|
48
48
|
"ts-jest": "^29.4.0",
|
|
49
49
|
"typescript": "5.8.3",
|
|
50
|
-
"@comet/admin": "8.7.0-canary-
|
|
51
|
-
"@comet/admin-icons": "8.7.0-canary-
|
|
52
|
-
"@comet/cms-admin": "8.7.0-canary-
|
|
53
|
-
"@comet/eslint-config": "8.7.0-canary-
|
|
50
|
+
"@comet/admin": "8.7.0-canary-20251113072631",
|
|
51
|
+
"@comet/admin-icons": "8.7.0-canary-20251113072631",
|
|
52
|
+
"@comet/cms-admin": "8.7.0-canary-20251113072631",
|
|
53
|
+
"@comet/eslint-config": "8.7.0-canary-20251113072631"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
56
56
|
"node": ">=22.0.0"
|