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:
gsxdsm
2026-04-08 22:56:48 -07:00
parent ef8522f0a8
commit 719ee27164
2 changed files with 66 additions and 3 deletions

View File

@@ -274,7 +274,7 @@ export function NewAgentDialog({ isOpen, onClose, onCreated, projectId }: NewAge
</div>
</div>
<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
id="agent-name"
type="text"
@@ -282,7 +282,6 @@ export function NewAgentDialog({ isOpen, onClose, onCreated, projectId }: NewAge
placeholder="e.g. Frontend Reviewer"
value={name}
onChange={e => setName(e.target.value)}
autoFocus
/>
</div>
<div className="agent-dialog-field">
@@ -504,7 +503,7 @@ export function NewAgentDialog({ isOpen, onClose, onCreated, projectId }: NewAge
<button
className="btn btn--primary"
onClick={() => setStep(s => s + 1)}
disabled={step === 0 && !name.trim()}
disabled={step === 0 && !name.trim() && !selectedPresetId}
>
Next
</button>

View File

@@ -842,5 +842,69 @@ describe("NewAgentDialog", () => {
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.");
});
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();
});
});
});