feat: move tailscale device discovery and settings into a plugin

Adds plugins/tailscale/ with a devices sidebar tab, admin settings
section, and re-auth dialog. Host Metrics tailscale manager card and
SSH re-auth banner parsing stay in core.
This commit is contained in:
LukeGus committed 2026-09-22 10:45:15 -05:00
1 parent 5fbd5fb7e2
commit 8742c5d381
27 files changed
+850 -266

No files matched your search

+10 -2
View File
@@ -50,8 +50,6 @@ import {
getUserRoles,
} from "@/main-axios";
import {
getTailscaleSettings,
updateTailscaleSettings,
getHostDefaults,
updateHostDefaults,
getAnalyticsEnabled,
@@ -66,6 +64,11 @@ import {
type TerminalImageStorageTestResult,
type BrandingSettings,
} from "@/api/settings-api";
import {
getTailscaleSettings,
updateTailscaleSettings,
} from "../../../plugins/tailscale/frontend/tailscale-api";
import { AdminTailscaleSection } from "../../../plugins/tailscale/frontend/AdminTailscaleSection";
import {
getSessionSharingGloballyEnabled,
updateSessionSharingGloballyEnabled,
@@ -1336,6 +1339,11 @@ export function AdminSettingsPanel({
handleSaveGuacamole={handleSaveGuacamole}
logLevel={logLevel}
handleSaveLogLevel={handleSaveLogLevel}
/>
<AdminTailscaleSection
open={openSections.has("tailscale")}
onToggle={() => toggle("tailscale")}
tailscaleApiKey={tailscaleApiKey}
setTailscaleApiKey={setTailscaleApiKey}
tailscaleApiBaseUrl={tailscaleApiBaseUrl}
-60
View File
@@ -77,11 +77,6 @@ type GeneralSettingsSectionProps = {
handleSaveGuacamole: () => void;
logLevel: string;
handleSaveLogLevel: (level: string) => void;
tailscaleApiKey: string;
setTailscaleApiKey: Dispatch<SetStateAction<string>>;
tailscaleApiBaseUrl: string;
setTailscaleApiBaseUrl: Dispatch<SetStateAction<string>>;
handleSaveTailscaleApiKey: () => void;
};
export function AdminGeneralSettingsSection({
@@ -138,11 +133,6 @@ export function AdminGeneralSettingsSection({
handleSaveGuacamole,
logLevel,
handleSaveLogLevel,
tailscaleApiKey,
setTailscaleApiKey,
tailscaleApiBaseUrl,
setTailscaleApiBaseUrl,
handleSaveTailscaleApiKey,
}: GeneralSettingsSectionProps) {
const { t } = useTranslation();
@@ -562,56 +552,6 @@ export function AdminGeneralSettingsSection({
)}
</div>
<div className="flex flex-col gap-2 border-t border-border pt-3 mt-2">
<div className="flex flex-col gap-0.5">
<span className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground">
{t("admin.tailscaleApiKey")}
</span>
<span className="text-[10px] text-muted-foreground">
{t("admin.tailscaleApiKeyDescription")}{" "}
<a
href="https://docs.termix.site/features/networking/tailscale"
target="_blank"
rel="noreferrer"
className="text-accent-brand hover:underline"
>
{t("admin.tailscaleApiKeyDocsLink")}
</a>
</span>
</div>
<div className="flex items-center gap-2">
<Input
type="password"
value={tailscaleApiKey}
onChange={(e) => setTailscaleApiKey(e.target.value)}
placeholder="tskey-api-... / hskey-api-..."
className="text-sm"
/>
<Button
variant="outline"
size="sm"
className="text-xs border-accent-brand/40 text-accent-brand hover:bg-accent-brand/10 hover:text-accent-brand h-7 shrink-0"
onClick={handleSaveTailscaleApiKey}
>
{t("common.save")}
</Button>
</div>
<div className="flex flex-col gap-1.5 mt-1">
<label className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest">
{t("admin.tailscaleApiBaseUrl")}
</label>
<span className="text-[10px] text-muted-foreground">
{t("admin.tailscaleApiBaseUrlDescription")}
</span>
<Input
value={tailscaleApiBaseUrl}
onChange={(e) => setTailscaleApiBaseUrl(e.target.value)}
placeholder="https://api.tailscale.com/api/v2"
className="text-sm"
/>
</div>
</div>
<div className="flex flex-col gap-2 border-t border-border pt-3 mt-2">
<span className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground">
{t("admin.logLevel")}
+1
View File
@@ -32,6 +32,7 @@ export type RailView =
| "automations"
| "ai"
| "fleets"
| "tailscale"
| "workspaces"
| "collab";
+2 -1
View File
@@ -56,7 +56,8 @@ import {
createCredential,
adminCreateUserCredential,
} from "@/main-axios";
import { getTailscaleDevices, getHostDefaults } from "@/api/settings-api";
import { getHostDefaults } from "@/api/settings-api";
import { getTailscaleDevices } from "../../../plugins/tailscale/frontend/tailscale-api";
import {
getUserPreferences,
saveUserPreferences,
+7
View File
@@ -11,6 +11,7 @@ import {
Network,
Play,
Plug,
Radar,
ScrollText,
Server,
Settings,
@@ -139,6 +140,12 @@ export const RAIL_ITEMS: RailItemDef[] = [
rightDockable: true,
},
{ id: "fleets", icon: Boxes, labelKey: "nav.fleets", separatorAfter: true },
{
id: "tailscale",
icon: Radar,
labelKey: "nav.tailscale",
separatorAfter: true,
},
{
id: "automations",
icon: Workflow,