feat(FN-2116): add start action for terminated agent cards
- Add a Start button for terminated agents in board cards alongside Delete - Add a Start action for terminated agents in list cards with icon + label - Reuse the existing state transition handler to move terminated agents back to active - Extend AgentListModal tests to cover Start button visibility and start action behavior
This commit is contained in:
@@ -792,13 +792,22 @@ export function AgentsView({ addToast, projectId }: AgentsViewProps) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{agent.state === "terminated" && (
|
{agent.state === "terminated" && (
|
||||||
<button
|
<>
|
||||||
className="btn btn--sm btn--danger"
|
<button
|
||||||
onClick={() => void handleDelete(agent.id, agent.name)}
|
className="btn btn--sm"
|
||||||
title="Delete"
|
onClick={() => void handleStateChange(agent.id, "active")}
|
||||||
>
|
title="Start"
|
||||||
<Trash2 size={14} />
|
>
|
||||||
</button>
|
<Play size={14} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn btn--sm btn--danger"
|
||||||
|
onClick={() => void handleDelete(agent.id, agent.name)}
|
||||||
|
title="Delete"
|
||||||
|
>
|
||||||
|
<Trash2 size={14} />
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1023,13 +1032,22 @@ export function AgentsView({ addToast, projectId }: AgentsViewProps) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{agent.state === "terminated" && (
|
{agent.state === "terminated" && (
|
||||||
<button
|
<>
|
||||||
className="btn btn--sm btn--danger"
|
<button
|
||||||
onClick={() => void handleDelete(agent.id, agent.name)}
|
className="btn btn--sm"
|
||||||
title="Delete"
|
onClick={() => void handleStateChange(agent.id, "active")}
|
||||||
>
|
title="Start"
|
||||||
<Trash2 size={14} /> Delete
|
>
|
||||||
</button>
|
<Play size={14} /> Start
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn btn--sm btn--danger"
|
||||||
|
onClick={() => void handleDelete(agent.id, agent.name)}
|
||||||
|
title="Delete"
|
||||||
|
>
|
||||||
|
<Trash2 size={14} /> Delete
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -564,6 +564,54 @@ describe("AgentListModal", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("shows Start button for terminated agents", async () => {
|
||||||
|
render(
|
||||||
|
<AgentListModal
|
||||||
|
isOpen={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
addToast={mockAddToast}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText("All States")).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
const filterSelect = screen.getByDisplayValue("All States");
|
||||||
|
fireEvent.change(filterSelect, { target: { value: "terminated" } });
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTitle("Start")).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("starts terminated agent", async () => {
|
||||||
|
render(
|
||||||
|
<AgentListModal
|
||||||
|
isOpen={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
addToast={mockAddToast}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText("All States")).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
const filterSelect = screen.getByDisplayValue("All States");
|
||||||
|
fireEvent.change(filterSelect, { target: { value: "terminated" } });
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTitle("Start")).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByTitle("Start"));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(mockUpdateAgentState).toHaveBeenCalledWith("agent-004", "active", undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("handles state change errors gracefully", async () => {
|
it("handles state change errors gracefully", async () => {
|
||||||
mockUpdateAgentState.mockRejectedValue(new Error("Invalid transition"));
|
mockUpdateAgentState.mockRejectedValue(new Error("Invalid transition"));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user