chore: lock the plugin boundary and remove 2.9.0 leftovers

This commit is contained in:
LukeGus committed 2026-09-25 07:24:46 -05:00
1 parent 6489b62ece
commit 2961297989
399 files changed
+3964 -5627

No files matched your search

@@ -1,5 +1,5 @@
import React from "react";
import { Button } from "@/components/button.tsx";
import { Button } from "@termix/plugin-sdk/ui";
import { Shield, ExternalLink, Loader2 } from "lucide-react";
import { useTranslation } from "@termix/plugin-sdk/frontend";
@@ -1,11 +1,11 @@
import { useEffect, useState } from "react";
import { useTranslation } from "@termix/plugin-sdk/frontend";
import { Loader2, RefreshCw, Terminal } from "lucide-react";
import { Button } from "@/components/button";
import { Input } from "@/components/input";
import type { Host } from "@/types/ui-types";
import { Button } from "@termix/plugin-sdk/ui";
import { Input } from "@termix/plugin-sdk/ui";
import type { PluginHostRecord as Host } from "@termix/plugin-sdk/frontend";
import { getTailscaleDevices } from "./tailscale-api";
import { createQuickConnectHost } from "@/sidebar/quick-connect-host";
import { createQuickConnectHost } from "@termix/plugin-sdk/ui";
interface TailscaleDevice {
id: string;
@@ -61,7 +61,7 @@ export function TailscaleDevicesPanel({
port: 22,
username,
authType: "tailscale",
});
}) as unknown as Host;
onConnect(host, "terminal");
}
@@ -9,7 +9,7 @@
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "@termix/plugin-sdk/frontend";
import { Loader2, RefreshCw } from "lucide-react";
import { Button } from "@/components/button";
import { Button } from "@termix/plugin-sdk/ui";
import type { SettingsComponentProps } from "@termix/plugin-sdk/frontend";
import { getTailscaleDevices } from "./tailscale-api";
+4 -1
View File
@@ -1,8 +1,9 @@
import type { ComponentType } from "react";
import { Radar } from "lucide-react";
import type { PanelProps, TermixApp } from "@termix/plugin-sdk/frontend";
import type { Host } from "@/types/ui-types";
import type { PluginHostRecord as Host } from "@termix/plugin-sdk/frontend";
import { TailscaleDevicesPanel } from "./TailscaleDevicesPanel";
import { setTailscaleApi } from "./tailscale-api";
import { TailscaleDevicesStatus } from "./TailscaleDevicesStatus";
import { TailscaleAuthEditor } from "./TailscaleAuthEditor";
import { TailscaleCheckOverlay } from "./TailscaleCheckOverlay";
@@ -22,6 +23,8 @@ function Panel({ shell }: PanelProps) {
}
export function activate(app: TermixApp): void {
setTailscaleApi(app.api);
app.onDispose(() => setTailscaleApi(null));
app.registerRailItem({
id: "tailscale",
icon: Radar,
+27 -24
View File
@@ -1,12 +1,11 @@
// The API key and base URL are this plugin's own settings now, read and
// written through the generic /plugins/tailscale/settings/admin routes that
// core renders from the manifest. Only the device list is left here, because
// it is this plugin's own route.
// The API key and base URL are this plugin's own settings, read and written
// through the generic /plugins/tailscale/settings/admin routes that core
// renders from the manifest. Only the device list is left here, because it is
// this plugin's own route.
import axios from "axios";
import { authApi, handleApiError } from "@/main-axios";
import type { PluginApiClient } from "@termix/plugin-sdk/frontend";
export async function getTailscaleDevices(): Promise<{
export interface TailscaleDevicesResponse {
devices: Array<{
id: string;
name: string;
@@ -17,27 +16,31 @@ export async function getTailscaleDevices(): Promise<{
}>;
hasApiKey: boolean;
error?: string;
}> {
}
let pluginApi: PluginApiClient | null = null;
/** Set from activate with app.api, cleared on deactivate. */
export function setTailscaleApi(api: PluginApiClient | null): void {
pluginApi = api;
}
export async function getTailscaleDevices(): Promise<TailscaleDevicesResponse> {
if (!pluginApi) throw new Error("The Tailscale plugin is not active");
try {
const response = await authApi.get("/plugin-api/tailscale/devices");
const response = await pluginApi.get<TailscaleDevicesResponse>("/devices");
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
const data = error.response?.data;
if (
data &&
typeof data === "object" &&
"hasApiKey" in data &&
typeof data.hasApiKey === "boolean"
) {
return data as {
devices: [];
hasApiKey: boolean;
error?: string;
};
}
// The route answers with the key state even when the tailnet call fails.
const data = (error as { response?: { data?: unknown } })?.response?.data;
if (
data &&
typeof data === "object" &&
"hasApiKey" in data &&
typeof (data as { hasApiKey: unknown }).hasApiKey === "boolean"
) {
return data as TailscaleDevicesResponse;
}
handleApiError(error, "fetch Tailscale devices");
throw error;
}
}