Action menu refactoring (#11454)
# Description Closes [#696](https://github.com/twentyhq/core-team-issues/issues/696) - `useAction` hooks have been removed for all actions - Every action can now declare a react component - Some standard action components have been introduced: `Action`, `ActionLink` and `ActionModal` - The `ActionDisplay` component uses the new `displayType` prop of the `ActionMenuContext` to render the right component for the action according to its container: `ActionButton`, `ActionDropdownItem` or `ActionListItem` - The `ActionDisplayer` wraps the action component inside a context which gives it all the information about the action -`actionMenuEntriesComponenState` has been removed and now all actions are computed directly using `useRegisteredAction` - This computation is done inside `ActionMenuContextProvider` and the actions are passed inside a context - `actionMenuType` gives information about the container of the action, so the action can know wether or not to close this container upon execution
This commit is contained in:
@ -1,10 +1,10 @@
|
||||
import { ActionConfig } from '@/action-menu/actions/types/ActionConfig';
|
||||
import { CommandGroup } from '@/command-menu/components/CommandGroup';
|
||||
import { CommandMenuList } from '@/command-menu/components/CommandMenuList';
|
||||
import { ResetContextToSelectionCommandButton } from '@/command-menu/components/ResetContextToSelectionCommandButton';
|
||||
import { RESET_CONTEXT_TO_SELECTION } from '@/command-menu/constants/ResetContextToSelection';
|
||||
import { useMatchingCommandMenuCommands } from '@/command-menu/hooks/useMatchingCommandMenuCommands';
|
||||
import { useMatchingCommandMenuActions } from '@/command-menu/hooks/useMatchingCommandMenuActions';
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
import { Command } from '@/command-menu/types/Command';
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
|
||||
@ -13,9 +13,9 @@ import { useLingui } from '@lingui/react/macro';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export type CommandGroupConfig = {
|
||||
export type ActionGroupConfig = {
|
||||
heading: string;
|
||||
items?: Command[];
|
||||
items?: ActionConfig[];
|
||||
};
|
||||
|
||||
export const CommandMenu = () => {
|
||||
@ -26,14 +26,14 @@ export const CommandMenu = () => {
|
||||
|
||||
const {
|
||||
noResults,
|
||||
matchingStandardActionRecordSelectionCommands,
|
||||
matchingStandardActionObjectCommands,
|
||||
matchingWorkflowRunRecordSelectionCommands,
|
||||
matchingStandardActionGlobalCommands,
|
||||
matchingWorkflowRunGlobalCommands,
|
||||
matchingNavigateCommands,
|
||||
fallbackCommands,
|
||||
} = useMatchingCommandMenuCommands({
|
||||
matchingStandardActionRecordSelectionActions,
|
||||
matchingStandardActionObjectActions,
|
||||
matchingWorkflowRunRecordSelectionActions,
|
||||
matchingStandardActionGlobalActions,
|
||||
matchingWorkflowRunGlobalActions,
|
||||
matchingNavigateActions,
|
||||
fallbackActions,
|
||||
} = useMatchingCommandMenuActions({
|
||||
commandMenuSearch,
|
||||
});
|
||||
|
||||
@ -50,34 +50,32 @@ export const CommandMenu = () => {
|
||||
(item) => item.id === objectMetadataItemId,
|
||||
);
|
||||
|
||||
const commandGroups: CommandGroupConfig[] = [
|
||||
const commandGroups: ActionGroupConfig[] = [
|
||||
{
|
||||
heading: t`Record Selection`,
|
||||
items: matchingStandardActionRecordSelectionCommands.concat(
|
||||
matchingWorkflowRunRecordSelectionCommands,
|
||||
items: matchingStandardActionRecordSelectionActions.concat(
|
||||
matchingWorkflowRunRecordSelectionActions,
|
||||
),
|
||||
},
|
||||
{
|
||||
heading: currentObjectMetadataItem?.labelPlural ?? t`Object`,
|
||||
items: matchingStandardActionObjectCommands,
|
||||
items: matchingStandardActionObjectActions,
|
||||
},
|
||||
{
|
||||
heading: t`Global`,
|
||||
items: matchingStandardActionGlobalCommands
|
||||
.concat(matchingWorkflowRunGlobalCommands)
|
||||
.concat(matchingNavigateCommands),
|
||||
items: matchingStandardActionGlobalActions
|
||||
.concat(matchingWorkflowRunGlobalActions)
|
||||
.concat(matchingNavigateActions),
|
||||
},
|
||||
{
|
||||
heading: t`Search ''${commandMenuSearch}'' with...`,
|
||||
items: fallbackCommands,
|
||||
items: fallbackActions,
|
||||
},
|
||||
];
|
||||
|
||||
const selectableItems: Command[] = commandGroups.flatMap(
|
||||
(group) => group.items ?? [],
|
||||
);
|
||||
const selectableItems = commandGroups.flatMap((group) => group.items ?? []);
|
||||
|
||||
const selectableItemIds = selectableItems.map((item) => item.id);
|
||||
const selectableItemIds = selectableItems.map((item) => item.key);
|
||||
|
||||
if (isDefined(previousContextStoreCurrentObjectMetadataItemId)) {
|
||||
selectableItemIds.unshift(RESET_CONTEXT_TO_SELECTION);
|
||||
|
||||
@ -1,17 +1,9 @@
|
||||
import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter';
|
||||
import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKeys';
|
||||
import { RecordAgnosticActionMenuEntriesSetter } from '@/action-menu/actions/record-agnostic-actions/components/RecordAgnosticActionMenuEntriesSetter';
|
||||
import { RunWorkflowRecordAgnosticActionMenuEntriesSetter } from '@/action-menu/actions/record-agnostic-actions/components/RunWorkflowRecordAgnosticActionMenuEntriesSetter';
|
||||
import { RecordAgnosticActionsKeys } from '@/action-menu/actions/record-agnostic-actions/types/RecordAgnosticActionsKeys';
|
||||
import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals';
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { COMMAND_MENU_ANIMATION_VARIANTS } from '@/command-menu/constants/CommandMenuAnimationVariants';
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useCommandMenuCloseAnimationCompleteCleanup } from '@/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup';
|
||||
import { useCommandMenuHotKeys } from '@/command-menu/hooks/useCommandMenuHotKeys';
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
import { CommandMenuAnimationVariant } from '@/command-menu/types/CommandMenuAnimationVariant';
|
||||
import { CommandMenuHotkeyScope } from '@/command-menu/types/CommandMenuHotkeyScope';
|
||||
@ -27,13 +19,11 @@ import { RootStackingContextZIndices } from '@/ui/layout/constants/RootStackingC
|
||||
import { currentHotkeyScopeState } from '@/ui/utilities/hotkey/states/internal/currentHotkeyScopeState';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useRef } from 'react';
|
||||
import { useRecoilCallback, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||
import { useIsMobile } from 'twenty-ui/utilities';
|
||||
|
||||
const StyledCommandMenu = styled(motion.div)`
|
||||
@ -57,7 +47,7 @@ export const CommandMenuContainer = ({
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const { toggleCommandMenu, closeCommandMenu } = useCommandMenu();
|
||||
const { closeCommandMenu } = useCommandMenu();
|
||||
|
||||
const { commandMenuCloseAnimationCompleteCleanup } =
|
||||
useCommandMenuCloseAnimationCompleteCleanup();
|
||||
@ -97,12 +87,6 @@ export const CommandMenuContainer = ({
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const isWorkflowEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IsWorkflowEnabled,
|
||||
);
|
||||
|
||||
const setCommandMenuSearch = useSetRecoilState(commandMenuSearchState);
|
||||
|
||||
const objectMetadataItemId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState,
|
||||
COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
@ -140,53 +124,25 @@ export const CommandMenuContainer = ({
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID }}
|
||||
>
|
||||
<ActionMenuContext.Provider
|
||||
value={{
|
||||
isInRightDrawer: true,
|
||||
onActionExecutedCallback: ({ key }) => {
|
||||
if (
|
||||
key !== RecordAgnosticActionsKeys.SEARCH_RECORDS &&
|
||||
key !==
|
||||
RecordAgnosticActionsKeys.SEARCH_RECORDS_FALLBACK &&
|
||||
key !== NoSelectionRecordActionKeys.CREATE_NEW_RECORD
|
||||
) {
|
||||
toggleCommandMenu();
|
||||
}
|
||||
|
||||
if (
|
||||
key !== RecordAgnosticActionsKeys.SEARCH_RECORDS_FALLBACK
|
||||
) {
|
||||
setCommandMenuSearch('');
|
||||
}
|
||||
},
|
||||
}}
|
||||
<AnimatePresence
|
||||
mode="wait"
|
||||
onExitComplete={commandMenuCloseAnimationCompleteCleanup}
|
||||
>
|
||||
<RecordActionMenuEntriesSetter />
|
||||
<RecordAgnosticActionMenuEntriesSetter />
|
||||
{isWorkflowEnabled && (
|
||||
<RunWorkflowRecordAgnosticActionMenuEntriesSetter />
|
||||
{isCommandMenuOpened && (
|
||||
<StyledCommandMenu
|
||||
data-testid="command-menu"
|
||||
ref={commandMenuRef}
|
||||
className="command-menu"
|
||||
animate={targetVariantForAnimation}
|
||||
initial="closed"
|
||||
exit="closed"
|
||||
variants={COMMAND_MENU_ANIMATION_VARIANTS}
|
||||
transition={{ duration: theme.animation.duration.normal }}
|
||||
>
|
||||
{children}
|
||||
</StyledCommandMenu>
|
||||
)}
|
||||
<ActionMenuConfirmationModals />
|
||||
<AnimatePresence
|
||||
mode="wait"
|
||||
onExitComplete={commandMenuCloseAnimationCompleteCleanup}
|
||||
>
|
||||
{isCommandMenuOpened && (
|
||||
<StyledCommandMenu
|
||||
data-testid="command-menu"
|
||||
ref={commandMenuRef}
|
||||
className="command-menu"
|
||||
animate={targetVariantForAnimation}
|
||||
initial="closed"
|
||||
exit="closed"
|
||||
variants={COMMAND_MENU_ANIMATION_VARIANTS}
|
||||
transition={{ duration: theme.animation.duration.normal }}
|
||||
>
|
||||
{children}
|
||||
</StyledCommandMenu>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</ActionMenuContext.Provider>
|
||||
</AnimatePresence>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
|
||||
@ -27,7 +27,6 @@ export const CommandMenuItem = ({
|
||||
onClick,
|
||||
Icon,
|
||||
hotKeys,
|
||||
shouldCloseCommandMenuOnClick,
|
||||
RightComponent,
|
||||
}: CommandMenuItemProps) => {
|
||||
const { onItemClick } = useCommandMenuOnItemClick();
|
||||
@ -47,7 +46,6 @@ export const CommandMenuItem = ({
|
||||
hotKeys={hotKeys}
|
||||
onClick={() =>
|
||||
onItemClick({
|
||||
shouldCloseCommandMenuOnClick,
|
||||
onClick,
|
||||
to,
|
||||
})
|
||||
|
||||
@ -1,26 +1,23 @@
|
||||
import { ActionComponent } from '@/action-menu/actions/display/components/ActionComponent';
|
||||
import { CommandGroup } from '@/command-menu/components/CommandGroup';
|
||||
import { CommandGroupConfig } from '@/command-menu/components/CommandMenu';
|
||||
import { ActionGroupConfig } from '@/command-menu/components/CommandMenu';
|
||||
import { CommandMenuDefaultSelectionEffect } from '@/command-menu/components/CommandMenuDefaultSelectionEffect';
|
||||
import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem';
|
||||
import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/CommandMenuSearchBarHeight';
|
||||
import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding';
|
||||
import { RESET_CONTEXT_TO_SELECTION } from '@/command-menu/constants/ResetContextToSelection';
|
||||
import { useCommandMenuOnItemClick } from '@/command-menu/hooks/useCommandMenuOnItemClick';
|
||||
import { useResetPreviousCommandMenuContext } from '@/command-menu/hooks/useResetPreviousCommandMenuContext';
|
||||
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import styled from '@emotion/styled';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
|
||||
|
||||
const MOBILE_NAVIGATION_BAR_HEIGHT = 64;
|
||||
|
||||
export type CommandMenuListProps = {
|
||||
commandGroups: CommandGroupConfig[];
|
||||
commandGroups: ActionGroupConfig[];
|
||||
selectableItemIds: string[];
|
||||
children?: React.ReactNode;
|
||||
loading?: boolean;
|
||||
@ -63,10 +60,6 @@ export const CommandMenuList = ({
|
||||
loading = false,
|
||||
noResults = false,
|
||||
}: CommandMenuListProps) => {
|
||||
const { onItemClick } = useCommandMenuOnItemClick();
|
||||
|
||||
const commands = commandGroups.flatMap((group) => group.items ?? []);
|
||||
|
||||
const { resetPreviousCommandMenuContext } =
|
||||
useResetPreviousCommandMenuContext();
|
||||
|
||||
@ -90,19 +83,6 @@ export const CommandMenuList = ({
|
||||
resetPreviousCommandMenuContext();
|
||||
return;
|
||||
}
|
||||
|
||||
const command = commands.find((item) => item.id === itemId);
|
||||
|
||||
if (isDefined(command)) {
|
||||
const { to, onCommandClick, shouldCloseCommandMenuOnClick } =
|
||||
command;
|
||||
|
||||
onItemClick({
|
||||
shouldCloseCommandMenuOnClick,
|
||||
onClick: onCommandClick,
|
||||
to,
|
||||
});
|
||||
}
|
||||
}}
|
||||
onSelect={() => {
|
||||
setHasUserSelectedCommand(true);
|
||||
@ -112,24 +92,9 @@ export const CommandMenuList = ({
|
||||
{commandGroups.map(({ heading, items }) =>
|
||||
items?.length ? (
|
||||
<CommandGroup heading={heading} key={heading}>
|
||||
{items.map((item) => {
|
||||
return (
|
||||
<SelectableItem itemId={item.id} key={item.id}>
|
||||
<CommandMenuItem
|
||||
id={item.id}
|
||||
Icon={item.Icon}
|
||||
label={item.label}
|
||||
description={item.description}
|
||||
to={item.to}
|
||||
onClick={item.onCommandClick}
|
||||
hotKeys={item.hotKeys}
|
||||
shouldCloseCommandMenuOnClick={
|
||||
item.shouldCloseCommandMenuOnClick
|
||||
}
|
||||
/>
|
||||
</SelectableItem>
|
||||
);
|
||||
})}
|
||||
{items.map((item) => (
|
||||
<ActionComponent action={item} key={item.key} />
|
||||
))}
|
||||
</CommandGroup>
|
||||
) : null,
|
||||
)}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { ActionMenuContextProvider } from '@/action-menu/contexts/ActionMenuContextProvider';
|
||||
import { CommandMenuContainer } from '@/command-menu/components/CommandMenuContainer';
|
||||
import { CommandMenuContextChipRecordSetterEffect } from '@/command-menu/components/CommandMenuContextChipRecordSetterEffect';
|
||||
import { CommandMenuTopBar } from '@/command-menu/components/CommandMenuTopBar';
|
||||
@ -47,7 +48,13 @@ export const CommandMenuRouter = () => {
|
||||
<CommandMenuTopBar />
|
||||
</motion.div>
|
||||
<StyledCommandMenuContent>
|
||||
{commandMenuPageComponent}
|
||||
<ActionMenuContextProvider
|
||||
isInRightDrawer={true}
|
||||
displayType="listItem"
|
||||
actionMenuType="command-menu"
|
||||
>
|
||||
{commandMenuPageComponent}
|
||||
</ActionMenuContextProvider>
|
||||
</StyledCommandMenuContent>
|
||||
</CommandMenuPageComponentInstanceContext.Provider>
|
||||
</CommandMenuContainer>
|
||||
|
||||
@ -26,10 +26,10 @@ import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/reco
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { HttpResponse, graphql } from 'msw';
|
||||
import { IconDotsVertical } from 'twenty-ui/display';
|
||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||
import { JestContextStoreSetter } from '~/testing/jest/JestContextStoreSetter';
|
||||
import { CommandMenu } from '../CommandMenu';
|
||||
import { IconDotsVertical } from 'twenty-ui/display';
|
||||
|
||||
const openTimeout = 50;
|
||||
|
||||
@ -115,10 +115,10 @@ export const DefaultWithoutSearch: Story = {
|
||||
const canvas = within(document.body);
|
||||
|
||||
expect(await canvas.findByText('Go to People')).toBeVisible();
|
||||
expect(await canvas.findByText('Go to Companies')).toBeVisible();
|
||||
expect(await canvas.findByText('Go to Opportunities')).toBeVisible();
|
||||
expect(await canvas.findByText('Go to Settings')).toBeVisible();
|
||||
expect(await canvas.findByText('Go to Tasks')).toBeVisible();
|
||||
expect(await canvas.findByText('Go to Notes')).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -42,13 +42,11 @@ describe('useCommandMenuOnItemClick', () => {
|
||||
|
||||
act(() => {
|
||||
result.current.onItemClick({
|
||||
shouldCloseCommandMenuOnClick: true,
|
||||
onClick: onClickMock,
|
||||
to: '/test',
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.isCommandMenuOpened).toBe(true);
|
||||
expect(onClickMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@ -7,8 +7,8 @@ import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuCl
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { isDragSelectionStartEnabledState } from '@/ui/utilities/drag-select/states/internal/isDragSelectionStartEnabledState';
|
||||
import { useCallback } from 'react';
|
||||
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
||||
import { IconDotsVertical } from 'twenty-ui/display';
|
||||
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
||||
|
||||
export const useCommandMenu = () => {
|
||||
const { navigateCommandMenu } = useNavigateCommandMenu();
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
import { ActionConfig } from '@/action-menu/actions/types/ActionConfig';
|
||||
import { ActionScope } from '@/action-menu/actions/types/ActionScope';
|
||||
import { ActionType } from '@/action-menu/actions/types/ActionType';
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { useContext } from 'react';
|
||||
|
||||
export const useCommandMenuActions = () => {
|
||||
const { actions } = useContext(ActionMenuContext);
|
||||
|
||||
const navigateActions = actions?.filter(
|
||||
(action) => action.type === ActionType.Navigation,
|
||||
);
|
||||
|
||||
const actionRecordSelectionActions: ActionConfig[] = actions?.filter(
|
||||
(action) =>
|
||||
action.type === ActionType.Standard &&
|
||||
action.scope === ActionScope.RecordSelection,
|
||||
);
|
||||
|
||||
const actionObjectActions: ActionConfig[] = actions?.filter(
|
||||
(action) =>
|
||||
action.type === ActionType.Standard &&
|
||||
action.scope === ActionScope.Object,
|
||||
);
|
||||
|
||||
const actionGlobalActions: ActionConfig[] = actions?.filter(
|
||||
(action) =>
|
||||
action.type === ActionType.Standard &&
|
||||
action.scope === ActionScope.Global,
|
||||
);
|
||||
|
||||
const workflowRunRecordSelectionActions: ActionConfig[] = actions?.filter(
|
||||
(action) =>
|
||||
action.type === ActionType.WorkflowRun &&
|
||||
action.scope === ActionScope.RecordSelection,
|
||||
);
|
||||
|
||||
const workflowRunGlobalActions: ActionConfig[] = actions?.filter(
|
||||
(action) =>
|
||||
action.type === ActionType.WorkflowRun &&
|
||||
action.scope === ActionScope.Global,
|
||||
);
|
||||
|
||||
const fallbackActions: ActionConfig[] = actions?.filter(
|
||||
(action) => action.type === ActionType.Fallback,
|
||||
);
|
||||
|
||||
return {
|
||||
navigateActions,
|
||||
actionRecordSelectionActions,
|
||||
actionGlobalActions,
|
||||
actionObjectActions,
|
||||
workflowRunRecordSelectionActions,
|
||||
workflowRunGlobalActions,
|
||||
fallbackActions,
|
||||
};
|
||||
};
|
||||
@ -1,138 +0,0 @@
|
||||
import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector';
|
||||
import {
|
||||
ActionMenuEntryScope,
|
||||
ActionMenuEntryType,
|
||||
} from '@/action-menu/types/ActionMenuEntry';
|
||||
import {
|
||||
Command,
|
||||
CommandScope,
|
||||
CommandType,
|
||||
} from '@/command-menu/types/Command';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { i18n } from '@lingui/core';
|
||||
|
||||
export const useCommandMenuCommands = () => {
|
||||
const actionMenuEntries = useRecoilComponentValueV2(
|
||||
actionMenuEntriesComponentSelector,
|
||||
);
|
||||
|
||||
const navigateCommands = actionMenuEntries
|
||||
?.filter(
|
||||
(actionMenuEntry) =>
|
||||
actionMenuEntry.type === ActionMenuEntryType.Navigation,
|
||||
)
|
||||
?.map((actionMenuEntry) => ({
|
||||
id: actionMenuEntry.key,
|
||||
label: i18n._(actionMenuEntry.label),
|
||||
Icon: actionMenuEntry.Icon,
|
||||
onCommandClick: actionMenuEntry.onClick,
|
||||
type: CommandType.Navigate,
|
||||
scope: CommandScope.Global,
|
||||
hotKeys: actionMenuEntry.hotKeys,
|
||||
})) as Command[];
|
||||
|
||||
const actionRecordSelectionCommands: Command[] = actionMenuEntries
|
||||
?.filter(
|
||||
(actionMenuEntry) =>
|
||||
actionMenuEntry.type === ActionMenuEntryType.Standard &&
|
||||
actionMenuEntry.scope === ActionMenuEntryScope.RecordSelection,
|
||||
)
|
||||
?.map((actionMenuEntry) => ({
|
||||
id: actionMenuEntry.key,
|
||||
label: i18n._(actionMenuEntry.label),
|
||||
Icon: actionMenuEntry.Icon,
|
||||
onCommandClick: actionMenuEntry.onClick,
|
||||
type: CommandType.StandardAction,
|
||||
scope: CommandScope.RecordSelection,
|
||||
hotKeys: actionMenuEntry.hotKeys,
|
||||
}));
|
||||
|
||||
const actionObjectCommands: Command[] = actionMenuEntries
|
||||
?.filter(
|
||||
(actionMenuEntry) =>
|
||||
actionMenuEntry.type === ActionMenuEntryType.Standard &&
|
||||
actionMenuEntry.scope === ActionMenuEntryScope.Object,
|
||||
)
|
||||
?.map((actionMenuEntry) => ({
|
||||
id: actionMenuEntry.key,
|
||||
label: i18n._(actionMenuEntry.label),
|
||||
Icon: actionMenuEntry.Icon,
|
||||
onCommandClick: actionMenuEntry.onClick,
|
||||
type: CommandType.StandardAction,
|
||||
scope: CommandScope.Object,
|
||||
hotKeys: actionMenuEntry.hotKeys,
|
||||
}));
|
||||
|
||||
const actionGlobalCommands: Command[] = actionMenuEntries
|
||||
?.filter(
|
||||
(actionMenuEntry) =>
|
||||
actionMenuEntry.type === ActionMenuEntryType.Standard &&
|
||||
actionMenuEntry.scope === ActionMenuEntryScope.Global,
|
||||
)
|
||||
?.map((actionMenuEntry) => ({
|
||||
id: actionMenuEntry.key,
|
||||
label: i18n._(actionMenuEntry.label),
|
||||
Icon: actionMenuEntry.Icon,
|
||||
onCommandClick: actionMenuEntry.onClick,
|
||||
type: CommandType.StandardAction,
|
||||
scope: CommandScope.Global,
|
||||
hotKeys: actionMenuEntry.hotKeys,
|
||||
}));
|
||||
|
||||
const workflowRunRecordSelectionCommands: Command[] = actionMenuEntries
|
||||
?.filter(
|
||||
(actionMenuEntry) =>
|
||||
actionMenuEntry.type === ActionMenuEntryType.WorkflowRun &&
|
||||
actionMenuEntry.scope === ActionMenuEntryScope.RecordSelection,
|
||||
)
|
||||
?.map((actionMenuEntry) => ({
|
||||
id: actionMenuEntry.key,
|
||||
label: i18n._(actionMenuEntry.label),
|
||||
Icon: actionMenuEntry.Icon,
|
||||
onCommandClick: actionMenuEntry.onClick,
|
||||
type: CommandType.WorkflowRun,
|
||||
scope: CommandScope.RecordSelection,
|
||||
hotKeys: actionMenuEntry.hotKeys,
|
||||
}));
|
||||
|
||||
const workflowRunGlobalCommands: Command[] = actionMenuEntries
|
||||
?.filter(
|
||||
(actionMenuEntry) =>
|
||||
actionMenuEntry.type === ActionMenuEntryType.WorkflowRun &&
|
||||
actionMenuEntry.scope === ActionMenuEntryScope.Global,
|
||||
)
|
||||
?.map((actionMenuEntry) => ({
|
||||
id: actionMenuEntry.key,
|
||||
label: i18n._(actionMenuEntry.label),
|
||||
Icon: actionMenuEntry.Icon,
|
||||
onCommandClick: actionMenuEntry.onClick,
|
||||
type: CommandType.WorkflowRun,
|
||||
scope: CommandScope.Global,
|
||||
hotKeys: actionMenuEntry.hotKeys,
|
||||
}));
|
||||
|
||||
const fallbackCommands: Command[] = actionMenuEntries
|
||||
?.filter(
|
||||
(actionMenuEntry) =>
|
||||
actionMenuEntry.type === ActionMenuEntryType.Fallback,
|
||||
)
|
||||
?.map((actionMenuEntry) => ({
|
||||
id: actionMenuEntry.key,
|
||||
label: i18n._(actionMenuEntry.label),
|
||||
Icon: actionMenuEntry.Icon,
|
||||
onCommandClick: actionMenuEntry.onClick,
|
||||
type: CommandType.Fallback,
|
||||
scope: CommandScope.Global,
|
||||
hotKeys: actionMenuEntry.hotKeys,
|
||||
}));
|
||||
|
||||
return {
|
||||
navigateCommands,
|
||||
actionRecordSelectionCommands,
|
||||
actionGlobalCommands,
|
||||
actionObjectCommands,
|
||||
workflowRunRecordSelectionCommands,
|
||||
workflowRunGlobalCommands,
|
||||
fallbackCommands,
|
||||
};
|
||||
};
|
||||
@ -1,40 +1,21 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useCommandMenuOnItemClick = () => {
|
||||
const { toggleCommandMenu } = useCommandMenu();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onItemClick = useCallback(
|
||||
({
|
||||
shouldCloseCommandMenuOnClick,
|
||||
onClick,
|
||||
to,
|
||||
}: {
|
||||
shouldCloseCommandMenuOnClick?: boolean;
|
||||
onClick?: () => void;
|
||||
to?: string;
|
||||
}) => {
|
||||
if (
|
||||
isDefined(shouldCloseCommandMenuOnClick) &&
|
||||
shouldCloseCommandMenuOnClick
|
||||
) {
|
||||
toggleCommandMenu();
|
||||
}
|
||||
|
||||
({ onClick, to }: { onClick?: () => void; to?: string }) => {
|
||||
if (isDefined(onClick)) {
|
||||
onClick();
|
||||
return;
|
||||
}
|
||||
if (isNonEmptyString(to)) {
|
||||
navigate(to);
|
||||
return;
|
||||
}
|
||||
},
|
||||
[navigate, toggleCommandMenu],
|
||||
[navigate],
|
||||
);
|
||||
|
||||
return { onItemClick };
|
||||
|
||||
@ -1,14 +1,19 @@
|
||||
import { Action } from '@/action-menu/actions/components/Action';
|
||||
import { ActionLink } from '@/action-menu/actions/components/ActionLink';
|
||||
import { ActionScope } from '@/action-menu/actions/types/ActionScope';
|
||||
import { ActionType } from '@/action-menu/actions/types/ActionType';
|
||||
import { MAX_SEARCH_RESULTS } from '@/command-menu/constants/MaxSearchResults';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
import { Avatar } from 'twenty-ui/display';
|
||||
import { useDebounce } from 'use-debounce';
|
||||
import { useSearchQuery } from '~/generated/graphql';
|
||||
import { Avatar } from 'twenty-ui/display';
|
||||
|
||||
export const useCommandMenuSearchRecords = () => {
|
||||
const commandMenuSearch = useRecoilValue(commandMenuSearchState);
|
||||
@ -25,14 +30,14 @@ export const useCommandMenuSearchRecords = () => {
|
||||
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
const commands = useMemo(() => {
|
||||
return (searchData?.search ?? []).map((searchRecord) => {
|
||||
const command = {
|
||||
id: searchRecord.recordId,
|
||||
const actionItems = useMemo(() => {
|
||||
return (searchData?.search ?? []).map((searchRecord, index) => {
|
||||
const baseAction = {
|
||||
type: ActionType.Navigation,
|
||||
scope: ActionScope.Global,
|
||||
key: searchRecord.recordId,
|
||||
label: searchRecord.label,
|
||||
description: capitalize(searchRecord.objectNameSingular),
|
||||
to: `object/${searchRecord.objectNameSingular}/${searchRecord.recordId}`,
|
||||
shouldCloseCommandMenuOnClick: true,
|
||||
position: index,
|
||||
Icon: () => (
|
||||
<Avatar
|
||||
type={
|
||||
@ -45,39 +50,59 @@ export const useCommandMenuSearchRecords = () => {
|
||||
placeholder={searchRecord.label}
|
||||
/>
|
||||
),
|
||||
shouldBeRegistered: () => true,
|
||||
description: capitalize(searchRecord.objectNameSingular),
|
||||
shouldCloseCommandMenuOnClick: true,
|
||||
};
|
||||
|
||||
if (
|
||||
[CoreObjectNameSingular.Task, CoreObjectNameSingular.Note].includes(
|
||||
searchRecord.objectNameSingular as CoreObjectNameSingular,
|
||||
)
|
||||
) {
|
||||
return {
|
||||
...command,
|
||||
to: '',
|
||||
onCommandClick: () => {
|
||||
searchRecord.objectNameSingular === 'task'
|
||||
? openRecordInCommandMenu({
|
||||
recordId: searchRecord.recordId,
|
||||
objectNameSingular: CoreObjectNameSingular.Task,
|
||||
})
|
||||
: openRecordInCommandMenu({
|
||||
recordId: searchRecord.recordId,
|
||||
objectNameSingular: CoreObjectNameSingular.Note,
|
||||
});
|
||||
},
|
||||
...baseAction,
|
||||
component: (
|
||||
<Action
|
||||
onClick={() => {
|
||||
searchRecord.objectNameSingular === 'task'
|
||||
? openRecordInCommandMenu({
|
||||
recordId: searchRecord.recordId,
|
||||
objectNameSingular: CoreObjectNameSingular.Task,
|
||||
})
|
||||
: openRecordInCommandMenu({
|
||||
recordId: searchRecord.recordId,
|
||||
objectNameSingular: CoreObjectNameSingular.Note,
|
||||
});
|
||||
}}
|
||||
preventCommandMenuClosing
|
||||
/>
|
||||
),
|
||||
};
|
||||
}
|
||||
return command;
|
||||
|
||||
return {
|
||||
...baseAction,
|
||||
component: (
|
||||
<ActionLink
|
||||
to={AppPath.RecordShowPage}
|
||||
params={{
|
||||
objectNameSingular: searchRecord.objectNameSingular,
|
||||
objectRecordId: searchRecord.recordId,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
};
|
||||
});
|
||||
}, [searchData, openRecordInCommandMenu]);
|
||||
|
||||
return {
|
||||
loading,
|
||||
noResults: !commands?.length,
|
||||
noResults: !actionItems?.length,
|
||||
commandGroups: [
|
||||
{
|
||||
heading: t`Results`,
|
||||
items: commands,
|
||||
items: actionItems,
|
||||
},
|
||||
],
|
||||
hasMore: false,
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||
@ -106,21 +105,6 @@ export const useCopyContextStoreStates = () => {
|
||||
}),
|
||||
contextStoreCurrentViewType,
|
||||
);
|
||||
|
||||
const actionMenuEntries = snapshot
|
||||
.getLoadable(
|
||||
actionMenuEntriesComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyFrom,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
set(
|
||||
actionMenuEntriesComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyTo,
|
||||
}),
|
||||
actionMenuEntries,
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
import { ActionConfig } from '@/action-menu/actions/types/ActionConfig';
|
||||
import { getActionLabel } from '@/action-menu/utils/getActionLabel';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useDebounce } from 'use-debounce';
|
||||
|
||||
export const useFilterActionsWithCommandMenuSearch = ({
|
||||
commandMenuSearch,
|
||||
}: {
|
||||
commandMenuSearch: string;
|
||||
}) => {
|
||||
const [deferredCommandMenuSearch] = useDebounce(commandMenuSearch, 300); // 200ms - 500ms
|
||||
|
||||
const checkInShortcuts = (action: ActionConfig, search: string) => {
|
||||
const concatenatedString = action.hotKeys?.join('') ?? '';
|
||||
return concatenatedString
|
||||
.toLowerCase()
|
||||
.includes(search.toLowerCase().trim());
|
||||
};
|
||||
|
||||
const checkInLabels = (action: ActionConfig, search: string) => {
|
||||
const actionLabel = getActionLabel(action.label);
|
||||
if (isNonEmptyString(actionLabel)) {
|
||||
return actionLabel.toLowerCase().includes(search.toLowerCase());
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const filterActionsWithCommandMenuSearch = (actions: ActionConfig[]) => {
|
||||
return actions.filter((action) =>
|
||||
deferredCommandMenuSearch.length > 0
|
||||
? checkInShortcuts(action, deferredCommandMenuSearch) ||
|
||||
checkInLabels(action, deferredCommandMenuSearch)
|
||||
: true,
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
filterActionsWithCommandMenuSearch,
|
||||
};
|
||||
};
|
||||
@ -1,38 +0,0 @@
|
||||
import { Command } from '@/command-menu/types/Command';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useDebounce } from 'use-debounce';
|
||||
|
||||
export const useMatchCommands = ({
|
||||
commandMenuSearch,
|
||||
}: {
|
||||
commandMenuSearch: string;
|
||||
}) => {
|
||||
const [deferredCommandMenuSearch] = useDebounce(commandMenuSearch, 300); // 200ms - 500ms
|
||||
|
||||
const checkInShortcuts = (cmd: Command, search: string) => {
|
||||
const concatenatedString = cmd.hotKeys?.join('') ?? '';
|
||||
return concatenatedString
|
||||
.toLowerCase()
|
||||
.includes(search.toLowerCase().trim());
|
||||
};
|
||||
|
||||
const checkInLabels = (cmd: Command, search: string) => {
|
||||
if (isNonEmptyString(cmd.label)) {
|
||||
return cmd.label.toLowerCase().includes(search.toLowerCase());
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const matchCommands = (commands: Command[]) => {
|
||||
return commands.filter((cmd) =>
|
||||
deferredCommandMenuSearch.length > 0
|
||||
? checkInShortcuts(cmd, deferredCommandMenuSearch) ||
|
||||
checkInLabels(cmd, deferredCommandMenuSearch)
|
||||
: true,
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
matchCommands,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,61 @@
|
||||
import { useCommandMenuActions } from '@/command-menu/hooks/useCommandMenuActions';
|
||||
import { useFilterActionsWithCommandMenuSearch } from '@/command-menu/hooks/useFilterActionsWithCommandMenuSearch';
|
||||
|
||||
export const useMatchingCommandMenuActions = ({
|
||||
commandMenuSearch,
|
||||
}: {
|
||||
commandMenuSearch: string;
|
||||
}) => {
|
||||
const { filterActionsWithCommandMenuSearch } =
|
||||
useFilterActionsWithCommandMenuSearch({
|
||||
commandMenuSearch,
|
||||
});
|
||||
|
||||
const {
|
||||
navigateActions,
|
||||
actionRecordSelectionActions,
|
||||
actionObjectActions,
|
||||
actionGlobalActions,
|
||||
workflowRunRecordSelectionActions,
|
||||
workflowRunGlobalActions,
|
||||
fallbackActions,
|
||||
} = useCommandMenuActions();
|
||||
|
||||
const matchingNavigateActions =
|
||||
filterActionsWithCommandMenuSearch(navigateActions);
|
||||
|
||||
const matchingStandardActionRecordSelectionActions =
|
||||
filterActionsWithCommandMenuSearch(actionRecordSelectionActions);
|
||||
|
||||
const matchingStandardActionObjectActions =
|
||||
filterActionsWithCommandMenuSearch(actionObjectActions);
|
||||
|
||||
const matchingStandardActionGlobalActions =
|
||||
filterActionsWithCommandMenuSearch(actionGlobalActions);
|
||||
|
||||
const matchingWorkflowRunRecordSelectionActions =
|
||||
filterActionsWithCommandMenuSearch(workflowRunRecordSelectionActions);
|
||||
|
||||
const matchingWorkflowRunGlobalActions = filterActionsWithCommandMenuSearch(
|
||||
workflowRunGlobalActions,
|
||||
);
|
||||
|
||||
const noResults =
|
||||
!matchingStandardActionRecordSelectionActions.length &&
|
||||
!matchingWorkflowRunRecordSelectionActions.length &&
|
||||
!matchingStandardActionGlobalActions.length &&
|
||||
!matchingWorkflowRunGlobalActions.length &&
|
||||
!matchingStandardActionObjectActions.length &&
|
||||
!matchingNavigateActions.length;
|
||||
|
||||
return {
|
||||
noResults,
|
||||
matchingStandardActionRecordSelectionActions,
|
||||
matchingStandardActionObjectActions,
|
||||
matchingWorkflowRunRecordSelectionActions,
|
||||
matchingStandardActionGlobalActions,
|
||||
matchingWorkflowRunGlobalActions,
|
||||
matchingNavigateActions,
|
||||
fallbackActions: noResults ? fallbackActions : [],
|
||||
};
|
||||
};
|
||||
@ -1,59 +0,0 @@
|
||||
import { useCommandMenuCommands } from '@/command-menu/hooks/useCommandMenuCommands';
|
||||
import { useMatchCommands } from '@/command-menu/hooks/useMatchCommands';
|
||||
|
||||
export const useMatchingCommandMenuCommands = ({
|
||||
commandMenuSearch,
|
||||
}: {
|
||||
commandMenuSearch: string;
|
||||
}) => {
|
||||
const { matchCommands } = useMatchCommands({ commandMenuSearch });
|
||||
|
||||
const {
|
||||
navigateCommands,
|
||||
actionRecordSelectionCommands,
|
||||
actionObjectCommands,
|
||||
actionGlobalCommands,
|
||||
workflowRunRecordSelectionCommands,
|
||||
workflowRunGlobalCommands,
|
||||
fallbackCommands,
|
||||
} = useCommandMenuCommands();
|
||||
|
||||
const matchingNavigateCommands = matchCommands(navigateCommands);
|
||||
|
||||
const matchingStandardActionRecordSelectionCommands = matchCommands(
|
||||
actionRecordSelectionCommands,
|
||||
);
|
||||
|
||||
const matchingStandardActionObjectCommands =
|
||||
matchCommands(actionObjectCommands);
|
||||
|
||||
const matchingStandardActionGlobalCommands =
|
||||
matchCommands(actionGlobalCommands);
|
||||
|
||||
const matchingWorkflowRunRecordSelectionCommands = matchCommands(
|
||||
workflowRunRecordSelectionCommands,
|
||||
);
|
||||
|
||||
const matchingWorkflowRunGlobalCommands = matchCommands(
|
||||
workflowRunGlobalCommands,
|
||||
);
|
||||
|
||||
const noResults =
|
||||
!matchingStandardActionRecordSelectionCommands.length &&
|
||||
!matchingWorkflowRunRecordSelectionCommands.length &&
|
||||
!matchingStandardActionGlobalCommands.length &&
|
||||
!matchingWorkflowRunGlobalCommands.length &&
|
||||
!matchingStandardActionObjectCommands.length &&
|
||||
!matchingNavigateCommands.length;
|
||||
|
||||
return {
|
||||
noResults,
|
||||
matchingStandardActionRecordSelectionCommands,
|
||||
matchingStandardActionObjectCommands,
|
||||
matchingWorkflowRunRecordSelectionCommands,
|
||||
matchingStandardActionGlobalCommands,
|
||||
matchingWorkflowRunGlobalCommands,
|
||||
matchingNavigateCommands,
|
||||
fallbackCommands: noResults ? fallbackCommands : [],
|
||||
};
|
||||
};
|
||||
@ -15,8 +15,8 @@ import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainCo
|
||||
import { isDragSelectionStartEnabledState } from '@/ui/utilities/drag-select/states/internal/isDragSelectionStartEnabledState';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
import { IconComponent } from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export type CommandMenuNavigationStackItem = {
|
||||
page: CommandMenuPages;
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
@ -47,20 +45,6 @@ export const useResetContextStoreStates = () => {
|
||||
}),
|
||||
undefined,
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreCurrentViewTypeComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
|
||||
set(
|
||||
actionMenuEntriesComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
new Map(),
|
||||
);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@ -6,7 +6,9 @@ export const CommandMenuSearchRecordsPage = () => {
|
||||
const { commandGroups, loading, noResults } = useCommandMenuSearchRecords();
|
||||
|
||||
const selectableItemIds = useMemo(() => {
|
||||
return commandGroups.flatMap((group) => group.items).map((item) => item.id);
|
||||
return commandGroups
|
||||
.flatMap((group) => group.items)
|
||||
.map((item) => item.key);
|
||||
}, [commandGroups]);
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user