545 replace objects icons and names with records avatars and labelidentifiers in command menu context chips (#10787)
Closes https://github.com/twentyhq/core-team-issues/issues/545 This PR: - Introduces `commandMenuNavigationMorphItemsState` which stores the information about the `recordId` and the `objectMetadataItemId` for each page - Creates `CommandMenuContextChipEffect`, which queries the records from the previous pages in case a record has been updated during the navigation, to keep up to date information and stores it inside `commandMenuNavigationRecordsState` - `useCommandMenuContextChips` returns the context chips information - Style updates (icons background and color) - Updates `useCommandMenu` to set and reset these new states https://github.com/user-attachments/assets/8886848a-721d-4709-9330-8e84ebc0d51e
This commit is contained in:
@ -47,6 +47,7 @@ export const CommandMenuContextChipGroupsWithRecordSelection = ({
|
||||
),
|
||||
Icons: Avatars,
|
||||
onClick: contextChips.length > 0 ? openRootCommandMenu : undefined,
|
||||
withIconBackground: false,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
|
||||
@ -0,0 +1,117 @@
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
import { commandMenuNavigationRecordsState } from '@/command-menu/states/commandMenuNavigationRecordsState';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode';
|
||||
import { usePerformCombinedFindManyRecords } from '@/object-record/multiple-objects/hooks/usePerformCombinedFindManyRecords';
|
||||
import { isNonEmptyArray } from '@sniptt/guards';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { capitalize, isDefined } from 'twenty-shared';
|
||||
|
||||
export const CommandMenuContextChipRecordSetterEffect = () => {
|
||||
const commandMenuNavigationMorphItemByPage = useRecoilValue(
|
||||
commandMenuNavigationMorphItemByPageState,
|
||||
);
|
||||
|
||||
const setCommandMenuNavigationRecords = useSetRecoilState(
|
||||
commandMenuNavigationRecordsState,
|
||||
);
|
||||
|
||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||
|
||||
const { performCombinedFindManyRecords } =
|
||||
usePerformCombinedFindManyRecords();
|
||||
|
||||
const objectMetadataIdsUsedInCommandMenuNavigation = Array.from(
|
||||
commandMenuNavigationMorphItemByPage.values(),
|
||||
).map(({ objectMetadataId }) => objectMetadataId);
|
||||
|
||||
const searchableObjectMetadataItems = objectMetadataItems.filter(({ id }) =>
|
||||
objectMetadataIdsUsedInCommandMenuNavigation.includes(id),
|
||||
);
|
||||
|
||||
const commandMenuNavigationStack = useRecoilValue(
|
||||
commandMenuNavigationStackState,
|
||||
);
|
||||
|
||||
const fetchRecords = useCallback(async () => {
|
||||
const filterPerMetadataItemFilteredOnRecordId = Object.fromEntries(
|
||||
searchableObjectMetadataItems
|
||||
.map(({ id, nameSingular }) => {
|
||||
const recordIdsForMetadataItem = Array.from(
|
||||
commandMenuNavigationMorphItemByPage.values(),
|
||||
)
|
||||
.filter(({ objectMetadataId }) => objectMetadataId === id)
|
||||
.map(({ recordId }) => recordId);
|
||||
|
||||
if (!isNonEmptyArray(recordIdsForMetadataItem)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
`filter${capitalize(nameSingular)}`,
|
||||
{
|
||||
id: {
|
||||
in: recordIdsForMetadataItem,
|
||||
},
|
||||
},
|
||||
];
|
||||
})
|
||||
.filter(isDefined),
|
||||
);
|
||||
|
||||
const operationSignatures = searchableObjectMetadataItems
|
||||
.filter(({ nameSingular }) =>
|
||||
isDefined(
|
||||
filterPerMetadataItemFilteredOnRecordId[
|
||||
`filter${capitalize(nameSingular)}`
|
||||
],
|
||||
),
|
||||
)
|
||||
.map((objectMetadataItem) => ({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
variables: {
|
||||
filter:
|
||||
filterPerMetadataItemFilteredOnRecordId[
|
||||
`filter${capitalize(objectMetadataItem.nameSingular)}`
|
||||
],
|
||||
},
|
||||
}));
|
||||
|
||||
if (operationSignatures.length === 0) {
|
||||
setCommandMenuNavigationRecords([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const { result } = await performCombinedFindManyRecords({
|
||||
operationSignatures,
|
||||
});
|
||||
|
||||
const formattedRecords = Object.entries(result).flatMap(
|
||||
([objectNamePlural, records]) =>
|
||||
records.map((record) => ({
|
||||
objectMetadataItem: searchableObjectMetadataItems.find(
|
||||
({ namePlural }) => namePlural === objectNamePlural,
|
||||
) as ObjectMetadataItem,
|
||||
record: record as RecordGqlNode,
|
||||
})),
|
||||
);
|
||||
|
||||
setCommandMenuNavigationRecords(formattedRecords);
|
||||
}, [
|
||||
commandMenuNavigationMorphItemByPage,
|
||||
performCombinedFindManyRecords,
|
||||
searchableObjectMetadataItems,
|
||||
setCommandMenuNavigationRecords,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (commandMenuNavigationStack.length > 1) {
|
||||
fetchRecords();
|
||||
}
|
||||
}, [commandMenuNavigationStack.length, fetchRecords]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@ -32,7 +32,6 @@ export const CommandMenuContextRecordChipAvatars = ({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
record,
|
||||
});
|
||||
|
||||
const { Icon, IconColor } = useGetStandardObjectIcon(
|
||||
objectMetadataItem.nameSingular,
|
||||
);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { CommandMenuContainer } from '@/command-menu/components/CommandMenuContainer';
|
||||
import { CommandMenuContextChipRecordSetterEffect } from '@/command-menu/components/CommandMenuContextChipRecordSetterEffect';
|
||||
import { CommandMenuTopBar } from '@/command-menu/components/CommandMenuTopBar';
|
||||
import { COMMAND_MENU_PAGES_CONFIG } from '@/command-menu/constants/CommandMenuPagesConfig';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
@ -30,6 +31,7 @@ export const CommandMenuRouter = () => {
|
||||
|
||||
return (
|
||||
<CommandMenuContainer>
|
||||
<CommandMenuContextChipRecordSetterEffect />
|
||||
<CommandMenuPageComponentInstanceContext.Provider
|
||||
value={{ instanceId: commandMenuPageInfo.instanceId }}
|
||||
>
|
||||
|
||||
@ -5,7 +5,7 @@ import { CommandMenuTopBarInputFocusEffect } from '@/command-menu/components/Com
|
||||
import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/CommandMenuSearchBarHeight';
|
||||
import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { useCommandMenuContextChips } from '@/command-menu/hooks/useCommandMenuContextChips';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
@ -16,7 +16,7 @@ import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useRef } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
@ -100,11 +100,7 @@ export const CommandMenuTopBar = () => {
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const {
|
||||
closeCommandMenu,
|
||||
goBackFromCommandMenu,
|
||||
navigateCommandMenuHistory,
|
||||
} = useCommandMenu();
|
||||
const { closeCommandMenu, goBackFromCommandMenu } = useCommandMenu();
|
||||
|
||||
const contextStoreCurrentObjectMetadataItem = useRecoilComponentValueV2(
|
||||
contextStoreCurrentObjectMetadataItemComponentState,
|
||||
@ -112,42 +108,13 @@ export const CommandMenuTopBar = () => {
|
||||
|
||||
const commandMenuPage = useRecoilValue(commandMenuPageState);
|
||||
|
||||
const commandMenuNavigationStack = useRecoilValue(
|
||||
commandMenuNavigationStackState,
|
||||
);
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IsCommandMenuV2Enabled,
|
||||
);
|
||||
|
||||
const contextChips = useMemo(() => {
|
||||
const filteredCommandMenuNavigationStack =
|
||||
commandMenuNavigationStack.filter(
|
||||
(page) => page.page !== CommandMenuPages.Root,
|
||||
);
|
||||
|
||||
return filteredCommandMenuNavigationStack.map((page, index) => {
|
||||
const isLastChip =
|
||||
index === filteredCommandMenuNavigationStack.length - 1;
|
||||
|
||||
return {
|
||||
page,
|
||||
Icons: [<page.pageIcon size={theme.icon.size.sm} />],
|
||||
text: page.pageTitle,
|
||||
onClick: isLastChip
|
||||
? undefined
|
||||
: () => {
|
||||
navigateCommandMenuHistory(index);
|
||||
},
|
||||
};
|
||||
});
|
||||
}, [
|
||||
commandMenuNavigationStack,
|
||||
navigateCommandMenuHistory,
|
||||
theme.icon.size.sm,
|
||||
]);
|
||||
const { contextChips } = useCommandMenuContextChips();
|
||||
|
||||
const location = useLocation();
|
||||
const isButtonVisible =
|
||||
|
||||
@ -24,6 +24,8 @@ import { useResetContextStoreStates } from '@/command-menu/hooks/useResetContext
|
||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||
import { viewableRecordNameSingularComponentState } from '@/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState';
|
||||
import { workflowIdComponentState } from '@/command-menu/pages/workflow/states/workflowIdComponentState';
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
import { commandMenuNavigationRecordsState } from '@/command-menu/states/commandMenuNavigationRecordsState';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
@ -38,10 +40,12 @@ import { contextStoreFiltersComponentState } from '@/context-store/states/contex
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { getIconColorForObjectType } from '@/object-metadata/utils/getIconColorForObjectType';
|
||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { emitRightDrawerCloseEvent } from '@/ui/layout/right-drawer/utils/emitRightDrawerCloseEvent';
|
||||
import { isDragSelectionStartEnabledState } from '@/ui/utilities/drag-select/states/internal/isDragSelectionStartEnabledState';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useCallback } from 'react';
|
||||
import { capitalize, isDefined } from 'twenty-shared';
|
||||
@ -52,6 +56,7 @@ export type CommandMenuNavigationStackItem = {
|
||||
page: CommandMenuPages;
|
||||
pageTitle: string;
|
||||
pageIcon: IconComponent;
|
||||
pageIconColor?: string;
|
||||
pageId?: string;
|
||||
};
|
||||
|
||||
@ -68,6 +73,8 @@ export const useCommandMenu = () => {
|
||||
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const closeCommandMenu = useRecoilCallback(
|
||||
({ set }) =>
|
||||
() => {
|
||||
@ -95,6 +102,8 @@ export const useCommandMenu = () => {
|
||||
});
|
||||
set(isCommandMenuOpenedState, false);
|
||||
set(commandMenuSearchState, '');
|
||||
set(commandMenuNavigationMorphItemByPageState, new Map());
|
||||
set(commandMenuNavigationRecordsState, []);
|
||||
set(commandMenuNavigationStackState, []);
|
||||
resetSelectedItem();
|
||||
set(hasUserSelectedCommandState, false);
|
||||
@ -154,6 +163,7 @@ export const useCommandMenu = () => {
|
||||
page,
|
||||
pageTitle,
|
||||
pageIcon,
|
||||
pageIconColor,
|
||||
pageId,
|
||||
resetNavigationStack = false,
|
||||
}: CommandMenuNavigationStackItem & {
|
||||
@ -185,9 +195,13 @@ export const useCommandMenu = () => {
|
||||
page,
|
||||
pageTitle,
|
||||
pageIcon,
|
||||
pageIconColor,
|
||||
pageId,
|
||||
},
|
||||
]);
|
||||
|
||||
set(commandMenuNavigationRecordsState, []);
|
||||
set(commandMenuNavigationMorphItemByPageState, new Map());
|
||||
} else {
|
||||
set(commandMenuNavigationStackState, [
|
||||
...currentNavigationStack,
|
||||
@ -195,6 +209,7 @@ export const useCommandMenu = () => {
|
||||
page,
|
||||
pageTitle,
|
||||
pageIcon,
|
||||
pageIconColor,
|
||||
pageId,
|
||||
},
|
||||
]);
|
||||
@ -255,6 +270,21 @@ export const useCommandMenu = () => {
|
||||
});
|
||||
|
||||
set(commandMenuNavigationStackState, newNavigationStack);
|
||||
|
||||
const currentMorphItems = snapshot
|
||||
.getLoadable(commandMenuNavigationMorphItemByPageState)
|
||||
.getValue();
|
||||
|
||||
if (currentNavigationStack.length > 0) {
|
||||
const removedItem = currentNavigationStack.at(-1);
|
||||
|
||||
if (isDefined(removedItem)) {
|
||||
const newMorphItems = new Map(currentMorphItems);
|
||||
newMorphItems.delete(removedItem.pageId);
|
||||
set(commandMenuNavigationMorphItemByPageState, newMorphItems);
|
||||
}
|
||||
}
|
||||
|
||||
set(hasUserSelectedCommandState, false);
|
||||
};
|
||||
},
|
||||
@ -285,6 +315,17 @@ export const useCommandMenu = () => {
|
||||
Icon: newNavigationStackItem?.pageIcon,
|
||||
instanceId: newNavigationStackItem?.pageId,
|
||||
});
|
||||
const currentMorphItems = snapshot
|
||||
.getLoadable(commandMenuNavigationMorphItemByPageState)
|
||||
.getValue();
|
||||
|
||||
const newMorphItems = new Map(
|
||||
Array.from(currentMorphItems.entries()).filter(([pageId]) =>
|
||||
newNavigationStack.some((item) => item.pageId === pageId),
|
||||
),
|
||||
);
|
||||
|
||||
set(commandMenuNavigationMorphItemByPageState, newMorphItems);
|
||||
|
||||
set(hasUserSelectedCommandState, false);
|
||||
};
|
||||
@ -376,10 +417,31 @@ export const useCommandMenu = () => {
|
||||
.getValue(),
|
||||
);
|
||||
|
||||
const currentMorphItems = snapshot
|
||||
.getLoadable(commandMenuNavigationMorphItemByPageState)
|
||||
.getValue();
|
||||
|
||||
const morphItemToAdd = {
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
recordId,
|
||||
};
|
||||
|
||||
const newMorphItems = new Map([
|
||||
...currentMorphItems,
|
||||
[pageComponentInstanceId, morphItemToAdd],
|
||||
]);
|
||||
|
||||
set(commandMenuNavigationMorphItemByPageState, newMorphItems);
|
||||
|
||||
const Icon = objectMetadataItem?.icon
|
||||
? getIcon(objectMetadataItem.icon)
|
||||
: getIcon('IconList');
|
||||
|
||||
const IconColor = getIconColorForObjectType({
|
||||
objectType: objectMetadataItem.nameSingular,
|
||||
theme,
|
||||
});
|
||||
|
||||
const capitalizedObjectNameSingular = capitalize(objectNameSingular);
|
||||
|
||||
navigateCommandMenu({
|
||||
@ -388,12 +450,13 @@ export const useCommandMenu = () => {
|
||||
? t`New ${capitalizedObjectNameSingular}`
|
||||
: capitalizedObjectNameSingular,
|
||||
pageIcon: Icon,
|
||||
pageIconColor: IconColor,
|
||||
pageId: pageComponentInstanceId,
|
||||
resetNavigationStack: false,
|
||||
});
|
||||
};
|
||||
},
|
||||
[getIcon, navigateCommandMenu],
|
||||
[getIcon, navigateCommandMenu, theme],
|
||||
);
|
||||
|
||||
const openWorkflowTriggerTypeInCommandMenu = useRecoilCallback(
|
||||
@ -522,6 +585,31 @@ export const useCommandMenu = () => {
|
||||
calendarEventId,
|
||||
);
|
||||
|
||||
// TODO: Uncomment this once we need to calendar event title in the navigation
|
||||
// const objectMetadataItem = snapshot
|
||||
// .getLoadable(objectMetadataItemsState)
|
||||
// .getValue()
|
||||
// .find(
|
||||
// ({ nameSingular }) =>
|
||||
// nameSingular === CoreObjectNameSingular.CalendarEvent,
|
||||
// );
|
||||
|
||||
// set(
|
||||
// commandMenuNavigationMorphItemsState,
|
||||
// new Map([
|
||||
// ...snapshot
|
||||
// .getLoadable(commandMenuNavigationMorphItemsState)
|
||||
// .getValue(),
|
||||
// [
|
||||
// pageComponentInstanceId,
|
||||
// {
|
||||
// objectMetadataId: objectMetadataItem?.id,
|
||||
// recordId: calendarEventId,
|
||||
// },
|
||||
// ],
|
||||
// ]),
|
||||
// );
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.ViewCalendarEvent,
|
||||
pageTitle: 'Calendar Event',
|
||||
@ -545,6 +633,31 @@ export const useCommandMenu = () => {
|
||||
emailThreadId,
|
||||
);
|
||||
|
||||
// TODO: Uncomment this once we need to show the thread title in the navigation
|
||||
// const objectMetadataItem = snapshot
|
||||
// .getLoadable(objectMetadataItemsState)
|
||||
// .getValue()
|
||||
// .find(
|
||||
// ({ nameSingular }) =>
|
||||
// nameSingular === CoreObjectNameSingular.MessageThread,
|
||||
// );
|
||||
|
||||
// set(
|
||||
// commandMenuNavigationMorphItemsState,
|
||||
// new Map([
|
||||
// ...snapshot
|
||||
// .getLoadable(commandMenuNavigationMorphItemsState)
|
||||
// .getValue(),
|
||||
// [
|
||||
// pageComponentInstanceId,
|
||||
// {
|
||||
// objectMetadataId: objectMetadataItem?.id,
|
||||
// recordId: emailThreadId,
|
||||
// },
|
||||
// ],
|
||||
// ]),
|
||||
// );
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.ViewEmailThread,
|
||||
pageTitle: 'Email Thread',
|
||||
|
||||
@ -0,0 +1,133 @@
|
||||
import { CommandMenuContextRecordChipAvatars } from '@/command-menu/components/CommandMenuContextRecordChipAvatars';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
import { commandMenuNavigationRecordsState } from '@/command-menu/states/commandMenuNavigationRecordsState';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { getObjectRecordIdentifier } from '@/object-metadata/utils/getObjectRecordIdentifier';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
const StyledIconWrapper = styled.div`
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
export const useCommandMenuContextChips = () => {
|
||||
const commandMenuNavigationStack = useRecoilValue(
|
||||
commandMenuNavigationStackState,
|
||||
);
|
||||
|
||||
const { navigateCommandMenuHistory } = useCommandMenu();
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const commandMenuNavigationMorphItemByPage = useRecoilValue(
|
||||
commandMenuNavigationMorphItemByPageState,
|
||||
);
|
||||
|
||||
const commandMenuNavigationRecords = useRecoilValue(
|
||||
commandMenuNavigationRecordsState,
|
||||
);
|
||||
|
||||
const contextChips = useMemo(() => {
|
||||
const filteredCommandMenuNavigationStack =
|
||||
commandMenuNavigationStack.filter(
|
||||
(page) => page.page !== CommandMenuPages.Root,
|
||||
);
|
||||
|
||||
return filteredCommandMenuNavigationStack
|
||||
.map((page, index) => {
|
||||
const isLastChip =
|
||||
index === filteredCommandMenuNavigationStack.length - 1;
|
||||
|
||||
const isRecordPage = page.page === CommandMenuPages.ViewRecord;
|
||||
|
||||
if (isRecordPage && !isLastChip) {
|
||||
const commandMenuNavigationMorphItem =
|
||||
commandMenuNavigationMorphItemByPage.get(page.pageId);
|
||||
|
||||
if (!isDefined(commandMenuNavigationMorphItem?.recordId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const objectMetadataItem = commandMenuNavigationRecords.find(
|
||||
({ objectMetadataItem }) =>
|
||||
objectMetadataItem.id ===
|
||||
commandMenuNavigationMorphItem.objectMetadataId,
|
||||
)?.objectMetadataItem;
|
||||
|
||||
const record = commandMenuNavigationRecords.find(
|
||||
({ record }) =>
|
||||
record.id === commandMenuNavigationMorphItem.recordId,
|
||||
)?.record;
|
||||
|
||||
if (!isDefined(objectMetadataItem) || !isDefined(record)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const name = getObjectRecordIdentifier({
|
||||
objectMetadataItem,
|
||||
record,
|
||||
}).name;
|
||||
|
||||
return {
|
||||
page,
|
||||
Icons: [
|
||||
<CommandMenuContextRecordChipAvatars
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
record={record}
|
||||
/>,
|
||||
],
|
||||
text: name,
|
||||
onClick: () => {
|
||||
navigateCommandMenuHistory(index);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
page,
|
||||
Icons: isLastChip
|
||||
? [<page.pageIcon size={theme.icon.size.sm} />]
|
||||
: [
|
||||
<StyledIconWrapper>
|
||||
<page.pageIcon
|
||||
size={theme.icon.size.sm}
|
||||
color={
|
||||
isDefined(page.pageIconColor) &&
|
||||
page.pageIconColor !== 'currentColor'
|
||||
? page.pageIconColor
|
||||
: theme.font.color.tertiary
|
||||
}
|
||||
/>
|
||||
</StyledIconWrapper>,
|
||||
],
|
||||
text: page.pageTitle,
|
||||
onClick: isLastChip
|
||||
? undefined
|
||||
: () => {
|
||||
navigateCommandMenuHistory(index);
|
||||
},
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
}, [
|
||||
commandMenuNavigationMorphItemByPage,
|
||||
commandMenuNavigationRecords,
|
||||
commandMenuNavigationStack,
|
||||
navigateCommandMenuHistory,
|
||||
theme.font.color.tertiary,
|
||||
theme.icon.size.sm,
|
||||
]);
|
||||
|
||||
return {
|
||||
contextChips,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,9 @@
|
||||
import { MorphItem } from '@/object-record/multiple-objects/types/MorphItem';
|
||||
import { createState } from '@ui/utilities/state/utils/createState';
|
||||
|
||||
export const commandMenuNavigationMorphItemByPageState = createState<
|
||||
Map<string, MorphItem>
|
||||
>({
|
||||
key: 'command-menu/commandMenuNavigationMorphItemByPageState',
|
||||
defaultValue: new Map(),
|
||||
});
|
||||
@ -0,0 +1,13 @@
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { createState } from '@ui/utilities/state/utils/createState';
|
||||
|
||||
export const commandMenuNavigationRecordsState = createState<
|
||||
{
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
record: ObjectRecord;
|
||||
}[]
|
||||
>({
|
||||
key: 'command-menu/commandMenuNavigationRecordsState',
|
||||
defaultValue: [],
|
||||
});
|
||||
@ -5,6 +5,7 @@ export type CommandMenuNavigationStackItem = {
|
||||
page: CommandMenuPages;
|
||||
pageTitle: string;
|
||||
pageIcon: IconComponent;
|
||||
pageIconColor?: string;
|
||||
pageId: string;
|
||||
};
|
||||
|
||||
|
||||
@ -1,63 +0,0 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
import { useLimitPerMetadataItem } from '@/object-metadata/hooks/useLimitPerMetadataItem';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext';
|
||||
|
||||
const instanceId = 'instanceId';
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<SingleRecordPickerComponentInstanceContext.Provider value={{ instanceId }}>
|
||||
<RecoilRoot>{children}</RecoilRoot>
|
||||
</SingleRecordPickerComponentInstanceContext.Provider>
|
||||
);
|
||||
|
||||
describe('useLimitPerMetadataItem', () => {
|
||||
const objectData: ObjectMetadataItem[] = [
|
||||
{
|
||||
createdAt: 'createdAt',
|
||||
id: 'id',
|
||||
isActive: true,
|
||||
isCustom: true,
|
||||
isSystem: true,
|
||||
isRemote: false,
|
||||
isSearchable: true,
|
||||
labelPlural: 'labelPlural',
|
||||
labelSingular: 'labelSingular',
|
||||
namePlural: 'namePlural',
|
||||
nameSingular: 'nameSingular',
|
||||
labelIdentifierFieldMetadataId: '20202020-72ba-4e11-a36d-e17b544541e1',
|
||||
updatedAt: 'updatedAt',
|
||||
isLabelSyncedWithName: false,
|
||||
fields: [],
|
||||
indexMetadatas: [],
|
||||
},
|
||||
];
|
||||
|
||||
it('should return object with nameSingular and default limit', async () => {
|
||||
const { result } = renderHook(
|
||||
() => useLimitPerMetadataItem({ objectMetadataItems: objectData }),
|
||||
{
|
||||
wrapper: Wrapper,
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.current.limitPerMetadataItem).toStrictEqual({
|
||||
limitNameSingular: 60,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an object with nameSingular and specified limit', async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useLimitPerMetadataItem({ objectMetadataItems: objectData, limit: 30 }),
|
||||
{
|
||||
wrapper: Wrapper,
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.current.limitPerMetadataItem).toStrictEqual({
|
||||
limitNameSingular: 30,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,36 +1,16 @@
|
||||
import { getIconColorForObjectType } from '@/object-metadata/utils/getIconColorForObjectType';
|
||||
import { getIconForObjectType } from '@/object-metadata/utils/getIconForObjectType';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { IconCheckbox, IconComponent, IconNotes } from 'twenty-ui';
|
||||
|
||||
export const useGetStandardObjectIcon = (objectNameSingular: string) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const getIconForObjectType = (
|
||||
objectType: string,
|
||||
): IconComponent | undefined => {
|
||||
switch (objectType) {
|
||||
case 'note':
|
||||
return IconNotes;
|
||||
case 'task':
|
||||
return IconCheckbox;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const getIconColorForObjectType = (objectType: string): string => {
|
||||
switch (objectType) {
|
||||
case 'note':
|
||||
return theme.color.yellow;
|
||||
case 'task':
|
||||
return theme.color.blue;
|
||||
default:
|
||||
return 'currentColor';
|
||||
}
|
||||
};
|
||||
|
||||
const { Icon, IconColor } = {
|
||||
Icon: getIconForObjectType(objectNameSingular),
|
||||
IconColor: getIconColorForObjectType(objectNameSingular),
|
||||
IconColor: getIconColorForObjectType({
|
||||
objectType: objectNameSingular,
|
||||
theme,
|
||||
}),
|
||||
};
|
||||
|
||||
return { Icon, IconColor };
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/object-record/constants/DefaultSearchRequestLimit';
|
||||
import { capitalize, isDefined } from 'twenty-shared';
|
||||
|
||||
export const useLimitPerMetadataItem = ({
|
||||
objectMetadataItems,
|
||||
limit = DEFAULT_SEARCH_REQUEST_LIMIT,
|
||||
}: {
|
||||
objectMetadataItems: ObjectMetadataItem[];
|
||||
limit?: number;
|
||||
}) => {
|
||||
const limitPerMetadataItem = Object.fromEntries(
|
||||
objectMetadataItems
|
||||
.map(({ nameSingular }) => {
|
||||
return [`limit${capitalize(nameSingular)}`, limit];
|
||||
})
|
||||
.filter(isDefined),
|
||||
);
|
||||
|
||||
return {
|
||||
limitPerMetadataItem,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,18 @@
|
||||
import { Theme } from '@emotion/react';
|
||||
|
||||
export const getIconColorForObjectType = ({
|
||||
objectType,
|
||||
theme,
|
||||
}: {
|
||||
objectType: string;
|
||||
theme: Theme;
|
||||
}): string => {
|
||||
switch (objectType) {
|
||||
case 'note':
|
||||
return theme.color.yellow;
|
||||
case 'task':
|
||||
return theme.color.blue;
|
||||
default:
|
||||
return 'currentColor';
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,14 @@
|
||||
import { IconCheckbox, IconComponent, IconNotes } from 'twenty-ui';
|
||||
|
||||
export const getIconForObjectType = (
|
||||
objectType: string,
|
||||
): IconComponent | undefined => {
|
||||
switch (objectType) {
|
||||
case 'note':
|
||||
return IconNotes;
|
||||
case 'task':
|
||||
return IconCheckbox;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
@ -3,9 +3,9 @@ import { useQuery } from '@apollo/client';
|
||||
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
|
||||
import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery';
|
||||
import { RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature';
|
||||
import { useCombinedFindManyRecordsQueryVariables } from '@/object-record/multiple-objects/hooks/useCombinedFindManyRecordsQueryVariables';
|
||||
import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery';
|
||||
import { CombinedFindManyRecordsQueryResult } from '@/object-record/multiple-objects/types/CombinedFindManyRecordsQueryResult';
|
||||
import { generateCombinedFindManyRecordsQueryVariables } from '@/object-record/multiple-objects/utils/generateCombinedFindManyRecordsQueryVariables';
|
||||
|
||||
export const useCombinedFindManyRecords = ({
|
||||
operationSignatures,
|
||||
@ -18,7 +18,7 @@ export const useCombinedFindManyRecords = ({
|
||||
operationSignatures,
|
||||
});
|
||||
|
||||
const queryVariables = useCombinedFindManyRecordsQueryVariables({
|
||||
const queryVariables = generateCombinedFindManyRecordsQueryVariables({
|
||||
operationSignatures,
|
||||
});
|
||||
|
||||
|
||||
@ -0,0 +1,153 @@
|
||||
import { ApolloClient, gql, useApolloClient } from '@apollo/client';
|
||||
import { isUndefined } from '@sniptt/guards';
|
||||
import { capitalize } from 'twenty-shared';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
|
||||
import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery';
|
||||
import { RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature';
|
||||
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
|
||||
import { CombinedFindManyRecordsQueryResult } from '@/object-record/multiple-objects/types/CombinedFindManyRecordsQueryResult';
|
||||
import { generateCombinedFindManyRecordsQueryVariables } from '@/object-record/multiple-objects/utils/generateCombinedFindManyRecordsQueryVariables';
|
||||
import { getCombinedFindManyRecordsQueryFilteringPart } from '@/object-record/multiple-objects/utils/getCombinedFindManyRecordsQueryFilteringPart';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
export const usePerformCombinedFindManyRecords = () => {
|
||||
const client = useApolloClient();
|
||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||
|
||||
const generateCombinedFindManyRecordsQuery = (
|
||||
operationSignatures: RecordGqlOperationSignature[],
|
||||
objectMetadataItemsValue: ObjectMetadataItem[],
|
||||
) => {
|
||||
const filterPerMetadataItemArray = operationSignatures
|
||||
.map(
|
||||
({ objectNameSingular }) =>
|
||||
`$filter${capitalize(objectNameSingular)}: ${capitalize(
|
||||
objectNameSingular,
|
||||
)}FilterInput`,
|
||||
)
|
||||
.join(', ');
|
||||
|
||||
const orderByPerMetadataItemArray = operationSignatures
|
||||
.map(
|
||||
({ objectNameSingular }) =>
|
||||
`$orderBy${capitalize(objectNameSingular)}: [${capitalize(
|
||||
objectNameSingular,
|
||||
)}OrderByInput]`,
|
||||
)
|
||||
.join(', ');
|
||||
|
||||
const cursorFilteringPerMetadataItemArray = operationSignatures
|
||||
.map(
|
||||
({ objectNameSingular }) =>
|
||||
`$after${capitalize(objectNameSingular)}: String, $before${capitalize(objectNameSingular)}: String, $first${capitalize(objectNameSingular)}: Int, $last${capitalize(objectNameSingular)}: Int`,
|
||||
)
|
||||
.join(', ');
|
||||
|
||||
const limitPerMetadataItemArray = operationSignatures
|
||||
.map(
|
||||
({ objectNameSingular }) =>
|
||||
`$limit${capitalize(objectNameSingular)}: Int`,
|
||||
)
|
||||
.join(', ');
|
||||
|
||||
const queryOperationSignatureWithObjectMetadataItemArray =
|
||||
operationSignatures.map((operationSignature) => {
|
||||
const objectMetadataItem = objectMetadataItemsValue.find(
|
||||
(objectMetadataItem) =>
|
||||
objectMetadataItem.nameSingular ===
|
||||
operationSignature.objectNameSingular,
|
||||
);
|
||||
|
||||
if (isUndefined(objectMetadataItem)) {
|
||||
throw new Error(
|
||||
`Object metadata item not found for object name singular: ${operationSignature.objectNameSingular}`,
|
||||
);
|
||||
}
|
||||
|
||||
return { operationSignature, objectMetadataItem };
|
||||
});
|
||||
|
||||
return gql`
|
||||
query CombinedFindManyRecords(
|
||||
${filterPerMetadataItemArray},
|
||||
${orderByPerMetadataItemArray},
|
||||
${cursorFilteringPerMetadataItemArray},
|
||||
${limitPerMetadataItemArray}
|
||||
) {
|
||||
${queryOperationSignatureWithObjectMetadataItemArray
|
||||
.map(
|
||||
({ objectMetadataItem, operationSignature }) =>
|
||||
`${getCombinedFindManyRecordsQueryFilteringPart(
|
||||
objectMetadataItem,
|
||||
)} {
|
||||
edges {
|
||||
node ${mapObjectMetadataToGraphQLQuery({
|
||||
objectMetadataItems: objectMetadataItemsValue,
|
||||
objectMetadataItem,
|
||||
recordGqlFields:
|
||||
operationSignature.fields ??
|
||||
generateDepthOneRecordGqlFields({
|
||||
objectMetadataItem,
|
||||
}),
|
||||
})}
|
||||
cursor
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
totalCount
|
||||
}`,
|
||||
)
|
||||
.join('\n')}
|
||||
}
|
||||
`;
|
||||
};
|
||||
|
||||
const performCombinedFindManyRecords = async ({
|
||||
operationSignatures,
|
||||
client: customClient,
|
||||
}: {
|
||||
operationSignatures: RecordGqlOperationSignature[];
|
||||
client?: ApolloClient<object>;
|
||||
}) => {
|
||||
const apolloClient = customClient || client;
|
||||
|
||||
const findManyQuery = generateCombinedFindManyRecordsQuery(
|
||||
operationSignatures,
|
||||
objectMetadataItems,
|
||||
);
|
||||
|
||||
const queryVariables = generateCombinedFindManyRecordsQueryVariables({
|
||||
operationSignatures,
|
||||
});
|
||||
|
||||
const { data, loading } =
|
||||
await apolloClient.query<CombinedFindManyRecordsQueryResult>({
|
||||
query: findManyQuery ?? EMPTY_QUERY,
|
||||
variables: queryVariables,
|
||||
});
|
||||
|
||||
const resultWithoutConnection = Object.fromEntries(
|
||||
Object.entries(data ?? {}).map(([namePlural, objectRecordConnection]) => [
|
||||
namePlural,
|
||||
getRecordsFromRecordConnection({
|
||||
recordConnection: objectRecordConnection,
|
||||
}),
|
||||
]),
|
||||
);
|
||||
|
||||
return {
|
||||
result: resultWithoutConnection,
|
||||
loading,
|
||||
};
|
||||
};
|
||||
|
||||
return { performCombinedFindManyRecords };
|
||||
};
|
||||
@ -0,0 +1,4 @@
|
||||
export type MorphItem = {
|
||||
recordId: string;
|
||||
objectMetadataId: string;
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
import { RecordGqlFields } from '@/object-record/graphql/types/RecordGqlFields';
|
||||
import { RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature';
|
||||
import { useCombinedFindManyRecordsQueryVariables } from '@/object-record/multiple-objects/hooks/useCombinedFindManyRecordsQueryVariables';
|
||||
import { generateCombinedFindManyRecordsQueryVariables } from '@/object-record/multiple-objects/utils/generateCombinedFindManyRecordsQueryVariables';
|
||||
|
||||
describe('useCombinedFindManyRecordsQueryVariables', () => {
|
||||
it('should generate variables with after cursor and first limit', () => {
|
||||
@ -26,7 +26,7 @@ describe('useCombinedFindManyRecordsQueryVariables', () => {
|
||||
},
|
||||
];
|
||||
|
||||
const result = useCombinedFindManyRecordsQueryVariables({
|
||||
const result = generateCombinedFindManyRecordsQueryVariables({
|
||||
operationSignatures,
|
||||
});
|
||||
|
||||
@ -58,7 +58,7 @@ describe('useCombinedFindManyRecordsQueryVariables', () => {
|
||||
},
|
||||
];
|
||||
|
||||
const result = useCombinedFindManyRecordsQueryVariables({
|
||||
const result = generateCombinedFindManyRecordsQueryVariables({
|
||||
operationSignatures,
|
||||
});
|
||||
|
||||
@ -86,7 +86,7 @@ describe('useCombinedFindManyRecordsQueryVariables', () => {
|
||||
},
|
||||
];
|
||||
|
||||
const result = useCombinedFindManyRecordsQueryVariables({
|
||||
const result = generateCombinedFindManyRecordsQueryVariables({
|
||||
operationSignatures,
|
||||
});
|
||||
|
||||
@ -125,7 +125,7 @@ describe('useCombinedFindManyRecordsQueryVariables', () => {
|
||||
},
|
||||
];
|
||||
|
||||
const result = useCombinedFindManyRecordsQueryVariables({
|
||||
const result = generateCombinedFindManyRecordsQueryVariables({
|
||||
operationSignatures,
|
||||
});
|
||||
|
||||
@ -139,7 +139,7 @@ describe('useCombinedFindManyRecordsQueryVariables', () => {
|
||||
});
|
||||
|
||||
it('should handle empty operation signatures', () => {
|
||||
const result = useCombinedFindManyRecordsQueryVariables({
|
||||
const result = generateCombinedFindManyRecordsQueryVariables({
|
||||
operationSignatures: [],
|
||||
});
|
||||
|
||||
@ -157,7 +157,7 @@ describe('useCombinedFindManyRecordsQueryVariables', () => {
|
||||
},
|
||||
];
|
||||
|
||||
const result = useCombinedFindManyRecordsQueryVariables({
|
||||
const result = generateCombinedFindManyRecordsQueryVariables({
|
||||
operationSignatures,
|
||||
});
|
||||
|
||||
@ -180,7 +180,7 @@ describe('useCombinedFindManyRecordsQueryVariables', () => {
|
||||
},
|
||||
];
|
||||
|
||||
const result = useCombinedFindManyRecordsQueryVariables({
|
||||
const result = generateCombinedFindManyRecordsQueryVariables({
|
||||
operationSignatures,
|
||||
});
|
||||
|
||||
@ -3,7 +3,7 @@ import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { capitalize, isDefined } from 'twenty-shared';
|
||||
import { isNonEmptyArray } from '~/utils/isNonEmptyArray';
|
||||
|
||||
export const useCombinedFindManyRecordsQueryVariables = ({
|
||||
export const generateCombinedFindManyRecordsQueryVariables = ({
|
||||
operationSignatures,
|
||||
}: {
|
||||
operationSignatures: RecordGqlOperationSignature[];
|
||||
@ -0,0 +1,13 @@
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { capitalize } from 'twenty-shared';
|
||||
|
||||
export const getLimitPerMetadataItem = (
|
||||
objectMetadataItems: Pick<ObjectMetadataItem, 'nameSingular'>[],
|
||||
limit: number,
|
||||
) => {
|
||||
return Object.fromEntries(
|
||||
objectMetadataItems.map(({ nameSingular }) => {
|
||||
return [`limit${capitalize(nameSingular)}`, limit];
|
||||
}),
|
||||
);
|
||||
};
|
||||
@ -1,6 +1,7 @@
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { CombinedFindManyRecordsQueryResult } from '@/object-record/multiple-objects/types/CombinedFindManyRecordsQueryResult';
|
||||
import { generateCombinedSearchRecordsQuery } from '@/object-record/multiple-objects/utils/generateCombinedSearchRecordsQuery';
|
||||
import { getLimitPerMetadataItem } from '@/object-record/multiple-objects/utils/getLimitPerMetadataItem';
|
||||
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
||||
import { multipleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState';
|
||||
import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState';
|
||||
@ -222,12 +223,9 @@ const performSearchForPickedRecords = async ({
|
||||
),
|
||||
});
|
||||
|
||||
const limitPerMetadataItem = Object.fromEntries(
|
||||
searchableObjectMetadataItems
|
||||
.map(({ nameSingular }) => {
|
||||
return [`limit${capitalize(nameSingular)}`, 10];
|
||||
})
|
||||
.filter(isDefined),
|
||||
const limitPerMetadataItem = getLimitPerMetadataItem(
|
||||
searchableObjectMetadataItemsFilteredOnPickedRecordId,
|
||||
10,
|
||||
);
|
||||
|
||||
const { data: combinedSearchRecordFilteredOnPickedRecordsQueryResult } =
|
||||
@ -309,12 +307,9 @@ const performSearchExcludingPickedRecords = async ({
|
||||
),
|
||||
});
|
||||
|
||||
const limitPerMetadataItem = Object.fromEntries(
|
||||
searchableObjectMetadataItems
|
||||
.map(({ nameSingular }) => {
|
||||
return [`limit${capitalize(nameSingular)}`, 10];
|
||||
})
|
||||
.filter(isDefined),
|
||||
const limitPerMetadataItem = getLimitPerMetadataItem(
|
||||
searchableObjectMetadataItems,
|
||||
10,
|
||||
);
|
||||
|
||||
const { data: combinedSearchRecordExcludingPickedRecordsQueryResult } =
|
||||
|
||||
Reference in New Issue
Block a user