matterbridge 3.4.1-dev-20251127-826b2bf → 3.4.1-dev-20251128-441f8db
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/CHANGELOG.md +2 -0
- package/README-DEV.md +20 -4
- package/README.md +2 -0
- package/dist/broadcastServer.js +15 -4
- package/dist/frontend.js +5 -1
- package/dist/jestutils/jestHelpers.js +49 -0
- package/dist/matterbridge.js +18 -0
- package/dist/pluginManager.js +24 -0
- package/dist/shelly.js +12 -12
- package/dist/update.js +69 -53
- package/frontend/build/assets/index.css +1 -1
- package/frontend/build/assets/index.js +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -39,10 +39,12 @@ Advantages:
|
|
|
39
39
|
- [frontend]: Updated dependencies.
|
|
40
40
|
- [frontend]: Bumped `frontend` version to 3.3.2.
|
|
41
41
|
- [platform]: Bumped MatterbridgePlatform v.1.5.0.
|
|
42
|
+
- [thread]: Bump BroadcastServer to v1.0.4.
|
|
42
43
|
|
|
43
44
|
### Fixed
|
|
44
45
|
|
|
45
46
|
- [frontend]: Fixed when the user put special characters in password. Thanks Dabern (https://github.com/Luligu/matterbridge/issues/443).
|
|
47
|
+
- [frontend]: Fixed minimum size to 1300x1024 and add a max width to Url. Thanks Ricardo B. (https://github.com/Luligu/matterbridge-home-assistant-addon/issues/23).
|
|
46
48
|
|
|
47
49
|
<a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/bmc-button.svg" alt="Buy me a coffee" width="80"></a>
|
|
48
50
|
|
package/README-DEV.md
CHANGED
|
@@ -251,9 +251,25 @@ It is called when the plugin config has been updated.
|
|
|
251
251
|
|
|
252
252
|
Retrieves the devices registered with the platform.
|
|
253
253
|
|
|
254
|
+
### getDeviceByName(deviceName: string): MatterbridgeEndpoint | undefined
|
|
255
|
+
|
|
256
|
+
### getDeviceByUniqueId(uniqueId: string): MatterbridgeEndpoint | undefined
|
|
257
|
+
|
|
258
|
+
### getDeviceBySerialNumber(serialNumber: string): MatterbridgeEndpoint | undefined
|
|
259
|
+
|
|
260
|
+
### getDeviceById(id: string): MatterbridgeEndpoint | undefined
|
|
261
|
+
|
|
262
|
+
### getDeviceByOriginalId(originalId: string): MatterbridgeEndpoint | undefined
|
|
263
|
+
|
|
264
|
+
### getDeviceByNumber(number: EndpointNumber | number): MatterbridgeEndpoint | undefined
|
|
265
|
+
|
|
266
|
+
They all return MatterbridgeEndpoint or undefined if not found.
|
|
267
|
+
|
|
254
268
|
### hasDeviceName(deviceName: string): boolean
|
|
255
269
|
|
|
256
|
-
|
|
270
|
+
### hasDeviceUniqueId(deviceUniqueId: string): boolean
|
|
271
|
+
|
|
272
|
+
Checks if a device with this name or uniqueId is already registered in the platform.
|
|
257
273
|
|
|
258
274
|
### async registerDevice(device: MatterbridgeEndpoint)
|
|
259
275
|
|
|
@@ -288,7 +304,7 @@ You create a Matter device with a new instance of MatterbridgeEndpoint(definitio
|
|
|
288
304
|
|
|
289
305
|
In the above example we create a contact sensor device type with also a power source device type feature replaceble battery.
|
|
290
306
|
|
|
291
|
-
All device types are defined in src\matterbridgeDeviceTypes.ts and taken from the 'Matter-1.4.
|
|
307
|
+
All device types are defined in src\matterbridgeDeviceTypes.ts and taken from the 'Matter-1.4.2-Device-Library-Specification.pdf'.
|
|
292
308
|
|
|
293
309
|
All default cluster helpers are available as methods of MatterbridgeEndpoint.
|
|
294
310
|
|
|
@@ -388,7 +404,7 @@ const heatPump = new HeatPump('Heat Pump', 'HP1234567890');
|
|
|
388
404
|
|
|
389
405
|
## Plugin config file
|
|
390
406
|
|
|
391
|
-
Each plugin has a minimal default config file injected by Matterbridge when it is loaded:
|
|
407
|
+
Each plugin has a minimal default config file injected by Matterbridge when it is loaded and the plugin doesn't have its own default one:
|
|
392
408
|
|
|
393
409
|
```typescript
|
|
394
410
|
{
|
|
@@ -408,7 +424,7 @@ In all subsequent loads the config file is loaded from the '.matterbridge' direc
|
|
|
408
424
|
|
|
409
425
|
## Plugin schema file
|
|
410
426
|
|
|
411
|
-
Each plugin has a minimal default schema file injected by Matterbridge when it is loaded:
|
|
427
|
+
Each plugin has a minimal default schema file injected by Matterbridge when it is loaded and the plugin doesn't have its own default one:
|
|
412
428
|
|
|
413
429
|
```typescript
|
|
414
430
|
{
|
package/README.md
CHANGED
|
@@ -56,6 +56,8 @@ Join us in the Matterbridge [Discord group](https://discord.gg/QX58CDe6hd) creat
|
|
|
56
56
|
|
|
57
57
|
https://www.youtube.com/watch?v=goNB9Cgh_Fk
|
|
58
58
|
|
|
59
|
+
https://www.youtube.com/watch?v=06zzl7o_IqQ
|
|
60
|
+
|
|
59
61
|
## Reviews
|
|
60
62
|
|
|
61
63
|
https://www.matteralpha.com/how-to/how-to-configure-an-open-source-matter-bridge-at-home
|
package/dist/broadcastServer.js
CHANGED
|
@@ -2,8 +2,9 @@ if (process.argv.includes('--loader') || process.argv.includes('-loader'))
|
|
|
2
2
|
console.log('\u001B[32mBroadcastServer loaded.\u001B[40;0m');
|
|
3
3
|
import { EventEmitter } from 'node:events';
|
|
4
4
|
import { BroadcastChannel } from 'node:worker_threads';
|
|
5
|
-
import { CYAN, db, debugStringify } from 'node-ansi-logger';
|
|
5
|
+
import { CYAN, db, debugStringify, er } from 'node-ansi-logger';
|
|
6
6
|
import { hasParameter } from './utils/commandLine.js';
|
|
7
|
+
import { logError } from './utils/error.js';
|
|
7
8
|
export class BroadcastServer extends EventEmitter {
|
|
8
9
|
name;
|
|
9
10
|
log;
|
|
@@ -56,7 +57,12 @@ export class BroadcastServer extends EventEmitter {
|
|
|
56
57
|
}
|
|
57
58
|
if (this.verbose)
|
|
58
59
|
this.log.debug(`Broadcasting request message: ${debugStringify(message)}`);
|
|
59
|
-
|
|
60
|
+
try {
|
|
61
|
+
this.broadcastChannel.postMessage(message);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
logError(this.log, `Failed to broadcast request message ${debugStringify(message)}${er}`, error);
|
|
65
|
+
}
|
|
60
66
|
}
|
|
61
67
|
respond(message) {
|
|
62
68
|
if (message.timestamp === undefined) {
|
|
@@ -68,7 +74,12 @@ export class BroadcastServer extends EventEmitter {
|
|
|
68
74
|
}
|
|
69
75
|
if (this.verbose)
|
|
70
76
|
this.log.debug(`Broadcasting response message: ${debugStringify(message)}`);
|
|
71
|
-
|
|
77
|
+
try {
|
|
78
|
+
this.broadcastChannel.postMessage(message);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
logError(this.log, `Failed to broadcast response message ${debugStringify(message)}${er}`, error);
|
|
82
|
+
}
|
|
72
83
|
}
|
|
73
84
|
async fetch(message, timeout = 250) {
|
|
74
85
|
if (message.id === undefined) {
|
|
@@ -97,7 +108,7 @@ export class BroadcastServer extends EventEmitter {
|
|
|
97
108
|
this.request(message);
|
|
98
109
|
const timeoutId = setTimeout(() => {
|
|
99
110
|
this.off('broadcast_message', responseHandler);
|
|
100
|
-
reject(new Error(`Fetch timeout after ${timeout}ms for message id ${message.id}`));
|
|
111
|
+
reject(new Error(`Fetch timeout after ${timeout}ms for message type ${message.type} id ${message.id} from ${message.src} to ${message.dst}`));
|
|
101
112
|
}, timeout);
|
|
102
113
|
});
|
|
103
114
|
}
|
package/dist/frontend.js
CHANGED
|
@@ -66,7 +66,7 @@ export class Frontend extends EventEmitter {
|
|
|
66
66
|
this.server.respond({ ...msg, response: { success: true } });
|
|
67
67
|
break;
|
|
68
68
|
case 'frontend_refreshrequired':
|
|
69
|
-
this.wssSendRefreshRequired(msg.params.changed, { matter: msg.params.matter });
|
|
69
|
+
this.wssSendRefreshRequired(msg.params.changed, msg.params.matter ? { matter: msg.params.matter } : undefined);
|
|
70
70
|
this.server.respond({ ...msg, response: { success: true } });
|
|
71
71
|
break;
|
|
72
72
|
case 'frontend_restartrequired':
|
|
@@ -93,6 +93,10 @@ export class Frontend extends EventEmitter {
|
|
|
93
93
|
this.wssSendLogMessage(msg.params.level, msg.params.time, msg.params.name, msg.params.message);
|
|
94
94
|
this.server.respond({ ...msg, response: { success: true } });
|
|
95
95
|
break;
|
|
96
|
+
case 'frontend_broadcast_message':
|
|
97
|
+
this.wssBroadcastMessage(msg.params.msg);
|
|
98
|
+
this.server.respond({ ...msg, response: { success: true } });
|
|
99
|
+
break;
|
|
96
100
|
default:
|
|
97
101
|
if (this.verbose)
|
|
98
102
|
this.log.debug(`Unknown broadcast request ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}`);
|
|
@@ -11,6 +11,9 @@ import { NodeStorageManager } from 'node-persist-manager';
|
|
|
11
11
|
import { Matterbridge } from '../matterbridge.js';
|
|
12
12
|
import { MATTER_STORAGE_NAME, NODE_STORAGE_DIR } from '../matterbridgeTypes.js';
|
|
13
13
|
import { bridge } from '../matterbridgeDeviceTypes.js';
|
|
14
|
+
import { PluginManager } from '../pluginManager.js';
|
|
15
|
+
import { Frontend } from '../frontend.js';
|
|
16
|
+
import { BroadcastServer } from '../broadcastServer.js';
|
|
14
17
|
export const originalProcessArgv = Object.freeze([...process.argv]);
|
|
15
18
|
export const originalProcessEnv = Object.freeze({ ...process.env });
|
|
16
19
|
export let loggerLogSpy;
|
|
@@ -28,6 +31,29 @@ export let consoleErrorSpy;
|
|
|
28
31
|
export let addBridgedEndpointSpy;
|
|
29
32
|
export let removeBridgedEndpointSpy;
|
|
30
33
|
export let removeAllBridgedEndpointsSpy;
|
|
34
|
+
export let addVirtualEndpointSpy;
|
|
35
|
+
export let installPluginSpy;
|
|
36
|
+
export let uninstallPluginSpy;
|
|
37
|
+
export let addPluginSpy;
|
|
38
|
+
export let loadPluginSpy;
|
|
39
|
+
export let startPluginSpy;
|
|
40
|
+
export let configurePluginSpy;
|
|
41
|
+
export let shutdownPluginSpy;
|
|
42
|
+
export let removePluginSpy;
|
|
43
|
+
export let enablePluginSpy;
|
|
44
|
+
export let disablePluginSpy;
|
|
45
|
+
export let wssSendSnackbarMessageSpy;
|
|
46
|
+
export let wssSendCloseSnackbarMessageSpy;
|
|
47
|
+
export let wssSendUpdateRequiredSpy;
|
|
48
|
+
export let wssSendRefreshRequiredSpy;
|
|
49
|
+
export let wssSendRestartRequiredSpy;
|
|
50
|
+
export let wssSendRestartNotRequiredSpy;
|
|
51
|
+
export let broadcastServerIsWorkerRequestSpy;
|
|
52
|
+
export let broadcastServerIsWorkerResponseSpy;
|
|
53
|
+
export let broadcastServerRequestSpy;
|
|
54
|
+
export let broadcastServerRespondSpy;
|
|
55
|
+
export let broadcastServerFetchSpy;
|
|
56
|
+
export let broadcastMessageHandlerSpy;
|
|
31
57
|
export let NAME;
|
|
32
58
|
export let HOMEDIR;
|
|
33
59
|
export let matterbridge;
|
|
@@ -71,6 +97,29 @@ export async function setupTest(name, debug = false) {
|
|
|
71
97
|
addBridgedEndpointSpy = jest.spyOn(Matterbridge.prototype, 'addBridgedEndpoint');
|
|
72
98
|
removeBridgedEndpointSpy = jest.spyOn(Matterbridge.prototype, 'removeBridgedEndpoint');
|
|
73
99
|
removeAllBridgedEndpointsSpy = jest.spyOn(Matterbridge.prototype, 'removeAllBridgedEndpoints');
|
|
100
|
+
addVirtualEndpointSpy = jest.spyOn(Matterbridge.prototype, 'addVirtualEndpoint');
|
|
101
|
+
installPluginSpy = jest.spyOn(PluginManager.prototype, 'install');
|
|
102
|
+
uninstallPluginSpy = jest.spyOn(PluginManager.prototype, 'uninstall');
|
|
103
|
+
addPluginSpy = jest.spyOn(PluginManager.prototype, 'add');
|
|
104
|
+
loadPluginSpy = jest.spyOn(PluginManager.prototype, 'load');
|
|
105
|
+
startPluginSpy = jest.spyOn(PluginManager.prototype, 'start');
|
|
106
|
+
configurePluginSpy = jest.spyOn(PluginManager.prototype, 'configure');
|
|
107
|
+
shutdownPluginSpy = jest.spyOn(PluginManager.prototype, 'shutdown');
|
|
108
|
+
removePluginSpy = jest.spyOn(PluginManager.prototype, 'remove');
|
|
109
|
+
enablePluginSpy = jest.spyOn(PluginManager.prototype, 'enable');
|
|
110
|
+
disablePluginSpy = jest.spyOn(PluginManager.prototype, 'disable');
|
|
111
|
+
wssSendSnackbarMessageSpy = jest.spyOn(Frontend.prototype, 'wssSendSnackbarMessage');
|
|
112
|
+
wssSendCloseSnackbarMessageSpy = jest.spyOn(Frontend.prototype, 'wssSendCloseSnackbarMessage');
|
|
113
|
+
wssSendUpdateRequiredSpy = jest.spyOn(Frontend.prototype, 'wssSendUpdateRequired');
|
|
114
|
+
wssSendRefreshRequiredSpy = jest.spyOn(Frontend.prototype, 'wssSendRefreshRequired');
|
|
115
|
+
wssSendRestartRequiredSpy = jest.spyOn(Frontend.prototype, 'wssSendRestartRequired');
|
|
116
|
+
wssSendRestartNotRequiredSpy = jest.spyOn(Frontend.prototype, 'wssSendRestartNotRequired');
|
|
117
|
+
broadcastServerIsWorkerRequestSpy = jest.spyOn(BroadcastServer.prototype, 'isWorkerRequest');
|
|
118
|
+
broadcastServerIsWorkerResponseSpy = jest.spyOn(BroadcastServer.prototype, 'isWorkerResponse');
|
|
119
|
+
broadcastServerRequestSpy = jest.spyOn(BroadcastServer.prototype, 'request');
|
|
120
|
+
broadcastServerRespondSpy = jest.spyOn(BroadcastServer.prototype, 'respond');
|
|
121
|
+
broadcastServerFetchSpy = jest.spyOn(BroadcastServer.prototype, 'fetch');
|
|
122
|
+
broadcastMessageHandlerSpy = jest.spyOn(BroadcastServer.prototype, 'broadcastMessageHandler');
|
|
74
123
|
}
|
|
75
124
|
export async function setDebug(debug) {
|
|
76
125
|
const { jest } = await import('@jest/globals');
|
package/dist/matterbridge.js
CHANGED
|
@@ -144,6 +144,24 @@ export class Matterbridge extends EventEmitter {
|
|
|
144
144
|
this.log.logLevel = msg.params.logLevel;
|
|
145
145
|
this.server.respond({ ...msg, response: { success: true, logLevel: this.log.logLevel } });
|
|
146
146
|
break;
|
|
147
|
+
case 'matterbridge_latest_version':
|
|
148
|
+
this.matterbridgeLatestVersion = msg.params.version;
|
|
149
|
+
await this.nodeContext?.set('matterbridgeLatestVersion', msg.params.version);
|
|
150
|
+
this.server.respond({ ...msg, response: { success: true } });
|
|
151
|
+
break;
|
|
152
|
+
case 'matterbridge_dev_version':
|
|
153
|
+
this.matterbridgeDevVersion = msg.params.version;
|
|
154
|
+
await this.nodeContext?.set('matterbridgeDevVersion', msg.params.version);
|
|
155
|
+
this.server.respond({ ...msg, response: { success: true } });
|
|
156
|
+
break;
|
|
157
|
+
case 'matterbridge_sys_update':
|
|
158
|
+
this.shellySysUpdate = true;
|
|
159
|
+
this.server.respond({ ...msg, response: { success: true } });
|
|
160
|
+
break;
|
|
161
|
+
case 'matterbridge_main_update':
|
|
162
|
+
this.shellyMainUpdate = true;
|
|
163
|
+
this.server.respond({ ...msg, response: { success: true } });
|
|
164
|
+
break;
|
|
147
165
|
default:
|
|
148
166
|
if (this.verbose)
|
|
149
167
|
this.log.debug(`Unknown broadcast request ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}`);
|
package/dist/pluginManager.js
CHANGED
|
@@ -194,6 +194,30 @@ export class PluginManager extends EventEmitter {
|
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
break;
|
|
197
|
+
case 'plugins_set_latest_version':
|
|
198
|
+
{
|
|
199
|
+
const plugin = this.get(msg.params.plugin.name);
|
|
200
|
+
if (plugin) {
|
|
201
|
+
plugin.latestVersion = msg.params.version;
|
|
202
|
+
this.server.respond({ ...msg, response: { success: true } });
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
this.server.respond({ ...msg, response: { success: false } });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
break;
|
|
209
|
+
case 'plugins_set_dev_version':
|
|
210
|
+
{
|
|
211
|
+
const plugin = this.get(msg.params.plugin.name);
|
|
212
|
+
if (plugin) {
|
|
213
|
+
plugin.devVersion = msg.params.version;
|
|
214
|
+
this.server.respond({ ...msg, response: { success: true } });
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
this.server.respond({ ...msg, response: { success: false } });
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
break;
|
|
197
221
|
default:
|
|
198
222
|
if (this.verbose)
|
|
199
223
|
this.log.debug(`Unknown broadcast message ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}`);
|
package/dist/shelly.js
CHANGED
|
@@ -7,22 +7,22 @@ export function setVerifyIntervalSecs(seconds) {
|
|
|
7
7
|
export function setVerifyTimeoutSecs(seconds) {
|
|
8
8
|
verifyTimeoutSecs = seconds;
|
|
9
9
|
}
|
|
10
|
-
export async function getShellySysUpdate(matterbridge) {
|
|
10
|
+
export async function getShellySysUpdate(matterbridge, log, server) {
|
|
11
11
|
try {
|
|
12
12
|
const updates = (await getShelly('/api/updates/sys/check'));
|
|
13
13
|
if (updates.length === 0)
|
|
14
14
|
return;
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
server.request({ type: 'matterbridge_sys_update', src: server.name, dst: 'matterbridge' });
|
|
16
|
+
server.request({ type: 'frontend_broadcast_message', src: server.name, dst: 'frontend', params: { msg: { id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'shelly_sys_update', success: true, response: { available: true } } } });
|
|
17
17
|
for (const { name } of updates) {
|
|
18
18
|
if (!name)
|
|
19
19
|
continue;
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
log.notice(`Shelly system update available: ${name}`);
|
|
21
|
+
server.request({ type: 'frontend_snackbarmessage', src: server.name, dst: 'frontend', params: { message: `Shelly system update available: ${name}`, timeout: 10 } });
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
catch (err) {
|
|
25
|
-
|
|
25
|
+
log.error(`Error getting Shelly system updates: ${err instanceof Error ? err.message : String(err)}`);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
export async function triggerShellySysUpdate(matterbridge) {
|
|
@@ -38,22 +38,22 @@ export async function triggerShellySysUpdate(matterbridge) {
|
|
|
38
38
|
matterbridge.log.error(`Error triggering Shelly system update: ${err instanceof Error ? err.message : String(err)}`);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
export async function getShellyMainUpdate(matterbridge) {
|
|
41
|
+
export async function getShellyMainUpdate(matterbridge, log, server) {
|
|
42
42
|
try {
|
|
43
43
|
const updates = (await getShelly('/api/updates/main/check'));
|
|
44
44
|
if (updates.length === 0)
|
|
45
45
|
return;
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
server.request({ type: 'matterbridge_main_update', src: server.name, dst: 'matterbridge' });
|
|
47
|
+
server.request({ type: 'frontend_broadcast_message', src: server.name, dst: 'frontend', params: { msg: { id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'shelly_main_update', success: true, response: { available: true } } } });
|
|
48
48
|
for (const { name } of updates) {
|
|
49
49
|
if (!name)
|
|
50
50
|
continue;
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
log.notice(`Shelly software update available: ${name}`);
|
|
52
|
+
server.request({ type: 'frontend_snackbarmessage', src: server.name, dst: 'frontend', params: { message: `Shelly software update available: ${name}`, timeout: 10 } });
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
catch (err) {
|
|
56
|
-
|
|
56
|
+
log.error(`Error getting Shelly main updates: ${err instanceof Error ? err.message : String(err)}`);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
export async function triggerShellyMainUpdate(matterbridge) {
|
package/dist/update.js
CHANGED
|
@@ -1,121 +1,137 @@
|
|
|
1
|
-
import { db, debugStringify, nt, wr } from 'node-ansi-logger';
|
|
1
|
+
import { AnsiLogger, db, debugStringify, nt, wr } from 'node-ansi-logger';
|
|
2
2
|
import { plg } from './matterbridgeTypes.js';
|
|
3
|
+
import { BroadcastServer } from './broadcastServer.js';
|
|
4
|
+
import { hasParameter } from './utils/commandLine.js';
|
|
5
|
+
import { isValidString } from './utils/isvalid.js';
|
|
3
6
|
export async function checkUpdates(matterbridge) {
|
|
4
|
-
const {
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
const log = new AnsiLogger({ logName: 'MatterbridgeUpdates', logTimestampFormat: 4, logLevel: matterbridge.logLevel });
|
|
8
|
+
const server = new BroadcastServer('updates', log);
|
|
9
|
+
const checkUpdatePromise = checkUpdatesAndLog(matterbridge, log, server);
|
|
10
|
+
const latestVersionPromise = getMatterbridgeLatestVersion(matterbridge, log, server);
|
|
11
|
+
const devVersionPromise = getMatterbridgeDevVersion(matterbridge, log, server);
|
|
12
|
+
const pluginsVersionPromises = [];
|
|
13
|
+
const pluginsDevVersionPromises = [];
|
|
14
|
+
const shellyUpdatesPromises = [];
|
|
15
|
+
const plugins = (await server.fetch({ type: 'plugins_apipluginarray', src: server.name, dst: 'plugins', params: {} })).response.plugins;
|
|
16
|
+
for (const plugin of plugins) {
|
|
17
|
+
pluginsVersionPromises.push(getPluginLatestVersion(log, server, plugin));
|
|
18
|
+
pluginsDevVersionPromises.push(getPluginDevVersion(log, server, plugin));
|
|
16
19
|
}
|
|
17
20
|
if (hasParameter('shelly')) {
|
|
18
21
|
const { getShellySysUpdate, getShellyMainUpdate } = await import('./shelly.js');
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const mainUpdate = getShellyMainUpdate(matterbridge);
|
|
22
|
-
shellyUpdates.push(mainUpdate);
|
|
22
|
+
shellyUpdatesPromises.push(getShellySysUpdate(matterbridge, log, server));
|
|
23
|
+
shellyUpdatesPromises.push(getShellyMainUpdate(matterbridge, log, server));
|
|
23
24
|
}
|
|
24
|
-
await Promise.all([
|
|
25
|
+
await Promise.all([checkUpdatePromise, latestVersionPromise, devVersionPromise, ...pluginsVersionPromises, ...pluginsDevVersionPromises, ...shellyUpdatesPromises]);
|
|
26
|
+
server.close();
|
|
25
27
|
}
|
|
26
|
-
export async function checkUpdatesAndLog(matterbridge) {
|
|
28
|
+
export async function checkUpdatesAndLog(matterbridge, log, server) {
|
|
27
29
|
const { getGitHubUpdate } = await import('./utils/network.js');
|
|
28
|
-
const { isValidString } = await import('./utils/isvalid.js');
|
|
29
30
|
const branch = matterbridge.matterbridgeVersion.includes('-dev-') ? 'dev' : 'main';
|
|
30
31
|
try {
|
|
31
32
|
const updateJson = await getGitHubUpdate(branch, 'update.json', 5_000);
|
|
32
|
-
|
|
33
|
+
log.debug(`GitHub ${branch} update status: ${debugStringify(updateJson)}.`);
|
|
33
34
|
if (isValidString(branch === 'main' ? updateJson.latestMessage : updateJson.devMessage, 1) &&
|
|
34
35
|
isValidString(branch === 'main' ? updateJson.latestMessageSeverity : updateJson.devMessageSeverity, 4) &&
|
|
35
36
|
['info', 'warning', 'error', 'success'].includes(branch === 'main' ? updateJson.latestMessageSeverity : updateJson.devMessageSeverity)) {
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
log.notice(`GitHub ${branch} update message: ${branch === 'main' ? updateJson.latestMessage : updateJson.devMessage}`);
|
|
38
|
+
server.request({
|
|
39
|
+
type: 'frontend_snackbarmessage',
|
|
40
|
+
src: server.name,
|
|
41
|
+
dst: 'frontend',
|
|
42
|
+
params: { message: branch === 'main' ? updateJson.latestMessage : updateJson.devMessage, timeout: 0, severity: branch === 'main' ? updateJson.latestMessageSeverity : updateJson.devMessageSeverity },
|
|
43
|
+
});
|
|
38
44
|
}
|
|
39
45
|
}
|
|
40
46
|
catch (error) {
|
|
41
|
-
|
|
47
|
+
log.debug(`Error checking GitHub ${branch} updates: ${error instanceof Error ? error.message : error}`);
|
|
42
48
|
}
|
|
43
49
|
}
|
|
44
|
-
export async function getMatterbridgeLatestVersion(matterbridge) {
|
|
50
|
+
export async function getMatterbridgeLatestVersion(matterbridge, log, server) {
|
|
45
51
|
const { getNpmPackageVersion } = await import('./utils/network.js');
|
|
46
52
|
try {
|
|
47
53
|
const version = await getNpmPackageVersion('matterbridge');
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
server.request({ type: 'matterbridge_latest_version', src: server.name, dst: 'matterbridge', params: { version } });
|
|
55
|
+
if (matterbridge.matterbridgeVersion !== version) {
|
|
56
|
+
log.notice(`Matterbridge is out of date. Current version: ${matterbridge.matterbridgeVersion}. Latest version: ${version}.`);
|
|
57
|
+
server.request({
|
|
58
|
+
type: 'frontend_snackbarmessage',
|
|
59
|
+
src: server.name,
|
|
60
|
+
dst: 'frontend',
|
|
61
|
+
params: { message: 'Matterbridge latest update available', timeout: 0, severity: 'info' },
|
|
62
|
+
});
|
|
63
|
+
server.request({ type: 'frontend_updaterequired', src: server.name, dst: 'frontend', params: { devVersion: false } });
|
|
64
|
+
server.request({ type: 'frontend_refreshrequired', src: server.name, dst: 'frontend', params: { changed: 'settings' } });
|
|
55
65
|
}
|
|
56
66
|
else {
|
|
57
|
-
|
|
67
|
+
log.debug(`Matterbridge is up to date. Current version: ${matterbridge.matterbridgeVersion}. Latest version: ${version}.`);
|
|
58
68
|
}
|
|
59
69
|
return version;
|
|
60
70
|
}
|
|
61
71
|
catch (error) {
|
|
62
|
-
|
|
72
|
+
log.warn(`Error getting Matterbridge latest version: ${error instanceof Error ? error.message : error}`);
|
|
63
73
|
}
|
|
64
74
|
}
|
|
65
|
-
export async function getMatterbridgeDevVersion(matterbridge) {
|
|
75
|
+
export async function getMatterbridgeDevVersion(matterbridge, log, server) {
|
|
66
76
|
const { getNpmPackageVersion } = await import('./utils/network.js');
|
|
67
77
|
try {
|
|
68
78
|
const version = await getNpmPackageVersion('matterbridge', 'dev');
|
|
69
|
-
|
|
70
|
-
await matterbridge.nodeContext?.set('matterbridgeDevVersion', version);
|
|
79
|
+
server.request({ type: 'matterbridge_dev_version', src: server.name, dst: 'matterbridge', params: { version } });
|
|
71
80
|
if (matterbridge.matterbridgeVersion.includes('-dev-') && matterbridge.matterbridgeVersion !== version) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
log.notice(`Matterbridge@dev is out of date. Current version: ${matterbridge.matterbridgeVersion}. Latest dev version: ${version}.`);
|
|
82
|
+
server.request({
|
|
83
|
+
type: 'frontend_snackbarmessage',
|
|
84
|
+
src: server.name,
|
|
85
|
+
dst: 'frontend',
|
|
86
|
+
params: { message: 'Matterbridge dev update available', timeout: 0, severity: 'info' },
|
|
87
|
+
});
|
|
88
|
+
server.request({ type: 'frontend_updaterequired', src: server.name, dst: 'frontend', params: { devVersion: true } });
|
|
89
|
+
server.request({ type: 'frontend_refreshrequired', src: server.name, dst: 'frontend', params: { changed: 'settings' } });
|
|
76
90
|
}
|
|
77
91
|
else if (matterbridge.matterbridgeVersion.includes('-dev-') && matterbridge.matterbridgeVersion === version) {
|
|
78
|
-
|
|
92
|
+
log.debug(`Matterbridge@dev is up to date. Current version: ${matterbridge.matterbridgeVersion}. Latest dev version: ${version}.`);
|
|
79
93
|
}
|
|
80
94
|
return version;
|
|
81
95
|
}
|
|
82
96
|
catch (error) {
|
|
83
|
-
|
|
97
|
+
log.warn(`Error getting Matterbridge latest dev version: ${error instanceof Error ? error.message : error}`);
|
|
84
98
|
}
|
|
85
99
|
}
|
|
86
|
-
export async function getPluginLatestVersion(
|
|
100
|
+
export async function getPluginLatestVersion(log, server, plugin) {
|
|
87
101
|
const { getNpmPackageVersion } = await import('./utils/network.js');
|
|
88
102
|
try {
|
|
89
103
|
const version = await getNpmPackageVersion(plugin.name);
|
|
90
104
|
plugin.latestVersion = version;
|
|
105
|
+
server.request({ type: 'plugins_set_latest_version', src: server.name, dst: 'plugins', params: { plugin, version } });
|
|
91
106
|
if (plugin.version !== plugin.latestVersion) {
|
|
92
|
-
|
|
93
|
-
|
|
107
|
+
log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
|
|
108
|
+
server.request({ type: 'frontend_refreshrequired', src: server.name, dst: 'frontend', params: { changed: 'plugins' } });
|
|
94
109
|
}
|
|
95
110
|
else {
|
|
96
|
-
|
|
111
|
+
log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
|
|
97
112
|
}
|
|
98
113
|
return version;
|
|
99
114
|
}
|
|
100
115
|
catch (error) {
|
|
101
|
-
|
|
116
|
+
log.warn(`Error getting plugin ${plg}${plugin.name}${wr} latest version: ${error instanceof Error ? error.message : error}`);
|
|
102
117
|
}
|
|
103
118
|
}
|
|
104
|
-
export async function getPluginDevVersion(
|
|
119
|
+
export async function getPluginDevVersion(log, server, plugin) {
|
|
105
120
|
const { getNpmPackageVersion } = await import('./utils/network.js');
|
|
106
121
|
try {
|
|
107
122
|
const version = await getNpmPackageVersion(plugin.name, 'dev');
|
|
108
123
|
plugin.devVersion = version;
|
|
124
|
+
server.request({ type: 'plugins_set_dev_version', src: server.name, dst: 'plugins', params: { plugin, version } });
|
|
109
125
|
if (plugin.version.includes('-dev-') && plugin.version !== plugin.devVersion) {
|
|
110
|
-
|
|
111
|
-
|
|
126
|
+
log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest dev version: ${plugin.devVersion}.`);
|
|
127
|
+
server.request({ type: 'frontend_refreshrequired', src: server.name, dst: 'frontend', params: { changed: 'plugins' } });
|
|
112
128
|
}
|
|
113
129
|
else if (plugin.version.includes('-dev-') && plugin.version === plugin.devVersion) {
|
|
114
|
-
|
|
130
|
+
log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest dev version: ${plugin.devVersion}.`);
|
|
115
131
|
}
|
|
116
132
|
return version;
|
|
117
133
|
}
|
|
118
134
|
catch (error) {
|
|
119
|
-
|
|
135
|
+
log.debug(`Error getting plugin ${plg}${plugin.name}${db} latest dev version: ${error instanceof Error ? error.message : error}`);
|
|
120
136
|
}
|
|
121
137
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
body{font-family:Roboto,sans-serif}[frontend-theme=classic]{--main-bg-color: #c4c2c2;--main-text-color: black;--main-grey-color: #616161;--main-light-color: #959595;--main-icon-color: #4d4d4d;--main-log-color: var(--main-text-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: #26292d;--main-menu-bg-color: #e2e2e2;--main-menu-hover-color: #959595;--main-label-color: var(--main-grey-color);--primary-color: #009a00;--secondary-color: #92771f;--header-bg-color: var(--primary-color);--header-text-color: white;--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: #ddd;--table-text-color: black;--table-even-bg-color: #bdbdbd;--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: #5f8c9e;--table-selected-bg-color: #5f8c9e;--div-bg-color: #adadad;--div-text-color: black;--div-shadow-color: #888;--div-border-color: rgb(139, 139, 139);--div-border-radius: 0px;--div-title-bg-color: var(--div-bg-color);--div-title-text-color: black;background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}[frontend-theme=dark]{--main-bg-color: #26292d;--main-text-color: #ffffff;--main-grey-color: #616161;--main-light-color: #959595;--main-icon-color: var(--main-light-color);--main-log-color: var(--main-light-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: var(--main-light-color);--main-menu-bg-color: var(--main-bg-color);--main-menu-hover-color: var(--div-bg-color);--main-label-color: var(--main-grey-color);--primary-color: #1976d2;--secondary-color: #a58827;--header-bg-color: var(--div-bg-color);--header-text-color: var(--primary-color);--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: var(--div-bg-color);--table-text-color: var(--main-light-color);--table-even-bg-color: var(--div-bg-color);--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: var(--main-bg-color);--table-selected-bg-color: var(--main-bg-color);--div-bg-color: #1b1d21;--div-text-color: var(--main-light-color);--div-shadow-color: #34373d;--div-border-color: #1b1d21;--div-border-radius: 5px;--div-title-bg-color: #1b1d21;--div-title-text-color: var(--primary-color);background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}[frontend-theme=light]{--main-bg-color: #f0f0f0;--main-text-color: #212121;--main-grey-color: #616161;--main-light-color: #363636;--main-icon-color: #7a7a7a;--main-log-color: var(--main-light-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: var(--main-text-color);--main-menu-bg-color: var(--div-bg-color);--main-menu-hover-color: #85c0d8;--main-label-color: var(--main-grey-color);--primary-color: #2196f3;--secondary-color: #a58827;--header-bg-color: var(--div-bg-color);--header-text-color: var(--div-text-color);--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: var(--div-bg-color);--table-text-color: var(--main-light-color);--table-even-bg-color: var(--div-bg-color);--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: #85c0d8;--table-selected-bg-color: #85c0d8;--div-bg-color: #ffffff;--div-text-color: #212121;--div-shadow-color: #bfbfbf;--div-border-color: var(--div-bg-color);--div-border-radius: 5px;--div-title-bg-color: var(--div-bg-color);--div-title-text-color: var(--div-text-color);background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}::-webkit-scrollbar{width:10px}::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:var(--primary-color);border-radius:5px}::-webkit-scrollbar-track{background:"inherit"}html,.thin-scroll{scrollbar-width:thin;scrollbar-color:var(--primary-color) var(--div-bg-color)}.thin-scroll::-webkit-scrollbar{width:5px;height:5px}.thin-scroll::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:5px}.tooltip-container{position:relative;display:inline-block;z-index:10}.tooltip-text{visibility:hidden;background-color:var(--ttip-bg-color);color:var(--ttip-text-color);text-align:center;padding:5px;border-radius:6px;position:absolute;z-index:10;bottom:calc(100% + 10px);left:50%;margin-left:-60px;opacity:0;transition:opacity .3s;font-size:12px}.tooltip-container:hover{cursor:pointer;z-index:10}.tooltip-container:hover .tooltip-text{visibility:visible;opacity:1;z-index:10}.status-enabled{background-color:green;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-disabled{background-color:red;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-information{background-color:#9e9e9e;color:#fff;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-warning{background-color:#e9db18;color:#000;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-sponsor{background-color:#b6409c;color:#fff;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-blue{background-color:#5f8c9e;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.header{display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:20px;margin:0;padding:0;height:40px}.sub-header{flex:0 0 auto;display:flex;flex-direction:row;align-items:center;gap:20px;margin:0;padding:0;height:40px}nav{display:flex;align-items:center;gap:10px}.nav-link{margin:0;font-size:20px;text-decoration:none;color:var(--main-icon-color);transition:color .3s ease}.nav-link:hover{color:var(--primary-color)}table{border-collapse:collapse;width:100%;table-layout:auto}thead{position:sticky;top:0;border:1px solid var(--table-border-color);z-index:10}thead th{border:1px solid var(--table-border-color);padding:5px 10px;color:var(--header-text-color);background:var(--header-bg-color);text-align:left;z-index:10}tbody td{border:1px solid var(--table-border-color);margin:0;padding:5px 10px;text-align:left;font-size:14px}tbody tr:hover{color:var(--table-text-color);background-color:var(--table-hover-bg-color)}.table-content-even{color:var(--table-text-color);background-color:var(--table-even-bg-color)}.table-content-odd{color:var(--table-text-color);background-color:var(--table-odd-bg-color)}.table-content-selected{color:var(--table-text-color);background-color:var(--table-selected-bg-color)}h3{margin:0}.MbfScreen{display:flex;flex-direction:column;width:calc(100vw - 40px);height:calc(100vh - 40px);gap:20px;margin:0;padding:20px;background-color:var(--main-bg-color)}.MbfPageDiv{display:flex;flex-direction:column;height:100%;width:100%;margin:0;padding:0;gap:20px}.MbfWindowDiv{display:flex;flex-direction:column;box-shadow:5px 5px 10px var(--div-shadow-color);border:1px solid var(--table-border-color);border-radius:var(--div-border-radius);box-sizing:border-box;background-color:var(--div-bg-color)}.MbfWindowDivTable{display:block;flex:1 1 auto;overflow:auto;margin:-1px;padding:0;gap:0}.MbfWindowHeaderFooterIcons{display:flex;flex-direction:row;margin:0;padding:0 10px;gap:10px}.MbfWindowHeader{display:flex;flex-direction:row;align-items:center;width:100%;border-bottom:1px solid var(--table-border-color);color:var(--header-text-color);background-color:var(--header-bg-color);margin:0;padding:0;box-sizing:border-box}.MbfWindowHeaderText{color:var(--header-text-color);font-weight:700;margin:0;padding:5px 10px}.MbfWindowFooter{display:flex;flex-direction:row;align-items:center;justify-content:center;color:var(--footer-text-color);background-color:var(--footer-bg-color);margin:0;padding:0}.MbfWindowFooterText{color:var(--footer-text-color);background-color:var(--footer-bg-color);font-weight:700;text-align:center;margin:0;padding:5px 10px}.MbfWindowBody{display:flex;flex:1 1 auto;margin:0;padding:10px;gap:10px}.MbfWindowBodyColumn{display:flex;flex-direction:column;flex:1 1 auto;width:100%;margin:0;padding:10px 0;gap:0px;overflow:auto}.MbfWindowBodyRow{display:flex;flex-direction:row;flex:1 1 auto;height:100%;margin:0;padding:0 10px;gap:0px;overflow:auto}.configSubmitButton{display:flex;flex-direction:row;justify-content:center;width:auto;margin:20px}.configSubmitButton button{width:auto}@media(max-width:1300px){.MbfScreen{width:1300px;height:1024px}
|
|
1
|
+
body{font-family:Roboto,sans-serif}[frontend-theme=classic]{--main-bg-color: #c4c2c2;--main-text-color: black;--main-grey-color: #616161;--main-light-color: #959595;--main-icon-color: #4d4d4d;--main-log-color: var(--main-text-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: #26292d;--main-menu-bg-color: #e2e2e2;--main-menu-hover-color: #959595;--main-label-color: var(--main-grey-color);--primary-color: #009a00;--secondary-color: #92771f;--header-bg-color: var(--primary-color);--header-text-color: white;--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: #ddd;--table-text-color: black;--table-even-bg-color: #bdbdbd;--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: #5f8c9e;--table-selected-bg-color: #5f8c9e;--div-bg-color: #adadad;--div-text-color: black;--div-shadow-color: #888;--div-border-color: rgb(139, 139, 139);--div-border-radius: 0px;--div-title-bg-color: var(--div-bg-color);--div-title-text-color: black;background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}[frontend-theme=dark]{--main-bg-color: #26292d;--main-text-color: #ffffff;--main-grey-color: #616161;--main-light-color: #959595;--main-icon-color: var(--main-light-color);--main-log-color: var(--main-light-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: var(--main-light-color);--main-menu-bg-color: var(--main-bg-color);--main-menu-hover-color: var(--div-bg-color);--main-label-color: var(--main-grey-color);--primary-color: #1976d2;--secondary-color: #a58827;--header-bg-color: var(--div-bg-color);--header-text-color: var(--primary-color);--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: var(--div-bg-color);--table-text-color: var(--main-light-color);--table-even-bg-color: var(--div-bg-color);--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: var(--main-bg-color);--table-selected-bg-color: var(--main-bg-color);--div-bg-color: #1b1d21;--div-text-color: var(--main-light-color);--div-shadow-color: #34373d;--div-border-color: #1b1d21;--div-border-radius: 5px;--div-title-bg-color: #1b1d21;--div-title-text-color: var(--primary-color);background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}[frontend-theme=light]{--main-bg-color: #f0f0f0;--main-text-color: #212121;--main-grey-color: #616161;--main-light-color: #363636;--main-icon-color: #7a7a7a;--main-log-color: var(--main-light-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: var(--main-text-color);--main-menu-bg-color: var(--div-bg-color);--main-menu-hover-color: #85c0d8;--main-label-color: var(--main-grey-color);--primary-color: #2196f3;--secondary-color: #a58827;--header-bg-color: var(--div-bg-color);--header-text-color: var(--div-text-color);--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: var(--div-bg-color);--table-text-color: var(--main-light-color);--table-even-bg-color: var(--div-bg-color);--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: #85c0d8;--table-selected-bg-color: #85c0d8;--div-bg-color: #ffffff;--div-text-color: #212121;--div-shadow-color: #bfbfbf;--div-border-color: var(--div-bg-color);--div-border-radius: 5px;--div-title-bg-color: var(--div-bg-color);--div-title-text-color: var(--div-text-color);background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}::-webkit-scrollbar{width:10px}::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:var(--primary-color);border-radius:5px}::-webkit-scrollbar-track{background:"inherit"}html,.thin-scroll{scrollbar-width:thin;scrollbar-color:var(--primary-color) var(--div-bg-color)}.thin-scroll::-webkit-scrollbar{width:5px;height:5px}.thin-scroll::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:5px}.tooltip-container{position:relative;display:inline-block;z-index:10}.tooltip-text{visibility:hidden;background-color:var(--ttip-bg-color);color:var(--ttip-text-color);text-align:center;padding:5px;border-radius:6px;position:absolute;z-index:10;bottom:calc(100% + 10px);left:50%;margin-left:-60px;opacity:0;transition:opacity .3s;font-size:12px}.tooltip-container:hover{cursor:pointer;z-index:10}.tooltip-container:hover .tooltip-text{visibility:visible;opacity:1;z-index:10}.status-enabled{background-color:green;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-disabled{background-color:red;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-information{background-color:#9e9e9e;color:#fff;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-warning{background-color:#e9db18;color:#000;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-sponsor{background-color:#b6409c;color:#fff;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-blue{background-color:#5f8c9e;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.header{display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:20px;margin:0;padding:0;height:40px}.sub-header{flex:0 0 auto;display:flex;flex-direction:row;align-items:center;gap:20px;margin:0;padding:0;height:40px}nav{display:flex;align-items:center;gap:10px}.nav-link{margin:0;font-size:20px;text-decoration:none;color:var(--main-icon-color);transition:color .3s ease}.nav-link:hover{color:var(--primary-color)}table{border-collapse:collapse;width:100%;table-layout:auto}thead{position:sticky;top:0;border:1px solid var(--table-border-color);z-index:10}thead th{border:1px solid var(--table-border-color);padding:5px 10px;color:var(--header-text-color);background:var(--header-bg-color);text-align:left;z-index:10}tbody td{border:1px solid var(--table-border-color);margin:0;padding:5px 10px;text-align:left;font-size:14px}tbody tr:hover{color:var(--table-text-color);background-color:var(--table-hover-bg-color)}.table-content-even{color:var(--table-text-color);background-color:var(--table-even-bg-color)}.table-content-odd{color:var(--table-text-color);background-color:var(--table-odd-bg-color)}.table-content-selected{color:var(--table-text-color);background-color:var(--table-selected-bg-color)}h3{margin:0}.MbfScreen{display:flex;flex-direction:column;width:calc(100vw - 40px);height:calc(100vh - 40px);gap:20px;margin:0;padding:20px;background-color:var(--main-bg-color)}.MbfPageDiv{display:flex;flex-direction:column;height:100%;width:100%;margin:0;padding:0;gap:20px}.MbfWindowDiv{display:flex;flex-direction:column;box-shadow:5px 5px 10px var(--div-shadow-color);border:1px solid var(--table-border-color);border-radius:var(--div-border-radius);box-sizing:border-box;background-color:var(--div-bg-color)}.MbfWindowDivTable{display:block;flex:1 1 auto;overflow:auto;margin:-1px;padding:0;gap:0}.MbfWindowHeaderFooterIcons{display:flex;flex-direction:row;margin:0;padding:0 10px;gap:10px}.MbfWindowHeader{display:flex;flex-direction:row;align-items:center;width:100%;border-bottom:1px solid var(--table-border-color);color:var(--header-text-color);background-color:var(--header-bg-color);margin:0;padding:0;box-sizing:border-box}.MbfWindowHeaderText{color:var(--header-text-color);font-weight:700;margin:0;padding:5px 10px}.MbfWindowFooter{display:flex;flex-direction:row;align-items:center;justify-content:center;color:var(--footer-text-color);background-color:var(--footer-bg-color);margin:0;padding:0}.MbfWindowFooterText{color:var(--footer-text-color);background-color:var(--footer-bg-color);font-weight:700;text-align:center;margin:0;padding:5px 10px}.MbfWindowBody{display:flex;flex:1 1 auto;margin:0;padding:10px;gap:10px}.MbfWindowBodyColumn{display:flex;flex-direction:column;flex:1 1 auto;width:100%;margin:0;padding:10px 0;gap:0px;overflow:auto}.MbfWindowBodyRow{display:flex;flex-direction:row;flex:1 1 auto;height:100%;margin:0;padding:0 10px;gap:0px;overflow:auto}.configSubmitButton{display:flex;flex-direction:row;justify-content:center;width:auto;margin:20px}.configSubmitButton button{width:auto}@media(max-width:1300px){.MbfScreen{width:1300px;height:1024px}}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}
|