@postxl/generator 0.74.2 → 1.0.1
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/LICENSE +50 -0
- package/README.md +79 -1
- package/dist/generator-manager.class.d.ts +59 -0
- package/dist/generator-manager.class.js +221 -0
- package/dist/generator.class.d.ts +90 -0
- package/dist/generator.class.js +32 -0
- package/dist/generator.context.d.ts +174 -0
- package/dist/generator.context.js +125 -0
- package/dist/helpers/branded.types.d.ts +149 -0
- package/dist/helpers/branded.types.js +111 -0
- package/dist/helpers/config-builder.class.d.ts +27 -0
- package/dist/helpers/config-builder.class.js +54 -0
- package/dist/helpers/import-generator.class.d.ts +70 -0
- package/dist/helpers/import-generator.class.js +166 -0
- package/dist/helpers/importable.types.d.ts +52 -0
- package/dist/helpers/importable.types.js +15 -0
- package/dist/helpers/index-generator.class.d.ts +10 -0
- package/dist/helpers/index-generator.class.js +46 -0
- package/dist/helpers/index.d.ts +8 -0
- package/dist/helpers/index.js +24 -0
- package/dist/helpers/package-json.generator.d.ts +56 -0
- package/dist/helpers/package-json.generator.js +36 -0
- package/dist/helpers/tsconfig.generator.d.ts +1 -0
- package/dist/helpers/tsconfig.generator.js +14 -0
- package/dist/helpers/verify-context.d.ts +4 -0
- package/dist/helpers/verify-context.js +23 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +21 -0
- package/dist/utils/checksum.d.ts +10 -0
- package/dist/utils/checksum.js +132 -0
- package/dist/utils/fs-utils.d.ts +34 -0
- package/dist/utils/fs-utils.js +126 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.js +26 -0
- package/dist/utils/jsdoc.d.ts +12 -0
- package/dist/utils/jsdoc.js +37 -0
- package/dist/utils/lint.d.ts +46 -0
- package/dist/utils/lint.js +154 -0
- package/dist/utils/lockfile.d.ts +7 -0
- package/dist/utils/lockfile.js +80 -0
- package/dist/utils/logger.class.d.ts +25 -0
- package/dist/utils/logger.class.js +55 -0
- package/dist/utils/merge-conflict.d.ts +55 -0
- package/dist/utils/merge-conflict.js +264 -0
- package/dist/utils/path.d.ts +52 -0
- package/dist/utils/path.js +183 -0
- package/dist/utils/prettier-config.d.ts +2 -0
- package/dist/utils/prettier-config.js +13 -0
- package/dist/utils/prettier.d.ts +5 -0
- package/dist/utils/prettier.js +67 -0
- package/dist/utils/prettier.skiptest.d.ts +1 -0
- package/dist/utils/prettier.skiptest.js +22 -0
- package/dist/utils/promise.d.ts +2 -0
- package/dist/utils/promise.js +10 -0
- package/dist/utils/string-functions.d.ts +9 -0
- package/dist/utils/string-functions.js +23 -0
- package/dist/utils/sync-log-result.d.ts +9 -0
- package/dist/utils/sync-log-result.js +90 -0
- package/dist/utils/sync.d.ts +143 -0
- package/dist/utils/sync.js +325 -0
- package/dist/utils/template.d.ts +66 -0
- package/dist/utils/template.js +159 -0
- package/dist/utils/vfs.class.d.ts +115 -0
- package/dist/utils/vfs.class.js +239 -0
- package/dist/utils/zip.d.ts +13 -0
- package/dist/utils/zip.js +40 -0
- package/package.json +57 -34
- package/dist/generator.d.ts +0 -13
- package/dist/generator.js +0 -455
- package/dist/generators/enums/react.generator.d.ts +0 -10
- package/dist/generators/enums/react.generator.js +0 -110
- package/dist/generators/enums/types.generator.d.ts +0 -10
- package/dist/generators/enums/types.generator.js +0 -39
- package/dist/generators/indices/data/module.generator.d.ts +0 -9
- package/dist/generators/indices/data/module.generator.js +0 -60
- package/dist/generators/indices/data/service.generator.d.ts +0 -9
- package/dist/generators/indices/data/service.generator.js +0 -249
- package/dist/generators/indices/data/types.generator.d.ts +0 -9
- package/dist/generators/indices/data/types.generator.js +0 -49
- package/dist/generators/indices/dispatcher-service.generator.d.ts +0 -9
- package/dist/generators/indices/dispatcher-service.generator.js +0 -107
- package/dist/generators/indices/export/class.generator.d.ts +0 -9
- package/dist/generators/indices/export/class.generator.js +0 -140
- package/dist/generators/indices/export/encoder.generator.d.ts +0 -9
- package/dist/generators/indices/export/encoder.generator.js +0 -50
- package/dist/generators/indices/import/convert-functions.generator.d.ts +0 -9
- package/dist/generators/indices/import/convert-functions.generator.js +0 -509
- package/dist/generators/indices/import/decoder.generator.d.ts +0 -9
- package/dist/generators/indices/import/decoder.generator.js +0 -40
- package/dist/generators/indices/import/service.generator.d.ts +0 -9
- package/dist/generators/indices/import/service.generator.js +0 -573
- package/dist/generators/indices/import/types.generator.d.ts +0 -9
- package/dist/generators/indices/import/types.generator.js +0 -242
- package/dist/generators/indices/repositories.generator.d.ts +0 -9
- package/dist/generators/indices/repositories.generator.js +0 -25
- package/dist/generators/indices/routes.generator.d.ts +0 -9
- package/dist/generators/indices/routes.generator.js +0 -29
- package/dist/generators/indices/seed-migration.generator.d.ts +0 -9
- package/dist/generators/indices/seed-migration.generator.js +0 -36
- package/dist/generators/indices/seed-template.generator.d.ts +0 -9
- package/dist/generators/indices/seed-template.generator.js +0 -80
- package/dist/generators/indices/testids.generator.d.ts +0 -7
- package/dist/generators/indices/testids.generator.js +0 -71
- package/dist/generators/indices/types.generator.d.ts +0 -10
- package/dist/generators/indices/types.generator.js +0 -35
- package/dist/generators/indices/update/actiontypes.generator.d.ts +0 -9
- package/dist/generators/indices/update/actiontypes.generator.js +0 -49
- package/dist/generators/indices/update/module.generator.d.ts +0 -9
- package/dist/generators/indices/update/module.generator.js +0 -41
- package/dist/generators/indices/update/service.generator.d.ts +0 -9
- package/dist/generators/indices/update/service.generator.js +0 -34
- package/dist/generators/indices/view/module.generator.d.ts +0 -9
- package/dist/generators/indices/view/module.generator.js +0 -39
- package/dist/generators/indices/view/service.generator.d.ts +0 -9
- package/dist/generators/indices/view/service.generator.js +0 -34
- package/dist/generators/models/admin.page.generator.d.ts +0 -7
- package/dist/generators/models/admin.page.generator.js +0 -74
- package/dist/generators/models/export/encoder.generator.d.ts +0 -9
- package/dist/generators/models/export/encoder.generator.js +0 -51
- package/dist/generators/models/import/decoder.generator.d.ts +0 -9
- package/dist/generators/models/import/decoder.generator.js +0 -148
- package/dist/generators/models/react/context.generator.d.ts +0 -9
- package/dist/generators/models/react/context.generator.js +0 -71
- package/dist/generators/models/react/index.d.ts +0 -10
- package/dist/generators/models/react/index.js +0 -31
- package/dist/generators/models/react/library.generator.d.ts +0 -10
- package/dist/generators/models/react/library.generator.js +0 -94
- package/dist/generators/models/react/lookup.generator.d.ts +0 -9
- package/dist/generators/models/react/lookup.generator.js +0 -175
- package/dist/generators/models/react/modals.generator.d.ts +0 -23
- package/dist/generators/models/react/modals.generator.js +0 -710
- package/dist/generators/models/repository.generator.d.ts +0 -9
- package/dist/generators/models/repository.generator.js +0 -955
- package/dist/generators/models/route.generator.d.ts +0 -9
- package/dist/generators/models/route.generator.js +0 -92
- package/dist/generators/models/seed.generator.d.ts +0 -21
- package/dist/generators/models/seed.generator.js +0 -285
- package/dist/generators/models/stub.generator.d.ts +0 -9
- package/dist/generators/models/stub.generator.js +0 -92
- package/dist/generators/models/types.generator.d.ts +0 -9
- package/dist/generators/models/types.generator.js +0 -125
- package/dist/generators/models/update/service.generator.d.ts +0 -10
- package/dist/generators/models/update/service.generator.js +0 -302
- package/dist/generators/models/view/service.generator.d.ts +0 -10
- package/dist/generators/models/view/service.generator.js +0 -239
- package/dist/lib/attributes.d.ts +0 -114
- package/dist/lib/attributes.js +0 -2
- package/dist/lib/exports.d.ts +0 -45
- package/dist/lib/exports.js +0 -90
- package/dist/lib/imports.d.ts +0 -65
- package/dist/lib/imports.js +0 -114
- package/dist/lib/meta.d.ts +0 -1191
- package/dist/lib/meta.js +0 -434
- package/dist/lib/schema/fields.d.ts +0 -46
- package/dist/lib/schema/fields.js +0 -62
- package/dist/lib/schema/schema.d.ts +0 -466
- package/dist/lib/schema/schema.js +0 -18
- package/dist/lib/schema/types.d.ts +0 -201
- package/dist/lib/schema/types.js +0 -112
- package/dist/lib/serializer.d.ts +0 -15
- package/dist/lib/serializer.js +0 -24
- package/dist/lib/test-id-collector.d.ts +0 -42
- package/dist/lib/test-id-collector.js +0 -53
- package/dist/lib/types.d.ts +0 -7
- package/dist/lib/types.js +0 -13
- package/dist/lib/typescript.d.ts +0 -5
- package/dist/lib/typescript.js +0 -22
- package/dist/lib/utils/ast.d.ts +0 -29
- package/dist/lib/utils/ast.js +0 -23
- package/dist/lib/utils/error.d.ts +0 -17
- package/dist/lib/utils/error.js +0 -52
- package/dist/lib/utils/file.d.ts +0 -10
- package/dist/lib/utils/file.js +0 -56
- package/dist/lib/utils/jsdoc.d.ts +0 -9
- package/dist/lib/utils/jsdoc.js +0 -37
- package/dist/lib/utils/logger.d.ts +0 -17
- package/dist/lib/utils/logger.js +0 -12
- package/dist/lib/utils/string.d.ts +0 -40
- package/dist/lib/utils/string.js +0 -187
- package/dist/lib/utils/types.d.ts +0 -12
- package/dist/lib/utils/types.js +0 -2
- package/dist/lib/zod.d.ts +0 -8
- package/dist/lib/zod.js +0 -60
- package/dist/prisma/attributes.d.ts +0 -21
- package/dist/prisma/attributes.js +0 -175
- package/dist/prisma/client-path.d.ts +0 -7
- package/dist/prisma/client-path.js +0 -29
- package/dist/prisma/parse.d.ts +0 -12
- package/dist/prisma/parse.js +0 -452
|
@@ -1,710 +0,0 @@
|
|
|
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 (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.generateDeleteModalModelComponent = exports.generateEditModalModelComponent = exports.generateModelCreateModalComponent = void 0;
|
|
27
|
-
const imports_1 = require("../../../lib/imports");
|
|
28
|
-
const meta_1 = require("../../../lib/meta");
|
|
29
|
-
const fields_1 = require("../../../lib/schema/fields");
|
|
30
|
-
const serializer_1 = require("../../../lib/serializer");
|
|
31
|
-
const test_id_collector_1 = require("../../../lib/test-id-collector");
|
|
32
|
-
const types_1 = require("../../../lib/types");
|
|
33
|
-
const StringUtils = __importStar(require("../../../lib/utils/string"));
|
|
34
|
-
/**
|
|
35
|
-
* Utility generator that creates a create modal component for a given model.
|
|
36
|
-
*/
|
|
37
|
-
function generateModelCreateModalComponent({ model, meta }) {
|
|
38
|
-
const { fields } = model;
|
|
39
|
-
const { react: { components: { modals }, }, trpc, } = meta;
|
|
40
|
-
const testIdCollector = test_id_collector_1.TestIdCollector.from(meta.seed.constantName + '-createModal');
|
|
41
|
-
const dimensions = getModalComponentDimensions({ model });
|
|
42
|
-
return `
|
|
43
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
44
|
-
${getFormImports({ model, meta })}
|
|
45
|
-
|
|
46
|
-
type CreateInputData = {
|
|
47
|
-
${getCreateFormInputFields({ model })}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const INITIAL_VALUES = {
|
|
51
|
-
${fields
|
|
52
|
-
.filter((f) => f.kind !== 'id' && !f.attributes.isReadonly)
|
|
53
|
-
.map((field) => `${getFormikFieldName(field.name)}: null,`)
|
|
54
|
-
.join('\n')}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* A modal component that lets the user create a new ${meta.userFriendlyName} instance.
|
|
59
|
-
*/
|
|
60
|
-
export const ${modals.createComponentName} = ({
|
|
61
|
-
show,
|
|
62
|
-
onHide,
|
|
63
|
-
data
|
|
64
|
-
}: {
|
|
65
|
-
show: boolean;
|
|
66
|
-
onHide: () => void;
|
|
67
|
-
data?: Partial<CreateInputData>
|
|
68
|
-
}) => {
|
|
69
|
-
const Typed = React.useMemo(
|
|
70
|
-
() => createTypedForm<CreateInputData>().with({ ${(() => {
|
|
71
|
-
const components = new Set();
|
|
72
|
-
for (const field of fields.values()) {
|
|
73
|
-
if (field.attributes.isReadonly) {
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
switch (field.kind) {
|
|
77
|
-
case 'enum': {
|
|
78
|
-
const enumMeta = (0, meta_1.getEnumMetadata)({ enumerator: field.enumerator });
|
|
79
|
-
components.add(enumMeta.react.selectFieldName);
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
case 'relation': {
|
|
83
|
-
const refMeta = (0, meta_1.getModelMetadata)({ model: field.relationToModel });
|
|
84
|
-
components.add(refMeta.react.components.forms.searchFieldName);
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
-
default:
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return [...components].join(', ');
|
|
92
|
-
})()} }),
|
|
93
|
-
[]
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
const cache = trpc.useContext()
|
|
97
|
-
const mutation = trpc.${trpc.create.reactQueryMethod}.useMutation()
|
|
98
|
-
|
|
99
|
-
return (
|
|
100
|
-
<ModalWithNavigationContainer label="Create new ${meta.userFriendlyName}" show={show} onHide={onHide} ${dimensions}>
|
|
101
|
-
<Typed.Formik
|
|
102
|
-
initialValues={{ ...INITIAL_VALUES, ...data }}
|
|
103
|
-
validate={(values) => {
|
|
104
|
-
const errors: { [K in keyof CreateInputData]?: string } = {}
|
|
105
|
-
|
|
106
|
-
${getFormikValidationCases({ model })}
|
|
107
|
-
|
|
108
|
-
return errors
|
|
109
|
-
}}
|
|
110
|
-
onSubmit={async (values) => {
|
|
111
|
-
|
|
112
|
-
try {
|
|
113
|
-
const res = await toast.promise(
|
|
114
|
-
mutation.mutateAsync(
|
|
115
|
-
{
|
|
116
|
-
${getFormikCreateMutationData({ model })}
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
async onSuccess() {
|
|
120
|
-
await cache.${trpc.routerName}.invalidate()
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
),
|
|
124
|
-
{
|
|
125
|
-
loading: "Creating new ${meta.userFriendlyName}...",
|
|
126
|
-
success: "New ${meta.userFriendlyName} created!",
|
|
127
|
-
error: (error) => {
|
|
128
|
-
if (error instanceof TRPCClientError) {
|
|
129
|
-
return error.message
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return 'Something went wrong...'
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
if (res.id) {
|
|
138
|
-
onHide()
|
|
139
|
-
}
|
|
140
|
-
} catch (err) {
|
|
141
|
-
console.error(err)
|
|
142
|
-
}
|
|
143
|
-
}}
|
|
144
|
-
>
|
|
145
|
-
{({ isSubmitting, submitForm }) => (
|
|
146
|
-
<ModalWithActions actions={
|
|
147
|
-
<ConfirmButton
|
|
148
|
-
color="primary"
|
|
149
|
-
label="Create"
|
|
150
|
-
fill="fill"
|
|
151
|
-
onClick={submitForm}
|
|
152
|
-
loading={isSubmitting}
|
|
153
|
-
__e2e_test_id__="${testIdCollector.idFor('submit', { typePrefix: 'buttons' })}"
|
|
154
|
-
/>
|
|
155
|
-
}>
|
|
156
|
-
${getFormFieldComponents({ model, testIdCollector: testIdCollector })}
|
|
157
|
-
</ModalWithActions>
|
|
158
|
-
)}
|
|
159
|
-
</Typed.Formik>
|
|
160
|
-
</ModalWithNavigationContainer>
|
|
161
|
-
)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
`;
|
|
165
|
-
}
|
|
166
|
-
exports.generateModelCreateModalComponent = generateModelCreateModalComponent;
|
|
167
|
-
/**
|
|
168
|
-
* Returns a React component that lets you edit a model instance.
|
|
169
|
-
*/
|
|
170
|
-
function generateEditModalModelComponent({ model, meta }) {
|
|
171
|
-
const { fields } = model;
|
|
172
|
-
const { react: { components }, trpc, } = meta;
|
|
173
|
-
const testIdCollector = test_id_collector_1.TestIdCollector.from(meta.seed.constantName + '-editModal');
|
|
174
|
-
const dimensions = getModalComponentDimensions({ model });
|
|
175
|
-
return `
|
|
176
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
177
|
-
${getFormImports({ model, meta })}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
type EditInputData = {
|
|
181
|
-
${getFormikFieldName(model.idField.name)}: ${model.brandedIdType}
|
|
182
|
-
${getEditFormInputFields({ model })}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Modal component that may be used to edit a ${model.name} instance.
|
|
187
|
-
*/
|
|
188
|
-
export const ${components.modals.editComponentName} = ({
|
|
189
|
-
data,
|
|
190
|
-
show,
|
|
191
|
-
onHide
|
|
192
|
-
}: { data: ${model.typeName}; show: boolean; onHide: () => void }) => {
|
|
193
|
-
const Typed = React.useMemo(
|
|
194
|
-
() => createTypedForm<EditInputData>().with({ ${(() => {
|
|
195
|
-
const components = new Set();
|
|
196
|
-
for (const field of fields.values()) {
|
|
197
|
-
switch (field.kind) {
|
|
198
|
-
case 'enum': {
|
|
199
|
-
const enumMeta = (0, meta_1.getEnumMetadata)({ enumerator: field.enumerator });
|
|
200
|
-
components.add(enumMeta.react.selectFieldName);
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
case 'relation': {
|
|
204
|
-
const refMeta = (0, meta_1.getModelMetadata)({ model: field.relationToModel });
|
|
205
|
-
components.add(refMeta.react.components.forms.searchFieldName);
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
default:
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
return [...components].join(', ');
|
|
213
|
-
})()} }),
|
|
214
|
-
[]
|
|
215
|
-
)
|
|
216
|
-
const cache = trpc.useContext()
|
|
217
|
-
const mutation = trpc.${trpc.update.reactQueryMethod}.useMutation()
|
|
218
|
-
|
|
219
|
-
return (
|
|
220
|
-
<ModalWithNavigationContainer label="Edit ${meta.userFriendlyName}" show={show} onHide={onHide} ${dimensions}>
|
|
221
|
-
<Typed.Formik
|
|
222
|
-
initialValues={{
|
|
223
|
-
${fields
|
|
224
|
-
.filter((f) => !f.attributes.isReadonly || f.kind === 'id')
|
|
225
|
-
.map((field) => {
|
|
226
|
-
switch (field.kind) {
|
|
227
|
-
case 'enum':
|
|
228
|
-
case 'relation':
|
|
229
|
-
if (field.isRequired) {
|
|
230
|
-
return `${getFormikFieldName(field.name)}: { id: data.${field.name} },`;
|
|
231
|
-
}
|
|
232
|
-
return `${getFormikFieldName(field.name)}: data.${field.name} ? { id: data.${field.name} } : null,`;
|
|
233
|
-
case 'id':
|
|
234
|
-
case 'scalar':
|
|
235
|
-
return `${getFormikFieldName(field.name)}: data.${field.name},`;
|
|
236
|
-
default:
|
|
237
|
-
throw new types_1.ExhaustiveSwitchCheck(field);
|
|
238
|
-
}
|
|
239
|
-
})
|
|
240
|
-
.join('\n')}
|
|
241
|
-
}}
|
|
242
|
-
validate={(values) => {
|
|
243
|
-
const errors: { [K in keyof EditInputData]?: string } = {}
|
|
244
|
-
|
|
245
|
-
${getFormikValidationCases({ model })}
|
|
246
|
-
|
|
247
|
-
return errors
|
|
248
|
-
}}
|
|
249
|
-
onSubmit={async (values) => {
|
|
250
|
-
try {
|
|
251
|
-
await toast.promise(
|
|
252
|
-
mutation.mutateAsync(
|
|
253
|
-
{
|
|
254
|
-
${getEditFormikMutationData({ model })}
|
|
255
|
-
},
|
|
256
|
-
{
|
|
257
|
-
async onSuccess() {
|
|
258
|
-
await cache.${trpc.routerName}.invalidate()
|
|
259
|
-
},
|
|
260
|
-
},
|
|
261
|
-
),
|
|
262
|
-
{
|
|
263
|
-
loading: "Updating ${meta.userFriendlyName}...",
|
|
264
|
-
success: "${meta.userFriendlyName} updated!",
|
|
265
|
-
error: (error) => {
|
|
266
|
-
if (error instanceof TRPCClientError) {
|
|
267
|
-
return error.message
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
return 'Something went wrong...'
|
|
271
|
-
},
|
|
272
|
-
},
|
|
273
|
-
)
|
|
274
|
-
|
|
275
|
-
onHide()
|
|
276
|
-
} catch (err) {
|
|
277
|
-
console.error(err)
|
|
278
|
-
}
|
|
279
|
-
}}
|
|
280
|
-
>
|
|
281
|
-
{({ isSubmitting, submitForm }) => (
|
|
282
|
-
<ModalWithActions
|
|
283
|
-
actions={
|
|
284
|
-
<ConfirmButton
|
|
285
|
-
label="Save"
|
|
286
|
-
color="primary"
|
|
287
|
-
onClick={submitForm}
|
|
288
|
-
loading={isSubmitting}
|
|
289
|
-
__e2e_test_id__="${testIdCollector.idFor('submit', { typePrefix: 'buttons' })}"
|
|
290
|
-
/>
|
|
291
|
-
}
|
|
292
|
-
>
|
|
293
|
-
${getFormFieldComponents({ model, testIdCollector: testIdCollector })}
|
|
294
|
-
</ModalWithActions>
|
|
295
|
-
)}
|
|
296
|
-
</Typed.Formik>
|
|
297
|
-
</ModalWithNavigationContainer>
|
|
298
|
-
)
|
|
299
|
-
}
|
|
300
|
-
`;
|
|
301
|
-
}
|
|
302
|
-
exports.generateEditModalModelComponent = generateEditModalModelComponent;
|
|
303
|
-
/**
|
|
304
|
-
* Generates a modal component that lets you delete a model instance.
|
|
305
|
-
*/
|
|
306
|
-
function generateDeleteModalModelComponent({ model, meta }) {
|
|
307
|
-
const { react: { components }, trpc, } = meta;
|
|
308
|
-
const imports = imports_1.ImportsGenerator.from(meta.react.folderPath).addTypeImport({
|
|
309
|
-
items: [model.brandedIdType],
|
|
310
|
-
from: meta.types.importPath,
|
|
311
|
-
});
|
|
312
|
-
return `
|
|
313
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
314
|
-
import { TRPCClientError } from '@trpc/client'
|
|
315
|
-
|
|
316
|
-
import { Formik } from 'formik'
|
|
317
|
-
import React, { useCallback } from 'react'
|
|
318
|
-
import { toast } from 'react-hot-toast'
|
|
319
|
-
|
|
320
|
-
import { ConfirmationModal } from '@components/atoms/Modal'
|
|
321
|
-
import { trpc } from '@lib/trpc'
|
|
322
|
-
|
|
323
|
-
${imports.generate()}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Modal components that shows a confirmation modal before deleting a ${meta.userFriendlyName}.
|
|
327
|
-
*/
|
|
328
|
-
export const ${components.modals.deleteComponentName} = ({
|
|
329
|
-
id,
|
|
330
|
-
show,
|
|
331
|
-
onHide
|
|
332
|
-
}: {
|
|
333
|
-
id: ${model.brandedIdType};
|
|
334
|
-
show: boolean;
|
|
335
|
-
onHide: () => void
|
|
336
|
-
}) => {
|
|
337
|
-
const cache = trpc.useContext()
|
|
338
|
-
const mutation = trpc.${trpc.delete.reactQueryMethod}.useMutation()
|
|
339
|
-
|
|
340
|
-
const handleDelete = useCallback(async () => {
|
|
341
|
-
try {
|
|
342
|
-
await toast.promise(
|
|
343
|
-
mutation.mutateAsync(id, {
|
|
344
|
-
async onSuccess() {
|
|
345
|
-
await cache.${trpc.routerName}.invalidate()
|
|
346
|
-
},
|
|
347
|
-
}),
|
|
348
|
-
{
|
|
349
|
-
loading: "Deleting ${meta.userFriendlyName}...",
|
|
350
|
-
success: "${meta.userFriendlyName} deleted!",
|
|
351
|
-
error: (err) => {
|
|
352
|
-
if (err instanceof TRPCClientError) {
|
|
353
|
-
return err.message
|
|
354
|
-
}
|
|
355
|
-
return 'Something went wrong...'
|
|
356
|
-
},
|
|
357
|
-
},
|
|
358
|
-
)
|
|
359
|
-
} catch (err) {
|
|
360
|
-
console.error(err)
|
|
361
|
-
}
|
|
362
|
-
}, [mutation, id, cache])
|
|
363
|
-
|
|
364
|
-
return (
|
|
365
|
-
<ConfirmationModal
|
|
366
|
-
show={show}
|
|
367
|
-
onHide={onHide}
|
|
368
|
-
onConfirm={handleDelete}
|
|
369
|
-
label="Delete ${meta.userFriendlyName}"
|
|
370
|
-
description="Please confirm that you want to delete this ${meta.userFriendlyName}."
|
|
371
|
-
variant="danger"
|
|
372
|
-
loading={mutation.isLoading}
|
|
373
|
-
/>
|
|
374
|
-
)
|
|
375
|
-
}
|
|
376
|
-
`;
|
|
377
|
-
}
|
|
378
|
-
exports.generateDeleteModalModelComponent = generateDeleteModalModelComponent;
|
|
379
|
-
/**
|
|
380
|
-
* Returns the import statements to the models that are used in this modal.
|
|
381
|
-
*/
|
|
382
|
-
function getFormImports({ model, meta }) {
|
|
383
|
-
const imports = imports_1.ImportsGenerator.from(meta.react.folderPath).addTypeImport({
|
|
384
|
-
items: [model.brandedIdType, model.typeName],
|
|
385
|
-
from: meta.types.importPath,
|
|
386
|
-
});
|
|
387
|
-
for (const ref of (0, fields_1.getRelationFields)(model)) {
|
|
388
|
-
const refModel = ref.relationToModel;
|
|
389
|
-
const refMeta = (0, meta_1.getModelMetadata)({ model: refModel });
|
|
390
|
-
imports.addImport({
|
|
391
|
-
items: [refMeta.react.components.forms.searchFieldName],
|
|
392
|
-
from: refMeta.react.folderPath,
|
|
393
|
-
});
|
|
394
|
-
imports.addTypeImport({
|
|
395
|
-
items: [refModel.brandedIdType],
|
|
396
|
-
from: refMeta.types.importPath,
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
for (const f of (0, fields_1.getEnumFields)(model)) {
|
|
400
|
-
const enumMeta = (0, meta_1.getEnumMetadata)(f);
|
|
401
|
-
imports.addTypeImport({
|
|
402
|
-
items: [f.enumerator.tsTypeName],
|
|
403
|
-
from: enumMeta.types.importPath,
|
|
404
|
-
});
|
|
405
|
-
imports.addImport({
|
|
406
|
-
items: [enumMeta.react.selectFieldName],
|
|
407
|
-
from: enumMeta.react.folderPath,
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
return `
|
|
411
|
-
import { TRPCClientError } from '@trpc/client'
|
|
412
|
-
import React from 'react'
|
|
413
|
-
import { toast } from 'react-hot-toast'
|
|
414
|
-
|
|
415
|
-
import { createTypedForm } from '@components/atoms/Form'
|
|
416
|
-
import { ConfirmButton, ModalWithNavigationContainer, Label, ModalWithActions } from '@components/atoms/Modal'
|
|
417
|
-
|
|
418
|
-
import { trpc } from '@lib/trpc'
|
|
419
|
-
|
|
420
|
-
${imports.generate()}
|
|
421
|
-
`;
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* Returns a string containing TypeScript type definition for the input data of the create mutation.
|
|
425
|
-
*
|
|
426
|
-
* NOTE: This function assumes that fields might also be null because we have no data yet.
|
|
427
|
-
*/
|
|
428
|
-
function getCreateFormInputFields({ model }) {
|
|
429
|
-
const form = new serializer_1.Serializer();
|
|
430
|
-
for (const field of model.fields.values()) {
|
|
431
|
-
if (field.attributes.isReadonly) {
|
|
432
|
-
continue;
|
|
433
|
-
}
|
|
434
|
-
switch (field.kind) {
|
|
435
|
-
case 'id':
|
|
436
|
-
continue;
|
|
437
|
-
case 'relation':
|
|
438
|
-
form.append(`${getFormikFieldName(field.name)}: { id: ${field.relationToModel.brandedIdType} } | null`);
|
|
439
|
-
break;
|
|
440
|
-
case 'scalar':
|
|
441
|
-
form.append(`${getFormikFieldName(field.name)}: ${field.tsTypeName} | null`);
|
|
442
|
-
break;
|
|
443
|
-
case 'enum':
|
|
444
|
-
form.append(`${getFormikFieldName(field.name)}: { id: ${field.typeName} } | null`);
|
|
445
|
-
break;
|
|
446
|
-
default:
|
|
447
|
-
throw new types_1.ExhaustiveSwitchCheck(field);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
return form.print();
|
|
451
|
-
}
|
|
452
|
-
function getFormikCreateMutationData({ model: { fields } }) {
|
|
453
|
-
return fields
|
|
454
|
-
.filter((f) => !f.attributes.isReadonly)
|
|
455
|
-
.map((field) => {
|
|
456
|
-
const formikFieldName = getFormikFieldName(field.name);
|
|
457
|
-
switch (field.kind) {
|
|
458
|
-
case 'id':
|
|
459
|
-
case 'scalar':
|
|
460
|
-
// NOTE: Create methods generate the ID field upon submission.
|
|
461
|
-
if (field.kind === 'id') {
|
|
462
|
-
return '';
|
|
463
|
-
}
|
|
464
|
-
if (field.isRequired) {
|
|
465
|
-
return `
|
|
466
|
-
// NOTE: We force unwrap values, because we validate values using Formik.
|
|
467
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
468
|
-
${field.name}: values.${formikFieldName}!,
|
|
469
|
-
`;
|
|
470
|
-
}
|
|
471
|
-
return `${field.name}: values.${formikFieldName},`;
|
|
472
|
-
case 'relation':
|
|
473
|
-
if (field.isRequired) {
|
|
474
|
-
return `
|
|
475
|
-
// NOTE: We force unwrap values, because we validate values using Formik.
|
|
476
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
477
|
-
${field.name}: values.${formikFieldName}!.id,
|
|
478
|
-
`;
|
|
479
|
-
}
|
|
480
|
-
return `${field.name}: values.${formikFieldName}?.id ? values.${formikFieldName}.id : null,`;
|
|
481
|
-
case 'enum':
|
|
482
|
-
if (field.isRequired) {
|
|
483
|
-
return `
|
|
484
|
-
// NOTE: We force unwrap values, because we validate values using Formik.
|
|
485
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
486
|
-
${field.name}: values.${formikFieldName}!.id,
|
|
487
|
-
`;
|
|
488
|
-
}
|
|
489
|
-
return `${field.name}: values.${formikFieldName}?.id ? values.${formikFieldName}.id : null,`;
|
|
490
|
-
default:
|
|
491
|
-
throw new types_1.ExhaustiveSwitchCheck(field);
|
|
492
|
-
}
|
|
493
|
-
})
|
|
494
|
-
.join('\n');
|
|
495
|
-
}
|
|
496
|
-
/**
|
|
497
|
-
* Returns a string containing the fields of the input data without the ID field.
|
|
498
|
-
*/
|
|
499
|
-
function getEditFormInputFields({ model }) {
|
|
500
|
-
const form = new serializer_1.Serializer();
|
|
501
|
-
for (const field of model.fields.values()) {
|
|
502
|
-
if (field.attributes.isReadonly) {
|
|
503
|
-
continue;
|
|
504
|
-
}
|
|
505
|
-
switch (field.kind) {
|
|
506
|
-
case 'id':
|
|
507
|
-
continue;
|
|
508
|
-
case 'relation':
|
|
509
|
-
if (field.isRequired) {
|
|
510
|
-
form.append(`${getFormikFieldName(field.name)}: { id: ${field.relationToModel.brandedIdType} }`);
|
|
511
|
-
}
|
|
512
|
-
else {
|
|
513
|
-
form.append(`${getFormikFieldName(field.name)}: { id: ${field.relationToModel.brandedIdType} } | null`);
|
|
514
|
-
}
|
|
515
|
-
break;
|
|
516
|
-
case 'scalar':
|
|
517
|
-
if (field.isRequired) {
|
|
518
|
-
form.append(`${getFormikFieldName(field.name)}: ${field.tsTypeName}`);
|
|
519
|
-
}
|
|
520
|
-
else {
|
|
521
|
-
form.append(`${getFormikFieldName(field.name)}: ${field.tsTypeName} | null`);
|
|
522
|
-
}
|
|
523
|
-
break;
|
|
524
|
-
case 'enum':
|
|
525
|
-
if (field.isRequired) {
|
|
526
|
-
form.append(`${getFormikFieldName(field.name)}: { id: ${field.typeName} }`);
|
|
527
|
-
}
|
|
528
|
-
else {
|
|
529
|
-
form.append(`${getFormikFieldName(field.name)}: { id: ${field.typeName} } | null`);
|
|
530
|
-
}
|
|
531
|
-
break;
|
|
532
|
-
default:
|
|
533
|
-
throw new types_1.ExhaustiveSwitchCheck(field);
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
return form.print();
|
|
537
|
-
}
|
|
538
|
-
function getEditFormikMutationData({ model: { fields } }) {
|
|
539
|
-
return fields
|
|
540
|
-
.filter((f) => !f.attributes.isReadonly || f.kind === 'id')
|
|
541
|
-
.map((field) => {
|
|
542
|
-
const formikFieldName = getFormikFieldName(field.name);
|
|
543
|
-
switch (field.kind) {
|
|
544
|
-
case 'id':
|
|
545
|
-
// NOTE: Edit mutation expects the ID field to identify the object.
|
|
546
|
-
// eslint-disable-next-line no-fallthrough
|
|
547
|
-
case 'scalar':
|
|
548
|
-
return `${field.name}: values.${formikFieldName},`;
|
|
549
|
-
case 'relation':
|
|
550
|
-
if (field.isRequired) {
|
|
551
|
-
return `${field.name}: values.${formikFieldName}.id,`;
|
|
552
|
-
}
|
|
553
|
-
return `${field.name}: values.${formikFieldName}?.id ? values.${formikFieldName}.id : null,`;
|
|
554
|
-
case 'enum':
|
|
555
|
-
if (field.isRequired) {
|
|
556
|
-
return `${field.name}: values.${formikFieldName}.id,`;
|
|
557
|
-
}
|
|
558
|
-
return `${field.name}: values.${formikFieldName}?.id ? values.${formikFieldName}.id : null,`;
|
|
559
|
-
default:
|
|
560
|
-
throw new types_1.ExhaustiveSwitchCheck(field);
|
|
561
|
-
}
|
|
562
|
-
})
|
|
563
|
-
.join('\n');
|
|
564
|
-
}
|
|
565
|
-
/**
|
|
566
|
-
* Returns a string containing all the components that should appear in the Formik form for this model.
|
|
567
|
-
*/
|
|
568
|
-
function getFormFieldComponents({ model, testIdCollector, }) {
|
|
569
|
-
var _a;
|
|
570
|
-
const form = new serializer_1.Serializer();
|
|
571
|
-
for (const field of model.fields.values()) {
|
|
572
|
-
// By default, we hide generated fields like createdAt, updatedAt, deletedAt.
|
|
573
|
-
if (field.attributes.isReadonly) {
|
|
574
|
-
continue;
|
|
575
|
-
}
|
|
576
|
-
const formikFieldName = getFormikFieldName(field.name);
|
|
577
|
-
const label = field.attributes.label;
|
|
578
|
-
switch (field.kind) {
|
|
579
|
-
case 'id': {
|
|
580
|
-
// NOTE: We never show the ID field in the form even if it's in the type signature of the form input.
|
|
581
|
-
break;
|
|
582
|
-
}
|
|
583
|
-
case 'scalar': {
|
|
584
|
-
// Each scalar field has a different generic component based on the provided type.
|
|
585
|
-
scalar: switch (field.tsTypeName) {
|
|
586
|
-
case 'string': {
|
|
587
|
-
form.append(`
|
|
588
|
-
<div>
|
|
589
|
-
<Label>${label}</Label>
|
|
590
|
-
<Typed.TextField
|
|
591
|
-
name="${formikFieldName}"
|
|
592
|
-
placeholder="Type..."
|
|
593
|
-
__e2e_field_test_id__="${testIdCollector.idFor(field.name, { typePrefix: 'fields' })}"
|
|
594
|
-
/>
|
|
595
|
-
</div>
|
|
596
|
-
`);
|
|
597
|
-
break scalar;
|
|
598
|
-
}
|
|
599
|
-
case 'number': {
|
|
600
|
-
let decimals = 0;
|
|
601
|
-
if (((_a = field.validation) === null || _a === void 0 ? void 0 : _a.type) === 'float') {
|
|
602
|
-
decimals = 2;
|
|
603
|
-
}
|
|
604
|
-
form.append(`
|
|
605
|
-
<div>
|
|
606
|
-
<Label>${label}</Label>
|
|
607
|
-
<Typed.NumberField
|
|
608
|
-
name="${formikFieldName}"
|
|
609
|
-
placeholder="2511"
|
|
610
|
-
decimals={${decimals}}
|
|
611
|
-
__e2e_field_test_id__="${testIdCollector.idFor(field.name, { typePrefix: 'fields' })}"
|
|
612
|
-
/>
|
|
613
|
-
</div>
|
|
614
|
-
`);
|
|
615
|
-
break scalar;
|
|
616
|
-
}
|
|
617
|
-
case 'boolean': {
|
|
618
|
-
form.append(`
|
|
619
|
-
<div>
|
|
620
|
-
<Label>Is ${label}</Label>
|
|
621
|
-
<Typed.CheckBoxField
|
|
622
|
-
name="${formikFieldName}"
|
|
623
|
-
label="${label}"
|
|
624
|
-
__e2e_field_test_id__="${testIdCollector.idFor(field.name, { typePrefix: 'fields' })}"
|
|
625
|
-
/>
|
|
626
|
-
</div>
|
|
627
|
-
`);
|
|
628
|
-
break scalar;
|
|
629
|
-
}
|
|
630
|
-
case 'Date': {
|
|
631
|
-
form.append(`{/* Skipped date field ${field.name}. */}`);
|
|
632
|
-
break scalar;
|
|
633
|
-
}
|
|
634
|
-
default: {
|
|
635
|
-
console.warn(`Unknown scalar type ${field.tsTypeName} for field ${model.name}.${field.name}.`);
|
|
636
|
-
break scalar;
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
break;
|
|
640
|
-
}
|
|
641
|
-
case 'relation': {
|
|
642
|
-
const refMeta = (0, meta_1.getModelMetadata)({ model: field.relationToModel });
|
|
643
|
-
form.append(`
|
|
644
|
-
<div>
|
|
645
|
-
<Label>${refMeta.userFriendlyName}</Label>
|
|
646
|
-
<Typed.${refMeta.react.components.forms.searchFieldName}
|
|
647
|
-
name="${formikFieldName}"
|
|
648
|
-
placeholder="Search..."
|
|
649
|
-
__e2e_options_test_id__="${testIdCollector.idFor(field.name, { typePrefix: 'options' })}"
|
|
650
|
-
__e2e_combobox_test_id__="${testIdCollector.idFor(field.name, { typePrefix: 'fields' })}"
|
|
651
|
-
/>
|
|
652
|
-
</div>
|
|
653
|
-
`);
|
|
654
|
-
break;
|
|
655
|
-
}
|
|
656
|
-
case 'enum': {
|
|
657
|
-
const enumMeta = (0, meta_1.getEnumMetadata)({ enumerator: field.enumerator });
|
|
658
|
-
form.append(`
|
|
659
|
-
<div>
|
|
660
|
-
<Label>${label}</Label>
|
|
661
|
-
<Typed.${enumMeta.react.selectFieldName}
|
|
662
|
-
name="${formikFieldName}"
|
|
663
|
-
placeholder="Search..."
|
|
664
|
-
__e2e_field_test_id__="${testIdCollector.idFor(field.name, { typePrefix: 'fields' })}"
|
|
665
|
-
/>
|
|
666
|
-
</div>
|
|
667
|
-
`);
|
|
668
|
-
break;
|
|
669
|
-
}
|
|
670
|
-
default:
|
|
671
|
-
throw new types_1.ExhaustiveSwitchCheck(field);
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
return form.print();
|
|
675
|
-
}
|
|
676
|
-
/**
|
|
677
|
-
* Returns a string containing a list of checks for Formik validation function.
|
|
678
|
-
*/
|
|
679
|
-
function getFormikValidationCases({ model }) {
|
|
680
|
-
const form = new serializer_1.Serializer();
|
|
681
|
-
for (const field of model.fields.values()) {
|
|
682
|
-
if (field.kind === 'id' || field.attributes.isReadonly) {
|
|
683
|
-
continue;
|
|
684
|
-
}
|
|
685
|
-
const formikFieldName = getFormikFieldName(field.name);
|
|
686
|
-
if (field.isRequired) {
|
|
687
|
-
form.append(`
|
|
688
|
-
if (!values.${formikFieldName}) {
|
|
689
|
-
errors.${formikFieldName} = "Required..."
|
|
690
|
-
}
|
|
691
|
-
`);
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
return form.print();
|
|
695
|
-
}
|
|
696
|
-
// NOTE: This function is separated because many parts rely on the name of the field.
|
|
697
|
-
function getFormikFieldName(name) {
|
|
698
|
-
return `formik${StringUtils.toPascalCase(name)}`;
|
|
699
|
-
}
|
|
700
|
-
/**
|
|
701
|
-
* Returns a string representing the "missing" dimension parameters for the modal component
|
|
702
|
-
* depending on the type of the modal.
|
|
703
|
-
*/
|
|
704
|
-
function getModalComponentDimensions({ model }) {
|
|
705
|
-
const _fields = model.fields.filter((f) => f.kind !== 'id' && !f.attributes.isReadonly);
|
|
706
|
-
if (_fields.length > 3) {
|
|
707
|
-
return 'fixed wide';
|
|
708
|
-
}
|
|
709
|
-
return '';
|
|
710
|
-
}
|