@agung_dhewe/webapps 1.1.2 → 1.2.1

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.

Potentially problematic release.


This version of @agung_dhewe/webapps might be problematic. Click here for more details.

Files changed (89) hide show
  1. package/lib/fgta5js-dist/fgta5js-v1.8.5.min.js +11 -0
  2. package/lib/fgta5js-dist/fgta5js-v1.8.5.min.js.map +1 -0
  3. package/{libs → lib}/webmodule/module-edit.css +73 -18
  4. package/{libs → lib}/webmodule/module-list.css +13 -0
  5. package/lib/webmodule/module-print.css +28 -0
  6. package/{libs → lib}/webmodule/module.css +13 -6
  7. package/{libs → lib}/webmodule/module.js +14 -4
  8. package/lib/webmodule/pagehelper.mjs +129 -0
  9. package/modules/generator/appgen-io.mjs +153 -76
  10. package/modules/generator/appgen-ui.mjs +234 -167
  11. package/modules/generator/generator-designtemplate-def.html +38 -0
  12. package/modules/generator/generator-designtemplate.html +11 -1492
  13. package/modules/generator/generator.css +103 -65
  14. package/modules/generator/generator.mjs +1 -1
  15. package/modules/generator/generator.svg +98 -0
  16. package/modules/generator/generatorEdit.mjs +43 -35
  17. package/modules/generator/generatorList.mjs +27 -0
  18. package/modules/generator/tpl-designerinfo.html +100 -0
  19. package/modules/generator/tpl-field-checkbox.html +200 -0
  20. package/modules/generator/tpl-field-combobox.html +228 -0
  21. package/modules/generator/tpl-field-datepicker.html +192 -0
  22. package/modules/generator/tpl-field-filebox.html +189 -0
  23. package/modules/generator/tpl-field-numberbox.html +218 -0
  24. package/modules/generator/tpl-field-textbox.html +255 -0
  25. package/modules/generator/tpl-field-timepicker.html +192 -0
  26. package/modules/generator/tpl-searchdesign.html +32 -0
  27. package/modules/generator/tpl-uniquedesign.html +25 -0
  28. package/modules/login/login.css +10 -2
  29. package/package.json +3 -1
  30. package/percobaan/coba-sequencer.js +16 -0
  31. package/src/api.js +12 -9
  32. package/src/apis/generator.api.js +35 -23
  33. package/src/apis/login.api.js +1 -0
  34. package/src/db.js +58 -32
  35. package/src/generator/createApiModule.js +4 -1
  36. package/src/generator/createIcon.js +24 -2
  37. package/src/generator/createLayoutCss.js +107 -0
  38. package/src/generator/createModuleDetilEditHtml.js +12 -1
  39. package/src/generator/createModuleDetilEditMjs.js +32 -28
  40. package/src/generator/createModuleDetilListHtml.js +14 -7
  41. package/src/generator/createModuleDetilListMjs.js +13 -1
  42. package/src/generator/createModuleHeaderEditHtml.js +13 -1
  43. package/src/generator/createModuleHeaderEditMjs.js +23 -2
  44. package/src/generator/createProgramData.js +3 -2
  45. package/src/generator/createTable.js +45 -38
  46. package/src/generator/helper.js +45 -27
  47. package/src/generator/templates/__rollup-module.ejs +1 -1
  48. package/src/generator/templates/api-module.js.ejs +171 -32
  49. package/src/generator/templates/layout.css.ejs +24 -0
  50. package/src/generator/templates/module-ext.html.ejs +1 -1
  51. package/src/generator/templates/module-ext.mjs.ejs +19 -1
  52. package/src/generator/templates/module.ejs.ejs +8 -0
  53. package/src/generator/templates/module.mjs.ejs +42 -5
  54. package/src/generator/templates/moduleDetilEdit.html.ejs +11 -0
  55. package/src/generator/templates/moduleDetilEdit.mjs.ejs +135 -30
  56. package/src/generator/templates/moduleDetilList.html.ejs +2 -1
  57. package/src/generator/templates/moduleDetilList.mjs.ejs +86 -11
  58. package/src/generator/templates/moduleHeaderEdit.html.ejs +8 -1
  59. package/src/generator/templates/moduleHeaderEdit.mjs.ejs +123 -36
  60. package/src/generator/templates/moduleHeaderList.html.ejs +5 -1
  61. package/src/generator/templates/moduleHeaderList.mjs.ejs +47 -15
  62. package/src/generator/trygenerate.js +18 -2
  63. package/src/generator/worker.js +83 -72
  64. package/src/logger.js +12 -12
  65. package/src/notifier.js +29 -0
  66. package/src/routers/generatorPage.js +3 -1
  67. package/src/routers/modulePage.js +32 -7
  68. package/src/sequencerdoc.js +22 -46
  69. package/src/sequencerline.js +16 -4
  70. package/src/session.js +69 -33
  71. package/src/startup.js +47 -10
  72. package/src/webapps.js +61 -18
  73. package/templates/_lib_debug.ejs +8 -8
  74. package/templates/_lib_production.ejs +2 -2
  75. package/templates/application.page.ejs +39 -6
  76. package/templates/generator.page.ejs +4 -3
  77. package/templates/index.page.ejs +2 -2
  78. package/templates/login.page.ejs +3 -3
  79. package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js +0 -11
  80. package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js.map +0 -1
  81. package/libs/webmodule/pagehelper.mjs +0 -45
  82. package/modules/generator/generator.png +0 -0
  83. /package/{libs/fgta5js-dist/fgta5js-v1.8.3.min.css → lib/fgta5js-dist/fgta5js-v1.8.5.min.css} +0 -0
  84. /package/{libs → lib}/fgta5js-dist/fonts/karla-italic-latin-ext.woff2 +0 -0
  85. /package/{libs → lib}/fgta5js-dist/fonts/karla-italic-latin.woff2 +0 -0
  86. /package/{libs → lib}/fgta5js-dist/fonts/karla-normal-latin-ext.woff2 +0 -0
  87. /package/{libs → lib}/fgta5js-dist/fonts/karla-normal-latin.woff2 +0 -0
  88. /package/{libs → lib}/fgta5js-dist/fonts/karla.css +0 -0
  89. /package/{libs → lib}/webmodule/module-footer.css +0 -0
@@ -0,0 +1,32 @@
1
+ <!-- SEARCH-DESIGN -->
2
+ <div name="designer-search" class="designer-search hidden">
3
+ Jika search tidak didefinisikan, akan otomatis ditambahkan search criteria exact berdasarkan id<br><br>
4
+ <table name="tbl-search">
5
+ <tr>
6
+ <td style="vertical-align: top;">
7
+ <input name="criteria_name" class="action-input" placeholder="criteria name">
8
+ <div style="padding-left: 6px; font-size: 0.8rem;">
9
+ <a name="btnNew" href="javascript:void(0)">new</a>
10
+ </div>
11
+ </td>
12
+ <td style="vertical-align: top;">
13
+ <input name="criteria_label" class="action-input" placeholder="criteria label">
14
+ </td>
15
+ <td style="vertical-align: top;">
16
+ <div>
17
+ <input name="criteria_fields" class="action-input" style="width: 400px" placeholder="fields">
18
+ </div>
19
+ <div style="font-size: 0.8em; font-style: italic; padding-left: 5px;">
20
+ untuk multiple fields, pisahkan dengan koma (,)<br>
21
+ ketikkan <b>namafield</b> untuk exact search,<br>
22
+ atau ketikkan <b>%namafield</b> untuk search like
23
+ </div>
24
+
25
+ </td>
26
+ <td style="vertical-align: top;">
27
+ <button name="btnAdd" class="action-button-add">Add</button>
28
+ </td>
29
+ </tr>
30
+
31
+ </table>
32
+ </div>
@@ -0,0 +1,25 @@
1
+ <!-- UNIQUE-DESIGN -->
2
+ <div name="designer-unique" class="designer-unique hidden">
3
+ <table name="tbl-unique">
4
+ <tr>
5
+ <td style="vertical-align: top;">
6
+ <input name="unique_name" class="action-input" placeholder="unique name">
7
+ <div style="padding-left: 6px; font-size: 0.8rem;">
8
+ <a name="btnNew" href="javascript:void(0)">new</a>
9
+ </div>
10
+ </td>
11
+ <td style="vertical-align: top;">
12
+ <div>
13
+ <input name="unique_fields" class="action-input" style="width: 400px" placeholder="fields">
14
+ </div>
15
+ <div style="font-size: 0.8em; font-style: italic; padding-left: 5px;">
16
+ untuk multiple fields, pisahkan dengan koma (,)
17
+ </div>
18
+
19
+ </td>
20
+ <td style="vertical-align: top;">
21
+ <button name="btnAdd" class="action-button-add">Add</button>
22
+ </td>
23
+ </tr>
24
+ </table>
25
+ </div>
@@ -2,10 +2,18 @@
2
2
  margin: 10px
3
3
  }
4
4
 
5
+ .loginbox h1 {
6
+ padding-left: 2px;
7
+ }
8
+
5
9
  .loginbox input {
6
- margin-bottom: 5px;
10
+ padding: 5px;
11
+ margin: 3px;
7
12
  }
8
13
 
9
14
  .loginbox button {
10
- margin-top: 5px;
15
+ margin: 8px 3px 3px 3px;
16
+ padding: 8px 30px 8px 30px;
17
+ font-weight: bold;
18
+ cursor: pointer;
11
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agung_dhewe/webapps",
3
- "version": "1.1.2",
3
+ "version": "1.2.1",
4
4
  "description": "library javascript (nodejs+express) untuk pengembangan applikasi web",
5
5
  "type": "module",
6
6
  "main": "./src/webapps.js",
@@ -41,6 +41,8 @@
41
41
  "pg-promise": "^11.14.0",
42
42
  "redis": "^5.5.6",
43
43
  "serve-favicon": "^2.5.0",
44
+ "session-file-store": "^1.5.0",
45
+ "svgo": "^4.0.0",
44
46
  "ws": "^8.18.3"
45
47
  }
46
48
  }
@@ -0,0 +1,16 @@
1
+ import dotenv from 'dotenv';
2
+ import db from '../src/db.js'
3
+
4
+ dotenv.config();
5
+
6
+ try {
7
+
8
+
9
+
10
+
11
+ } catch (err) {
12
+ console.error(err)
13
+ // process.exit(1)
14
+ } finally {
15
+ // process.exit(0)
16
+ }
package/src/api.js CHANGED
@@ -22,15 +22,15 @@ export default class Api {
22
22
  static cekLogin(req) {
23
23
  // jika req.session.user tidak ada datanya, berarti belum login
24
24
  try {
25
- if (req.session.user==null) {
25
+ if (req.session.user == null) {
26
26
  throw new Error('belum login')
27
27
  }
28
28
 
29
- if (req.session.user.isLogin==null) {
29
+ if (req.session.user.isLogin == null) {
30
30
  throw new Error('belum login')
31
31
  }
32
32
 
33
- if (req.session.user.isLogin==false) {
33
+ if (req.session.user.isLogin == false) {
34
34
  throw new Error('belum login')
35
35
  }
36
36
  } catch (err) {
@@ -42,13 +42,13 @@ export default class Api {
42
42
  static parseUploadData(data, files) {
43
43
  const jsonFieldName = 'form-body-jsondata'
44
44
  try {
45
- if (files!=undefined) {
45
+ if (files != undefined) {
46
46
  // ambil json data
47
- const jsondata = files.filter(file => file.fieldname==jsonFieldName)
47
+ const jsondata = files.filter(file => file.fieldname == jsonFieldName)
48
48
  const jsonstring = jsondata[0].buffer.toString('utf-8')
49
49
  Object.assign(data, JSON.parse(jsonstring).data)
50
50
 
51
- const filelist = files.filter(file => file.fieldname!=jsonFieldName)
51
+ const filelist = files.filter(file => file.fieldname != jsonFieldName)
52
52
  return filelist
53
53
  }
54
54
 
@@ -63,10 +63,10 @@ export default class Api {
63
63
  try {
64
64
  if (typeof this[methodName] === 'function') {
65
65
  const result = await this[methodName](body)
66
- return result
66
+ return result
67
67
  } else {
68
68
  const errNotFound = new Error(`Method "${methodName}" tidak ditemukan.`)
69
- errNotFound.code = 404
69
+ errNotFound.code = 404
70
70
  throw errNotFound
71
71
  }
72
72
  } catch (err) {
@@ -74,7 +74,10 @@ export default class Api {
74
74
  }
75
75
  }
76
76
 
77
-
78
77
  }
79
78
 
80
79
 
80
+
81
+
82
+
83
+
@@ -14,7 +14,16 @@ import jwt from 'jsonwebtoken';
14
14
  const MINUTES = 60 * 1000
15
15
 
16
16
  const moduleName = 'generator'
17
- const generateTimeoutMs = 5 * MINUTES
17
+ const generateTimeoutMs = 5 * MINUTES
18
+
19
+ const ModuleDbContract = {
20
+ apps: {
21
+ table: 'core."apps"'
22
+ },
23
+ generator: {
24
+ table: 'core.generator'
25
+ }
26
+ }
18
27
 
19
28
  // api: account
20
29
  export default class extends Api {
@@ -24,6 +33,7 @@ export default class extends Api {
24
33
 
25
34
  }
26
35
 
36
+
27
37
  // dipanggil dengan model snake syntax
28
38
  // contoh: header-list
29
39
  // header-open-data
@@ -45,7 +55,7 @@ async function generator_init(self, body) {
45
55
 
46
56
  try {
47
57
  // ambil data app dari database
48
- const sql = 'select apps_id, apps_url, apps_name, apps_directory from core."apps"'
58
+ const sql = `select apps_id, apps_url, apps_name, apps_directory from ${ModuleDbContract.apps.table}`
49
59
  const result = await db.any(sql)
50
60
 
51
61
  const appsUrls = {}
@@ -61,7 +71,7 @@ async function generator_init(self, body) {
61
71
  userId: req.session.user.userId,
62
72
  userName: req.session.user.userName,
63
73
  userFullname: req.session.userFullname,
64
- sid: req.session.sid ,
74
+ sid: req.session.sid,
65
75
  notifierId: Api.generateNotifierId(moduleName, req.sessionID),
66
76
  notifierSocket: req.app.locals.appConfig.notifierSocket,
67
77
  targetDirectory: context.getRootDirectory(),
@@ -77,17 +87,17 @@ async function generator_init(self, body) {
77
87
 
78
88
 
79
89
  async function generator_list(self, body) {
80
- const { criteria={}, limit=0, offset=0, columns=[], sort={} } = body
90
+ const { criteria = {}, limit = 0, offset = 0, columns = [], sort = {} } = body
81
91
  const searchMap = {
82
92
  searchtext: `generator_modulename ILIKE '%' || \${searchtext} || '%' OR generator_id=try_cast_bigint(\${searchtext}, 0)`,
83
93
  appname: `generator_appname=\${appname}`
84
94
  };
85
95
 
86
96
  try {
87
-
97
+
88
98
  // hilangkan criteria '' atau null
89
99
  for (var cname in criteria) {
90
- if (criteria[cname]==='' || criteria[cname]===null) {
100
+ if (criteria[cname] === '' || criteria[cname] === null) {
91
101
  delete criteria[cname]
92
102
  }
93
103
  }
@@ -99,29 +109,29 @@ async function generator_list(self, body) {
99
109
 
100
110
  sort._modifydate = 'desc'
101
111
 
102
- var max_rows = limit==0 ? 50 : limit
103
- const tablename = 'core."generator"'
104
- const {whereClause, queryParams} = sqlUtil.createWhereClause(criteria, searchMap)
105
- const sql = sqlUtil.createSqlSelect({tablename, columns, whereClause, sort, limit:max_rows+1, offset, queryParams})
112
+ var max_rows = limit == 0 ? 50 : limit
113
+ const tablename = ModuleDbContract.generator.table
114
+ const { whereClause, queryParams } = sqlUtil.createWhereClause(criteria, searchMap)
115
+ const sql = sqlUtil.createSqlSelect({ tablename, columns, whereClause, sort, limit: max_rows + 1, offset, queryParams })
106
116
  const rows = await db.any(sql, queryParams);
107
117
 
108
-
118
+
109
119
  var i = 0
110
120
  const data = []
111
121
  for (var row of rows) {
112
122
  i++
113
- if (i>max_rows) { break }
123
+ if (i > max_rows) { break }
114
124
  data.push(row)
115
125
  }
116
126
 
117
127
  var nextoffset = null
118
- if (rows.length>max_rows) {
119
- nextoffset = offset+max_rows
128
+ if (rows.length > max_rows) {
129
+ nextoffset = offset + max_rows
120
130
  }
121
131
 
122
132
  return {
123
133
  criteria: criteria,
124
- limit: max_rows,
134
+ limit: max_rows,
125
135
  nextoffset: nextoffset,
126
136
  data: data
127
137
  }
@@ -132,13 +142,14 @@ async function generator_list(self, body) {
132
142
  }
133
143
 
134
144
  async function generator_open(self, body) {
145
+ const tablename = ModuleDbContract.generator.table
135
146
  try {
136
- const { id } = body
137
- const queryParams = {generator_id: id}
138
- const sql = 'select * from core."generator" where generator_id = \${generator_id}'
147
+ const { id } = body
148
+ const queryParams = { generator_id: id }
149
+ const sql = `select * from ${tablename} where generator_id = \${generator_id}`
139
150
  const data = await db.one(sql, queryParams);
140
151
 
141
- if (data==null) { throw new Error("data tidak ditemukan") }
152
+ if (data == null) { throw new Error("data tidak ditemukan") }
142
153
 
143
154
  return data
144
155
  } catch (err) {
@@ -148,7 +159,7 @@ async function generator_open(self, body) {
148
159
 
149
160
  async function generator_save(self, body) {
150
161
  const { data } = body
151
- const tablename = 'core."generator"'
162
+ const tablename = ModuleDbContract.generator.table
152
163
  const req = self.req
153
164
  const user_id = req.session.user.userId
154
165
 
@@ -168,7 +179,7 @@ async function generator_save(self, body) {
168
179
  }
169
180
 
170
181
  let cmd
171
- if (id=='') {
182
+ if (id == '') {
172
183
  obj._createby = user_id
173
184
  obj._createdate = (new Date()).toISOString()
174
185
  cmd = sqlUtil.createInsertCommand(tablename, obj, ['generator_id'])
@@ -196,7 +207,7 @@ async function generator_generate(self, body) {
196
207
  const ipaddress = req.ip
197
208
 
198
209
  try {
199
- if (id=='') {
210
+ if (id == '') {
200
211
  throw new Error('save data dahulu sebelum generate')
201
212
  }
202
213
 
@@ -213,7 +224,8 @@ async function generator_generate(self, body) {
213
224
  user_name: user_name,
214
225
  ipaddress: ipaddress,
215
226
  timeout: generateTimeoutMs,
216
- jeda: 0.5, // jeda 1 detik per masing-masing generate
227
+ ModuleDbContract: ModuleDbContract,
228
+ jeda: 0.5, // jeda 0.5 detik per masing-masing generate
217
229
  })
218
230
 
219
231
 
@@ -44,6 +44,7 @@ async function login_init(self, body) {
44
44
  }
45
45
 
46
46
  async function login_doLogin(self, body) {
47
+ const req = self.req
47
48
  try {
48
49
  const {username, password} = body
49
50
 
package/src/db.js CHANGED
@@ -1,43 +1,31 @@
1
1
  import dotenv from 'dotenv';
2
2
  import pgp from 'pg-promise';
3
3
 
4
+
4
5
  dotenv.config();
5
6
 
7
+ // const initOptions = {};
6
8
  const initOptions = {
7
- // Misalnya, event untuk memantau query atau error
8
- // query: (e) => {
9
- // console.log('QUERY:', e.query);
10
- // },
11
- // error: (err, e) => {
12
- // console.log('ERROR:', err, e.query);
13
- // }
9
+ async connect(db, dc, useCount) {
10
+ await db.client.query("SET TIMEZONE = 'Asia/Jakarta'");
11
+ }
14
12
  };
15
13
 
16
14
  const pgpInstance = pgp(initOptions); // <-- Panggil pgp() hanya satu kali di sini
17
15
 
18
16
 
19
17
  const configDb = {
20
- port: process.env.DB_PORT,
21
- host: process.env.DB_HOST,
22
- database: process.env.DB_NAME,
23
- user: process.env.DB_USER,
24
- password: process.env.DB_PASS,
18
+ port: process.env.DB_PORT,
19
+ host: process.env.DB_HOST,
20
+ database: process.env.DB_NAME,
21
+ user: process.env.DB_USER,
22
+ password: process.env.DB_PASS,
25
23
  }
26
24
 
27
- const configDbLog = {
28
- port: process.env.LOGGER_DB_PORT,
29
- host: process.env.LOGGER_DB_HOST,
30
- database: process.env.LOGGER_DB_NAME,
31
- user: process.env.LOGGER_DB_USER,
32
- password: process.env.LOGGER_DB_PASS,
33
- }
34
25
 
26
+ pgpInstance.pg.types.setTypeParser(1082, (stringValue) => stringValue);
35
27
 
36
28
  const db = pgpInstance(configDb);
37
- export default db
38
-
39
- export const dblog = pgpInstance(configDbLog);
40
-
41
29
 
42
30
 
43
31
  db.connect()
@@ -50,12 +38,50 @@ db.connect()
50
38
  process.exit(1);
51
39
  });
52
40
 
53
- dblog.connect()
54
- .then(obj => {
55
- console.log('Connected to Logger Database!');
56
- obj.done(); // Klien dikembalikan ke pool
57
- })
58
- .catch(error => {
59
- console.error('\n\x1b[31mError!\x1b[0m cannot\nconnect to Logger Database:', error.message || error, "\n");
60
- process.exit(1);
61
- });
41
+
42
+ export default db
43
+ export let dblog = db
44
+
45
+
46
+ export function setDbLog() {
47
+ const configDbLog = {
48
+ port: process.env.LOGGER_DB_PORT,
49
+ host: process.env.LOGGER_DB_HOST,
50
+ database: process.env.LOGGER_DB_NAME,
51
+ user: process.env.LOGGER_DB_USER,
52
+ password: process.env.LOGGER_DB_PASS,
53
+ }
54
+
55
+ dblog = pgpInstance(configDbLog);
56
+ if (configDbLog.host !== undefined) {
57
+ dblog.connect()
58
+ .then(obj => {
59
+ console.log('Connected to Logger Database!');
60
+ obj.done(); // Klien dikembalikan ke pool
61
+ })
62
+ .catch(error => {
63
+ console.error('\n\x1b[31mError!\x1b[0m cannot\nconnect to Logger Database:', error.message || error, "\n");
64
+ process.exit(1);
65
+ });
66
+ }
67
+ }
68
+
69
+
70
+
71
+
72
+
73
+ // export const dblog = pgpInstance(configDbLog);
74
+
75
+ // if (configDbLog.host !== undefined) {
76
+
77
+ // dblog.connect()
78
+ // .then(obj => {
79
+ // console.log('Connected to Logger Database!');
80
+ // obj.done(); // Klien dikembalikan ke pool
81
+ // })
82
+ // .catch(error => {
83
+ // console.error('\n\x1b[31mError!\x1b[0m cannot\nconnect to Logger Database:', error.message || error, "\n");
84
+ // process.exit(1);
85
+ // });
86
+ // }
87
+
@@ -82,9 +82,11 @@ export async function createApiModule(context, options) {
82
82
 
83
83
  }
84
84
 
85
+ // const headerusesequencerline = entityHeader.identifierMethod=='auto-yearly-short' ? true : false
85
86
  const usesequencerline = entityHeader.identifierMethod=='auto-yearly-short' || entitiesDetil.length>0 ? true : false
86
- // const autoid = usesequencer || usesequencerline ? true : false
87
87
  const autoid = ['auto-by-default', 'auto-always', 'auto-yearly', 'auto-monthly', 'auto-yearly-short'].includes(entityHeader.identifierMethod)
88
+ const shortsequencer = entityHeader.identifierMethod=='auto-yearly-short'
89
+
88
90
 
89
91
 
90
92
  const variables = {
@@ -94,6 +96,7 @@ export async function createApiModule(context, options) {
94
96
  autoid,
95
97
  usesequencer,
96
98
  usesequencerline,
99
+ shortsequencer,
97
100
  yearly,
98
101
  identifierPrefix,
99
102
  identifierBlock,
@@ -3,6 +3,7 @@ import { fileURLToPath } from 'url';
3
3
  import path from 'path'
4
4
  import fs from 'fs/promises'
5
5
  import ejs from 'ejs'
6
+ import { optimize } from 'svgo';
6
7
 
7
8
  const __filename = fileURLToPath(import.meta.url);
8
9
  const __dirname = path.dirname(__filename);
@@ -27,8 +28,29 @@ export async function createIcon(context, options) {
27
28
  throw new Error('data icon tidak di support, gunakan svg atau png')
28
29
  }
29
30
 
30
- const svgBuffer = Buffer.from(base64, 'base64');
31
- await fs.writeFile(targetFile, svgBuffer, 'utf8');
31
+ const buff = Buffer.from(base64, 'base64');
32
+
33
+ // jika icon yang di attach adalah svg
34
+ // optimasi svg agar ukurannya kecil
35
+ if (ext=='svg') {
36
+ const svgText = buff.toString('utf8');
37
+ const result = optimize(svgText, {
38
+ path: `${moduleName}.${ext}`, // recommended
39
+ multipass: true, // all other config fields are available here
40
+ });
41
+ const optimizedSvgString = result.data;
42
+
43
+ // simpan ke file dengan data yang telah dioptimasi
44
+ await fs.writeFile(targetFile, optimizedSvgString, 'utf8');
45
+
46
+ } else {
47
+
48
+ // tulis ke file apa adanya
49
+ await fs.writeFile(targetFile, buff, 'utf8');
50
+ }
51
+
52
+
53
+
32
54
 
33
55
  return `${moduleName}.${ext}`
34
56
  } catch (err) {
@@ -0,0 +1,107 @@
1
+ import { kebabToCamel, isFileExist, getSectionData, createAdditionalAttributes } from './helper.js'
2
+ import { fileURLToPath } from 'url';
3
+ import path, { basename } 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 createLayoutCss(context, options) {
11
+ const overwrite = options.overwrite===true
12
+ const moduleName = context.moduleName
13
+
14
+ try {
15
+
16
+ const targetLayoutFile = path.join(context.moduleDir, `${moduleName}.layout.css`)
17
+ const layoutFiles = []
18
+
19
+ for (let entityName in context.entities) {
20
+ const sectionName = entityName
21
+ const sectionPart = 'edit'
22
+ const modulePart = kebabToCamel(`${moduleName}-${sectionName}-${sectionPart}`)
23
+ const targetFile = path.join(context.moduleDir, `${modulePart}.layout.css`)
24
+
25
+ // cek dulu apakah file ada
26
+ const fileExists = await isFileExist(targetFile)
27
+ if (fileExists && !overwrite) {
28
+ context.postMessage({message: `skip file: '${targetFile}`})
29
+ return
30
+ }
31
+ context.postMessage({message: `generating file: '${targetFile}`}) // reporting progress to parent process
32
+
33
+
34
+ const entityData = context.entities[entityName]
35
+ if (!entityData.formGridLayout) {
36
+ continue // jika tidak menggunakan formGridLautout tidak perlu generate css layout
37
+ }
38
+
39
+
40
+ layoutFiles.push(basename(targetFile))
41
+
42
+ const fields = []
43
+ let index = 0
44
+ for (var fieldName in entityData.Items) {
45
+ const item = entityData.Items[fieldName]
46
+ index++
47
+
48
+ if (!item.showInForm) {
49
+ continue
50
+ }
51
+
52
+
53
+ const component = item.component
54
+ const fieldname = item.data_fieldname
55
+ const elementId = `${modulePart}-${item.input_name}`
56
+ const dposrow = item.input_dposrow??'auto'
57
+ const dposrowspan = item.input_dposrowspan??''
58
+ const dposcol = item.input_dposcol??'1'
59
+ const dposcolspan = item.input_dposcolspan??''
60
+ const dposstyle = item.input_dposstyle??''
61
+
62
+
63
+
64
+ fields.push({
65
+ elementId,
66
+ dposrow,
67
+ dposcol,
68
+ dposrowspan: dposrowspan.trim()!='' ? ` / span ${dposrowspan}` : '',
69
+ dposcolspan: dposcolspan.trim()!='' ? ` / span ${dposcolspan}` : '',
70
+ dposstyle
71
+ })
72
+
73
+
74
+ }
75
+
76
+
77
+ const variables = {
78
+ moduleName: moduleName,
79
+ modulePart: modulePart,
80
+ fields: fields,
81
+ }
82
+
83
+ // console.log(variables)
84
+
85
+ const tplFilePath = path.join(__dirname, 'templates', 'layout.css.ejs')
86
+ const template = await fs.readFile(tplFilePath, 'utf-8');
87
+ const content = ejs.render(template, variables)
88
+
89
+ await fs.writeFile(targetFile, content, 'utf8');
90
+ }
91
+
92
+ // buat parent css
93
+ let content = `/* auto generated Layout CSS */\n`
94
+ if (layoutFiles.length>0) {
95
+ for (var layoutfile of layoutFiles) {
96
+ content += `@import url('${layoutfile}');\n`
97
+ }
98
+ }
99
+ await fs.writeFile(targetLayoutFile, content, 'utf8');
100
+
101
+
102
+
103
+ } catch (err) {
104
+ throw err
105
+ }
106
+
107
+ }
@@ -14,6 +14,9 @@ export async function createModuleDetilEditHtml(context, options) {
14
14
  const sectionPart = 'edit'
15
15
 
16
16
  try {
17
+
18
+ const entityHeader = context.entities['header']
19
+
17
20
  for (let entityName in context.entities) {
18
21
  // process selain header
19
22
  if (entityName=='header') {
@@ -67,7 +70,15 @@ export async function createModuleDetilEditHtml(context, options) {
67
70
  const tabindex = item.input_index
68
71
  const binding = item.data_fieldname
69
72
  const additionalAttributes = createAdditionalAttributes(item)
70
- const cssContainer = item.input_containercss.trim() == '' ? 'input-field' : `input-field ${item.input_containercss.trim()}`
73
+
74
+ let cssContainer = item.input_containercss.trim() == '' ? 'input-field' : `input-field ${item.input_containercss.trim()}`
75
+
76
+
77
+
78
+ if (fieldName==entityHeader.pk) {
79
+ cssContainer += ' hidden'
80
+ }
81
+
71
82
 
72
83
  fields.push({
73
84
  component,