@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.
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env node
2
+
2
3
  require("ts-node").register({
3
4
  require: ["tsconfig-paths/register"],
5
+ transpileOnly: true,
4
6
  });
7
+
5
8
  require("../lib/adminGenerator");
@@ -0,0 +1 @@
1
+ export declare function parseConfig(file: string): Promise<any>;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.parseConfig = parseConfig;
46
+ const fs_1 = require("fs");
47
+ const path_1 = require("path");
48
+ const transformConfig_1 = require("./transformConfig");
49
+ function parseConfig(file) {
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ //1. parse config file using TypeScript Complier Api and transform it (replace imports and functions that can't be executed)
52
+ const transformedConfig = (0, transformConfig_1.transformConfigFile)(file, yield fs_1.promises.readFile(file, "utf-8"));
53
+ //2. save modified config file to temp file
54
+ const tempFileName = `${(0, path_1.dirname)(file)}/.temp-${(0, path_1.basename)(file)}`;
55
+ yield fs_1.promises.writeFile(tempFileName, transformedConfig, "utf-8");
56
+ //3. import (=execute) temp modified config file
57
+ let executedConfig;
58
+ try {
59
+ const configFile = yield Promise.resolve(`${tempFileName.replace(/\.tsx?$/, "")}`).then(s => __importStar(require(s)));
60
+ if (!configFile.default) {
61
+ throw new Error(`No default export found in ${file}`);
62
+ }
63
+ executedConfig = configFile.default;
64
+ }
65
+ catch (e) {
66
+ console.error(e);
67
+ throw new Error(`Error executing config file ${file}: ${e}`);
68
+ }
69
+ yield fs_1.promises.rm(tempFileName);
70
+ return executedConfig;
71
+ });
72
+ }
@@ -0,0 +1 @@
1
+ export declare function transformConfigFile(fileName: string, sourceText: string): string;
@@ -0,0 +1,239 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.transformConfigFile = transformConfigFile;
37
+ const ts = __importStar(require("typescript"));
38
+ const supportedImportPaths = [
39
+ "[type=grid].columns.filterOperators",
40
+ "[type=grid].columns.block",
41
+ "[type=grid].columns.component",
42
+ // TODO implement in generator "[type=grid].columns.renderCell",
43
+ //support in up to 5 levels of nested fields (eg. fieldSet)
44
+ ...Array.from(Array(5).keys()).map((i) => `[type=form]${".fields".repeat(i + 1)}.validate`),
45
+ ...Array.from(Array(5).keys()).map((i) => `[type=form]${".fields".repeat(i + 1)}.block`),
46
+ ...Array.from(Array(5).keys()).map((i) => `[type=form]${".fields".repeat(i + 1)}.component`),
47
+ ];
48
+ const supportedInlineCodePaths = [
49
+ // TODO implement in generator "[type=grid].columns.filterOperators",
50
+ "[type=grid].columns.renderCell",
51
+ //support in up to 5 levels of nested fields (eg. fieldSet)
52
+ ...Array.from(Array(5).keys()).map((i) => `[type=form]${".fields".repeat(i + 1)}.validate`),
53
+ ];
54
+ // transform the config file to replace all imports and inline code with a { code, imports } object
55
+ // this is needed to be able to execute the config file in a node environment
56
+ function transformConfigFile(fileName, sourceText) {
57
+ const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.ES2024, // language version
58
+ true);
59
+ const importedIdentifiers = collectImports(sourceFile);
60
+ function configTransformer() {
61
+ return (context) => {
62
+ const visit = (node, path) => {
63
+ if (ts.isArrowFunction(node)) {
64
+ if (supportedInlineCodePaths.includes(path)) {
65
+ let code = node.getText();
66
+ if (code.endsWith(","))
67
+ code = code.slice(0, -1); // for some unknown reason node can contain the trailing comma
68
+ const imports = findUsedImports(node.body, importedIdentifiers); //find all imports used in the function body
69
+ // replace inline code with { code, imports } object
70
+ return ts.factory.createObjectLiteralExpression([
71
+ ts.factory.createPropertyAssignment("code", ts.factory.createStringLiteral(code)),
72
+ ts.factory.createPropertyAssignment("imports", ts.factory.createArrayLiteralExpression(imports.map((imprt) => {
73
+ return ts.factory.createObjectLiteralExpression([
74
+ ts.factory.createPropertyAssignment("name", ts.factory.createStringLiteral(imprt.name)),
75
+ ts.factory.createPropertyAssignment("import", ts.factory.createStringLiteral(imprt.import)),
76
+ ]);
77
+ }))),
78
+ ], true);
79
+ }
80
+ else {
81
+ throw new Error(`Inline Function is not allowed here and calling the function is not supported: ${path}`);
82
+ }
83
+ }
84
+ else if (ts.isIdentifier(node)) {
85
+ const imported = importedIdentifiers.get(node.text);
86
+ if (imported) {
87
+ if (supportedImportPaths.includes(path)) {
88
+ // replace imported identifier with { name, import } object
89
+ return ts.factory.createObjectLiteralExpression([
90
+ ts.factory.createPropertyAssignment("name", ts.factory.createStringLiteral(node.text)),
91
+ ts.factory.createPropertyAssignment("import", ts.factory.createStringLiteral(imported.import)),
92
+ ], true);
93
+ }
94
+ else {
95
+ throw new Error(`Following the import is not supported: ${path} ${node.text}`);
96
+ }
97
+ }
98
+ }
99
+ const transformKinds = [
100
+ ts.SyntaxKind.Identifier,
101
+ ts.SyntaxKind.ArrayLiteralExpression,
102
+ ts.SyntaxKind.ObjectLiteralExpression,
103
+ ts.SyntaxKind.TaggedTemplateExpression,
104
+ ts.SyntaxKind.SpreadElement,
105
+ ts.SyntaxKind.PropertyAssignment,
106
+ ts.SyntaxKind.ShorthandPropertyAssignment,
107
+ ];
108
+ if (!transformKinds.includes(node.kind)) {
109
+ // if the node is not one of the transformKinds, stop transformation at this level return it as is
110
+ return node;
111
+ }
112
+ let newPath = path;
113
+ if (path == "") {
114
+ // first entry of path is the type, then property names (. separated) are added
115
+ if (ts.isObjectLiteralExpression(node)) {
116
+ const typeProperty = getTypePropertyFromObjectLiteral(node);
117
+ newPath = typeProperty ? `[type=${typeProperty}]` : "";
118
+ }
119
+ }
120
+ else {
121
+ if (ts.isPropertyAssignment(node)) {
122
+ newPath = `${path}.${node.name.getText()}`;
123
+ }
124
+ }
125
+ return ts.visitEachChild(node, (child) => {
126
+ return visit(child, newPath);
127
+ }, context);
128
+ };
129
+ return (node) => ts.visitNode(node, (child) => visit(child, ""));
130
+ };
131
+ }
132
+ const configNode = findConfigNode(sourceFile);
133
+ const transformedConfigNode = ts.transform(configNode, [configTransformer()]).transformed[0];
134
+ const updatedSource = ts.transform(sourceFile, [
135
+ (context) => {
136
+ const visitor = (node) => {
137
+ if (node === configNode)
138
+ return transformedConfigNode;
139
+ return ts.visitEachChild(node, visitor, context);
140
+ };
141
+ return (node) => ts.visitNode(node, visitor);
142
+ },
143
+ ]).transformed[0];
144
+ const printer = ts.createPrinter();
145
+ return printer.printFile(updatedSource);
146
+ }
147
+ // finds the config node in the source file (=default export, might be wrapped in defineConfig or uses satisfies)
148
+ function findConfigNode(sourceFile) {
149
+ let ret;
150
+ sourceFile.forEachChild((node) => {
151
+ if (ts.isExportAssignment(node)) {
152
+ const exportedNode = node.expression;
153
+ if (ts.isCallExpression(exportedNode) && exportedNode.expression.getText() == "defineConfig") {
154
+ //export default defineConfig<Foo>({ ... });
155
+ const args = exportedNode.arguments;
156
+ if (args.length != 1) {
157
+ throw new Error(`Expected exactly one argument for defineConfig`);
158
+ }
159
+ ret = args[0];
160
+ return false;
161
+ }
162
+ else if (ts.isSatisfiesExpression(exportedNode)) {
163
+ //export default { ... } satisfies GeneratorConfig<Foo>;
164
+ if (ts.isObjectLiteralExpression(exportedNode.expression)) {
165
+ ret = exportedNode.expression;
166
+ return false;
167
+ }
168
+ }
169
+ else if (ts.isObjectLiteralExpression(exportedNode)) {
170
+ //export default { ... };
171
+ ret = exportedNode;
172
+ return false;
173
+ }
174
+ }
175
+ });
176
+ if (!ret) {
177
+ throw new Error(`No default export found, please export the GeneratorConfig as default, preferrable using defineConfig helper.`);
178
+ }
179
+ return ret;
180
+ }
181
+ // simple helper that extracts the value of the type property from a object literal ({ type: "grid" } returns "grid")
182
+ function getTypePropertyFromObjectLiteral(node) {
183
+ for (const property of node.properties) {
184
+ if (ts.isPropertyAssignment(property)) {
185
+ if (property.name.getText() == "type") {
186
+ const propertyAssignmentInitializer = property.initializer;
187
+ if (ts.isStringLiteral(propertyAssignmentInitializer)) {
188
+ return propertyAssignmentInitializer.text;
189
+ }
190
+ }
191
+ }
192
+ }
193
+ return null;
194
+ }
195
+ // visits ast and collects all imports statements in the source file
196
+ function collectImports(rootNode) {
197
+ const importedIdentifiers = new Map();
198
+ function visit(node) {
199
+ if (ts.isImportDeclaration(node) &&
200
+ node.importClause &&
201
+ node.importClause.namedBindings &&
202
+ ts.isNamedImports(node.importClause.namedBindings)) {
203
+ const moduleSpecifier = node.moduleSpecifier.text;
204
+ for (const element of node.importClause.namedBindings.elements) {
205
+ const localName = element.name.text;
206
+ const originalName = element.propertyName ? element.propertyName.text : localName;
207
+ importedIdentifiers.set(localName, {
208
+ name: originalName,
209
+ import: moduleSpecifier,
210
+ });
211
+ }
212
+ }
213
+ ts.forEachChild(node, visit);
214
+ }
215
+ visit(rootNode);
216
+ return importedIdentifiers;
217
+ }
218
+ // visits ast and collects all identifiers that are an import
219
+ function findUsedImports(rootNode, importedIdentifiers) {
220
+ const imports = [];
221
+ const usedNames = new Set();
222
+ // Collect all identifiers used in the rootNode
223
+ function collectUsedIdentifiers(node) {
224
+ if (ts.isIdentifier(node)) {
225
+ usedNames.add(node.text);
226
+ }
227
+ ts.forEachChild(node, collectUsedIdentifiers);
228
+ }
229
+ collectUsedIdentifiers(rootNode);
230
+ // Match used identifiers to imported ones
231
+ // NOTE: this is not 100% correct as it doesn't recognize cases where a import is overwritten by a local variable. But it is fast.
232
+ for (const name of usedNames) {
233
+ const imported = importedIdentifiers.get(name);
234
+ if (imported) {
235
+ imports.push(imported);
236
+ }
237
+ }
238
+ return imports;
239
+ }
@@ -40,6 +40,7 @@ export type FormFieldConfig<T> = (({
40
40
  multiline?: boolean;
41
41
  } & InputBaseFieldConfig) | ({
42
42
  type: "number";
43
+ decimals?: number;
43
44
  } & InputBaseFieldConfig) | ({
44
45
  type: "numberRange";
45
46
  minValue: number;
@@ -105,13 +106,6 @@ export type FormConfig<T extends {
105
106
  createMutation?: string;
106
107
  fields: (FormFieldConfig<T> | FormLayoutConfig<T> | ComponentFormFieldConfig)[];
107
108
  };
108
- type TabsConfig = {
109
- type: "tabs";
110
- tabs: {
111
- name: string;
112
- content: GeneratorConfig;
113
- }[];
114
- };
115
109
  type BaseColumnConfig = Pick<GridColDef, "headerName" | "width" | "minWidth" | "maxWidth" | "flex" | "pinned" | "disableExport"> & {
116
110
  headerInfoTooltip?: string;
117
111
  visible?: ColumnVisibleOption;
@@ -127,6 +121,8 @@ export type GridColumnConfig<T extends GridValidRowModel> = ({
127
121
  renderCell?: (params: GridRenderCellParams<T, any, any>) => JSX.Element;
128
122
  } | {
129
123
  type: "number";
124
+ currency?: string;
125
+ decimals?: number;
130
126
  renderCell?: (params: GridRenderCellParams<T, any, any>) => JSX.Element;
131
127
  } | {
132
128
  type: "boolean";
@@ -157,7 +153,7 @@ export type ActionsGridColumnConfig = {
157
153
  export type VirtualGridColumnConfig<T extends GridValidRowModel> = {
158
154
  type: "virtual";
159
155
  name: string;
160
- queryFields?: UsableFields<T>[];
156
+ queryFields?: UsableFields<T, true>[];
161
157
  renderCell: (params: GridRenderCellParams<T, any, any>) => JSX.Element;
162
158
  } & Pick<GridColDef, "sortBy"> & BaseColumnConfig;
163
159
  type InitialFilterConfig = {
@@ -190,8 +186,17 @@ export type GridConfig<T extends {
190
186
  newEntryText?: string;
191
187
  rowActionProp?: boolean;
192
188
  selectionProps?: "multiSelect" | "singleSelect";
189
+ rowReordering?: {
190
+ enabled: boolean;
191
+ dragPreviewField?: UsableFields<T>;
192
+ };
193
193
  };
194
- export type GeneratorConfig = FormConfig<any> | GridConfig<any> | TabsConfig;
194
+ export type GeneratorConfig<T extends {
195
+ __typename?: string;
196
+ }> = FormConfig<T> | GridConfig<T>;
197
+ export declare function defineConfig<T extends {
198
+ __typename?: string;
199
+ }>(config: GeneratorConfig<T>): GeneratorConfig<T>;
195
200
  type GQLDocumentConfig = {
196
201
  document: string;
197
202
  export: boolean;
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.generateCommand = void 0;
13
13
  exports.isFormFieldConfig = isFormFieldConfig;
14
14
  exports.isFormLayoutConfig = isFormLayoutConfig;
15
+ exports.defineConfig = defineConfig;
15
16
  const graphql_file_loader_1 = require("@graphql-tools/graphql-file-loader");
16
17
  const load_1 = require("@graphql-tools/load");
17
18
  const commander_1 = require("commander");
@@ -19,9 +20,9 @@ const fs_1 = require("fs");
19
20
  const glob_1 = require("glob");
20
21
  const graphql_1 = require("graphql");
21
22
  const path_1 = require("path");
23
+ const parseConfig_1 = require("./config/parseConfig");
22
24
  const generateForm_1 = require("./generateForm/generateForm");
23
25
  const generateGrid_1 = require("./generateGrid/generateGrid");
24
- const tsMorphHelper_1 = require("./utils/tsMorphHelper");
25
26
  const writeGenerated_1 = require("./utils/writeGenerated");
26
27
  function isFormFieldConfig(arg) {
27
28
  return !isFormLayoutConfig(arg);
@@ -29,11 +30,15 @@ function isFormFieldConfig(arg) {
29
30
  function isFormLayoutConfig(arg) {
30
31
  return arg.type !== undefined && ["fieldSet", "optionalNestedFields"].includes(arg.type);
31
32
  }
33
+ function defineConfig(config) {
34
+ return config;
35
+ }
32
36
  /**
33
37
  * @experimental
34
38
  */
35
39
  function runGenerate() {
36
40
  return __awaiter(this, arguments, void 0, function* (filePattern = "src/**/*.cometGen.{ts,tsx}") {
41
+ var _a;
37
42
  const schema = yield (0, load_1.loadSchema)("./schema.gql", {
38
43
  loaders: [new graphql_file_loader_1.GraphQLFileLoader()],
39
44
  });
@@ -44,28 +49,27 @@ function runGenerate() {
44
49
  let gqlDocumentsOutputCode = "";
45
50
  const targetDirectory = `${(0, path_1.dirname)(file)}/generated`;
46
51
  const baseOutputFilename = (0, path_1.basename)(file).replace(/\.cometGen\.tsx?$/, "");
47
- const configs = (0, tsMorphHelper_1.configsFromSourceFile)((0, tsMorphHelper_1.morphTsSource)(file));
48
- //const configs = await import(`${process.cwd()}/${file.replace(/\.ts$/, "")}`);
52
+ console.log(`generating ${file}`);
53
+ const config = yield (0, parseConfig_1.parseConfig)(file);
49
54
  const codeOuputFilename = `${targetDirectory}/${(0, path_1.basename)(file.replace(/\.cometGen\.tsx?$/, ""))}.tsx`;
50
55
  yield fs_1.promises.rm(codeOuputFilename, { force: true });
51
- console.log(`generating ${file}`);
52
- for (const exportName in configs) {
53
- const config = configs[exportName];
54
- let generated;
55
- if (config.type == "form") {
56
- generated = (0, generateForm_1.generateForm)({ exportName, gqlIntrospection, baseOutputFilename, targetDirectory }, config);
57
- }
58
- else if (config.type == "grid") {
59
- generated = (0, generateGrid_1.generateGrid)({ exportName, gqlIntrospection, baseOutputFilename, targetDirectory }, config);
60
- }
61
- else {
62
- throw new Error(`Unknown config type: ${config.type}`);
63
- }
64
- outputCode += generated.code;
65
- for (const queryName in generated.gqlDocuments) {
66
- const exportStatement = generated.gqlDocuments[queryName].export ? "export " : "";
67
- gqlDocumentsOutputCode += `${exportStatement} const ${queryName} = gql\`${generated.gqlDocuments[queryName].document}\`\n`;
68
- }
56
+ const exportName = (_a = file.match(/([^/]+)\.cometGen\.tsx?$/)) === null || _a === void 0 ? void 0 : _a[1];
57
+ if (!exportName)
58
+ throw new Error("Can not determine exportName");
59
+ let generated;
60
+ if (config.type == "form") {
61
+ generated = (0, generateForm_1.generateForm)({ exportName, gqlIntrospection, baseOutputFilename, targetDirectory }, config);
62
+ }
63
+ else if (config.type == "grid") {
64
+ generated = (0, generateGrid_1.generateGrid)({ exportName, gqlIntrospection, baseOutputFilename, targetDirectory }, config);
65
+ }
66
+ else {
67
+ throw new Error(`Unknown config type`);
68
+ }
69
+ outputCode += generated.code;
70
+ for (const queryName in generated.gqlDocuments) {
71
+ const exportStatement = generated.gqlDocuments[queryName].export ? "export " : "";
72
+ gqlDocumentsOutputCode += `${exportStatement} const ${queryName} = gql\`${generated.gqlDocuments[queryName].document}\`\n`;
69
73
  }
70
74
  yield (0, writeGenerated_1.writeGenerated)(codeOuputFilename, outputCode);
71
75
  if (gqlDocumentsOutputCode != "") {
@@ -78,6 +82,7 @@ function runGenerate() {
78
82
  `;
79
83
  yield (0, writeGenerated_1.writeGenerated)(gqlDocumentsOuputFilename, gqlDocumentsOutputCode);
80
84
  }
85
+ console.log("");
81
86
  }
82
87
  });
83
88
  }
@@ -48,7 +48,43 @@ config) {
48
48
  const instanceGqlType = gqlType[0].toLowerCase() + gqlType.substring(1);
49
49
  const formFragmentName = (_a = config.fragmentName) !== null && _a !== void 0 ? _a : `${gqlType}Form`;
50
50
  const gqlDocuments = {};
51
- const imports = [];
51
+ const imports = [
52
+ { name: "FormattedMessage", importPath: "react-intl" },
53
+ { name: "useApolloClient", importPath: "@apollo/client" },
54
+ { name: "useQuery", importPath: "@apollo/client" },
55
+ { name: "gql", importPath: "@apollo/client" },
56
+ { name: "AsyncSelectField", importPath: "@comet/admin" },
57
+ { name: "CheckboxField", importPath: "@comet/admin" },
58
+ { name: "Field", importPath: "@comet/admin" },
59
+ { name: "filterByFragment", importPath: "@comet/admin" },
60
+ { name: "FinalForm", importPath: "@comet/admin" },
61
+ { name: "FinalFormInput", importPath: "@comet/admin" },
62
+ { name: "FinalFormRangeInput", importPath: "@comet/admin" },
63
+ { name: "FinalFormSelect", importPath: "@comet/admin" },
64
+ { name: "FinalFormSubmitEvent", importPath: "@comet/admin" },
65
+ { name: "Loading", importPath: "@comet/admin" },
66
+ { name: "NumberField", importPath: "@comet/admin" },
67
+ { name: "RadioGroupField", importPath: "@comet/admin" },
68
+ { name: "TextAreaField", importPath: "@comet/admin" },
69
+ { name: "TextField", importPath: "@comet/admin" },
70
+ { name: "useFormApiRef", importPath: "@comet/admin" },
71
+ { name: "useStackSwitchApi", importPath: "@comet/admin" },
72
+ { name: "ArrowLeft", importPath: "@comet/admin-icons" },
73
+ { name: "Lock", importPath: "@comet/admin-icons" },
74
+ { name: "DateTimeField", importPath: "@comet/admin-date-time" },
75
+ { name: "FinalFormDatePicker", importPath: "@comet/admin-date-time" },
76
+ { name: "BlockState", importPath: "@comet/cms-admin" },
77
+ { name: "createFinalFormBlock", importPath: "@comet/cms-admin" },
78
+ { name: "queryUpdatedAt", importPath: "@comet/cms-admin" },
79
+ { name: "resolveHasSaveConflict", importPath: "@comet/cms-admin" },
80
+ { name: "useFormSaveConflict", importPath: "@comet/cms-admin" },
81
+ { name: "FileUploadField", importPath: "@comet/cms-admin" },
82
+ { name: "IconButton", importPath: "@mui/material" },
83
+ { name: "MenuItem", importPath: "@mui/material" },
84
+ { name: "InputAdornment", importPath: "@mui/material" },
85
+ { name: "FormApi", importPath: "final-form" },
86
+ { name: "useMemo", importPath: "react" },
87
+ ];
52
88
  const props = [];
53
89
  const mode = (_b = config.mode) !== null && _b !== void 0 ? _b : "all";
54
90
  const editMode = mode === "edit" || mode == "all";
@@ -219,10 +255,12 @@ config) {
219
255
  name: `GQL${documentName}${type[0].toUpperCase() + type.substring(1)}`,
220
256
  importPath: `./${baseOutputFilename}.gql.generated`,
221
257
  });
222
- imports.push({
223
- name: `GQL${documentName}${type[0].toUpperCase() + type.substring(1)}Variables`,
224
- importPath: `./${baseOutputFilename}.gql.generated`,
225
- });
258
+ if (type !== "fragment") {
259
+ imports.push({
260
+ name: `GQL${documentName}${type[0].toUpperCase() + type.substring(1)}Variables`,
261
+ importPath: `./${baseOutputFilename}.gql.generated`,
262
+ });
263
+ }
226
264
  }
227
265
  const finalFormSubscription = Object.keys((_e = (_d = generatedFields.finalFormConfig) === null || _d === void 0 ? void 0 : _d.subscription) !== null && _e !== void 0 ? _e : {});
228
266
  const finalFormRenderProps = Object.keys((_g = (_f = generatedFields.finalFormConfig) === null || _f === void 0 ? void 0 : _f.renderProps) !== null && _g !== void 0 ? _g : {});
@@ -248,33 +286,10 @@ config) {
248
286
  }`;
249
287
  filterByFragmentType = `${formFragmentName}Fragment`;
250
288
  }
251
- const code = `import { useApolloClient, useQuery, gql } from "@apollo/client";
252
- import {
253
- AsyncSelectField,
254
- CheckboxField,
255
- Field,
256
- filterByFragment,
257
- FinalForm,
258
- FinalFormInput,
259
- FinalFormRangeInput,
260
- FinalFormSelect,
261
- FinalFormSubmitEvent,
262
- Loading,
263
- RadioGroupField,
264
- TextAreaField,
265
- TextField,
266
- useFormApiRef,
267
- useStackSwitchApi,
268
- } from "@comet/admin";
269
- import { ArrowLeft, Lock } from "@comet/admin-icons";
270
- import { DateTimeField, FinalFormDatePicker } from "@comet/admin-date-time";
271
- import { BlockState, createFinalFormBlock, queryUpdatedAt, resolveHasSaveConflict, useFormSaveConflict, FileUploadField } from "@comet/cms-admin";
272
- import { FormControlLabel, IconButton, MenuItem, InputAdornment } from "@mui/material";
273
- import { FormApi } from "final-form";
274
- import isEqual from "lodash.isequal";
275
- import { useMemo } from "react";
276
- import { FormattedMessage } from "react-intl";
289
+ const code = `
277
290
  ${(0, generateImportsCode_1.generateImportsCode)(imports)}
291
+ import isEqual from "lodash.isequal";
292
+
278
293
  ${rootBlockFields.length > 0
279
294
  ? `const rootBlocks = {
280
295
  ${rootBlockFields.map((field) => `${String(field.name)}: ${field.block.name}`)}
@@ -283,11 +298,11 @@ config) {
283
298
 
284
299
  ${customFilterByFragment}
285
300
 
286
- type FormValues = ${formValuesConfig.filter((config) => !!config.omitFromFragmentType).length > 0
287
- ? `Omit<${filterByFragmentType}, ${formValuesConfig
288
- .filter((config) => !!config.omitFromFragmentType)
289
- .map((config) => `"${config.omitFromFragmentType}"`)
290
- .join(" | ")}>`
301
+ type FormValues = ${formValuesConfig.filter((config) => !!config.omitFromFragmentType).length > 0 || rootBlockFields.length > 0
302
+ ? `Omit<${filterByFragmentType}, ${[
303
+ ...(rootBlockFields.length > 0 ? ["keyof typeof rootBlocks"] : []),
304
+ ...formValuesConfig.filter((config) => !!config.omitFromFragmentType).map((config) => `"${config.omitFromFragmentType}"`),
305
+ ].join(" | ")}>`
291
306
  : `${filterByFragmentType}`} ${formValuesConfig.filter((config) => !!config.typeCode).length > 0
292
307
  ? `& {
293
308
  ${formValuesConfig
@@ -140,6 +140,7 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
140
140
  let formValueToGqlInputCode = "";
141
141
  let formFragmentField = name;
142
142
  if (config.type == "text") {
143
+ const required = config.required !== undefined ? config.required : false; // don't use inferred from gql here, non-nullable textinput allows empty string
143
144
  const TextInputComponent = config.multiline ? "TextAreaField" : "TextField";
144
145
  code = `
145
146
  <${TextInputComponent}
@@ -158,18 +159,20 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
158
159
  : ""}
159
160
  ${validateCode}
160
161
  />`;
162
+ if (!config.virtual && !required && !config.readOnly) {
163
+ formValueToGqlInputCode = `${name}: formValues.${name} ?? "",`;
164
+ }
161
165
  }
162
166
  else if (config.type == "number") {
163
167
  code = `
164
- <Field
168
+ <NumberField
165
169
  ${required ? "required" : ""}
166
170
  ${config.readOnly ? readOnlyPropsWithLock : ""}
167
171
  variant="horizontal"
168
172
  fullWidth
169
173
  name="${nameWithPrefix}"
170
- component={FinalFormInput}
171
- type="number"
172
174
  label={${fieldLabel}}
175
+ ${config.decimals ? `decimals={${config.decimals}}` : ""}
173
176
  ${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
174
177
  ${config.endAdornment ? `endAdornment={<InputAdornment position="end">${endAdornment.adornmentString}</InputAdornment>}` : ""}
175
178
  ${config.helperText
@@ -462,7 +465,14 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
462
465
  imports.push({ name: "OnChangeField", importPath: "@comet/admin" });
463
466
  finalFormConfig = { subscription: { values: true }, renderProps: { values: true, form: true } };
464
467
  }
465
- formValueToGqlInputCode = !config.virtual ? `${name}: formValues.${name}?.id,` : ``;
468
+ if (!config.virtual) {
469
+ if (!required) {
470
+ formValueToGqlInputCode = `${name}: formValues.${name} ? formValues.${name}.id : null,`;
471
+ }
472
+ else {
473
+ formValueToGqlInputCode = `${name}: formValues.${name}?.id,`;
474
+ }
475
+ }
466
476
  imports.push({
467
477
  name: `GQL${queryName}Query`,
468
478
  importPath: `./${baseOutputFilename}.generated`,