Archived
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.
This commit is contained in:
@@ -1,10 +1,6 @@
|
||||
import type { TemplateResult } from "lit";
|
||||
import type { HtmlTemplateTag, PiWebComponentStatus, PiWebInstallationInfo, PiWebPlugin, PiWebStatusMessage, PiWebStatusResponse, PluginRuntimeState, WorkspacePanelTerminal } from "@jmfederico/pi-web/plugin-api";
|
||||
|
||||
interface CommandEntry {
|
||||
label: string;
|
||||
command: string;
|
||||
}
|
||||
import type { HtmlTemplateTag, PiWebComponentStatus, PiWebPlugin, PiWebStatusResponse, PluginRuntimeState, WorkspacePanelTerminal } from "@jmfederico/pi-web/plugin-api";
|
||||
import { additionalCommands, formatVersion, installationLabel, messageCount, recommendedCommand, shouldShowUpdatesPanel, statusFor } from "./updatesLogic.js";
|
||||
|
||||
function runCommandInTerminal(terminal: WorkspacePanelTerminal, label: string, command: string): void {
|
||||
void terminal.runCommand({
|
||||
@@ -17,74 +13,6 @@ function runCommandInTerminal(terminal: WorkspacePanelTerminal, label: string, c
|
||||
});
|
||||
}
|
||||
|
||||
// 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.
|
||||
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;
|
||||
}
|
||||
|
||||
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 }));
|
||||
}
|
||||
|
||||
function messagesFor(state: PluginRuntimeState | undefined): PiWebStatusMessage[] {
|
||||
return state?.piWebStatus?.messages ?? [];
|
||||
}
|
||||
|
||||
function statusFor(state: PluginRuntimeState | undefined): PiWebStatusResponse | undefined {
|
||||
return state?.piWebStatus;
|
||||
}
|
||||
|
||||
function messageCount(state: PluginRuntimeState | undefined): number {
|
||||
return messagesFor(state).length;
|
||||
}
|
||||
|
||||
function isLocalOrUnknownInstallation(installation: PiWebInstallationInfo | undefined): boolean {
|
||||
return installation === undefined || installation.kind === "local" || installation.kind === "unknown";
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
function formatVersion(version: string | undefined): string {
|
||||
return version === undefined || version === "" ? "unknown" : version;
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
function renderComponent(html: HtmlTemplateTag, component: PiWebComponentStatus): TemplateResult {
|
||||
const status = !component.available
|
||||
? "unavailable"
|
||||
|
||||
Reference in New Issue
Block a user