@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 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 V1 --- */
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.6.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": "^2.144.0",
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.10.1",
44
+ "morgan": "^1.11.0",
45
45
  "session-file-store": "^1.5.0",
46
- "terser": "^5.46.0"
46
+ "terser": "^5.48.0"
47
47
  }
48
48
  }
@@ -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.image), data.filename)}</td>
43
+ <td>\${this.toImg($.toStr(data.filename), data.filename)}</td>
44
44
  <td>\${this.toPayload(data.error, '${_('Error Message')}')}</td>
45
- <td>\${this.toPayload(data.data, '${_('Error Data')}')}</td>
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
- if (typeof data === 'string' && data.startsWith('{')) {
62
- try {
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
- const payload = $.toStr(data);
69
- let excerpt = payload;
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 += '&hellip;';
80
81
  }
81
- return \`
82
- <a href="#" class="err-clicker" data-op="view" data-title="\${title}">
83
- <span>\${excerpt}</span>
84
- <pre style="display: none;">\${payload}</pre>
85
- </a>\`;
82
+ } else {
83
+ excerpt = '&hellip;';
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
- content = \`<div class="ui fluid scrolling container"><pre>\${$.safeStr(pre.text())}</pre></div>\`;
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);