Merge codex/approvals-tab-tooltip-fix into big-one

This commit is contained in:
George Pickett
2026-02-24 12:18:43 -08:00
11 changed files with 59 additions and 18 deletions
@@ -963,6 +963,7 @@ const AgentChatComposer = memo(function AgentChatComposer({
onChange={(event) => {
const nextValue = event.target.value.trim();
onModelChange(nextValue ? nextValue : null);
event.currentTarget.blur();
}}
>
{modelOptions.length === 0 ? (
@@ -22,7 +22,7 @@ type FleetSidebarProps = {
const FILTER_OPTIONS: Array<{ value: FocusFilter; label: string; testId: string }> = [
{ value: "all", label: "All", testId: "fleet-filter-all" },
{ value: "running", label: "Running", testId: "fleet-filter-running" },
{ value: "idle", label: "Idle", testId: "fleet-filter-idle" },
{ value: "approvals", label: "Approvals", testId: "fleet-filter-approvals" },
];
export const FleetSidebar = ({
+3 -3
View File
@@ -20,7 +20,7 @@ import {
} from "@/features/agents/state/transcript";
export type AgentStatus = "idle" | "running" | "error";
export type FocusFilter = "all" | "running" | "idle";
export type FocusFilter = "all" | "running" | "approvals";
export type AgentStoreSeed = {
agentId: string;
@@ -526,8 +526,8 @@ export const getFilteredAgents = (state: AgentStoreState, filter: FocusFilter):
return sortAgents(state.agents, true);
case "running":
return sortAgents(state.agents.filter((agent) => agent.status === "running"), false);
case "idle":
return sortAgents(state.agents.filter((agent) => agent.status === "idle"), false);
case "approvals":
return sortAgents(state.agents.filter((agent) => agent.awaitingUserInput), false);
default: {
const _exhaustive: never = filter;
void _exhaustive;
+3 -2
View File
@@ -3,7 +3,7 @@ export type StudioGatewaySettings = {
token: string;
};
export type FocusFilter = "all" | "running" | "idle";
export type FocusFilter = "all" | "running" | "approvals";
export type StudioViewMode = "focused";
export type StudioFocusedPreference = {
@@ -66,10 +66,11 @@ const normalizeFocusFilter = (
): FocusFilter => {
const filter = coerceString(value);
if (filter === "needs-attention") return "all";
if (filter === "idle") return "approvals";
if (
filter === "all" ||
filter === "running" ||
filter === "idle"
filter === "approvals"
) {
return filter;
}
+7 -2
View File
@@ -222,7 +222,7 @@ describe("AgentChatPanel controls", () => {
expect(runningBadge).toBeNull();
});
it("invokes_on_model_change_when_model_select_changes", () => {
it("invokes_on_model_change_when_model_select_changes_and_blurs_select", () => {
const onModelChange = vi.fn();
render(
createElement(AgentChatPanel, {
@@ -242,10 +242,15 @@ describe("AgentChatPanel controls", () => {
})
);
fireEvent.change(screen.getByLabelText("Model"), {
const modelSelect = screen.getByLabelText("Model") as HTMLSelectElement;
modelSelect.focus();
expect(modelSelect).toHaveFocus();
fireEvent.change(modelSelect, {
target: { value: "openai/gpt-5-mini" },
});
expect(onModelChange).toHaveBeenCalledWith("openai/gpt-5-mini");
expect(modelSelect).not.toHaveFocus();
});
it("invokes_on_thinking_change_when_thinking_select_changes", () => {
+3 -3
View File
@@ -261,7 +261,7 @@ describe("agent store", () => {
expect(cleared?.hasUnseenActivity).toBe(false);
});
it("filters_agents_by_status", () => {
it("filters_agents_by_status_and_approvals", () => {
const seeds: AgentStoreSeed[] = [
{
agentId: "agent-1",
@@ -286,7 +286,7 @@ describe("agent store", () => {
state = agentStoreReducer(state, {
type: "updateAgent",
agentId: "agent-1",
patch: { status: "idle" },
patch: { status: "idle", awaitingUserInput: true },
});
state = agentStoreReducer(state, {
type: "updateAgent",
@@ -307,7 +307,7 @@ describe("agent store", () => {
expect(getFilteredAgents(state, "running").map((agent) => agent.agentId)).toEqual([
"agent-2",
]);
expect(getFilteredAgents(state, "idle").map((agent) => agent.agentId)).toEqual([
expect(getFilteredAgents(state, "approvals").map((agent) => agent.agentId)).toEqual([
"agent-1",
]);
});
+16
View File
@@ -93,6 +93,22 @@ describe("FleetSidebar new agent action", () => {
expect(screen.getByTestId("fleet-new-agent-button")).toBeDisabled();
});
it("shows approvals tab instead of idle tab", () => {
render(
createElement(FleetSidebar, {
agents: [createAgent()],
selectedAgentId: "agent-1",
filter: "all",
onFilterChange: vi.fn(),
onSelectAgent: vi.fn(),
onCreateAgent: vi.fn(),
})
);
expect(screen.getByTestId("fleet-filter-approvals")).toBeInTheDocument();
expect(screen.queryByTestId("fleet-filter-idle")).toBeNull();
});
it("shows needs approval badge for awaiting agents", () => {
render(
createElement(FleetSidebar, {
+2 -2
View File
@@ -238,7 +238,7 @@ describe("studioBootstrapOperation", () => {
commands: [
{ kind: "set-focused-preferences-loaded", value: false },
{ kind: "set-preferred-selected-agent-id", agentId: "agent-1" },
{ kind: "set-focus-filter", filter: "idle" },
{ kind: "set-focus-filter", filter: "approvals" },
{ kind: "log-error", message: "failed", error: new Error("boom") },
],
setFocusedPreferencesLoaded,
@@ -249,7 +249,7 @@ describe("studioBootstrapOperation", () => {
expect(setFocusedPreferencesLoaded).toHaveBeenCalledWith(false);
expect(setPreferredSelectedAgentId).toHaveBeenCalledWith("agent-1");
expect(setFocusFilter).toHaveBeenCalledWith("idle");
expect(setFocusFilter).toHaveBeenCalledWith("approvals");
expect(logError).toHaveBeenCalledTimes(1);
});
+2 -2
View File
@@ -150,7 +150,7 @@ describe("studioBootstrapWorkflow", () => {
"https://gateway.test": {
mode: "focused",
selectedAgentId: "agent-3",
filter: "idle",
filter: "approvals",
},
},
avatars: {},
@@ -164,7 +164,7 @@ describe("studioBootstrapWorkflow", () => {
})
).toEqual({
preferredSelectedAgentId: "agent-3",
focusFilter: "idle",
focusFilter: "approvals",
});
expect(
+20 -2
View File
@@ -59,6 +59,24 @@ describe("studio settings normalization", () => {
});
});
it("normalizes_legacy_idle_filter_to_approvals", () => {
const normalized = normalizeStudioSettings({
focused: {
"ws://localhost:18789": {
mode: "focused",
selectedAgentId: "agent-1",
filter: "idle",
},
},
});
expect(normalized.focused["ws://localhost:18789"]).toEqual({
mode: "focused",
selectedAgentId: "agent-1",
filter: "approvals",
});
});
it("merges_dual_mode_preferences", () => {
const current = normalizeStudioSettings({
focused: {
@@ -73,7 +91,7 @@ describe("studio settings normalization", () => {
const merged = mergeStudioSettings(current, {
focused: {
"ws://localhost:18789": {
filter: "idle",
filter: "approvals",
},
},
});
@@ -81,7 +99,7 @@ describe("studio settings normalization", () => {
expect(merged.focused["ws://localhost:18789"]).toEqual({
mode: "focused",
selectedAgentId: "main",
filter: "idle",
filter: "approvals",
});
});
+1 -1
View File
@@ -77,7 +77,7 @@ describe("StudioSettingsCoordinator", () => {
focused: {
"ws://localhost:18789": {
mode: "focused",
filter: "idle",
filter: "approvals",
selectedAgentId: null,
},
},