feat: add New Field Step 2 form (#2138)

Closes #2001

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Thaïs
2023-10-21 13:28:15 +02:00
committed by GitHub
parent c90cf1eb8f
commit 34bbbdff41
15 changed files with 367 additions and 34 deletions

View File

@ -0,0 +1,64 @@
import styled from '@emotion/styled';
import { H2Title } from '@/ui/display/typography/components/H2Title';
import { IconPicker } from '@/ui/input/components/IconPicker';
import { TextArea } from '@/ui/input/components/TextArea';
import { TextInput } from '@/ui/input/components/TextInput';
import { Section } from '@/ui/layout/section/components/Section';
type SettingsObjectFieldFormSectionProps = {
disabled?: boolean;
name?: string;
description?: string;
iconKey?: string;
onChange?: (
formValues: Partial<{
iconKey: string;
name: string;
description: string;
}>,
) => void;
};
const StyledInputsContainer = styled.div`
display: flex;
gap: ${({ theme }) => theme.spacing(2)};
margin-bottom: ${({ theme }) => theme.spacing(2)};
width: 100%;
`;
export const SettingsObjectFieldFormSection = ({
disabled,
name = '',
description = '',
iconKey = 'IconUsers',
onChange,
}: SettingsObjectFieldFormSectionProps) => (
<Section>
<H2Title
title="Name and description"
description="The name and description of this field"
/>
<StyledInputsContainer>
<IconPicker
selectedIconKey={iconKey}
onChange={(value) => onChange?.({ iconKey: value.iconKey })}
variant="primary"
/>
<TextInput
placeholder="Employees"
value={name}
onChange={(value) => onChange?.({ name: value })}
disabled={disabled}
fullWidth
/>
</StyledInputsContainer>
<TextArea
placeholder="Write a description"
minRows={4}
value={description}
onChange={(value) => onChange?.({ description: value })}
disabled={disabled}
/>
</Section>
);

View File

@ -0,0 +1,32 @@
import { H2Title } from '@/ui/display/typography/components/H2Title';
import { Select } from '@/ui/input/components/Select';
import { Section } from '@/ui/layout/section/components/Section';
import { dataTypes } from '../constants/dataTypes';
import { ObjectFieldDataType } from '../types/ObjectFieldDataType';
type SettingsObjectFieldTypeSelectSectionProps = {
type: ObjectFieldDataType;
onChange: (value: ObjectFieldDataType) => void;
};
export const SettingsObjectFieldTypeSelectSection = ({
type,
onChange,
}: SettingsObjectFieldTypeSelectSectionProps) => (
<Section>
<H2Title
title="Type and values"
description="The field's type and values."
/>
<Select
dropdownScopeId="object-field-type-select"
value={type}
onChange={onChange}
options={Object.entries(dataTypes).map(([key, dataType]) => ({
value: key as ObjectFieldDataType,
...dataType,
}))}
/>
</Section>
);

View File

@ -26,10 +26,6 @@ const StyledInputsContainer = styled.div`
width: 100%;
`;
const StyledTextInput = styled(TextInput)`
flex: 1 0 auto;
`;
export const SettingsObjectFormSection = ({
disabled,
singularName = '',
@ -43,19 +39,21 @@ export const SettingsObjectFormSection = ({
description="Name in both singular (e.g., 'Invoice') and plural (e.g., 'Invoices') forms."
/>
<StyledInputsContainer>
<StyledTextInput
<TextInput
label="Singular"
placeholder="Investor"
value={singularName}
onChange={(value) => onChange?.({ singularName: value })}
disabled={disabled}
fullWidth
/>
<StyledTextInput
<TextInput
label="Plural"
placeholder="Investors"
value={pluralName}
onChange={(value) => onChange?.({ pluralName: value })}
disabled={disabled}
fullWidth
/>
</StyledInputsContainer>
<TextArea

View File

@ -0,0 +1,24 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { SettingsObjectFieldFormSection } from '../SettingsObjectFieldFormSection';
const meta: Meta<typeof SettingsObjectFieldFormSection> = {
title: 'Modules/Settings/DataModel/SettingsObjectFieldFormSection',
component: SettingsObjectFieldFormSection,
decorators: [ComponentDecorator],
};
export default meta;
type Story = StoryObj<typeof SettingsObjectFieldFormSection>;
export const Default: Story = {};
export const WithDefaultValues: Story = {
args: {
iconKey: 'IconLink',
name: 'URL',
description: 'Lorem ipsum',
},
};

View File

@ -0,0 +1,28 @@
import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { SettingsObjectFieldTypeSelectSection } from '../SettingsObjectFieldTypeSelectSection';
const meta: Meta<typeof SettingsObjectFieldTypeSelectSection> = {
title: 'Modules/Settings/DataModel/SettingsObjectFieldTypeSelectSection',
component: SettingsObjectFieldTypeSelectSection,
decorators: [ComponentDecorator],
args: { type: 'number' },
};
export default meta;
type Story = StoryObj<typeof SettingsObjectFieldTypeSelectSection>;
export const Default: Story = {};
export const WithOpenSelect: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const selectLabel = canvas.getByText('Number');
await userEvent.click(selectLabel);
},
};

View File

@ -0,0 +1,25 @@
import {
IconCheck,
IconLink,
IconNumbers,
IconPlug,
IconSocial,
IconTextSize,
IconUserCircle,
} from '@/ui/display/icon';
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { ObjectFieldDataType } from '../types/ObjectFieldDataType';
export const dataTypes: Record<
ObjectFieldDataType,
{ label: string; Icon: IconComponent }
> = {
number: { label: 'Number', Icon: IconNumbers },
text: { label: 'Text', Icon: IconTextSize },
link: { label: 'Link', Icon: IconLink },
teammate: { label: 'Team member', Icon: IconUserCircle },
boolean: { label: 'True/False', Icon: IconCheck },
relation: { label: 'Relation', Icon: IconPlug },
social: { label: 'Social', Icon: IconSocial },
};

View File

@ -1,16 +1,7 @@
import { css, useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import {
IconCheck,
IconLink,
IconNumbers,
IconPlug,
IconSocial,
IconUserCircle,
} from '@/ui/display/icon';
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { dataTypes } from '../../constants/dataTypes';
import { ObjectFieldDataType } from '../../types/ObjectFieldDataType';
const StyledDataType = styled.div<{ value: ObjectFieldDataType }>`
@ -32,18 +23,6 @@ const StyledDataType = styled.div<{ value: ObjectFieldDataType }>`
: ''}
`;
const dataTypes: Record<
ObjectFieldDataType,
{ label: string; Icon: IconComponent }
> = {
boolean: { label: 'True/False', Icon: IconCheck },
number: { label: 'Number', Icon: IconNumbers },
relation: { label: 'Relation', Icon: IconPlug },
social: { label: 'Social', Icon: IconSocial },
teammate: { label: 'Teammate', Icon: IconUserCircle },
text: { label: 'Text', Icon: IconLink },
};
type SettingsObjectFieldDataTypeProps = {
value: ObjectFieldDataType;
};

View File

@ -1,5 +1,6 @@
export type ObjectFieldDataType =
| 'boolean'
| 'link'
| 'number'
| 'relation'
| 'social'