@simitgroup/simpleapp-generator 1.0.23 → 1.0.24

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 (60) hide show
  1. package/README.md +48 -0
  2. package/dist/createproject.js +1 -1
  3. package/dist/createproject.js.map +1 -1
  4. package/dist/framework.js +20 -16
  5. package/dist/framework.js.map +1 -1
  6. package/dist/generate.js +38 -16
  7. package/dist/generate.js.map +1 -1
  8. package/dist/index.js +2 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/processors/jsonschemabuilder.js +9 -9
  11. package/dist/processors/jsonschemabuilder.js.map +1 -1
  12. package/package.json +1 -1
  13. package/src/framework.ts +37 -30
  14. package/src/generate.ts +37 -21
  15. package/src/index.ts +2 -1
  16. package/src/processors/jsonschemabuilder.ts +9 -9
  17. package/src/type.ts +1 -0
  18. package/templates/basic/apischema.eta +8 -4
  19. package/templates/basic/controller.eta +21 -5
  20. package/templates/basic/jsonschema.eta +2 -0
  21. package/templates/basic/model.eta +2 -6
  22. package/templates/basic/module.eta +2 -0
  23. package/templates/basic/pageindex.vue.eta +28 -15
  24. package/templates/basic/pageindexwithid.vue.eta +13 -1
  25. package/templates/basic/service.eta +11 -9
  26. package/templates/basic/simpleappclient.eta +9 -8
  27. package/templates/basic/type.eta +2 -1
  28. package/templates/nest/SimpleAppController.eta +5 -5
  29. package/templates/nest/SimpleAppService.eta +87 -31
  30. package/templates/nest/TenantMiddleware.eta +30 -0
  31. package/templates/nest/User.eta +80 -0
  32. package/templates/nest/app.module.eta +14 -3
  33. package/templates/nest/inputvalidation-exception.eta +6 -0
  34. package/templates/nest/nest.main.eta +2 -0
  35. package/templates/nuxt/components.crudsimple.vue.eta +61 -48
  36. package/templates/nuxt/components.debugdocdata.vue.eta +12 -4
  37. package/templates/nuxt/components.eventmonitor.vue.eta +17 -11
  38. package/templates/nuxt/components.menus.vue.eta +14 -12
  39. package/templates/nuxt/composables.getautocomplete.ts.eta +7 -1
  40. package/templates/nuxt/composables.getmenus.ts.eta +9 -2
  41. package/templates/nuxt/env.eta +2 -0
  42. package/templates/nuxt/layouts.default.vue.eta +10 -3
  43. package/templates/nuxt/nuxt.config.ts.eta +4 -1
  44. package/templates/nuxt/pages.index.vue.eta +8 -0
  45. package/templates/nuxt/plugins.simpleapp.ts.eta +10 -1
  46. package/templates/nuxt/server.api.ts.eta +14 -5
  47. package/src/createproject.ts +0 -121
  48. package/src/index2.ts-old +0 -132
  49. package/src/installdependency.sh +0 -5
  50. package/src/installnest.ts +0 -0
  51. package/src/installnuxt.ts +0 -0
  52. package/templates/basic/backend.config.eta +0 -1
  53. package/templates/basic/beforesave.eta +0 -7
  54. package/templates/basic/controller2.eta +0 -86
  55. package/templates/basic/frontend.config.eta +0 -1
  56. package/templates/basic/model-converter.etabackup +0 -21
  57. package/templates/basic/readme.eta +0 -3
  58. package/templates/basic/service.etabackupe +0 -106
  59. package/templates/basic/type.etabackup +0 -23
  60. package/templates/basic/uischema.eta +0 -13
@@ -4,10 +4,18 @@ import { Model } from 'mongoose';
4
4
  import Ajv from 'ajv';
5
5
  import addFormats from 'ajv-formats';
6
6
  import foreignkeys from '../dicts/foreignkeys.json';
7
+
7
8
  import {
8
9
  NotFoundException,
9
10
  InternalServerErrorException,
10
11
  } from '@nestjs/common/exceptions';
12
+ import { User } from './User';
13
+
14
+ export enum IsolationType {
15
+ 'org' = 'org',
16
+ 'tenant' = 'tenant',
17
+ 'branch' = 'branch',
18
+ }
11
19
  @Injectable()
12
20
  export class SimpleAppService<T extends { _id?: string }> {
13
21
  protected jsonschema = { type: 'object', properties: {}, required: [] };
@@ -16,11 +24,19 @@ export class SimpleAppService<T extends { _id?: string }> {
16
24
  protected documentName = 'category';
17
25
  protected documentType = 'CAT';
18
26
  protected LIMITPERPAGE = 20;
27
+ protected isolationtype: IsolationType = IsolationType.org;
28
+ protected isolationFilter: any = {};
19
29
  protected data: T = { _id: '' } as T;
20
- protected doc: Model<T>;
30
+ private doc: Model<T>; //set private to prevent developer break data isolation control
21
31
  protected errorlist = [];
22
- constructor(newdoc: Model<T>) {
32
+ constructor(
33
+ newdoc: Model<T>,
34
+ isolationtype: IsolationType = IsolationType.org,
35
+ ) {
23
36
  this.doc = newdoc;
37
+ this.isolationtype = isolationtype;
38
+
39
+ // this.tenantdoc = tenantdoc
24
40
  }
25
41
  getRecordId = (): string => this.data._id;
26
42
  setSchema = (newschema) => (this.jsonschema = newschema);
@@ -34,9 +50,27 @@ export class SimpleAppService<T extends { _id?: string }> {
34
50
  this.data = { ...newdata };
35
51
  return this;
36
52
  };
53
+ getIsolationFilter = () => {
54
+ let isolationFilter = {};
55
+ switch (this.isolationtype) {
56
+ case 'branch':
57
+ isolationFilter = User.getInstance().getBranchFilter();
58
+ break;
59
+ case 'tenant':
60
+ isolationFilter = User.getInstance().getTenantFilter();
61
+ break;
62
+ case 'org':
63
+ default:
64
+ isolationFilter = User.getInstance().getOrgFilter();
65
+ break;
66
+ }
67
+ return isolationFilter;
68
+ };
37
69
  async list() {
38
70
  try {
39
- const products = await this.doc.find();
71
+ //console.log("this.isolationFilter",this.getIsolationFilter())
72
+ const products = await this.doc.find(this.getIsolationFilter());
73
+ // console.log(products)
40
74
  const productlist = products.map((p: T) => {
41
75
  return p;
42
76
  });
@@ -53,6 +87,8 @@ export class SimpleAppService<T extends { _id?: string }> {
53
87
  filter1[this.documentIdentityCode] = { $regex: keyword };
54
88
  filter2[this.documentIdentityName] = { $regex: keyword };
55
89
  const filterobj = { $or: [filter1, filter2] };
90
+
91
+ Object.assign(filterobj, this.getIsolationFilter());
56
92
  const projections = {
57
93
  id: `\$_id`,
58
94
  label: `\$${this.documentIdentityCode}`,
@@ -69,31 +105,37 @@ export class SimpleAppService<T extends { _id?: string }> {
69
105
  throw new InternalServerErrorException(err.message);
70
106
  }
71
107
  }
72
- async findById(id: string) {
108
+ async search(filters: Object) {
73
109
  try {
74
- //console.log('findById', id);
75
- this.data = await this.doc.findById(id);
76
- //console.log('findById done', this.data);
110
+ Object.assign(filters, this.getIsolationFilter());
111
+ const products = await this.doc.find(filters);
112
+ const productlist = products.map((p: T) => {
113
+ return p;
114
+ });
115
+ // console.log(products);
116
+ return productlist;
77
117
  } catch (err) {
78
- //error
79
118
  throw new InternalServerErrorException(err.message);
80
119
  }
81
-
82
- if (!this.data) {
83
- //data not found
84
- throw new NotFoundException('Document Not found:');
85
- }
86
- //console.log('this.data', this.data);
87
- return this.data;
88
120
  // return this;
89
121
  }
122
+ async findById(id: string) {
123
+ const data = await this.search({ _id: id });
124
+ if (data.length == 1) {
125
+ // console.log('data0', data[0]);
126
+ return data[0];
127
+ } else {
128
+ return null;
129
+ }
130
+ }
90
131
 
91
132
  async create() {
92
133
  let result;
93
134
 
94
135
  try {
136
+ Object.assign(this.data, User.getInstance().getCreateFilter());
95
137
  delete this.data._id;
96
- this.validateData(this.data);
138
+ this.validateData(this.data);
97
139
  const newdoc = new this.doc(this.data);
98
140
  result = await newdoc.save();
99
141
  } catch (err) {
@@ -103,14 +145,14 @@ export class SimpleAppService<T extends { _id?: string }> {
103
145
  }
104
146
  async update() {
105
147
  const id: string = this.getRecordId();
148
+ Object.assign(this.data, User.getInstance().getUpdateFilter());
106
149
  this.findIdThenUpdate(id, this.data);
107
150
  }
108
151
  async delete() {
109
-
110
152
  const id: string = this.getRecordId();
111
153
  const dependency = await this.getRelatedRecords(id);
112
154
  if (!dependency) {
113
- return await this.findIdThenDelete(id);
155
+ return await this.findIdThenDelete(id);
114
156
  } else {
115
157
  return dependency;
116
158
  }
@@ -121,10 +163,10 @@ export class SimpleAppService<T extends { _id?: string }> {
121
163
  validateData(data: T) {
122
164
  const ajv = new Ajv({ allErrors: true });
123
165
  addFormats(ajv);
124
- ajv.addFormat('field-autocomplete-code', /.*$/);
125
- ajv.addFormat('field-autocomplete-name', /.*$/);
126
- ajv.addFormat('x-text',/.*$/)
127
- ajv.addFormat('x-html',/.*$/)
166
+ ajv.addFormat('x-document-no', /.*$/);
167
+ ajv.addFormat('x-document-name', /.*$/);
168
+ ajv.addFormat('x-text', /.*$/);
169
+ ajv.addFormat('x-html', /.*$/);
128
170
  ajv.addKeyword({
129
171
  keyword: 'x-foreignkey',
130
172
  type: 'string',
@@ -135,28 +177,36 @@ export class SimpleAppService<T extends { _id?: string }> {
135
177
  for (let i = 0; i < this.errorlist.length; i++) {
136
178
  erromsg.push(this.errorlist[i].message);
137
179
  }
180
+ console.log("pre-validation:",erromsg)
138
181
  throw new InternalServerErrorException(erromsg.join('\n'));
139
182
  }
140
183
  const validate = ajv.compile(this.jsonschema);
141
184
  const valid = validate(data);
185
+ //console.log(validate.errors);
142
186
  if (!valid) {
143
- //console.log(validate.errors);
187
+ // console.log(validate.errors);
144
188
  const erromsg: string[] = [];
145
189
  for (let i = 0; i < validate.errors.length; i++) {
146
190
  erromsg.push(validate.errors[i].message);
147
191
  }
192
+ console.log("ajv erromsg: ",erromsg)
148
193
  throw new InternalServerErrorException(erromsg.join('\n'));
149
194
  }
150
195
  this.hook('post-validation', data);
151
196
  }
152
197
 
153
- async findIdThenDelete(id: string) {
198
+ async findIdThenDelete(id: string): Promise<any> {
154
199
  // const data = await this.findById(id);
155
200
  try {
156
201
  //console.log('deletedeletedeletedelete');
157
202
  const dependency = await this.getRelatedRecords(id);
158
203
  if (!dependency) {
159
- const deleteresult = await this.doc.findByIdAndDelete(id);
204
+ let filter = this.getIsolationFilter();
205
+ filter['_id'] = id;
206
+ const deleteresult = await this.doc.deleteOne(filter);
207
+ // this.doc.findByIdAndDelete(id)
208
+
209
+ //this.doc.findByIdAndDelete(id);
160
210
  return deleteresult;
161
211
  } else {
162
212
  return Promise.reject(dependency);
@@ -166,20 +216,26 @@ export class SimpleAppService<T extends { _id?: string }> {
166
216
  }
167
217
  }
168
218
 
169
- async findIdThenUpdate(id: string, data: T) {
170
- // const existingdata = await this.findById(id);
219
+ updateOne = async (data: T) => {
220
+ this.doc.updateOne(data);
221
+ };
222
+
223
+ findIdThenUpdate = async (id: string, data: T) => {
224
+ const existingdata = await this.findById(id);
171
225
 
172
226
  try {
173
- //console.log('findIdThenUpdate', id);
227
+ Object.assign(data, User.getInstance().getUpdateFilter());
228
+ Object.assign(existingdata, data);
174
229
  this.validateData(data);
175
- // const result = await existingdata.doc.updateOne(data);
176
- const result = await this.doc.findByIdAndUpdate(id, data);
230
+ let filter = this.getIsolationFilter();
231
+ filter['_id'] = id;
232
+ const result = await this.doc.findOneAndUpdate(filter, data);
177
233
 
178
234
  return result;
179
235
  } catch (err) {
180
236
  throw new InternalServerErrorException(err.message);
181
237
  }
182
- }
238
+ };
183
239
 
184
240
  //find what foreign key constraint
185
241
  async getRelatedRecords(id: string) {
@@ -0,0 +1,30 @@
1
+
2
+ import { Injectable, NestMiddleware,Scope } from '@nestjs/common';
3
+ import { Request, Response, NextFunction } from 'express';
4
+ import {User} from './User'
5
+
6
+ @Injectable({
7
+ scope: Scope.REQUEST
8
+ })
9
+ export class TenantMiddleware implements NestMiddleware {
10
+ use(req: Request, res: Response, next: NextFunction) {
11
+ req.headers['x-org']
12
+ if(req.headers['x-org']){
13
+ const u = User.getInstance()
14
+ try{
15
+ u.setXorg(req.headers['x-org'].toString())
16
+ u.setUser('user1')
17
+ //console.log(u.getInfo())
18
+ // u.uid='user1'
19
+ next();
20
+ }catch{
21
+ return res.status(401).send("Invalid x-org or user info")
22
+ }
23
+
24
+ }else{
25
+ return res.status(401).send("undefine header string x-org")
26
+
27
+ }
28
+
29
+ }
30
+ }
@@ -0,0 +1,80 @@
1
+ import { Injectable, Scope } from '@nestjs/common';
2
+ import Base64URL from '@darkwolf/base64url'
3
+
4
+ @Injectable({
5
+ scope: Scope.REQUEST
6
+ })
7
+ export class User {
8
+ private static instance: User;
9
+ protected uid:string=''
10
+ protected uname:string=''
11
+ protected email:string=''
12
+ protected xOrg:string=''
13
+ protected tenantId:number=0
14
+ protected orgId:number=0
15
+ protected branchId:number=0
16
+ constructor() {}
17
+ public static getInstance(): User {
18
+ if (!User.instance) {
19
+ User.instance = new User();
20
+ }
21
+ return User.instance;
22
+ }
23
+ setUser = (uid:string)=>{
24
+ User.getInstance().uid=uid
25
+ }
26
+ getInfo=()=>{
27
+ return User.getInstance()
28
+ }
29
+ getBranchFilter=()=>{
30
+ return {
31
+ tenantId:User.getInstance().tenantId,
32
+ orgId: User.getInstance().orgId,
33
+ branchId:User.getInstance().branchId
34
+ }
35
+ }
36
+ getTenantFilter=()=>{
37
+ return {tenantId:User.getInstance().tenantId}
38
+ }
39
+ getOrgFilter=()=>{
40
+ return {tenantId:User.getInstance().tenantId,orgId: User.getInstance().orgId}
41
+ }
42
+
43
+ getCreateFilter=()=>{
44
+ const u = User.getInstance()
45
+ return {
46
+ tenantId:u.tenantId,
47
+ orgId: u.orgId,
48
+ branchId:u.branchId,
49
+ createdby: u.uid,
50
+ updatedby: u.uid,
51
+ created: new Date().getTime().toString(),
52
+ updated: new Date().getTime().toString()
53
+ }
54
+ }
55
+ getUpdateFilter=()=>{
56
+ const u = User.getInstance()
57
+ return {
58
+ updatedby: u.uid,
59
+ updated: new Date().getTime().toString()
60
+ }
61
+ }
62
+ setXorg = (xorg)=>{
63
+ try{
64
+ const decodedText:string = Base64URL.decodeText(xorg)
65
+ const arrXorg = decodedText.split('-')
66
+
67
+ if(arrXorg.length==3){
68
+ const u = User.getInstance()
69
+ u.tenantId = Number(arrXorg[0])
70
+ u.orgId = Number(arrXorg[1])
71
+ u.branchId = Number(arrXorg[2])
72
+ }else{
73
+ throw "invalid x-org"
74
+ }
75
+ }catch(err){
76
+ throw err
77
+ }
78
+
79
+ }
80
+ }
@@ -1,7 +1,7 @@
1
- import { Module } from '@nestjs/common';
1
+ import { Module,MiddlewareConsumer,NestModule } from '@nestjs/common';
2
2
  import { MongooseModule } from '@nestjs/mongoose';
3
3
  import { ConfigModule } from '@nestjs/config';
4
-
4
+ import {TenantMiddleware} from './class/TenantMiddleware'
5
5
  <% for(let i=0;i<it.length; i++){ %>
6
6
  import {<%= it[i].docname %>Module} from './docs/<%= it[i].doctype %>/<%= it[i].doctype %>.module'
7
7
  <%}%>
@@ -12,4 +12,15 @@ import {<%= it[i].docname %>Module} from './docs/<%= it[i].doctype %>/<%= it[i].
12
12
  controllers: [],
13
13
  providers: [],
14
14
  })
15
- export class AppModule {}
15
+ export class AppModule implements NestModule{
16
+ configure(consumer: MiddlewareConsumer) {
17
+ consumer
18
+ .apply(TenantMiddleware)
19
+ // .exclude('/api-yaml')
20
+ // .exclude('/api-json')
21
+ // .exclude('/api')
22
+ .forRoutes('*')
23
+
24
+
25
+ }
26
+ }
@@ -0,0 +1,6 @@
1
+ import {HttpException,HttpStatus} from '@nestjs/common'
2
+ export class InputValidationExceptions extends HttpException {
3
+ constructor() {
4
+ super('input error', HttpStatus.INTERNAL_SERVER_ERROR);
5
+ }
6
+ }
@@ -9,6 +9,8 @@ async function bootstrap() {
9
9
  .setTitle(process.env.PROJECT_NAME)
10
10
  .setDescription(process.env.PROJECT_DESCRIPTION)
11
11
  .setVersion(process.env.PROJECT_VERSION)
12
+ .addApiKey({in:'header',name:'x-org',type:'apiKey',description:'base 64 url encode. example: MS0xLTE'},'x-org')
13
+ .addSecurityRequirements('x-org')
12
14
  .build();
13
15
  const document = SwaggerModule.createDocument(app, config);
14
16
  SwaggerModule.setup('api', app, document, {
@@ -1,32 +1,10 @@
1
- <template>
2
- <div class="simpleapp-crudsimple">
3
- <button class="bg-primary" type="reset" @click="newData">New</button>
4
-
5
-
6
- <SimpleAppDatatable
7
- @row-dblclick="editRecord"
8
- v-model="recordlist"
9
- :setting="{}"
10
- :columns="listColumns"
11
- ></SimpleAppDatatable>
12
-
13
- <DebugDocumentData v-model="data"/>
14
- </div>
15
-
16
- <Dialog v-model:visible="visible" modal header="Header" class="crudsimple-dialog" :autoZIndex="false" :style="{zIndex:100, width: '80vw' }">
17
- <SimpleAppForm :document="obj" :title="title" #default="o">
18
- <div class="simpleapp-tool-bar" >
19
- <button class="bg-default" :disabled="disabled" @click="newData" type="reset">New</button>
20
- <button class="bg-primary" :disabled="disabled" @click="saveData" type="submit">Save</button>
21
- <button class="bg-danger" :disabled="disabled" @click="deleteData($event)">Delete</button>
22
- <ProgressSpinner v-if="disabled==true" style="width: 2rem; height: 2rem" ></ProgressSpinner>
23
- <ConfirmPopup></ConfirmPopup>
24
- </div>
25
- <slot :data="o.data" :getField="o.getField" name="default"></slot>
26
- </SimpleAppForm>
27
- </Dialog>
28
- </template>
29
1
  <script setup lang="ts">
2
+ /**
3
+ * This file was automatically generated by simpleapp generator during initialization.
4
+ * DO NOT MODIFY IT BY HAND.
5
+ * last change 2023-09-09
6
+ * author: Ks Tan
7
+ */
30
8
 
31
9
  import { SimpleAppClient } from '@simitgroup//simpleapp-vue-component/src/SimpleAppClient';
32
10
  import SimpleAppForm from '@simitgroup/simpleapp-vue-component/src/components/SimpleAppForm.vue';
@@ -34,7 +12,6 @@ import SimpleAppDatatable from '@simitgroup/simpleapp-vue-component/src/componen
34
12
  import Dialog from 'primevue/dialog';
35
13
  import axios from 'axios'
36
14
  import ProgressSpinner from 'primevue/progressspinner';
37
-
38
15
  import ConfirmPopup from 'primevue/confirmpopup';
39
16
  import { useConfirm } from "primevue/useconfirm";
40
17
 
@@ -42,6 +19,7 @@ const confirm = useConfirm();
42
19
  const props = defineProps<{
43
20
  document:SimpleAppClient<any,any>
44
21
  listColumns:string[]
22
+ path:string
45
23
  title:string
46
24
  }>()
47
25
  const visible = ref(false)
@@ -49,14 +27,12 @@ const obj = props.document
49
27
  const data = obj.getReactiveData()
50
28
  const disabled=ref(false)
51
29
  const recordlist = ref();
52
- const setCsrf=()=>{
53
- // const { csrf } = useCsrf()
54
- // console.log('csrf',csrf)
55
- // axios.defaults.headers.common = {
56
- // "X-CSRF-TOKEN": csrf
57
- // };
58
- }
59
-
30
+ const router = useRouter()
31
+ const route = useRoute()
32
+ const filters = ref()
33
+ defineShortcuts({
34
+ 'ctrl_i': () => newData()
35
+ })
60
36
  const refresh = () => {
61
37
  obj.list().then((res:any) => {
62
38
  recordlist.value = res;
@@ -64,23 +40,27 @@ const refresh = () => {
64
40
  });
65
41
  };
66
42
  const newData = () => {
67
- obj.setNew()
68
- setCsrf()
69
- visible.value=true;
43
+ router.push({ path: `${props.path}` })
44
+ obj.setNew()
45
+ visible.value=true;
70
46
  };
71
47
 
72
- const editRecord = (event: any) => {
73
- obj.getById(event.data._id);
74
- setCsrf()
48
+ const triggerEdit = (event: any) => {
49
+ let id = event.data._id.toString()
50
+ editRecord(event.data._id);
51
+ router.push({ path: `${props.path}/${id}` })
52
+ };
53
+ const editRecord = (id:string) => {
54
+ obj.getById(id);
75
55
  visible.value=true
76
56
  };
77
57
 
78
58
  const saveData = () => {
79
59
  disabled.value=true
80
60
  if (data.value._id == "") {
81
- obj.create().then(()=>{visible.value=false}).catch(()=>setCsrf()).finally(() => refresh());
61
+ obj.create().then(()=>{visible.value=false}).finally(() => refresh());
82
62
  } else {
83
- obj.update().then(()=>visible.value=false).catch(()=>setCsrf()).finally(() => refresh());
63
+ obj.update().then(()=>visible.value=false).finally(() => refresh());
84
64
  }
85
65
  };
86
66
  const deleteData = (event:Event) => {
@@ -97,14 +77,47 @@ const deleteData = (event:Event) => {
97
77
  });
98
78
  },
99
79
  reject: () => {
100
- setCsrf()
101
80
  console.log("Cancel delete")
102
81
  }
103
- })
104
-
82
+ })
105
83
  };
84
+
85
+ if (route.params.id) {
86
+ const recordid:string = route.params.id.toString()
87
+ editRecord(recordid)
88
+ }
89
+
106
90
  refresh();
107
91
  </script>
92
+
93
+ <template>
94
+ <div class="simpleapp-crudsimple">
95
+ <button class="bg-primary" @click="newData" v-tooltip="'Add new(ctrl+i)'" >New</button>
96
+ <SimpleAppDatatable
97
+ @row-dblclick="triggerEdit"
98
+ v-model="recordlist"
99
+ :setting="{}"
100
+ :columns="listColumns"
101
+ >
102
+ </SimpleAppDatatable>
103
+
104
+ <DebugDocumentData v-model="data"/>
105
+ </div>
106
+
107
+ <Dialog v-model:visible="visible" modal header="Header" class="crudsimple-dialog" :autoZIndex="false" :style="{zIndex:100, width: '80vw' }">
108
+ <SimpleAppForm :document="obj" :title="title" #default="o">
109
+ <div class="simpleapp-tool-bar" >
110
+ <button class="bg-default" :disabled="disabled" @click="newData" type="button">New</button>
111
+ <button class="bg-primary" :disabled="disabled" @click="saveData" type="submit">Save</button>
112
+ <button class="bg-danger" :disabled="disabled" @click="deleteData($event)" type="button">Delete</button>
113
+ <ProgressSpinner v-if="disabled==true" style="width: 2rem; height: 2rem" ></ProgressSpinner>
114
+ <ConfirmPopup></ConfirmPopup>
115
+ </div>
116
+ <slot :data="o.data" :getField="o.getField" name="default"></slot>
117
+ </SimpleAppForm>
118
+ </Dialog>
119
+ </template>
120
+
108
121
  <style scoped>
109
122
  .crudsimple-dialog{
110
123
  z-index: 100;
@@ -1,14 +1,22 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * This file was automatically generated by simpleapp generator during initialization.
4
+ * DO NOT MODIFY IT BY HAND.
5
+ * last change 2023-09-09
6
+ * author: Ks Tan
7
+ */
8
+
9
+ const modelValue = defineModel()
10
+ const isdebug = ref(useRuntimeConfig().public.DEBUGDATA)
11
+ </script>
1
12
  <template>
2
- <div class="floatright">
13
+ <div class="floatright" v-if="isdebug=='1'">
3
14
  <h3>data in json</h3>
4
15
  <pre>
5
16
  {{ modelValue }}
6
17
  </pre>
7
18
  </div>
8
19
  </template>
9
- <script setup lang="ts">
10
- const modelValue = defineModel()
11
- </script>
12
20
  <style scoped>
13
21
  .floatright{
14
22
  position: fixed;
@@ -1,14 +1,10 @@
1
- <template>
2
- <Toast group="default"/>
3
- <Toast group="list">
4
- <template #message="p">
5
- <ol>
6
- <li v-for="(item,index) in p.message.detail" :key="index">{{item.instancePath}} {{ item.message }}</li>
7
- </ol>
8
- </template>
9
- </Toast>
10
- </template>
11
1
  <script setup lang="ts">
2
+ /**
3
+ * This file was automatically generated by simpleapp generator during initialization.
4
+ * DO NOT MODIFY IT BY HAND.
5
+ * last change 2023-09-09
6
+ * author: Ks Tan
7
+ */
12
8
 
13
9
  import { useToast, } from 'primevue/usetoast';
14
10
  import type { ToastMessageOptions } from 'primevue/toast';
@@ -76,4 +72,14 @@ const prepareMsg=(data:any,msgtype:string):string=>{
76
72
 
77
73
  }
78
74
 
79
- </script>
75
+ </script>
76
+ <template>
77
+ <Toast group="default"/>
78
+ <Toast group="list">
79
+ <template #message="p">
80
+ <ol>
81
+ <li v-for="(item,index) in p.message.detail" :key="index">{{item.instancePath}} {{ item.message }}</li>
82
+ </ol>
83
+ </template>
84
+ </Toast>
85
+ </template>
@@ -1,18 +1,20 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * This file was automatically generated by simpleapp generator during initialization.
4
+ * You may modify it by hand
5
+ * last change 2023-09-10
6
+ * author: Ks Tan
7
+ */
8
+
9
+ // import MegaMenu from 'primevue/megamenu';
10
+ import Menubar from 'primevue/menubar';
11
+ const route = useRoute()
12
+ const menus = getMenus(route.params.xorg)
13
+ </script>
1
14
  <template>
2
15
  <header>
3
16
  <!-- <MegaMenu :model="getMenus()" orientation="horizontal" /> -->
4
- <Menubar :model="getMenus()">
5
- <template #start>
6
- <h1>[Logo Container]</h1>
7
- </template>
8
- <template #end>
9
- <InputText placeholder="Search" type="text" />
10
- </template>
17
+ <Menubar :model="menus">
11
18
  </Menubar>
12
19
  </header>
13
20
  </template>
14
- <script setup lang="ts">
15
- // import MegaMenu from 'primevue/megamenu';
16
- import Menubar from 'primevue/menubar';
17
-
18
- </script>
@@ -1,4 +1,10 @@
1
-
1
+ /**
2
+ * This file was automatically generated by simpleapp generator during initialization.
3
+ * DO NOT MODIFY IT BY HAND.
4
+ * last change 2023-09-09
5
+ * author: Ks Tan
6
+ */
7
+
2
8
  import * as o from "../simpleapp/openapi";
3
9
 
4
10
  const getAutoComplete = (apiname: string): any => {
@@ -1,8 +1,15 @@
1
- export const getMenus =()=>[
1
+ /**
2
+ * This file was automatically generated by simpleapp generator during initialization.
3
+ * DO NOT MODIFY IT BY HAND.
4
+ * last change 2023-09-10
5
+ * author: Ks Tan
6
+ */
7
+
8
+ export const getMenus =(xorg:string)=>[
2
9
  {label: 'Cruds',icon: 'pi pi-fw pi-pencil',items:[
3
10
  <% for(let i=0;i<it.length; i++){ %>
4
11
  <% let obj = it[i]%>
5
- {label: '<%=obj.docname.toLowerCase()%>', to:'/<%=obj.docname.toLowerCase()%>'},
12
+ {label: '<%=obj.docname.toLowerCase()%>', to:`/${xorg}/<%=obj.docname.toLowerCase()%>`},
6
13
  <%}%>
7
14
  ]},
8
15
  {label: 'Profile',icon: 'pi pi-fw pi-user'},