@comet/admin-generator 8.0.0-beta.3 → 8.0.0-beta.5

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";
@@ -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,49 +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
- ToolbarActions,
491
- FillSpace,
492
- ToolbarItem,
493
- Tooltip,
494
- useBufferedRowCount,
495
- useDataGridExcelExport,
496
- useDataGridRemote,
497
- usePersistentColumnState,
498
- } from "@comet/admin";
499
- import { Add as AddIcon, Edit, Info, MoreVertical, Excel } from "@comet/admin-icons";
500
- import { BlockPreviewContent } from "@comet/cms-admin";
501
- import { Alert, Box, IconButton, Typography, useTheme, Menu, MenuItem, ListItemIcon, ListItemText, CircularProgress } from "@mui/material";
502
- import { DataGridPro, GridLinkOperator, GridRenderCellParams, GridSlotsComponent, GridToolbarProps, GridColumnHeaderTitle, GridToolbarQuickFilter } from "@mui/x-data-grid-pro";
503
- import { useContentScope } from "@src/common/ContentScopeProvider";
504
- import {
548
+ const code = `import {
505
549
  GQL${gqlTypePlural}GridQuery,
506
550
  GQL${gqlTypePlural}GridQueryVariables,
507
551
  GQL${fragmentName}Fragment,
508
552
  GQLCreate${gqlType}Mutation,
509
553
  GQLCreate${gqlType}MutationVariables,
554
+ GQLUpdate${gqlType}PositionMutation,
555
+ GQLUpdate${gqlType}PositionMutationVariables,
510
556
  GQLDelete${gqlType}Mutation,
511
557
  GQLDelete${gqlType}MutationVariables
512
558
  } from "./${baseOutputFilename}.generated";
513
- import { ReactNode } from "react";
514
- import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";
515
559
  ${(0, generateImportsCode_1.generateImportsCode)(imports)}
516
560
 
517
561
  const ${instanceGqlTypePlural}Fragment = gql\`
@@ -547,6 +591,17 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
547
591
  \${${instanceGqlTypePlural}Fragment}
548
592
  \`;
549
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
+ : ""}
550
605
 
551
606
  ${allowDeleting
552
607
  ? `const delete${gqlType}Mutation = gql\`
@@ -602,6 +657,8 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
602
657
  ${hasScope ? `const { scope } = useContentScope();` : ""}
603
658
  ${gridNeedsTheme ? `const theme = useTheme();` : ""}
604
659
 
660
+ ${generateHandleRowOrderChange(allowRowReordering, gqlType, instanceGqlTypePlural)}
661
+
605
662
  const columns: GridColDef<GQL${fragmentName}Fragment>[] = [
606
663
  ${gridColumnFields
607
664
  .map((column) => {
@@ -632,7 +689,7 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
632
689
  <Tooltip
633
690
  title={<FormattedMessage id="${instanceGqlType}.${column.name}.tooltip" defaultMessage="${column.headerInfoTooltip}" />}
634
691
  >
635
- <Info sx={{ marginLeft: 1 }} />
692
+ <InfoIcon sx={{ marginLeft: 1 }} />
636
693
  </Tooltip>
637
694
  </>
638
695
  )`
@@ -641,8 +698,8 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
641
698
  ? `intl.formatMessage({ id: "${instanceGqlType}.${column.name}", defaultMessage: "${column.headerName || (0, camelCaseToHumanReadable_1.camelCaseToHumanReadable)(column.name)}" })`
642
699
  : undefined,
643
700
  type: column.gridType ? `"${column.gridType}"` : undefined,
644
- filterable: !column.filterOperators && !filterFields.includes(column.name) ? `false` : undefined,
645
- 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,
646
703
  valueGetter: column.valueGetter,
647
704
  valueFormatter: column.valueFormatter,
648
705
  valueOptions: column.valueOptions,
@@ -755,17 +812,20 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
755
812
  : []
756
813
  : []),
757
814
  ...(hasSearch ? ["search: gqlSearch"] : []),
758
- ...[
759
- `offset: dataGridProps.paginationModel.page * dataGridProps.paginationModel.pageSize`,
760
- `limit: dataGridProps.paginationModel.pageSize`,
761
- `sort: muiGridSortToGql(dataGridProps.sortModel)`,
762
- ],
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" }`]),
763
823
  ].join(", ")}
764
824
  },
765
825
  });
766
826
  const rowCount = useBufferedRowCount(data?.${gridQuery}.totalCount);
767
827
  if (error) throw error;
768
- 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)} ?? [];
769
829
 
770
830
  ${generateGridExportApi(config.excelExport, gqlTypePlural, gridQuery)}
771
831
 
@@ -781,6 +841,11 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
781
841
  toolbar: ${gridToolbarComponentName} as GridSlotsComponent["toolbar"],
782
842
  }}
783
843
  ${getDataGridSlotProps(gridToolbarComponentName, forwardToolbarAction, config.excelExport)}`
844
+ : ""}
845
+ ${allowRowReordering
846
+ ? `rowReordering
847
+ onRowOrderChange={handleRowOrderChange}
848
+ hideFooterPagination`
784
849
  : ""}
785
850
  />
786
851
  );
@@ -791,6 +856,14 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
791
856
  gqlDocuments,
792
857
  };
793
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
+ };
794
867
  const getDefaultActionsColumnWidth = (showCrudContextMenu, showEdit) => {
795
868
  let numberOfActions = 0;
796
869
  if (showCrudContextMenu) {
@@ -832,3 +905,16 @@ const generateGridExportApi = (excelExport, gqlTypePlural, gridQuery) => {
832
905
  },
833
906
  });`;
834
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
+ };
@@ -9,8 +9,8 @@ const generateGridToolbar = ({ componentName, forwardToolbarAction, hasSearch, h
9
9
  function ${componentName}(${getGridToolbarProps(componentName, !!forwardToolbarAction, !!excelExport)}) {
10
10
  return (
11
11
  <DataGridToolbar>
12
- ${hasSearch ? searchItem : ""}
13
- ${hasFilter ? filterItem : ""}
12
+ ${hasSearch ? "<GridToolbarQuickFilter />" : ""}
13
+ ${hasFilter ? "<GridFilterButton />" : ""}
14
14
  <FillSpace />
15
15
  ${renderToolbarActions({
16
16
  forwardToolbarAction,
@@ -44,12 +44,6 @@ const getGridToolbarProps = (componentName, toolbarAction, exportApi) => {
44
44
  ${props.map((prop) => `${prop.destructured}`).join(",")}
45
45
  }: ${componentName}ToolbarProps`;
46
46
  };
47
- const searchItem = `<ToolbarItem>
48
- <GridToolbarQuickFilter />
49
- </ToolbarItem>`;
50
- const filterItem = `<ToolbarItem>
51
- <GridFilterButton />
52
- </ToolbarItem>`;
53
47
  const renderToolbarActions = ({ forwardToolbarAction, addItemText, excelExport, allowAdding }) => {
54
48
  const showMoreActionsMenu = excelExport;
55
49
  if (!showMoreActionsMenu && !allowAdding) {
@@ -65,7 +59,7 @@ const renderToolbarActions = ({ forwardToolbarAction, addItemText, excelExport,
65
59
  ${excelExport
66
60
  ? `{
67
61
  label: <FormattedMessage {...messages.downloadAsExcel} />,
68
- icon: exportApi.loading ? <CircularProgress size={20} /> : <Excel />,
62
+ icon: exportApi.loading ? <CircularProgress size={20} /> : <ExcelIcon />,
69
63
  onClick: () => exportApi.exportGrid(),
70
64
  disabled: exportApi.loading,
71
65
  }`
@@ -76,10 +70,9 @@ const renderToolbarActions = ({ forwardToolbarAction, addItemText, excelExport,
76
70
  ${addItemText}
77
71
  </Button>`;
78
72
  const addAction = forwardToolbarAction ? "{toolbarAction}" : defaultAddItemButton;
79
- return `<ToolbarActions>
73
+ return `
80
74
  ${showMoreActionsMenu ? moreActionsMenu : ""}
81
- ${allowAdding ? addAction : ""}
82
- </ToolbarActions>`;
75
+ ${allowAdding ? addAction : ""}`;
83
76
  };
84
77
  const renderToolbarProps = (componentName, forwardToolbarAction, exportApi) => {
85
78
  if (forwardToolbarAction || exportApi) {
@@ -1,8 +1,9 @@
1
- type GqlLeaves<T> = T extends any ? "__typename" extends keyof T ? {
2
- [K in keyof T as K extends "__typename" ? never : K]-?: GqlLeaves<T[K]>;
1
+ type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
2
+ type GqlLeaves<T, FollowArrays extends boolean = false, Depth extends number = 5> = [Depth] extends [never] ? never : T extends any ? T extends Array<infer ArrayType> ? FollowArrays extends true ? GqlLeaves<ArrayType, FollowArrays, Prev[Depth]> : never : "__typename" extends keyof T ? {
3
+ [K in keyof T as K extends "__typename" ? never : K]-?: GqlLeaves<T[K], FollowArrays, Prev[Depth]>;
3
4
  } : never : never;
4
5
  type FieldNames<T> = {
5
6
  [K in keyof T]: `${Exclude<K, symbol>}${FieldNames<T[K]> extends never ? "" : `.${FieldNames<T[K]>}`}`;
6
7
  }[keyof T];
7
- export type UsableFields<T> = FieldNames<GqlLeaves<T>>;
8
+ export type UsableFields<T, FollowArrays extends boolean = false> = FieldNames<GqlLeaves<T, FollowArrays>>;
8
9
  export {};
@@ -1,2 +1,3 @@
1
1
  "use strict";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -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/lib/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export type { FormConfig, FormFieldConfig, GeneratorConfig, GridColumnConfig, GridConfig } from "./commands/generate/generate-command";
2
+ export { defineConfig } from "./commands/generate/generate-command";
package/lib/index.js CHANGED
@@ -1,2 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defineConfig = void 0;
4
+ var generate_command_1 = require("./commands/generate/generate-command");
5
+ Object.defineProperty(exports, "defineConfig", { enumerable: true, get: function () { return generate_command_1.defineConfig; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comet/admin-generator",
3
- "version": "8.0.0-beta.3",
3
+ "version": "8.0.0-beta.5",
4
4
  "repository": {
5
5
  "directory": "packages/admin/admin-generator",
6
6
  "type": "git",
@@ -19,38 +19,36 @@
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": "^6.4.8",
34
- "@mui/x-data-grid": "^7.28.0",
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.13.10",
34
+ "@types/node": "^22.15.21",
37
35
  "@types/object-path": "^0.11.4",
38
36
  "@types/pluralize": "^0.0.33",
39
- "@types/react": "^18.3.19",
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",
43
41
  "npm-run-all2": "^5.0.2",
44
42
  "prettier": "^3.5.3",
45
43
  "react": "^18.3.1",
46
- "react-intl": "^7.1.6",
44
+ "react-intl": "^7.1.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.3",
51
- "@comet/admin-icons": "8.0.0-beta.3",
52
- "@comet/cms-admin": "8.0.0-beta.3",
53
- "@comet/eslint-config": "8.0.0-beta.3"
48
+ "@comet/admin": "8.0.0-beta.5",
49
+ "@comet/admin-icons": "8.0.0-beta.5",
50
+ "@comet/cms-admin": "8.0.0-beta.5",
51
+ "@comet/eslint-config": "8.0.0-beta.5"
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 configsFromSourceFile(sourceFile: SourceFile): Record<string, GeneratorConfig>;