From 8208a3e976bc499b0046bb1548f2e74156729167 Mon Sep 17 00:00:00 2001
From: "gitstart-app[bot]"
<57568882+gitstart-app[bot]@users.noreply.github.com>
Date: Mon, 16 Sep 2024 14:07:55 +0200
Subject: [PATCH] Introduce ARRAY field type (#6862)
This PR was created by \[GitStart\]() to address
the requirements from this ticket:
\[TWNTY-6447\]().
This ticket was imported from:
### Description
\- We added a new field type
### Refs
#6447
### Demo
Fixes #6447
---------
Co-authored-by: gitstart-twenty
Co-authored-by: Charles Bochet
---
.../src/generated-metadata/graphql.ts | 3 +-
.../twenty-front/src/generated/graphql.tsx | 1 +
...atFieldMetadataItemsAsFilterDefinitions.ts | 2 +
.../utils/mapFieldMetadataToGraphQLQuery.ts | 1 +
.../MultipleFiltersDropdownContent.tsx | 1 +
.../types/FilterType.ts | 3 +-
.../utils/getOperandsForFilterType.ts | 1 +
.../record-field/components/FieldDisplay.tsx | 4 ++
.../record-field/components/FieldInput.tsx | 4 ++
.../record-field/hooks/usePersistField.ts | 8 ++-
.../display/components/ArrayFieldDisplay.tsx | 34 ++++++++++
.../meta-types/hooks/useArrayField.ts | 44 +++++++++++++
.../meta-types/hooks/useArrayFieldDisplay.ts | 24 +++++++
.../input/components/ArrayFieldInput.tsx | 39 ++++++++++++
.../input/components/ArrayFieldMenuItem.tsx | 27 ++++++++
.../input/components/MultiItemFieldInput.tsx | 5 +-
.../components/MultiItemFieldMenuItem.tsx | 4 +-
.../record-field/types/FieldMetadata.ts | 11 +++-
.../types/guards/assertFieldMetadata.ts | 37 ++++++-----
.../record-field/types/guards/isFieldArray.ts | 9 +++
.../types/guards/isFieldArrayValue.ts | 8 +++
.../record-field/utils/getFieldButtonIcon.tsx | 2 +
.../record-field/utils/isFieldValueEmpty.ts | 5 +-
.../utils/generateEmptyFieldValue.ts | 3 +
.../constants/SettingsFieldTypeConfigs.ts | 7 +++
...SettingsDataModelFieldSettingsFormCard.tsx | 1 +
.../field/display/components/ArrayDisplay.tsx | 62 +++++++++++++++++++
.../link/components/RoundedLink.tsx | 2 +-
.../__mocks__/object-metadata-item.mock.ts | 8 +++
.../input/array-filter.input-type.ts | 10 +++
.../graphql-types/input/index.ts | 1 +
.../services/type-mapper.service.ts | 10 ++-
...p-field-metadata-to-graphql-query.utils.ts | 1 +
.../utils/__tests__/components.utils.spec.ts | 18 ++++++
.../open-api/utils/components.utils.ts | 10 ++-
.../field-metadata/field-metadata.entity.ts | 1 +
.../factories/basic-column-action.factory.ts | 6 +-
...field-metadata-type-to-column-type.util.ts | 1 +
.../workspace-migration.factory.ts | 1 +
.../display/icon/components/TablerIcons.ts | 1 +
40 files changed, 392 insertions(+), 28 deletions(-)
create mode 100644 packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/ArrayFieldDisplay.tsx
create mode 100644 packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useArrayField.ts
create mode 100644 packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useArrayFieldDisplay.ts
create mode 100644 packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/ArrayFieldInput.tsx
create mode 100644 packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/ArrayFieldMenuItem.tsx
create mode 100644 packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldArray.ts
create mode 100644 packages/twenty-front/src/modules/object-record/record-field/types/guards/isFieldArrayValue.ts
create mode 100644 packages/twenty-front/src/modules/ui/field/display/components/ArrayDisplay.tsx
create mode 100644 packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-types/input/array-filter.input-type.ts
diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts
index 18ef62e76..23d7caab7 100644
--- a/packages/twenty-front/src/generated-metadata/graphql.ts
+++ b/packages/twenty-front/src/generated-metadata/graphql.ts
@@ -376,7 +376,8 @@ export enum FieldMetadataType {
RichText = 'RICH_TEXT',
Select = 'SELECT',
Text = 'TEXT',
- Uuid = 'UUID'
+ Uuid = 'UUID',
+ Array = 'ARRAY'
}
export enum FileFolder {
diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx
index b96a53cbf..88b52322e 100644
--- a/packages/twenty-front/src/generated/graphql.tsx
+++ b/packages/twenty-front/src/generated/graphql.tsx
@@ -260,6 +260,7 @@ export type FieldConnection = {
export enum FieldMetadataType {
Actor = 'ACTOR',
Address = 'ADDRESS',
+ Array = 'ARRAY',
Boolean = 'BOOLEAN',
Currency = 'CURRENCY',
Date = 'DATE',
diff --git a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions.ts b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions.ts
index ea5adb09c..7ebeb0afe 100644
--- a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions.ts
+++ b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions.ts
@@ -98,6 +98,8 @@ export const getFilterTypeFromFieldType = (fieldType: FieldMetadataType) => {
return 'RATING';
case FieldMetadataType.Actor:
return 'ACTOR';
+ case FieldMetadataType.Array:
+ return 'ARRAY';
default:
return 'TEXT';
}
diff --git a/packages/twenty-front/src/modules/object-metadata/utils/mapFieldMetadataToGraphQLQuery.ts b/packages/twenty-front/src/modules/object-metadata/utils/mapFieldMetadataToGraphQLQuery.ts
index 11da8c73d..d379313a0 100644
--- a/packages/twenty-front/src/modules/object-metadata/utils/mapFieldMetadataToGraphQLQuery.ts
+++ b/packages/twenty-front/src/modules/object-metadata/utils/mapFieldMetadataToGraphQLQuery.ts
@@ -38,6 +38,7 @@ export const mapFieldMetadataToGraphQLQuery = ({
FieldMetadataType.Position,
FieldMetadataType.RawJson,
FieldMetadataType.RichText,
+ FieldMetadataType.Array,
].includes(fieldType);
if (fieldIsSimpleValue) {
diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx
index a735dc7fe..ec3df12f0 100644
--- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx
@@ -67,6 +67,7 @@ export const MultipleFiltersDropdownContent = ({
'LINKS',
'ADDRESS',
'ACTOR',
+ 'ARRAY',
'PHONES',
].includes(filterDefinitionUsedInDropdown.type) && (
diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/FilterType.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/FilterType.ts
index bc1c0489d..1803a88a5 100644
--- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/FilterType.ts
+++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/FilterType.ts
@@ -16,4 +16,5 @@ export type FilterType =
| 'SELECT'
| 'RATING'
| 'MULTI_SELECT'
- | 'ACTOR';
+ | 'ACTOR'
+ | 'ARRAY';
diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getOperandsForFilterType.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getOperandsForFilterType.ts
index 5b10825b4..f75dca40f 100644
--- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getOperandsForFilterType.ts
+++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/getOperandsForFilterType.ts
@@ -22,6 +22,7 @@ export const getOperandsForFilterType = (
case 'LINK':
case 'LINKS':
case 'ACTOR':
+ case 'ARRAY':
case 'PHONES':
return [
ViewFilterOperand.Contains,
diff --git a/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx
index 3f9297833..781ac98a6 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx
@@ -1,6 +1,7 @@
import { useContext } from 'react';
import { ActorFieldDisplay } from '@/object-record/record-field/meta-types/display/components/ActorFieldDisplay';
+import { ArrayFieldDisplay } from '@/object-record/record-field/meta-types/display/components/ArrayFieldDisplay';
import { BooleanFieldDisplay } from '@/object-record/record-field/meta-types/display/components/BooleanFieldDisplay';
import { EmailsFieldDisplay } from '@/object-record/record-field/meta-types/display/components/EmailsFieldDisplay';
import { LinksFieldDisplay } from '@/object-record/record-field/meta-types/display/components/LinksFieldDisplay';
@@ -10,6 +11,7 @@ import { RelationFromManyFieldDisplay } from '@/object-record/record-field/meta-
import { RichTextFieldDisplay } from '@/object-record/record-field/meta-types/display/components/RichTextFieldDisplay';
import { isFieldIdentifierDisplay } from '@/object-record/record-field/meta-types/display/utils/isFieldIdentifierDisplay';
import { isFieldActor } from '@/object-record/record-field/types/guards/isFieldActor';
+import { isFieldArray } from '@/object-record/record-field/types/guards/isFieldArray';
import { isFieldBoolean } from '@/object-record/record-field/types/guards/isFieldBoolean';
import { isFieldDisplayedAsPhone } from '@/object-record/record-field/types/guards/isFieldDisplayedAsPhone';
import { isFieldEmails } from '@/object-record/record-field/types/guards/isFieldEmails';
@@ -104,6 +106,8 @@ export const FieldDisplay = () => {
) : isFieldActor(fieldDefinition) ? (
+ ) : isFieldArray(fieldDefinition) ? (
+
) : isFieldEmails(fieldDefinition) ? (
) : isFieldPhones(fieldDefinition) ? (
diff --git a/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx
index 4e1537106..144a24a8b 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx
@@ -24,7 +24,9 @@ import { isFieldRelationToOneObject } from '@/object-record/record-field/types/g
import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect';
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
+import { ArrayFieldInput } from '@/object-record/record-field/meta-types/input/components/ArrayFieldInput';
import { RichTextFieldInput } from '@/object-record/record-field/meta-types/input/components/RichTextFieldInput';
+import { isFieldArray } from '@/object-record/record-field/types/guards/isFieldArray';
import { isFieldRichText } from '@/object-record/record-field/types/guards/isFieldRichText';
import { FieldContext } from '../contexts/FieldContext';
import { BooleanFieldInput } from '../meta-types/input/components/BooleanFieldInput';
@@ -187,6 +189,8 @@ export const FieldInput = ({
/>
) : isFieldRichText(fieldDefinition) ? (
+ ) : isFieldArray(fieldDefinition) ? (
+
) : (
<>>
)}
diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/usePersistField.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/usePersistField.ts
index 0d3344e12..0aa155a86 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/hooks/usePersistField.ts
+++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/usePersistField.ts
@@ -26,6 +26,8 @@ import { isFieldSelectValue } from '@/object-record/record-field/types/guards/is
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
+import { isFieldArray } from '@/object-record/record-field/types/guards/isFieldArray';
+import { isFieldArrayValue } from '@/object-record/record-field/types/guards/isFieldArrayValue';
import { FieldContext } from '../contexts/FieldContext';
import { isFieldBoolean } from '../types/guards/isFieldBoolean';
import { isFieldBooleanValue } from '../types/guards/isFieldBooleanValue';
@@ -124,6 +126,9 @@ export const usePersistField = () => {
isFieldRawJson(fieldDefinition) &&
isFieldRawJsonValue(valueToPersist);
+ const fieldIsArray =
+ isFieldArray(fieldDefinition) && isFieldArrayValue(valueToPersist);
+
const isValuePersistable =
fieldIsRelationToOneObject ||
fieldIsText ||
@@ -143,7 +148,8 @@ export const usePersistField = () => {
fieldIsSelect ||
fieldIsMultiSelect ||
fieldIsAddress ||
- fieldIsRawJson;
+ fieldIsRawJson ||
+ fieldIsArray;
if (isValuePersistable) {
const fieldName = fieldDefinition.metadata.fieldName;
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/ArrayFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/ArrayFieldDisplay.tsx
new file mode 100644
index 000000000..195d3bb87
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/ArrayFieldDisplay.tsx
@@ -0,0 +1,34 @@
+import { THEME_COMMON } from 'twenty-ui';
+
+import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus';
+import { useArrayFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useArrayFieldDisplay';
+import { ArrayDisplay } from '@/ui/field/display/components/ArrayDisplay';
+import styled from '@emotion/styled';
+
+const spacing1 = THEME_COMMON.spacing(1);
+
+const StyledContainer = styled.div`
+ align-items: center;
+ display: flex;
+ flex-wrap: wrap;
+ gap: ${spacing1};
+ justify-content: flex-start;
+ max-width: 100%;
+ overflow: hidden;
+`;
+
+export const ArrayFieldDisplay = () => {
+ const { fieldValue } = useArrayFieldDisplay();
+
+ const { isFocused } = useFieldFocus();
+
+ if (!Array.isArray(fieldValue)) {
+ return <>>;
+ }
+
+ return (
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useArrayField.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useArrayField.ts
new file mode 100644
index 000000000..7178d7aff
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useArrayField.ts
@@ -0,0 +1,44 @@
+import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
+import { usePersistField } from '@/object-record/record-field/hooks/usePersistField';
+import { FieldArrayValue } from '@/object-record/record-field/types/FieldMetadata';
+import { assertFieldMetadata } from '@/object-record/record-field/types/guards/assertFieldMetadata';
+import { isFieldArray } from '@/object-record/record-field/types/guards/isFieldArray';
+import { arraySchema } from '@/object-record/record-field/types/guards/isFieldArrayValue';
+import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
+import { useContext } from 'react';
+import { useRecoilState } from 'recoil';
+import { FieldMetadataType } from '~/generated-metadata/graphql';
+
+export const useArrayField = () => {
+ const { recordId, fieldDefinition, hotkeyScope } = useContext(FieldContext);
+
+ assertFieldMetadata(FieldMetadataType.Array, isFieldArray, fieldDefinition);
+
+ const fieldName = fieldDefinition.metadata.fieldName;
+
+ const [fieldValue, setFieldValue] = useRecoilState(
+ recordStoreFamilySelector({
+ recordId,
+ fieldName,
+ }),
+ );
+
+ const persistField = usePersistField();
+
+ const persistArrayField = (nextValue: string[]) => {
+ if (!nextValue) persistField(null);
+
+ try {
+ persistField(arraySchema.parse(nextValue));
+ } catch {
+ return;
+ }
+ };
+
+ return {
+ fieldValue,
+ setFieldValue,
+ persistArrayField,
+ hotkeyScope,
+ };
+};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useArrayFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useArrayFieldDisplay.ts
new file mode 100644
index 000000000..e735febeb
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useArrayFieldDisplay.ts
@@ -0,0 +1,24 @@
+import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
+import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
+import {
+ FieldArrayMetadata,
+ FieldArrayValue,
+} from '@/object-record/record-field/types/FieldMetadata';
+import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
+import { useContext } from 'react';
+
+export const useArrayFieldDisplay = () => {
+ const { recordId, fieldDefinition } = useContext(FieldContext);
+
+ const { fieldName } = fieldDefinition.metadata;
+
+ const fieldValue = useRecordFieldValue(
+ recordId,
+ fieldName,
+ );
+
+ return {
+ fieldDefinition: fieldDefinition as FieldDefinition,
+ fieldValue,
+ };
+};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/ArrayFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/ArrayFieldInput.tsx
new file mode 100644
index 000000000..2353f7d2f
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/ArrayFieldInput.tsx
@@ -0,0 +1,39 @@
+import { useArrayField } from '@/object-record/record-field/meta-types/hooks/useArrayField';
+import { ArrayFieldMenuItem } from '@/object-record/record-field/meta-types/input/components/ArrayFieldMenuItem';
+import { MultiItemFieldInput } from '@/object-record/record-field/meta-types/input/components/MultiItemFieldInput';
+import { useMemo } from 'react';
+import { FieldMetadataType } from '~/generated-metadata/graphql';
+
+type ArrayFieldInputProps = {
+ onCancel?: () => void;
+};
+
+export const ArrayFieldInput = ({ onCancel }: ArrayFieldInputProps) => {
+ const { persistArrayField, hotkeyScope, fieldValue } = useArrayField();
+
+ const arrayItems = useMemo>(
+ () => (Array.isArray(fieldValue) ? fieldValue : []),
+ [fieldValue],
+ );
+
+ return (
+ (
+
+ )}
+ >
+ );
+};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/ArrayFieldMenuItem.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/ArrayFieldMenuItem.tsx
new file mode 100644
index 000000000..cfe06add3
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/ArrayFieldMenuItem.tsx
@@ -0,0 +1,27 @@
+import { MultiItemFieldMenuItem } from '@/object-record/record-field/meta-types/input/components/MultiItemFieldMenuItem';
+import { ArrayDisplay } from '@/ui/field/display/components/ArrayDisplay';
+
+type ArrayFieldMenuItemProps = {
+ dropdownId: string;
+ onEdit?: () => void;
+ onDelete?: () => void;
+ value: string;
+};
+
+export const ArrayFieldMenuItem = ({
+ dropdownId,
+ onEdit,
+ onDelete,
+ value,
+}: ArrayFieldMenuItemProps) => {
+ return (
+ }
+ hasPrimaryButton={false}
+ />
+ );
+};
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldInput.tsx
index 4a5bcb5c7..a73e49498 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldInput.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldInput.tsx
@@ -40,10 +40,12 @@ type MultiItemFieldInputProps = {
handleDelete: () => void;
}) => React.ReactNode;
hotkeyScope: string;
+ newItemLabel?: string;
fieldMetadataType: FieldMetadataType;
renderInput?: DropdownMenuInputProps['renderInput'];
};
+// Todo: the API of this component does not look healthy: we have renderInput, renderItem, formatInput, ...
export const MultiItemFieldInput = ({
items,
onPersist,
@@ -53,6 +55,7 @@ export const MultiItemFieldInput = ({
formatInput,
renderItem,
hotkeyScope,
+ newItemLabel,
fieldMetadataType,
renderInput,
}: MultiItemFieldInputProps) => {
@@ -181,7 +184,7 @@ export const MultiItemFieldInput = ({
)}
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldMenuItem.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldMenuItem.tsx
index 95fcf4e5a..383b47121 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldMenuItem.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/MultiItemFieldMenuItem.tsx
@@ -21,6 +21,7 @@ type MultiItemFieldMenuItemProps = {
onSetAsPrimary?: () => void;
onDelete?: () => void;
DisplayComponent: React.ComponentType<{ value: T }>;
+ hasPrimaryButton?: boolean;
};
const StyledIconBookmark = styled(IconBookmark)`
@@ -37,6 +38,7 @@ export const MultiItemFieldMenuItem = ({
onSetAsPrimary,
onDelete,
DisplayComponent,
+ hasPrimaryButton = true,
}: MultiItemFieldMenuItemProps) => {
const [isHovered, setIsHovered] = useState(false);
const { isDropdownOpen, closeDropdown } = useDropdown(dropdownId);
@@ -74,7 +76,7 @@ export const MultiItemFieldMenuItem = ({
clickableComponent={iconButton}
dropdownComponents={
- {!isPrimary && (
+ {hasPrimaryButton && !isPrimary && (