Allow many record fields relative to the same record type in workflow forms (#12522)
Relative to https://github.com/twentyhq/twenty/issues/12517 ## Before https://private-user-images.githubusercontent.com/29370468/453438380-58c52f55-9145-40f9-a9e9-caec2a2281ea.mp4?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDk1NzAwODAsIm5iZiI6MTc0OTU2OTc4MCwicGF0aCI6Ii8yOTM3MDQ2OC80NTM0MzgzODAtNThjNTJmNTUtOTE0NS00MGY5LWE5ZTktY2FlYzJhMjI4MWVhLm1wND9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTA2MTAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwNjEwVDE1MzYyMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWYxY2VlZWVmM2I2ZDBhOGQ3NzdlMjEyZTE3OTg0ZDZmMWRmMjQzZTVmYWM5MmU4NDM1NjkyZjNiYWZmMzUxZTAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.n3nrJ4-I-pUjMz2YripGDHZtKc_P3hSlOFK7apFqVIA ## After https://github.com/user-attachments/assets/4877ca29-f900-48ea-ba3c-124f910d8cf3
This commit is contained in:
committed by
GitHub
parent
4c81d60dc7
commit
0b406042a1
@ -15,7 +15,7 @@ import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-sta
|
|||||||
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
|
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
|
||||||
import { css, useTheme } from '@emotion/react';
|
import { css, useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useCallback } from 'react';
|
import { useCallback, useId } from 'react';
|
||||||
import { isDefined, isValidUuid } from 'twenty-shared/utils';
|
import { isDefined, isValidUuid } from 'twenty-shared/utils';
|
||||||
import { IconChevronDown, IconForbid } from 'twenty-ui/display';
|
import { IconChevronDown, IconForbid } from 'twenty-ui/display';
|
||||||
|
|
||||||
@ -98,8 +98,9 @@ export const FormSingleRecordPicker = ({
|
|||||||
skip: !isDefined(defaultValue) || !isValidUuid(defaultValue),
|
skip: !isDefined(defaultValue) || !isValidUuid(defaultValue),
|
||||||
});
|
});
|
||||||
|
|
||||||
const dropdownId = `form-record-picker-${objectNameSingular}`;
|
const componentId = useId();
|
||||||
const variablesDropdownId = `form-record-picker-${objectNameSingular}-variables`;
|
const dropdownId = `form-record-picker-${componentId}`;
|
||||||
|
const variablesDropdownId = `form-record-picker-${componentId}-variables`;
|
||||||
|
|
||||||
const { closeDropdown } = useDropdown(dropdownId);
|
const { closeDropdown } = useDropdown(dropdownId);
|
||||||
|
|
||||||
|
|||||||
@ -41,9 +41,13 @@ export const Default: Story = {
|
|||||||
play: async ({ canvasElement }) => {
|
play: async ({ canvasElement }) => {
|
||||||
const canvas = within(canvasElement);
|
const canvas = within(canvasElement);
|
||||||
|
|
||||||
await canvas.findByText('Company');
|
const label = await canvas.findByText('Company');
|
||||||
|
expect(label).toBeVisible();
|
||||||
|
|
||||||
const dropdown = await canvas.findByRole('button');
|
const dropdown = await canvas.findByRole('button');
|
||||||
expect(dropdown).toBeVisible();
|
expect(dropdown).toBeVisible();
|
||||||
|
|
||||||
|
await userEvent.click(dropdown);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,15 @@
|
|||||||
import { WorkflowFormAction } from '@/workflow/types/Workflow';
|
import { WorkflowFormAction } from '@/workflow/types/Workflow';
|
||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
import { expect, within } from '@storybook/test';
|
import { expect, userEvent, waitFor, within } from '@storybook/test';
|
||||||
import { FieldMetadataType } from 'twenty-shared/types';
|
import { FieldMetadataType } from 'twenty-shared/types';
|
||||||
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
|
import {
|
||||||
|
ComponentDecorator,
|
||||||
|
getCanvasElementForDropdownTesting,
|
||||||
|
RouterDecorator,
|
||||||
|
} from 'twenty-ui/testing';
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/WorkflowStepActionDrawerDecorator';
|
import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/WorkflowStepActionDrawerDecorator';
|
||||||
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
||||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||||
@ -25,6 +30,7 @@ const meta: Meta<typeof WorkflowEditActionFormFiller> = {
|
|||||||
RouterDecorator,
|
RouterDecorator,
|
||||||
ObjectMetadataItemsDecorator,
|
ObjectMetadataItemsDecorator,
|
||||||
WorkspaceDecorator,
|
WorkspaceDecorator,
|
||||||
|
SnackBarDecorator,
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -81,6 +87,42 @@ const mockAction: WorkflowFormAction = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockActionWithDuplicatedRecordFields: WorkflowFormAction = {
|
||||||
|
id: 'form-action-1',
|
||||||
|
type: 'FORM',
|
||||||
|
name: 'Test Form',
|
||||||
|
valid: true,
|
||||||
|
settings: {
|
||||||
|
input: [
|
||||||
|
{
|
||||||
|
id: 'field-1',
|
||||||
|
name: 'record',
|
||||||
|
label: 'Record',
|
||||||
|
type: 'RECORD',
|
||||||
|
placeholder: 'Select a record',
|
||||||
|
settings: {
|
||||||
|
objectName: 'company',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'field-2',
|
||||||
|
name: 'record',
|
||||||
|
label: 'Record',
|
||||||
|
type: 'RECORD',
|
||||||
|
placeholder: 'Select a record',
|
||||||
|
settings: {
|
||||||
|
objectName: 'company',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
outputSchema: {},
|
||||||
|
errorHandlingOptions: {
|
||||||
|
retryOnFailure: { value: false },
|
||||||
|
continueOnFailure: { value: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
action: mockAction,
|
action: mockAction,
|
||||||
@ -124,7 +166,41 @@ export const ReadonlyMode: Story = {
|
|||||||
const dateInput = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
const dateInput = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||||
expect(dateInput).toBeDisabled();
|
expect(dateInput).toBeDisabled();
|
||||||
|
|
||||||
const submitButton = await canvas.queryByText('Submit');
|
const submitButton = canvas.queryByText('Submit');
|
||||||
expect(submitButton).not.toBeInTheDocument();
|
expect(submitButton).not.toBeInTheDocument();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const CanHaveManyRecordFieldsForTheSameRecordType: Story = {
|
||||||
|
args: {
|
||||||
|
action: mockActionWithDuplicatedRecordFields,
|
||||||
|
actionOptions: {
|
||||||
|
readonly: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
play: async ({ canvasElement }) => {
|
||||||
|
const canvas = within(canvasElement);
|
||||||
|
|
||||||
|
const recordSelects = await waitFor(() => {
|
||||||
|
const elements = canvas.getAllByText('Select a company');
|
||||||
|
|
||||||
|
expect(elements.length).toBe(2);
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const recordSelect of recordSelects) {
|
||||||
|
expect(recordSelect).toBeVisible();
|
||||||
|
|
||||||
|
await userEvent.click(recordSelect);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
within(getCanvasElementForDropdownTesting()).getByText('Louis Duss'),
|
||||||
|
).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
await userEvent.click(canvasElement);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user