@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.
- package/bin/admin-generator.js +3 -0
- package/lib/commands/generate/config/parseConfig.d.ts +1 -0
- package/lib/commands/generate/config/parseConfig.js +72 -0
- package/lib/commands/generate/config/transformConfig.d.ts +1 -0
- package/lib/commands/generate/config/transformConfig.js +239 -0
- package/lib/commands/generate/generate-command.d.ts +14 -9
- package/lib/commands/generate/generate-command.js +26 -21
- package/lib/commands/generate/generateForm/generateForm.js +51 -36
- package/lib/commands/generate/generateForm/generateFormField.js +14 -4
- package/lib/commands/generate/generateGrid/generateGrid.js +139 -53
- package/lib/commands/generate/generateGrid/generateGridToolbar.js +5 -12
- package/lib/commands/generate/generateGrid/usableFields.d.ts +4 -3
- package/lib/commands/generate/generateGrid/usableFields.js +1 -0
- package/lib/commands/generate/utils/writeGenerated.js +63 -24
- package/lib/index.d.ts +1 -0
- package/lib/index.js +3 -0
- package/package.json +12 -14
- package/lib/commands/generate/utils/tsMorphHelper.d.ts +0 -4
- package/lib/commands/generate/utils/tsMorphHelper.js +0 -199
|
@@ -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
|
-
|
|
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 = (
|
|
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
|
|
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 = (
|
|
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:
|
|
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 {
|
|
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
|
-
<
|
|
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
|
-
|
|
760
|
-
|
|
761
|
-
|
|
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 ?
|
|
13
|
-
${hasFilter ?
|
|
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} /> : <
|
|
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
|
|
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
|
|
2
|
-
|
|
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 {};
|
|
@@ -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
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
64
|
-
yield fs_1.promises.writeFile(filePath,
|
|
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
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
|
+
"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": "^
|
|
34
|
-
"@mui/x-data-grid": "^7.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
51
|
-
"@comet/admin-icons": "8.0.0-beta.
|
|
52
|
-
"@comet/cms-admin": "8.0.0-beta.
|
|
53
|
-
"@comet/eslint-config": "8.0.0-beta.
|
|
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>;
|