Archived
refactor: simplify workspace panel terminal flow
This commit is contained in:
@@ -3,4 +3,4 @@
|
|||||||
"@jmfederico/pi-web-actions": patch
|
"@jmfederico/pi-web-actions": patch
|
||||||
---
|
---
|
||||||
|
|
||||||
Document and harden separate Pi Web plugin package development, including the Actions plugin refresh flow and private API dogfooding notes.
|
Document and harden separate Pi Web plugin package development, including the Actions plugin refresh flow and public terminal navigation helper.
|
||||||
|
|||||||
+3
-3
@@ -334,7 +334,7 @@ interface PluginRuntimeContext {
|
|||||||
configureAuth: () => void | Promise<void>;
|
configureAuth: () => void | Promise<void>;
|
||||||
logoutAuth: () => void | Promise<void>;
|
logoutAuth: () => void | Promise<void>;
|
||||||
selectWorkspaceTool: (tool: QualifiedContributionId) => void;
|
selectWorkspaceTool: (tool: QualifiedContributionId) => void;
|
||||||
openTerminal?: (options?: { terminalId?: string }) => void;
|
openTerminal: (options?: { terminalId?: string }) => void;
|
||||||
refreshFiles: () => void | Promise<void>;
|
refreshFiles: () => void | Promise<void>;
|
||||||
refreshGit: () => void | Promise<void>;
|
refreshGit: () => void | Promise<void>;
|
||||||
startSession: () => void | Promise<void>;
|
startSession: () => void | Promise<void>;
|
||||||
@@ -397,11 +397,11 @@ interface WorkspacePanelContribution {
|
|||||||
|
|
||||||
interface WorkspacePanelContext {
|
interface WorkspacePanelContext {
|
||||||
workspace: Workspace;
|
workspace: Workspace;
|
||||||
openTerminal?: (options?: { terminalId?: string }) => void;
|
openTerminal: (options?: { terminalId?: string }) => void;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`workspace` and `openTerminal()` are documented as stable for panel callbacks. Other fields may exist at runtime, but they are Pi Web internals and can change quickly. Use `openTerminal?.({ terminalId })` when a panel creates a terminal and wants Pi Web to navigate to that specific terminal. If a panel needs file, git, or session data, prefer explicit `fetch()` calls and keep them isolated.
|
`workspace` and `openTerminal()` are documented as stable for panel callbacks. Other fields may exist at runtime, but they are Pi Web internals and can change quickly. Use `openTerminal({ terminalId })` when a panel creates a terminal and wants Pi Web to navigate to that specific terminal. If a panel needs file, git, or session data, prefer explicit `fetch()` calls and keep them isolated.
|
||||||
|
|
||||||
Useful workspace shape:
|
Useful workspace shape:
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
-2
@@ -47,7 +47,7 @@ export interface PluginRuntimeContext {
|
|||||||
openThemePicker: () => void;
|
openThemePicker: () => void;
|
||||||
selectMainView: (view: string) => void;
|
selectMainView: (view: string) => void;
|
||||||
selectWorkspaceTool: (tool: QualifiedContributionId) => void;
|
selectWorkspaceTool: (tool: QualifiedContributionId) => void;
|
||||||
openTerminal?: (options?: { terminalId?: string | undefined }) => void;
|
openTerminal: (options?: { terminalId?: string | undefined }) => void;
|
||||||
refreshFiles: () => void | Promise<void>;
|
refreshFiles: () => void | Promise<void>;
|
||||||
refreshGit: () => void | Promise<void>;
|
refreshGit: () => void | Promise<void>;
|
||||||
startSession: () => void | Promise<void>;
|
startSession: () => void | Promise<void>;
|
||||||
@@ -79,7 +79,7 @@ export interface Workspace {
|
|||||||
export interface WorkspacePanelContext {
|
export interface WorkspacePanelContext {
|
||||||
workspace: Workspace;
|
workspace: Workspace;
|
||||||
state?: PluginRuntimeState;
|
state?: PluginRuntimeState;
|
||||||
openTerminal?: (options?: { terminalId?: string | undefined }) => void;
|
openTerminal: (options?: { terminalId?: string | undefined }) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WorkspacePanelContribution {
|
export interface WorkspacePanelContribution {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Configurable workspace actions for Pi Web.
|
Configurable workspace actions for Pi Web.
|
||||||
|
|
||||||
The plugin adds an **Actions** workspace tab. Actions create a new Pi Web terminal, send the configured shell command, and switch to the Terminal tab so the user can monitor progress or take over.
|
The plugin adds an **Actions** workspace tab. Actions create a new Pi Web terminal, send the configured shell command, and switch to that terminal so the user can monitor progress or take over.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { Workspace } from "@jmfederico/pi-web/plugin-api";
|
import type { Workspace } from "@jmfederico/pi-web/plugin-api";
|
||||||
import { ACTIONS_CONFIG_PATH, type WorkspaceAction } from "./config.js";
|
import { ACTIONS_CONFIG_PATH, type WorkspaceAction } from "./config.js";
|
||||||
import { createWorkspaceTerminal, sendTerminalCommand } from "./terminalDispatcher.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";
|
import { loadWorkspaceActionsConfig, type WorkspaceActionsConfigLoadResult } from "./workspaceActionsClient.js";
|
||||||
|
|
||||||
export const actionsPanelTagName = "pi-web-actions-panel";
|
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.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.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()}`;
|
if (state.config.actions.length === 0) return `<p class="muted">No actions configured in ${escapeHtml(ACTIONS_CONFIG_PATH)}.</p>${this.renderStatus()}`;
|
||||||
return `
|
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)}
|
${renderActionGroups(state.config.actions, this.runningActionId)}
|
||||||
${this.renderStatus()}
|
${this.renderStatus()}
|
||||||
`;
|
`;
|
||||||
@@ -148,7 +148,7 @@ class PiWebActionsPanel extends HTMLElement {
|
|||||||
};
|
};
|
||||||
this.runningActionId = undefined;
|
this.runningActionId = undefined;
|
||||||
this.render();
|
this.render();
|
||||||
this.openWorkspaceTerminal(workspace, terminal.id);
|
this.openWorkspaceTerminal(terminal.id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.runningActionId = undefined;
|
this.runningActionId = undefined;
|
||||||
this.status = { kind: "error", message: error instanceof Error ? error.message : String(error) };
|
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 {
|
private openWorkspaceTerminal(terminalId?: string): void {
|
||||||
if (this.openTerminalValue !== undefined) {
|
if (this.openTerminalValue === undefined) {
|
||||||
if (terminalId === undefined) this.openTerminalValue();
|
this.status = { kind: "error", message: "This Pi Web version does not provide terminal navigation to plugins." };
|
||||||
else this.openTerminalValue({ terminalId });
|
this.render();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
openTerminalPanel(workspace, terminalId);
|
if (terminalId === undefined) this.openTerminalValue();
|
||||||
|
else this.openTerminalValue({ terminalId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
interface Updatable {
|
||||||
requestUpdate: () => void;
|
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 {
|
export function requestPiWebRender(): void {
|
||||||
const app = document.querySelector("pi-web-app");
|
const app = document.querySelector("pi-web-app");
|
||||||
if (isUpdatable(app)) app.requestUpdate();
|
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 {
|
function isUpdatable(value: unknown): value is Updatable {
|
||||||
return isRecord(value) && typeof value["requestUpdate"] === "function";
|
return isRecord(value) && typeof value["requestUpdate"] === "function";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { Workspace } from "@jmfederico/pi-web/plugin-api";
|
import type { Workspace } from "@jmfederico/pi-web/plugin-api";
|
||||||
|
|
||||||
export const terminalToolId = "core:workspace.terminal";
|
|
||||||
export const actionTerminalCols = 120;
|
export const actionTerminalCols = 120;
|
||||||
export const actionTerminalRows = 32;
|
export const actionTerminalRows = 32;
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,40 @@ export type AuthDialogState =
|
|||||||
| { step: "oauth"; flow: OAuthFlowState; responding?: boolean; inputValue?: string; error?: string }
|
| { step: "oauth"; flow: OAuthFlowState; responding?: boolean; inputValue?: string; error?: string }
|
||||||
| { step: "logout"; providers: AuthProviderOption[] };
|
| { step: "logout"; providers: AuthProviderOption[] };
|
||||||
|
|
||||||
|
export type WorkspaceScopedStateReset = Pick<AppState,
|
||||||
|
| "sessions"
|
||||||
|
| "fileTree"
|
||||||
|
| "expandedDirs"
|
||||||
|
| "selectedFilePath"
|
||||||
|
| "selectedFileContent"
|
||||||
|
| "fileTreeStale"
|
||||||
|
| "gitStatus"
|
||||||
|
| "selectedDiffPath"
|
||||||
|
| "selectedDiff"
|
||||||
|
| "selectedStagedDiff"
|
||||||
|
| "gitStale"
|
||||||
|
| "selectedTerminalId"
|
||||||
|
| "error"
|
||||||
|
>;
|
||||||
|
|
||||||
|
export function resetWorkspaceScopedState(): WorkspaceScopedStateReset {
|
||||||
|
return {
|
||||||
|
sessions: [],
|
||||||
|
fileTree: [],
|
||||||
|
expandedDirs: {},
|
||||||
|
selectedFilePath: undefined,
|
||||||
|
selectedFileContent: undefined,
|
||||||
|
fileTreeStale: false,
|
||||||
|
gitStatus: undefined,
|
||||||
|
selectedDiffPath: undefined,
|
||||||
|
selectedDiff: undefined,
|
||||||
|
selectedStagedDiff: undefined,
|
||||||
|
gitStale: false,
|
||||||
|
selectedTerminalId: undefined,
|
||||||
|
error: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function initialAppState(): AppState {
|
export function initialAppState(): AppState {
|
||||||
return {
|
return {
|
||||||
projects: [],
|
projects: [],
|
||||||
|
|||||||
@@ -414,8 +414,10 @@ export class PiWebApp extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private renderWorkspacePanel() {
|
private renderWorkspacePanel() {
|
||||||
const workspaceLabelItems = this.state.selectedWorkspace === undefined ? [] : this.plugins.getWorkspaceLabelItems(this.state, this.state.selectedWorkspace);
|
const workspace = this.state.selectedWorkspace;
|
||||||
return html`<workspace-panel .workspace=${this.state.selectedWorkspace} .appState=${this.state} .tool=${this.state.workspaceTool} .panels=${this.visibleWorkspacePanels()} .workspaceLabelItems=${workspaceLabelItems} .fileTree=${this.state.fileTree} .expandedDirs=${this.state.expandedDirs} .selectedFilePath=${this.state.selectedFilePath} .selectedFileContent=${this.state.selectedFileContent} .fileTreeStale=${this.state.fileTreeStale} .gitStatus=${this.state.gitStatus} .selectedDiffPath=${this.state.selectedDiffPath} .selectedDiff=${this.state.selectedDiff} .selectedStagedDiff=${this.state.selectedStagedDiff} .gitStale=${this.state.gitStale} .activeTerminalCount=${this.state.activeTerminalCount} .selectedTerminalId=${this.state.selectedTerminalId} .terminalAutoStart=${this.terminalAutoStartWorkspaceId === this.state.selectedWorkspace?.id} .openTerminal=${(options?: { terminalId?: string | undefined }) => { this.openTerminal(options); }} .onSelectTool=${(tool: QualifiedContributionId) => { this.openWorkspaceTool(tool); }} .onRefreshFiles=${() => this.files.refreshFiles()} .onExpandDir=${(path: string) => this.files.expandDir(path)} .onSelectFile=${(path: string) => this.files.selectFile(path)} .onRefreshGit=${() => this.git.refreshGit()} .onSelectDiff=${(path: string) => this.git.selectDiff(path)} .onSelectTerminal=${(terminalId: string | undefined, options?: { replace?: boolean | undefined }) => { this.selectTerminal(terminalId, options); }}></workspace-panel>`;
|
const panelContext = workspace === undefined ? undefined : this.createWorkspacePanelContext(workspace);
|
||||||
|
const workspaceLabelItems = workspace === undefined ? [] : this.plugins.getWorkspaceLabelItems(this.state, workspace);
|
||||||
|
return html`<workspace-panel .workspace=${workspace} .panelContext=${panelContext} .tool=${this.state.workspaceTool} .panels=${this.visibleWorkspacePanels()} .workspaceLabelItems=${workspaceLabelItems} .onSelectTool=${(tool: QualifiedContributionId) => { this.openWorkspaceTool(tool); }}></workspace-panel>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderNavigationPanel(autoSwitchToChat: boolean) {
|
private renderNavigationPanel(autoSwitchToChat: boolean) {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { LitElement, html, type TemplateResult } from "lit";
|
import { LitElement, html, type TemplateResult } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators.js";
|
import { customElement, property, query, state } from "lit/decorators.js";
|
||||||
import type { FileContentResponse, FileTreeEntry, GitDiffResponse, GitStatusResponse, Workspace } from "../api";
|
import type { Workspace } from "../api";
|
||||||
import type { AppState } from "../appState";
|
|
||||||
import type { QualifiedContributionId, QualifiedWorkspacePanelContribution, WorkspaceLabelItem, WorkspacePanelContext } from "../plugins/types";
|
import type { QualifiedContributionId, QualifiedWorkspacePanelContribution, WorkspaceLabelItem, WorkspacePanelContext } from "../plugins/types";
|
||||||
import { workspacePanelStyles } from "./shared";
|
import { workspacePanelStyles } from "./shared";
|
||||||
import { renderWorkspaceLabel } from "./workspaceLabel";
|
import { renderWorkspaceLabel } from "./workspaceLabel";
|
||||||
@@ -9,32 +8,12 @@ import { renderWorkspaceLabel } from "./workspaceLabel";
|
|||||||
@customElement("workspace-panel")
|
@customElement("workspace-panel")
|
||||||
export class WorkspacePanel extends LitElement {
|
export class WorkspacePanel extends LitElement {
|
||||||
@property({ attribute: false }) workspace: Workspace | undefined;
|
@property({ attribute: false }) workspace: Workspace | undefined;
|
||||||
@property({ attribute: false }) appState!: AppState;
|
@property({ attribute: false }) panelContext: WorkspacePanelContext | undefined;
|
||||||
@property() tool: QualifiedContributionId = "core:workspace.files";
|
@property() tool: QualifiedContributionId = "core:workspace.files";
|
||||||
@property({ attribute: false }) panels: QualifiedWorkspacePanelContribution[] = [];
|
@property({ attribute: false }) panels: QualifiedWorkspacePanelContribution[] = [];
|
||||||
@property({ attribute: false }) workspaceLabelItems: WorkspaceLabelItem[] = [];
|
@property({ attribute: false }) workspaceLabelItems: WorkspaceLabelItem[] = [];
|
||||||
@property({ type: Boolean }) hideToolTabs = false;
|
@property({ type: Boolean }) hideToolTabs = false;
|
||||||
@property({ attribute: false }) fileTree: FileTreeEntry[] = [];
|
|
||||||
@property({ attribute: false }) expandedDirs: Record<string, FileTreeEntry[]> = {};
|
|
||||||
@property({ attribute: false }) selectedFilePath: string | undefined;
|
|
||||||
@property({ attribute: false }) selectedFileContent: FileContentResponse | undefined;
|
|
||||||
@property({ type: Boolean }) fileTreeStale = false;
|
|
||||||
@property({ attribute: false }) gitStatus: GitStatusResponse | undefined;
|
|
||||||
@property({ attribute: false }) selectedDiffPath: string | undefined;
|
|
||||||
@property({ attribute: false }) selectedDiff: GitDiffResponse | undefined;
|
|
||||||
@property({ attribute: false }) selectedStagedDiff: GitDiffResponse | undefined;
|
|
||||||
@property({ type: Boolean }) gitStale = false;
|
|
||||||
@property({ attribute: false }) onSelectTool: (tool: QualifiedContributionId) => void = () => undefined;
|
@property({ attribute: false }) onSelectTool: (tool: QualifiedContributionId) => void = () => undefined;
|
||||||
@property({ attribute: false }) onRefreshFiles: () => void = () => undefined;
|
|
||||||
@property({ attribute: false }) onExpandDir: (path: string) => void = () => undefined;
|
|
||||||
@property({ attribute: false }) onSelectFile: (path: string) => void = () => undefined;
|
|
||||||
@property({ attribute: false }) onRefreshGit: () => void = () => undefined;
|
|
||||||
@property({ attribute: false }) onSelectDiff: (path: string) => void = () => undefined;
|
|
||||||
@property({ type: Number }) activeTerminalCount = 0;
|
|
||||||
@property({ attribute: false }) selectedTerminalId: string | undefined;
|
|
||||||
@property({ type: Boolean }) terminalAutoStart = false;
|
|
||||||
@property({ attribute: false }) openTerminal: (options?: { terminalId?: string | undefined }) => void = () => undefined;
|
|
||||||
@property({ attribute: false }) onSelectTerminal: (terminalId: string | undefined, options?: { replace?: boolean | undefined }) => void = () => undefined;
|
|
||||||
@query(".workspace-header-strip") private workspaceHeaderStrip?: HTMLElement | null;
|
@query(".workspace-header-strip") private workspaceHeaderStrip?: HTMLElement | null;
|
||||||
@state() private workspaceHeaderCanScrollLeft = false;
|
@state() private workspaceHeaderCanScrollLeft = false;
|
||||||
@state() private workspaceHeaderCanScrollRight = false;
|
@state() private workspaceHeaderCanScrollRight = false;
|
||||||
@@ -65,9 +44,10 @@ export class WorkspacePanel extends LitElement {
|
|||||||
override render() {
|
override render() {
|
||||||
const workspace = this.workspace;
|
const workspace = this.workspace;
|
||||||
if (workspace === undefined) return html`<section class="empty">Select a workspace.</section>`;
|
if (workspace === undefined) return html`<section class="empty">Select a workspace.</section>`;
|
||||||
|
const context = this.panelContext;
|
||||||
|
if (context === undefined) return html`<section class="empty">Workspace panel unavailable.</section>`;
|
||||||
const visiblePanels = this.panels;
|
const visiblePanels = this.panels;
|
||||||
const selectedPanel = visiblePanels.find((panel) => panel.id === this.tool) ?? visiblePanels[0];
|
const selectedPanel = visiblePanels.find((panel) => panel.id === this.tool) ?? visiblePanels[0];
|
||||||
const context = this.createPanelContext(workspace);
|
|
||||||
return html`
|
return html`
|
||||||
<header>
|
<header>
|
||||||
<div class=${this.workspaceHeaderFrameClass()}>
|
<div class=${this.workspaceHeaderFrameClass()}>
|
||||||
@@ -128,32 +108,5 @@ export class WorkspacePanel extends LitElement {
|
|||||||
return strip instanceof HTMLElement ? strip : undefined;
|
return strip instanceof HTMLElement ? strip : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private createPanelContext(workspace: Workspace): WorkspacePanelContext {
|
|
||||||
return {
|
|
||||||
workspace,
|
|
||||||
state: this.appState,
|
|
||||||
fileTree: this.fileTree,
|
|
||||||
expandedDirs: this.expandedDirs,
|
|
||||||
selectedFilePath: this.selectedFilePath,
|
|
||||||
selectedFileContent: this.selectedFileContent,
|
|
||||||
fileTreeStale: this.fileTreeStale,
|
|
||||||
gitStatus: this.gitStatus,
|
|
||||||
selectedDiffPath: this.selectedDiffPath,
|
|
||||||
selectedDiff: this.selectedDiff,
|
|
||||||
selectedStagedDiff: this.selectedStagedDiff,
|
|
||||||
gitStale: this.gitStale,
|
|
||||||
activeTerminalCount: this.activeTerminalCount,
|
|
||||||
selectedTerminalId: this.selectedTerminalId,
|
|
||||||
terminalAutoStart: this.terminalAutoStart,
|
|
||||||
openTerminal: this.openTerminal,
|
|
||||||
onRefreshFiles: this.onRefreshFiles,
|
|
||||||
onExpandDir: this.onExpandDir,
|
|
||||||
onSelectFile: this.onSelectFile,
|
|
||||||
onRefreshGit: this.onRefreshGit,
|
|
||||||
onSelectDiff: this.onSelectDiff,
|
|
||||||
onSelectTerminal: this.onSelectTerminal,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static override styles = workspacePanelStyles;
|
static override styles = workspacePanelStyles;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { api, type Project, type Workspace } from "../api";
|
import { api, type Project, type Workspace } from "../api";
|
||||||
|
import { resetWorkspaceScopedState } from "../appState";
|
||||||
import { mergeCachedNewSessions } from "../cachedNewSessions";
|
import { mergeCachedNewSessions } from "../cachedNewSessions";
|
||||||
import type { GetState, RouteTarget, SetState, UpdateUrl } from "./types";
|
import type { GetState, RouteTarget, SetState, UpdateUrl } from "./types";
|
||||||
import type { SessionController } from "./sessionController";
|
import type { SessionController } from "./sessionController";
|
||||||
@@ -15,7 +16,7 @@ export class WorkspaceController {
|
|||||||
|
|
||||||
clearSelection(options?: { updateUrl?: boolean | undefined }) {
|
clearSelection(options?: { updateUrl?: boolean | undefined }) {
|
||||||
this.sessions.clearActiveSession();
|
this.sessions.clearActiveSession();
|
||||||
this.setState({ selectedProject: undefined, selectedWorkspace: undefined, sessions: [], workspaces: [], fileTree: [], expandedDirs: {}, selectedFilePath: undefined, selectedFileContent: undefined, fileTreeStale: false, gitStatus: undefined, selectedDiffPath: undefined, selectedDiff: undefined, selectedStagedDiff: undefined, gitStale: false, selectedTerminalId: undefined, error: "" });
|
this.setState({ selectedProject: undefined, selectedWorkspace: undefined, workspaces: [], ...resetWorkspaceScopedState() });
|
||||||
if (options?.updateUrl !== false) this.updateUrl();
|
if (options?.updateUrl !== false) this.updateUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ export class WorkspaceController {
|
|||||||
|
|
||||||
async selectProject(project: Project, target?: RouteTarget) {
|
async selectProject(project: Project, target?: RouteTarget) {
|
||||||
this.sessions.clearActiveSession();
|
this.sessions.clearActiveSession();
|
||||||
this.setState({ selectedProject: project, selectedWorkspace: undefined, sessions: [], workspaces: [], fileTree: [], expandedDirs: {}, selectedFilePath: undefined, selectedFileContent: undefined, fileTreeStale: false, gitStatus: undefined, selectedDiffPath: undefined, selectedDiff: undefined, selectedStagedDiff: undefined, gitStale: false, selectedTerminalId: undefined, error: "" });
|
this.setState({ selectedProject: project, selectedWorkspace: undefined, workspaces: [], ...resetWorkspaceScopedState() });
|
||||||
try {
|
try {
|
||||||
const workspaces = await api.workspaces(project.id);
|
const workspaces = await api.workspaces(project.id);
|
||||||
this.setState({ workspaces, workspacesByProjectId: { ...this.getState().workspacesByProjectId, [project.id]: workspaces } });
|
this.setState({ workspaces, workspacesByProjectId: { ...this.getState().workspacesByProjectId, [project.id]: workspaces } });
|
||||||
@@ -42,7 +43,7 @@ export class WorkspaceController {
|
|||||||
async selectWorkspace(workspace: Workspace, target?: { sessionId?: string | undefined; updateUrl?: boolean | undefined }) {
|
async selectWorkspace(workspace: Workspace, target?: { sessionId?: string | undefined; updateUrl?: boolean | undefined }) {
|
||||||
this.workspaceSelection.rememberWorkspace(workspace);
|
this.workspaceSelection.rememberWorkspace(workspace);
|
||||||
this.sessions.clearActiveSession();
|
this.sessions.clearActiveSession();
|
||||||
this.setState({ selectedWorkspace: workspace, sessions: [], fileTree: [], expandedDirs: {}, selectedFilePath: undefined, selectedFileContent: undefined, fileTreeStale: false, gitStatus: undefined, selectedDiffPath: undefined, selectedDiff: undefined, selectedStagedDiff: undefined, gitStale: false, selectedTerminalId: undefined, error: "" });
|
this.setState({ selectedWorkspace: workspace, ...resetWorkspaceScopedState() });
|
||||||
try {
|
try {
|
||||||
const sessions = mergeCachedNewSessions(workspace.path, await api.sessions(workspace.path));
|
const sessions = mergeCachedNewSessions(workspace.path, await api.sessions(workspace.path));
|
||||||
this.setState({ sessions });
|
this.setState({ sessions });
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export interface PluginRuntimeContext {
|
|||||||
openThemePicker: () => void;
|
openThemePicker: () => void;
|
||||||
selectMainView: (view: AppState["mainView"]) => void;
|
selectMainView: (view: AppState["mainView"]) => void;
|
||||||
selectWorkspaceTool: (tool: QualifiedContributionId) => void;
|
selectWorkspaceTool: (tool: QualifiedContributionId) => void;
|
||||||
openTerminal?: (options?: { terminalId?: string | undefined }) => void;
|
openTerminal: (options?: { terminalId?: string | undefined }) => void;
|
||||||
refreshFiles: () => void | Promise<void>;
|
refreshFiles: () => void | Promise<void>;
|
||||||
refreshGit: () => void | Promise<void>;
|
refreshGit: () => void | Promise<void>;
|
||||||
startSession: () => void | Promise<void>;
|
startSession: () => void | Promise<void>;
|
||||||
@@ -91,7 +91,7 @@ export interface WorkspacePanelContext {
|
|||||||
activeTerminalCount: number;
|
activeTerminalCount: number;
|
||||||
selectedTerminalId: string | undefined;
|
selectedTerminalId: string | undefined;
|
||||||
terminalAutoStart: boolean;
|
terminalAutoStart: boolean;
|
||||||
openTerminal?: (options?: { terminalId?: string | undefined }) => void;
|
openTerminal: (options?: { terminalId?: string | undefined }) => void;
|
||||||
onRefreshFiles: () => void;
|
onRefreshFiles: () => void;
|
||||||
onExpandDir: (path: string) => void;
|
onExpandDir: (path: string) => void;
|
||||||
onSelectFile: (path: string) => void;
|
onSelectFile: (path: string) => void;
|
||||||
|
|||||||
Reference in New Issue
Block a user