fix: reset default value on field type switch in Settings/Data Model … (#5436)
…field form Closes #5412
This commit is contained in:
@ -1,82 +0,0 @@
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import styled from '@emotion/styled';
|
||||
import { IconCheck, IconX } from 'twenty-ui';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
import { CardContent } from '@/ui/layout/card/components/CardContent';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
// TODO: rename to SettingsDataModelFieldBooleanForm and move to settings/data-model/fields/forms/components
|
||||
|
||||
export const settingsDataModelFieldBooleanFormSchema = z.object({
|
||||
defaultValue: z.boolean(),
|
||||
});
|
||||
|
||||
type SettingsDataModelFieldBooleanFormValues = z.infer<
|
||||
typeof settingsDataModelFieldBooleanFormSchema
|
||||
>;
|
||||
|
||||
type SettingsDataModelFieldBooleanFormProps = {
|
||||
className?: string;
|
||||
fieldMetadataItem?: Pick<FieldMetadataItem, 'defaultValue'>;
|
||||
};
|
||||
|
||||
const StyledContainer = styled(CardContent)`
|
||||
padding-bottom: ${({ theme }) => theme.spacing(3.5)};
|
||||
`;
|
||||
|
||||
const StyledLabel = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
display: block;
|
||||
font-size: ${({ theme }) => theme.font.size.xs};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
margin-bottom: 6px;
|
||||
margin-top: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
export const SettingsDataModelFieldBooleanForm = ({
|
||||
className,
|
||||
fieldMetadataItem,
|
||||
}: SettingsDataModelFieldBooleanFormProps) => {
|
||||
const { control } = useFormContext<SettingsDataModelFieldBooleanFormValues>();
|
||||
|
||||
const isEditMode = isDefined(fieldMetadataItem?.defaultValue);
|
||||
const initialValue = fieldMetadataItem?.defaultValue ?? true;
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledLabel>Default Value</StyledLabel>
|
||||
<Controller
|
||||
name="defaultValue"
|
||||
control={control}
|
||||
defaultValue={initialValue}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Select
|
||||
className={className}
|
||||
fullWidth
|
||||
// TODO: temporary fix - disabling edition because after editing the defaultValue,
|
||||
// newly created records are not taking into account the updated defaultValue properly.
|
||||
disabled={isEditMode}
|
||||
dropdownId="object-field-default-value-select"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
options={[
|
||||
{
|
||||
value: true,
|
||||
label: 'True',
|
||||
Icon: IconCheck,
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
label: 'False',
|
||||
Icon: IconX,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
@ -1,175 +0,0 @@
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import styled from '@emotion/styled';
|
||||
import { useIcons } from 'twenty-ui';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { isObjectMetadataAvailableForRelation } from '@/object-metadata/utils/isObjectMetadataAvailableForRelation';
|
||||
import { fieldMetadataItemSchema } from '@/object-metadata/validation-schemas/fieldMetadataItemSchema';
|
||||
import { useRelationSettingsFormInitialValues } from '@/settings/data-model/fields/forms/hooks/useRelationSettingsFormInitialValues';
|
||||
import { IconPicker } from '@/ui/input/components/IconPicker';
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
|
||||
import { RELATION_TYPES } from '../constants/RelationTypes';
|
||||
import { RelationType } from '../types/RelationType';
|
||||
|
||||
// TODO: rename to SettingsDataModelFieldRelationForm and move to settings/data-model/fields/forms/components
|
||||
|
||||
export const settingsDataModelFieldRelationFormSchema = z.object({
|
||||
relation: z.object({
|
||||
field: fieldMetadataItemSchema.pick({
|
||||
icon: true,
|
||||
label: true,
|
||||
}),
|
||||
objectMetadataId: z.string().uuid(),
|
||||
type: z.enum(
|
||||
Object.keys(RELATION_TYPES) as [RelationType, ...RelationType[]],
|
||||
),
|
||||
}),
|
||||
});
|
||||
|
||||
export type SettingsDataModelFieldRelationFormValues = z.infer<
|
||||
typeof settingsDataModelFieldRelationFormSchema
|
||||
>;
|
||||
|
||||
type SettingsDataModelFieldRelationFormProps = {
|
||||
fieldMetadataItem?: Pick<
|
||||
FieldMetadataItem,
|
||||
'fromRelationMetadata' | 'toRelationMetadata' | 'type'
|
||||
>;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
padding: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledSelectsContainer = styled.div`
|
||||
display: grid;
|
||||
gap: ${({ theme }) => theme.spacing(4)};
|
||||
grid-template-columns: 1fr 1fr;
|
||||
margin-bottom: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledInputsLabel = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
display: block;
|
||||
font-size: ${({ theme }) => theme.font.size.xs};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
margin-bottom: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledInputsContainer = styled.div`
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const RELATION_TYPE_OPTIONS = Object.entries(RELATION_TYPES)
|
||||
.filter(([value]) => 'ONE_TO_ONE' !== value)
|
||||
.map(([value, { label, Icon }]) => ({
|
||||
label,
|
||||
value: value as RelationType,
|
||||
Icon,
|
||||
}));
|
||||
|
||||
export const SettingsDataModelFieldRelationForm = ({
|
||||
fieldMetadataItem,
|
||||
}: SettingsDataModelFieldRelationFormProps) => {
|
||||
const { control, watch: watchFormValue } =
|
||||
useFormContext<SettingsDataModelFieldRelationFormValues>();
|
||||
const { getIcon } = useIcons();
|
||||
const { objectMetadataItems, findObjectMetadataItemById } =
|
||||
useFilteredObjectMetadataItems();
|
||||
|
||||
const {
|
||||
disableFieldEdition,
|
||||
disableRelationEdition,
|
||||
initialRelationFieldMetadataItem,
|
||||
initialRelationObjectMetadataItem,
|
||||
initialRelationType,
|
||||
} = useRelationSettingsFormInitialValues({ fieldMetadataItem });
|
||||
|
||||
const selectedObjectMetadataItem = findObjectMetadataItemById(
|
||||
watchFormValue('relation.objectMetadataId'),
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledSelectsContainer>
|
||||
<Controller
|
||||
name="relation.type"
|
||||
control={control}
|
||||
defaultValue={initialRelationType}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Select
|
||||
label="Relation type"
|
||||
dropdownId="relation-type-select"
|
||||
fullWidth
|
||||
disabled={disableRelationEdition}
|
||||
value={value}
|
||||
options={RELATION_TYPE_OPTIONS}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="relation.objectMetadataId"
|
||||
control={control}
|
||||
defaultValue={initialRelationObjectMetadataItem.id}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Select
|
||||
label="Object destination"
|
||||
dropdownId="object-destination-select"
|
||||
fullWidth
|
||||
disabled={disableRelationEdition}
|
||||
value={value}
|
||||
options={objectMetadataItems
|
||||
.filter(isObjectMetadataAvailableForRelation)
|
||||
.map((objectMetadataItem) => ({
|
||||
label: objectMetadataItem.labelPlural,
|
||||
value: objectMetadataItem.id,
|
||||
Icon: getIcon(objectMetadataItem.icon),
|
||||
}))}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</StyledSelectsContainer>
|
||||
<StyledInputsLabel>
|
||||
Field on {selectedObjectMetadataItem?.labelPlural}
|
||||
</StyledInputsLabel>
|
||||
<StyledInputsContainer>
|
||||
<Controller
|
||||
name="relation.field.icon"
|
||||
control={control}
|
||||
defaultValue={initialRelationFieldMetadataItem.icon}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<IconPicker
|
||||
disabled={disableFieldEdition}
|
||||
dropdownId="field-destination-icon-picker"
|
||||
selectedIconKey={value ?? undefined}
|
||||
onChange={({ iconKey }) => onChange(iconKey)}
|
||||
variant="primary"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="relation.field.label"
|
||||
control={control}
|
||||
defaultValue={initialRelationFieldMetadataItem.label}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextInput
|
||||
disabled={disableFieldEdition}
|
||||
placeholder="Field name"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</StyledInputsContainer>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
@ -1,259 +0,0 @@
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import styled from '@emotion/styled';
|
||||
import { DropResult } from '@hello-pangea/dnd';
|
||||
import { IconPlus } from 'twenty-ui';
|
||||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
FieldMetadataItem,
|
||||
FieldMetadataItemOption,
|
||||
} from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { selectOptionsSchema } from '@/object-metadata/validation-schemas/selectOptionsSchema';
|
||||
import { useSelectSettingsFormInitialValues } from '@/settings/data-model/fields/forms/hooks/useSelectSettingsFormInitialValues';
|
||||
import { generateNewSelectOption } from '@/settings/data-model/fields/forms/utils/generateNewSelectOption';
|
||||
import { isSelectOptionDefaultValue } from '@/settings/data-model/utils/isSelectOptionDefaultValue';
|
||||
import { LightButton } from '@/ui/input/button/components/LightButton';
|
||||
import { CardContent } from '@/ui/layout/card/components/CardContent';
|
||||
import { CardFooter } from '@/ui/layout/card/components/CardFooter';
|
||||
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';
|
||||
import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { moveArrayItem } from '~/utils/array/moveArrayItem';
|
||||
import { toSpliced } from '~/utils/array/toSpliced';
|
||||
import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToString';
|
||||
import { simpleQuotesStringSchema } from '~/utils/validation-schemas/simpleQuotesStringSchema';
|
||||
|
||||
import { SettingsObjectFieldSelectFormOptionRow } from './SettingsObjectFieldSelectFormOptionRow';
|
||||
|
||||
// TODO: rename to SettingsDataModelFieldSelectForm and move to settings/data-model/fields/forms/components
|
||||
|
||||
export const settingsDataModelFieldSelectFormSchema = z.object({
|
||||
defaultValue: simpleQuotesStringSchema.nullable(),
|
||||
options: selectOptionsSchema,
|
||||
});
|
||||
|
||||
export const settingsDataModelFieldMultiSelectFormSchema = z.object({
|
||||
defaultValue: z.array(simpleQuotesStringSchema).nullable(),
|
||||
options: selectOptionsSchema,
|
||||
});
|
||||
|
||||
const selectOrMultiSelectFormSchema = z.union([
|
||||
settingsDataModelFieldSelectFormSchema,
|
||||
settingsDataModelFieldMultiSelectFormSchema,
|
||||
]);
|
||||
|
||||
export type SettingsDataModelFieldSelectFormValues = z.infer<
|
||||
typeof selectOrMultiSelectFormSchema
|
||||
>;
|
||||
|
||||
type SettingsDataModelFieldSelectFormProps = {
|
||||
fieldMetadataItem: Pick<
|
||||
FieldMetadataItem,
|
||||
'defaultValue' | 'options' | 'type'
|
||||
>;
|
||||
};
|
||||
|
||||
const StyledContainer = styled(CardContent)`
|
||||
padding-bottom: ${({ theme }) => theme.spacing(3.5)};
|
||||
`;
|
||||
|
||||
const StyledLabel = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
display: block;
|
||||
font-size: ${({ theme }) => theme.font.size.xs};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
margin-bottom: 6px;
|
||||
margin-top: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledFooter = styled(CardFooter)`
|
||||
background-color: ${({ theme }) => theme.background.secondary};
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledButton = styled(LightButton)`
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const SettingsDataModelFieldSelectForm = ({
|
||||
fieldMetadataItem,
|
||||
}: SettingsDataModelFieldSelectFormProps) => {
|
||||
const { initialDefaultValue, initialOptions } =
|
||||
useSelectSettingsFormInitialValues({ fieldMetadataItem });
|
||||
|
||||
const {
|
||||
control,
|
||||
setValue: setFormValue,
|
||||
watch: watchFormValue,
|
||||
getValues,
|
||||
} = useFormContext<SettingsDataModelFieldSelectFormValues>();
|
||||
|
||||
const handleDragEnd = (
|
||||
values: FieldMetadataItemOption[],
|
||||
result: DropResult,
|
||||
onChange: (options: FieldMetadataItemOption[]) => void,
|
||||
) => {
|
||||
if (!result.destination) return;
|
||||
|
||||
const nextOptions = moveArrayItem(values, {
|
||||
fromIndex: result.source.index,
|
||||
toIndex: result.destination.index,
|
||||
}).map((option, index) => ({ ...option, position: index }));
|
||||
|
||||
onChange(nextOptions);
|
||||
};
|
||||
|
||||
const isOptionDefaultValue = (
|
||||
optionValue: FieldMetadataItemOption['value'],
|
||||
) =>
|
||||
isSelectOptionDefaultValue(optionValue, {
|
||||
type: fieldMetadataItem.type,
|
||||
defaultValue: watchFormValue('defaultValue'),
|
||||
});
|
||||
|
||||
const handleSetOptionAsDefault = (
|
||||
optionValue: FieldMetadataItemOption['value'],
|
||||
) => {
|
||||
if (isOptionDefaultValue(optionValue)) return;
|
||||
|
||||
if (fieldMetadataItem.type === FieldMetadataType.Select) {
|
||||
setFormValue('defaultValue', applySimpleQuotesToString(optionValue), {
|
||||
shouldDirty: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const previousDefaultValue = getValues('defaultValue');
|
||||
|
||||
if (
|
||||
fieldMetadataItem.type === FieldMetadataType.MultiSelect &&
|
||||
(Array.isArray(previousDefaultValue) || previousDefaultValue === null)
|
||||
) {
|
||||
setFormValue(
|
||||
'defaultValue',
|
||||
[
|
||||
...(previousDefaultValue ?? []),
|
||||
applySimpleQuotesToString(optionValue),
|
||||
],
|
||||
{ shouldDirty: true },
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveOptionAsDefault = (
|
||||
optionValue: FieldMetadataItemOption['value'],
|
||||
) => {
|
||||
if (!isOptionDefaultValue(optionValue)) return;
|
||||
|
||||
if (fieldMetadataItem.type === FieldMetadataType.Select) {
|
||||
setFormValue('defaultValue', null, { shouldDirty: true });
|
||||
return;
|
||||
}
|
||||
|
||||
const previousDefaultValue = getValues('defaultValue');
|
||||
|
||||
if (
|
||||
fieldMetadataItem.type === FieldMetadataType.MultiSelect &&
|
||||
(Array.isArray(previousDefaultValue) || previousDefaultValue === null)
|
||||
) {
|
||||
const nextDefaultValue = previousDefaultValue?.filter(
|
||||
(value) => value !== applySimpleQuotesToString(optionValue),
|
||||
);
|
||||
setFormValue(
|
||||
'defaultValue',
|
||||
nextDefaultValue?.length ? nextDefaultValue : null,
|
||||
{ shouldDirty: true },
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Controller
|
||||
name="defaultValue"
|
||||
control={control}
|
||||
defaultValue={initialDefaultValue}
|
||||
render={() => <></>}
|
||||
/>
|
||||
<Controller
|
||||
name="options"
|
||||
control={control}
|
||||
defaultValue={initialOptions}
|
||||
render={({ field: { onChange, value: options } }) => (
|
||||
<>
|
||||
<StyledContainer>
|
||||
<StyledLabel>Options</StyledLabel>
|
||||
<DraggableList
|
||||
onDragEnd={(result) => handleDragEnd(options, result, onChange)}
|
||||
draggableItems={
|
||||
<>
|
||||
{options.map((option, index) => (
|
||||
<DraggableItem
|
||||
key={option.id}
|
||||
draggableId={option.id}
|
||||
index={index}
|
||||
isDragDisabled={options.length === 1}
|
||||
itemComponent={
|
||||
<SettingsObjectFieldSelectFormOptionRow
|
||||
key={option.id}
|
||||
option={option}
|
||||
onChange={(nextOption) => {
|
||||
const nextOptions = toSpliced(
|
||||
options,
|
||||
index,
|
||||
1,
|
||||
nextOption,
|
||||
);
|
||||
onChange(nextOptions);
|
||||
|
||||
// Update option value in defaultValue if value has changed
|
||||
if (
|
||||
nextOption.value !== option.value &&
|
||||
isOptionDefaultValue(option.value)
|
||||
) {
|
||||
handleRemoveOptionAsDefault(option.value);
|
||||
handleSetOptionAsDefault(nextOption.value);
|
||||
}
|
||||
}}
|
||||
onRemove={() => {
|
||||
const nextOptions = toSpliced(
|
||||
options,
|
||||
index,
|
||||
1,
|
||||
).map((option, nextOptionIndex) => ({
|
||||
...option,
|
||||
position: nextOptionIndex,
|
||||
}));
|
||||
onChange(nextOptions);
|
||||
}}
|
||||
isDefault={isOptionDefaultValue(option.value)}
|
||||
onSetAsDefault={() =>
|
||||
handleSetOptionAsDefault(option.value)
|
||||
}
|
||||
onRemoveAsDefault={() =>
|
||||
handleRemoveOptionAsDefault(option.value)
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</StyledContainer>
|
||||
<StyledFooter>
|
||||
<StyledButton
|
||||
title="Add option"
|
||||
Icon={IconPlus}
|
||||
onClick={() =>
|
||||
onChange([...options, generateNewSelectOption(options)])
|
||||
}
|
||||
/>
|
||||
</StyledFooter>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -1,164 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import {
|
||||
IconCheck,
|
||||
IconDotsVertical,
|
||||
IconGripVertical,
|
||||
IconTrash,
|
||||
IconX,
|
||||
} from 'twenty-ui';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/utils/getOptionValueFromLabel';
|
||||
import { ColorSample } from '@/ui/display/color/components/ColorSample';
|
||||
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||
import { MenuItemSelectColor } from '@/ui/navigation/menu-item/components/MenuItemSelectColor';
|
||||
import { MAIN_COLOR_NAMES } from '@/ui/theme/constants/MainColorNames';
|
||||
|
||||
type SettingsObjectFieldSelectFormOptionRowProps = {
|
||||
className?: string;
|
||||
isDefault?: boolean;
|
||||
onChange: (value: FieldMetadataItemOption) => void;
|
||||
onRemove?: () => void;
|
||||
onSetAsDefault?: () => void;
|
||||
onRemoveAsDefault?: () => void;
|
||||
option: FieldMetadataItemOption;
|
||||
};
|
||||
|
||||
const StyledRow = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: ${({ theme }) => theme.spacing(6)};
|
||||
padding: ${({ theme }) => theme.spacing(1.5)} 0;
|
||||
`;
|
||||
|
||||
const StyledColorSample = styled(ColorSample)`
|
||||
cursor: pointer;
|
||||
margin-left: 9px;
|
||||
margin-right: 14px;
|
||||
`;
|
||||
|
||||
const StyledOptionInput = styled(TextInput)`
|
||||
flex: 1 0 auto;
|
||||
margin-right: ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
& input {
|
||||
height: ${({ theme }) => theme.spacing(6)};
|
||||
}
|
||||
`;
|
||||
|
||||
export const SettingsObjectFieldSelectFormOptionRow = ({
|
||||
className,
|
||||
isDefault,
|
||||
onChange,
|
||||
onRemove,
|
||||
onSetAsDefault,
|
||||
onRemoveAsDefault,
|
||||
option,
|
||||
}: SettingsObjectFieldSelectFormOptionRowProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const dropdownIds = useMemo(() => {
|
||||
const baseScopeId = `select-field-option-row-${v4()}`;
|
||||
return { color: `${baseScopeId}-color`, actions: `${baseScopeId}-actions` };
|
||||
}, []);
|
||||
|
||||
const { closeDropdown: closeColorDropdown } = useDropdown(dropdownIds.color);
|
||||
const { closeDropdown: closeActionsDropdown } = useDropdown(
|
||||
dropdownIds.actions,
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledRow className={className}>
|
||||
<IconGripVertical
|
||||
size={theme.icon.size.md}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
color={theme.font.color.extraLight}
|
||||
/>
|
||||
<Dropdown
|
||||
dropdownId={dropdownIds.color}
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownHotkeyScope={{
|
||||
scope: dropdownIds.color,
|
||||
}}
|
||||
clickableComponent={<StyledColorSample colorName={option.color} />}
|
||||
dropdownComponents={
|
||||
<DropdownMenu>
|
||||
<DropdownMenuItemsContainer>
|
||||
{MAIN_COLOR_NAMES.map((colorName) => (
|
||||
<MenuItemSelectColor
|
||||
key={colorName}
|
||||
onClick={() => {
|
||||
onChange({ ...option, color: colorName });
|
||||
closeColorDropdown();
|
||||
}}
|
||||
color={colorName}
|
||||
selected={colorName === option.color}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
}
|
||||
/>
|
||||
<StyledOptionInput
|
||||
value={option.label}
|
||||
onChange={(label) =>
|
||||
onChange({ ...option, label, value: getOptionValueFromLabel(label) })
|
||||
}
|
||||
RightIcon={isDefault ? IconCheck : undefined}
|
||||
/>
|
||||
<Dropdown
|
||||
dropdownId={dropdownIds.actions}
|
||||
dropdownPlacement="right-start"
|
||||
dropdownHotkeyScope={{
|
||||
scope: dropdownIds.actions,
|
||||
}}
|
||||
clickableComponent={<LightIconButton Icon={IconDotsVertical} />}
|
||||
dropdownComponents={
|
||||
<DropdownMenu>
|
||||
<DropdownMenuItemsContainer>
|
||||
{isDefault ? (
|
||||
<MenuItem
|
||||
LeftIcon={IconX}
|
||||
text="Remove as default"
|
||||
onClick={() => {
|
||||
onRemoveAsDefault?.();
|
||||
closeActionsDropdown();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<MenuItem
|
||||
LeftIcon={IconCheck}
|
||||
text="Set as default"
|
||||
onClick={() => {
|
||||
onSetAsDefault?.();
|
||||
closeActionsDropdown();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{!!onRemove && !isDefault && (
|
||||
<MenuItem
|
||||
accent="danger"
|
||||
LeftIcon={IconTrash}
|
||||
text="Remove option"
|
||||
onClick={() => {
|
||||
onRemove();
|
||||
closeActionsDropdown();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
}
|
||||
/>
|
||||
</StyledRow>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user