nosignal-shell/modules/nexus/common/SudoToggleRow.qml
28allday e42538896f fix(nosignal): hardware-test round 4 — Wi-Fi join, multi-monitor popouts, sudo focus
From the 2026-06-20 Acer muxless-Optimus hardware test:

- F-wifi (NsNetwork.qml): the Wi-Fi panel was display-only — no onClicked,
  no password field — so a secured network could not be joined from the GUI.
  Wire the existing Network service: click to connect; open/saved networks
  connect directly; secured-without-profile expands an inline password field
  (StyledTextField, echoMode Password). Also strip a stray NUL byte that the
  on-box edit left at the `?? " "` sentinel. HW-verified on the test laptop.
- F-multimon (NsShell.qml + NsBar.qml + NsOverlay.qml): bar popouts mirrored
  on every monitor. Add a `screen` identity to NsShell; pills pass their
  output name; each NsOverlay only renders when it owns the open panel ("" =
  unscoped, for the global power modal). HW-verified dual-monitor.
- F-sudo (SudoToggleRow.qml): the passwordless-sudo prompt used the shared
  TUI.float class with no focus rule, so keystrokes missed it and three blank
  tries tripped pam_faillock with no feedback. Use a dedicated `nosignal-sudo`
  class (builder ships float/center/pin/stayfocused rules) and call the new
  `nosignal-sudo-toggle enable-tui` wrapper, which keeps the terminal open on
  failure so the reason is visible.

Add .gitattributes (*.qml/*.conf/*.json text) for clean diffs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 18:49:18 +01:00

76 lines
2.9 KiB
QML

// SudoToggleRow.qml (NoSignal) — Settings -> Services toggle for time-boxed
// passwordless sudo. Reflects live state by polling `nosignal-sudo-toggle
// status` (no root needed); enabling opens a floating terminal for the ONE
// password prompt, disabling runs passwordless inside the active window.
//
// Untracked file under modules/nexus/common — auto-discovered as the type
// `SudoToggleRow` via `import qs.modules.nexus.common`. Survives caelestia
// upgrades; only the one-line insert in ServicesPage.qml is re-applied by hook.
import QtQuick
import Quickshell.Io
import qs.modules.nexus.common
ToggleRow {
id: root
property bool active: false
property int remaining: 0
text: qsTr("Passwordless sudo (15 min)")
subtext: active
? qsTr("On — %1 min left. Auto-reverts; a reboot also clears it.").arg(remaining)
: qsTr("Run sudo without a password for 15 minutes, then it reverts")
onToggled: {
if (checked)
enableProc.running = true; // needs a password -> floating terminal
else
disableProc.running = true; // no password inside the active window
reconcile.restart();
}
// --- live state -----------------------------------------------------------
Process {
id: statusProc
command: ["nosignal-sudo-toggle", "status"]
stdout: StdioCollector {
onStreamFinished: {
const p = text.trim().split(/\s+/);
root.active = p[0] === "active";
root.remaining = parseInt(p[1] || "0") || 0;
root.checked = root.active; // drive switch from real state
}
}
}
// --- actions --------------------------------------------------------------
Process {
id: enableProc
// Dedicated window class (nosignal-sudo) so the shipped hypr windowrules
// (float/center/pin/stayfocused) force this prompt to GRAB keyboard focus.
// With the shared TUI.float class and no focus rule the prompt did not get
// keystrokes -> three blank tries tripped pam_faillock and the switch just
// snapped back with no feedback (hardware bug 2026-06-20). `enable-tui`
// runs the sudo prompt as the user and keeps the terminal open on failure
// so the reason is visible instead of vanishing.
command: ["kitty", "--class", "nosignal-sudo", "-e", "nosignal-sudo-toggle", "enable-tui"]
}
Process {
id: disableProc
command: ["sudo", "-n", "nosignal-sudo-toggle", "disable"]
}
// --- polling --------------------------------------------------------------
Timer {
interval: 5000
repeat: true
running: true
triggeredOnStart: true
onTriggered: statusProc.running = true
}
Timer {
id: reconcile
interval: 2000
onTriggered: statusProc.running = true
}
}