refactor: simplify workspace panel terminal flow

This commit is contained in:
Federico Jaramillo Martinez
2026-05-21 09:31:33 +02:00
parent fb7903f3cb
commit c740ac3dcb
12 changed files with 65 additions and 129 deletions
+10 -9
View File
@@ -1,7 +1,7 @@
import type { Workspace } from "@jmfederico/pi-web/plugin-api";
import { ACTIONS_CONFIG_PATH, type WorkspaceAction } from "./config.js";
import { createWorkspaceTerminal, sendTerminalCommand } from "./terminalDispatcher.js";
import { openTerminalPanel, requestPiWebRender } from "./piWebPrivateUi.js";
import { requestPiWebRender } from "./piWebPrivateUi.js";
import { loadWorkspaceActionsConfig, type WorkspaceActionsConfigLoadResult } from "./workspaceActionsClient.js";
export const actionsPanelTagName = "pi-web-actions-panel";
@@ -94,7 +94,7 @@ class PiWebActionsPanel extends HTMLElement {
}
this.root.querySelector("button[data-open-terminal]")?.addEventListener("click", () => {
this.openWorkspaceTerminal(workspace);
this.openWorkspaceTerminal();
});
}
@@ -103,7 +103,7 @@ class PiWebActionsPanel extends HTMLElement {
if (state.kind === "unavailable") return `${renderUnavailableState(state)}${this.renderStatus()}`;
if (state.config.actions.length === 0) return `<p class="muted">No actions configured in ${escapeHtml(ACTIONS_CONFIG_PATH)}.</p>${this.renderStatus()}`;
return `
<p class="muted">Actions create a new workspace terminal, send the command, then switch to the Terminal tab. Edit ${escapeHtml(ACTIONS_CONFIG_PATH)} and click Refresh to reload.</p>
<p class="muted">Actions create a new workspace terminal, send the command, then switch to that terminal. Edit ${escapeHtml(ACTIONS_CONFIG_PATH)} and click Refresh to reload.</p>
${renderActionGroups(state.config.actions, this.runningActionId)}
${this.renderStatus()}
`;
@@ -148,7 +148,7 @@ class PiWebActionsPanel extends HTMLElement {
};
this.runningActionId = undefined;
this.render();
this.openWorkspaceTerminal(workspace, terminal.id);
this.openWorkspaceTerminal(terminal.id);
} catch (error) {
this.runningActionId = undefined;
this.status = { kind: "error", message: error instanceof Error ? error.message : String(error) };
@@ -156,13 +156,14 @@ class PiWebActionsPanel extends HTMLElement {
}
}
private openWorkspaceTerminal(workspace: Workspace, terminalId?: string): void {
if (this.openTerminalValue !== undefined) {
if (terminalId === undefined) this.openTerminalValue();
else this.openTerminalValue({ terminalId });
private openWorkspaceTerminal(terminalId?: string): void {
if (this.openTerminalValue === undefined) {
this.status = { kind: "error", message: "This Pi Web version does not provide terminal navigation to plugins." };
this.render();
return;
}
openTerminalPanel(workspace, terminalId);
if (terminalId === undefined) this.openTerminalValue();
else this.openTerminalValue({ terminalId });
}
}
-54
View File
@@ -1,66 +1,12 @@
import type { Workspace } from "@jmfederico/pi-web/plugin-api";
import { terminalToolId, type TerminalInfo } from "./terminalDispatcher.js";
interface TerminalPanelElement {
terminals: TerminalInfo[];
selectTerminal: (terminalId: string) => void;
}
interface Updatable {
requestUpdate: () => void;
}
/**
* Private Pi Web UI fallback used while the plugin API is still being dogfooded.
* The current host provides a panel `openTerminal` helper; keep this fallback contained
* for older hosts and replace/remove it once the public helper is required.
*/
export function openTerminalPanel(workspace: Workspace, terminalId?: string): void {
const url = new URL(window.location.href);
url.searchParams.set("project", workspace.projectId);
url.searchParams.set("workspace", workspace.id);
url.searchParams.set("tool", terminalToolId);
url.searchParams.set("view", terminalToolId);
window.history.pushState({}, "", url);
dispatchPopState();
if (terminalId !== undefined) selectTerminalWhenAvailable(terminalId);
}
export function requestPiWebRender(): void {
const app = document.querySelector("pi-web-app");
if (isUpdatable(app)) app.requestUpdate();
}
function dispatchPopState(): void {
if (typeof PopStateEvent === "function") {
window.dispatchEvent(new PopStateEvent("popstate"));
return;
}
window.dispatchEvent(new Event("popstate"));
}
function selectTerminalWhenAvailable(terminalId: string, attempt = 0): void {
const terminalPanel = findTerminalPanel();
const terminals = terminalPanel?.terminals ?? [];
const hasTerminal = terminals.some((terminal) => terminal.id === terminalId);
if (terminalPanel !== undefined && hasTerminal) {
terminalPanel.selectTerminal(terminalId);
return;
}
if (attempt < 50) window.setTimeout(() => { selectTerminalWhenAvailable(terminalId, attempt + 1); }, 150);
}
function findTerminalPanel(): TerminalPanelElement | undefined {
const panel = document.querySelector("workspace-panel")?.shadowRoot?.querySelector("terminal-panel");
return isTerminalPanelElement(panel) ? panel : undefined;
}
function isTerminalPanelElement(value: unknown): value is TerminalPanelElement {
return isRecord(value) && Array.isArray(value["terminals"]) && typeof value["selectTerminal"] === "function";
}
function isUpdatable(value: unknown): value is Updatable {
return isRecord(value) && typeof value["requestUpdate"] === "function";
}
@@ -1,6 +1,5 @@
import type { Workspace } from "@jmfederico/pi-web/plugin-api";
export const terminalToolId = "core:workspace.terminal";
export const actionTerminalCols = 120;
export const actionTerminalRows = 32;