@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.
- package/LICENSE +28 -0
- package/README.md +2 -0
- package/jsconfig.json +10 -0
- package/libs/fgta5js-dist/fgta5js-v1.8.3.min.css +2 -0
- package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js +11 -0
- package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js.map +1 -0
- package/libs/fgta5js-dist/fonts/karla-italic-latin-ext.woff2 +0 -0
- package/libs/fgta5js-dist/fonts/karla-italic-latin.woff2 +0 -0
- package/libs/fgta5js-dist/fonts/karla-normal-latin-ext.woff2 +0 -0
- package/libs/fgta5js-dist/fonts/karla-normal-latin.woff2 +0 -0
- package/libs/fgta5js-dist/fonts/karla.css +142 -0
- package/libs/webmodule/module-edit.css +163 -0
- package/libs/webmodule/module-footer.css +22 -0
- package/libs/webmodule/module-list.css +25 -0
- package/libs/webmodule/module.css +52 -0
- package/libs/webmodule/module.js +195 -0
- package/libs/webmodule/pagehelper.mjs +45 -0
- package/modules/generator/appgen-components.mjs +142 -0
- package/modules/generator/appgen-icons.mjs +6 -0
- package/modules/generator/appgen-io.mjs +784 -0
- package/modules/generator/appgen-ui-search.mjs +173 -0
- package/modules/generator/appgen-ui-unique.mjs +153 -0
- package/modules/generator/appgen-ui.mjs +1181 -0
- package/modules/generator/generator-context.mjs +18 -0
- package/modules/generator/generator-designtemplate.html +1508 -0
- package/modules/generator/generator-ext.html +0 -0
- package/modules/generator/generator-ext.mjs +3 -0
- package/modules/generator/generator.css +642 -0
- package/modules/generator/generator.mjs +195 -0
- package/modules/generator/generator.png +0 -0
- package/modules/generator/generatorEdit.html +185 -0
- package/modules/generator/generatorEdit.mjs +238 -0
- package/modules/generator/generatorList.html +32 -0
- package/modules/generator/generatorList.mjs +243 -0
- package/modules/login/login.css +11 -0
- package/modules/login/login.html +12 -0
- package/modules/login/login.mjs +111 -0
- package/package.json +46 -0
- package/percobaan/simmpan-ke-minio.js +24 -0
- package/src/api.js +80 -0
- package/src/apis/generator.api.js +226 -0
- package/src/apis/login.api.js +109 -0
- package/src/bucket.js +24 -0
- package/src/context.js +26 -0
- package/src/datalog.sql +22 -0
- package/src/datarecords.js +0 -0
- package/src/db.js +61 -0
- package/src/generator/createApiExtenderModule.js +54 -0
- package/src/generator/createApiModule.js +218 -0
- package/src/generator/createIcon.js +62 -0
- package/src/generator/createInfoAboutExtender.js +42 -0
- package/src/generator/createInfoLogs.js +41 -0
- package/src/generator/createInfoRecordExtender.js +41 -0
- package/src/generator/createModuleContext.js +48 -0
- package/src/generator/createModuleDetilEditHtml.js +110 -0
- package/src/generator/createModuleDetilEditMjs.js +172 -0
- package/src/generator/createModuleDetilListHtml.js +146 -0
- package/src/generator/createModuleDetilListMjs.js +73 -0
- package/src/generator/createModuleEjs.js +51 -0
- package/src/generator/createModuleExtenderHtml.js +43 -0
- package/src/generator/createModuleExtenderMjs.js +43 -0
- package/src/generator/createModuleHeaderEditHtml.js +148 -0
- package/src/generator/createModuleHeaderEditMjs.js +197 -0
- package/src/generator/createModuleHeaderListHtml.js +144 -0
- package/src/generator/createModuleHeaderListMjs.js +67 -0
- package/src/generator/createModuleMjs.js +67 -0
- package/src/generator/createModuleRollup.js +42 -0
- package/src/generator/createProgramData.js +96 -0
- package/src/generator/createTable.js +156 -0
- package/src/generator/ddl.js +475 -0
- package/src/generator/helper.js +149 -0
- package/src/generator/templates/__rollup-module.ejs +90 -0
- package/src/generator/templates/api-extender-module.js.ejs +0 -0
- package/src/generator/templates/api-module.js.ejs +818 -0
- package/src/generator/templates/module-context.ejs +16 -0
- package/src/generator/templates/module-ext-about.ejs +1 -0
- package/src/generator/templates/module-ext-record.ejs +1 -0
- package/src/generator/templates/module-ext.html.ejs +3 -0
- package/src/generator/templates/module-ext.mjs.ejs +21 -0
- package/src/generator/templates/module-logs.ejs +14 -0
- package/src/generator/templates/module.ejs.ejs +48 -0
- package/src/generator/templates/module.mjs.ejs +256 -0
- package/src/generator/templates/moduleDetilEdit.html.ejs +34 -0
- package/src/generator/templates/moduleDetilEdit.mjs.ejs +792 -0
- package/src/generator/templates/moduleDetilList.html.ejs +26 -0
- package/src/generator/templates/moduleDetilList.mjs.ejs +319 -0
- package/src/generator/templates/moduleHeaderEdit.html.ejs +53 -0
- package/src/generator/templates/moduleHeaderEdit.mjs.ejs +807 -0
- package/src/generator/templates/moduleHeaderList.html.ejs +24 -0
- package/src/generator/templates/moduleHeaderList.mjs.ejs +308 -0
- package/src/generator/templates/sqlAddField.ejs +3 -0
- package/src/generator/templates/sqlAddForeignKey.ejs +12 -0
- package/src/generator/templates/sqlAddUniqueIndex.ejs +4 -0
- package/src/generator/templates/sqlCreateTable.ejs +9 -0
- package/src/generator/templates/sqlDropForeignKey.ejs +3 -0
- package/src/generator/templates/sqlDropUniqueIndex.ejs +4 -0
- package/src/generator/templates/sqlModifyField.ejs +6 -0
- package/src/generator/trygenerate.js +83 -0
- package/src/generator/worker.js +389 -0
- package/src/helper.js +82 -0
- package/src/logger.js +39 -0
- package/src/router.js +84 -0
- package/src/routers/defaultLoginApi.js +29 -0
- package/src/routers/defaultLoginAsset.js +18 -0
- package/src/routers/defaultLoginPage.js +36 -0
- package/src/routers/defaultRootIndex.js +16 -0
- package/src/routers/downloadHandler.js +51 -0
- package/src/routers/fileUploadApi.js +15 -0
- package/src/routers/generatorApi.js +30 -0
- package/src/routers/generatorAsset.js +18 -0
- package/src/routers/generatorPage.js +37 -0
- package/src/routers/handleError.js +43 -0
- package/src/routers/handleModuleNotfound.js +12 -0
- package/src/routers/moduleApi.js +34 -0
- package/src/routers/modulePage.js +102 -0
- package/src/sequencerdoc.js +311 -0
- package/src/sequencerline.js +214 -0
- package/src/session.js +57 -0
- package/src/startup.js +59 -0
- package/src/webapps.js +239 -0
- package/src/workermanager.js +83 -0
- package/templates/_lib_debug.ejs +11 -0
- package/templates/_lib_production.ejs +5 -0
- package/templates/application.page.ejs +143 -0
- package/templates/generator.page.ejs +131 -0
- package/templates/index.page.ejs +24 -0
- package/templates/login.page.ejs +102 -0
- package/templates/moduleError.ejs +16 -0
- package/templates/moduleNotfound.ejs +14 -0
- package/webapps.code-workspace +11 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import Context from './generator-context.mjs'
|
|
2
|
+
import * as generatorList from './generatorList.mjs'
|
|
3
|
+
import * as generatorEdit from './generatorEdit.mjs'
|
|
4
|
+
import * as generatorExtender from './generator-ext.mjs'
|
|
5
|
+
|
|
6
|
+
const app = Context.app
|
|
7
|
+
const Crsl = Context.Crsl
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export default class extends Module {
|
|
11
|
+
constructor() {
|
|
12
|
+
super()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async main(args={}) {
|
|
16
|
+
|
|
17
|
+
console.log('initializing module...')
|
|
18
|
+
app.setTitle('Generator')
|
|
19
|
+
app.showFooter(true)
|
|
20
|
+
|
|
21
|
+
args.autoLoadGridData = true
|
|
22
|
+
|
|
23
|
+
const self = this
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
// module-module yang di load perlu di pack dulu ke dalam variable
|
|
27
|
+
// jangan import lagi module-module ini di dalam mjs tersebut
|
|
28
|
+
// karena akan terjadi cyclic redudancy pada saat di rollup
|
|
29
|
+
self.Modules = {
|
|
30
|
+
generatorList,
|
|
31
|
+
generatorEdit,
|
|
32
|
+
generatorExtender
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
|
|
37
|
+
// inisiasi sisi server
|
|
38
|
+
try {
|
|
39
|
+
const result = await Module.apiCall(`/${Context.moduleName}/init`, { })
|
|
40
|
+
Context.notifierId = result.notifierId
|
|
41
|
+
Context.notifierSocket = result.notifierSocket
|
|
42
|
+
Context.userId = result.userId
|
|
43
|
+
Context.userFullname = result.userFullname
|
|
44
|
+
Context.sid = result.sid
|
|
45
|
+
Context.targetDirectory = result.targetDirectory
|
|
46
|
+
Context.appsUrls = result.appsUrls
|
|
47
|
+
|
|
48
|
+
} catch (err) {
|
|
49
|
+
throw err
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
await Promise.all([
|
|
54
|
+
generatorList.init(self, args),
|
|
55
|
+
generatorEdit.init(self, args),
|
|
56
|
+
generatorExtender.init(self, args)
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
// render dan setup halaman
|
|
60
|
+
await render(self)
|
|
61
|
+
|
|
62
|
+
// listen keyboard action
|
|
63
|
+
listenUserKeys(self)
|
|
64
|
+
|
|
65
|
+
// kalau user melakukan reload, konfirm dulu
|
|
66
|
+
const isFormDirty = true
|
|
67
|
+
window.onbeforeunload = (evt)=>{
|
|
68
|
+
if (isFormDirty) {
|
|
69
|
+
evt.preventDefault();
|
|
70
|
+
return "Changes you made may not be saved."
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
} catch (err) {
|
|
74
|
+
throw err
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
numberboxDatatypeChange(el) {
|
|
80
|
+
const datatype = el.value
|
|
81
|
+
const designField = el.closest('div[name="design-data-field"]');
|
|
82
|
+
const gridFormatter = designField.querySelector('input[name="gridformatter"]')
|
|
83
|
+
|
|
84
|
+
// datatype: int, smallint, bigint, decimal
|
|
85
|
+
// format: decimal, int
|
|
86
|
+
if (datatype=='smallint') {
|
|
87
|
+
gridFormatter.value = 'int(v)'
|
|
88
|
+
} else if (datatype=='decimal') {
|
|
89
|
+
gridFormatter.value = 'decimal(v, 2)'
|
|
90
|
+
} else {
|
|
91
|
+
gridFormatter.value = 'decimal(v, 0)'
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
async function render(self) {
|
|
99
|
+
try {
|
|
100
|
+
const footerButtonsContainer = document.getElementsByClassName('footer-buttons-container')
|
|
101
|
+
Module.renderFooterButtons(footerButtonsContainer)
|
|
102
|
+
|
|
103
|
+
Crsl.setIconUrl('/generator/generator.png')
|
|
104
|
+
|
|
105
|
+
Crsl.addEventListener($fgta5.SectionCarousell.EVT_SECTIONSHOWING, (evt)=>{
|
|
106
|
+
var sectionId = evt.detail.commingSection.Id
|
|
107
|
+
for (let cont of footerButtonsContainer) {
|
|
108
|
+
var currContainerSectionId = cont.getAttribute('data-section')
|
|
109
|
+
if (currContainerSectionId==sectionId) {
|
|
110
|
+
setTimeout(()=>{
|
|
111
|
+
cont.classList.remove('hidden')
|
|
112
|
+
cont.style.animation = 'dropped 0.3s forwards'
|
|
113
|
+
setTimeout(()=>{
|
|
114
|
+
cont.style.animation = 'unset'
|
|
115
|
+
}, 300)
|
|
116
|
+
}, 500)
|
|
117
|
+
} else {
|
|
118
|
+
cont.classList.add('hidden')
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// generator-ext.mjs, export function extendPage(self) {}
|
|
124
|
+
// jangan exekusi langsung dari userExtender, karena akan error saat di rollup
|
|
125
|
+
const extendPage = self.Modules.generatorExtender.extendPage
|
|
126
|
+
if (typeof extendPage === 'function') {
|
|
127
|
+
extendPage(self)
|
|
128
|
+
} else {
|
|
129
|
+
console.warn(`'extendPage' tidak diimplementasikan di extender`)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
} catch (err) {
|
|
133
|
+
throw err
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
function listenUserKeys(self) {
|
|
139
|
+
document.addEventListener('keydown', (evt) => {
|
|
140
|
+
const id = Crsl.CurrentSection.Id
|
|
141
|
+
const moduleId = Context.SectionMap[id]
|
|
142
|
+
const module = self.Modules[moduleId]
|
|
143
|
+
|
|
144
|
+
// jika ada dialog yang terbuka, semua event keyboard abaikan dulu, keculai tombol escape
|
|
145
|
+
const dialog = document.querySelector('dialog[open]');
|
|
146
|
+
if (dialog) {
|
|
147
|
+
if (evt.key.toLowerCase()=='escape') {
|
|
148
|
+
dialog.close();
|
|
149
|
+
evt.preventDefault();
|
|
150
|
+
} else if ((evt.ctrlKey || evt.metaKey) && evt.key.toLowerCase() === 's') {
|
|
151
|
+
evt.preventDefault();
|
|
152
|
+
}
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Cek apakah tombol Ctrl (atau Cmd di Mac) ditekan bersamaan dengan huruf 'S'
|
|
157
|
+
const key = evt.key.toLowerCase()
|
|
158
|
+
if ((evt.ctrlKey || evt.metaKey) && key === 's') {
|
|
159
|
+
evt.preventDefault(); // Mencegah aksi default (save page)
|
|
160
|
+
keyboardAction(self, module, 'save', evt)
|
|
161
|
+
} else if ((evt.ctrlKey || evt.metaKey) && key === 'n') {
|
|
162
|
+
evt.preventDefault(); // Mencegah aksi default
|
|
163
|
+
keyboardAction(self, module, 'new', evt)
|
|
164
|
+
} else if ( key ==='escape') {
|
|
165
|
+
evt.preventDefault();
|
|
166
|
+
keyboardAction(self, module, 'escape', evt)
|
|
167
|
+
} else if ( key === 'f2' ) {
|
|
168
|
+
keyboardAction(self, module, 'togleEdit', evt)
|
|
169
|
+
} else if ( key === 'arrowup' ) {
|
|
170
|
+
keyboardAction(self, module, 'up', evt)
|
|
171
|
+
} else if ( key === 'arrowdown' ) {
|
|
172
|
+
keyboardAction(self, module, 'down', evt)
|
|
173
|
+
} else if ( key === 'arrowright' ) {
|
|
174
|
+
keyboardAction(self, module, 'right', evt)
|
|
175
|
+
} else if ( key === 'arrowleft' ) {
|
|
176
|
+
keyboardAction(self, module, 'left', evt)
|
|
177
|
+
} else if ( key === 'enter' ) {
|
|
178
|
+
keyboardAction(self, module, 'enter', evt)
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
function keyboardAction(self, module, actionName, evt) {
|
|
185
|
+
|
|
186
|
+
if (module!=null) {
|
|
187
|
+
module.keyboardAction(self, actionName, evt)
|
|
188
|
+
} else {
|
|
189
|
+
// untuk keperluan log dan about, saat escape: back
|
|
190
|
+
if (actionName=='escape') {
|
|
191
|
+
Crsl.CurrentSection.back()
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
* Designer Editor
|
|
3
|
+
* nama program, deskripsi, table utama
|
|
4
|
+
* data2 detil related ke data utama
|
|
5
|
+
* drag and drop componen-component ke masing2 header / detail, kemudian dikonfigurasi
|
|
6
|
+
* -->
|
|
7
|
+
<div id="appgen-datadesign-layout">
|
|
8
|
+
<div id="layout-definition">
|
|
9
|
+
<div class="subtitle" style="grid-column: span 3;">Module Definition</div>
|
|
10
|
+
|
|
11
|
+
<label for="obj_programid">ID</label>
|
|
12
|
+
<input type="text" id="obj_programid" placeholder="[auto-id]" disabled>
|
|
13
|
+
|
|
14
|
+
<!-- kalau mau nambah baru, row span harus disesuaikan -->
|
|
15
|
+
<div id="upload-icon" style="grid-row: span 6;">
|
|
16
|
+
<label>
|
|
17
|
+
change
|
|
18
|
+
<input id="btn_IconUpload" type="file" accept=".svg,.png" style="display: none;" />
|
|
19
|
+
</label>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<label for="obj_appname">App Name</label>
|
|
23
|
+
<input type="text" id="obj_appname" style="text-transform: lowercase;">
|
|
24
|
+
|
|
25
|
+
<label for="obj_programname">Program Name</label>
|
|
26
|
+
<input type="text" id="obj_programname" style="text-transform: lowercase;">
|
|
27
|
+
|
|
28
|
+
<label for="obj_programname">Title</label>
|
|
29
|
+
<input type="text" id="obj_programtitle">
|
|
30
|
+
|
|
31
|
+
<label for="obj_directory">Directory</label>
|
|
32
|
+
<input type="text" id="obj_directory">
|
|
33
|
+
|
|
34
|
+
<label for="obj_programdescription">Description</label>
|
|
35
|
+
<input type="text" id="obj_programdescription">
|
|
36
|
+
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div id="layout-action">
|
|
40
|
+
<div class="subtitle">Actions</div>
|
|
41
|
+
<table cellpadding="0" cellspacing="0">
|
|
42
|
+
<tbody id="action-lists">
|
|
43
|
+
</tbody>
|
|
44
|
+
<tfoot>
|
|
45
|
+
<tr>
|
|
46
|
+
<td>
|
|
47
|
+
<input type="textbox" placeholder="action name" id="txt_action_name" class="action-input action-name">
|
|
48
|
+
</td>
|
|
49
|
+
<td>
|
|
50
|
+
<input type="textbox" placeholder="title" id="txt_action_title" class="action-input action-title">
|
|
51
|
+
</td>
|
|
52
|
+
<td>
|
|
53
|
+
<input type="textbox" placeholder="permission" id="txt_action_permission" class="action-input action-permission">
|
|
54
|
+
</td>
|
|
55
|
+
<td>
|
|
56
|
+
<button id="btn_action_add" class="action-button-add">Add</button>
|
|
57
|
+
</td>
|
|
58
|
+
</tr>
|
|
59
|
+
</tfoot>
|
|
60
|
+
</table>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<!-- Definisi Header Detil -->
|
|
64
|
+
<div id="layout-entity">
|
|
65
|
+
<div class="subtitle">Entites</div>
|
|
66
|
+
<table id="tbl_entity" cellpadding="0" cellspacing="0">
|
|
67
|
+
<thead>
|
|
68
|
+
<tr>
|
|
69
|
+
<th name="col_name">Name</th>
|
|
70
|
+
<th name="col_title">Title</th>
|
|
71
|
+
<th name="col_table">Table</th>
|
|
72
|
+
<th name="col_pk">PK</th>
|
|
73
|
+
<th name="col_btndesign"></th>
|
|
74
|
+
<th name="col_btnremove"></th>
|
|
75
|
+
<th name="col_id">ID</th>
|
|
76
|
+
</tr>
|
|
77
|
+
</thead>
|
|
78
|
+
<tbody id="data-entities">
|
|
79
|
+
|
|
80
|
+
</tbody>
|
|
81
|
+
<tfoot>
|
|
82
|
+
<tr>
|
|
83
|
+
<td colspan="7" style="padding-left: 0;"><button id="btn_addentity">Add Entity</button></td>
|
|
84
|
+
</tr>
|
|
85
|
+
</tfoot>
|
|
86
|
+
|
|
87
|
+
</table>
|
|
88
|
+
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<!-- Table Editor, menerima drag and drop dari component -->
|
|
92
|
+
<div id="layout-editor" class="hidden">
|
|
93
|
+
<div class="subtitle">Data Editor</div>
|
|
94
|
+
<div id="entities-design"></div>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<!-- Side Bar, untuk daftar komponen yang bisa di drag and drop, dan lain2 -->
|
|
98
|
+
<div id="layout-sidebar" class="hidden">
|
|
99
|
+
<div >
|
|
100
|
+
<div class="subtitle">Components</div>
|
|
101
|
+
<div id="crud-component-list">
|
|
102
|
+
</div>
|
|
103
|
+
<div class="subtitle">Design</div>
|
|
104
|
+
<div class="design-tools-container">
|
|
105
|
+
<a id="btn_ShowSummary" class="design-button">
|
|
106
|
+
<svg version="1.1" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
|
107
|
+
<g fill="#e6e6e6" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
|
108
|
+
<path d="m3 40h42v5h-42z"/>
|
|
109
|
+
<path d="m3 31.5h42v5h-42z"/>
|
|
110
|
+
<path d="m3 22h42v5h-42z"/>
|
|
111
|
+
<path d="m3 12.5h42v5h-42z"/>
|
|
112
|
+
<path d="m3 3h42v5h-42z"/>
|
|
113
|
+
</g>
|
|
114
|
+
</svg>
|
|
115
|
+
</a>
|
|
116
|
+
<a id="btn_ShowDetail" class="design-button">
|
|
117
|
+
<svg version="1.1" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
|
118
|
+
<g fill="#e6e6e6" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
|
119
|
+
<path d="m3 3h42v16h-42z"/>
|
|
120
|
+
<path d="m3 23h42v10h-42z"/>
|
|
121
|
+
<path d="m3 37h42v8h-42z"/>
|
|
122
|
+
</g>
|
|
123
|
+
</svg>
|
|
124
|
+
</a>
|
|
125
|
+
</div>
|
|
126
|
+
<div class="design-tools-container" style="margin-top: 30px">
|
|
127
|
+
<a id="btn_ShowFields" class="design-button">
|
|
128
|
+
<svg version="1.1" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
|
129
|
+
<rect x="5" y="11" width="39" height="25" fill="#e6e6e6"/>
|
|
130
|
+
<path d="m20.5 10.25h-16.5v27h16.5" fill="none" stroke="#000" stroke-linecap="square" stroke-width="3"/>
|
|
131
|
+
<path d="m38 10.25h6v27h-6" fill="none" stroke="#000" stroke-linecap="square" stroke-width="3"/>
|
|
132
|
+
<path d="m30 3.4251v41.15" fill="none" stroke="#000" stroke-linecap="square" stroke-width="3"/>
|
|
133
|
+
<path d="m25 3.0239h10" fill="none" stroke="#000" stroke-linecap="square" stroke-width="3"/>
|
|
134
|
+
<path d="m25 44.575h10" fill="none" stroke="#000" stroke-linecap="square" stroke-width="3"/>
|
|
135
|
+
<path d="m21.791 30.263h-2.2408l-1.5505-4.2631h-6.8392l-1.5505 4.2631h-2.1346l5.7559-15.296h2.8036zm-4.4391-6.0094-2.7718-7.5091-2.7824 7.5091z" fill="#1a1a1a" stroke-linecap="square" stroke-width="3" aria-label="A"/>
|
|
136
|
+
</svg>
|
|
137
|
+
</a>
|
|
138
|
+
|
|
139
|
+
<a id="btn_ShowUniq" class="design-button">
|
|
140
|
+
<svg version="1.1" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
|
141
|
+
<g fill="#1a1a1a">
|
|
142
|
+
<ellipse cx="24.5" cy="11" rx="16.5" ry="8"/>
|
|
143
|
+
<path d="m18.25 6.4615v30.462l5 5.5385 8.3333-6.9231v-2.7692l-5-2.7692 6.6667-4.1538-6.6667-4.1538 5.4167-4.1538v-11.077z"/>
|
|
144
|
+
</g>
|
|
145
|
+
</svg>
|
|
146
|
+
</a>
|
|
147
|
+
|
|
148
|
+
<a id="btn_ShowSearch" class="design-button">
|
|
149
|
+
<svg version="1.1" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
|
150
|
+
<g fill="#e6e6e6" stroke="#000" stroke-linecap="square">
|
|
151
|
+
<circle cx="29.75" cy="18.75" r="13.25" stroke-width="3"/>
|
|
152
|
+
<path d="m15 32-8 7" stroke-width="6"/>
|
|
153
|
+
</g>
|
|
154
|
+
</svg>
|
|
155
|
+
</a>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
</div>
|
|
161
|
+
<div style="margin-top: 100px" class="hidden">
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
<div class="footer-buttons-container hidden">
|
|
170
|
+
<div></div>
|
|
171
|
+
<div>
|
|
172
|
+
<button id="generatorEdit-btn_save">Save</button>
|
|
173
|
+
|
|
174
|
+
<button id="generatorEdit-btn_new" data-action="generator-new">New</button>
|
|
175
|
+
|
|
176
|
+
<button id="btnAppGenLoad" class="hidden">
|
|
177
|
+
Import<input id="input-file" type="file" style="display: none;">
|
|
178
|
+
</button>
|
|
179
|
+
|
|
180
|
+
<button id="btnAppGenSave" class="hidden">Export</button>
|
|
181
|
+
|
|
182
|
+
<button id="generatorEdit-btn_generate">Generate</button>
|
|
183
|
+
</div>
|
|
184
|
+
<div></div>
|
|
185
|
+
</div>
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import Context from './generator-context.mjs'
|
|
2
|
+
import AppGenUI from './appgen-ui.mjs'
|
|
3
|
+
import * as Extender from './generator-ext.mjs'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const CurrentState = {}
|
|
7
|
+
const Crsl = Context.Crsl
|
|
8
|
+
const CurrentSectionId = Context.Sections.generatorEdit
|
|
9
|
+
const CurrentSection = Crsl.Items[CurrentSectionId]
|
|
10
|
+
|
|
11
|
+
const ui = new AppGenUI(Context.app)
|
|
12
|
+
const btn_new = new $fgta5.ActionButton('generatorEdit-btn_new', 'generator-new')
|
|
13
|
+
const btn_save = new $fgta5.ActionButton('generatorEdit-btn_save')
|
|
14
|
+
const btn_generate = new $fgta5.ActionButton('generatorEdit-btn_generate')
|
|
15
|
+
|
|
16
|
+
const obj_appname = document.getElementById('obj_appname')
|
|
17
|
+
const obj_directory = document.getElementById('obj_directory')
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
export const Section = CurrentSection
|
|
21
|
+
|
|
22
|
+
export async function init(self, args) {
|
|
23
|
+
console.log('initializing generatorEdit ...')
|
|
24
|
+
|
|
25
|
+
CurrentSection.addEventListener($fgta5.Section.EVT_BACKBUTTONCLICK, async (evt)=>{
|
|
26
|
+
backToList(self, evt)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
btn_new.addEventListener('click', (evt)=>{ btn_new_click(self, evt)})
|
|
31
|
+
btn_save.addEventListener('click', (evt)=>{ btn_save_click(self, evt)})
|
|
32
|
+
btn_generate.addEventListener('click', (evt)=>{ btn_generate_click(self, evt) })
|
|
33
|
+
|
|
34
|
+
obj_appname.addEventListener('change', (evt)=>{ obj_appname_change(self, evt) })
|
|
35
|
+
|
|
36
|
+
await ui.Init(Context)
|
|
37
|
+
|
|
38
|
+
ui.pauseAutoSave(true)
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function openSelectedData(self, params) {
|
|
43
|
+
console.log('openSelectedData')
|
|
44
|
+
|
|
45
|
+
let mask = $fgta5.Modal.createMask()
|
|
46
|
+
try {
|
|
47
|
+
const id = params.keyvalue
|
|
48
|
+
|
|
49
|
+
console.log(params)
|
|
50
|
+
const result = await openData(self, id)
|
|
51
|
+
const data = result.generator_data
|
|
52
|
+
|
|
53
|
+
data.id = result.generator_id
|
|
54
|
+
|
|
55
|
+
ui.load(data)
|
|
56
|
+
} catch (err) {
|
|
57
|
+
throw err
|
|
58
|
+
} finally {
|
|
59
|
+
mask.close()
|
|
60
|
+
mask = null
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
export function keyboardAction(self, actionName) {
|
|
66
|
+
if (actionName=='save') {
|
|
67
|
+
btn_save.click()
|
|
68
|
+
} else if (actionName=='escape') {
|
|
69
|
+
const listSection = Crsl.Items[Context.Sections.generatorList]
|
|
70
|
+
listSection.show({direction:1})
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function openData(self, id) {
|
|
75
|
+
const apiOpen = new $fgta5.ApiEndpoint(`/${Context.moduleName}/open`)
|
|
76
|
+
try {
|
|
77
|
+
const result = await apiOpen.execute({ id })
|
|
78
|
+
return result
|
|
79
|
+
} catch (err) {
|
|
80
|
+
CurrentState.currentOpenedId = null
|
|
81
|
+
throw err
|
|
82
|
+
} finally {
|
|
83
|
+
apiOpen.dispose()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function backToList(self, evt) {
|
|
88
|
+
let goback = true
|
|
89
|
+
if (goback) {
|
|
90
|
+
evt.detail.fn_ShowNextSection()
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
async function obj_appname_change(self, evt) {
|
|
96
|
+
const el = evt.target
|
|
97
|
+
const value = el.value
|
|
98
|
+
|
|
99
|
+
if (Context.appsUrls[value]===undefined) {
|
|
100
|
+
const resp = await $fgta5.MessageBox.error(`nama apps '${value}' tidak teregister di daftar apps`)
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// console.log(Context.appsUrls[value].directory)
|
|
105
|
+
obj_directory.value = Context.appsUrls[value].directory
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
async function btn_new_click(self, evt) {
|
|
110
|
+
console.log('btn_new_click')
|
|
111
|
+
const sourceSection = evt.target.getAttribute('data-sectionsource')
|
|
112
|
+
const generatorList = self.Modules.generatorList
|
|
113
|
+
const listsecid = generatorList.Section.Id
|
|
114
|
+
const fromListSection = sourceSection===listsecid
|
|
115
|
+
if (fromListSection) {
|
|
116
|
+
// btn new di klik dari list
|
|
117
|
+
await CurrentSection.show()
|
|
118
|
+
|
|
119
|
+
// cek id, jika tidak kosong, perlu di-reset
|
|
120
|
+
const id = document.getElementById('obj_programid')
|
|
121
|
+
if (id!='') {
|
|
122
|
+
await ui.reset()
|
|
123
|
+
await ui.NewData()
|
|
124
|
+
ui.updateCache()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
} else {
|
|
128
|
+
const resp = await $fgta5.MessageBox.confirm('apakah anda yakin akan membuat data baru?')
|
|
129
|
+
if (resp=='ok') {
|
|
130
|
+
await ui.reset()
|
|
131
|
+
await ui.NewData()
|
|
132
|
+
ui.updateCache()
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function btn_save_click(self, evt) {
|
|
139
|
+
console.log('btn_save_click')
|
|
140
|
+
const data = await ui.getCurrentData()
|
|
141
|
+
|
|
142
|
+
let mask = $fgta5.Modal.createMask()
|
|
143
|
+
try {
|
|
144
|
+
const result = await Save(self, data)
|
|
145
|
+
ui.setCurrentId(result.generator_id)
|
|
146
|
+
|
|
147
|
+
console.log(result)
|
|
148
|
+
} catch (err) {
|
|
149
|
+
console.error(err)
|
|
150
|
+
$fgta5.MessageBox.error(err.message)
|
|
151
|
+
} finally {
|
|
152
|
+
mask.close()
|
|
153
|
+
mask = null
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
async function btn_generate_click(self, evt) {
|
|
159
|
+
console.log('btn_generate_click')
|
|
160
|
+
const data = await ui.getCurrentData()
|
|
161
|
+
|
|
162
|
+
let mask = $fgta5.Modal.createMask()
|
|
163
|
+
btn_generate.disabled = true
|
|
164
|
+
ui.pauseAutoSave(true)
|
|
165
|
+
try {
|
|
166
|
+
if (data.id=='') {
|
|
167
|
+
throw new Error('save dahulu sebelum generate')
|
|
168
|
+
}
|
|
169
|
+
const result = await Generate(self, data, mask)
|
|
170
|
+
console.log(result)
|
|
171
|
+
$fgta5.MessageBox.info('done')
|
|
172
|
+
} catch (err) {
|
|
173
|
+
console.error(err)
|
|
174
|
+
$fgta5.MessageBox.error(err.message)
|
|
175
|
+
} finally {
|
|
176
|
+
btn_generate.disabled = false
|
|
177
|
+
ui.pauseAutoSave(false)
|
|
178
|
+
mask.close()
|
|
179
|
+
mask = null
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
async function Save(self, data) {
|
|
186
|
+
const url = `/${Context.moduleName}/save`
|
|
187
|
+
try {
|
|
188
|
+
const result = await Module.apiCall(url, { data })
|
|
189
|
+
return result
|
|
190
|
+
} catch (err) {
|
|
191
|
+
throw err
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function Generate(self, data, mask) {
|
|
196
|
+
return new Promise(async (resolve, reject)=>{
|
|
197
|
+
const jobId = Date.now()
|
|
198
|
+
const clientId = `${Context.notifierId}-${jobId}`
|
|
199
|
+
const notifierSocket = Context.notifierSocket
|
|
200
|
+
const ws = new WebSocket(`${notifierSocket}/?clientId=${clientId}`);
|
|
201
|
+
|
|
202
|
+
ws.onmessage = (event) => {
|
|
203
|
+
const data = JSON.parse(event.data);
|
|
204
|
+
if (data.status === 'done') {
|
|
205
|
+
ws.close();
|
|
206
|
+
resolve(data);
|
|
207
|
+
} else if (data.status=='error') {
|
|
208
|
+
ws.close();
|
|
209
|
+
reject(new Error(data.info.message))
|
|
210
|
+
} else if (data.status=='message') {
|
|
211
|
+
console.log(data)
|
|
212
|
+
mask.setText(data.info.message)
|
|
213
|
+
} else if (data.status==='timeout') {
|
|
214
|
+
ws.close();
|
|
215
|
+
reject(new Error('generate timeout'));
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
ws.onerror = (err) => {
|
|
220
|
+
ws.close();
|
|
221
|
+
console.error(err)
|
|
222
|
+
reject(err);
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
const apiGen = new $fgta5.ApiEndpoint(`/${Context.moduleName}/generate`)
|
|
227
|
+
try {
|
|
228
|
+
const result = await apiGen.execute({ data, notifierSocket, clientId })
|
|
229
|
+
console.log(result)
|
|
230
|
+
|
|
231
|
+
// di sini tidak perlu resolve, karena resolve akan menunggu message dari websocket
|
|
232
|
+
} catch (err) {
|
|
233
|
+
reject(err)
|
|
234
|
+
} finally {
|
|
235
|
+
apiGen.dispose()
|
|
236
|
+
}
|
|
237
|
+
})
|
|
238
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<div class="search-container">
|
|
2
|
+
<div id="generatorList-pnl_search" class="search-parameters">
|
|
3
|
+
<input id="generatorList-txt_appname" fgta5-component="Textbox" placeholder="application" autocomplete="off" spellcheck="false" binding="appname">
|
|
4
|
+
<input id="generatorList-txt_searchtext" fgta5-component="Textbox" placeholder="search" autocomplete="off" spellcheck="false" binding="searchtext">
|
|
5
|
+
</div>
|
|
6
|
+
<button id="generatorList-btn_gridload">Load</button>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<table id="generatorList-tbl" fgta5-component="Gridview">
|
|
10
|
+
<thead>
|
|
11
|
+
<tr data-header key="generator_id">
|
|
12
|
+
<th data-name="generator_id" binding="generator_id">ID</th>
|
|
13
|
+
<th data-name="generator_modulename" binding="generator_modulename" sorting="true">Module</th>
|
|
14
|
+
<th data-name="generator_appname" binding="generator_appname" sorting="true">Application</th>
|
|
15
|
+
</tr>
|
|
16
|
+
</thead>
|
|
17
|
+
</table>
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
<div class="footer-buttons-container">
|
|
27
|
+
<div></div>
|
|
28
|
+
<div>
|
|
29
|
+
<button id="generatorList-btn_new" data-action="generator-new" data-sectionsource="generatorList-section">New</button>
|
|
30
|
+
</div>
|
|
31
|
+
<div></div>
|
|
32
|
+
</div>
|