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" && (
|
||||
<button
|
||||
className="btn btn--sm btn--danger"
|
||||
onClick={() => void handleDelete(agent.id, agent.name)}
|
||||
title="Delete"
|
||||
>
|
||||
<Trash2 size={14} />
|
||||
</button>
|
||||
<>
|
||||
<button
|
||||
className="btn btn--sm"
|
||||
onClick={() => void handleStateChange(agent.id, "active")}
|
||||
title="Start"
|
||||
>
|
||||
<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>
|
||||
@@ -1023,13 +1032,22 @@ export function AgentsView({ addToast, projectId }: AgentsViewProps) {
|
||||
</>
|
||||
)}
|
||||
{agent.state === "terminated" && (
|
||||
<button
|
||||
className="btn btn--sm btn--danger"
|
||||
onClick={() => void handleDelete(agent.id, agent.name)}
|
||||
title="Delete"
|
||||
>
|
||||
<Trash2 size={14} /> Delete
|
||||
</button>
|
||||
<>
|
||||
<button
|
||||
className="btn btn--sm"
|
||||
onClick={() => void handleStateChange(agent.id, "active")}
|
||||
title="Start"
|
||||
>
|
||||
<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>
|
||||
|
||||
@@ -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 () => {
|
||||
mockUpdateAgentState.mockRejectedValue(new Error("Invalid transition"));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user