@simitgroup/simpleapp-generator 1.6.3-alpha → 1.6.4-alpha

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.
Files changed (148) hide show
  1. package/dist/buildinschemas/branch.d.ts.map +1 -1
  2. package/dist/buildinschemas/branch.js +1 -0
  3. package/dist/buildinschemas/branch.js.map +1 -1
  4. package/dist/buildinschemas/changehistories.d.ts +3 -0
  5. package/dist/buildinschemas/changehistories.d.ts.map +1 -0
  6. package/dist/buildinschemas/changehistories.js +36 -0
  7. package/dist/buildinschemas/changehistories.js.map +1 -0
  8. package/dist/buildinschemas/index.d.ts +1 -0
  9. package/dist/buildinschemas/index.d.ts.map +1 -1
  10. package/dist/buildinschemas/index.js +3 -1
  11. package/dist/buildinschemas/index.js.map +1 -1
  12. package/dist/buildinschemas/organization.js +2 -2
  13. package/dist/buildinschemas/organization.js.map +1 -1
  14. package/dist/buildinschemas/user.d.ts.map +1 -1
  15. package/dist/buildinschemas/user.js +5 -1
  16. package/dist/buildinschemas/user.js.map +1 -1
  17. package/dist/buildinschemas/webhook.d.ts +3 -0
  18. package/dist/buildinschemas/webhook.d.ts.map +1 -0
  19. package/dist/buildinschemas/webhook.js +33 -0
  20. package/dist/buildinschemas/webhook.js.map +1 -0
  21. package/dist/framework.d.ts.map +1 -1
  22. package/dist/framework.js +3 -2
  23. package/dist/framework.js.map +1 -1
  24. package/dist/generate.js +30 -11
  25. package/dist/generate.js.map +1 -1
  26. package/dist/processors/jsonschemabuilder.d.ts.map +1 -1
  27. package/dist/processors/jsonschemabuilder.js +10 -2
  28. package/dist/processors/jsonschemabuilder.js.map +1 -1
  29. package/dist/type.d.ts +2 -0
  30. package/dist/type.d.ts.map +1 -1
  31. package/package.json +1 -1
  32. package/src/buildinschemas/branch.ts +1 -0
  33. package/src/buildinschemas/changehistories.ts +33 -0
  34. package/src/buildinschemas/index.ts +2 -1
  35. package/src/buildinschemas/organization.ts +2 -2
  36. package/src/buildinschemas/user.ts +5 -1
  37. package/src/buildinschemas/webhook.ts +31 -0
  38. package/src/framework.ts +3 -2
  39. package/src/generate.ts +35 -15
  40. package/src/processors/jsonschemabuilder.ts +10 -2
  41. package/src/type.ts +2 -0
  42. package/templates/basic/nest/controller.ts.eta +23 -2
  43. package/templates/basic/nest/model.ts.eta +9 -1
  44. package/templates/basic/nest/resolver.ts.eta +2 -2
  45. package/templates/basic/nuxt/pages.[id].vue.eta +7 -7
  46. package/templates/basic/nuxt/pages.form.vue.eta +1 -4
  47. package/templates/basic/nuxt/pages.landing.vue.eta +1 -20
  48. package/templates/basic/nuxt/simpleapp.generate.client.ts.eta +8 -1
  49. package/templates/nest/src/simpleapp/generate/apischemas/simpleapp.apischema.ts.eta +2 -0
  50. package/templates/nest/src/simpleapp/generate/commons/dicts/documents.ts.eta +9 -2
  51. package/templates/nest/src/simpleapp/generate/commons/roles/roles.enum.ts.eta +5 -10
  52. package/templates/nest/src/simpleapp/generate/commons/roles/roles.group.ts.eta +1 -0
  53. package/templates/nest/src/simpleapp/generate/commons/runwebhook.service.ts.eta +50 -0
  54. package/templates/nest/src/simpleapp/generate/commons/user.context.ts.eta +13 -3
  55. package/templates/nest/src/simpleapp/generate/controllers/simpleapp.controller.ts.eta +9 -1
  56. package/templates/nest/src/simpleapp/generate/processors/branch.processor.ts.eta +12 -6
  57. package/templates/nest/src/simpleapp/generate/processors/simpleapp.processor.ts.eta +120 -19
  58. package/templates/nest/src/simpleapp/generate/types/schema.type.ts.eta +3 -1
  59. package/templates/nest/src/simpleapp/generate/types/simpleapp.type.ts.eta +1 -0
  60. package/templates/nest/src/simpleapp/profile/profile.controller.ts.eta +19 -0
  61. package/templates/nest/src/simpleapp/profile/profile.service.ts.eta +30 -8
  62. package/templates/nest/src/simpleapp/simpleapp.module.ts.eta +2 -1
  63. package/templates/nuxt/assets/css/calendar.css._eta +3 -0
  64. package/templates/nuxt/assets/css/style.css._eta +1 -1
  65. package/templates/nuxt/assets/images/unknown.png.eta +0 -0
  66. package/templates/nuxt/assets/primevue/passthrough.ts._eta +6 -1
  67. package/templates/nuxt/components/button/ButtonAction.vue._eta +40 -39
  68. package/templates/nuxt/components/button/ButtonDanger.vue._eta +11 -3
  69. package/templates/nuxt/components/button/ButtonDefault.vue._eta +11 -3
  70. package/templates/nuxt/components/button/ButtonPrimary.vue._eta +9 -3
  71. package/templates/nuxt/components/button/ButtonSecondary.vue._eta +33 -0
  72. package/templates/nuxt/components/button/ButtonText.vue._eta +9 -5
  73. package/templates/nuxt/components/button/ButtonWarning.vue._eta +11 -3
  74. package/templates/nuxt/components/calendar/CalendarInput.vue.eta +4 -3
  75. package/templates/nuxt/components/calendar/CalendarSmall.vue.eta +33 -16
  76. package/templates/nuxt/components/chart/card.vue._eta +1 -1
  77. package/templates/nuxt/components/debug/DebugDocumentData.vue.eta +36 -26
  78. package/templates/nuxt/components/event/EventDocumentViewer.vue._eta +36 -13
  79. package/templates/nuxt/components/form/FormBranch.vue._eta +52 -5
  80. package/templates/nuxt/components/form/FormDocnoformat.vue.eta +14 -10
  81. package/templates/nuxt/components/form/FormUser.vue._eta +1 -1
  82. package/templates/nuxt/components/form/user/FormUserPermission.vue.eta +77 -59
  83. package/templates/nuxt/components/header/HeaderSelectBranch.vue.eta +42 -35
  84. package/templates/nuxt/components/image/ImageAvatar.vue.eta._vue +30 -0
  85. package/templates/nuxt/components/image/ImageOrganization.vue.eta.vue +7 -5
  86. package/templates/nuxt/components/image/ImageToBase64Uploader.vue.eta.vue +67 -50
  87. package/templates/nuxt/components/list/ListDocumentTable.vue.eta +20 -12
  88. package/templates/nuxt/components/list/ListView.vue.eta +64 -35
  89. package/templates/nuxt/components/overlay/OverlayPanelWithToolBar.vue.eta +5 -4
  90. package/templates/nuxt/components/overlay/OverlayViewer.vue.eta +8 -8
  91. package/templates/nuxt/components/page/PageDocList.vue.eta +36 -13
  92. package/templates/nuxt/components/renderer/RendererDate.vue.eta +8 -2
  93. package/templates/nuxt/components/renderer/RendererDateTime.vue.eta +7 -1
  94. package/templates/nuxt/components/renderer/RendererDocHistories.vue.eta +56 -0
  95. package/templates/nuxt/components/renderer/RendererForeignKey.vue.eta +9 -8
  96. package/templates/nuxt/components/renderer/RendererLink.vue.eta +7 -4
  97. package/templates/nuxt/components/renderer/RendererMoney.vue.eta +25 -17
  98. package/templates/nuxt/components/renderer/RendererTime.vue.eta +7 -1
  99. package/templates/nuxt/components/renderer/RendererViewer.vue.eta +19 -9
  100. package/templates/nuxt/components/select/SelectTemplate.vue.eta +47 -21
  101. package/templates/nuxt/components/session/SessionBlock.vue.eta +44 -46
  102. package/templates/nuxt/components/simpleApp/SimpleAppAutocomplete.vue.eta +24 -15
  103. package/templates/nuxt/components/simpleApp/SimpleAppCalendarInput.vue.eta +64 -0
  104. package/templates/nuxt/components/simpleApp/SimpleAppChildrenList.vue.eta +16 -8
  105. package/templates/nuxt/components/simpleApp/SimpleAppDocumentNo.vue.eta +8 -8
  106. package/templates/nuxt/components/simpleApp/SimpleAppFieldContainer.vue.eta +1 -1
  107. package/templates/nuxt/components/simpleApp/SimpleAppFormToolBar.vue._eta +66 -22
  108. package/templates/nuxt/components/simpleApp/SimpleAppInput.vue.eta +89 -168
  109. package/templates/nuxt/components/simpleApp/SimpleAppInputTable.vue.eta +43 -40
  110. package/templates/nuxt/components/simpleApp/SimpleAppUserPicker.vue.eta +387 -0
  111. package/templates/nuxt/components/text/TextDocStatus.vue._eta +22 -0
  112. package/templates/nuxt/components/user/UserButtonCreateTenant.vue._eta +13 -15
  113. package/templates/nuxt/components/user/UserButtonPermissionInfo.vue.eta +127 -93
  114. package/templates/nuxt/components/user/UserTenantPicker.vue.eta +1 -1
  115. package/templates/nuxt/composables/date.generate.ts.eta +105 -8
  116. package/templates/nuxt/composables/getDocument.generate.ts.eta +8 -6
  117. package/templates/nuxt/composables/getOpenApi.generate.ts.eta +58 -10
  118. package/templates/nuxt/composables/getUserStore.generate.ts.eta +37 -5
  119. package/templates/nuxt/composables/goTo.generate.ts.eta +14 -1
  120. package/templates/nuxt/composables/graphquery.generate.ts.eta +20 -2
  121. package/templates/nuxt/composables/recently.generate.ts.eta +16 -0
  122. package/templates/nuxt/composables/roles.generate.ts.eta +8 -13
  123. package/templates/nuxt/composables/stringHelper.generate.ts.eta +52 -0
  124. package/templates/nuxt/composables/sysmessage.generate.ts.eta +1 -1
  125. package/templates/nuxt/pages/[xorg]/{organization.vue.eta → organization.vue._eta} +38 -9
  126. package/templates/nuxt/pages/[xorg]/user.vue.eta +12 -9
  127. package/templates/nuxt/pages/login.vue._eta +4 -1
  128. package/templates/nuxt/plugins/20.simpleapp-userstore.ts.eta +45 -26
  129. package/templates/nuxt/plugins/70.recently.ts.eta +55 -0
  130. package/templates/nuxt/providers/my-provider.ts.eta +22 -0
  131. package/templates/nuxt/server/api/[xorg]/{[...].ts.eta → [...].ts._eta} +47 -21
  132. package/templates/nuxt/simpleapp/generate/clients/SimpleAppClient.ts.eta +44 -3
  133. package/templates/nuxt/types/events.ts.eta +3 -2
  134. package/templates/nuxt/types/others.ts.eta +11 -1
  135. package/templates/nuxt/types/schema.ts.eta +3 -1
  136. package/templates/nuxt/types/simpleappinput.ts.eta +1 -1
  137. package/templates/nuxt/types/user.ts.eta +8 -7
  138. package/templates/project/jsonschemas/branch.json._eta +1 -0
  139. package/templates/project/jsonschemas/invoice.json._eta +4 -3
  140. package/templates/project/jsonschemas/organization.json._eta +2 -2
  141. package/templates/project/lang/default._json +3 -2
  142. package/tsconfig.tsbuildinfo +1 -1
  143. package/templates/nuxt/components/image/ImageAvatar.vue.eta.vue +0 -38
  144. /package/templates/nuxt/pages/[xorg]/mobile/docnoformat/{index.vue.eta → index.vue.etaxxx} +0 -0
  145. /package/templates/nuxt/pages/[xorg]/mobile/{index.vue._eta → index.vue._etaxxx} +0 -0
  146. /package/templates/nuxt/pages/[xorg]/mobile/organization/{[id].vue._eta → [id].vue._etaxxx} +0 -0
  147. /package/templates/nuxt/pages/[xorg]/mobile/{pickgroup.vue._eta → pickgroup.vue._etaxxx} +0 -0
  148. /package/templates/nuxt/pages/[xorg]/mobile/user/{index.vue.eta → index.vue.etaxxx} +0 -0
@@ -0,0 +1,33 @@
1
+ import {SchemaType,RESTMethods,IsolationType} from '../type'
2
+
3
+ export const permission:SchemaType ={
4
+ type: "object",
5
+ "x-simpleapp-config":{
6
+ documentType:'hist',
7
+ documentName:'histories',
8
+ isolationType:IsolationType.tenant
9
+ },
10
+ required:["document"],
11
+ properties: {
12
+ _id:{type:'string'},
13
+ created:{type:'string'},
14
+ updated:{type:'string'},
15
+ createdBy:{type:'string'},
16
+ updatedBy:{type:'string'},
17
+ tenantId: {type:'integer',default:1,minimum:0},
18
+ orgId: {type:'integer',default:1,minimum:0 },
19
+ branchId: {type:'integer',default:1,minimum:0 },
20
+ document:{type:'string',minLength:3},
21
+ histories:{
22
+ type:"array",
23
+ items:{
24
+ type:"object",
25
+ properties:{
26
+ datetime:{type:"string",format:"datetime"},
27
+ uid:{type:"string",format:"uuid"},
28
+ action:{type:"string",minLength:3},
29
+ }
30
+ }
31
+ }
32
+ }
33
+ }
@@ -6,4 +6,5 @@ export {permission} from './permission'
6
6
  export {autoincreament} from './autoincreament'
7
7
  export {docnoformat} from './docnoformat'
8
8
  export {systemmessage} from './systemmessage'
9
- export {keyvaluepair} from './keyvaluepair'
9
+ export {keyvaluepair} from './keyvaluepair'
10
+ export {webhook} from './webhook'
@@ -14,14 +14,14 @@ export const organization:SchemaType ={
14
14
  additionalApis:[{
15
15
  "action":"getlogo",
16
16
  "entryPoint":"logo",
17
- "requiredRole":[],
17
+ "requiredRole":["User"],
18
18
  "method":RESTMethods.get,
19
19
  "responseType":"String",
20
20
  "description":"obtain avatar base64 jpg image"
21
21
  },{
22
22
  "action":"uploadlogo",
23
23
  "entryPoint":"logo",
24
- "requiredRole":[],
24
+ "requiredRole":["Admin"],
25
25
  "method":RESTMethods.post,
26
26
  "schema":"KeyValue",
27
27
  "responseType":"String",
@@ -47,6 +47,10 @@ export const user:SchemaType ={
47
47
  email: {type: "string",minLength:10,format: "email"},
48
48
  active: {type: "boolean",default:true},
49
49
  description: {type:"string"},
50
- lastActivity: {type: "string",description:"capture ISO8601 last api call"}
50
+ lastActivity: {type: "string",description:"capture ISO8601 last api call"},
51
+ completedTours: {
52
+ type: "array",
53
+ items: { "type": "string", "examples": ["mainpage"] }
54
+ }
51
55
  }
52
56
  }
@@ -0,0 +1,31 @@
1
+ import {SchemaType,RESTMethods,IsolationType} from '../type'
2
+
3
+ export const webhook:SchemaType = {
4
+ type: "object",
5
+ "x-simpleapp-config":{
6
+ documentType:'webhook',
7
+ documentName:'webhook',
8
+ isolationType:IsolationType.tenant,
9
+ uniqueKey:'documentName',
10
+ documentTitle:'documentName',
11
+ pageType:"crud",
12
+ },
13
+ required:["documentName","url"],
14
+ properties: {
15
+ _id:{type:'string'},
16
+ created:{type:'string'},
17
+ updated:{type:'string'},
18
+ createdBy:{type:'string'},
19
+ updatedBy:{type:'string'},
20
+ tenantId: {type:'integer',default:1,minimum:0 },
21
+ orgId: {type:'integer',default:1,minimum:0 },
22
+ branchId: {type:'integer',default:1,minimum:0 },
23
+ documentName:{type:"string",minLength:3,},
24
+ url: {type: "string", format:'uri'},
25
+ secret: {type: "string"},
26
+ description: {type: "string",format:"text"},
27
+ active: {type: "boolean", default:true},
28
+ setting:{type:"string",format:"text"}
29
+ }
30
+ }
31
+
package/src/framework.ts CHANGED
@@ -16,6 +16,7 @@ let config = {
16
16
  "mongoConnectStr":'mongodb://127.0.0.1:27017/simpleapp',
17
17
  "mongoDbName":'simpleapp',
18
18
  "frontendFolder":"./frontend",
19
+ "splitMobilePage":false,
19
20
  "frontendPort":"8080",
20
21
  "printFormatDir":"./printformats",
21
22
  "additionalNestModules":["cloudapi","printapi"],
@@ -163,10 +164,10 @@ export const prepareNuxt = (callback:Function)=>{
163
164
  const targetfolder = config.frontendFolder
164
165
  if(!fs.existsSync(`${targetfolder}/.env`)){
165
166
  //asume no environment. prepare now
166
- exec(`cd ${targetfolder};pnpm install;pnpm install -D @nuxtjs/apollo@next dayjs-nuxt @nuxtjs/device @nuxtjs/color-mode @types/json-schema @nuxtjs/i18n@next nuxt-primevue @nuxtjs/tailwindcss @types/jsonpath @sidebase/nuxt-auth @types/node @vueuse/nuxt @sidebase/nuxt-auth @vueuse/core prettier `, (error, stdout, stderr)=>{
167
+ exec(`cd ${targetfolder};pnpm install;pnpm install -D @nuxtjs/apollo@next dayjs-nuxt @nuxtjs/device @nuxtjs/color-mode @types/json-schema @nuxtjs/i18n@next nuxt-primevue@latest @nuxtjs/tailwindcss @types/jsonpath @sidebase/nuxt-auth @types/node @vueuse/nuxt @sidebase/nuxt-auth @vueuse/core prettier `, (error, stdout, stderr)=>{
167
168
  //;pnpm install
168
169
  console.log(error, stdout, stderr)
169
- exec(`cd ${targetfolder};pnpm install --save vue-pdf-embed dayjs pusher-js country-code-dateformat chart.js tailwind-merge @iconify-json/heroicons json-schema @vueuse/core ts-md5 primeicons memory-cache jsonpath pinia @pinia/nuxt @nuxt/kit lodash @types/lodash @darkwolf/base64url next-auth@4.21.1 @darkwolf/base64url @nuxt/ui ajv ajv-formats ajv-errors dotenv @fullcalendar/core @fullcalendar/vue3 quill prettier axios json-schema mitt `, (error, stdout, stderr)=>{
170
+ exec(`cd ${targetfolder};pnpm install --save vue-camera-lib vue-pdf-embed dayjs pusher-js country-code-dateformat chart.js tailwind-merge @iconify-json/heroicons json-schema @vueuse/core ts-md5 primeicons memory-cache jsonpath pinia @pinia/nuxt @nuxt/kit lodash @types/lodash @darkwolf/base64url next-auth@4.21.1 @darkwolf/base64url @nuxt/ui ajv ajv-formats ajv-errors dotenv @fullcalendar/core @fullcalendar/vue3 quill prettier axios json-schema mitt `, (error, stdout, stderr)=>{
170
171
  console.log(error, stdout, stderr)
171
172
 
172
173
  // fs.mkdirSync(`${targetfolder}/assets/css/`,{recursive:true})
package/src/generate.ts CHANGED
@@ -237,6 +237,9 @@ const generateSchema = ( docname: string,
237
237
  // log.warn("skip file: ",filename)
238
238
  continue;
239
239
  }
240
+
241
+ // no turn on split mobile url, skip create mobile page
242
+ if(!configs?.splitMobilePage && filename.includes('mobile.')) continue
240
243
  if(foldertype=='nest'){
241
244
  const arrfilename:string[] = filename.split('.')
242
245
  const filecategory = arrfilename[0]
@@ -315,7 +318,16 @@ const generateSchema = ( docname: string,
315
318
  as: `Form${_.upperFirst(docname)}.vue`,
316
319
  validate: validateWritePage
317
320
  },
318
-
321
+ 'pages.mobile.[id].vue.eta': {
322
+ to:`pages/[xorg]/mobile/${docname}`,
323
+ as:'[id].vue',
324
+ validate: validateWritePage
325
+ },
326
+ 'pages.mobile.landing.vue.eta':{
327
+ to:`pages/[xorg]/mobile/${docname}`,
328
+ as:`index.vue`,
329
+ validate: validateWritePage
330
+ },
319
331
  'component.select.vue.eta': {
320
332
  to:'components/select',
321
333
  as: `Select${_.upperFirst(docname)}.vue`,
@@ -336,16 +348,7 @@ const generateSchema = ( docname: string,
336
348
  as:`../${docname}.vue`,
337
349
  validate: validateWritePage
338
350
  },
339
- 'pages.mobile.[id].vue.eta': {
340
- to:`pages/[xorg]/mobile/${docname}`,
341
- as:'[id].vue',
342
- validate: validateWritePage
343
- },
344
- 'pages.mobile.landing.vue.eta': {
345
- to:`pages/[xorg]/mobile/${docname}`,
346
- as:`index.vue`,
347
- validate: validateWritePage
348
- },
351
+
349
352
  'simpleapp.doc.ts.eta': {
350
353
  to:`simpleapp/docs`,
351
354
  as:`${capname}Doc.ts`,
@@ -367,25 +370,42 @@ const generateSchema = ( docname: string,
367
370
  }
368
371
  },
369
372
  }
373
+
374
+
375
+ // if(configs?.splitMobilePage){
376
+ // mapfiles['pages.mobile.[id].vue.eta'] = {
377
+ // to:`pages/[xorg]/mobile/${docname}`,
378
+ // as:'[id].vue',
379
+ // validate: validateWritePage
380
+ // }
381
+ // mapfiles['pages.mobile.landing.vue.eta'] = {
382
+ // to:`pages/[xorg]/mobile/${docname}`,
383
+ // as:`index.vue`,
384
+ // validate: validateWritePage
385
+ // }
386
+ // }
370
387
 
371
- const target = mapfiles[filename]
388
+ const target = mapfiles[filename]
389
+ console.log(target);
372
390
  const targetfolder = `${generateTypes[foldertype]}/${target.to}`
373
391
  const targetfile = `${targetfolder}/${target.as}`
374
-
392
+
393
+ console.log("targetfile",targetfile);
375
394
  if(jsonschemas[docname][X_SIMPLEAPP_CONFIG]['pageType'] && !existsSync(targetfolder)){
395
+ console.log("Mkdir",targetfolder)
376
396
  mkdirSync(targetfolder,{recursive:true})
377
397
  }
378
398
 
379
399
 
380
400
  const isexists = existsSync(targetfile)
381
401
  const iswrite:boolean = target.validate(targetfile,isexists)
382
- log.info("process: ",targetfile)
402
+ log.info("iswrite: ",iswrite)
383
403
 
384
404
  if(iswrite){
385
405
  const filecontent = eta.render(templatepath, variables)
386
406
  writeFileSync(targetfile,filecontent);
387
407
  }
388
-
408
+ console.log("complete, go to next file")
389
409
 
390
410
 
391
411
 
@@ -42,6 +42,10 @@ export const readJsonSchemaBuilder = async (docname: string,orijsondata:JSONSche
42
42
  }
43
43
 
44
44
  if(schemaconfigs.generateDocumentNumber){
45
+ if(!schemaconfigs.docNoPattern){
46
+ log.error(docname+" generateDocumentNumber=true but undefine docNoPattern")
47
+ throw new Error(docname+" generateDocumentNumber=true but undefine docNoPattern")
48
+ }
45
49
  const tmp = {
46
50
  type: "object",
47
51
  "x-foreignkey":"docnoformat",
@@ -58,8 +62,12 @@ export const readJsonSchemaBuilder = async (docname: string,orijsondata:JSONSche
58
62
  const apis = schemaconfigs.additionalApis
59
63
  for(let i =0 ; i< apis.length; i++ ){
60
64
  if(!apis[i].responseType){
61
- log.error("Undefine responseType in api "+ apis[i].action)
62
- throw new Error("Undefine responseType in api "+ apis[i].action)
65
+ log.error(docname +" undefine responseType in api "+ apis[i].action)
66
+ throw new Error(docname+ " undefine responseType in api "+ apis[i].action)
67
+ }
68
+ if(!Array.isArray(apis[i].requiredRole) || apis[i].requiredRole.length==0 ){
69
+ log.error(docname+ " undefine requiredRole in api "+ apis[i].action)
70
+ throw new Error(docname +" undefine requiredRole in api "+ apis[i].action)
63
71
  }
64
72
  }
65
73
  }
package/src/type.ts CHANGED
@@ -140,10 +140,12 @@ export type SchemaConfig = {
140
140
  documentTitle?:string
141
141
  loseDataIsolation?:boolean
142
142
  generateDocumentNumber?:boolean
143
+ docNoPattern?:string
143
144
  documentDate?:string
144
145
  allStatus?:DocumentStatus[]
145
146
  additionalApis?:DocumentApi[]
146
147
  additionalAutoCompleteFields ?: string[]
148
+ search?:string[]
147
149
  // libs?:ImportLibs[] // both process class and frontend client class will import same lib
148
150
  formulas?: Formula[]
149
151
  documentType: string
@@ -149,19 +149,40 @@ export class <%= it.typename %>Controller extends SimpleAppAbstractController<
149
149
  }
150
150
 
151
151
 
152
+ <% if(simpleappconfig.search !==undefined){%>
153
+ @Get('/fulltextsearch/:keyword')
154
+ @HttpCode(200)
155
+ @Roles(Role.SuperAdmin, Role.SuperUser, Role.<%= `${it.typename}_search`%>)
156
+ @ApiResponse({
157
+ status: 200,
158
+ description: 'success',
159
+ type: [schemas.<%= it.typename%>]
160
+ })
161
+ @ApiResponse({ status: 400, description: 'bad request' })
162
+ @ApiResponse({ status: 500, description: 'internal error' })
163
+ @ApiOperation({ operationId: 'runFullTextSearch' })
164
+ async fulltextsearch(
165
+ @AppUser() appuser: UserContext,
166
+ @Param('keyword') keyword:string
167
+ ) {
168
+ return await this._fulltextsearch(appuser, keyword);
169
+ }
170
+ <%}%>
171
+
172
+
152
173
  /***************************** begin additionalAPI definations *****************************************/
153
174
 
154
175
  <% for(let i=0;i<it.apiSettings.length;i++){%>
155
176
  <% let api = it.apiSettings[i] %>
156
177
  <%~ `@${capitalizeFirstLetter(api.method)}('${api.entryPoint}')`%>
157
178
  <%if(superadmindoctype.includes(it.doctype)){%>
158
- @Roles(Role.SuperAdmin,Role.<%= `${it.typename}_${api.action}`%>,
179
+ @Roles(Role.SuperAdmin,
159
180
  <%if(api.requiredRole && api.requiredRole.length>0) { %>
160
181
  <% for(let r=0;r<api.requiredRole.length;r++){%>Role.<%=api.requiredRole[r]%>,<%}%>
161
182
  <%}%>
162
183
  )
163
184
  <%}else{%>
164
- @Roles(Role.SuperAdmin,Role.SuperUser,Role.<%= `${it.typename}_${api.action}`%>,
185
+ @Roles(Role.SuperAdmin,Role.SuperUser,
165
186
  <%if(api.requiredRole && api.requiredRole.length>0) { %>
166
187
  <% for(let r=0;r<api.requiredRole.length;r++){%>Role.<%=api.requiredRole[r]%>,<%}%>
167
188
  <%}%>
@@ -46,7 +46,7 @@ export const <%= capitalizeFirstLetter(it.name) %>MongoSchema = new Schema(schem
46
46
  <%}%>
47
47
  <%}%>
48
48
 
49
- <% if(config['uniqueKeys']) {%>
49
+ <% if(config['uniqueKeys']!==undefined) {%>
50
50
  <% for(let i=0; i< config['uniqueKeys'].length; i++ ){ %>
51
51
  <% const keys = config['uniqueKeys'][i] %>
52
52
  .index({
@@ -59,6 +59,14 @@ export const <%= capitalizeFirstLetter(it.name) %>MongoSchema = new Schema(schem
59
59
  <% } %>
60
60
  <%}%>
61
61
 
62
+ <% if(config['search']) {%>
63
+ .index({
64
+ <% for(let i=0; i< config['search'].length; i++ ){ %>
65
+ <% const key = config['search'][i] %>
66
+ '<%= key %>' : 'text',
67
+ <% } %>
68
+ },{name:"<%= it.typename %>TextIndex"})
69
+ <%}%>
62
70
 
63
71
 
64
72
  <% if(it.foreignkeys){%>
@@ -77,13 +77,13 @@ export class <%= it.typename %>Resolver {
77
77
  <% let api = it.apiSettings[i] %>
78
78
  <% if(api.method!='get') continue %>
79
79
  <%if(superadmindoctype.includes(it.doctype)){%>
80
- @Roles(Role.SuperAdmin,Role.<%= `${it.typename}_${api.action}`%>,
80
+ @Roles(Role.SuperAdmin,
81
81
  <%if(api.requiredRole && api.requiredRole.length>0) { %>
82
82
  <% for(let r=0;r<api.requiredRole.length;r++){%>Role.<%=api.requiredRole[r]%>,<%}%>
83
83
  <%}%>
84
84
  )
85
85
  <%}else{%>
86
- @Roles(Role.SuperAdmin,Role.SuperUser,Role.<%= `${it.typename}_${api.action}`%>,
86
+ @Roles(Role.SuperAdmin,Role.SuperUser,
87
87
  <%if(api.requiredRole && api.requiredRole.length>0) { %>
88
88
  <% for(let r=0;r<api.requiredRole.length;r++){%>Role.<%=api.requiredRole[r]%>,<%}%>
89
89
  <%}%>
@@ -11,25 +11,25 @@
11
11
  */
12
12
 
13
13
  import {<%= it.typename %>} from '~/simpleapp/generate/types'
14
+ import {FormCrudEvent} from "~/types"
14
15
  const doc = useNuxtApp().$<%= it.typename %>Doc()
15
16
  const _id = getPathPara('id','')
16
17
 
17
- const after = (actionName: string, data: <%= it.typename %>) => {
18
- console.log("<%= it.typename %> capture after emits ", actionName)
18
+ const after = (actionName: FormCrudEvent, data: <%= it.typename %>) => {
19
19
  switch (actionName) {
20
- case "exit":
20
+ case FormCrudEvent.exit:
21
21
  goTo(doc.getDocName());
22
22
  break;
23
- case "create":
23
+ case FormCrudEvent.create:
24
24
  goTo(doc.getDocName(), data._id);
25
25
  refreshDocumentList(doc.getDocName())
26
26
  useNuxtApp().$event('CloseDialog',doc.getDocName().toLowerCase())
27
27
  break;
28
- case "update":
28
+ case FormCrudEvent.update:
29
29
  refreshDocumentList(doc.getDocName());
30
- useNuxtApp().$event('CloseDialog',doc.getDocName().toLowerCase())
30
+ //useNuxtApp().$event('CloseDialog',doc.getDocName().toLowerCase())
31
31
  break;
32
- case "delete":
32
+ case FormCrudEvent.delete:
33
33
  goTo(doc.getDocName(), "new");
34
34
  refreshDocumentList(doc.getDocName())
35
35
  useNuxtApp().$event('CloseDialog',doc.getDocName().toLowerCase())
@@ -131,7 +131,6 @@
131
131
  <%})%>
132
132
  </div>
133
133
  </SimpleAppForm>
134
- <DebugDocumentData v-model="data" :label="doc.getDocName()"/>
135
134
  </div>
136
135
  </template>
137
136
 
@@ -161,9 +160,7 @@ const newData = () => doc.setNew()
161
160
  const getRecord = async () => {
162
161
  if(id.value && id.value != 'new'){
163
162
  await doc.getById(id.value)
164
- }else{
165
- newData()
166
- }
163
+ }
167
164
  }
168
165
 
169
166
  getRecord()
@@ -4,26 +4,7 @@
4
4
  <PageDocList :document="doc" :columns="columns" :data="docdata" :sorts="sorts">
5
5
  <template #mobileList="{index,item}">
6
6
  </template>
7
- <template #dataTableColumns>
8
- <%Object.keys(it.jsonschema.properties).forEach(function(key) { %>
9
- <%let obj=it.jsonschema.properties[key] %>
10
- <%let config=it.jsonschema['x-simpleapp-config'] %>
11
- <%if(skipcolumns.indexOf(key)>=0){%>
12
- <%} else if(config['uniqueKey'] && (config['uniqueKey']==key || config['documentTitle']==key) ){%>
13
- <Column #body="{index,data}" :header="t('<%=key%>')">
14
- <RendererLink :value="data" :setting="{path:'<%=it.name%>'}" :fields="['<%=key%>']">{{ data.<%=key%> }}</RendererLink>
15
- </Column>
16
-
17
- <%} else if(['string','number','integer','boolean'].indexOf(obj.type)>=0){%>
18
- <Column #body="{index,data}" :header="t('<%=key%>')">
19
- {{data.<%=key%>}}
20
- </Column>
21
- <%} else if(obj.type =='object' && obj['x-foreignkey'] ){%>
22
- <Column #body="{index,data}" :header="t('<%=key%>')">
23
- <RendererViewer :value="data.<%=key%>" :setting="{documentName:'<%=obj["x-foreignkey"]%>'}" :fields="['<%=key%>']">{{ data.label }}</RendererViewer>
24
- </Column>
25
- <%}%>
26
- <%})%>
7
+ <template #dataTableColumns>
27
8
  </template>
28
9
  <template #default><div><NuxtPage :_id="id ?? 'new'"/></div></template>
29
10
  </PageDocList>
@@ -121,7 +121,7 @@ export class <%= it.typename%>Client extends SimpleAppClient<openapi.<%= it.type
121
121
 
122
122
 
123
123
  /*****************************begin x-document-api code*****************************************/
124
-
124
+
125
125
  <%for(let i=0;i<it.apiSettings.length;i++){%>
126
126
  <% let api = it.apiSettings[i] %>
127
127
  async run<%=capitalizeFirstLetter(api.action)%>(
@@ -299,4 +299,11 @@ export class <%= it.typename%>Client extends SimpleAppClient<openapi.<%= it.type
299
299
  }
300
300
  <%}%>
301
301
  /***************************** end document status code*****************************************/
302
+
303
+ <%if(it.jsonschema['x-simpleapp-config']['search']!==undefined){%>
304
+ async runFullTextSearh(keyword:string) {
305
+ const response = await this.docapi.runFullTextSearch(keyword)
306
+ return response.data
307
+ }
308
+ <%}%>
302
309
  }
@@ -17,4 +17,6 @@ export class ApiSearchBody{
17
17
  fields: [Object];
18
18
  @ApiProperty({"type":()=>[Object],"required":true,"examples":['[[ "field1", "asc" ]]'],"default":[[ 'field1', 'asc' ]]} )
19
19
  sorts: [Object];
20
+ @ApiProperty({type: () => Object,required: false,})
21
+ lookup: Object
20
22
  }
@@ -8,7 +8,14 @@ export const alldocuments:any[] = [
8
8
  <%for(let i=0; i<it.modules.length;i++){ %>
9
9
  <% const d = it.modules[i] %>
10
10
  <% const conf = d.schema["x-simpleapp-config"] %>
11
- {docName:'<%= d['docname'] %>',docType:'<%= d['doctype'].toUpperCase()%>',page: '<%=d['pagetype']%>', isolationType:'<%=conf['isolationType']%>',
12
- documentDate:'<%=conf['documentDate']??""%>', docNumber:<%=conf['generateDocumentNumber']??false%>},
11
+ {
12
+ docName:'<%= d['docname'] %>',
13
+ docType:'<%= d['doctype'].toUpperCase()%>',
14
+ page: '<%=d['pagetype']%>',
15
+ isolationType:'<%=conf['isolationType']%>',
16
+ documentDate:'<%=conf['documentDate']??""%>',
17
+ docNumber:<%=conf['generateDocumentNumber']??false%>,
18
+ docNoPattern: '<%=conf['docNoPattern']%>'
19
+ },
13
20
  <%}%>
14
21
  ]
@@ -11,6 +11,11 @@ export enum Role {
11
11
  SuperUser = 'suerpuser', //reserved, plan use by support
12
12
  TenantOwner = 'tenantowner', //tenant owner/creator
13
13
  User = 'user',
14
+ //role generated from groups
15
+ <% Object.getOwnPropertyNames(it.allroles).forEach((key)=>{%>
16
+ <%= capitalizeFirstLetter(key) %> = '<%=key%>',
17
+ <%})%>
18
+ //role generate from schema
14
19
  <% for(let i=0;i<it.modules.length; i++){ %>
15
20
  <% const m = it.modules[i] %>
16
21
  <%=m.docname%>_access='<%=m.docname%>:access',
@@ -26,17 +31,7 @@ export enum Role {
26
31
  <%if(m.schema['x-simpleapp-config']['printFormats']){%>
27
32
  <%=m.docname%>_print='<%=m.docname%>:print',
28
33
  <%}%>
29
-
30
-
31
- <% if(m.api && m.api.length >0) {%>
32
-
33
- <% for(let j=0;j<m.api.length; j++){ %>
34
- <%let api = m.api[j]%>
35
34
 
36
- <%=m.docname%>_<%=api.action%>='<%=m.docname%>:<%=api.action%>',
37
-
38
- <%}%>
39
- <%}%>
40
35
  <% if(m.schema['x-simpleapp-config']['allStatus'] && m.schema['x-simpleapp-config']['allStatus'].length >0) {%>
41
36
  <%let allstatus = m.schema['x-simpleapp-config']['allStatus']%>
42
37
  <% for(let j=0;j<allstatus.length; j++){ %>
@@ -9,6 +9,7 @@ import {Role} from './roles.enum'
9
9
  <% Object.getOwnPropertyNames(it.allroles).forEach((key)=>{ %>
10
10
  export const <%=key%>=()=>[
11
11
  Role.User,
12
+ Role.<%=capitalizeFirstLetter(key)%>,
12
13
  <%for(let i=0; i <it.allroles[key].length; i++){%>
13
14
  Role.<%=it.allroles[key][i]%>,
14
15
  <%}%>
@@ -0,0 +1,50 @@
1
+ import {
2
+ BadRequestException,
3
+ Injectable,
4
+ InternalServerErrorException,
5
+ Logger,
6
+ NotFoundException,
7
+ } from '@nestjs/common';
8
+ import { EventEmitter2, OnEvent } from '@nestjs/event-emitter';
9
+ import { UserContext } from './user.context';
10
+ import { WebhookService } from 'src/simpleapp/services/webhook.service';
11
+ @Injectable()
12
+ export class RunWebhookService {
13
+ public constructor(private webhookService: WebhookService) {}
14
+ @OnEvent('webhook')
15
+ async runWebhook(
16
+ appuser: UserContext,
17
+ documentName: string,
18
+ actionName: string,
19
+ data?: any,
20
+ ) {
21
+ let subscribeall=false
22
+ const webhooks = await this.webhookService.search(appuser, {
23
+ documentName: documentName,
24
+ active: true,
25
+ });
26
+ if (webhooks.length == 0) return;
27
+
28
+ const webhook = webhooks[0];
29
+ let subscribes:string[] = []
30
+ if(webhook.setting=='' || webhook.setting===undefined){
31
+ subscribeall=true
32
+ }else{
33
+ subscribes= JSON.parse(webhook.setting)
34
+ }
35
+
36
+ if(subscribes.includes(actionName)){
37
+ const webhookurl = webhook.url;
38
+ const secretkey = webhook.secret;
39
+ const req = await fetch(webhookurl, {
40
+ method: 'POST',
41
+ headers: { 'x-apiKey': secretkey },
42
+ body: JSON.stringify(data),
43
+ });
44
+ const statusCode = req.status
45
+ const body = req.body
46
+
47
+ }
48
+
49
+ }
50
+ }
@@ -91,6 +91,7 @@ export class UserContext {
91
91
  getTenantId = () => this.tenantId;
92
92
  getOrgId = () => this.orgId;
93
93
  getBranchId = () => this.branchId;
94
+ getBranchCode = () => this.branchCode;
94
95
  getEmail = () => this.email;
95
96
  getTimeZone = () => this.timeZone;
96
97
  getCountry = () => this.country;
@@ -218,7 +219,7 @@ export class UserContext {
218
219
  }
219
220
  }
220
221
 
221
- userinfo.branchRecordId = myperm.currentbranch[0].branchRecordId;
222
+ userinfo.branchRecordId = myperm.currentbranch[0]._id;
222
223
  userinfo.branchCode = myperm.currentbranch[0].branchCode;
223
224
  userinfo.branchName = myperm.currentbranch[0].branchName;
224
225
  userinfo.orgRecordId = myperm.currentorg[0]._id;
@@ -258,7 +259,7 @@ export class UserContext {
258
259
  const tokeninfo = jwt.decode(tokenstr);
259
260
  this.token = tokenstr;
260
261
  this.uid = tokeninfo?.sub ?? '';
261
- this.email = tokeninfo?.email ??'';
262
+ this.email = tokeninfo?.email ?? '';
262
263
  this.uname = tokeninfo?.preferred_username ?? '';
263
264
  this.fullname = tokeninfo?.name ?? [];
264
265
  this.ssoACL = tokeninfo?.resource_access ?? [];
@@ -535,7 +536,7 @@ export class UserContext {
535
536
  };
536
537
 
537
538
  searchInsertedRecordId(collection: string, _id: string) {
538
- if(!this.modifiedRecords.createds[collection]) return undefined
539
+ if (!this.modifiedRecords.createds[collection]) return undefined;
539
540
  return this.modifiedRecords.createds[collection].find(
540
541
  (item) => item === _id,
541
542
  );
@@ -724,4 +725,13 @@ export class UserContext {
724
725
  }
725
726
  return data;
726
727
  }
728
+
729
+ offsetDate(date: string): string {
730
+ const timestamp = new Date(date).getTime();
731
+ const offsets = this.getOffsetMinute() * 60000;
732
+ const isodate =
733
+ new Date(timestamp + offsets).toISOString().split('.')[0] + 'Z';
734
+ // console.log("Generate schedule ",date,":",appuser.getOffsetMinute()," => ",isodate)
735
+ return isodate;
736
+ }
727
737
  }
@@ -30,6 +30,7 @@ type ServiceType = {
30
30
  findIdThenPatch: Function;
31
31
  setData: Function;
32
32
  getAutoComplete: Function;
33
+ fullTextSearch:Function;
33
34
  };
34
35
 
35
36
  // @ApiTags(doctype)
@@ -50,15 +51,22 @@ export class SimpleAppAbstractController<
50
51
  async _list(appuser: UserContext) {
51
52
  return this.service.list(appuser);
52
53
  }
54
+ async _fulltextsearch(appuser: UserContext, keyword: string) {
55
+ return this.service.fullTextSearch(
56
+ appuser,
57
+ keyword
58
+ );
59
+ }
53
60
  async _search(appuser: UserContext, searchObject: SearchBody) {
54
61
  return this.service.search(
55
62
  appuser,
56
63
  searchObject['filter'],
57
64
  searchObject['fields'],
58
65
  searchObject['sorts'],
66
+ searchObject['lookup'],
59
67
  );
60
68
  }
61
- async _autocomplete(appuser: UserContext, keyword:string,data?:T) {
69
+ async _autocomplete(appuser: UserContext, keyword: string, data?: T) {
62
70
  return this.service.getAutoComplete(appuser, keyword, data);
63
71
  }
64
72
  async _findOne(appuser: UserContext, id: string) {