iobroker.eos-admin 7.9.51 → 7.9.53
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/adminWww/assets/Objects-DPw52Fast.js +878 -0
- package/adminWww/assets/Objects-DPw53Native.js +878 -0
- package/adminWww/assets/bootstrap-DPWrite52.js +317 -0
- package/adminWww/assets/bootstrap-DPWrite53.js +317 -0
- package/adminWww/assets/hostInit-DPWrite52.js +2 -0
- package/adminWww/assets/hostInit-DPWrite53.js +2 -0
- package/adminWww/assets/index-DPAdapter52.js +950 -0
- package/adminWww/assets/index-DPAdapter53.js +950 -0
- package/adminWww/assets/index-DPWrite52.js +2 -0
- package/adminWww/assets/index-DPWrite53.js +2 -0
- package/adminWww/index.html +9 -8
- package/adminWww/js/eos-branding.js +19 -1
- package/adminWww/js/eos-objects-state-tools.js +26 -518
- package/adminWww/js/eos-performance-guard.js +37 -0
- package/adminWww/js/eos-role-ui.js +5 -4
- package/adminWww/js/eos-security-ui.js +13 -5
- package/adminWww/mf-manifest.json +1 -1
- package/adminWww/remoteEntry-DPWrite52.js +2 -0
- package/adminWww/remoteEntry-DPWrite53.js +2 -0
- package/build/main.js +7 -4
- package/io-package.json +11 -7
- package/package.json +1 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./bootstrap-DPWrite52.js","./DefaultPropsProvider-BiXBMQYQ.js","./_commonjsHelpers-CE1G-McA.js","./iobroker_admin__mf_v__runtimeInit__mf_v__-g2X2zhAf.js","./emotion-serialize.esm-Q4o_CgeF.js","./iobroker_admin__loadShare___mf_0_emotion_mf_1_react__loadShare__-BywLg1Xe.js","./iobroker_admin__loadShare__react__loadShare__-LM7uyL45.js","./ace-DEUjyTIn.js","./iobroker_admin__loadShare___mf_0_iobroker_mf_1_adapter_mf_2_react_mf_2_v5__loadShare__-LFZoiUTt.js","./iobroker_admin__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__-CpA7pnS5.js","./iobroker_admin__loadShare__leaflet__loadShare__-CNUAG3AH.js","./ext-language_tools-ylAoucDh.js","./iobroker_admin__loadShare__react_mf_2_dropzone__loadShare__-CwjnV48g.js","./iobroker_admin__loadShare__react_mf_2_dom__loadShare__-CVeAXnkk.js","./preload-helper-BDBacUwf.js","./iobroker_admin__loadShare___mf_0_mui_mf_1_icons_mf_2_material__loadShare__-CJO5yP3h.js","./sdk-C-e-e2gd.js","./extends-CF3RwP-h.js","./assertThisInitialized-B0aQ9eG_.js","./useTheme-Bl-M1DYp.js","./createTheme-DFX8CY6F.js","./blue-CagzI6CQ.js","./index-DcK0RDrH.js","./ThemeProvider-BOFFjWAF.js","./emotion-cache.browser.esm-BgJfNZJN.js","./setYear-3ufv5yRD.js","./en-US-DBFJNIH6.js","./bootstrap-D57bMhRi.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{_ as c}from"./preload-helper-BDBacUwf.js";import"./iobroker_admin__mf_v__runtimeInit__mf_v__-g2X2zhAf.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))s(e);new MutationObserver(e=>{for(const r of e)if(r.type==="childList")for(const o of r.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&s(o)}).observe(document,{childList:!0,subtree:!0});function n(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerPolicy&&(r.referrerPolicy=e.referrerPolicy),e.crossOrigin==="use-credentials"?r.credentials="include":e.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function s(e){if(e.ep)return;e.ep=!0;const r=n(e);fetch(e.href,r)}})();c(()=>import("./bootstrap-DPWrite52.js").then(i=>i.o),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]),import.meta.url);
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./bootstrap-DPWrite53.js","./DefaultPropsProvider-BiXBMQYQ.js","./_commonjsHelpers-CE1G-McA.js","./iobroker_admin__mf_v__runtimeInit__mf_v__-g2X2zhAf.js","./emotion-serialize.esm-Q4o_CgeF.js","./iobroker_admin__loadShare___mf_0_emotion_mf_1_react__loadShare__-BywLg1Xe.js","./iobroker_admin__loadShare__react__loadShare__-LM7uyL45.js","./ace-DEUjyTIn.js","./iobroker_admin__loadShare___mf_0_iobroker_mf_1_adapter_mf_2_react_mf_2_v5__loadShare__-LFZoiUTt.js","./iobroker_admin__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__-CpA7pnS5.js","./iobroker_admin__loadShare__leaflet__loadShare__-CNUAG3AH.js","./ext-language_tools-ylAoucDh.js","./iobroker_admin__loadShare__react_mf_2_dropzone__loadShare__-CwjnV48g.js","./iobroker_admin__loadShare__react_mf_2_dom__loadShare__-CVeAXnkk.js","./preload-helper-BDBacUwf.js","./iobroker_admin__loadShare___mf_0_mui_mf_1_icons_mf_2_material__loadShare__-CJO5yP3h.js","./sdk-C-e-e2gd.js","./extends-CF3RwP-h.js","./assertThisInitialized-B0aQ9eG_.js","./useTheme-Bl-M1DYp.js","./createTheme-DFX8CY6F.js","./blue-CagzI6CQ.js","./index-DcK0RDrH.js","./ThemeProvider-BOFFjWAF.js","./emotion-cache.browser.esm-BgJfNZJN.js","./setYear-3ufv5yRD.js","./en-US-DBFJNIH6.js","./bootstrap-D57bMhRi.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{_ as c}from"./preload-helper-BDBacUwf.js";import"./iobroker_admin__mf_v__runtimeInit__mf_v__-g2X2zhAf.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))s(e);new MutationObserver(e=>{for(const r of e)if(r.type==="childList")for(const o of r.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&s(o)}).observe(document,{childList:!0,subtree:!0});function n(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerPolicy&&(r.referrerPolicy=e.referrerPolicy),e.crossOrigin==="use-credentials"?r.credentials="include":e.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function s(e){if(e.ep)return;e.ep=!0;const r=n(e);fetch(e.href,r)}})();c(()=>import("./bootstrap-DPWrite53.js").then(i=>i.o),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]),import.meta.url);
|
package/adminWww/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
translate="no"
|
|
5
5
|
>
|
|
6
6
|
<head>
|
|
7
|
-
<script type="module" src="./assets/hostInit-
|
|
7
|
+
<script type="module" src="./assets/hostInit-DPWrite53.js?v=53"></script>
|
|
8
8
|
|
|
9
9
|
<meta charset="utf-8" />
|
|
10
10
|
<link
|
|
@@ -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=53" />
|
|
35
35
|
<link
|
|
36
36
|
rel="manifest"
|
|
37
37
|
href="manifest.json"
|
|
@@ -151,14 +151,15 @@
|
|
|
151
151
|
false,
|
|
152
152
|
);
|
|
153
153
|
</script>
|
|
154
|
-
|
|
154
|
+
<script src="./js/eos-performance-guard.js?v=53"></script>
|
|
155
|
+
<script type="module" crossorigin src="./assets/index-DPWrite53.js?v=53"></script>
|
|
155
156
|
<link rel="modulepreload" crossorigin href="./assets/preload-helper-BDBacUwf.js">
|
|
156
157
|
<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=
|
|
159
|
-
<script defer src="./js/eos-role-ui.js?v=
|
|
160
|
-
<script defer src="./js/eos-assistant.js?v=
|
|
161
|
-
<script defer src="./js/eos-objects-state-tools.js?v=
|
|
158
|
+
<script defer src="./js/eos-branding.js?v=53"></script>
|
|
159
|
+
<script defer src="./js/eos-security-ui.js?v=53"></script>
|
|
160
|
+
<script defer src="./js/eos-role-ui.js?v=53"></script>
|
|
161
|
+
<script defer src="./js/eos-assistant.js?v=53"></script>
|
|
162
|
+
<script defer src="./js/eos-objects-state-tools.js?v=53"></script>
|
|
162
163
|
</head>
|
|
163
164
|
<body>
|
|
164
165
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
window.NEXOWATT_EOS_UI_VERSION = '
|
|
4
|
+
window.NEXOWATT_EOS_UI_VERSION = 'v52-fast-unrestricted-dp-write';
|
|
5
5
|
|
|
6
6
|
const BRAND = 'NexoWatt EOS';
|
|
7
7
|
const EOS_MEANING = 'Energy Operation System';
|
|
@@ -1391,6 +1391,14 @@
|
|
|
1391
1391
|
releaseNotificationControls();
|
|
1392
1392
|
ensurePopupCompatibility();
|
|
1393
1393
|
applySecurityUiGuard();
|
|
1394
|
+
if (isObjectsRoute()) {
|
|
1395
|
+
// v52: keep branding out of the large virtualized data-point table. Shell,
|
|
1396
|
+
// assistant and rights helpers above are enough; text/attribute walking here
|
|
1397
|
+
// caused slow refreshes and blocked value clicks under load.
|
|
1398
|
+
document.documentElement.classList.add('eos-objects-fast-route');
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
document.documentElement.classList.remove('eos-objects-fast-route');
|
|
1394
1402
|
if (isAdapterConfigSurface()) {
|
|
1395
1403
|
// Adapter-owned configuration pages must not be rebranded or structurally patched.
|
|
1396
1404
|
// We still repair broken UTF-8/mojibake text because jsonConfig labels can be
|
|
@@ -1431,6 +1439,11 @@
|
|
|
1431
1439
|
releaseNotificationControls();
|
|
1432
1440
|
ensurePopupCompatibility();
|
|
1433
1441
|
applySecurityUiGuard();
|
|
1442
|
+
if (isObjectsRoute()) {
|
|
1443
|
+
document.documentElement.classList.add('eos-objects-fast-route');
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
document.documentElement.classList.remove('eos-objects-fast-route');
|
|
1434
1447
|
for (const scope of scopes.slice(0, 80)) {
|
|
1435
1448
|
if (!scope || !scope.isConnected) continue;
|
|
1436
1449
|
if (isAdapterConfigSurface() && (scope.id === 'app-paper' || scope.closest?.('#app-paper'))) {
|
|
@@ -1467,6 +1480,11 @@
|
|
|
1467
1480
|
|
|
1468
1481
|
const installObserver = () => safe(() => {
|
|
1469
1482
|
const observer = new MutationObserver(mutations => {
|
|
1483
|
+
if (isObjectsRoute()) {
|
|
1484
|
+
// Ignore virtualization churn in the data-point table. Hash/load timers
|
|
1485
|
+
// still run the shell patch when the user enters or leaves the page.
|
|
1486
|
+
return;
|
|
1487
|
+
}
|
|
1470
1488
|
for (const mutation of mutations) {
|
|
1471
1489
|
if (mutation.type === 'characterData') {
|
|
1472
1490
|
if (isAdapterConfigSurface() && mutation.target?.parentElement?.closest?.('#app-paper')) patchMojibakeTextNode(mutation.target);
|
|
@@ -1,522 +1,30 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
'
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
'.MuiButton-root',
|
|
31
|
-
'.MuiIconButton-root',
|
|
32
|
-
'.MuiCheckbox-root',
|
|
33
|
-
'.MuiSwitch-root',
|
|
34
|
-
'.MuiSwitch-switchBase',
|
|
35
|
-
'.MuiMenuItem-root',
|
|
36
|
-
'.MuiAutocomplete-option',
|
|
37
|
-
'.MuiSelect-select',
|
|
38
|
-
'.admin-button',
|
|
39
|
-
'.copyButton'
|
|
40
|
-
].join(',');
|
|
41
|
-
|
|
42
|
-
const nativeLayerSelector = [
|
|
43
|
-
'.MuiDialog-root',
|
|
44
|
-
'.MuiModal-root',
|
|
45
|
-
'.MuiPopover-root',
|
|
46
|
-
'.MuiPopper-root',
|
|
47
|
-
'.MuiTooltip-popper',
|
|
48
|
-
'[role="dialog"]',
|
|
49
|
-
'[role="listbox"]',
|
|
50
|
-
'[role="menu"]',
|
|
51
|
-
'[role="tooltip"]'
|
|
52
|
-
].join(',');
|
|
53
|
-
|
|
54
|
-
const valueCellSelector = [
|
|
55
|
-
'.eos-object-value-cell',
|
|
56
|
-
'[data-eos-object-value-cell]',
|
|
57
|
-
'[title*="Wert schreiben"]',
|
|
58
|
-
'[title*="Wert klicken"]',
|
|
59
|
-
'[title*="Button sofort testen"]'
|
|
60
|
-
].join(',');
|
|
61
|
-
|
|
62
|
-
const collect = (base, selector) => {
|
|
63
|
-
const out = [];
|
|
64
|
-
if (!base) return out;
|
|
65
|
-
if (base.nodeType === Node.ELEMENT_NODE && base.matches?.(selector)) out.push(base);
|
|
66
|
-
if (base.querySelectorAll) out.push(...Array.from(base.querySelectorAll(selector)));
|
|
67
|
-
return out;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const getSocket = () => window.NEXOWATT_EOS_OBJECTS_SOCKET || window.NEXOWATT_EOS_SOCKET || window.socket || null;
|
|
71
|
-
|
|
72
|
-
const normalizeText = value => String(value ?? '').replace(/\s+/g, ' ').trim();
|
|
73
|
-
|
|
74
|
-
const isWritableCell = cell => {
|
|
75
|
-
if (!cell) return false;
|
|
76
|
-
// v51: the React ObjectBrowser now marks every state value cell as writable.
|
|
77
|
-
// Do not treat common.write=false as an EOS-side lock; the socket/ACL layer is
|
|
78
|
-
// the only authority that may reject a write.
|
|
79
|
-
if (cell.getAttribute('data-eos-object-writable') === '1') return true;
|
|
80
|
-
if (cell.hasAttribute('data-eos-object-value-cell') && cell.getAttribute('data-eos-object-writable') !== '0') return true;
|
|
81
|
-
const title = `${cell.getAttribute('title') || ''} ${cell.textContent || ''}`;
|
|
82
|
-
return /wert\s*(klicken|schreiben)|write\s*value|sofort\s*testen/i.test(title);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const isStateValueCandidate = cell => !!cell && (
|
|
86
|
-
cell.hasAttribute?.('data-eos-object-value-cell') ||
|
|
87
|
-
cell.classList?.contains('eos-object-value-cell') ||
|
|
88
|
-
isWritableCell(cell)
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
const releaseNativeControls = root => safe(() => {
|
|
92
|
-
if (!setSurfaceState()) return;
|
|
93
|
-
const base = root && root.nodeType ? root : document;
|
|
94
|
-
collect(base, `${interactiveSelector},${nativeLayerSelector}`).forEach(el => {
|
|
95
|
-
if (!el || el.closest?.('#eos-assist-root,.eos-assist-root')) return;
|
|
96
|
-
el.classList?.remove('eos-security-hidden-delete', 'eos-protected-delete-control', 'eos-disabled-by-security');
|
|
97
|
-
el.removeAttribute?.('data-eos-security-blocked');
|
|
98
|
-
el.removeAttribute?.('aria-disabled');
|
|
99
|
-
if (el.style?.pointerEvents === 'none') el.style.pointerEvents = 'auto';
|
|
100
|
-
if (el.style?.visibility === 'hidden') el.style.visibility = 'visible';
|
|
101
|
-
if (el.style?.display === 'none' && !el.classList?.contains('eos-native-logout-hidden')) el.style.display = '';
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
const annotateValueCells = root => safe(() => {
|
|
106
|
-
if (!setSurfaceState()) return;
|
|
107
|
-
const base = root && root.nodeType ? root : document;
|
|
108
|
-
collect(base, valueCellSelector).forEach(cell => {
|
|
109
|
-
const id = cell.getAttribute('data-eos-object-value-cell') || cell.closest?.('[id]')?.getAttribute('id') || '';
|
|
110
|
-
const writable = isWritableCell(cell);
|
|
111
|
-
const visibleValue = normalizeText(cell.textContent || '') || '(leer)';
|
|
112
|
-
const cache = `${id}|${writable ? 1 : 0}|${visibleValue}`;
|
|
113
|
-
|
|
114
|
-
cell.style.pointerEvents = 'auto';
|
|
115
|
-
cell.style.cursor = writable ? 'pointer' : 'default';
|
|
116
|
-
cell.classList.add('eos-object-value-cell');
|
|
117
|
-
cell.classList.toggle('eos-object-value-writable', writable);
|
|
118
|
-
cell.classList.toggle('eos-object-value-readonly', !writable);
|
|
119
|
-
if (writable) cell.setAttribute('tabindex', '0');
|
|
120
|
-
|
|
121
|
-
if (cell.getAttribute('data-eos-value-cache') !== cache) {
|
|
122
|
-
cell.setAttribute('data-eos-value-cache', cache);
|
|
123
|
-
cell.setAttribute('data-eos-current-visible-value', visibleValue);
|
|
124
|
-
const nextTitle = [
|
|
125
|
-
id ? `ID: ${id}` : null,
|
|
126
|
-
`Aktueller Wert: ${visibleValue}`,
|
|
127
|
-
`Status: ${writable ? 'beschreibbar' : 'nur lesbar'}`,
|
|
128
|
-
writable ? 'Klicken: Wert schreiben' : 'Nur lesbarer Wert'
|
|
129
|
-
].filter(Boolean).join('\n');
|
|
130
|
-
if (cell.getAttribute('title') !== nextTitle) cell.setAttribute('title', nextTitle);
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
const parseBoolean = value => {
|
|
136
|
-
if (value === true || value === 1) return true;
|
|
137
|
-
if (value === false || value === 0 || value == null) return false;
|
|
138
|
-
const normalized = String(value).trim().toLowerCase();
|
|
139
|
-
return normalized === 'true' || normalized === '1' || normalized === 'on' || normalized === 'yes' || normalized === 'ja';
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
const isNullToken = value => /^\s*(\(null\)|null|undefined)?\s*$/i.test(String(value ?? ''));
|
|
143
|
-
|
|
144
|
-
const coerceValue = (rawValue, type) => {
|
|
145
|
-
const raw = String(rawValue ?? '');
|
|
146
|
-
if (isNullToken(raw) && type !== 'string' && type !== 'json') return null;
|
|
147
|
-
if (type === 'boolean') return parseBoolean(raw);
|
|
148
|
-
if (type === 'number') {
|
|
149
|
-
const normalized = raw.replace(',', '.').trim();
|
|
150
|
-
const number = Number(normalized);
|
|
151
|
-
if (!Number.isFinite(number)) throw new Error(`Ungültige Zahl: ${raw}`);
|
|
152
|
-
return number;
|
|
153
|
-
}
|
|
154
|
-
if (type === 'json' || type === 'object') {
|
|
155
|
-
if (isNullToken(raw)) return null;
|
|
156
|
-
return JSON.parse(raw);
|
|
157
|
-
}
|
|
158
|
-
return raw;
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const stateToString = value => {
|
|
162
|
-
if (value === null || value === undefined) return 'null';
|
|
163
|
-
if (typeof value === 'object') {
|
|
164
|
-
try { return JSON.stringify(value, null, 2); } catch (_) { return String(value); }
|
|
165
|
-
}
|
|
166
|
-
return String(value);
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
const hasNativeWriteDialog = () => {
|
|
170
|
-
const dialogs = Array.from(document.querySelectorAll('.MuiDialog-root,[role="dialog"]'));
|
|
171
|
-
return dialogs.some(dialog => /write value|wert schreiben|set value|wert setzen/i.test(dialog.textContent || ''));
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
let cachedEosAdminInstance = null;
|
|
176
|
-
|
|
177
|
-
const formatWriteError = error => {
|
|
178
|
-
if (!error) return 'unbekannter Fehler';
|
|
179
|
-
if (typeof error === 'string') return error;
|
|
180
|
-
if (error.message) return error.message;
|
|
181
|
-
try { return JSON.stringify(error); } catch (_) { return String(error); }
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
const normalizeInstanceId = value => {
|
|
185
|
-
if (!value) return null;
|
|
186
|
-
if (typeof value === 'string') {
|
|
187
|
-
const id = value.replace(/^system\.adapter\./, '').trim();
|
|
188
|
-
return /^eos-admin\.\d+$/.test(id) ? id : null;
|
|
189
|
-
}
|
|
190
|
-
if (typeof value === 'object') {
|
|
191
|
-
return normalizeInstanceId(value._id || value.id || value.instance || value.namespace);
|
|
192
|
-
}
|
|
193
|
-
return null;
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
const resolveEosAdminInstance = async socket => {
|
|
197
|
-
if (cachedEosAdminInstance) return cachedEosAdminInstance;
|
|
198
|
-
const explicit = normalizeInstanceId(window.NEXOWATT_EOS_ADMIN_INSTANCE || window.adminInstance || window.adapterInstance);
|
|
199
|
-
if (explicit) return (cachedEosAdminInstance = explicit);
|
|
200
|
-
|
|
201
|
-
if (socket && typeof socket.getCurrentInstance === 'function') {
|
|
202
|
-
try {
|
|
203
|
-
const current = normalizeInstanceId(await socket.getCurrentInstance());
|
|
204
|
-
if (current) return (cachedEosAdminInstance = current);
|
|
205
|
-
} catch (_) {
|
|
206
|
-
// ignore and try instance list/fallback
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (socket && typeof socket.getAdapterInstances === 'function') {
|
|
211
|
-
try {
|
|
212
|
-
const instances = await socket.getAdapterInstances('eos-admin');
|
|
213
|
-
const list = Array.isArray(instances) ? instances : [];
|
|
214
|
-
const alive = list.find(instance => normalizeInstanceId(instance) && instance?.common?.enabled !== false);
|
|
215
|
-
const id = normalizeInstanceId(alive || list[0]);
|
|
216
|
-
if (id) return (cachedEosAdminInstance = id);
|
|
217
|
-
} catch (_) {
|
|
218
|
-
// ignore and use default
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return (cachedEosAdminInstance = 'eos-admin.0');
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
const callEosAdmin = async (socket, command, message) => {
|
|
226
|
-
const instance = await resolveEosAdminInstance(socket);
|
|
227
|
-
if (!instance) throw new Error('EOS Admin Instanz konnte nicht ermittelt werden');
|
|
228
|
-
|
|
229
|
-
if (socket && typeof socket.sendTo === 'function') {
|
|
230
|
-
const result = socket.sendTo(instance, command, message);
|
|
231
|
-
if (result && typeof result.then === 'function') return result;
|
|
232
|
-
if (result !== undefined) return result;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const rawSocket = socket?._socket || socket?.socket || window.socket;
|
|
236
|
-
if (rawSocket && typeof rawSocket.emit === 'function') {
|
|
237
|
-
return await new Promise((resolve, reject) => {
|
|
238
|
-
try {
|
|
239
|
-
rawSocket.emit('sendTo', instance, command, message, response => resolve(response));
|
|
240
|
-
} catch (error) {
|
|
241
|
-
reject(error);
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
throw new Error('socket.sendTo ist nicht verfügbar');
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
const writeStateUnrestricted = async (socket, id, state) => {
|
|
250
|
-
let directError = null;
|
|
251
|
-
if (!socket) throw new Error('Socket ist nicht bereit');
|
|
252
|
-
|
|
253
|
-
if (typeof socket.setState === 'function') {
|
|
254
|
-
try {
|
|
255
|
-
await socket.setState(id, state);
|
|
256
|
-
return { ok: true, via: 'socket' };
|
|
257
|
-
} catch (error) {
|
|
258
|
-
directError = error;
|
|
259
|
-
}
|
|
260
|
-
} else {
|
|
261
|
-
directError = new Error('socket.setState ist nicht verfügbar');
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
try {
|
|
265
|
-
const response = await callEosAdmin(socket, 'eos:writeState', { id, state });
|
|
266
|
-
if (response === 'permissionError') throw new Error('sendTo permissionError');
|
|
267
|
-
if (response && response.ok === false) throw new Error(response.error || 'EOS Backend hat das Schreiben abgelehnt');
|
|
268
|
-
if (response && response.error) throw new Error(response.error);
|
|
269
|
-
return { ok: true, via: 'eos-admin' };
|
|
270
|
-
} catch (backendError) {
|
|
271
|
-
throw new Error(`Direkt: ${formatWriteError(directError)}\nEOS-Backend: ${formatWriteError(backendError)}`);
|
|
272
|
-
}
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
window.NEXOWATT_EOS_WRITE_STATE_UNRESTRICTED = writeStateUnrestricted;
|
|
276
|
-
|
|
277
|
-
const injectDialogStyle = () => {
|
|
278
|
-
if (document.getElementById('eos-dp-write-style')) return;
|
|
279
|
-
const style = document.createElement('style');
|
|
280
|
-
style.id = 'eos-dp-write-style';
|
|
281
|
-
style.textContent = `
|
|
282
|
-
.eos-dp-write-backdrop{position:fixed;inset:0;z-index:9000;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;padding:18px;font-family:Roboto,Arial,sans-serif}.eos-dp-write-dialog{width:min(620px,calc(100vw - 36px));max-height:calc(100vh - 36px);overflow:auto;background:#061827;color:#fff;border:1px solid rgba(0,255,180,.45);border-radius:16px;box-shadow:0 18px 60px rgba(0,0,0,.65),0 0 34px rgba(0,255,180,.22);padding:18px}.eos-dp-write-dialog h3{margin:0 0 8px;font-size:19px;color:#18f4c0}.eos-dp-write-id{font-family:monospace;font-size:12px;opacity:.82;word-break:break-all;margin-bottom:12px}.eos-dp-write-meta{font-size:12px;opacity:.76;margin-bottom:12px}.eos-dp-write-dialog label{display:block;font-size:13px;margin:12px 0 6px}.eos-dp-write-dialog input[type=text],.eos-dp-write-dialog textarea,.eos-dp-write-dialog select{box-sizing:border-box;width:100%;background:#07111d;color:#fff;border:1px solid rgba(255,255,255,.28);border-radius:8px;padding:10px;font-size:15px;outline:none}.eos-dp-write-dialog textarea{min-height:130px;font-family:monospace}.eos-dp-write-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:18px}.eos-dp-write-actions button{border:0;border-radius:10px;padding:9px 16px;font-weight:700;cursor:pointer}.eos-dp-write-primary{background:#00d6a1;color:#03130f}.eos-dp-write-secondary{background:#273746;color:#fff}.eos-dp-write-actions button:disabled{opacity:.55;cursor:wait}.eos-dp-write-error{color:#ff7676;margin-top:10px;font-size:13px;white-space:pre-wrap}.eos-object-value-cell.eos-dp-write-pulse{outline:2px solid #00d6a1;outline-offset:-2px}`;
|
|
283
|
-
document.head.appendChild(style);
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
const closeExistingDialog = () => document.querySelector('.eos-dp-write-backdrop')?.remove();
|
|
287
|
-
|
|
288
|
-
const openWriteDialog = async (cell, event) => {
|
|
289
|
-
const id = cell?.getAttribute('data-eos-object-value-cell') || cell?.closest?.('[id]')?.id || '';
|
|
290
|
-
if (!id || busyIds.has(id)) return;
|
|
291
|
-
const socket = getSocket();
|
|
292
|
-
if (!socket || typeof socket.setState !== 'function') {
|
|
293
|
-
window.alert('EOS: Socket für Datenpunkt-Schreiben ist noch nicht bereit. Bitte Seite einmal hart neu laden (Strg+F5).');
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
busyIds.add(id);
|
|
298
|
-
cell?.classList.add('eos-dp-write-pulse');
|
|
299
|
-
window.setTimeout(() => cell?.classList.remove('eos-dp-write-pulse'), 900);
|
|
300
|
-
|
|
301
|
-
try {
|
|
302
|
-
const [objResult, stateResult] = await Promise.allSettled([
|
|
303
|
-
typeof socket.getObject === 'function' ? socket.getObject(id) : Promise.resolve(null),
|
|
304
|
-
typeof socket.getState === 'function' ? socket.getState(id) : Promise.resolve(null),
|
|
305
|
-
]);
|
|
306
|
-
const obj = objResult.status === 'fulfilled' ? objResult.value : null;
|
|
307
|
-
const state = stateResult.status === 'fulfilled' ? stateResult.value : null;
|
|
308
|
-
if (!obj || obj.type !== 'state') {
|
|
309
|
-
busyIds.delete(id);
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
const common = obj?.common || {};
|
|
313
|
-
if (common.type === 'file') {
|
|
314
|
-
busyIds.delete(id);
|
|
315
|
-
window.alert('EOS: Datei-Datenpunkte werden über die Datei-/Objektansicht geöffnet und nicht als State-Wert geschrieben.');
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
const role = String(common.role || '');
|
|
319
|
-
let type = common.type || typeof state?.val;
|
|
320
|
-
if (!type || type === 'undefined') type = 'string';
|
|
321
|
-
if (type === 'object') type = 'json';
|
|
322
|
-
const current = state?.val;
|
|
323
|
-
const states = common.states && typeof common.states === 'object' ? common.states : null;
|
|
324
|
-
|
|
325
|
-
if (/^button/.test(role)) {
|
|
326
|
-
await writeStateUnrestricted(socket, id, { val: true, ack: false, q: 0 });
|
|
327
|
-
busyIds.delete(id);
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
injectDialogStyle();
|
|
332
|
-
closeExistingDialog();
|
|
333
|
-
|
|
334
|
-
const backdrop = document.createElement('div');
|
|
335
|
-
backdrop.className = 'eos-dp-write-backdrop';
|
|
336
|
-
const dialog = document.createElement('div');
|
|
337
|
-
dialog.className = 'eos-dp-write-dialog';
|
|
338
|
-
dialog.setAttribute('role', 'dialog');
|
|
339
|
-
dialog.setAttribute('aria-modal', 'true');
|
|
340
|
-
dialog.innerHTML = `
|
|
341
|
-
<h3>Datenpunkt schreiben</h3>
|
|
342
|
-
<div class="eos-dp-write-id"></div>
|
|
343
|
-
<div class="eos-dp-write-meta"></div>
|
|
344
|
-
<label class="eos-dp-write-label">Neuer Wert</label>
|
|
345
|
-
<div class="eos-dp-write-input-wrap"></div>
|
|
346
|
-
<label style="display:flex;align-items:center;gap:8px;margin-top:12px"><input class="eos-dp-write-ack" type="checkbox"> ack=true schreiben</label>
|
|
347
|
-
<div class="eos-dp-write-error" hidden></div>
|
|
348
|
-
<div class="eos-dp-write-actions"><button class="eos-dp-write-secondary" type="button">Abbrechen</button><button class="eos-dp-write-primary" type="button">Schreiben</button></div>`;
|
|
349
|
-
backdrop.appendChild(dialog);
|
|
350
|
-
document.body.appendChild(backdrop);
|
|
351
|
-
|
|
352
|
-
dialog.querySelector('.eos-dp-write-id').textContent = id;
|
|
353
|
-
dialog.querySelector('.eos-dp-write-meta').textContent = `Typ: ${type}${role ? ` · Rolle: ${role}` : ''}${common.unit ? ` · Einheit: ${common.unit}` : ''}`;
|
|
354
|
-
|
|
355
|
-
const inputWrap = dialog.querySelector('.eos-dp-write-input-wrap');
|
|
356
|
-
let input;
|
|
357
|
-
if (states) {
|
|
358
|
-
input = document.createElement('select');
|
|
359
|
-
Object.keys(states).forEach(key => {
|
|
360
|
-
const option = document.createElement('option');
|
|
361
|
-
option.value = key;
|
|
362
|
-
option.textContent = `${states[key]} (${key})`;
|
|
363
|
-
input.appendChild(option);
|
|
364
|
-
});
|
|
365
|
-
input.value = current == null ? Object.keys(states)[0] || '' : String(current);
|
|
366
|
-
} else if (type === 'boolean') {
|
|
367
|
-
input = document.createElement('select');
|
|
368
|
-
input.innerHTML = '<option value="true">true</option><option value="false">false</option>';
|
|
369
|
-
input.value = parseBoolean(current) ? 'true' : 'false';
|
|
370
|
-
} else if (type === 'json') {
|
|
371
|
-
input = document.createElement('textarea');
|
|
372
|
-
input.value = stateToString(current);
|
|
373
|
-
} else {
|
|
374
|
-
input = document.createElement('input');
|
|
375
|
-
input.type = 'text';
|
|
376
|
-
input.value = stateToString(current);
|
|
377
|
-
}
|
|
378
|
-
input.className = 'eos-dp-write-input';
|
|
379
|
-
inputWrap.appendChild(input);
|
|
380
|
-
|
|
381
|
-
const errorEl = dialog.querySelector('.eos-dp-write-error');
|
|
382
|
-
const cancelBtn = dialog.querySelector('.eos-dp-write-secondary');
|
|
383
|
-
const writeBtn = dialog.querySelector('.eos-dp-write-primary');
|
|
384
|
-
const ackInput = dialog.querySelector('.eos-dp-write-ack');
|
|
385
|
-
|
|
386
|
-
const close = () => {
|
|
387
|
-
backdrop.remove();
|
|
388
|
-
busyIds.delete(id);
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
const write = async () => {
|
|
392
|
-
errorEl.hidden = true;
|
|
393
|
-
writeBtn.disabled = true;
|
|
394
|
-
cancelBtn.disabled = true;
|
|
395
|
-
try {
|
|
396
|
-
let value = input.value;
|
|
397
|
-
const effectiveType = states ? (common.type || type) : type;
|
|
398
|
-
value = coerceValue(value, effectiveType);
|
|
399
|
-
await writeStateUnrestricted(socket, id, { val: value, ack: !!ackInput.checked, q: 0 });
|
|
400
|
-
close();
|
|
401
|
-
} catch (error) {
|
|
402
|
-
errorEl.textContent = `Schreiben fehlgeschlagen: ${error?.message || error}`;
|
|
403
|
-
errorEl.hidden = false;
|
|
404
|
-
writeBtn.disabled = false;
|
|
405
|
-
cancelBtn.disabled = false;
|
|
406
|
-
}
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
cancelBtn.addEventListener('click', close);
|
|
410
|
-
writeBtn.addEventListener('click', write);
|
|
411
|
-
backdrop.addEventListener('click', e => { if (e.target === backdrop) close(); });
|
|
412
|
-
input.addEventListener('keydown', e => {
|
|
413
|
-
if ((e.key === 'Enter' && type !== 'json') || (e.key === 'Enter' && e.ctrlKey)) {
|
|
414
|
-
e.preventDefault();
|
|
415
|
-
write();
|
|
416
|
-
}
|
|
417
|
-
if (e.key === 'Escape') close();
|
|
418
|
-
});
|
|
419
|
-
window.setTimeout(() => input.focus(), 30);
|
|
420
|
-
} catch (error) {
|
|
421
|
-
busyIds.delete(id);
|
|
422
|
-
window.alert(`EOS: Datenpunkt konnte nicht geschrieben werden: ${error?.message || error}`);
|
|
423
|
-
}
|
|
424
|
-
};
|
|
425
|
-
|
|
426
|
-
const run = root => {
|
|
427
|
-
if (!setSurfaceState()) return;
|
|
428
|
-
releaseNativeControls(root);
|
|
429
|
-
annotateValueCells(root);
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
let scheduled = false;
|
|
433
|
-
const pendingRoots = new Set();
|
|
434
|
-
const schedule = root => {
|
|
435
|
-
if (!setSurfaceState()) return;
|
|
436
|
-
if (root) pendingRoots.add(root);
|
|
437
|
-
if (scheduled) return;
|
|
438
|
-
scheduled = true;
|
|
439
|
-
const execute = () => {
|
|
440
|
-
scheduled = false;
|
|
441
|
-
const roots = pendingRoots.size ? Array.from(pendingRoots) : [document];
|
|
442
|
-
pendingRoots.clear();
|
|
443
|
-
roots.slice(0, 80).forEach(run);
|
|
444
|
-
};
|
|
445
|
-
if ('requestIdleCallback' in window) window.requestIdleCallback(execute, { timeout: 500 });
|
|
446
|
-
else window.requestAnimationFrame(execute);
|
|
447
|
-
};
|
|
448
|
-
|
|
449
|
-
const handlePointerAssist = event => {
|
|
450
|
-
if (!setSurfaceState()) return;
|
|
451
|
-
const cell = event.target?.closest?.('.eos-object-value-cell');
|
|
452
|
-
if (isWritableCell(cell)) cell.classList.add('eos-object-value-hover');
|
|
453
|
-
};
|
|
454
|
-
|
|
455
|
-
const handlePointerLeave = event => {
|
|
456
|
-
event.target?.closest?.('.eos-object-value-cell')?.classList.remove('eos-object-value-hover');
|
|
457
|
-
};
|
|
458
|
-
|
|
459
|
-
const shouldSkipFallback = cell => !!cell?.querySelector?.('.MuiSwitch-root,.admin-button,button,.copyButton');
|
|
460
|
-
|
|
461
|
-
const scheduleFallbackWriter = event => {
|
|
462
|
-
if (!setSurfaceState()) return;
|
|
463
|
-
const cell = event.target?.closest?.('.eos-object-value-cell,[data-eos-object-value-cell]');
|
|
464
|
-
if (!cell || !isStateValueCandidate(cell) || shouldSkipFallback(cell)) return;
|
|
465
|
-
const id = cell.getAttribute('data-eos-object-value-cell') || '';
|
|
466
|
-
if (!id) return;
|
|
467
|
-
window.setTimeout(() => {
|
|
468
|
-
if (!setSurfaceState()) return;
|
|
469
|
-
if (!cell.isConnected || hasNativeWriteDialog()) return;
|
|
470
|
-
openWriteDialog(cell, event);
|
|
471
|
-
}, 180);
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
window.addEventListener('hashchange', () => window.setTimeout(() => schedule(document), 30));
|
|
475
|
-
window.addEventListener('popstate', () => window.setTimeout(() => schedule(document), 30));
|
|
476
|
-
document.addEventListener('mouseover', handlePointerAssist, true);
|
|
477
|
-
document.addEventListener('mouseout', handlePointerLeave, true);
|
|
478
|
-
document.addEventListener('click', event => {
|
|
479
|
-
if (!setSurfaceState()) return;
|
|
480
|
-
const cell = event.target?.closest?.('.eos-object-value-cell,[data-eos-object-value-cell]');
|
|
481
|
-
if (cell) {
|
|
482
|
-
releaseNativeControls(cell);
|
|
483
|
-
scheduleFallbackWriter(event);
|
|
484
|
-
}
|
|
485
|
-
}, true);
|
|
486
|
-
document.addEventListener('click', event => {
|
|
487
|
-
if (!setSurfaceState()) return;
|
|
488
|
-
const nativeInteractive = event.target?.closest?.(`${interactiveSelector},${nativeLayerSelector},.eos-object-value-cell,[data-eos-object-value-cell]`);
|
|
489
|
-
if (nativeInteractive) {
|
|
490
|
-
releaseNativeControls(nativeInteractive);
|
|
491
|
-
scheduleFallbackWriter(event);
|
|
492
|
-
window.setTimeout(() => schedule(nativeInteractive), 80);
|
|
493
|
-
}
|
|
494
|
-
}, false);
|
|
495
|
-
document.addEventListener('keydown', event => {
|
|
496
|
-
if (!setSurfaceState()) return;
|
|
497
|
-
if (event.key !== 'Enter') return;
|
|
498
|
-
const cell = event.target?.closest?.('.eos-object-value-cell,[data-eos-object-value-cell]');
|
|
499
|
-
if (!cell || !isStateValueCandidate(cell) || shouldSkipFallback(cell)) return;
|
|
500
|
-
event.preventDefault();
|
|
501
|
-
openWriteDialog(cell, event);
|
|
502
|
-
}, true);
|
|
503
|
-
|
|
504
|
-
const observer = new MutationObserver(records => {
|
|
505
|
-
if (!setSurfaceState()) return;
|
|
506
|
-
for (const rec of records) {
|
|
507
|
-
rec.addedNodes?.forEach(node => {
|
|
508
|
-
if (node.nodeType === Node.ELEMENT_NODE) schedule(node);
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
const start = () => {
|
|
514
|
-
setSurfaceState();
|
|
515
|
-
schedule(document);
|
|
516
|
-
observer.observe(document.documentElement, { childList: true, subtree: true });
|
|
517
|
-
window.setInterval(() => schedule(document), 60000);
|
|
518
|
-
};
|
|
519
|
-
|
|
520
|
-
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start, { once: true });
|
|
521
|
-
else start();
|
|
4
|
+
/**
|
|
5
|
+
* v53: native ObjectBrowser write mode
|
|
6
|
+
*
|
|
7
|
+
* The earlier EOS fast-write fallback captured value-cell clicks before the
|
|
8
|
+
* ioBroker ObjectBrowser could process them. That made the UI look writable
|
|
9
|
+
* for every state and caused unreliable writes on large object trees.
|
|
10
|
+
*
|
|
11
|
+
* From v53 on, this helper is intentionally passive: it only publishes a
|
|
12
|
+
* version marker and removes the unrestricted writer from older cached
|
|
13
|
+
* sessions. The original ioBroker ObjectBrowser decides writability via
|
|
14
|
+
* common.write and performs the state write through socket.setState.
|
|
15
|
+
*/
|
|
16
|
+
window.NEXOWATT_EOS_OBJECTS_STATE_TOOLS_VERSION = 'v53-native-objectbrowser-write';
|
|
17
|
+
window.NEXOWATT_EOS_OBJECTS_STATE_TOOLS_MODE = 'native-objectbrowser';
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
delete window.NEXOWATT_EOS_WRITE_STATE_UNRESTRICTED;
|
|
21
|
+
} catch {
|
|
22
|
+
window.NEXOWATT_EOS_WRITE_STATE_UNRESTRICTED = undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
document.documentElement.classList.remove('eos-dp-write-ready');
|
|
27
|
+
} catch {
|
|
28
|
+
// ignore
|
|
29
|
+
}
|
|
522
30
|
})();
|