Hide Git panel outside repositories

This commit is contained in:
Federico Jaramillo Martinez
2026-05-08 15:39:37 +02:00
parent 87d0aa3b21
commit 8b355f414b
9 changed files with 30 additions and 13 deletions
+1
View File
@@ -67,6 +67,7 @@ export function parseWorkspace(value: unknown): Workspace {
label: requireString(record, "label"),
...(branch === undefined ? {} : { branch }),
isMain: requireBoolean(record, "isMain"),
isGitRepo: requireBoolean(record, "isGitRepo"),
isGitWorktree: requireBoolean(record, "isGitWorktree"),
};
}
+8 -3
View File
@@ -9,7 +9,7 @@ import { ProjectController } from "../controllers/projectController";
import { SessionController } from "../controllers/sessionController";
import { WorkspaceController } from "../controllers/workspaceController";
import { KeyboardShortcutDispatcher } from "../keyboardShortcuts";
import type { QualifiedContributionId, PluginRuntimeContext } from "../plugins/types";
import type { QualifiedContributionId, QualifiedWorkspacePanelContribution, PluginRuntimeContext } from "../plugins/types";
import { corePlugin } from "../plugins/core";
import { examplePlugin } from "../plugins/example";
import { PluginRegistry } from "../plugins/registry";
@@ -179,7 +179,12 @@ export class PiWebApp extends LitElement {
}
private renderWorkspacePanel() {
return html`<workspace-panel .workspace=${this.state.selectedWorkspace} .tool=${this.state.workspaceTool} .panels=${this.plugins.getWorkspacePanels()} .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} .onSelectTool=${(tool: QualifiedContributionId) => { this.selectWorkspaceTool(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)}></workspace-panel>`;
return html`<workspace-panel .workspace=${this.state.selectedWorkspace} .tool=${this.state.workspaceTool} .panels=${this.visibleWorkspacePanels()} .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} .onSelectTool=${(tool: QualifiedContributionId) => { this.selectWorkspaceTool(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)}></workspace-panel>`;
}
private visibleWorkspacePanels(): QualifiedWorkspacePanelContribution[] {
const workspace = this.state.selectedWorkspace;
return this.plugins.getWorkspacePanels().filter((panel) => workspace === undefined || (panel.visible?.(workspace) ?? true));
}
private getActions(): AppAction[] {
@@ -223,7 +228,7 @@ export class PiWebApp extends LitElement {
<main class=${state.mainView === "chat" ? "chat-view" : "workspace-view"}>
<div class="mobile-tabs">
<button class=${state.mainView === "chat" ? "selected" : ""} @click=${() => { this.selectMainView("chat"); }}>Chat</button>
${this.plugins.getWorkspacePanels().map((panel) => html`
${this.visibleWorkspacePanels().map((panel) => html`
<button class=${state.mainView === panel.id ? "selected" : ""} @click=${() => { this.selectMainView(panel.id); }}>${panel.title}</button>
`)}
</div>
+3 -2
View File
@@ -28,11 +28,12 @@ export class WorkspacePanel extends LitElement {
override render() {
if (!this.workspace) return html`<section class="empty">Select a workspace.</section>`;
const selectedPanel = this.panels.find((panel) => panel.id === this.tool) ?? this.panels[0];
const visiblePanels = this.panels.filter((panel) => panel.visible?.(this.workspace as Workspace) ?? true);
const selectedPanel = visiblePanels.find((panel) => panel.id === this.tool) ?? visiblePanels[0];
return html`
<header>
<div class="tabs">
${this.panels.map((panel) => html`
${visiblePanels.map((panel) => html`
<button class=${selectedPanel?.id === panel.id ? "selected" : ""} @click=${() => { this.onSelectTool(panel.id); }}>${panel.title}</button>
`)}
</div>
+7 -3
View File
@@ -45,7 +45,7 @@ export function createCoreActions(): PluginAction[] {
title: "Go to Git",
shortcut: "mod+3",
group: "Navigation",
enabled: hasWorkspace,
enabled: hasGitWorkspace,
run: (context) => { context.selectMainView("core:workspace.git"); },
},
{
@@ -61,7 +61,7 @@ export function createCoreActions(): PluginAction[] {
title: "Refresh Git",
shortcut: "mod+shift+g",
group: "Workspace",
enabled: hasWorkspace,
enabled: hasGitWorkspace,
run: (context) => context.refreshGit(),
},
{
@@ -70,7 +70,7 @@ export function createCoreActions(): PluginAction[] {
shortcut: "mod+shift+r",
group: "Workspace",
enabled: hasWorkspace,
run: (context) => context.state.workspaceTool === "core:workspace.git" ? context.refreshGit() : context.refreshFiles(),
run: (context) => context.state.workspaceTool === "core:workspace.git" && context.state.selectedWorkspace?.isGitRepo === true ? context.refreshGit() : context.refreshFiles(),
},
{
id: "session.start",
@@ -103,6 +103,10 @@ function hasWorkspace(context: { state: AppState }): boolean {
return context.state.selectedWorkspace !== undefined;
}
function hasGitWorkspace(context: { state: AppState }): boolean {
return context.state.selectedWorkspace?.isGitRepo === true;
}
function isActive(status: AppState["status"]): boolean {
return status?.isStreaming === true || status?.isBashRunning === true || status?.isCompacting === true;
}
+1
View File
@@ -15,6 +15,7 @@ export function createCoreWorkspacePanels(): WorkspacePanelContribution[] {
id: "workspace.git",
title: "Git",
order: 20,
visible: (workspace) => workspace.isGitRepo,
render: renderGit,
},
];
+1 -1
View File
@@ -75,5 +75,5 @@ describe("PluginRegistry", () => {
});
function testWorkspace(): AppState["selectedWorkspace"] {
return { id: "w1", projectId: "p1", path: "/tmp/project", label: "main", isMain: true, isGitWorktree: false };
return { id: "w1", projectId: "p1", path: "/tmp/project", label: "main", isMain: true, isGitRepo: true, isGitWorktree: false };
}
+1
View File
@@ -74,6 +74,7 @@ export interface WorkspacePanelContribution {
id: LocalContributionId;
title: string;
order?: number;
visible?: (workspace: Workspace) => boolean;
render: (context: WorkspacePanelContext) => TemplateResult;
}
+7 -4
View File
@@ -7,12 +7,13 @@ const idFor = (value: string) => createHash("sha1").update(value).digest("hex").
export class WorkspaceService {
async list(project: Project): Promise<Workspace[]> {
if (!(await isGitRepository(project.path))) {
return [this.single(project)];
const isGitRepo = await isGitRepository(project.path);
if (!isGitRepo) {
return [this.single(project, false)];
}
const worktrees = await discoverGitWorktrees(project.path);
if (worktrees.length === 0) return [this.single(project)];
if (worktrees.length === 0) return [this.single(project, true)];
return worktrees.map((worktree) => {
const leafName = worktree.path.split("/").filter((part) => part !== "").at(-1);
@@ -23,18 +24,20 @@ export class WorkspaceService {
label: worktree.branch ?? (worktree.detached === true ? "detached" : leafName ?? worktree.path),
...(worktree.branch === undefined ? {} : { branch: worktree.branch }),
isMain: worktree.path === project.path,
isGitRepo: true,
isGitWorktree: true,
};
});
}
private single(project: Project): Workspace {
private single(project: Project, isGitRepo: boolean): Workspace {
return {
id: idFor(`${project.id}:${project.path}`),
projectId: project.id,
path: project.path,
label: project.name,
isMain: true,
isGitRepo,
isGitWorktree: false,
};
}
+1
View File
@@ -12,6 +12,7 @@ export interface Workspace {
label: string;
branch?: string;
isMain: boolean;
isGitRepo: boolean;
isGitWorktree: boolean;
}