feat(tailscalectl): add initial DMS widget plugin scaffolding
Minimal loadable DMS widget skeleton with plugin.json manifest and TailscaleWidget.qml component. Symlinked, enabled, and loaded cleanly in Dank Material Shell. References #1, #2
This commit is contained in:
parent
db08aa1ff7
commit
778f1969e0
3 changed files with 85 additions and 0 deletions
51
.scratch/tailscale-widget-prd.md
Normal file
51
.scratch/tailscale-widget-prd.md
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
## Problem Statement
|
||||||
|
|
||||||
|
Users of Dank Material Shell want a lightweight, native-feeling status widget on the Dank Bar that shows Tailscale connectivity at a glance and provides quick controls (toggle connection, switch exit nodes, copy addresses) without leaving the shell or opening a separate GUI.
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
A DMS widget plugin (`tailscale`) that renders a compact pill in the Dank Bar using the standard `PluginComponent` + `DankIcon` pattern. The icon reflects connected/disconnected state. Right-click toggles Tailscale via the official CLI. Left-click opens a `PopoutComponent` flyout containing current IP, active exit node, and a peer list with one-click exit-node selection and copy-to-clipboard actions. All interaction is driven by `tailscale status --json`, `tailscale up/down`, and `tailscale set --exit-node=...`.
|
||||||
|
|
||||||
|
## User Stories
|
||||||
|
|
||||||
|
1. As a DMS user, I want to see a Tailscale icon in my Dank Bar so that I know at a glance whether I am connected to my tailnet.
|
||||||
|
2. As a DMS user, I want the icon to change when Tailscale is connected vs. disconnected so that I can visually confirm status without clicking.
|
||||||
|
3. As a DMS user, I want to right-click the widget to toggle my Tailscale connection so that I can quickly go online or offline.
|
||||||
|
4. As a DMS user, I want to left-click the widget to open a flyout with my current Tailscale IP and active exit node so that I have the most important information in one place.
|
||||||
|
5. As a DMS user, I want the flyout to list all devices on my tailnet with their Tailscale IPs so that I can quickly find a peer.
|
||||||
|
6. As a DMS user, I want to click any device name or IP in the flyout to copy it to the clipboard so that I can easily share or paste addresses.
|
||||||
|
7. As a DMS user, I want any peer that offers an exit node to show a “Use as exit node” button so that I can route my traffic through that node with one click.
|
||||||
|
8. As a DMS user, I want the widget to automatically refresh status every few seconds so that the displayed information stays current.
|
||||||
|
9. As a DMS user, I want errors from Tailscale commands to appear as toast notifications so that I am informed when something goes wrong.
|
||||||
|
10. As a DMS user, I want the plugin to work with the standard DMS plugin loading mechanism (plugin.json + QML component) so that I can enable it like any other widget.
|
||||||
|
|
||||||
|
## Implementation Decisions
|
||||||
|
|
||||||
|
- The plugin will be implemented as a single `PluginComponent` widget (type: "widget").
|
||||||
|
- Iconography will reuse existing Material symbols (`vpn_key` / `vpn_key_off`) for connected/disconnected states; no custom assets required for v1.
|
||||||
|
- All Tailscale interaction will be performed via `Process` + `StdioCollector` calling the `tailscale` CLI (no direct Tailscale API or daemon socket).
|
||||||
|
- Status polling will be driven by a `Timer` inside the QML component (interval exposed only via code, not user settings).
|
||||||
|
- The flyout will be implemented with `popoutContent` + `PopoutComponent` following the DMS widget-with-popout pattern.
|
||||||
|
- Click-to-copy will use `Quickshell.execDetached(["sh","-c","echo -n '…' | wl-copy"])` and `ToastService`.
|
||||||
|
- Exit-node selection will call `tailscale set --exit-node=<hostname>` (and `tailscale set --exit-node=` to clear).
|
||||||
|
- The plugin will request the three permissions: `settings_read`, `settings_write`, `process`.
|
||||||
|
- No `PluginSettings` component or persistent user preferences will be provided in v1.
|
||||||
|
- The widget will support both horizontal and vertical bar orientations using the standard `horizontalBarPill` / `verticalBarPill` properties.
|
||||||
|
|
||||||
|
## Testing Decisions
|
||||||
|
|
||||||
|
- Good tests exercise external behavior only: icon state changes when `tailscale status` reports Running vs. Stopped, toggle commands are issued on right-click, flyout content matches parsed JSON, copy actions invoke the expected clipboard command.
|
||||||
|
- The primary testable module is the status-parsing and command-generation logic inside `TailscaleWidget.qml`.
|
||||||
|
- Prior art: the existing `dms-tailscale` plugin in the DMS plugin library uses the same `Process` + `StdioCollector` + `Timer` pattern; tests should mirror that style.
|
||||||
|
|
||||||
|
## Out of Scope
|
||||||
|
|
||||||
|
- Custom Tailscale logo SVG or branded assets.
|
||||||
|
- Settings UI, refresh-interval configuration, or preferred-exit-node list.
|
||||||
|
- Traffic graphs, ping, or file-send/receive features (those belong in a full GUI like KTailCtl).
|
||||||
|
- Multi-user or multi-profile Tailscale support.
|
||||||
|
- Any changes to Dank Material Shell core or Quickshell itself.
|
||||||
|
|
||||||
|
## Further Notes
|
||||||
|
|
||||||
|
The implementation deliberately stays close to the lightweight `dms-tailscale` reference while adding the exit-node and copy-to-clipboard features requested. It follows the exact DMS plugin development patterns documented at https://danklinux.com/docs/dankmaterialshell/plugin-development (v1.4).
|
||||||
23
tailscalectl/TailscaleWidget.qml
Normal file
23
tailscalectl/TailscaleWidget.qml
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
import qs.Modules.Plugins
|
||||||
|
|
||||||
|
PluginComponent {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
horizontalBarPill: Component {
|
||||||
|
StyledText {
|
||||||
|
text: "TS"
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verticalBarPill: Component {
|
||||||
|
StyledText {
|
||||||
|
text: "TS"
|
||||||
|
color: Theme.surfaceText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
tailscalectl/plugin.json
Normal file
11
tailscalectl/plugin.json
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"id": "tailscalectl",
|
||||||
|
"name": "Tailscale",
|
||||||
|
"description": "Tailscale status and controls on the Dank Bar",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"author": "John Morris",
|
||||||
|
"icon": "vpn_key",
|
||||||
|
"type": "widget",
|
||||||
|
"component": "./TailscaleWidget.qml",
|
||||||
|
"permissions": ["settings_read", "settings_write", "process"]
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue