@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.
Files changed (46) hide show
  1. package/README.md +97 -12
  2. package/dist/framework.js +9 -3
  3. package/dist/framework.js.map +1 -1
  4. package/dist/generate.js +21 -4
  5. package/dist/generate.js.map +1 -1
  6. package/dist/index.js +4 -3
  7. package/dist/index.js.map +1 -1
  8. package/dist/processors/jsonschemabuilder.js +91 -15
  9. package/dist/processors/jsonschemabuilder.js.map +1 -1
  10. package/dist/type.js.map +1 -1
  11. package/documentation/designconcept.bpmn +349 -0
  12. package/documentation/documentation.png +0 -0
  13. package/documentation/infra.drawio +141 -0
  14. package/documentation/infra.png +0 -0
  15. package/documentation/management.drawio +57 -0
  16. package/documentation/stack.drawio +106 -0
  17. package/package.json +1 -1
  18. package/src/framework.ts +9 -3
  19. package/src/generate.ts +29 -6
  20. package/src/index.ts +4 -3
  21. package/src/processors/jsonschemabuilder.ts +113 -22
  22. package/src/type.ts +44 -1
  23. package/templates/basic/controller.eta +34 -17
  24. package/templates/basic/model.eta +2 -1
  25. package/templates/basic/pageindex.vue.eta +4 -3
  26. package/templates/basic/service.eta +2 -1
  27. package/templates/basic/simpleappclient.eta +23 -1
  28. package/templates/nest/SimpleAppService.eta +141 -70
  29. package/templates/nest/TenantMiddleware.eta +8 -13
  30. package/templates/nest/UserProvider.eta +127 -0
  31. package/templates/nest/Workflow.eta +75 -0
  32. package/templates/nest/app.controller.eta +12 -0
  33. package/templates/nest/app.module.eta +6 -2
  34. package/templates/nest/app.service.eta +8 -0
  35. package/templates/nest/nest.env.eta +7 -0
  36. package/templates/nuxt/components.debugdocdata.vue.eta +1 -1
  37. package/templates/nuxt/components.menus.vue.eta +43 -7
  38. package/templates/nuxt/composables.stringHelper.ts.eta +5 -0
  39. package/templates/nuxt/nuxt.config.ts.eta +1 -1
  40. package/templates/nuxt/pages.[xorg].index.vue.eta +13 -9
  41. package/templates/nuxt/pages.index.vue.eta +58 -8
  42. package/templates/nuxt/plugins.simpleapp.ts.eta +10 -1
  43. package/templates/nuxt/server.api.ts.eta +2 -1
  44. package/templates/nuxt/tailwind.css.eta +14 -1
  45. package/tsconfig.json +4 -1
  46. package/templates/nest/User.eta +0 -115
@@ -0,0 +1,75 @@
1
+ import { BPMNClient } from "bpmn-client";
2
+ import { UserProvider } from './UserProvider';
3
+ import { Injectable } from '@nestjs/common';
4
+
5
+ export type UserTaskActorOptions={
6
+ userId:string
7
+ actGroups?:string[]
8
+ actUsers?:string[]
9
+ }
10
+ @Injectable()
11
+ export class Workflow{
12
+ private static instance: Workflow;
13
+ server:BPMNClient
14
+
15
+ constructor(){
16
+ this.server= new BPMNClient(process.env.BPMN_HOST, process.env.BPMN_PORT, process.env.BPMN_API_KEY);
17
+ }
18
+ public static getInstance(): Workflow {
19
+ if (!Workflow.instance) {
20
+ Workflow.instance = new Workflow();
21
+ }
22
+ return Workflow.instance;
23
+ }
24
+
25
+ async executeWorkFlow(id: string, bpmnname: string, docstatus: string,data:any) {
26
+ const workflowactoroptions : UserTaskActorOptions ={
27
+ userId:UserProvider.getInstance().getUid(),
28
+ actGroups:[],
29
+ actUsers:[]
30
+ }
31
+ var instance = await this.server.engine.start(bpmnname, data,null,workflowactoroptions);
32
+ const res = {instanceId:instance.id,data:instance.data,name:instance.name,status:instance.status}
33
+ return Promise.resolve(res);
34
+ }
35
+ async getMyUserTask(){
36
+ const uid = UserProvider.getInstance().getUid()
37
+ const groups = UserProvider.getInstance().getGroups()
38
+ // 'assignments.candidateUsers': User.getInstance().getUid(),
39
+ // 'assignments.candidateGroups': User.getInstance().getGroups
40
+
41
+ let anyof:any = [
42
+ {'items.assignments.assignee':uid},
43
+ ]
44
+ let usersfilter={}
45
+ usersfilter[uid]={$in: 'items.assignments.candidateUsers'}
46
+ anyof.push(usersfilter)
47
+ //{'data.tenantId': 1,'$or':[{
48
+ // 'items.assignments.assignee': 'b2a49a8f-a943-4814-8087-60b1ef2f304f'
49
+ // }]}
50
+ //any of the group
51
+ for(let i=0;i<groups.length;i++){
52
+ const gname = groups[i]
53
+ const tmp = {}
54
+ tmp[gname]={ $in: 'items.assignments.candidateGroups'}
55
+ anyof.push(tmp)
56
+ }
57
+ const filters = {
58
+ 'data.tenantId': UserProvider.getInstance().getTenantId(),
59
+ '$or':anyof
60
+ }
61
+ console.dir(filters)
62
+
63
+
64
+ // 'assignments.assignee': User.getInstance().getUid(),
65
+ const client = new BPMNClient(process.env.BPMN_HOST, process.env.BPMN_PORT, process.env.BPMN_API_KEY);
66
+ const items = await client.datastore.findItems(filters)
67
+ let data=[]
68
+ for(let i=0;i<items.length;i++){
69
+ if(items[i].status=='wait'){
70
+ data.push(items[i])
71
+ }
72
+ }
73
+ return Promise.resolve(data);
74
+ }
75
+ }
@@ -0,0 +1,12 @@
1
+ import { Controller, Get } from '@nestjs/common';
2
+ import { AppService } from './app.service';
3
+
4
+ @Controller()
5
+ export class AppController {
6
+ constructor(private readonly appService: AppService) {}
7
+
8
+ @Get('myworkflowtask')
9
+ async getHello() {
10
+ return await this.appService.getMyTask();
11
+ }
12
+ }
@@ -10,6 +10,8 @@ import { ConfigModule } from '@nestjs/config';
10
10
  import { ServeStaticModule } from '@nestjs/serve-static';
11
11
  import { join } from 'path';
12
12
  import {TenantMiddleware} from './class/TenantMiddleware'
13
+ import {AppController} from './app.controller'
14
+ import {AppService} from './app.service'
13
15
  <% for(let i=0;i<it.length; i++){ %>
14
16
  import {<%= it[i].docname %>Module} from './docs/<%= it[i].doctype %>/<%= it[i].doctype %>.module'
15
17
  <%}%>
@@ -32,8 +34,10 @@ import {<%= it[i].docname %>Module} from './docs/<%= it[i].doctype %>/<%= it[i].
32
34
  tokenValidation: TokenValidation.ONLINE,
33
35
  }),
34
36
  <% for(let i=0;i<it.length; i++){ %><%= it[i].docname %>Module,<%}%>],
35
- controllers: [],
36
- providers: [ {
37
+ controllers: [AppController],
38
+ providers: [
39
+ AppService,
40
+ {
37
41
  provide: APP_GUARD,
38
42
  useClass: AuthGuard,
39
43
  },
@@ -0,0 +1,8 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { Workflow } from './class/Workflow';
3
+ @Injectable()
4
+ export class AppService {
5
+ async getMyTask() {
6
+ return await Workflow.getInstance().getMyUserTask()
7
+ }
8
+ }
@@ -6,6 +6,13 @@ PROJECT_NAME=SimpleApp Demo1
6
6
  PROJECT_DESCRIPTION=Try CRUD
7
7
  PROJECT_Version=1.0.0
8
8
 
9
+ BPMN_HOST=<%=it.bpmnsetting.BPMN_HOST%>
10
+
11
+ BPMN_PORT=<%=it.bpmnsetting.BPMN_PORT%>
12
+
13
+ BPMN_API_KEY=<%=it.bpmnsetting.BPMN_API_KEY%>
14
+
15
+
9
16
  OAUTH2_BASEURL=<%=it.keycloaksetting.OAUTH2_BASEURL%>
10
17
 
11
18
  OAUTH2_REALM=<%=it.keycloaksetting.OAUTH2_REALM%>
@@ -29,6 +29,6 @@ const visible = ref(false)
29
29
  right: 0;
30
30
  background-color: antiquewhite;
31
31
  font-size: large;
32
- top: 0;
32
+ top: 20;
33
33
  }
34
34
  </style>
@@ -7,14 +7,50 @@
7
7
  */
8
8
 
9
9
  // import MegaMenu from 'primevue/megamenu';
10
- import Menubar from 'primevue/menubar';
11
- const route = useRoute()
12
- const menus = getMenus(route.params.xorg)
10
+ // import Menubar from 'primevue/menubar';
11
+ // const route = useRoute()
12
+ // const menus = getMenus(route.params.xorg)
13
+ import MenuIndex from "../pages/[xorg]/index.vue"
14
+ import TenantIndex from "../pages/index.vue"
15
+ import Dialog from 'primevue/dialog';
16
+ import {ref} from 'vue'
17
+ const visible = ref(false)
18
+ const visibletenant = ref(false)
19
+ const logout = async () => {
20
+ const { signOut } = useAuth();
21
+ const { data } = await <any>useFetch('/api/auth/logout');
22
+ const addPath = encodeURIComponent("/login");
23
+ signOut({ redirect: false });
24
+ window.location.href = data?.value?.path + addPath;
25
+ };
13
26
  </script>
14
27
  <template>
15
- <header>
28
+ <!-- <header> -->
16
29
  <!-- <MegaMenu :model="getMenus()" orientation="horizontal" /> -->
17
- <Menubar :model="menus">
18
- </Menubar>
19
- </header>
30
+ <div class="bg-white border-b-2 border-b-gray-300 h-10 flex">
31
+ <Dialog v-model:visible="visible" modal header="Pick Document" :autoZIndex="false" :style="{zIndex:100, width: '80vw' }">
32
+ <MenuIndex></MenuIndex>
33
+ </Dialog>
34
+ <Dialog v-model:visible="visibletenant" modal header="Pick Tenant" :autoZIndex="false" :style="{zIndex:100, width: '80vw' }">
35
+ <TenantIndex></TenantIndex>
36
+ </Dialog>
37
+
38
+ <div class="flex-1">
39
+ <NuxtLink to="/"><i class="pi pi-home m-2"></i>Home</NuxtLink>
40
+ </div>
41
+ <div class="flex-1 p-1">
42
+ <A class="text-center cursor-pointer" @click="visible=true"><i class="pi pi-microsoft mr-2"></i>Menu</A>
43
+ </div>
44
+ <div class="flex-1 p-1">
45
+ <A class="text-center cursor-pointer" @click="visibletenant=true"><i class="pi pi-globe mr-2"></i>Switch Tenant</A>
46
+ </div>
47
+ <div class="flex-1 text-right p-1">
48
+ <A class=" cursor-pointer" @click="logout()">
49
+ <i class="pi pi-sign-out mr-2"></i>logout
50
+ </A>
51
+ </div>
52
+
53
+
54
+ </div>
55
+ <!-- </header> -->
20
56
  </template>
@@ -0,0 +1,5 @@
1
+ export const camelCaseToWords = (s: string) =>{
2
+ const result = s.replace(/([A-Z])/g, ' $1');
3
+ return result.charAt(0).toUpperCase() + result.slice(1);
4
+ }
5
+
@@ -30,7 +30,7 @@ tailwindcss: {
30
30
  security: {
31
31
  //csrf: true, // been force to off csrf cash it crash with nuxt-auth
32
32
  },
33
- ssr: true,
33
+ ssr: false,
34
34
 
35
35
  css: [
36
36
  "primevue/resources/themes/lara-light-blue/theme.css",
@@ -2,18 +2,22 @@
2
2
  /**
3
3
  * This file was automatically generated by simpleapp generator during initialization.
4
4
  * You may modify it for your need
5
- * last change 2023-09-09
5
+ * last change 2023-09-20
6
6
  * author: Ks Tan
7
7
  */
8
- </script>
8
+
9
+ const menus = getMenus();
10
+ </script>
9
11
  <template>
10
12
  <div>
11
- <h1>index page</h1>
12
- <ul>
13
- <li><NuxtLink :external="true" to="/MS0xLTE" >MS0xLTE (1-1-1)</NuxtLink></li>
14
- <li><NuxtLink :external="true" to="/Mi0yLTI" >Mi0yLTI (2-2-2)</NuxtLink></li>
15
- </ul>
16
-
13
+ <div class="desktop-shortcut-link">
14
+
15
+ <NuxtLink v-for="menu in menus[1].items" :external="true" :to="menu.to">
16
+ <div>
17
+ {{ camelCaseToWords(menu.label) }}
18
+ </div>
19
+ </NuxtLink>
20
+
21
+ </div>
17
22
  </div>
18
-
19
23
  </template>
@@ -5,15 +5,65 @@
5
5
  * last change 2023-09-09
6
6
  * author: Ks Tan
7
7
  */
8
- </script>
8
+ import { ref, Ref } from "vue";
9
+ import { TenantDoc } from "../simpleapp/simpleappdocs/TenantDoc";
10
+ // import OrderList from 'primevue/orderlist';
11
+ import Panel from "primevue/panel";
12
+
13
+ const { $event, $listen } = useNuxtApp();
14
+ const route = useRoute();
15
+ const doc = new TenantDoc("", $event, $listen);
16
+ type tenantDataType = {
17
+ tenantId: number;
18
+ tenantCode: string;
19
+ tenantName: string;
20
+ xorg: string;
21
+ };
22
+ const initialtenant: tenantDataType[] = [];
23
+ const tenantlist = ref(initialtenant);
24
+
25
+ doc.getApi().getMyTenants()
26
+ .then((res: any) => {
27
+ for (let i = 0; i < res.data.length; i++) {
28
+ const x = res.data[i];
29
+ const tmp: tenantDataType = {
30
+ xorg: x.xOrg,
31
+ tenantId: x.tenantId,
32
+ tenantCode: x.tenantCode,
33
+ tenantName: x.tenantName,
34
+ };
35
+ tenantlist.value.push(tmp);
36
+ }
37
+ console.log(tenantlist.value);
38
+ });
39
+ // const mytenant = doc.get
40
+ </script>
9
41
  <template>
10
42
  <div>
11
- <h1>index page</h1>
12
- <ul>
13
- <li><NuxtLink :external="true" to="/MS0xLTE" >MS0xLTE (1-1-1)</NuxtLink></li>
14
- <li><NuxtLink :external="true" to="/Mi0yLTI" >Mi0yLTI (2-2-2)</NuxtLink></li>
15
- </ul>
16
-
43
+ <Panel header="Tenant List">
44
+ <div>
45
+ <NuxtLink
46
+ v-for="item in tenantlist"
47
+ :external="true"
48
+ :to="item.xorg"
49
+ class="tenant-link"
50
+ >
51
+ <div class="flex flex-wrap p-2 align-items-center gap-3">
52
+ <div class="flex-1 flex flex-column gap-2">
53
+ <span class="font-bold">{{ item.tenantName }}</span>
54
+ <div class="flex align-items-center gap-2">
55
+ <span>{{ item.xorg }}</span>
56
+ </div>
57
+ </div>
58
+ <span class="font-bold text-900">{{ item.tenantCode }}</span>
59
+ </div>
60
+ </NuxtLink>
61
+ </div>
62
+ </Panel>
17
63
  </div>
18
-
19
64
  </template>
65
+ <style scoped>
66
+ .p-panel {
67
+ @apply m-2;
68
+ }
69
+ </style>
@@ -45,6 +45,14 @@ const emitter = mitt()
45
45
  export default defineNuxtPlugin((nuxtApp) => {
46
46
  //const { csrf } = useCsrf()
47
47
  //axios.defaults.headers.common = {"CSRF-TOKEN": csrf};
48
+ const myaxios = axios.create()
49
+ myaxios.interceptors.response.use((response) => response, (error) => {
50
+ if(error.response.status==401){
51
+ console.error("sso session expired, redirect to logout page")
52
+ const { signOut } = useAuth();
53
+ signOut({redirect:false});
54
+ }
55
+ });
48
56
  nuxtApp.vueApp.use(PrimeVue, { ripple: true });
49
57
  nuxtApp.vueApp
50
58
  .component("SimpleAppAutocomplete",SimpleAppAutocomplete)
@@ -81,7 +89,8 @@ export default defineNuxtPlugin((nuxtApp) => {
81
89
  return {
82
90
  provide: {
83
91
  event: emitter.emit, // Will emit an event
84
- listen: emitter.on // Will register a listener for an event
92
+ listen: emitter.on, // Will register a listener for an event
93
+ axios: myaxios
85
94
  }
86
95
  }
87
96
  //other components that you need
@@ -127,7 +127,8 @@ export default defineEventHandler(async (event) => {
127
127
  // console.log('#####################################')
128
128
 
129
129
  if (error.response?.status && error.response.status == '401') {
130
- return reject({ statusMessage: 'Unauthorized', statusCode: 401 });
130
+ //return reject({ statusMessage: 'Unauthorized', statusCode: 401 });
131
+ return sendRedirect(event, '/login', 401)
131
132
  // throw createError({ statusMessage: 'Unauthorized', statusCode: 401 })
132
133
  }
133
134
 
@@ -5,7 +5,7 @@
5
5
  button {
6
6
  @apply p-2 border-2
7
7
  }
8
- .simpleapp-input-container{
8
+ .simpleapp-input-container,.simpleapp-input-container,.simpleapp-input-container .simpleapp-inputfield{
9
9
  @apply flex flex-col
10
10
  }
11
11
  .simpleapp-input-container .p-chips ul{
@@ -33,4 +33,17 @@ button {
33
33
  }
34
34
  .bg-warning{
35
35
  @apply bg-orange-600 text-white
36
+ }
37
+
38
+ .desktop-shortcut-link{
39
+ @apply m-2 m-2 p-2 space-x-2 rounded-sm text-center grid grid-cols-4 gap-4
40
+ }
41
+ .desktop-shortcut-link div{
42
+ @apply bg-teal-300 p-2
43
+ }
44
+ .desktop-shortcut-link div:hover{
45
+ @apply bg-teal-600 p-2
46
+ }
47
+ .tenant-link:hover div{
48
+ @apply bg-gray-300
36
49
  }
package/tsconfig.json CHANGED
@@ -13,5 +13,8 @@
13
13
  "noImplicitAny": false,
14
14
  "strictBindCallApply": false,
15
15
  "paths": {"@": ["./"]}
16
- }
16
+ },
17
+ "exclude": [
18
+ "node_modules" , "./dist" , "./tools"
19
+ ]
17
20
  }
@@ -1,115 +0,0 @@
1
- import { Injectable, Scope } from '@nestjs/common';
2
- import Base64URL from '@darkwolf/base64url';
3
- import * as jwt from 'jsonwebtoken'
4
-
5
-
6
-
7
-
8
-
9
- @Injectable({
10
- scope: Scope.REQUEST,
11
- })
12
- export class User {
13
- private static instance: User;
14
- protected uid: string = '';
15
- protected uname: string = '';
16
- protected email: string = '';
17
- protected fullname:string=''
18
- protected xOrg: string = '';
19
- protected tenantId: number = 0;
20
- protected orgId: number = 0;
21
- protected branchId: number = 0;
22
- protected accessrights:any = {}
23
- protected token:string = ''
24
- protected refreshtoken:string = ''
25
- constructor() {}
26
- public static getInstance(): User {
27
- if (!User.instance) {
28
- User.instance = new User();
29
- }
30
- return User.instance;
31
- }
32
- setUserToken = (tokenstr: string) => {
33
- const tokeninfo = jwt.decode(tokenstr)
34
- // realm_access: {
35
- // roles: [
36
- // 'default-roles-simitdeveloper',
37
- // 'offline_access',
38
- // 'uma_authorization'
39
- // ]
40
- // },
41
- // resource_access: { account: { roles: [Array] } },
42
- // scope: 'openid email profile',
43
- // sid: '53192f53-d4af-413b-b8d7-1e186419fe53',
44
- // email_verified: false,
45
- // name: 'kstan kstan',
46
- // preferred_username: 'kstan',
47
- // given_name: 'kstan',
48
- // family_name: 'kstan',
49
- // email: 'kstan@simitgroup.com'
50
-
51
- const u = User.getInstance()
52
- u.token = tokenstr
53
- u.uid = tokeninfo.sub;
54
- u.email = tokeninfo.email
55
- u.uname = tokeninfo.preferred_username
56
- u.fullname = tokeninfo.name
57
- u.accessrights = tokeninfo.resource_access
58
- };
59
- getInfo = () => {
60
- return User.getInstance();
61
- };
62
- getBranchFilter = () => {
63
- return {
64
- tenantId: User.getInstance().tenantId,
65
- orgId: User.getInstance().orgId,
66
- branchId: User.getInstance().branchId,
67
- };
68
- };
69
- getTenantFilter = () => {
70
- return { tenantId: User.getInstance().tenantId };
71
- };
72
- getOrgFilter = () => {
73
- return {
74
- tenantId: User.getInstance().tenantId,
75
- orgId: User.getInstance().orgId,
76
- };
77
- };
78
-
79
- getCreateFilter = () => {
80
- const u = User.getInstance();
81
- return {
82
- tenantId: u.tenantId,
83
- orgId: u.orgId,
84
- branchId: u.branchId,
85
- createdby: u.uid,
86
- updatedby: u.uid,
87
- created: new Date().getTime().toString(),
88
- updated: new Date().getTime().toString(),
89
- };
90
- };
91
- getUpdateFilter = () => {
92
- const u = User.getInstance();
93
- return {
94
- updatedby: u.uid,
95
- updated: new Date().getTime().toString(),
96
- };
97
- };
98
- setXorg = (xorg) => {
99
- try {
100
- const decodedText: string = Base64URL.decodeText(xorg);
101
- const arrXorg = decodedText.split('-');
102
-
103
- if (arrXorg.length == 3) {
104
- const u = User.getInstance();
105
- u.tenantId = Number(arrXorg[0]);
106
- u.orgId = Number(arrXorg[1]);
107
- u.branchId = Number(arrXorg[2]);
108
- } else {
109
- throw 'invalid x-org';
110
- }
111
- } catch (err) {
112
- throw err;
113
- }
114
- };
115
- }