@simitgroup/simpleapp-generator 1.0.31 → 1.0.33
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/README.md +97 -12
- package/dist/framework.js +9 -3
- package/dist/framework.js.map +1 -1
- package/dist/generate.js +21 -4
- package/dist/generate.js.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/processors/jsonschemabuilder.js +91 -15
- package/dist/processors/jsonschemabuilder.js.map +1 -1
- package/dist/type.js.map +1 -1
- package/documentation/designconcept.bpmn +349 -0
- package/documentation/documentation.png +0 -0
- package/documentation/infra.drawio +141 -0
- package/documentation/infra.png +0 -0
- package/documentation/management.drawio +57 -0
- package/documentation/stack.drawio +106 -0
- package/package.json +1 -1
- package/src/framework.ts +9 -3
- package/src/generate.ts +29 -6
- package/src/index.ts +4 -3
- package/src/processors/jsonschemabuilder.ts +113 -22
- package/src/type.ts +44 -1
- package/templates/basic/controller.eta +34 -17
- package/templates/basic/model.eta +2 -1
- package/templates/basic/pageindex.vue.eta +4 -3
- package/templates/basic/service.eta +2 -1
- package/templates/basic/simpleappclient.eta +23 -1
- package/templates/nest/SimpleAppService.eta +141 -70
- package/templates/nest/TenantMiddleware.eta +8 -13
- package/templates/nest/UserProvider.eta +127 -0
- package/templates/nest/Workflow.eta +75 -0
- package/templates/nest/app.controller.eta +12 -0
- package/templates/nest/app.module.eta +6 -2
- package/templates/nest/app.service.eta +8 -0
- package/templates/nest/nest.env.eta +7 -0
- package/templates/nuxt/components.debugdocdata.vue.eta +1 -1
- package/templates/nuxt/components.menus.vue.eta +43 -7
- package/templates/nuxt/composables.stringHelper.ts.eta +5 -0
- package/templates/nuxt/nuxt.config.ts.eta +1 -1
- package/templates/nuxt/pages.[xorg].index.vue.eta +13 -9
- package/templates/nuxt/pages.index.vue.eta +58 -8
- package/templates/nuxt/plugins.simpleapp.ts.eta +10 -1
- package/templates/nuxt/server.api.ts.eta +2 -1
- package/templates/nuxt/tailwind.css.eta +14 -1
- package/tsconfig.json +4 -1
- package/templates/nest/User.eta +0 -115
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<mxfile host="65bd71144e">
|
|
2
|
+
<diagram id="g2NRvyCy43iObyQwmQN3" name="Page-1">
|
|
3
|
+
<mxGraphModel dx="1092" dy="595" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
|
4
|
+
<root>
|
|
5
|
+
<mxCell id="0"/>
|
|
6
|
+
<mxCell id="1" parent="0"/>
|
|
7
|
+
<mxCell id="8" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="2" target="7">
|
|
8
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
9
|
+
</mxCell>
|
|
10
|
+
<mxCell id="11" style="edgeStyle=none;html=1;" edge="1" parent="1" source="2" target="10">
|
|
11
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
12
|
+
</mxCell>
|
|
13
|
+
<mxCell id="13" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="2" target="12">
|
|
14
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
15
|
+
</mxCell>
|
|
16
|
+
<mxCell id="37" style="edgeStyle=none;html=1;" edge="1" parent="1" source="2" target="36">
|
|
17
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
18
|
+
</mxCell>
|
|
19
|
+
<mxCell id="2" value="npm" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
|
20
|
+
<mxGeometry x="230" y="40" width="110" height="30" as="geometry"/>
|
|
21
|
+
</mxCell>
|
|
22
|
+
<mxCell id="4" value="Nuxt Frontend" style="swimlane;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
|
23
|
+
<mxGeometry x="80" y="140" width="200" height="200" as="geometry"/>
|
|
24
|
+
</mxCell>
|
|
25
|
+
<mxCell id="7" value="simpleapp-vue-component" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="4">
|
|
26
|
+
<mxGeometry x="30" y="40" width="110" height="30" as="geometry"/>
|
|
27
|
+
</mxCell>
|
|
28
|
+
<mxCell id="21" style="edgeStyle=none;html=1;" edge="1" parent="4" source="14" target="19">
|
|
29
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
30
|
+
</mxCell>
|
|
31
|
+
<mxCell id="14" value="pages &amp; client libs" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="4">
|
|
32
|
+
<mxGeometry x="40" y="90" width="110" height="30" as="geometry"/>
|
|
33
|
+
</mxCell>
|
|
34
|
+
<mxCell id="19" value="api-client" style="whiteSpace=wrap;html=1;rounded=1;" vertex="1" parent="4">
|
|
35
|
+
<mxGeometry x="40" y="150" width="75" height="35" as="geometry"/>
|
|
36
|
+
</mxCell>
|
|
37
|
+
<mxCell id="5" value="Nest Backend" style="swimlane;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
|
38
|
+
<mxGeometry x="310" y="140" width="200" height="200" as="geometry"/>
|
|
39
|
+
</mxCell>
|
|
40
|
+
<mxCell id="23" value="mongoose-schema" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="5">
|
|
41
|
+
<mxGeometry x="40" y="155" width="110" height="30" as="geometry"/>
|
|
42
|
+
</mxCell>
|
|
43
|
+
<mxCell id="24" value="doc-service" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="5">
|
|
44
|
+
<mxGeometry x="40" y="125" width="110" height="30" as="geometry"/>
|
|
45
|
+
</mxCell>
|
|
46
|
+
<mxCell id="25" value="api-countroller" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="5">
|
|
47
|
+
<mxGeometry x="40" y="95" width="110" height="30" as="geometry"/>
|
|
48
|
+
</mxCell>
|
|
49
|
+
<mxCell id="36" value="backend-libs" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="5">
|
|
50
|
+
<mxGeometry x="40" y="30" width="110" height="30" as="geometry"/>
|
|
51
|
+
</mxCell>
|
|
52
|
+
<mxCell id="6" value="Nest BPMN" style="swimlane;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
|
53
|
+
<mxGeometry x="530" y="140" width="200" height="200" as="geometry"/>
|
|
54
|
+
</mxCell>
|
|
55
|
+
<mxCell id="10" value="bpmn-server" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="6">
|
|
56
|
+
<mxGeometry x="30" y="40" width="110" height="30" as="geometry"/>
|
|
57
|
+
</mxCell>
|
|
58
|
+
<mxCell id="15" value="" style="edgeStyle=none;html=1;entryX=0.75;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="12" target="4">
|
|
59
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
60
|
+
</mxCell>
|
|
61
|
+
<mxCell id="17" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="12" target="16">
|
|
62
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
63
|
+
</mxCell>
|
|
64
|
+
<mxCell id="26" style="edgeStyle=none;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="12" target="5">
|
|
65
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
66
|
+
</mxCell>
|
|
67
|
+
<mxCell id="27" style="edgeStyle=none;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="12" target="6">
|
|
68
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
69
|
+
</mxCell>
|
|
70
|
+
<mxCell id="35" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="12" target="34">
|
|
71
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
72
|
+
</mxCell>
|
|
73
|
+
<mxCell id="12" value="simpleapp-generator" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
|
74
|
+
<mxGeometry x="250" y="430" width="110" height="30" as="geometry"/>
|
|
75
|
+
</mxCell>
|
|
76
|
+
<mxCell id="20" style="edgeStyle=none;html=1;entryX=0.75;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="16" target="19">
|
|
77
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
78
|
+
</mxCell>
|
|
79
|
+
<mxCell id="16" value="openapi-generator" style="whiteSpace=wrap;html=1;rounded=1;" vertex="1" parent="1">
|
|
80
|
+
<mxGeometry x="140" y="380" width="75" height="35" as="geometry"/>
|
|
81
|
+
</mxCell>
|
|
82
|
+
<mxCell id="32" style="edgeStyle=none;html=1;" edge="1" parent="1" source="28" target="12">
|
|
83
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
84
|
+
</mxCell>
|
|
85
|
+
<mxCell id="28" value="jsonschema" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
|
86
|
+
<mxGeometry x="175" y="550" width="120" height="80" as="geometry"/>
|
|
87
|
+
</mxCell>
|
|
88
|
+
<mxCell id="31" style="edgeStyle=none;html=1;" edge="1" parent="1" source="29" target="12">
|
|
89
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
90
|
+
</mxCell>
|
|
91
|
+
<mxCell id="29" value="bpmn" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
|
92
|
+
<mxGeometry x="340" y="550" width="120" height="80" as="geometry"/>
|
|
93
|
+
</mxCell>
|
|
94
|
+
<mxCell id="33" style="edgeStyle=none;html=1;entryX=0.916;entryY=1.003;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="30" target="12">
|
|
95
|
+
<mxGeometry relative="1" as="geometry"/>
|
|
96
|
+
</mxCell>
|
|
97
|
+
<mxCell id="30" value="UI Design (One day)" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
|
98
|
+
<mxGeometry x="490" y="550" width="120" height="80" as="geometry"/>
|
|
99
|
+
</mxCell>
|
|
100
|
+
<mxCell id="34" value="mobile app (One day)" style="whiteSpace=wrap;html=1;rounded=1;" vertex="1" parent="1">
|
|
101
|
+
<mxGeometry x="600" y="415" width="120" height="60" as="geometry"/>
|
|
102
|
+
</mxCell>
|
|
103
|
+
</root>
|
|
104
|
+
</mxGraphModel>
|
|
105
|
+
</diagram>
|
|
106
|
+
</mxfile>
|
package/package.json
CHANGED
package/src/framework.ts
CHANGED
|
@@ -6,7 +6,8 @@ import {Eta} from 'eta';
|
|
|
6
6
|
const log: Logger<ILogObj> = new Logger();
|
|
7
7
|
|
|
8
8
|
let config = {
|
|
9
|
-
"
|
|
9
|
+
"jsonschemaFolder":"./jsonschemaFolder",
|
|
10
|
+
"bpmnFolder":"./bpmn",
|
|
10
11
|
"backendFolder":"./mybackend",
|
|
11
12
|
"backendPort":"8000",
|
|
12
13
|
"mongoConnectStr":'mongodb://<user>:<pass>@<host>:<port>/<db>?authMechanism=DEFAULT',
|
|
@@ -20,6 +21,11 @@ let config = {
|
|
|
20
21
|
"OAUTH2_CLIENTID":"client-id",
|
|
21
22
|
"OAUTH2_CLIENTSECRET":"client-secret-value",
|
|
22
23
|
"AUTH_SECRET_KEY":"my-secret",
|
|
24
|
+
},
|
|
25
|
+
"bpmnsetting":{
|
|
26
|
+
"BPMN_HOST":"127.0.0.1",
|
|
27
|
+
"BPMN_PORT":"9000",
|
|
28
|
+
"BPMN_API_KEY":"12345"
|
|
23
29
|
}
|
|
24
30
|
}
|
|
25
31
|
|
|
@@ -61,7 +67,7 @@ export const prepareNest = (callback:Function)=>{
|
|
|
61
67
|
if(!fs.existsSync(`${targetfolder}/.env`)){
|
|
62
68
|
|
|
63
69
|
|
|
64
|
-
exec(`cd ${targetfolder};pnpm install --save nest-keycloak-connect keycloak-connect @nestjs/serve-static jsonwebtoken axios @darkwolf/base64url json-schema @wearenova/mongoose-tenant @nestjs/swagger @nestjs/mongoose mongoose ajv ajv-formats ajv-errors @nestjs/config`,async (error, stdout, stderr)=>{
|
|
70
|
+
exec(`cd ${targetfolder};pnpm install --save nest-keycloak-connect keycloak-connect bpmn-client @nestjs/serve-static jsonwebtoken axios @darkwolf/base64url json-schema @wearenova/mongoose-tenant @nestjs/swagger @nestjs/mongoose mongoose ajv ajv-formats ajv-errors @nestjs/config`,async (error, stdout, stderr)=>{
|
|
65
71
|
// log.info(`dependency installed`)
|
|
66
72
|
if(!error){
|
|
67
73
|
fs.mkdirSync(`${targetfolder}/public_html`,{recursive:true})
|
|
@@ -101,7 +107,7 @@ export const prepareNuxt = (callback:Function)=>{
|
|
|
101
107
|
exec(`cd ${targetfolder};pnpm install;pnpm install -D @sidebase/nuxt-auth @nuxt/ui @types/node @vueuse/nuxt @sidebase/nuxt-auth @vueuse/core nuxt-security prettier `, (error, stdout, stderr)=>{
|
|
102
108
|
//;pnpm install
|
|
103
109
|
console.log(error, stdout, stderr)
|
|
104
|
-
exec(`cd ${targetfolder};pnpm install --save next-auth@4.21.1 @darkwolf/base64url @nuxt/ui ajv ajv-formats ajv-errors dotenv @fullcalendar/core @fullcalendar/vue3 quill uuid primeflex primeicons prettier primevue axios json-schema mitt @simitgroup/simpleapp-vue-component@latest`, (error, stdout, stderr)=>{
|
|
110
|
+
exec(`cd ${targetfolder};pnpm install --save @darkwolf/base64url next-auth@4.21.1 @darkwolf/base64url @nuxt/ui ajv ajv-formats ajv-errors dotenv @fullcalendar/core @fullcalendar/vue3 quill uuid primeflex primeicons prettier primevue axios json-schema mitt @simitgroup/simpleapp-vue-component@latest`, (error, stdout, stderr)=>{
|
|
105
111
|
console.log(error, stdout, stderr)
|
|
106
112
|
|
|
107
113
|
fs.mkdirSync(`${targetfolder}/assets/css/`,{recursive:true})
|
package/src/generate.ts
CHANGED
|
@@ -15,16 +15,22 @@ const path = require('path');
|
|
|
15
15
|
import {mkdirSync, readdir,readFileSync,writeFileSync,existsSync,copyFileSync, readdirSync} from 'fs'
|
|
16
16
|
const { Eta } = require('eta');
|
|
17
17
|
const { capitalizeFirstLetter }= require('./libs');
|
|
18
|
+
const X_DOCUMENT_TYPE='x-document-type'
|
|
19
|
+
const X_DOCUMENT_NAME='x-document-name'
|
|
20
|
+
const X_COLLECTION_NAME='x-collection-name'
|
|
18
21
|
const extFb = '.xfb.json';
|
|
19
22
|
const extHfb = '.xhfb.json';
|
|
20
23
|
const extjsonschema = '.jsonschema.json';
|
|
21
24
|
let jsonschemas = {};
|
|
22
25
|
const docs = [];
|
|
23
26
|
|
|
24
|
-
export const initialize = async (defFolder:string,backendfolder:string,frontendfolder:string,callback:Function) => {
|
|
27
|
+
export const initialize = async (defFolder:string,bpmnFolder:string,backendfolder:string,frontendfolder:string,callback:Function) => {
|
|
25
28
|
prepareEnvironments(backendfolder,frontendfolder)
|
|
26
29
|
let activatemodules:ModuleObject[]=[]
|
|
27
30
|
//
|
|
31
|
+
/*
|
|
32
|
+
load available bpmn into array
|
|
33
|
+
*/
|
|
28
34
|
const files = readdirSync(defFolder)
|
|
29
35
|
// log.warn("all schemas:",files)
|
|
30
36
|
// readdir(defFolder, (err, files) => {
|
|
@@ -34,19 +40,21 @@ export const initialize = async (defFolder:string,backendfolder:string,frontend
|
|
|
34
40
|
log.info(`Load `+clc.green(file))
|
|
35
41
|
const filearr = file.split('.');
|
|
36
42
|
let rendertype = 'basic';
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
let docname = filearr[0].toLowerCase();
|
|
44
|
+
let doctype = filearr[1].toLowerCase();
|
|
45
|
+
|
|
39
46
|
const jsonstring = readFileSync(defFolder +path.sep+ file, 'utf-8');
|
|
40
47
|
let allmodels: ChildModels = {} as ChildModels;
|
|
41
48
|
|
|
42
49
|
if (file.endsWith(extjsonschema)) {
|
|
43
|
-
const jsondata = JSON.parse(jsonstring);
|
|
50
|
+
const jsondata = JSON.parse(jsonstring);
|
|
44
51
|
rendertype = 'basic';
|
|
45
52
|
jsonschemas[docname] = jsondata;
|
|
53
|
+
|
|
46
54
|
// foreignkeys:
|
|
47
55
|
// tmpforeignkeys:TypeForeignKey
|
|
48
56
|
allmodels = await readJsonSchemaBuilder(doctype, docname, jsondata,foreignkeys);
|
|
49
|
-
|
|
57
|
+
|
|
50
58
|
//foreignkeycatalogues
|
|
51
59
|
// foreignkeys
|
|
52
60
|
generate(docname, doctype, rendertype, allmodels,backendfolder,frontendfolder);
|
|
@@ -110,6 +118,10 @@ const generate = (
|
|
|
110
118
|
backEndCode: '',
|
|
111
119
|
controllerCode:'',
|
|
112
120
|
apiSchemaCode:'',
|
|
121
|
+
docStatusSettings:allmodels[capitalizeFirstLetter(docname)].docStatusSettings,
|
|
122
|
+
apiSettings:allmodels[capitalizeFirstLetter(docname)].apiSettings,
|
|
123
|
+
requireautocomplete:allmodels[capitalizeFirstLetter(docname)].requireautocomplete,
|
|
124
|
+
isolationtype:allmodels[capitalizeFirstLetter(docname)].isolationtype
|
|
113
125
|
};
|
|
114
126
|
|
|
115
127
|
// console.log('generate 2', JSON.stringify(variables));
|
|
@@ -271,8 +283,9 @@ const prepareEnvironments = (backendfolder:string,frontendfolder:string)=>{
|
|
|
271
283
|
|
|
272
284
|
copyFileSync(`${constants.templatedir}/nest/SimpleAppService.eta`,`${targetfolder}/SimpleAppService.ts`)
|
|
273
285
|
copyFileSync(`${constants.templatedir}/nest/SimpleAppController.eta`,`${targetfolder}/SimpleAppController.ts`)
|
|
286
|
+
copyFileSync(`${constants.templatedir}/nest/Workflow.eta`,`${targetfolder}/Workflow.ts`)
|
|
274
287
|
copyFileSync(`${constants.templatedir}/nest/TenantMiddleware.eta`,`${targetfolder}/TenantMiddleware.ts`)
|
|
275
|
-
copyFileSync(`${constants.templatedir}/nest/
|
|
288
|
+
copyFileSync(`${constants.templatedir}/nest/UserProvider.eta`,`${targetfolder}/UserProvider.ts`)
|
|
276
289
|
|
|
277
290
|
//copy over frontend apiabstract class
|
|
278
291
|
// copyFileSync(`${constants.templatedir}/nuxt.apigateway.eta`,`${targetfrontendfolder}/[...].ts`)
|
|
@@ -291,6 +304,12 @@ const finalize=(modules:ModuleObject[],backendfolder:string,frontendfolder:strin
|
|
|
291
304
|
const eta = new Eta({views:constants.templatedir});
|
|
292
305
|
const txtMainModule = eta.render('./nest/app.module.eta', modules);
|
|
293
306
|
writeFileSync(`${backendfolder}/src/app.module.ts`, txtMainModule);
|
|
307
|
+
|
|
308
|
+
const txtMainService = eta.render('./nest/app.service.eta', modules);
|
|
309
|
+
writeFileSync(`${backendfolder}/src/app.service.ts`, txtMainService);
|
|
310
|
+
|
|
311
|
+
const txtAppController = eta.render('./nest/app.controller.eta', modules);
|
|
312
|
+
writeFileSync(`${backendfolder}/src/app.controller.ts`, txtAppController);
|
|
294
313
|
|
|
295
314
|
const foreignkeyfile =`${backendfolder}/src/dicts/foreignkeys.json`
|
|
296
315
|
writeFileSync(foreignkeyfile, JSON.stringify(foreignkeys));
|
|
@@ -301,5 +320,9 @@ const finalize=(modules:ModuleObject[],backendfolder:string,frontendfolder:strin
|
|
|
301
320
|
|
|
302
321
|
const txtMenus = eta.render('./nuxt/composables.getmenus.ts.eta', modules);
|
|
303
322
|
writeFileSync(`${frontendfolder}/composables/getMenus.ts`, txtMenus);
|
|
323
|
+
|
|
324
|
+
const txtStringHelper= eta.render('./nuxt/composables.stringHelper.ts.eta', modules);
|
|
325
|
+
writeFileSync(`${frontendfolder}/composables/stringHelper.ts`, txtStringHelper);
|
|
326
|
+
|
|
304
327
|
|
|
305
328
|
}
|
package/src/index.ts
CHANGED
|
@@ -22,7 +22,7 @@ let version=pj.version
|
|
|
22
22
|
program
|
|
23
23
|
.version(version)
|
|
24
24
|
.description("An simpleapp CLI tool for generate frontend (vuejs) and backend(nestjs) codes")
|
|
25
|
-
.option("-c, --config-file <value>", 'configuration file
|
|
25
|
+
.option("-c, --config-file <value>", 'configuration file')
|
|
26
26
|
.parse(process.argv);
|
|
27
27
|
|
|
28
28
|
let path=''
|
|
@@ -44,7 +44,8 @@ if(!options.configFile){
|
|
|
44
44
|
}
|
|
45
45
|
const configs = require(path)
|
|
46
46
|
console.log("configurations: ",configs)
|
|
47
|
-
const
|
|
47
|
+
const jsonschemaFolder = configs.jsonschemaFolder
|
|
48
|
+
const bpmnFolder = configs.bpmnFolder
|
|
48
49
|
const backendFolder = configs.backendFolder
|
|
49
50
|
const frontendFolder = configs.frontendFolder
|
|
50
51
|
const openapi3Yaml = configs.openapi3Yaml
|
|
@@ -55,7 +56,7 @@ const run = async()=>{
|
|
|
55
56
|
fw.runCreateNest(()=>{
|
|
56
57
|
fw.prepareNest(()=>{
|
|
57
58
|
fw.prepareNuxt(()=>{
|
|
58
|
-
generate.initialize(
|
|
59
|
+
generate.initialize(jsonschemaFolder,bpmnFolder,backendFolder,frontendFolder,()=>{
|
|
59
60
|
fw.prepareOpenApiClient()
|
|
60
61
|
fw.prettyNuxt()
|
|
61
62
|
fw.prettyNest()
|
|
@@ -13,32 +13,64 @@ import {
|
|
|
13
13
|
ChildModels,
|
|
14
14
|
SchemaModel,
|
|
15
15
|
TypeForeignKey,
|
|
16
|
-
TypeForeignKeyCatalogue
|
|
16
|
+
TypeForeignKeyCatalogue,
|
|
17
|
+
DocSetting,ApiSetting,DocStatusSetting,
|
|
18
|
+
|
|
17
19
|
} from '../type';
|
|
18
20
|
import { json } from 'stream/consumers';
|
|
19
21
|
const log: Logger<ILogObj> = new Logger();
|
|
22
|
+
|
|
20
23
|
const X_DOCUMENT_NO='x-document-no'
|
|
21
|
-
const
|
|
24
|
+
const X_DOCUMENT_LABEL='x-document-label'
|
|
22
25
|
const X_AUTOCOMPLETE_FIELD='x-autocomplete-field'
|
|
26
|
+
const X_DOCUMENT_NAME='x-document-name'
|
|
27
|
+
const X_DOCUMENT_TYPE='x-document-type'
|
|
28
|
+
const X_COLLECTION_NAME='x-document-collection'
|
|
29
|
+
const X_DOCUMENT_STATUS='x-document-status'
|
|
30
|
+
const X_DOCUMENT_API='x-document-api'
|
|
31
|
+
const X_IGNORE_AUTOCOMPLETE='x-ignore-autocomplete'
|
|
23
32
|
const FOREIGNKEY_PROPERTY='x-foreignkey'
|
|
24
|
-
|
|
25
33
|
const X_TEL_NO='x-tel'
|
|
34
|
+
const X_ISOLATION_TYPE='x-isolation-type'
|
|
35
|
+
|
|
36
|
+
let docSetting:DocSetting={} as DocSetting
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
26
40
|
let allmodels: ChildModels = {};
|
|
27
41
|
let fullschema={}
|
|
28
|
-
let fieldAutoCompleteCode=''
|
|
29
|
-
let fieldAutoCompleteName=''
|
|
42
|
+
// let fieldAutoCompleteCode=''
|
|
43
|
+
// let fieldAutoCompleteName=''
|
|
30
44
|
let moreAutoComplete:string[]=[]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
const newDocSetting=(doctype:string,docname:string):DocSetting=>{
|
|
48
|
+
return {
|
|
49
|
+
docName:docname, //done
|
|
50
|
+
docType:doctype, //done
|
|
51
|
+
colDocNo:'', //done
|
|
52
|
+
colDocLabel:'', //done
|
|
53
|
+
collectionName:docname, //done
|
|
54
|
+
autocompleteFields:[],
|
|
55
|
+
docStatusSettings:[],
|
|
56
|
+
apiSettings:[],
|
|
57
|
+
requireautocomplete:true,
|
|
58
|
+
isolationtype:"org"
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
}
|
|
31
62
|
export const readJsonSchemaBuilder = async (
|
|
32
63
|
doctype: string,
|
|
33
64
|
docname: string,
|
|
34
65
|
orijsondata:JSONSchema7,
|
|
35
66
|
allforeignkeys:TypeForeignKeyCatalogue
|
|
36
67
|
) => {
|
|
37
|
-
|
|
38
|
-
fieldAutoCompleteCode=''
|
|
39
|
-
fieldAutoCompleteName=''
|
|
68
|
+
docSetting=newDocSetting(doctype,docname)
|
|
69
|
+
// fieldAutoCompleteCode=''
|
|
70
|
+
// fieldAutoCompleteName=''
|
|
40
71
|
moreAutoComplete=[]
|
|
41
72
|
allmodels = {};
|
|
73
|
+
|
|
42
74
|
const validateddata: JSONSchema7 = { ...orijsondata };
|
|
43
75
|
let schema: SchemaModel | SchemaModel[];
|
|
44
76
|
const tmpjsondata = await $RefParser.dereference(orijsondata).then((schema)=>{
|
|
@@ -56,12 +88,12 @@ export const readJsonSchemaBuilder = async (
|
|
|
56
88
|
} else if (jsondata.type == 'array') {
|
|
57
89
|
throw(`unsupport array type for ${docname}.${doctype}`)
|
|
58
90
|
}
|
|
59
|
-
if(
|
|
91
|
+
if(docSetting.colDocNo=='' && docSetting.requireautocomplete) {
|
|
60
92
|
log.error(`you shall define 1 field with format:'${X_DOCUMENT_NO}'`)
|
|
61
93
|
throw "missing field format"
|
|
62
94
|
}
|
|
63
|
-
if(
|
|
64
|
-
log.error(`you shall define 1 field with format: '${
|
|
95
|
+
if(docSetting.colDocLabel=='' && docSetting.requireautocomplete) {
|
|
96
|
+
log.error(`you shall define 1 field with format: '${X_DOCUMENT_LABEL}'}`)
|
|
65
97
|
throw "missing field format"
|
|
66
98
|
}
|
|
67
99
|
|
|
@@ -86,6 +118,50 @@ const processObject = (doctype: string,
|
|
|
86
118
|
jsondata.properties['updated'] = {type: 'string',description: 'Control value, dont edit it',};
|
|
87
119
|
jsondata.properties['createdby'] = {type: 'string',description: 'Control value, dont edit it',};
|
|
88
120
|
jsondata.properties['updatedby'] = {type: 'string',description: 'Control value, dont edit it',};
|
|
121
|
+
|
|
122
|
+
if(jsondata[X_ISOLATION_TYPE] && ['none','tenant','org','branch'].includes(jsondata[X_ISOLATION_TYPE]) ){
|
|
123
|
+
docSetting.isolationtype=jsondata[X_ISOLATION_TYPE]
|
|
124
|
+
}
|
|
125
|
+
if(jsondata[X_IGNORE_AUTOCOMPLETE] && jsondata[X_IGNORE_AUTOCOMPLETE]==true){
|
|
126
|
+
docSetting.requireautocomplete=false
|
|
127
|
+
}
|
|
128
|
+
if(jsondata[X_DOCUMENT_API] && Array.isArray(jsondata[X_DOCUMENT_API])){
|
|
129
|
+
log.warn("x-document-api exists:")
|
|
130
|
+
log.warn(jsondata[X_DOCUMENT_API])
|
|
131
|
+
for(let i=0; i<jsondata[X_DOCUMENT_API].length;i++){
|
|
132
|
+
const tmp:ApiSetting =jsondata[X_DOCUMENT_API][i]
|
|
133
|
+
if(!tmp.action){
|
|
134
|
+
const errmsg = "x-document-api defined but undefine property 'action'"
|
|
135
|
+
log.error(errmsg)
|
|
136
|
+
|
|
137
|
+
throw errmsg
|
|
138
|
+
}
|
|
139
|
+
if(!tmp.method){
|
|
140
|
+
const errmsg = "x-document-api defined but undefine property 'method'"
|
|
141
|
+
log.error(errmsg)
|
|
142
|
+
throw errmsg
|
|
143
|
+
}
|
|
144
|
+
docSetting.apiSettings.push(tmp)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if(jsondata[X_DOCUMENT_STATUS] && Array.isArray(jsondata[X_DOCUMENT_STATUS])){
|
|
148
|
+
for(let i=0; i<jsondata[X_DOCUMENT_STATUS].length;i++){
|
|
149
|
+
const tmp:DocStatusSetting =jsondata[X_DOCUMENT_STATUS][i]
|
|
150
|
+
if(tmp.statusCode ===undefined){
|
|
151
|
+
const errmsg = "x-document-status defined but undefine property 'statusCode'"
|
|
152
|
+
log.error(errmsg)
|
|
153
|
+
throw errmsg
|
|
154
|
+
}
|
|
155
|
+
if(!tmp.statusName ===undefined){
|
|
156
|
+
const errmsg = "x-document-status defined but undefine property 'statusName'"
|
|
157
|
+
log.error(errmsg)
|
|
158
|
+
throw errmsg
|
|
159
|
+
}
|
|
160
|
+
docSetting.docStatusSettings.push(tmp)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
89
165
|
return genSchema(
|
|
90
166
|
capitalizeFirstLetter(docname),
|
|
91
167
|
'object',
|
|
@@ -94,12 +170,8 @@ const processObject = (doctype: string,
|
|
|
94
170
|
);
|
|
95
171
|
}
|
|
96
172
|
|
|
97
|
-
const genSchema = (
|
|
98
|
-
|
|
99
|
-
schematype: string,
|
|
100
|
-
jsondata: JsonSchemaProperties,//JSONSchema7,//|JsonSchemaProperties|JSONSchema7Definition,
|
|
101
|
-
requiredlist: string[] | undefined,
|
|
102
|
-
): SchemaModel => {
|
|
173
|
+
const genSchema = (docname: string,schematype: string,jsondata: JsonSchemaProperties,
|
|
174
|
+
requiredlist: string[] | undefined): SchemaModel => {
|
|
103
175
|
const newmodel: SchemaModel = {};
|
|
104
176
|
const props = Object.getOwnPropertyNames(jsondata ??{});
|
|
105
177
|
// console.log('==== jsondata', jsondata);
|
|
@@ -116,18 +188,25 @@ const genSchema = (
|
|
|
116
188
|
const isrequired = requiredlist && requiredlist.includes(key);
|
|
117
189
|
const newName: string = docname + capitalizeFirstLetter(key);
|
|
118
190
|
if(obj.format && obj.format==X_DOCUMENT_NO){
|
|
119
|
-
|
|
191
|
+
docSetting.colDocNo=key
|
|
120
192
|
obj.minLength=obj.minLength??1
|
|
121
193
|
jsondata[key]['minLength']=obj.minLength
|
|
122
194
|
}
|
|
123
|
-
if(obj.format && obj.format==
|
|
124
|
-
|
|
195
|
+
if(obj.format && obj.format==X_DOCUMENT_LABEL){
|
|
196
|
+
docSetting.colDocLabel=key
|
|
125
197
|
obj.minLength=obj.minLength??1
|
|
126
198
|
jsondata[key]['minLength']=obj.minLength
|
|
127
199
|
}
|
|
200
|
+
|
|
201
|
+
if(obj[X_COLLECTION_NAME]){
|
|
202
|
+
docSetting.collectionName=key
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
|
|
128
206
|
if(obj[X_AUTOCOMPLETE_FIELD]){
|
|
129
|
-
|
|
207
|
+
docSetting.autocompleteFields.push(key)
|
|
130
208
|
}
|
|
209
|
+
|
|
131
210
|
|
|
132
211
|
// if(obj.format && obj.format==X_TEL_NO){
|
|
133
212
|
// obj.pattern=obj.pattern ?? '/^\d{7,15}$/gm'
|
|
@@ -177,7 +256,18 @@ const genSchema = (
|
|
|
177
256
|
// console.log(key,'--------newmodel',obj, newmodel[key]);
|
|
178
257
|
}
|
|
179
258
|
}
|
|
180
|
-
allmodels[docname] = {
|
|
259
|
+
allmodels[docname] = {
|
|
260
|
+
type: schematype,
|
|
261
|
+
model: newmodel,
|
|
262
|
+
codeField: docSetting.colDocNo ,
|
|
263
|
+
nameField: docSetting.colDocLabel,
|
|
264
|
+
moreAutoComplete:docSetting.autocompleteFields,
|
|
265
|
+
docStatusSettings:docSetting.docStatusSettings,
|
|
266
|
+
apiSettings:docSetting.apiSettings,
|
|
267
|
+
requireautocomplete:docSetting.requireautocomplete,
|
|
268
|
+
isolationtype:docSetting.isolationtype
|
|
269
|
+
};
|
|
270
|
+
// console.warn(docname,docSetting.isolationtype)
|
|
181
271
|
return newmodel;
|
|
182
272
|
};
|
|
183
273
|
|
|
@@ -216,3 +306,4 @@ const getField = (
|
|
|
216
306
|
}
|
|
217
307
|
return f;
|
|
218
308
|
};
|
|
309
|
+
|
package/src/type.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { JSONSchema7, JSONSchema7Definition } from 'json-schema';
|
|
2
2
|
export type ChildModels = {
|
|
3
|
-
[key: string]: {
|
|
3
|
+
[key: string]: {
|
|
4
|
+
type: string;
|
|
5
|
+
model: SchemaModel,
|
|
6
|
+
codeField:string,
|
|
7
|
+
nameField:string,
|
|
8
|
+
moreAutoComplete:string[],
|
|
9
|
+
docStatusSettings:DocStatusSetting[],
|
|
10
|
+
apiSettings:ApiSetting[],
|
|
11
|
+
requireautocomplete: boolean
|
|
12
|
+
isolationtype:string
|
|
13
|
+
};
|
|
4
14
|
};
|
|
5
15
|
export enum Fieldtypes {
|
|
6
16
|
'string' = 'string',
|
|
@@ -63,4 +73,37 @@ frontEndCode: string
|
|
|
63
73
|
backEndCode: string
|
|
64
74
|
controllerCode:string
|
|
65
75
|
apiSchemaCode:string
|
|
76
|
+
docStatusSettings:DocStatusSetting[],
|
|
77
|
+
apiSettings:ApiSetting[],
|
|
78
|
+
requireautocomplete:boolean,
|
|
79
|
+
isolationtype:string
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export type DocStatusSetting = {
|
|
83
|
+
statusCode:string,
|
|
84
|
+
statusName:string,
|
|
85
|
+
allowApi:string[],
|
|
86
|
+
readonly?:boolean,
|
|
87
|
+
description?:''
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export type ApiSetting = {
|
|
91
|
+
method:string,
|
|
92
|
+
action:string,
|
|
93
|
+
setDocStatus?:'',
|
|
94
|
+
description?:'',
|
|
95
|
+
bpmnApi?:'',
|
|
96
|
+
data?:any
|
|
97
|
+
}
|
|
98
|
+
export type DocSetting = {
|
|
99
|
+
docName:string,
|
|
100
|
+
docType:string,
|
|
101
|
+
colDocNo:string,
|
|
102
|
+
colDocLabel:string,
|
|
103
|
+
collectionName:string,
|
|
104
|
+
autocompleteFields:string[],
|
|
105
|
+
docStatusSettings:DocStatusSetting[],
|
|
106
|
+
apiSettings:ApiSetting[],
|
|
107
|
+
requireautocomplete:boolean
|
|
108
|
+
isolationtype:string
|
|
66
109
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* This file was automatically generated by simpleapp generator. Every
|
|
3
3
|
* MODIFICATION OVERRIDE BY GENERATEOR Except content between:
|
|
4
4
|
* <begin-controller-code><end-controller-code>
|
|
5
|
-
* last change 2023-09-
|
|
5
|
+
* last change 2023-09-18
|
|
6
6
|
* Author: Ks Tan
|
|
7
7
|
*/
|
|
8
8
|
import {
|
|
@@ -59,20 +59,6 @@ export class <%= it.typename %>Controller extends SimpleAppController<
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
@Get(':id')
|
|
63
|
-
@ApiResponse({
|
|
64
|
-
status: 200,
|
|
65
|
-
description: 'Founds',
|
|
66
|
-
type: <%= it.fullApiSchemaName%>
|
|
67
|
-
})
|
|
68
|
-
@ApiResponse({ status: 404, description: 'Document not found' })
|
|
69
|
-
@ApiResponse({ status: 500, description: 'Internal error' })
|
|
70
|
-
@ApiOperation({ operationId: 'runFindOne' })
|
|
71
|
-
async findOne(@Param('id') id: string) {
|
|
72
|
-
return await this._findOne(id);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
62
|
|
|
77
63
|
@Post()
|
|
78
64
|
@ApiResponse({
|
|
@@ -102,6 +88,38 @@ export class <%= it.typename %>Controller extends SimpleAppController<
|
|
|
102
88
|
return await this._search(data)
|
|
103
89
|
}
|
|
104
90
|
|
|
91
|
+
|
|
92
|
+
/***************************** x-document-api definations *****************************************/
|
|
93
|
+
|
|
94
|
+
<% for(let i=0;i<it.apiSettings.length;i++){%>
|
|
95
|
+
<% let api = it.apiSettings[i] %>
|
|
96
|
+
<%~ `@${capitalizeFirstLetter(api.method)}('${api.action}')`%>
|
|
97
|
+
@ApiResponse({status: 200,description: '<%=api.description%>',type: () =><%~JSON.stringify(api.returntype)%> })
|
|
98
|
+
@ApiOperation({ operationId: '<%=api.execute%>' })
|
|
99
|
+
async <%=api.execute%>(){
|
|
100
|
+
return await this.service.<%=api.execute%>()
|
|
101
|
+
}
|
|
102
|
+
<%}%>
|
|
103
|
+
|
|
104
|
+
/*****************************customized code begin here *****************************************/
|
|
105
|
+
<%~ it.controllerCode %>
|
|
106
|
+
|
|
107
|
+
/*****************************customized code end here *****************************************/
|
|
108
|
+
|
|
109
|
+
@Get(':id')
|
|
110
|
+
@ApiResponse({
|
|
111
|
+
status: 200,
|
|
112
|
+
description: 'Founds',
|
|
113
|
+
type: <%= it.fullApiSchemaName%>
|
|
114
|
+
})
|
|
115
|
+
@ApiResponse({ status: 404, description: 'Document not found' })
|
|
116
|
+
@ApiResponse({ status: 500, description: 'Internal error' })
|
|
117
|
+
@ApiOperation({ operationId: 'runFindOne' })
|
|
118
|
+
async findOne(@Param('id') id: string) {
|
|
119
|
+
return await this._findOne(id);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
105
123
|
@Put(':id')
|
|
106
124
|
@ApiResponse({
|
|
107
125
|
status: 200,
|
|
@@ -129,7 +147,6 @@ export class <%= it.typename %>Controller extends SimpleAppController<
|
|
|
129
147
|
}
|
|
130
148
|
|
|
131
149
|
|
|
132
|
-
|
|
133
|
-
<%~ it.controllerCode %>
|
|
150
|
+
|
|
134
151
|
|
|
135
152
|
}
|
|
@@ -29,6 +29,7 @@ const schemasetting = {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
export const <%= it.doctype %>MongoSchema = new Schema(schemasetting,{collection: '<%= it.name %>'})
|
|
32
|
+
<%if(it.requireautocomplete){%>
|
|
32
33
|
.index({<%=it.autocompletecode%>:1,orgId:1},{unique:true})
|
|
33
34
|
.index({<%=it.autocompletename%>:1,orgId:1});
|
|
34
|
-
|
|
35
|
+
<%}%>
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
]
|
|
37
37
|
<%}%>
|
|
38
38
|
<%})%>
|
|
39
|
-
|
|
39
|
+
//end
|
|
40
40
|
</script>
|
|
41
41
|
<template>
|
|
42
42
|
<div>
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
:listColumns="columns">
|
|
47
47
|
|
|
48
48
|
<%Object.keys(it.jsonschema.properties).forEach(function(key) { %>
|
|
49
|
-
|
|
49
|
+
|
|
50
|
+
<% let obj=it.jsonschema.properties[key] %>
|
|
50
51
|
<% if(skipcolumns.indexOf(key)>=0){ %>
|
|
51
52
|
<% } else if(obj.type=='boolean'){ %>
|
|
52
53
|
<SimpleAppCheckbox autofocus :setting="o.getField('#/properties/<%= key %>')" v-model="data.<%= key %>"/>
|
|
@@ -55,7 +56,7 @@
|
|
|
55
56
|
<% } else if(obj.type=='array' && obj.items && obj.items.type =='string' ){ %>
|
|
56
57
|
<SimpleAppChip autofocus :setting="o.getField('#/properties/<%= key %>')" v-model="data.<%= key %>"/>
|
|
57
58
|
<% } else if(obj.type=='object' && typeof obj['x-foreignkey']!='undefined'){ %>
|
|
58
|
-
<SimpleAppAutocomplete
|
|
59
|
+
<SimpleAppAutocomplete :setting="o.getField('#/properties/<%= key %>')"
|
|
59
60
|
v-model="data.<%= key %>" optionLabel="label" :remote-src="getAutocomplete('<%=obj['x-foreignkey']%>')"/>
|
|
60
61
|
<% } else if(obj.type=='string'){ %>
|
|
61
62
|
<% if(obj.format=='date'){ %>
|