@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.
Files changed (55) hide show
  1. package/LICENSE +24 -0
  2. package/bin/admin-generator.js +5 -0
  3. package/lib/adminGenerator.d.ts +1 -0
  4. package/lib/adminGenerator.js +8 -0
  5. package/lib/commands/generate/generate-command.d.ts +197 -0
  6. package/lib/commands/generate/generate-command.js +114 -0
  7. package/lib/commands/generate/generateForm/generateComponentFormField.d.ts +5 -0
  8. package/lib/commands/generate/generateForm/generateComponentFormField.js +18 -0
  9. package/lib/commands/generate/generateForm/generateFields.d.ts +35 -0
  10. package/lib/commands/generate/generateForm/generateFields.js +88 -0
  11. package/lib/commands/generate/generateForm/generateForm.d.ts +13 -0
  12. package/lib/commands/generate/generateForm/generateForm.js +468 -0
  13. package/lib/commands/generate/generateForm/generateFormField.d.ts +12 -0
  14. package/lib/commands/generate/generateForm/generateFormField.js +525 -0
  15. package/lib/commands/generate/generateForm/generateFormLayout.d.ts +12 -0
  16. package/lib/commands/generate/generateForm/generateFormLayout.js +164 -0
  17. package/lib/commands/generate/generateForm/getForwardedGqlArgs.d.ts +19 -0
  18. package/lib/commands/generate/generateForm/getForwardedGqlArgs.js +79 -0
  19. package/lib/commands/generate/generateGrid/combinationColumn.d.ts +43 -0
  20. package/lib/commands/generate/generateGrid/combinationColumn.js +151 -0
  21. package/lib/commands/generate/generateGrid/findInputObjectType.d.ts +2 -0
  22. package/lib/commands/generate/generateGrid/findInputObjectType.js +16 -0
  23. package/lib/commands/generate/generateGrid/generateGqlFieldList.d.ts +5 -0
  24. package/lib/commands/generate/generateGrid/generateGqlFieldList.js +43 -0
  25. package/lib/commands/generate/generateGrid/generateGrid.d.ts +14 -0
  26. package/lib/commands/generate/generateGrid/generateGrid.js +827 -0
  27. package/lib/commands/generate/generateGrid/generateGridToolbar.d.ts +14 -0
  28. package/lib/commands/generate/generateGrid/generateGridToolbar.js +92 -0
  29. package/lib/commands/generate/generateGrid/getForwardedGqlArgs.d.ts +14 -0
  30. package/lib/commands/generate/generateGrid/getForwardedGqlArgs.js +64 -0
  31. package/lib/commands/generate/generateGrid/getPropsForFilterProp.d.ts +12 -0
  32. package/lib/commands/generate/generateGrid/getPropsForFilterProp.js +14 -0
  33. package/lib/commands/generate/generateGrid/usableFields.d.ts +8 -0
  34. package/lib/commands/generate/generateGrid/usableFields.js +2 -0
  35. package/lib/commands/generate/utils/camelCaseToHumanReadable.d.ts +1 -0
  36. package/lib/commands/generate/utils/camelCaseToHumanReadable.js +8 -0
  37. package/lib/commands/generate/utils/columnVisibility.d.ts +6 -0
  38. package/lib/commands/generate/utils/columnVisibility.js +2 -0
  39. package/lib/commands/generate/utils/findMutationType.d.ts +3 -0
  40. package/lib/commands/generate/utils/findMutationType.js +19 -0
  41. package/lib/commands/generate/utils/findQueryType.d.ts +2 -0
  42. package/lib/commands/generate/utils/findQueryType.js +19 -0
  43. package/lib/commands/generate/utils/findRootBlocks.d.ts +8 -0
  44. package/lib/commands/generate/utils/findRootBlocks.js +67 -0
  45. package/lib/commands/generate/utils/generateImportsCode.d.ts +5 -0
  46. package/lib/commands/generate/utils/generateImportsCode.js +27 -0
  47. package/lib/commands/generate/utils/intl.d.ts +1 -0
  48. package/lib/commands/generate/utils/intl.js +7 -0
  49. package/lib/commands/generate/utils/isFieldOptional.d.ts +7 -0
  50. package/lib/commands/generate/utils/isFieldOptional.js +21 -0
  51. package/lib/commands/generate/utils/writeGenerated.d.ts +1 -0
  52. package/lib/commands/generate/utils/writeGenerated.js +57 -0
  53. package/lib/index.d.ts +1 -0
  54. package/lib/index.js +2 -0
  55. 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;