@frangoteam/fuxa-min 1.2.11 → 1.3.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.
Files changed (67) hide show
  1. package/api/auth/index.js +141 -3
  2. package/api/command/index.js +1 -1
  3. package/api/index.js +21 -2
  4. package/api/jwt-helper.js +3 -1
  5. package/api/resources/index.js +19 -2
  6. package/api/scripts/index.js +7 -3
  7. package/dist/3rdpartylicenses.txt +139 -7
  8. package/dist/assets/i18n/de.json +10 -0
  9. package/dist/assets/i18n/en.json +21 -3
  10. package/dist/assets/i18n/es.json +12 -0
  11. package/dist/assets/i18n/fr.json +11 -0
  12. package/dist/assets/i18n/ja.json +16 -6
  13. package/dist/assets/i18n/ko.json +12 -0
  14. package/dist/assets/i18n/pt.json +9 -2
  15. package/dist/assets/i18n/ru.json +11 -0
  16. package/dist/assets/i18n/sv.json +11 -1
  17. package/dist/assets/i18n/tr.json +8 -1
  18. package/dist/assets/i18n/ua.json +9 -2
  19. package/dist/assets/i18n/zh-cn.json +11 -0
  20. package/dist/assets/i18n/zh-tw.json +12 -1
  21. package/dist/assets/lib/svgeditor/fuxa-editor.min.js +17 -23
  22. package/dist/index.html +2 -2
  23. package/dist/main.72bdfed42c527918.js +329 -0
  24. package/dist/polyfills.d7de05f9af2fb559.js +1 -0
  25. package/dist/{runtime.8ef63094e52a66ba.js → runtime.9136a61a9b98f987.js} +1 -1
  26. package/dist/{scripts.40b60f02658462e4.js → scripts.d9e6ee984bf6f3b7.js} +1 -1
  27. package/dist/styles.545e37beb3e671ba.css +1 -0
  28. package/docs/openapi.yaml +3 -0
  29. package/integrations/node-red/index.js +4 -5
  30. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-daq.html +56 -5
  31. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-daq.js +8 -2
  32. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-change.html +56 -5
  33. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-change.js +12 -12
  34. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-daq-settings.html +56 -5
  35. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-daq-settings.js +14 -10
  36. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag.html +69 -14
  37. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag.js +44 -12
  38. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag-daq-settings.html +56 -5
  39. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag-daq-settings.js +24 -20
  40. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag.html +72 -13
  41. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag.js +33 -7
  42. package/main.js +38 -17
  43. package/package.json +10 -5
  44. package/runtime/alarms/alarmstorage.js +45 -30
  45. package/runtime/apikeys/apiKeysStorage.js +34 -22
  46. package/runtime/devices/adsclient/index.js +1 -1
  47. package/runtime/devices/ethernetip/index.js +1 -1
  48. package/runtime/devices/gpio/index.js +1 -1
  49. package/runtime/devices/odbc/index.js +14 -9
  50. package/runtime/devices/s7/index.js +2 -2
  51. package/runtime/devices/template/index.js +14 -14
  52. package/runtime/notificator/notifystorage.js +34 -23
  53. package/runtime/project/index.js +16 -0
  54. package/runtime/project/prjstorage.js +78 -40
  55. package/runtime/scripts/index.js +6 -2
  56. package/runtime/storage/calculator.js +17 -13
  57. package/runtime/storage/daqstorage.js +28 -2
  58. package/runtime/storage/influxdb/index.js +8 -3
  59. package/runtime/storage/questdb/index.js +224 -0
  60. package/runtime/storage/sqlite/index.js +11 -8
  61. package/runtime/storage/tdengine/index.js +24 -9
  62. package/runtime/users/usrstorage.js +65 -61
  63. package/runtime/utils.js +5 -0
  64. package/settings.default.js +8 -2
  65. package/dist/main.92522279642ef880.js +0 -329
  66. package/dist/polyfills.c8e7db9850a3ad8b.js +0 -1
  67. package/dist/styles.03cc550382689976.css +0 -1
package/api/auth/index.js CHANGED
@@ -10,12 +10,78 @@ const authJwt = require('../jwt-helper');
10
10
  var runtime;
11
11
  var secretCode;
12
12
  var tokenExpiresIn;
13
+ var enableRefreshCookieAuth = false;
14
+ var refreshTokenExpiresIn = '7d';
15
+ const refreshCookieName = 'fuxa_refresh';
16
+
17
+ function parseExpiresToMs(expiresIn) {
18
+ if (expiresIn === undefined || expiresIn === null) {
19
+ return null;
20
+ }
21
+ if (typeof expiresIn === 'number') {
22
+ return expiresIn * 1000;
23
+ }
24
+ if (typeof expiresIn !== 'string') {
25
+ return null;
26
+ }
27
+ const match = expiresIn.trim().match(/^(\d+)\s*([smhd])?$/i);
28
+ if (!match) {
29
+ return null;
30
+ }
31
+ const value = Number(match[1]);
32
+ const unit = (match[2] || 's').toLowerCase();
33
+ const multipliers = { s: 1000, m: 60000, h: 3600000, d: 86400000 };
34
+ return value * (multipliers[unit] || 1000);
35
+ }
36
+
37
+ function getCookieValue(req, name) {
38
+ const cookieHeader = req.headers.cookie;
39
+ if (!cookieHeader) return null;
40
+ const cookies = cookieHeader.split(';');
41
+ for (const cookie of cookies) {
42
+ const [key, ...rest] = cookie.trim().split('=');
43
+ if (key === name) {
44
+ return decodeURIComponent(rest.join('='));
45
+ }
46
+ }
47
+ return null;
48
+ }
49
+
50
+ function buildAccessToken(user) {
51
+ return jwt.sign({ id: user.username, groups: user.groups }, secretCode, { expiresIn: tokenExpiresIn });
52
+ }
53
+
54
+ function buildRefreshToken(user) {
55
+ return jwt.sign({ id: user.username, groups: user.groups, type: 'refresh' }, secretCode, { expiresIn: refreshTokenExpiresIn });
56
+ }
57
+
58
+ function setRefreshCookie(res, token) {
59
+ const maxAge = parseExpiresToMs(refreshTokenExpiresIn);
60
+ const options = {
61
+ httpOnly: true,
62
+ sameSite: 'lax',
63
+ secure: !!runtime?.settings?.https,
64
+ path: '/api/refresh'
65
+ };
66
+ if (maxAge) {
67
+ options.maxAge = maxAge;
68
+ }
69
+ res.cookie(refreshCookieName, token, options);
70
+ }
71
+
72
+ function clearRefreshCookie(res) {
73
+ res.clearCookie(refreshCookieName, { path: '/api/refresh' });
74
+ }
13
75
 
14
76
  module.exports = {
15
- init: function (_runtime, _secretCode, _tokenExpires) {
77
+ init: function (_runtime, _secretCode, _tokenExpires, _enableRefreshCookieAuth, _refreshTokenExpires) {
16
78
  runtime = _runtime;
17
79
  secretCode = _secretCode;
18
80
  tokenExpiresIn = _tokenExpires;
81
+ enableRefreshCookieAuth = !!_enableRefreshCookieAuth;
82
+ if (_refreshTokenExpires) {
83
+ refreshTokenExpiresIn = _refreshTokenExpires;
84
+ }
19
85
  },
20
86
  app: function () {
21
87
  var authApp = express();
@@ -35,7 +101,11 @@ module.exports = {
35
101
  runtime.users.findOne(req.body).then(function (userInfo) {
36
102
  if (userInfo && userInfo.length && userInfo[0].password) {
37
103
  if (bcrypt.compareSync(req.body.password, userInfo[0].password)) {
38
- const token = jwt.sign({ id: userInfo[0].username, groups: userInfo[0].groups }, secretCode, { expiresIn: tokenExpiresIn });//'1h' });
104
+ const token = buildAccessToken(userInfo[0]);
105
+ if (enableRefreshCookieAuth) {
106
+ const refreshToken = buildRefreshToken(userInfo[0]);
107
+ setRefreshCookie(res, refreshToken);
108
+ }
39
109
  res.json({
40
110
  status: 'success',
41
111
  message: 'user found!!!',
@@ -66,6 +136,74 @@ module.exports = {
66
136
  });
67
137
  });
68
138
 
139
+ /**
140
+ * POST Refresh
141
+ * Refresh access token using HttpOnly refresh cookie
142
+ */
143
+ authApp.post('/api/refresh', async function (req, res, next) {
144
+ if (!runtime?.settings?.secureEnabled || !enableRefreshCookieAuth) {
145
+ return res.status(204).end();
146
+ }
147
+ const refreshToken = getCookieValue(req, refreshCookieName);
148
+ if (!refreshToken) {
149
+ return res.status(401).json({ status: 'error', message: 'Refresh token missing' });
150
+ }
151
+ try {
152
+ const decoded = jwt.verify(refreshToken, secretCode);
153
+ if (decoded?.type !== 'refresh') {
154
+ clearRefreshCookie(res);
155
+ return res.status(401).json({ status: 'error', message: 'Invalid refresh token' });
156
+ }
157
+
158
+ let userData = null;
159
+ try {
160
+ const users = await runtime.users.getUsers({ username: decoded.id });
161
+ if (users && users.length) {
162
+ userData = users[0];
163
+ }
164
+ } catch (err) {
165
+ runtime.logger.error(`api refresh: user lookup failed ${err}`);
166
+ }
167
+
168
+ const user = {
169
+ username: decoded.id,
170
+ fullname: userData?.fullname,
171
+ groups: userData?.groups || decoded.groups,
172
+ info: userData?.info
173
+ };
174
+
175
+ const newAccessToken = buildAccessToken(user);
176
+ const newRefreshToken = buildRefreshToken(user);
177
+ setRefreshCookie(res, newRefreshToken);
178
+
179
+ res.json({
180
+ status: 'success',
181
+ message: 'token refreshed',
182
+ data: {
183
+ username: user.username,
184
+ fullname: user.fullname,
185
+ groups: user.groups,
186
+ info: user.info,
187
+ token: newAccessToken
188
+ }
189
+ });
190
+ } catch (err) {
191
+ clearRefreshCookie(res);
192
+ res.status(401).json({ status: 'error', message: 'Invalid refresh token' });
193
+ }
194
+ });
195
+
196
+ /**
197
+ * POST SignOut
198
+ * Clear refresh cookie
199
+ */
200
+ authApp.post('/api/signout', function (req, res, next) {
201
+ if (enableRefreshCookieAuth) {
202
+ clearRefreshCookie(res);
203
+ }
204
+ res.status(204).end();
205
+ });
206
+
69
207
  return authApp;
70
208
  }
71
- }
209
+ }
@@ -78,7 +78,7 @@ module.exports = {
78
78
  if (res.statusCode === 403) {
79
79
  runtime.logger.error("api get getTagValue: Tocken Expired");
80
80
  } else if (!authJwt.haveAdminPermission(permission) && !runtime.scriptsMgr.isAuthorisedByScriptName(req.query.sourceScriptName, permission)) {
81
- res.status(400).json({error:"unauthorized_error", message: "Unauthorized!"});
81
+ res.status(401).json({error:"unauthorized_error", message: "Unauthorized!"});
82
82
  runtime.logger.error("api get getTagValue: Unauthorized");
83
83
  } else {
84
84
  try {
package/api/index.js CHANGED
@@ -56,7 +56,7 @@ function init(_server, _runtime) {
56
56
  apiApp.use(usersApi.app());
57
57
  alarmsApi.init(runtime, authMiddleware, verifyGroups);
58
58
  apiApp.use(alarmsApi.app());
59
- authApi.init(runtime, authJwt.secretCode, authJwt.tokenExpiresIn);
59
+ authApi.init(runtime, authJwt.secretCode, authJwt.tokenExpiresIn, runtime.settings.enableRefreshCookieAuth, runtime.settings.refreshTokenExpiresIn);
60
60
  apiApp.use(authApi.app());
61
61
  pluginsApi.init(runtime, authMiddleware, verifyGroups);
62
62
  apiApp.use(pluginsApi.app());
@@ -146,9 +146,15 @@ function init(_server, _runtime) {
146
146
  if (!req.body.secretCode && runtime.settings.secretCode) {
147
147
  req.body.secretCode = runtime.settings.secretCode;
148
148
  }
149
+ if (req.body.secureEnabled && !req.body.secretCode) {
150
+ req.body.secretCode = utils.generateSecretCode();
151
+ runtime.logger.warn('Generated random JWT secret because secureEnabled=true and no secretCode was provided.');
152
+ }
149
153
  const prevAuth = {
150
154
  secureEnabled: runtime.settings.secureEnabled,
151
155
  tokenExpiresIn: runtime.settings.tokenExpiresIn,
156
+ enableRefreshCookieAuth: runtime.settings.enableRefreshCookieAuth,
157
+ refreshTokenExpiresIn: runtime.settings.refreshTokenExpiresIn,
152
158
  secretCode: runtime.settings.secretCode
153
159
  };
154
160
  if (req.body.nodeRedEnabled === true &&
@@ -160,9 +166,11 @@ function init(_server, _runtime) {
160
166
  mergeUserSettings(req.body);
161
167
  if (prevAuth.secureEnabled !== runtime.settings.secureEnabled ||
162
168
  prevAuth.tokenExpiresIn !== runtime.settings.tokenExpiresIn ||
169
+ prevAuth.enableRefreshCookieAuth !== runtime.settings.enableRefreshCookieAuth ||
170
+ prevAuth.refreshTokenExpiresIn !== runtime.settings.refreshTokenExpiresIn ||
163
171
  prevAuth.secretCode !== runtime.settings.secretCode) {
164
172
  authJwt.init(runtime.settings.secureEnabled, runtime.settings.secretCode, runtime.settings.tokenExpiresIn);
165
- authApi.init(runtime, authJwt.secretCode, authJwt.tokenExpiresIn);
173
+ authApi.init(runtime, authJwt.secretCode, authJwt.tokenExpiresIn, runtime.settings.enableRefreshCookieAuth, runtime.settings.refreshTokenExpiresIn);
166
174
  }
167
175
  runtime.restart(true).then(function(result) {
168
176
  res.end();
@@ -221,6 +229,9 @@ function mergeUserSettings(settings) {
221
229
  if (settings.language) {
222
230
  runtime.settings.language = settings.language;
223
231
  }
232
+ if (!utils.isNullOrUndefined(settings.hideEditorOnboarding)) {
233
+ runtime.settings.hideEditorOnboarding = settings.hideEditorOnboarding;
234
+ }
224
235
  runtime.settings.broadcastAll = settings.broadcastAll;
225
236
  runtime.settings.secureEnabled = settings.secureEnabled;
226
237
  runtime.settings.logFull = settings.logFull;
@@ -229,6 +240,12 @@ function mergeUserSettings(settings) {
229
240
  if (!utils.isNullOrUndefined(settings.nodeRedAuthMode)) {
230
241
  runtime.settings.nodeRedAuthMode = settings.nodeRedAuthMode;
231
242
  }
243
+ if (!utils.isNullOrUndefined(settings.enableRefreshCookieAuth)) {
244
+ runtime.settings.enableRefreshCookieAuth = settings.enableRefreshCookieAuth;
245
+ }
246
+ if (!utils.isNullOrUndefined(settings.refreshTokenExpiresIn)) {
247
+ runtime.settings.refreshTokenExpiresIn = settings.refreshTokenExpiresIn;
248
+ }
232
249
  if (!utils.isNullOrUndefined(settings.nodeRedUnsafeModules)) {
233
250
  runtime.settings.nodeRedUnsafeModules = settings.nodeRedUnsafeModules;
234
251
  }
@@ -238,6 +255,8 @@ function mergeUserSettings(settings) {
238
255
  }
239
256
  if (settings.secureEnabled) {
240
257
  runtime.settings.tokenExpiresIn = settings.tokenExpiresIn;
258
+ runtime.settings.enableRefreshCookieAuth = settings.enableRefreshCookieAuth;
259
+ runtime.settings.refreshTokenExpiresIn = settings.refreshTokenExpiresIn;
241
260
  }
242
261
  if (settings.smtp) {
243
262
  runtime.settings.smtp = settings.smtp;
package/api/jwt-helper.js CHANGED
@@ -1,9 +1,11 @@
1
1
  'use strict';
2
2
 
3
3
  const jwt = require('jsonwebtoken');
4
+ const utils = require('../runtime/utils');
4
5
 
5
6
  var secureEnabled = false;
6
- var secretCode = 'frangoteam751';
7
+ // Runtime fallback secret used only when no persistent secret is configured.
8
+ var secretCode = utils.generateSecretCode();
7
9
  var tokenExpiresIn = 60 * 60; // 60 minutes
8
10
  const adminGroups = [-1, 255];
9
11
 
@@ -275,10 +275,13 @@ module.exports = {
275
275
  var group = { name: resourcesDirs[i], items: [] };
276
276
  var dirPath = path.resolve(runtime.settings.widgetsFileDir, resourcesDirs[i]);
277
277
  var wwwSubDir = path.join('_widgets', resourcesDirs[i]);
278
- var files = getFiles(dirPath, ['.svg']);
278
+ var files = getFilesRecursive(dirPath, ['.svg']);
279
279
  for (var x = 0; x < files.length; x++) {
280
280
  var filename = files[x];
281
- group.items.push({ path: path.join(wwwSubDir, files[x]).split(path.sep).join(path.posix.sep), name: filename });
281
+ group.items.push({
282
+ path: path.join(wwwSubDir, files[x]).split(path.sep).join(path.posix.sep),
283
+ name: filename
284
+ });
282
285
  }
283
286
  result.groups.push(group);
284
287
  }
@@ -358,3 +361,17 @@ function getFiles(pathDir, extensions) {
358
361
  .filter((item) => extensions.indexOf(path.extname(item).toLowerCase()) !== -1);
359
362
  return filesInDIrectory;
360
363
  }
364
+
365
+ function getFilesRecursive(pathDir, extensions, baseDir = pathDir) {
366
+ const entries = fs.readdirSync(pathDir, { withFileTypes: true });
367
+ const files = [];
368
+ for (const entry of entries) {
369
+ const entryPath = path.join(pathDir, entry.name);
370
+ if (entry.isDirectory()) {
371
+ files.push(...getFilesRecursive(entryPath, extensions, baseDir));
372
+ } else if (extensions.indexOf(path.extname(entry.name).toLowerCase()) !== -1) {
373
+ files.push(path.relative(baseDir, entryPath));
374
+ }
375
+ }
376
+ return files;
377
+ }
@@ -32,15 +32,19 @@ module.exports = {
32
32
  */
33
33
  scriptsApp.post("/api/runscript", secureFnc, function (req, res, next) {
34
34
  const permission = checkGroupsFnc(req);
35
+ const script = req.body?.params?.script;
35
36
  if (res.statusCode === 403) {
36
37
  runtime.logger.error("api post runscript: Tocken Expired");
37
38
  //runtime.settings.secureEnabled
38
- } else if (!runtime.scriptsMgr.isAuthorised(req.body.params.script, permission)) {
39
+ } else if (script?.test && (!req.isAuthenticated || !authJwt.haveAdminPermission(permission))) {
40
+ res.status(401).json({ error: "unauthorized_error", message: "Unauthorized!" });
41
+ runtime.logger.error("api post runscript: Unauthorized test mode");
42
+ } else if (!runtime.scriptsMgr.isAuthorised(script, permission)) {
39
43
  res.status(400).json({ error: "unauthorized_error", message: "Unauthorized!" });
40
44
  runtime.logger.error("api post runscript: Unauthorized");
41
45
  } else {
42
46
  //req.body.params.script.parameters.permission = groups;
43
- runtime.scriptsMgr.runScript(req.body.params.script, req.body.params.toLogEvent).then(function (result) {
47
+ runtime.scriptsMgr.runScript(script, req.body.params.toLogEvent).then(function (result) {
44
48
  res.json(result);
45
49
  }).catch(function (err) {
46
50
  if (err.code) {
@@ -82,4 +86,4 @@ module.exports = {
82
86
  });
83
87
  return scriptsApp;
84
88
  }
85
- }
89
+ }
@@ -1,11 +1,33 @@
1
1
  @angular/animations
2
2
  MIT
3
+ The MIT License
4
+
5
+ Copyright (c) 2010-2024 Google LLC. https://angular.dev/license
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ THE SOFTWARE.
24
+
3
25
 
4
26
  @angular/cdk
5
27
  MIT
6
28
  The MIT License
7
29
 
8
- Copyright (c) 2023 Google LLC.
30
+ Copyright (c) 2024 Google LLC.
9
31
 
10
32
  Permission is hereby granted, free of charge, to any person obtaining a copy
11
33
  of this software and associated documentation files (the "Software"), to deal
@@ -28,18 +50,84 @@ THE SOFTWARE.
28
50
 
29
51
  @angular/common
30
52
  MIT
53
+ The MIT License
54
+
55
+ Copyright (c) 2010-2024 Google LLC. https://angular.dev/license
56
+
57
+ Permission is hereby granted, free of charge, to any person obtaining a copy
58
+ of this software and associated documentation files (the "Software"), to deal
59
+ in the Software without restriction, including without limitation the rights
60
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
61
+ copies of the Software, and to permit persons to whom the Software is
62
+ furnished to do so, subject to the following conditions:
63
+
64
+ The above copyright notice and this permission notice shall be included in
65
+ all copies or substantial portions of the Software.
66
+
67
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
68
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
69
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
70
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
71
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
72
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
73
+ THE SOFTWARE.
74
+
31
75
 
32
76
  @angular/core
33
77
  MIT
78
+ The MIT License
79
+
80
+ Copyright (c) 2010-2024 Google LLC. https://angular.dev/license
81
+
82
+ Permission is hereby granted, free of charge, to any person obtaining a copy
83
+ of this software and associated documentation files (the "Software"), to deal
84
+ in the Software without restriction, including without limitation the rights
85
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
86
+ copies of the Software, and to permit persons to whom the Software is
87
+ furnished to do so, subject to the following conditions:
88
+
89
+ The above copyright notice and this permission notice shall be included in
90
+ all copies or substantial portions of the Software.
91
+
92
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
93
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
94
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
95
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
96
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
97
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
98
+ THE SOFTWARE.
99
+
34
100
 
35
101
  @angular/forms
36
102
  MIT
103
+ The MIT License
104
+
105
+ Copyright (c) 2010-2024 Google LLC. https://angular.dev/license
106
+
107
+ Permission is hereby granted, free of charge, to any person obtaining a copy
108
+ of this software and associated documentation files (the "Software"), to deal
109
+ in the Software without restriction, including without limitation the rights
110
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
111
+ copies of the Software, and to permit persons to whom the Software is
112
+ furnished to do so, subject to the following conditions:
113
+
114
+ The above copyright notice and this permission notice shall be included in
115
+ all copies or substantial portions of the Software.
116
+
117
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
118
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
119
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
120
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
121
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
122
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
123
+ THE SOFTWARE.
124
+
37
125
 
38
126
  @angular/material
39
127
  MIT
40
128
  The MIT License
41
129
 
42
- Copyright (c) 2023 Google LLC.
130
+ Copyright (c) 2024 Google LLC.
43
131
 
44
132
  Permission is hereby granted, free of charge, to any person obtaining a copy
45
133
  of this software and associated documentation files (the "Software"), to deal
@@ -64,7 +152,7 @@ THE SOFTWARE.
64
152
  MIT
65
153
  The MIT License
66
154
 
67
- Copyright (c) 2023 Google LLC.
155
+ Copyright (c) 2024 Google LLC.
68
156
 
69
157
  Permission is hereby granted, free of charge, to any person obtaining a copy
70
158
  of this software and associated documentation files (the "Software"), to deal
@@ -87,9 +175,53 @@ THE SOFTWARE.
87
175
 
88
176
  @angular/platform-browser
89
177
  MIT
178
+ The MIT License
179
+
180
+ Copyright (c) 2010-2024 Google LLC. https://angular.dev/license
181
+
182
+ Permission is hereby granted, free of charge, to any person obtaining a copy
183
+ of this software and associated documentation files (the "Software"), to deal
184
+ in the Software without restriction, including without limitation the rights
185
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
186
+ copies of the Software, and to permit persons to whom the Software is
187
+ furnished to do so, subject to the following conditions:
188
+
189
+ The above copyright notice and this permission notice shall be included in
190
+ all copies or substantial portions of the Software.
191
+
192
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
193
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
194
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
195
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
196
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
197
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
198
+ THE SOFTWARE.
199
+
90
200
 
91
201
  @angular/router
92
202
  MIT
203
+ The MIT License
204
+
205
+ Copyright (c) 2010-2024 Google LLC. https://angular.dev/license
206
+
207
+ Permission is hereby granted, free of charge, to any person obtaining a copy
208
+ of this software and associated documentation files (the "Software"), to deal
209
+ in the Software without restriction, including without limitation the rights
210
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
211
+ copies of the Software, and to permit persons to whom the Software is
212
+ furnished to do so, subject to the following conditions:
213
+
214
+ The above copyright notice and this permission notice shall be included in
215
+ all copies or substantial portions of the Software.
216
+
217
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
218
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
219
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
220
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
221
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
222
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
223
+ THE SOFTWARE.
224
+
93
225
 
94
226
  @babel/runtime
95
227
  MIT
@@ -179,7 +311,7 @@ angular-gridster2
179
311
  MIT
180
312
  MIT License
181
313
 
182
- Copyright (c) 2023 Tiberiu Zuld
314
+ Copyright (c) 2024 Tiberiu Zuld
183
315
 
184
316
  Permission is hereby granted, free of charge, to any person obtaining a copy
185
317
  of this software and associated documentation files (the "Software"), to deal
@@ -990,7 +1122,7 @@ MIT
990
1122
  The MIT License (MIT)
991
1123
 
992
1124
  Copyright (c) 2014-2015 bpampuch
993
- 2016-2025 liborm85
1125
+ 2016-2026 liborm85
994
1126
 
995
1127
  Permission is hereby granted, free of charge, to any person obtaining a copy of
996
1128
  this software and associated documentation files (the "Software"), to deal in
@@ -1222,7 +1354,7 @@ socket.io-parser
1222
1354
  MIT
1223
1355
  (The MIT License)
1224
1356
 
1225
- Copyright (c) 2014 Guillermo Rauch <guillermo@learnboost.com>
1357
+ Copyright (c) 2014-present Guillermo Rauch and Socket.IO contributors
1226
1358
 
1227
1359
  Permission is hereby granted, free of charge, to any person obtaining a copy of
1228
1360
  this software and associated documentation files (the 'Software'), to deal in
@@ -1316,7 +1448,7 @@ zone.js
1316
1448
  MIT
1317
1449
  The MIT License
1318
1450
 
1319
- Copyright (c) 2010-2023 Google LLC. https://angular.io/license
1451
+ Copyright (c) 2010-2024 Google LLC. https://angular.io/license
1320
1452
 
1321
1453
  Permission is hereby granted, free of charge, to any person obtaining a copy
1322
1454
  of this software and associated documentation files (the "Software"), to deal
@@ -834,6 +834,8 @@
834
834
  "device.tag-daq-changed": "Wert speichern, wenn geändert",
835
835
  "device.tag-daq-interval": "Intervall für Speichern (Sek.)",
836
836
  "device.tag-format": "Ziffern formatieren (2 = #.##)",
837
+
838
+ "device.tag-uns-path": "UNS Path",
837
839
  "device.tag-scale": "Skalierungsmodus",
838
840
  "device.tag-scale-mode-undefined": "Keine Skalierung",
839
841
  "device.tag-scale-mode-undefined-tooltip": "Tag-Wert",
@@ -1240,6 +1242,11 @@
1240
1242
  "dlg.app-settings-daqstore": "DAQ-Speicher",
1241
1243
  "dlg.app-settings-daqstore-type": "Datenbanktyp",
1242
1244
  "dlg.app-settings-daqstore-url": "URL",
1245
+ "dlg.app-settings-daqstore-configurl": "Config URL",
1246
+ "dlg.app-settings-daqstore-queryconn": "Query connection (PGWire)",
1247
+
1248
+ "dlg.app-settings-daqstore-questdb-host": "QuestDB Host",
1249
+ "dlg.app-settings-daqstore-ingestconn": "Ingestion connection (ILP)",
1243
1250
  "dlg.app-settings-daqstore-token": "Token",
1244
1251
  "dlg.app-settings-daqstore-bucket": "Bucket",
1245
1252
  "dlg.app-settings-daqstore-organization": "Organisation",
@@ -1306,3 +1313,6 @@
1306
1313
  "msg.report-build-error": "Senden zum Erstellen des Berichts fehlgeschlagen!",
1307
1314
  "msg.device-tags-request-result": "Lade {{value}} von {{current}}"
1308
1315
  }
1316
+
1317
+
1318
+
@@ -307,6 +307,9 @@
307
307
  "chart.property-refresh-interval": "Refresh interval (min.)",
308
308
  "chart.property-hide-toolbar": "Hide toolbar",
309
309
  "chart.property-thouch-zoom": "Thouch Zoom",
310
+ "chart.property-mouse-wheel-scroll": "Mouse wheel scroll",
311
+ "chart.property-mouse-wheel-zoom": "Mouse wheel zoom",
312
+ "chart.property-static-chart": "Static chart",
310
313
  "chart.property-load-old-values": "Load history",
311
314
  "chart.property-date.format": "Date format",
312
315
  "chart.property-time.format": "Time format",
@@ -575,6 +578,12 @@
575
578
  "editor.controls-slider": "Slider",
576
579
  "editor.controls-slider-settings": "Slider settings",
577
580
  "editor.controls-shape-settings": "Shape settings",
581
+ "editor.onboarding-wizard-title": "Initial Security Setup",
582
+ "editor.onboarding-wizard-message": "Configure the editor's initial security now to avoid unprotected access and the use of default credentials.",
583
+ "editor.onboarding-wizard-hide": "Do not show this wizard again",
584
+ "editor.onboarding-wizard-admin-password": "Administrator password",
585
+ "editor.onboarding-wizard-admin-password-message": "Set a new password for the default administrator account 'admin'.",
586
+ "editor.onboarding-wizard-admin-password-required": "Administrator password required",
578
587
  "editor.controls-html-switch-settings": "Switch settings",
579
588
  "editor.controls-switch": "Switch",
580
589
  "editor.controls-graphbar": "Bar Graph",
@@ -992,6 +1001,7 @@
992
1001
  "device.property-name": "Name",
993
1002
  "device.property-type": "Type",
994
1003
  "device.property-polling": "Polling",
1004
+ "device.property-polling-warning": "Warning: Low polling intervals may cause high CPU and network load. Use with care.",
995
1005
  "device.property-enable": "Enable",
996
1006
  "device.property-subscribe": "Subscribe",
997
1007
  "device.property-address": "Address (IP or opc.tcp://[server]:[port])",
@@ -1153,6 +1163,8 @@
1153
1163
 
1154
1164
  "device.tag-format": "Format digits (2 = #.##)",
1155
1165
  "device.tag-deadband": "Deadband",
1166
+
1167
+ "device.tag-uns-path": "UNS Path",
1156
1168
  "device.tag-scale": "Scale Mode / Convertion",
1157
1169
  "device.tag-scale-mode-undefined": "No Scaling",
1158
1170
  "device.tag-scale-mode-undefined-tooltip": "Tag Value",
@@ -1615,6 +1627,7 @@
1615
1627
  "report.item-interval": "Interval (period)",
1616
1628
  "report.item-interval-min5": "5 minutes",
1617
1629
  "report.item-interval-min10": "10 minutes",
1630
+ "report.item-interval-min15": "15 minutes",
1618
1631
  "report.item-interval-min30": "30 minutes",
1619
1632
  "report.item-interval-hour": "1 Hour",
1620
1633
  "report.item-interval-day": "1 Day",
@@ -1811,6 +1824,11 @@
1811
1824
  "dlg.app-settings-daqstore": "DAQ storage",
1812
1825
  "dlg.app-settings-daqstore-type": "Database type",
1813
1826
  "dlg.app-settings-daqstore-url": "URL",
1827
+ "dlg.app-settings-daqstore-configurl": "Config URL",
1828
+ "dlg.app-settings-daqstore-queryconn": "Query connection (PGWire)",
1829
+
1830
+ "dlg.app-settings-daqstore-questdb-host": "QuestDB Host",
1831
+ "dlg.app-settings-daqstore-ingestconn": "Ingestion connection (ILP)",
1814
1832
  "dlg.app-settings-daqstore-token": "Token",
1815
1833
  "dlg.app-settings-daqstore-bucket": "Bucket",
1816
1834
  "dlg.app-settings-daqstore-organization": "Organization",
@@ -1868,7 +1886,7 @@
1868
1886
  "msg.alarmproperty-missing-value": "Some values are missing!",
1869
1887
  "msg.textproperty-error-exist": "Text-ID exists!",
1870
1888
  "msg.textproperty-missing-value": "Some values are missing!",
1871
- "msg.device-remove": "Would you like to remove Device?",
1889
+ "msg.device-remove": "Would you like to remove Device '{{value}}'?",
1872
1890
  "msg.device-tag-remove": "Would you like to remove Tag?",
1873
1891
  "msg.device-tag-exist": "Tag name exists!",
1874
1892
  "msg.device-tag-invalid-char": "The '@' character is not allowed in tag names!",
@@ -1884,7 +1902,7 @@
1884
1902
  "msg.project-load-error": "Unable to read '{{value}}'",
1885
1903
  "msg.project": "Would you like to save the Project changes?",
1886
1904
  "msg.tags-remove-all": "Would you like to remove all Tags?",
1887
- "msg.view-remove": "Would you like to remove View '{{value}}'?",
1905
+ "msg.view-remove": "Would you like to remove View '{{value}}' ?",
1888
1906
  "msg.chart-remove": "Would you like to remove Chart '{{value}}'?",
1889
1907
  "msg.role-remove": "Would you like to remove Role '{{value}}'?",
1890
1908
  "msg.graph-remove": "Would you like to remove Bar chart '{{value}}'?",
@@ -1895,7 +1913,7 @@
1895
1913
  "msg.sendmail-success": "Mail send successful!",
1896
1914
  "msg.sendmail-error": "Mail send failed!",
1897
1915
  "msg.users-save-error": "User save failed!",
1898
- "msg.user-remove": "Would you like to remove User ",
1916
+ "msg.user-remove": "Would you like to remove User '{{value}}'?",
1899
1917
  "msg.project-save-success": "Project save successful!",
1900
1918
  "msg.project-save-error": "Project save failed!",
1901
1919
  "msg.project-format-error": "Project wrong format!",