@ntlab/sipd-tu-bridge-ui 1.6.1 → 1.7.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.
- package/controller/ui.js +17 -0
- package/index.js +13 -1
- package/package.json +4 -4
- package/views/ui/error.ejs +44 -19
package/controller/ui.js
CHANGED
|
@@ -115,6 +115,23 @@ class UiController extends Controller {
|
|
|
115
115
|
result.pages = req.app.locals.pager(result.count, result.size, result.page);
|
|
116
116
|
res.json(result);
|
|
117
117
|
});
|
|
118
|
+
this.addRoute('capture', 'get', '/capture/:filename', async (req, res, next) => {
|
|
119
|
+
/** @type {import('..').SipdApi} */
|
|
120
|
+
const api = req.app.api;
|
|
121
|
+
const result = await api.getCapture(req.params.filename);
|
|
122
|
+
if (result.data) {
|
|
123
|
+
const ext = req.params.filename.substr(req.params.filename.lastIndexOf('.') + 1).toLowerCase();
|
|
124
|
+
switch (ext) {
|
|
125
|
+
case 'png':
|
|
126
|
+
case 'json':
|
|
127
|
+
res.type(ext);
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
res.send(result.data);
|
|
131
|
+
} else {
|
|
132
|
+
res.sendStatus(404);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
118
135
|
this.addRoute('task', 'post', '/task/:op', async (req, res, next) => {
|
|
119
136
|
const result = {
|
|
120
137
|
success: false
|
package/index.js
CHANGED
|
@@ -35,7 +35,10 @@ const { Assets, CDN } = require('@ntlab/ntjs-assets');
|
|
|
35
35
|
// register script repository
|
|
36
36
|
require('@ntlab/ntjs-repo')();
|
|
37
37
|
|
|
38
|
-
/* --- BEGIN API
|
|
38
|
+
/* --- BEGIN API V2 --- */
|
|
39
|
+
|
|
40
|
+
/* V1: 2026-03-05 */
|
|
41
|
+
/* V2: 2026-06-23 */
|
|
39
42
|
|
|
40
43
|
/**
|
|
41
44
|
* SIPD Penatausahaan Bridge main application.
|
|
@@ -52,6 +55,7 @@ require('@ntlab/ntjs-repo')();
|
|
|
52
55
|
* @property {ActivityFunction} getActivity Get activity logs
|
|
53
56
|
* @property {ObjectFunction} getCount Get activity count
|
|
54
57
|
* @property {PagedObjectsFunction} getErrors Get captured errors
|
|
58
|
+
* @property {CaptureFileFunction} getCapture Get captured error file
|
|
55
59
|
* @property {QueryFunction} query Perform API query
|
|
56
60
|
*/
|
|
57
61
|
|
|
@@ -127,6 +131,14 @@ require('@ntlab/ntjs-repo')();
|
|
|
127
131
|
* @returns {Promise<[{name: string, seq: string, time: number}]>}
|
|
128
132
|
*/
|
|
129
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Get captured error file.
|
|
136
|
+
*
|
|
137
|
+
* @callback CaptureFileFunction
|
|
138
|
+
* @param {string} filename Filename
|
|
139
|
+
* @returns {Promise<{data: Buffer}>}
|
|
140
|
+
*/
|
|
141
|
+
|
|
130
142
|
/* --- END API --- */
|
|
131
143
|
|
|
132
144
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ntlab/sipd-tu-bridge-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "SIPD Penatausahaan Bridge Web Interface",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -34,15 +34,15 @@
|
|
|
34
34
|
"@ntlab/express-controller": "^1.3.0",
|
|
35
35
|
"@ntlab/express-middleware": "^2.6.0",
|
|
36
36
|
"@ntlab/ntjs": "^3.1.0",
|
|
37
|
-
"@ntlab/ntjs-assets": "^
|
|
37
|
+
"@ntlab/ntjs-assets": "^3.28.0",
|
|
38
38
|
"@ntlab/ntjs-repo": "^3.1.0",
|
|
39
39
|
"@ntlab/ntlib": "^2.9.1",
|
|
40
40
|
"ejs": "^3.1.10",
|
|
41
41
|
"express": "^5.2.1",
|
|
42
42
|
"express-session": "^1.19.0",
|
|
43
43
|
"http-errors": "^2.0.1",
|
|
44
|
-
"morgan": "^1.
|
|
44
|
+
"morgan": "^1.11.0",
|
|
45
45
|
"session-file-store": "^1.5.0",
|
|
46
|
-
"terser": "^5.
|
|
46
|
+
"terser": "^5.48.0"
|
|
47
47
|
}
|
|
48
48
|
}
|
package/views/ui/error.ejs
CHANGED
|
@@ -40,9 +40,9 @@ $.error = $.loader($('div[data-tab="error"] table'), {
|
|
|
40
40
|
$.error.toRow = function(data) {
|
|
41
41
|
return $(\`
|
|
42
42
|
<tr><td>\${data.nr}</td>
|
|
43
|
-
<td>\${this.toImg($.toStr(data.
|
|
43
|
+
<td>\${this.toImg($.toStr(data.filename), data.filename)}</td>
|
|
44
44
|
<td>\${this.toPayload(data.error, '${_('Error Message')}')}</td>
|
|
45
|
-
<td>\${this.toPayload(
|
|
45
|
+
<td>\${this.toPayload(null, '${_('Error Data')}', data.datafilename)}</td>
|
|
46
46
|
<td>
|
|
47
47
|
<a href="#" class="err-clicker" data-op="delete" data-filename="\${data.filename}" role="button"><i class="trash alternate outline red icon"></i></a>
|
|
48
48
|
</td>
|
|
@@ -52,21 +52,22 @@ $.error.toImg = function(data, alt) {
|
|
|
52
52
|
if (data) {
|
|
53
53
|
return \`
|
|
54
54
|
<a href="#" class="err-clicker" data-op="view" data-title="\${alt}" data-tooltip="\${alt}" data-position="right center">
|
|
55
|
-
<img class="ui medium rounded bordered image" src="\${data}" alt="\${alt}">
|
|
55
|
+
<img class="ui medium rounded bordered image" src="\${'${route('Ui', {name: 'capture', filename: 'FILENAME'})}'.replace(/FILENAME/, data)}" alt="\${alt}">
|
|
56
56
|
</a>\`;
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
$.error.toPayload = function(data, title) {
|
|
60
|
-
if (data) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
data = JSON.parse(data);
|
|
64
|
-
}
|
|
65
|
-
catch (err) {
|
|
66
|
-
}
|
|
59
|
+
$.error.toPayload = function(data, title, filename) {
|
|
60
|
+
if (typeof data === 'string' && data.startsWith('{')) {
|
|
61
|
+
try {
|
|
62
|
+
data = JSON.parse(data);
|
|
67
63
|
}
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
catch (err) {
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
let excerpt, payload;
|
|
68
|
+
if (data) {
|
|
69
|
+
payload = $.toStr(data);
|
|
70
|
+
excerpt = payload;
|
|
70
71
|
if (excerpt.length > 100) {
|
|
71
72
|
excerpt = excerpt.substr(0, 100);
|
|
72
73
|
if (excerpt.includes('\\n')) {
|
|
@@ -78,12 +79,16 @@ $.error.toPayload = function(data, title) {
|
|
|
78
79
|
}
|
|
79
80
|
excerpt += '…';
|
|
80
81
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
<pre style="display: none;">\${payload}</pre>
|
|
85
|
-
</a>\`;
|
|
82
|
+
} else {
|
|
83
|
+
excerpt = '…';
|
|
84
|
+
payload = '';
|
|
86
85
|
}
|
|
86
|
+
const url = filename ? '${route('Ui', {name: 'capture', filename: 'FILENAME'})}'.replace(/FILENAME/, filename) : '#';
|
|
87
|
+
return \`
|
|
88
|
+
<a href="\${url}" class="err-clicker" data-op="view" data-title="\${title}">
|
|
89
|
+
<span>\${excerpt}</span>
|
|
90
|
+
<pre style="display: none;">\${payload}</pre>
|
|
91
|
+
</a>\`;
|
|
87
92
|
}
|
|
88
93
|
$.error.handle = function(el) {
|
|
89
94
|
const self = this;
|
|
@@ -96,7 +101,19 @@ $.error.handle = function(el) {
|
|
|
96
101
|
size = 'fullscreen';
|
|
97
102
|
}
|
|
98
103
|
if (pre.length) {
|
|
99
|
-
|
|
104
|
+
if (el.attr('href') !== '#') {
|
|
105
|
+
content = \`
|
|
106
|
+
<div class="ui placeholder">
|
|
107
|
+
<div class="line"></div>
|
|
108
|
+
<div class="line"></div>
|
|
109
|
+
<div class="line"></div>
|
|
110
|
+
<div class="line"></div>
|
|
111
|
+
<div class="line"></div>
|
|
112
|
+
</div>\`;
|
|
113
|
+
} else {
|
|
114
|
+
content = \`<pre>\${$.safeStr(pre.text())}</pre>\`;
|
|
115
|
+
}
|
|
116
|
+
content = \`<div class="ui fluid scrolling container">\${content}</div>\`;
|
|
100
117
|
}
|
|
101
118
|
const dlg = $.ntdlg.create('err-view-dlg', el.data('title'), content, {
|
|
102
119
|
size,
|
|
@@ -105,6 +122,14 @@ $.error.handle = function(el) {
|
|
|
105
122
|
type: 'green approve',
|
|
106
123
|
caption: '<i class="check icon"></i>${_('Ok')}',
|
|
107
124
|
}
|
|
125
|
+
},
|
|
126
|
+
show() {
|
|
127
|
+
if (el.attr('href') !== '#') {
|
|
128
|
+
$.get(el.attr('href'))
|
|
129
|
+
.done(function(data) {
|
|
130
|
+
$('#err-view-dlg .container').html(typeof data === 'object' ? JSON.stringify(data, null, 2) : $.safeStr(data));
|
|
131
|
+
});
|
|
132
|
+
}
|
|
108
133
|
}
|
|
109
134
|
});
|
|
110
135
|
$.ntdlg.show(dlg);
|