diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useUpdateCommandMenuPageInfo.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useUpdateCommandMenuPageInfo.test.tsx
new file mode 100644
index 000000000..90d80cbe3
--- /dev/null
+++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useUpdateCommandMenuPageInfo.test.tsx
@@ -0,0 +1,135 @@
+import { useUpdateCommandMenuPageInfo } from '@/command-menu/hooks/useUpdateCommandMenuPageInfo';
+import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
+import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
+import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
+import { renderHook } from '@testing-library/react';
+import { act } from 'react';
+import { RecoilRoot, useRecoilValue } from 'recoil';
+import { IconArrowDown, IconDotsVertical } from 'twenty-ui';
+
+const mockedPageInfo = {
+ title: 'Initial Title',
+ Icon: IconDotsVertical,
+ instanceId: 'test-instance',
+};
+
+const mockedNavigationStack = [
+ {
+ page: CommandMenuPages.Root,
+ pageTitle: 'Initial Title',
+ pageIcon: IconDotsVertical,
+ pageId: 'test-page-id',
+ },
+];
+
+const Wrapper = ({ children }: { children: React.ReactNode }) => (
+ {
+ set(commandMenuNavigationStackState, mockedNavigationStack);
+ set(commandMenuPageInfoState, mockedPageInfo);
+ }}
+ >
+ {children}
+
+);
+
+describe('useUpdateCommandMenuPageInfo', () => {
+ const renderHooks = () => {
+ const { result } = renderHook(
+ () => {
+ const { updateCommandMenuPageInfo } = useUpdateCommandMenuPageInfo();
+ const commandMenuNavigationStack = useRecoilValue(
+ commandMenuNavigationStackState,
+ );
+ const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState);
+
+ return {
+ updateCommandMenuPageInfo,
+ commandMenuNavigationStack,
+ commandMenuPageInfo,
+ };
+ },
+ { wrapper: Wrapper },
+ );
+
+ return {
+ result,
+ };
+ };
+
+ it('should update command menu page info with new title and icon', () => {
+ const { result } = renderHooks();
+
+ act(() => {
+ result.current.updateCommandMenuPageInfo({
+ pageTitle: 'New Title',
+ pageIcon: IconArrowDown,
+ });
+ });
+
+ expect(result.current.commandMenuNavigationStack).toEqual([
+ {
+ page: CommandMenuPages.Root,
+ pageTitle: 'New Title',
+ pageIcon: IconArrowDown,
+ pageId: 'test-page-id',
+ },
+ ]);
+
+ expect(result.current.commandMenuPageInfo).toEqual({
+ title: 'New Title',
+ Icon: IconArrowDown,
+ instanceId: 'test-instance',
+ });
+ });
+
+ it('should update command menu page info with new title', () => {
+ const { result } = renderHooks();
+
+ act(() => {
+ result.current.updateCommandMenuPageInfo({
+ pageTitle: 'New Title',
+ });
+ });
+
+ expect(result.current.commandMenuNavigationStack).toEqual([
+ {
+ page: CommandMenuPages.Root,
+ pageTitle: 'New Title',
+ pageIcon: IconDotsVertical,
+ pageId: 'test-page-id',
+ },
+ ]);
+
+ expect(result.current.commandMenuPageInfo).toEqual({
+ title: 'New Title',
+ Icon: IconDotsVertical,
+ instanceId: 'test-instance',
+ });
+ });
+
+ it('should update command menu page info with new icon', () => {
+ const { result } = renderHooks();
+
+ act(() => {
+ result.current.updateCommandMenuPageInfo({
+ pageIcon: IconArrowDown,
+ });
+ });
+
+ expect(result.current.commandMenuNavigationStack).toEqual([
+ {
+ page: CommandMenuPages.Root,
+ pageTitle: 'Initial Title',
+ pageIcon: IconArrowDown,
+ pageId: 'test-page-id',
+ },
+ ]);
+
+ expect(result.current.commandMenuPageInfo).toEqual({
+ title: 'Initial Title',
+ Icon: IconArrowDown,
+ instanceId: 'test-instance',
+ });
+ });
+});
diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useUpdateCommandMenuPageInfo.ts b/packages/twenty-front/src/modules/command-menu/hooks/useUpdateCommandMenuPageInfo.ts
new file mode 100644
index 000000000..896547b2a
--- /dev/null
+++ b/packages/twenty-front/src/modules/command-menu/hooks/useUpdateCommandMenuPageInfo.ts
@@ -0,0 +1,57 @@
+import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
+import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
+import { useRecoilCallback } from 'recoil';
+import { IconComponent, IconDotsVertical } from 'twenty-ui';
+
+export const useUpdateCommandMenuPageInfo = () => {
+ const updateCommandMenuPageInfo = useRecoilCallback(
+ ({ snapshot, set }) =>
+ ({
+ pageTitle,
+ pageIcon,
+ }: {
+ pageTitle?: string;
+ pageIcon?: IconComponent;
+ }) => {
+ const commandMenuPageInfo = snapshot
+ .getLoadable(commandMenuPageInfoState)
+ .getValue();
+
+ const newCommandMenuPageInfo = {
+ ...commandMenuPageInfo,
+ title: pageTitle ?? commandMenuPageInfo.title ?? '',
+ Icon: pageIcon ?? commandMenuPageInfo.Icon ?? IconDotsVertical,
+ };
+
+ set(commandMenuPageInfoState, newCommandMenuPageInfo);
+
+ const commandMenuNavigationStack = snapshot
+ .getLoadable(commandMenuNavigationStackState)
+ .getValue();
+
+ const lastCommandMenuNavigationStackItem =
+ commandMenuNavigationStack.at(-1);
+
+ if (!lastCommandMenuNavigationStackItem) {
+ return;
+ }
+
+ const newCommandMenuNavigationStack = [
+ ...commandMenuNavigationStack.slice(0, -1),
+ {
+ page: lastCommandMenuNavigationStackItem.page,
+ pageTitle: newCommandMenuPageInfo.title,
+ pageIcon: newCommandMenuPageInfo.Icon,
+ pageId: lastCommandMenuNavigationStackItem.pageId,
+ },
+ ];
+
+ set(commandMenuNavigationStackState, newCommandMenuNavigationStack);
+ },
+ [],
+ );
+
+ return {
+ updateCommandMenuPageInfo,
+ };
+};
diff --git a/packages/twenty-front/src/modules/ui/input/components/TitleInput.tsx b/packages/twenty-front/src/modules/ui/input/components/TitleInput.tsx
new file mode 100644
index 000000000..f24aadf22
--- /dev/null
+++ b/packages/twenty-front/src/modules/ui/input/components/TitleInput.tsx
@@ -0,0 +1,182 @@
+import {
+ TextInputV2,
+ TextInputV2Size,
+} from '@/ui/input/components/TextInputV2';
+import { useRef, useState } from 'react';
+import { isDefined } from 'twenty-shared/utils';
+
+import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents';
+import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
+import styled from '@emotion/styled';
+import { OverflowingTextWithTooltip } from 'twenty-ui';
+
+type InputProps = {
+ value?: string;
+ onChange: (value: string) => void;
+ placeholder?: string;
+ hotkeyScope?: string;
+ onEnter?: () => void;
+ onEscape?: () => void;
+ onClickOutside?: () => void;
+ onTab?: () => void;
+ onShiftTab?: () => void;
+ sizeVariant?: TextInputV2Size;
+};
+
+export type TitleInputProps = {
+ disabled?: boolean;
+} & InputProps;
+
+const StyledDiv = styled.div<{
+ sizeVariant: TextInputV2Size;
+ disabled?: boolean;
+}>`
+ background: inherit;
+ border: none;
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.primary};
+ cursor: ${({ disabled }) => (disabled ? 'default' : 'pointer')};
+ overflow: hidden;
+ height: ${({ sizeVariant }) =>
+ sizeVariant === 'xs'
+ ? '20px'
+ : sizeVariant === 'sm'
+ ? '24px'
+ : sizeVariant === 'md'
+ ? '28px'
+ : '32px'};
+ padding: ${({ theme }) => theme.spacing(0, 1.25)};
+ box-sizing: border-box;
+ display: flex;
+ align-items: center;
+ :hover {
+ background: ${({ theme, disabled }) =>
+ disabled ? 'inherit' : theme.background.transparent.light};
+ }
+`;
+
+const Input = ({
+ value,
+ onChange,
+ placeholder,
+ hotkeyScope = 'title-input',
+ onEnter,
+ onEscape,
+ onClickOutside,
+ onTab,
+ onShiftTab,
+ setIsOpened,
+ sizeVariant,
+}: InputProps & { setIsOpened: (isOpened: boolean) => void }) => {
+ const wrapperRef = useRef(null);
+
+ const [draftValue, setDraftValue] = useState(value ?? '');
+
+ const handleFocus = (event: React.FocusEvent) => {
+ if (isDefined(value)) {
+ event.target.select();
+ }
+ };
+
+ const { goBackToPreviousHotkeyScope } = usePreviousHotkeyScope();
+
+ const handleLeaveFocus = () => {
+ setIsOpened(false);
+ goBackToPreviousHotkeyScope();
+ };
+
+ useRegisterInputEvents({
+ inputRef: wrapperRef,
+ inputValue: draftValue,
+ onEnter: () => {
+ handleLeaveFocus();
+ onEnter?.();
+ },
+ onEscape: () => {
+ handleLeaveFocus();
+ onEscape?.();
+ },
+ onClickOutside: (event) => {
+ event.stopImmediatePropagation();
+ handleLeaveFocus();
+ onClickOutside?.();
+ },
+ onTab: () => {
+ handleLeaveFocus();
+ onTab?.();
+ },
+ onShiftTab: () => {
+ handleLeaveFocus();
+ onShiftTab?.();
+ },
+ hotkeyScope: hotkeyScope,
+ });
+
+ return (
+ {
+ setDraftValue(text);
+ onChange?.(text);
+ }}
+ placeholder={placeholder}
+ onFocus={handleFocus}
+ autoFocus
+ />
+ );
+};
+
+export const TitleInput = ({
+ disabled,
+ value,
+ sizeVariant = 'md',
+ onChange,
+ placeholder,
+ hotkeyScope = 'title-input',
+ onEnter,
+ onEscape,
+ onClickOutside,
+ onTab,
+ onShiftTab,
+}: TitleInputProps) => {
+ const [isOpened, setIsOpened] = useState(false);
+
+ const { setHotkeyScopeAndMemorizePreviousScope } = usePreviousHotkeyScope();
+
+ return (
+ <>
+ {isOpened ? (
+
+ ) : (
+ {
+ if (!disabled) {
+ setIsOpened(true);
+ setHotkeyScopeAndMemorizePreviousScope(hotkeyScope);
+ }
+ }}
+ >
+
+
+ )}
+ >
+ );
+};
diff --git a/packages/twenty-front/src/modules/ui/input/components/__stories__/TitleInput.stories.tsx b/packages/twenty-front/src/modules/ui/input/components/__stories__/TitleInput.stories.tsx
new file mode 100644
index 000000000..4e4a6b331
--- /dev/null
+++ b/packages/twenty-front/src/modules/ui/input/components/__stories__/TitleInput.stories.tsx
@@ -0,0 +1,64 @@
+import { Meta, StoryObj } from '@storybook/react';
+import { ComponentDecorator } from 'twenty-ui';
+
+import { TitleInput } from '@/ui/input/components/TitleInput';
+
+const meta: Meta = {
+ title: 'UI/Input/TitleInput',
+ component: TitleInput,
+ decorators: [ComponentDecorator],
+ args: {
+ placeholder: 'Enter title',
+ hotkeyScope: 'titleInput',
+ sizeVariant: 'md',
+ },
+ argTypes: {
+ hotkeyScope: { control: false },
+ sizeVariant: { control: false },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {};
+
+export const WithValue: Story = {
+ args: { value: 'Sample Title' },
+};
+
+export const Disabled: Story = {
+ args: { disabled: true, value: 'Disabled Title' },
+};
+
+export const ExtraSmall: Story = {
+ args: { sizeVariant: 'xs', value: 'Extra Small Title' },
+};
+
+export const Small: Story = {
+ args: { sizeVariant: 'sm', value: 'Small Title' },
+};
+
+export const Medium: Story = {
+ args: { sizeVariant: 'md', value: 'Medium Title' },
+};
+
+export const Large: Story = {
+ args: { sizeVariant: 'lg', value: 'Large Title' },
+};
+
+export const WithLongText: Story = {
+ args: {
+ value:
+ 'This is a very long title that will likely overflow and demonstrate the tooltip behavior of the component',
+ },
+ parameters: {
+ container: {
+ width: 250,
+ },
+ },
+};
+
+export const WithCustomPlaceholder: Story = {
+ args: { placeholder: 'Custom placeholder example' },
+};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepHeader.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepHeader.tsx
index 05ad3fda7..8ed5d7c64 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepHeader.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepHeader.tsx
@@ -1,10 +1,9 @@
-import { TextInput } from '@/ui/field/input/components/TextInput';
+import { useUpdateCommandMenuPageInfo } from '@/command-menu/hooks/useUpdateCommandMenuPageInfo';
+import { TitleInput } from '@/ui/input/components/TitleInput';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useState } from 'react';
import { IconComponent } from 'twenty-ui';
-import { useDebouncedCallback } from 'use-debounce';
-
const StyledHeader = styled.div`
background-color: ${({ theme }) => theme.background.secondary};
border-bottom: 1px solid ${({ theme }) => theme.border.color.medium};
@@ -17,6 +16,7 @@ const StyledHeader = styled.div`
const StyledHeaderInfo = styled.div`
display: flex;
flex-direction: column;
+ width: 100%;
gap: ${({ theme }) => theme.spacing(2)};
`;
@@ -24,9 +24,8 @@ const StyledHeaderTitle = styled.div`
color: ${({ theme }) => theme.font.color.primary};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
font-size: ${({ theme }) => theme.font.size.xl};
- width: 420px;
- overflow: hidden;
-
+ width: fit-content;
+ max-width: 420px;
& > input:disabled {
color: ${({ theme }) => theme.font.color.primary};
}
@@ -34,7 +33,7 @@ const StyledHeaderTitle = styled.div`
const StyledHeaderType = styled.div`
color: ${({ theme }) => theme.font.color.tertiary};
- padding-left: ${({ theme }) => theme.spacing(2)};
+ padding-left: ${({ theme }) => theme.spacing(1)};
`;
const StyledHeaderIconContainer = styled.div`
@@ -75,13 +74,18 @@ export const WorkflowStepHeader = ({
const [title, setTitle] = useState(initialTitle);
- const debouncedOnTitleChange = useDebouncedCallback((newTitle: string) => {
- onTitleChange?.(newTitle);
- }, 100);
+ const { updateCommandMenuPageInfo } = useUpdateCommandMenuPageInfo();
const handleChange = (newTitle: string) => {
setTitle(newTitle);
- debouncedOnTitleChange(newTitle);
+ };
+
+ const saveTitle = () => {
+ onTitleChange?.(title);
+ updateCommandMenuPageInfo({
+ pageTitle: title,
+ pageIcon: Icon,
+ });
};
return (
@@ -95,15 +99,20 @@ export const WorkflowStepHeader = ({
- {
+ setTitle(initialTitle);
+ }}
+ onClickOutside={saveTitle}
+ onTab={saveTitle}
+ onShiftTab={saveTitle}
/>
{headerType}
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/__stories__/WorkflowStepHeader.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/__stories__/WorkflowStepHeader.stories.tsx
index 574efaa80..81606fd37 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/__stories__/WorkflowStepHeader.stories.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/__stories__/WorkflowStepHeader.stories.tsx
@@ -27,7 +27,8 @@ export const Default: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- expect(await canvas.findByDisplayValue('Create Record')).toBeVisible();
+ // TitleInput shows text in a div when not being edited
+ expect(await canvas.findByText('Create Record')).toBeVisible();
expect(await canvas.findByText('Action')).toBeVisible();
},
};
@@ -43,24 +44,25 @@ export const EditableTitle: Story = {
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
+ // First find the div with the text, then click it to activate the input
+ const titleText = await canvas.findByText('Create Record');
+ await userEvent.click(titleText);
+
+ // Now find the input that appears after clicking
const titleInput = await canvas.findByDisplayValue('Create Record');
const NEW_TITLE = 'New Title';
await userEvent.clear(titleInput);
-
- await waitFor(() => {
- expect(args.onTitleChange).toHaveBeenCalledWith('');
- });
-
await userEvent.type(titleInput, NEW_TITLE);
+ // Press Enter to submit the edit
+ await userEvent.keyboard('{Enter}');
+
+ // Wait for the callback to be called
await waitFor(() => {
expect(args.onTitleChange).toHaveBeenCalledWith(NEW_TITLE);
});
-
- expect(args.onTitleChange).toHaveBeenCalledTimes(2);
- expect(titleInput).toHaveValue(NEW_TITLE);
},
};
@@ -76,14 +78,20 @@ export const Disabled: Story = {
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
- const titleInput = await canvas.findByDisplayValue('Create Record');
- expect(titleInput).toBeDisabled();
+ // When disabled, TitleInput just shows text in a div, not an input
+ const titleText = await canvas.findByText('Create Record');
- const NEW_TITLE = 'New Title';
+ // Check if the element has the disabled styling (cursor: default)
+ expect(window.getComputedStyle(titleText).cursor).toBe('default');
- await userEvent.type(titleInput, NEW_TITLE);
+ // Try to click it - nothing should happen
+ await userEvent.click(titleText);
+ // Confirm there is no input field
+ const titleInput = canvas.queryByDisplayValue('Create Record');
+ expect(titleInput).not.toBeInTheDocument();
+
+ // Confirm the callback is not called
expect(args.onTitleChange).not.toHaveBeenCalled();
- expect(titleInput).toHaveValue('Create Record');
},
};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionCreateRecord.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionCreateRecord.stories.tsx
index 32db820d1..de0a68a78 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionCreateRecord.stories.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionCreateRecord.stories.tsx
@@ -73,9 +73,14 @@ export const Disabled: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- const titleInput = await canvas.findByDisplayValue('Create Record');
+ const titleText = await canvas.findByText('Create Record');
- expect(titleInput).toBeDisabled();
+ expect(window.getComputedStyle(titleText).cursor).toBe('default');
+
+ await userEvent.click(titleText);
+
+ const titleInput = canvas.queryByDisplayValue('Create Record');
+ expect(titleInput).not.toBeInTheDocument();
const objectSelectCurrentValue = await canvas.findByText('People');
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionDeleteRecord.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionDeleteRecord.stories.tsx
index f37a0fb8d..aaee9d16d 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionDeleteRecord.stories.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionDeleteRecord.stories.tsx
@@ -77,9 +77,14 @@ export const DisabledWithEmptyValues: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- const titleInput = await canvas.findByDisplayValue('Delete Record');
+ const titleText = await canvas.findByText('Delete Record');
- expect(titleInput).toBeDisabled();
+ expect(window.getComputedStyle(titleText).cursor).toBe('default');
+
+ await userEvent.click(titleText);
+
+ const titleInput = canvas.queryByDisplayValue('Delete Record');
+ expect(titleInput).not.toBeInTheDocument();
const objectSelectCurrentValue = await canvas.findByText('People');
@@ -123,9 +128,14 @@ export const DisabledWithDefaultStaticValues: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- const titleInput = await canvas.findByDisplayValue('Delete Record');
+ const titleText = await canvas.findByText('Delete Record');
- expect(titleInput).toBeDisabled();
+ expect(window.getComputedStyle(titleText).cursor).toBe('default');
+
+ await userEvent.click(titleText);
+
+ const titleInput = canvas.queryByDisplayValue('Delete Record');
+ expect(titleInput).not.toBeInTheDocument();
const objectSelectCurrentValue = await canvas.findByText('People');
@@ -173,9 +183,14 @@ export const DisabledWithDefaultVariableValues: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- const titleInput = await canvas.findByDisplayValue('Delete Record');
+ const titleText = await canvas.findByText('Delete Record');
- expect(titleInput).toBeDisabled();
+ expect(window.getComputedStyle(titleText).cursor).toBe('default');
+
+ await userEvent.click(titleText);
+
+ const titleInput = canvas.queryByDisplayValue('Delete Record');
+ expect(titleInput).not.toBeInTheDocument();
const objectSelectCurrentValue = await canvas.findByText('People');
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionFindRecords.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionFindRecords.stories.tsx
index d3e3f3bca..16e3c26b4 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionFindRecords.stories.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionFindRecords.stories.tsx
@@ -76,9 +76,14 @@ export const DisabledWithEmptyValues: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- const titleInput = await canvas.findByDisplayValue('Search Records');
+ const titleText = await canvas.findByText('Search Records');
- expect(titleInput).toBeDisabled();
+ expect(window.getComputedStyle(titleText).cursor).toBe('default');
+
+ await userEvent.click(titleText);
+
+ const titleInput = canvas.queryByDisplayValue('Search Records');
+ expect(titleInput).not.toBeInTheDocument();
const objectSelectCurrentValue = await canvas.findByText('People');
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionUpdateRecord.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionUpdateRecord.stories.tsx
index 2f65208b5..6b74ffcc6 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionUpdateRecord.stories.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionUpdateRecord.stories.tsx
@@ -90,9 +90,14 @@ export const DisabledWithEmptyValues: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- const titleInput = await canvas.findByDisplayValue('Update Record');
+ const titleText = await canvas.findByText('Update Record');
- expect(titleInput).toBeDisabled();
+ expect(window.getComputedStyle(titleText).cursor).toBe('default');
+
+ await userEvent.click(titleText);
+
+ const titleInput = canvas.queryByDisplayValue('Update Record');
+ expect(titleInput).not.toBeInTheDocument();
const objectSelectCurrentValue = await canvas.findByText('People');
@@ -151,9 +156,14 @@ export const DisabledWithDefaultStaticValues: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- const titleInput = await canvas.findByDisplayValue('Update Record');
+ const titleText = await canvas.findByText('Update Record');
- expect(titleInput).toBeDisabled();
+ expect(window.getComputedStyle(titleText).cursor).toBe('default');
+
+ await userEvent.click(titleText);
+
+ const titleInput = canvas.queryByDisplayValue('Update Record');
+ expect(titleInput).not.toBeInTheDocument();
const objectSelectCurrentValue = await canvas.findByText('People');
@@ -214,9 +224,14 @@ export const DisabledWithDefaultVariableValues: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- const titleInput = await canvas.findByDisplayValue('Update Record');
+ const titleText = await canvas.findByText('Update Record');
- expect(titleInput).toBeDisabled();
+ expect(window.getComputedStyle(titleText).cursor).toBe('default');
+
+ await userEvent.click(titleText);
+
+ const titleInput = canvas.queryByDisplayValue('Update Record');
+ expect(titleInput).not.toBeInTheDocument();
const objectSelectCurrentValue = await canvas.findByText('People');
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/__stories__/WorkflowEditActionFormBuilder.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/__stories__/WorkflowEditActionFormBuilder.stories.tsx
index 3eacec391..194a7ff6b 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/__stories__/WorkflowEditActionFormBuilder.stories.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/__stories__/WorkflowEditActionFormBuilder.stories.tsx
@@ -2,12 +2,13 @@ import { WorkflowFormAction } from '@/workflow/types/Workflow';
import { WorkflowEditActionFormBuilder } from '@/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormBuilder';
import { Meta, StoryObj } from '@storybook/react';
import { expect, fn, within } from '@storybook/test';
+import { userEvent } from '@storybook/testing-library';
+import { FieldMetadataType } from 'twenty-shared/types';
import { ComponentDecorator, RouterDecorator } from 'twenty-ui';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/WorkflowStepActionDrawerDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow';
-import { FieldMetadataType } from 'twenty-shared/types';
const DEFAULT_ACTION = {
id: getWorkflowNodeIdMock(),
@@ -89,9 +90,14 @@ export const DisabledWithEmptyValues: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- const titleInput = await canvas.findByDisplayValue('Form');
+ const titleText = await canvas.findByText('Form');
- expect(titleInput).toBeDisabled();
+ expect(window.getComputedStyle(titleText).cursor).toBe('default');
+
+ await userEvent.click(titleText);
+
+ const titleInput = canvas.queryByDisplayValue('Form');
+ expect(titleInput).not.toBeInTheDocument();
await canvas.findByText('Company');