make command menu actions searchable

This commit is contained in:
bosiraphael
2024-10-23 11:39:34 +02:00
parent 08c8dddf3b
commit fcc4f0bb80
3 changed files with 46 additions and 12 deletions

View File

@@ -31,7 +31,7 @@ import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import styled from '@emotion/styled';
import { isNonEmptyString } from '@sniptt/guards';
import { useMemo, useRef } from 'react';
import { useMemo, useRef, useState } from 'react';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { Key } from 'ts-key-enum';
import { Avatar, IconNotes, IconSparkles, IconX, isDefined } from 'twenty-ui';
@@ -146,6 +146,8 @@ export const CommandMenu = () => {
setCommandMenuSearch(event.target.value);
};
const [actionCommands, setActionCommands] = useState<Command[]>([]);
const isMobile = useIsMobile();
useScopedHotkeys(
@@ -290,6 +292,14 @@ export const CommandMenu = () => {
: true) && cmd.type === CommandType.Create,
);
const matchingActionCommands = actionCommands.filter(
(cmd) =>
(deferredCommandMenuSearch.length > 0
? checkInShortcuts(cmd, deferredCommandMenuSearch) ||
checkInLabels(cmd, deferredCommandMenuSearch)
: true) && cmd.type === CommandType.Action,
);
useListenClickOutside({
refs: [commandMenuRef],
callback: closeCommandMenu,
@@ -315,6 +325,7 @@ export const CommandMenu = () => {
const selectableItemIds = copilotCommands
.map((cmd) => cmd.id)
.concat(matchingActionCommands.map((cmd) => cmd.id))
.concat(matchingCreateCommand.map((cmd) => cmd.id))
.concat(matchingNavigateCommand.map((cmd) => cmd.id))
.concat(people?.map((person) => person.id))
@@ -323,12 +334,14 @@ export const CommandMenu = () => {
.concat(notes?.map((note) => note.id));
const isNoResults =
!matchingActionCommands.length &&
!matchingCreateCommand.length &&
!matchingNavigateCommand.length &&
!people?.length &&
!companies?.length &&
!notes?.length &&
!opportunities?.length;
const isLoading =
isPeopleLoading ||
isNotesLoading ||
@@ -370,6 +383,7 @@ export const CommandMenu = () => {
hotkeyScope={AppHotkeyScope.CommandMenu}
onEnter={(itemId) => {
const command = [
...actionCommands,
...copilotCommands,
...commandMenuCommands,
...otherCommands,
@@ -405,6 +419,8 @@ export const CommandMenu = () => {
mainContextStoreComponentInstanceId={
mainContextStoreComponentInstanceId
}
matchingActionCommands={matchingActionCommands}
setActionCommands={setActionCommands}
/>
)}
<CommandGroup heading="Create">

View File

@@ -1,31 +1,48 @@
import { CommandGroup } from '@/command-menu/components/CommandGroup';
import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem';
import { Command, CommandType } from '@/command-menu/types/Command';
import { contextStoreActionMenuEntriesComponentSelector } from '@/context-store/states/contextStoreActionMenuEntriesComponentSelector';
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useEffect, useMemo } from 'react';
export const CommandMenuActions = ({
mainContextStoreComponentInstanceId,
matchingActionCommands,
setActionCommands,
}: {
mainContextStoreComponentInstanceId: string;
matchingActionCommands: Command[];
setActionCommands: (actionCommands: Command[]) => void;
}) => {
const actionMenuEntries = useRecoilComponentValueV2(
contextStoreActionMenuEntriesComponentSelector,
mainContextStoreComponentInstanceId,
);
const actionCommands = useMemo(() => {
return actionMenuEntries?.map((actionMenuEntry) => ({
id: actionMenuEntry.label,
label: actionMenuEntry.label,
Icon: actionMenuEntry.Icon,
onCommandClick: actionMenuEntry.onClick,
type: CommandType.Action,
}));
}, [actionMenuEntries]);
useEffect(() => {
setActionCommands(actionCommands);
}, [actionCommands, setActionCommands]);
return (
<CommandGroup heading="Actions">
{actionMenuEntries?.map((actionMenuEntry) => (
<SelectableItem
itemId={actionMenuEntry.label}
key={actionMenuEntry.label}
>
{matchingActionCommands?.map((actionCommand) => (
<SelectableItem itemId={actionCommand.id} key={actionCommand.id}>
<CommandMenuItem
id={actionMenuEntry.label}
label={actionMenuEntry.label}
Icon={actionMenuEntry.Icon}
onClick={actionMenuEntry.onClick}
id={actionCommand.id}
label={actionCommand.label}
Icon={actionCommand.Icon}
onClick={actionCommand.onCommandClick}
/>
</SelectableItem>
))}

View File

@@ -3,13 +3,14 @@ import { IconComponent } from 'twenty-ui';
export enum CommandType {
Navigate = 'Navigate',
Create = 'Create',
Action = 'Action',
}
export type Command = {
id: string;
to: string;
to?: string;
label: string;
type: CommandType.Navigate | CommandType.Create;
type: CommandType.Navigate | CommandType.Create | CommandType.Action;
Icon?: IconComponent;
firstHotKey?: string;
secondHotKey?: string;