Archived
refactor: simplify workspace panel terminal flow
This commit is contained in:
@@ -52,6 +52,40 @@ export type AuthDialogState =
|
||||
| { step: "oauth"; flow: OAuthFlowState; responding?: boolean; inputValue?: string; error?: string }
|
||||
| { 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 {
|
||||
return {
|
||||
projects: [],
|
||||
|
||||
@@ -414,8 +414,10 @@ export class PiWebApp extends LitElement {
|
||||
}
|
||||
|
||||
private renderWorkspacePanel() {
|
||||
const workspaceLabelItems = this.state.selectedWorkspace === undefined ? [] : this.plugins.getWorkspaceLabelItems(this.state, 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 workspace = this.state.selectedWorkspace;
|
||||
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) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { LitElement, html, type TemplateResult } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators.js";
|
||||
import type { FileContentResponse, FileTreeEntry, GitDiffResponse, GitStatusResponse, Workspace } from "../api";
|
||||
import type { AppState } from "../appState";
|
||||
import type { Workspace } from "../api";
|
||||
import type { QualifiedContributionId, QualifiedWorkspacePanelContribution, WorkspaceLabelItem, WorkspacePanelContext } from "../plugins/types";
|
||||
import { workspacePanelStyles } from "./shared";
|
||||
import { renderWorkspaceLabel } from "./workspaceLabel";
|
||||
@@ -9,32 +8,12 @@ import { renderWorkspaceLabel } from "./workspaceLabel";
|
||||
@customElement("workspace-panel")
|
||||
export class WorkspacePanel extends LitElement {
|
||||
@property({ attribute: false }) workspace: Workspace | undefined;
|
||||
@property({ attribute: false }) appState!: AppState;
|
||||
@property({ attribute: false }) panelContext: WorkspacePanelContext | undefined;
|
||||
@property() tool: QualifiedContributionId = "core:workspace.files";
|
||||
@property({ attribute: false }) panels: QualifiedWorkspacePanelContribution[] = [];
|
||||
@property({ attribute: false }) workspaceLabelItems: WorkspaceLabelItem[] = [];
|
||||
@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 }) 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;
|
||||
@state() private workspaceHeaderCanScrollLeft = false;
|
||||
@state() private workspaceHeaderCanScrollRight = false;
|
||||
@@ -65,9 +44,10 @@ export class WorkspacePanel extends LitElement {
|
||||
override render() {
|
||||
const workspace = this.workspace;
|
||||
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 selectedPanel = visiblePanels.find((panel) => panel.id === this.tool) ?? visiblePanels[0];
|
||||
const context = this.createPanelContext(workspace);
|
||||
return html`
|
||||
<header>
|
||||
<div class=${this.workspaceHeaderFrameClass()}>
|
||||
@@ -128,32 +108,5 @@ export class WorkspacePanel extends LitElement {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { api, type Project, type Workspace } from "../api";
|
||||
import { resetWorkspaceScopedState } from "../appState";
|
||||
import { mergeCachedNewSessions } from "../cachedNewSessions";
|
||||
import type { GetState, RouteTarget, SetState, UpdateUrl } from "./types";
|
||||
import type { SessionController } from "./sessionController";
|
||||
@@ -15,7 +16,7 @@ export class WorkspaceController {
|
||||
|
||||
clearSelection(options?: { updateUrl?: boolean | undefined }) {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -27,7 +28,7 @@ export class WorkspaceController {
|
||||
|
||||
async selectProject(project: Project, target?: RouteTarget) {
|
||||
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 {
|
||||
const workspaces = await api.workspaces(project.id);
|
||||
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 }) {
|
||||
this.workspaceSelection.rememberWorkspace(workspace);
|
||||
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 {
|
||||
const sessions = mergeCachedNewSessions(workspace.path, await api.sessions(workspace.path));
|
||||
this.setState({ sessions });
|
||||
|
||||
@@ -47,7 +47,7 @@ export interface PluginRuntimeContext {
|
||||
openThemePicker: () => void;
|
||||
selectMainView: (view: AppState["mainView"]) => void;
|
||||
selectWorkspaceTool: (tool: QualifiedContributionId) => void;
|
||||
openTerminal?: (options?: { terminalId?: string | undefined }) => void;
|
||||
openTerminal: (options?: { terminalId?: string | undefined }) => void;
|
||||
refreshFiles: () => void | Promise<void>;
|
||||
refreshGit: () => void | Promise<void>;
|
||||
startSession: () => void | Promise<void>;
|
||||
@@ -91,7 +91,7 @@ export interface WorkspacePanelContext {
|
||||
activeTerminalCount: number;
|
||||
selectedTerminalId: string | undefined;
|
||||
terminalAutoStart: boolean;
|
||||
openTerminal?: (options?: { terminalId?: string | undefined }) => void;
|
||||
openTerminal: (options?: { terminalId?: string | undefined }) => void;
|
||||
onRefreshFiles: () => void;
|
||||
onExpandDir: (path: string) => void;
|
||||
onSelectFile: (path: string) => void;
|
||||
|
||||
Reference in New Issue
Block a user