From 66be7c3ef4fa13374f10305431f375e2ce35c5a2 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Fri, 20 Mar 2026 13:22:27 +0100 Subject: [PATCH] fix: autogrow input sizing + surface nested error details in upgrade command (#18796) ## Summary ### Fix 1: Autogrow input unclickable when value is empty string - Fixes the last name input on the Person record show page being unclickable on regular screens ### Fix 2: Surface nested migration errors in add-missing-system-fields command - `AddMissingSystemFieldsToStandardObjectsCommand` calls `workspaceMigrationRunnerService.run()` directly and was re-throwing `WorkspaceMigrationRunnerException` without reading its nested `errors` - Extracted `getNestedErrorMessages()` helper (reused by both `isUniqueViolationError` and `enrichErrorMessage`) - Both catch sites now call `enrichErrorMessage()` before re-throwing, appending nested error details to the message **Before:** ``` ERROR [UpgradeCommand] Error in workspace ...: Migration action 'create' for 'fieldMetadata' failed ERROR [UpgradeCommand] undefined ``` **After:** ``` ERROR [UpgradeCommand] Error in workspace ...: Migration action 'create' for 'fieldMetadata' failed (metadata: duplicate key value violates unique constraint "...") ``` ## Test plan - [x] Lint passes - [x] Typecheck passes - [x] Verify upgrade command errors now include nested error details - [x] Verify autogrow input is clickable when value is empty string --- .../modules/ui/input/components/TextInput.tsx | 3 +- ...stem-fields-to-standard-objects.command.ts | 51 +++++++++++++++---- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx b/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx index 77b67d8f39..c0525fe782 100644 --- a/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx @@ -1,4 +1,5 @@ import { InputErrorHelper } from '@/ui/input/components/InputErrorHelper'; +import { isNonEmptyString } from '@sniptt/guards'; import { isDefined } from 'twenty-shared/utils'; import { InputLabel } from '@/ui/input/components/InputLabel'; import { css } from '@linaria/core'; @@ -459,7 +460,7 @@ const TextInputWithAutoGrowWrapper = forwardRef< {props.autoGrow ? ( { + const nestedErrors = error.errors; + + if (!isDefined(nestedErrors)) { + return undefined; + } + + const details = [ + nestedErrors.metadata && `metadata: ${nestedErrors.metadata.message}`, + nestedErrors.workspaceSchema && + `workspaceSchema: ${nestedErrors.workspaceSchema.message}`, + nestedErrors.actionTranspilation && + `actionTranspilation: ${nestedErrors.actionTranspilation.message}`, + ] + .filter(isDefined) + .join('; '); + + return details || undefined; +}; + const isUniqueViolationError = (error: Error): boolean => { if (error.message.includes(DUPLICATE_KEY_MESSAGE)) { return true; } if (error instanceof WorkspaceMigrationRunnerException) { - const nestedErrors = [ - error.errors?.metadata, - error.errors?.workspaceSchema, - error.errors?.actionTranspilation, - ]; + const nestedMessages = getNestedErrorMessages(error); - return nestedErrors.some( - (nestedError) => - nestedError?.message?.includes(DUPLICATE_KEY_MESSAGE) === true, - ); + return nestedMessages?.includes(DUPLICATE_KEY_MESSAGE) === true; } return false; }; +const enrichErrorMessage = (error: Error): Error => { + if (!(error instanceof WorkspaceMigrationRunnerException)) { + return error; + } + + const details = getNestedErrorMessages(error); + + if (isDefined(details)) { + error.message = `${error.message} (${details})`; + } + + return error; +}; + @Command({ name: 'upgrade:1-19:add-missing-system-fields-to-standard-objects', description: @@ -123,7 +152,7 @@ export class AddMissingSystemFieldsToStandardObjectsCommand extends ActiveOrSusp }); } catch (error) { if (!isUniqueViolationError(error)) { - throw error; + throw enrichErrorMessage(error); } this.logger.warn( @@ -182,7 +211,7 @@ export class AddMissingSystemFieldsToStandardObjectsCommand extends ActiveOrSusp }); } catch (error) { if (!isUniqueViolationError(error)) { - throw error; + throw enrichErrorMessage(error); } this.logger.warn(