mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Normalize tooltip and ARIA labeling
This commit is contained in:
parent
f000fa7e75
commit
9f5232ec58
11 changed files with 50 additions and 58 deletions
|
|
@ -323,7 +323,6 @@ function renderReferencedThread(parent: HTMLElement, item: Extract<DisplayItem,
|
|||
label.createSpan({ text: reference.title });
|
||||
label.createSpan({ cls: "codex-panel__edited-files-separator", text: "·" });
|
||||
label.createSpan({ text: `${String(reference.includedTurns)}/${String(reference.turnLimit)} turns` });
|
||||
wrapper.title = reference.threadId;
|
||||
}
|
||||
|
||||
function renderEditedFiles(parent: HTMLElement, item: Extract<DisplayItem, { kind: "message" }>, context: MessageStreamContext): void {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export function renderToolResult(parent: HTMLElement, item: ToolResultDisplayIte
|
|||
const messageEl = root;
|
||||
applyExecutionStateClass(messageEl, view.state);
|
||||
createToolResultHeader(messageEl, view);
|
||||
const content = messageEl.createDiv({ cls: "codex-panel__tool-summary", attr: { title: view.summary } });
|
||||
const content = messageEl.createDiv({ cls: "codex-panel__tool-summary" });
|
||||
context.renderTextWithWikiLinks(content, view.summary);
|
||||
|
||||
for (const section of view.details) {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ export interface ToolbarChoice {
|
|||
label: string;
|
||||
selected?: boolean;
|
||||
disabled?: boolean;
|
||||
title?: string;
|
||||
meta?: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
|
@ -52,7 +51,6 @@ export interface ToolbarViewModel {
|
|||
fastActive: boolean;
|
||||
runtimeSummary: string;
|
||||
runtimeTitle: string;
|
||||
runtimeAriaLabel: string;
|
||||
runtimeEmphasized: boolean;
|
||||
context: { level: "ok" | "warn" | "danger"; title: string; label: string; percent: number | null } | null;
|
||||
rateLimit: RateLimitSummary | null;
|
||||
|
|
@ -139,7 +137,7 @@ export function renderToolbar(toolbar: HTMLElement, model: ToolbarViewModel, act
|
|||
}
|
||||
|
||||
function renderHistoryButton(parent: HTMLElement, model: ToolbarViewModel, actions: ToolbarActions): void {
|
||||
const button = createToolbarButton(parent, "history", "Threads");
|
||||
const button = createToolbarButton(parent, "history", "Toggle thread list");
|
||||
button.addClass("codex-panel__history-toggle");
|
||||
if (model.historyOpen) button.addClass("is-active");
|
||||
button.setAttr("aria-pressed", model.historyOpen ? "true" : "false");
|
||||
|
|
@ -147,7 +145,7 @@ function renderHistoryButton(parent: HTMLElement, model: ToolbarViewModel, actio
|
|||
}
|
||||
|
||||
function renderAutoReviewButton(parent: HTMLElement, model: ToolbarViewModel, actions: ToolbarActions): void {
|
||||
const button = createToolbarButton(parent, "shield", `Auto-review: ${model.autoReviewActive ? "on" : "off"}`);
|
||||
const button = createToolbarButton(parent, "shield", "Toggle auto-review");
|
||||
button.addClass("codex-panel__auto-review-toggle");
|
||||
if (model.autoReviewActive) button.addClass("is-active");
|
||||
button.setAttr("aria-pressed", model.autoReviewActive ? "true" : "false");
|
||||
|
|
@ -160,7 +158,7 @@ function renderStatusButton(parent: HTMLElement, model: ToolbarViewModel, action
|
|||
cls: `clickable-icon nav-action-button codex-panel-ui__toolbar-control codex-panel__status-dot codex-panel__status-dot--${model.statusState}${alertClass} ${model.statusPanelOpen ? "is-active" : ""}`,
|
||||
attr: {
|
||||
type: "button",
|
||||
"aria-label": statusButtonLabel(model),
|
||||
"aria-label": "Toggle connection status",
|
||||
"aria-expanded": model.statusPanelOpen ? "true" : "false",
|
||||
},
|
||||
});
|
||||
|
|
@ -173,20 +171,10 @@ function renderStatusButton(parent: HTMLElement, model: ToolbarViewModel, action
|
|||
button.onclick = actions.toggleStatusPanel;
|
||||
}
|
||||
|
||||
function statusButtonLabel(model: ToolbarViewModel): string {
|
||||
const status = model.status.trim() || (model.connected ? "Connected" : "Not connected");
|
||||
const connection = model.connected ? "connected" : "not connected";
|
||||
const normalizedStatus = status.toLowerCase().replace(/[.!…]+$/u, "");
|
||||
const parts = [`Status: ${status}`];
|
||||
if (normalizedStatus !== connection) parts.push(`Connection: ${connection}`);
|
||||
parts.push(`Diagnostics: ${model.diagnosticAlertLevel}`);
|
||||
return parts.join("; ");
|
||||
}
|
||||
|
||||
function renderRuntimeStatus(parent: HTMLElement, model: ToolbarViewModel, actions: ToolbarActions): void {
|
||||
const row = parent.createDiv({ cls: "codex-panel__runtime-strip" });
|
||||
renderRuntimeIcon(row, "list-checks", `Plan mode: ${model.planActive ? "on" : "off"}`, model.planActive, actions.togglePlan);
|
||||
renderRuntimeIcon(row, "zap", `Fast mode: ${model.fastActive ? "on" : "off"}`, model.fastActive, actions.toggleFast);
|
||||
renderRuntimeIcon(row, "list-checks", "Toggle plan mode", model.planActive, actions.togglePlan);
|
||||
renderRuntimeIcon(row, "zap", "Toggle fast mode", model.fastActive, actions.toggleFast);
|
||||
renderRuntimeModelControl(row, model, actions);
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +205,7 @@ function renderRuntimeModelControl(parent: HTMLElement, model: ToolbarViewModel,
|
|||
cls,
|
||||
attr: {
|
||||
type: "button",
|
||||
"aria-label": model.runtimeAriaLabel,
|
||||
"aria-label": "Change runtime settings",
|
||||
"aria-expanded": model.runtimeOpen ? "true" : "false",
|
||||
},
|
||||
});
|
||||
|
|
@ -231,7 +219,6 @@ function renderContextMeter(parent: HTMLElement, model: ToolbarViewModel): void
|
|||
const context = parent.createDiv({
|
||||
cls: `codex-panel__meter-compact codex-panel__context-compact codex-panel__meter-compact--${model.context.level}`,
|
||||
});
|
||||
context.title = model.context.title;
|
||||
context.createSpan({ cls: "codex-panel__meter-compact-label codex-panel__context-compact-label", text: model.context.label });
|
||||
const bar = context.createSpan({ cls: "codex-panel__meter-compact-bar codex-panel__context-compact-bar" });
|
||||
bar.createSpan({
|
||||
|
|
@ -257,14 +244,20 @@ function renderToolbarPanel(toolbar: HTMLElement, model: ToolbarViewModel, actio
|
|||
|
||||
function renderStatusPanel(parent: HTMLElement, model: ToolbarViewModel, actions: ToolbarActions): void {
|
||||
const statusItems = parent.createDiv({ cls: "codex-panel__status-panel-items", attr: { role: "menu" } });
|
||||
createToolbarPanelRow(statusItems, model.connectLabel, { onClick: actions.connect, className: "codex-panel__status-panel-item" });
|
||||
createToolbarPanelRow(statusItems, model.connectLabel, {
|
||||
onClick: actions.connect,
|
||||
className: "codex-panel__status-panel-item",
|
||||
role: "menuitem",
|
||||
});
|
||||
createToolbarPanelRow(statusItems, "Refresh diagnostics", {
|
||||
onClick: actions.refreshDiagnostics,
|
||||
className: "codex-panel__status-panel-item",
|
||||
role: "menuitem",
|
||||
});
|
||||
createToolbarPanelRow(statusItems, "Refresh thread list", {
|
||||
onClick: actions.refreshThreads,
|
||||
className: "codex-panel__status-panel-item",
|
||||
role: "menuitem",
|
||||
});
|
||||
renderRateLimitPanel(parent, model.rateLimit);
|
||||
renderConnectionDiagnostics(parent, model.diagnostics);
|
||||
|
|
@ -280,7 +273,6 @@ function renderRateLimitPanel(parent: HTMLElement, rateLimit: RateLimitSummary |
|
|||
for (const row of rateLimit.rows) {
|
||||
const item = list.createDiv({
|
||||
cls: `codex-panel__limit-panel-row codex-panel__limit-panel-row--${row.level}`,
|
||||
attr: { title: row.title },
|
||||
});
|
||||
item.createDiv({ cls: "codex-panel__limit-panel-label", text: row.label });
|
||||
item.createDiv({ cls: "codex-panel__limit-panel-value", text: row.value });
|
||||
|
|
@ -313,18 +305,22 @@ function renderRuntimePicker(parent: HTMLElement, model: ToolbarViewModel): void
|
|||
const picker = parent.createDiv({ cls: "codex-panel__runtime-picker", attr: { role: "listbox" } });
|
||||
picker.createDiv({ cls: "codex-panel__runtime-picker-label", text: "Reasoning effort" });
|
||||
for (const choice of model.effortChoices) {
|
||||
createToolbarPanelRow(picker, choice.label, { ...choice, className: "codex-panel__runtime-choice" });
|
||||
createToolbarPanelRow(picker, choice.label, { ...choice, className: "codex-panel__runtime-choice", role: "option" });
|
||||
}
|
||||
picker.createDiv({ cls: "codex-panel__runtime-picker-label", text: "Model" });
|
||||
for (const choice of model.modelChoices) {
|
||||
createToolbarPanelRow(picker, choice.label, { ...choice, className: "codex-panel__runtime-choice" });
|
||||
createToolbarPanelRow(picker, choice.label, { ...choice, className: "codex-panel__runtime-choice", role: "option" });
|
||||
}
|
||||
}
|
||||
|
||||
function renderThreadList(parent: HTMLElement, threads: ToolbarThreadRow[], actions: ToolbarActions): void {
|
||||
const threadsEl = parent.createDiv({ cls: "codex-panel__threads" });
|
||||
if (threads.length === 0) {
|
||||
createToolbarPanelRow(threadsEl, "No threads", { disabled: true, className: "codex-panel__thread codex-panel__thread--empty" });
|
||||
createToolbarPanelRow(threadsEl, "No threads", {
|
||||
disabled: true,
|
||||
className: "codex-panel__thread codex-panel__thread--empty",
|
||||
interactive: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -340,7 +336,6 @@ function renderThreadList(parent: HTMLElement, threads: ToolbarThreadRow[], acti
|
|||
createToolbarPanelRow(row, thread.title, {
|
||||
selected: thread.selected,
|
||||
disabled: thread.disabled,
|
||||
title: `${thread.title}\n${thread.threadId}`,
|
||||
className: "codex-panel__thread",
|
||||
onClick: () => {
|
||||
actions.resumeThread(thread.threadId);
|
||||
|
|
@ -372,7 +367,6 @@ function renderThreadRenameRow(parent: HTMLElement, thread: ToolbarThreadRow, ac
|
|||
createToolbarPanelRow(parent, thread.title, {
|
||||
className: "codex-panel__thread codex-panel__thread-rename",
|
||||
interactive: false,
|
||||
title: `Rename ${thread.title}`,
|
||||
renderContent: (row) => {
|
||||
const field = row.createDiv({ cls: "codex-panel__thread-rename-field" });
|
||||
input = field.createEl("input", {
|
||||
|
|
@ -436,10 +430,10 @@ function createToolbarPanelRow(
|
|||
options: {
|
||||
selected?: boolean;
|
||||
disabled?: boolean;
|
||||
title?: string;
|
||||
meta?: string;
|
||||
className?: string;
|
||||
interactive?: boolean;
|
||||
role?: "button" | "menuitem" | "option";
|
||||
renderContent?: (parent: HTMLElement) => void;
|
||||
onClick?: () => void;
|
||||
} = {},
|
||||
|
|
@ -447,12 +441,17 @@ function createToolbarPanelRow(
|
|||
const selected = Boolean(options.selected);
|
||||
const disabled = Boolean(options.disabled);
|
||||
const interactive = options.interactive ?? true;
|
||||
const attr: Record<string, string> = { title: options.title ?? label };
|
||||
const role = options.role ?? "button";
|
||||
const attr: Record<string, string> = {};
|
||||
if (interactive) {
|
||||
attr["role"] = "button";
|
||||
attr["role"] = role;
|
||||
attr["tabindex"] = disabled ? "-1" : "0";
|
||||
attr["aria-disabled"] = disabled ? "true" : "false";
|
||||
attr["aria-selected"] = selected ? "true" : "false";
|
||||
if (role === "option") {
|
||||
attr["aria-selected"] = selected ? "true" : "false";
|
||||
} else if (role === "button" && selected) {
|
||||
attr["aria-current"] = "true";
|
||||
}
|
||||
}
|
||||
const item = parent.createDiv({
|
||||
cls: ["codex-panel__toolbar-panel-item", options.className ?? "", selected ? "is-checked" : "", disabled ? "is-disabled" : ""]
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ function renderTurnDiffHeader(
|
|||
titleBlock.createDiv({
|
||||
cls: "codex-panel-chat-turn-diff__meta",
|
||||
text: `${shortThreadId(state.threadId)} / ${shortThreadId(state.turnId)} · ${fileCountLabel(state.files)}`,
|
||||
attr: { title: `Thread ${state.threadId}\nTurn ${state.turnId}${state.cwd ? `\n${state.cwd}` : ""}` },
|
||||
});
|
||||
if (copyDiff) {
|
||||
const copyButton = createIconButton(header, "copy", "Copy diff", "codex-panel-chat-turn-diff__copy");
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ export function renderAgentItem(parent: HTMLElement, item: AgentDisplayItem, con
|
|||
const list = messageEl.createEl("ul", { cls: "codex-panel__agent-list" });
|
||||
for (const agent of item.agents) {
|
||||
const row = list.createEl("li", { cls: "codex-panel__agent-row" });
|
||||
row.title = agent.threadId;
|
||||
row.createSpan({ cls: "codex-panel__agent-thread", text: shortThreadId(agent.threadId) });
|
||||
row.createSpan({ cls: "codex-panel__agent-status", text: agentStatusLabel(agent.status, agent.message) });
|
||||
}
|
||||
|
|
@ -129,7 +128,6 @@ function renderAgentSummaryRows(parent: HTMLElement, summary: AgentRunSummary):
|
|||
const list = parent.createEl("ul", { cls: "codex-panel__agent-list codex-panel__agent-list--summary" });
|
||||
for (const agent of summary.agents) {
|
||||
const row = list.createEl("li", { cls: "codex-panel__agent-row" });
|
||||
row.title = agent.threadId;
|
||||
row.createSpan({ cls: "codex-panel__agent-thread", text: shortThreadId(agent.threadId) });
|
||||
row.createSpan({ cls: "codex-panel__agent-status", text: agentSummaryStatusLabel(agent) });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1277,7 +1277,6 @@ export class CodexChatView extends ItemView {
|
|||
fastActive: currentServiceTier(snapshot, config) === "fast",
|
||||
runtimeSummary: runtimeSummaryLabel(model, effort),
|
||||
runtimeTitle: `Model: ${model ?? "(from default)"}; Effort: ${effort ?? "(from default)"}`,
|
||||
runtimeAriaLabel: `Runtime: ${model ?? "default"} ${effort ?? "default"}`,
|
||||
runtimeEmphasized: false,
|
||||
context: context ? { ...context, label: compactContextLabel(context.percent, context.label) } : null,
|
||||
rateLimit: limit,
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export function renderThreadsView(parent: HTMLElement, model: ThreadsViewModel,
|
|||
function renderThreadRow(parent: HTMLElement, row: ThreadsRowModel, actions: ThreadsViewActions): void {
|
||||
const item = parent.createDiv({
|
||||
cls: "codex-panel-threads__row",
|
||||
attr: { role: "button", tabindex: "0", "aria-label": `Open thread: ${row.title}` },
|
||||
attr: { role: "button", tabindex: "0" },
|
||||
});
|
||||
if (row.live) item.addClass(`codex-panel-threads__row--${row.live.status}`);
|
||||
if (row.rename.active) item.addClass("codex-panel-threads__row--renaming");
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Setting } from "obsidian";
|
|||
|
||||
import type { HookMetadata } from "../generated/app-server/v2/HookMetadata";
|
||||
import type { Thread } from "../generated/app-server/v2/Thread";
|
||||
import { archivedThreadDisplayTitle, fullThreadTitle } from "../domain/threads/model";
|
||||
import { archivedThreadDisplayTitle } from "../domain/threads/model";
|
||||
import { shortThreadId } from "../utils";
|
||||
|
||||
export interface ArchivedThreadSectionState {
|
||||
|
|
@ -152,7 +152,6 @@ function renderArchivedThreadList(containerEl: HTMLElement, state: ArchivedThrea
|
|||
button.extraSettingsEl.setAttr("aria-label", `Restore ${title}`);
|
||||
});
|
||||
setting.settingEl.addClass("codex-panel-settings__archived-row");
|
||||
setting.settingEl.setAttr("title", fullThreadTitle(thread));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -202,11 +201,9 @@ function renderHookRow(list: HTMLElement, hook: HookMetadata, state: HookSection
|
|||
});
|
||||
});
|
||||
setting.settingEl.addClass("codex-panel-settings__hook-row");
|
||||
setting.settingEl.setAttr("title", hook.command ?? hook.key);
|
||||
setting.descEl.createDiv({
|
||||
cls: "codex-panel-settings__hook-hash",
|
||||
text: hook.currentHash,
|
||||
attr: { title: hook.key },
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ export function renderTextWithWikiLinks(parent: HTMLElement, text: string, openL
|
|||
text: label,
|
||||
attr: {
|
||||
href: target,
|
||||
title: target,
|
||||
},
|
||||
});
|
||||
link.onclick = (event) => {
|
||||
|
|
|
|||
|
|
@ -752,7 +752,7 @@ describe("message stream block identity and message actions", () => {
|
|||
const element = block.render();
|
||||
|
||||
expect(element.querySelector(".codex-panel__tool-summary")?.textContent).toBe("npm run check (exit 1)");
|
||||
expect(element.querySelector(".codex-panel__tool-summary")?.getAttribute("title")).toBe("npm run check (exit 1)");
|
||||
expect(element.querySelector(".codex-panel__tool-summary")?.getAttribute("title")).toBeNull();
|
||||
expect(topLevelDetailsSummaries(element)).toEqual(["command"]);
|
||||
expect([...element.querySelectorAll("details summary")].map((summary) => summary.textContent)).toEqual(["command"]);
|
||||
expect(element.textContent).not.toContain("Details");
|
||||
|
|
@ -947,7 +947,7 @@ describe("message stream block identity and message actions", () => {
|
|||
expect(user?.querySelector(".codex-panel__message-content")?.textContent).toBe("この続きです");
|
||||
expect(user?.querySelector(".codex-panel__referenced-thread")?.textContent).toContain("Referenced 参照元");
|
||||
expect(user?.querySelector(".codex-panel__referenced-thread")?.textContent).toContain("2/20 turns");
|
||||
expect(user?.querySelector<HTMLElement>(".codex-panel__referenced-thread")?.title).toBe("thread-reference");
|
||||
expect(user?.querySelector<HTMLElement>(".codex-panel__referenced-thread")?.getAttribute("title")).toBeNull();
|
||||
});
|
||||
|
||||
it("renders resolved file mentions as a collapsed user message attachment", () => {
|
||||
|
|
@ -1238,7 +1238,7 @@ describe("work log renderer decisions", () => {
|
|||
const element = block.render();
|
||||
|
||||
expect(element.querySelector(".codex-panel__tool-summary")?.textContent).toBe("assets/image.png");
|
||||
expect(element.querySelector(".codex-panel__tool-summary")?.getAttribute("title")).toBe("assets/image.png");
|
||||
expect(element.querySelector(".codex-panel__tool-summary")?.getAttribute("title")).toBeNull();
|
||||
});
|
||||
|
||||
it("keeps path summary tools absolute outside the workspace root", () => {
|
||||
|
|
@ -1651,20 +1651,18 @@ describe("toolbar renderer decisions", () => {
|
|||
const statusButton = parent.querySelector(".codex-panel__status-dot");
|
||||
expect(statusButton?.tagName).toBe("BUTTON");
|
||||
expect(statusButton?.getAttribute("role")).toBeNull();
|
||||
expect(statusButton?.getAttribute("aria-label")).toBe("Status: Connected.; Diagnostics: normal");
|
||||
expect(statusButton?.getAttribute("aria-label")).toBe("Toggle connection status");
|
||||
parent.querySelector<HTMLButtonElement>(".codex-panel__history-toggle")?.click();
|
||||
expect(toggleHistory).toHaveBeenCalled();
|
||||
const autoReviewButton = parent.querySelector<HTMLButtonElement>(".codex-panel__auto-review-toggle");
|
||||
expect(autoReviewButton?.getAttribute("aria-label")).toBe("Auto-review: off");
|
||||
expect(autoReviewButton?.getAttribute("aria-label")).toBe("Toggle auto-review");
|
||||
expect(autoReviewButton?.getAttribute("aria-pressed")).toBe("false");
|
||||
autoReviewButton?.click();
|
||||
expect(toggleAutoReview).toHaveBeenCalled();
|
||||
|
||||
parent.empty();
|
||||
renderToolbar(parent, toolbarModel({ status: "Turn running...", statusState: "running", autoReviewActive: true }), toolbarActions());
|
||||
expect(parent.querySelector(".codex-panel__status-dot")?.getAttribute("aria-label")).toBe(
|
||||
"Status: Turn running...; Connection: connected; Diagnostics: normal",
|
||||
);
|
||||
expect(parent.querySelector(".codex-panel__status-dot")?.getAttribute("aria-label")).toBe("Toggle connection status");
|
||||
expect(parent.querySelector(".codex-panel__auto-review-toggle")?.getAttribute("aria-pressed")).toBe("true");
|
||||
|
||||
expect(toolbarSignature(baseModel)).not.toBe(toolbarSignature({ ...baseModel, status: "Turn running..." }));
|
||||
|
|
@ -1708,6 +1706,8 @@ describe("toolbar renderer decisions", () => {
|
|||
]);
|
||||
expect([...parent.querySelectorAll(".codex-panel__runtime-choice")].map((choice) => choice.textContent)).toEqual(["high", "gpt-5.5"]);
|
||||
for (const choice of parent.querySelectorAll(".codex-panel__runtime-choice")) {
|
||||
expect(choice.getAttribute("role")).toBe("option");
|
||||
expect(choice.getAttribute("aria-selected")).toBe("true");
|
||||
expect(choice.querySelector<HTMLElement>(".codex-panel__toolbar-panel-check")?.dataset["icon"]).toBe("check");
|
||||
expect(choice.classList.contains("selected")).toBe(false);
|
||||
expect(choice.classList.contains("is-selected")).toBe(false);
|
||||
|
|
@ -1783,9 +1783,10 @@ describe("toolbar renderer decisions", () => {
|
|||
expect(parent.textContent).toContain("Refresh diagnostics");
|
||||
expect(parent.textContent).toContain("codex-cli/1.2.3");
|
||||
expect(parent.querySelector(".codex-panel__connection-diagnostics-row--error")?.textContent).toContain("model/list failed");
|
||||
[...parent.querySelectorAll<HTMLElement>(".codex-panel__status-panel-item")]
|
||||
.find((item) => item.textContent.includes("Refresh diagnostics"))
|
||||
?.click();
|
||||
const statusItems = [...parent.querySelectorAll<HTMLElement>(".codex-panel__status-panel-item")];
|
||||
expect(statusItems.map((item) => item.getAttribute("role"))).toEqual(["menuitem", "menuitem", "menuitem"]);
|
||||
expect(statusItems.every((item) => item.getAttribute("aria-selected") === null)).toBe(true);
|
||||
statusItems.find((item) => item.textContent.includes("Refresh diagnostics"))?.click();
|
||||
expect(refreshDiagnostics).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
|
@ -1794,21 +1795,21 @@ describe("toolbar renderer decisions", () => {
|
|||
renderToolbar(normal, toolbarModel({ diagnosticAlertLevel: "normal" }), toolbarActions());
|
||||
const normalStatus = normal.querySelector(".codex-panel__status-dot");
|
||||
expect(normalStatus?.querySelector(".codex-panel__status-dot-diagnostic")).toBeNull();
|
||||
expect(normalStatus?.getAttribute("aria-label")).toContain("Diagnostics: normal");
|
||||
expect(normalStatus?.getAttribute("aria-label")).toBe("Toggle connection status");
|
||||
|
||||
const warning = document.createElement("div");
|
||||
renderToolbar(warning, toolbarModel({ diagnosticAlertLevel: "warning" }), toolbarActions());
|
||||
const warningStatus = warning.querySelector(".codex-panel__status-dot");
|
||||
expect(warningStatus?.classList.contains("codex-panel__status-dot--diagnostic-warning")).toBe(true);
|
||||
expect(warningStatus?.querySelector(".codex-panel__status-dot-diagnostic--warning")).not.toBeNull();
|
||||
expect(warningStatus?.getAttribute("aria-label")).toContain("Diagnostics: warning");
|
||||
expect(warningStatus?.getAttribute("aria-label")).toBe("Toggle connection status");
|
||||
|
||||
const error = document.createElement("div");
|
||||
renderToolbar(error, toolbarModel({ diagnosticAlertLevel: "error" }), toolbarActions());
|
||||
const errorStatus = error.querySelector(".codex-panel__status-dot");
|
||||
expect(errorStatus?.classList.contains("codex-panel__status-dot--diagnostic-error")).toBe(true);
|
||||
expect(errorStatus?.querySelector(".codex-panel__status-dot-diagnostic--error")).not.toBeNull();
|
||||
expect(errorStatus?.getAttribute("aria-label")).toContain("Diagnostics: error");
|
||||
expect(errorStatus?.getAttribute("aria-label")).toBe("Toggle connection status");
|
||||
});
|
||||
|
||||
it("renders effective config inside the status menu without a separate toggle", () => {
|
||||
|
|
@ -2426,7 +2427,6 @@ function toolbarModel(overrides: Partial<ToolbarViewModel> = {}): ToolbarViewMod
|
|||
fastActive: false,
|
||||
runtimeSummary: "5.5 high",
|
||||
runtimeTitle: "Model: gpt-5.5; Effort: high",
|
||||
runtimeAriaLabel: "Runtime: gpt-5.5 high",
|
||||
runtimeEmphasized: false,
|
||||
context: null,
|
||||
rateLimit: null,
|
||||
|
|
|
|||
|
|
@ -158,7 +158,9 @@ describe("CodexThreadsView", () => {
|
|||
const view = await threadsView(host);
|
||||
|
||||
await view.refresh();
|
||||
view.containerEl.querySelector<HTMLElement>(".codex-panel-threads__row")?.click();
|
||||
const row = view.containerEl.querySelector<HTMLElement>(".codex-panel-threads__row");
|
||||
expect(row?.getAttribute("aria-label")).toBeNull();
|
||||
row?.click();
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(host.openThreadInAvailableView).toHaveBeenCalledWith("thread");
|
||||
|
|
|
|||
Loading…
Reference in a new issue