Enhance ChatStatusDashboard to allow custom title header container for improved layout integration

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
mrleemurray
2026-04-29 17:03:22 +01:00
parent 4c778cc426
commit 820a1bc0d8
2 changed files with 15 additions and 18 deletions
@@ -35,7 +35,7 @@ import { URI } from '../../../../base/common/uri.js';
import { isWindows, isMacintosh } from '../../../../base/common/platform.js';
import { UpdateHoverWidget } from './updateHoverWidget.js';
import { ChatEntitlement, ChatEntitlementService, IChatEntitlementService } from '../../../../workbench/services/chat/common/chatEntitlementService.js';
import { ChatStatusDashboard } from '../../../../workbench/contrib/chat/browser/chatStatus/chatStatusDashboard.js';
import { ChatStatusDashboard, IChatStatusDashboardOptions } from '../../../../workbench/contrib/chat/browser/chatStatus/chatStatusDashboard.js';
import { HoverPosition } from '../../../../base/browser/ui/hover/hoverWidget.js';
import { ThemeIcon } from '../../../../base/common/themables.js';
import { getAccountProfileImageUrl, getAccountTitleBarBadgeKey, getAccountTitleBarState, resolveAccountInfo } from '../../../browser/accountTitleBarState.js';
@@ -608,22 +608,10 @@ class TitleBarAccountWidget extends BaseActionViewItem {
const subscriptionHeader = append(subscriptionSection, $('.sessions-account-titlebar-panel-section-header'));
const subscriptionHeading = append(subscriptionHeader, $('div.sessions-account-titlebar-panel-section-title', { id: subscriptionId }));
subscriptionHeading.textContent = localize('sessionsAccountMenu.subscription', "Subscription");
const dashboard = this.createCopilotHoverContent();
// Render the dashboard's title header (plan name + manage / CTA actions)
// directly into our section header row via the dashboard's public API.
const dashboard = this.createCopilotHoverContent({ titleHeaderContainer: subscriptionHeader });
append(subscriptionSection, dashboard);
// Move the dashboard's plan-name + manage-action header into our section header row,
// so the plan name and settings button appear right-aligned next to "Subscription".
// The dashboard is wrapped in a `display: contents` div, hence reaching one level in.
// Note: the dashboard renders the title header synchronously and never re-creates it,
// so a one-time move is safe today. Tolerate non-`.header` first children defensively.
const tooltipRoot = dashboard.firstElementChild;
if (tooltipRoot) {
for (const child of Array.from(tooltipRoot.children)) {
if (child.classList.contains('header')) {
subscriptionHeader.appendChild(child);
break;
}
}
}
} else if (!this.isAccountLoading) {
const summary = append(contentSection, $('.sessions-account-titlebar-panel-summary'));
summary.textContent = this.lastState.ariaLabel;
@@ -760,7 +748,7 @@ class TitleBarAccountWidget extends BaseActionViewItem {
return !this.chatEntitlementService.sentiment.hidden && !!this.accountName;
}
private createCopilotHoverContent(): HTMLElement {
private createCopilotHoverContent(extraOptions?: Partial<IChatStatusDashboardOptions>): HTMLElement {
const store = new DisposableStore();
this.copilotDashboardStore.value = store;
const dashboardElement = ChatStatusDashboard.instantiateInContents(this.instantiationService, store, {
@@ -769,6 +757,7 @@ class TitleBarAccountWidget extends BaseActionViewItem {
disableProviderOptions: true,
disableCompletionsSnooze: true,
disableQuickSettingsCollapsible: true,
...extraOptions,
});
store.add(disposableWindowInterval(mainWindow, () => {
@@ -75,6 +75,13 @@ export interface IChatStatusDashboardOptions {
disableCompletionsSnooze?: boolean;
/** When true, the Quick Settings region is rendered always-expanded without a collapsible header. */
disableQuickSettingsCollapsible?: boolean;
/**
* When provided, the title header (plan name + manage / CTA actions) is
* rendered into this caller-owned container instead of inline at the top
* of the dashboard. Use this to embed the title header in a host layout
* without reaching into the dashboard's private DOM.
*/
titleHeaderContainer?: HTMLElement;
}
export class ChatStatusDashboard extends DomWidget {
@@ -133,7 +140,8 @@ export class ChatStatusDashboard extends DomWidget {
let headerAdditionalSpendButton: Button | undefined;
if (hasUsageSection) {
const planName = getChatPlanName(this.chatEntitlementService.entitlement);
const header = this.renderHeader(this.element, this._store, planName, toAction({
const headerHost = this.options?.titleHeaderContainer ?? this.element;
const header = this.renderHeader(headerHost, this._store, planName, toAction({
id: 'workbench.action.manageCopilot',
label: localize('quotaLabel', "Manage Chat"),
tooltip: localize('quotaTooltip', "Manage Chat"),