Redirect to select option creation when no result (#14460)

fix:Ability to add a new option for a multi-select on the fly 
Issues:#13877

---------

Co-authored-by: ehconitin <nitinkoche03@gmail.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
ANIMESH DUTTA
2025-10-07 20:09:48 +05:30
committed by GitHub
parent 2445668e96
commit 9c8e0f628e
13 changed files with 242 additions and 17 deletions
@@ -0,0 +1,37 @@
import { t } from '@lingui/core/macro';
import { isNonEmptyString } from '@sniptt/guards';
import { isDefined } from 'twenty-shared/utils';
import { IconPlus } from 'twenty-ui/display';
import { MenuItem } from 'twenty-ui/navigation';
type AddSelectOptionMenuItemProps = {
name: string;
onAddSelectOption?: (optionName: string) => void;
};
export const AddSelectOptionMenuItem = ({
name,
onAddSelectOption,
}: AddSelectOptionMenuItemProps) => {
const trimmedName = name.trim();
const showAddOption =
isNonEmptyString(trimmedName) && isDefined(onAddSelectOption);
const handleClick = () => {
if (isDefined(onAddSelectOption)) {
onAddSelectOption(trimmedName);
}
};
if (!showAddOption) {
return null;
}
return (
<MenuItem
onClick={handleClick}
LeftIcon={IconPlus}
text={t`Add "${trimmedName}" to options`}
/>
);
};
@@ -20,7 +20,10 @@ import { applySimpleQuotesToString } from '~/utils/string/applySimpleQuotesToStr
import { AdvancedSettingsWrapper } from '@/settings/components/AdvancedSettingsWrapper';
import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState';
import { t } from '@lingui/core/macro';
import { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { IconPlus, IconPoint } from 'twenty-ui/display';
import { LightButton } from 'twenty-ui/input';
import { CardContent, CardFooter } from 'twenty-ui/layout';
@@ -114,8 +117,11 @@ export const SettingsDataModelFieldSelectForm = ({
useSelectSettingsFormInitialValues({
fieldMetadataId: existingFieldMetadataId,
});
const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState);
const [searchParams] = useSearchParams();
const {
control,
setValue: setFormValue,
@@ -123,6 +129,21 @@ export const SettingsDataModelFieldSelectForm = ({
getValues,
} = useFormContext<SettingsDataModelFieldSelectFormValues>();
const [hasAppliedNewOption, setHasAppliedNewOption] = useState(false);
useEffect(() => {
const newOptionValue = searchParams.get('newOption');
if (isDefined(newOptionValue) && !hasAppliedNewOption) {
const newOption = generateNewSelectOption(initialOptions, newOptionValue);
const optionsWithNew = [...initialOptions, newOption];
setFormValue('options', optionsWithNew, { shouldDirty: true });
setHasAppliedNewOption(true);
}
}, [searchParams, hasAppliedNewOption, initialOptions, setFormValue]);
const handleDragEnd = (
values: FieldMetadataItemOption[],
result: DropResult,
@@ -7,9 +7,9 @@ import { computeOptionValueFromLabel } from '~/pages/settings/data-model/utils/c
export const generateNewSelectOption = (
options: FieldMetadataItemOption[],
label?: string,
): FieldMetadataItemOption => {
const newOptionLabel = generateNewSelectOptionLabel(options);
const newOptionLabel = label ?? generateNewSelectOptionLabel(options);
return {
color: getNextThemeColor(options[options.length - 1]?.color),
id: v4(),