iobroker.eos-admin 7.10.6 → 7.10.8
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/INSTALL_TEST_V7.10.7.md +9 -0
- package/MERGE_UPDATE_README_V7.10.7.md +7 -0
- package/NEXOWATT_EOS_BUILD_INFO.json +19 -19
- package/NEXOWATT_EOS_PREBUILT_MANIFEST.json +26 -24
- package/PUBLISH_STABLE_V7.10.7.md +9 -0
- package/README_STABILITY_V7.10.7.md +7 -0
- package/RELEASE_ACCEPTANCE_V7.10.7.md +12 -0
- package/RELEASE_NOTES_V7.10.7.md +19 -0
- package/{SECURITY_ROLE_MATRIX_V7.10.6.md → SECURITY_ROLE_MATRIX_V7.10.7.md} +4 -2
- package/adminWww/css/nexowatt-native-shell.css +332 -0
- package/adminWww/index.html +14 -14
- package/adminWww/js/eos-role-bootstrap.js +4 -3
- package/adminWww/js/eos-role-ui.js +34 -18
- package/adminWww/js/nexowatt-native-shell.js +104 -2
- package/adminWww/static/js/{nexowatt-stable-v7106.js → nexowatt-stable-v7108.js} +2 -2
- package/build/lib/web.js +3 -0
- package/io-package.json +10 -5
- package/package.json +16 -12
- package/tools/nexowatt-installer-ems-selftest.cjs +44 -0
- package/tools/nexowatt-merge-update-selftest.cjs +1 -1
- package/tools/nexowatt-role-security-selftest.cjs +19 -6
- package/tools/nexowatt-stable-v7103-selftest.cjs +2 -2
- package/tools/nexowatt-user-area-selftest.cjs +1 -1
- package/tools/nexowatt-v7108-ui-foundation-selftest.cjs +64 -0
- package/tools/nexowatt-validate-package.cjs +9 -7
- package/INSTALL_TEST_V7.10.6.md +0 -8
- package/MERGE_UPDATE_README_V7.10.6.md +0 -7
- package/PUBLISH_STABLE_V7.10.6.md +0 -8
- package/README_STABILITY_V7.10.6.md +0 -5
- package/RELEASE_ACCEPTANCE_V7.10.6.md +0 -11
- package/RELEASE_NOTES_V7.10.6.md +0 -14
package/adminWww/index.html
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate" />
|
|
9
9
|
<meta http-equiv="Pragma" content="no-cache" />
|
|
10
10
|
<meta http-equiv="Expires" content="0" />
|
|
11
|
-
<script src="./js/eos-manual-write-policy.js?v=
|
|
11
|
+
<script src="./js/eos-manual-write-policy.js?v=7108"></script>
|
|
12
12
|
<script type="module" src="./assets/hostInit-v84.js?v=84"></script>
|
|
13
13
|
|
|
14
14
|
<meta charset="utf-8" />
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
rel="stylesheet"
|
|
37
37
|
href="css/leaflet.css"
|
|
38
38
|
/>
|
|
39
|
-
<link rel="stylesheet" href="./css/nexowatt-native-shell.css?v=
|
|
40
|
-
<link rel="stylesheet" href="./css/eos-ems-overview.css?v=
|
|
39
|
+
<link rel="stylesheet" href="./css/nexowatt-native-shell.css?v=7108" />
|
|
40
|
+
<link rel="stylesheet" href="./css/eos-ems-overview.css?v=7108" />
|
|
41
41
|
<link rel="stylesheet" href="./css/eos-auto-update.css?v=7103" />
|
|
42
42
|
<link
|
|
43
43
|
rel="manifest"
|
|
@@ -160,22 +160,22 @@
|
|
|
160
160
|
</script>
|
|
161
161
|
<link rel="modulepreload" crossorigin href="./assets/preload-helper-BDBacUwf.js">
|
|
162
162
|
<link rel="modulepreload" crossorigin href="./assets/iobroker_admin__mf_v__runtimeInit__mf_v__-g2X2zhAf.js">
|
|
163
|
-
<script defer src="./js/eos-role-bootstrap.js?v=
|
|
164
|
-
<script defer src="./js/eos-policy-client.js?v=
|
|
165
|
-
<script defer src="./js/eos-branding-sanitizer.js?v=
|
|
166
|
-
<script defer src="./js/nexowatt-native-shell.js?v=
|
|
167
|
-
<script defer src="./js/eos-native-security.js?v=
|
|
168
|
-
<script defer src="./js/eos-basic-settings.js?v=
|
|
169
|
-
<script defer src="./js/eos-role-ui.js?v=
|
|
170
|
-
<script defer src="./js/eos-ems-overview.js?v=
|
|
163
|
+
<script defer src="./js/eos-role-bootstrap.js?v=7108" data-eos-entry="./assets/index-CQZugZ1z-v84.js?v=84"></script>
|
|
164
|
+
<script defer src="./js/eos-policy-client.js?v=7108"></script>
|
|
165
|
+
<script defer src="./js/eos-branding-sanitizer.js?v=7108"></script>
|
|
166
|
+
<script defer src="./js/nexowatt-native-shell.js?v=7108"></script>
|
|
167
|
+
<script defer src="./js/eos-native-security.js?v=7108"></script>
|
|
168
|
+
<script defer src="./js/eos-basic-settings.js?v=7108"></script>
|
|
169
|
+
<script defer src="./js/eos-role-ui.js?v=7108"></script>
|
|
170
|
+
<script defer src="./js/eos-ems-overview.js?v=7108"></script>
|
|
171
171
|
|
|
172
172
|
<script defer src="./js/eos-auto-update.js?v=7103"></script>
|
|
173
|
-
<script defer src="./js/eos-assistant.js?v=
|
|
173
|
+
<script defer src="./js/eos-assistant.js?v=7108"></script>
|
|
174
174
|
</head>
|
|
175
175
|
<body>
|
|
176
176
|
<noscript>Für NexoWatt EOS muss JavaScript aktiviert sein.</noscript>
|
|
177
177
|
<div id="root"></div>
|
|
178
|
-
<script defer src="static/js/nexowatt-stable-login.js?v=
|
|
179
|
-
<script defer src="static/js/nexowatt-stable-
|
|
178
|
+
<script defer src="static/js/nexowatt-stable-login.js?v=7108"></script>
|
|
179
|
+
<script defer src="static/js/nexowatt-stable-v7108.js?v=7108"></script>
|
|
180
180
|
</body>
|
|
181
181
|
</html>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const VERSION = '
|
|
4
|
+
const VERSION = 'v7108-modern-core-surfaces-rbac';
|
|
5
5
|
const script = document.currentScript || document.querySelector('script[src*="eos-role-bootstrap.js"]');
|
|
6
6
|
const entry = script?.dataset?.eosEntry || '';
|
|
7
7
|
let launched = false;
|
|
@@ -25,11 +25,12 @@
|
|
|
25
25
|
const isCustomerBackupTab = tab => /^(?:tab-)?(?:nexowatt-backup|eos-backup|nexowatt-sicherung)(?:-|$)/.test(normalize(tab));
|
|
26
26
|
const isReleasedEndUserTab = tab => /^(?:tab-)?(?:nexowatt-ui|nexowatt-cockpit|eos-cockpit|eos-dashboard|kunden-cockpit|endkunden-cockpit|lovelace|jarvis|vis|iqontrol|material)(?:-|$)/.test(normalize(tab));
|
|
27
27
|
const isOfficialReserveTab = tab => /^(?:tab-)?(?:admin|backitup)(?:-\d+)?$/.test(normalize(tab));
|
|
28
|
+
const isGloballyHiddenTab = tab => normalize(tab) === 'tab-enums';
|
|
28
29
|
const isInstallerDenied = tab => /(?:tab-users|tab-hosts|tab-files|tab-xterm|tab-xtrem|tab-system|users|hosts|files|console|terminal|security)/.test(normalize(tab)) || isOfficialReserveTab(tab);
|
|
29
|
-
const isAllowed = (role, route) => route !== 'easy' && (role === 'admin'
|
|
30
|
+
const isAllowed = (role, route) => route !== 'easy' && !isGloballyHiddenTab(route) && (role === 'admin'
|
|
30
31
|
|| (role === 'installer'
|
|
31
32
|
? route === 'tab-intro' || isCustomerBackupTab(route) || !isInstallerDenied(route)
|
|
32
|
-
: route === 'tab-intro' || route === 'tab-
|
|
33
|
+
: route === 'tab-intro' || route === 'tab-objects' || isCustomerBackupTab(route) || isReleasedEndUserTab(route)));
|
|
33
34
|
const defaultTab = () => 'tab-intro';
|
|
34
35
|
const currentRoute = () => {
|
|
35
36
|
const hash = decodeURIComponent(window.location.hash || '').toLowerCase();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const VERSION = '
|
|
4
|
+
const VERSION = 'v7108-modern-core-surfaces-rbac';
|
|
5
5
|
window.NEXOWATT_EOS_ROLE_UI_VERSION = VERSION;
|
|
6
6
|
|
|
7
7
|
const state = {
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
if (policy?.isInstaller || /installateur|installer|installation|inbetriebnahme|techniker|technician|integrator|partner/.test(raw)) return 'installer';
|
|
46
46
|
return 'enduser';
|
|
47
47
|
};
|
|
48
|
+
const isGloballyHiddenTab = tab => normalize(tab) === 'tab-enums';
|
|
48
49
|
const isOfficialAdminTab = tab => /^tab-admin(?:-\d+)?$/.test(normalize(tab));
|
|
49
50
|
const isOfficialBackupTab = tab => /^tab-backitup(?:-\d+)?$/.test(normalize(tab));
|
|
50
51
|
const isOfficialReserveTab = tab => isOfficialAdminTab(tab) || isOfficialBackupTab(tab);
|
|
@@ -53,7 +54,7 @@
|
|
|
53
54
|
const endUserDeniedByText = value => /(module|dienste|systemlogs|logs|zugange|rechte|benutzer|users|gruppen|groups|system hosts|system-hosts|hosts|dateien|files|konsole|console|terminal|xterm|adapter|instances?|instanzen|geraetesuche|discovery|systemschutz|security)/.test(normalize(value));
|
|
54
55
|
const isEndUserTab = (tab, label = '') => {
|
|
55
56
|
const clean = normalize(tab); const text = `${clean} ${normalize(label)}`;
|
|
56
|
-
if (clean === 'tab-intro' || clean === 'tab-
|
|
57
|
+
if (clean === 'tab-intro' || clean === 'tab-objects' || isCustomerBackupTab(clean)) return true;
|
|
57
58
|
if (/^tab-(nexowatt-ui|nexowatt-cockpit|eos-cockpit|eos-dashboard|kunden-cockpit|endkunden-cockpit|lovelace|jarvis|vis|iqontrol|material)(?:-|$)/.test(clean)) return true;
|
|
58
59
|
return !!clean && !endUserDeniedByText(text) && endUserAllowedByText(text);
|
|
59
60
|
};
|
|
@@ -64,7 +65,7 @@
|
|
|
64
65
|
return /(?:tab-users|tab-hosts|tab-files|tab-xterm|tab-xtrem|tab-system|users|benutzer|gruppen|groups|system-hosts|system hosts|hosts|dateien|files|konsole|console|terminal|xterm|systemschutz|security)/.test(text);
|
|
65
66
|
};
|
|
66
67
|
const isRouteAllowed = (role, route, label = '') => {
|
|
67
|
-
if (route === 'easy') return false;
|
|
68
|
+
if (route === 'easy' || isGloballyHiddenTab(route)) return false;
|
|
68
69
|
if (role === 'admin') return true;
|
|
69
70
|
if (isOfficialReserveTab(route)) return false;
|
|
70
71
|
if (role === 'installer') return route === 'tab-intro' || (route !== 'tab-users' && !isInstallerDenied(route, label));
|
|
@@ -136,6 +137,8 @@
|
|
|
136
137
|
return normalize(`${button?.getAttribute?.('aria-label') || ''} ${button?.getAttribute?.('title') || ''} ${testIds}`);
|
|
137
138
|
};
|
|
138
139
|
const isSystemSettingsButton = button => /buildicon|system settings|systemeinstellungen|systeeminstellingen/.test(toolbarButtonSignature(button));
|
|
140
|
+
const isHeaderSystemSettingsButton = button => button?.dataset?.eosSystemSettingsControl === '1'
|
|
141
|
+
&& !!button.closest?.('.eos-top-toolbar,.MuiAppBar-root .MuiToolbar-root');
|
|
139
142
|
const isExpertModeButton = button => button?.dataset?.eosExpertControl === '1' || /expert|experten/.test(toolbarButtonSignature(button));
|
|
140
143
|
const markAdminOnlyToolbarControls = () => safe(() => {
|
|
141
144
|
const toolbar = document.querySelector('.eos-top-toolbar,.MuiAppBar-root .MuiToolbar-root');
|
|
@@ -227,7 +230,6 @@
|
|
|
227
230
|
['Dienste', 'Instanzen starten, stoppen und diagnostizieren', 'tab-instances', 'services'],
|
|
228
231
|
['Module', 'Module installieren, aktualisieren und konfigurieren', 'tab-adapters', 'modules'],
|
|
229
232
|
['Datenpunkte', 'Messwerte prüfen und freigegebene Werte schreiben', 'tab-objects', 'datapoints'],
|
|
230
|
-
['Struktur', 'Räume und Funktionen für Smart Home zuordnen', 'tab-enums', 'structure'],
|
|
231
233
|
['Geräte', 'Geräteintegration und Inbetriebnahme öffnen', 'tab-devicemanager', 'devices'],
|
|
232
234
|
['Basis-Einstellungen', 'Standort, Sprache und Anlagenparameter', 'basic-settings', 'settings'],
|
|
233
235
|
...(backupTab ? [['NexoWatt Sicherung', 'Sicherung und Wiederherstellung des EOS-Systems', backupTab, 'backup']] : []),
|
|
@@ -237,7 +239,6 @@
|
|
|
237
239
|
return [
|
|
238
240
|
['EOS Cockpit', 'Energie, Laden und Gebäude bedienen', uiTab, 'eos'],
|
|
239
241
|
['Datenpunkte', 'Messwerte und Zustände ausschließlich lesen', 'tab-objects', 'datapoints'],
|
|
240
|
-
['Smart Home', 'Räume, Funktionen und freigegebene Geräte zuordnen', 'tab-enums', 'structure'],
|
|
241
242
|
...(backupTab ? [['NexoWatt Sicherung', 'Eigene Sicherungen ausführen und wiederherstellen', backupTab, 'backup']] : []),
|
|
242
243
|
];
|
|
243
244
|
};
|
|
@@ -483,12 +484,26 @@
|
|
|
483
484
|
|
|
484
485
|
|
|
485
486
|
const privilegedFrameObservers = new WeakMap();
|
|
486
|
-
const
|
|
487
|
-
const isPrivilegedAction = element => {
|
|
487
|
+
const privilegedActionKind = element => {
|
|
488
488
|
const signature = normalize(textOf(element));
|
|
489
489
|
const href = normalize(element?.getAttribute?.('href') || element?.href || element?.getAttribute?.('data-href') || '');
|
|
490
|
-
|
|
491
|
-
|| /(?:^|[\/#?&_.-])(?:appcenter|app-center
|
|
490
|
+
if (/^(?:ems apps?(?: offnen| öffnen)?|app center|app-center|appcenter)$/.test(signature)
|
|
491
|
+
|| /(?:^|[\/#?&_.-])(?:appcenter|app-center)(?:$|[\/#?&=_.-])/.test(href)) return 'ems';
|
|
492
|
+
if (/^(?:simulation|simulator)$/.test(signature)
|
|
493
|
+
|| /(?:^|[\/#?&_.-])(?:simulation|simulator)(?:$|[\/#?&=_.-])/.test(href)) return 'simulation';
|
|
494
|
+
if (/^(?:lizenz|license)$/.test(signature)
|
|
495
|
+
|| /(?:^|[\/#?&_.-])(?:license|lizenz)(?:$|[\/#?&=_.-])/.test(href)) return 'license';
|
|
496
|
+
return '';
|
|
497
|
+
};
|
|
498
|
+
const isPrivilegedAction = element => !!privilegedActionKind(element);
|
|
499
|
+
const canUsePrivilegedAction = element => {
|
|
500
|
+
const action = privilegedActionKind(element);
|
|
501
|
+
if (!action) return true;
|
|
502
|
+
if (action === 'ems') {
|
|
503
|
+
return state.role === 'admin'
|
|
504
|
+
|| (state.role === 'installer' && state.policy?.capabilities?.emsAppCenter !== false);
|
|
505
|
+
}
|
|
506
|
+
return state.role === 'admin';
|
|
492
507
|
};
|
|
493
508
|
const setPrivilegedActionHidden = (element, hidden) => {
|
|
494
509
|
if (!element) return;
|
|
@@ -507,19 +522,18 @@
|
|
|
507
522
|
};
|
|
508
523
|
const applyPrivilegedActionsInDocument = doc => safe(() => {
|
|
509
524
|
if (!doc?.documentElement) return;
|
|
510
|
-
const admin = state.role === 'admin';
|
|
511
525
|
doc.querySelectorAll('[data-eos-privileged-action-hidden="1"]').forEach(element => {
|
|
512
|
-
if (
|
|
526
|
+
if (!isPrivilegedAction(element) || canUsePrivilegedAction(element)) setPrivilegedActionHidden(element, false);
|
|
513
527
|
});
|
|
514
528
|
for (const element of doc.querySelectorAll('a,button,[role="button"],[role="tab"],.MuiButtonBase-root')) {
|
|
515
|
-
if (isPrivilegedAction(element)) setPrivilegedActionHidden(element, !
|
|
529
|
+
if (isPrivilegedAction(element)) setPrivilegedActionHidden(element, !canUsePrivilegedAction(element));
|
|
516
530
|
}
|
|
517
531
|
if (!doc.documentElement.dataset.eosPrivilegedClickGuard) {
|
|
518
532
|
doc.documentElement.dataset.eosPrivilegedClickGuard = '1';
|
|
519
533
|
doc.addEventListener('click', event => {
|
|
520
|
-
if (state.role === '
|
|
534
|
+
if (state.role === 'unknown') return;
|
|
521
535
|
const target = event.target?.closest?.('a,button,[role="button"],[role="tab"],.MuiButtonBase-root');
|
|
522
|
-
if (!target || !isPrivilegedAction(target)) return;
|
|
536
|
+
if (!target || !isPrivilegedAction(target) || canUsePrivilegedAction(target)) return;
|
|
523
537
|
event.preventDefault();
|
|
524
538
|
event.stopImmediatePropagation();
|
|
525
539
|
}, true);
|
|
@@ -544,9 +558,9 @@
|
|
|
544
558
|
});
|
|
545
559
|
});
|
|
546
560
|
const scrubInheritedUiAdminSession = () => safe(() => {
|
|
547
|
-
if (state.role
|
|
561
|
+
if (state.role !== 'enduser') return;
|
|
548
562
|
const user = String(state.policy?.user || state.policy?.userId || '').replace(/^system\.user\./, '') || state.role;
|
|
549
|
-
const key = `eosUiAdminSessionScrubbed:
|
|
563
|
+
const key = `eosUiAdminSessionScrubbed:v7108:${user}:${state.role}`;
|
|
550
564
|
if (sessionStorage.getItem(key) === '1') return;
|
|
551
565
|
sessionStorage.setItem(key, '1');
|
|
552
566
|
const frame = document.createElement('iframe');
|
|
@@ -676,7 +690,7 @@
|
|
|
676
690
|
if (clickedButton && isExpertModeButton(clickedButton)) {
|
|
677
691
|
event.preventDefault(); event.stopImmediatePropagation(); lockExpertMode(); return;
|
|
678
692
|
}
|
|
679
|
-
if (clickedButton &&
|
|
693
|
+
if (clickedButton && isHeaderSystemSettingsButton(clickedButton)) {
|
|
680
694
|
event.preventDefault(); event.stopImmediatePropagation();
|
|
681
695
|
if (state.role === 'installer') window.NEXOWATT_EOS_BASIC_SETTINGS?.open?.();
|
|
682
696
|
return;
|
|
@@ -688,7 +702,7 @@
|
|
|
688
702
|
const target = event.target?.closest?.('[data-eos-admin-only-control="1"],[data-eos-system-settings-control="1"],[data-eos-role-tab],a[href*="#tab-"],a[href*="#/tab-"]');
|
|
689
703
|
if (!target) return;
|
|
690
704
|
if (target.matches('[data-eos-admin-only-control="1"]')) { event.preventDefault(); event.stopImmediatePropagation(); return; }
|
|
691
|
-
if (target
|
|
705
|
+
if (isHeaderSystemSettingsButton(target) && state.role === 'installer') {
|
|
692
706
|
event.preventDefault(); event.stopImmediatePropagation(); window.NEXOWATT_EOS_BASIC_SETTINGS?.open?.(); return;
|
|
693
707
|
}
|
|
694
708
|
const roleTab = target.getAttribute('data-eos-role-tab');
|
|
@@ -709,6 +723,8 @@
|
|
|
709
723
|
getRole: () => state.role,
|
|
710
724
|
getPolicy: () => state.policy,
|
|
711
725
|
isRouteAllowed,
|
|
726
|
+
isGloballyHiddenTab,
|
|
727
|
+
isHeaderSystemSettingsButton,
|
|
712
728
|
defaultTab,
|
|
713
729
|
isOfficialReserveTab,
|
|
714
730
|
isCustomerBackupTab,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const VERSION = '
|
|
4
|
+
const VERSION = 'v7108-nexowatt-native-shell-modern-core-surfaces';
|
|
5
5
|
const previous = window.NEXOWATT_NATIVE_SHELL;
|
|
6
6
|
if (previous?.version === VERSION) return;
|
|
7
7
|
previous?.destroy?.();
|
|
@@ -25,7 +25,27 @@
|
|
|
25
25
|
const safe = fn => {
|
|
26
26
|
try { return fn(); } catch (_) { return undefined; }
|
|
27
27
|
};
|
|
28
|
-
|
|
28
|
+
const escapeHtml = value => String(value ?? '').replace(/[&<>"']/g, match => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[match] || match));
|
|
29
|
+
const TECHNICAL_SURFACES = Object.freeze({
|
|
30
|
+
instances: {
|
|
31
|
+
eyebrow: 'EOS SYSTEMDIENSTE',
|
|
32
|
+
title: 'Dienste & Instanzen',
|
|
33
|
+
text: 'Laufzeit, Status, Ressourcen und Konfiguration aller aktiven EOS-Dienste auf einen Blick.',
|
|
34
|
+
icon: '<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="4" y="4" width="16" height="6" rx="2"/><rect x="4" y="14" width="16" height="6" rx="2"/><path d="M8 7h.01M8 17h.01M12 7h5M12 17h5"/></svg>',
|
|
35
|
+
},
|
|
36
|
+
objects: {
|
|
37
|
+
eyebrow: 'EOS DATENEBENE',
|
|
38
|
+
title: 'Datenpunkte & Zustände',
|
|
39
|
+
text: 'Messwerte, Status und freigegebene Steuerwerte in einer klaren technischen Ansicht.',
|
|
40
|
+
icon: '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="6" cy="12" r="2.5"/><circle cx="18" cy="6" r="2.5"/><circle cx="18" cy="18" r="2.5"/><path d="M8.3 10.9 15.7 7M8.3 13.1l7.4 3.9"/></svg>',
|
|
41
|
+
},
|
|
42
|
+
logs: {
|
|
43
|
+
eyebrow: 'EOS DIAGNOSE',
|
|
44
|
+
title: 'Systemlogs',
|
|
45
|
+
text: 'Live-Protokoll für Adapter, Dienste und Systemereignisse mit klarer Priorisierung.',
|
|
46
|
+
icon: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 5h14M5 10h14M5 15h9M5 20h6"/><circle cx="18" cy="17" r="3"/><path d="m20.2 19.2 1.8 1.8"/></svg>',
|
|
47
|
+
},
|
|
48
|
+
});
|
|
29
49
|
|
|
30
50
|
// Navigation labels and icons are rendered natively by Drawer.tsx.
|
|
31
51
|
// This runtime only positions the shell and never rewrites React content.
|
|
@@ -177,6 +197,85 @@
|
|
|
177
197
|
<div class="eos-overview-role" data-nexowatt-overview-role="${role}"><span class="eos-overview-status-dot"></span>${config.label}</div>`;
|
|
178
198
|
};
|
|
179
199
|
|
|
200
|
+
const roleLabel = () => {
|
|
201
|
+
const role = String(window.NEXOWATT_EOS_ACCESS_ROLE || 'unknown').toLowerCase();
|
|
202
|
+
if (role === 'admin') return 'Admin / Service';
|
|
203
|
+
if (role === 'installer' || role === 'installateur') return 'Installateur';
|
|
204
|
+
return 'Endkunde';
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const classifyTechnicalRows = (paper, surface) => {
|
|
208
|
+
if (!paper || !surface) return;
|
|
209
|
+
if (surface === 'instances') {
|
|
210
|
+
paper.querySelectorAll('.MuiAccordion-root,tbody tr,.MuiTableRow-root,[role="row"]').forEach(row => {
|
|
211
|
+
if (row.closest?.('.eos-technical-surface-header') || row.classList.contains('MuiTableHead-root')) return;
|
|
212
|
+
row.classList.add('eos-service-row');
|
|
213
|
+
const expanded = row.classList.contains('Mui-expanded') || !!row.querySelector?.('[aria-expanded="true"]');
|
|
214
|
+
row.classList.toggle('eos-service-row-expanded', expanded);
|
|
215
|
+
});
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (surface === 'objects') {
|
|
219
|
+
paper.querySelectorAll('[role="row"],.MuiTableRow-root,.MuiDataGrid-row').forEach(row => {
|
|
220
|
+
if (row.closest?.('.eos-technical-surface-header')) return;
|
|
221
|
+
row.classList.add('eos-datapoint-row');
|
|
222
|
+
});
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (surface === 'logs') {
|
|
226
|
+
paper.querySelectorAll('tbody tr,.MuiTableRow-root,[role="row"]').forEach(row => {
|
|
227
|
+
if (row.closest?.('.eos-technical-surface-header')) return;
|
|
228
|
+
const text = String(row.textContent || '').toLowerCase();
|
|
229
|
+
let level = 'info';
|
|
230
|
+
if (/\b(error|fatal|fehler|kritisch|critical)\b/.test(text)) level = 'error';
|
|
231
|
+
else if (/\b(warn|warning|warnung)\b/.test(text)) level = 'warn';
|
|
232
|
+
else if (/\b(debug|trace)\b/.test(text)) level = 'debug';
|
|
233
|
+
row.classList.remove('eos-log-row-error','eos-log-row-warn','eos-log-row-info','eos-log-row-debug');
|
|
234
|
+
row.classList.add('eos-log-row', `eos-log-row-${level}`);
|
|
235
|
+
row.dataset.eosLogLevel = level;
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const ensureTechnicalSurface = () => {
|
|
241
|
+
const paper = document.getElementById('app-paper');
|
|
242
|
+
if (!paper || isLogin()) return;
|
|
243
|
+
const surface = routeKey(currentTab());
|
|
244
|
+
const config = TECHNICAL_SURFACES[surface];
|
|
245
|
+
const existing = document.getElementById('eos-technical-surface-header');
|
|
246
|
+
if (!config) {
|
|
247
|
+
existing?.remove();
|
|
248
|
+
paper.removeAttribute('data-eos-technical-surface');
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
paper.setAttribute('data-eos-technical-surface', surface);
|
|
252
|
+
let header = existing;
|
|
253
|
+
if (!header) {
|
|
254
|
+
header = document.createElement('section');
|
|
255
|
+
header.id = 'eos-technical-surface-header';
|
|
256
|
+
header.className = 'eos-technical-surface-header';
|
|
257
|
+
header.setAttribute('aria-live', 'polite');
|
|
258
|
+
paper.insertBefore(header, paper.firstChild || null);
|
|
259
|
+
}
|
|
260
|
+
if (header.dataset.eosSurface !== surface || header.dataset.eosRole !== roleLabel()) {
|
|
261
|
+
header.dataset.eosSurface = surface;
|
|
262
|
+
header.dataset.eosRole = roleLabel();
|
|
263
|
+
header.innerHTML = `
|
|
264
|
+
<div class="eos-technical-surface-icon">${config.icon}</div>
|
|
265
|
+
<div class="eos-technical-surface-copy">
|
|
266
|
+
<span>${escapeHtml(config.eyebrow)}</span>
|
|
267
|
+
<h1>${escapeHtml(config.title)}</h1>
|
|
268
|
+
<p>${escapeHtml(config.text)}</p>
|
|
269
|
+
</div>
|
|
270
|
+
<div class="eos-technical-surface-meta">
|
|
271
|
+
<i aria-hidden="true"></i>
|
|
272
|
+
<strong>${escapeHtml(roleLabel())}</strong>
|
|
273
|
+
<small>${surface === 'logs' ? 'Live-Diagnose' : surface === 'instances' ? 'Betriebsbereit' : 'Zentrale Datenansicht'}</small>
|
|
274
|
+
</div>`;
|
|
275
|
+
}
|
|
276
|
+
classifyTechnicalRows(paper, surface);
|
|
277
|
+
};
|
|
278
|
+
|
|
180
279
|
const apply = () => {
|
|
181
280
|
if (destroyed) return;
|
|
182
281
|
setShellClasses();
|
|
@@ -184,8 +283,10 @@
|
|
|
184
283
|
ensureBrand();
|
|
185
284
|
ensureNavigationContainer();
|
|
186
285
|
ensureModernOverview();
|
|
286
|
+
ensureTechnicalSurface();
|
|
187
287
|
} else {
|
|
188
288
|
document.getElementById('eos-native-overview-hero')?.remove();
|
|
289
|
+
document.getElementById('eos-technical-surface-header')?.remove();
|
|
189
290
|
}
|
|
190
291
|
};
|
|
191
292
|
|
|
@@ -231,6 +332,7 @@
|
|
|
231
332
|
unsubscribeDom = null;
|
|
232
333
|
if (retryTimer) clearTimeout(retryTimer);
|
|
233
334
|
retryTimer = 0;
|
|
335
|
+
document.getElementById('eos-technical-surface-header')?.remove();
|
|
234
336
|
},
|
|
235
337
|
};
|
|
236
338
|
})();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
|
-
const VERSION = '
|
|
3
|
+
const VERSION = 'v7108-scroll-standard-password';
|
|
4
4
|
const ensureScroll = () => {
|
|
5
5
|
const root = document.documentElement;
|
|
6
6
|
const paper = document.getElementById('app-paper');
|
|
@@ -23,5 +23,5 @@
|
|
|
23
23
|
const schedule=()=>{if(scheduled)return;scheduled=true;requestAnimationFrame(()=>{scheduled=false;apply();});};
|
|
24
24
|
const start=()=>{apply();new MutationObserver(schedule).observe(document.documentElement,{subtree:true,childList:true});window.addEventListener('hashchange',schedule);window.addEventListener('resize',schedule,{passive:true});};
|
|
25
25
|
document.readyState==='loading'?document.addEventListener('DOMContentLoaded',start,{once:true}):start();
|
|
26
|
-
window.
|
|
26
|
+
window.NEXOWATT_EOS_STABLE_V7108=Object.freeze({version:VERSION,refresh:apply,ensureScroll});
|
|
27
27
|
})();
|
package/build/lib/web.js
CHANGED
|
@@ -650,6 +650,9 @@ class Web {
|
|
|
650
650
|
objectDiagnostics: technical,
|
|
651
651
|
logDiagnostics: technical,
|
|
652
652
|
basicSystemSettings: technical,
|
|
653
|
+
emsAppCenter: technical,
|
|
654
|
+
simulation: role === 'admin',
|
|
655
|
+
licenseAdministration: role === 'admin',
|
|
653
656
|
fullSystemSettings: role === 'admin',
|
|
654
657
|
expertMode: role === 'admin',
|
|
655
658
|
userManagement: role === 'admin',
|
package/io-package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "eos-admin",
|
|
4
|
-
"version": "7.10.
|
|
4
|
+
"version": "7.10.8",
|
|
5
5
|
"titleLang": {
|
|
6
6
|
"en": "NexoWatt EOS Admin",
|
|
7
7
|
"de": "NexoWatt EOS Admin",
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
"connectionType": "local",
|
|
19
19
|
"dataSource": "push",
|
|
20
20
|
"news": {
|
|
21
|
+
"7.10.7": {
|
|
22
|
+
"de": "Stable 7.10.7 gibt dem Installateur den Zugriff auf „EMS Apps öffnen“ und das EMS App-Center frei. Simulation und Lizenzverwaltung bleiben ausschließlich dem Administrator vorbehalten. Endkundenbereich, Nur-Lese-Datenpunkte und Adminrechte bleiben unverändert.",
|
|
23
|
+
"en": "Stable 7.10.7 grants the Installer access to “Open EMS Apps” and the EMS App-Center. Simulation and license administration remain Administrator-only. End User read-only datapoints and all Administrator rights remain unchanged.",
|
|
24
|
+
"nl": "Stable 7.10.7 geeft de installateur toegang tot “EMS Apps openen” en het EMS App-Center. Simulatie en licentiebeheer blijven uitsluitend voor beheerders. Alleen-lezen datapunten voor eindgebruikers en alle beheerdersrechten blijven ongewijzigd."
|
|
25
|
+
},
|
|
21
26
|
"7.10.6": {
|
|
22
27
|
"de": "Stable 7.10.6 bereinigt ausschließlich den Endkundenbereich: Datenpunkte bleiben sichtbar und nur lesbar, Bearbeiten-/Löschen-/Einstellungsaktionen werden ausgeblendet, und die Systeminfokarte erhält Plattform, RAM, Node.js und NPM über einen authentifizierten Nur-Lese-Endpunkt. Die Administratoroberfläche und sämtliche Adminrechte bleiben unverändert.",
|
|
23
28
|
"en": "Stable 7.10.6 cleans up the End User area only: datapoints stay visible and read-only, edit/delete/settings actions are hidden, and the system information card receives platform, RAM, Node.js and NPM through an authenticated read-only endpoint. The administrator UI and all Admin rights remain unchanged.",
|
|
@@ -359,7 +364,7 @@
|
|
|
359
364
|
"icon": "admin.svg",
|
|
360
365
|
"messagebox": true,
|
|
361
366
|
"enabled": true,
|
|
362
|
-
"extIcon": "https://unpkg.com/iobroker.eos-admin@7.10.
|
|
367
|
+
"extIcon": "https://unpkg.com/iobroker.eos-admin@7.10.8/admin/admin.svg",
|
|
363
368
|
"keywords": [
|
|
364
369
|
"NexoWatt",
|
|
365
370
|
"EOS",
|
|
@@ -370,7 +375,7 @@
|
|
|
370
375
|
"licensed"
|
|
371
376
|
],
|
|
372
377
|
"compact": true,
|
|
373
|
-
"readme": "https://unpkg.com/iobroker.eos-admin@7.10.
|
|
378
|
+
"readme": "https://unpkg.com/iobroker.eos-admin@7.10.8/README.md",
|
|
374
379
|
"authors": [
|
|
375
380
|
"NexoWatt"
|
|
376
381
|
],
|
|
@@ -438,7 +443,7 @@
|
|
|
438
443
|
"nondeletable": false,
|
|
439
444
|
"allowAdapterUpdate": true,
|
|
440
445
|
"allowAdapterDelete": false,
|
|
441
|
-
"meta": "https://unpkg.com/iobroker.eos-admin@7.10.
|
|
446
|
+
"meta": "https://unpkg.com/iobroker.eos-admin@7.10.8/io-package.json",
|
|
442
447
|
"npmPackage": "iobroker.eos-admin",
|
|
443
448
|
"packetName": "iobroker.eos-admin",
|
|
444
449
|
"publisher": "NexoWatt"
|
|
@@ -1215,5 +1220,5 @@
|
|
|
1215
1220
|
}
|
|
1216
1221
|
}
|
|
1217
1222
|
},
|
|
1218
|
-
"version": "7.10.
|
|
1223
|
+
"version": "7.10.8"
|
|
1219
1224
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.eos-admin",
|
|
3
3
|
"description": "NexoWatt EOS Admin – repaired stable baseline with restart-safe automatic updates, native account passwords and persistent cockpit scrolling.",
|
|
4
|
-
"version": "7.10.
|
|
4
|
+
"version": "7.10.8",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"bluefox <dogafox@gmail.com>",
|
|
7
7
|
"apollon77",
|
|
@@ -133,16 +133,18 @@
|
|
|
133
133
|
"NEXOWATT_EOS_PREBUILT_MANIFEST.json",
|
|
134
134
|
"tools/nexowatt-prebuilt-release-selftest.cjs",
|
|
135
135
|
"tools/nexowatt-stable-v7103-selftest.cjs",
|
|
136
|
-
"README_STABILITY_V7.10.
|
|
137
|
-
"RELEASE_NOTES_V7.10.
|
|
138
|
-
"PUBLISH_STABLE_V7.10.
|
|
139
|
-
"INSTALL_TEST_V7.10.
|
|
140
|
-
"RELEASE_ACCEPTANCE_V7.10.
|
|
141
|
-
"MERGE_UPDATE_README_V7.10.
|
|
136
|
+
"README_STABILITY_V7.10.7.md",
|
|
137
|
+
"RELEASE_NOTES_V7.10.7.md",
|
|
138
|
+
"PUBLISH_STABLE_V7.10.7.md",
|
|
139
|
+
"INSTALL_TEST_V7.10.7.md",
|
|
140
|
+
"RELEASE_ACCEPTANCE_V7.10.7.md",
|
|
141
|
+
"MERGE_UPDATE_README_V7.10.7.md",
|
|
142
142
|
"tools/nexowatt-auto-update-placement-selftest.cjs",
|
|
143
143
|
"tools/nexowatt-role-security-selftest.cjs",
|
|
144
|
-
"SECURITY_ROLE_MATRIX_V7.10.
|
|
145
|
-
"tools/nexowatt-user-area-selftest.cjs"
|
|
144
|
+
"SECURITY_ROLE_MATRIX_V7.10.7.md",
|
|
145
|
+
"tools/nexowatt-user-area-selftest.cjs",
|
|
146
|
+
"tools/nexowatt-installer-ems-selftest.cjs",
|
|
147
|
+
"tools/nexowatt-v7108-ui-foundation-selftest.cjs"
|
|
146
148
|
],
|
|
147
149
|
"scripts": {
|
|
148
150
|
"npm": "npm i -f && cd src-admin && npm i -f",
|
|
@@ -177,7 +179,7 @@
|
|
|
177
179
|
"nexowatt:repo-entry": "node tools/nexowatt-generate-repo-entry.cjs",
|
|
178
180
|
"nexowatt:patch-repo": "node tools/nexowatt-patch-repo.cjs",
|
|
179
181
|
"nexowatt:repair-update": "node tools/nexowatt-repair-eos-admin-update.cjs",
|
|
180
|
-
"check:eos-stability": "node tools/nexowatt-stability-check.cjs && node tools/nexowatt-esm-syntax-selftest.cjs && node tools/nexowatt-backend-runtime-selftest.cjs && node tools/nexowatt-prebuilt-release-selftest.cjs && node tools/nexowatt-import-integrity-selftest.cjs && node tools/nexowatt-entrypoint-smoke-selftest.cjs && node tools/nexowatt-frontend-graph-check.cjs && node tools/nexowatt-policy-selftest.cjs && node tools/nexowatt-publish-channel-selftest.cjs && node tools/nexowatt-release-defaults-selftest.cjs && node tools/nexowatt-role-access-selftest.cjs && node tools/nexowatt-internal-reserve-selftest.cjs && node tools/nexowatt-modern-ui-selftest.cjs && node tools/nexowatt-login-layout-selftest.cjs && node tools/nexowatt-branding-selftest.cjs && node tools/nexowatt-default-port-selftest.cjs && node tools/nexowatt-module-popup-selftest.cjs && node tools/nexowatt-datapoint-selftest.cjs && node tools/nexowatt-update-selftest.cjs && node tools/nexowatt-datapoint-interaction-selftest.cjs && node tools/nexowatt-manual-write-policy-selftest.cjs && node tools/nexowatt-value-column-selftest.cjs && node tools/nexowatt-native-shell-selftest.cjs && node tools/nexowatt-assistant-separation-selftest.cjs && node tools/nexowatt-runtime-cleanup-selftest.cjs && node tools/nexowatt-version-sync-selftest.cjs && node tools/nexowatt-merge-update-selftest.cjs && node tools/nexowatt-password-write-selftest.cjs && node tools/nexowatt-account-password-flow-selftest.cjs && npm run check:eos-stable-v7103 && node tools/nexowatt-ems-overview-selftest.cjs && node tools/nexowatt-ui-overview-runtime-selftest.cjs && node tools/nexowatt-auto-update-selftest.cjs && node tools/nexowatt-auto-update-placement-selftest.cjs && node tools/nexowatt-role-security-selftest.cjs && node tools/nexowatt-user-area-selftest.cjs",
|
|
182
|
+
"check:eos-stability": "node tools/nexowatt-stability-check.cjs && node tools/nexowatt-esm-syntax-selftest.cjs && node tools/nexowatt-backend-runtime-selftest.cjs && node tools/nexowatt-prebuilt-release-selftest.cjs && node tools/nexowatt-import-integrity-selftest.cjs && node tools/nexowatt-entrypoint-smoke-selftest.cjs && node tools/nexowatt-frontend-graph-check.cjs && node tools/nexowatt-policy-selftest.cjs && node tools/nexowatt-publish-channel-selftest.cjs && node tools/nexowatt-release-defaults-selftest.cjs && node tools/nexowatt-role-access-selftest.cjs && node tools/nexowatt-internal-reserve-selftest.cjs && node tools/nexowatt-modern-ui-selftest.cjs && node tools/nexowatt-login-layout-selftest.cjs && node tools/nexowatt-branding-selftest.cjs && node tools/nexowatt-default-port-selftest.cjs && node tools/nexowatt-module-popup-selftest.cjs && node tools/nexowatt-datapoint-selftest.cjs && node tools/nexowatt-update-selftest.cjs && node tools/nexowatt-datapoint-interaction-selftest.cjs && node tools/nexowatt-manual-write-policy-selftest.cjs && node tools/nexowatt-value-column-selftest.cjs && node tools/nexowatt-native-shell-selftest.cjs && node tools/nexowatt-assistant-separation-selftest.cjs && node tools/nexowatt-runtime-cleanup-selftest.cjs && node tools/nexowatt-version-sync-selftest.cjs && node tools/nexowatt-merge-update-selftest.cjs && node tools/nexowatt-password-write-selftest.cjs && node tools/nexowatt-account-password-flow-selftest.cjs && npm run check:eos-stable-v7103 && node tools/nexowatt-ems-overview-selftest.cjs && node tools/nexowatt-ui-overview-runtime-selftest.cjs && node tools/nexowatt-auto-update-selftest.cjs && node tools/nexowatt-auto-update-placement-selftest.cjs && node tools/nexowatt-role-security-selftest.cjs && node tools/nexowatt-user-area-selftest.cjs && node tools/nexowatt-installer-ems-selftest.cjs && node tools/nexowatt-v7108-ui-foundation-selftest.cjs",
|
|
181
183
|
"nexowatt:patch-built-frontend": "node tools/nexowatt-patch-built-frontend.cjs",
|
|
182
184
|
"clean:eos-runtime": "node tools/nexowatt-clean-legacy-runtime.cjs",
|
|
183
185
|
"precheck:eos-package": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime",
|
|
@@ -206,7 +208,9 @@
|
|
|
206
208
|
"seal:eos-prebuilt-release": "node tools/nexowatt-prebuilt-release-selftest.cjs --write",
|
|
207
209
|
"check:eos-stable-v7103": "node tools/nexowatt-stable-v7103-selftest.cjs",
|
|
208
210
|
"test:eos-auto-update-placement": "node tools/nexowatt-auto-update-placement-selftest.cjs",
|
|
209
|
-
"check:eos-role-security": "node tools/nexowatt-role-security-selftest.cjs"
|
|
211
|
+
"check:eos-role-security": "node tools/nexowatt-role-security-selftest.cjs",
|
|
212
|
+
"test:eos-installer-ems": "node tools/nexowatt-installer-ems-selftest.cjs",
|
|
213
|
+
"check:eos-v7108-ui": "node tools/nexowatt-v7108-ui-foundation-selftest.cjs"
|
|
210
214
|
},
|
|
211
215
|
"author": "NexoWatt",
|
|
212
216
|
"private": false,
|
|
@@ -217,7 +221,7 @@
|
|
|
217
221
|
},
|
|
218
222
|
"nexowattReleasePolicy": {
|
|
219
223
|
"distTag": "latest",
|
|
220
|
-
"purpose": "
|
|
224
|
+
"purpose": "stable NexoWatt EOS Admin 7.10.8 modern core surfaces and installer service controls"
|
|
221
225
|
},
|
|
222
226
|
"publisher": "NexoWatt"
|
|
223
227
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const assert = require('node:assert/strict');
|
|
5
|
+
const fs = require('node:fs');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
|
|
8
|
+
const root = path.resolve(__dirname, '..');
|
|
9
|
+
const read = file => fs.readFileSync(path.join(root, file), 'utf8');
|
|
10
|
+
const json = file => JSON.parse(read(file));
|
|
11
|
+
|
|
12
|
+
const pkg = json('package.json');
|
|
13
|
+
const sourceRole = read('src-admin/public/js/eos-role-ui.js');
|
|
14
|
+
const runtimeRole = read('adminWww/js/eos-role-ui.js');
|
|
15
|
+
const sourceWeb = read('src/lib/web.ts');
|
|
16
|
+
const runtimeWeb = read('build/lib/web.js');
|
|
17
|
+
|
|
18
|
+
assert.equal(pkg.version, '7.10.8', 'Installer EMS release must use npm version 7.10.8');
|
|
19
|
+
assert.equal(runtimeRole, sourceRole, 'built and source role runtimes must be identical');
|
|
20
|
+
|
|
21
|
+
for (const code of [sourceRole, runtimeRole]) {
|
|
22
|
+
assert.match(code, /const privilegedActionKind = element =>/, 'privileged action classifier missing');
|
|
23
|
+
assert.match(code, /return 'ems';/, 'EMS action classification missing');
|
|
24
|
+
assert.match(code, /return 'simulation';/, 'Simulation action classification missing');
|
|
25
|
+
assert.match(code, /return 'license';/, 'License action classification missing');
|
|
26
|
+
assert.match(code, /action === 'ems'/, 'EMS-specific access branch missing');
|
|
27
|
+
assert.match(
|
|
28
|
+
code,
|
|
29
|
+
/state\.role === 'installer' && state\.policy\?\.capabilities\?\.emsAppCenter !== false/,
|
|
30
|
+
'Installer is not allowed to open EMS App-Center',
|
|
31
|
+
);
|
|
32
|
+
assert.match(code, /return state\.role === 'admin';/, 'Simulation and License must remain Admin-only');
|
|
33
|
+
assert.match(code, /!canUsePrivilegedAction\(element\)/, 'UI visibility does not use the role-aware action permission');
|
|
34
|
+
assert.match(code, /\|\| canUsePrivilegedAction\(target\)\) return;/, 'click guard does not use the role-aware action permission');
|
|
35
|
+
assert.match(code, /if \(state\.role !== 'enduser'\) return;/, 'port 8188 session scrubbing must apply only to End User');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
for (const code of [sourceWeb, runtimeWeb]) {
|
|
39
|
+
assert.match(code, /emsAppCenter: technical/, 'backend capability must grant EMS App-Center to Admin and Installer');
|
|
40
|
+
assert.match(code, /simulation: role === 'admin'/, 'Simulation capability must remain Admin-only');
|
|
41
|
+
assert.match(code, /licenseAdministration: role === 'admin'/, 'License capability must remain Admin-only');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
console.log('[NexoWatt EOS installer EMS] OK (Installer may use EMS App-Center; Simulation/License remain Admin-only; End User remains blocked)');
|
|
@@ -16,7 +16,7 @@ for (const file of [
|
|
|
16
16
|
'MERGE_UPDATE.ps1',
|
|
17
17
|
'MERGE_UPDATE.cmd',
|
|
18
18
|
'MERGE_UPDATE.sh',
|
|
19
|
-
'MERGE_UPDATE_README_V7.10.
|
|
19
|
+
'MERGE_UPDATE_README_V7.10.7.md',
|
|
20
20
|
'tools/nexowatt-apply-ems-overview.cjs',
|
|
21
21
|
'tools/nexowatt-sync-release-version.cjs',
|
|
22
22
|
'tools/nexowatt-version-sync-selftest.cjs',
|