From 66632014584523b152cad644236c5d39f452b65b Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:26:29 -0700 Subject: [PATCH 1/2] fix(byo): reserve field hint space through blur (TASK-461) Co-authored-by: Polish Agent-Model: codex/gpt-6-sol/medium --- frontend/src/v2/__tests__/v2-layout-invariants.test.ts | 7 +++++++ frontend/src/v2/v2.css | 9 ++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/frontend/src/v2/__tests__/v2-layout-invariants.test.ts b/frontend/src/v2/__tests__/v2-layout-invariants.test.ts index 9e87921548..2ee6b76360 100644 --- a/frontend/src/v2/__tests__/v2-layout-invariants.test.ts +++ b/frontend/src/v2/__tests__/v2-layout-invariants.test.ts @@ -213,6 +213,13 @@ describe('v2 layout invariants (CSS rule presence)', () => { expect(ruleBody(v2, '.v2-byo__hint')).toContain('margin: 0'); }); + test('BYO field hints keep their layout space when focus moves to the submit button', () => { + expect(ruleBody(v2, '.v2-byo__field > .v2-byo__hint')).toContain('visibility: hidden'); + expect(selectorRuleBody(v2, '.v2-byo__field:focus-within > .v2-byo__hint,\n.v2-byo__field--error > .v2-byo__hint')) + .toContain('visibility: visible'); + expect(ruleBody(v2, '.v2-byo__field > .v2-byo__hint')).not.toContain('display: none'); + }); + // #2287 (QA BYO walk 1): "Other ways to connect" folds the alternatives so the // page shows one command, and the needs line is read before the Copy button. // jsdom cannot see either; sprint-review deleted all three rules and every diff --git a/frontend/src/v2/v2.css b/frontend/src/v2/v2.css index 1c72c468fb..56c183e8e6 100644 --- a/frontend/src/v2/v2.css +++ b/frontend/src/v2/v2.css @@ -6037,12 +6037,11 @@ body.modern-ui.v2-canvas { color: var(--v2-text-tertiary); margin: 0; } -/* Field guidance is available at the moment it is useful, not as a permanent - second label. Errors keep the relevant hint visible until the person edits - that field again. */ -.v2-byo__field > .v2-byo__hint { display: none; } +/* Reserve each hint's space so a click below a focused field cannot miss when + blur hides the guidance between mousedown and mouseup (TASK-461). */ +.v2-byo__field > .v2-byo__hint { visibility: hidden; } .v2-byo__field:focus-within > .v2-byo__hint, -.v2-byo__field--error > .v2-byo__hint { display: block; } +.v2-byo__field--error > .v2-byo__hint { visibility: visible; } /* §3 error — a white card with a border, ink text, no icon. The red fill was the pre-Signal shape: it read as a state of the page rather than a message beside the field it belongs to. */ From cba96a5abcd641d352ed515006f05ff4b56cf026 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:47:40 -0700 Subject: [PATCH 2/2] fix(byo): keep field focus through action press Co-authored-by: Polish Agent-Model: codex/gpt-6-sol/medium --- .../src/v2/__tests__/V2AgentBYOName.test.tsx | 16 ++++++++++++++++ .../v2/__tests__/v2-layout-invariants.test.ts | 7 +++---- frontend/src/v2/components/V2AgentBYO.tsx | 11 +++++++++-- frontend/src/v2/v2.css | 9 +++++---- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/frontend/src/v2/__tests__/V2AgentBYOName.test.tsx b/frontend/src/v2/__tests__/V2AgentBYOName.test.tsx index bdbd6d5597..73b48d8af5 100644 --- a/frontend/src/v2/__tests__/V2AgentBYOName.test.tsx +++ b/frontend/src/v2/__tests__/V2AgentBYOName.test.tsx @@ -79,6 +79,22 @@ afterEach(() => { }); describe('BYO default agent name follows where it runs', () => { + test('pressing the connect action keeps the name field focused until click', async () => { + mockGet(); + renderAt(); + await waitFor(() => expect(screen.getByTestId('byo-mode-byo')).toBeInTheDocument()); + fireEvent.click(screen.getByTestId('byo-mode-byo')); + const action = screen.getByRole('button', { name: /get my connect command/i }); + await waitFor(() => expect(action).toBeEnabled()); + nameInput().focus(); + expect(nameInput()).toHaveFocus(); + expect(fireEvent.mouseDown(action, { cancelable: true })).toBe(false); + expect(nameInput()).toHaveFocus(); + const moreWays = screen.getByTestId('byo-more-ways').querySelector('summary'); + expect(fireEvent.mouseDown(moreWays, { cancelable: true })).toBe(false); + expect(nameInput()).toHaveFocus(); + }); + test('reconnect deep link keeps the name and rotates a revoked key with one action', async () => { mockGet([{ name: 'local', installedBy: 'u1', runtime: { runtimeType: 'webhook' }, connection: { state: 'revoked', lastSeenAt: null } }]); diff --git a/frontend/src/v2/__tests__/v2-layout-invariants.test.ts b/frontend/src/v2/__tests__/v2-layout-invariants.test.ts index 2ee6b76360..890abb1f21 100644 --- a/frontend/src/v2/__tests__/v2-layout-invariants.test.ts +++ b/frontend/src/v2/__tests__/v2-layout-invariants.test.ts @@ -213,11 +213,10 @@ describe('v2 layout invariants (CSS rule presence)', () => { expect(ruleBody(v2, '.v2-byo__hint')).toContain('margin: 0'); }); - test('BYO field hints keep their layout space when focus moves to the submit button', () => { - expect(ruleBody(v2, '.v2-byo__field > .v2-byo__hint')).toContain('visibility: hidden'); + test('BYO field hints take no space until focused or in error', () => { + expect(ruleBody(v2, '.v2-byo__field > .v2-byo__hint')).toContain('display: none'); expect(selectorRuleBody(v2, '.v2-byo__field:focus-within > .v2-byo__hint,\n.v2-byo__field--error > .v2-byo__hint')) - .toContain('visibility: visible'); - expect(ruleBody(v2, '.v2-byo__field > .v2-byo__hint')).not.toContain('display: none'); + .toContain('display: block'); }); // #2287 (QA BYO walk 1): "Other ways to connect" folds the alternatives so the diff --git a/frontend/src/v2/components/V2AgentBYO.tsx b/frontend/src/v2/components/V2AgentBYO.tsx index 5d34d92787..fe09611e33 100644 --- a/frontend/src/v2/components/V2AgentBYO.tsx +++ b/frontend/src/v2/components/V2AgentBYO.tsx @@ -1201,7 +1201,8 @@ const V2AgentBYO: React.FC = () => { {t('agentByo.actions.chooseFirst')} ) : canReconnect ? ( -