diff --git a/src/client/src/api/parsers.ts b/src/client/src/api/parsers.ts index 5f750d9..c13b022 100644 --- a/src/client/src/api/parsers.ts +++ b/src/client/src/api/parsers.ts @@ -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"), }; } diff --git a/src/client/src/components/PiWebApp.ts b/src/client/src/components/PiWebApp.ts index 35b8fed..036439b 100644 --- a/src/client/src/components/PiWebApp.ts +++ b/src/client/src/components/PiWebApp.ts @@ -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` { 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)}>`; + return html` { 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)}>`; + } + + 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 {
- ${this.plugins.getWorkspacePanels().map((panel) => html` + ${this.visibleWorkspacePanels().map((panel) => html` `)}
diff --git a/src/client/src/components/WorkspacePanel.ts b/src/client/src/components/WorkspacePanel.ts index 030cdd7..9b1b315 100644 --- a/src/client/src/components/WorkspacePanel.ts +++ b/src/client/src/components/WorkspacePanel.ts @@ -28,11 +28,12 @@ export class WorkspacePanel extends LitElement { override render() { if (!this.workspace) return html`
Select a workspace.
`; - 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`
- ${this.panels.map((panel) => html` + ${visiblePanels.map((panel) => html` `)}
diff --git a/src/client/src/plugins/core/actions.ts b/src/client/src/plugins/core/actions.ts index d550557..e124056 100644 --- a/src/client/src/plugins/core/actions.ts +++ b/src/client/src/plugins/core/actions.ts @@ -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; } diff --git a/src/client/src/plugins/core/panels.ts b/src/client/src/plugins/core/panels.ts index 2e21f52..460c865 100644 --- a/src/client/src/plugins/core/panels.ts +++ b/src/client/src/plugins/core/panels.ts @@ -15,6 +15,7 @@ export function createCoreWorkspacePanels(): WorkspacePanelContribution[] { id: "workspace.git", title: "Git", order: 20, + visible: (workspace) => workspace.isGitRepo, render: renderGit, }, ]; diff --git a/src/client/src/plugins/registry.test.ts b/src/client/src/plugins/registry.test.ts index f25d211..c231262 100644 --- a/src/client/src/plugins/registry.test.ts +++ b/src/client/src/plugins/registry.test.ts @@ -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 }; } diff --git a/src/client/src/plugins/types.ts b/src/client/src/plugins/types.ts index c3e54bb..cc81909 100644 --- a/src/client/src/plugins/types.ts +++ b/src/client/src/plugins/types.ts @@ -74,6 +74,7 @@ export interface WorkspacePanelContribution { id: LocalContributionId; title: string; order?: number; + visible?: (workspace: Workspace) => boolean; render: (context: WorkspacePanelContext) => TemplateResult; } diff --git a/src/server/workspaces/workspaceService.ts b/src/server/workspaces/workspaceService.ts index bb50aec..786fa6f 100644 --- a/src/server/workspaces/workspaceService.ts +++ b/src/server/workspaces/workspaceService.ts @@ -7,12 +7,13 @@ const idFor = (value: string) => createHash("sha1").update(value).digest("hex"). export class WorkspaceService { async list(project: Project): Promise { - 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, }; } diff --git a/src/shared/apiTypes.ts b/src/shared/apiTypes.ts index d198af7..ce23abc 100644 --- a/src/shared/apiTypes.ts +++ b/src/shared/apiTypes.ts @@ -12,6 +12,7 @@ export interface Workspace { label: string; branch?: string; isMain: boolean; + isGitRepo: boolean; isGitWorktree: boolean; }