merge feature/frontend-mcp-panel-terminal-refit-fixes dans develop (panneau permissions idea_ask_agents + fit terminal au remount projet)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -2462,6 +2462,7 @@ export class MockPermissionGateway implements PermissionGateway {
|
||||
],
|
||||
writeActionTools: [
|
||||
"idea_ask_agent",
|
||||
"idea_ask_agents",
|
||||
"idea_run_in_background",
|
||||
"idea_launch_agent",
|
||||
"idea_stop_agent",
|
||||
|
||||
@ -108,6 +108,19 @@ describe("PermissionsPanel — Tools MCP IdeA tab", () => {
|
||||
expect(screen.getByRole("button", { name: "Enregistrer" })).toHaveProperty("disabled", true);
|
||||
});
|
||||
|
||||
it("shows multi-agent delegation in the Délégation agents MCP group", async () => {
|
||||
await renderPanel();
|
||||
await openMcpToolsTab();
|
||||
|
||||
const delegationGroup = screen.getByRole("button", {
|
||||
name: /Délégation agents/,
|
||||
});
|
||||
expect(delegationGroup).toBeTruthy();
|
||||
expect(screen.getByRole("checkbox", {
|
||||
name: /Solliciter plusieurs agents, idea_ask_agents$/,
|
||||
})).toBeTruthy();
|
||||
});
|
||||
|
||||
it("creating an override prefills the draft with the current effective allowlist", async () => {
|
||||
await renderPanel();
|
||||
await openMcpToolsTab();
|
||||
|
||||
@ -39,7 +39,12 @@ export const MCP_TOOL_GROUPS: McpToolGroupDef[] = [
|
||||
{
|
||||
id: "delegation",
|
||||
label: "Délégation agents",
|
||||
tools: ["idea_ask_agent", "idea_launch_agent", "idea_stop_agent"],
|
||||
tools: [
|
||||
"idea_ask_agent",
|
||||
"idea_ask_agents",
|
||||
"idea_launch_agent",
|
||||
"idea_stop_agent",
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "contextMemory",
|
||||
@ -83,6 +88,7 @@ export const MCP_TOOL_LABELS: Record<string, string> = {
|
||||
idea_ticket_read_carnet: "Lire le carnet d'un ticket",
|
||||
idea_sprint_list: "Lister les sprints",
|
||||
idea_ask_agent: "Déléguer à un agent",
|
||||
idea_ask_agents: "Solliciter plusieurs agents",
|
||||
idea_launch_agent: "Lancer un agent",
|
||||
idea_stop_agent: "Arrêter un agent",
|
||||
idea_update_context: "Modifier le contexte d'un agent",
|
||||
|
||||
@ -455,6 +455,52 @@ describe("TerminalView — visible launch-failure surface (ticket #14 F3)", () =
|
||||
fitSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("keeps fitting across a keyed project remount until the new cell settles", async () => {
|
||||
// ProjectsView keys LayoutGrid by project. A project switch therefore
|
||||
// unmounts/remounts TerminalView, so the mount path itself must keep a
|
||||
// short tail of fits alive while the new cell geometry settles.
|
||||
const fitSpy = vi.spyOn(FitAddon.prototype, "fit");
|
||||
const firstHandle = makeHandle({ sessionId: "project-1" });
|
||||
const secondHandle = makeHandle({ sessionId: "project-2" });
|
||||
const open = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce(firstHandle)
|
||||
.mockResolvedValueOnce(secondHandle);
|
||||
|
||||
function ProjectTerminal({ projectId }: { projectId: string }) {
|
||||
return (
|
||||
<DIProvider gateways={{ terminal: new MockTerminalGateway() } as unknown as Gateways}>
|
||||
<TerminalView
|
||||
key={projectId}
|
||||
cwd={`/cwd/${projectId}`}
|
||||
open={open}
|
||||
/>
|
||||
</DIProvider>
|
||||
);
|
||||
}
|
||||
|
||||
const { rerender } = render(<ProjectTerminal projectId="p1" />);
|
||||
await waitFor(() => expect(open).toHaveBeenCalledTimes(1));
|
||||
setTerminalBoxSize(400, 200);
|
||||
await waitFor(() => expect(firstHandle.resize).toHaveBeenCalled());
|
||||
|
||||
fitSpy.mockClear();
|
||||
rerender(<ProjectTerminal projectId="p2" />);
|
||||
await waitFor(() => expect(open).toHaveBeenCalledTimes(2));
|
||||
setTerminalBoxSize(520, 260);
|
||||
|
||||
for (let i = 0; i < 8; i += 1) {
|
||||
await new Promise((resolve) => requestAnimationFrame(resolve));
|
||||
}
|
||||
|
||||
expect(fitSpy.mock.calls.length).toBeGreaterThan(5);
|
||||
await waitFor(() => expect(secondHandle.resize).toHaveBeenCalled());
|
||||
expect(firstHandle.close).not.toHaveBeenCalled();
|
||||
expect(secondHandle.close).not.toHaveBeenCalled();
|
||||
|
||||
fitSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("does not refit when refitSignal is left undefined (no-op for callers that don't pass it)", async () => {
|
||||
const fitSpy = vi.spyOn(FitAddon.prototype, "fit");
|
||||
const open = vi.fn(async () => makeHandle({ sessionId: "no-signal-1" }));
|
||||
|
||||
@ -368,7 +368,11 @@ export function TerminalView({
|
||||
// manual resize. This stays bounded and preserves the rows/cols-changed
|
||||
// guard before touching the PTY.
|
||||
const SETTLE_REFIT_FRAMES = 4;
|
||||
const MAX_ZERO_SIZE_RETRIES = 8;
|
||||
// Project switches remount LayoutGrid/TerminalView by key. The new cell can
|
||||
// report a non-zero but still intermediate box for more than the ordinary
|
||||
// transition tail, so the mount path keeps fitting a little longer.
|
||||
const MOUNT_SETTLE_REFIT_FRAMES = 12;
|
||||
const MAX_ZERO_SIZE_RETRIES = MOUNT_SETTLE_REFIT_FRAMES;
|
||||
let zeroSizeRetries = 0;
|
||||
const refit = () => {
|
||||
rafId = 0;
|
||||
@ -418,7 +422,7 @@ export function TerminalView({
|
||||
};
|
||||
const ro = new ResizeObserver(() => scheduleRefit());
|
||||
ro.observe(container);
|
||||
scheduleSettledRefit();
|
||||
scheduleRefit(MOUNT_SETTLE_REFIT_FRAMES);
|
||||
window.addEventListener("resize", scheduleSettledRefit);
|
||||
window.addEventListener("focus", scheduleSettledRefit);
|
||||
window.addEventListener("pageshow", scheduleSettledRefit);
|
||||
|
||||
Reference in New Issue
Block a user