@simitgroup/simpleapp-generator 1.0.29 → 1.0.32
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 +136 -16
- package/dist/framework.js +8 -3
- package/dist/framework.js.map +1 -1
- package/dist/generate.js +14 -3
- package/dist/generate.js.map +1 -1
- package/dist/processors/jsonschemabuilder.js +109 -16
- package/dist/processors/jsonschemabuilder.js.map +1 -1
- package/dist/type.js.map +1 -1
- package/package.json +1 -1
- package/src/framework.ts +8 -3
- package/src/generate.ts +18 -5
- package/src/processors/jsonschemabuilder.ts +129 -20
- package/src/type.ts +45 -1
- package/templates/basic/controller.eta +34 -17
- package/templates/basic/model.eta +4 -1
- package/templates/basic/pageindex.vue.eta +60 -5
- package/templates/basic/service.eta +29 -3
- package/templates/basic/simpleappclient.eta +54 -1
- package/templates/nest/SimpleAppService.eta +136 -39
- 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/nest/nest.main.eta +2 -2
- package/templates/nuxt/components.crudsimple.vue.eta +2 -2
- package/templates/nuxt/components.debugdocdata.vue.eta +12 -6
- package/templates/nuxt/components.menus.vue.eta +22 -7
- package/templates/nuxt/composables.getautocomplete.ts.eta +3 -5
- package/templates/nuxt/composables.getmenus.ts.eta +12 -2
- package/templates/nuxt/pages.[xorg].index.vue.eta +9 -8
- package/templates/nuxt/pages.index.vue.eta +61 -8
- package/templates/nuxt/plugins.simpleapp.ts.eta +7 -0
- package/templates/nuxt/server.api.ts.eta +2 -1
- package/templates/nuxt/tailwind.css.eta +22 -1
- package/tsconfig.json +4 -1
- package/templates/nest/User.eta +0 -115
package/src/framework.ts
CHANGED
|
@@ -20,6 +20,11 @@ let config = {
|
|
|
20
20
|
"OAUTH2_CLIENTID":"client-id",
|
|
21
21
|
"OAUTH2_CLIENTSECRET":"client-secret-value",
|
|
22
22
|
"AUTH_SECRET_KEY":"my-secret",
|
|
23
|
+
},
|
|
24
|
+
"bpmnsetting":{
|
|
25
|
+
"BPMN_HOST":"127.0.0.1",
|
|
26
|
+
"BPMN_PORT":"9000",
|
|
27
|
+
"BPMN_API_KEY":"12345"
|
|
23
28
|
}
|
|
24
29
|
}
|
|
25
30
|
|
|
@@ -61,7 +66,7 @@ export const prepareNest = (callback:Function)=>{
|
|
|
61
66
|
if(!fs.existsSync(`${targetfolder}/.env`)){
|
|
62
67
|
|
|
63
68
|
|
|
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 @nestjs/config`,async (error, stdout, stderr)=>{
|
|
69
|
+
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
70
|
// log.info(`dependency installed`)
|
|
66
71
|
if(!error){
|
|
67
72
|
fs.mkdirSync(`${targetfolder}/public_html`,{recursive:true})
|
|
@@ -101,7 +106,7 @@ export const prepareNuxt = (callback:Function)=>{
|
|
|
101
106
|
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
107
|
//;pnpm install
|
|
103
108
|
console.log(error, stdout, stderr)
|
|
104
|
-
exec(`cd ${targetfolder};pnpm install --save next-auth@4.21.1 @darkwolf/base64url @nuxt/ui ajv dotenv @fullcalendar/core @fullcalendar/vue3 quill uuid
|
|
109
|
+
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
110
|
console.log(error, stdout, stderr)
|
|
106
111
|
|
|
107
112
|
fs.mkdirSync(`${targetfolder}/assets/css/`,{recursive:true})
|
|
@@ -159,7 +164,7 @@ export const prettyNuxt = ()=>{
|
|
|
159
164
|
|
|
160
165
|
}
|
|
161
166
|
export const prettyNest = ()=>{
|
|
162
|
-
exec(`cd ${config.backendFolder};npm run format`)
|
|
167
|
+
exec(`cd ${config.backendFolder};npm run format;npx prettier --write src/dicts/foreignkeys.json`)
|
|
163
168
|
}
|
|
164
169
|
|
|
165
170
|
export const prepareOpenApiClient = () => {
|
package/src/generate.ts
CHANGED
|
@@ -26,20 +26,21 @@ export const initialize = async (defFolder:string,backendfolder:string,frontend
|
|
|
26
26
|
let activatemodules:ModuleObject[]=[]
|
|
27
27
|
//
|
|
28
28
|
const files = readdirSync(defFolder)
|
|
29
|
+
// log.warn("all schemas:",files)
|
|
29
30
|
// readdir(defFolder, (err, files) => {
|
|
30
31
|
// files.forEach((file) => {
|
|
31
32
|
for(let j = 0; j< files.length;j++){
|
|
32
33
|
const file = files[j]
|
|
34
|
+
log.info(`Load `+clc.green(file))
|
|
33
35
|
const filearr = file.split('.');
|
|
34
36
|
let rendertype = 'basic';
|
|
35
37
|
const docname = filearr[0].toLowerCase();
|
|
36
38
|
const doctype = filearr[1].toLowerCase();
|
|
37
|
-
const jsonstring = readFileSync(defFolder +path.sep+ file, 'utf-8');
|
|
38
|
-
const jsondata = JSON.parse(jsonstring);
|
|
39
|
+
const jsonstring = readFileSync(defFolder +path.sep+ file, 'utf-8');
|
|
39
40
|
let allmodels: ChildModels = {} as ChildModels;
|
|
40
41
|
|
|
41
|
-
if (file.endsWith(extjsonschema)) {
|
|
42
|
-
|
|
42
|
+
if (file.endsWith(extjsonschema)) {
|
|
43
|
+
const jsondata = JSON.parse(jsonstring);
|
|
43
44
|
rendertype = 'basic';
|
|
44
45
|
jsonschemas[docname] = jsondata;
|
|
45
46
|
// foreignkeys:
|
|
@@ -96,6 +97,7 @@ const generate = (
|
|
|
96
97
|
models: allmodels,
|
|
97
98
|
autocompletecode:allmodels[capitalizeFirstLetter(docname)].codeField,
|
|
98
99
|
autocompletename:allmodels[capitalizeFirstLetter(docname)].nameField,
|
|
100
|
+
moreAutoComplete:allmodels[capitalizeFirstLetter(docname)].moreAutoComplete,
|
|
99
101
|
schema: allmodels[capitalizeFirstLetter(docname)].model,
|
|
100
102
|
apiSchemaName: capitalizeFirstLetter(docname), //capitalizeFirstLetter(doctype) + 'ApiSchema',
|
|
101
103
|
typename: capitalizeFirstLetter(docname),
|
|
@@ -108,6 +110,10 @@ const generate = (
|
|
|
108
110
|
backEndCode: '',
|
|
109
111
|
controllerCode:'',
|
|
110
112
|
apiSchemaCode:'',
|
|
113
|
+
docStatusSettings:allmodels[capitalizeFirstLetter(docname)].docStatusSettings,
|
|
114
|
+
apiSettings:allmodels[capitalizeFirstLetter(docname)].apiSettings,
|
|
115
|
+
requireautocomplete:allmodels[capitalizeFirstLetter(docname)].requireautocomplete,
|
|
116
|
+
isolationtype:allmodels[capitalizeFirstLetter(docname)].isolationtype
|
|
111
117
|
};
|
|
112
118
|
|
|
113
119
|
// console.log('generate 2', JSON.stringify(variables));
|
|
@@ -269,8 +275,9 @@ const prepareEnvironments = (backendfolder:string,frontendfolder:string)=>{
|
|
|
269
275
|
|
|
270
276
|
copyFileSync(`${constants.templatedir}/nest/SimpleAppService.eta`,`${targetfolder}/SimpleAppService.ts`)
|
|
271
277
|
copyFileSync(`${constants.templatedir}/nest/SimpleAppController.eta`,`${targetfolder}/SimpleAppController.ts`)
|
|
278
|
+
copyFileSync(`${constants.templatedir}/nest/Workflow.eta`,`${targetfolder}/Workflow.ts`)
|
|
272
279
|
copyFileSync(`${constants.templatedir}/nest/TenantMiddleware.eta`,`${targetfolder}/TenantMiddleware.ts`)
|
|
273
|
-
copyFileSync(`${constants.templatedir}/nest/
|
|
280
|
+
copyFileSync(`${constants.templatedir}/nest/UserProvider.eta`,`${targetfolder}/UserProvider.ts`)
|
|
274
281
|
|
|
275
282
|
//copy over frontend apiabstract class
|
|
276
283
|
// copyFileSync(`${constants.templatedir}/nuxt.apigateway.eta`,`${targetfrontendfolder}/[...].ts`)
|
|
@@ -289,6 +296,12 @@ const finalize=(modules:ModuleObject[],backendfolder:string,frontendfolder:strin
|
|
|
289
296
|
const eta = new Eta({views:constants.templatedir});
|
|
290
297
|
const txtMainModule = eta.render('./nest/app.module.eta', modules);
|
|
291
298
|
writeFileSync(`${backendfolder}/src/app.module.ts`, txtMainModule);
|
|
299
|
+
|
|
300
|
+
const txtMainService = eta.render('./nest/app.service.eta', modules);
|
|
301
|
+
writeFileSync(`${backendfolder}/src/app.service.ts`, txtMainService);
|
|
302
|
+
|
|
303
|
+
const txtAppController = eta.render('./nest/app.controller.eta', modules);
|
|
304
|
+
writeFileSync(`${backendfolder}/src/app.controller.ts`, txtAppController);
|
|
292
305
|
|
|
293
306
|
const foreignkeyfile =`${backendfolder}/src/dicts/foreignkeys.json`
|
|
294
307
|
writeFileSync(foreignkeyfile, JSON.stringify(foreignkeys));
|
|
@@ -13,28 +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'
|
|
24
|
+
const X_DOCUMENT_LABEL='x-document-label'
|
|
25
|
+
const X_AUTOCOMPLETE_FIELD='x-autocomplete-field'
|
|
21
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'
|
|
22
32
|
const FOREIGNKEY_PROPERTY='x-foreignkey'
|
|
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
|
+
|
|
23
40
|
let allmodels: ChildModels = {};
|
|
24
41
|
let fullschema={}
|
|
25
|
-
let fieldAutoCompleteCode=''
|
|
26
|
-
let fieldAutoCompleteName=''
|
|
42
|
+
// let fieldAutoCompleteCode=''
|
|
43
|
+
// let fieldAutoCompleteName=''
|
|
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"
|
|
27
59
|
|
|
60
|
+
}
|
|
61
|
+
}
|
|
28
62
|
export const readJsonSchemaBuilder = async (
|
|
29
63
|
doctype: string,
|
|
30
64
|
docname: string,
|
|
31
65
|
orijsondata:JSONSchema7,
|
|
32
66
|
allforeignkeys:TypeForeignKeyCatalogue
|
|
33
67
|
) => {
|
|
34
|
-
|
|
35
|
-
fieldAutoCompleteCode=''
|
|
36
|
-
fieldAutoCompleteName=''
|
|
68
|
+
docSetting=newDocSetting(doctype,docname)
|
|
69
|
+
// fieldAutoCompleteCode=''
|
|
70
|
+
// fieldAutoCompleteName=''
|
|
71
|
+
moreAutoComplete=[]
|
|
37
72
|
allmodels = {};
|
|
73
|
+
|
|
38
74
|
const validateddata: JSONSchema7 = { ...orijsondata };
|
|
39
75
|
let schema: SchemaModel | SchemaModel[];
|
|
40
76
|
const tmpjsondata = await $RefParser.dereference(orijsondata).then((schema)=>{
|
|
@@ -52,12 +88,12 @@ export const readJsonSchemaBuilder = async (
|
|
|
52
88
|
} else if (jsondata.type == 'array') {
|
|
53
89
|
throw(`unsupport array type for ${docname}.${doctype}`)
|
|
54
90
|
}
|
|
55
|
-
if(
|
|
91
|
+
if(docSetting.colDocNo=='' && docSetting.requireautocomplete) {
|
|
56
92
|
log.error(`you shall define 1 field with format:'${X_DOCUMENT_NO}'`)
|
|
57
93
|
throw "missing field format"
|
|
58
94
|
}
|
|
59
|
-
if(
|
|
60
|
-
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}'}`)
|
|
61
97
|
throw "missing field format"
|
|
62
98
|
}
|
|
63
99
|
|
|
@@ -82,6 +118,50 @@ const processObject = (doctype: string,
|
|
|
82
118
|
jsondata.properties['updated'] = {type: 'string',description: 'Control value, dont edit it',};
|
|
83
119
|
jsondata.properties['createdby'] = {type: 'string',description: 'Control value, dont edit it',};
|
|
84
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
|
+
|
|
85
165
|
return genSchema(
|
|
86
166
|
capitalizeFirstLetter(docname),
|
|
87
167
|
'object',
|
|
@@ -90,12 +170,8 @@ const processObject = (doctype: string,
|
|
|
90
170
|
);
|
|
91
171
|
}
|
|
92
172
|
|
|
93
|
-
const genSchema = (
|
|
94
|
-
|
|
95
|
-
schematype: string,
|
|
96
|
-
jsondata: JsonSchemaProperties,//JSONSchema7,//|JsonSchemaProperties|JSONSchema7Definition,
|
|
97
|
-
requiredlist: string[] | undefined,
|
|
98
|
-
): SchemaModel => {
|
|
173
|
+
const genSchema = (docname: string,schematype: string,jsondata: JsonSchemaProperties,
|
|
174
|
+
requiredlist: string[] | undefined): SchemaModel => {
|
|
99
175
|
const newmodel: SchemaModel = {};
|
|
100
176
|
const props = Object.getOwnPropertyNames(jsondata ??{});
|
|
101
177
|
// console.log('==== jsondata', jsondata);
|
|
@@ -112,11 +188,29 @@ const genSchema = (
|
|
|
112
188
|
const isrequired = requiredlist && requiredlist.includes(key);
|
|
113
189
|
const newName: string = docname + capitalizeFirstLetter(key);
|
|
114
190
|
if(obj.format && obj.format==X_DOCUMENT_NO){
|
|
115
|
-
|
|
191
|
+
docSetting.colDocNo=key
|
|
192
|
+
obj.minLength=obj.minLength??1
|
|
193
|
+
jsondata[key]['minLength']=obj.minLength
|
|
194
|
+
}
|
|
195
|
+
if(obj.format && obj.format==X_DOCUMENT_LABEL){
|
|
196
|
+
docSetting.colDocLabel=key
|
|
197
|
+
obj.minLength=obj.minLength??1
|
|
198
|
+
jsondata[key]['minLength']=obj.minLength
|
|
116
199
|
}
|
|
117
|
-
|
|
118
|
-
|
|
200
|
+
|
|
201
|
+
if(obj[X_COLLECTION_NAME]){
|
|
202
|
+
docSetting.collectionName=key
|
|
119
203
|
}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
if(obj[X_AUTOCOMPLETE_FIELD]){
|
|
207
|
+
docSetting.autocompleteFields.push(key)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
// if(obj.format && obj.format==X_TEL_NO){
|
|
212
|
+
// obj.pattern=obj.pattern ?? '/^\d{7,15}$/gm'
|
|
213
|
+
// }
|
|
120
214
|
// if (obj.type == 'object' && obj.items ){
|
|
121
215
|
// console.log("Refer to another object",docname,': ',key,obj,obj.items)
|
|
122
216
|
|
|
@@ -132,11 +226,14 @@ const genSchema = (
|
|
|
132
226
|
// console.warn("FOREIGNKEY_PROPERTY exists",FOREIGNKEY_PROPERTY,obj[FOREIGNKEY_PROPERTY])
|
|
133
227
|
const masterdatacollection = obj[FOREIGNKEY_PROPERTY]
|
|
134
228
|
const clientdatacollection = docname.toLowerCase()
|
|
135
|
-
const foreignkeyidentity= key
|
|
229
|
+
const foreignkeyidentity= key
|
|
136
230
|
if(!foreignkeys[masterdatacollection]){
|
|
137
231
|
let tmp:TypeForeignKey = {} as TypeForeignKey
|
|
138
232
|
tmp[clientdatacollection]=[foreignkeyidentity]
|
|
139
233
|
foreignkeys[masterdatacollection] = tmp
|
|
234
|
+
}
|
|
235
|
+
else if(!foreignkeys[masterdatacollection][clientdatacollection]){
|
|
236
|
+
foreignkeys[masterdatacollection][clientdatacollection]=[foreignkeyidentity]
|
|
140
237
|
}else{
|
|
141
238
|
foreignkeys[masterdatacollection][clientdatacollection].push(foreignkeyidentity)
|
|
142
239
|
}
|
|
@@ -159,7 +256,18 @@ const genSchema = (
|
|
|
159
256
|
// console.log(key,'--------newmodel',obj, newmodel[key]);
|
|
160
257
|
}
|
|
161
258
|
}
|
|
162
|
-
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)
|
|
163
271
|
return newmodel;
|
|
164
272
|
};
|
|
165
273
|
|
|
@@ -198,3 +306,4 @@ const getField = (
|
|
|
198
306
|
}
|
|
199
307
|
return f;
|
|
200
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',
|
|
@@ -51,6 +61,7 @@ doctype: string
|
|
|
51
61
|
models: ChildModels
|
|
52
62
|
autocompletecode:string
|
|
53
63
|
autocompletename:string
|
|
64
|
+
moreAutoComplete:string[]
|
|
54
65
|
schema: SchemaModel
|
|
55
66
|
apiSchemaName: string
|
|
56
67
|
typename: string
|
|
@@ -62,4 +73,37 @@ frontEndCode: string
|
|
|
62
73
|
backEndCode: string
|
|
63
74
|
controllerCode:string
|
|
64
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
|
|
65
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)}(':id/${api.action}')`%>
|
|
97
|
+
@ApiResponse({status: 200,description: '<%=api.description%>'})
|
|
98
|
+
@ApiOperation({ operationId: 'exec<%=capitalizeFirstLetter(api.action)%>' })
|
|
99
|
+
async exec<%=capitalizeFirstLetter(api.action)%>(@Param('id') id: string){
|
|
100
|
+
return await this.service.exec<%=capitalizeFirstLetter(api.action)%>(id)
|
|
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,4 +29,7 @@ const schemasetting = {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
export const <%= it.doctype %>MongoSchema = new Schema(schemasetting,{collection: '<%= it.name %>'})
|
|
32
|
-
|
|
32
|
+
<%if(it.requireautocomplete){%>
|
|
33
|
+
.index({<%=it.autocompletecode%>:1,orgId:1},{unique:true})
|
|
34
|
+
.index({<%=it.autocompletename%>:1,orgId:1});
|
|
35
|
+
<%}%>
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
<% let skipcolumns = ['_id','createdby','created','updatedby','updated','orgId','branchId','tenantId','doctype'] %>
|
|
10
10
|
|
|
11
11
|
import { <%= it.typename %>Doc } from "../../../simpleapp/simpleappdocs/<%= it.typename %>Doc";
|
|
12
|
+
import SimpleAppDatatable from "@simitgroup/simpleapp-vue-component/src/components/SimpleAppDatatable.vue";
|
|
13
|
+
import {InputTableColumnType,InputTableColumn} from "@simitgroup/simpleapp-vue-component/src/type";
|
|
12
14
|
const { $event, $listen } = useNuxtApp();
|
|
13
15
|
const route = useRoute()
|
|
14
|
-
const doc = new <%= it.typename %>Doc(route.params.xorg,$event, $listen);
|
|
16
|
+
const doc = new <%= it.typename %>Doc(route.params.xorg.toString(),$event, $listen);
|
|
15
17
|
const documentpath = `/${route.params.xorg}/<%= it.name %>`;
|
|
16
18
|
const data = doc.getReactiveData();
|
|
17
19
|
const columns = [
|
|
@@ -21,6 +23,20 @@
|
|
|
21
23
|
<%} else if(['string','number','integer'].indexOf(obj.type)>=0){%>'<%=key%>',<%}%>
|
|
22
24
|
<%})%>
|
|
23
25
|
]
|
|
26
|
+
//prepare subtable if exists
|
|
27
|
+
<%Object.keys(it.jsonschema.properties).forEach(function(key) { %>
|
|
28
|
+
<% let obj=it.jsonschema.properties[key] %>
|
|
29
|
+
|
|
30
|
+
<% if(obj.type=='array' && obj.items.type=='object' && obj.items['properties']){ %>
|
|
31
|
+
<%let tablefields = Object.keys(obj.items.properties) %>
|
|
32
|
+
const <%=it.name%>_<%=key%> :InputTableColumn[] = [
|
|
33
|
+
<% for(let a=0;a<tablefields.length;a++){%>
|
|
34
|
+
{type:InputTableColumnType.field, field:'<%= tablefields[a] %>',style:'width:10%'},
|
|
35
|
+
<%}%>
|
|
36
|
+
]
|
|
37
|
+
<%}%>
|
|
38
|
+
<%})%>
|
|
39
|
+
|
|
24
40
|
</script>
|
|
25
41
|
<template>
|
|
26
42
|
<div>
|
|
@@ -39,7 +55,7 @@
|
|
|
39
55
|
<% } else if(obj.type=='array' && obj.items && obj.items.type =='string' ){ %>
|
|
40
56
|
<SimpleAppChip autofocus :setting="o.getField('#/properties/<%= key %>')" v-model="data.<%= key %>"/>
|
|
41
57
|
<% } else if(obj.type=='object' && typeof obj['x-foreignkey']!='undefined'){ %>
|
|
42
|
-
<SimpleAppAutocomplete
|
|
58
|
+
<SimpleAppAutocomplete :setting="o.getField('#/properties/<%= key %>')"
|
|
43
59
|
v-model="data.<%= key %>" optionLabel="label" :remote-src="getAutocomplete('<%=obj['x-foreignkey']%>')"/>
|
|
44
60
|
<% } else if(obj.type=='string'){ %>
|
|
45
61
|
<% if(obj.format=='date'){ %>
|
|
@@ -55,9 +71,48 @@
|
|
|
55
71
|
<% } else {%>
|
|
56
72
|
<SimpleAppText autofocus :setting="o.getField('#/properties/<%= key %>')" v-model="data.<%= key %>"/>
|
|
57
73
|
<% }%>
|
|
58
|
-
<% } else { %>
|
|
59
|
-
<
|
|
60
|
-
|
|
74
|
+
<% } else if(obj.type=='object' && obj.properties){ %>
|
|
75
|
+
<SimpleAppValue :setting="o.getField('#/properties/<%= key %>')">
|
|
76
|
+
<%Object.keys(obj.properties).forEach(function(skey) { %>
|
|
77
|
+
<% let sobj=obj.properties[skey] %>
|
|
78
|
+
<% let fieldpath=`o.getField('#/properties/${key}/properties/${skey}')` %>
|
|
79
|
+
<% let vmodel=`data.${key}.${skey}` %>
|
|
80
|
+
<% let instancePath=`#/${key}/${skey}` %>
|
|
81
|
+
|
|
82
|
+
<% if(sobj.type=='boolean'){ %>
|
|
83
|
+
<SimpleAppCheckbox autofocus :setting="<%~fieldpath%>" instancePath="<%=instancePath%>" v-model="<%= vmodel %>"/>
|
|
84
|
+
<% } else if(sobj.type=='number' || sobj.type=='integer'){ %>
|
|
85
|
+
<SimpleAppNumber autofocus :setting="<%~fieldpath%>" instancePath="<%=instancePath%>" v-model="<%= vmodel %>"/>
|
|
86
|
+
<% } else if(sobj.type=='array' && sobj.items && sobj.items.type =='string' ){ %>
|
|
87
|
+
<SimpleAppChip autofocus :setting="<%~fieldpath%>" instancePath="<%=instancePath%>" v-model="<%= vmodel %>"/>
|
|
88
|
+
<% } else if(sobj.type=='object' && typeof sobj['x-foreignkey']!='undefined'){ %>
|
|
89
|
+
<SimpleAppAutocomplete autofocus :setting="<%~fieldpath%>" instancePath="<%=instancePath%>"
|
|
90
|
+
v-model="<%= vmodel %>" optionLabel="label" :remote-src="getAutocomplete('<%=sobj['x-foreignkey']%>')"/>
|
|
91
|
+
<% } else if(sobj.type=='string'){ %>
|
|
92
|
+
<% if(sobj.format=='date'){ %>
|
|
93
|
+
<SimpleAppText type="<%=sobj.format%>" instancePath="<%=instancePath%>" autofocus :setting="<%~fieldpath%>" v-model="<%= vmodel %>"/>
|
|
94
|
+
<% } else if(sobj.format=='x-text'){ %>
|
|
95
|
+
<SimpleAppTextarea :setting="<%~fieldpath%>'" instancePath="<%=instancePath%>" v-model="<%= vmodel %>"/>
|
|
96
|
+
<% } else if(sobj.format=='x-html'){ %>
|
|
97
|
+
<SimpleAppEditor editorStyle="height: 320px" instancePath="<%=instancePath%>" :setting="<%=fieldpath%>" v-model="<%= vmodel %>"/>
|
|
98
|
+
<% } else if(sobj.format=='email'){ %>
|
|
99
|
+
<SimpleAppText autofocus type="<%=~obj.type%>" instancePath="<%=instancePath%>" :setting="<%=fieldpath%>" v-model="<%= vmodel %>"/>
|
|
100
|
+
<% } else if(sobj.enum){ %>
|
|
101
|
+
<SimpleAppRadio autofocus :setting="<%~fieldpath%>" instancePath="<%=instancePath%>" v-model="<%= vmodel %>"/>
|
|
102
|
+
<% } else {%>
|
|
103
|
+
<SimpleAppText autofocus :setting="<%~fieldpath%>" instancePath="<%=instancePath%>" v-model="<%= vmodel %>"/>
|
|
104
|
+
<% }%>
|
|
105
|
+
<% } %>
|
|
106
|
+
<%})%>
|
|
107
|
+
</SimpleAppValue>
|
|
108
|
+
<% } else if(obj.type=='array' && obj.items.type=='object'){%>
|
|
109
|
+
<button @click="doc.add<%=key%>()" type="button">+</button>
|
|
110
|
+
<SimpleAppInputTable :getAutocomplete="getAutocomplete" :getField="o.getField"
|
|
111
|
+
:setting="o.getField('#/properties/<%=key%>')" #default="row" v-model="data.<%=key%>" :columns="<%=it.name%>_<%=key%>"></SimpleAppInputTable>
|
|
112
|
+
<% } else{%>
|
|
113
|
+
<!-- Can auto generate <%=obj.key %> -->
|
|
114
|
+
<!-- <%~ JSON.stringify(obj) %>-->
|
|
115
|
+
<%}%>
|
|
61
116
|
<%})%>
|
|
62
117
|
|
|
63
118
|
</CrudSimple>
|
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
* last change 2023-09-09
|
|
7
7
|
* Author: Ks Tan
|
|
8
8
|
*/
|
|
9
|
+
import { UserProvider } from '../../class/UserProvider'
|
|
9
10
|
import { Injectable } from '@nestjs/common';
|
|
10
11
|
import { InjectModel } from '@nestjs/mongoose';
|
|
11
12
|
import { Model } from 'mongoose';
|
|
12
13
|
import {<%= it.typename%>JsonSchema } from './<%= it.doctype %>.jsonschema'
|
|
13
|
-
import { SimpleAppService,IsolationType } from '../../class/SimpleAppService';
|
|
14
|
+
import { SimpleAppService,IsolationType,HookType } from '../../class/SimpleAppService';
|
|
14
15
|
import { <%Object.keys(it.models).forEach(function(key) { %> <%=key %>, <%})%> } from './<%= it.doctype %>.type';
|
|
15
16
|
|
|
16
17
|
|
|
@@ -20,11 +21,36 @@ export class <%= it.typename %>Service extends SimpleAppService<<%= it.typename
|
|
|
20
21
|
protected documentIdentityName='<%~ it.autocompletename %>'
|
|
21
22
|
constructor(@InjectModel('<%= it.name %>') mydoc: Model<<%= it.typename %>>,
|
|
22
23
|
) {
|
|
23
|
-
super(mydoc,IsolationType.
|
|
24
|
+
super('<%= it.doctype %>','<%= it.name %>',mydoc,IsolationType.<%=it.isolationtype%>);
|
|
24
25
|
this.setSchema(<%= it.typename%>JsonSchema)
|
|
26
|
+
|
|
27
|
+
<%if(it.moreAutoComplete.length>0){%>
|
|
28
|
+
this.addAutoCompleteField({
|
|
29
|
+
<%Object.keys(it.moreAutoComplete).forEach(function(key) { %>
|
|
30
|
+
<% let f=it.moreAutoComplete[key] %>
|
|
31
|
+
<%~ `${f}: '${f}'`, %>
|
|
32
|
+
<%})%>
|
|
33
|
+
})
|
|
34
|
+
<%}%>
|
|
35
|
+
|
|
25
36
|
}
|
|
26
37
|
|
|
27
|
-
|
|
38
|
+
/***************************** x-document-api definations *****************************************/
|
|
39
|
+
|
|
40
|
+
<%for(let i=0;i<it.apiSettings.length;i++){%>
|
|
41
|
+
<% let api = it.apiSettings[i] %>
|
|
42
|
+
async exec<%=capitalizeFirstLetter(api.action)%>(id:string){
|
|
43
|
+
<%if(api.bpmn!==undefined){%>
|
|
44
|
+
return await this.executeWorkFlow(id,"<%=api.bpmn%>","<%=api.setDocumentStatus%>")
|
|
45
|
+
<%}else if (api.setDocumentStatus !== undefined){%>
|
|
46
|
+
return await this.setDocumentStatus(id,'<%=api.setDocumentStatus%>')
|
|
47
|
+
<%}else {%>
|
|
48
|
+
return Promise.resolve("unknown action")
|
|
49
|
+
<%}%>
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
<%}%>
|
|
53
|
+
|
|
28
54
|
/*****************************customized frontend + backend code*****************************************/
|
|
29
55
|
|
|
30
56
|
<%~ it.bothEndCode %>
|