@quatrain/app 1.1.1 → 1.1.2
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 +364 -25
- package/dist/CodeGenerator.js.map +1 -1
- package/dist/InfraBuilder.d.ts.map +1 -1
- package/dist/InfraBuilder.js +11 -1
- package/dist/InfraBuilder.js.map +1 -1
- package/package.json +8 -8
- package/src/CodeGenerator.ts +405 -28
- package/src/InfraBuilder.ts +14 -2
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;IAyB5D,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAqClC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAiB/B,OAAO,CAAC,MAAM,CAAC,cAAc;IAkD7B,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAWnC,OAAO,CAAC,MAAM,CAAC,aAAa;IAuD5B,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAyEhC,OAAO,CAAC,MAAM,CAAC,gBAAgB;CA0VjC"}
|
package/dist/CodeGenerator.js
CHANGED
|
@@ -53,6 +53,7 @@ class CodeGenerator {
|
|
|
53
53
|
this.generateApiEndpoints(config, fullTargetDir, generatedModels);
|
|
54
54
|
this.generateIndex(config, fullTargetDir, generatedModels);
|
|
55
55
|
this.generateMigration(config, fullTargetDir);
|
|
56
|
+
this.generateFrontend(config, fullTargetDir, generatedModels);
|
|
56
57
|
log_1.Log.info(`[CodeGenerator] Application générée avec succès dans ${fullTargetDir}`);
|
|
57
58
|
}
|
|
58
59
|
static generatePackageJson(config, targetDir) {
|
|
@@ -65,7 +66,8 @@ class CodeGenerator {
|
|
|
65
66
|
main: "src/index.ts",
|
|
66
67
|
type: "module",
|
|
67
68
|
scripts: {
|
|
68
|
-
start: "bun run src/index.ts"
|
|
69
|
+
"start:dev": "NODE_ENV=development bun run --watch src/index.ts",
|
|
70
|
+
"start:prod": "NODE_ENV=production bun run src/index.ts"
|
|
69
71
|
},
|
|
70
72
|
dependencies: {
|
|
71
73
|
"@quatrain/core": targetNpmTag,
|
|
@@ -110,15 +112,20 @@ class CodeGenerator {
|
|
|
110
112
|
const className = model.name;
|
|
111
113
|
const collectionName = model.collectionName || className.toLowerCase();
|
|
112
114
|
generatedNames.push(className);
|
|
115
|
+
const mapTypeToClass = (type) => {
|
|
116
|
+
if (type.toLowerCase() === 'datetime')
|
|
117
|
+
return 'DateTimeProperty';
|
|
118
|
+
return type.charAt(0).toUpperCase() + type.slice(1) + 'Property';
|
|
119
|
+
};
|
|
113
120
|
const propsCode = model.properties.map((p) => {
|
|
114
|
-
const
|
|
121
|
+
const propClass = mapTypeToClass(p.type);
|
|
115
122
|
return ` {
|
|
116
123
|
name: '${p.name}',
|
|
117
|
-
type: ${
|
|
124
|
+
type: ${propClass}.TYPE,
|
|
118
125
|
mandatory: ${p.options?.mandatory ? 'true' : 'false'}
|
|
119
126
|
}`;
|
|
120
127
|
}).join(',\n');
|
|
121
|
-
const propTypesToImport = Array.from(new Set(model.properties.map((p) => p.type)));
|
|
128
|
+
const propTypesToImport = Array.from(new Set(model.properties.map((p) => mapTypeToClass(p.type))));
|
|
122
129
|
const modelCode = `import { PersistedBaseObject } from '@quatrain/backend'
|
|
123
130
|
import { ${propTypesToImport.join(', ')} } from '@quatrain/core'
|
|
124
131
|
|
|
@@ -144,11 +151,7 @@ export class ${className} extends PersistedBaseObject {
|
|
|
144
151
|
const apiCode = `import { CrudEndpoint } from '@quatrain/api-server'
|
|
145
152
|
import { ${className} } from '../models/${className}'
|
|
146
153
|
|
|
147
|
-
export
|
|
148
|
-
constructor() {
|
|
149
|
-
super('/api/${className.toLowerCase()}s', ${className})
|
|
150
|
-
}
|
|
151
|
-
}
|
|
154
|
+
export const ${className}Api = CrudEndpoint(${className})
|
|
152
155
|
`;
|
|
153
156
|
fs.writeFileSync(path.resolve(targetDir, `src/api/${className}Api.ts`), apiCode);
|
|
154
157
|
}
|
|
@@ -158,27 +161,31 @@ export class ${className}Api extends CrudEndpoint {
|
|
|
158
161
|
const adapterImport = config.backend?.adapter === 'PostgresAdapter' ? '@quatrain/backend-postgres' : '@quatrain/backend-sqlite';
|
|
159
162
|
const modelImports = models.map(m => `import { ${m} } from './models/${m}'`).join('\n');
|
|
160
163
|
const apiImports = models.map(m => `import { ${m}Api } from './api/${m}Api'`).join('\n');
|
|
161
|
-
const apiRegisters = models.map(m => ` server.addEndpoint(
|
|
164
|
+
const apiRegisters = models.map(m => ` server.addEndpoint(${m}Api, '/api/${m.toLowerCase()}s')`).join('\n');
|
|
162
165
|
const indexCode = `import * as path from 'path'
|
|
163
166
|
import { Backend, InjectMetaMiddleware } from '@quatrain/backend'
|
|
164
167
|
import { ${adapterClass} } from '${adapterImport}'
|
|
165
168
|
import { ExpressAdapter } from '@quatrain/api-server'
|
|
166
169
|
import { MigrationManager } from '@quatrain/backend-migrations'
|
|
170
|
+
import { Log, DefaultLoggerAdapter, LogLevel } from '@quatrain/log'
|
|
167
171
|
${config.authMode === 'oauth' ? `import { AuthOIDC } from '@quatrain/auth-oidc'\n` : ''}
|
|
168
172
|
${modelImports}
|
|
169
173
|
${apiImports}
|
|
170
174
|
|
|
171
175
|
;(async () => {
|
|
172
176
|
try {
|
|
177
|
+
const isProd = process.env.NODE_ENV === 'production'
|
|
178
|
+
Log.addLogger('default', new DefaultLoggerAdapter('', isProd ? LogLevel.INFO : LogLevel.DEBUG), true)
|
|
179
|
+
|
|
173
180
|
const adapter = new ${adapterClass}({
|
|
174
181
|
config: ${adapterClass === 'SQLiteAdapter' ? '{ database: path.resolve(process.cwd(), "data/app.sqlite") }' : 'process.env.DATABASE_URL'},
|
|
175
182
|
middlewares: [new InjectMetaMiddleware()]
|
|
176
183
|
})
|
|
177
184
|
|
|
178
|
-
Backend.
|
|
185
|
+
Backend.addBackend(adapter, 'default', true)
|
|
179
186
|
|
|
180
|
-
const mm = new MigrationManager()
|
|
181
|
-
await mm.
|
|
187
|
+
const mm = new MigrationManager(adapter)
|
|
188
|
+
await mm.executeMigrations()
|
|
182
189
|
|
|
183
190
|
const server = new ExpressAdapter()
|
|
184
191
|
|
|
@@ -186,7 +193,7 @@ ${apiRegisters}
|
|
|
186
193
|
|
|
187
194
|
${config.authMode === 'oauth' ? ` // Initialize OIDC Auth
|
|
188
195
|
const oidc = AuthOIDC.init('http://localhost:4001')
|
|
189
|
-
server.
|
|
196
|
+
server.getNativeInstance().use('/oidc', oidc.callback())
|
|
190
197
|
` : ''}
|
|
191
198
|
|
|
192
199
|
const PORT = Number(process.env.PORT) || 4001
|
|
@@ -209,21 +216,30 @@ ${config.authMode === 'oauth' ? ` // Initialize OIDC Auth
|
|
|
209
216
|
if (!model.name)
|
|
210
217
|
continue;
|
|
211
218
|
const collectionName = model.collectionName || model.name.toLowerCase();
|
|
212
|
-
const
|
|
219
|
+
const baseColumns = ['id', 'name', 'status', 'createdby', 'createdat', 'updatedby', 'updatedat', 'deletedby', 'deletedat'];
|
|
220
|
+
const customColumns = model.properties
|
|
221
|
+
.filter((p) => !baseColumns.includes(p.name.toLowerCase()))
|
|
222
|
+
.map((p) => {
|
|
213
223
|
let sqlType = 'TEXT';
|
|
214
224
|
if (p.type === 'NumberProperty' || p.type === 'BooleanProperty')
|
|
215
225
|
sqlType = 'INTEGER';
|
|
216
|
-
return `${p.name} ${sqlType}`;
|
|
217
|
-
})
|
|
226
|
+
return `${p.name.toLowerCase()} ${sqlType}`;
|
|
227
|
+
});
|
|
228
|
+
const allColumns = [
|
|
229
|
+
'id TEXT PRIMARY KEY',
|
|
230
|
+
'name TEXT',
|
|
231
|
+
'status TEXT',
|
|
232
|
+
'createdat INTEGER',
|
|
233
|
+
'updatedat INTEGER',
|
|
234
|
+
'deletedat INTEGER',
|
|
235
|
+
'createdby TEXT',
|
|
236
|
+
'updatedby TEXT',
|
|
237
|
+
'deletedby TEXT',
|
|
238
|
+
...customColumns
|
|
239
|
+
].join(',\n ');
|
|
218
240
|
upQueries += `
|
|
219
241
|
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}
|
|
242
|
+
${allColumns}
|
|
227
243
|
)\`)\n`;
|
|
228
244
|
downQueries += `
|
|
229
245
|
await adapter.rawQuery('DROP TABLE IF EXISTS ${collectionName}')\n`;
|
|
@@ -244,8 +260,331 @@ export const down = async ({ context: adapter }: { context: AbstractBackendAdapt
|
|
|
244
260
|
}
|
|
245
261
|
}
|
|
246
262
|
`;
|
|
263
|
+
const migrationsDir = path.resolve(targetDir, 'data/migrations/default');
|
|
264
|
+
if (fs.existsSync(migrationsDir)) {
|
|
265
|
+
fs.readdirSync(migrationsDir).forEach(file => {
|
|
266
|
+
if (file.endsWith('.ts')) {
|
|
267
|
+
fs.unlinkSync(path.join(migrationsDir, file));
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
247
271
|
const timestamp = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14);
|
|
248
|
-
fs.writeFileSync(path.
|
|
272
|
+
fs.writeFileSync(path.join(migrationsDir, `${timestamp}_init.ts`), migrationCode);
|
|
273
|
+
}
|
|
274
|
+
static generateFrontend(config, targetDir, models) {
|
|
275
|
+
const webDir = path.resolve(targetDir, 'web');
|
|
276
|
+
if (!fs.existsSync(webDir)) {
|
|
277
|
+
fs.mkdirSync(webDir, { recursive: true });
|
|
278
|
+
}
|
|
279
|
+
const srcDir = path.resolve(webDir, 'src');
|
|
280
|
+
if (!fs.existsSync(srcDir)) {
|
|
281
|
+
fs.mkdirSync(srcDir, { recursive: true });
|
|
282
|
+
}
|
|
283
|
+
const pagesDir = path.resolve(srcDir, 'pages');
|
|
284
|
+
if (!fs.existsSync(pagesDir)) {
|
|
285
|
+
fs.mkdirSync(pagesDir, { recursive: true });
|
|
286
|
+
}
|
|
287
|
+
const packageJson = {
|
|
288
|
+
name: "quatrain-ui-front",
|
|
289
|
+
private: true,
|
|
290
|
+
version: "1.0.0",
|
|
291
|
+
type: "module",
|
|
292
|
+
scripts: {
|
|
293
|
+
"dev": "vite",
|
|
294
|
+
"build": "tsc && vite build",
|
|
295
|
+
"preview": "vite preview"
|
|
296
|
+
},
|
|
297
|
+
dependencies: {
|
|
298
|
+
"@mantine/core": "^7.11.1",
|
|
299
|
+
"@mantine/hooks": "^7.11.1",
|
|
300
|
+
"@quatrain/api-client": "latest-dev",
|
|
301
|
+
"react": "^18.3.1",
|
|
302
|
+
"react-dom": "^18.3.1",
|
|
303
|
+
"react-router-dom": "^6.24.1"
|
|
304
|
+
},
|
|
305
|
+
devDependencies: {
|
|
306
|
+
"@types/react": "^18.3.3",
|
|
307
|
+
"@types/react-dom": "^18.3.0",
|
|
308
|
+
"@vitejs/plugin-react": "^4.3.1",
|
|
309
|
+
"typescript": "^5.5.3",
|
|
310
|
+
"vite": "^5.3.4"
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
fs.writeFileSync(path.join(webDir, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
314
|
+
const tsConfig = {
|
|
315
|
+
compilerOptions: {
|
|
316
|
+
target: "ES2020",
|
|
317
|
+
useDefineForClassFields: true,
|
|
318
|
+
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
319
|
+
module: "ESNext",
|
|
320
|
+
skipLibCheck: true,
|
|
321
|
+
moduleResolution: "bundler",
|
|
322
|
+
allowImportingTsExtensions: true,
|
|
323
|
+
resolveJsonModule: true,
|
|
324
|
+
isolatedModules: true,
|
|
325
|
+
noEmit: true,
|
|
326
|
+
jsx: "react-jsx",
|
|
327
|
+
strict: true,
|
|
328
|
+
noUnusedLocals: true,
|
|
329
|
+
noUnusedParameters: true,
|
|
330
|
+
noFallthroughCasesInSwitch: true
|
|
331
|
+
},
|
|
332
|
+
include: ["src"]
|
|
333
|
+
};
|
|
334
|
+
fs.writeFileSync(path.join(webDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2));
|
|
335
|
+
const viteConfig = `import { defineConfig } from 'vite'
|
|
336
|
+
import react from '@vitejs/plugin-react'
|
|
337
|
+
|
|
338
|
+
// https://vitejs.dev/config/
|
|
339
|
+
export default defineConfig({
|
|
340
|
+
plugins: [react()],
|
|
341
|
+
server: {
|
|
342
|
+
host: '0.0.0.0',
|
|
343
|
+
port: 3000,
|
|
344
|
+
proxy: {
|
|
345
|
+
'/api': {
|
|
346
|
+
target: 'http://localhost:4001',
|
|
347
|
+
changeOrigin: true
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
})
|
|
352
|
+
`;
|
|
353
|
+
fs.writeFileSync(path.join(webDir, 'vite.config.ts'), viteConfig);
|
|
354
|
+
const indexHtml = `<!doctype html>
|
|
355
|
+
<html lang="en">
|
|
356
|
+
<head>
|
|
357
|
+
<meta charset="UTF-8" />
|
|
358
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
359
|
+
<title>Quatrain App</title>
|
|
360
|
+
</head>
|
|
361
|
+
<body>
|
|
362
|
+
<div id="root"></div>
|
|
363
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
364
|
+
</body>
|
|
365
|
+
</html>
|
|
366
|
+
`;
|
|
367
|
+
fs.writeFileSync(path.join(webDir, 'index.html'), indexHtml);
|
|
368
|
+
const mainTsx = `import React from 'react'
|
|
369
|
+
import ReactDOM from 'react-dom/client'
|
|
370
|
+
import { MantineProvider } from '@mantine/core'
|
|
371
|
+
import '@mantine/core/styles.css'
|
|
372
|
+
import { BrowserRouter } from 'react-router-dom'
|
|
373
|
+
import App from './App.tsx'
|
|
374
|
+
|
|
375
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
376
|
+
<React.StrictMode>
|
|
377
|
+
<MantineProvider defaultColorScheme="dark">
|
|
378
|
+
<BrowserRouter>
|
|
379
|
+
<App />
|
|
380
|
+
</BrowserRouter>
|
|
381
|
+
</MantineProvider>
|
|
382
|
+
</React.StrictMode>,
|
|
383
|
+
)
|
|
384
|
+
`;
|
|
385
|
+
fs.writeFileSync(path.join(srcDir, 'main.tsx'), mainTsx);
|
|
386
|
+
const apiTs = `import { ApiClient } from '@quatrain/api-client'
|
|
387
|
+
|
|
388
|
+
export const api = new ApiClient('/api')
|
|
389
|
+
`;
|
|
390
|
+
fs.writeFileSync(path.join(srcDir, 'api.ts'), apiTs);
|
|
391
|
+
const menuItems = models.map(m => ` <a href="/${m.toLowerCase()}s" style={{display: 'block', padding: '10px', color: 'white', textDecoration: 'none'}}>${m}s</a>`).join('\n');
|
|
392
|
+
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');
|
|
393
|
+
const imports = models.map(m => `import { ${m}List } from './pages/${m}List'\nimport { ${m}Form } from './pages/${m}Form'`).join('\n');
|
|
394
|
+
const appTsx = `import { AppShell, Burger, Group, Title } from '@mantine/core'
|
|
395
|
+
import { useDisclosure } from '@mantine/hooks'
|
|
396
|
+
import { Routes, Route } from 'react-router-dom'
|
|
397
|
+
${imports}
|
|
398
|
+
|
|
399
|
+
export default function App() {
|
|
400
|
+
const [opened, { toggle }] = useDisclosure()
|
|
401
|
+
|
|
402
|
+
return (
|
|
403
|
+
<AppShell
|
|
404
|
+
header={{ height: 60 }}
|
|
405
|
+
navbar={{
|
|
406
|
+
width: 300,
|
|
407
|
+
breakpoint: 'sm',
|
|
408
|
+
collapsed: { mobile: !opened },
|
|
409
|
+
}}
|
|
410
|
+
padding="md"
|
|
411
|
+
>
|
|
412
|
+
<AppShell.Header>
|
|
413
|
+
<Group h="100%" px="md">
|
|
414
|
+
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
|
|
415
|
+
<Title order={3}>Quatrain App</Title>
|
|
416
|
+
</Group>
|
|
417
|
+
</AppShell.Header>
|
|
418
|
+
|
|
419
|
+
<AppShell.Navbar p="md">
|
|
420
|
+
${menuItems}
|
|
421
|
+
</AppShell.Navbar>
|
|
422
|
+
|
|
423
|
+
<AppShell.Main>
|
|
424
|
+
<Routes>
|
|
425
|
+
${routes}
|
|
426
|
+
<Route path="/" element={<div>Welcome to your Quatrain Application</div>} />
|
|
427
|
+
</Routes>
|
|
428
|
+
</AppShell.Main>
|
|
429
|
+
</AppShell>
|
|
430
|
+
)
|
|
431
|
+
}
|
|
432
|
+
`;
|
|
433
|
+
fs.writeFileSync(path.join(srcDir, 'App.tsx'), appTsx);
|
|
434
|
+
for (const m of models) {
|
|
435
|
+
const modelConfig = config.models.find((mod) => mod.name === m);
|
|
436
|
+
const props = modelConfig?.properties || [];
|
|
437
|
+
const listTsx = `import { useEffect, useState } from 'react'
|
|
438
|
+
import { Table, Button, Group, Title } from '@mantine/core'
|
|
439
|
+
import { useNavigate } from 'react-router-dom'
|
|
440
|
+
import { api } from '../api'
|
|
441
|
+
|
|
442
|
+
export function ${m}List() {
|
|
443
|
+
const [data, setData] = useState<any[]>([])
|
|
444
|
+
const navigate = useNavigate()
|
|
445
|
+
|
|
446
|
+
useEffect(() => {
|
|
447
|
+
api.get('${m.toLowerCase()}s').then((res) => {
|
|
448
|
+
if (res && res.data) {
|
|
449
|
+
setData(res.data)
|
|
450
|
+
}
|
|
451
|
+
})
|
|
452
|
+
}, [])
|
|
453
|
+
|
|
454
|
+
const handleDelete = async (id: string) => {
|
|
455
|
+
if (confirm('Are you sure?')) {
|
|
456
|
+
await api.delete('${m.toLowerCase()}s/' + id, {})
|
|
457
|
+
setData(data.filter(item => item.uid !== id))
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return (
|
|
462
|
+
<div>
|
|
463
|
+
<Group justify="space-between" mb="md">
|
|
464
|
+
<Title order={2}>${m}s</Title>
|
|
465
|
+
<Button onClick={() => navigate('/${m.toLowerCase()}s/new')}>Create ${m}</Button>
|
|
466
|
+
</Group>
|
|
467
|
+
<Table>
|
|
468
|
+
<Table.Thead>
|
|
469
|
+
<Table.Tr>
|
|
470
|
+
<Table.Th>Name</Table.Th>
|
|
471
|
+
<Table.Th>Status</Table.Th>
|
|
472
|
+
<Table.Th>Actions</Table.Th>
|
|
473
|
+
</Table.Tr>
|
|
474
|
+
</Table.Thead>
|
|
475
|
+
<Table.Tbody>
|
|
476
|
+
{data.map(item => (
|
|
477
|
+
<Table.Tr key={item.uid}>
|
|
478
|
+
<Table.Td>{item.name || item.uid}</Table.Td>
|
|
479
|
+
<Table.Td>{item.status}</Table.Td>
|
|
480
|
+
<Table.Td>
|
|
481
|
+
<Group>
|
|
482
|
+
<Button size="xs" variant="outline" onClick={() => navigate(\`/${m.toLowerCase()}s/\${item.uid}\`)}>Edit</Button>
|
|
483
|
+
<Button size="xs" color="red" variant="outline" onClick={() => handleDelete(item.uid)}>Delete</Button>
|
|
484
|
+
</Group>
|
|
485
|
+
</Table.Td>
|
|
486
|
+
</Table.Tr>
|
|
487
|
+
))}
|
|
488
|
+
</Table.Tbody>
|
|
489
|
+
</Table>
|
|
490
|
+
</div>
|
|
491
|
+
)
|
|
492
|
+
}
|
|
493
|
+
`;
|
|
494
|
+
fs.writeFileSync(path.join(pagesDir, `${m}List.tsx`), listTsx);
|
|
495
|
+
const formTsx = `import { useEffect, useState } from 'react'
|
|
496
|
+
import { TextInput, Button, Group, Title, Paper, Select } from '@mantine/core'
|
|
497
|
+
import { useNavigate, useParams } from 'react-router-dom'
|
|
498
|
+
import { api } from '../api'
|
|
499
|
+
|
|
500
|
+
export function ${m}Form() {
|
|
501
|
+
const { id } = useParams()
|
|
502
|
+
const navigate = useNavigate()
|
|
503
|
+
const [formData, setFormData] = useState<any>({ status: 'created' })
|
|
504
|
+
|
|
505
|
+
useEffect(() => {
|
|
506
|
+
if (id && id !== 'new') {
|
|
507
|
+
api.get('${m.toLowerCase()}s/' + id).then(res => {
|
|
508
|
+
if (res && res.data) {
|
|
509
|
+
setFormData(res.data)
|
|
510
|
+
}
|
|
511
|
+
})
|
|
512
|
+
}
|
|
513
|
+
}, [id])
|
|
514
|
+
|
|
515
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
516
|
+
e.preventDefault()
|
|
517
|
+
if (id === 'new') {
|
|
518
|
+
await api.post('${m.toLowerCase()}s', formData)
|
|
519
|
+
} else {
|
|
520
|
+
await api.patch('${m.toLowerCase()}s/' + id, formData)
|
|
521
|
+
}
|
|
522
|
+
navigate('/${m.toLowerCase()}s')
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
return (
|
|
526
|
+
<Paper p="md" shadow="sm">
|
|
527
|
+
<Title order={2} mb="md">{id === 'new' ? \`Create ${m}\` : \`Edit ${m}\`}</Title>
|
|
528
|
+
<form onSubmit={handleSubmit}>
|
|
529
|
+
<TextInput
|
|
530
|
+
label="Name"
|
|
531
|
+
value={formData.name || ''}
|
|
532
|
+
onChange={e => setFormData({...formData, name: e.target.value})}
|
|
533
|
+
mb="sm"
|
|
534
|
+
/>
|
|
535
|
+
<Select
|
|
536
|
+
label="Status"
|
|
537
|
+
data={['created', 'pending', 'active', 'deleted']}
|
|
538
|
+
value={formData.status || 'created'}
|
|
539
|
+
onChange={val => setFormData({...formData, status: val})}
|
|
540
|
+
mb="md"
|
|
541
|
+
/>
|
|
542
|
+
<Group>
|
|
543
|
+
<Button type="submit">Save</Button>
|
|
544
|
+
<Button variant="outline" onClick={() => navigate('/${m.toLowerCase()}s')}>Cancel</Button>
|
|
545
|
+
</Group>
|
|
546
|
+
</form>
|
|
547
|
+
</Paper>
|
|
548
|
+
)
|
|
549
|
+
}
|
|
550
|
+
`;
|
|
551
|
+
fs.writeFileSync(path.join(pagesDir, `${m}Form.tsx`), formTsx);
|
|
552
|
+
}
|
|
553
|
+
const dockerfile = `FROM node:22-alpine as builder
|
|
554
|
+
WORKDIR /app
|
|
555
|
+
COPY package*.json ./
|
|
556
|
+
RUN yarn install
|
|
557
|
+
COPY . .
|
|
558
|
+
RUN yarn build
|
|
559
|
+
|
|
560
|
+
FROM nginx:alpine
|
|
561
|
+
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
562
|
+
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
563
|
+
EXPOSE 80
|
|
564
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
565
|
+
`;
|
|
566
|
+
fs.writeFileSync(path.join(webDir, 'Dockerfile'), dockerfile);
|
|
567
|
+
const nginxConf = `server {
|
|
568
|
+
listen 80;
|
|
569
|
+
server_name localhost;
|
|
570
|
+
|
|
571
|
+
location / {
|
|
572
|
+
root /usr/share/nginx/html;
|
|
573
|
+
index index.html index.htm;
|
|
574
|
+
try_files $uri $uri/ /index.html;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
location /api/ {
|
|
578
|
+
proxy_pass http://api:4001/;
|
|
579
|
+
proxy_http_version 1.1;
|
|
580
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
581
|
+
proxy_set_header Connection 'upgrade';
|
|
582
|
+
proxy_set_header Host $host;
|
|
583
|
+
proxy_cache_bypass $http_upgrade;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
`;
|
|
587
|
+
fs.writeFileSync(path.join(webDir, 'nginx.conf'), nginxConf);
|
|
249
588
|
}
|
|
250
589
|
}
|
|
251
590
|
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
56
|
volumes: ['./quatrain.json:/app/quatrain.json:ro'],
|
|
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';
|
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,CAAC;YACpB,WAAW,EAAE;gBACV,QAAQ,EAAE,YAAY;aACxB;YACD,OAAO,EAAE,CAAC,uCAAuC,CAAC;YAClD,UAAU,EAAE,EAAE;SAChB,CAAA;QAGD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG;YACtB,KAAK,EAAE;gBACJ,OAAO,EAAE,OAAO;gBAChB,UAAU,EAAE,YAAY;aAC1B;YACD,cAAc,EAAE,GAAG,OAAO,KAAK;YAC/B,OAAO,EAAE,gBAAgB;YACzB,KAAK,EAAE,CAAC,SAAS,CAAC;YAClB,UAAU,EAAE,CAAC,QAAQ,CAAC;SACxB,CAAA;QAGD,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,KAAK,iBAAiB,EAAE,CAAC;YAClE,MAAM,MAAM,GAAG,UAAU,CAAA;YACzB,MAAM,MAAM,GAAG,eAAe,CAAA;YAC9B,MAAM,MAAM,GAAG,aAAa,CAAA;YAE5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG;gBAC5B,KAAK,EAAE,oBAAoB;gBAC3B,cAAc,EAAE,GAAG,OAAO,WAAW;gBACrC,OAAO,EAAE,gBAAgB;gBACzB,KAAK,EAAE,CAAC,WAAW,CAAC;gBACpB,WAAW,EAAE;oBACV,aAAa,EAAE,MAAM;oBACrB,iBAAiB,EAAE,MAAM;oBACzB,WAAW,EAAE,MAAM;iBACrB;gBACD,OAAO,EAAE,CAAC,wCAAwC,CAAC;aACrD,CAAA;YACD,OAAO,CAAC,OAAQ,CAAC,eAAe,CAAC,GAAG,EAAE,CAAA;YAGtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,UAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;YACvD,OAAO,CAAC,cAAc,CAAC,GAAG,gBAAgB,MAAM,IAAI,MAAM,kBAAkB,MAAM,EAAE,CAAA;QACvF,CAAC;QAGD,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,KAAK,WAAW,EAAE,CAAC;YAC5D,MAAM,MAAM,GAAG,YAAY,CAAA;YAC3B,MAAM,MAAM,GAAG,oBAAoB,CAAA;YAEnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG;gBACzB,KAAK,EAAE,oBAAoB;gBAC3B,cAAc,EAAE,GAAG,OAAO,QAAQ;gBAClC,OAAO,EAAE,gBAAgB;gBACzB,KAAK,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC;gBACjC,WAAW,EAAE;oBACV,eAAe,EAAE,MAAM;oBACvB,mBAAmB,EAAE,MAAM;iBAC7B;gBACD,OAAO,EAAE,wCAAwC;gBACjD,OAAO,EAAE,CAAC,kBAAkB,CAAC;aAC/B,CAAA;YACD,OAAO,CAAC,OAAQ,CAAC,YAAY,CAAC,GAAG,EAAE,CAAA;YAGnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,UAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACpD,OAAO,CAAC,aAAa,CAAC,GAAG,mBAAmB,CAAA;YAC5C,OAAO,CAAC,eAAe,CAAC,GAAG,MAAM,CAAA;YACjC,OAAO,CAAC,eAAe,CAAC,GAAG,MAAM,CAAA;QACpC,CAAC;QAGD,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,KAAK,aAAa,EAAE,CAAC;YAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG;gBAC5B,KAAK,EAAE,8BAA8B;gBACrC,cAAc,EAAE,GAAG,OAAO,WAAW;gBACrC,OAAO,EAAE,gBAAgB;gBACzB,KAAK,EAAE,CAAC,WAAW,EAAE,aAAa,CAAC;aACrC,CAAA;YAGD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,UAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;YACvD,OAAO,CAAC,UAAU,CAAC,GAAG,sBAAsB,CAAA;QAC/C,CAAC;QAGD,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,UAAU,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;YACvD,OAAO,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAA;QAC/C,CAAC;QAGD,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAQ,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,OAAO,OAAO,CAAC,OAAO,CAAA;QACzB,CAAC;QAGD,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;QAC3C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAE/E,MAAM,UAAU,GAAG;;;;;;;;;OASlB,CAAC,IAAI,EAAE,CAAA;QAER,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,CAAA;IAC5D,CAAC;CACH;AApID,oCAoIC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quatrain/app",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
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
|
@@ -25,6 +25,8 @@ export class CodeGenerator {
|
|
|
25
25
|
this.generateApiEndpoints(config, fullTargetDir, generatedModels)
|
|
26
26
|
this.generateIndex(config, fullTargetDir, generatedModels)
|
|
27
27
|
this.generateMigration(config, fullTargetDir)
|
|
28
|
+
|
|
29
|
+
this.generateFrontend(config, fullTargetDir, generatedModels)
|
|
28
30
|
|
|
29
31
|
Log.info(`[CodeGenerator] Application générée avec succès dans ${fullTargetDir}`)
|
|
30
32
|
}
|
|
@@ -41,7 +43,8 @@ export class CodeGenerator {
|
|
|
41
43
|
main: "src/index.ts",
|
|
42
44
|
type: "module",
|
|
43
45
|
scripts: {
|
|
44
|
-
start: "bun run src/index.ts"
|
|
46
|
+
"start:dev": "NODE_ENV=development bun run --watch src/index.ts",
|
|
47
|
+
"start:prod": "NODE_ENV=production bun run src/index.ts"
|
|
45
48
|
},
|
|
46
49
|
dependencies: {
|
|
47
50
|
"@quatrain/core": targetNpmTag,
|
|
@@ -92,17 +95,23 @@ export class CodeGenerator {
|
|
|
92
95
|
const collectionName = model.collectionName || className.toLowerCase()
|
|
93
96
|
generatedNames.push(className)
|
|
94
97
|
|
|
98
|
+
// Helper to map raw types to Property classes
|
|
99
|
+
const mapTypeToClass = (type: string) => {
|
|
100
|
+
if (type.toLowerCase() === 'datetime') return 'DateTimeProperty'
|
|
101
|
+
return type.charAt(0).toUpperCase() + type.slice(1) + 'Property'
|
|
102
|
+
}
|
|
103
|
+
|
|
95
104
|
// Use imports from core properties
|
|
96
105
|
const propsCode = model.properties.map((p: any) => {
|
|
97
|
-
const
|
|
106
|
+
const propClass = mapTypeToClass(p.type)
|
|
98
107
|
return ` {
|
|
99
108
|
name: '${p.name}',
|
|
100
|
-
type: ${
|
|
109
|
+
type: ${propClass}.TYPE,
|
|
101
110
|
mandatory: ${p.options?.mandatory ? 'true' : 'false'}
|
|
102
111
|
}`
|
|
103
112
|
}).join(',\n')
|
|
104
113
|
|
|
105
|
-
const propTypesToImport = Array.from(new Set(model.properties.map((p: any) => p.type)))
|
|
114
|
+
const propTypesToImport = Array.from(new Set(model.properties.map((p: any) => mapTypeToClass(p.type))))
|
|
106
115
|
|
|
107
116
|
const modelCode = `import { PersistedBaseObject } from '@quatrain/backend'
|
|
108
117
|
import { ${propTypesToImport.join(', ')} } from '@quatrain/core'
|
|
@@ -131,11 +140,7 @@ export class ${className} extends PersistedBaseObject {
|
|
|
131
140
|
const apiCode = `import { CrudEndpoint } from '@quatrain/api-server'
|
|
132
141
|
import { ${className} } from '../models/${className}'
|
|
133
142
|
|
|
134
|
-
export
|
|
135
|
-
constructor() {
|
|
136
|
-
super('/api/${className.toLowerCase()}s', ${className})
|
|
137
|
-
}
|
|
138
|
-
}
|
|
143
|
+
export const ${className}Api = CrudEndpoint(${className})
|
|
139
144
|
`
|
|
140
145
|
fs.writeFileSync(path.resolve(targetDir, `src/api/${className}Api.ts`), apiCode)
|
|
141
146
|
}
|
|
@@ -147,28 +152,32 @@ export class ${className}Api extends CrudEndpoint {
|
|
|
147
152
|
|
|
148
153
|
const modelImports = models.map(m => `import { ${m} } from './models/${m}'`).join('\n')
|
|
149
154
|
const apiImports = models.map(m => `import { ${m}Api } from './api/${m}Api'`).join('\n')
|
|
150
|
-
const apiRegisters = models.map(m => ` server.addEndpoint(
|
|
155
|
+
const apiRegisters = models.map(m => ` server.addEndpoint(${m}Api, '/api/${m.toLowerCase()}s')`).join('\n')
|
|
151
156
|
|
|
152
157
|
const indexCode = `import * as path from 'path'
|
|
153
158
|
import { Backend, InjectMetaMiddleware } from '@quatrain/backend'
|
|
154
159
|
import { ${adapterClass} } from '${adapterImport}'
|
|
155
160
|
import { ExpressAdapter } from '@quatrain/api-server'
|
|
156
161
|
import { MigrationManager } from '@quatrain/backend-migrations'
|
|
162
|
+
import { Log, DefaultLoggerAdapter, LogLevel } from '@quatrain/log'
|
|
157
163
|
${config.authMode === 'oauth' ? `import { AuthOIDC } from '@quatrain/auth-oidc'\n` : ''}
|
|
158
164
|
${modelImports}
|
|
159
165
|
${apiImports}
|
|
160
166
|
|
|
161
167
|
;(async () => {
|
|
162
168
|
try {
|
|
169
|
+
const isProd = process.env.NODE_ENV === 'production'
|
|
170
|
+
Log.addLogger('default', new DefaultLoggerAdapter('', isProd ? LogLevel.INFO : LogLevel.DEBUG), true)
|
|
171
|
+
|
|
163
172
|
const adapter = new ${adapterClass}({
|
|
164
173
|
config: ${adapterClass === 'SQLiteAdapter' ? '{ database: path.resolve(process.cwd(), "data/app.sqlite") }' : 'process.env.DATABASE_URL'},
|
|
165
174
|
middlewares: [new InjectMetaMiddleware()]
|
|
166
175
|
})
|
|
167
176
|
|
|
168
|
-
Backend.
|
|
177
|
+
Backend.addBackend(adapter, 'default', true)
|
|
169
178
|
|
|
170
|
-
const mm = new MigrationManager()
|
|
171
|
-
await mm.
|
|
179
|
+
const mm = new MigrationManager(adapter)
|
|
180
|
+
await mm.executeMigrations()
|
|
172
181
|
|
|
173
182
|
const server = new ExpressAdapter()
|
|
174
183
|
|
|
@@ -176,7 +185,7 @@ ${apiRegisters}
|
|
|
176
185
|
|
|
177
186
|
${config.authMode === 'oauth' ? ` // Initialize OIDC Auth
|
|
178
187
|
const oidc = AuthOIDC.init('http://localhost:4001')
|
|
179
|
-
server.
|
|
188
|
+
server.getNativeInstance().use('/oidc', oidc.callback())
|
|
180
189
|
` : ''}
|
|
181
190
|
|
|
182
191
|
const PORT = Number(process.env.PORT) || 4001
|
|
@@ -202,22 +211,33 @@ ${config.authMode === 'oauth' ? ` // Initialize OIDC Auth
|
|
|
202
211
|
if (!model.name) continue
|
|
203
212
|
const collectionName = model.collectionName || model.name.toLowerCase()
|
|
204
213
|
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
214
|
+
const baseColumns = ['id', 'name', 'status', 'createdby', 'createdat', 'updatedby', 'updatedat', 'deletedby', 'deletedat']
|
|
215
|
+
|
|
216
|
+
const customColumns = model.properties
|
|
217
|
+
.filter((p: any) => !baseColumns.includes(p.name.toLowerCase()))
|
|
218
|
+
.map((p: any) => {
|
|
219
|
+
// Very simplified SQLite type mapping for the PoC
|
|
220
|
+
let sqlType = 'TEXT'
|
|
221
|
+
if (p.type === 'NumberProperty' || p.type === 'BooleanProperty') sqlType = 'INTEGER'
|
|
222
|
+
return `${p.name.toLowerCase()} ${sqlType}`
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
const allColumns = [
|
|
226
|
+
'id TEXT PRIMARY KEY',
|
|
227
|
+
'name TEXT',
|
|
228
|
+
'status TEXT',
|
|
229
|
+
'createdat INTEGER',
|
|
230
|
+
'updatedat INTEGER',
|
|
231
|
+
'deletedat INTEGER',
|
|
232
|
+
'createdby TEXT',
|
|
233
|
+
'updatedby TEXT',
|
|
234
|
+
'deletedby TEXT',
|
|
235
|
+
...customColumns
|
|
236
|
+
].join(',\n ')
|
|
211
237
|
|
|
212
238
|
upQueries += `
|
|
213
239
|
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}
|
|
240
|
+
${allColumns}
|
|
221
241
|
)\`)\n`
|
|
222
242
|
|
|
223
243
|
downQueries += `
|
|
@@ -240,7 +260,364 @@ export const down = async ({ context: adapter }: { context: AbstractBackendAdapt
|
|
|
240
260
|
}
|
|
241
261
|
}
|
|
242
262
|
`
|
|
263
|
+
const migrationsDir = path.resolve(targetDir, 'data/migrations/default')
|
|
264
|
+
// Clear old migrations to prevent executing buggy or duplicate past generations
|
|
265
|
+
if (fs.existsSync(migrationsDir)) {
|
|
266
|
+
fs.readdirSync(migrationsDir).forEach(file => {
|
|
267
|
+
if (file.endsWith('.ts')) {
|
|
268
|
+
fs.unlinkSync(path.join(migrationsDir, file))
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
|
|
243
273
|
const timestamp = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14)
|
|
244
|
-
fs.writeFileSync(path.
|
|
274
|
+
fs.writeFileSync(path.join(migrationsDir, `${timestamp}_init.ts`), migrationCode)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private static generateFrontend(config: any, targetDir: string, models: string[]): void {
|
|
278
|
+
const webDir = path.resolve(targetDir, 'web')
|
|
279
|
+
if (!fs.existsSync(webDir)) {
|
|
280
|
+
fs.mkdirSync(webDir, { recursive: true })
|
|
281
|
+
}
|
|
282
|
+
const srcDir = path.resolve(webDir, 'src')
|
|
283
|
+
if (!fs.existsSync(srcDir)) {
|
|
284
|
+
fs.mkdirSync(srcDir, { recursive: true })
|
|
285
|
+
}
|
|
286
|
+
const pagesDir = path.resolve(srcDir, 'pages')
|
|
287
|
+
if (!fs.existsSync(pagesDir)) {
|
|
288
|
+
fs.mkdirSync(pagesDir, { recursive: true })
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// package.json
|
|
292
|
+
const packageJson = {
|
|
293
|
+
name: "quatrain-ui-front",
|
|
294
|
+
private: true,
|
|
295
|
+
version: "1.0.0",
|
|
296
|
+
type: "module",
|
|
297
|
+
scripts: {
|
|
298
|
+
"dev": "vite",
|
|
299
|
+
"build": "tsc && vite build",
|
|
300
|
+
"preview": "vite preview"
|
|
301
|
+
},
|
|
302
|
+
dependencies: {
|
|
303
|
+
"@mantine/core": "^7.11.1",
|
|
304
|
+
"@mantine/hooks": "^7.11.1",
|
|
305
|
+
"@quatrain/api-client": "latest-dev",
|
|
306
|
+
"react": "^18.3.1",
|
|
307
|
+
"react-dom": "^18.3.1",
|
|
308
|
+
"react-router-dom": "^6.24.1"
|
|
309
|
+
},
|
|
310
|
+
devDependencies: {
|
|
311
|
+
"@types/react": "^18.3.3",
|
|
312
|
+
"@types/react-dom": "^18.3.0",
|
|
313
|
+
"@vitejs/plugin-react": "^4.3.1",
|
|
314
|
+
"typescript": "^5.5.3",
|
|
315
|
+
"vite": "^5.3.4"
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
fs.writeFileSync(path.join(webDir, 'package.json'), JSON.stringify(packageJson, null, 2))
|
|
319
|
+
|
|
320
|
+
// tsconfig.json
|
|
321
|
+
const tsConfig = {
|
|
322
|
+
compilerOptions: {
|
|
323
|
+
target: "ES2020",
|
|
324
|
+
useDefineForClassFields: true,
|
|
325
|
+
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
326
|
+
module: "ESNext",
|
|
327
|
+
skipLibCheck: true,
|
|
328
|
+
moduleResolution: "bundler",
|
|
329
|
+
allowImportingTsExtensions: true,
|
|
330
|
+
resolveJsonModule: true,
|
|
331
|
+
isolatedModules: true,
|
|
332
|
+
noEmit: true,
|
|
333
|
+
jsx: "react-jsx",
|
|
334
|
+
strict: true,
|
|
335
|
+
noUnusedLocals: true,
|
|
336
|
+
noUnusedParameters: true,
|
|
337
|
+
noFallthroughCasesInSwitch: true
|
|
338
|
+
},
|
|
339
|
+
include: ["src"]
|
|
340
|
+
}
|
|
341
|
+
fs.writeFileSync(path.join(webDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2))
|
|
342
|
+
|
|
343
|
+
// vite.config.ts
|
|
344
|
+
const viteConfig = `import { defineConfig } from 'vite'
|
|
345
|
+
import react from '@vitejs/plugin-react'
|
|
346
|
+
|
|
347
|
+
// https://vitejs.dev/config/
|
|
348
|
+
export default defineConfig({
|
|
349
|
+
plugins: [react()],
|
|
350
|
+
server: {
|
|
351
|
+
host: '0.0.0.0',
|
|
352
|
+
port: 3000,
|
|
353
|
+
proxy: {
|
|
354
|
+
'/api': {
|
|
355
|
+
target: 'http://localhost:4001',
|
|
356
|
+
changeOrigin: true
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
})
|
|
361
|
+
`
|
|
362
|
+
fs.writeFileSync(path.join(webDir, 'vite.config.ts'), viteConfig)
|
|
363
|
+
|
|
364
|
+
// index.html
|
|
365
|
+
const indexHtml = `<!doctype html>
|
|
366
|
+
<html lang="en">
|
|
367
|
+
<head>
|
|
368
|
+
<meta charset="UTF-8" />
|
|
369
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
370
|
+
<title>Quatrain App</title>
|
|
371
|
+
</head>
|
|
372
|
+
<body>
|
|
373
|
+
<div id="root"></div>
|
|
374
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
375
|
+
</body>
|
|
376
|
+
</html>
|
|
377
|
+
`
|
|
378
|
+
fs.writeFileSync(path.join(webDir, 'index.html'), indexHtml)
|
|
379
|
+
|
|
380
|
+
// main.tsx
|
|
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
|
+
|
|
400
|
+
// api.ts
|
|
401
|
+
const apiTs = `import { ApiClient } from '@quatrain/api-client'
|
|
402
|
+
|
|
403
|
+
export const api = new ApiClient('/api')
|
|
404
|
+
`
|
|
405
|
+
fs.writeFileSync(path.join(srcDir, 'api.ts'), apiTs)
|
|
406
|
+
|
|
407
|
+
// App.tsx
|
|
408
|
+
const menuItems = models.map(m =>
|
|
409
|
+
` <a href="/${m.toLowerCase()}s" style={{display: 'block', padding: '10px', color: 'white', textDecoration: 'none'}}>${m}s</a>`
|
|
410
|
+
).join('\n')
|
|
411
|
+
|
|
412
|
+
const routes = models.map(m =>
|
|
413
|
+
` <Route path="/${m.toLowerCase()}s" element={<${m}List />} />\n <Route path="/${m.toLowerCase()}s/:id" element={<${m}Form />} />`
|
|
414
|
+
).join('\n')
|
|
415
|
+
|
|
416
|
+
const imports = models.map(m =>
|
|
417
|
+
`import { ${m}List } from './pages/${m}List'\nimport { ${m}Form } from './pages/${m}Form'`
|
|
418
|
+
).join('\n')
|
|
419
|
+
|
|
420
|
+
const appTsx = `import { AppShell, Burger, Group, Title } from '@mantine/core'
|
|
421
|
+
import { useDisclosure } from '@mantine/hooks'
|
|
422
|
+
import { Routes, Route } from 'react-router-dom'
|
|
423
|
+
${imports}
|
|
424
|
+
|
|
425
|
+
export default function App() {
|
|
426
|
+
const [opened, { toggle }] = useDisclosure()
|
|
427
|
+
|
|
428
|
+
return (
|
|
429
|
+
<AppShell
|
|
430
|
+
header={{ height: 60 }}
|
|
431
|
+
navbar={{
|
|
432
|
+
width: 300,
|
|
433
|
+
breakpoint: 'sm',
|
|
434
|
+
collapsed: { mobile: !opened },
|
|
435
|
+
}}
|
|
436
|
+
padding="md"
|
|
437
|
+
>
|
|
438
|
+
<AppShell.Header>
|
|
439
|
+
<Group h="100%" px="md">
|
|
440
|
+
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
|
|
441
|
+
<Title order={3}>Quatrain App</Title>
|
|
442
|
+
</Group>
|
|
443
|
+
</AppShell.Header>
|
|
444
|
+
|
|
445
|
+
<AppShell.Navbar p="md">
|
|
446
|
+
${menuItems}
|
|
447
|
+
</AppShell.Navbar>
|
|
448
|
+
|
|
449
|
+
<AppShell.Main>
|
|
450
|
+
<Routes>
|
|
451
|
+
${routes}
|
|
452
|
+
<Route path="/" element={<div>Welcome to your Quatrain Application</div>} />
|
|
453
|
+
</Routes>
|
|
454
|
+
</AppShell.Main>
|
|
455
|
+
</AppShell>
|
|
456
|
+
)
|
|
457
|
+
}
|
|
458
|
+
`
|
|
459
|
+
fs.writeFileSync(path.join(srcDir, 'App.tsx'), appTsx)
|
|
460
|
+
|
|
461
|
+
// Generate CRUD pages
|
|
462
|
+
for (const m of models) {
|
|
463
|
+
const modelConfig = config.models.find((mod: any) => mod.name === m)
|
|
464
|
+
const props = modelConfig?.properties || []
|
|
465
|
+
|
|
466
|
+
const listTsx = `import { useEffect, useState } from 'react'
|
|
467
|
+
import { Table, Button, Group, Title } from '@mantine/core'
|
|
468
|
+
import { useNavigate } from 'react-router-dom'
|
|
469
|
+
import { api } from '../api'
|
|
470
|
+
|
|
471
|
+
export function ${m}List() {
|
|
472
|
+
const [data, setData] = useState<any[]>([])
|
|
473
|
+
const navigate = useNavigate()
|
|
474
|
+
|
|
475
|
+
useEffect(() => {
|
|
476
|
+
api.get('${m.toLowerCase()}s').then((res) => {
|
|
477
|
+
if (res && res.data) {
|
|
478
|
+
setData(res.data)
|
|
479
|
+
}
|
|
480
|
+
})
|
|
481
|
+
}, [])
|
|
482
|
+
|
|
483
|
+
const handleDelete = async (id: string) => {
|
|
484
|
+
if (confirm('Are you sure?')) {
|
|
485
|
+
await api.delete('${m.toLowerCase()}s/' + id, {})
|
|
486
|
+
setData(data.filter(item => item.uid !== id))
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return (
|
|
491
|
+
<div>
|
|
492
|
+
<Group justify="space-between" mb="md">
|
|
493
|
+
<Title order={2}>${m}s</Title>
|
|
494
|
+
<Button onClick={() => navigate('/${m.toLowerCase()}s/new')}>Create ${m}</Button>
|
|
495
|
+
</Group>
|
|
496
|
+
<Table>
|
|
497
|
+
<Table.Thead>
|
|
498
|
+
<Table.Tr>
|
|
499
|
+
<Table.Th>Name</Table.Th>
|
|
500
|
+
<Table.Th>Status</Table.Th>
|
|
501
|
+
<Table.Th>Actions</Table.Th>
|
|
502
|
+
</Table.Tr>
|
|
503
|
+
</Table.Thead>
|
|
504
|
+
<Table.Tbody>
|
|
505
|
+
{data.map(item => (
|
|
506
|
+
<Table.Tr key={item.uid}>
|
|
507
|
+
<Table.Td>{item.name || item.uid}</Table.Td>
|
|
508
|
+
<Table.Td>{item.status}</Table.Td>
|
|
509
|
+
<Table.Td>
|
|
510
|
+
<Group>
|
|
511
|
+
<Button size="xs" variant="outline" onClick={() => navigate(\`/${m.toLowerCase()}s/\${item.uid}\`)}>Edit</Button>
|
|
512
|
+
<Button size="xs" color="red" variant="outline" onClick={() => handleDelete(item.uid)}>Delete</Button>
|
|
513
|
+
</Group>
|
|
514
|
+
</Table.Td>
|
|
515
|
+
</Table.Tr>
|
|
516
|
+
))}
|
|
517
|
+
</Table.Tbody>
|
|
518
|
+
</Table>
|
|
519
|
+
</div>
|
|
520
|
+
)
|
|
521
|
+
}
|
|
522
|
+
`
|
|
523
|
+
fs.writeFileSync(path.join(pagesDir, `${m}List.tsx`), listTsx)
|
|
524
|
+
|
|
525
|
+
const formTsx = `import { useEffect, useState } from 'react'
|
|
526
|
+
import { TextInput, Button, Group, Title, Paper, Select } from '@mantine/core'
|
|
527
|
+
import { useNavigate, useParams } from 'react-router-dom'
|
|
528
|
+
import { api } from '../api'
|
|
529
|
+
|
|
530
|
+
export function ${m}Form() {
|
|
531
|
+
const { id } = useParams()
|
|
532
|
+
const navigate = useNavigate()
|
|
533
|
+
const [formData, setFormData] = useState<any>({ status: 'created' })
|
|
534
|
+
|
|
535
|
+
useEffect(() => {
|
|
536
|
+
if (id && id !== 'new') {
|
|
537
|
+
api.get('${m.toLowerCase()}s/' + id).then(res => {
|
|
538
|
+
if (res && res.data) {
|
|
539
|
+
setFormData(res.data)
|
|
540
|
+
}
|
|
541
|
+
})
|
|
542
|
+
}
|
|
543
|
+
}, [id])
|
|
544
|
+
|
|
545
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
546
|
+
e.preventDefault()
|
|
547
|
+
if (id === 'new') {
|
|
548
|
+
await api.post('${m.toLowerCase()}s', formData)
|
|
549
|
+
} else {
|
|
550
|
+
await api.patch('${m.toLowerCase()}s/' + id, formData)
|
|
551
|
+
}
|
|
552
|
+
navigate('/${m.toLowerCase()}s')
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return (
|
|
556
|
+
<Paper p="md" shadow="sm">
|
|
557
|
+
<Title order={2} mb="md">{id === 'new' ? \`Create ${m}\` : \`Edit ${m}\`}</Title>
|
|
558
|
+
<form onSubmit={handleSubmit}>
|
|
559
|
+
<TextInput
|
|
560
|
+
label="Name"
|
|
561
|
+
value={formData.name || ''}
|
|
562
|
+
onChange={e => setFormData({...formData, name: e.target.value})}
|
|
563
|
+
mb="sm"
|
|
564
|
+
/>
|
|
565
|
+
<Select
|
|
566
|
+
label="Status"
|
|
567
|
+
data={['created', 'pending', 'active', 'deleted']}
|
|
568
|
+
value={formData.status || 'created'}
|
|
569
|
+
onChange={val => setFormData({...formData, status: val})}
|
|
570
|
+
mb="md"
|
|
571
|
+
/>
|
|
572
|
+
<Group>
|
|
573
|
+
<Button type="submit">Save</Button>
|
|
574
|
+
<Button variant="outline" onClick={() => navigate('/${m.toLowerCase()}s')}>Cancel</Button>
|
|
575
|
+
</Group>
|
|
576
|
+
</form>
|
|
577
|
+
</Paper>
|
|
578
|
+
)
|
|
579
|
+
}
|
|
580
|
+
`
|
|
581
|
+
fs.writeFileSync(path.join(pagesDir, `${m}Form.tsx`), formTsx)
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Dockerfile
|
|
585
|
+
const dockerfile = `FROM node:22-alpine as builder
|
|
586
|
+
WORKDIR /app
|
|
587
|
+
COPY package*.json ./
|
|
588
|
+
RUN yarn install
|
|
589
|
+
COPY . .
|
|
590
|
+
RUN yarn build
|
|
591
|
+
|
|
592
|
+
FROM nginx:alpine
|
|
593
|
+
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
594
|
+
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
595
|
+
EXPOSE 80
|
|
596
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
597
|
+
`
|
|
598
|
+
fs.writeFileSync(path.join(webDir, 'Dockerfile'), dockerfile)
|
|
599
|
+
|
|
600
|
+
// nginx.conf
|
|
601
|
+
const nginxConf = `server {
|
|
602
|
+
listen 80;
|
|
603
|
+
server_name localhost;
|
|
604
|
+
|
|
605
|
+
location / {
|
|
606
|
+
root /usr/share/nginx/html;
|
|
607
|
+
index index.html index.htm;
|
|
608
|
+
try_files $uri $uri/ /index.html;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
location /api/ {
|
|
612
|
+
proxy_pass http://api:4001/;
|
|
613
|
+
proxy_http_version 1.1;
|
|
614
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
615
|
+
proxy_set_header Connection 'upgrade';
|
|
616
|
+
proxy_set_header Host $host;
|
|
617
|
+
proxy_cache_bypass $http_upgrade;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
`
|
|
621
|
+
fs.writeFileSync(path.join(webDir, 'nginx.conf'), nginxConf)
|
|
245
622
|
}
|
|
246
623
|
}
|
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,7 +38,7 @@ 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
|
},
|
|
@@ -46,6 +46,18 @@ export class InfraBuilder {
|
|
|
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'
|