@frangoteam/fuxa-min 1.2.11 → 1.3.0

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 (50) hide show
  1. package/api/auth/index.js +141 -3
  2. package/api/index.js +18 -2
  3. package/api/jwt-helper.js +3 -1
  4. package/api/resources/index.js +19 -2
  5. package/dist/3rdpartylicenses.txt +139 -7
  6. package/dist/assets/i18n/de.json +10 -0
  7. package/dist/assets/i18n/en.json +14 -3
  8. package/dist/assets/i18n/es.json +12 -0
  9. package/dist/assets/i18n/fr.json +10 -0
  10. package/dist/assets/i18n/ja.json +15 -6
  11. package/dist/assets/i18n/ko.json +12 -0
  12. package/dist/assets/i18n/pt.json +9 -2
  13. package/dist/assets/i18n/ru.json +11 -0
  14. package/dist/assets/i18n/sv.json +10 -1
  15. package/dist/assets/i18n/tr.json +8 -1
  16. package/dist/assets/i18n/ua.json +9 -2
  17. package/dist/assets/i18n/zh-cn.json +10 -0
  18. package/dist/assets/i18n/zh-tw.json +11 -1
  19. package/dist/index.html +2 -2
  20. package/dist/main.bafae830903d548e.js +329 -0
  21. package/dist/polyfills.d7de05f9af2fb559.js +1 -0
  22. package/dist/{runtime.8ef63094e52a66ba.js → runtime.9136a61a9b98f987.js} +1 -1
  23. package/dist/{scripts.40b60f02658462e4.js → scripts.d9e6ee984bf6f3b7.js} +1 -1
  24. package/dist/styles.545e37beb3e671ba.css +1 -0
  25. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-daq.html +56 -5
  26. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-daq.js +8 -2
  27. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-change.html +56 -5
  28. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-change.js +12 -12
  29. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-daq-settings.html +56 -5
  30. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-daq-settings.js +14 -10
  31. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag.html +56 -5
  32. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag.js +8 -2
  33. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag-daq-settings.html +56 -5
  34. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag-daq-settings.js +24 -20
  35. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag.html +56 -5
  36. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag.js +8 -2
  37. package/main.js +35 -17
  38. package/package.json +10 -5
  39. package/runtime/devices/adsclient/index.js +1 -1
  40. package/runtime/devices/ethernetip/index.js +1 -1
  41. package/runtime/devices/gpio/index.js +1 -1
  42. package/runtime/devices/odbc/index.js +5 -5
  43. package/runtime/devices/template/index.js +14 -14
  44. package/runtime/storage/daqstorage.js +28 -2
  45. package/runtime/storage/questdb/index.js +224 -0
  46. package/runtime/utils.js +5 -0
  47. package/settings.default.js +5 -2
  48. package/dist/main.92522279642ef880.js +0 -329
  49. package/dist/polyfills.c8e7db9850a3ad8b.js +0 -1
  50. 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
+ }
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();
@@ -229,6 +237,12 @@ function mergeUserSettings(settings) {
229
237
  if (!utils.isNullOrUndefined(settings.nodeRedAuthMode)) {
230
238
  runtime.settings.nodeRedAuthMode = settings.nodeRedAuthMode;
231
239
  }
240
+ if (!utils.isNullOrUndefined(settings.enableRefreshCookieAuth)) {
241
+ runtime.settings.enableRefreshCookieAuth = settings.enableRefreshCookieAuth;
242
+ }
243
+ if (!utils.isNullOrUndefined(settings.refreshTokenExpiresIn)) {
244
+ runtime.settings.refreshTokenExpiresIn = settings.refreshTokenExpiresIn;
245
+ }
232
246
  if (!utils.isNullOrUndefined(settings.nodeRedUnsafeModules)) {
233
247
  runtime.settings.nodeRedUnsafeModules = settings.nodeRedUnsafeModules;
234
248
  }
@@ -238,6 +252,8 @@ function mergeUserSettings(settings) {
238
252
  }
239
253
  if (settings.secureEnabled) {
240
254
  runtime.settings.tokenExpiresIn = settings.tokenExpiresIn;
255
+ runtime.settings.enableRefreshCookieAuth = settings.enableRefreshCookieAuth;
256
+ runtime.settings.refreshTokenExpiresIn = settings.refreshTokenExpiresIn;
241
257
  }
242
258
  if (settings.smtp) {
243
259
  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
+ }
@@ -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
+
@@ -992,6 +992,7 @@
992
992
  "device.property-name": "Name",
993
993
  "device.property-type": "Type",
994
994
  "device.property-polling": "Polling",
995
+ "device.property-polling-warning": "Warning: Low polling intervals may cause high CPU and network load. Use with care.",
995
996
  "device.property-enable": "Enable",
996
997
  "device.property-subscribe": "Subscribe",
997
998
  "device.property-address": "Address (IP or opc.tcp://[server]:[port])",
@@ -1153,6 +1154,8 @@
1153
1154
 
1154
1155
  "device.tag-format": "Format digits (2 = #.##)",
1155
1156
  "device.tag-deadband": "Deadband",
1157
+
1158
+ "device.tag-uns-path": "UNS Path",
1156
1159
  "device.tag-scale": "Scale Mode / Convertion",
1157
1160
  "device.tag-scale-mode-undefined": "No Scaling",
1158
1161
  "device.tag-scale-mode-undefined-tooltip": "Tag Value",
@@ -1811,6 +1814,11 @@
1811
1814
  "dlg.app-settings-daqstore": "DAQ storage",
1812
1815
  "dlg.app-settings-daqstore-type": "Database type",
1813
1816
  "dlg.app-settings-daqstore-url": "URL",
1817
+ "dlg.app-settings-daqstore-configurl": "Config URL",
1818
+ "dlg.app-settings-daqstore-queryconn": "Query connection (PGWire)",
1819
+
1820
+ "dlg.app-settings-daqstore-questdb-host": "QuestDB Host",
1821
+ "dlg.app-settings-daqstore-ingestconn": "Ingestion connection (ILP)",
1814
1822
  "dlg.app-settings-daqstore-token": "Token",
1815
1823
  "dlg.app-settings-daqstore-bucket": "Bucket",
1816
1824
  "dlg.app-settings-daqstore-organization": "Organization",
@@ -1868,7 +1876,7 @@
1868
1876
  "msg.alarmproperty-missing-value": "Some values are missing!",
1869
1877
  "msg.textproperty-error-exist": "Text-ID exists!",
1870
1878
  "msg.textproperty-missing-value": "Some values are missing!",
1871
- "msg.device-remove": "Would you like to remove Device?",
1879
+ "msg.device-remove": "Would you like to remove Device '{{value}}'?",
1872
1880
  "msg.device-tag-remove": "Would you like to remove Tag?",
1873
1881
  "msg.device-tag-exist": "Tag name exists!",
1874
1882
  "msg.device-tag-invalid-char": "The '@' character is not allowed in tag names!",
@@ -1884,7 +1892,7 @@
1884
1892
  "msg.project-load-error": "Unable to read '{{value}}'",
1885
1893
  "msg.project": "Would you like to save the Project changes?",
1886
1894
  "msg.tags-remove-all": "Would you like to remove all Tags?",
1887
- "msg.view-remove": "Would you like to remove View '{{value}}'?",
1895
+ "msg.view-remove": "Would you like to remove View '{{value}}' ?",
1888
1896
  "msg.chart-remove": "Would you like to remove Chart '{{value}}'?",
1889
1897
  "msg.role-remove": "Would you like to remove Role '{{value}}'?",
1890
1898
  "msg.graph-remove": "Would you like to remove Bar chart '{{value}}'?",
@@ -1895,7 +1903,7 @@
1895
1903
  "msg.sendmail-success": "Mail send successful!",
1896
1904
  "msg.sendmail-error": "Mail send failed!",
1897
1905
  "msg.users-save-error": "User save failed!",
1898
- "msg.user-remove": "Would you like to remove User ",
1906
+ "msg.user-remove": "Would you like to remove User '{{value}}'?",
1899
1907
  "msg.project-save-success": "Project save successful!",
1900
1908
  "msg.project-save-error": "Project save failed!",
1901
1909
  "msg.project-format-error": "Project wrong format!",
@@ -1930,3 +1938,6 @@
1930
1938
  "msg.operation-unauthorized": "Operation Unauthorized!",
1931
1939
  "msg.secret-code-required": "Secret code required to sign authentication tokens"
1932
1940
  }
1941
+
1942
+
1943
+
@@ -544,6 +544,9 @@
544
544
  "device-tag-dialog-title": "Etiqueta seleccionada",
545
545
 
546
546
  "device.tag-options-title": "Opciones de etiquetas",
547
+
548
+
549
+ "device.tag-uns-path": "UNS Path",
547
550
  "device.tag-daq-enabled": "Registration Enabled",
548
551
  "device.tag-daq-changed": "Guardar valor si cambia",
549
552
  "device.tag-daq-interval": "Intervalo para guardar valor (segundos)",
@@ -736,6 +739,12 @@
736
739
  "dlg.app-settings-server-port": "Servidor esta escuchando el puerto",
737
740
  "dlg.app-settings-alarms-clear": "Borrar todas las alarmas y el historias",
738
741
  "dlg.app-settings-auth-token": "Autenticación con token",
742
+ "dlg.app-settings-daqstore-url": "URL",
743
+ "dlg.app-settings-daqstore-configurl": "Config URL",
744
+ "dlg.app-settings-daqstore-queryconn": "Query connection (PGWire)",
745
+
746
+ "dlg.app-settings-daqstore-questdb-host": "QuestDB Host",
747
+ "dlg.app-settings-daqstore-ingestconn": "Ingestion connection (ILP)",
739
748
  "dlg.app-auth-disabled": "Deshabilitado",
740
749
  "dlg.app-auth-expiration-15m": "Habilitado con token expira en 15 min.",
741
750
  "dlg.app-auth-expiration-1h": "Habilitado con token expira en 1 hora.",
@@ -774,3 +783,6 @@
774
783
  "msg.editor-mode-locked": "El editor ya esta abierto!",
775
784
  "msg.alarms-clear-success": "Todas las alarmas han sido canceladas!"
776
785
  }
786
+
787
+
788
+
@@ -1009,6 +1009,8 @@
1009
1009
 
1010
1010
  "device.tag-format": "Format du nombre (2 = #.##)",
1011
1011
  "device.tag-deadband": "Zone morte",
1012
+
1013
+ "device.tag-uns-path": "UNS Path",
1012
1014
  "device.tag-scale": "Mode mise à l'échelle / Conversion",
1013
1015
  "device.tag-scale-mode-undefined": "Pas de mise à l'échelle",
1014
1016
  "device.tag-scale-mode-undefined-tooltip": "Valeur du tag",
@@ -1618,6 +1620,11 @@
1618
1620
  "dlg.app-settings-daqstore": "Stockage DAQ",
1619
1621
  "dlg.app-settings-daqstore-type": "Type de base de données",
1620
1622
  "dlg.app-settings-daqstore-url": "URL",
1623
+ "dlg.app-settings-daqstore-configurl": "Config URL",
1624
+ "dlg.app-settings-daqstore-queryconn": "Query connection (PGWire)",
1625
+
1626
+ "dlg.app-settings-daqstore-questdb-host": "QuestDB Host",
1627
+ "dlg.app-settings-daqstore-ingestconn": "Ingestion connection (ILP)",
1621
1628
  "dlg.app-settings-daqstore-token": "Jeton",
1622
1629
  "dlg.app-settings-daqstore-bucket": "Seau",
1623
1630
  "dlg.app-settings-daqstore-organization": "Organisation",
@@ -1715,3 +1722,6 @@
1715
1722
  "msg.texts-text-remove": "Souhaitez-vous supprimer le texte '{{value}}' ?",
1716
1723
  "msg.operation-unauthorized": "Opération non autorisée !"
1717
1724
  }
1725
+
1726
+
1727
+