iobroker.eos-admin 7.9.79 → 7.9.81

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.
@@ -3842,3 +3842,111 @@ html.eos-app.eos-objects-surface .eos-object-value-cell .admin-button,
3842
3842
  html.eos-objects-surface .eos-object-value-cell .admin-button {
3843
3843
  margin-left: auto !important;
3844
3844
  }
3845
+
3846
+ /* === NexoWatt EOS v80: modern navigation icon refresh ==================== */
3847
+ html.eos-app .eos-top-toolbar .MuiIconButton-root,
3848
+ html.eos-app .eos-top-toolbar button.MuiButtonBase-root:not(.eos-brand-badge) {
3849
+ border: 1px solid rgba(104, 208, 255, 0.16) !important;
3850
+ background: linear-gradient(180deg, rgba(10, 30, 46, 0.88), rgba(7, 19, 32, 0.94)) !important;
3851
+ box-shadow: 0 10px 22px rgba(0, 0, 0, 0.22), inset 0 1px 0 rgba(255,255,255,0.05) !important;
3852
+ transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease, background .18s ease !important;
3853
+ }
3854
+
3855
+ html.eos-app .eos-top-toolbar .MuiIconButton-root:hover,
3856
+ html.eos-app .eos-top-toolbar button.MuiButtonBase-root:not(.eos-brand-badge):hover {
3857
+ transform: translateY(-1px);
3858
+ border-color: rgba(0, 255, 136, 0.30) !important;
3859
+ box-shadow: 0 14px 26px rgba(0, 0, 0, 0.28), 0 0 0 1px rgba(0,255,136,0.12) inset !important;
3860
+ }
3861
+
3862
+ html.eos-app .eos-top-toolbar .MuiSvgIcon-root {
3863
+ filter: drop-shadow(0 0 10px rgba(0, 212, 255, 0.10));
3864
+ }
3865
+
3866
+ html.eos-app .eos-scroll-nav .MuiListItemButton-root,
3867
+ html.eos-app .eos-scroll-nav .MuiButtonBase-root.MuiListItemButton-root,
3868
+ html.eos-app .eos-scroll-nav a,
3869
+ html.eos-app .eos-scroll-nav button {
3870
+ display: inline-flex !important;
3871
+ align-items: center !important;
3872
+ gap: 12px !important;
3873
+ }
3874
+
3875
+ html.eos-app .eos-scroll-nav .MuiListItemIcon-root.eos-legacy-nav-icon {
3876
+ display: none !important;
3877
+ }
3878
+
3879
+ html.eos-app .eos-scroll-nav .MuiListItemText-root {
3880
+ margin: 0 !important;
3881
+ }
3882
+
3883
+ html.eos-app .eos-scroll-nav .MuiListItemText-root .MuiTypography-root,
3884
+ html.eos-app .eos-scroll-nav .MuiTypography-root {
3885
+ font-weight: 800 !important;
3886
+ letter-spacing: -0.01em;
3887
+ }
3888
+
3889
+ .eos-modern-nav-icon {
3890
+ width: 34px;
3891
+ height: 34px;
3892
+ min-width: 34px;
3893
+ min-height: 34px;
3894
+ display: inline-flex;
3895
+ align-items: center;
3896
+ justify-content: center;
3897
+ border-radius: 12px;
3898
+ color: rgba(225, 244, 255, 0.92);
3899
+ background:
3900
+ radial-gradient(circle at 30% 30%, rgba(0,255,136,0.18), transparent 48%),
3901
+ linear-gradient(180deg, rgba(17, 43, 66, 0.96), rgba(7, 19, 33, 0.96));
3902
+ border: 1px solid rgba(96, 189, 255, 0.18);
3903
+ box-shadow:
3904
+ 0 9px 18px rgba(0, 0, 0, 0.22),
3905
+ inset 0 1px 0 rgba(255,255,255,0.06),
3906
+ 0 0 0 1px rgba(0,255,136,0.05);
3907
+ transition: transform .18s ease, border-color .18s ease, color .18s ease, box-shadow .18s ease, background .18s ease;
3908
+ }
3909
+
3910
+ .eos-modern-nav-icon svg {
3911
+ width: 18px;
3912
+ height: 18px;
3913
+ display: block;
3914
+ }
3915
+
3916
+ html.eos-app .eos-scroll-nav .MuiListItemButton-root:hover .eos-modern-nav-icon,
3917
+ html.eos-app .eos-scroll-nav .MuiButtonBase-root.MuiListItemButton-root:hover .eos-modern-nav-icon,
3918
+ html.eos-app .eos-scroll-nav a:hover .eos-modern-nav-icon,
3919
+ html.eos-app .eos-scroll-nav button:hover .eos-modern-nav-icon {
3920
+ transform: translateY(-1px);
3921
+ color: #f9ffff;
3922
+ border-color: rgba(0, 255, 136, 0.30);
3923
+ box-shadow:
3924
+ 0 12px 22px rgba(0, 0, 0, 0.26),
3925
+ 0 0 20px rgba(0, 255, 136, 0.10),
3926
+ inset 0 1px 0 rgba(255,255,255,0.08);
3927
+ }
3928
+
3929
+ html.eos-app .eos-scroll-nav .Mui-selected .eos-modern-nav-icon,
3930
+ html.eos-app .eos-scroll-nav .MuiListItemButton-root[aria-current="page"] .eos-modern-nav-icon,
3931
+ html.eos-app .eos-scroll-nav .MuiButtonBase-root.MuiListItemButton-root[aria-current="page"] .eos-modern-nav-icon {
3932
+ color: #022031;
3933
+ background: linear-gradient(135deg, rgba(0,255,136,0.98), rgba(0,212,255,0.92));
3934
+ border-color: rgba(255,255,255,0.30);
3935
+ box-shadow:
3936
+ 0 12px 24px rgba(0, 0, 0, 0.28),
3937
+ 0 0 22px rgba(0,255,136,0.22),
3938
+ inset 0 1px 0 rgba(255,255,255,0.26);
3939
+ }
3940
+
3941
+ html.eos-app.eos-nav-compact .eos-modern-nav-icon {
3942
+ width: 30px;
3943
+ height: 30px;
3944
+ min-width: 30px;
3945
+ min-height: 30px;
3946
+ border-radius: 10px;
3947
+ }
3948
+
3949
+ html.eos-app.eos-nav-compact .eos-modern-nav-icon svg {
3950
+ width: 16px;
3951
+ height: 16px;
3952
+ }
@@ -36,7 +36,7 @@
36
36
  rel="stylesheet"
37
37
  href="css/leaflet.css"
38
38
  />
39
- <link rel="stylesheet" href="./css/eos-branding.css?v=79" />
39
+ <link rel="stylesheet" href="./css/eos-branding.css?v=81" />
40
40
  <link
41
41
  rel="manifest"
42
42
  href="manifest.json"
@@ -160,7 +160,7 @@
160
160
  <link rel="modulepreload" crossorigin href="./assets/preload-helper-BDBacUwf.js">
161
161
  <link rel="modulepreload" crossorigin href="./assets/iobroker_admin__mf_v__runtimeInit__mf_v__-g2X2zhAf.js">
162
162
  <script defer src="./js/eos-policy-client.js?v=79"></script>
163
- <script defer src="./js/eos-branding.js?v=79"></script>
163
+ <script defer src="./js/eos-branding.js?v=81"></script>
164
164
  <script defer src="./js/eos-security-ui.js?v=79"></script>
165
165
  <script defer src="./js/eos-role-ui.js?v=79"></script>
166
166
  <script defer src="./js/eos-assistant.js?v=79"></script>
@@ -1,7 +1,7 @@
1
1
  (() => {
2
2
  'use strict';
3
3
 
4
- window.NEXOWATT_EOS_UI_VERSION = 'v79-direct-control-runtime-fix';
4
+ window.NEXOWATT_EOS_UI_VERSION = 'v81-modern-nav-icons-validation-fix';
5
5
 
6
6
  const BRAND = 'NexoWatt EOS';
7
7
  const EOS_MEANING = 'Energy Operation System';
@@ -905,6 +905,7 @@
905
905
  ensureBrandBadge(toolbar);
906
906
  }
907
907
  patchDrawerHeader(document.querySelector('.MuiDrawer-paper'));
908
+ applyModernNavIcons();
908
909
  hideNativeLogoutNav();
909
910
  releaseNotificationControls();
910
911
  ensurePopupCompatibility();
@@ -943,6 +944,70 @@
943
944
  .replace(/\s+/g, ' ')
944
945
  .trim();
945
946
 
947
+
948
+ const MODERN_NAV_ICONS = {
949
+ cockpit: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="3.5" width="7" height="7" rx="1.8"/><rect x="13.5" y="3.5" width="7" height="7" rx="1.8"/><rect x="3.5" y="13.5" width="7" height="7" rx="1.8"/><rect x="13.5" y="13.5" width="7" height="7" rx="1.8"/></svg>',
950
+ modules: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3.7 18.7 7.5v8.9L12 20.3 5.3 16.4V7.5L12 3.7Z"/><path d="M12 3.7v8.3m6.7-4.5L12 12 5.3 7.5"/></svg>',
951
+ services: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4.5" width="16" height="5" rx="2"/><rect x="4" y="14.5" width="16" height="5" rx="2"/><path d="M8 7h.01M8 17h.01M12 7h5M12 17h5"/></svg>',
952
+ datapoints: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="12" r="2.3"/><circle cx="18" cy="6" r="2.3"/><circle cx="18" cy="18" r="2.3"/><path d="M8.2 11l7.4-4M8.2 13l7.4 4"/></svg>',
953
+ structure: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="4" width="7" height="4.5" rx="1.4"/><rect x="13.5" y="4" width="7" height="4.5" rx="1.4"/><rect x="8.5" y="15.5" width="7" height="4.5" rx="1.4"/><path d="M7 8.5v3h10v-3M12 11.5v4"/></svg>',
954
+ logs: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M5 6.5h14M5 12h9M5 17.5h14"/><path d="m15.5 10.5 2.2 2.2 3.3-4"/></svg>',
955
+ rights: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3.5 18.5 6v5.1c0 4.2-2.7 7.3-6.5 9.4-3.8-2.1-6.5-5.2-6.5-9.4V6L12 3.5Z"/><path d="M9.6 11.8 11 13.2l3.6-3.6"/></svg>',
956
+ scripts: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M8.8 7 4.5 12l4.3 5M15.2 7l4.3 5-4.3 5M13.2 5 10.8 19"/></svg>',
957
+ eos: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3.5v4.3M12 16.2v4.3M4.9 6.2l3 3M16.1 14.8l3 3M3.5 12h4.3M16.2 12h4.3M4.9 17.8l3-3M16.1 9.2l3-3"/><circle cx="12" cy="12" r="3.7"/></svg>',
958
+ hosts: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4.5" width="16" height="10" rx="2.2"/><path d="M8 19.5h8M12 14.5v5M7.5 8.5h.01M11 8.5h6"/></svg>',
959
+ backup: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M6 6h10a3 3 0 0 1 3 3v7.5a2.5 2.5 0 0 1-2.5 2.5h-9A2.5 2.5 0 0 1 5 16.5V8a2 2 0 0 1 2-2Z"/><path d="M9 6V4.5h4V6M9 12.5h6M12 9.5v6"/></svg>',
960
+ files: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7.5A2.5 2.5 0 0 1 6.5 5H10l2 2h5.5A2.5 2.5 0 0 1 20 9.5v7A2.5 2.5 0 0 1 17.5 19h-11A2.5 2.5 0 0 1 4 16.5v-9Z"/></svg>',
961
+ default: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="8"/><path d="M12 8v4l2.6 2.6"/></svg>'
962
+ };
963
+
964
+ const navKeyFromLabel = label => {
965
+ const text = normalize(label);
966
+ if (!text) return '';
967
+ if (/cockpit|ubersicht|overview/.test(text)) return 'cockpit';
968
+ if (/module|adapter/.test(text)) return 'modules';
969
+ if (/dienste|instanzen|instances|services/.test(text)) return 'services';
970
+ if (/datenpunkte|objekte|objects|states/.test(text)) return 'datapoints';
971
+ if (/struktur|kategorien|categories|tree|enum/.test(text)) return 'structure';
972
+ if (/systemlogs|protokolle|logs/.test(text)) return 'logs';
973
+ if (/zugange|rechte|benutzer|users|permissions/.test(text)) return 'rights';
974
+ if (/skripte|scripts|javascript/.test(text)) return 'scripts';
975
+ if (/eos cockpit|nexowatt eos|nexowatt ems/.test(text)) return 'eos';
976
+ if (/system-hosts|hosts|host/.test(text)) return 'hosts';
977
+ if (/sicherung|backup|backitup/.test(text)) return 'backup';
978
+ if (/dateien|files/.test(text)) return 'files';
979
+ return '';
980
+ };
981
+
982
+ const applyModernNavIcons = () => safe(() => {
983
+ const navRoot = document.querySelector('.eos-scroll-nav');
984
+ if (!navRoot) return;
985
+ const items = Array.from(navRoot.querySelectorAll('.MuiListItemButton-root, .MuiButtonBase-root.MuiListItemButton-root, a, button'));
986
+ items.forEach(item => {
987
+ if (!item || item.closest('.eos-native-drawer-header') || item.classList.contains('eos-hidden-logout')) return;
988
+ const labelNode = item.querySelector('.MuiListItemText-root .MuiTypography-root, .MuiListItemText-root, .MuiTypography-root') || item;
989
+ const rawText = labelNode.textContent || item.getAttribute('aria-label') || item.getAttribute('title') || item.textContent || '';
990
+ const key = navKeyFromLabel(rawText);
991
+ if (!key) return;
992
+ item.dataset.eosNavKey = key;
993
+ let icon = item.querySelector(':scope > .eos-modern-nav-icon');
994
+ if (!icon) {
995
+ icon = document.createElement('span');
996
+ icon.className = 'eos-modern-nav-icon';
997
+ icon.setAttribute('aria-hidden', 'true');
998
+ const before = item.querySelector('.MuiListItemText-root') || item.firstElementChild || null;
999
+ item.insertBefore(icon, before);
1000
+ }
1001
+ const svg = MODERN_NAV_ICONS[key] || MODERN_NAV_ICONS.default;
1002
+ if (icon.dataset.svg !== svg) {
1003
+ icon.dataset.svg = svg;
1004
+ icon.innerHTML = svg;
1005
+ }
1006
+ const legacyIcon = item.querySelector('.MuiListItemIcon-root');
1007
+ if (legacyIcon) legacyIcon.classList.add('eos-legacy-nav-icon');
1008
+ });
1009
+ });
1010
+
946
1011
  const permissionKey = label => {
947
1012
  const text = normalize(label);
948
1013
  if (/auflisten|list/.test(text)) return 'list';
package/io-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "eos-admin",
4
- "version": "7.9.79",
4
+ "version": "7.9.81",
5
5
  "titleLang": {
6
6
  "en": "NexoWatt EOS Admin",
7
7
  "de": "NexoWatt EOS Admin",
@@ -242,6 +242,11 @@
242
242
  "en": "Stability consolidation: one coherent frontend runtime, resilient role policy loading, reversible EOS ACL handling, native datapoint semantics and hardened update caching.",
243
243
  "de": "Stabilitätskonsolidierung: eine einheitliche Frontend-Laufzeit, robuste Rollenabfrage, reversible EOS-ACLs, native Datenpunktlogik und abgesicherter Update-Cache.",
244
244
  "nl": "Stabiliteitsconsolidatie: één consistente frontend-runtime, robuuste rolcontrole, herstelbare EOS-ACLs, native datapuntlogica en veiligere updatecache."
245
+ },
246
+ "7.9.81": {
247
+ "en": "Fixes release validation for the modern EOS navigation icon update: package, lockfile and src-admin versions are synchronized, branding cache versioning is separated from the stable v79 React runtime, and future package checks verify both values explicitly.",
248
+ "de": "Korrigiert die Release-Validierung des modernen EOS-Navigations-Icon-Updates: Paket-, Lockfile- und src-admin-Versionen sind synchron, die Branding-Cache-Version ist sauber von der stabilen v79-React-Runtime getrennt und zukünftige Paketprüfungen kontrollieren beide Werte ausdrücklich.",
249
+ "nl": "Herstelt de releasevalidatie van de moderne EOS-navigatie-iconen: pakket-, lockfile- en src-admin-versies zijn gesynchroniseerd, de branding-cacheversie is gescheiden van de stabiele v79 React-runtime en toekomstige pakketcontroles valideren beide waarden expliciet."
245
250
  }
246
251
  },
247
252
  "desc": {
@@ -279,7 +284,7 @@
279
284
  "icon": "admin.svg",
280
285
  "messagebox": true,
281
286
  "enabled": true,
282
- "extIcon": "https://unpkg.com/iobroker.eos-admin@7.9.79/admin/admin.svg",
287
+ "extIcon": "https://unpkg.com/iobroker.eos-admin@7.9.81/admin/admin.svg",
283
288
  "keywords": [
284
289
  "NexoWatt",
285
290
  "EOS",
@@ -290,7 +295,7 @@
290
295
  "licensed"
291
296
  ],
292
297
  "compact": true,
293
- "readme": "https://unpkg.com/iobroker.eos-admin@7.9.79/README.md",
298
+ "readme": "https://unpkg.com/iobroker.eos-admin@7.9.81/README.md",
294
299
  "authors": [
295
300
  "bluefox <bluefox@ccu.io>",
296
301
  "hobbyquaker <hq@ccu.io>"
@@ -359,7 +364,7 @@
359
364
  "nondeletable": false,
360
365
  "allowAdapterUpdate": true,
361
366
  "allowAdapterDelete": false,
362
- "meta": "https://unpkg.com/iobroker.eos-admin@7.9.79/io-package.json",
367
+ "meta": "https://unpkg.com/iobroker.eos-admin@7.9.81/io-package.json",
363
368
  "npmPackage": "iobroker.eos-admin",
364
369
  "packetName": "iobroker.eos-admin"
365
370
  },
@@ -1038,5 +1043,5 @@
1038
1043
  }
1039
1044
  }
1040
1045
  },
1041
- "version": "7.9.79"
1046
+ "version": "7.9.81"
1042
1047
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "iobroker.eos-admin",
3
3
  "description": "NexoWatt EOS Admin stable runtime with reliable module filter popups and native datapoint semantics",
4
- "version": "7.9.79",
4
+ "version": "7.9.81",
5
5
  "contributors": [
6
6
  "bluefox <dogafox@gmail.com>",
7
7
  "apollon77",
@@ -11,11 +11,22 @@ const readJson = file => JSON.parse(fs.readFileSync(path.join(root, file), 'utf8
11
11
  const exists = file => fs.existsSync(path.join(root, file));
12
12
 
13
13
  const pkg = readJson('package.json');
14
+ const pkgLock = readJson('package-lock.json');
14
15
  const io = readJson('io-package.json');
16
+ const srcPkg = readJson('src-admin/package.json');
17
+ const srcPkgLock = readJson('src-admin/package-lock.json');
18
+ const srcVersion = readJson('src-admin/src/version.json');
19
+ const buildInfo = readJson('NEXOWATT_EOS_BUILD_INFO.json');
15
20
 
16
21
  if (pkg.name !== 'iobroker.eos-admin') fail(`package.json name must be iobroker.eos-admin, got ${pkg.name}`);
17
22
  if (pkg.private !== false) fail('package.json private must be false for npm publishing');
18
- if (pkg.version !== io.common.version) fail(`package.json and io-package.json versions differ: ${pkg.version} vs ${io.common.version}`);
23
+ if (pkg.version !== io.common.version) fail(`package.json and io-package.json common.version differ: ${pkg.version} vs ${io.common.version}`);
24
+ if (io.version !== pkg.version) fail(`io-package top-level version must match package.json: ${io.version} vs ${pkg.version}`);
25
+ if (pkgLock.version !== pkg.version || pkgLock.packages?.['']?.version !== pkg.version) fail('package-lock.json versions must match package.json');
26
+ if (srcPkg.version !== pkg.version) fail('src-admin/package.json version must match package.json');
27
+ if (srcPkgLock.version !== pkg.version || srcPkgLock.packages?.['']?.version !== pkg.version) fail('src-admin/package-lock.json versions must match package.json');
28
+ if (srcVersion.version !== pkg.version) fail('src-admin/src/version.json version must match package.json');
29
+ if (buildInfo.version !== pkg.version) fail('NEXOWATT_EOS_BUILD_INFO.json version must match package.json');
19
30
  if (io.common.name !== 'eos-admin') fail(`io-package common.name must be eos-admin, got ${io.common.name}`);
20
31
 
21
32
  if (io.common.packetName !== 'iobroker.eos-admin') fail(`io-package common.packetName must be iobroker.eos-admin, got ${io.common.packetName}`);
@@ -72,14 +83,14 @@ const mainBuild = fs.readFileSync(path.join(root, 'build/main.js'), 'utf8');
72
83
  if (!mainBuild.includes('v37 BackItUp/runtime-adapter compatibility')) fail('build/main.js lacks v37 BackItUp compatibility guard');
73
84
 
74
85
 
75
- const srcPkg = readJson('src-admin/package.json');
76
- const srcVersion = readJson('src-admin/src/version.json');
77
86
  if (srcPkg.version !== pkg.version || srcVersion.version !== pkg.version) fail('src-admin versions must match package.json');
78
- const buildInfo = readJson('NEXOWATT_EOS_BUILD_INFO.json');
79
87
  const runtime = buildInfo.runtimeEntry;
80
88
  const runtimeNumber = Number(String(runtime).replace(/^v/, ''));
89
+ const brandingCacheVersion = Number(buildInfo.brandingCacheVersion ?? runtimeNumber);
81
90
  if (!runtime || !Number.isFinite(runtimeNumber)) fail(`invalid runtimeEntry ${runtime}`);
91
+ if (!Number.isFinite(brandingCacheVersion)) fail(`invalid brandingCacheVersion ${buildInfo.brandingCacheVersion}`);
82
92
  if (!index.includes(`hostInit-${runtime}.js?v=${runtimeNumber}`) || !index.includes(`index-CQZugZ1z-${runtime}.js?v=${runtimeNumber}`)) fail(`adminWww/index.html must load the ${runtime} runtime`);
93
+ if (!index.includes(`css/eos-branding.css?v=${brandingCacheVersion}`) || !index.includes(`js/eos-branding.js?v=${brandingCacheVersion}`)) fail(`adminWww/index.html must load branding cache v${brandingCacheVersion}`);
83
94
  if (!index.includes(`eos-manual-write-policy.js?v=${runtimeNumber}`)) fail(`adminWww/index.html must load the ${runtime} manual-write policy`);
84
95
  if (index.indexOf(`eos-manual-write-policy.js?v=${runtimeNumber}`) > index.indexOf(`index-CQZugZ1z-${runtime}.js?v=${runtimeNumber}`)) fail('manual-write policy must load before the React runtime');
85
96