This repository has been archived on 2026-08-23. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Federico Jaramillo Martinez 8517800a24 feat(plugins): turn Info panel into a PI WEB status view
Rework the bundled Info plugin from a demo into an always-available
status view: running and installed versions, installation details,
release state, and per-service health rendered from host-provided
state, plus machine and workspace details. Replace the window.alert
demo action with a Copy PI WEB Diagnostics action that copies a
plain-text summary for bug reports.

Add state.selectedMachine to the stable plugin runtime state so
actions and other runtime callbacks can read the selected machine's
identity, and split the plugin into a copy-paste-friendly skeleton
(pi-web-plugin.ts) and replaceable internals (infoInternals.ts).
2026-07-27 18:03:25 +02:00

163 lines
5.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import type { PiWebComponentStatus, PiWebReleaseStatus, PiWebStatusResponse, PluginMachine, Workspace } from "@jmfederico/pi-web/plugin-api";
import { componentDetails, componentHealth, diagnosticsSummary, formatVersion, installationLabel, machineKindLabel, releaseSummary, workspaceFlags } from "./infoInternals.js";
describe("componentHealth", () => {
it("reports current when the component is available and not stale", () => {
expect(componentHealth(componentStatus())).toBe("current");
});
it("reports restart needed when the installed version is newer than the running one", () => {
expect(componentHealth(componentStatus({ stale: true }))).toBe("restart needed");
});
it("reports unavailable when the component cannot be reached", () => {
expect(componentHealth(componentStatus({ available: false, stale: true }))).toBe("unavailable");
});
});
describe("releaseSummary", () => {
it("names the latest version when an update is available", () => {
expect(releaseSummary(release({ updateAvailable: true, latestVersion: "1.2.3" }))).toBe("Update available: 1.2.3");
});
it("still reports an update when the latest version is unknown", () => {
expect(releaseSummary(release({ updateAvailable: true }))).toBe("Update available");
});
it("surfaces a failed release check", () => {
expect(releaseSummary(release({ error: "registry unreachable" }))).toBe("Update check failed: registry unreachable");
});
it("reports skipped checks distinctly from an up-to-date install", () => {
expect(releaseSummary(release({ skipped: true }))).toBe("Update check skipped");
expect(releaseSummary(release())).toBe("Up to date");
});
});
describe("componentDetails", () => {
it("combines versions, health, and installation into one line", () => {
expect(componentDetails(componentStatus())).toBe("running 1.0.0 · installed 1.0.0 · current · global npm package · /usr/lib/node_modules");
});
it("includes the component error when present", () => {
const details = componentDetails(componentStatus({ available: false, error: "connection refused" }));
expect(details).toContain("unavailable");
expect(details).toContain("error: connection refused");
});
});
describe("diagnosticsSummary", () => {
it("renders a full status block for bug reports", () => {
const summary = diagnosticsSummary({ status: statusResponse(), machine: machineFixture(), workspace: workspaceFixture() });
expect(summary).toBe([
"PI WEB diagnostics",
"Package: @jmfederico/pi-web",
"Web/UI: running 1.0.0 · installed 1.0.1 · restart needed · global npm package · /usr/lib/node_modules",
"Session daemon: running 1.0.0 · installed 1.0.0 · current · local checkout · /srv/dev/pi-web",
"Release: Update available: 1.1.0 (checked 2025-01-02T03:04:05Z)",
"Status generated: 2025-01-02T03:04:06Z",
"Machine: devbox (local machine)",
"Workspace: pi-web — /srv/dev/pi-web (branch main, git worktree, main workspace)",
].join("\n"));
});
it("degrades gracefully when the status and workspace are unavailable", () => {
const summary = diagnosticsSummary({ status: undefined });
expect(summary).toBe([
"PI WEB diagnostics",
"Status: unavailable",
"Workspace: none selected",
].join("\n"));
});
});
describe("small formatters", () => {
it("formats missing versions as unknown", () => {
expect(formatVersion(undefined)).toBe("unknown");
expect(formatVersion("")).toBe("unknown");
expect(formatVersion("1.0.0")).toBe("1.0.0");
});
it("labels installations", () => {
expect(installationLabel(undefined)).toBe("installation unknown");
expect(installationLabel({ kind: "pi-package", source: "Pi package", scope: "user" })).toBe("Pi package · user");
expect(installationLabel({ kind: "docker", dockerMode: "dev" })).toBe("Docker development runtime");
expect(installationLabel({ kind: "docker" })).toBe("Docker runtime");
expect(installationLabel({ kind: "unknown" })).toBe("installation unknown");
});
it("labels machine kinds", () => {
expect(machineKindLabel("local")).toBe("local machine");
expect(machineKindLabel("remote")).toBe("remote machine");
});
it("describes workspaces without git metadata", () => {
expect(workspaceFlags({
id: "ws-1",
projectId: "proj-1",
path: "/srv/dev/plain",
label: "plain",
isMain: false,
isGitRepo: false,
isGitWorktree: false,
})).toEqual(["not a git repo"]);
});
});
function componentStatus(patch: Partial<PiWebComponentStatus> = {}): PiWebComponentStatus {
return {
component: "web",
label: "Web/UI",
runtimeVersion: "1.0.0",
installedVersion: "1.0.0",
stale: false,
available: true,
installation: { kind: "npm-global", path: "/usr/lib/node_modules" },
...patch,
};
}
function release(patch: Partial<PiWebReleaseStatus> = {}): PiWebReleaseStatus {
return {
packageName: "@jmfederico/pi-web",
updateAvailable: false,
checkedAt: "2025-01-02T03:04:05Z",
...patch,
};
}
function statusResponse(): PiWebStatusResponse {
return {
packageName: "@jmfederico/pi-web",
generatedAt: "2025-01-02T03:04:06Z",
components: {
web: componentStatus({ installedVersion: "1.0.1", stale: true }),
sessiond: componentStatus({ component: "sessiond", label: "Session daemon", installation: { kind: "local", path: "/srv/dev/pi-web" } }),
},
release: release({ updateAvailable: true, latestVersion: "1.1.0" }),
commands: {},
messages: [],
};
}
function machineFixture(): PluginMachine {
return { id: "local", name: "devbox", kind: "local" };
}
function workspaceFixture(patch: Partial<Workspace> = {}): Workspace {
return {
id: "ws-1",
projectId: "proj-1",
path: "/srv/dev/pi-web",
label: "pi-web",
branch: "main",
isMain: true,
isGitRepo: true,
isGitWorktree: true,
...patch,
};
}