refactor: unify SSH machines as services

This commit is contained in:
Developer
2026-07-14 20:58:46 +00:00
parent fe90feb1b7
commit 37533dd219
42 changed files with 3103 additions and 4960 deletions
@@ -1,4 +1,4 @@
import { describe, it, expect } from "vitest";
import { describe, expect, it } from "vitest";
import { configuredNavEntries, SERVICE_TYPE_NAV_ENTRIES } from "../navEntries";
describe("navEntries", () => {
@@ -13,37 +13,44 @@ describe("navEntries", () => {
expect(entries[0].path).toBe("/services/jellyfin");
});
it("returns one SSH Tasks entry when ssh_tasks is configured", () => {
const entries = configuredNavEntries(new Set(["ssh_tasks"]));
expect(entries).toHaveLength(1);
expect(entries[0].label).toBe("SSH Tasks");
it("does not expose remote machines as a top-level entry", () => {
expect(configuredNavEntries(new Set(["remote_machine"]))).toEqual([]);
});
it("returns all observability entries", () => {
const entries = configuredNavEntries(
new Set(["alertmanager", "prometheus"]),
);
expect(entries.map((e) => e.label)).toEqual(["Alertmanager", "Prometheus"]);
expect(entries.map((entry) => entry.label)).toEqual([
"Alertmanager",
"Prometheus",
]);
});
it("returns Backups + Authentik when configured", () => {
const entries = configuredNavEntries(new Set(["backups", "authentik"]));
expect(entries.map((e) => e.label)).toEqual(["Backups", "Authentik"]);
expect(entries.map((entry) => entry.label)).toEqual([
"Backups",
"Authentik",
]);
});
it("nextcloud has no nav entries in the static map", () => {
it("keeps non-operational service types out of the static map", () => {
expect(
SERVICE_TYPE_NAV_ENTRIES.filter((e) => e.serviceType === "nextcloud"),
SERVICE_TYPE_NAV_ENTRIES.filter(
(entry) =>
entry.serviceType === "nextcloud" ||
entry.serviceType === "remote_machine",
),
).toEqual([]);
});
it("preserves declaration order across mixed types", () => {
it("preserves declaration order across mixed navigable types", () => {
const entries = configuredNavEntries(
new Set(["authentik", "ssh_tasks", "jellyfin"]),
new Set(["authentik", "remote_machine", "jellyfin"]),
);
expect(entries.map((e) => e.label)).toEqual([
expect(entries.map((entry) => entry.label)).toEqual([
"Jellyfin",
"SSH Tasks",
"Authentik",
]);
});
-7
View File
@@ -12,7 +12,6 @@ import {
GanttChartSquare,
Magnet,
Monitor,
Server,
Users,
type LucideIcon,
} from "lucide-react";
@@ -37,12 +36,6 @@ export const SERVICE_TYPE_NAV_ENTRIES: NavEntry[] = [
icon: Monitor,
path: "/services/jellyfin",
},
{
serviceType: "ssh_tasks",
label: "SSH Tasks",
icon: Server,
path: "/services/ssh_tasks",
},
{
serviceType: "alertmanager",
label: "Alertmanager",
+2 -2
View File
@@ -16,7 +16,7 @@ describe("service registry", () => {
"nextcloud",
"prometheus",
"qbittorrent",
"ssh_tasks",
"remote_machine",
]);
});
@@ -30,7 +30,7 @@ describe("service registry", () => {
expect(SERVICE_REGISTRY.alertmanager.widgets.map((w) => w.kind)).toEqual([
"active_alerts",
]);
expect(SERVICE_REGISTRY.ssh_tasks.widgets.map((w) => w.kind)).toEqual([
expect(SERVICE_REGISTRY.remote_machine.widgets.map((w) => w.kind)).toEqual([
"task_output",
]);
expect(SERVICE_REGISTRY.nextcloud.widgets).toEqual([]);
+4 -4
View File
@@ -310,10 +310,10 @@ export const SERVICE_REGISTRY: Record<string, ServiceBinding> = {
description: "Self-hosted files and collaboration.",
widgets: [],
},
ssh_tasks: {
serviceType: "ssh_tasks",
name: "SSH task runner",
description: "Run reusable saved tasks over SSH and keep run history.",
remote_machine: {
serviceType: "remote_machine",
name: "Remote machine",
description: "SSH transport for files and reusable actions.",
widgets: [
{
kind: "task_output",