@comet/admin-generator 8.0.0-beta.4 → 8.0.0-beta.6

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.
@@ -115,7 +115,7 @@ const getValueOptionsLabelData = (messageId, label) => {
115
115
  };
116
116
  };
117
117
  function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntrospection, }, config) {
118
- var _a, _b;
118
+ var _a, _b, _c, _d, _e, _f, _g, _h;
119
119
  const gqlType = config.gqlType;
120
120
  const gqlTypePlural = (0, pluralize_1.plural)(gqlType);
121
121
  //const title = config.title ?? camelCaseToHumanReadable(gqlType);
@@ -123,8 +123,58 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
123
123
  const instanceGqlTypePlural = gqlTypePlural[0].toLowerCase() + gqlTypePlural.substring(1);
124
124
  const gridQuery = config.query ? config.query : instanceGqlType != instanceGqlTypePlural ? instanceGqlTypePlural : `${instanceGqlTypePlural}List`;
125
125
  const gqlDocuments = {};
126
- const imports = [];
127
- const iconsToImport = ["Add", "Edit"];
126
+ const imports = [
127
+ { name: "FormattedMessage", importPath: "react-intl" },
128
+ { name: "FormattedNumber", importPath: "react-intl" },
129
+ { name: "useIntl", importPath: "react-intl" },
130
+ { name: "ReactNode", importPath: "react" },
131
+ { name: "gql", importPath: "@apollo/client" },
132
+ { name: "useApolloClient", importPath: "@apollo/client" },
133
+ { name: "useQuery", importPath: "@apollo/client" },
134
+ { name: "Button", importPath: "@comet/admin" },
135
+ { name: "CrudContextMenu", importPath: "@comet/admin" },
136
+ { name: "CrudMoreActionsMenu", importPath: "@comet/admin" },
137
+ { name: "DataGridToolbar", importPath: "@comet/admin" },
138
+ { name: "ExportApi", importPath: "@comet/admin" },
139
+ { name: "filterByFragment", importPath: "@comet/admin" },
140
+ { name: "GridFilterButton", importPath: "@comet/admin" },
141
+ { name: "GridCellContent", importPath: "@comet/admin" },
142
+ { name: "GridColDef", importPath: "@comet/admin" },
143
+ { name: "dataGridDateTimeColumn", importPath: "@comet/admin" },
144
+ { name: "dataGridDateColumn", importPath: "@comet/admin" },
145
+ { name: "renderStaticSelectCell", importPath: "@comet/admin" },
146
+ { name: "messages", importPath: "@comet/admin" },
147
+ { name: "muiGridFilterToGql", importPath: "@comet/admin" },
148
+ { name: "muiGridSortToGql", importPath: "@comet/admin" },
149
+ { name: "StackLink", importPath: "@comet/admin" },
150
+ { name: "FillSpace", importPath: "@comet/admin" },
151
+ { name: "Tooltip", importPath: "@comet/admin" },
152
+ { name: "useBufferedRowCount", importPath: "@comet/admin" },
153
+ { name: "useDataGridExcelExport", importPath: "@comet/admin" },
154
+ { name: "useDataGridRemote", importPath: "@comet/admin" },
155
+ { name: "usePersistentColumnState", importPath: "@comet/admin" },
156
+ { name: "BlockPreviewContent", importPath: "@comet/cms-admin" },
157
+ { name: "useContentScope", importPath: "@comet/cms-admin" },
158
+ { name: "Alert", importPath: "@mui/material" },
159
+ { name: "Box", importPath: "@mui/material" },
160
+ { name: "IconButton", importPath: "@mui/material" },
161
+ { name: "Typography", importPath: "@mui/material" },
162
+ { name: "useTheme", importPath: "@mui/material" },
163
+ { name: "Menu", importPath: "@mui/material" },
164
+ { name: "MenuItem", importPath: "@mui/material" },
165
+ { name: "ListItemIcon", importPath: "@mui/material" },
166
+ { name: "ListItemText", importPath: "@mui/material" },
167
+ { name: "CircularProgress", importPath: "@mui/material" },
168
+ { name: "DataGridPro", importPath: "@mui/x-data-grid-pro" },
169
+ { name: "GridLogicOperator", importPath: "@mui/x-data-grid-pro" },
170
+ { name: "GridRenderCellParams", importPath: "@mui/x-data-grid-pro" },
171
+ { name: "GridSlotsComponent", importPath: "@mui/x-data-grid-pro" },
172
+ { name: "GridToolbarProps", importPath: "@mui/x-data-grid-pro" },
173
+ { name: "GridColumnHeaderTitle", importPath: "@mui/x-data-grid-pro" },
174
+ { name: "GridToolbarQuickFilter", importPath: "@mui/x-data-grid-pro" },
175
+ { name: "GridRowOrderChangeParams", importPath: "@mui/x-data-grid-pro" },
176
+ ];
177
+ const iconsToImport = ["Add", "Edit", "Info", "Excel"];
128
178
  const props = [];
129
179
  const fieldList = (0, generateGqlFieldList_1.generateGqlFieldList)({
130
180
  columns: config.columns.filter((column) => {
@@ -161,12 +211,29 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
161
211
  });
162
212
  const gridQueryType = (0, findQueryType_1.findQueryTypeOrThrow)(gridQuery, gqlIntrospection);
163
213
  const createMutationType = (0, findMutationType_1.findMutationType)(`create${gqlType}`, gqlIntrospection);
214
+ const updateMutationType = (0, findMutationType_1.findMutationType)(`update${gqlType}`, gqlIntrospection);
164
215
  const hasDeleteMutation = !!(0, findMutationType_1.findMutationType)(`delete${gqlType}`, gqlIntrospection);
165
216
  const hasCreateMutation = !!createMutationType;
217
+ const hasUpdateMutation = !!updateMutationType;
166
218
  const allowCopyPaste = (typeof config.copyPaste === "undefined" || config.copyPaste === true) && !config.readOnly && hasCreateMutation;
167
219
  const allowAdding = (typeof config.add === "undefined" || config.add === true) && !config.readOnly;
168
220
  const allowEditing = (typeof config.edit === "undefined" || config.edit === true) && !config.readOnly;
169
221
  const allowDeleting = (typeof config.delete === "undefined" || config.delete === true) && !config.readOnly && hasDeleteMutation;
222
+ const allowRowReordering = typeof ((_a = config.rowReordering) === null || _a === void 0 ? void 0 : _a.enabled) !== "undefined" && ((_b = config.rowReordering) === null || _b === void 0 ? void 0 : _b.enabled) && hasUpdateMutation;
223
+ const updateInputArg = updateMutationType === null || updateMutationType === void 0 ? void 0 : updateMutationType.args.find((arg) => arg.name === "input");
224
+ if (allowRowReordering && updateInputArg) {
225
+ const inputType = (0, findInputObjectType_1.findInputObjectType)(updateInputArg, gqlIntrospection);
226
+ if (!inputType)
227
+ throw new Error("Can't find update input type");
228
+ if (!((_c = inputType.inputFields) === null || _c === void 0 ? void 0 : _c.find((field) => field.name === "position"))) {
229
+ throw new Error("Position field is needed when using 'rowReordering'");
230
+ }
231
+ }
232
+ const hasRowReorderingOnDragField = allowRowReordering && typeof ((_d = config.rowReordering) === null || _d === void 0 ? void 0 : _d.dragPreviewField) !== "undefined";
233
+ if (hasRowReorderingOnDragField &&
234
+ !config.columns.find((column) => { var _a; return column.type !== "actions" && (column === null || column === void 0 ? void 0 : column.name) === ((_a = config.rowReordering) === null || _a === void 0 ? void 0 : _a.dragPreviewField); })) {
235
+ throw new Error(`rowReorderingOnDragField '${(_e = config.rowReordering) === null || _e === void 0 ? void 0 : _e.dragPreviewField}' must exist in columns`);
236
+ }
170
237
  const forwardRowAction = allowEditing && config.rowActionProp;
171
238
  const showActionsColumn = allowCopyPaste || allowEditing || allowDeleting;
172
239
  const showCrudContextMenuInActionsColumn = allowCopyPaste || allowDeleting;
@@ -175,9 +242,9 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
175
242
  const { imports: forwardedGqlArgsImports, props: forwardedGqlArgsProps, gqlArgs, } = (0, getForwardedGqlArgs_1.getForwardedGqlArgs)([gridQueryType, ...(createMutationType ? [createMutationType] : [])]);
176
243
  imports.push(...forwardedGqlArgsImports);
177
244
  props.push(...forwardedGqlArgsProps);
178
- const renderToolbar = (_a = config.toolbar) !== null && _a !== void 0 ? _a : true;
245
+ const renderToolbar = (_f = config.toolbar) !== null && _f !== void 0 ? _f : true;
179
246
  const filterArg = gridQueryType.args.find((arg) => arg.name === "filter");
180
- const hasFilter = !!filterArg && renderToolbar;
247
+ const hasFilter = !!filterArg && renderToolbar && !allowRowReordering;
181
248
  let hasFilterProp = false;
182
249
  let filterFields = [];
183
250
  if (filterArg) {
@@ -223,8 +290,11 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
223
290
  if (!sortInputEnum)
224
291
  throw new Error("Can't find sortInputEnum");
225
292
  sortFields = sortInputEnum.enumValues.map((v) => v.name.replace(/_/g, "."));
293
+ if (allowRowReordering && !sortFields.includes("position")) {
294
+ throw new Error("Sort argument must include 'position' field for row reordering");
295
+ }
226
296
  }
227
- const hasSearch = gridQueryType.args.some((arg) => arg.name === "search");
297
+ const hasSearch = gridQueryType.args.some((arg) => arg.name === "search") && !allowRowReordering;
228
298
  const hasScope = gridQueryType.args.some((arg) => arg.name === "scope");
229
299
  const schemaEntity = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === gqlType);
230
300
  if (!schemaEntity)
@@ -247,7 +317,7 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
247
317
  return true;
248
318
  });
249
319
  const actionsColumnConfig = config.columns.find((column) => column.type === "actions");
250
- 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"]);
320
+ const _j = actionsColumnConfig !== null && actionsColumnConfig !== void 0 ? actionsColumnConfig : {}, { component: actionsColumnComponent, type: actionsColumnType, headerName: actionsColumnHeaderName, pinned: actionsColumnPinned = "right", width: actionsColumnWidth = defaultActionsColumnWidth, visible: actionsColumnVisible = undefined } = _j, restActionsColumnConfig = __rest(_j, ["component", "type", "headerName", "pinned", "width", "visible"]);
251
321
  if (actionsColumnComponent) {
252
322
  if (!(0, runtimeTypeGuards_1.isGeneratorConfigImport)(actionsColumnComponent)) {
253
323
  throw new Error("Unsupported actionsColumnComponent, only imports are supported");
@@ -281,6 +351,12 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
281
351
  }
282
352
  else if (type == "number") {
283
353
  gridType = "number";
354
+ const defaultDecimals = column.currency ? 2 : 0;
355
+ const decimals = typeof column.decimals === "number" ? column.decimals : defaultDecimals;
356
+ const currencyProps = column.currency ? `style="currency" currency="${column.currency}"` : "";
357
+ renderCell = `({ value }) => {
358
+ return (typeof value === "number") ? <FormattedNumber value={value} ${currencyProps} minimumFractionDigits={${decimals}} maximumFractionDigits={${decimals}} /> : "";
359
+ }`;
284
360
  }
285
361
  else if (type == "boolean") {
286
362
  gridType = "boolean";
@@ -325,10 +401,10 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
325
401
  throw new Error(`Enum type not found`);
326
402
  }
327
403
  const values = columnValues.map((value) => {
328
- if (typeof value === "string") {
404
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
329
405
  return {
330
406
  value,
331
- label: (0, camelCaseToHumanReadable_1.camelCaseToHumanReadable)(value),
407
+ label: (0, camelCaseToHumanReadable_1.camelCaseToHumanReadable)(value.toString()),
332
408
  };
333
409
  }
334
410
  else {
@@ -337,7 +413,7 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
337
413
  });
338
414
  const valueOptions = `[${values
339
415
  .map(({ value, label }) => {
340
- const labelData = getValueOptionsLabelData(`${instanceGqlType}.${name}.${value.charAt(0).toLowerCase() + value.slice(1)}`, label);
416
+ const labelData = getValueOptionsLabelData(`${instanceGqlType}.${name}.${value.toString().charAt(0).toLowerCase() + value.toString().slice(1)}`, label);
341
417
  return `{
342
418
  value: ${JSON.stringify(value)},
343
419
  label: ${labelData.textLabel},
@@ -419,7 +495,7 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
419
495
  createMutationInputFields = inputType.inputFields.filter((field) => fieldsToLoad.some((gridColumnField) => gridColumnField.name == field.name));
420
496
  }
421
497
  }
422
- const fragmentName = (_b = config.fragmentName) !== null && _b !== void 0 ? _b : `${gqlTypePlural}Form`;
498
+ const fragmentName = (_g = config.fragmentName) !== null && _g !== void 0 ? _g : `${gqlTypePlural}Form`;
423
499
  if (forwardRowAction) {
424
500
  props.push({
425
501
  name: "rowAction",
@@ -458,7 +534,7 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
458
534
  : ""}
459
535
  ${config.initialFilter
460
536
  ? `initialFilter:{ ${config.initialFilter.linkOperator
461
- ? `linkOperator: GridLinkOperator.${config.initialFilter.linkOperator === "or" ? "Or" : "And"},`
537
+ ? `linkOperator: GridLogicOperator.${config.initialFilter.linkOperator === "or" ? "Or" : "And"},`
462
538
  : ""}
463
539
  items: [${config.initialFilter.items
464
540
  .map((item) => {
@@ -469,47 +545,17 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
469
545
  ${config.queryParamsPrefix ? `queryParamsPrefix: "${config.queryParamsPrefix}",` : ""}
470
546
  }`
471
547
  : "";
472
- const code = `import { gql, useApolloClient, useQuery } from "@apollo/client";
473
- import {
474
- Button,
475
- CrudContextMenu,
476
- CrudMoreActionsMenu,
477
- DataGridToolbar,
478
- ExportApi,
479
- filterByFragment,
480
- GridFilterButton,
481
- GridCellContent,
482
- GridColDef,
483
- dataGridDateTimeColumn,
484
- dataGridDateColumn,
485
- renderStaticSelectCell,
486
- messages,
487
- muiGridFilterToGql,
488
- muiGridSortToGql,
489
- StackLink,
490
- FillSpace,
491
- Tooltip,
492
- useBufferedRowCount,
493
- useDataGridExcelExport,
494
- useDataGridRemote,
495
- usePersistentColumnState,
496
- } from "@comet/admin";
497
- import { Add as AddIcon, Edit, Info, MoreVertical, Excel } from "@comet/admin-icons";
498
- import { BlockPreviewContent } from "@comet/cms-admin";
499
- import { Alert, Box, IconButton, Typography, useTheme, Menu, MenuItem, ListItemIcon, ListItemText, CircularProgress } from "@mui/material";
500
- import { DataGridPro, GridLinkOperator, GridRenderCellParams, GridSlotsComponent, GridToolbarProps, GridColumnHeaderTitle, GridToolbarQuickFilter } from "@mui/x-data-grid-pro";
501
- import { useContentScope } from "@src/common/ContentScopeProvider";
502
- import {
548
+ const code = `import {
503
549
  GQL${gqlTypePlural}GridQuery,
504
550
  GQL${gqlTypePlural}GridQueryVariables,
505
551
  GQL${fragmentName}Fragment,
506
552
  GQLCreate${gqlType}Mutation,
507
553
  GQLCreate${gqlType}MutationVariables,
554
+ GQLUpdate${gqlType}PositionMutation,
555
+ GQLUpdate${gqlType}PositionMutationVariables,
508
556
  GQLDelete${gqlType}Mutation,
509
557
  GQLDelete${gqlType}MutationVariables
510
558
  } from "./${baseOutputFilename}.generated";
511
- import { ReactNode } from "react";
512
- import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";
513
559
  ${(0, generateImportsCode_1.generateImportsCode)(imports)}
514
560
 
515
561
  const ${instanceGqlTypePlural}Fragment = gql\`
@@ -545,6 +591,17 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
545
591
  \${${instanceGqlTypePlural}Fragment}
546
592
  \`;
547
593
 
594
+ ${allowRowReordering
595
+ ? `const update${gqlType}PositionMutation = gql\`
596
+ mutation Update${gqlType}Position($id: ID!, $input: ${gqlType}UpdateInput!) {
597
+ update${gqlType}(id: $id, input: $input) {
598
+ id
599
+ position
600
+ updatedAt
601
+ }
602
+ }
603
+ \`;`
604
+ : ""}
548
605
 
549
606
  ${allowDeleting
550
607
  ? `const delete${gqlType}Mutation = gql\`
@@ -600,6 +657,8 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
600
657
  ${hasScope ? `const { scope } = useContentScope();` : ""}
601
658
  ${gridNeedsTheme ? `const theme = useTheme();` : ""}
602
659
 
660
+ ${generateHandleRowOrderChange(allowRowReordering, gqlType, instanceGqlTypePlural)}
661
+
603
662
  const columns: GridColDef<GQL${fragmentName}Fragment>[] = [
604
663
  ${gridColumnFields
605
664
  .map((column) => {
@@ -630,7 +689,7 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
630
689
  <Tooltip
631
690
  title={<FormattedMessage id="${instanceGqlType}.${column.name}.tooltip" defaultMessage="${column.headerInfoTooltip}" />}
632
691
  >
633
- <Info sx={{ marginLeft: 1 }} />
692
+ <InfoIcon sx={{ marginLeft: 1 }} />
634
693
  </Tooltip>
635
694
  </>
636
695
  )`
@@ -639,8 +698,8 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
639
698
  ? `intl.formatMessage({ id: "${instanceGqlType}.${column.name}", defaultMessage: "${column.headerName || (0, camelCaseToHumanReadable_1.camelCaseToHumanReadable)(column.name)}" })`
640
699
  : undefined,
641
700
  type: column.gridType ? `"${column.gridType}"` : undefined,
642
- filterable: !column.filterOperators && !filterFields.includes(column.name) ? `false` : undefined,
643
- sortable: !sortFields.includes(column.name) ? `false` : undefined,
701
+ filterable: (!column.filterOperators && !filterFields.includes(column.name)) || allowRowReordering ? `false` : undefined,
702
+ sortable: !sortFields.includes(column.name) || allowRowReordering ? `false` : undefined,
644
703
  valueGetter: column.valueGetter,
645
704
  valueFormatter: column.valueFormatter,
646
705
  valueOptions: column.valueOptions,
@@ -753,17 +812,20 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
753
812
  : []
754
813
  : []),
755
814
  ...(hasSearch ? ["search: gqlSearch"] : []),
756
- ...[
757
- `offset: dataGridProps.paginationModel.page * dataGridProps.paginationModel.pageSize`,
758
- `limit: dataGridProps.paginationModel.pageSize`,
759
- `sort: muiGridSortToGql(dataGridProps.sortModel)`,
760
- ],
815
+ ...(!allowRowReordering
816
+ ? [
817
+ `offset: dataGridProps.paginationModel.page * dataGridProps.paginationModel.pageSize`,
818
+ `limit: dataGridProps.paginationModel.pageSize`,
819
+ `sort: muiGridSortToGql(dataGridProps.sortModel)`,
820
+ ]
821
+ : // TODO: offset and limit should not be necessary for row reordering but not yet possible to disable in the api generator
822
+ [`offset: 0`, `limit: 100`, `sort: { field: "position", direction: "ASC" }`]),
761
823
  ].join(", ")}
762
824
  },
763
825
  });
764
826
  const rowCount = useBufferedRowCount(data?.${gridQuery}.totalCount);
765
827
  if (error) throw error;
766
- const rows = data?.${gridQuery}.nodes ?? [];
828
+ const rows = ${!allowRowReordering ? `data?.${gridQuery}.nodes` : generateRowReorderingRows(gridQuery, fieldList, (_h = config.rowReordering) === null || _h === void 0 ? void 0 : _h.dragPreviewField)} ?? [];
767
829
 
768
830
  ${generateGridExportApi(config.excelExport, gqlTypePlural, gridQuery)}
769
831
 
@@ -779,6 +841,11 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
779
841
  toolbar: ${gridToolbarComponentName} as GridSlotsComponent["toolbar"],
780
842
  }}
781
843
  ${getDataGridSlotProps(gridToolbarComponentName, forwardToolbarAction, config.excelExport)}`
844
+ : ""}
845
+ ${allowRowReordering
846
+ ? `rowReordering
847
+ onRowOrderChange={handleRowOrderChange}
848
+ hideFooterPagination`
782
849
  : ""}
783
850
  />
784
851
  );
@@ -789,6 +856,14 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
789
856
  gqlDocuments,
790
857
  };
791
858
  }
859
+ const generateRowReorderingRows = (gridQuery, fieldList, dragPreviewField) => {
860
+ const fields = fieldList.split(" ");
861
+ const reorderField = dragPreviewField || fields.find((field) => field === "title" || field === "name") || "id";
862
+ return `data?.${gridQuery}.nodes.map((node) => ({
863
+ ...node,
864
+ __reorder__: node.${reorderField}
865
+ }))`;
866
+ };
792
867
  const getDefaultActionsColumnWidth = (showCrudContextMenu, showEdit) => {
793
868
  let numberOfActions = 0;
794
869
  if (showCrudContextMenu) {
@@ -830,3 +905,16 @@ const generateGridExportApi = (excelExport, gqlTypePlural, gridQuery) => {
830
905
  },
831
906
  });`;
832
907
  };
908
+ const generateHandleRowOrderChange = (allowRowReordering, gqlType, instanceGqlTypePlural) => {
909
+ if (!allowRowReordering) {
910
+ return "";
911
+ }
912
+ return `const handleRowOrderChange = async ({ row: { id }, targetIndex }: GridRowOrderChangeParams) => {
913
+ await client.mutate<GQLUpdate${gqlType}PositionMutation, GQLUpdate${gqlType}PositionMutationVariables>({
914
+ mutation: update${gqlType}PositionMutation,
915
+ variables: { id, input: { position: targetIndex + 1 } },
916
+ awaitRefetchQueries: true,
917
+ refetchQueries: [${instanceGqlTypePlural}Query]
918
+ });
919
+ };`;
920
+ };
@@ -59,7 +59,7 @@ const renderToolbarActions = ({ forwardToolbarAction, addItemText, excelExport,
59
59
  ${excelExport
60
60
  ? `{
61
61
  label: <FormattedMessage {...messages.downloadAsExcel} />,
62
- icon: exportApi.loading ? <CircularProgress size={20} /> : <Excel />,
62
+ icon: exportApi.loading ? <CircularProgress size={20} /> : <ExcelIcon />,
63
63
  onClick: () => exportApi.exportGrid(),
64
64
  disabled: exportApi.loading,
65
65
  }`
@@ -46,39 +46,78 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
48
  exports.writeGenerated = writeGenerated;
49
- const chalk_1 = __importDefault(require("chalk"));
50
- const eslint_1 = require("eslint");
51
49
  const fs_1 = require("fs");
52
50
  const path = __importStar(require("path"));
51
+ const typescript_1 = __importDefault(require("typescript"));
53
52
  function writeGenerated(filePath, contents) {
54
53
  return __awaiter(this, void 0, void 0, function* () {
55
54
  const header = `// This file has been generated by comet admin-generator.
56
55
  // You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment.
57
56
  `;
58
57
  yield fs_1.promises.mkdir(path.dirname(filePath), { recursive: true });
59
- const eslint = new eslint_1.ESLint({
60
- cwd: process.cwd(),
61
- fix: true,
58
+ const sourceFile = typescript_1.default.createSourceFile(filePath, header + contents, typescript_1.default.ScriptTarget.Latest, true, typescript_1.default.ScriptKind.TSX);
59
+ const result = typescript_1.default.transform(sourceFile, [removeUnusedImports()]);
60
+ const printer = typescript_1.default.createPrinter({
61
+ newLine: typescript_1.default.NewLineKind.LineFeed,
62
+ removeComments: false,
62
63
  });
63
- // Write not linted generated code into file. This is necessary to avoid linting errors like: Parsing error: file/path/file.tsx was not found by the project service.
64
- yield fs_1.promises.writeFile(filePath, header + contents);
65
- const lintResult = yield eslint.lintText(header + contents, {
66
- filePath,
67
- });
68
- if (lintResult[0].errorCount > 0 || lintResult[0].fatalErrorCount > 0) {
69
- const errorMessage = lintResult[0].messages
70
- .map((message) => {
71
- return message.message;
72
- })
73
- .join(".");
74
- console.error(chalk_1.default.red(`Linting error in ${filePath}: \n${errorMessage}`));
75
- }
76
- else if (lintResult[0].output != null) {
77
- yield fs_1.promises.writeFile(filePath, lintResult[0].output);
78
- }
79
- else {
80
- console.error(chalk_1.default.red("No output from linting"));
81
- }
64
+ const prettyCode = printer.printFile(result.transformed[0]).replace(/gql `/g, "gql`");
65
+ yield fs_1.promises.writeFile(filePath, prettyCode);
82
66
  console.log(`generated ${filePath}`);
83
67
  });
84
68
  }
69
+ // copy from @comet/api-generator
70
+ function removeUnusedImports() {
71
+ return (context) => {
72
+ function visit(sourceFile) {
73
+ const usedIdentifiers = new Set();
74
+ // Step 1: Collect all used identifiers
75
+ function collectUsage(node) {
76
+ if (typescript_1.default.isIdentifier(node)) {
77
+ usedIdentifiers.add(node.text);
78
+ }
79
+ else if (typescript_1.default.isImportDeclaration(node)) {
80
+ // Skip import declarations (those identifiers are not usages)
81
+ return;
82
+ }
83
+ typescript_1.default.forEachChild(node, collectUsage);
84
+ }
85
+ typescript_1.default.forEachChild(sourceFile, collectUsage);
86
+ // Step 2: Visit and update the import declarations
87
+ function visitor(node) {
88
+ if (typescript_1.default.isImportDeclaration(node) && node.importClause) {
89
+ const { name, namedBindings } = node.importClause;
90
+ const updatedBindings = [];
91
+ if (name && usedIdentifiers.has(name.text)) {
92
+ // default import is used
93
+ }
94
+ else if (name) {
95
+ // default import is unused
96
+ return undefined;
97
+ }
98
+ if (namedBindings && typescript_1.default.isNamedImports(namedBindings)) {
99
+ for (const specifier of namedBindings.elements) {
100
+ const importName = specifier.name.text;
101
+ if (usedIdentifiers.has(importName)) {
102
+ updatedBindings.push(specifier);
103
+ }
104
+ }
105
+ if (updatedBindings.length === 0 && !name) {
106
+ // nothing left in this import
107
+ return undefined;
108
+ }
109
+ return typescript_1.default.factory.updateImportDeclaration(node, node.modifiers, typescript_1.default.factory.updateImportClause(node.importClause, node.importClause.isTypeOnly, name, updatedBindings.length > 0 ? typescript_1.default.factory.updateNamedImports(namedBindings, updatedBindings) : undefined), node.moduleSpecifier, node.assertClause);
110
+ }
111
+ if (!namedBindings && !name) {
112
+ // empty import, probably a side-effect import
113
+ return node;
114
+ }
115
+ return node;
116
+ }
117
+ return typescript_1.default.visitEachChild(node, visitor, context);
118
+ }
119
+ return typescript_1.default.visitNode(sourceFile, visitor);
120
+ }
121
+ return (sourceFile) => visit(sourceFile);
122
+ };
123
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comet/admin-generator",
3
- "version": "8.0.0-beta.4",
3
+ "version": "8.0.0-beta.6",
4
4
  "repository": {
5
5
  "directory": "packages/admin/admin-generator",
6
6
  "type": "git",
@@ -19,24 +19,22 @@
19
19
  "dependencies": {
20
20
  "@graphql-tools/graphql-file-loader": "^7.5.17",
21
21
  "@graphql-tools/load": "^7.8.14",
22
- "chalk": "^5.4.1",
23
22
  "change-case": "^4.1.2",
24
23
  "commander": "^9.5.0",
25
24
  "glob": "^10.4.5",
26
25
  "graphql": "^16.10.0",
27
26
  "object-path": "^0.11.8",
28
27
  "pluralize": "^8.0.0",
29
- "ts-morph": "^25.0.1",
30
28
  "ts-node": "^10.9.2"
31
29
  },
32
30
  "devDependencies": {
33
- "@mui/material": "^7.0.0",
34
- "@mui/x-data-grid": "^7.28.1",
31
+ "@mui/material": "^7.1.0",
32
+ "@mui/x-data-grid": "^7.29.4",
35
33
  "@types/jest": "^29.5.14",
36
- "@types/node": "^22.14.0",
34
+ "@types/node": "^22.15.34",
37
35
  "@types/object-path": "^0.11.4",
38
36
  "@types/pluralize": "^0.0.33",
39
- "@types/react": "^18.3.20",
37
+ "@types/react": "^18.3.22",
40
38
  "eslint": "^9.22.0",
41
39
  "final-form": "^4.20.10",
42
40
  "jest": "^29.7.0",
@@ -47,10 +45,10 @@
47
45
  "rimraf": "^6.0.1",
48
46
  "ts-jest": "^29.2.6",
49
47
  "typescript": "^5.7.3",
50
- "@comet/admin": "8.0.0-beta.4",
51
- "@comet/admin-icons": "8.0.0-beta.4",
52
- "@comet/cms-admin": "8.0.0-beta.4",
53
- "@comet/eslint-config": "8.0.0-beta.4"
48
+ "@comet/admin": "8.0.0-beta.6",
49
+ "@comet/admin-icons": "8.0.0-beta.6",
50
+ "@comet/cms-admin": "8.0.0-beta.6",
51
+ "@comet/eslint-config": "8.0.0-beta.6"
54
52
  },
55
53
  "engines": {
56
54
  "node": ">=22.0.0"
@@ -67,7 +65,7 @@
67
65
  "lint:eslint": "eslint --max-warnings 0 src/ **/*.json --no-warn-ignored",
68
66
  "lint:prettier": "npx prettier --check './**/*.{js,json,md,yml,yaml}'",
69
67
  "lint:tsc": "tsc",
70
- "test": "jest --passWithNoTests",
71
- "test:watch": "jest --watch"
68
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests",
69
+ "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
72
70
  }
73
71
  }
@@ -1,4 +0,0 @@
1
- import { type SourceFile } from "ts-morph";
2
- import { type GeneratorConfig } from "../generate-command";
3
- export declare function morphTsSource(path: string): SourceFile;
4
- export declare function configFromSourceFile(sourceFile: SourceFile): GeneratorConfig<any>;