diff --git a/README.md b/README.md index 7b83e2c..1efd598 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,21 @@ A lightweight widget plugin that shows Tailscale connectivity status on the Dank Bar with quick controls for toggling connection, switching exit nodes, and copying peer addresses. -![Tailscale Widget v0.2.0](resources/dms_tailscalectl_v0.1.0.png) +![Tailscale Widget v0.2.1](resources/dms_tailscalectl_v0.1.0.png) ## Features - **Status icon** in the bar — `vpn_key` when connected, `vpn_key_off` when disconnected - **Right-click** to toggle Tailscale on/off - **Left-click** to open a popout showing: - - Your current Tailscale IP + - Your current Tailscale IP (when connected) - Active exit node (with clear button) - - Peer list with hostnames and IPs + - Peer list with hostnames and IPs (when connected) + - A clear "Not connected" empty state when disconnected (no stale peer list) - **Click-to-copy** any hostname or IP to clipboard - **Exit node selection** — click `↗` on any exit-node-capable peer to route through it - **On-demand status** — polls Tailscale for ground truth on load, explicit actions, and post-mutation verification (defensive poll-act-poll for toggles; no always-on timer) +- **Single-flight actions** — concurrent status/toggle/exit/copy chains are rejected while an operation is in flight - **Toast notifications** for all errors ## Requirements @@ -42,7 +44,8 @@ A lightweight widget plugin that shows Tailscale connectivity status on the Dank tailscalectl/ ├── plugin.json ├── TailscaleWidget.qml - └── lib.js + ├── lib.js + └── i18n/ ``` 3. Reload the plugin: @@ -70,12 +73,14 @@ A lightweight widget plugin that shows Tailscale connectivity status on the Dank "id": "tailscalectl", "name": "Tailscale", "description": "Tailscale status and controls on the Dank Bar", - "version": "0.2.0", - "author": "John Morris & Vybe (AI Slop... er... Coding Assistant)", + "author": "John Morris", "icon": "vpn_key", "type": "widget", + "capabilities": ["dankbar-widget"], "component": "./TailscaleWidget.qml", - "permissions": ["settings_read", "settings_write", "process"] + "permissions": ["process"], + "requires": ["tailscale"], + "version": "0.2.1" } ``` @@ -84,7 +89,10 @@ A lightweight widget plugin that shows Tailscale connectivity status on the Dank - Uses `Proc` singleton (from `qs.Common`) for all external `tailscale` commands (one-shot stdout capture + auto cleanup). - Fully I18n-ready via `I18n.tr(...)` (source keys in American English only today; see `tailscalectl/i18n/` for scaffolding). - Follows current `dms-plugin-dev` + DMS 1.4 plugin best practices (capabilities, requires, no raw Process for one-shots, etc.). -- Toggle uses intentional defensive poll-act-poll (see code comments). +- Toggle uses intentional defensive poll-act-poll; a failed status poll aborts the pending toggle (does not invent `up`/`down`). +- When `BackendState` is not `Running`, peer list / exit node / self IP are cleared so the UI never shows a stale connected-looking peer list. +- Status row uses `RowLayout` with a real `Layout.fillWidth` spacer (not a no-op on plain `Row`). +- Peer `ListView` uses `Flickable.StopAtBounds` (no desktop rubber-band overshoot). ## Testing diff --git a/tailscalectl/i18n/README.md b/tailscalectl/i18n/README.md index 5e29d35..52fd6ba 100644 --- a/tailscalectl/i18n/README.md +++ b/tailscalectl/i18n/README.md @@ -11,25 +11,7 @@ This plugin is fully instrumented with `I18n.tr(...)` (from `qs.Common`) for all See `getStrings()` and `errorMessage()` in `lib.js` for the canonical list. -Example `en.json` (for documentation / future tools): - -```json -{ - "Tailscale": "Tailscale", - "Connected": "Connected", - "Disconnected": "Disconnected", - "Exit node: ": "Exit node: ", - "None": "None", - "Copied %1 to clipboard": "Copied %1 to clipboard", - "Invalid exit node hostname": "Invalid exit node hostname", - "Failed to connect to Tailscale": "Failed to connect to Tailscale", - "Failed to disconnect from Tailscale": "Failed to disconnect from Tailscale", - "Failed to set exit node": "Failed to set exit node", - "Failed to read Tailscale status": "Failed to read Tailscale status", - "Error copying to clipboard": "Error copying to clipboard", - "Tailscale command failed": "Tailscale command failed" -} -``` +Example `en.json` (for documentation / future tools) lives beside this README. ## Notes @@ -37,4 +19,4 @@ Example `en.json` (for documentation / future tools): - Plugin name/description in `plugin.json` and technical IDs ("tailscalectl") remain English. - This follows DMS `dms-plugin-dev` best practice for future-proofing even when only en is shipped. -Written by AI agent working for @jtmorris. Model: grok-build-0.1. +Written by AI agent working for @jtmorris. Model: Grok 4.5. diff --git a/tailscalectl/i18n/en.json b/tailscalectl/i18n/en.json index bd5b57a..b0b9fbd 100644 --- a/tailscalectl/i18n/en.json +++ b/tailscalectl/i18n/en.json @@ -6,6 +6,7 @@ "None": "None", "Copied %1 to clipboard": "Copied %1 to clipboard", "Invalid exit node hostname": "Invalid exit node hostname", + "Not connected": "Not connected", "Failed to connect to Tailscale": "Failed to connect to Tailscale", "Failed to disconnect from Tailscale": "Failed to disconnect from Tailscale", "Failed to set exit node": "Failed to set exit node", diff --git a/tailscalectl/plugin.json b/tailscalectl/plugin.json index 5b8ece6..a2ce106 100644 --- a/tailscalectl/plugin.json +++ b/tailscalectl/plugin.json @@ -9,5 +9,5 @@ "component": "./TailscaleWidget.qml", "permissions": ["process"], "requires": ["tailscale"], - "version": "0.2.0" + "version": "0.2.1" }