@comet/admin-generator 8.0.0-beta.0
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/LICENSE +24 -0
- package/bin/admin-generator.js +5 -0
- package/lib/adminGenerator.d.ts +1 -0
- package/lib/adminGenerator.js +8 -0
- package/lib/commands/generate/generate-command.d.ts +197 -0
- package/lib/commands/generate/generate-command.js +114 -0
- package/lib/commands/generate/generateForm/generateComponentFormField.d.ts +5 -0
- package/lib/commands/generate/generateForm/generateComponentFormField.js +18 -0
- package/lib/commands/generate/generateForm/generateFields.d.ts +35 -0
- package/lib/commands/generate/generateForm/generateFields.js +88 -0
- package/lib/commands/generate/generateForm/generateForm.d.ts +13 -0
- package/lib/commands/generate/generateForm/generateForm.js +468 -0
- package/lib/commands/generate/generateForm/generateFormField.d.ts +12 -0
- package/lib/commands/generate/generateForm/generateFormField.js +525 -0
- package/lib/commands/generate/generateForm/generateFormLayout.d.ts +12 -0
- package/lib/commands/generate/generateForm/generateFormLayout.js +164 -0
- package/lib/commands/generate/generateForm/getForwardedGqlArgs.d.ts +19 -0
- package/lib/commands/generate/generateForm/getForwardedGqlArgs.js +79 -0
- package/lib/commands/generate/generateGrid/combinationColumn.d.ts +43 -0
- package/lib/commands/generate/generateGrid/combinationColumn.js +151 -0
- package/lib/commands/generate/generateGrid/findInputObjectType.d.ts +2 -0
- package/lib/commands/generate/generateGrid/findInputObjectType.js +16 -0
- package/lib/commands/generate/generateGrid/generateGqlFieldList.d.ts +5 -0
- package/lib/commands/generate/generateGrid/generateGqlFieldList.js +43 -0
- package/lib/commands/generate/generateGrid/generateGrid.d.ts +14 -0
- package/lib/commands/generate/generateGrid/generateGrid.js +827 -0
- package/lib/commands/generate/generateGrid/generateGridToolbar.d.ts +14 -0
- package/lib/commands/generate/generateGrid/generateGridToolbar.js +92 -0
- package/lib/commands/generate/generateGrid/getForwardedGqlArgs.d.ts +14 -0
- package/lib/commands/generate/generateGrid/getForwardedGqlArgs.js +64 -0
- package/lib/commands/generate/generateGrid/getPropsForFilterProp.d.ts +12 -0
- package/lib/commands/generate/generateGrid/getPropsForFilterProp.js +14 -0
- package/lib/commands/generate/generateGrid/usableFields.d.ts +8 -0
- package/lib/commands/generate/generateGrid/usableFields.js +2 -0
- package/lib/commands/generate/utils/camelCaseToHumanReadable.d.ts +1 -0
- package/lib/commands/generate/utils/camelCaseToHumanReadable.js +8 -0
- package/lib/commands/generate/utils/columnVisibility.d.ts +6 -0
- package/lib/commands/generate/utils/columnVisibility.js +2 -0
- package/lib/commands/generate/utils/findMutationType.d.ts +3 -0
- package/lib/commands/generate/utils/findMutationType.js +19 -0
- package/lib/commands/generate/utils/findQueryType.d.ts +2 -0
- package/lib/commands/generate/utils/findQueryType.js +19 -0
- package/lib/commands/generate/utils/findRootBlocks.d.ts +8 -0
- package/lib/commands/generate/utils/findRootBlocks.js +67 -0
- package/lib/commands/generate/utils/generateImportsCode.d.ts +5 -0
- package/lib/commands/generate/utils/generateImportsCode.js +27 -0
- package/lib/commands/generate/utils/intl.d.ts +1 -0
- package/lib/commands/generate/utils/intl.js +7 -0
- package/lib/commands/generate/utils/isFieldOptional.d.ts +7 -0
- package/lib/commands/generate/utils/isFieldOptional.js +21 -0
- package/lib/commands/generate/utils/writeGenerated.d.ts +1 -0
- package/lib/commands/generate/utils/writeGenerated.js +57 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -0
- package/package.json +67 -0
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.generateFormField = void 0;
|
|
15
|
+
const generate_command_1 = require("../generate-command");
|
|
16
|
+
const camelCaseToHumanReadable_1 = require("../utils/camelCaseToHumanReadable");
|
|
17
|
+
const findQueryType_1 = require("../utils/findQueryType");
|
|
18
|
+
const isFieldOptional_1 = require("../utils/isFieldOptional");
|
|
19
|
+
const generateFields_1 = require("./generateFields");
|
|
20
|
+
const getAdornmentData = ({ adornmentData }) => {
|
|
21
|
+
let adornmentString = "";
|
|
22
|
+
let adornmentImport = { name: "", importPath: "" };
|
|
23
|
+
if (typeof adornmentData === "string") {
|
|
24
|
+
return { adornmentString: adornmentData };
|
|
25
|
+
}
|
|
26
|
+
if (typeof adornmentData.icon === "string") {
|
|
27
|
+
adornmentString = `<${adornmentData.icon}Icon />`;
|
|
28
|
+
adornmentImport = {
|
|
29
|
+
name: `${adornmentData.icon} as ${adornmentData.icon}Icon`,
|
|
30
|
+
importPath: "@comet/admin-icons",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
else if (typeof adornmentData.icon === "object") {
|
|
34
|
+
if ("import" in adornmentData.icon) {
|
|
35
|
+
adornmentString = `<${adornmentData.icon.name} />`;
|
|
36
|
+
adornmentImport = {
|
|
37
|
+
name: `${adornmentData.icon.name}`,
|
|
38
|
+
importPath: `${adornmentData.icon.import}`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const _a = adornmentData.icon, { name } = _a, iconProps = __rest(_a, ["name"]);
|
|
43
|
+
adornmentString = `<${name}Icon
|
|
44
|
+
${Object.entries(iconProps)
|
|
45
|
+
.map(([key, value]) => `${key}="${value}"`)
|
|
46
|
+
.join("\n")}
|
|
47
|
+
/>`;
|
|
48
|
+
adornmentImport = {
|
|
49
|
+
name: `${adornmentData.icon.name} as ${adornmentData.icon.name}Icon`,
|
|
50
|
+
importPath: "@comet/admin-icons",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { adornmentString, adornmentImport };
|
|
55
|
+
};
|
|
56
|
+
function getTypeInfo(arg, gqlIntrospection) {
|
|
57
|
+
let typeKind = undefined;
|
|
58
|
+
let typeClass = "unknown";
|
|
59
|
+
let required = false;
|
|
60
|
+
let type = arg.type;
|
|
61
|
+
if (type.kind === "NON_NULL") {
|
|
62
|
+
required = true;
|
|
63
|
+
type = type.ofType;
|
|
64
|
+
}
|
|
65
|
+
if (type.kind === "INPUT_OBJECT") {
|
|
66
|
+
typeClass = type.name;
|
|
67
|
+
typeKind = type.kind;
|
|
68
|
+
}
|
|
69
|
+
else if (type.kind === "ENUM") {
|
|
70
|
+
typeClass = type.name;
|
|
71
|
+
typeKind = type.kind;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
throw new Error(`Resolving kind ${type.kind} currently not supported.`);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
required,
|
|
78
|
+
typeKind,
|
|
79
|
+
typeClass,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function generateFormField({ gqlIntrospection, baseOutputFilename, config, formConfig, gqlType, namePrefix, }) {
|
|
83
|
+
var _a, _b, _c;
|
|
84
|
+
const rootGqlType = formConfig.gqlType;
|
|
85
|
+
const formattedMessageRootId = rootGqlType[0].toLowerCase() + rootGqlType.substring(1);
|
|
86
|
+
const dataRootName = rootGqlType[0].toLowerCase() + rootGqlType.substring(1); // TODO should probably be deteced via query
|
|
87
|
+
const name = String(config.name);
|
|
88
|
+
const nameWithPrefix = `${namePrefix ? `${namePrefix}.` : ``}${name}`;
|
|
89
|
+
const label = (_a = config.label) !== null && _a !== void 0 ? _a : (0, camelCaseToHumanReadable_1.camelCaseToHumanReadable)(name);
|
|
90
|
+
const introspectionObject = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === gqlType);
|
|
91
|
+
if (!introspectionObject)
|
|
92
|
+
throw new Error(`didn't find object ${gqlType} in gql introspection`);
|
|
93
|
+
const introspectionField = introspectionObject.fields.find((field) => field.name === name);
|
|
94
|
+
if (!introspectionField)
|
|
95
|
+
throw new Error(`didn't find field ${name} in gql introspection type ${gqlType}`);
|
|
96
|
+
const introspectionFieldType = introspectionField.type.kind === "NON_NULL" ? introspectionField.type.ofType : introspectionField.type;
|
|
97
|
+
const required = !(0, isFieldOptional_1.isFieldOptional)({ config, gqlIntrospection, gqlType });
|
|
98
|
+
//TODO verify introspectionField.type is compatbile with config.type
|
|
99
|
+
const endAdornmentWithLockIconProp = `endAdornment={<InputAdornment position="end"><Lock /></InputAdornment>}`;
|
|
100
|
+
const readOnlyProps = `readOnly disabled`;
|
|
101
|
+
const readOnlyPropsWithLock = `${readOnlyProps} ${endAdornmentWithLockIconProp}`;
|
|
102
|
+
const imports = [];
|
|
103
|
+
const defaultFormValuesConfig = {
|
|
104
|
+
destructFromFormValues: config.virtual ? name : undefined,
|
|
105
|
+
};
|
|
106
|
+
let formValuesConfig = [defaultFormValuesConfig]; // FormFields should only contain one entry
|
|
107
|
+
const gqlDocuments = {};
|
|
108
|
+
const hooksCode = "";
|
|
109
|
+
let finalFormConfig;
|
|
110
|
+
let validateCode = "";
|
|
111
|
+
if (config.validate) {
|
|
112
|
+
let importPath = config.validate.import;
|
|
113
|
+
if (importPath.startsWith("./")) {
|
|
114
|
+
//go one level up as generated files are in generated subfolder
|
|
115
|
+
importPath = `.${importPath}`;
|
|
116
|
+
}
|
|
117
|
+
imports.push({
|
|
118
|
+
name: config.validate.name,
|
|
119
|
+
importPath,
|
|
120
|
+
});
|
|
121
|
+
validateCode = `validate={${config.validate.name}}`;
|
|
122
|
+
}
|
|
123
|
+
const fieldLabel = `<FormattedMessage id="${formattedMessageRootId}.${name}" defaultMessage="${label}" />`;
|
|
124
|
+
let startAdornment = { adornmentString: "" };
|
|
125
|
+
let endAdornment = { adornmentString: "" };
|
|
126
|
+
if ("startAdornment" in config && config.startAdornment) {
|
|
127
|
+
startAdornment = getAdornmentData({
|
|
128
|
+
adornmentData: config.startAdornment,
|
|
129
|
+
});
|
|
130
|
+
if (startAdornment.adornmentImport) {
|
|
131
|
+
imports.push(startAdornment.adornmentImport);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if ("endAdornment" in config && config.endAdornment) {
|
|
135
|
+
endAdornment = getAdornmentData({
|
|
136
|
+
adornmentData: config.endAdornment,
|
|
137
|
+
});
|
|
138
|
+
if (endAdornment.adornmentImport) {
|
|
139
|
+
imports.push(endAdornment.adornmentImport);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
let code = "";
|
|
143
|
+
let formValueToGqlInputCode = "";
|
|
144
|
+
let formFragmentField = name;
|
|
145
|
+
if (config.type == "text") {
|
|
146
|
+
const TextInputComponent = config.multiline ? "TextAreaField" : "TextField";
|
|
147
|
+
code = `
|
|
148
|
+
<${TextInputComponent}
|
|
149
|
+
${required ? "required" : ""}
|
|
150
|
+
${config.readOnly ? readOnlyPropsWithLock : ""}
|
|
151
|
+
variant="horizontal"
|
|
152
|
+
fullWidth
|
|
153
|
+
name="${nameWithPrefix}"
|
|
154
|
+
label={${fieldLabel}}
|
|
155
|
+
${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
156
|
+
${config.endAdornment ? `endAdornment={<InputAdornment position="end">${endAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
157
|
+
${config.helperText
|
|
158
|
+
? `helperText={<FormattedMessage id=` +
|
|
159
|
+
`"${formattedMessageRootId}.${name}.helperText" ` +
|
|
160
|
+
`defaultMessage="${config.helperText}" />}`
|
|
161
|
+
: ""}
|
|
162
|
+
${validateCode}
|
|
163
|
+
/>`;
|
|
164
|
+
}
|
|
165
|
+
else if (config.type == "number") {
|
|
166
|
+
code = `
|
|
167
|
+
<Field
|
|
168
|
+
${required ? "required" : ""}
|
|
169
|
+
${config.readOnly ? readOnlyPropsWithLock : ""}
|
|
170
|
+
variant="horizontal"
|
|
171
|
+
fullWidth
|
|
172
|
+
name="${nameWithPrefix}"
|
|
173
|
+
component={FinalFormInput}
|
|
174
|
+
type="number"
|
|
175
|
+
label={${fieldLabel}}
|
|
176
|
+
${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
177
|
+
${config.endAdornment ? `endAdornment={<InputAdornment position="end">${endAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
178
|
+
${config.helperText
|
|
179
|
+
? `helperText={<FormattedMessage id=` +
|
|
180
|
+
`"${formattedMessageRootId}.${name}.helperText" ` +
|
|
181
|
+
`defaultMessage="${config.helperText}" />}`
|
|
182
|
+
: ""}
|
|
183
|
+
${validateCode}
|
|
184
|
+
/>`;
|
|
185
|
+
//TODO MUI suggest not using type=number https://mui.com/material-ui/react-text-field/#type-quot-number-quot
|
|
186
|
+
let assignment = `parseFloat(formValues.${nameWithPrefix})`;
|
|
187
|
+
if ((0, isFieldOptional_1.isFieldOptional)({ config, gqlIntrospection: gqlIntrospection, gqlType: gqlType })) {
|
|
188
|
+
assignment = `formValues.${nameWithPrefix} ? ${assignment} : null`;
|
|
189
|
+
}
|
|
190
|
+
formValueToGqlInputCode = !config.virtual ? `${name}: ${assignment},` : ``;
|
|
191
|
+
let initializationAssignment = `String(data.${dataRootName}.${nameWithPrefix})`;
|
|
192
|
+
if (!required) {
|
|
193
|
+
initializationAssignment = `data.${dataRootName}.${nameWithPrefix} ? ${initializationAssignment} : undefined`;
|
|
194
|
+
}
|
|
195
|
+
formValuesConfig = [
|
|
196
|
+
Object.assign(Object.assign({}, defaultFormValuesConfig), {
|
|
197
|
+
omitFromFragmentType: name,
|
|
198
|
+
typeCode: `${name}${!required ? `?` : ``}: string;`,
|
|
199
|
+
initializationCode: `${name}: ${initializationAssignment}`,
|
|
200
|
+
}),
|
|
201
|
+
];
|
|
202
|
+
}
|
|
203
|
+
else if (config.type === "numberRange") {
|
|
204
|
+
code = `
|
|
205
|
+
<Field
|
|
206
|
+
${required ? "required" : ""}
|
|
207
|
+
${config.readOnly ? readOnlyPropsWithLock : ""}
|
|
208
|
+
variant="horizontal"
|
|
209
|
+
fullWidth
|
|
210
|
+
name="${nameWithPrefix}"
|
|
211
|
+
component={FinalFormRangeInput}
|
|
212
|
+
label={${fieldLabel}}
|
|
213
|
+
min={${config.minValue}}
|
|
214
|
+
max={${config.maxValue}}
|
|
215
|
+
${config.disableSlider ? "disableSlider" : ""}
|
|
216
|
+
${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
217
|
+
${config.endAdornment ? `endAdornment={<InputAdornment position="end">${endAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
218
|
+
${config.helperText
|
|
219
|
+
? `helperText={<FormattedMessage id=` +
|
|
220
|
+
`"${formattedMessageRootId}.${name}.helperText" ` +
|
|
221
|
+
`defaultMessage="${config.helperText}" />}`
|
|
222
|
+
: ""}
|
|
223
|
+
${validateCode}
|
|
224
|
+
/>`;
|
|
225
|
+
formFragmentField = `${name} { min max }`;
|
|
226
|
+
}
|
|
227
|
+
else if (config.type == "boolean") {
|
|
228
|
+
code = `<CheckboxField
|
|
229
|
+
label={${fieldLabel}}
|
|
230
|
+
name="${nameWithPrefix}"
|
|
231
|
+
fullWidth
|
|
232
|
+
variant="horizontal"
|
|
233
|
+
${config.readOnly ? readOnlyProps : ""}
|
|
234
|
+
${config.helperText
|
|
235
|
+
? `helperText={<FormattedMessage id=` +
|
|
236
|
+
`"${formattedMessageRootId}.${name}.helperText" ` +
|
|
237
|
+
`defaultMessage="${config.helperText}" />}`
|
|
238
|
+
: ""}
|
|
239
|
+
${validateCode}
|
|
240
|
+
/>`;
|
|
241
|
+
formValuesConfig = [
|
|
242
|
+
Object.assign(Object.assign({}, defaultFormValuesConfig), {
|
|
243
|
+
defaultInitializationCode: `${name}: false`,
|
|
244
|
+
}),
|
|
245
|
+
];
|
|
246
|
+
}
|
|
247
|
+
else if (config.type == "date") {
|
|
248
|
+
code = `
|
|
249
|
+
<Field
|
|
250
|
+
${required ? "required" : ""}
|
|
251
|
+
${config.readOnly ? readOnlyPropsWithLock : ""}
|
|
252
|
+
variant="horizontal"
|
|
253
|
+
fullWidth
|
|
254
|
+
name="${nameWithPrefix}"
|
|
255
|
+
component={FinalFormDatePicker}
|
|
256
|
+
label={${fieldLabel}}
|
|
257
|
+
${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
258
|
+
${config.endAdornment ? `endAdornment={<InputAdornment position="end">${endAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
259
|
+
${config.helperText
|
|
260
|
+
? `helperText={<FormattedMessage id=` +
|
|
261
|
+
`"${formattedMessageRootId}.${name}.helperText" ` +
|
|
262
|
+
`defaultMessage="${config.helperText}" />}`
|
|
263
|
+
: ""}
|
|
264
|
+
${validateCode}
|
|
265
|
+
/>`;
|
|
266
|
+
formValuesConfig = [
|
|
267
|
+
Object.assign(Object.assign({}, defaultFormValuesConfig), {
|
|
268
|
+
initializationCode: `${name}: data.${dataRootName}.${nameWithPrefix} ? new Date(data.${dataRootName}.${nameWithPrefix}) : undefined`,
|
|
269
|
+
}),
|
|
270
|
+
];
|
|
271
|
+
}
|
|
272
|
+
else if (config.type == "dateTime") {
|
|
273
|
+
code = `<DateTimeField
|
|
274
|
+
${required ? "required" : ""}
|
|
275
|
+
${config.readOnly ? readOnlyPropsWithLock : ""}
|
|
276
|
+
variant="horizontal"
|
|
277
|
+
fullWidth
|
|
278
|
+
name="${nameWithPrefix}"
|
|
279
|
+
label={${fieldLabel}}
|
|
280
|
+
${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
281
|
+
${config.endAdornment ? `endAdornment={<InputAdornment position="end">${endAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
282
|
+
${config.helperText
|
|
283
|
+
? `helperText={<FormattedMessage id=` +
|
|
284
|
+
`"${formattedMessageRootId}.${name}.helperText" ` +
|
|
285
|
+
`defaultMessage="${config.helperText}" />}`
|
|
286
|
+
: ""}
|
|
287
|
+
${validateCode}
|
|
288
|
+
/>`;
|
|
289
|
+
formValuesConfig = [
|
|
290
|
+
Object.assign(Object.assign({}, defaultFormValuesConfig), {
|
|
291
|
+
initializationCode: `${name}: data.${dataRootName}.${nameWithPrefix} ? new Date(data.${dataRootName}.${nameWithPrefix}) : undefined`,
|
|
292
|
+
}),
|
|
293
|
+
];
|
|
294
|
+
}
|
|
295
|
+
else if (config.type == "block") {
|
|
296
|
+
code = `<Field name="${nameWithPrefix}" isEqual={isEqual} label={${fieldLabel}} variant="horizontal" fullWidth>
|
|
297
|
+
{createFinalFormBlock(rootBlocks.${String(config.name)})}
|
|
298
|
+
</Field>`;
|
|
299
|
+
formValueToGqlInputCode = !config.virtual ? `${name}: rootBlocks.${name}.state2Output(formValues.${nameWithPrefix}),` : ``;
|
|
300
|
+
formValuesConfig = [
|
|
301
|
+
Object.assign(Object.assign({}, defaultFormValuesConfig), {
|
|
302
|
+
typeCode: `${name}: BlockState<typeof rootBlocks.${name}>;`,
|
|
303
|
+
initializationCode: `${name}: rootBlocks.${name}.input2State(data.${dataRootName}.${nameWithPrefix})`,
|
|
304
|
+
defaultInitializationCode: `${name}: rootBlocks.${name}.defaultValues()`,
|
|
305
|
+
}),
|
|
306
|
+
];
|
|
307
|
+
}
|
|
308
|
+
else if (config.type === "fileUpload") {
|
|
309
|
+
const multiple = config.multiple || (typeof config.maxFiles === "number" && config.maxFiles > 1);
|
|
310
|
+
code = `<FileUploadField name="${name}" label={${fieldLabel}}
|
|
311
|
+
variant="horizontal"
|
|
312
|
+
${config.multiple ? "multiple" : ""}
|
|
313
|
+
${config.maxFiles ? `maxFiles={${config.maxFiles}}` : ""}
|
|
314
|
+
${config.maxFileSize ? `maxFileSize={${config.maxFileSize}}` : ""}
|
|
315
|
+
${config.readOnly ? `readOnly` : ""}
|
|
316
|
+
${config.layout ? `layout="${config.layout}"` : ""}
|
|
317
|
+
${config.accept ? `accept="${config.accept}"` : ""}
|
|
318
|
+
/>`;
|
|
319
|
+
if (multiple) {
|
|
320
|
+
formValueToGqlInputCode = `${name}: formValues.${name}?.map(({ id }) => id),`;
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
formValueToGqlInputCode = `${name}: formValues.${name} ? formValues.${name}.id : null,`;
|
|
324
|
+
}
|
|
325
|
+
formFragmentField = `${name} { ...${config.download ? "FinalFormFileUploadDownloadable" : "FinalFormFileUpload"} }`;
|
|
326
|
+
}
|
|
327
|
+
else if (config.type == "staticSelect") {
|
|
328
|
+
const enumType = gqlIntrospection.__schema.types.find((t) => t.kind === "ENUM" && t.name === introspectionFieldType.name);
|
|
329
|
+
if (!enumType)
|
|
330
|
+
throw new Error(`Enum type ${introspectionFieldType.name} not found for field ${name}`);
|
|
331
|
+
const values = (config.values ? config.values : enumType.enumValues.map((i) => i.name)).map((value) => {
|
|
332
|
+
if (typeof value === "string") {
|
|
333
|
+
return {
|
|
334
|
+
value,
|
|
335
|
+
label: (0, camelCaseToHumanReadable_1.camelCaseToHumanReadable)(value),
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
return value;
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
const renderAsRadio = config.inputType === "radio" || (required && values.length <= 5 && config.inputType !== "select");
|
|
343
|
+
if (renderAsRadio) {
|
|
344
|
+
code = `<RadioGroupField
|
|
345
|
+
${required ? "required" : ""}
|
|
346
|
+
variant="horizontal"
|
|
347
|
+
fullWidth
|
|
348
|
+
name="${nameWithPrefix}"
|
|
349
|
+
label={<FormattedMessage id="${formattedMessageRootId}.${name}" defaultMessage="${label}" />}
|
|
350
|
+
options={[
|
|
351
|
+
${values
|
|
352
|
+
.map((value) => {
|
|
353
|
+
return `{
|
|
354
|
+
label: <FormattedMessage id="${formattedMessageRootId}.${name}.${value.value.charAt(0).toLowerCase() + value.value.slice(1)}" defaultMessage="${value.label}" />,
|
|
355
|
+
value: "${value.value}",
|
|
356
|
+
}`;
|
|
357
|
+
})
|
|
358
|
+
.join(",")}
|
|
359
|
+
]}/>`;
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
code = `<Field
|
|
363
|
+
${required ? "required" : ""}
|
|
364
|
+
variant="horizontal"
|
|
365
|
+
fullWidth
|
|
366
|
+
name="${nameWithPrefix}"
|
|
367
|
+
label={${fieldLabel}}
|
|
368
|
+
${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
369
|
+
${config.helperText
|
|
370
|
+
? `helperText={<FormattedMessage id=` +
|
|
371
|
+
`"${formattedMessageRootId}.${name}.helperText" ` +
|
|
372
|
+
`defaultMessage="${config.helperText}" />}`
|
|
373
|
+
: ""}
|
|
374
|
+
${validateCode}>
|
|
375
|
+
{(props) =>
|
|
376
|
+
<FinalFormSelect ${config.readOnly ? readOnlyPropsWithLock : ""} {...props}>
|
|
377
|
+
${values
|
|
378
|
+
.map((value) => {
|
|
379
|
+
const id = `${formattedMessageRootId}.${name}.${value.value.charAt(0).toLowerCase() + value.value.slice(1)}`;
|
|
380
|
+
const label = `<FormattedMessage id="${id}" defaultMessage="${value.label}" />`;
|
|
381
|
+
return `<MenuItem value="${value.value}">${label}</MenuItem>`;
|
|
382
|
+
})
|
|
383
|
+
.join("\n")}
|
|
384
|
+
</FinalFormSelect>
|
|
385
|
+
}
|
|
386
|
+
</Field>`;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
else if (config.type == "asyncSelect") {
|
|
390
|
+
if (introspectionFieldType.kind !== "OBJECT")
|
|
391
|
+
throw new Error(`asyncSelect only supports OBJECT types`);
|
|
392
|
+
const objectType = gqlIntrospection.__schema.types.find((t) => t.kind === "OBJECT" && t.name === introspectionFieldType.name);
|
|
393
|
+
if (!objectType)
|
|
394
|
+
throw new Error(`Object type ${introspectionFieldType.name} not found for field ${name}`);
|
|
395
|
+
//find labelField: 1. as configured
|
|
396
|
+
let labelField = config.labelField;
|
|
397
|
+
//find labelField: 2. common names (name or title)
|
|
398
|
+
if (!labelField) {
|
|
399
|
+
labelField = (_b = objectType.fields.find((field) => {
|
|
400
|
+
let type = field.type;
|
|
401
|
+
if (type.kind == "NON_NULL")
|
|
402
|
+
type = type.ofType;
|
|
403
|
+
if ((field.name == "name" || field.name == "title") && type.kind == "SCALAR" && type.name == "String") {
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
})) === null || _b === void 0 ? void 0 : _b.name;
|
|
407
|
+
}
|
|
408
|
+
//find labelField: 3. first string field
|
|
409
|
+
if (!labelField) {
|
|
410
|
+
labelField = (_c = objectType.fields.find((field) => {
|
|
411
|
+
let type = field.type;
|
|
412
|
+
if (type.kind == "NON_NULL")
|
|
413
|
+
type = type.ofType;
|
|
414
|
+
if (field.type.kind == "SCALAR" && field.type.name == "String") {
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
})) === null || _c === void 0 ? void 0 : _c.name;
|
|
418
|
+
}
|
|
419
|
+
const rootQuery = config.rootQuery; //TODO we should infer a default value from the gql schema
|
|
420
|
+
const queryName = `${rootQuery[0].toUpperCase() + rootQuery.substring(1)}Select`;
|
|
421
|
+
const rootQueryType = (0, findQueryType_1.findQueryTypeOrThrow)(rootQuery, gqlIntrospection);
|
|
422
|
+
formFragmentField = `${name} { id ${labelField} }`;
|
|
423
|
+
const filterConfig = config.filterField
|
|
424
|
+
? (() => {
|
|
425
|
+
var _a, _b, _c;
|
|
426
|
+
const filterField = (0, generateFields_1.findFieldByName)(config.filterField.name, formConfig.fields);
|
|
427
|
+
if (!filterField) {
|
|
428
|
+
throw new Error(`Field ${String(config.name)}: No field with name "${(_a = config.filterField) === null || _a === void 0 ? void 0 : _a.name}" referenced as filterField found in form-config.`);
|
|
429
|
+
}
|
|
430
|
+
if (!(0, generate_command_1.isFormFieldConfig)(filterField)) {
|
|
431
|
+
throw new Error(`Field ${String(config.name)}: Field with name "${(_b = config.filterField) === null || _b === void 0 ? void 0 : _b.name}" referenced as filterField is no FormField.`);
|
|
432
|
+
}
|
|
433
|
+
const gqlName = (_c = config.filterField.gqlName) !== null && _c !== void 0 ? _c : config.filterField.name;
|
|
434
|
+
// try to find arg used to filter by checking names of root-props and filter-prop-fields
|
|
435
|
+
const rootArgForName = rootQueryType.args.find((arg) => arg.name === gqlName);
|
|
436
|
+
let filterType = rootArgForName ? getTypeInfo(rootArgForName, gqlIntrospection) : undefined;
|
|
437
|
+
let filterVarName = undefined;
|
|
438
|
+
let filterVarValue = undefined;
|
|
439
|
+
if (filterType) {
|
|
440
|
+
// there is a root-prop with same name, so the dev probably wants to filter with this prop
|
|
441
|
+
filterVarName = gqlName;
|
|
442
|
+
filterVarValue = `values.${filterField.type === "asyncSelect" ? `${String(filterField.name)}?.id` : String(filterField.name)}`;
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
// no root-prop with same name, check filter-prop-fields
|
|
446
|
+
const rootArgFilter = rootQueryType.args.find((arg) => arg.name === "filter");
|
|
447
|
+
filterType = rootArgFilter ? getTypeInfo(rootArgFilter, gqlIntrospection) : undefined;
|
|
448
|
+
if (filterType) {
|
|
449
|
+
filterVarName = "filter";
|
|
450
|
+
filterVarValue = `{ ${gqlName}: { equal: values.${filterField.type === "asyncSelect" ? `${String(filterField.name)}?.id` : String(filterField.name)} } }`;
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
throw new Error(`Neither filter-prop nor root-prop with name: ${gqlName} for asyncSelect-query not found. Consider setting filterField.gqlVarName explicitly.`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return {
|
|
457
|
+
filterField,
|
|
458
|
+
filterType,
|
|
459
|
+
filterVarName,
|
|
460
|
+
filterVarValue,
|
|
461
|
+
};
|
|
462
|
+
})()
|
|
463
|
+
: undefined;
|
|
464
|
+
if (filterConfig) {
|
|
465
|
+
imports.push({ name: "OnChangeField", importPath: "@comet/admin" });
|
|
466
|
+
finalFormConfig = { subscription: { values: true }, renderProps: { values: true, form: true } };
|
|
467
|
+
}
|
|
468
|
+
formValueToGqlInputCode = !config.virtual ? `${name}: formValues.${name}?.id,` : ``;
|
|
469
|
+
imports.push({
|
|
470
|
+
name: `GQL${queryName}Query`,
|
|
471
|
+
importPath: `./${baseOutputFilename}.generated`,
|
|
472
|
+
});
|
|
473
|
+
imports.push({
|
|
474
|
+
name: `GQL${queryName}QueryVariables`,
|
|
475
|
+
importPath: `./${baseOutputFilename}.generated`,
|
|
476
|
+
});
|
|
477
|
+
code = `<AsyncSelectField
|
|
478
|
+
${required ? "required" : ""}
|
|
479
|
+
variant="horizontal"
|
|
480
|
+
fullWidth
|
|
481
|
+
name="${nameWithPrefix}"
|
|
482
|
+
label={${fieldLabel}}
|
|
483
|
+
${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
|
|
484
|
+
loadOptions={async () => {
|
|
485
|
+
const { data } = await client.query<GQL${queryName}Query, GQL${queryName}QueryVariables>({
|
|
486
|
+
query: gql\`query ${queryName}${filterConfig
|
|
487
|
+
? `($${filterConfig.filterVarName}: ${filterConfig.filterType.typeClass}${filterConfig.filterType.required ? `!` : ``})`
|
|
488
|
+
: ``} {
|
|
489
|
+
${rootQuery}${filterConfig ? `(${filterConfig.filterVarName}: $${filterConfig.filterVarName})` : ``} {
|
|
490
|
+
nodes {
|
|
491
|
+
id
|
|
492
|
+
${labelField}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}\`${filterConfig ? `, variables: { ${filterConfig.filterVarName}: ${filterConfig.filterVarValue} }` : ``}
|
|
496
|
+
});
|
|
497
|
+
return data.${rootQuery}.nodes;
|
|
498
|
+
}}
|
|
499
|
+
getOptionLabel={(option) => option.${labelField}}
|
|
500
|
+
${filterConfig ? `disabled={!values?.${String(filterConfig.filterField.name)}}` : ``}
|
|
501
|
+
/>${filterConfig
|
|
502
|
+
? `<OnChangeField name="${String(filterConfig.filterField.name)}">
|
|
503
|
+
{(value, previousValue) => {
|
|
504
|
+
if (value.id !== previousValue.id) {
|
|
505
|
+
form.change("${String(config.name)}", undefined);
|
|
506
|
+
}
|
|
507
|
+
}}
|
|
508
|
+
</OnChangeField>`
|
|
509
|
+
: ``}`;
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
throw new Error(`Unsupported type`);
|
|
513
|
+
}
|
|
514
|
+
return {
|
|
515
|
+
code,
|
|
516
|
+
hooksCode,
|
|
517
|
+
formValueToGqlInputCode,
|
|
518
|
+
formFragmentFields: [formFragmentField],
|
|
519
|
+
gqlDocuments,
|
|
520
|
+
imports,
|
|
521
|
+
formValuesConfig,
|
|
522
|
+
finalFormConfig,
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
exports.generateFormField = generateFormField;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type IntrospectionQuery } from "graphql";
|
|
2
|
+
import { type FormConfig, type FormLayoutConfig } from "../generate-command";
|
|
3
|
+
import { type GenerateFieldsReturn } from "./generateFields";
|
|
4
|
+
export declare function generateFormLayout({ gqlIntrospection, baseOutputFilename, config, formFragmentName, formConfig, gqlType, namePrefix, }: {
|
|
5
|
+
gqlIntrospection: IntrospectionQuery;
|
|
6
|
+
baseOutputFilename: string;
|
|
7
|
+
config: FormLayoutConfig<any>;
|
|
8
|
+
formFragmentName: string;
|
|
9
|
+
formConfig: FormConfig<any>;
|
|
10
|
+
gqlType: string;
|
|
11
|
+
namePrefix?: string;
|
|
12
|
+
}): GenerateFieldsReturn;
|