Skip to content

Commit

Permalink
Command menu search bar (twentyhq#4337)
Browse files Browse the repository at this point in the history
* Improve performance on findMany queries

* Fix

* Fix command menu not emptying the search on toggle

* Fix tests
  • Loading branch information
charlesBochet authored Mar 6, 2024
1 parent 0359e0c commit b02a9ce
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 113 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useMemo, useRef, useState } from 'react';
import { useMemo, useRef } from 'react';
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { useRecoilState, useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';

import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer';
import { Activity } from '@/activities/types/Activity';
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
import { Company } from '@/companies/types/Company';
import { useKeyboardShortcutMenu } from '@/keyboard-shortcut-menu/hooks/useKeyboardShortcutMenu';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
Expand Down Expand Up @@ -105,23 +106,24 @@ export const CommandMenu = () => {

const openActivityRightDrawer = useOpenActivityRightDrawer();
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
const [search, setSearch] = useState('');
const [commandMenuSearch, setCommandMenuSearch] = useRecoilState(
commandMenuSearchState,
);
const commandMenuCommands = useRecoilValue(commandMenuCommandsState);
const { closeKeyboardShortcutMenu } = useKeyboardShortcutMenu();

const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearch(event.target.value);
setCommandMenuSearch(event.target.value);
};

useScopedHotkeys(
'ctrl+k,meta+k',
() => {
closeKeyboardShortcutMenu();
setSearch('');
toggleCommandMenu();
},
AppHotkeyScope.CommandMenu,
[toggleCommandMenu, setSearch],
[toggleCommandMenu],
);

useScopedHotkeys(
Expand All @@ -136,12 +138,12 @@ export const CommandMenu = () => {
const { records: people } = useFindManyRecords<Person>({
skip: !isCommandMenuOpened,
objectNameSingular: CoreObjectNameSingular.Person,
filter: search
filter: commandMenuSearch
? makeOrFilterVariables([
{ name: { firstName: { ilike: `%${search}%` } } },
{ name: { lastName: { ilike: `%${search}%` } } },
{ email: { ilike: `%${search}%` } },
{ phone: { ilike: `%${search}%` } },
{ name: { firstName: { ilike: `%${commandMenuSearch}%` } } },
{ name: { lastName: { ilike: `%${commandMenuSearch}%` } } },
{ email: { ilike: `%${commandMenuSearch}%` } },
{ phone: { ilike: `%${commandMenuSearch}%` } },
])
: undefined,
limit: 3,
Expand All @@ -150,9 +152,9 @@ export const CommandMenu = () => {
const { records: companies } = useFindManyRecords<Company>({
skip: !isCommandMenuOpened,
objectNameSingular: CoreObjectNameSingular.Company,
filter: search
filter: commandMenuSearch
? {
name: { ilike: `%${search}%` },
name: { ilike: `%${commandMenuSearch}%` },
}
: undefined,
limit: 3,
Expand All @@ -161,10 +163,10 @@ export const CommandMenu = () => {
const { records: activities } = useFindManyRecords<Activity>({
skip: !isCommandMenuOpened,
objectNameSingular: CoreObjectNameSingular.Activity,
filter: search
filter: commandMenuSearch
? makeOrFilterVariables([
{ title: { ilike: `%${search}%` } },
{ body: { ilike: `%${search}%` } },
{ title: { ilike: `%${commandMenuSearch}%` } },
{ body: { ilike: `%${commandMenuSearch}%` } },
])
: undefined,
limit: 3,
Expand Down Expand Up @@ -224,15 +226,17 @@ export const CommandMenu = () => {

const matchingNavigateCommand = commandMenuCommands.filter(
(cmd) =>
(search.length > 0
? checkInShortcuts(cmd, search) || checkInLabels(cmd, search)
(commandMenuSearch.length > 0
? checkInShortcuts(cmd, commandMenuSearch) ||
checkInLabels(cmd, commandMenuSearch)
: true) && cmd.type === CommandType.Navigate,
);

const matchingCreateCommand = commandMenuCommands.filter(
(cmd) =>
(search.length > 0
? checkInShortcuts(cmd, search) || checkInLabels(cmd, search)
(commandMenuSearch.length > 0
? checkInShortcuts(cmd, commandMenuSearch) ||
checkInLabels(cmd, commandMenuSearch)
: true) && cmd.type === CommandType.Create,
);

Expand All @@ -254,7 +258,7 @@ export const CommandMenu = () => {
<StyledDialog ref={commandMenuRef}>
<StyledInput
autoFocus
value={search}
value={commandMenuSearch}
placeholder="Search"
onChange={handleSearchChange}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { useRecoilCallback, useSetRecoilState } from 'recoil';

import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
Expand Down Expand Up @@ -42,17 +43,22 @@ export const useCommandMenu = () => {
[goBackToPreviousHotkeyScope, resetSelectedItem, setIsCommandMenuOpened],
);

const toggleCommandMenu = useRecoilCallback(({ snapshot }) => async () => {
const isCommandMenuOpened = snapshot
.getLoadable(isCommandMenuOpenedState)
.getValue();
const toggleCommandMenu = useRecoilCallback(
({ snapshot, set }) =>
async () => {
const isCommandMenuOpened = snapshot
.getLoadable(isCommandMenuOpenedState)
.getValue();

set(commandMenuSearchState, '');

if (isCommandMenuOpened) {
closeCommandMenu();
} else {
openCommandMenu();
}
});
if (isCommandMenuOpened) {
closeCommandMenu();
} else {
openCommandMenu();
}
},
);

const addToCommandMenu = useCallback(
(addCommand: Command[]) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { atom } from 'recoil';

export const commandMenuSearchState = atom<string>({
key: 'command-menu/commandMenuSearchState',
default: '',
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,43 +20,20 @@ const getOneToManyRelation = () => {
return {
field: objectMetadataItem.fields.find((field) => field.name === 'company')!,
res: `company
{
__typename
id
{
__typename
id
xLink
{
label
url
}
accountOwner
{
__typename
id
}
linkedinLink
{
label
url
}
attachments
{
edges {
node {
__typename
id
}
}
}
domainName
opportunities
{
edges {
node {
__typename
id
}
}
}
annualRecurringRevenue
{
amountMicros
Expand All @@ -65,39 +42,12 @@ opportunities
createdAt
address
updatedAt
activityTargets
{
edges {
node {
__typename
id
}
}
}
favorites
{
edges {
node {
__typename
id
}
}
}
people
{
edges {
node {
__typename
id
}
}
}
name
accountOwnerId
employees
id
idealCustomerProfile
}`,
}`,
};
};

Expand Down Expand Up @@ -133,27 +83,17 @@ const getOneToManyFromRelationField = () => {
return {
field,
res: `opportunities
{
edges {
node {
__typename
id
personId
{
edges {
node {
__typename
id
personId
pointOfContactId
updatedAt
company
{
__typename
id
}
companyId
pipelineStepId
probability
pipelineStep
{
__typename
id
}
closeDate
amount
{
Expand All @@ -162,19 +102,9 @@ closeDate
}
id
createdAt
pointOfContact
{
__typename
id
}
person
{
__typename
id
}
}
}
}
}`,
}`,
};
};

Expand Down

0 comments on commit b02a9ce

Please sign in to comment.