From f4219449dbf23190eb98ed8f94e5a8d21d57bda4 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Sun, 21 Jun 2026 18:13:40 +0200 Subject: [PATCH] fix(front): prevent AI agent output field error message from overlapping the Type field (#21921) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem Follow-up to #21834, found during QA. That PR added an inline validation error on the AI Agent **Output → Variable Name** field. The error is rendered with `InputErrorHelper`, which is `position: absolute`. When the message wraps to two lines (which it does at the side-panel width), it is taken out of the layout flow and **overlaps the "Type" selector** directly below it: ``` Variable Name [ sdlfkj sdlkj ] Use only letters, numbers, underscores, dots or hyphens (max 64 Type <-- overlapped by the error message [ Text ▾ ] ``` ## Fix Render the error with `InputHint danger` instead of `InputErrorHelper`, matching how the sibling `FormNumberFieldInput` already shows its errors. `InputHint` flows in the column (`margin-top`, not absolute), so the error reserves its own space and pushes the following fields down instead of overlapping them. This is a one-line behaviour change in `FormTextFieldInput`; no new component or styling is introduced. ## After The `Type` field is pushed below the wrapped error message with correct spacing: ![after](https://raw.githubusercontent.com/twentyhq/twenty/pr-21921-assets/repro-after.png) ## Tests - Added a `WithError` story to `FormTextFieldInput` (mirrors the existing `FormNumberFieldInput` `WithError` story) asserting the error message is visible. ## QA Reproduced and verified in Storybook against the real `WorkflowOutputSchemaBuilder` (throwaway story, not committed): before the fix the error overlapped `Type`; after the fix the `Type` field is pushed below the wrapped message with correct spacing. --- .../components/FormTextFieldInput.tsx | 3 +-- .../FormTextFieldInput.stories.tsx | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormTextFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormTextFieldInput.tsx index c6098e2a49..536c898276 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormTextFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormTextFieldInput.tsx @@ -5,7 +5,6 @@ import { FormFieldInputRowContainer } from '@/object-record/record-field/ui/form import { TextVariableEditor } from '@/object-record/record-field/ui/form-types/components/TextVariableEditor'; import { useTextVariableEditor } from '@/object-record/record-field/ui/form-types/hooks/useTextVariableEditor'; import { type VariablePickerComponent } from '@/object-record/record-field/ui/form-types/types/VariablePickerComponent'; -import { InputErrorHelper } from '@/ui/input/components/InputErrorHelper'; import { InputHint } from '@/ui/input/components/InputHint'; import { InputLabel } from '@/ui/input/components/InputLabel'; import { parseEditorContent } from '@/workflow/workflow-variables/utils/parseEditorContent'; @@ -93,7 +92,7 @@ export const FormTextFieldInput = ({ ) : null} {hint && {hint}} - {error && {error}} + {error && {error}} ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormTextFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormTextFieldInput.stories.tsx index 444b97a22b..a11253a929 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormTextFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormTextFieldInput.stories.tsx @@ -42,6 +42,25 @@ export const WithLabel: Story = { }, }; +export const WithError: Story = { + args: { + label: 'Variable Name', + placeholder: 'Text field...', + defaultValue: 'invalid name', + error: + 'Use only letters, numbers, underscores, dots or hyphens (max 64 characters).', + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + + const error = await canvas.findByText( + 'Use only letters, numbers, underscores, dots or hyphens (max 64 characters).', + ); + + expect(error).toBeVisible(); + }, +}; + export const Multiline: Story = { args: { label: 'Text',