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
pi-web/pi-web-plugins/updates/updatesLogic.ts
T
Federico Jaramillo Martinez 59a13f5058 test(updates): extract panel logic into a tested module
Move the Updates plugin's pure decision logic (recommended/additional
commands, panel visibility, installation labels, version formatting)
into a sibling updatesLogic.ts module so it can be unit tested directly,
matching the workspace-tasks multi-file plugin layout. The plugin file
is now thin rendering glue that imports those helpers.

Add unit tests for the extracted logic and render smoke tests that
exercise the panel through its public contribution API, including that
Run actions wire to the terminal with the "pi.plugin": "updates"
metadata. No behavior change; the beta label stays.
2026-06-14 17:32:34 +02:00

75 lines
3.2 KiB
TypeScript

import type { PiWebInstallationInfo, PiWebStatusMessage, PiWebStatusResponse, PluginRuntimeState } from "@jmfederico/pi-web/plugin-api";
export interface CommandEntry {
label: string;
command: string;
}
// The single command users should run when they do not want to think: if an
// update is available, `commands.update` already chains the update and a full
// restart; otherwise, when anything is stale, a full restart is enough.
export function recommendedCommand(status: PiWebStatusResponse): CommandEntry | undefined {
const { commands, release, components } = status;
if (release.updateAvailable && typeof commands.update === "string" && commands.update !== "") {
return { label: "Update & restart everything", command: commands.update };
}
const restartNeeded = components.web.stale || components.sessiond.stale || !components.sessiond.available;
if (restartNeeded && typeof commands.restart === "string" && commands.restart !== "") {
return { label: "Restart everything", command: commands.restart };
}
return undefined;
}
export function additionalCommands(status: PiWebStatusResponse, recommended: CommandEntry | undefined): CommandEntry[] {
return [
["Update", status.commands.update],
["Restart all", status.commands.restart],
["Restart Web/UI", status.commands.restartWeb],
["Restart session daemon", status.commands.restartSessiond],
["Status", status.commands.status],
]
.filter((entry): entry is [string, string] => typeof entry[1] === "string" && entry[1] !== "")
.filter(([, command]) => command !== recommended?.command)
.map(([label, command]) => ({ label, command }));
}
export function messagesFor(state: PluginRuntimeState | undefined): PiWebStatusMessage[] {
return state?.piWebStatus?.messages ?? [];
}
export function statusFor(state: PluginRuntimeState | undefined): PiWebStatusResponse | undefined {
return state?.piWebStatus;
}
export function messageCount(state: PluginRuntimeState | undefined): number {
return messagesFor(state).length;
}
export function isLocalOrUnknownInstallation(installation: PiWebInstallationInfo | undefined): boolean {
return installation === undefined || installation.kind === "local" || installation.kind === "unknown";
}
export function shouldShowUpdatesPanel(state: PluginRuntimeState | undefined): boolean {
const status = statusFor(state);
if (messageCount(state) > 0) return true;
if (status === undefined) return false;
return isLocalOrUnknownInstallation(status.components.web.installation)
|| isLocalOrUnknownInstallation(status.components.sessiond.installation);
}
export function formatVersion(version: string | undefined): string {
return version === undefined || version === "" ? "unknown" : version;
}
export function installationLabel(installation: PiWebInstallationInfo | undefined): string {
if (installation === undefined) return "installation unknown";
if (installation.kind === "pi-package") {
const scope = installation.scope === undefined ? "" : ` · ${installation.scope}`;
const source = installation.source ?? "Pi package";
return `${source}${scope}`;
}
if (installation.kind === "npm-global") return "global npm package";
if (installation.kind === "local") return "local checkout";
return "installation unknown";
}