Command menu search bar (#4337)

* Improve performance on findMany queries

* Fix

* Fix command menu not emptying the search on toggle

* Fix tests
This commit is contained in:
Charles Bochet
2024-03-06 14:20:05 +01:00
committed by GitHub
parent e7857d7fa3
commit b08b361dc0
4 changed files with 59 additions and 113 deletions

View File

@ -1,10 +1,11 @@
import { useMemo, useRef, useState } from 'react'; import { useMemo, useRef } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil'; import { useRecoilState, useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum'; import { Key } from 'ts-key-enum';
import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer'; import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer';
import { Activity } from '@/activities/types/Activity'; import { Activity } from '@/activities/types/Activity';
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
import { Company } from '@/companies/types/Company'; import { Company } from '@/companies/types/Company';
import { useKeyboardShortcutMenu } from '@/keyboard-shortcut-menu/hooks/useKeyboardShortcutMenu'; import { useKeyboardShortcutMenu } from '@/keyboard-shortcut-menu/hooks/useKeyboardShortcutMenu';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
@ -105,23 +106,24 @@ export const CommandMenu = () => {
const openActivityRightDrawer = useOpenActivityRightDrawer(); const openActivityRightDrawer = useOpenActivityRightDrawer();
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState); const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
const [search, setSearch] = useState(''); const [commandMenuSearch, setCommandMenuSearch] = useRecoilState(
commandMenuSearchState,
);
const commandMenuCommands = useRecoilValue(commandMenuCommandsState); const commandMenuCommands = useRecoilValue(commandMenuCommandsState);
const { closeKeyboardShortcutMenu } = useKeyboardShortcutMenu(); const { closeKeyboardShortcutMenu } = useKeyboardShortcutMenu();
const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => { const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearch(event.target.value); setCommandMenuSearch(event.target.value);
}; };
useScopedHotkeys( useScopedHotkeys(
'ctrl+k,meta+k', 'ctrl+k,meta+k',
() => { () => {
closeKeyboardShortcutMenu(); closeKeyboardShortcutMenu();
setSearch('');
toggleCommandMenu(); toggleCommandMenu();
}, },
AppHotkeyScope.CommandMenu, AppHotkeyScope.CommandMenu,
[toggleCommandMenu, setSearch], [toggleCommandMenu],
); );
useScopedHotkeys( useScopedHotkeys(
@ -136,12 +138,12 @@ export const CommandMenu = () => {
const { records: people } = useFindManyRecords<Person>({ const { records: people } = useFindManyRecords<Person>({
skip: !isCommandMenuOpened, skip: !isCommandMenuOpened,
objectNameSingular: CoreObjectNameSingular.Person, objectNameSingular: CoreObjectNameSingular.Person,
filter: search filter: commandMenuSearch
? makeOrFilterVariables([ ? makeOrFilterVariables([
{ name: { firstName: { ilike: `%${search}%` } } }, { name: { firstName: { ilike: `%${commandMenuSearch}%` } } },
{ name: { lastName: { ilike: `%${search}%` } } }, { name: { lastName: { ilike: `%${commandMenuSearch}%` } } },
{ email: { ilike: `%${search}%` } }, { email: { ilike: `%${commandMenuSearch}%` } },
{ phone: { ilike: `%${search}%` } }, { phone: { ilike: `%${commandMenuSearch}%` } },
]) ])
: undefined, : undefined,
limit: 3, limit: 3,
@ -150,9 +152,9 @@ export const CommandMenu = () => {
const { records: companies } = useFindManyRecords<Company>({ const { records: companies } = useFindManyRecords<Company>({
skip: !isCommandMenuOpened, skip: !isCommandMenuOpened,
objectNameSingular: CoreObjectNameSingular.Company, objectNameSingular: CoreObjectNameSingular.Company,
filter: search filter: commandMenuSearch
? { ? {
name: { ilike: `%${search}%` }, name: { ilike: `%${commandMenuSearch}%` },
} }
: undefined, : undefined,
limit: 3, limit: 3,
@ -161,10 +163,10 @@ export const CommandMenu = () => {
const { records: activities } = useFindManyRecords<Activity>({ const { records: activities } = useFindManyRecords<Activity>({
skip: !isCommandMenuOpened, skip: !isCommandMenuOpened,
objectNameSingular: CoreObjectNameSingular.Activity, objectNameSingular: CoreObjectNameSingular.Activity,
filter: search filter: commandMenuSearch
? makeOrFilterVariables([ ? makeOrFilterVariables([
{ title: { ilike: `%${search}%` } }, { title: { ilike: `%${commandMenuSearch}%` } },
{ body: { ilike: `%${search}%` } }, { body: { ilike: `%${commandMenuSearch}%` } },
]) ])
: undefined, : undefined,
limit: 3, limit: 3,
@ -224,15 +226,17 @@ export const CommandMenu = () => {
const matchingNavigateCommand = commandMenuCommands.filter( const matchingNavigateCommand = commandMenuCommands.filter(
(cmd) => (cmd) =>
(search.length > 0 (commandMenuSearch.length > 0
? checkInShortcuts(cmd, search) || checkInLabels(cmd, search) ? checkInShortcuts(cmd, commandMenuSearch) ||
checkInLabels(cmd, commandMenuSearch)
: true) && cmd.type === CommandType.Navigate, : true) && cmd.type === CommandType.Navigate,
); );
const matchingCreateCommand = commandMenuCommands.filter( const matchingCreateCommand = commandMenuCommands.filter(
(cmd) => (cmd) =>
(search.length > 0 (commandMenuSearch.length > 0
? checkInShortcuts(cmd, search) || checkInLabels(cmd, search) ? checkInShortcuts(cmd, commandMenuSearch) ||
checkInLabels(cmd, commandMenuSearch)
: true) && cmd.type === CommandType.Create, : true) && cmd.type === CommandType.Create,
); );
@ -254,7 +258,7 @@ export const CommandMenu = () => {
<StyledDialog ref={commandMenuRef}> <StyledDialog ref={commandMenuRef}>
<StyledInput <StyledInput
autoFocus autoFocus
value={search} value={commandMenuSearch}
placeholder="Search" placeholder="Search"
onChange={handleSearchChange} onChange={handleSearchChange}
/> />

View File

@ -2,6 +2,7 @@ import { useCallback } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useRecoilCallback, useSetRecoilState } from 'recoil'; import { useRecoilCallback, useSetRecoilState } from 'recoil';
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope'; import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
@ -42,17 +43,22 @@ export const useCommandMenu = () => {
[goBackToPreviousHotkeyScope, resetSelectedItem, setIsCommandMenuOpened], [goBackToPreviousHotkeyScope, resetSelectedItem, setIsCommandMenuOpened],
); );
const toggleCommandMenu = useRecoilCallback(({ snapshot }) => async () => { const toggleCommandMenu = useRecoilCallback(
({ snapshot, set }) =>
async () => {
const isCommandMenuOpened = snapshot const isCommandMenuOpened = snapshot
.getLoadable(isCommandMenuOpenedState) .getLoadable(isCommandMenuOpenedState)
.getValue(); .getValue();
set(commandMenuSearchState, '');
if (isCommandMenuOpened) { if (isCommandMenuOpened) {
closeCommandMenu(); closeCommandMenu();
} else { } else {
openCommandMenu(); openCommandMenu();
} }
}); },
);
const addToCommandMenu = useCallback( const addToCommandMenu = useCallback(
(addCommand: Command[]) => { (addCommand: Command[]) => {

View File

@ -0,0 +1,6 @@
import { atom } from 'recoil';
export const commandMenuSearchState = atom<string>({
key: 'command-menu/commandMenuSearchState',
default: '',
});

View File

@ -28,35 +28,12 @@ const getOneToManyRelation = () => {
label label
url url
} }
accountOwner
{
__typename
id
}
linkedinLink linkedinLink
{ {
label label
url url
} }
attachments
{
edges {
node {
__typename
id
}
}
}
domainName domainName
opportunities
{
edges {
node {
__typename
id
}
}
}
annualRecurringRevenue annualRecurringRevenue
{ {
amountMicros amountMicros
@ -65,33 +42,6 @@ opportunities
createdAt createdAt
address address
updatedAt updatedAt
activityTargets
{
edges {
node {
__typename
id
}
}
}
favorites
{
edges {
node {
__typename
id
}
}
}
people
{
edges {
node {
__typename
id
}
}
}
name name
accountOwnerId accountOwnerId
employees employees
@ -141,19 +91,9 @@ const getOneToManyFromRelationField = () => {
personId personId
pointOfContactId pointOfContactId
updatedAt updatedAt
company
{
__typename
id
}
companyId companyId
pipelineStepId pipelineStepId
probability probability
pipelineStep
{
__typename
id
}
closeDate closeDate
amount amount
{ {
@ -162,16 +102,6 @@ closeDate
} }
id id
createdAt createdAt
pointOfContact
{
__typename
id
}
person
{
__typename
id
}
} }
} }
}`, }`,