@agung_dhewe/webapps 1.1.2

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 (130) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +2 -0
  3. package/jsconfig.json +10 -0
  4. package/libs/fgta5js-dist/fgta5js-v1.8.3.min.css +2 -0
  5. package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js +11 -0
  6. package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js.map +1 -0
  7. package/libs/fgta5js-dist/fonts/karla-italic-latin-ext.woff2 +0 -0
  8. package/libs/fgta5js-dist/fonts/karla-italic-latin.woff2 +0 -0
  9. package/libs/fgta5js-dist/fonts/karla-normal-latin-ext.woff2 +0 -0
  10. package/libs/fgta5js-dist/fonts/karla-normal-latin.woff2 +0 -0
  11. package/libs/fgta5js-dist/fonts/karla.css +142 -0
  12. package/libs/webmodule/module-edit.css +163 -0
  13. package/libs/webmodule/module-footer.css +22 -0
  14. package/libs/webmodule/module-list.css +25 -0
  15. package/libs/webmodule/module.css +52 -0
  16. package/libs/webmodule/module.js +195 -0
  17. package/libs/webmodule/pagehelper.mjs +45 -0
  18. package/modules/generator/appgen-components.mjs +142 -0
  19. package/modules/generator/appgen-icons.mjs +6 -0
  20. package/modules/generator/appgen-io.mjs +784 -0
  21. package/modules/generator/appgen-ui-search.mjs +173 -0
  22. package/modules/generator/appgen-ui-unique.mjs +153 -0
  23. package/modules/generator/appgen-ui.mjs +1181 -0
  24. package/modules/generator/generator-context.mjs +18 -0
  25. package/modules/generator/generator-designtemplate.html +1508 -0
  26. package/modules/generator/generator-ext.html +0 -0
  27. package/modules/generator/generator-ext.mjs +3 -0
  28. package/modules/generator/generator.css +642 -0
  29. package/modules/generator/generator.mjs +195 -0
  30. package/modules/generator/generator.png +0 -0
  31. package/modules/generator/generatorEdit.html +185 -0
  32. package/modules/generator/generatorEdit.mjs +238 -0
  33. package/modules/generator/generatorList.html +32 -0
  34. package/modules/generator/generatorList.mjs +243 -0
  35. package/modules/login/login.css +11 -0
  36. package/modules/login/login.html +12 -0
  37. package/modules/login/login.mjs +111 -0
  38. package/package.json +46 -0
  39. package/percobaan/simmpan-ke-minio.js +24 -0
  40. package/src/api.js +80 -0
  41. package/src/apis/generator.api.js +226 -0
  42. package/src/apis/login.api.js +109 -0
  43. package/src/bucket.js +24 -0
  44. package/src/context.js +26 -0
  45. package/src/datalog.sql +22 -0
  46. package/src/datarecords.js +0 -0
  47. package/src/db.js +61 -0
  48. package/src/generator/createApiExtenderModule.js +54 -0
  49. package/src/generator/createApiModule.js +218 -0
  50. package/src/generator/createIcon.js +62 -0
  51. package/src/generator/createInfoAboutExtender.js +42 -0
  52. package/src/generator/createInfoLogs.js +41 -0
  53. package/src/generator/createInfoRecordExtender.js +41 -0
  54. package/src/generator/createModuleContext.js +48 -0
  55. package/src/generator/createModuleDetilEditHtml.js +110 -0
  56. package/src/generator/createModuleDetilEditMjs.js +172 -0
  57. package/src/generator/createModuleDetilListHtml.js +146 -0
  58. package/src/generator/createModuleDetilListMjs.js +73 -0
  59. package/src/generator/createModuleEjs.js +51 -0
  60. package/src/generator/createModuleExtenderHtml.js +43 -0
  61. package/src/generator/createModuleExtenderMjs.js +43 -0
  62. package/src/generator/createModuleHeaderEditHtml.js +148 -0
  63. package/src/generator/createModuleHeaderEditMjs.js +197 -0
  64. package/src/generator/createModuleHeaderListHtml.js +144 -0
  65. package/src/generator/createModuleHeaderListMjs.js +67 -0
  66. package/src/generator/createModuleMjs.js +67 -0
  67. package/src/generator/createModuleRollup.js +42 -0
  68. package/src/generator/createProgramData.js +96 -0
  69. package/src/generator/createTable.js +156 -0
  70. package/src/generator/ddl.js +475 -0
  71. package/src/generator/helper.js +149 -0
  72. package/src/generator/templates/__rollup-module.ejs +90 -0
  73. package/src/generator/templates/api-extender-module.js.ejs +0 -0
  74. package/src/generator/templates/api-module.js.ejs +818 -0
  75. package/src/generator/templates/module-context.ejs +16 -0
  76. package/src/generator/templates/module-ext-about.ejs +1 -0
  77. package/src/generator/templates/module-ext-record.ejs +1 -0
  78. package/src/generator/templates/module-ext.html.ejs +3 -0
  79. package/src/generator/templates/module-ext.mjs.ejs +21 -0
  80. package/src/generator/templates/module-logs.ejs +14 -0
  81. package/src/generator/templates/module.ejs.ejs +48 -0
  82. package/src/generator/templates/module.mjs.ejs +256 -0
  83. package/src/generator/templates/moduleDetilEdit.html.ejs +34 -0
  84. package/src/generator/templates/moduleDetilEdit.mjs.ejs +792 -0
  85. package/src/generator/templates/moduleDetilList.html.ejs +26 -0
  86. package/src/generator/templates/moduleDetilList.mjs.ejs +319 -0
  87. package/src/generator/templates/moduleHeaderEdit.html.ejs +53 -0
  88. package/src/generator/templates/moduleHeaderEdit.mjs.ejs +807 -0
  89. package/src/generator/templates/moduleHeaderList.html.ejs +24 -0
  90. package/src/generator/templates/moduleHeaderList.mjs.ejs +308 -0
  91. package/src/generator/templates/sqlAddField.ejs +3 -0
  92. package/src/generator/templates/sqlAddForeignKey.ejs +12 -0
  93. package/src/generator/templates/sqlAddUniqueIndex.ejs +4 -0
  94. package/src/generator/templates/sqlCreateTable.ejs +9 -0
  95. package/src/generator/templates/sqlDropForeignKey.ejs +3 -0
  96. package/src/generator/templates/sqlDropUniqueIndex.ejs +4 -0
  97. package/src/generator/templates/sqlModifyField.ejs +6 -0
  98. package/src/generator/trygenerate.js +83 -0
  99. package/src/generator/worker.js +389 -0
  100. package/src/helper.js +82 -0
  101. package/src/logger.js +39 -0
  102. package/src/router.js +84 -0
  103. package/src/routers/defaultLoginApi.js +29 -0
  104. package/src/routers/defaultLoginAsset.js +18 -0
  105. package/src/routers/defaultLoginPage.js +36 -0
  106. package/src/routers/defaultRootIndex.js +16 -0
  107. package/src/routers/downloadHandler.js +51 -0
  108. package/src/routers/fileUploadApi.js +15 -0
  109. package/src/routers/generatorApi.js +30 -0
  110. package/src/routers/generatorAsset.js +18 -0
  111. package/src/routers/generatorPage.js +37 -0
  112. package/src/routers/handleError.js +43 -0
  113. package/src/routers/handleModuleNotfound.js +12 -0
  114. package/src/routers/moduleApi.js +34 -0
  115. package/src/routers/modulePage.js +102 -0
  116. package/src/sequencerdoc.js +311 -0
  117. package/src/sequencerline.js +214 -0
  118. package/src/session.js +57 -0
  119. package/src/startup.js +59 -0
  120. package/src/webapps.js +239 -0
  121. package/src/workermanager.js +83 -0
  122. package/templates/_lib_debug.ejs +11 -0
  123. package/templates/_lib_production.ejs +5 -0
  124. package/templates/application.page.ejs +143 -0
  125. package/templates/generator.page.ejs +131 -0
  126. package/templates/index.page.ejs +24 -0
  127. package/templates/login.page.ejs +102 -0
  128. package/templates/moduleError.ejs +16 -0
  129. package/templates/moduleNotfound.ejs +14 -0
  130. package/webapps.code-workspace +11 -0
@@ -0,0 +1,218 @@
1
+ import { kebabToCamel, isFileExist, getSectionData } from './helper.js'
2
+ import { fileURLToPath } from 'url';
3
+ import path from 'path'
4
+ import fs from 'fs/promises'
5
+ import ejs from 'ejs'
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ export async function createApiModule(context, options) {
11
+ const overwrite = options.overwrite===true
12
+ const moduleName = context.moduleName
13
+ const title = context.title
14
+ const targetFile = path.join(context.apiDir, `${moduleName}.api.js`)
15
+
16
+ try {
17
+ // cek dulu apakah file ada
18
+ let fileExists = await isFileExist(targetFile)
19
+ if (fileExists && !overwrite) {
20
+ context.postMessage({message: `skip file: '${targetFile}`})
21
+ return
22
+ }
23
+
24
+ // reporting progress to parent process
25
+ context.postMessage({message: `generating file: '${targetFile}`})
26
+
27
+
28
+ // get header information
29
+ const entityHeader = context.entities['header']
30
+ const headerTableName = entityHeader.table
31
+ const headerPrimaryKey = entityHeader.pk
32
+ const headerSearchMap = createSearchMap(entityHeader.Search, entityHeader.Items, headerTableName)
33
+ const usesequencer = ['auto-yearly', 'auto-monthly'].includes(entityHeader.identifierMethod) ? true : false
34
+
35
+ const yearly = entityHeader.identifierMethod == 'auto-yearly' ? true : false
36
+ const identifierPrefix = entityHeader.identifierPrefix
37
+ const identifierBlock = entityHeader.identifierBlock
38
+ const identifierLength = entityHeader.identifierLength
39
+ const headerFieldsLookup = createLookup(entityHeader.Items)
40
+
41
+ // cek apakah di header ada file upload
42
+ let importbucket = false
43
+ let headerHasUpload = false
44
+ for (var fieldName in entityHeader.Items) {
45
+ const item = entityHeader.Items[fieldName]
46
+ const component = item.component
47
+ if (component=='Filebox') {
48
+ headerHasUpload = true
49
+ importbucket = true
50
+ }
51
+ }
52
+
53
+
54
+
55
+ // get detil information
56
+ const entitiesDetil = []
57
+ for (let entityName in context.entities) {
58
+ if (entityName=='header') {
59
+ continue
60
+ }
61
+
62
+ const entity = context.entities[entityName]
63
+
64
+ let detilHasUpload
65
+ for (var fieldName in entity.Items) {
66
+ const item = entity.Items[fieldName]
67
+ const component = item.component
68
+ if (component=='Filebox') {
69
+ detilHasUpload = true
70
+ importbucket = true
71
+ }
72
+ }
73
+
74
+ const e = {
75
+ name: entityName,
76
+ table: entity.table,
77
+ pk: entity.pk,
78
+ detilHasUpload: detilHasUpload,
79
+ fieldsLookup: createLookup(entity.Items)
80
+ }
81
+ entitiesDetil.push(e)
82
+
83
+ }
84
+
85
+ const usesequencerline = entityHeader.identifierMethod=='auto-yearly-short' || entitiesDetil.length>0 ? true : false
86
+ // const autoid = usesequencer || usesequencerline ? true : false
87
+ const autoid = ['auto-by-default', 'auto-always', 'auto-yearly', 'auto-monthly', 'auto-yearly-short'].includes(entityHeader.identifierMethod)
88
+
89
+
90
+ const variables = {
91
+ timeGenerated: context.timeGenerated,
92
+ title: title,
93
+ moduleName: moduleName,
94
+ autoid,
95
+ usesequencer,
96
+ usesequencerline,
97
+ yearly,
98
+ identifierPrefix,
99
+ identifierBlock,
100
+ identifierLength,
101
+ headerTableName,
102
+ headerPrimaryKey,
103
+ headerSearchMap,
104
+ headerFieldsLookup,
105
+ headerHasUpload,
106
+ importbucket,
107
+ entitiesDetil
108
+ }
109
+
110
+
111
+ const tplFilePath = path.join(__dirname, 'templates', 'api-module.js.ejs')
112
+ const template = await fs.readFile(tplFilePath, 'utf-8');
113
+ const content = ejs.render(template, variables)
114
+
115
+ await fs.writeFile(targetFile, content, 'utf8');
116
+ } catch (err) {
117
+ throw err
118
+ }
119
+
120
+ }
121
+
122
+
123
+ function createSearchMap(searchdata, items, tablename) {
124
+ // searchtext: `user_fullname ILIKE '%' || \${searchtext} || '%' OR user_id=try_cast_bigint(\${searchtext}, 0)`,
125
+ // searchgroup: `group_id = \${searchgroup}`,
126
+ // user_isdisabled: `user_isdisabled = \${user_isdisabled}`
127
+
128
+ let searchtextExists = false
129
+ const searchMap = []
130
+ for (let searchname in searchdata) {
131
+ const search = searchdata[searchname]
132
+ const searchfield = parseSearchField(search.fields)
133
+
134
+ // harus ada 1 criteria searchtext
135
+ if (searchname=='searchtext') {
136
+ searchtextExists = true
137
+ }
138
+
139
+ // cek tipe data dari masing-masing search field
140
+ const params = []
141
+ for (let fieldname in searchfield) {
142
+ const field = items[fieldname]
143
+ const search = searchfield[fieldname]
144
+ if (field===undefined) {
145
+ throw new Error(`parameter search '${searchname}' tidak mengacu pada design tabel '${tablename}' `)
146
+ }
147
+
148
+ const datatype = field.data_type
149
+ const hasPercent = search.hasPercent
150
+
151
+ let searchToken
152
+ if (datatype=='int') {
153
+ searchToken = `${fieldname}=try_cast_int(\\\${${searchname}}, 0)`
154
+ } else if (datatype=='bigint') {
155
+ searchToken = `${fieldname}=try_cast_bigint(\\\${${searchname}}, 0)`
156
+ } else {
157
+ if (hasPercent) {
158
+ searchToken = `${fieldname} ILIKE '%' || \\\${${searchname}} || '%'`
159
+ } else {
160
+ searchToken = `${fieldname} = \\\${${searchname}}`
161
+ }
162
+ }
163
+ params.push(searchToken)
164
+ }
165
+ const searchcriteria = params.join(' OR ')
166
+
167
+ searchMap.push({
168
+ name: searchname,
169
+ data: searchcriteria
170
+ })
171
+ }
172
+
173
+ if (!searchtextExists) {
174
+ throw new Error(`search criteria untuk 'searchtext' belum dibuat`)
175
+ }
176
+
177
+ return searchMap
178
+ }
179
+
180
+ function parseSearchField(rawFields) {
181
+ const parsedFields = rawFields
182
+ .split(',')
183
+ .map(field => field.trim())
184
+ .reduce((acc, field) => {
185
+ const hasPercent = field.startsWith('%');
186
+ const name = hasPercent ? field.slice(1) : field;
187
+
188
+ acc[name] = {
189
+ name,
190
+ hasPercent
191
+ };
192
+
193
+ return acc;
194
+ }, {}
195
+ );
196
+
197
+ return parsedFields
198
+ }
199
+
200
+ function createLookup(items) {
201
+ const lookup = []
202
+ for (let fieldname in items) {
203
+ const item = items[fieldname]
204
+ if (item.component=='Combobox') {
205
+ const {bindingValue, bindingText, bindingDisplay, table} = item.Reference
206
+
207
+ let displayField = bindingText
208
+ if (bindingDisplay!='' && bindingDisplay!=null) {
209
+ displayField = bindingDisplay
210
+ }
211
+
212
+ lookup.push({
213
+ fieldname, bindingValue, bindingText, bindingDisplay:displayField, table
214
+ })
215
+ }
216
+ }
217
+ return lookup
218
+ }
@@ -0,0 +1,62 @@
1
+ import { isFileExist } from './helper.js'
2
+ import { fileURLToPath } from 'url';
3
+ import path from 'path'
4
+ import fs from 'fs/promises'
5
+ import ejs from 'ejs'
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ export async function createIcon(context, options) {
11
+ const rawData = context.icon
12
+
13
+ if (rawData=='' || rawData==null) {
14
+ return
15
+ }
16
+
17
+ const overwrite = options.overwrite===true
18
+ const moduleName = context.moduleName
19
+
20
+ try {
21
+
22
+ const ext = detectImageType(rawData);
23
+ const targetFile = path.join(context.moduleDir, `${moduleName}.${ext}`)
24
+ const base64 = getBase64data(rawData, ext)
25
+
26
+ if (base64==null) {
27
+ throw new Error('data icon tidak di support, gunakan svg atau png')
28
+ }
29
+
30
+ const svgBuffer = Buffer.from(base64, 'base64');
31
+ await fs.writeFile(targetFile, svgBuffer, 'utf8');
32
+
33
+ return `${moduleName}.${ext}`
34
+ } catch (err) {
35
+ throw err
36
+ }
37
+ }
38
+
39
+
40
+ function detectImageType(dataUrl) {
41
+ const match = dataUrl.match(/^url\("data:(image\/[a-zA-Z0-9\+\.-]+);base64,/);
42
+ if (!match) return null;
43
+ const mime = match[1];
44
+
45
+ if (mime === 'image/png') return 'png';
46
+ if (mime === 'image/jpeg') return 'jpg';
47
+ if (mime === 'image/svg+xml') return 'svg';
48
+ return mime; // fallback: raw MIME
49
+ }
50
+
51
+
52
+ function getBase64data(rawData, ext) {
53
+ if (ext=='svg') {
54
+ return rawData.replace(/^url\("data:image\/svg\+xml;base64,/, '').replace(/"\)$/, '');
55
+ } else if (ext=='png') {
56
+ return rawData.replace(/^url\("data:image\/png;base64,/, '').replace(/"\)$/, '');
57
+ } else if (ext=='jpg') {
58
+ return rawData.replace(/^url\("data:image\/jpeg;base64,/, '').replace(/"\)$/, '');
59
+ } else {
60
+ return null
61
+ }
62
+ }
@@ -0,0 +1,42 @@
1
+ import { isFileExist } from './helper.js'
2
+ import { fileURLToPath } from 'url';
3
+ import path from 'path'
4
+ import fs from 'fs/promises'
5
+ import ejs from 'ejs'
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ export async function createInfoAboutExtender(context, options) {
11
+ const overwrite = options.overwrite===true
12
+ const moduleName = context.moduleName
13
+ const targetFile = path.join(context.moduleDir, `${moduleName}-ext-about.html`)
14
+
15
+
16
+ try {
17
+ // cek dulu apakah file ada
18
+ var fileExists = await isFileExist(targetFile)
19
+ if (fileExists && !overwrite) {
20
+ context.postMessage({message: `skip file: '${targetFile}`})
21
+ return
22
+ }
23
+
24
+ // reporting progress to parent process
25
+ context.postMessage({message: `generating file: '${targetFile}`})
26
+
27
+
28
+ // start geneate program code
29
+ const variables = {
30
+ moduleName: moduleName
31
+
32
+ }
33
+
34
+ const tplFilePath = path.join(__dirname, 'templates', 'module-ext-about.ejs')
35
+ const template = await fs.readFile(tplFilePath, 'utf-8');
36
+ const content = ejs.render(template, variables)
37
+
38
+ await fs.writeFile(targetFile, content, 'utf8');
39
+ } catch (err) {
40
+ throw err
41
+ }
42
+ }
@@ -0,0 +1,41 @@
1
+ import { isFileExist } from './helper.js'
2
+ import { fileURLToPath } from 'url';
3
+ import path from 'path'
4
+ import fs from 'fs/promises'
5
+ import ejs from 'ejs'
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ export async function createInfoLogs(context, options) {
11
+ const overwrite = options.overwrite===true
12
+ const moduleName = context.moduleName
13
+ const targetFile = path.join(context.moduleDir, `${moduleName}-logs.html`)
14
+
15
+
16
+ try {
17
+ // cek dulu apakah file ada
18
+ var fileExists = await isFileExist(targetFile)
19
+ if (fileExists && !overwrite) {
20
+ context.postMessage({message: `skip file: '${targetFile}`})
21
+ return
22
+ }
23
+
24
+ // reporting progress to parent process
25
+ context.postMessage({message: `generating file: '${targetFile}`})
26
+
27
+
28
+ // start geneate program code
29
+ const variables = {
30
+ moduleName: moduleName
31
+ }
32
+
33
+ const tplFilePath = path.join(__dirname, 'templates', 'module-logs.ejs')
34
+ const template = await fs.readFile(tplFilePath, 'utf-8');
35
+ const content = ejs.render(template, variables)
36
+
37
+ await fs.writeFile(targetFile, content, 'utf8');
38
+ } catch (err) {
39
+ throw err
40
+ }
41
+ }
@@ -0,0 +1,41 @@
1
+ import { isFileExist } from './helper.js'
2
+ import { fileURLToPath } from 'url';
3
+ import path from 'path'
4
+ import fs from 'fs/promises'
5
+ import ejs from 'ejs'
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ export async function createInfoRecordExtender(context, options) {
11
+ const overwrite = options.overwrite===true
12
+ const moduleName = context.moduleName
13
+ const targetFile = path.join(context.moduleDir, `${moduleName}-ext-record.html`)
14
+
15
+
16
+ try {
17
+ // cek dulu apakah file ada
18
+ var fileExists = await isFileExist(targetFile)
19
+ if (fileExists && !overwrite) {
20
+ context.postMessage({message: `skip file: '${targetFile}`})
21
+ return
22
+ }
23
+
24
+ // reporting progress to parent process
25
+ context.postMessage({message: `generating file: '${targetFile}`})
26
+
27
+
28
+ // start geneate program code
29
+ const variables = {
30
+ moduleName: moduleName
31
+ }
32
+
33
+ const tplFilePath = path.join(__dirname, 'templates', 'module-ext-record.ejs')
34
+ const template = await fs.readFile(tplFilePath, 'utf-8');
35
+ const content = ejs.render(template, variables)
36
+
37
+ await fs.writeFile(targetFile, content, 'utf8');
38
+ } catch (err) {
39
+ throw err
40
+ }
41
+ }
@@ -0,0 +1,48 @@
1
+ import { kebabToCamel, isFileExist, getSectionData } from './helper.js'
2
+ import { fileURLToPath } from 'url';
3
+ import path from 'path'
4
+ import fs from 'fs/promises'
5
+ import ejs from 'ejs'
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ export async function createModuleContext(context, options) {
11
+ const overwrite = options.overwrite===true
12
+ const moduleName = context.moduleName
13
+ const targetFile = path.join(context.moduleDir, `${moduleName}-context.mjs`)
14
+
15
+ try {
16
+ // cek dulu apakah file ada
17
+ var fileExists = await isFileExist(targetFile)
18
+ if (fileExists && !overwrite) {
19
+ context.postMessage({message: `skip file: '${targetFile}`})
20
+ return
21
+ }
22
+
23
+ // reporting progress to parent process
24
+ context.postMessage({message: `generating file: '${targetFile}`})
25
+
26
+
27
+ // start geneate program code
28
+ let sections = []
29
+ for (var entityName in context.entities) {
30
+ sections.push(getSectionData(moduleName, entityName, context.entities[entityName], 'list'))
31
+ sections.push(getSectionData(moduleName, entityName, context.entities[entityName], 'edit'))
32
+ }
33
+
34
+ const variables = {
35
+ timeGenerated: context.timeGenerated,
36
+ moduleName: moduleName,
37
+ sections: sections
38
+ }
39
+
40
+ const tplFilePath = path.join(__dirname, 'templates', 'module-context.ejs')
41
+ const template = await fs.readFile(tplFilePath, 'utf-8');
42
+ const content = ejs.render(template, variables)
43
+
44
+ await fs.writeFile(targetFile, content, 'utf8');
45
+ } catch (err) {
46
+ throw err
47
+ }
48
+ }
@@ -0,0 +1,110 @@
1
+ import { kebabToCamel, isFileExist, getSectionData, createAdditionalAttributes } from './helper.js'
2
+ import { fileURLToPath } from 'url';
3
+ import path from 'path'
4
+ import fs from 'fs/promises'
5
+ import ejs from 'ejs'
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ export async function createModuleDetilEditHtml(context, options) {
11
+ const overwrite = options.overwrite===true
12
+ const moduleName = context.moduleName
13
+ const title = context.title
14
+ const sectionPart = 'edit'
15
+
16
+ try {
17
+ for (let entityName in context.entities) {
18
+ // process selain header
19
+ if (entityName=='header') {
20
+ continue
21
+ }
22
+
23
+ const sectionName = entityName
24
+ const modulePart = kebabToCamel(`${moduleName}-${sectionName}-${sectionPart}`)
25
+ const targetFile = path.join(context.moduleDir, `${modulePart}.html`)
26
+
27
+ // cek dulu apakah file ada
28
+ var fileExists = await isFileExist(targetFile)
29
+ if (fileExists && !overwrite) {
30
+ context.postMessage({message: `skip file: '${targetFile}`})
31
+ return
32
+ }
33
+ context.postMessage({message: `generating file: '${targetFile}`}) // reporting progress to parent process
34
+
35
+ // start geneate program code
36
+ const entityData = context.entities[entityName]
37
+ const sectionData = getSectionData(moduleName, entityName, entityData, 'edit')
38
+ const primaryKeyFieldData = entityData.Items[sectionData.primaryKey]
39
+ const primaryKeyName = primaryKeyFieldData.input_name
40
+ const primaryKeyElementId = `${modulePart}-${primaryKeyName}`
41
+
42
+ const autoid = true // untuk detil, pasti autoid
43
+
44
+
45
+ // ambil data field header
46
+ const fields = []
47
+ let index = 0
48
+ for (var fieldName in entityData.Items) {
49
+ const item = entityData.Items[fieldName]
50
+ index++
51
+
52
+
53
+ item.index = index
54
+ // if (item.data_fieldname=='grouptype_id') {
55
+ // console.log(item)
56
+ // }
57
+
58
+ if (!item.showInForm) {
59
+ continue
60
+ }
61
+
62
+ const component = item.component
63
+ const fieldname = item.data_fieldname
64
+ const elementId = `${modulePart}-${item.input_name}`
65
+ const placeholder = item.input_placeholder
66
+ const label = item.input_label
67
+ const tabindex = item.input_index
68
+ const binding = item.data_fieldname
69
+ const additionalAttributes = createAdditionalAttributes(item)
70
+ const cssContainer = item.input_containercss.trim() == '' ? 'input-field' : `input-field ${item.input_containercss.trim()}`
71
+
72
+ fields.push({
73
+ component,
74
+ cssContainer,
75
+ fieldname,
76
+ elementId,
77
+ placeholder,
78
+ label,
79
+ tabindex,
80
+ binding,
81
+ additionalAttributes
82
+ })
83
+
84
+ }
85
+
86
+
87
+ const variables = {
88
+ timeGenerated: context.timeGenerated,
89
+ title: title,
90
+ moduleName: moduleName,
91
+ modulePart: modulePart,
92
+ moduleSection: kebabToCamel(`${moduleName}-${sectionName}`),
93
+ section: sectionData,
94
+ autoid,
95
+ primaryKeyElementId: primaryKeyElementId,
96
+ fields: fields,
97
+ }
98
+
99
+ const tplFilePath = path.join(__dirname, 'templates', 'moduleDetilEdit.html.ejs')
100
+ const template = await fs.readFile(tplFilePath, 'utf-8');
101
+ const content = ejs.render(template, variables)
102
+
103
+ await fs.writeFile(targetFile, content, 'utf8');
104
+ }
105
+
106
+ } catch (err) {
107
+ throw err
108
+ }
109
+
110
+ }