@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,827 @@
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.generateGrid = void 0;
15
+ const pluralize_1 = require("pluralize");
16
+ const camelCaseToHumanReadable_1 = require("../utils/camelCaseToHumanReadable");
17
+ const findMutationType_1 = require("../utils/findMutationType");
18
+ const findQueryType_1 = require("../utils/findQueryType");
19
+ const findRootBlocks_1 = require("../utils/findRootBlocks");
20
+ const generateImportsCode_1 = require("../utils/generateImportsCode");
21
+ const combinationColumn_1 = require("./combinationColumn");
22
+ const findInputObjectType_1 = require("./findInputObjectType");
23
+ const generateGqlFieldList_1 = require("./generateGqlFieldList");
24
+ const generateGridToolbar_1 = require("./generateGridToolbar");
25
+ const getForwardedGqlArgs_1 = require("./getForwardedGqlArgs");
26
+ const getPropsForFilterProp_1 = require("./getPropsForFilterProp");
27
+ function tsCodeRecordToString(object, spreadAbove) {
28
+ return `{${spreadAbove ? `${spreadAbove}` : ""}${Object.entries(object)
29
+ .filter(([key, value]) => value !== undefined)
30
+ .map(([key, value]) => `${key}: ${value},`)
31
+ .join("\n")}}`;
32
+ }
33
+ function generateGridPropsCode(props) {
34
+ if (!props.length)
35
+ return { gridPropsTypeCode: "", gridPropsParamsCode: "" };
36
+ const uniqueProps = props.reduce((acc, prop) => {
37
+ const propWithSameName = acc.find((filteredProps) => filteredProps.name === prop.name);
38
+ if (propWithSameName) {
39
+ if (propWithSameName.type === prop.type) {
40
+ // ignore prop, it's a duplicate. e.g. same prop for mutation and for query
41
+ }
42
+ else {
43
+ throw new Error(`Prop ${prop.name} with same name but different types (${propWithSameName.type} and ${prop.type}) detected.`);
44
+ }
45
+ }
46
+ else {
47
+ acc.push(prop);
48
+ }
49
+ return acc;
50
+ }, []);
51
+ return {
52
+ gridPropsTypeCode: `type Props = {
53
+ ${uniqueProps
54
+ .map((prop) => `${prop.type.includes("any")
55
+ ? `// eslint-disable-next-line @typescript-eslint/no-explicit-any
56
+ `
57
+ : ``}${prop.name}${prop.optional ? `?` : ``}: ${prop.type};`)
58
+ .join("\n")}
59
+ };`,
60
+ gridPropsParamsCode: `{${uniqueProps.map((prop) => `${prop.name} ${prop.defaultValue ? `= ${prop.defaultValue}` : ""}`).join(", ")}}: Props`,
61
+ };
62
+ }
63
+ const getSortByValue = (sortBy) => {
64
+ if (Array.isArray(sortBy)) {
65
+ return `[${sortBy.map((i) => `"${i}"`).join(", ")}]`;
66
+ }
67
+ if (typeof sortBy === "string") {
68
+ return `"${sortBy}"`;
69
+ }
70
+ return sortBy;
71
+ };
72
+ const getValueOptionsLabelData = (messageId, label) => {
73
+ if (typeof label === "string") {
74
+ return {
75
+ textLabel: `intl.formatMessage({ id: "${messageId}", defaultMessage: "${label}" })`,
76
+ };
77
+ }
78
+ const textLabelParts = [];
79
+ const gridCellContentProps = {};
80
+ if (label.primaryText) {
81
+ const primaryMessageId = `${messageId}.primary`;
82
+ textLabelParts.push(`intl.formatMessage({ id: "${primaryMessageId}", defaultMessage: "${label.primaryText}" })`);
83
+ gridCellContentProps.primaryText = `<FormattedMessage id="${primaryMessageId}" defaultMessage="${label.primaryText}" />`;
84
+ }
85
+ if (label.secondaryText) {
86
+ const secondaryMessageId = `${messageId}.secondary`;
87
+ textLabelParts.push(`intl.formatMessage({ id: "${secondaryMessageId}", defaultMessage: "${label.secondaryText}" })`);
88
+ gridCellContentProps.secondaryText = `<FormattedMessage id="${secondaryMessageId}" defaultMessage="${label.secondaryText}" />`;
89
+ }
90
+ if (typeof label.icon === "string") {
91
+ gridCellContentProps.icon = `<${label.icon}Icon />`;
92
+ }
93
+ else if (typeof label.icon === "object") {
94
+ if ("import" in label.icon) {
95
+ gridCellContentProps.icon = `<${label.icon.name} />`;
96
+ }
97
+ else {
98
+ const _a = label.icon, { name } = _a, iconProps = __rest(_a, ["name"]);
99
+ gridCellContentProps.icon = `<${name}Icon
100
+ ${Object.entries(iconProps)
101
+ .map(([key, value]) => `${key}="${value}"`)
102
+ .join("\n")}
103
+ />`;
104
+ }
105
+ }
106
+ const gridCellContent = `<GridCellContent
107
+ ${Object.entries(gridCellContentProps)
108
+ .map(([key, value]) => `${key}={${value}}`)
109
+ .join("\n")}
110
+ />`;
111
+ return {
112
+ textLabel: textLabelParts.join(" + ' ' + "),
113
+ gridCellContent,
114
+ };
115
+ };
116
+ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntrospection, },
117
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
118
+ config) {
119
+ var _a, _b;
120
+ const gqlType = config.gqlType;
121
+ const gqlTypePlural = (0, pluralize_1.plural)(gqlType);
122
+ //const title = config.title ?? camelCaseToHumanReadable(gqlType);
123
+ const instanceGqlType = gqlType[0].toLowerCase() + gqlType.substring(1);
124
+ const instanceGqlTypePlural = gqlTypePlural[0].toLowerCase() + gqlTypePlural.substring(1);
125
+ const gridQuery = config.query ? config.query : instanceGqlType != instanceGqlTypePlural ? instanceGqlTypePlural : `${instanceGqlTypePlural}List`;
126
+ const gqlDocuments = {};
127
+ const imports = [];
128
+ const iconsToImport = ["Add", "Edit"];
129
+ const props = [];
130
+ const fieldList = (0, generateGqlFieldList_1.generateGqlFieldList)({
131
+ columns: config.columns.filter((column) => {
132
+ return (
133
+ // exclude id because it's always required
134
+ column.type !== "actions" && column.name !== "id");
135
+ }),
136
+ });
137
+ // all root blocks including those we don't have columns for (required for copy/paste)
138
+ // this is not configured in the grid config, it's just an heuristics
139
+ const rootBlocks = (0, findRootBlocks_1.findRootBlocks)({ gqlType, targetDirectory }, gqlIntrospection);
140
+ const rootBlockColumns = config.columns
141
+ .filter((column) => column.type == "block")
142
+ .map((column) => {
143
+ // map is for ts to infer block type correctly
144
+ if (column.type !== "block")
145
+ throw new Error("Field is not a block field");
146
+ return column;
147
+ });
148
+ rootBlockColumns.forEach((field) => {
149
+ if (rootBlocks[String(field.name)]) {
150
+ // update rootBlocks if they are also used in columns
151
+ rootBlocks[String(field.name)].import = field.block.import;
152
+ rootBlocks[String(field.name)].name = field.block.name;
153
+ }
154
+ });
155
+ Object.values(rootBlocks).forEach((block) => {
156
+ imports.push({
157
+ name: block.name,
158
+ importPath: block.import,
159
+ });
160
+ });
161
+ const gridQueryType = (0, findQueryType_1.findQueryTypeOrThrow)(gridQuery, gqlIntrospection);
162
+ const createMutationType = (0, findMutationType_1.findMutationType)(`create${gqlType}`, gqlIntrospection);
163
+ const hasDeleteMutation = !!(0, findMutationType_1.findMutationType)(`delete${gqlType}`, gqlIntrospection);
164
+ const hasCreateMutation = !!createMutationType;
165
+ const allowCopyPaste = (typeof config.copyPaste === "undefined" || config.copyPaste === true) && !config.readOnly && hasCreateMutation;
166
+ const allowAdding = (typeof config.add === "undefined" || config.add === true) && !config.readOnly;
167
+ const allowEditing = (typeof config.edit === "undefined" || config.edit === true) && !config.readOnly;
168
+ const allowDeleting = (typeof config.delete === "undefined" || config.delete === true) && !config.readOnly && hasDeleteMutation;
169
+ const forwardRowAction = allowEditing && config.rowActionProp;
170
+ const showActionsColumn = allowCopyPaste || allowEditing || allowDeleting;
171
+ const showCrudContextMenuInActionsColumn = allowCopyPaste || allowDeleting;
172
+ const showEditInActionsColumn = allowEditing && !forwardRowAction;
173
+ const defaultActionsColumnWidth = getDefaultActionsColumnWidth(showCrudContextMenuInActionsColumn, showEditInActionsColumn);
174
+ const { imports: forwardedGqlArgsImports, props: forwardedGqlArgsProps, gqlArgs, } = (0, getForwardedGqlArgs_1.getForwardedGqlArgs)([gridQueryType, ...(createMutationType ? [createMutationType] : [])]);
175
+ imports.push(...forwardedGqlArgsImports);
176
+ props.push(...forwardedGqlArgsProps);
177
+ const renderToolbar = (_a = config.toolbar) !== null && _a !== void 0 ? _a : true;
178
+ const filterArg = gridQueryType.args.find((arg) => arg.name === "filter");
179
+ const hasFilter = !!filterArg && renderToolbar;
180
+ let hasFilterProp = false;
181
+ let filterFields = [];
182
+ if (filterArg) {
183
+ const filterType = (0, findInputObjectType_1.findInputObjectType)(filterArg, gqlIntrospection);
184
+ if (!filterType)
185
+ throw new Error("Can't find filter type");
186
+ filterFields = filterType.inputFields.map((f) => f.name.replace(/_/g, "."));
187
+ const { hasFilterProp: tempHasFilterProp, imports: filterPropImports, props: filterPropProps, } = (0, getPropsForFilterProp_1.getPropsForFilterProp)({ config, filterType });
188
+ hasFilterProp = tempHasFilterProp;
189
+ imports.push(...filterPropImports);
190
+ props.push(...filterPropProps);
191
+ }
192
+ const forwardToolbarAction = allowAdding && renderToolbar && config.toolbarActionProp;
193
+ if (forwardToolbarAction) {
194
+ props.push({ name: "toolbarAction", type: "ReactNode", optional: true });
195
+ }
196
+ const sortArg = gridQueryType.args.find((arg) => arg.name === "sort");
197
+ const hasSort = !!sortArg;
198
+ let sortFields = [];
199
+ if (sortArg) {
200
+ if (sortArg.type.kind !== "LIST") {
201
+ throw new Error("Sort argument must be LIST");
202
+ }
203
+ if (sortArg.type.ofType.kind !== "NON_NULL") {
204
+ throw new Error("Sort argument must be LIST->NON_NULL");
205
+ }
206
+ if (sortArg.type.ofType.ofType.kind !== "INPUT_OBJECT") {
207
+ throw new Error("Sort argument must be LIST->NON_NULL->INPUT_OBJECT");
208
+ }
209
+ const sortTypeName = sortArg.type.ofType.ofType.name;
210
+ const sortType = gqlIntrospection.__schema.types.find((type) => type.kind === "INPUT_OBJECT" && type.name === sortTypeName);
211
+ if (!sortType)
212
+ throw new Error("Can't find sort type");
213
+ const sortField = sortType.inputFields.find((i) => i.name == "field");
214
+ if (!sortField)
215
+ throw new Error("Can't find sortFieldName");
216
+ if (sortField.type.kind !== "NON_NULL")
217
+ throw new Error("sortField must be NON_NULL");
218
+ if (sortField.type.ofType.kind != "ENUM")
219
+ throw new Error("sortField must be NON_NULL->ENUM");
220
+ const sortFieldEnumName = sortField.type.ofType.name;
221
+ const sortInputEnum = gqlIntrospection.__schema.types.find((type) => type.kind === "ENUM" && type.name === sortFieldEnumName);
222
+ if (!sortInputEnum)
223
+ throw new Error("Can't find sortInputEnum");
224
+ sortFields = sortInputEnum.enumValues.map((v) => v.name.replace(/_/g, "."));
225
+ }
226
+ const hasSearch = gridQueryType.args.some((arg) => arg.name === "search");
227
+ const hasScope = gridQueryType.args.some((arg) => arg.name === "scope");
228
+ const schemaEntity = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === gqlType);
229
+ if (!schemaEntity)
230
+ throw new Error("didn't find entity in schema types");
231
+ //we load /all/ fields as we need it for copy/paste TODO: lazy load during copy?
232
+ const fieldsToLoad = schemaEntity.fields
233
+ .filter((field) => {
234
+ if (field.name === "id" || field.name === "scope")
235
+ return false;
236
+ return true;
237
+ })
238
+ .filter((field) => {
239
+ let type = field.type;
240
+ if (type.kind == "NON_NULL")
241
+ type = type.ofType;
242
+ if (type.kind == "LIST")
243
+ return false;
244
+ if (type.kind == "OBJECT")
245
+ return false; //TODO support nested objects
246
+ return true;
247
+ });
248
+ const actionsColumnConfig = config.columns.find((column) => column.type === "actions");
249
+ const _c = actionsColumnConfig !== null && actionsColumnConfig !== void 0 ? actionsColumnConfig : {}, { component: actionsColumnComponent, type: actionsColumnType, headerName: actionsColumnHeaderName, pinned: actionsColumnPinned = "right", width: actionsColumnWidth = defaultActionsColumnWidth, visible: actionsColumnVisible = undefined } = _c, restActionsColumnConfig = __rest(_c, ["component", "type", "headerName", "pinned", "width", "visible"]);
250
+ const gridNeedsTheme = config.columns.some((column) => typeof column.visible === "string");
251
+ const gridColumnFields = config.columns.filter((column) => column.type !== "actions").map((column) => {
252
+ var _a;
253
+ const type = column.type;
254
+ const name = String(column.name);
255
+ let gridColumnType = undefined;
256
+ let renderCell = undefined;
257
+ let valueFormatter = undefined;
258
+ let gridType;
259
+ let filterOperators;
260
+ if (column.filterOperators) {
261
+ let importPath = column.filterOperators.import;
262
+ if (importPath.startsWith("./")) {
263
+ //go one level up as generated files are in generated subfolder
264
+ importPath = `.${importPath}`;
265
+ }
266
+ imports.push({
267
+ name: column.filterOperators.name,
268
+ importPath,
269
+ });
270
+ filterOperators = column.filterOperators.name;
271
+ }
272
+ if (type == "dateTime") {
273
+ gridColumnType = "...dataGridDateTimeColumn,";
274
+ }
275
+ else if (type == "date") {
276
+ gridColumnType = "...dataGridDateColumn,";
277
+ }
278
+ else if (type == "number") {
279
+ gridType = "number";
280
+ }
281
+ else if (type == "boolean") {
282
+ gridType = "boolean";
283
+ valueFormatter = `(value, row) => typeof row.${name} === "boolean" ? row.${name}.toString() : ""`;
284
+ }
285
+ else if (column.type == "block") {
286
+ renderCell = `(params) => {
287
+ return <BlockPreviewContent block={${column.block.name}} input={params.row.${name}} />;
288
+ }`;
289
+ }
290
+ else if (type == "staticSelect") {
291
+ valueFormatter = `(value, row) => row.${name}?.toString()`;
292
+ const introspectionField = schemaEntity.fields.find((field) => field.name === name);
293
+ if (!introspectionField)
294
+ throw new Error(`didn't find field ${name} in gql introspection type ${gqlType}`);
295
+ const introspectionFieldType = introspectionField.type.kind === "NON_NULL" ? introspectionField.type.ofType : introspectionField.type;
296
+ const enumType = gqlIntrospection.__schema.types.find((t) => t.kind === "ENUM" && t.name === introspectionFieldType.name);
297
+ (_a = column.values) === null || _a === void 0 ? void 0 : _a.forEach((value) => {
298
+ var _a;
299
+ if (typeof value === "object" && typeof value.label === "object" && typeof value.label.icon !== "undefined") {
300
+ if (typeof value.label.icon === "string") {
301
+ iconsToImport.push(value.label.icon);
302
+ }
303
+ else if (typeof ((_a = value.label.icon) === null || _a === void 0 ? void 0 : _a.name) === "string") {
304
+ if ("import" in value.label.icon) {
305
+ imports.push({
306
+ name: value.label.icon.name,
307
+ importPath: value.label.icon.import,
308
+ });
309
+ }
310
+ else {
311
+ iconsToImport.push(value.label.icon.name);
312
+ }
313
+ }
314
+ }
315
+ });
316
+ let columnValues = [];
317
+ if (column.values) {
318
+ columnValues = column.values;
319
+ }
320
+ else if (enumType) {
321
+ columnValues = enumType.enumValues.map((i) => i.name);
322
+ }
323
+ else {
324
+ throw new Error(`Enum type not found`);
325
+ }
326
+ const values = columnValues.map((value) => {
327
+ if (typeof value === "string") {
328
+ return {
329
+ value,
330
+ label: (0, camelCaseToHumanReadable_1.camelCaseToHumanReadable)(value),
331
+ };
332
+ }
333
+ else {
334
+ return value;
335
+ }
336
+ });
337
+ const valueOptions = `[${values
338
+ .map(({ value, label }) => {
339
+ const labelData = getValueOptionsLabelData(`${instanceGqlType}.${name}.${value.charAt(0).toLowerCase() + value.slice(1)}`, label);
340
+ return `{
341
+ value: ${JSON.stringify(value)},
342
+ label: ${labelData.textLabel},
343
+ ${labelData.gridCellContent !== undefined ? `cellContent: ${labelData.gridCellContent},` : ""}
344
+ },`;
345
+ })
346
+ .join(" ")}]`;
347
+ renderCell = `renderStaticSelectCell`;
348
+ return {
349
+ name,
350
+ headerName: column.headerName,
351
+ type,
352
+ gridType: "singleSelect",
353
+ columnType: gridColumnType,
354
+ valueOptions,
355
+ renderCell,
356
+ valueFormatter,
357
+ width: column.width,
358
+ minWidth: column.minWidth,
359
+ maxWidth: column.maxWidth,
360
+ flex: column.flex,
361
+ headerInfoTooltip: column.headerInfoTooltip,
362
+ visible: column.visible && `theme.breakpoints.${column.visible}`,
363
+ pinned: column.pinned,
364
+ disableExport: column.disableExport,
365
+ };
366
+ }
367
+ else if (type == "combination") {
368
+ renderCell = (0, combinationColumn_1.getCombinationColumnRenderCell)(column, `${instanceGqlType}.${name}`);
369
+ }
370
+ //TODO support n:1 relation with singleSelect
371
+ return {
372
+ name,
373
+ fieldName: column.fieldName,
374
+ headerName: column.headerName,
375
+ type,
376
+ gridType,
377
+ columnType: gridColumnType,
378
+ renderCell,
379
+ valueGetter: name.includes(".") ? `(params, row) => row.${name.replace(/\./g, "?.")}` : undefined,
380
+ filterOperators: filterOperators,
381
+ valueFormatter,
382
+ width: column.width,
383
+ minWidth: column.minWidth,
384
+ maxWidth: column.maxWidth,
385
+ flex: column.flex,
386
+ headerInfoTooltip: column.headerInfoTooltip,
387
+ visible: column.visible && `theme.breakpoints.${column.visible}`,
388
+ pinned: column.pinned,
389
+ disableExport: column.disableExport,
390
+ sortBy: "sortBy" in column && column.sortBy,
391
+ };
392
+ });
393
+ iconsToImport.forEach((icon) => {
394
+ imports.push({
395
+ name: `${icon} as ${icon}Icon`,
396
+ importPath: "@comet/admin-icons",
397
+ });
398
+ });
399
+ let createMutationInputFields = [];
400
+ {
401
+ const inputArg = createMutationType === null || createMutationType === void 0 ? void 0 : createMutationType.args.find((arg) => arg.name === "input");
402
+ if (inputArg) {
403
+ const inputType = (0, findInputObjectType_1.findInputObjectType)(inputArg, gqlIntrospection);
404
+ if (!inputType)
405
+ throw new Error("Can't find input type");
406
+ createMutationInputFields = inputType.inputFields.filter((field) => fieldsToLoad.some((gridColumnField) => gridColumnField.name == field.name));
407
+ }
408
+ }
409
+ const fragmentName = (_b = config.fragmentName) !== null && _b !== void 0 ? _b : `${gqlTypePlural}Form`;
410
+ if (forwardRowAction) {
411
+ props.push({
412
+ name: "rowAction",
413
+ type: `(params: GridRenderCellParams<any, GQL${fragmentName}Fragment, any>) => ReactNode`,
414
+ optional: true,
415
+ });
416
+ props.push({
417
+ name: "actionsColumnWidth",
418
+ type: `number`,
419
+ optional: true,
420
+ defaultValue: defaultActionsColumnWidth,
421
+ });
422
+ }
423
+ if (config.selectionProps) {
424
+ imports.push({ name: "DataGridProProps", importPath: "@mui/x-data-grid-pro" });
425
+ props.push({
426
+ name: "rowSelectionModel",
427
+ type: `DataGridProProps["rowSelectionModel"]`,
428
+ optional: true,
429
+ });
430
+ props.push({
431
+ name: "onRowSelectionModelChange",
432
+ type: `DataGridProProps["onRowSelectionModelChange"]`,
433
+ optional: true,
434
+ });
435
+ }
436
+ const { gridPropsTypeCode, gridPropsParamsCode } = generateGridPropsCode(props);
437
+ const gridToolbarComponentName = `${gqlTypePlural}GridToolbar`;
438
+ const dataGridRemoteParameters = config.initialSort || config.queryParamsPrefix || config.initialFilter
439
+ ? `{${config.initialSort
440
+ ? ` initialSort: [${config.initialSort
441
+ .map((item) => {
442
+ return `{field: "${item.field}", sort: "${item.sort}"}`;
443
+ })
444
+ .join(",\n")} ], `
445
+ : ""}
446
+ ${config.initialFilter
447
+ ? `initialFilter:{ ${config.initialFilter.linkOperator
448
+ ? `linkOperator: GridLinkOperator.${config.initialFilter.linkOperator === "or" ? "Or" : "And"},`
449
+ : ""}
450
+ items: [${config.initialFilter.items
451
+ .map((item) => {
452
+ return `{ field: "${item.field}", operator: "${item.operator}", value: "${item.value}" }`;
453
+ })
454
+ .join(",\n")} ],},`
455
+ : ""}
456
+ ${config.queryParamsPrefix ? `queryParamsPrefix: "${config.queryParamsPrefix}",` : ""}
457
+ }`
458
+ : "";
459
+ const code = `import { gql, useApolloClient, useQuery } from "@apollo/client";
460
+ import {
461
+ Button,
462
+ CrudContextMenu,
463
+ CrudMoreActionsMenu,
464
+ DataGridToolbar,
465
+ ExportApi,
466
+ filterByFragment,
467
+ GridFilterButton,
468
+ GridCellContent,
469
+ GridColDef,
470
+ dataGridDateTimeColumn,
471
+ dataGridDateColumn,
472
+ renderStaticSelectCell,
473
+ messages,
474
+ muiGridFilterToGql,
475
+ muiGridSortToGql,
476
+ StackLink,
477
+ ToolbarActions,
478
+ FillSpace,
479
+ ToolbarItem,
480
+ Tooltip,
481
+ useBufferedRowCount,
482
+ useDataGridExcelExport,
483
+ useDataGridRemote,
484
+ usePersistentColumnState,
485
+ } from "@comet/admin";
486
+ import { Add as AddIcon, Edit, Info, MoreVertical, Excel } from "@comet/admin-icons";
487
+ import { BlockPreviewContent } from "@comet/cms-admin";
488
+ import { Alert, Box, IconButton, Typography, useTheme, Menu, MenuItem, ListItemIcon, ListItemText, CircularProgress } from "@mui/material";
489
+ import { DataGridPro, GridLinkOperator, GridRenderCellParams, GridSlotsComponent, GridToolbarProps, GridColumnHeaderTitle, GridToolbarQuickFilter } from "@mui/x-data-grid-pro";
490
+ import { useContentScope } from "@src/common/ContentScopeProvider";
491
+ import {
492
+ GQL${gqlTypePlural}GridQuery,
493
+ GQL${gqlTypePlural}GridQueryVariables,
494
+ GQL${fragmentName}Fragment,
495
+ GQLCreate${gqlType}Mutation,
496
+ GQLCreate${gqlType}MutationVariables,
497
+ GQLDelete${gqlType}Mutation,
498
+ GQLDelete${gqlType}MutationVariables
499
+ } from "./${baseOutputFilename}.generated";
500
+ import { ReactNode } from "react";
501
+ import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";
502
+ ${(0, generateImportsCode_1.generateImportsCode)(imports)}
503
+
504
+ ${Object.entries(rootBlocks)
505
+ .map(([rootBlockKey, rootBlock]) => `import { ${rootBlock.name} } from "${rootBlock.import}";`)
506
+ .join("\n")}
507
+ ${actionsColumnComponent ? `import { ${actionsColumnComponent.name} } from "${actionsColumnComponent.import}";` : ""}
508
+
509
+ const ${instanceGqlTypePlural}Fragment = gql\`
510
+ fragment ${fragmentName} on ${gqlType} {
511
+ id
512
+ ${fieldList}
513
+ }
514
+ \`;
515
+
516
+ const ${instanceGqlTypePlural}Query = gql\`
517
+ query ${gqlTypePlural}Grid(${[
518
+ ...gqlArgs.filter((gqlArg) => gqlArg.queryOrMutationName === gridQueryType.name).map((gqlArg) => `$${gqlArg.name}: ${gqlArg.type}!`),
519
+ ...[`$offset: Int!`, `$limit: Int!`],
520
+ ...(hasSort ? [`$sort: [${gqlType}Sort!]`] : []),
521
+ ...(hasSearch ? [`$search: String`] : []),
522
+ ...(filterArg && (hasFilter || hasFilterProp) ? [`$filter: ${gqlType}Filter`] : []),
523
+ ...(hasScope ? [`$scope: ${gqlType}ContentScopeInput!`] : []),
524
+ ].join(", ")}) {
525
+ ${gridQuery}(${[
526
+ ...gqlArgs.filter((gqlArg) => gqlArg.queryOrMutationName === gridQueryType.name).map((gqlArg) => `${gqlArg.name}: $${gqlArg.name}`),
527
+ ...[`offset: $offset`, `limit: $limit`],
528
+ ...(hasSort ? [`sort: $sort`] : []),
529
+ ...(hasSearch ? [`search: $search`] : []),
530
+ ...(filterArg && (hasFilter || hasFilterProp) ? [`filter: $filter`] : []),
531
+ ...(hasScope ? [`scope: $scope`] : []),
532
+ ].join(", ")}) {
533
+ nodes {
534
+ ...${fragmentName}
535
+ }
536
+ totalCount
537
+ }
538
+ }
539
+ \${${instanceGqlTypePlural}Fragment}
540
+ \`;
541
+
542
+
543
+ ${allowDeleting
544
+ ? `const delete${gqlType}Mutation = gql\`
545
+ mutation Delete${gqlType}($id: ID!) {
546
+ delete${gqlType}(id: $id)
547
+ }
548
+ \`;`
549
+ : ""}
550
+
551
+ ${allowCopyPaste
552
+ ? `const create${gqlType}Mutation = gql\`
553
+ mutation Create${gqlType}(${[
554
+ ...gqlArgs.filter((gqlArg) => gqlArg.queryOrMutationName === createMutationType.name).map((gqlArg) => `$${gqlArg.name}: ${gqlArg.type}!`),
555
+ ...(hasScope ? [`$scope: ${gqlType}ContentScopeInput!`] : []),
556
+ ...[`$input: ${gqlType}Input!`],
557
+ ].join(", ")}) {
558
+ create${gqlType}(${[
559
+ gqlArgs.filter((gqlArg) => gqlArg.queryOrMutationName === createMutationType.name).map((gqlArg) => `${gqlArg.name}: $${gqlArg.name}`),
560
+ ...(hasScope ? [`scope: $scope`] : []),
561
+ ...[`input: $input`],
562
+ ].join(", ")}) {
563
+ id
564
+ }
565
+ }
566
+ \`;`
567
+ : ""}
568
+
569
+ ${renderToolbar
570
+ ? (0, generateGridToolbar_1.generateGridToolbar)({
571
+ componentName: gridToolbarComponentName,
572
+ forwardToolbarAction,
573
+ hasSearch,
574
+ hasFilter,
575
+ allowAdding,
576
+ instanceGqlType,
577
+ gqlType,
578
+ excelExport: config.excelExport,
579
+ newEntryText: config.newEntryText,
580
+ fragmentName,
581
+ })
582
+ : ""}
583
+
584
+ ${gridPropsTypeCode}
585
+
586
+ export function ${gqlTypePlural}Grid(${gridPropsParamsCode}) {
587
+ ${showCrudContextMenuInActionsColumn ? "const client = useApolloClient();" : ""}
588
+ const intl = useIntl();
589
+ const dataGridProps = { ...useDataGridRemote(${dataGridRemoteParameters}), ...usePersistentColumnState("${gqlTypePlural}Grid")${config.selectionProps === "multiSelect"
590
+ ? `, rowSelectionModel, onRowSelectionModelChange, checkboxSelection: true, keepNonExistentRowsSelected: true`
591
+ : config.selectionProps === "singleSelect"
592
+ ? `, rowSelectionModel, onRowSelectionModelChange, checkboxSelection: false, keepNonExistentRowsSelected: false, disableSelectionOnClick: true`
593
+ : ``} };
594
+ ${hasScope ? `const { scope } = useContentScope();` : ""}
595
+ ${gridNeedsTheme ? `const theme = useTheme();` : ""}
596
+
597
+ const columns: GridColDef<GQL${fragmentName}Fragment>[] = [
598
+ ${gridColumnFields
599
+ .map((column) => {
600
+ const defaultMinWidth = 150;
601
+ const defaultColumnFlex = 1;
602
+ let minWidth;
603
+ let maxWidth;
604
+ let tooltipColumnWidth = column.width;
605
+ if (typeof column.width === "undefined") {
606
+ maxWidth = column.maxWidth;
607
+ if (typeof column.minWidth === "undefined" &&
608
+ (typeof column.maxWidth === "undefined" || column.maxWidth >= defaultMinWidth)) {
609
+ minWidth = defaultMinWidth;
610
+ tooltipColumnWidth = defaultMinWidth;
611
+ }
612
+ else if (typeof column.minWidth !== "undefined") {
613
+ minWidth = column.minWidth;
614
+ tooltipColumnWidth = column.minWidth;
615
+ }
616
+ }
617
+ const columnDefinition = {
618
+ field: column.fieldName ? `"${column.fieldName}"` : `"${column.name.replace(/\./g, "_")}"`,
619
+ renderHeader: column.headerInfoTooltip
620
+ ? `() => (
621
+ <>
622
+ <GridColumnHeaderTitle label={intl.formatMessage({ id: "${instanceGqlType}.${column.name}", defaultMessage: "${column.headerName || (0, camelCaseToHumanReadable_1.camelCaseToHumanReadable)(column.name)}"})} columnWidth= {${tooltipColumnWidth}}
623
+ />
624
+ <Tooltip
625
+ title={<FormattedMessage id="${instanceGqlType}.${column.name}.tooltip" defaultMessage="${column.headerInfoTooltip}" />}
626
+ >
627
+ <Info sx={{ marginLeft: 1 }} />
628
+ </Tooltip>
629
+ </>
630
+ )`
631
+ : undefined,
632
+ headerName: !column.headerInfoTooltip
633
+ ? `intl.formatMessage({ id: "${instanceGqlType}.${column.name}", defaultMessage: "${column.headerName || (0, camelCaseToHumanReadable_1.camelCaseToHumanReadable)(column.name)}" })`
634
+ : undefined,
635
+ type: column.gridType ? `"${column.gridType}"` : undefined,
636
+ filterable: !column.filterOperators && !filterFields.includes(column.name) ? `false` : undefined,
637
+ sortable: !sortFields.includes(column.name) ? `false` : undefined,
638
+ valueGetter: column.valueGetter,
639
+ valueFormatter: column.valueFormatter,
640
+ valueOptions: column.valueOptions,
641
+ renderCell: column.renderCell,
642
+ filterOperators: column.filterOperators,
643
+ width: column.width,
644
+ flex: column.flex,
645
+ pinned: column.pinned && `"${column.pinned}"`,
646
+ visible: column.visible,
647
+ disableExport: column.disableExport ? "true" : undefined,
648
+ };
649
+ if ("sortBy" in column && column.sortBy) {
650
+ columnDefinition["sortBy"] = getSortByValue(column.sortBy);
651
+ }
652
+ if (typeof column.width === "undefined") {
653
+ columnDefinition.flex = defaultColumnFlex;
654
+ columnDefinition.minWidth = minWidth;
655
+ columnDefinition.maxWidth = maxWidth;
656
+ }
657
+ return tsCodeRecordToString(columnDefinition, column.columnType);
658
+ })
659
+ .join(",\n")},
660
+ ${showActionsColumn
661
+ ? tsCodeRecordToString(Object.assign(Object.assign({ field: '"actions"', headerName: actionsColumnHeaderName
662
+ ? `intl.formatMessage({ id: "${instanceGqlType}.actions", defaultMessage: "${actionsColumnHeaderName}" })`
663
+ : `""`, sortable: "false", filterable: "false", type: '"actions"', align: '"right"', pinned: `"${actionsColumnPinned}"`, width: forwardRowAction ? "actionsColumnWidth" : actionsColumnWidth, visible: actionsColumnVisible && `theme.breakpoints.${actionsColumnVisible}` }, restActionsColumnConfig), { disableExport: config.excelExport ? "true" : undefined, renderCell: `(params) => {
664
+ return (
665
+ <>
666
+ ${(actionsColumnComponent === null || actionsColumnComponent === void 0 ? void 0 : actionsColumnComponent.name) ? `<${actionsColumnComponent.name} {...params} />` : ""}${allowEditing
667
+ ? forwardRowAction
668
+ ? `{rowAction && rowAction(params)}`
669
+ : `
670
+ <IconButton color="primary" component={StackLink} pageName="edit" payload={params.row.id}>
671
+ <EditIcon />
672
+ </IconButton>`
673
+ : ""}${showCrudContextMenuInActionsColumn
674
+ ? `
675
+ <CrudContextMenu
676
+ ${allowCopyPaste
677
+ ? `
678
+ copyData={() => {
679
+ // Don't copy id, because we want to create a new entity with this data
680
+ ${createMutationInputFields.filter((field) => rootBlocks[field.name]).length
681
+ ? `const { id, ...filteredData } = filterByFragment(${instanceGqlTypePlural}Fragment, params.row);
682
+ return {
683
+ ...filteredData,
684
+ ${createMutationInputFields
685
+ .filter((field) => rootBlocks[field.name])
686
+ .map((field) => {
687
+ if (rootBlocks[field.name]) {
688
+ const blockName = rootBlocks[field.name].name;
689
+ return `${field.name}: ${blockName}.state2Output(${blockName}.input2State(filteredData.${field.name}))`;
690
+ }
691
+ })
692
+ .join(",\n")}
693
+ };`
694
+ : `const { id, ...filteredData } = filterByFragment(${instanceGqlTypePlural}Fragment, params.row);
695
+ return filteredData;`}
696
+ }}
697
+ onPaste={async ({ input }) => {
698
+ await client.mutate<GQLCreate${gqlType}Mutation, GQLCreate${gqlType}MutationVariables>({
699
+ mutation: create${gqlType}Mutation,
700
+ variables: { ${[
701
+ ...gqlArgs
702
+ .filter((gqlArg) => gqlArg.queryOrMutationName === createMutationType.name)
703
+ .map((arg) => arg.name),
704
+ ...(hasScope ? [`scope`] : []),
705
+ ...["input"],
706
+ ].join(", ")} },
707
+ });
708
+ }}
709
+ `
710
+ : ""}
711
+ ${allowDeleting
712
+ ? `
713
+ onDelete={async () => {
714
+ await client.mutate<GQLDelete${gqlType}Mutation, GQLDelete${gqlType}MutationVariables>({
715
+ mutation: delete${gqlType}Mutation,
716
+ variables: { id: params.row.id },
717
+ });
718
+ }}
719
+ `
720
+ : ""}
721
+ refetchQueries={[${instanceGqlTypePlural}Query]}
722
+ />
723
+ `
724
+ : ""}
725
+ </>
726
+ );
727
+ }` }))
728
+ : ""}
729
+ ];
730
+
731
+ ${hasFilter || hasSearch
732
+ ? `const { ${hasFilter ? `filter: gqlFilter, ` : ""}${hasSearch ? `search: gqlSearch, ` : ""} } = muiGridFilterToGql(columns, dataGridProps.filterModel);`
733
+ : ""}
734
+
735
+ const { data, loading, error } = useQuery<GQL${gqlTypePlural}GridQuery, GQL${gqlTypePlural}GridQueryVariables>(${instanceGqlTypePlural}Query, {
736
+ variables: {
737
+ ${[
738
+ ...gqlArgs.filter((gqlArg) => gqlArg.queryOrMutationName === gridQueryType.name).map((arg) => arg.name),
739
+ ...(hasScope ? ["scope"] : []),
740
+ ...(filterArg
741
+ ? hasFilter && hasFilterProp
742
+ ? ["filter: filter ? { and: [gqlFilter, filter] } : gqlFilter"]
743
+ : hasFilter
744
+ ? ["filter: gqlFilter"]
745
+ : hasFilterProp
746
+ ? ["filter"]
747
+ : []
748
+ : []),
749
+ ...(hasSearch ? ["search: gqlSearch"] : []),
750
+ ...[
751
+ `offset: dataGridProps.paginationModel.page * dataGridProps.paginationModel.pageSize`,
752
+ `limit: dataGridProps.paginationModel.pageSize`,
753
+ `sort: muiGridSortToGql(dataGridProps.sortModel)`,
754
+ ],
755
+ ].join(", ")}
756
+ },
757
+ });
758
+ const rowCount = useBufferedRowCount(data?.${gridQuery}.totalCount);
759
+ if (error) throw error;
760
+ const rows = data?.${gridQuery}.nodes ?? [];
761
+
762
+ ${generateGridExportApi(config.excelExport, gqlTypePlural, gridQuery)}
763
+
764
+ return (
765
+ <DataGridPro
766
+ {...dataGridProps}
767
+ rows={rows}
768
+ rowCount={rowCount}
769
+ columns={columns}
770
+ loading={loading}
771
+ ${renderToolbar
772
+ ? `slots={{
773
+ toolbar: ${gridToolbarComponentName} as GridSlotsComponent["toolbar"],
774
+ }}
775
+ ${getDataGridSlotProps(gridToolbarComponentName, forwardToolbarAction, config.excelExport)}`
776
+ : ""}
777
+ />
778
+ );
779
+ }
780
+ `;
781
+ return {
782
+ code,
783
+ gqlDocuments,
784
+ };
785
+ }
786
+ exports.generateGrid = generateGrid;
787
+ const getDefaultActionsColumnWidth = (showCrudContextMenu, showEdit) => {
788
+ let numberOfActions = 0;
789
+ if (showCrudContextMenu) {
790
+ numberOfActions += 1;
791
+ }
792
+ if (showEdit) {
793
+ numberOfActions += 1;
794
+ }
795
+ const widthOfSingleAction = 32;
796
+ const spacingAroundActions = 20;
797
+ return numberOfActions * widthOfSingleAction + spacingAroundActions;
798
+ };
799
+ const getDataGridSlotProps = (componentName, forwardToolbarAction, excelExport) => {
800
+ if (!forwardToolbarAction && !excelExport) {
801
+ return "";
802
+ }
803
+ const values = `{
804
+ ${forwardToolbarAction ? `toolbarAction,` : ""}
805
+ ${excelExport ? `exportApi,` : ""}
806
+ } as ${componentName}ToolbarProps`.replace(/\n/g, "");
807
+ return `slotProps={{
808
+ toolbar: ${values}
809
+ }}`;
810
+ };
811
+ const generateGridExportApi = (excelExport, gqlTypePlural, gridQuery) => {
812
+ if (!excelExport) {
813
+ return "";
814
+ }
815
+ return `const exportApi = useDataGridExcelExport<GQL${gqlTypePlural}GridQuery["${gridQuery}"]["nodes"][0], GQL${gqlTypePlural}GridQuery, Omit<GQL${gqlTypePlural}GridQueryVariables, "offset" | "limit">>({
816
+ columns,
817
+ variables: {
818
+ ...muiGridFilterToGql(columns, dataGridProps.filterModel),
819
+ },
820
+ query: ${gridQuery}Query,
821
+ resolveQueryNodes: (data) => data.${gridQuery}.nodes,
822
+ totalCount: data?.${gridQuery}.totalCount ?? 0,
823
+ exportOptions: {
824
+ fileName: "${gqlTypePlural}",
825
+ },
826
+ });`;
827
+ };