@agung_dhewe/webapps 1.1.2 → 1.2.4
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/lib/fgta5js-dist/fgta5js-v1.8.5.min.js +11 -0
- package/lib/fgta5js-dist/fgta5js-v1.8.5.min.js.map +1 -0
- package/{libs → lib}/webmodule/module-edit.css +73 -18
- package/{libs → lib}/webmodule/module-list.css +13 -0
- package/lib/webmodule/module-print.css +28 -0
- package/{libs → lib}/webmodule/module.css +13 -6
- package/{libs → lib}/webmodule/module.js +14 -4
- package/lib/webmodule/pagehelper.mjs +129 -0
- package/modules/generator/appgen-io.mjs +153 -76
- package/modules/generator/appgen-ui.mjs +234 -167
- package/modules/generator/generator-designtemplate-def.html +38 -0
- package/modules/generator/generator-designtemplate.html +11 -1492
- package/modules/generator/generator.css +103 -65
- package/modules/generator/generator.mjs +1 -1
- package/modules/generator/generator.svg +98 -0
- package/modules/generator/generatorEdit.mjs +43 -35
- package/modules/generator/generatorList.mjs +27 -0
- package/modules/generator/tpl-designerinfo.html +100 -0
- package/modules/generator/tpl-field-checkbox.html +200 -0
- package/modules/generator/tpl-field-combobox.html +228 -0
- package/modules/generator/tpl-field-datepicker.html +192 -0
- package/modules/generator/tpl-field-filebox.html +189 -0
- package/modules/generator/tpl-field-numberbox.html +218 -0
- package/modules/generator/tpl-field-textbox.html +255 -0
- package/modules/generator/tpl-field-timepicker.html +192 -0
- package/modules/generator/tpl-searchdesign.html +32 -0
- package/modules/generator/tpl-uniquedesign.html +25 -0
- package/modules/login/login.css +10 -2
- package/package.json +5 -3
- package/percobaan/coba-sequencer.js +16 -0
- package/src/api.js +12 -9
- package/src/apis/generator.api.js +35 -23
- package/src/apis/login.api.js +1 -0
- package/src/context.js +12 -2
- package/src/db.js +58 -32
- package/src/generator/createApiModule.js +4 -1
- package/src/generator/createIcon.js +24 -2
- package/src/generator/createLayoutCss.js +107 -0
- package/src/generator/createModuleDetilEditHtml.js +12 -1
- package/src/generator/createModuleDetilEditMjs.js +32 -28
- package/src/generator/createModuleDetilListHtml.js +14 -7
- package/src/generator/createModuleDetilListMjs.js +13 -1
- package/src/generator/createModuleHeaderEditHtml.js +13 -1
- package/src/generator/createModuleHeaderEditMjs.js +23 -2
- package/src/generator/createProgramData.js +3 -2
- package/src/generator/createTable.js +42 -38
- package/src/generator/helper.js +45 -27
- package/src/generator/templates/__rollup-module copy.ejs +90 -0
- package/src/generator/templates/__rollup-module.ejs +102 -31
- package/src/generator/templates/api-module.js.ejs +171 -32
- package/src/generator/templates/layout.css.ejs +24 -0
- package/src/generator/templates/module-ext.html.ejs +1 -1
- package/src/generator/templates/module-ext.mjs.ejs +19 -1
- package/src/generator/templates/module.ejs.ejs +8 -0
- package/src/generator/templates/module.mjs.ejs +42 -5
- package/src/generator/templates/moduleDetilEdit.html.ejs +11 -0
- package/src/generator/templates/moduleDetilEdit.mjs.ejs +135 -30
- package/src/generator/templates/moduleDetilList.html.ejs +2 -1
- package/src/generator/templates/moduleDetilList.mjs.ejs +86 -11
- package/src/generator/templates/moduleHeaderEdit.html.ejs +8 -1
- package/src/generator/templates/moduleHeaderEdit.mjs.ejs +123 -36
- package/src/generator/templates/moduleHeaderList.html.ejs +5 -1
- package/src/generator/templates/moduleHeaderList.mjs.ejs +47 -15
- package/src/generator/trygenerate.js +18 -2
- package/src/generator/worker.js +83 -72
- package/src/helper.js +12 -13
- package/src/logger.js +12 -12
- package/src/notifier.js +29 -0
- package/src/routers/generatorApi.js +9 -3
- package/src/routers/generatorPage.js +3 -1
- package/src/routers/moduleApi.js +1 -1
- package/src/routers/modulePage.js +42 -7
- package/src/sequencerdoc.js +22 -46
- package/src/sequencerline.js +16 -4
- package/src/session.js +69 -33
- package/src/startup.js +47 -10
- package/src/webapps.js +62 -18
- package/templates/_lib_debug.ejs +8 -8
- package/templates/_lib_production.ejs +2 -2
- package/templates/application.page.ejs +43 -8
- package/templates/generator.page.ejs +4 -3
- package/templates/index.page.ejs +2 -2
- package/templates/login.page.ejs +3 -3
- package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js +0 -11
- package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js.map +0 -1
- package/libs/webmodule/pagehelper.mjs +0 -45
- package/modules/generator/generator.png +0 -0
- /package/{libs/fgta5js-dist/fgta5js-v1.8.3.min.css → lib/fgta5js-dist/fgta5js-v1.8.5.min.css} +0 -0
- /package/{libs → lib}/fgta5js-dist/fonts/karla-italic-latin-ext.woff2 +0 -0
- /package/{libs → lib}/fgta5js-dist/fonts/karla-italic-latin.woff2 +0 -0
- /package/{libs → lib}/fgta5js-dist/fonts/karla-normal-latin-ext.woff2 +0 -0
- /package/{libs → lib}/fgta5js-dist/fonts/karla-normal-latin.woff2 +0 -0
- /package/{libs → lib}/fgta5js-dist/fonts/karla.css +0 -0
- /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>
|
package/modules/login/login.css
CHANGED
|
@@ -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
|
-
|
|
10
|
+
padding: 5px;
|
|
11
|
+
margin: 3px;
|
|
7
12
|
}
|
|
8
13
|
|
|
9
14
|
.loginbox button {
|
|
10
|
-
margin
|
|
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.
|
|
3
|
+
"version": "1.2.4",
|
|
4
4
|
"description": "library javascript (nodejs+express) untuk pengembangan applikasi web",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/webapps.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"postgresql"
|
|
17
17
|
],
|
|
18
18
|
"author": "Agung Nugroho",
|
|
19
|
-
"license": "
|
|
19
|
+
"license": "BSD-3-Clause",
|
|
20
20
|
"publishConfig": {
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
@@ -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
|
+
}
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
227
|
+
ModuleDbContract: ModuleDbContract,
|
|
228
|
+
jeda: 0.5, // jeda 0.5 detik per masing-masing generate
|
|
217
229
|
})
|
|
218
230
|
|
|
219
231
|
|
package/src/apis/login.api.js
CHANGED
package/src/context.js
CHANGED
|
@@ -4,12 +4,22 @@ let __rootDirectory
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
let fnParseModuleRequest
|
|
7
|
+
let apiCache = true
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
export default {
|
|
9
|
-
|
|
11
|
+
|
|
12
|
+
alwaysLoadApi: (cached = true) => {
|
|
13
|
+
apiCache = cached
|
|
14
|
+
},
|
|
15
|
+
isApiCached: () => {
|
|
16
|
+
return apiCache
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
setWebappsDirectory: (dirname) => { __dir = dirname },
|
|
10
20
|
getWebappsDirectory: () => { return __dir },
|
|
11
21
|
|
|
12
|
-
setRootDirectory: (rootdir) => { __rootDirectory=rootdir },
|
|
22
|
+
setRootDirectory: (rootdir) => { __rootDirectory = rootdir },
|
|
13
23
|
getRootDirectory: () => { return __rootDirectory },
|
|
14
24
|
|
|
15
25
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
process.
|
|
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
|
|
31
|
-
|
|
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
|
-
|
|
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,
|