From b35ce1d3e039663d02e2d668b802649a49443339 Mon Sep 17 00:00:00 2001 From: Federico Jaramillo Martinez Date: Fri, 5 Jun 2026 20:26:12 +0200 Subject: [PATCH] fix: reduce repeated workspace context --- .changeset/lean-workspace-context.md | 5 +++++ src/client/src/components/PiWebApp.ts | 4 +--- src/client/src/components/StatusBar.ts | 7 +------ src/client/src/components/WorkspacePanel.ts | 19 ++++++++----------- src/client/src/components/shared.ts | 10 +--------- 5 files changed, 16 insertions(+), 29 deletions(-) create mode 100644 .changeset/lean-workspace-context.md diff --git a/.changeset/lean-workspace-context.md b/.changeset/lean-workspace-context.md new file mode 100644 index 0000000..4542b43 --- /dev/null +++ b/.changeset/lean-workspace-context.md @@ -0,0 +1,5 @@ +--- +"@jmfederico/pi-web": patch +--- + +Reduce repeated workspace details in the chat status bar and workspace tool header so workspace context stays in the workspace chip. diff --git a/src/client/src/components/PiWebApp.ts b/src/client/src/components/PiWebApp.ts index 4bc238c..d8c0efc 100644 --- a/src/client/src/components/PiWebApp.ts +++ b/src/client/src/components/PiWebApp.ts @@ -726,7 +726,6 @@ export class PiWebApp extends LitElement { private renderWorkspacePanel() { const workspace = this.state.selectedWorkspace; const panelContext = workspace === undefined ? undefined : this.createWorkspacePanelContext(workspace); - const workspaceLabelItems = workspace === undefined ? [] : this.workspaceLabelItems(workspace); const emptyState = workspace === undefined ? this.workspacePanelEmptyState() : undefined; return html` { this.openWorkspaceTool(tool); }} > `; @@ -1384,7 +1382,7 @@ export class PiWebApp extends LitElement { ${state.selectedSession ? html` 0} .loadingMore=${state.isLoadingEarlierMessages} .isReceivingPartialStream=${state.isReceivingPartialStream} .isCompacting=${state.status?.isCompacting === true} .pendingMessageCount=${state.status?.pendingMessageCount ?? 0} .status=${state.status} .activity=${state.activity} .onLoadMore=${() => this.withChatPrependTransition(() => this.sessions.loadEarlierMessages())}> 0} .status=${state.status} .onSend=${(text: string, streamingBehavior?: "steer" | "followUp") => { this.sendPrompt(text, streamingBehavior); }} .onStop=${() => this.sessions.stopActiveWork()} .onSelectModel=${() => { void this.openModelDialog(); }} .onSelectThinking=${() => { void this.openThinkingDialog(); }}> - + ${state.commandDialog !== undefined ? html` this.sessions.respondToCommand(state.commandDialog?.requestId ?? "", value)} .onCancel=${() => { this.sessions.cancelCommand(); }}>` : null} ${state.modelDialog !== undefined ? html` { void this.pickModel(value); }} .onCancel=${() => { this.setState({ modelDialog: undefined }); }}>` : null} ${state.thinkingDialog !== undefined ? html` { void this.pickThinking(value); }} .onCancel=${() => { this.setState({ thinkingDialog: undefined }); }}>` : null} diff --git a/src/client/src/components/StatusBar.ts b/src/client/src/components/StatusBar.ts index 72666e1..3fa605b 100644 --- a/src/client/src/components/StatusBar.ts +++ b/src/client/src/components/StatusBar.ts @@ -1,17 +1,13 @@ import { LitElement, html } from "lit"; import { customElement, property } from "lit/decorators.js"; -import type { Machine, SessionStatus, Workspace } from "../api"; -import type { WorkspaceLabelItem } from "../plugins/types"; +import type { Machine, SessionStatus } from "../api"; import { formatCost, formatTokenCount } from "../utils/format"; import { statusBarStyles } from "./shared"; -import { renderWorkspaceLabel } from "./workspaceLabel"; @customElement("status-bar") export class StatusBar extends LitElement { @property({ attribute: false }) status?: SessionStatus; @property({ attribute: false }) machine?: Machine; - @property({ attribute: false }) workspace?: Workspace; - @property({ attribute: false }) workspaceLabelItems: WorkspaceLabelItem[] = []; override render() { const status = this.status; @@ -26,7 +22,6 @@ export class StatusBar extends LitElement { return html`
${this.machine?.name ?? "Local"} - ${renderWorkspaceLabel(this.workspace?.label ?? "workspace", this.workspaceLabelItems, this.workspace?.path)} ↑${formatTokenCount(tokens.input)} ↓${formatTokenCount(tokens.output)} ${contextText} diff --git a/src/client/src/components/WorkspacePanel.ts b/src/client/src/components/WorkspacePanel.ts index ced47fb..43f3029 100644 --- a/src/client/src/components/WorkspacePanel.ts +++ b/src/client/src/components/WorkspacePanel.ts @@ -1,9 +1,8 @@ import { LitElement, html, type TemplateResult } from "lit"; import { customElement, property, query, state } from "lit/decorators.js"; import type { Workspace } from "../api"; -import type { QualifiedContributionId, QualifiedWorkspacePanelContribution, WorkspaceLabelItem, WorkspacePanelContext } from "../plugins/types"; +import type { QualifiedContributionId, QualifiedWorkspacePanelContribution, WorkspacePanelContext } from "../plugins/types"; import { workspacePanelStyles } from "./shared"; -import { renderWorkspaceLabel } from "./workspaceLabel"; export interface WorkspacePanelEmptyState { title: string; @@ -19,7 +18,6 @@ export class WorkspacePanel extends LitElement { @property({ attribute: false }) emptyState: WorkspacePanelEmptyState | 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 }) onSelectTool: (tool: QualifiedContributionId) => void = () => undefined; @query(".workspace-header-strip") private workspaceHeaderStrip?: HTMLElement | null; @@ -63,10 +61,10 @@ export class WorkspacePanel extends LitElement { const visiblePanels = this.panels; const selectedPanel = visiblePanels.find((panel) => panel.id === this.tool) ?? visiblePanels[0]; return html` -
-
-
- ${this.hideToolTabs ? null : html` + ${this.hideToolTabs ? null : html` +
+
+
${visiblePanels.map((panel) => { const selected = selectedPanel?.id === panel.id; @@ -79,11 +77,10 @@ export class WorkspacePanel extends LitElement { `; })}
- `} - ${renderWorkspaceLabel(workspace.label, this.workspaceLabelItems, workspace.path)} +
-
-
+ + `} ${selectedPanel === undefined ? this.renderEmptyState({ title: "No workspace tools available", body: "No tools are available for this workspace.", diff --git a/src/client/src/components/shared.ts b/src/client/src/components/shared.ts index e4a4ee1..8aeca75 100644 --- a/src/client/src/components/shared.ts +++ b/src/client/src/components/shared.ts @@ -186,10 +186,7 @@ export const workspacePanelStyles = css` .empty-state h2 { margin: 0; color: var(--pi-text); font-size: 15px; line-height: 1.3; } .empty-state p { margin: 0; line-height: 1.45; } small, .muted { color: var(--pi-muted); } - header small { flex: 0 0 auto; min-width: max-content; overflow: visible; text-overflow: clip; white-space: nowrap; } - header .workspace-label { width: max-content; max-width: none; overflow: visible; } - header .workspace-label-base, header .workspace-label-item, header .workspace-label-render { overflow: visible; text-overflow: clip; } - @media (max-width: 1180px) { .tabs { display: none; } } + @media (max-width: 1180px) { header { display: none; } } .workspace-label { min-width: 0; display: inline-flex; align-items: baseline; gap: 5px; max-width: 100%; overflow: hidden; white-space: nowrap; } .workspace-label-base, .workspace-label-item, .workspace-label-render { min-width: 0; overflow: hidden; text-overflow: ellipsis; } .workspace-label-item, .workspace-label-render, .workspace-label-separator { color: var(--pi-muted); } @@ -395,11 +392,6 @@ export const statusBarStyles = css` :host { display: block; color: var(--pi-muted); font: 12px system-ui, sans-serif; } .bar { display: flex; gap: 12px; align-items: center; min-width: 0; padding: 7px 12px; border-top: 1px solid var(--pi-border); background: var(--pi-bg); white-space: nowrap; overflow: hidden; } span { overflow: hidden; text-overflow: ellipsis; } - .workspace-label { min-width: 0; display: inline-flex; align-items: baseline; gap: 5px; max-width: 100%; overflow: hidden; white-space: nowrap; } - .workspace-label-base, .workspace-label-item, .workspace-label-render { min-width: 0; overflow: hidden; text-overflow: ellipsis; } - .workspace-label-item, .workspace-label-render, .workspace-label-separator { color: var(--pi-muted); } - .workspace-label-link { color: var(--pi-accent); text-decoration: none; } - .workspace-label-link:hover, .workspace-label-link:focus { text-decoration: underline; } .bar > span:first-child { flex: 1 1 auto; min-width: 80px; } .activity { display: inline-flex; align-items: center; gap: 6px; color: var(--pi-muted); } .activity.active { color: var(--pi-success); }