Settings Form Select refacto (#8875)

fixes #8751
This commit is contained in:
Guillim
2024-12-05 14:44:24 +01:00
committed by GitHub
parent 6c78cac908
commit 9ed9b4746a
8 changed files with 156 additions and 142 deletions

View File

@ -5,45 +5,31 @@ import {
StyledSettingsOptionCardTitle, StyledSettingsOptionCardTitle,
} from '@/settings/components/SettingsOptions/SettingsOptionCardContentBase'; } from '@/settings/components/SettingsOptions/SettingsOptionCardContentBase';
import { SettingsOptionIconCustomizer } from '@/settings/components/SettingsOptions/SettingsOptionIconCustomizer'; import { SettingsOptionIconCustomizer } from '@/settings/components/SettingsOptions/SettingsOptionIconCustomizer';
import { Select, SelectValue } from '@/ui/input/components/Select';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { IconComponent } from 'twenty-ui'; import { IconComponent } from 'twenty-ui';
type SettingsOptionCardContentSelectProps<Value extends SelectValue> = { type SettingsOptionCardContentSelectProps = {
Icon?: IconComponent; Icon?: IconComponent;
title: React.ReactNode; title: React.ReactNode;
description?: string; description?: string;
divider?: boolean; divider?: boolean;
disabled?: boolean; disabled?: boolean;
value: Value;
onChange: (value: Value) => void;
options: {
value: Value;
label: string;
Icon?: IconComponent;
}[];
selectClassName?: string; selectClassName?: string;
dropdownId: string; children?: React.ReactNode;
fullWidth?: boolean;
}; };
const StyledSelectContainer = styled.div` const StyledSelectContainer = styled.div`
margin-left: auto; margin-left: auto;
`; `;
export const SettingsOptionCardContentSelect = <Value extends SelectValue>({ export const SettingsOptionCardContentSelect = ({
Icon, Icon,
title, title,
description, description,
divider, divider,
disabled = false, disabled = false,
value, children,
onChange, }: SettingsOptionCardContentSelectProps) => {
options,
selectClassName,
dropdownId,
fullWidth,
}: SettingsOptionCardContentSelectProps<Value>) => {
return ( return (
<StyledSettingsOptionCardContent divider={divider} disabled={disabled}> <StyledSettingsOptionCardContent divider={divider} disabled={disabled}>
{Icon && ( {Icon && (
@ -57,18 +43,7 @@ export const SettingsOptionCardContentSelect = <Value extends SelectValue>({
{description} {description}
</StyledSettingsOptionCardDescription> </StyledSettingsOptionCardDescription>
</div> </div>
<StyledSelectContainer> <StyledSelectContainer>{children}</StyledSelectContainer>
<Select<Value>
className={selectClassName}
dropdownWidth={fullWidth ? 'auto' : 120}
disabled={disabled}
dropdownId={dropdownId}
value={value}
onChange={onChange}
options={options}
selectSizeVariant="small"
/>
</StyledSelectContainer>
</StyledSettingsOptionCardContent> </StyledSettingsOptionCardContent>
); );
}; };

View File

@ -1,4 +1,5 @@
import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect'; import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect';
import { Select, SelectValue } from '@/ui/input/components/Select';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { Meta, StoryObj } from '@storybook/react'; import { Meta, StoryObj } from '@storybook/react';
import { useState } from 'react'; import { useState } from 'react';
@ -16,28 +17,37 @@ const StyledContainer = styled.div`
width: 480px; width: 480px;
`; `;
type SelectValue = string | number | boolean | null; interface SettingsOptionCardContentSelectProps
extends React.ComponentProps<typeof SettingsOptionCardContentSelect> {}
interface SettingsOptionCardContentSelectWrapperProps
extends SettingsOptionCardContentSelectProps {
onChange: any;
options: any;
value: any;
dropdownId: string;
}
const SettingsOptionCardContentSelectWrapper = <Value extends SelectValue>( const SettingsOptionCardContentSelectWrapper = <Value extends SelectValue>(
args: React.ComponentProps<typeof SettingsOptionCardContentSelect<Value>>, args: SettingsOptionCardContentSelectWrapperProps,
) => { ) => {
const [value, setValue] = useState<Value>(args.value); const [value] = useState<Value>(args.value);
return ( return (
<StyledContainer> <StyledContainer>
<SettingsOptionCardContentSelect <SettingsOptionCardContentSelect
value={value}
onChange={(newValue) => setValue(newValue as Value)}
Icon={args.Icon} Icon={args.Icon}
title={args.title} title={args.title}
description={args.description} description={args.description}
divider={args.divider} >
disabled={args.disabled} <Select<Value>
options={args.options} value={value}
selectClassName={args.selectClassName} onChange={args.onChange}
dropdownId={args.dropdownId} dropdownId={args.dropdownId}
fullWidth={args.fullWidth} options={args.options}
selectSizeVariant="small"
dropdownWidth={120}
/> />
</SettingsOptionCardContentSelect>
</StyledContainer> </StyledContainer>
); );
}; };
@ -137,6 +147,5 @@ export const FullWidth: Story = {
}, },
], ],
dropdownId: 'full-width-select', dropdownId: 'full-width-select',
fullWidth: true,
}, },
}; };

View File

@ -4,11 +4,11 @@ import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { addressSchema as addressFieldDefaultValueSchema } from '@/object-record/record-field/types/guards/isFieldAddressValue'; import { addressSchema as addressFieldDefaultValueSchema } from '@/object-record/record-field/types/guards/isFieldAddressValue';
import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect'; import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect';
import { useCountries } from '@/ui/input/components/internal/hooks/useCountries'; import { useCountries } from '@/ui/input/components/internal/hooks/useCountries';
import { Select } from '@/ui/input/components/Select';
import { IconMap } from 'twenty-ui'; import { IconMap } from 'twenty-ui';
import { z } from 'zod'; import { z } from 'zod';
import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString'; import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString';
import { stripSimpleQuotesFromString } from '~/utils/string/stripSimpleQuotesFromString'; import { stripSimpleQuotesFromString } from '~/utils/string/stripSimpleQuotesFromString';
type SettingsDataModelFieldAddressFormProps = { type SettingsDataModelFieldAddressFormProps = {
disabled?: boolean; disabled?: boolean;
defaultCountry?: string; defaultCountry?: string;
@ -63,11 +63,15 @@ export const SettingsDataModelFieldAddressForm = ({
render={({ field: { onChange, value } }) => { render={({ field: { onChange, value } }) => {
const defaultCountry = value?.addressCountry || ''; const defaultCountry = value?.addressCountry || '';
return ( return (
<SettingsOptionCardContentSelect<string> <SettingsOptionCardContentSelect
Icon={IconMap} Icon={IconMap}
dropdownId="selectDefaultCountry"
title="Default Country" title="Default Country"
description="The default country for new addresses" description="The default country for new addresses"
>
<Select<string>
dropdownWidth={'auto'}
disabled={disabled}
dropdownId="selectDefaultCountry"
value={stripSimpleQuotesFromString(defaultCountry)} value={stripSimpleQuotesFromString(defaultCountry)}
onChange={(newCountry) => onChange={(newCountry) =>
onChange({ onChange({
@ -75,10 +79,10 @@ export const SettingsDataModelFieldAddressForm = ({
addressCountry: applySimpleQuotesToString(newCountry), addressCountry: applySimpleQuotesToString(newCountry),
}) })
} }
disabled={disabled}
options={countries} options={countries}
fullWidth={true} selectSizeVariant="small"
/> />
</SettingsOptionCardContentSelect>
); );
}} }}
/> />

View File

@ -5,6 +5,7 @@ import { z } from 'zod';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect'; import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect';
import { useBooleanSettingsFormInitialValues } from '@/settings/data-model/fields/forms/boolean/hooks/useBooleanSettingsFormInitialValues'; import { useBooleanSettingsFormInitialValues } from '@/settings/data-model/fields/forms/boolean/hooks/useBooleanSettingsFormInitialValues';
import { Select } from '@/ui/input/components/Select';
export const settingsDataModelFieldBooleanFormSchema = z.object({ export const settingsDataModelFieldBooleanFormSchema = z.object({
defaultValue: z.boolean(), defaultValue: z.boolean(),
@ -15,12 +16,10 @@ export type SettingsDataModelFieldBooleanFormValues = z.infer<
>; >;
type SettingsDataModelFieldBooleanFormProps = { type SettingsDataModelFieldBooleanFormProps = {
className?: string;
fieldMetadataItem: Pick<FieldMetadataItem, 'defaultValue'>; fieldMetadataItem: Pick<FieldMetadataItem, 'defaultValue'>;
}; };
export const SettingsDataModelFieldBooleanForm = ({ export const SettingsDataModelFieldBooleanForm = ({
className,
fieldMetadataItem, fieldMetadataItem,
}: SettingsDataModelFieldBooleanFormProps) => { }: SettingsDataModelFieldBooleanFormProps) => {
const { control } = useFormContext<SettingsDataModelFieldBooleanFormValues>(); const { control } = useFormContext<SettingsDataModelFieldBooleanFormValues>();
@ -39,10 +38,12 @@ export const SettingsDataModelFieldBooleanForm = ({
Icon={IconCheck} Icon={IconCheck}
title="Default Value" title="Default Value"
description="Select the default value for this boolean field" description="Select the default value for this boolean field"
>
<Select<boolean>
value={value} value={value}
onChange={onChange} onChange={onChange}
selectClassName={className}
dropdownId="object-field-default-value-select-boolean" dropdownId="object-field-default-value-select-boolean"
dropdownWidth={120}
options={[ options={[
{ {
value: true, value: true,
@ -55,7 +56,9 @@ export const SettingsDataModelFieldBooleanForm = ({
Icon: IconX, Icon: IconX,
}, },
]} ]}
selectSizeVariant="small"
/> />
</SettingsOptionCardContentSelect>
)} )}
/> />
); );

View File

@ -2,6 +2,7 @@ import { Controller, useFormContext } from 'react-hook-form';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect'; import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect';
import { Select } from '@/ui/input/components/Select';
import { IconTextWrap } from 'twenty-ui'; import { IconTextWrap } from 'twenty-ui';
import { z } from 'zod'; import { z } from 'zod';
@ -44,9 +45,11 @@ export const SettingsDataModelFieldTextForm = ({
<> <>
<SettingsOptionCardContentSelect <SettingsOptionCardContentSelect
Icon={IconTextWrap} Icon={IconTextWrap}
dropdownId="text-wrap"
title="Wrap on record pages" title="Wrap on record pages"
description="Display text on multiple lines" description="Display text on multiple lines"
>
<Select<number>
dropdownId="text-wrap"
value={displayedMaxRows} value={displayedMaxRows}
onChange={(value) => onChange({ displayedMaxRows: value })} onChange={(value) => onChange({ displayedMaxRows: value })}
disabled={disabled} disabled={disabled}
@ -72,7 +75,9 @@ export const SettingsDataModelFieldTextForm = ({
value: 99, value: 99,
}, },
]} ]}
selectSizeVariant="small"
/> />
</SettingsOptionCardContentSelect>
</> </>
); );
}} }}

View File

@ -6,6 +6,7 @@ import { currencyFieldDefaultValueSchema } from '@/object-record/record-field/va
import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect'; import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect';
import { SETTINGS_FIELD_CURRENCY_CODES } from '@/settings/data-model/constants/SettingsFieldCurrencyCodes'; import { SETTINGS_FIELD_CURRENCY_CODES } from '@/settings/data-model/constants/SettingsFieldCurrencyCodes';
import { useCurrencySettingsFormInitialValues } from '@/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues'; import { useCurrencySettingsFormInitialValues } from '@/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues';
import { Select } from '@/ui/input/components/Select';
import { IconCurrencyDollar } from 'twenty-ui'; import { IconCurrencyDollar } from 'twenty-ui';
import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString'; import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString';
@ -57,13 +58,17 @@ export const SettingsDataModelFieldCurrencyForm = ({
Icon={IconCurrencyDollar} Icon={IconCurrencyDollar}
title="Default Value" title="Default Value"
description="Choose the default currency that will apply" description="Choose the default currency that will apply"
>
<Select<string>
dropdownWidth={'auto'}
value={value} value={value}
onChange={onChange} onChange={onChange}
disabled={disabled} disabled={disabled}
fullWidth
dropdownId="object-field-default-value-select-currency" dropdownId="object-field-default-value-select-currency"
options={OPTIONS} options={OPTIONS}
selectSizeVariant="small"
/> />
</SettingsOptionCardContentSelect>
)} )}
/> />
</> </>

View File

@ -5,6 +5,7 @@ import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { numberFieldDefaultValueSchema } from '@/object-record/record-field/validation-schemas/numberFieldDefaultValueSchema'; import { numberFieldDefaultValueSchema } from '@/object-record/record-field/validation-schemas/numberFieldDefaultValueSchema';
import { SettingsOptionCardContentCounter } from '@/settings/components/SettingsOptions/SettingsOptionCardContentCounter'; import { SettingsOptionCardContentCounter } from '@/settings/components/SettingsOptions/SettingsOptionCardContentCounter';
import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect'; import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect';
import { Select } from '@/ui/input/components/Select';
import { IconDecimal, IconEye, IconNumber9, IconPercentage } from 'twenty-ui'; import { IconDecimal, IconEye, IconNumber9, IconPercentage } from 'twenty-ui';
import { DEFAULT_DECIMAL_VALUE } from '~/utils/format/number'; import { DEFAULT_DECIMAL_VALUE } from '~/utils/format/number';
@ -47,9 +48,13 @@ export const SettingsDataModelFieldNumberForm = ({
<> <>
<SettingsOptionCardContentSelect <SettingsOptionCardContentSelect
Icon={IconEye} Icon={IconEye}
dropdownId="number-type"
title="Number type" title="Number type"
description="Display as a plain number or a percentage" description="Display as a plain number or a percentage"
>
<Select<string>
selectSizeVariant="small"
dropdownId="number-type"
dropdownWidth={120}
value={type} value={type}
onChange={(value) => onChange({ type: value, decimals: count })} onChange={(value) => onChange({ type: value, decimals: count })}
disabled={disabled} disabled={disabled}
@ -66,6 +71,7 @@ export const SettingsDataModelFieldNumberForm = ({
}, },
]} ]}
/> />
</SettingsOptionCardContentSelect>
<SettingsOptionCardContentCounter <SettingsOptionCardContentCounter
Icon={IconDecimal} Icon={IconDecimal}
title="Number of decimals" title="Number of decimals"

View File

@ -4,6 +4,7 @@ import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { phonesSchema as phonesFieldDefaultValueSchema } from '@/object-record/record-field/types/guards/isFieldPhonesValue'; import { phonesSchema as phonesFieldDefaultValueSchema } from '@/object-record/record-field/types/guards/isFieldPhonesValue';
import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect'; import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect';
import { useCountries } from '@/ui/input/components/internal/hooks/useCountries'; import { useCountries } from '@/ui/input/components/internal/hooks/useCountries';
import { Select } from '@/ui/input/components/Select';
import { IconMap } from 'twenty-ui'; import { IconMap } from 'twenty-ui';
import { z } from 'zod'; import { z } from 'zod';
import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString'; import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString';
@ -56,12 +57,17 @@ export const SettingsDataModelFieldPhonesForm = ({
control={control} control={control}
render={({ field: { onChange, value } }) => { render={({ field: { onChange, value } }) => {
return ( return (
<SettingsOptionCardContentSelect<string> <SettingsOptionCardContentSelect
Icon={IconMap} Icon={IconMap}
dropdownId="selectDefaultCountryCode"
title="Default Country Code" title="Default Country Code"
description="The default country code for new phone numbers." description="The default country code for new phone numbers."
value={stripSimpleQuotesFromString(value?.primaryPhoneCountryCode)} >
<Select<string>
dropdownWidth={'auto'}
dropdownId="selectDefaultCountryCode"
value={stripSimpleQuotesFromString(
value?.primaryPhoneCountryCode,
)}
onChange={(newPhoneCountryCode) => onChange={(newPhoneCountryCode) =>
onChange({ onChange({
...value, ...value,
@ -71,8 +77,9 @@ export const SettingsDataModelFieldPhonesForm = ({
} }
disabled={disabled} disabled={disabled}
options={countries} options={countries}
fullWidth={true} selectSizeVariant="small"
/> />
</SettingsOptionCardContentSelect>
); );
}} }}
/> />