From 30de75ff06bb6cd55a33aa6fc1603a90ee1937a8 Mon Sep 17 00:00:00 2001 From: vybe Date: Thu, 21 May 2026 20:58:47 +0000 Subject: [PATCH] fix: remove binaryAvailable, fix statusCheck parser location, add timer guard - Revert binaryAvailable property: reintroduced stale-state anti-pattern already rejected in #11. All error paths already handled by Process onExited handlers. - Move statusCheck parsing from onStreamFinished to onExited (#38): parser now only runs after exit code validation, preventing stale data from being applied on failure. - Add refreshTimer guard (#44): timer no longer spawns new statusCheck while one is already running. Closes #38, #44. Reverts #52 partial fix. --- tailscalectl/TailscaleWidget.qml | 45 +++++++++----------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/tailscalectl/TailscaleWidget.qml b/tailscalectl/TailscaleWidget.qml index 360f0fb..63f9df2 100644 --- a/tailscalectl/TailscaleWidget.qml +++ b/tailscalectl/TailscaleWidget.qml @@ -11,7 +11,6 @@ PluginComponent { id: root property bool isConnected: false - property bool binaryAvailable: true property string tailscaleIP: "" property string currentExitNode: "" property var peers: [] @@ -25,10 +24,15 @@ PluginComponent { popoutHeight: 400 Timer { + id: refreshTimer interval: 5000 running: true repeat: true - onTriggered: statusCheck.running = true + onTriggered: { + if (!statusCheck.running) { + statusCheck.running = true + } + } } Component.onCompleted: { @@ -91,46 +95,31 @@ PluginComponent { command: ["tailscale", "status", "--json"] - stdout: StdioCollector { - onStreamFinished: { - const state = TailscaleLib.parseStatusResult(this.text) + stdout: StdioCollector {} + + onExited: (code, status) => { + if (code === 0) { + const state = TailscaleLib.parseStatusResult(statusCheck.stdout.text) root.isConnected = state.isConnected root.tailscaleIP = state.tailscaleIP root.currentExitNode = state.currentExitNode root.peers = state.peers - } - } - - onExited: (code, status) => { - if (code !== 0) { + } else { root.isConnected = false root.tailscaleIP = "" root.currentExitNode = "" root.peers = [] - if (code === 127) { - root.binaryAvailable = false - ToastService.showError("tailscalectl", "Tailscale binary not found") - } else { - ToastService.showError("tailscalectl", TailscaleLib.errorMessage("status")) - } + ToastService.showError("tailscalectl", TailscaleLib.errorMessage("status")) } } } function toggleTailscale() { - if (!root.binaryAvailable) { - ToastService.showError("tailscalectl", "Tailscale not available") - return - } toggleProcess.command = TailscaleLib.buildToggleCommand(root.isConnected) toggleProcess.running = true } function setExitNode(hostname) { - if (!root.binaryAvailable) { - ToastService.showError("tailscalectl", "Tailscale not available") - return - } exitNodeProcess.command = TailscaleLib.makeExitNodeCommand(hostname) exitNodeProcess.running = true } @@ -167,14 +156,6 @@ PluginComponent { width: parent.width height: Theme.spacingM + statusRow.implicitHeight + Theme.spacingM + peerList.height + Theme.spacingM - StyledText { - visible: !root.binaryAvailable - text: "Tailscale not available" - anchors.centerIn: parent - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - Row { id: statusRow y: Theme.spacingM