@ -11,17 +11,17 @@ import { Field } from '~/generated-metadata/graphql';
|
||||
import { relationTypes } from '../constants/relationTypes';
|
||||
import { RelationType } from '../types/RelationType';
|
||||
|
||||
export type SettingsObjectFieldRelationFormValues = Partial<{
|
||||
field: Partial<Pick<Field, 'icon' | 'label'>>;
|
||||
export type SettingsObjectFieldRelationFormValues = {
|
||||
field: Pick<Field, 'icon' | 'label'>;
|
||||
objectMetadataId: string;
|
||||
type: RelationType;
|
||||
}>;
|
||||
};
|
||||
|
||||
type SettingsObjectFieldRelationFormProps = {
|
||||
disableFieldEdition?: boolean;
|
||||
disableRelationEdition?: boolean;
|
||||
onChange: (values: SettingsObjectFieldRelationFormValues) => void;
|
||||
values?: SettingsObjectFieldRelationFormValues;
|
||||
onChange: (values: Partial<SettingsObjectFieldRelationFormValues>) => void;
|
||||
values: SettingsObjectFieldRelationFormValues;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@ -61,7 +61,7 @@ export const SettingsObjectFieldRelationForm = ({
|
||||
useObjectMetadataItemForSettings();
|
||||
|
||||
const selectedObjectMetadataItem =
|
||||
(values?.objectMetadataId
|
||||
(values.objectMetadataId
|
||||
? findObjectMetadataItemById(values.objectMetadataId)
|
||||
: undefined) || objectMetadataItems[0];
|
||||
|
||||
@ -72,7 +72,7 @@ export const SettingsObjectFieldRelationForm = ({
|
||||
label="Relation type"
|
||||
dropdownScopeId="relation-type-select"
|
||||
disabled={disableRelationEdition}
|
||||
value={values?.type}
|
||||
value={values.type}
|
||||
options={Object.entries(relationTypes).map(
|
||||
([value, { label, Icon }]) => ({
|
||||
label,
|
||||
@ -86,7 +86,7 @@ export const SettingsObjectFieldRelationForm = ({
|
||||
label="Object destination"
|
||||
dropdownScopeId="object-destination-select"
|
||||
disabled={disableRelationEdition}
|
||||
value={values?.objectMetadataId}
|
||||
value={values.objectMetadataId}
|
||||
options={objectMetadataItems.map((objectMetadataItem) => ({
|
||||
label: objectMetadataItem.labelPlural,
|
||||
value: objectMetadataItem.id,
|
||||
@ -104,10 +104,10 @@ export const SettingsObjectFieldRelationForm = ({
|
||||
<IconPicker
|
||||
disabled={disableFieldEdition}
|
||||
dropdownScopeId="field-destination-icon-picker"
|
||||
selectedIconKey={values?.field?.icon || undefined}
|
||||
selectedIconKey={values.field.icon || undefined}
|
||||
onChange={(value) =>
|
||||
onChange({
|
||||
field: { ...values?.field, icon: value.iconKey },
|
||||
field: { ...values.field, icon: value.iconKey },
|
||||
})
|
||||
}
|
||||
variant="primary"
|
||||
@ -115,11 +115,11 @@ export const SettingsObjectFieldRelationForm = ({
|
||||
<TextInput
|
||||
disabled={disableFieldEdition}
|
||||
placeholder="Field name"
|
||||
value={values?.field?.label || ''}
|
||||
value={values.field.label}
|
||||
onChange={(value) => {
|
||||
if (!value || validateMetadataLabel(value)) {
|
||||
onChange({
|
||||
field: { ...values?.field, label: value },
|
||||
field: { ...values.field, label: value },
|
||||
});
|
||||
}
|
||||
}}
|
||||
|
||||
@ -4,17 +4,16 @@ import { IconPlus } from '@/ui/display/icon';
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
import { mainColors, ThemeColor } from '@/ui/theme/constants/colors';
|
||||
|
||||
import {
|
||||
SettingsObjectFieldSelectFormOption,
|
||||
SettingsObjectFieldSelectFormOptionRow,
|
||||
} from './SettingsObjectFieldSelectFormOptionRow';
|
||||
import { SettingsObjectFieldSelectFormOption } from '../types/SettingsObjectFieldSelectFormOption';
|
||||
|
||||
import { SettingsObjectFieldSelectFormOptionRow } from './SettingsObjectFieldSelectFormOptionRow';
|
||||
|
||||
export type SettingsObjectFieldSelectFormValues =
|
||||
SettingsObjectFieldSelectFormOption[];
|
||||
|
||||
type SettingsObjectFieldSelectFormProps = {
|
||||
onChange: (values: SettingsObjectFieldSelectFormValues) => void;
|
||||
values?: SettingsObjectFieldSelectFormValues;
|
||||
values: SettingsObjectFieldSelectFormValues;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@ -54,31 +53,38 @@ const getNextColor = (currentColor: ThemeColor) => {
|
||||
|
||||
export const SettingsObjectFieldSelectForm = ({
|
||||
onChange,
|
||||
values = [],
|
||||
values,
|
||||
}: SettingsObjectFieldSelectFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<StyledContainer>
|
||||
<StyledLabel>Options</StyledLabel>
|
||||
<StyledRows>
|
||||
{values.map((value, index) => (
|
||||
{values.map((option, index) => (
|
||||
<SettingsObjectFieldSelectFormOptionRow
|
||||
key={index}
|
||||
onChange={(optionValue) => {
|
||||
const nextValues = [...values];
|
||||
nextValues.splice(index, 1, optionValue);
|
||||
onChange(nextValues);
|
||||
isDefault={option.isDefault}
|
||||
onChange={(nextOption) => {
|
||||
const hasDefaultOptionChanged =
|
||||
!option.isDefault && nextOption.isDefault;
|
||||
const nextOptions = hasDefaultOptionChanged
|
||||
? values.map((value) => ({ ...value, isDefault: false }))
|
||||
: [...values];
|
||||
|
||||
nextOptions.splice(index, 1, nextOption);
|
||||
|
||||
onChange(nextOptions);
|
||||
}}
|
||||
onRemove={
|
||||
values.length > 1
|
||||
? () => {
|
||||
const nextValues = [...values];
|
||||
nextValues.splice(index, 1);
|
||||
onChange(nextValues);
|
||||
const nextOptions = [...values];
|
||||
nextOptions.splice(index, 1);
|
||||
onChange(nextOptions);
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
value={value}
|
||||
option={option}
|
||||
/>
|
||||
))}
|
||||
</StyledRows>
|
||||
@ -92,7 +98,7 @@ export const SettingsObjectFieldSelectForm = ({
|
||||
...values,
|
||||
{
|
||||
color: getNextColor(values[values.length - 1].color),
|
||||
text: `Option ${values.length + 1}`,
|
||||
label: `Option ${values.length + 1}`,
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
@ -2,7 +2,12 @@ import { useMemo } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { IconDotsVertical, IconTrash } from '@/ui/display/icon';
|
||||
import {
|
||||
IconCheck,
|
||||
IconDotsVertical,
|
||||
IconTrash,
|
||||
IconX,
|
||||
} from '@/ui/display/icon';
|
||||
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
@ -11,17 +16,14 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||
import { ThemeColor } from '@/ui/theme/constants/colors';
|
||||
|
||||
export type SettingsObjectFieldSelectFormOption = {
|
||||
color: ThemeColor;
|
||||
text: string;
|
||||
};
|
||||
import { SettingsObjectFieldSelectFormOption } from '../types/SettingsObjectFieldSelectFormOption';
|
||||
|
||||
type SettingsObjectFieldSelectFormOptionRowProps = {
|
||||
isDefault?: boolean;
|
||||
onChange: (value: SettingsObjectFieldSelectFormOption) => void;
|
||||
onRemove?: () => void;
|
||||
value: SettingsObjectFieldSelectFormOption;
|
||||
option: SettingsObjectFieldSelectFormOption;
|
||||
};
|
||||
|
||||
const StyledRow = styled.div`
|
||||
@ -41,9 +43,10 @@ const StyledOptionInput = styled(TextInput)`
|
||||
`;
|
||||
|
||||
export const SettingsObjectFieldSelectFormOptionRow = ({
|
||||
isDefault,
|
||||
onChange,
|
||||
onRemove,
|
||||
value,
|
||||
option,
|
||||
}: SettingsObjectFieldSelectFormOptionRowProps) => {
|
||||
const dropdownScopeId = useMemo(() => `select-field-option-row-${v4()}`, []);
|
||||
|
||||
@ -52,8 +55,9 @@ export const SettingsObjectFieldSelectFormOptionRow = ({
|
||||
return (
|
||||
<StyledRow>
|
||||
<StyledOptionInput
|
||||
value={value.text}
|
||||
onChange={(text) => onChange({ ...value, text })}
|
||||
value={option.label}
|
||||
onChange={(label) => onChange({ ...option, label })}
|
||||
RightIcon={isDefault ? IconCheck : undefined}
|
||||
/>
|
||||
<DropdownScope dropdownScopeId={dropdownScopeId}>
|
||||
<Dropdown
|
||||
@ -65,6 +69,25 @@ export const SettingsObjectFieldSelectFormOptionRow = ({
|
||||
dropdownComponents={
|
||||
<DropdownMenu>
|
||||
<DropdownMenuItemsContainer>
|
||||
{isDefault ? (
|
||||
<MenuItem
|
||||
LeftIcon={IconX}
|
||||
text="Remove as default"
|
||||
onClick={() => {
|
||||
onChange({ ...option, isDefault: false });
|
||||
closeDropdown();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<MenuItem
|
||||
LeftIcon={IconCheck}
|
||||
text="Set as default"
|
||||
onClick={() => {
|
||||
onChange({ ...option, isDefault: true });
|
||||
closeDropdown();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{!!onRemove && (
|
||||
<MenuItem
|
||||
accent="danger"
|
||||
|
||||
@ -22,18 +22,20 @@ import {
|
||||
} from './SettingsObjectFieldSelectForm';
|
||||
import { SettingsObjectFieldTypeCard } from './SettingsObjectFieldTypeCard';
|
||||
|
||||
export type SettingsObjectFieldTypeSelectSectionFormValues = Partial<{
|
||||
export type SettingsObjectFieldTypeSelectSectionFormValues = {
|
||||
type: FieldMetadataType;
|
||||
relation: SettingsObjectFieldRelationFormValues;
|
||||
select: SettingsObjectFieldSelectFormValues;
|
||||
}>;
|
||||
};
|
||||
|
||||
type SettingsObjectFieldTypeSelectSectionProps = {
|
||||
excludedFieldTypes?: FieldMetadataType[];
|
||||
fieldMetadata: Pick<Field, 'icon' | 'label'> & { id?: string };
|
||||
onChange: (values: SettingsObjectFieldTypeSelectSectionFormValues) => void;
|
||||
onChange: (
|
||||
values: Partial<SettingsObjectFieldTypeSelectSectionFormValues>,
|
||||
) => void;
|
||||
relationFieldMetadata?: Pick<Field, 'id' | 'isCustom'>;
|
||||
values?: SettingsObjectFieldTypeSelectSectionFormValues;
|
||||
values: SettingsObjectFieldTypeSelectSectionFormValues;
|
||||
} & Pick<SettingsObjectFieldPreviewProps, 'objectMetadataId'>;
|
||||
|
||||
const StyledSettingsObjectFieldTypeCard = styled(SettingsObjectFieldTypeCard)`
|
||||
@ -58,8 +60,8 @@ export const SettingsObjectFieldTypeSelectSection = ({
|
||||
relationFieldMetadata,
|
||||
values,
|
||||
}: SettingsObjectFieldTypeSelectSectionProps) => {
|
||||
const relationFormConfig = values?.relation;
|
||||
const selectFormConfig = values?.select;
|
||||
const relationFormConfig = values.relation;
|
||||
const selectFormConfig = values.select;
|
||||
|
||||
const fieldTypeOptions = Object.entries(settingsFieldMetadataTypes)
|
||||
.filter(([key]) => !excludedFieldTypes?.includes(key as FieldMetadataType))
|
||||
|
||||
@ -26,8 +26,10 @@ const defaultValues: FormValues = {
|
||||
type: FieldMetadataType.Text,
|
||||
relation: {
|
||||
type: RelationMetadataType.OneToMany,
|
||||
objectMetadataId: '',
|
||||
field: { label: '' },
|
||||
},
|
||||
select: [{ color: 'green', text: 'Option 1' }],
|
||||
select: [{ color: 'green', label: 'Option 1' }],
|
||||
};
|
||||
|
||||
const fieldSchema = z.object({
|
||||
@ -60,7 +62,8 @@ const selectSchema = fieldSchema.merge(
|
||||
color: z.enum(
|
||||
Object.keys(mainColors) as [ThemeColor, ...ThemeColor[]],
|
||||
),
|
||||
text: z.string().min(1),
|
||||
isDefault: z.boolean().optional(),
|
||||
label: z.string().min(1),
|
||||
}),
|
||||
)
|
||||
.nonempty(),
|
||||
@ -90,7 +93,7 @@ const schema = z.discriminatedUnion('type', [
|
||||
otherFieldTypesSchema,
|
||||
]);
|
||||
|
||||
type PartialFormValues = Partial<FormValues> &
|
||||
type PartialFormValues = Partial<Omit<FormValues, 'relation'>> &
|
||||
DeepPartial<Pick<FormValues, 'relation'>>;
|
||||
|
||||
export const useFieldMetadataForm = () => {
|
||||
|
||||
@ -2,8 +2,8 @@ import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObj
|
||||
import { useLazyLoadIcon } from '@/ui/input/hooks/useLazyLoadIcon';
|
||||
import { Field, FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
import { SettingsObjectFieldSelectFormValues } from '../components/SettingsObjectFieldSelectForm';
|
||||
import { settingsFieldMetadataTypes } from '../constants/settingsFieldMetadataTypes';
|
||||
import { SettingsObjectFieldSelectFormOption } from '../types/SettingsObjectFieldSelectFormOption';
|
||||
|
||||
import { useFieldPreviewValue } from './useFieldPreviewValue';
|
||||
import { useRelationFieldPreviewValue } from './useRelationFieldPreviewValue';
|
||||
@ -17,7 +17,7 @@ export const useFieldPreview = ({
|
||||
fieldMetadata: Pick<Field, 'icon' | 'label' | 'type'> & { id?: string };
|
||||
objectMetadataId: string;
|
||||
relationObjectMetadataId?: string;
|
||||
selectOptions?: SettingsObjectFieldSelectFormValues;
|
||||
selectOptions?: SettingsObjectFieldSelectFormOption[];
|
||||
}) => {
|
||||
const { findObjectMetadataItemById } = useObjectMetadataItemForSettings();
|
||||
const objectMetadataItem = findObjectMetadataItemById(objectMetadataId);
|
||||
@ -44,17 +44,16 @@ export const useFieldPreview = ({
|
||||
skip: fieldMetadata.type !== FieldMetadataType.Relation,
|
||||
});
|
||||
|
||||
const defaultValue =
|
||||
fieldMetadata.type === FieldMetadataType.Enum
|
||||
? selectOptions?.[0]
|
||||
: settingsFieldMetadataTypes[fieldMetadata.type].defaultValue;
|
||||
const { defaultValue } = settingsFieldMetadataTypes[fieldMetadata.type];
|
||||
|
||||
const isValidSelectValue =
|
||||
const defaultSelectValue = selectOptions?.[0];
|
||||
const selectValue =
|
||||
fieldMetadata.type === FieldMetadataType.Enum &&
|
||||
!!firstRecordFieldValue &&
|
||||
selectOptions?.some(
|
||||
(selectOption) => selectOption.text === firstRecordFieldValue,
|
||||
);
|
||||
typeof firstRecordFieldValue === 'string'
|
||||
? selectOptions?.find(
|
||||
(selectOption) => selectOption.value === firstRecordFieldValue,
|
||||
)
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
entityId: `${objectMetadataId}-field-form`,
|
||||
@ -64,10 +63,10 @@ export const useFieldPreview = ({
|
||||
objectMetadataItem,
|
||||
relationObjectMetadataItem,
|
||||
value:
|
||||
(fieldMetadata.type === FieldMetadataType.Relation
|
||||
fieldMetadata.type === FieldMetadataType.Relation
|
||||
? relationValue
|
||||
: fieldMetadata.type !== FieldMetadataType.Enum || isValidSelectValue
|
||||
? firstRecordFieldValue
|
||||
: undefined) || defaultValue,
|
||||
: fieldMetadata.type === FieldMetadataType.Enum
|
||||
? selectValue || defaultSelectValue
|
||||
: firstRecordFieldValue || defaultValue,
|
||||
};
|
||||
};
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
import { ThemeColor } from '@/ui/theme/constants/colors';
|
||||
|
||||
export type SettingsObjectFieldSelectFormOption = {
|
||||
color: ThemeColor;
|
||||
isDefault?: boolean;
|
||||
label: string;
|
||||
value?: string;
|
||||
};
|
||||
@ -13,6 +13,7 @@ import { Key } from 'ts-key-enum';
|
||||
|
||||
import { IconAlertCircle } from '@/ui/display/icon';
|
||||
import { IconEye, IconEyeOff } from '@/ui/display/icon/index';
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useCombinedRefs } from '~/hooks/useCombinedRefs';
|
||||
@ -29,6 +30,7 @@ export type TextInputComponentProps = Omit<
|
||||
fullWidth?: boolean;
|
||||
disableHotkeys?: boolean;
|
||||
error?: string;
|
||||
RightIcon?: IconComponent;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div<Pick<TextInputComponentProps, 'fullWidth'>>`
|
||||
@ -101,7 +103,7 @@ const StyledTrailingIconContainer = styled.div`
|
||||
const StyledTrailingIcon = styled.div`
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
cursor: pointer;
|
||||
cursor: ${({ onClick }) => (onClick ? 'pointer' : 'default')};
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
`;
|
||||
@ -125,6 +127,7 @@ const TextInputComponent = (
|
||||
placeholder,
|
||||
disabled,
|
||||
tabIndex,
|
||||
RightIcon,
|
||||
}: TextInputComponentProps,
|
||||
// eslint-disable-next-line twenty/component-props-naming
|
||||
ref: ForwardedRef<HTMLInputElement>,
|
||||
@ -201,6 +204,11 @@ const TextInputComponent = (
|
||||
)}
|
||||
</StyledTrailingIcon>
|
||||
)}
|
||||
{!error && type !== INPUT_TYPE_PASSWORD && !!RightIcon && (
|
||||
<StyledTrailingIcon>
|
||||
<RightIcon size={theme.icon.size.md} />
|
||||
</StyledTrailingIcon>
|
||||
)}
|
||||
</StyledTrailingIconContainer>
|
||||
</StyledInputContainer>
|
||||
{error && <StyledErrorHelper>{error}</StyledErrorHelper>}
|
||||
|
||||
@ -5,5 +5,5 @@ import { useSelectField } from '../../hooks/useSelectField';
|
||||
export const SelectFieldDisplay = () => {
|
||||
const { fieldValue } = useSelectField();
|
||||
|
||||
return <Tag color={fieldValue.color} text={fieldValue.text} />;
|
||||
return <Tag color={fieldValue.color} text={fieldValue.label} />;
|
||||
};
|
||||
|
||||
@ -26,15 +26,15 @@ export const useSelectField = () => {
|
||||
);
|
||||
const fieldSelectValue = isFieldSelectValue(fieldValue)
|
||||
? fieldValue
|
||||
: { color: 'green' as ThemeColor, text: '' };
|
||||
: { color: 'green' as ThemeColor, label: '' };
|
||||
|
||||
const fieldInitialValue = useFieldInitialValue();
|
||||
|
||||
const initialValue = {
|
||||
color: 'green' as ThemeColor,
|
||||
text: fieldInitialValue?.isEmpty
|
||||
label: fieldInitialValue?.isEmpty
|
||||
? ''
|
||||
: fieldInitialValue?.value ?? fieldSelectValue?.text ?? '',
|
||||
: fieldInitialValue?.value ?? fieldSelectValue?.label ?? '',
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@ -116,6 +116,6 @@ export type FieldCurrencyValue = {
|
||||
};
|
||||
export type FieldFullNameValue = { firstName: string; lastName: string };
|
||||
export type FieldProbabilityValue = number;
|
||||
export type FieldSelectValue = { color: ThemeColor; text: string };
|
||||
export type FieldSelectValue = { color: ThemeColor; label: string };
|
||||
|
||||
export type FieldRelationValue = EntityForSelect | null;
|
||||
|
||||
@ -5,7 +5,7 @@ import { mainColors, ThemeColor } from '@/ui/theme/constants/colors';
|
||||
const selectColors = Object.keys(mainColors) as [ThemeColor, ...ThemeColor[]];
|
||||
const selectValueSchema = z.object({
|
||||
color: z.enum(selectColors),
|
||||
text: z.string(),
|
||||
label: z.string(),
|
||||
});
|
||||
|
||||
export const isFieldSelectValue = (
|
||||
|
||||
@ -19,7 +19,10 @@ import { Button } from '@/ui/input/button/components/Button';
|
||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||
import { Section } from '@/ui/layout/section/components/Section';
|
||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import {
|
||||
FieldMetadataType,
|
||||
RelationMetadataType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const SettingsObjectFieldEdit = () => {
|
||||
const navigate = useNavigate();
|
||||
@ -70,10 +73,10 @@ export const SettingsObjectFieldEdit = () => {
|
||||
relation: {
|
||||
field: {
|
||||
icon: relationFieldMetadataItem?.icon,
|
||||
label: relationFieldMetadataItem?.label,
|
||||
label: relationFieldMetadataItem?.label || '',
|
||||
},
|
||||
objectMetadataId: relationObjectMetadataItem?.id,
|
||||
type: relationType,
|
||||
objectMetadataId: relationObjectMetadataItem?.id || '',
|
||||
type: relationType || RelationMetadataType.OneToMany,
|
||||
},
|
||||
});
|
||||
}, [
|
||||
|
||||
@ -54,7 +54,8 @@ export const SettingsObjectNewFieldStep2 = () => {
|
||||
initForm({
|
||||
relation: {
|
||||
field: { icon: activeObjectMetadataItem.icon },
|
||||
objectMetadataId: findObjectMetadataItemByNamePlural('people')?.id,
|
||||
objectMetadataId:
|
||||
findObjectMetadataItemByNamePlural('people')?.id || '',
|
||||
},
|
||||
});
|
||||
}, [
|
||||
|
||||
Reference in New Issue
Block a user