mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 15:15:24 +00:00
feat: harden plugin api for separate repos, signed updates and generic external login
This commit is contained in:
1 parent
fb9c168b6b
commit
80944301dd
310 files changed
+6577
-4927
No files matched your search
@@ -6,14 +6,27 @@
|
||||
"scripts": {
|
||||
"build": "termix-plugin build",
|
||||
"test": "termix-plugin test",
|
||||
"typecheck": "tsc -b ../../tsconfig.plugins.backend.json ../../tsconfig.plugins.frontend.json",
|
||||
"typecheck": "tsc -p .",
|
||||
"validate": "termix-plugin validate"
|
||||
},
|
||||
"dependencies": {
|
||||
"cytoscape": "^3.34.3",
|
||||
"lucide-react": "^1.33.0",
|
||||
"react-cytoscapejs": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@termix/plugin-sdk": "*"
|
||||
"@termix/plugin-sdk": "^1.0.0",
|
||||
"@types/node": "^26.2.0",
|
||||
"@types/react": "^19.2.18",
|
||||
"@types/react-dom": "^19.2.4",
|
||||
"better-sqlite3": "^13.0.3",
|
||||
"jsdom": "^30.0.1",
|
||||
"vitest": "^4.1.11"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@termix/plugin-sdk": "^1.0.0",
|
||||
"drizzle-orm": "^0.45.2",
|
||||
"express": "^5.2.1",
|
||||
"react": "^19.2.8"
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,8 @@ import {
|
||||
useTranslation,
|
||||
usePluginApi,
|
||||
useHosts,
|
||||
useTabs,
|
||||
getHostStatusColorScheme,
|
||||
useHostActions,
|
||||
type PluginHostRecord,
|
||||
} from "@termix/plugin-sdk/frontend";
|
||||
@@ -101,24 +103,6 @@ interface NetworkGraphCardProps {
|
||||
|
||||
type NetworkElement = NetworkTopologyNode | NetworkTopologyEdge;
|
||||
|
||||
type StatusColorScheme = "accent" | "status";
|
||||
|
||||
/** Reads the sidebar preferences cache directly, same as core's status dots do. */
|
||||
function readStatusColorScheme(): StatusColorScheme {
|
||||
try {
|
||||
const raw = localStorage.getItem("hostSidebarPreferences");
|
||||
if (!raw) return "accent";
|
||||
const parsed = JSON.parse(raw) as {
|
||||
display?: { statusColorScheme?: string };
|
||||
};
|
||||
return parsed?.display?.statusColorScheme === "status"
|
||||
? "status"
|
||||
: "accent";
|
||||
} catch {
|
||||
return "accent";
|
||||
}
|
||||
}
|
||||
|
||||
function resolveCssVar(varName: string, fallback: string): string {
|
||||
const raw = getComputedStyle(document.documentElement)
|
||||
.getPropertyValue(varName)
|
||||
@@ -151,7 +135,7 @@ function buildNodeSvg(
|
||||
): string {
|
||||
const isOnline = status === "online";
|
||||
const isOffline = status === "offline";
|
||||
const useRealColors = readStatusColorScheme() === "status";
|
||||
const useRealColors = getHostStatusColorScheme() === "status";
|
||||
let statusColor: string;
|
||||
if (isOnline) {
|
||||
statusColor = useRealColors
|
||||
@@ -583,10 +567,10 @@ export function NetworkGraphCard({
|
||||
|
||||
const hideMenu = () => setContextMenu((p) => ({ ...p, visible: false }));
|
||||
|
||||
const shellTabs = useTabs();
|
||||
const fireOpen = (hostId: string, type?: string) => {
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("termix:open-tab", { detail: { hostId, type } }),
|
||||
);
|
||||
const host = liveHosts.find((candidate) => String(candidate.id) === hostId);
|
||||
if (host) shellTabs.connectHost(host, type);
|
||||
};
|
||||
|
||||
const handleContextAction = (action: string) => {
|
||||
|
||||
@@ -38,7 +38,7 @@ describe("network-topology activate", () => {
|
||||
const service = server.mock.services.get("network-topology.graph") as {
|
||||
get: () => Promise<unknown>;
|
||||
};
|
||||
const result = await server.mock.ctx.asUser("user-1", () => service.get());
|
||||
const result = await server.mock.actAs("user-1", () => service.get());
|
||||
expect(result).toEqual({ nodes: [{ data: { id: "1" } }], edges: [] });
|
||||
});
|
||||
|
||||
@@ -47,7 +47,7 @@ describe("network-topology activate", () => {
|
||||
const service = server.mock.services.get("network-topology.graph") as {
|
||||
get: () => Promise<unknown>;
|
||||
};
|
||||
const result = await server.mock.ctx.asUser("user-1", () => service.get());
|
||||
const result = await server.mock.actAs("user-1", () => service.get());
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user