mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Align status diagnostics sections
This commit is contained in:
parent
48ca57ebe8
commit
6575ad7bf3
7 changed files with 53 additions and 74 deletions
|
|
@ -4,7 +4,7 @@ import type { MessageStreamNoticeSection } from "../domain/message-stream/items"
|
|||
import { collaborationModeLabel as formatCollaborationModeLabel } from "../domain/runtime/labels";
|
||||
import type { RuntimeSnapshot } from "../domain/runtime/snapshot";
|
||||
import { appServerDiagnosticSections } from "../presentation/runtime/diagnostic-sections";
|
||||
import { runtimePermissionDetails } from "../presentation/runtime/permission-sections";
|
||||
import { runtimePermissionSections } from "../presentation/runtime/permission-sections";
|
||||
import {
|
||||
effortStatusLines as buildEffortStatusLines,
|
||||
modelStatusLines as buildModelStatusLines,
|
||||
|
|
@ -86,10 +86,10 @@ function toolInventoryDetails(input: ChatPanelRuntimeProjectionInput): MessageSt
|
|||
function permissionDetails(input: ChatPanelRuntimeProjectionInput): MessageStreamNoticeSection[] {
|
||||
const state = input.state();
|
||||
return noticeSectionsFromDiagnostics(
|
||||
runtimePermissionDetails({
|
||||
runtimePermissionSections({
|
||||
snapshot: runtimeSnapshot(state),
|
||||
vaultPath: input.vaultPath(),
|
||||
}).sections,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import type { Thread } from "../../../../domain/threads/model";
|
|||
import { threadRowCoreProjection } from "../../../threads/list/row-projection";
|
||||
import type { RuntimeSnapshot } from "../../domain/runtime/snapshot";
|
||||
import { appServerDiagnosticSections } from "../../presentation/runtime/diagnostic-sections";
|
||||
import { runtimePermissionDetails } from "../../presentation/runtime/permission-sections";
|
||||
import { runtimePermissionSections } from "../../presentation/runtime/permission-sections";
|
||||
import { rateLimitSummary } from "../../presentation/runtime/status";
|
||||
import { toolInventoryDiagnosticSections } from "../../presentation/runtime/tool-inventory-diagnostic-sections";
|
||||
import { Toolbar, type ToolbarActions, type ToolbarThreadRow, type ToolbarViewModel } from "../../ui/toolbar";
|
||||
|
|
@ -76,7 +76,7 @@ function chatPanelToolbarProjection(input: ToolbarViewModelInput): ToolbarViewMo
|
|||
const projection = toolbarStateProjection(input);
|
||||
const limit = rateLimitSummary(snapshot, input.nowMs);
|
||||
const diagnostics = model.diagnostics.value;
|
||||
const permissions = runtimePermissionDetails({
|
||||
const permissions = runtimePermissionSections({
|
||||
snapshot,
|
||||
vaultPath: input.vaultPath,
|
||||
});
|
||||
|
|
@ -90,8 +90,7 @@ function chatPanelToolbarProjection(input: ToolbarViewModelInput): ToolbarViewMo
|
|||
openPanel: projection.openPanel,
|
||||
threads: projection.threads,
|
||||
connectLabel: input.connected ? "Reconnect" : "Connect",
|
||||
runtimePermissionsTitle: permissions.title,
|
||||
runtimePermissions: permissions.sections,
|
||||
permissionsAndApprovals: permissions,
|
||||
diagnostics: appServerDiagnosticSections({
|
||||
connected: input.connected,
|
||||
configuredCommand: input.configuredCommand,
|
||||
|
|
|
|||
|
|
@ -2,46 +2,29 @@ import { runtimeConfigOrDefault } from "../../../../domain/runtime/config";
|
|||
import type { RuntimePermissionState, RuntimeSandboxPolicy } from "../../../../domain/runtime/permissions";
|
||||
import { resolveRuntimeControls } from "../../domain/runtime/resolution";
|
||||
import type { RuntimeSnapshot } from "../../domain/runtime/snapshot";
|
||||
|
||||
interface RuntimePermissionRow {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface RuntimePermissionSection {
|
||||
title: string;
|
||||
rows: RuntimePermissionRow[];
|
||||
}
|
||||
|
||||
interface RuntimePermissionDetails {
|
||||
title: string;
|
||||
sections: RuntimePermissionSection[];
|
||||
}
|
||||
import type { DiagnosticRow, DiagnosticSection } from "./diagnostic-sections";
|
||||
|
||||
interface RuntimePermissionSectionsInput {
|
||||
snapshot: RuntimeSnapshot;
|
||||
vaultPath: string;
|
||||
}
|
||||
|
||||
export function runtimePermissionDetails(input: RuntimePermissionSectionsInput): RuntimePermissionDetails {
|
||||
export function runtimePermissionSections(input: RuntimePermissionSectionsInput): DiagnosticSection[] {
|
||||
const config = runtimeConfigOrDefault(input.snapshot.runtimeConfig);
|
||||
const resolution = resolveRuntimeControls(input.snapshot, config);
|
||||
return {
|
||||
title: "Permissions & Approvals",
|
||||
sections: [
|
||||
{
|
||||
title: "Permissions",
|
||||
rows: accessRows(resolution.permissions.effective, input.vaultPath),
|
||||
},
|
||||
{
|
||||
title: "Approvals",
|
||||
rows: approvalRows(resolution.permissions.effective, resolution.approvalsReviewer.effective),
|
||||
},
|
||||
],
|
||||
};
|
||||
return [
|
||||
{
|
||||
title: "Permissions",
|
||||
rows: accessRows(resolution.permissions.effective, input.vaultPath),
|
||||
},
|
||||
{
|
||||
title: "Approvals",
|
||||
rows: approvalRows(resolution.permissions.effective, resolution.approvalsReviewer.effective),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function accessRows(permissions: RuntimePermissionState, vaultPath: string): RuntimePermissionRow[] {
|
||||
function accessRows(permissions: RuntimePermissionState, vaultPath: string): DiagnosticRow[] {
|
||||
return [
|
||||
{ label: "Profile", value: profileLabel(permissions) },
|
||||
{ label: "Sandbox", value: sandboxLabel(permissions.sandboxPolicy) },
|
||||
|
|
@ -50,7 +33,7 @@ function accessRows(permissions: RuntimePermissionState, vaultPath: string): Run
|
|||
];
|
||||
}
|
||||
|
||||
function approvalRows(permissions: RuntimePermissionState, reviewer: string | null): RuntimePermissionRow[] {
|
||||
function approvalRows(permissions: RuntimePermissionState, reviewer: string | null): DiagnosticRow[] {
|
||||
return [
|
||||
{ label: "Approval policy", value: approvalPolicyLabel(permissions.approvalPolicy) },
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,8 +42,7 @@ export interface ToolbarViewModel {
|
|||
openPanel: "history" | "chat-actions" | "status" | null;
|
||||
threads: ToolbarThreadRow[];
|
||||
connectLabel: string;
|
||||
runtimePermissionsTitle: string;
|
||||
runtimePermissions: ToolbarStatusSection[];
|
||||
permissionsAndApprovals: ToolbarStatusSection[];
|
||||
diagnostics: ToolbarStatusSection[];
|
||||
toolInventory: ToolbarStatusSection[];
|
||||
}
|
||||
|
|
@ -196,7 +195,7 @@ function StatusPanel({ model, actions }: { model: ToolbarViewModel; actions: Too
|
|||
</div>
|
||||
<RateLimitPanel rateLimit={model.rateLimit} />
|
||||
<DiagnosticSectionsPanel title="Connection diagnostics" sections={model.diagnostics} />
|
||||
<DiagnosticSectionsPanel title={model.runtimePermissionsTitle} sections={model.runtimePermissions} />
|
||||
<DiagnosticSectionsPanel title="Permissions & Approvals" sections={model.permissionsAndApprovals} />
|
||||
<DiagnosticSectionsPanel title="Codex capabilities" sections={model.toolInventory} />
|
||||
</>
|
||||
);
|
||||
|
|
@ -252,8 +251,8 @@ function RateLimitPanel({ rateLimit }: { rateLimit: RateLimitSummary | null }):
|
|||
|
||||
function DiagnosticSectionsPanel({ title, sections }: { title: string; sections: ToolbarStatusSection[] }): UiNode {
|
||||
return (
|
||||
<div className="codex-panel__connection-diagnostics">
|
||||
<div className="codex-panel__connection-diagnostics-title">{title}</div>
|
||||
<div className="codex-panel__status-diagnostics">
|
||||
<div className="codex-panel__status-diagnostics-title">{title}</div>
|
||||
{sections.map((section) => (
|
||||
<DiagnosticSection key={section.title} section={section} />
|
||||
))}
|
||||
|
|
@ -263,7 +262,7 @@ function DiagnosticSectionsPanel({ title, sections }: { title: string; sections:
|
|||
|
||||
function DiagnosticRows({ rows }: { rows: ToolbarStatusRow[] }): UiNode {
|
||||
return (
|
||||
<dl className="codex-panel__connection-diagnostics-list">
|
||||
<dl className="codex-panel__status-diagnostics-list">
|
||||
{rows.map((row) => (
|
||||
<DiagnosticRow key={`${row.label}:${row.value}:${row.level ?? "normal"}`} row={row} />
|
||||
))}
|
||||
|
|
@ -274,7 +273,7 @@ function DiagnosticRows({ rows }: { rows: ToolbarStatusRow[] }): UiNode {
|
|||
function DiagnosticSection({ section }: { section: ToolbarStatusSection }): UiNode {
|
||||
return (
|
||||
<>
|
||||
{section.title ? <div className="codex-panel__connection-diagnostics-section">{section.title}</div> : null}
|
||||
{section.title ? <div className="codex-panel__status-diagnostics-section">{section.title}</div> : null}
|
||||
<DiagnosticRows rows={section.rows} />
|
||||
</>
|
||||
);
|
||||
|
|
@ -286,10 +285,10 @@ function DiagnosticRow({ row }: { row: ToolbarStatusRow }): UiNode {
|
|||
<div
|
||||
className={
|
||||
level === "error"
|
||||
? "codex-panel__connection-diagnostics-row codex-panel__connection-diagnostics-row--error"
|
||||
? "codex-panel__status-diagnostics-row codex-panel__status-diagnostics-row--error"
|
||||
: level === "warning"
|
||||
? "codex-panel__connection-diagnostics-row codex-panel__connection-diagnostics-row--warning"
|
||||
: "codex-panel__connection-diagnostics-row"
|
||||
? "codex-panel__status-diagnostics-row codex-panel__status-diagnostics-row--warning"
|
||||
: "codex-panel__status-diagnostics-row"
|
||||
}
|
||||
>
|
||||
<dt>{row.label}</dt>
|
||||
|
|
|
|||
|
|
@ -217,12 +217,12 @@
|
|||
color: var(--codex-panel-color-danger);
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics {
|
||||
.codex-panel__status-diagnostics {
|
||||
margin-top: var(--codex-panel-panel-gap);
|
||||
padding-top: var(--codex-panel-item-gap);
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-title {
|
||||
.codex-panel__status-diagnostics-title {
|
||||
padding: var(--codex-panel-section-label-padding);
|
||||
color: var(--codex-panel-section-label-color);
|
||||
font-size: var(--codex-panel-section-label-size);
|
||||
|
|
@ -230,7 +230,7 @@
|
|||
line-height: var(--codex-panel-section-label-line-height);
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-section {
|
||||
.codex-panel__status-diagnostics-section {
|
||||
padding: var(--codex-panel-section-label-block-padding);
|
||||
color: var(--codex-panel-section-label-color);
|
||||
font-size: var(--codex-panel-section-label-size);
|
||||
|
|
@ -238,37 +238,37 @@
|
|||
line-height: var(--codex-panel-section-label-line-height);
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-title + .codex-panel__connection-diagnostics-section {
|
||||
.codex-panel__status-diagnostics-title + .codex-panel__status-diagnostics-section {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-list {
|
||||
.codex-panel__status-diagnostics-list {
|
||||
margin: 0;
|
||||
cursor: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-row {
|
||||
.codex-panel__status-diagnostics-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 36%) minmax(0, 1fr);
|
||||
gap: var(--codex-panel-section-gap);
|
||||
padding: var(--codex-panel-control-gap) var(--codex-panel-section-gap);
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-row dt,
|
||||
.codex-panel__connection-diagnostics-row dd {
|
||||
.codex-panel__status-diagnostics-row dt,
|
||||
.codex-panel__status-diagnostics-row dd {
|
||||
margin: 0;
|
||||
min-width: 0;
|
||||
font-size: var(--font-ui-smaller);
|
||||
line-height: var(--line-height-tight);
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-row dt {
|
||||
.codex-panel__status-diagnostics-row dt {
|
||||
color: var(--codex-panel-text-faint);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-row dd {
|
||||
.codex-panel__status-diagnostics-row dd {
|
||||
color: var(--codex-panel-text-muted);
|
||||
overflow-wrap: anywhere;
|
||||
cursor: text;
|
||||
|
|
@ -276,11 +276,11 @@
|
|||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-row--warning dd {
|
||||
.codex-panel__status-diagnostics-row--warning dd {
|
||||
color: var(--codex-panel-color-warning);
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-row--error dd {
|
||||
.codex-panel__status-diagnostics-row--error dd {
|
||||
color: var(--codex-panel-color-danger);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -144,9 +144,9 @@ describe("chat panel surface projections", () => {
|
|||
expect(parent.textContent).toContain("Permissions & Approvals");
|
||||
expect(parent.textContent).toContain("Permissions");
|
||||
expect(parent.textContent).toContain("Approvals");
|
||||
expect(
|
||||
[...parent.querySelectorAll(".codex-panel__connection-diagnostics-section")].map((section) => section.textContent),
|
||||
).not.toContain("New thread");
|
||||
expect([...parent.querySelectorAll(".codex-panel__status-diagnostics-section")].map((section) => section.textContent)).not.toContain(
|
||||
"New thread",
|
||||
);
|
||||
expect(parent.textContent).toContain(":workspace");
|
||||
expect(parent.textContent).toContain("on-request");
|
||||
expect(parent.textContent).toContain("auto_review");
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ describe("Toolbar decisions", () => {
|
|||
toolbarActions({ refreshStatus }),
|
||||
);
|
||||
|
||||
expect([...parent.querySelectorAll(".codex-panel__connection-diagnostics-title")].map((title) => title.textContent)).toEqual([
|
||||
expect([...parent.querySelectorAll(".codex-panel__status-diagnostics-title")].map((title) => title.textContent)).toEqual([
|
||||
"Connection diagnostics",
|
||||
"Permissions & Approvals",
|
||||
"Codex capabilities",
|
||||
|
|
@ -179,7 +179,7 @@ describe("Toolbar decisions", () => {
|
|||
expect(parent.textContent).toContain("Copy debug details");
|
||||
expect(parent.textContent).toContain("Refresh");
|
||||
expect(parent.textContent).toContain("codex-cli/1.2.3");
|
||||
expect(parent.querySelector(".codex-panel__connection-diagnostics-row--error")?.textContent).toContain("model/list failed");
|
||||
expect(parent.querySelector(".codex-panel__status-diagnostics-row--error")?.textContent).toContain("model/list failed");
|
||||
const statusItems = [...parent.querySelectorAll<HTMLElement>(".codex-panel__status-panel-item")];
|
||||
expect(parent.querySelector(".codex-panel__status-panel-items")?.tagName).toBe("DIV");
|
||||
expect(parent.querySelector(".codex-panel__status-panel-items")?.getAttribute("aria-label")).toBeNull();
|
||||
|
|
@ -198,8 +198,7 @@ describe("Toolbar decisions", () => {
|
|||
toolbarModel({
|
||||
statusPanelOpen: true,
|
||||
openPanel: "status",
|
||||
runtimePermissionsTitle: "Permissions & Approvals",
|
||||
runtimePermissions: [
|
||||
permissionsAndApprovals: [
|
||||
{
|
||||
title: "Permissions",
|
||||
rows: [
|
||||
|
|
@ -225,14 +224,14 @@ describe("Toolbar decisions", () => {
|
|||
expect(parent.textContent).toContain("Permissions & Approvals");
|
||||
expect(parent.textContent).toContain("Permissions");
|
||||
expect(parent.textContent).toContain("Approvals");
|
||||
expect(
|
||||
[...parent.querySelectorAll(".codex-panel__connection-diagnostics-section")].map((section) => section.textContent),
|
||||
).not.toContain("Current thread");
|
||||
expect([...parent.querySelectorAll(".codex-panel__status-diagnostics-section")].map((section) => section.textContent)).not.toContain(
|
||||
"Current thread",
|
||||
);
|
||||
expect(parent.textContent).toContain(":workspace");
|
||||
expect(parent.textContent).toContain("workspace-write");
|
||||
expect(parent.textContent).toContain("auto_review");
|
||||
expect(parent.querySelector(".codex-panel__connection-diagnostics-row--warning")).toBeNull();
|
||||
expect(parent.querySelector(".codex-panel__connection-diagnostics-row--error")).toBeNull();
|
||||
expect(parent.querySelector(".codex-panel__status-diagnostics-row--warning")).toBeNull();
|
||||
expect(parent.querySelector(".codex-panel__status-diagnostics-row--error")).toBeNull();
|
||||
});
|
||||
|
||||
it("copies raw debug details from the status menu", () => {
|
||||
|
|
@ -411,8 +410,7 @@ function toolbarModel(overrides: Partial<ToolbarViewModel> = {}): ToolbarViewMod
|
|||
openPanel: null,
|
||||
threads: [{ title: "Thread", threadId: "thread", selected: true, disabled: false, canArchive: true, rename: null }],
|
||||
connectLabel: "Reconnect",
|
||||
runtimePermissionsTitle: "Permissions & Approvals",
|
||||
runtimePermissions: [{ title: "Permissions", rows: [{ label: "Thread", value: "(none)" }] }],
|
||||
permissionsAndApprovals: [{ title: "Permissions", rows: [{ label: "Thread", value: "(none)" }] }],
|
||||
diagnostics: [{ title: "Process", rows: [{ label: "Codex App Server", value: "codex-cli/test" }] }],
|
||||
toolInventory: [{ title: "Tool providers", rows: [{ label: "Tool providers", value: "not loaded", level: "warning" }] }],
|
||||
...overrides,
|
||||
|
|
|
|||
Loading…
Reference in a new issue