fix(FN-1337): remove autoFocus from agent name field in NewAgentDialog
- Remove autoFocus attribute from agent name input to prevent unexpected focus behavior - Make name field non-blocking so preset flow is not interrupted by focus steal - Add comprehensive tests for NewAgentDialog covering preset flow and name field behavior
This commit is contained in:
@@ -274,7 +274,7 @@ export function NewAgentDialog({ isOpen, onClose, onCreated, projectId }: NewAge
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="agent-dialog-field">
|
<div className="agent-dialog-field">
|
||||||
<label htmlFor="agent-name">Name <span className="agent-dialog-required">*</span></label>
|
<label htmlFor="agent-name">Name {!selectedPresetId && <span className="agent-dialog-required">*</span>}</label>
|
||||||
<input
|
<input
|
||||||
id="agent-name"
|
id="agent-name"
|
||||||
type="text"
|
type="text"
|
||||||
@@ -282,7 +282,6 @@ export function NewAgentDialog({ isOpen, onClose, onCreated, projectId }: NewAge
|
|||||||
placeholder="e.g. Frontend Reviewer"
|
placeholder="e.g. Frontend Reviewer"
|
||||||
value={name}
|
value={name}
|
||||||
onChange={e => setName(e.target.value)}
|
onChange={e => setName(e.target.value)}
|
||||||
autoFocus
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="agent-dialog-field">
|
<div className="agent-dialog-field">
|
||||||
@@ -504,7 +503,7 @@ export function NewAgentDialog({ isOpen, onClose, onCreated, projectId }: NewAge
|
|||||||
<button
|
<button
|
||||||
className="btn btn--primary"
|
className="btn btn--primary"
|
||||||
onClick={() => setStep(s => s + 1)}
|
onClick={() => setStep(s => s + 1)}
|
||||||
disabled={step === 0 && !name.trim()}
|
disabled={step === 0 && !name.trim() && !selectedPresetId}
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -842,5 +842,69 @@ describe("NewAgentDialog", () => {
|
|||||||
const titleInput = screen.getByLabelText(/Title/) as HTMLInputElement;
|
const titleInput = screen.getByLabelText(/Title/) as HTMLInputElement;
|
||||||
expect(titleInput.value).toBe("Oversees project strategy, sets priorities, and coordinates between departments to ensure alignment with business goals.");
|
expect(titleInput.value).toBe("Oversees project strategy, sets priorities, and coordinates between departments to ensure alignment with business goals.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("name label shows required indicator when no preset is selected", () => {
|
||||||
|
render(
|
||||||
|
<NewAgentDialog isOpen={true} onClose={mockOnClose} onCreated={mockOnCreated} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
// On initial render (step 0, no preset), the * required indicator should be visible
|
||||||
|
const nameLabel = screen.getByText("Name", { selector: "label" });
|
||||||
|
const requiredSpan = nameLabel.querySelector(".agent-dialog-required");
|
||||||
|
expect(requiredSpan).toBeTruthy();
|
||||||
|
expect(requiredSpan?.textContent).toBe("*");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("name label does not show required indicator when preset is selected", async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(
|
||||||
|
<NewAgentDialog isOpen={true} onClose={mockOnClose} onCreated={mockOnCreated} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => expect(mockFetchModels).toHaveBeenCalledOnce());
|
||||||
|
|
||||||
|
// Select a preset
|
||||||
|
await user.click(screen.getByTestId("preset-engineer"));
|
||||||
|
|
||||||
|
// Preset advances to step 1, go back to step 0
|
||||||
|
await user.click(screen.getByText("Back"));
|
||||||
|
|
||||||
|
// The * required indicator should NOT be visible when a preset is selected
|
||||||
|
const nameLabel = screen.getByText("Name", { selector: "label" });
|
||||||
|
const requiredSpan = nameLabel.querySelector(".agent-dialog-required");
|
||||||
|
expect(requiredSpan).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Next button is enabled when preset is selected even if name is empty", async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(
|
||||||
|
<NewAgentDialog isOpen={true} onClose={mockOnClose} onCreated={mockOnCreated} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => expect(mockFetchModels).toHaveBeenCalledOnce());
|
||||||
|
|
||||||
|
// Select a preset (this fills the name and advances to step 1)
|
||||||
|
await user.click(screen.getByTestId("preset-ceo"));
|
||||||
|
|
||||||
|
// Go back to step 0
|
||||||
|
await user.click(screen.getByText("Back"));
|
||||||
|
|
||||||
|
// Clear the name field
|
||||||
|
const nameInput = screen.getByLabelText(/Name/) as HTMLInputElement;
|
||||||
|
await user.clear(nameInput);
|
||||||
|
expect(nameInput.value).toBe("");
|
||||||
|
|
||||||
|
// Next button should still be enabled because a preset was selected
|
||||||
|
expect(screen.getByText("Next")).not.toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Next button is disabled when no preset is selected and name is empty", () => {
|
||||||
|
render(
|
||||||
|
<NewAgentDialog isOpen={true} onClose={mockOnClose} onCreated={mockOnCreated} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
// On initial render (step 0, no preset, empty name), Next should be disabled
|
||||||
|
expect(screen.getByText("Next")).toBeDisabled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user