@quatrain/app 1.1.1 → 1.1.3
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/dist/CodeGenerator.d.ts +1 -0
- package/dist/CodeGenerator.d.ts.map +1 -1
- package/dist/CodeGenerator.js +345 -27
- package/dist/CodeGenerator.js.map +1 -1
- package/dist/InfraBuilder.d.ts.map +1 -1
- package/dist/InfraBuilder.js +13 -3
- package/dist/InfraBuilder.js.map +1 -1
- package/package.json +8 -8
- package/src/CodeGenerator.ts +387 -31
- package/src/InfraBuilder.ts +16 -4
package/dist/CodeGenerator.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeGenerator.d.ts","sourceRoot":"","sources":["../src/CodeGenerator.ts"],"names":[],"mappings":"AAIA,qBAAa,aAAa;WAIT,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"CodeGenerator.d.ts","sourceRoot":"","sources":["../src/CodeGenerator.ts"],"names":[],"mappings":"AAIA,qBAAa,aAAa;WAIT,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IA+B5D,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAqClC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAiB/B,OAAO,CAAC,MAAM,CAAC,cAAc;IAmD7B,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAenC,OAAO,CAAC,MAAM,CAAC,aAAa;IAuD5B,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAyEhC,OAAO,CAAC,MAAM,CAAC,gBAAgB;CA0TjC"}
|
package/dist/CodeGenerator.js
CHANGED
|
@@ -40,12 +40,19 @@ const log_1 = require("@quatrain/log");
|
|
|
40
40
|
class CodeGenerator {
|
|
41
41
|
static generate(config, targetDir) {
|
|
42
42
|
const fullTargetDir = path.resolve(process.cwd(), targetDir);
|
|
43
|
-
const dirs = ['src/models', 'src/api', 'data/migrations/default'];
|
|
43
|
+
const dirs = ['src/models', 'src/api', 'data/migrations/default', 'web/src/pages'];
|
|
44
44
|
for (const dir of dirs) {
|
|
45
45
|
const d = path.resolve(fullTargetDir, dir);
|
|
46
46
|
if (!fs.existsSync(d)) {
|
|
47
47
|
fs.mkdirSync(d, { recursive: true });
|
|
48
48
|
}
|
|
49
|
+
else if (dir === 'src/models' || dir === 'src/api' || dir === 'web/src/pages') {
|
|
50
|
+
fs.readdirSync(d).forEach(file => {
|
|
51
|
+
if (file.endsWith('.ts') || file.endsWith('.tsx')) {
|
|
52
|
+
fs.unlinkSync(path.join(d, file));
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
49
56
|
}
|
|
50
57
|
this.generatePackageJson(config, fullTargetDir);
|
|
51
58
|
this.generateTsConfig(fullTargetDir);
|
|
@@ -53,6 +60,7 @@ class CodeGenerator {
|
|
|
53
60
|
this.generateApiEndpoints(config, fullTargetDir, generatedModels);
|
|
54
61
|
this.generateIndex(config, fullTargetDir, generatedModels);
|
|
55
62
|
this.generateMigration(config, fullTargetDir);
|
|
63
|
+
this.generateFrontend(config, fullTargetDir, generatedModels);
|
|
56
64
|
log_1.Log.info(`[CodeGenerator] Application générée avec succès dans ${fullTargetDir}`);
|
|
57
65
|
}
|
|
58
66
|
static generatePackageJson(config, targetDir) {
|
|
@@ -65,7 +73,8 @@ class CodeGenerator {
|
|
|
65
73
|
main: "src/index.ts",
|
|
66
74
|
type: "module",
|
|
67
75
|
scripts: {
|
|
68
|
-
start: "bun run src/index.ts"
|
|
76
|
+
"start:dev": "NODE_ENV=development bun run --watch src/index.ts",
|
|
77
|
+
"start:prod": "NODE_ENV=production bun run src/index.ts"
|
|
69
78
|
},
|
|
70
79
|
dependencies: {
|
|
71
80
|
"@quatrain/core": targetNpmTag,
|
|
@@ -110,15 +119,21 @@ class CodeGenerator {
|
|
|
110
119
|
const className = model.name;
|
|
111
120
|
const collectionName = model.collectionName || className.toLowerCase();
|
|
112
121
|
generatedNames.push(className);
|
|
122
|
+
const mapTypeToClass = (type) => {
|
|
123
|
+
if (type.toLowerCase() === 'datetime')
|
|
124
|
+
return 'DateTimeProperty';
|
|
125
|
+
return type.charAt(0).toUpperCase() + type.slice(1) + 'Property';
|
|
126
|
+
};
|
|
113
127
|
const propsCode = model.properties.map((p) => {
|
|
114
|
-
const
|
|
128
|
+
const propClass = mapTypeToClass(p.type);
|
|
129
|
+
const htmlTypeLine = p.htmlType ? `,\n htmlType: '${p.htmlType}'` : '';
|
|
115
130
|
return ` {
|
|
116
131
|
name: '${p.name}',
|
|
117
|
-
type: ${
|
|
118
|
-
mandatory: ${p.options?.mandatory ? 'true' : 'false'}
|
|
132
|
+
type: ${propClass}.TYPE,
|
|
133
|
+
mandatory: ${p.options?.mandatory ? 'true' : 'false'}${htmlTypeLine}
|
|
119
134
|
}`;
|
|
120
135
|
}).join(',\n');
|
|
121
|
-
const propTypesToImport = Array.from(new Set(model.properties.map((p) => p.type)));
|
|
136
|
+
const propTypesToImport = Array.from(new Set(model.properties.map((p) => mapTypeToClass(p.type))));
|
|
122
137
|
const modelCode = `import { PersistedBaseObject } from '@quatrain/backend'
|
|
123
138
|
import { ${propTypesToImport.join(', ')} } from '@quatrain/core'
|
|
124
139
|
|
|
@@ -141,13 +156,13 @@ export class ${className} extends PersistedBaseObject {
|
|
|
141
156
|
}
|
|
142
157
|
static generateApiEndpoints(config, targetDir, models) {
|
|
143
158
|
for (const className of models) {
|
|
144
|
-
const apiCode = `import { CrudEndpoint } from '@quatrain/api-server'
|
|
159
|
+
const apiCode = `import { CrudEndpoint, ValuesEndpoint } from '@quatrain/api-server'
|
|
160
|
+
import { ServerAdapter, EndpointOptions } from '@quatrain/api'
|
|
145
161
|
import { ${className} } from '../models/${className}'
|
|
146
162
|
|
|
147
|
-
export
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
163
|
+
export const ${className}Api = (router: ServerAdapter, path: string, options: EndpointOptions) => {
|
|
164
|
+
CrudEndpoint(${className})(router, path, options)
|
|
165
|
+
ValuesEndpoint(${className})(router, path, options)
|
|
151
166
|
}
|
|
152
167
|
`;
|
|
153
168
|
fs.writeFileSync(path.resolve(targetDir, `src/api/${className}Api.ts`), apiCode);
|
|
@@ -158,27 +173,31 @@ export class ${className}Api extends CrudEndpoint {
|
|
|
158
173
|
const adapterImport = config.backend?.adapter === 'PostgresAdapter' ? '@quatrain/backend-postgres' : '@quatrain/backend-sqlite';
|
|
159
174
|
const modelImports = models.map(m => `import { ${m} } from './models/${m}'`).join('\n');
|
|
160
175
|
const apiImports = models.map(m => `import { ${m}Api } from './api/${m}Api'`).join('\n');
|
|
161
|
-
const apiRegisters = models.map(m => ` server.addEndpoint(
|
|
176
|
+
const apiRegisters = models.map(m => ` server.addEndpoint(${m}Api, '/api/${m.toLowerCase()}s')`).join('\n');
|
|
162
177
|
const indexCode = `import * as path from 'path'
|
|
163
178
|
import { Backend, InjectMetaMiddleware } from '@quatrain/backend'
|
|
164
179
|
import { ${adapterClass} } from '${adapterImport}'
|
|
165
180
|
import { ExpressAdapter } from '@quatrain/api-server'
|
|
166
181
|
import { MigrationManager } from '@quatrain/backend-migrations'
|
|
182
|
+
import { Log, DefaultLoggerAdapter, LogLevel } from '@quatrain/log'
|
|
167
183
|
${config.authMode === 'oauth' ? `import { AuthOIDC } from '@quatrain/auth-oidc'\n` : ''}
|
|
168
184
|
${modelImports}
|
|
169
185
|
${apiImports}
|
|
170
186
|
|
|
171
187
|
;(async () => {
|
|
172
188
|
try {
|
|
189
|
+
const isProd = process.env.NODE_ENV === 'production'
|
|
190
|
+
Log.addLogger('default', new DefaultLoggerAdapter('', isProd ? LogLevel.INFO : LogLevel.DEBUG), true)
|
|
191
|
+
|
|
173
192
|
const adapter = new ${adapterClass}({
|
|
174
193
|
config: ${adapterClass === 'SQLiteAdapter' ? '{ database: path.resolve(process.cwd(), "data/app.sqlite") }' : 'process.env.DATABASE_URL'},
|
|
175
194
|
middlewares: [new InjectMetaMiddleware()]
|
|
176
195
|
})
|
|
177
196
|
|
|
178
|
-
Backend.
|
|
197
|
+
Backend.addBackend(adapter, 'default', true)
|
|
179
198
|
|
|
180
|
-
const mm = new MigrationManager()
|
|
181
|
-
await mm.
|
|
199
|
+
const mm = new MigrationManager(adapter)
|
|
200
|
+
await mm.executeMigrations()
|
|
182
201
|
|
|
183
202
|
const server = new ExpressAdapter()
|
|
184
203
|
|
|
@@ -186,7 +205,7 @@ ${apiRegisters}
|
|
|
186
205
|
|
|
187
206
|
${config.authMode === 'oauth' ? ` // Initialize OIDC Auth
|
|
188
207
|
const oidc = AuthOIDC.init('http://localhost:4001')
|
|
189
|
-
server.
|
|
208
|
+
server.getNativeInstance().use('/oidc', oidc.callback())
|
|
190
209
|
` : ''}
|
|
191
210
|
|
|
192
211
|
const PORT = Number(process.env.PORT) || 4001
|
|
@@ -209,21 +228,30 @@ ${config.authMode === 'oauth' ? ` // Initialize OIDC Auth
|
|
|
209
228
|
if (!model.name)
|
|
210
229
|
continue;
|
|
211
230
|
const collectionName = model.collectionName || model.name.toLowerCase();
|
|
212
|
-
const
|
|
231
|
+
const baseColumns = ['id', 'name', 'status', 'createdby', 'createdat', 'updatedby', 'updatedat', 'deletedby', 'deletedat'];
|
|
232
|
+
const customColumns = model.properties
|
|
233
|
+
.filter((p) => !baseColumns.includes(p.name.toLowerCase()))
|
|
234
|
+
.map((p) => {
|
|
213
235
|
let sqlType = 'TEXT';
|
|
214
236
|
if (p.type === 'NumberProperty' || p.type === 'BooleanProperty')
|
|
215
237
|
sqlType = 'INTEGER';
|
|
216
|
-
return `${p.name} ${sqlType}`;
|
|
217
|
-
})
|
|
238
|
+
return `${p.name.toLowerCase()} ${sqlType}`;
|
|
239
|
+
});
|
|
240
|
+
const allColumns = [
|
|
241
|
+
'id TEXT PRIMARY KEY',
|
|
242
|
+
'name TEXT',
|
|
243
|
+
'status TEXT',
|
|
244
|
+
'createdat INTEGER',
|
|
245
|
+
'updatedat INTEGER',
|
|
246
|
+
'deletedat INTEGER',
|
|
247
|
+
'createdby TEXT',
|
|
248
|
+
'updatedby TEXT',
|
|
249
|
+
'deletedby TEXT',
|
|
250
|
+
...customColumns
|
|
251
|
+
].join(',\n ');
|
|
218
252
|
upQueries += `
|
|
219
253
|
await adapter.rawQuery(\`CREATE TABLE IF NOT EXISTS ${collectionName} (
|
|
220
|
-
|
|
221
|
-
status TEXT,
|
|
222
|
-
created_at TEXT,
|
|
223
|
-
updated_at TEXT,
|
|
224
|
-
created_by TEXT,
|
|
225
|
-
updated_by TEXT,
|
|
226
|
-
${columns}
|
|
254
|
+
${allColumns}
|
|
227
255
|
)\`)\n`;
|
|
228
256
|
downQueries += `
|
|
229
257
|
await adapter.rawQuery('DROP TABLE IF EXISTS ${collectionName}')\n`;
|
|
@@ -244,8 +272,298 @@ export const down = async ({ context: adapter }: { context: AbstractBackendAdapt
|
|
|
244
272
|
}
|
|
245
273
|
}
|
|
246
274
|
`;
|
|
275
|
+
const migrationsDir = path.resolve(targetDir, 'data/migrations/default');
|
|
276
|
+
if (fs.existsSync(migrationsDir)) {
|
|
277
|
+
fs.readdirSync(migrationsDir).forEach(file => {
|
|
278
|
+
if (file.endsWith('.ts')) {
|
|
279
|
+
fs.unlinkSync(path.join(migrationsDir, file));
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
}
|
|
247
283
|
const timestamp = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14);
|
|
248
|
-
fs.writeFileSync(path.
|
|
284
|
+
fs.writeFileSync(path.join(migrationsDir, `${timestamp}_init.ts`), migrationCode);
|
|
285
|
+
}
|
|
286
|
+
static generateFrontend(config, targetDir, models) {
|
|
287
|
+
const webDir = path.resolve(targetDir, 'web');
|
|
288
|
+
if (!fs.existsSync(webDir)) {
|
|
289
|
+
fs.mkdirSync(webDir, { recursive: true });
|
|
290
|
+
}
|
|
291
|
+
const srcDir = path.resolve(webDir, 'src');
|
|
292
|
+
if (!fs.existsSync(srcDir)) {
|
|
293
|
+
fs.mkdirSync(srcDir, { recursive: true });
|
|
294
|
+
}
|
|
295
|
+
const pagesDir = path.resolve(srcDir, 'pages');
|
|
296
|
+
if (!fs.existsSync(pagesDir)) {
|
|
297
|
+
fs.mkdirSync(pagesDir, { recursive: true });
|
|
298
|
+
}
|
|
299
|
+
const packageJson = {
|
|
300
|
+
name: "quatrain-ui-front",
|
|
301
|
+
private: true,
|
|
302
|
+
version: "1.0.0",
|
|
303
|
+
type: "module",
|
|
304
|
+
scripts: {
|
|
305
|
+
"dev": "vite",
|
|
306
|
+
"build": "tsc && vite build",
|
|
307
|
+
"preview": "vite preview"
|
|
308
|
+
},
|
|
309
|
+
dependencies: {
|
|
310
|
+
"@mantine/core": "^7.11.1",
|
|
311
|
+
"@mantine/hooks": "^7.11.1",
|
|
312
|
+
"@quatrain/api-client": "latest-dev",
|
|
313
|
+
"@quatrain/ui-form-react": "latest-dev",
|
|
314
|
+
"react": "^18.3.1",
|
|
315
|
+
"react-dom": "^18.3.1",
|
|
316
|
+
"react-router-dom": "^6.24.1"
|
|
317
|
+
},
|
|
318
|
+
devDependencies: {
|
|
319
|
+
"@types/react": "^18.3.3",
|
|
320
|
+
"@types/react-dom": "^18.3.0",
|
|
321
|
+
"@vitejs/plugin-react": "^4.3.1",
|
|
322
|
+
"typescript": "^5.5.3",
|
|
323
|
+
"vite": "^5.3.4"
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
fs.writeFileSync(path.join(webDir, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
327
|
+
const tsConfig = {
|
|
328
|
+
compilerOptions: {
|
|
329
|
+
target: "ES2020",
|
|
330
|
+
useDefineForClassFields: true,
|
|
331
|
+
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
332
|
+
module: "ESNext",
|
|
333
|
+
skipLibCheck: true,
|
|
334
|
+
moduleResolution: "bundler",
|
|
335
|
+
allowImportingTsExtensions: true,
|
|
336
|
+
resolveJsonModule: true,
|
|
337
|
+
isolatedModules: true,
|
|
338
|
+
noEmit: true,
|
|
339
|
+
jsx: "react-jsx",
|
|
340
|
+
strict: true,
|
|
341
|
+
noUnusedLocals: true,
|
|
342
|
+
noUnusedParameters: true,
|
|
343
|
+
noFallthroughCasesInSwitch: true
|
|
344
|
+
},
|
|
345
|
+
include: ["src"]
|
|
346
|
+
};
|
|
347
|
+
fs.writeFileSync(path.join(webDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2));
|
|
348
|
+
const viteConfig = `import { defineConfig } from 'vite'
|
|
349
|
+
import react from '@vitejs/plugin-react'
|
|
350
|
+
|
|
351
|
+
// https://vitejs.dev/config/
|
|
352
|
+
export default defineConfig({
|
|
353
|
+
plugins: [react()],
|
|
354
|
+
server: {
|
|
355
|
+
host: '0.0.0.0',
|
|
356
|
+
port: 3000,
|
|
357
|
+
proxy: {
|
|
358
|
+
'/api': {
|
|
359
|
+
target: 'http://localhost:4001',
|
|
360
|
+
changeOrigin: true
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
})
|
|
365
|
+
`;
|
|
366
|
+
fs.writeFileSync(path.join(webDir, 'vite.config.ts'), viteConfig);
|
|
367
|
+
const indexHtml = `<!doctype html>
|
|
368
|
+
<html lang="en">
|
|
369
|
+
<head>
|
|
370
|
+
<meta charset="UTF-8" />
|
|
371
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
372
|
+
<title>Quatrain App</title>
|
|
373
|
+
</head>
|
|
374
|
+
<body>
|
|
375
|
+
<div id="root"></div>
|
|
376
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
377
|
+
</body>
|
|
378
|
+
</html>
|
|
379
|
+
`;
|
|
380
|
+
fs.writeFileSync(path.join(webDir, 'index.html'), indexHtml);
|
|
381
|
+
const mainTsx = `import React from 'react'
|
|
382
|
+
import ReactDOM from 'react-dom/client'
|
|
383
|
+
import { MantineProvider } from '@mantine/core'
|
|
384
|
+
import '@mantine/core/styles.css'
|
|
385
|
+
import { BrowserRouter } from 'react-router-dom'
|
|
386
|
+
import App from './App.tsx'
|
|
387
|
+
|
|
388
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
389
|
+
<React.StrictMode>
|
|
390
|
+
<MantineProvider defaultColorScheme="dark">
|
|
391
|
+
<BrowserRouter>
|
|
392
|
+
<App />
|
|
393
|
+
</BrowserRouter>
|
|
394
|
+
</MantineProvider>
|
|
395
|
+
</React.StrictMode>,
|
|
396
|
+
)
|
|
397
|
+
`;
|
|
398
|
+
fs.writeFileSync(path.join(srcDir, 'main.tsx'), mainTsx);
|
|
399
|
+
const apiTs = `import { ApiClient } from '@quatrain/api-client'
|
|
400
|
+
|
|
401
|
+
export const api = new ApiClient('/api')
|
|
402
|
+
`;
|
|
403
|
+
fs.writeFileSync(path.join(srcDir, 'api.ts'), apiTs);
|
|
404
|
+
const menuItems = models.map(m => ` <a href="/${m.toLowerCase()}s" style={{display: 'block', padding: '10px', color: 'white', textDecoration: 'none'}}>${m}s</a>`).join('\n');
|
|
405
|
+
const routes = models.map(m => ` <Route path="/${m.toLowerCase()}s" element={<${m}List />} />\n <Route path="/${m.toLowerCase()}s/:id" element={<${m}Form />} />`).join('\n');
|
|
406
|
+
const imports = models.map(m => `import { ${m}List } from './pages/${m}List'\nimport { ${m}Form } from './pages/${m}Form'`).join('\n');
|
|
407
|
+
const appTsx = `import { AppShell, Burger, Group, Title } from '@mantine/core'
|
|
408
|
+
import { useDisclosure } from '@mantine/hooks'
|
|
409
|
+
import { Routes, Route } from 'react-router-dom'
|
|
410
|
+
${imports}
|
|
411
|
+
|
|
412
|
+
export default function App() {
|
|
413
|
+
const [opened, { toggle }] = useDisclosure()
|
|
414
|
+
|
|
415
|
+
return (
|
|
416
|
+
<AppShell
|
|
417
|
+
header={{ height: 60 }}
|
|
418
|
+
navbar={{
|
|
419
|
+
width: 300,
|
|
420
|
+
breakpoint: 'sm',
|
|
421
|
+
collapsed: { mobile: !opened },
|
|
422
|
+
}}
|
|
423
|
+
padding="md"
|
|
424
|
+
>
|
|
425
|
+
<AppShell.Header>
|
|
426
|
+
<Group h="100%" px="md">
|
|
427
|
+
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
|
|
428
|
+
<Title order={3}>Quatrain App</Title>
|
|
429
|
+
</Group>
|
|
430
|
+
</AppShell.Header>
|
|
431
|
+
|
|
432
|
+
<AppShell.Navbar p="md">
|
|
433
|
+
${menuItems}
|
|
434
|
+
</AppShell.Navbar>
|
|
435
|
+
|
|
436
|
+
<AppShell.Main>
|
|
437
|
+
<Routes>
|
|
438
|
+
${routes}
|
|
439
|
+
<Route path="/" element={<div>Welcome to your Quatrain Application</div>} />
|
|
440
|
+
</Routes>
|
|
441
|
+
</AppShell.Main>
|
|
442
|
+
</AppShell>
|
|
443
|
+
)
|
|
444
|
+
}
|
|
445
|
+
`;
|
|
446
|
+
fs.writeFileSync(path.join(srcDir, 'App.tsx'), appTsx);
|
|
447
|
+
for (const m of models) {
|
|
448
|
+
const modelConfig = config.models.find((mod) => mod.name === m);
|
|
449
|
+
const props = modelConfig?.properties || [];
|
|
450
|
+
const listTsx = `import { useEffect, useState } from 'react'
|
|
451
|
+
import { Table, Button, Group, Title } from '@mantine/core'
|
|
452
|
+
import { useNavigate } from 'react-router-dom'
|
|
453
|
+
import { api } from '../api'
|
|
454
|
+
|
|
455
|
+
export function ${m}List() {
|
|
456
|
+
const [data, setData] = useState<any[]>([])
|
|
457
|
+
const navigate = useNavigate()
|
|
458
|
+
|
|
459
|
+
useEffect(() => {
|
|
460
|
+
api.get('${m.toLowerCase()}s').then((res) => {
|
|
461
|
+
if (res && res.data) {
|
|
462
|
+
setData(res.data)
|
|
463
|
+
}
|
|
464
|
+
})
|
|
465
|
+
}, [])
|
|
466
|
+
|
|
467
|
+
const handleDelete = async (id: string) => {
|
|
468
|
+
if (confirm('Are you sure?')) {
|
|
469
|
+
await api.delete('${m.toLowerCase()}s/' + id, {})
|
|
470
|
+
setData(data.filter(item => item.uid !== id))
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return (
|
|
475
|
+
<div>
|
|
476
|
+
<Group justify="space-between" mb="md">
|
|
477
|
+
<Title order={2}>${m}s</Title>
|
|
478
|
+
<Button onClick={() => navigate('/${m.toLowerCase()}s/new')}>Create ${m}</Button>
|
|
479
|
+
</Group>
|
|
480
|
+
<Table>
|
|
481
|
+
<Table.Thead>
|
|
482
|
+
<Table.Tr>
|
|
483
|
+
<Table.Th>Name</Table.Th>
|
|
484
|
+
<Table.Th>Status</Table.Th>
|
|
485
|
+
<Table.Th>Actions</Table.Th>
|
|
486
|
+
</Table.Tr>
|
|
487
|
+
</Table.Thead>
|
|
488
|
+
<Table.Tbody>
|
|
489
|
+
{data.map(item => (
|
|
490
|
+
<Table.Tr key={item.uid}>
|
|
491
|
+
<Table.Td>{item.name || item.uid}</Table.Td>
|
|
492
|
+
<Table.Td>{item.status}</Table.Td>
|
|
493
|
+
<Table.Td>
|
|
494
|
+
<Group>
|
|
495
|
+
<Button size="xs" variant="outline" onClick={() => navigate(\`/${m.toLowerCase()}s/\${item.uid}\`)}>Edit</Button>
|
|
496
|
+
<Button size="xs" color="red" variant="outline" onClick={() => handleDelete(item.uid)}>Delete</Button>
|
|
497
|
+
</Group>
|
|
498
|
+
</Table.Td>
|
|
499
|
+
</Table.Tr>
|
|
500
|
+
))}
|
|
501
|
+
</Table.Tbody>
|
|
502
|
+
</Table>
|
|
503
|
+
</div>
|
|
504
|
+
)
|
|
505
|
+
}
|
|
506
|
+
`;
|
|
507
|
+
fs.writeFileSync(path.join(pagesDir, `${m}List.tsx`), listTsx);
|
|
508
|
+
const modelSchemaStr = JSON.stringify(modelConfig, null, 3);
|
|
509
|
+
const formTsx = `import { CoreForm } from '@quatrain/ui-form-react'
|
|
510
|
+
import { useNavigate, useParams } from 'react-router-dom'
|
|
511
|
+
import { api } from '../api'
|
|
512
|
+
|
|
513
|
+
export function ${m}Form() {
|
|
514
|
+
const { id } = useParams()
|
|
515
|
+
const navigate = useNavigate()
|
|
516
|
+
|
|
517
|
+
const modelSchema = ${modelSchemaStr}
|
|
518
|
+
|
|
519
|
+
return (
|
|
520
|
+
<CoreForm
|
|
521
|
+
modelSchema={modelSchema}
|
|
522
|
+
objectId={id}
|
|
523
|
+
apiClient={api}
|
|
524
|
+
onSave={() => navigate('/${m.toLowerCase()}s')}
|
|
525
|
+
onCancel={() => navigate('/${m.toLowerCase()}s')}
|
|
526
|
+
/>
|
|
527
|
+
)
|
|
528
|
+
}
|
|
529
|
+
`;
|
|
530
|
+
fs.writeFileSync(path.join(pagesDir, `${m}Form.tsx`), formTsx);
|
|
531
|
+
}
|
|
532
|
+
const dockerfile = `FROM node:22-alpine as builder
|
|
533
|
+
WORKDIR /app
|
|
534
|
+
COPY package*.json ./
|
|
535
|
+
RUN yarn install
|
|
536
|
+
COPY . .
|
|
537
|
+
RUN yarn build
|
|
538
|
+
|
|
539
|
+
FROM nginx:alpine
|
|
540
|
+
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
541
|
+
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
542
|
+
EXPOSE 80
|
|
543
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
544
|
+
`;
|
|
545
|
+
fs.writeFileSync(path.join(webDir, 'Dockerfile'), dockerfile);
|
|
546
|
+
const nginxConf = `server {
|
|
547
|
+
listen 80;
|
|
548
|
+
server_name localhost;
|
|
549
|
+
|
|
550
|
+
location / {
|
|
551
|
+
root /usr/share/nginx/html;
|
|
552
|
+
index index.html index.htm;
|
|
553
|
+
try_files $uri $uri/ /index.html;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
location /api/ {
|
|
557
|
+
proxy_pass http://engine:4001/;
|
|
558
|
+
proxy_http_version 1.1;
|
|
559
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
560
|
+
proxy_set_header Connection 'upgrade';
|
|
561
|
+
proxy_set_header Host $host;
|
|
562
|
+
proxy_cache_bypass $http_upgrade;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
`;
|
|
566
|
+
fs.writeFileSync(path.join(webDir, 'nginx.conf'), nginxConf);
|
|
249
567
|
}
|
|
250
568
|
}
|
|
251
569
|
exports.CodeGenerator = CodeGenerator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeGenerator.js","sourceRoot":"","sources":["../src/CodeGenerator.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CodeGenerator.js","sourceRoot":"","sources":["../src/CodeGenerator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfraBuilder.d.ts","sourceRoot":"","sources":["../src/InfraBuilder.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,WAAW;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAC/B;AAED,qBAAa,YAAY;WAIR,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,GAAE,MAAuB,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;
|
|
1
|
+
{"version":3,"file":"InfraBuilder.d.ts","sourceRoot":"","sources":["../src/InfraBuilder.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,WAAW;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAC/B;AAED,qBAAa,YAAY;WAIR,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,GAAE,MAAuB,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;CAgI1H"}
|
package/dist/InfraBuilder.js
CHANGED
|
@@ -49,13 +49,23 @@ class InfraBuilder {
|
|
|
49
49
|
},
|
|
50
50
|
container_name: `${appName}-engine`,
|
|
51
51
|
restart: 'unless-stopped',
|
|
52
|
-
ports: ['
|
|
52
|
+
ports: ['4001:4001'],
|
|
53
53
|
environment: {
|
|
54
54
|
NODE_ENV: 'production'
|
|
55
55
|
},
|
|
56
|
-
volumes: ['./quatrain.json:/app/quatrain.json:ro'],
|
|
56
|
+
volumes: ['./quatrain.json:/app/quatrain.json:ro', './data:/app/data'],
|
|
57
57
|
depends_on: []
|
|
58
58
|
};
|
|
59
|
+
compose.services['ui'] = {
|
|
60
|
+
build: {
|
|
61
|
+
context: './web',
|
|
62
|
+
dockerfile: 'Dockerfile'
|
|
63
|
+
},
|
|
64
|
+
container_name: `${appName}-ui`,
|
|
65
|
+
restart: 'unless-stopped',
|
|
66
|
+
ports: ['3000:80'],
|
|
67
|
+
depends_on: ['engine']
|
|
68
|
+
};
|
|
59
69
|
if (config.backend && config.backend.adapter === 'PostgresAdapter') {
|
|
60
70
|
const dbUser = 'quatrain';
|
|
61
71
|
const dbPass = 'quatrain_pass';
|
|
@@ -122,7 +132,7 @@ COPY package.json tsconfig.json quatrain.json ./
|
|
|
122
132
|
RUN bun install
|
|
123
133
|
COPY src ./src
|
|
124
134
|
COPY data ./data
|
|
125
|
-
EXPOSE
|
|
135
|
+
EXPOSE 4001
|
|
126
136
|
CMD ["bun", "run", "src/index.ts"]
|
|
127
137
|
`.trim();
|
|
128
138
|
return { compose: composeYaml, env: envFile, dockerfile };
|
package/dist/InfraBuilder.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfraBuilder.js","sourceRoot":"","sources":["../src/InfraBuilder.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA4B;AAoB5B,MAAa,YAAY;IAIf,MAAM,CAAC,KAAK,CAAC,MAAW,EAAE,UAAkB,cAAc;QAC9D,MAAM,OAAO,GAAgB;YAC1B,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACb,CAAA;QAED,MAAM,OAAO,GAA2B,EAAE,CAAA;QAG1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG;YAC1B,KAAK,EAAE;gBACJ,OAAO,EAAE,GAAG;gBACZ,UAAU,EAAE,eAAe;aAC7B;YACD,cAAc,EAAE,GAAG,OAAO,SAAS;YACnC,OAAO,EAAE,gBAAgB;YACzB,KAAK,EAAE,CAAC,WAAW,
|
|
1
|
+
{"version":3,"file":"InfraBuilder.js","sourceRoot":"","sources":["../src/InfraBuilder.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quatrain/app",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
5
|
"description": "Quatrain App Bootloader and configuration helpers",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,13 +20,13 @@
|
|
|
20
20
|
},
|
|
21
21
|
"author": "Quatrain Développement SAS <developers@quatrain.com>",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@quatrain/auth": "^1.2.
|
|
24
|
-
"@quatrain/backend": "^1.2.
|
|
25
|
-
"@quatrain/core": "^1.2.
|
|
26
|
-
"@quatrain/log": "^1.2.
|
|
27
|
-
"@quatrain/messaging": "^1.1.
|
|
28
|
-
"@quatrain/queue": "^1.2.
|
|
29
|
-
"@quatrain/storage": "^1.2.
|
|
23
|
+
"@quatrain/auth": "^1.2.1",
|
|
24
|
+
"@quatrain/backend": "^1.2.1",
|
|
25
|
+
"@quatrain/core": "^1.2.1",
|
|
26
|
+
"@quatrain/log": "^1.2.1",
|
|
27
|
+
"@quatrain/messaging": "^1.1.1",
|
|
28
|
+
"@quatrain/queue": "^1.2.1",
|
|
29
|
+
"@quatrain/storage": "^1.2.1",
|
|
30
30
|
"yaml": "^2.4.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
package/src/CodeGenerator.ts
CHANGED
|
@@ -9,12 +9,18 @@ export class CodeGenerator {
|
|
|
9
9
|
public static generate(config: any, targetDir: string): void {
|
|
10
10
|
const fullTargetDir = path.resolve(process.cwd(), targetDir)
|
|
11
11
|
|
|
12
|
-
// Ensure base directories exist
|
|
13
|
-
const dirs = ['src/models', 'src/api', 'data/migrations/default']
|
|
12
|
+
// Ensure base directories exist and clear old files to prevent orphans
|
|
13
|
+
const dirs = ['src/models', 'src/api', 'data/migrations/default', 'web/src/pages']
|
|
14
14
|
for (const dir of dirs) {
|
|
15
15
|
const d = path.resolve(fullTargetDir, dir)
|
|
16
16
|
if (!fs.existsSync(d)) {
|
|
17
17
|
fs.mkdirSync(d, { recursive: true })
|
|
18
|
+
} else if (dir === 'src/models' || dir === 'src/api' || dir === 'web/src/pages') {
|
|
19
|
+
fs.readdirSync(d).forEach(file => {
|
|
20
|
+
if (file.endsWith('.ts') || file.endsWith('.tsx')) {
|
|
21
|
+
fs.unlinkSync(path.join(d, file))
|
|
22
|
+
}
|
|
23
|
+
})
|
|
18
24
|
}
|
|
19
25
|
}
|
|
20
26
|
|
|
@@ -25,6 +31,8 @@ export class CodeGenerator {
|
|
|
25
31
|
this.generateApiEndpoints(config, fullTargetDir, generatedModels)
|
|
26
32
|
this.generateIndex(config, fullTargetDir, generatedModels)
|
|
27
33
|
this.generateMigration(config, fullTargetDir)
|
|
34
|
+
|
|
35
|
+
this.generateFrontend(config, fullTargetDir, generatedModels)
|
|
28
36
|
|
|
29
37
|
Log.info(`[CodeGenerator] Application générée avec succès dans ${fullTargetDir}`)
|
|
30
38
|
}
|
|
@@ -41,7 +49,8 @@ export class CodeGenerator {
|
|
|
41
49
|
main: "src/index.ts",
|
|
42
50
|
type: "module",
|
|
43
51
|
scripts: {
|
|
44
|
-
start: "bun run src/index.ts"
|
|
52
|
+
"start:dev": "NODE_ENV=development bun run --watch src/index.ts",
|
|
53
|
+
"start:prod": "NODE_ENV=production bun run src/index.ts"
|
|
45
54
|
},
|
|
46
55
|
dependencies: {
|
|
47
56
|
"@quatrain/core": targetNpmTag,
|
|
@@ -92,17 +101,24 @@ export class CodeGenerator {
|
|
|
92
101
|
const collectionName = model.collectionName || className.toLowerCase()
|
|
93
102
|
generatedNames.push(className)
|
|
94
103
|
|
|
104
|
+
// Helper to map raw types to Property classes
|
|
105
|
+
const mapTypeToClass = (type: string) => {
|
|
106
|
+
if (type.toLowerCase() === 'datetime') return 'DateTimeProperty'
|
|
107
|
+
return type.charAt(0).toUpperCase() + type.slice(1) + 'Property'
|
|
108
|
+
}
|
|
109
|
+
|
|
95
110
|
// Use imports from core properties
|
|
96
111
|
const propsCode = model.properties.map((p: any) => {
|
|
97
|
-
const
|
|
112
|
+
const propClass = mapTypeToClass(p.type)
|
|
113
|
+
const htmlTypeLine = p.htmlType ? `,\n htmlType: '${p.htmlType}'` : ''
|
|
98
114
|
return ` {
|
|
99
115
|
name: '${p.name}',
|
|
100
|
-
type: ${
|
|
101
|
-
mandatory: ${p.options?.mandatory ? 'true' : 'false'}
|
|
116
|
+
type: ${propClass}.TYPE,
|
|
117
|
+
mandatory: ${p.options?.mandatory ? 'true' : 'false'}${htmlTypeLine}
|
|
102
118
|
}`
|
|
103
119
|
}).join(',\n')
|
|
104
120
|
|
|
105
|
-
const propTypesToImport = Array.from(new Set(model.properties.map((p: any) => p.type)))
|
|
121
|
+
const propTypesToImport = Array.from(new Set(model.properties.map((p: any) => mapTypeToClass(p.type))))
|
|
106
122
|
|
|
107
123
|
const modelCode = `import { PersistedBaseObject } from '@quatrain/backend'
|
|
108
124
|
import { ${propTypesToImport.join(', ')} } from '@quatrain/core'
|
|
@@ -128,13 +144,13 @@ export class ${className} extends PersistedBaseObject {
|
|
|
128
144
|
|
|
129
145
|
private static generateApiEndpoints(config: any, targetDir: string, models: string[]): void {
|
|
130
146
|
for (const className of models) {
|
|
131
|
-
const apiCode = `import { CrudEndpoint } from '@quatrain/api-server'
|
|
147
|
+
const apiCode = `import { CrudEndpoint, ValuesEndpoint } from '@quatrain/api-server'
|
|
148
|
+
import { ServerAdapter, EndpointOptions } from '@quatrain/api'
|
|
132
149
|
import { ${className} } from '../models/${className}'
|
|
133
150
|
|
|
134
|
-
export
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
151
|
+
export const ${className}Api = (router: ServerAdapter, path: string, options: EndpointOptions) => {
|
|
152
|
+
CrudEndpoint(${className})(router, path, options)
|
|
153
|
+
ValuesEndpoint(${className})(router, path, options)
|
|
138
154
|
}
|
|
139
155
|
`
|
|
140
156
|
fs.writeFileSync(path.resolve(targetDir, `src/api/${className}Api.ts`), apiCode)
|
|
@@ -147,28 +163,32 @@ export class ${className}Api extends CrudEndpoint {
|
|
|
147
163
|
|
|
148
164
|
const modelImports = models.map(m => `import { ${m} } from './models/${m}'`).join('\n')
|
|
149
165
|
const apiImports = models.map(m => `import { ${m}Api } from './api/${m}Api'`).join('\n')
|
|
150
|
-
const apiRegisters = models.map(m => ` server.addEndpoint(
|
|
166
|
+
const apiRegisters = models.map(m => ` server.addEndpoint(${m}Api, '/api/${m.toLowerCase()}s')`).join('\n')
|
|
151
167
|
|
|
152
168
|
const indexCode = `import * as path from 'path'
|
|
153
169
|
import { Backend, InjectMetaMiddleware } from '@quatrain/backend'
|
|
154
170
|
import { ${adapterClass} } from '${adapterImport}'
|
|
155
171
|
import { ExpressAdapter } from '@quatrain/api-server'
|
|
156
172
|
import { MigrationManager } from '@quatrain/backend-migrations'
|
|
173
|
+
import { Log, DefaultLoggerAdapter, LogLevel } from '@quatrain/log'
|
|
157
174
|
${config.authMode === 'oauth' ? `import { AuthOIDC } from '@quatrain/auth-oidc'\n` : ''}
|
|
158
175
|
${modelImports}
|
|
159
176
|
${apiImports}
|
|
160
177
|
|
|
161
178
|
;(async () => {
|
|
162
179
|
try {
|
|
180
|
+
const isProd = process.env.NODE_ENV === 'production'
|
|
181
|
+
Log.addLogger('default', new DefaultLoggerAdapter('', isProd ? LogLevel.INFO : LogLevel.DEBUG), true)
|
|
182
|
+
|
|
163
183
|
const adapter = new ${adapterClass}({
|
|
164
184
|
config: ${adapterClass === 'SQLiteAdapter' ? '{ database: path.resolve(process.cwd(), "data/app.sqlite") }' : 'process.env.DATABASE_URL'},
|
|
165
185
|
middlewares: [new InjectMetaMiddleware()]
|
|
166
186
|
})
|
|
167
187
|
|
|
168
|
-
Backend.
|
|
188
|
+
Backend.addBackend(adapter, 'default', true)
|
|
169
189
|
|
|
170
|
-
const mm = new MigrationManager()
|
|
171
|
-
await mm.
|
|
190
|
+
const mm = new MigrationManager(adapter)
|
|
191
|
+
await mm.executeMigrations()
|
|
172
192
|
|
|
173
193
|
const server = new ExpressAdapter()
|
|
174
194
|
|
|
@@ -176,7 +196,7 @@ ${apiRegisters}
|
|
|
176
196
|
|
|
177
197
|
${config.authMode === 'oauth' ? ` // Initialize OIDC Auth
|
|
178
198
|
const oidc = AuthOIDC.init('http://localhost:4001')
|
|
179
|
-
server.
|
|
199
|
+
server.getNativeInstance().use('/oidc', oidc.callback())
|
|
180
200
|
` : ''}
|
|
181
201
|
|
|
182
202
|
const PORT = Number(process.env.PORT) || 4001
|
|
@@ -202,22 +222,33 @@ ${config.authMode === 'oauth' ? ` // Initialize OIDC Auth
|
|
|
202
222
|
if (!model.name) continue
|
|
203
223
|
const collectionName = model.collectionName || model.name.toLowerCase()
|
|
204
224
|
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
225
|
+
const baseColumns = ['id', 'name', 'status', 'createdby', 'createdat', 'updatedby', 'updatedat', 'deletedby', 'deletedat']
|
|
226
|
+
|
|
227
|
+
const customColumns = model.properties
|
|
228
|
+
.filter((p: any) => !baseColumns.includes(p.name.toLowerCase()))
|
|
229
|
+
.map((p: any) => {
|
|
230
|
+
// Very simplified SQLite type mapping for the PoC
|
|
231
|
+
let sqlType = 'TEXT'
|
|
232
|
+
if (p.type === 'NumberProperty' || p.type === 'BooleanProperty') sqlType = 'INTEGER'
|
|
233
|
+
return `${p.name.toLowerCase()} ${sqlType}`
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
const allColumns = [
|
|
237
|
+
'id TEXT PRIMARY KEY',
|
|
238
|
+
'name TEXT',
|
|
239
|
+
'status TEXT',
|
|
240
|
+
'createdat INTEGER',
|
|
241
|
+
'updatedat INTEGER',
|
|
242
|
+
'deletedat INTEGER',
|
|
243
|
+
'createdby TEXT',
|
|
244
|
+
'updatedby TEXT',
|
|
245
|
+
'deletedby TEXT',
|
|
246
|
+
...customColumns
|
|
247
|
+
].join(',\n ')
|
|
211
248
|
|
|
212
249
|
upQueries += `
|
|
213
250
|
await adapter.rawQuery(\`CREATE TABLE IF NOT EXISTS ${collectionName} (
|
|
214
|
-
|
|
215
|
-
status TEXT,
|
|
216
|
-
created_at TEXT,
|
|
217
|
-
updated_at TEXT,
|
|
218
|
-
created_by TEXT,
|
|
219
|
-
updated_by TEXT,
|
|
220
|
-
${columns}
|
|
251
|
+
${allColumns}
|
|
221
252
|
)\`)\n`
|
|
222
253
|
|
|
223
254
|
downQueries += `
|
|
@@ -240,7 +271,332 @@ export const down = async ({ context: adapter }: { context: AbstractBackendAdapt
|
|
|
240
271
|
}
|
|
241
272
|
}
|
|
242
273
|
`
|
|
274
|
+
const migrationsDir = path.resolve(targetDir, 'data/migrations/default')
|
|
275
|
+
// Clear old migrations to prevent executing buggy or duplicate past generations
|
|
276
|
+
if (fs.existsSync(migrationsDir)) {
|
|
277
|
+
fs.readdirSync(migrationsDir).forEach(file => {
|
|
278
|
+
if (file.endsWith('.ts')) {
|
|
279
|
+
fs.unlinkSync(path.join(migrationsDir, file))
|
|
280
|
+
}
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
|
|
243
284
|
const timestamp = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14)
|
|
244
|
-
fs.writeFileSync(path.
|
|
285
|
+
fs.writeFileSync(path.join(migrationsDir, `${timestamp}_init.ts`), migrationCode)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
private static generateFrontend(config: any, targetDir: string, models: string[]): void {
|
|
289
|
+
const webDir = path.resolve(targetDir, 'web')
|
|
290
|
+
if (!fs.existsSync(webDir)) {
|
|
291
|
+
fs.mkdirSync(webDir, { recursive: true })
|
|
292
|
+
}
|
|
293
|
+
const srcDir = path.resolve(webDir, 'src')
|
|
294
|
+
if (!fs.existsSync(srcDir)) {
|
|
295
|
+
fs.mkdirSync(srcDir, { recursive: true })
|
|
296
|
+
}
|
|
297
|
+
const pagesDir = path.resolve(srcDir, 'pages')
|
|
298
|
+
if (!fs.existsSync(pagesDir)) {
|
|
299
|
+
fs.mkdirSync(pagesDir, { recursive: true })
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// package.json
|
|
303
|
+
const packageJson = {
|
|
304
|
+
name: "quatrain-ui-front",
|
|
305
|
+
private: true,
|
|
306
|
+
version: "1.0.0",
|
|
307
|
+
type: "module",
|
|
308
|
+
scripts: {
|
|
309
|
+
"dev": "vite",
|
|
310
|
+
"build": "tsc && vite build",
|
|
311
|
+
"preview": "vite preview"
|
|
312
|
+
},
|
|
313
|
+
dependencies: {
|
|
314
|
+
"@mantine/core": "^7.11.1",
|
|
315
|
+
"@mantine/hooks": "^7.11.1",
|
|
316
|
+
"@quatrain/api-client": "latest-dev",
|
|
317
|
+
"@quatrain/ui-form-react": "latest-dev",
|
|
318
|
+
"react": "^18.3.1",
|
|
319
|
+
"react-dom": "^18.3.1",
|
|
320
|
+
"react-router-dom": "^6.24.1"
|
|
321
|
+
},
|
|
322
|
+
devDependencies: {
|
|
323
|
+
"@types/react": "^18.3.3",
|
|
324
|
+
"@types/react-dom": "^18.3.0",
|
|
325
|
+
"@vitejs/plugin-react": "^4.3.1",
|
|
326
|
+
"typescript": "^5.5.3",
|
|
327
|
+
"vite": "^5.3.4"
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
fs.writeFileSync(path.join(webDir, 'package.json'), JSON.stringify(packageJson, null, 2))
|
|
331
|
+
|
|
332
|
+
// tsconfig.json
|
|
333
|
+
const tsConfig = {
|
|
334
|
+
compilerOptions: {
|
|
335
|
+
target: "ES2020",
|
|
336
|
+
useDefineForClassFields: true,
|
|
337
|
+
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
338
|
+
module: "ESNext",
|
|
339
|
+
skipLibCheck: true,
|
|
340
|
+
moduleResolution: "bundler",
|
|
341
|
+
allowImportingTsExtensions: true,
|
|
342
|
+
resolveJsonModule: true,
|
|
343
|
+
isolatedModules: true,
|
|
344
|
+
noEmit: true,
|
|
345
|
+
jsx: "react-jsx",
|
|
346
|
+
strict: true,
|
|
347
|
+
noUnusedLocals: true,
|
|
348
|
+
noUnusedParameters: true,
|
|
349
|
+
noFallthroughCasesInSwitch: true
|
|
350
|
+
},
|
|
351
|
+
include: ["src"]
|
|
352
|
+
}
|
|
353
|
+
fs.writeFileSync(path.join(webDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2))
|
|
354
|
+
|
|
355
|
+
// vite.config.ts
|
|
356
|
+
const viteConfig = `import { defineConfig } from 'vite'
|
|
357
|
+
import react from '@vitejs/plugin-react'
|
|
358
|
+
|
|
359
|
+
// https://vitejs.dev/config/
|
|
360
|
+
export default defineConfig({
|
|
361
|
+
plugins: [react()],
|
|
362
|
+
server: {
|
|
363
|
+
host: '0.0.0.0',
|
|
364
|
+
port: 3000,
|
|
365
|
+
proxy: {
|
|
366
|
+
'/api': {
|
|
367
|
+
target: 'http://localhost:4001',
|
|
368
|
+
changeOrigin: true
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
})
|
|
373
|
+
`
|
|
374
|
+
fs.writeFileSync(path.join(webDir, 'vite.config.ts'), viteConfig)
|
|
375
|
+
|
|
376
|
+
// index.html
|
|
377
|
+
const indexHtml = `<!doctype html>
|
|
378
|
+
<html lang="en">
|
|
379
|
+
<head>
|
|
380
|
+
<meta charset="UTF-8" />
|
|
381
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
382
|
+
<title>Quatrain App</title>
|
|
383
|
+
</head>
|
|
384
|
+
<body>
|
|
385
|
+
<div id="root"></div>
|
|
386
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
387
|
+
</body>
|
|
388
|
+
</html>
|
|
389
|
+
`
|
|
390
|
+
fs.writeFileSync(path.join(webDir, 'index.html'), indexHtml)
|
|
391
|
+
|
|
392
|
+
// main.tsx
|
|
393
|
+
const mainTsx = `import React from 'react'
|
|
394
|
+
import ReactDOM from 'react-dom/client'
|
|
395
|
+
import { MantineProvider } from '@mantine/core'
|
|
396
|
+
import '@mantine/core/styles.css'
|
|
397
|
+
import { BrowserRouter } from 'react-router-dom'
|
|
398
|
+
import App from './App.tsx'
|
|
399
|
+
|
|
400
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
401
|
+
<React.StrictMode>
|
|
402
|
+
<MantineProvider defaultColorScheme="dark">
|
|
403
|
+
<BrowserRouter>
|
|
404
|
+
<App />
|
|
405
|
+
</BrowserRouter>
|
|
406
|
+
</MantineProvider>
|
|
407
|
+
</React.StrictMode>,
|
|
408
|
+
)
|
|
409
|
+
`
|
|
410
|
+
fs.writeFileSync(path.join(srcDir, 'main.tsx'), mainTsx)
|
|
411
|
+
|
|
412
|
+
// api.ts
|
|
413
|
+
const apiTs = `import { ApiClient } from '@quatrain/api-client'
|
|
414
|
+
|
|
415
|
+
export const api = new ApiClient('/api')
|
|
416
|
+
`
|
|
417
|
+
fs.writeFileSync(path.join(srcDir, 'api.ts'), apiTs)
|
|
418
|
+
|
|
419
|
+
// App.tsx
|
|
420
|
+
const menuItems = models.map(m =>
|
|
421
|
+
` <a href="/${m.toLowerCase()}s" style={{display: 'block', padding: '10px', color: 'white', textDecoration: 'none'}}>${m}s</a>`
|
|
422
|
+
).join('\n')
|
|
423
|
+
|
|
424
|
+
const routes = models.map(m =>
|
|
425
|
+
` <Route path="/${m.toLowerCase()}s" element={<${m}List />} />\n <Route path="/${m.toLowerCase()}s/:id" element={<${m}Form />} />`
|
|
426
|
+
).join('\n')
|
|
427
|
+
|
|
428
|
+
const imports = models.map(m =>
|
|
429
|
+
`import { ${m}List } from './pages/${m}List'\nimport { ${m}Form } from './pages/${m}Form'`
|
|
430
|
+
).join('\n')
|
|
431
|
+
|
|
432
|
+
const appTsx = `import { AppShell, Burger, Group, Title } from '@mantine/core'
|
|
433
|
+
import { useDisclosure } from '@mantine/hooks'
|
|
434
|
+
import { Routes, Route } from 'react-router-dom'
|
|
435
|
+
${imports}
|
|
436
|
+
|
|
437
|
+
export default function App() {
|
|
438
|
+
const [opened, { toggle }] = useDisclosure()
|
|
439
|
+
|
|
440
|
+
return (
|
|
441
|
+
<AppShell
|
|
442
|
+
header={{ height: 60 }}
|
|
443
|
+
navbar={{
|
|
444
|
+
width: 300,
|
|
445
|
+
breakpoint: 'sm',
|
|
446
|
+
collapsed: { mobile: !opened },
|
|
447
|
+
}}
|
|
448
|
+
padding="md"
|
|
449
|
+
>
|
|
450
|
+
<AppShell.Header>
|
|
451
|
+
<Group h="100%" px="md">
|
|
452
|
+
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
|
|
453
|
+
<Title order={3}>Quatrain App</Title>
|
|
454
|
+
</Group>
|
|
455
|
+
</AppShell.Header>
|
|
456
|
+
|
|
457
|
+
<AppShell.Navbar p="md">
|
|
458
|
+
${menuItems}
|
|
459
|
+
</AppShell.Navbar>
|
|
460
|
+
|
|
461
|
+
<AppShell.Main>
|
|
462
|
+
<Routes>
|
|
463
|
+
${routes}
|
|
464
|
+
<Route path="/" element={<div>Welcome to your Quatrain Application</div>} />
|
|
465
|
+
</Routes>
|
|
466
|
+
</AppShell.Main>
|
|
467
|
+
</AppShell>
|
|
468
|
+
)
|
|
469
|
+
}
|
|
470
|
+
`
|
|
471
|
+
fs.writeFileSync(path.join(srcDir, 'App.tsx'), appTsx)
|
|
472
|
+
|
|
473
|
+
// Generate CRUD pages
|
|
474
|
+
for (const m of models) {
|
|
475
|
+
const modelConfig = config.models.find((mod: any) => mod.name === m)
|
|
476
|
+
const props = modelConfig?.properties || []
|
|
477
|
+
|
|
478
|
+
const listTsx = `import { useEffect, useState } from 'react'
|
|
479
|
+
import { Table, Button, Group, Title } from '@mantine/core'
|
|
480
|
+
import { useNavigate } from 'react-router-dom'
|
|
481
|
+
import { api } from '../api'
|
|
482
|
+
|
|
483
|
+
export function ${m}List() {
|
|
484
|
+
const [data, setData] = useState<any[]>([])
|
|
485
|
+
const navigate = useNavigate()
|
|
486
|
+
|
|
487
|
+
useEffect(() => {
|
|
488
|
+
api.get('${m.toLowerCase()}s').then((res) => {
|
|
489
|
+
if (res && res.data) {
|
|
490
|
+
setData(res.data)
|
|
491
|
+
}
|
|
492
|
+
})
|
|
493
|
+
}, [])
|
|
494
|
+
|
|
495
|
+
const handleDelete = async (id: string) => {
|
|
496
|
+
if (confirm('Are you sure?')) {
|
|
497
|
+
await api.delete('${m.toLowerCase()}s/' + id, {})
|
|
498
|
+
setData(data.filter(item => item.uid !== id))
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return (
|
|
503
|
+
<div>
|
|
504
|
+
<Group justify="space-between" mb="md">
|
|
505
|
+
<Title order={2}>${m}s</Title>
|
|
506
|
+
<Button onClick={() => navigate('/${m.toLowerCase()}s/new')}>Create ${m}</Button>
|
|
507
|
+
</Group>
|
|
508
|
+
<Table>
|
|
509
|
+
<Table.Thead>
|
|
510
|
+
<Table.Tr>
|
|
511
|
+
<Table.Th>Name</Table.Th>
|
|
512
|
+
<Table.Th>Status</Table.Th>
|
|
513
|
+
<Table.Th>Actions</Table.Th>
|
|
514
|
+
</Table.Tr>
|
|
515
|
+
</Table.Thead>
|
|
516
|
+
<Table.Tbody>
|
|
517
|
+
{data.map(item => (
|
|
518
|
+
<Table.Tr key={item.uid}>
|
|
519
|
+
<Table.Td>{item.name || item.uid}</Table.Td>
|
|
520
|
+
<Table.Td>{item.status}</Table.Td>
|
|
521
|
+
<Table.Td>
|
|
522
|
+
<Group>
|
|
523
|
+
<Button size="xs" variant="outline" onClick={() => navigate(\`/${m.toLowerCase()}s/\${item.uid}\`)}>Edit</Button>
|
|
524
|
+
<Button size="xs" color="red" variant="outline" onClick={() => handleDelete(item.uid)}>Delete</Button>
|
|
525
|
+
</Group>
|
|
526
|
+
</Table.Td>
|
|
527
|
+
</Table.Tr>
|
|
528
|
+
))}
|
|
529
|
+
</Table.Tbody>
|
|
530
|
+
</Table>
|
|
531
|
+
</div>
|
|
532
|
+
)
|
|
533
|
+
}
|
|
534
|
+
`
|
|
535
|
+
fs.writeFileSync(path.join(pagesDir, `${m}List.tsx`), listTsx)
|
|
536
|
+
|
|
537
|
+
const modelSchemaStr = JSON.stringify(modelConfig, null, 3)
|
|
538
|
+
|
|
539
|
+
const formTsx = `import { CoreForm } from '@quatrain/ui-form-react'
|
|
540
|
+
import { useNavigate, useParams } from 'react-router-dom'
|
|
541
|
+
import { api } from '../api'
|
|
542
|
+
|
|
543
|
+
export function ${m}Form() {
|
|
544
|
+
const { id } = useParams()
|
|
545
|
+
const navigate = useNavigate()
|
|
546
|
+
|
|
547
|
+
const modelSchema = ${modelSchemaStr}
|
|
548
|
+
|
|
549
|
+
return (
|
|
550
|
+
<CoreForm
|
|
551
|
+
modelSchema={modelSchema}
|
|
552
|
+
objectId={id}
|
|
553
|
+
apiClient={api}
|
|
554
|
+
onSave={() => navigate('/${m.toLowerCase()}s')}
|
|
555
|
+
onCancel={() => navigate('/${m.toLowerCase()}s')}
|
|
556
|
+
/>
|
|
557
|
+
)
|
|
558
|
+
}
|
|
559
|
+
`
|
|
560
|
+
fs.writeFileSync(path.join(pagesDir, `${m}Form.tsx`), formTsx)
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// Dockerfile
|
|
564
|
+
const dockerfile = `FROM node:22-alpine as builder
|
|
565
|
+
WORKDIR /app
|
|
566
|
+
COPY package*.json ./
|
|
567
|
+
RUN yarn install
|
|
568
|
+
COPY . .
|
|
569
|
+
RUN yarn build
|
|
570
|
+
|
|
571
|
+
FROM nginx:alpine
|
|
572
|
+
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
573
|
+
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
574
|
+
EXPOSE 80
|
|
575
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
576
|
+
`
|
|
577
|
+
fs.writeFileSync(path.join(webDir, 'Dockerfile'), dockerfile)
|
|
578
|
+
|
|
579
|
+
// nginx.conf
|
|
580
|
+
const nginxConf = `server {
|
|
581
|
+
listen 80;
|
|
582
|
+
server_name localhost;
|
|
583
|
+
|
|
584
|
+
location / {
|
|
585
|
+
root /usr/share/nginx/html;
|
|
586
|
+
index index.html index.htm;
|
|
587
|
+
try_files $uri $uri/ /index.html;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
location /api/ {
|
|
591
|
+
proxy_pass http://engine:4001/;
|
|
592
|
+
proxy_http_version 1.1;
|
|
593
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
594
|
+
proxy_set_header Connection 'upgrade';
|
|
595
|
+
proxy_set_header Host $host;
|
|
596
|
+
proxy_cache_bypass $http_upgrade;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
`
|
|
600
|
+
fs.writeFileSync(path.join(webDir, 'nginx.conf'), nginxConf)
|
|
245
601
|
}
|
|
246
602
|
}
|
package/src/InfraBuilder.ts
CHANGED
|
@@ -30,7 +30,7 @@ export class InfraBuilder {
|
|
|
30
30
|
|
|
31
31
|
const envVars: Record<string, string> = {}
|
|
32
32
|
|
|
33
|
-
// 1.
|
|
33
|
+
// 1. Backend Engine Container
|
|
34
34
|
compose.services['engine'] = {
|
|
35
35
|
build: {
|
|
36
36
|
context: '.',
|
|
@@ -38,14 +38,26 @@ export class InfraBuilder {
|
|
|
38
38
|
},
|
|
39
39
|
container_name: `${appName}-engine`,
|
|
40
40
|
restart: 'unless-stopped',
|
|
41
|
-
ports: ['
|
|
41
|
+
ports: ['4001:4001'],
|
|
42
42
|
environment: {
|
|
43
43
|
NODE_ENV: 'production'
|
|
44
44
|
},
|
|
45
|
-
volumes: ['./quatrain.json:/app/quatrain.json:ro'],
|
|
45
|
+
volumes: ['./quatrain.json:/app/quatrain.json:ro', './data:/app/data'],
|
|
46
46
|
depends_on: []
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// 1b. Frontend UI Container
|
|
50
|
+
compose.services['ui'] = {
|
|
51
|
+
build: {
|
|
52
|
+
context: './web',
|
|
53
|
+
dockerfile: 'Dockerfile'
|
|
54
|
+
},
|
|
55
|
+
container_name: `${appName}-ui`,
|
|
56
|
+
restart: 'unless-stopped',
|
|
57
|
+
ports: ['3000:80'],
|
|
58
|
+
depends_on: ['engine']
|
|
59
|
+
}
|
|
60
|
+
|
|
49
61
|
// 2. Backend Infrastructure
|
|
50
62
|
if (config.backend && config.backend.adapter === 'PostgresAdapter') {
|
|
51
63
|
const dbUser = 'quatrain'
|
|
@@ -132,7 +144,7 @@ COPY package.json tsconfig.json quatrain.json ./
|
|
|
132
144
|
RUN bun install
|
|
133
145
|
COPY src ./src
|
|
134
146
|
COPY data ./data
|
|
135
|
-
EXPOSE
|
|
147
|
+
EXPOSE 4001
|
|
136
148
|
CMD ["bun", "run", "src/index.ts"]
|
|
137
149
|
`.trim()
|
|
138
150
|
|