iobroker.eos-admin 7.9.26 → 7.9.28
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/README.md +37 -3
- package/admin/jsonConfig.json5 +1 -1
- package/adminWww/assets/Adapters-B5_jQ7DE.js +2 -2
- package/adminWww/assets/bootstrap-COulQZax.js +1 -1
- package/adminWww/css/eos-branding.css +199 -0
- package/adminWww/index.html +4 -3
- package/adminWww/js/eos-assistant.js +203 -0
- package/adminWww/js/eos-branding.js +136 -1
- package/adminWww/js/eos-security-ui.js +1 -1
- package/build/main.js +5 -10
- package/docs/NEXOWATT_EOS_UI_V28_UPDATE_FIX_DE.md +43 -0
- package/io-package.json +884 -876
- package/package.json +5 -4
- package/tools/nexowatt-generate-eos-admin-repo-entry.cjs +21 -2
- package/tools/nexowatt-generate-repo-entry.cjs +1 -31
- package/tools/nexowatt-patch-repo.cjs +31 -8
- package/tools/nexowatt-repair-eos-admin-update.cjs +15 -0
- package/tools/nexowatt-validate-package.cjs +3 -0
|
@@ -2448,3 +2448,202 @@ html.eos-app .MuiAppBar-root .MuiToolbar-root img[alt*="user" i] {
|
|
|
2448
2448
|
}
|
|
2449
2449
|
}
|
|
2450
2450
|
|
|
2451
|
+
|
|
2452
|
+
/* === NexoWatt EOS v27: logo contrast, compact nav, EOS Assist ============
|
|
2453
|
+
Der Pfeil ist kein Voll-Schließen mehr: er schaltet nur zwischen normaler
|
|
2454
|
+
und kompakter Navigationsstufe um. Das Logo bekommt einen schwarzen Grund,
|
|
2455
|
+
damit das NexoWatt-Zeichen sauberer und hochwertiger wirkt. */
|
|
2456
|
+
html.eos-app .eos-brand-badge {
|
|
2457
|
+
grid-template-columns: 78px minmax(170px, 1fr) 12px !important;
|
|
2458
|
+
padding-left: 6px !important;
|
|
2459
|
+
background:
|
|
2460
|
+
radial-gradient(circle at 38px 29px, rgba(0, 255, 136, 0.18), transparent 44px),
|
|
2461
|
+
linear-gradient(135deg, rgba(4, 18, 26, 0.98), rgba(0, 7, 12, 0.84) 52%, rgba(0, 32, 26, 0.50)) !important;
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
html.eos-app .eos-brand-badge-mark {
|
|
2465
|
+
background:
|
|
2466
|
+
radial-gradient(circle at 50% 44%, rgba(0, 255, 136, 0.16), rgba(0, 0, 0, 0.96) 58%, #000000 100%) !important;
|
|
2467
|
+
border-color: rgba(126, 255, 216, 0.84) !important;
|
|
2468
|
+
box-shadow:
|
|
2469
|
+
inset 0 0 0 1px rgba(255, 255, 255, 0.05),
|
|
2470
|
+
inset 0 0 20px rgba(0, 255, 136, 0.18),
|
|
2471
|
+
0 0 0 1px rgba(0, 0, 0, 0.55),
|
|
2472
|
+
0 0 20px rgba(0, 255, 136, 0.62),
|
|
2473
|
+
0 0 40px rgba(0, 212, 255, 0.20) !important;
|
|
2474
|
+
transform: translateY(-5px) !important;
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2477
|
+
html.eos-app .eos-brand-badge-logo {
|
|
2478
|
+
filter:
|
|
2479
|
+
brightness(2.35)
|
|
2480
|
+
contrast(1.22)
|
|
2481
|
+
saturate(1.48)
|
|
2482
|
+
drop-shadow(0 0 1px rgba(255, 255, 255, 0.95))
|
|
2483
|
+
drop-shadow(0 0 11px rgba(0, 255, 136, 0.82))
|
|
2484
|
+
drop-shadow(0 0 22px rgba(0, 212, 255, 0.28)) !important;
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
/* Drawer/rail stays visible. The native arrow becomes a compact-mode toggle. */
|
|
2488
|
+
html.eos-app .MuiDrawer-paper,
|
|
2489
|
+
html.eos-app .eos-drawer {
|
|
2490
|
+
transform: none !important;
|
|
2491
|
+
visibility: visible !important;
|
|
2492
|
+
opacity: 1 !important;
|
|
2493
|
+
display: flex !important;
|
|
2494
|
+
padding-left: 86px !important;
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
html.eos-app .eos-native-drawer-header {
|
|
2498
|
+
position: absolute !important;
|
|
2499
|
+
left: 12px !important;
|
|
2500
|
+
top: 8px !important;
|
|
2501
|
+
flex: 0 0 58px !important;
|
|
2502
|
+
width: 58px !important;
|
|
2503
|
+
min-width: 58px !important;
|
|
2504
|
+
max-width: 58px !important;
|
|
2505
|
+
height: 56px !important;
|
|
2506
|
+
min-height: 56px !important;
|
|
2507
|
+
margin: 0 !important;
|
|
2508
|
+
z-index: 4 !important;
|
|
2509
|
+
background: rgba(0, 0, 0, 0.38) !important;
|
|
2510
|
+
border-color: rgba(0, 255, 136, 0.38) !important;
|
|
2511
|
+
box-shadow: inset 0 0 16px rgba(0, 255, 136, 0.10), 0 0 20px rgba(0, 255, 136, 0.10) !important;
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
html.eos-app .eos-native-drawer-header > div:first-child {
|
|
2515
|
+
width: 58px !important;
|
|
2516
|
+
min-width: 58px !important;
|
|
2517
|
+
max-width: 58px !important;
|
|
2518
|
+
padding: 4px 6px !important;
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
html.eos-app .eos-native-drawer-header button.eos-nav-compact-toggle,
|
|
2522
|
+
html.eos-app .eos-native-drawer-header .eos-nav-compact-toggle {
|
|
2523
|
+
width: 46px !important;
|
|
2524
|
+
height: 46px !important;
|
|
2525
|
+
min-width: 46px !important;
|
|
2526
|
+
min-height: 46px !important;
|
|
2527
|
+
border-radius: 16px !important;
|
|
2528
|
+
background:
|
|
2529
|
+
radial-gradient(circle at 50% 50%, rgba(0, 255, 136, 0.18), rgba(0, 0, 0, 0.72)) !important;
|
|
2530
|
+
border: 1px solid rgba(0, 255, 136, 0.44) !important;
|
|
2531
|
+
box-shadow: 0 0 16px rgba(0, 255, 136, 0.18) !important;
|
|
2532
|
+
}
|
|
2533
|
+
|
|
2534
|
+
html.eos-app.eos-nav-compact .eos-native-drawer-header .eos-nav-compact-toggle svg,
|
|
2535
|
+
html.eos-app.eos-nav-compact .eos-native-drawer-header button.eos-nav-compact-toggle svg {
|
|
2536
|
+
transform: rotate(180deg) !important;
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
html.eos-app .eos-scroll-nav,
|
|
2540
|
+
html.eos-app .MuiDrawer-paper .MuiList-root {
|
|
2541
|
+
margin-left: 0 !important;
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
html.eos-app.eos-nav-compact .MuiDrawer-paper .MuiListItemButton-root,
|
|
2545
|
+
html.eos-app.eos-nav-compact .MuiDrawer-paper .MuiButtonBase-root.MuiListItemButton-root {
|
|
2546
|
+
width: 58px !important;
|
|
2547
|
+
min-width: 58px !important;
|
|
2548
|
+
max-width: 58px !important;
|
|
2549
|
+
padding: 0 !important;
|
|
2550
|
+
justify-content: center !important;
|
|
2551
|
+
gap: 0 !important;
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
html.eos-app.eos-nav-compact .MuiDrawer-paper .MuiListItemText-root,
|
|
2555
|
+
html.eos-app.eos-nav-compact .MuiDrawer-paper .MuiListItemButton-root .MuiTypography-root,
|
|
2556
|
+
html.eos-app.eos-nav-compact .MuiDrawer-paper .MuiButtonBase-root.MuiListItemButton-root .MuiTypography-root {
|
|
2557
|
+
display: none !important;
|
|
2558
|
+
max-width: 0 !important;
|
|
2559
|
+
opacity: 0 !important;
|
|
2560
|
+
overflow: hidden !important;
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
html.eos-app.eos-nav-compact .MuiDrawer-paper .MuiListItemIcon-root {
|
|
2564
|
+
min-width: 0 !important;
|
|
2565
|
+
margin: 0 !important;
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
html.eos-app.eos-nav-compact .MuiDrawer-paper .MuiBadge-root .MuiBadge-badge {
|
|
2569
|
+
transform: scale(0.88) translate(42%, -42%) !important;
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2572
|
+
/* EOS Assist: leichte Bedienhilfe als Vorbereitung für eine spätere echte KI. */
|
|
2573
|
+
.eos-assist-root {
|
|
2574
|
+
position: fixed !important;
|
|
2575
|
+
right: 26px !important;
|
|
2576
|
+
bottom: 24px !important;
|
|
2577
|
+
z-index: 1700 !important;
|
|
2578
|
+
font-family: inherit !important;
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2581
|
+
.eos-assist-button {
|
|
2582
|
+
display: grid !important;
|
|
2583
|
+
grid-template-columns: 12px auto !important;
|
|
2584
|
+
grid-template-rows: auto auto !important;
|
|
2585
|
+
column-gap: 8px !important;
|
|
2586
|
+
align-items: center !important;
|
|
2587
|
+
min-width: 156px !important;
|
|
2588
|
+
padding: 10px 14px !important;
|
|
2589
|
+
border-radius: 18px !important;
|
|
2590
|
+
border: 1px solid rgba(0, 255, 136, 0.44) !important;
|
|
2591
|
+
background: linear-gradient(135deg, rgba(0, 255, 136, 0.19), rgba(0, 212, 255, 0.10) 62%, rgba(0, 0, 0, 0.64)) !important;
|
|
2592
|
+
color: #f3fffb !important;
|
|
2593
|
+
box-shadow: 0 14px 32px rgba(0, 0, 0, 0.38), 0 0 24px rgba(0, 255, 136, 0.18) !important;
|
|
2594
|
+
cursor: pointer !important;
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
.eos-assist-button strong { grid-column: 2; font-weight: 900; font-size: 13px; line-height: 1; }
|
|
2598
|
+
.eos-assist-button small { grid-column: 2; color: rgba(226, 255, 247, .72); font-size: 10px; line-height: 1.1; }
|
|
2599
|
+
.eos-assist-dot { grid-row: 1 / span 2; width: 10px; height: 10px; border-radius: 999px; background: #16ff98; box-shadow: 0 0 12px rgba(0, 255, 136, .9); }
|
|
2600
|
+
|
|
2601
|
+
.eos-assist-panel {
|
|
2602
|
+
position: absolute !important;
|
|
2603
|
+
right: 0 !important;
|
|
2604
|
+
bottom: calc(100% + 12px) !important;
|
|
2605
|
+
width: min(420px, calc(100vw - 36px)) !important;
|
|
2606
|
+
padding: 16px !important;
|
|
2607
|
+
border-radius: 22px !important;
|
|
2608
|
+
border: 1px solid rgba(0, 255, 136, 0.32) !important;
|
|
2609
|
+
background:
|
|
2610
|
+
radial-gradient(circle at 18% 0%, rgba(0, 255, 136, .12), transparent 44%),
|
|
2611
|
+
linear-gradient(180deg, rgba(8, 29, 44, 0.98), rgba(2, 9, 20, 0.98)) !important;
|
|
2612
|
+
color: #f3fffb !important;
|
|
2613
|
+
box-shadow: 0 24px 60px rgba(0,0,0,.52), 0 0 26px rgba(0,255,136,.13) !important;
|
|
2614
|
+
opacity: 0 !important;
|
|
2615
|
+
pointer-events: none !important;
|
|
2616
|
+
transform: translateY(10px) scale(.98) !important;
|
|
2617
|
+
transition: opacity .16s ease, transform .16s ease !important;
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
.eos-assist-root.eos-assist-open .eos-assist-panel {
|
|
2621
|
+
opacity: 1 !important;
|
|
2622
|
+
pointer-events: auto !important;
|
|
2623
|
+
transform: translateY(0) scale(1) !important;
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
.eos-assist-head { display: flex; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
|
|
2627
|
+
.eos-assist-head strong { display: block; font-size: 16px; font-weight: 950; margin-bottom: 5px; }
|
|
2628
|
+
.eos-assist-head span { display: block; color: rgba(226, 245, 255, .76); font-size: 12px; line-height: 1.35; }
|
|
2629
|
+
.eos-assist-close { width: 32px; height: 32px; border-radius: 12px; border: 1px solid rgba(0,255,136,.26); background: rgba(0,0,0,.34); color: #fff; cursor: pointer; }
|
|
2630
|
+
.eos-assist-steps { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 13px; }
|
|
2631
|
+
.eos-assist-steps span { padding: 5px 9px; border-radius: 999px; background: rgba(0,255,136,.10); border: 1px solid rgba(0,255,136,.18); color: rgba(237,255,250,.90); font-size: 11px; font-weight: 750; }
|
|
2632
|
+
.eos-assist-input-label { display: block; color: rgba(226,245,255,.78); font-size: 11px; margin: 0 0 6px; font-weight: 750; }
|
|
2633
|
+
.eos-assist-input-row { display: flex; gap: 8px; }
|
|
2634
|
+
.eos-assist-input { flex: 1; min-width: 0; border-radius: 14px; border: 1px solid rgba(98,190,255,.28); background: rgba(0,7,13,.62); color: #f3fffb; padding: 10px 12px; outline: none; }
|
|
2635
|
+
.eos-assist-send { border: 0; border-radius: 14px; padding: 0 13px; background: linear-gradient(135deg, #00ff88, #00d4ff); color: #001019; font-weight: 900; cursor: pointer; }
|
|
2636
|
+
.eos-assist-answer { margin-top: 12px; padding: 12px 13px; border-radius: 16px; border: 1px solid rgba(0,212,255,.20); background: rgba(0,0,0,.28); color: rgba(238,255,250,.90); font-size: 12px; line-height: 1.42; }
|
|
2637
|
+
|
|
2638
|
+
@media (max-width: 720px) {
|
|
2639
|
+
html.eos-app .MuiDrawer-paper,
|
|
2640
|
+
html.eos-app .eos-drawer { padding-left: 68px !important; }
|
|
2641
|
+
html.eos-app .eos-native-drawer-header { left: 8px !important; width: 50px !important; min-width: 50px !important; max-width: 50px !important; }
|
|
2642
|
+
html.eos-app .eos-native-drawer-header > div:first-child { width: 50px !important; min-width: 50px !important; max-width: 50px !important; }
|
|
2643
|
+
html.eos-app .eos-native-drawer-header button.eos-nav-compact-toggle,
|
|
2644
|
+
html.eos-app .eos-native-drawer-header .eos-nav-compact-toggle { width: 40px !important; height: 40px !important; min-width: 40px !important; min-height: 40px !important; }
|
|
2645
|
+
.eos-assist-root { right: 14px !important; bottom: 16px !important; }
|
|
2646
|
+
.eos-assist-button { min-width: 54px !important; width: 54px !important; height: 54px !important; border-radius: 18px !important; grid-template-columns: 1fr !important; padding: 0 !important; place-items: center !important; }
|
|
2647
|
+
.eos-assist-button strong, .eos-assist-button small { display: none !important; }
|
|
2648
|
+
.eos-assist-dot { grid-column: 1; grid-row: 1; width: 14px; height: 14px; }
|
|
2649
|
+
}
|
package/adminWww/index.html
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
rel="stylesheet"
|
|
32
32
|
href="css/leaflet.css"
|
|
33
33
|
/>
|
|
34
|
-
<link rel="stylesheet" href="./css/eos-branding.css?v=
|
|
34
|
+
<link rel="stylesheet" href="./css/eos-branding.css?v=28" />
|
|
35
35
|
<link
|
|
36
36
|
rel="manifest"
|
|
37
37
|
href="manifest.json"
|
|
@@ -154,8 +154,9 @@
|
|
|
154
154
|
<script type="module" crossorigin src="./assets/index-CQZugZ1z.js"></script>
|
|
155
155
|
<link rel="modulepreload" crossorigin href="./assets/preload-helper-BDBacUwf.js">
|
|
156
156
|
<link rel="modulepreload" crossorigin href="./assets/iobroker_admin__mf_v__runtimeInit__mf_v__-g2X2zhAf.js">
|
|
157
|
-
<script defer src="./js/eos-branding.js?v=
|
|
158
|
-
<script defer src="./js/eos-security-ui.js?v=
|
|
157
|
+
<script defer src="./js/eos-branding.js?v=28"></script>
|
|
158
|
+
<script defer src="./js/eos-security-ui.js?v=28"></script>
|
|
159
|
+
<script defer src="./js/eos-assistant.js?v=28"></script>
|
|
159
160
|
</head>
|
|
160
161
|
<body>
|
|
161
162
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
window.NEXOWATT_EOS_ASSIST_VERSION = 'v27-local-setup-guide';
|
|
5
|
+
|
|
6
|
+
const ASSET_BASE = (() => {
|
|
7
|
+
const script = document.currentScript?.src || document.querySelector('script[src*="eos-assistant.js"]')?.src || window.location.href;
|
|
8
|
+
return new URL('../', script).href;
|
|
9
|
+
})();
|
|
10
|
+
const asset = path => new URL(path.replace(/^\.\//, ''), ASSET_BASE).href;
|
|
11
|
+
const LOGO = asset('img/eos/nexowatt-192.png');
|
|
12
|
+
const STORE_KEY = 'nexowatt.eos.assist.open';
|
|
13
|
+
const state = { checked: false, allowed: true };
|
|
14
|
+
|
|
15
|
+
const fetchAssistantPolicy = async () => {
|
|
16
|
+
if (state.checked) return state.allowed;
|
|
17
|
+
state.checked = true;
|
|
18
|
+
try {
|
|
19
|
+
const url = new URL('eos/security/status', ASSET_BASE).href;
|
|
20
|
+
const response = await fetch(url, { credentials: 'same-origin', cache: 'no-store' });
|
|
21
|
+
if (!response.ok) return state.allowed;
|
|
22
|
+
const json = await response.json();
|
|
23
|
+
const assistant = json.assistant || {};
|
|
24
|
+
const enabled = assistant.enabled !== false && json.eosAssistantEnabled !== false;
|
|
25
|
+
const adminOnly = assistant.adminOnly === true || json.eosAssistantAdminOnly === true;
|
|
26
|
+
const isAdmin = json.isAdmin === true || json.isAdministrator === true || json.isEosAdminGroup === true;
|
|
27
|
+
state.allowed = enabled && (!adminOnly || isAdmin);
|
|
28
|
+
} catch {
|
|
29
|
+
state.allowed = true;
|
|
30
|
+
}
|
|
31
|
+
return state.allowed;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const normalize = value => String(value || '')
|
|
35
|
+
.toLowerCase()
|
|
36
|
+
.normalize('NFD')
|
|
37
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
38
|
+
.replace(/\s+/g, ' ')
|
|
39
|
+
.trim();
|
|
40
|
+
|
|
41
|
+
const route = () => {
|
|
42
|
+
const hash = window.location.hash || '';
|
|
43
|
+
const text = normalize(document.body?.innerText || '');
|
|
44
|
+
if (hash.includes('tab-adapters') || /module|adapter/.test(text.slice(0, 4000))) return 'modules';
|
|
45
|
+
if (hash.includes('tab-instances') || /dienste|instanzen/.test(text.slice(0, 4000))) return 'services';
|
|
46
|
+
if (hash.includes('tab-logs') || /systemlogs|protokolle|log-grosse/.test(text.slice(0, 4000))) return 'logs';
|
|
47
|
+
if (hash.includes('tab-users') || /zugange & rechte|benutzer|rollen/.test(text.slice(0, 4000))) return 'rights';
|
|
48
|
+
if (hash.includes('tab-objects') || /datenpunkte|objekte/.test(text.slice(0, 4000))) return 'objects';
|
|
49
|
+
if (hash.includes('tab-hosts') || /system-hosts|hosts/.test(text.slice(0, 4000))) return 'hosts';
|
|
50
|
+
return 'overview';
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const contextTitle = () => ({
|
|
54
|
+
modules: 'Module & Adapter',
|
|
55
|
+
services: 'Dienste & Instanzen',
|
|
56
|
+
logs: 'Systemlogs',
|
|
57
|
+
rights: 'Zugänge & Rechte',
|
|
58
|
+
objects: 'Datenpunkte',
|
|
59
|
+
hosts: 'System-Hosts',
|
|
60
|
+
overview: 'EOS Cockpit',
|
|
61
|
+
}[route()] || 'EOS Cockpit');
|
|
62
|
+
|
|
63
|
+
const routeAdvice = () => ({
|
|
64
|
+
modules: 'Hier installierst und aktualisierst du Module. Prüfe vor einer Installation immer: Zweck, benötigte Instanzen, Version, Abhängigkeiten und ob das Modul zu den geschützten EOS-Komponenten gehört.',
|
|
65
|
+
services: 'Hier siehst du laufende Dienste. Wichtig sind Status, Speicherverbrauch, Log-Level und ob eine Instanz automatisch startet. Fehlerhafte Dienste zuerst öffnen, Log prüfen, dann gezielt neu starten.',
|
|
66
|
+
logs: 'Hier erkennst du die Ursache vieler Probleme. Filtere nach Quelle und Level. Wiederholte Warnungen sind meist wichtiger als einzelne Meldungen.',
|
|
67
|
+
rights: 'Hier steuerst du Rollen und Benutzer. Installateur- und Endkundenrollen sollten keine geschützten EOS-Systemmodule löschen, stoppen oder aktivieren können.',
|
|
68
|
+
objects: 'Datenpunkte sind die technische Basis. Ändere Rollen, States und Alias-Strukturen nur bewusst, weil Adapter und Visualisierungen davon abhängen.',
|
|
69
|
+
hosts: 'Hier prüfst du Systemlast, Node.js, npm, Speicher und laufende Prozesse. Bei Updateproblemen zuerst Host-Status und freien Speicher prüfen.',
|
|
70
|
+
overview: 'Das Cockpit gibt den Überblick. Starte von hier aus mit Modulen, Diensten, Logs oder Rechten, je nachdem ob du einrichten, prüfen oder absichern möchtest.',
|
|
71
|
+
}[route()] || 'Wähle einen Bereich aus, dann kann EOS Assist dir die nächsten Schritte erklären.');
|
|
72
|
+
|
|
73
|
+
const answerFor = question => {
|
|
74
|
+
const q = normalize(question);
|
|
75
|
+
const r = route();
|
|
76
|
+
if (!q) return `Aktueller Bereich: ${contextTitle()}\n\n${routeAdvice()}\n\nDu kannst z. B. fragen: „Wie richte ich Modbus ein?“, „Warum ist ein Dienst rot?“ oder „Welche Rechte braucht der Installateur?“`;
|
|
77
|
+
|
|
78
|
+
if (/modbus|wechselrichter|tcp|rs485/.test(q)) {
|
|
79
|
+
return 'Modbus-Einrichtung:\n1. Modul installieren und Instanz anlegen.\n2. IP/Port oder seriellen Adapter prüfen.\n3. Unit-ID, Registerbereich und Byte-Reihenfolge dokumentieren.\n4. Dienst starten und Systemlogs auf Timeout/CRC prüfen.\n5. Erst wenn Werte stabil laufen, Datenpunkte in EOS Cockpit verwenden.';
|
|
80
|
+
}
|
|
81
|
+
if (/shelly|relay|schalter|steckdose/.test(q)) {
|
|
82
|
+
return 'Shelly-/Schaltmodul-Einrichtung:\n1. Gerät im gleichen Netzwerk erreichbar machen.\n2. Authentifizierung im Gerät setzen, damit keine Warnung wie „not protected via restricted login“ entsteht.\n3. Adapterinstanz konfigurieren und neu starten.\n4. In Datenpunkten prüfen, ob Power, Energy und Relay-State sauber aktualisieren.';
|
|
83
|
+
}
|
|
84
|
+
if (/ev|wallbox|laden|ladepunkt|ocpp/.test(q)) {
|
|
85
|
+
return 'Ladepunkt-/EVCS-Einrichtung:\n1. OCPP/Wallbox-Modul installieren.\n2. Ladepunkt-ID, Endpoint und Authentifizierung prüfen.\n3. Dienst starten und Verbindung im Log kontrollieren.\n4. Danach Ladeleistung, Fahrzeugstatus und Freigabe-Datenpunkte mit dem EOS Energiemanagement verknüpfen.';
|
|
86
|
+
}
|
|
87
|
+
if (/backup|backitup|sicherung|restore/.test(q)) {
|
|
88
|
+
return 'Backup-Empfehlung:\n1. BackItUp bleibt ein geschütztes EOS-Systemmodul.\n2. Vor Updates immer ein Backup starten.\n3. Restore-Ziel und Speicherort prüfen.\n4. Installateur-/Endkundenrollen sollten BackItUp nicht löschen oder deaktivieren dürfen.';
|
|
89
|
+
}
|
|
90
|
+
if (/recht|rolle|benutzer|installateur|kunde|admin/.test(q)) {
|
|
91
|
+
return 'Rechte-Empfehlung:\n1. Administrator: volle Wartung und Systemschutz.\n2. Installateur: Module konfigurieren, aber geschützte Adapter nicht löschen.\n3. Endkunde: Bedienung und Ansicht, keine Systemmodule.\n4. Geschützte Adapter legt der Administrator im EOS-Sicherheitsbereich fest.';
|
|
92
|
+
}
|
|
93
|
+
if (/log|fehler|warn|error|timeout|offline/.test(q)) {
|
|
94
|
+
return 'Fehleranalyse:\n1. In Systemlogs nach Quelle und Level filtern.\n2. Wiederholte Meldungen priorisieren.\n3. Bei Timeout Netzwerk/IP/Port prüfen.\n4. Bei Auth-Warnungen Zugangsdaten im Gerät und Adapter vergleichen.\n5. Danach nur die betroffene Instanz neu starten, nicht das komplette System.';
|
|
95
|
+
}
|
|
96
|
+
if (/update|aktualisieren|npm|repository|repo/.test(q)) {
|
|
97
|
+
return 'Update-Prüfung:\n1. NexoWatt-Repository aktiv setzen.\n2. Version im Repository und npm vergleichen.\n3. Bei EOS Admin: iobroker upgrade eos-admin, danach iobroker upload eos-admin.\n4. Browser mit Strg+F5 neu laden.\n5. Vor größeren Updates Backup erstellen.';
|
|
98
|
+
}
|
|
99
|
+
if (/dienst|instanz|start|stop|neustart/.test(q)) {
|
|
100
|
+
return 'Dienst prüfen:\n1. Status ansehen: grün/läuft, rot/gestoppt, gelb/Warnung.\n2. Speicherverbrauch und Log-Level prüfen.\n3. Bei Fehlern zuerst Log öffnen.\n4. Dann Instanz neu starten.\n5. Wenn der Fehler wiederkommt, Konfiguration und Abhängigkeiten prüfen.';
|
|
101
|
+
}
|
|
102
|
+
return `Ich habe deine Frage lokal eingeordnet.\n\nBereich: ${contextTitle()}\n\nEmpfohlene nächsten Schritte:\n1. Ziel klären: installieren, konfigurieren, Fehler suchen oder absichern.\n2. Betroffenes Modul/Dienst auswählen.\n3. Logs und Status prüfen.\n4. Änderung speichern und nur die betroffene Instanz neu starten.\n\nHinweis: Diese erste EOS-Assistenz arbeitet lokal ohne Cloud. Eine echte KI-Anbindung kann später über einen NexoWatt- oder MCP-Dienst ergänzt werden.`;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const setOpen = open => {
|
|
106
|
+
document.documentElement.classList.toggle('eos-assist-open', !!open);
|
|
107
|
+
try { localStorage.setItem(STORE_KEY, open ? '1' : '0'); } catch { /* ignore */ }
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const renderAnswer = (panel, question) => {
|
|
111
|
+
const out = panel.querySelector('.eos-assist-answer');
|
|
112
|
+
if (out) out.textContent = answerFor(question);
|
|
113
|
+
const ctx = panel.querySelector('.eos-assist-context');
|
|
114
|
+
if (ctx) ctx.textContent = contextTitle();
|
|
115
|
+
const hint = panel.querySelector('.eos-assist-hint');
|
|
116
|
+
if (hint) hint.textContent = routeAdvice();
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const ensureAssistant = () => {
|
|
120
|
+
if (!document.body || document.querySelector('.eos-assist-launcher')) return;
|
|
121
|
+
if (document.documentElement.classList.contains('eos-login')) return;
|
|
122
|
+
if (!document.getElementById('app-paper')) return;
|
|
123
|
+
|
|
124
|
+
const launcher = document.createElement('button');
|
|
125
|
+
launcher.type = 'button';
|
|
126
|
+
launcher.className = 'eos-assist-launcher';
|
|
127
|
+
launcher.innerHTML = '<span>✦</span><span>EOS Assist</span>';
|
|
128
|
+
launcher.setAttribute('aria-label', 'EOS Assist öffnen');
|
|
129
|
+
|
|
130
|
+
const panel = document.createElement('aside');
|
|
131
|
+
panel.className = 'eos-assist-panel';
|
|
132
|
+
panel.setAttribute('aria-label', 'EOS Assist');
|
|
133
|
+
panel.innerHTML = `
|
|
134
|
+
<div class="eos-assist-head">
|
|
135
|
+
<span class="eos-assist-logo"><img src="${LOGO}" alt="NexoWatt EOS" /></span>
|
|
136
|
+
<span><strong>EOS Assist</strong><small><span class="eos-assist-context"></span> · geführte Einrichtung</small></span>
|
|
137
|
+
<button type="button" class="eos-assist-close" aria-label="Schließen">×</button>
|
|
138
|
+
</div>
|
|
139
|
+
<div class="eos-assist-body">
|
|
140
|
+
<div class="eos-assist-card"><strong>Aktueller Hinweis</strong><p class="eos-assist-hint"></p></div>
|
|
141
|
+
<div class="eos-assist-actions">
|
|
142
|
+
<button type="button" data-question="Wie richte ich dieses Modul ein?">Modul einrichten</button>
|
|
143
|
+
<button type="button" data-question="Wie prüfe ich Fehler in den Logs?">Fehler prüfen</button>
|
|
144
|
+
<button type="button" data-question="Welche Rechte braucht der Installateur?">Rechte erklären</button>
|
|
145
|
+
<button type="button" data-question="Was muss ich vor einem Update beachten?">Update-Check</button>
|
|
146
|
+
</div>
|
|
147
|
+
<div class="eos-assist-input-row">
|
|
148
|
+
<input class="eos-assist-input" type="text" placeholder="Frage eingeben, z. B. Modbus einrichten" />
|
|
149
|
+
<button type="button" class="eos-assist-send">Fragen</button>
|
|
150
|
+
</div>
|
|
151
|
+
<div class="eos-assist-card eos-assist-answer"></div>
|
|
152
|
+
<div class="eos-assist-foot">Lokale Assistenz ohne Cloud. Für echte KI-Automation kann später ein NexoWatt-Dienst angebunden werden.</div>
|
|
153
|
+
</div>
|
|
154
|
+
`;
|
|
155
|
+
|
|
156
|
+
document.body.appendChild(launcher);
|
|
157
|
+
document.body.appendChild(panel);
|
|
158
|
+
renderAnswer(panel, '');
|
|
159
|
+
|
|
160
|
+
launcher.addEventListener('click', () => setOpen(!document.documentElement.classList.contains('eos-assist-open')));
|
|
161
|
+
panel.querySelector('.eos-assist-close')?.addEventListener('click', () => setOpen(false));
|
|
162
|
+
panel.querySelector('.eos-assist-send')?.addEventListener('click', () => renderAnswer(panel, panel.querySelector('.eos-assist-input')?.value || ''));
|
|
163
|
+
panel.querySelector('.eos-assist-input')?.addEventListener('keydown', event => {
|
|
164
|
+
if (event.key === 'Enter') renderAnswer(panel, event.currentTarget.value || '');
|
|
165
|
+
});
|
|
166
|
+
panel.querySelectorAll('button[data-question]').forEach(button => {
|
|
167
|
+
button.addEventListener('click', () => {
|
|
168
|
+
const question = button.getAttribute('data-question') || '';
|
|
169
|
+
const input = panel.querySelector('.eos-assist-input');
|
|
170
|
+
if (input) input.value = question;
|
|
171
|
+
renderAnswer(panel, question);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
try { if (localStorage.getItem(STORE_KEY) === '1') setOpen(true); } catch { /* ignore */ }
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const removeOnLogin = () => {
|
|
179
|
+
if (!document.documentElement.classList.contains('eos-login')) return;
|
|
180
|
+
document.querySelectorAll('.eos-assist-launcher,.eos-assist-panel').forEach(el => el.remove());
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const run = () => {
|
|
184
|
+
removeOnLogin();
|
|
185
|
+
void fetchAssistantPolicy().then(allowed => {
|
|
186
|
+
if (!allowed) {
|
|
187
|
+
document.querySelectorAll('.eos-assist-launcher,.eos-assist-panel').forEach(el => el.remove());
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
ensureAssistant();
|
|
191
|
+
const panel = document.querySelector('.eos-assist-panel');
|
|
192
|
+
if (panel) renderAnswer(panel, panel.querySelector('.eos-assist-input')?.value || '');
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', run, { once: true });
|
|
197
|
+
else run();
|
|
198
|
+
window.addEventListener('hashchange', () => setTimeout(run, 80));
|
|
199
|
+
window.addEventListener('load', () => setTimeout(run, 120), { once: true });
|
|
200
|
+
new MutationObserver(() => {
|
|
201
|
+
if (!document.querySelector('.eos-assist-launcher')) run();
|
|
202
|
+
}).observe(document.documentElement, { childList: true, subtree: true });
|
|
203
|
+
})();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
window.NEXOWATT_EOS_UI_VERSION = '
|
|
4
|
+
window.NEXOWATT_EOS_UI_VERSION = 'v27-logo-nav-assist-polish';
|
|
5
5
|
|
|
6
6
|
const BRAND = 'NexoWatt EOS';
|
|
7
7
|
const EOS_MEANING = 'Energy Operation System';
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
protectedAdapters: ['eos-admin', 'backitup'],
|
|
73
73
|
},
|
|
74
74
|
securityFetchStarted: false,
|
|
75
|
+
assistOpen: false,
|
|
75
76
|
};
|
|
76
77
|
|
|
77
78
|
const safe = fn => {
|
|
@@ -518,6 +519,26 @@
|
|
|
518
519
|
}
|
|
519
520
|
if (header) {
|
|
520
521
|
header.classList.add('eos-native-drawer-header');
|
|
522
|
+
const toggleButton = header.querySelector('button, .MuiIconButton-root, [role="button"]');
|
|
523
|
+
if (toggleButton && !toggleButton.dataset.eosNavCompactToggle) {
|
|
524
|
+
toggleButton.dataset.eosNavCompactToggle = 'true';
|
|
525
|
+
toggleButton.classList.add('eos-nav-compact-toggle');
|
|
526
|
+
toggleButton.setAttribute('title', 'Navigation kompakt/normal umschalten');
|
|
527
|
+
toggleButton.setAttribute('aria-label', 'Navigation kompakt/normal umschalten');
|
|
528
|
+
const toggleCompact = event => {
|
|
529
|
+
event.preventDefault();
|
|
530
|
+
event.stopPropagation();
|
|
531
|
+
if (event.stopImmediatePropagation) event.stopImmediatePropagation();
|
|
532
|
+
const compact = !document.documentElement.classList.contains('eos-nav-compact');
|
|
533
|
+
document.documentElement.classList.toggle('eos-nav-compact', compact);
|
|
534
|
+
safe(() => localStorage.setItem('nexowatt:eosNavCompact', compact ? '1' : '0'));
|
|
535
|
+
toggleButton.setAttribute('aria-pressed', compact ? 'true' : 'false');
|
|
536
|
+
};
|
|
537
|
+
toggleButton.addEventListener('click', toggleCompact, true);
|
|
538
|
+
toggleButton.addEventListener('keydown', event => {
|
|
539
|
+
if (event.key === 'Enter' || event.key === ' ') toggleCompact(event);
|
|
540
|
+
}, true);
|
|
541
|
+
}
|
|
521
542
|
const img = header.querySelector('img');
|
|
522
543
|
if (img) patchImage(img);
|
|
523
544
|
const avatarImg = header.querySelector('.MuiAvatar-img');
|
|
@@ -728,6 +749,116 @@
|
|
|
728
749
|
});
|
|
729
750
|
});
|
|
730
751
|
|
|
752
|
+
|
|
753
|
+
const applyNavCompactPreference = () => safe(() => {
|
|
754
|
+
const compact = localStorage.getItem('nexowatt:eosNavCompact') === '1';
|
|
755
|
+
document.documentElement.classList.toggle('eos-nav-compact', compact);
|
|
756
|
+
document.querySelectorAll('.eos-nav-compact-toggle').forEach(button => {
|
|
757
|
+
button.setAttribute('aria-pressed', compact ? 'true' : 'false');
|
|
758
|
+
button.setAttribute('title', compact ? 'Navigation normal anzeigen' : 'Navigation kompakt anzeigen');
|
|
759
|
+
});
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
const assistContext = () => {
|
|
763
|
+
const routes = routeInfo();
|
|
764
|
+
if (routes.adapters) return {
|
|
765
|
+
title: 'Module einrichten',
|
|
766
|
+
text: 'Wähle zuerst das passende Modul, prüfe Version und Instanzstatus und öffne dann die Konfiguration über die drei Punkte oder das Werkzeug-Symbol.',
|
|
767
|
+
steps: ['Modul suchen', 'Instanz anlegen', 'Verbindung testen', 'Datenpunkte prüfen']
|
|
768
|
+
};
|
|
769
|
+
if (routes.instances) return {
|
|
770
|
+
title: 'Dienste prüfen',
|
|
771
|
+
text: 'Kontrolliere Status, Port, Speicherverbrauch und Logmeldungen. Gestoppte Dienste erst nach Ursache und Abhängigkeiten prüfen.',
|
|
772
|
+
steps: ['Status ansehen', 'Log öffnen', 'Konfiguration prüfen', 'Dienst neu starten']
|
|
773
|
+
};
|
|
774
|
+
if (routes.users) return {
|
|
775
|
+
title: 'Zugänge & Rechte',
|
|
776
|
+
text: 'Installateure und Endkunden sollten nur die Module sehen, die sie wirklich bedienen dürfen. Geschützte EOS-Module bleiben Administratoren vorbehalten.',
|
|
777
|
+
steps: ['Benutzer wählen', 'Rolle zuordnen', 'Rechteprofil setzen', 'Löschschutz prüfen']
|
|
778
|
+
};
|
|
779
|
+
if (routeInfo().intro) return {
|
|
780
|
+
title: 'EOS Cockpit',
|
|
781
|
+
text: 'Beginne mit Systemstatus, Hosts und gesicherten Basisdiensten. Danach Module Schritt für Schritt freischalten.',
|
|
782
|
+
steps: ['System prüfen', 'Sicherung prüfen', 'Module planen', 'Rechte vergeben']
|
|
783
|
+
};
|
|
784
|
+
return {
|
|
785
|
+
title: 'EOS Bedienhilfe',
|
|
786
|
+
text: 'Ich unterstütze dich beim Einrichten, Prüfen und Absichern deiner EOS-Module.',
|
|
787
|
+
steps: ['Ziel beschreiben', 'Modul auswählen', 'Parameter prüfen', 'Test starten']
|
|
788
|
+
};
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
const assistAnswer = query => {
|
|
792
|
+
const q = normalize(query);
|
|
793
|
+
if (!q) return 'Beschreibe kurz, was eingerichtet werden soll, zum Beispiel: PV, Speicher, Wallbox, Modbus, Backup oder Benutzerrechte.';
|
|
794
|
+
if (/wallbox|evcs|lade|auto|ocpp/.test(q)) return 'Für Ladepunkte: zuerst OCPP/EVCS-Modul installieren, Verbindung zur Wallbox prüfen, Ladepunkt-ID setzen, danach Datenpunkte für Status, Leistung und Freigabe testen.';
|
|
795
|
+
if (/pv|solar|wechselrichter|sun2000|fronius|kostal|sma/.test(q)) return 'Für PV/Wechselrichter: IP-Adresse, Modbus/TCP oder Hersteller-API aktivieren, Abfrageintervall moderat setzen und danach Erzeugung, Bezug und Einspeisung in den Datenpunkten prüfen.';
|
|
796
|
+
if (/speicher|batterie|akku/.test(q)) return 'Für Speicher: Kommunikationsweg prüfen, Lade-/Entladeleistung und SoC-Datenpunkte kontrollieren und Grenzwerte erst setzen, wenn Livewerte plausibel sind.';
|
|
797
|
+
if (/modbus/.test(q)) return 'Für Modbus: Host/IP, Port 502, Unit-ID und Registertabelle prüfen. Danach erst lesen testen, dann Schreibrechte gezielt freischalten.';
|
|
798
|
+
if (/mqtt/.test(q)) return 'Für MQTT: Broker-Adresse, Zugangsdaten, Topic-Struktur und TLS prüfen. Danach mit einem Test-Topic starten und erst dann produktive Topics freigeben.';
|
|
799
|
+
if (/backup|sicherung|restore/.test(q)) return 'Für Sicherung: BackItUp aktiv halten, Zielpfad oder Cloud-Ziel prüfen, Test-Backup starten und Restore-Hinweise dokumentieren.';
|
|
800
|
+
if (/rechte|benutzer|installateur|kunde|admin/.test(q)) return 'Für Rechte: Benutzer in Rollen trennen. Installateure dürfen konfigurieren, aber geschützte EOS-Systemmodule nicht löschen. Endkunden bekommen nur Bedien- und Leserechte.';
|
|
801
|
+
if (/fehler|log|offline|404|timeout/.test(q)) return 'Bei Fehlern: zuerst Systemlogs öffnen, betroffene Instanz filtern, letzte Änderung prüfen, Dienst neu starten und danach Port/WebSocket/Repository prüfen.';
|
|
802
|
+
return 'Vorschlag: Starte mit dem passenden Modul, prüfe die Verbindung, kontrolliere die erzeugten Datenpunkte und sichere danach die Rechte. Für konkrete Hilfe nenne bitte Modulname und Zielgerät.';
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
const ensureEosAssist = () => safe(() => {
|
|
806
|
+
const hasApp = !!document.getElementById('app-paper');
|
|
807
|
+
if (!hasApp || isLoginView()) {
|
|
808
|
+
document.getElementById('eos-assist-root')?.remove();
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
let root = document.getElementById('eos-assist-root');
|
|
812
|
+
if (!root) {
|
|
813
|
+
root = document.createElement('section');
|
|
814
|
+
root.id = 'eos-assist-root';
|
|
815
|
+
root.className = 'eos-assist-root';
|
|
816
|
+
document.body.appendChild(root);
|
|
817
|
+
}
|
|
818
|
+
const ctx = assistContext();
|
|
819
|
+
root.classList.toggle('eos-assist-open', !!state.assistOpen);
|
|
820
|
+
root.innerHTML = `
|
|
821
|
+
<button class="eos-assist-button" type="button" aria-expanded="${state.assistOpen ? 'true' : 'false'}">
|
|
822
|
+
<span class="eos-assist-dot"></span><strong>EOS Assist</strong><small>Einrichtungshilfe</small>
|
|
823
|
+
</button>
|
|
824
|
+
<div class="eos-assist-panel" role="dialog" aria-label="EOS Assist Einrichtungshilfe">
|
|
825
|
+
<div class="eos-assist-head">
|
|
826
|
+
<div><strong>${ctx.title}</strong><span>${ctx.text}</span></div>
|
|
827
|
+
<button type="button" class="eos-assist-close" aria-label="EOS Assist schließen">×</button>
|
|
828
|
+
</div>
|
|
829
|
+
<div class="eos-assist-steps">${ctx.steps.map(step => `<span>${step}</span>`).join('')}</div>
|
|
830
|
+
<label class="eos-assist-input-label">Was möchtest du einrichten?</label>
|
|
831
|
+
<div class="eos-assist-input-row"><input class="eos-assist-input" placeholder="z. B. Wallbox, PV, Modbus, Rechte..." /><button type="button" class="eos-assist-send">Fragen</button></div>
|
|
832
|
+
<div class="eos-assist-answer">${assistAnswer('')}</div>
|
|
833
|
+
</div>
|
|
834
|
+
`;
|
|
835
|
+
const openButton = root.querySelector('.eos-assist-button');
|
|
836
|
+
const closeButton = root.querySelector('.eos-assist-close');
|
|
837
|
+
const input = root.querySelector('.eos-assist-input');
|
|
838
|
+
const send = root.querySelector('.eos-assist-send');
|
|
839
|
+
const answer = root.querySelector('.eos-assist-answer');
|
|
840
|
+
openButton?.addEventListener('click', event => {
|
|
841
|
+
event.preventDefault();
|
|
842
|
+
state.assistOpen = !state.assistOpen;
|
|
843
|
+
root.classList.toggle('eos-assist-open', state.assistOpen);
|
|
844
|
+
openButton.setAttribute('aria-expanded', state.assistOpen ? 'true' : 'false');
|
|
845
|
+
if (state.assistOpen) setTimeout(() => input?.focus(), 40);
|
|
846
|
+
});
|
|
847
|
+
closeButton?.addEventListener('click', event => {
|
|
848
|
+
event.preventDefault();
|
|
849
|
+
state.assistOpen = false;
|
|
850
|
+
root.classList.remove('eos-assist-open');
|
|
851
|
+
openButton?.setAttribute('aria-expanded', 'false');
|
|
852
|
+
});
|
|
853
|
+
const ask = () => {
|
|
854
|
+
if (answer) answer.textContent = assistAnswer(input?.value || '');
|
|
855
|
+
};
|
|
856
|
+
send?.addEventListener('click', ask);
|
|
857
|
+
input?.addEventListener('keydown', event => {
|
|
858
|
+
if (event.key === 'Enter') ask();
|
|
859
|
+
});
|
|
860
|
+
});
|
|
861
|
+
|
|
731
862
|
const patchDocumentMeta = () => safe(() => {
|
|
732
863
|
document.title = BRAND_LONG;
|
|
733
864
|
const theme = document.querySelector('meta[name="theme-color"]');
|
|
@@ -745,6 +876,8 @@
|
|
|
745
876
|
patchDocumentMeta();
|
|
746
877
|
patchLogin();
|
|
747
878
|
patchShell();
|
|
879
|
+
applyNavCompactPreference();
|
|
880
|
+
ensureEosAssist();
|
|
748
881
|
ensureRightsHelper();
|
|
749
882
|
ensurePermissionPresets();
|
|
750
883
|
ensureSettingsDialogClasses();
|
|
@@ -762,6 +895,8 @@
|
|
|
762
895
|
normalizeBadAddressAfterLogin();
|
|
763
896
|
patchLogin();
|
|
764
897
|
patchShell();
|
|
898
|
+
applyNavCompactPreference();
|
|
899
|
+
ensureEosAssist();
|
|
765
900
|
ensureRightsHelper();
|
|
766
901
|
ensurePermissionPresets();
|
|
767
902
|
ensureSettingsDialogClasses();
|
package/build/main.js
CHANGED
|
@@ -828,13 +828,8 @@ class Admin extends adapter_core_1.Adapter {
|
|
|
828
828
|
}
|
|
829
829
|
let changed = false;
|
|
830
830
|
obj.common = obj.common || {};
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
obj.common.dontDelete = true;
|
|
834
|
-
changed = true;
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
else if (obj.common.dontDelete === true && id !== `system.adapter.${EOS_ADMIN_ADAPTER_NAME}`) {
|
|
831
|
+
// v28: do not use common.dontDelete for EOS protection because it can block adapter upgrades.
|
|
832
|
+
if (obj.common.dontDelete === true) {
|
|
838
833
|
delete obj.common.dontDelete;
|
|
839
834
|
changed = true;
|
|
840
835
|
}
|
|
@@ -870,7 +865,7 @@ class Admin extends adapter_core_1.Adapter {
|
|
|
870
865
|
const isEosAdmin = adapter === EOS_ADMIN_ADAPTER_NAME;
|
|
871
866
|
const adminOnlyAcl = isEosAdmin || this.shouldApplyAdminOnlyAclToProtectedAdapters();
|
|
872
867
|
let changed = await this.ensureObjectProtectionPolicy(`system.adapter.${adapter}`, {
|
|
873
|
-
keepDontDelete:
|
|
868
|
+
keepDontDelete: false,
|
|
874
869
|
adminOnlyAcl,
|
|
875
870
|
});
|
|
876
871
|
try {
|
|
@@ -880,7 +875,7 @@ class Admin extends adapter_core_1.Adapter {
|
|
|
880
875
|
});
|
|
881
876
|
for (const row of instances.rows) {
|
|
882
877
|
changed = (await this.ensureObjectProtectionPolicy(row.id, {
|
|
883
|
-
keepDontDelete:
|
|
878
|
+
keepDontDelete: false,
|
|
884
879
|
adminOnlyAcl,
|
|
885
880
|
})) || changed;
|
|
886
881
|
}
|
|
@@ -889,7 +884,7 @@ class Admin extends adapter_core_1.Adapter {
|
|
|
889
884
|
this.log.warn(`Cannot protect instances of adapter "${adapter}": ${e instanceof Error ? e.message : e}`);
|
|
890
885
|
}
|
|
891
886
|
if (changed) {
|
|
892
|
-
this.log.info(`EOS
|
|
887
|
+
this.log.info(`EOS ACL/UI delete guard applied to adapter "${adapter}"`);
|
|
893
888
|
}
|
|
894
889
|
}
|
|
895
890
|
async ensureLegacyAdminLocked() {
|