@simitgroup/simpleapp-generator 2.0.3-g-alpha → 2.0.3-i-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.
package/ReleaseNote.md CHANGED
@@ -1,3 +1,11 @@
1
+ [2.0.3i-alpha]
2
+ 1. Add uiSchema for custom field
3
+ 2. Remove unused lang template files (cn.ts._eta, en.ts.eta)
4
+ 3. Migrate getValidateService import to @simtrain/shared
5
+
6
+ [2.0.3h-alpha]
7
+ 1. Split monolithic simpleapp-event plugin into focused plugins
8
+
1
9
  [2.0.3g-alpha]
2
10
  1. Remove unused workflow dead code from frontend and backend
3
11
 
@@ -1 +1 @@
1
- {"version":3,"file":"customfield.d.ts","sourceRoot":"","sources":["../../src/buildinschemas/customfield.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,UAAU,EAAE,MAAM,SAAS,CAAC;AAEjE,eAAO,MAAM,WAAW,EAAE,UA6CzB,CAAC"}
1
+ {"version":3,"file":"customfield.d.ts","sourceRoot":"","sources":["../../src/buildinschemas/customfield.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,UAAU,EAAE,MAAM,SAAS,CAAC;AAEjE,eAAO,MAAM,WAAW,EAAE,UAiDzB,CAAC"}
@@ -32,6 +32,10 @@ exports.customfield = {
32
32
  jsonSchema: {
33
33
  type: 'object',
34
34
  properties: {}
35
+ },
36
+ uiSchema: {
37
+ type: 'object',
38
+ properties: {}
35
39
  }
36
40
  }
37
41
  },
@@ -1 +1 @@
1
- {"version":3,"file":"customfield.js","sourceRoot":"","sources":["../../src/buildinschemas/customfield.ts"],"names":[],"mappings":";;;AAAA,kCAAiE;AAEpD,QAAA,WAAW,GAAe;IACrC,IAAI,EAAE,QAAQ;IACd,oBAAoB,EAAE;QACpB,YAAY,EAAE,aAAa;QAC3B,YAAY,EAAE,aAAa;QAC3B,aAAa,EAAE,oBAAa,CAAC,MAAM;QACnC,SAAS,EAAE,gBAAgB;QAC3B,aAAa,EAAE,gBAAgB;QAC/B,QAAQ,EAAE,UAAU;QACpB,YAAY,EAAE,aAAa;KAC5B;IACD,UAAU,EAAE;QACV,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACvB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC3B,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC3B,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC7B,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC7B,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACzC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACzC,cAAc,EAAE;YACd,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,CAAC;SACb;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,UAAU,EAAE;oBACV,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,EAAE;iBACf;aACF;SACF;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,MAAM,EAAE;oBACN,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE;wBACL,IAAI,EAAE,QAAQ;qBACf;iBACF;aACF;SACF;KACF;CACF,CAAC"}
1
+ {"version":3,"file":"customfield.js","sourceRoot":"","sources":["../../src/buildinschemas/customfield.ts"],"names":[],"mappings":";;;AAAA,kCAAiE;AAEpD,QAAA,WAAW,GAAe;IACrC,IAAI,EAAE,QAAQ;IACd,oBAAoB,EAAE;QACpB,YAAY,EAAE,aAAa;QAC3B,YAAY,EAAE,aAAa;QAC3B,aAAa,EAAE,oBAAa,CAAC,MAAM;QACnC,SAAS,EAAE,gBAAgB;QAC3B,aAAa,EAAE,gBAAgB;QAC/B,QAAQ,EAAE,UAAU;QACpB,YAAY,EAAE,aAAa;KAC5B;IACD,UAAU,EAAE;QACV,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACvB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC3B,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC3B,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC7B,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC7B,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACzC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACzC,cAAc,EAAE;YACd,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,CAAC;SACb;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,UAAU,EAAE;oBACV,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,EAAE;iBACf;gBACD,QAAQ,EAAE;oBACR,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,EAAE;iBACf;aACF;SACF;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,MAAM,EAAE;oBACN,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE;wBACL,IAAI,EAAE,QAAQ;qBACf;iBACF;aACF;SACF;KACF;CACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simitgroup/simpleapp-generator",
3
- "version": "2.0.3g-alpha",
3
+ "version": "2.0.3i-alpha",
4
4
  "description": "frontend nuxtjs and backend nests code generator using jsonschema.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -30,6 +30,10 @@ export const customfield: SchemaType = {
30
30
  jsonSchema: {
31
31
  type: 'object',
32
32
  properties: {}
33
+ },
34
+ uiSchema: {
35
+ type: 'object',
36
+ properties: {}
33
37
  }
34
38
  }
35
39
  },
@@ -14,6 +14,7 @@
14
14
  v-bind="<CalendarProps>componentProps"
15
15
  :select-other-months="true"
16
16
  pt:pcInputText:root="w-full"
17
+ class="w-full"
17
18
  @update:model-value="updateDateTime"
18
19
  />
19
20
  </template>
@@ -37,14 +38,10 @@ const modelValue = defineModel<string>({ required: true });
37
38
  const datetimevalue = ref<Date>();
38
39
 
39
40
  const refreshFromParent = () => {
40
- if (modelValue.value === undefined || modelValue.value == "")
41
- datetimevalue.value = undefined;
41
+ if (modelValue.value === undefined || modelValue.value == "") datetimevalue.value = undefined;
42
42
  else if (props.type == "time")
43
- datetimevalue.value = stringToDate(
44
- "2000-01-01 " + (modelValue.value ?? "00:00:00"),
45
- );
46
- else if (props.type == "date")
47
- datetimevalue.value = stringToDate(modelValue.value + "T00:00:00");
43
+ datetimevalue.value = stringToDate("2000-01-01 " + (modelValue.value ?? "00:00:00"));
44
+ else if (props.type == "date") datetimevalue.value = stringToDate(modelValue.value + "T00:00:00");
48
45
  else datetimevalue.value = stringToDate(modelValue.value);
49
46
  };
50
47
 
@@ -1,12 +1,18 @@
1
1
  <template>
2
- <form class="simpleapp-form" @submit.prevent="true">
3
- <slot name="default" :data="document.getData()" :getField="getField"></slot>
2
+ <form
3
+ class="simpleapp-form"
4
+ @submit.prevent="true"
5
+ >
6
+ <slot
7
+ name="default"
8
+ :data="document.getData()"
9
+ :getField="getField"
10
+ ></slot>
4
11
  <slot name="customField">
5
- <CustomFieldFormSection
12
+ <SimpleAppCustomFieldForm
6
13
  v-if="document.schema.properties.more"
7
- :customFieldJsonSchema="document.schema.properties.more"
8
- :data="document.getData().more"
9
- :handleGetField="getField"
14
+ :document="document"
15
+ :readonly="isreadonly"
10
16
  />
11
17
  </slot>
12
18
  </form>
@@ -18,12 +24,12 @@
18
24
  * last change 2023-10-28
19
25
  * Author: Ks Tan
20
26
  */
27
+ import type { JSONSchema7 } from "json-schema";
21
28
  import jsonpath from "jsonpath";
29
+ import _ from "lodash";
22
30
  import { SimpleAppClient } from "~/simpleapp/generate/clients/SimpleAppClient";
23
- import type { JSONSchema7, JSONSchema7Definition } from "json-schema";
24
31
  import * as alldefaults from "~/simpleapp/generate/defaults";
25
- import _, { upperFirst } from "lodash";
26
- import CustomFieldFormSection from "~/simpleapp/generate/features/customField/components/CustomFieldFormSection.vue";
32
+
27
33
  const props = defineProps<{
28
34
  document: SimpleAppClient<any, any>;
29
35
  readonly?: boolean;
@@ -32,9 +38,7 @@ if (!props.document) {
32
38
  throw "undefine SimpleAppForm property 'document'";
33
39
  }
34
40
 
35
- const isreadonly = computed(() =>
36
- props.readonly ? props.readonly : props.document.isReadOnly(),
37
- );
41
+ const isreadonly = computed(() => (props.readonly ? props.readonly : props.document.isReadOnly()));
38
42
 
39
43
  // const obj = {schema:props.schema,data: props.schema}
40
44
  const getField = (path: string) => {
@@ -121,10 +125,7 @@ const getInstancePath = (schema: any, path: string) => {
121
125
  // let paths = path.replace('#/','').split('/')
122
126
  // return '/'+paths[1]
123
127
  };
124
- const getPathObject = (
125
- schema: JSONSchema7,
126
- path: string,
127
- ): JSONSchema7 | undefined => {
128
+ const getPathObject = (schema: JSONSchema7, path: string): JSONSchema7 | undefined => {
128
129
  // console.log("path",path)
129
130
  if (!path || !path.includes("#/properties")) {
130
131
  console.error("unknown path");
@@ -1,161 +1,163 @@
1
1
  <template>
2
- <form class="simpleapp-form" @submit.prevent="true">
3
- <slot name="header"><h3 class="flex flex-col">{{ title }}</h3></slot>
4
- <slot name="default" :getField="getField" :validate="validate"></slot>
5
- </form>
2
+ <form
3
+ class="simpleapp-form"
4
+ @submit.prevent="true"
5
+ >
6
+ <slot name="header"
7
+ ><h3 class="flex flex-col">{{ title }}</h3></slot
8
+ >
9
+ <slot
10
+ name="default"
11
+ :getField="getField"
12
+ :validate="validate"
13
+ ></slot>
14
+ </form>
6
15
  </template>
7
- <script setup lang="ts" >
16
+ <script setup lang="ts">
8
17
  /**
9
18
  * This file was automatically generated by simpleapp generator. Every
10
19
  * MODIFICATION OVERRIDE BY GENERATEOR
11
20
  * last change 2023-10-28
12
21
  * Author: Ks Tan
13
22
  */
14
- import type { JSONSchema7,JSONSchema7Definition } from 'json-schema';
15
- import { getValidateService } from "~/simpleapp/generate/sharelibs/validate";
16
- import _ from 'lodash'
23
+ import { getValidateService } from "@simtrain/shared";
24
+ import type { JSONSchema7, JSONSchema7Definition } from "json-schema";
25
+ import _ from "lodash";
17
26
 
18
- const props = defineProps<{
19
- title?:string,
20
- schema:JSONSchema7,
21
- data:any,
22
- // document: SimpleAppClient<any,any>
23
- readonly?:boolean
24
- }>()
25
- if(!props.schema){
26
- throw "undefine jsonschema property 'schema'"
27
- }
28
- const formerrors = ref<any>({})
29
- const getField = (path:string)=>{
30
- const schema = props.schema
31
- const fieldsetting = getPathObject(schema,path)
32
-
33
- return {
34
- path: path,
35
- key: _.last(path.split('/')),
36
- instancepath: getInstancePath(schema,path),
37
- fieldsetting: fieldsetting,
38
- isrequired: getIsRequired(schema,path),
39
- errors: formerrors,
40
- readonly: props.readonly
41
- } //as SimpleAppFieldSetting
42
- }
27
+ const props = defineProps<{
28
+ title?: string;
29
+ schema: JSONSchema7;
30
+ data: any;
31
+ // document: SimpleAppClient<any,any>
32
+ readonly?: boolean;
33
+ }>();
34
+ if (!props.schema) {
35
+ throw "undefine jsonschema property 'schema'";
36
+ }
37
+ const formerrors = ref<any>({});
38
+ const getField = (path: string) => {
39
+ const schema = props.schema;
40
+ const fieldsetting = getPathObject(schema, path);
43
41
 
44
-
45
- const getIsRequired=(schema:any,path:string)=>{
46
- if(!path){
47
- console.error('unknown path')
48
- return 'xx'
49
- }
42
+ return {
43
+ path: path,
44
+ key: _.last(path.split("/")),
45
+ instancepath: getInstancePath(schema, path),
46
+ fieldsetting: fieldsetting,
47
+ isrequired: getIsRequired(schema, path),
48
+ errors: formerrors,
49
+ readonly: props.readonly,
50
+ }; //as SimpleAppFieldSetting
51
+ };
50
52
 
51
- try{
52
- let paths = path.replace('#/','').split('/')
53
- const fieldname = paths[paths.length-1]
54
- paths = paths.slice(0, -2);
55
- let tmp = schema
56
- for(let i=0;i<paths.length;i++){
57
- tmp = tmp[paths[i]]
58
-
59
- }
60
- if(Array.isArray(tmp['required']) ) {
61
- const arr:string[] = tmp['required']
62
- return arr.includes (fieldname)
63
- }else{
64
- return false
65
- }
53
+ const getIsRequired = (schema: any, path: string) => {
54
+ if (!path) {
55
+ console.error("unknown path");
56
+ return "xx";
57
+ }
66
58
 
67
- // console.log("get instance path",instancepath)
68
-
69
- // return tmp
70
- }catch(err:any){
71
- console.error(err.message)
72
- }
59
+ try {
60
+ let paths = path.replace("#/", "").split("/");
61
+ const fieldname = paths[paths.length - 1];
62
+ paths = paths.slice(0, -2);
63
+ let tmp = schema;
64
+ for (let i = 0; i < paths.length; i++) {
65
+ tmp = tmp[paths[i]];
73
66
  }
74
- const getInstancePath=(schema:any,path:string)=>{
75
- if(!path){
76
- console.error('unknown path')
77
- return 'yy'
67
+ if (Array.isArray(tmp["required"])) {
68
+ const arr: string[] = tmp["required"];
69
+ return arr.includes(fieldname);
70
+ } else {
71
+ return false;
78
72
  }
79
- try{
80
- let paths = path.replace('#/','').split('/')
81
- let tmp = schema
82
- let instancepath=''
83
- for(let i=0;i<paths.length;i++){
84
- tmp = tmp[paths[i]]
85
- if(tmp['type'] && paths[i] !='items'){
86
- instancepath=instancepath+'/'+paths[i]
87
- }
88
- }
89
73
 
90
- // console.log("get instance path",instancepath)
91
- return instancepath
92
- // return tmp
93
- }catch(err:any){
94
- console.error(err.message)
74
+ // console.log("get instance path",instancepath)
75
+
76
+ // return tmp
77
+ } catch (err: any) {
78
+ console.error(err.message);
79
+ }
80
+ };
81
+ const getInstancePath = (schema: any, path: string) => {
82
+ if (!path) {
83
+ console.error("unknown path");
84
+ return "yy";
85
+ }
86
+ try {
87
+ let paths = path.replace("#/", "").split("/");
88
+ let tmp = schema;
89
+ let instancepath = "";
90
+ for (let i = 0; i < paths.length; i++) {
91
+ tmp = tmp[paths[i]];
92
+ if (tmp["type"] && paths[i] != "items") {
93
+ instancepath = instancepath + "/" + paths[i];
94
+ }
95
95
  }
96
96
 
97
+ // console.log("get instance path",instancepath)
98
+ return instancepath;
99
+ // return tmp
100
+ } catch (err: any) {
101
+ console.error(err.message);
102
+ }
97
103
 
98
- // let paths = path.replace('#/','').split('/')
99
- // return '/'+paths[1]
100
- }
101
- const getPathObject=(schema:JSONSchema7,path:string):JSONSchema7|undefined=>{
102
- // console.log("path",path)
103
- if(!path){
104
- console.error('unknown path')
105
- return undefined
104
+ // let paths = path.replace('#/','').split('/')
105
+ // return '/'+paths[1]
106
+ };
107
+ const getPathObject = (schema: JSONSchema7, path: string): JSONSchema7 | undefined => {
108
+ // console.log("path",path)
109
+ if (!path) {
110
+ console.error("unknown path");
111
+ return undefined;
112
+ }
113
+ try {
114
+ let paths: string[] = path.replace("#/", "").split("/");
115
+ let tmp: JSONSchema7Definition = schema;
116
+ // console.log(path)
117
+ for (let i = 0; i < paths.length; i++) {
118
+ //silly code, but it seems require to avoid typescript complaint.
119
+ //ultimately it is to obtain result as "tmp=tmp[path[i]]"
120
+ const key1 = paths[i] as keyof JSONSchema7;
121
+ let jsonkey: keyof JSONSchema7 = key1;
122
+ let obj: JSONSchema7 = {} as JSONSchema7;
123
+ Object.assign(obj, tmp[jsonkey]);
124
+ tmp = { ...obj };
106
125
  }
107
- try{
108
- let paths:string[] = path.replace('#/','').split('/')
109
- let tmp :JSONSchema7Definition= schema
110
- // console.log(path)
111
- for(let i=0;i<paths.length;i++){
112
-
113
- //silly code, but it seems require to avoid typescript complaint.
114
- //ultimately it is to obtain result as "tmp=tmp[path[i]]"
115
- const key1 = paths[i] as keyof JSONSchema7
116
- let jsonkey: keyof JSONSchema7 = key1
117
- let obj:JSONSchema7 = {} as JSONSchema7
118
- Object.assign(obj,tmp[jsonkey])
119
- tmp = {...obj}
120
- }
121
- // console.log('final ',path,tmp)
122
- return tmp
123
- }catch(err:any){
124
- console.error(err.message)
125
-
126
- }
127
- }
126
+ // console.log('final ',path,tmp)
127
+ return tmp;
128
+ } catch (err: any) {
129
+ console.error(err.message);
130
+ }
131
+ };
128
132
 
133
+ const validate = (callback: Function) => {
134
+ const ajv = getValidateService();
129
135
 
130
- const validate=(callback:Function) => {
131
- const ajv = getValidateService();
132
-
133
- // this.errorlist.value = {};
134
- // this.hook('pre-validation', this.data.value);
135
- const validate = ajv.compile(props.schema);
136
- // console.log("validate data",props.data)
137
- const valid = validate(props.data);
138
- if (!valid) {
139
- const errors = validate.errors;
140
- const tmp: { [key: string]: any } = {};
141
- if (errors) {
142
- for (let i = 0; i < errors?.length; i++) {
143
- const key: string = errors[i]['instancePath'];
144
- if (!tmp[key]) {
145
- tmp[key] = [];
146
- }
147
- tmp[key].push(errors[i]);
136
+ // this.errorlist.value = {};
137
+ // this.hook('pre-validation', this.data.value);
138
+ const validate = ajv.compile(props.schema);
139
+ // console.log("validate data",props.data)
140
+ const valid = validate(props.data);
141
+ if (!valid) {
142
+ const errors = validate.errors;
143
+ const tmp: { [key: string]: any } = {};
144
+ if (errors) {
145
+ for (let i = 0; i < errors?.length; i++) {
146
+ const key: string = errors[i]["instancePath"];
147
+ if (!tmp[key]) {
148
+ tmp[key] = [];
148
149
  }
150
+ tmp[key].push(errors[i]);
149
151
  }
150
- formerrors.value = tmp;
151
- console.error(formerrors.value );
152
-
153
- // return validate.errors;
154
- callback(formerrors.value )
155
- } else {
156
- // this.hook('post-validation', this.data.value);
157
- callback(false)
158
152
  }
159
- }
153
+ formerrors.value = tmp;
154
+ console.error(formerrors.value);
160
155
 
161
- </script>
156
+ // return validate.errors;
157
+ callback(formerrors.value);
158
+ } else {
159
+ // this.hook('post-validation', this.data.value);
160
+ callback(false);
161
+ }
162
+ };
163
+ </script>
@@ -36,28 +36,25 @@ function handleChange(newValue: any) {
36
36
  const actions = remoteConfig?.onChangeAction ?? [];
37
37
  if (!Array.isArray(actions) || actions.length === 0) return;
38
38
 
39
- const modelObject = props.setting.modelObject ?? {};
40
- const selectedOption = options.value.find(
41
- (opt: any) => opt.value === newValue,
42
- );
39
+ const selectedOption = options.value.find((opt: any) => opt.value === newValue);
43
40
 
44
41
  for (const action of actions) {
45
42
  if (!action.updateField) continue;
46
43
 
47
44
  let updateVal: any = action.updateValue;
48
45
 
49
- if (
50
- typeof updateVal === "string" &&
51
- updateVal.startsWith("{") &&
52
- updateVal.endsWith("}")
53
- ) {
46
+ if (typeof updateVal === "string" && updateVal.startsWith("{") && updateVal.endsWith("}")) {
54
47
  // ✅ Replace {path.to.value} using selectedOption
55
48
  const path = updateVal.slice(1, -1).trim();
56
49
  const resolvedVal = resolvePath(selectedOption ?? {}, path);
57
50
  updateVal = resolvedVal !== undefined ? resolvedVal : "";
58
51
  }
59
52
 
60
- setPath(modelObject, action.updateField, updateVal);
53
+ if (props.setting.handleFieldChange) {
54
+ props.setting.handleFieldChange(action.updateField, updateVal);
55
+ } else {
56
+ setPath(props.setting.modelObject ?? {}, action.updateField, updateVal);
57
+ }
61
58
  }
62
59
  }
63
60
 
@@ -0,0 +1,13 @@
1
+ /**
2
+ * This file was automatically generated by simpleapp generator. Every
3
+ * MODIFICATION OVERRIDE BY GENERATEOR
4
+ * last change 2026-05-13
5
+ */
6
+
7
+ import { defineNuxtPlugin } from "#app";
8
+
9
+ export default defineNuxtPlugin(() => {
10
+ onNuxtReady(() => {
11
+ window.__NUXT__ = undefined;
12
+ });
13
+ });
@@ -0,0 +1,86 @@
1
+ /**
2
+ * This file was automatically generated by simpleapp generator. Every
3
+ * MODIFICATION OVERRIDE BY GENERATEOR
4
+ * last change 2026-05-13
5
+ */
6
+
7
+ import { defineNuxtPlugin } from "#app";
8
+ import axios, { type AxiosError } from "axios";
9
+
10
+ function extractErrorPayload(error: AxiosError): {
11
+ statusCode: number;
12
+ statusMessage: string;
13
+ message: string;
14
+ } {
15
+ const data = error.response?.data as Record<string, any> | undefined;
16
+ if (data?.data?.message) {
17
+ return {
18
+ statusCode: data.data.status,
19
+ statusMessage: data.data.name,
20
+ message: data.data.message,
21
+ };
22
+ }
23
+ if (data) {
24
+ return {
25
+ statusCode: data.statusCode,
26
+ statusMessage: data.message,
27
+ message: data.statusMessage,
28
+ };
29
+ }
30
+ return {
31
+ statusCode: error.status ?? 0,
32
+ statusMessage: error.name,
33
+ message: error.message,
34
+ };
35
+ }
36
+
37
+ export default defineNuxtPlugin(() => {
38
+ const axiosInstance = axios.create({ timeout: 10000 });
39
+
40
+ axiosInstance.interceptors.response.use(
41
+ (response) => response,
42
+ (error: AxiosError) => {
43
+ const status = error.response?.status;
44
+
45
+ // 401: unauthenticated / session expired
46
+ // 302: backend redirecting to /login instead of returning 401 (legacy server behaviour)
47
+ // Both cases: let the caller handle the login flow
48
+ if (status === 401 || status === 302) {
49
+ return Promise.reject(error);
50
+ }
51
+
52
+ // 403: forbidden — user lacks permission, hard-redirect to home
53
+ if (status === 403) {
54
+ navigateTo("/", { external: true });
55
+ return Promise.reject(error);
56
+ }
57
+
58
+ // 402: subscription/plan expired — show a fatal system-expired screen
59
+ if (status === 402) {
60
+ throw createError({
61
+ statusCode: 402,
62
+ statusMessage: "System Expired",
63
+ message: error.response?.statusText ?? "",
64
+ fatal: true,
65
+ });
66
+ }
67
+
68
+ if (error.response) {
69
+ const payload = extractErrorPayload(error);
70
+ throw createError({ ...payload, fatal: true });
71
+ }
72
+
73
+ if (error.code) {
74
+ throw createError({
75
+ statusCode: 500,
76
+ statusMessage: error.message,
77
+ fatal: true,
78
+ });
79
+ }
80
+
81
+ throw createError({ statusCode: 500, statusMessage: "Internal server error", fatal: true });
82
+ },
83
+ );
84
+
85
+ return { provide: { axios: axiosInstance } };
86
+ });
@@ -0,0 +1,20 @@
1
+ /**
2
+ * This file was automatically generated by simpleapp generator. Every
3
+ * MODIFICATION OVERRIDE BY GENERATEOR
4
+ * last change 2026-05-13
5
+ */
6
+
7
+ import { defineNuxtPlugin } from "#app";
8
+ import { EventType } from "~/types";
9
+ import mitt from "mitt";
10
+
11
+ const emitter = mitt<EventType>();
12
+
13
+ export default defineNuxtPlugin(() => {
14
+ return {
15
+ provide: {
16
+ event: emitter.emit,
17
+ listen: emitter.on,
18
+ },
19
+ };
20
+ });
@@ -0,0 +1,18 @@
1
+ /**
2
+ * This file was automatically generated by simpleapp generator. Every
3
+ * MODIFICATION OVERRIDE BY GENERATEOR
4
+ * last change 2026-05-13
5
+ */
6
+
7
+ import { defineNuxtPlugin } from "#app";
8
+ import { useConfirm } from "primevue/useconfirm";
9
+ import { useDialog } from "primevue/usedialog";
10
+
11
+ export default defineNuxtPlugin(() => {
12
+ return {
13
+ provide: {
14
+ confirm: useConfirm(),
15
+ dialog: useDialog,
16
+ },
17
+ };
18
+ });
@@ -4,23 +4,23 @@
4
4
  * last change 2024-03-08
5
5
  * Author: Ks Tan
6
6
  */
7
- import { ref } from "vue";
8
- import type { Ref } from "vue";
7
+ import type { VerticalLayout } from "@jsonforms/core";
8
+ import { getValidateService } from "@simtrain/shared";
9
9
  import type { AxiosResponse } from "axios";
10
+ import { cloneDeep, isEmpty } from "lodash";
11
+ import type { Ref } from "vue";
12
+ import { ref, WatchHandle } from "vue";
10
13
  import {
11
- SearchBody,
12
- TextSearchBody,
14
+ DynamicObject,
15
+ FormActions,
13
16
  NotificationStatus,
14
17
  SchemaType,
15
- FormActions,
16
- DynamicObject,
18
+ SearchBody,
19
+ TextSearchBody,
17
20
  } from "~/types";
18
- import { getValidateService } from "~/simpleapp/generate/sharelibs/validate";
19
- import { WatchHandle } from "vue";
21
+ import { CustomFieldDataModeEnum } from "../features/customField/enums/common";
20
22
  import { CustomFieldService } from "../features/customField/services/CustomFieldService";
21
23
  import { CustomFieldDataMode } from "../features/customField/types/common";
22
- import { CustomFieldDataModeEnum } from "../features/customField/enums/common";
23
- import { cloneDeep, isEmpty } from "lodash";
24
24
 
25
25
  // import { useToast, } from 'primevue/usetoast';
26
26
  // import type { ToastMessageOptions } from 'primevue/toast';
@@ -58,6 +58,7 @@ export class SimpleAppClient<
58
58
  // FLAG::CUSTOM_FIELD
59
59
  protected _customFieldWatch: WatchHandle | null = null;
60
60
  private _customFieldService = new CustomFieldService();
61
+ public customFieldUiSchema: VerticalLayout | undefined = undefined;
61
62
 
62
63
  constructor(apiobj: TApi, doctype: string, docname: string) {
63
64
  this.docapi = apiobj;
@@ -67,10 +68,8 @@ export class SimpleAppClient<
67
68
  }
68
69
  isReady = () => this.ready;
69
70
  getDocType = () => this.doctype;
70
- getDocName = (capFirst: boolean = false) =>
71
- capFirst ? upperFirst(this.docname) : this.docname;
72
- getResourceName = () =>
73
- upperFirst(this.schema["x-simpleapp-config"]?.resourceName ?? "");
71
+ getDocName = (capFirst: boolean = false) => (capFirst ? upperFirst(this.docname) : this.docname);
72
+ getResourceName = () => upperFirst(this.schema["x-simpleapp-config"]?.resourceName ?? "");
74
73
  setNew = () => {};
75
74
  isNew = () => this.data.value?.created == "";
76
75
  setSchema = (schema: SchemaType) => (this.schema = schema);
@@ -115,9 +114,7 @@ export class SimpleAppClient<
115
114
  const attributeName = keys[keys.length - 1];
116
115
  if (allowedPatchAttributes.includes(attributeName)) {
117
116
  if (attributeName === "required" && Array.isArray(value)) {
118
- target.required = Array.from(
119
- new Set([...(target.required ?? []), ...value]),
120
- );
117
+ target.required = Array.from(new Set([...(target.required ?? []), ...value]));
121
118
  } else {
122
119
  target[attributeName] = value;
123
120
  }
@@ -132,16 +129,13 @@ export class SimpleAppClient<
132
129
  prepareCustomFieldJsonSchema() {
133
130
  this.prepareSchemaPatches();
134
131
 
135
- const resp = this._customFieldService.prepareCustomFieldJsonSchema(
136
- this.docname,
137
- );
138
- this.schema.properties.more = resp;
132
+ const { jsonSchema, uiSchema } = this._customFieldService.prepareCustomFieldJsonSchema(this.docname);
133
+ this.schema.properties.more = jsonSchema;
134
+ this.customFieldUiSchema = uiSchema;
139
135
  }
140
136
 
141
- prepareCustomFieldData<T extends DynamicObject>(
142
- mode: CustomFieldDataMode,
143
- data: T,
144
- ) {
137
+ prepareCustomFieldData<T extends DynamicObject>(mode: CustomFieldDataMode, data: T) {
138
+ if (!data || typeof data !== "object") return data;
145
139
  const customFieldData = this._customFieldService.prepareCustomFieldData(
146
140
  this.docname,
147
141
  mode,
@@ -1,83 +1,108 @@
1
+ import { type ControlElement, type GroupLayout, type UISchemaElement, type VerticalLayout } from "@jsonforms/core";
1
2
  import _ from "lodash";
3
+ import { DynamicObject, SimpleAppJSONSchema7Definition } from "~/types";
4
+ import { CustomFieldDataModeEnum } from "../enums/common";
2
5
  import {
3
6
  CustomFieldDataMode,
4
7
  CustomFieldMoreSchema,
5
8
  CustomFieldMoreSchemaGroup,
6
9
  } from "../types/common";
7
- import { CustomFieldDataModeEnum } from "../enums/common";
8
- import { DynamicObject, SimpleAppJSONSchema7Definition } from "~/types";
9
10
 
10
11
  export class CustomFieldService {
11
12
  // =============================== Prepare Schema Function ===============================
12
- prepareCustomFieldJsonSchema(collectionName: string) {
13
- const customFieldFromDB = this.findCustomFieldSchemaFromDB(collectionName);
14
- const customFieldFromMiniApp =
15
- this.findCustomFieldSchemaFromMiniApp(collectionName);
16
-
17
- if (customFieldFromDB && !_.isEmpty(customFieldFromDB)) {
18
- }
13
+ prepareCustomFieldJsonSchema(collectionName: string): { jsonSchema: CustomFieldMoreSchema; uiSchema: VerticalLayout | undefined } {
14
+ const fromDB = this.findCustomFieldSchemaFromDB(collectionName);
15
+ const fromMiniApp = this.findCustomFieldSchemaFromMiniApp(collectionName);
19
16
 
20
- const schema: CustomFieldMoreSchema = {
17
+ const jsonSchema: CustomFieldMoreSchema = {
21
18
  type: "object",
22
19
  properties: {
23
- ...customFieldFromDB,
24
- ...customFieldFromMiniApp,
20
+ ...fromDB.jsonSchema,
21
+ ...fromMiniApp.jsonSchema,
25
22
  },
26
23
  };
27
24
 
28
- return schema;
25
+ const uiSchema = this.buildMoreUiSchema({ ...fromDB.uiSchema, ...fromMiniApp.uiSchema });
26
+
27
+ return { jsonSchema, uiSchema };
29
28
  }
30
29
 
31
30
  prepareSchemaPatches(collectionName: string) {
32
31
  return this.findSchemaPatchFromMiniApp(collectionName);
33
32
  }
34
33
 
35
- private findCustomFieldSchemaFromDB(collectionName: string) {
34
+ private findCustomFieldSchemaFromDB(collectionName: string): { jsonSchema: CustomFieldMoreSchemaGroup; uiSchema: Record<string, VerticalLayout> } {
36
35
  const { $customFieldStore } = useNuxtApp();
37
36
  if (!$customFieldStore.data || _.isEmpty($customFieldStore.data)) {
38
- return {};
37
+ return { jsonSchema: {}, uiSchema: {} };
39
38
  }
40
39
 
41
40
  const customField = $customFieldStore.findByCollectionName(collectionName);
42
41
  if (!customField) {
43
- return {};
42
+ return { jsonSchema: {}, uiSchema: {} };
44
43
  }
45
44
 
46
- if (
47
- !customField?.form?.jsonSchema ||
48
- _.isEmpty(customField?.form?.jsonSchema)
49
- ) {
50
- return {};
45
+ if (!customField?.form?.jsonSchema || _.isEmpty(customField?.form?.jsonSchema)) {
46
+ return { jsonSchema: {}, uiSchema: {} };
51
47
  }
52
48
 
53
- const schema: CustomFieldMoreSchemaGroup = {
54
- default: {
55
- title: "Custom Field",
56
- ...customField.form.jsonSchema,
49
+ return {
50
+ jsonSchema: {
51
+ default: {
52
+ title: "Custom Field",
53
+ ...customField.form.jsonSchema,
54
+ },
57
55
  },
56
+ uiSchema: customField.form.uiSchema ? { default: customField.form.uiSchema as VerticalLayout } : {},
58
57
  };
59
-
60
- return schema;
61
58
  }
62
59
 
63
- private findCustomFieldSchemaFromMiniApp(collectionName: string) {
64
- const schema: CustomFieldMoreSchemaGroup = {};
60
+ private findCustomFieldSchemaFromMiniApp(collectionName: string): { jsonSchema: CustomFieldMoreSchemaGroup; uiSchema: Record<string, VerticalLayout> } {
61
+ const jsonSchema: CustomFieldMoreSchemaGroup = {};
62
+ const uiSchema: Record<string, VerticalLayout> = {};
65
63
 
66
64
  const { $miniAppStore } = useNuxtApp();
67
65
 
68
66
  const miniAppForms = $miniAppStore.getForm(collectionName);
69
67
  if (!miniAppForms || miniAppForms.length <= 0) {
70
- return schema;
68
+ return { jsonSchema, uiSchema };
71
69
  }
72
70
 
73
71
  for (let i = 0; i < miniAppForms.length; i++) {
74
- const miniAppItem = miniAppForms[i];
75
- const { miniAppCode, jsonSchema } = miniAppItem;
72
+ const miniAppItem = miniAppForms[i] as any;
73
+ const { miniAppCode, jsonSchema: itemJsonSchema, uiSchema: itemUiSchema } = miniAppItem;
74
+
75
+ jsonSchema[miniAppCode] = itemJsonSchema as SimpleAppJSONSchema7Definition;
76
+ if (itemUiSchema) uiSchema[miniAppCode] = itemUiSchema as VerticalLayout;
77
+ }
78
+
79
+ return { jsonSchema, uiSchema };
80
+ }
76
81
 
77
- schema[miniAppCode] = jsonSchema as SimpleAppJSONSchema7Definition;
82
+ private buildMoreUiSchema(groupUiSchemas: Record<string, VerticalLayout>): VerticalLayout | undefined {
83
+ const elements: UISchemaElement[] = [];
84
+ for (const [groupKey, uischema] of Object.entries(groupUiSchemas)) {
85
+ if (!uischema?.elements?.length) continue;
86
+ const group: GroupLayout = {
87
+ type: "Group",
88
+ label: groupKey === "default" ? "Custom Field" : groupKey,
89
+ options: { cols: "grid-cols-1" },
90
+ elements: [this.prefixElement(uischema, groupKey)],
91
+ };
92
+ elements.push(group);
78
93
  }
94
+ return elements.length ? { type: "VerticalLayout", elements } : undefined;
95
+ }
79
96
 
80
- return schema;
97
+ private prefixElement(elem: UISchemaElement, groupKey: string): UISchemaElement {
98
+ if (elem.type === "Control") {
99
+ const ctrl = elem as ControlElement;
100
+ return { ...ctrl, scope: ctrl.scope.replace("#/properties/", `#/properties/${groupKey}/properties/`) };
101
+ }
102
+ if ("elements" in elem && Array.isArray(elem.elements)) {
103
+ return { ...elem, elements: (elem as any).elements.map((e: UISchemaElement) => this.prefixElement(e, groupKey)) } as UISchemaElement;
104
+ }
105
+ return elem;
81
106
  }
82
107
 
83
108
  private findSchemaPatchFromMiniApp(collectionName: string) {
@@ -107,11 +132,7 @@ export class CustomFieldService {
107
132
  customSchema: CustomFieldMoreSchema | undefined,
108
133
  resourceData: T | undefined,
109
134
  ): T | undefined {
110
- if (
111
- !customSchema ||
112
- !customSchema?.properties ||
113
- _.isEmpty(customSchema.properties)
114
- ) {
135
+ if (!customSchema || !customSchema?.properties || _.isEmpty(customSchema.properties)) {
115
136
  return resourceData;
116
137
  }
117
138
 
@@ -125,10 +146,7 @@ export class CustomFieldService {
125
146
  return this.prepareCustomFieldWithDefaultData<T>(customSchema);
126
147
  }
127
148
 
128
- return this.prepareCustomFieldWithExistingData(
129
- customSchema,
130
- resourceData,
131
- );
149
+ return this.prepareCustomFieldWithExistingData(customSchema, resourceData);
132
150
  break;
133
151
  }
134
152
  }
@@ -137,9 +155,7 @@ export class CustomFieldService {
137
155
  customSchema: CustomFieldMoreSchema,
138
156
  ) {
139
157
  const data: DynamicObject = {};
140
- for (const [groupName, groupItem] of Object.entries(
141
- customSchema.properties,
142
- )) {
158
+ for (const [groupName, groupItem] of Object.entries(customSchema.properties)) {
143
159
  const defaultData = this.generateDefaultData(groupItem);
144
160
 
145
161
  data[groupName] = defaultData;
@@ -153,14 +169,9 @@ export class CustomFieldService {
153
169
  resourceData: T,
154
170
  ) {
155
171
  const data: DynamicObject = {};
156
- for (const [groupName, groupItem] of Object.entries(
157
- customSchema.properties,
158
- )) {
172
+ for (const [groupName, groupItem] of Object.entries(customSchema.properties)) {
159
173
  const defaultData = this.generateDefaultData(groupItem);
160
- const mergedData = this.mergeWithDefault(
161
- defaultData,
162
- resourceData?.[groupName],
163
- );
174
+ const mergedData = this.mergeWithDefault(defaultData, resourceData?.[groupName]);
164
175
 
165
176
  data[groupName] = mergedData;
166
177
  }
@@ -193,11 +204,7 @@ export class CustomFieldService {
193
204
  const arr = [];
194
205
  const itemsCount = minItems > 0 ? 1 : 0;
195
206
  for (let i = 0; i < itemsCount; i++) {
196
- arr.push(
197
- this.generateDefaultData(
198
- itemSchema as SimpleAppJSONSchema7Definition,
199
- ),
200
- );
207
+ arr.push(this.generateDefaultData(itemSchema as SimpleAppJSONSchema7Definition));
201
208
  }
202
209
  return arr;
203
210
  }
@@ -220,10 +227,7 @@ export class CustomFieldService {
220
227
  }
221
228
  }
222
229
 
223
- private mergeWithDefault<T extends DynamicObject>(
224
- defaultData: T,
225
- collectionData: T | undefined,
226
- ) {
230
+ private mergeWithDefault<T extends DynamicObject>(defaultData: T, collectionData: T | undefined) {
227
231
  if (Array.isArray(defaultData)) {
228
232
  if (Array.isArray(collectionData)) {
229
233
  if (_.isEmpty(collectionData)) {
@@ -242,16 +246,11 @@ export class CustomFieldService {
242
246
  } else if (typeof defaultData === "object" && defaultData !== null) {
243
247
  const result: any = {};
244
248
  for (const key of Object.keys(defaultData)) {
245
- result[key] = this.mergeWithDefault(
246
- defaultData[key],
247
- collectionData?.[key],
248
- );
249
+ result[key] = this.mergeWithDefault(defaultData[key], collectionData?.[key]);
249
250
  }
250
251
  return result;
251
252
  } else {
252
- return typeof collectionData !== "undefined"
253
- ? collectionData
254
- : defaultData;
253
+ return typeof collectionData !== "undefined" ? collectionData : defaultData;
255
254
  }
256
255
  }
257
256
  }
@@ -1,15 +0,0 @@
1
- /**
2
- * This file was automatically generated by simpleapp generator during initialization. It is changable.
3
- * --remove-this-line-to-prevent-override--
4
- * last change 2024-02-22
5
- * author: Ks Tan
6
- */
7
- export default {
8
- welcome:'欢迎',
9
- welcomeSimpleApp: '你好,欢迎来到 SimpleApp',
10
- changeHomePageMsg: '改了这面',
11
- category: '类别',
12
- /*manually fix from df.ts.eta*/
13
- }
14
-
15
- // or
@@ -1,19 +0,0 @@
1
-
2
- export default {
3
- //auto generate from lang/default.ts
4
- <%let langkeys = Object.keys(it.lang) %>
5
- <% for(let l=0; l< langkeys.length; l++){ %>
6
- <% let key = langkeys[l] %>
7
- "<%=key%>" : <% if (typeof it.lang[key] === 'object') { %><%~ JSON.stringify(it.lang[key], null, 2) %><% } else { %>"<%~ it.lang[key] %>"<% } %>,
8
- <%}%>
9
-
10
-
11
- //auto generate from schema
12
- <% for(let i=0; i< it.allfields.length; i++){ %>
13
- <% let f = it.allfields[i] %>
14
- <% if(!it.lang[f]){%>
15
- '<%= f %>' : '<%= camelCaseToWords(f) %>',
16
- <%}%>
17
- <%}%>
18
-
19
- }
@@ -1,126 +0,0 @@
1
- /**
2
- * This file was automatically generated by simpleapp generator. Every
3
- * MODIFICATION OVERRIDE BY GENERATEOR
4
- * last change 2025-10-25
5
- * Author: Ks Tan
6
- */
7
- import { defineNuxtPlugin } from "#app";
8
- import axios from "axios";
9
- import { EventType } from "~/types";
10
- // import PrimeVue from "primevue/config";
11
- import mitt from "mitt";
12
- import { useConfirm } from "primevue/useconfirm";
13
- import { useDialog } from "primevue/usedialog";
14
-
15
- // import ToastService from 'primevue/toastservice';
16
- // import ConfirmationService from 'primevue/confirmationservice';
17
- // import Tooltip from 'primevue/tooltip';
18
- const emitter = mitt<EventType>();
19
- export default defineNuxtPlugin(async (nuxtApp) => {
20
- //hide __NUXT__ at client side.
21
- onNuxtReady(() => {
22
- window.__NUXT__ = undefined;
23
- });
24
- // useNuxtApp().vueApp.use(DialogService)
25
- //const { csrf } = useCsrf()
26
- //axios.defaults.headers.common = {"CSRF-TOKEN": csrf};
27
- const myaxios = axios.create({ timeout: 10000 });
28
- myaxios.interceptors.response.use(
29
- (response) => {
30
- return response;
31
- },
32
- (error) => {
33
- // console.log("error catch",error)
34
-
35
- if (error?.code && error.code == "ERR_BAD_REQUEST") {
36
- if (error.response && (error.response.status == 401 || error.response.status == 302)) {
37
- return Promise.reject(error);
38
- } else if (error.response && error.response.status == 403) {
39
- console.warn("error status 403, redirect to external link /");
40
- navigateTo("/", { external: true });
41
- } else if (error.response && error.response.status === 402) {
42
- const route = useRoute();
43
- // if (route.fullPath.endsWith("/billing")) {
44
- // return Promise.resolve({});
45
- // } else {
46
- throw createError({
47
- statusCode: error.response.status,
48
- statusMessage: "System Expired",
49
- message: error.response.statusText,
50
- });
51
- // }
52
- console.log(route);
53
- } else {
54
- console.error("axios ERR_BAD_REQUEST", error);
55
- let errorMsg = "";
56
- let errorCode = 0;
57
- let moreMsg = "";
58
- if (error.response?.data?.data?.message) {
59
- errorCode = error.response.data.data.status;
60
- moreMsg = error.response.data.data.message;
61
- errorMsg = error.response.data.data.name;
62
- } else if (error.response?.data) {
63
- errorCode = error.response.data.statusCode;
64
- moreMsg = error.response.data.statusMessage;
65
- errorMsg = error.response.data.message;
66
- } else {
67
- errorCode = error.status;
68
- moreMsg = error.message;
69
- errorMsg = error.name;
70
- }
71
-
72
- const errorData = {
73
- statusCode: errorCode,
74
- statusMessage: errorMsg,
75
- message: moreMsg,
76
- fatal: true,
77
- };
78
-
79
- // console.log(error.response)
80
- throw createError(errorData);
81
- }
82
- } else if (error.code) {
83
- throw createError({
84
- statusCode: error.code,
85
- statusMessage: error.message,
86
- fatal: true,
87
- });
88
- } else if (error.response && (error.response.status == 302 || error.response.status == 401)) {
89
- console.error("axios 302 session expired, start login flow");
90
- } else if (error.response && error.response.status) {
91
- let errmsg = error.response.message;
92
- let errorcode = error.response.status;
93
- if (error.response?.data && error.response?.data?.message) {
94
- errmsg = error.response.data.message;
95
- errorcode = error.response.data.statusCode;
96
- }
97
-
98
- throw createError({
99
- statusCode: errorcode,
100
- statusMessage: errmsg,
101
- fatal: true,
102
- });
103
- // return Promise.reject(error)
104
- } else {
105
- console.error("unknown error");
106
- throw createError({ statusCode: 500, statusMessage: "Internal server error" });
107
- }
108
- // if (error.response) {
109
- // console.error("Backend error response:", error.response.data);
110
- // } else {
111
- // console.error("Network error:", error);
112
- // }
113
- return Promise.reject(error);
114
- },
115
- );
116
- return {
117
- provide: {
118
- event: emitter.emit, // Will emit an event
119
- listen: emitter.on, // Will register a listener for an event
120
- axios: myaxios,
121
- confirm: useConfirm(),
122
- dialog: useDialog,
123
- },
124
- };
125
- //other components that you need
126
- });