iobroker.eos-admin 7.9.66 → 7.9.67

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.
@@ -0,0 +1,2 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./bootstrap-COulQZax-v67.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-COulQZax-v67.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);
@@ -3864,7 +3864,7 @@ html.eos-app .eos-native-drawer-header-hidden {
3864
3864
  }
3865
3865
 
3866
3866
 
3867
- /* === NexoWatt EOS v7.9.66: native desktop drawer-header hard remove ======
3867
+ /* === NexoWatt EOS v7.9.65: native desktop drawer-header hard remove ======
3868
3868
  The upstream drawer identity block contains a /#easy link plus the chevron
3869
3869
  button. It is redundant in the EOS horizontal shell and caused the small
3870
3870
  floating NexoWatt tab above the real header. Target the actual structure,
@@ -3893,32 +3893,58 @@ html.eos-app [data-eos-native-drawer-header-hidden="true"] {
3893
3893
  }
3894
3894
 
3895
3895
 
3896
- /* === NexoWatt EOS v7.9.66: exact desktop AppBar duplicate removal =========
3897
- The top-left ghost tab is the native desktop MenuIcon plus the compact
3898
- /#easy logo identity from App.renderToolbar(), not Drawer.getHeader(). */
3899
- html.eos-app .eos-top-toolbar > .eos-native-toolbar-menu-hidden,
3900
- html.eos-app .eos-top-toolbar > .eos-native-toolbar-identity-hidden,
3901
- html.eos-app .eos-top-toolbar > [data-eos-native-toolbar-hidden="true"] {
3896
+ /* === NexoWatt EOS v7.9.67: restore primary brand, remove only ghost tab ===
3897
+ Keep the large NexoWatt EOS / Energy Operation System card. Hide only the
3898
+ short native NexoWatt+arrow block that is redundant in the EOS shell. */
3899
+ html.eos-app .eos-top-toolbar > .eos-brand-badge,
3900
+ html.eos-app .eos-top-toolbar > .eos-primary-brand,
3901
+ html.eos-app [data-eos-primary-brand="true"] {
3902
+ display: grid !important;
3903
+ visibility: visible !important;
3904
+ opacity: 1 !important;
3905
+ pointer-events: auto !important;
3906
+ overflow: visible !important;
3907
+ flex: 0 0 auto !important;
3908
+ }
3909
+
3910
+ html.eos-app .eos-native-top-left-ghost-hidden,
3911
+ html.eos-app [data-eos-native-top-left-ghost="true"] {
3902
3912
  display: none !important;
3903
3913
  visibility: hidden !important;
3904
3914
  opacity: 0 !important;
3905
3915
  pointer-events: none !important;
3906
- width: 0 !important; min-width: 0 !important; max-width: 0 !important;
3907
- height: 0 !important; min-height: 0 !important; max-height: 0 !important;
3908
- margin: 0 !important; padding: 0 !important; overflow: hidden !important;
3916
+ width: 0 !important;
3917
+ min-width: 0 !important;
3918
+ max-width: 0 !important;
3919
+ height: 0 !important;
3920
+ min-height: 0 !important;
3921
+ max-height: 0 !important;
3922
+ margin: 0 !important;
3923
+ padding: 0 !important;
3924
+ overflow: hidden !important;
3909
3925
  flex: 0 0 0 !important;
3926
+ border: 0 !important;
3927
+ box-shadow: none !important;
3910
3928
  }
3929
+
3911
3930
  @media (min-width: 901px) {
3912
- html.eos-app .eos-top-toolbar > button:has(svg[data-testid="MenuIcon"]),
3913
- html.eos-app .eos-top-toolbar > .MuiIconButton-root:has(svg[data-testid="MenuIcon"]),
3914
- html.eos-app .eos-top-toolbar > .MuiGrid-root:has(a[href="/#easy"]) {
3931
+ /* Exact upstream Drawer.getHeader fingerprint. This rule never targets the
3932
+ primary .eos-brand-badge in the AppBar. */
3933
+ html.eos-app .MuiDrawer-paper > *:not(.MuiList-root):has(a[href*="#easy"]):has(button),
3934
+ html.eos-app .MuiSwipeableDrawer-paper > *:not(.MuiList-root):has(a[href*="#easy"]):has(.MuiIconButton-root) {
3915
3935
  display: none !important;
3916
3936
  visibility: hidden !important;
3917
3937
  opacity: 0 !important;
3918
3938
  pointer-events: none !important;
3919
- width: 0 !important; min-width: 0 !important; max-width: 0 !important;
3920
- height: 0 !important; min-height: 0 !important; max-height: 0 !important;
3921
- margin: 0 !important; padding: 0 !important; overflow: hidden !important;
3939
+ width: 0 !important;
3940
+ min-width: 0 !important;
3941
+ max-width: 0 !important;
3942
+ height: 0 !important;
3943
+ min-height: 0 !important;
3944
+ max-height: 0 !important;
3945
+ margin: 0 !important;
3946
+ padding: 0 !important;
3947
+ overflow: hidden !important;
3922
3948
  flex: 0 0 0 !important;
3923
3949
  }
3924
3950
  }
@@ -4,8 +4,8 @@
4
4
  translate="no"
5
5
  >
6
6
  <head>
7
- <script src="./js/eos-console-quiet.js?v=66"></script>
8
- <script type="module" src="./assets/hostInit-v61.js?v=66"></script>
7
+ <script src="./js/eos-console-quiet.js?v=67"></script>
8
+ <script type="module" src="./assets/hostInit-v61.js?v=67"></script>
9
9
 
10
10
  <meta charset="utf-8" />
11
11
  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
@@ -35,7 +35,7 @@
35
35
  rel="stylesheet"
36
36
  href="css/leaflet.css"
37
37
  />
38
- <link rel="stylesheet" href="./css/eos-branding.css?v=66" />
38
+ <link rel="stylesheet" href="./css/eos-branding.css?v=67" />
39
39
  <link
40
40
  rel="manifest"
41
41
  href="manifest.json"
@@ -155,15 +155,15 @@
155
155
  false,
156
156
  );
157
157
  </script>
158
- <script type="module" crossorigin src="./assets/index-CQZugZ1z-v61.js?v=66"></script>
158
+ <script type="module" crossorigin src="./assets/index-CQZugZ1z-v67.js?v=67"></script>
159
159
  <link rel="modulepreload" crossorigin href="./assets/preload-helper-BDBacUwf.js">
160
160
  <link rel="modulepreload" crossorigin href="./assets/iobroker_admin__mf_v__runtimeInit__mf_v__-g2X2zhAf.js">
161
- <script defer src="./js/eos-branding.js?v=66"></script>
162
- <script defer src="./js/eos-adapter-surface-cleanup.js?v=66"></script>
163
- <script defer src="./js/eos-security-ui.js?v=66"></script>
164
- <script defer src="./js/eos-role-ui.js?v=66"></script>
165
- <script defer src="./js/eos-assistant.js?v=66"></script>
166
- <script defer src="./js/eos-objects-state-tools.js?v=66"></script>
161
+ <script defer src="./js/eos-branding.js?v=67"></script>
162
+ <script defer src="./js/eos-adapter-surface-cleanup.js?v=67"></script>
163
+ <script defer src="./js/eos-security-ui.js?v=67"></script>
164
+ <script defer src="./js/eos-role-ui.js?v=67"></script>
165
+ <script defer src="./js/eos-assistant.js?v=67"></script>
166
+ <script defer src="./js/eos-objects-state-tools.js?v=67"></script>
167
167
  </head>
168
168
  <body>
169
169
  <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 = 'v65-native-drawer-header-hard-remove';
4
+ window.NEXOWATT_EOS_UI_VERSION = 'v67-primary-logo-restore-native-ghost-remove';
5
5
 
6
6
  const BRAND = 'NexoWatt EOS';
7
7
  const EOS_MEANING = 'Energy Operation System';
@@ -771,14 +771,29 @@
771
771
  document.querySelectorAll('.eos-brand-badge').forEach(existing => {
772
772
  if (!toolbar.contains(existing)) existing.remove();
773
773
  });
774
- let badge = toolbar.querySelector('.eos-brand-badge');
774
+
775
+ let badge = toolbar.querySelector(':scope > .eos-brand-badge') || toolbar.querySelector('.eos-brand-badge');
775
776
  if (!badge) {
776
777
  badge = document.createElement('span');
777
- badge.className = 'eos-brand-badge eos-system-brand';
778
- const firstButton = toolbar.querySelector('button');
779
- toolbar.insertBefore(badge, firstButton || toolbar.firstChild || null);
778
+ badge.className = 'eos-brand-badge eos-system-brand eos-primary-brand';
779
+ }
780
+
781
+ // Never use a nested button as insertBefore reference. App.renderToolbar()
782
+ // can omit the desktop MenuIcon, in which case querySelector('button')
783
+ // points into a child wrapper and insertBefore throws a NotFoundError.
784
+ if (badge.parentElement !== toolbar || toolbar.firstElementChild !== badge) {
785
+ toolbar.insertBefore(badge, toolbar.firstElementChild || null);
780
786
  }
781
- badge.classList.add('eos-system-brand');
787
+
788
+ badge.classList.add('eos-system-brand', 'eos-primary-brand');
789
+ badge.dataset.eosPrimaryBrand = 'true';
790
+ badge.removeAttribute('hidden');
791
+ badge.removeAttribute('aria-hidden');
792
+ badge.removeAttribute('inert');
793
+ badge.style.removeProperty('display');
794
+ badge.style.removeProperty('visibility');
795
+ badge.style.removeProperty('opacity');
796
+ badge.style.removeProperty('pointer-events');
782
797
  badge.innerHTML = `
783
798
  <span class="eos-brand-badge-mark"><img class="eos-brand-badge-logo" src="${LOGO}" alt="${BRAND}" /></span>
784
799
  <span class="eos-brand-badge-copy"><strong>${BRAND}</strong><small>${EOS_MEANING}</small></span>
@@ -786,42 +801,79 @@
786
801
  `;
787
802
  };
788
803
 
804
+ const hideNativeTopLeftGhost = element => safe(() => {
805
+ if (!element) return;
806
+ if (
807
+ element.matches?.('.eos-brand-badge, .eos-primary-brand') ||
808
+ element.closest?.('.eos-brand-badge, .eos-primary-brand') ||
809
+ element.querySelector?.('.eos-brand-badge, .eos-primary-brand')
810
+ ) return;
811
+
812
+ const text = normalize(element.textContent || '');
813
+ // The wanted primary card contains the full product name and subtitle.
814
+ // The unwanted native tab contains only the short NexoWatt identity.
815
+ if (/energy operation system|nexowatt eos/.test(text)) return;
816
+
817
+ element.classList.add('eos-native-top-left-ghost-hidden');
818
+ element.dataset.eosNativeTopLeftGhost = 'true';
819
+ element.setAttribute('aria-hidden', 'true');
820
+ element.setAttribute('inert', '');
821
+ element.querySelectorAll?.('button, a, [role="button"], input, select, textarea').forEach(control => {
822
+ control.setAttribute('tabindex', '-1');
823
+ control.setAttribute('aria-hidden', 'true');
824
+ });
825
+ if (element.style) {
826
+ for (const name of [
827
+ 'display', 'visibility', 'opacity', 'pointer-events',
828
+ 'width', 'min-width', 'max-width', 'height', 'min-height', 'max-height',
829
+ 'margin', 'padding', 'overflow', 'flex', 'border', 'box-shadow',
830
+ ]) {
831
+ const value = name === 'display' ? 'none'
832
+ : name === 'visibility' ? 'hidden'
833
+ : name === 'opacity' ? '0'
834
+ : name === 'pointer-events' ? 'none'
835
+ : name === 'overflow' ? 'hidden'
836
+ : name === 'flex' ? '0 0 0'
837
+ : name === 'border' || name === 'box-shadow' ? 'none'
838
+ : '0';
839
+ element.style.setProperty(name, value, 'important');
840
+ }
841
+ }
842
+ });
789
843
 
844
+ const removeNativeTopLeftGhost = () => safe(() => {
845
+ if (!window.matchMedia('(min-width: 901px)').matches) return;
790
846
 
791
- const hideNativeCompactToolbarIdentity = toolbar => safe(() => {
792
- if (!toolbar || !window.matchMedia('(min-width: 901px)').matches) return;
793
-
794
- const hide = (element, className) => {
795
- if (!element || element.closest?.('.eos-brand-badge')) return;
796
- element.classList.add(className);
797
- element.dataset.eosNativeToolbarHidden = 'true';
798
- element.setAttribute('aria-hidden', 'true');
799
- element.setAttribute('inert', '');
800
- element.querySelectorAll?.('button, a, [role="button"], input, select, textarea').forEach(control => {
801
- control.setAttribute('tabindex', '-1');
802
- control.setAttribute('aria-hidden', 'true');
847
+ // Source 1: upstream Drawer.getHeader() identity + chevron block.
848
+ document.querySelectorAll('.MuiDrawer-paper, .MuiSwipeableDrawer-paper').forEach(drawer => {
849
+ Array.from(drawer.children || []).forEach(child => {
850
+ if (!child?.querySelector) return;
851
+ const text = normalize(child.textContent || '');
852
+ const hasIdentity = !!child.querySelector('a[href*="#easy"], img, .MuiAvatar-root') || /nexowatt|iobroker/.test(text);
853
+ const hasToggle = !!child.querySelector('button, .MuiIconButton-root, [role="button"]');
854
+ const isNavigationList = child.classList?.contains('MuiList-root') || !!child.querySelector('.MuiListItemButton-root');
855
+ if (hasIdentity && hasToggle && !isNavigationList) hideNativeTopLeftGhost(child);
803
856
  });
804
- if (element.style) {
805
- for (const [name, value] of Object.entries({
806
- display: 'none', visibility: 'hidden', opacity: '0',
807
- 'pointer-events': 'none', width: '0', 'min-width': '0', 'max-width': '0',
808
- height: '0', 'min-height': '0', 'max-height': '0',
809
- margin: '0', padding: '0', overflow: 'hidden', flex: '0 0 0',
810
- })) element.style.setProperty(name, value, 'important');
811
- }
812
- };
813
-
814
- // The visible tab is two native AppBar children: MenuIcon + compact /#easy identity.
815
- Array.from(toolbar.children).forEach(child => {
816
- if (child.matches?.('button, .MuiIconButton-root') && child.querySelector?.('svg[data-testid="MenuIcon"]')) {
817
- hide(child, 'eos-native-toolbar-menu-hidden');
818
- }
819
857
  });
820
- toolbar.querySelectorAll('a[href="/#easy"], a[href$="#easy"], a[href*="/#easy"]').forEach(link => {
821
- let directChild = link;
822
- while (directChild?.parentElement && directChild.parentElement !== toolbar) directChild = directChild.parentElement;
823
- if (directChild?.parentElement === toolbar) hide(directChild, 'eos-native-toolbar-identity-hidden');
858
+
859
+ // Source 2: stale native compact identity rendered as a small top-left
860
+ // AppBar child. Use geometry + short label, and explicitly protect the
861
+ // large primary EOS badge.
862
+ document.querySelectorAll('.MuiAppBar-root .MuiToolbar-root > *, .eos-top-toolbar > *').forEach(child => {
863
+ if (!child?.querySelector || child.matches?.('.eos-brand-badge, .eos-primary-brand')) return;
864
+ if (child.querySelector('.eos-brand-badge, .eos-primary-brand')) return;
865
+ const text = normalize(child.textContent || '');
866
+ const hasShortIdentity = text === 'nexowatt' || text === 'iobroker' || /^nexowatt\s*$/.test(text);
867
+ const hasEasyLink = !!child.querySelector('a[href*="#easy"]');
868
+ const hasToggle = !!child.querySelector('button, .MuiIconButton-root, svg');
869
+ const rect = child.getBoundingClientRect?.();
870
+ const isTopLeft = rect && rect.top < 105 && rect.left < 220 && rect.width < 230 && rect.height < 100;
871
+ if (isTopLeft && (hasShortIdentity || hasEasyLink) && hasToggle) hideNativeTopLeftGhost(child);
824
872
  });
873
+
874
+ // Restore/verify the correct large EOS identity after cleanup.
875
+ const toolbar = document.querySelector('#root > .MuiPaper-root > .MuiAppBar-root .MuiToolbar-root, header .MuiToolbar-root, .MuiAppBar-root .MuiToolbar-root');
876
+ if (toolbar) ensureBrandBadge(toolbar);
825
877
  });
826
878
 
827
879
  const ensureLogoutButton = () => {
@@ -952,8 +1004,8 @@
952
1004
  if (toolbar) {
953
1005
  toolbar.classList.add('eos-top-toolbar');
954
1006
  ensureBrandBadge(toolbar);
955
- hideNativeCompactToolbarIdentity(toolbar);
956
1007
  }
1008
+ removeNativeTopLeftGhost();
957
1009
  removeStrayNativeDrawerHeaders();
958
1010
  hideNativeLogoutNav();
959
1011
  releaseNotificationControls();
package/io-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "eos-admin",
4
- "version": "7.9.66",
4
+ "version": "7.9.67",
5
5
  "titleLang": {
6
6
  "en": "NexoWatt EOS Admin",
7
7
  "de": "NexoWatt EOS Admin",
@@ -259,7 +259,7 @@
259
259
  "icon": "admin.svg",
260
260
  "messagebox": true,
261
261
  "enabled": true,
262
- "extIcon": "https://unpkg.com/iobroker.eos-admin@7.9.66/admin/admin.svg",
262
+ "extIcon": "https://unpkg.com/iobroker.eos-admin@7.9.67/admin/admin.svg",
263
263
  "keywords": [
264
264
  "NexoWatt",
265
265
  "EOS",
@@ -270,7 +270,7 @@
270
270
  "licensed"
271
271
  ],
272
272
  "compact": true,
273
- "readme": "https://unpkg.com/iobroker.eos-admin@7.9.66/README.md",
273
+ "readme": "https://unpkg.com/iobroker.eos-admin@7.9.67/README.md",
274
274
  "authors": [
275
275
  "bluefox <bluefox@ccu.io>",
276
276
  "hobbyquaker <hq@ccu.io>"
@@ -339,7 +339,7 @@
339
339
  "nondeletable": false,
340
340
  "allowAdapterUpdate": true,
341
341
  "allowAdapterDelete": false,
342
- "meta": "https://unpkg.com/iobroker.eos-admin@7.9.66/io-package.json",
342
+ "meta": "https://unpkg.com/iobroker.eos-admin@7.9.67/io-package.json",
343
343
  "npmPackage": "iobroker.eos-admin",
344
344
  "packetName": "iobroker.eos-admin"
345
345
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "iobroker.eos-admin",
3
3
  "description": "NexoWatt EOS Admin interface with reliable repository update mapping and technical log preservation.",
4
- "version": "7.9.66",
4
+ "version": "7.9.67",
5
5
  "contributors": [
6
6
  "bluefox <dogafox@gmail.com>",
7
7
  "apollon77",
@@ -81,7 +81,7 @@ for (const asset of [
81
81
  if (!new RegExp(`${escaped}\\?v=${cacheTag}(?:["'])`).test(adminIndex)) fail(`adminWww/index.html cache tag is stale for ${asset}`);
82
82
  if (!new RegExp(`${escaped}\\?v=${cacheTag}(?:["'])`).test(sourceIndex)) fail(`src-admin/index.html cache tag is stale for ${asset}`);
83
83
  }
84
- for (const entry of ['hostInit-v61.js', 'index-CQZugZ1z-v61.js']) {
84
+ for (const entry of ['hostInit-v61.js', 'index-CQZugZ1z-v67.js']) {
85
85
  const escaped = entry.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
86
86
  if (!new RegExp(`${escaped}\\?v=${cacheTag}(?:["'])`).test(adminIndex)) fail(`adminWww/index.html entry cache tag is stale for ${entry}`);
87
87
  }
@@ -121,32 +121,41 @@ if (!branding.includes('eos-native-drawer-header-hidden') || !branding.includes(
121
121
  if (!branding.includes('removeStrayNativeDrawerHeaders') || !branding.includes('a[href=\"/#easy\"]')) fail('eos-branding.js lacks structural native drawer-header cleanup');
122
122
  if (!branding.includes('ensureStandaloneNavToggle')) fail('eos-branding.js lacks the independent EOS navigation toggle');
123
123
  const activeGraph = [
124
- fs.readFileSync(path.join(root, 'adminWww/assets/index-CQZugZ1z-v61.js'), 'utf8'),
125
- fs.readFileSync(path.join(root, 'adminWww/assets/bootstrap-COulQZax-v61.js'), 'utf8'),
124
+ fs.readFileSync(path.join(root, 'adminWww/assets/index-CQZugZ1z-v67.js'), 'utf8'),
125
+ fs.readFileSync(path.join(root, 'adminWww/assets/bootstrap-COulQZax-v67.js'), 'utf8'),
126
126
  fs.readFileSync(path.join(root, 'adminWww/remoteEntry-v61.js'), 'utf8'),
127
127
  ].join('\n');
128
- if (/-v(?:54|55|56|57|58|59|60)\.js/.test(activeGraph)) fail('active v61 frontend graph still imports an old versioned runtime file');
128
+ if (/bootstrap-COulQZax-v61\.js|(?:AdapterUpdateDialog|Adapters|Config|CustomTab|DeviceManager|EasyMode|Enums|Fields|Files|Hosts|Instances|Intro|Logs|Objects|Users)-[^\"']+-v61\.js/.test(activeGraph)) fail('active v67 frontend graph still imports a v61 application runtime/route chunk');
129
129
 
130
130
  const drawerSource = fs.readFileSync(path.join(root, 'src-admin/src/components/Drawer.tsx'), 'utf8');
131
- const activeBootstrap = fs.readFileSync(path.join(root, 'adminWww/assets/bootstrap-COulQZax-v61.js'), 'utf8');
131
+ const activeBootstrap = fs.readFileSync(path.join(root, 'adminWww/assets/bootstrap-COulQZax-v67.js'), 'utf8');
132
132
  const brandingCss = fs.readFileSync(path.join(root, 'adminWww/css/eos-branding.css'), 'utf8');
133
133
  if (!drawerSource.includes('if (!this.isSwipeable())') || !drawerSource.includes('return null;')) fail('Drawer.tsx still renders the native desktop drawer header');
134
134
  if (!activeBootstrap.includes('getHeader(){if(!this.isSwipeable())return null;')) fail('active bootstrap still renders the native desktop drawer header');
135
135
  if (!brandingCss.includes('a[href=\"/#easy\"]') || !brandingCss.includes('data-eos-native-drawer-header-hidden')) fail('branding CSS lacks structural native drawer-header fallback');
136
136
 
137
137
  const appSource = fs.readFileSync(path.join(root, 'src-admin/src/App.tsx'), 'utf8');
138
- const toolbarStart = activeBootstrap.indexOf('renderToolbar(e){');
139
- const toolbarEnd = toolbarStart >= 0 ? activeBootstrap.indexOf('renderSampleError()', toolbarStart) : -1;
140
- const activeToolbar = toolbarStart >= 0 && toolbarEnd > toolbarStart ? activeBootstrap.slice(toolbarStart, toolbarEnd) : '';
141
- if (!appSource.includes('EOS desktop: do not render the upstream compact toolbar menu/logo')) fail('App.tsx lacks exact desktop toolbar duplicate removal');
142
- if (!activeToolbar.includes('children:[e&&jsxRuntimeExports.jsx(')) fail('active bootstrap still renders desktop MenuIcon unconditionally');
143
- if (!activeToolbar.includes('e&&this.state.drawerState!==STATES.opened&&!this.state.expertMode&&window.innerWidth>450&&')) fail('active bootstrap still renders compact desktop /#easy identity');
144
- if (!branding.includes('hideNativeCompactToolbarIdentity')) fail('branding lacks exact AppBar compact identity fallback');
145
- if (!brandingCss.includes('eos-native-toolbar-menu-hidden') || !brandingCss.includes('svg[data-testid="MenuIcon"]')) fail('branding CSS lacks exact AppBar duplicate fallback');
138
+ if (!branding.includes('eos-primary-brand') || !branding.includes('toolbar.firstElementChild')) fail('branding lacks robust primary EOS brand insertion');
139
+ if (!branding.includes('removeNativeTopLeftGhost') || !branding.includes('eos-native-top-left-ghost-hidden')) fail('branding lacks exact native top-left ghost removal');
140
+ if (!brandingCss.includes('data-eos-primary-brand') || !brandingCss.includes('data-eos-native-top-left-ghost')) fail('branding CSS lacks primary-brand/ghost safeguards');
141
+ if (!activeBootstrap.includes('getHeader(){if(!this.isSwipeable())return null;')) fail('fresh v67 bootstrap still renders desktop Drawer.getHeader()');
142
+ if (!activeBootstrap.includes('children:[jsxRuntimeExports.jsx(')) fail('v67 bootstrap did not restore the normal toolbar structure required by the EOS brand injector');
143
+
144
+ for (const file of [
145
+ 'AdapterUpdateDialog-BMg84Hpf-v67.js', 'Adapters-B5_jQ7DE-v67.js', 'Config-hHK2UzGP-v67.js',
146
+ 'CustomTab-B0wqoazH-v67.js', 'DeviceManager-BFmQeYQ1-v67.js', 'EasyMode-B1d9Vdc4-v67.js',
147
+ 'Enums-DbWYxKOo-v67.js', 'Fields-CX3rKuWb-v67.js', 'Files-Cd2HOzIE-v67.js',
148
+ 'Hosts-Bg8QzW5i-v67.js', 'Instances-YdaGnS5a-v67.js', 'Intro-DkwRiz1n-v67.js',
149
+ 'Logs-CsVPSLJH-v67.js', 'Objects-DPan0bzw-v67.js', 'Users-BgnBRgwU-v67.js',
150
+ ]) {
151
+ if (!exists(path.join('adminWww/assets', file))) fail(`missing fresh v67 route chunk: ${file}`);
152
+ const chunk = fs.readFileSync(path.join(root, 'adminWww/assets', file), 'utf8');
153
+ if (chunk.includes('bootstrap-COulQZax-v61.js')) fail(`${file} still imports bootstrap-v61`);
154
+ }
146
155
 
147
156
  const activeAdapterReact = fs.readFileSync(path.join(root, 'adminWww/assets/index-D2ymscJA-v61.js'), 'utf8');
148
- const activeObjects = fs.readFileSync(path.join(root, 'adminWww/assets/Objects-DPan0bzw-v61.js'), 'utf8');
149
- const activeAdapters = fs.readFileSync(path.join(root, 'adminWww/assets/Adapters-B5_jQ7DE-v61.js'), 'utf8');
157
+ const activeObjects = fs.readFileSync(path.join(root, 'adminWww/assets/Objects-DPan0bzw-v67.js'), 'utf8');
158
+ const activeAdapters = fs.readFileSync(path.join(root, 'adminWww/assets/Adapters-B5_jQ7DE-v67.js'), 'utf8');
150
159
  for (const marker of ['eos-object-value-cell', 'data-eos-object-writable']) {
151
160
  if (!activeAdapterReact.includes(marker)) fail(`active ObjectBrowser bundle lacks required marker: ${marker}`);
152
161
  }