fix(front): prevent AI agent output field error message from overlapping the Type field (#21921)

## 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.
This commit is contained in:
Charles Bochet
2026-06-21 18:13:40 +02:00
committed by GitHub
parent 334e962ab5
commit f4219449db
2 changed files with 20 additions and 2 deletions
@@ -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}
</FormFieldInputRowContainer>
{hint && <InputHint>{hint}</InputHint>}
{error && <InputErrorHelper>{error}</InputErrorHelper>}
{error && <InputHint danger>{error}</InputHint>}
</FormFieldInputContainer>
);
};
@@ -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',