pinokiod 7.5.50 → 7.5.52

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "7.5.50",
3
+ "version": "7.5.52",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1530,6 +1530,40 @@ body.main-sidebar-page aside.main-sidebar .tab.selected .main-sidebar-action-ico
1530
1530
  white-space: nowrap;
1531
1531
  word-wrap: normal !important;
1532
1532
  }
1533
+ .main-sidebar .main-sidebar-status-badge {
1534
+ grid-column: 3;
1535
+ justify-self: end;
1536
+ min-width: 28px;
1537
+ height: 15px;
1538
+ padding: 0 5px;
1539
+ box-sizing: border-box;
1540
+ border-radius: 999px;
1541
+ display: inline-flex;
1542
+ align-items: center;
1543
+ justify-content: center;
1544
+ background: rgba(15, 23, 42, 0.07);
1545
+ color: rgba(31, 41, 55, 0.6);
1546
+ font-size: 9px;
1547
+ font-weight: 700;
1548
+ line-height: 1;
1549
+ letter-spacing: 0;
1550
+ white-space: nowrap;
1551
+ }
1552
+ .main-sidebar .main-sidebar-status-badge[hidden] {
1553
+ display: none !important;
1554
+ }
1555
+ .main-sidebar .main-sidebar-status-badge[data-state="on"] {
1556
+ background: rgba(45, 180, 92, 0.14);
1557
+ color: #247a43;
1558
+ }
1559
+ body.dark .main-sidebar .main-sidebar-status-badge {
1560
+ background: rgba(255, 255, 255, 0.08);
1561
+ color: rgba(229, 231, 235, 0.68);
1562
+ }
1563
+ body.dark .main-sidebar .main-sidebar-status-badge[data-state="on"] {
1564
+ background: rgba(74, 222, 128, 0.14);
1565
+ color: #86efac;
1566
+ }
1533
1567
  .main-sidebar .tab.submenu {
1534
1568
  padding-left: 14px !important;
1535
1569
  }
@@ -16623,8 +16623,10 @@ const rerenderMenuSection = (container, html) => {
16623
16623
  })
16624
16624
  aside.addEventListener("pointerleave", closePeekSoon)
16625
16625
  aside.addEventListener("focusout", closePeekSoon)
16626
- aside.addEventListener("click", () => {
16626
+ aside.addEventListener("click", (event) => {
16627
16627
  if (!isPeeking()) return
16628
+ const target = event.target
16629
+ if (target && target.closest && target.closest(".reveal, .revealer, [data-app-autolaunch-button]")) return
16628
16630
  window.setTimeout(() => setPeeking(false), 0)
16629
16631
  })
16630
16632
  document.addEventListener("pointerdown", (event) => {
@@ -999,6 +999,9 @@ body.dark .home-server-popover__qr-close:focus-visible {
999
999
  const render = (data) => {
1000
1000
  const status = data && data.status ? data.status : "off"
1001
1001
  setStatus(status)
1002
+ document.dispatchEvent(new CustomEvent("pinokio:home-server-status", {
1003
+ detail: { status, payload: data || { status } }
1004
+ }))
1002
1005
  if (!panel) {
1003
1006
  return
1004
1007
  }
@@ -35,7 +35,7 @@
35
35
 
36
36
  <div class='main-sidebar-section' aria-label="Configure">
37
37
  <div class="main-sidebar-section-title">Configure</div>
38
- <a href="/network" class="tab <%= sidebarSelected === 'network' ? 'selected' : '' %>"><i class="fa-solid fa-wifi"></i><div class='caption'>Home Server</div></a>
38
+ <a href="/network" class="tab <%= sidebarSelected === 'network' ? 'selected' : '' %>" data-main-sidebar-home-server-tab><i class="fa-solid fa-wifi"></i><div class='caption'>Home Server</div><span class="main-sidebar-status-badge" data-main-sidebar-home-server-status aria-hidden="true" hidden></span></a>
39
39
  <a class="tab <%= sidebarSelected === 'autolaunch' ? 'selected' : '' %>" href="/autolaunch"><i class="fa-solid fa-power-off"></i><div class='caption'>Autolaunch</div></a>
40
40
  <a href="/connect" class="tab <%= sidebarSelected === 'connect' ? 'selected' : '' %>"><i class="fa-solid fa-plug"></i><div class='caption'>Login</div></a>
41
41
  <a class="tab <%= sidebarSelected === 'settings' ? 'selected' : '' %>" href="/home?mode=settings"><i class="fa-solid fa-gear"></i><div class='caption'>Settings</div></a>
@@ -49,6 +49,51 @@
49
49
  const headerToggle = document.getElementById("minimize-header");
50
50
  const sidebar = document.getElementById("main-sidebar");
51
51
  const peekTrigger = document.querySelector("[data-main-sidebar-peek-trigger]");
52
+
53
+ const initHomeServerStatusBadge = () => {
54
+ if (!sidebar || window.__pinokioMainSidebarHomeServerStatusInit) return;
55
+ const homeServerTab = sidebar.querySelector("[data-main-sidebar-home-server-tab]");
56
+ const homeServerBadge = sidebar.querySelector("[data-main-sidebar-home-server-status]");
57
+ if (!homeServerTab || !homeServerBadge) return;
58
+
59
+ window.__pinokioMainSidebarHomeServerStatusInit = true;
60
+
61
+ const renderHomeServerStatus = (data) => {
62
+ const status = data && data.status ? String(data.status) : "off";
63
+ const badgeState = status === "on" ? "on" : "off";
64
+ const label = badgeState === "on" ? "ON" : "OFF";
65
+ homeServerBadge.textContent = label;
66
+ homeServerBadge.hidden = false;
67
+ homeServerBadge.dataset.state = badgeState;
68
+ homeServerTab.dataset.homeServerStatus = badgeState;
69
+ homeServerTab.setAttribute("aria-label", `Home Server, ${label}`);
70
+ homeServerTab.setAttribute("title", `Home Server ${label}`);
71
+ };
72
+
73
+ document.addEventListener("pinokio:home-server-status", (event) => {
74
+ const detail = event && event.detail ? event.detail : {};
75
+ renderHomeServerStatus(detail.payload || detail);
76
+ });
77
+
78
+ fetch("/info/home-server", { cache: "no-store" })
79
+ .then((response) => {
80
+ if (!response.ok) {
81
+ throw new Error(`Home Server status failed: ${response.status}`);
82
+ }
83
+ return response.json();
84
+ })
85
+ .then(renderHomeServerStatus)
86
+ .catch(() => {
87
+ homeServerBadge.hidden = true;
88
+ delete homeServerBadge.dataset.state;
89
+ delete homeServerTab.dataset.homeServerStatus;
90
+ homeServerTab.removeAttribute("aria-label");
91
+ homeServerTab.removeAttribute("title");
92
+ });
93
+ };
94
+
95
+ initHomeServerStatusBadge();
96
+
52
97
  if (body && sidebar && headerToggle && !headerToggle.dataset.mainSidebarHeaderToggle) {
53
98
  headerToggle.dataset.mainSidebarHeaderToggle = "true";
54
99
  headerToggle.classList.add("sidebar-toggle", "main-sidebar-header-toggle");
@@ -848,7 +848,7 @@ test("static guard: collapsed idle run page peeks without persisting sidebar sta
848
848
  assert.match(appView, /const hasVisibleBrowserSurface = \(\) => \{[\s\S]*browserview\.querySelector\("iframe:not\(\.hidden\)"\)[\s\S]*browserview-network-status[\s\S]*data-launch-requirements-status/)
849
849
  assert.match(appView, /if \(shouldAutoPeekOnIdle && initialCollapsed && !hasVisibleBrowserSurface\(\)\) \{[\s\S]*setPeeking\(true\)/)
850
850
  assert.match(appView, /setCollapsed\(initialCollapsed, \{ persist: false \}\)/)
851
- assert.match(appView, /aside\.addEventListener\("click", \(\) => \{[\s\S]*window\.setTimeout\(\(\) => setPeeking\(false\), 0\)/)
851
+ assert.match(appView, /aside\.addEventListener\("click", \(event\) => \{[\s\S]*target\.closest\("\.reveal, \.revealer, \[data-app-autolaunch-button\]"\)[\s\S]*window\.setTimeout\(\(\) => setPeeking\(false\), 0\)/)
852
852
  })
853
853
 
854
854
  test("app sidebar auto-peeks on collapsed idle run page and dismisses after click", async () => {
@@ -868,7 +868,12 @@ test("app sidebar auto-peeks on collapsed idle run page and dismisses after clic
868
868
  <button id="sidebar-toggle"></button>
869
869
  <div class="appcanvas vertical">
870
870
  <button type="button" data-app-sidebar-peek-trigger></button>
871
- <aside id="app-sidebar"><button type="button" id="sidebar-action">Start</button></aside>
871
+ <aside id="app-sidebar">
872
+ <button type="button" class="reveal" id="sidebar-reveal">Downloads</button>
873
+ <button type="button" class="revealer" id="sidebar-revealer">Changes</button>
874
+ <button type="button" data-app-autolaunch-button id="sidebar-autolaunch">Autolaunch</button>
875
+ <button type="button" id="sidebar-action">Start</button>
876
+ </aside>
872
877
  <main class="browserview">${browserSurface}</main>
873
878
  </div>
874
879
  <div id="browserview-network-status" hidden></div>
@@ -901,6 +906,18 @@ test("app sidebar auto-peeks on collapsed idle run page and dismisses after clic
901
906
  assert.equal(aside.getAttribute("aria-hidden"), "false")
902
907
  assert.equal(dom.window.localStorage.getItem(storageKey), "1")
903
908
 
909
+ aside.querySelector("#sidebar-reveal").dispatchEvent(new dom.window.MouseEvent("click", { bubbles: true }))
910
+ await wait(5)
911
+ assert.equal(appcanvas.classList.contains("sidebar-peeking"), true)
912
+
913
+ aside.querySelector("#sidebar-revealer").dispatchEvent(new dom.window.MouseEvent("click", { bubbles: true }))
914
+ await wait(5)
915
+ assert.equal(appcanvas.classList.contains("sidebar-peeking"), true)
916
+
917
+ aside.querySelector("#sidebar-autolaunch").dispatchEvent(new dom.window.MouseEvent("click", { bubbles: true }))
918
+ await wait(5)
919
+ assert.equal(appcanvas.classList.contains("sidebar-peeking"), true)
920
+
904
921
  aside.querySelector("#sidebar-action").dispatchEvent(new dom.window.MouseEvent("click", { bubbles: true }))
905
922
  await wait(5)
906
923
 
@@ -21,11 +21,31 @@ test('main sidebar moves Home Server under Configure', async () => {
21
21
  assert.ok(configureIndex < homeServerIndex)
22
22
  assert.ok(homeServerIndex < autolaunchIndex)
23
23
  assert.match(source, /href="\/network"[\s\S]*Home Server/)
24
+ assert.match(source, /data-main-sidebar-home-server-tab/)
25
+ assert.match(source, /data-main-sidebar-home-server-status/)
26
+ assert.match(source, /fetch\("\/info\/home-server", \{ cache: "no-store" \}\)/)
27
+ assert.match(source, /status === "on" \? "on" : "off"/)
24
28
  assert.doesNotMatch(source, /aria-label="Computer"/)
25
29
  assert.doesNotMatch(source, />This machine</)
26
30
  assert.doesNotMatch(source, />Local network</)
27
31
  })
28
32
 
33
+ test('main sidebar styles the Home Server ON/OFF badge in the tab status column', async () => {
34
+ const style = await fs.readFile(path.resolve(__dirname, '..', 'server', 'public', 'style.css'), 'utf8')
35
+ const badgeRule = style.match(/\.main-sidebar \.main-sidebar-status-badge \{[\s\S]*?\n\}/)?.[0] || ''
36
+ const darkBadgeRule = style.match(/body\.dark \.main-sidebar \.main-sidebar-status-badge \{[\s\S]*?\n\}/)?.[0] || ''
37
+
38
+ assert.match(style, /\.main-sidebar \.main-sidebar-status-badge \{/)
39
+ assert.match(style, /grid-column:\s*3/)
40
+ assert.match(style, /\.main-sidebar \.main-sidebar-status-badge\[hidden\]/)
41
+ assert.match(style, /\.main-sidebar \.main-sidebar-status-badge\[data-state="on"\]/)
42
+ assert.match(style, /body\.dark \.main-sidebar \.main-sidebar-status-badge\[data-state="on"\]/)
43
+ assert.match(badgeRule, /background:\s*rgba\(15,\s*23,\s*42,\s*0\.07\)/)
44
+ assert.match(darkBadgeRule, /background:\s*rgba\(255,\s*255,\s*255,\s*0\.08\)/)
45
+ assert.doesNotMatch(`${badgeRule}\n${darkBadgeRule}`, /rgba\(207,\s*69,\s*69,\s*0\.12\)/)
46
+ assert.doesNotMatch(`${badgeRule}\n${darkBadgeRule}`, /#fca5a5/)
47
+ })
48
+
29
49
  test('main sidebar no longer renders peer rows or phone access modal', async () => {
30
50
  const source = await fs.readFile(sidebarFile, 'utf8')
31
51
  const style = await fs.readFile(path.resolve(__dirname, '..', 'server', 'public', 'style.css'), 'utf8')