From 49e4484937df8c42f68255115413d29e0de0f760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Mon, 3 Feb 2025 15:54:24 +0100 Subject: [PATCH] 324 add search records as a fallback action in case of no results (#9976) Closes https://github.com/twentyhq/core-team-issues/issues/324 Fixed typos: 'No results' is used when multiple results are expected and 'No result' is used when only one result is expected. https://github.com/user-attachments/assets/e3655ced-465a-44b1-92af-63878b9d8a94 --- .../command-menu/components/CommandMenu.tsx | 6 +++ .../components/CommandMenuList.tsx | 6 +-- .../__stories__/CommandMenu.stories.tsx | 48 +++++++++++++++++-- .../hooks/useCommandMenuCommands.tsx | 21 ++++++++ .../hooks/useMatchingCommandMenuCommands.ts | 2 + .../ObjectFilterDropdownOptionSelect.tsx | 2 +- .../components/MultipleSelectDropdown.tsx | 2 +- .../components/MatchColumnSelect.tsx | 2 +- .../CurrencyPickerDropdownSelect.tsx | 2 +- .../PhoneCountryPickerDropdownSelect.tsx | 2 +- 10 files changed, 81 insertions(+), 12 deletions(-) diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx index 19ed37ad0..2be276609 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx @@ -32,6 +32,7 @@ export const CommandMenu = () => { matchingStandardActionGlobalCommands, matchingWorkflowRunGlobalCommands, matchingNavigateCommands, + fallbackCommands, } = useMatchingCommandMenuCommands({ commandMenuSearch, }); @@ -44,6 +45,7 @@ export const CommandMenu = () => { matchingStandardActionGlobalCommands, matchingWorkflowRunGlobalCommands, matchingNavigateCommands, + fallbackCommands, ) .filter(isDefined); @@ -79,6 +81,10 @@ export const CommandMenu = () => { .concat(matchingNavigateCommands) .concat(matchingWorkflowRunGlobalCommands), }, + { + heading: t`Search ''${commandMenuSearch}'' with...`, + items: fallbackCommands, + }, ]; return ( diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuList.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuList.tsx index 6667fbe67..2b0c61739 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuList.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuList.tsx @@ -111,9 +111,6 @@ export const CommandMenuList = ({ }} > {children} - {noResults && !loading && ( - No result found - )} {commandGroups.map(({ heading, items }) => items?.length ? ( @@ -139,6 +136,9 @@ export const CommandMenuList = ({ ) : null, )} + {noResults && !loading && ( + No results found + )} diff --git a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx index 96fbedc8f..3c6c9c920 100644 --- a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx @@ -8,7 +8,6 @@ import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWith import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { getCompaniesMock } from '~/testing/mock-data/companies'; import { mockCurrentWorkspace, mockedWorkspaceMemberData, @@ -20,14 +19,16 @@ import { CommandMenuRouter } from '@/command-menu/components/CommandMenuRouter'; import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; +import { HttpResponse, graphql } from 'msw'; import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; import { JestContextStoreSetter } from '~/testing/jest/JestContextStoreSetter'; +import { getCompaniesMock } from '~/testing/mock-data/companies'; import { CommandMenu } from '../CommandMenu'; -const companiesMock = getCompaniesMock(); - const openTimeout = 50; +const companiesMock = getCompaniesMock(); + const ContextStoreDecorator: Decorator = (Story) => { return ( { + const canvas = within(document.body); + const searchInput = await canvas.findByPlaceholderText('Type anything'); + await sleep(openTimeout); + await userEvent.type(searchInput, 'Linkedin'); + expect(await canvas.findByText('No results found')).toBeVisible(); + const searchRecordsButton = await canvas.findByText('Search records'); + expect(searchRecordsButton).toBeVisible(); + await userEvent.click(searchRecordsButton); + expect(await canvas.findByText('Linkedin')).toBeVisible(); + }, + parameters: { + msw: { + handlers: [ + graphql.query('CombinedSearchRecords', () => { + return HttpResponse.json({ + data: { + searchCompanies: { + edges: [ + { + node: companiesMock[0], + cursor: null, + }, + ], + pageInfo: { + hasNextPage: false, + hasPreviousPage: false, + startCursor: null, + endCursor: null, + }, + }, + }, + }); + }), + ], + }, }, }; diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCommands.tsx b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCommands.tsx index 469bda462..2e7897b5e 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCommands.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuCommands.tsx @@ -1,3 +1,4 @@ +import { RecordAgnosticActionsKey } from '@/action-menu/actions/record-agnostic-actions/types/RecordAgnosticActionsKey'; import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector'; import { ActionMenuEntryScope, @@ -128,6 +129,25 @@ export const useCommandMenuCommands = () => { hotKeys: actionMenuEntry.hotKeys, })); + const searchRecordsAction = actionMenuEntries.find( + (actionMenuEntry) => + actionMenuEntry.key === RecordAgnosticActionsKey.SEARCH_RECORDS, + ); + + const fallbackCommands: Command[] = searchRecordsAction + ? [ + { + id: searchRecordsAction.key, + label: i18n._(searchRecordsAction.label), + Icon: searchRecordsAction.Icon, + onCommandClick: searchRecordsAction.onClick, + type: CommandType.StandardAction, + scope: CommandScope.Global, + hotKeys: searchRecordsAction.hotKeys, + }, + ] + : []; + return { copilotCommands, navigateCommands, @@ -136,5 +156,6 @@ export const useCommandMenuCommands = () => { actionObjectCommands, workflowRunRecordSelectionCommands, workflowRunGlobalCommands, + fallbackCommands, }; }; diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useMatchingCommandMenuCommands.ts b/packages/twenty-front/src/modules/command-menu/hooks/useMatchingCommandMenuCommands.ts index 698b0e179..72f66580b 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useMatchingCommandMenuCommands.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useMatchingCommandMenuCommands.ts @@ -16,6 +16,7 @@ export const useMatchingCommandMenuCommands = ({ actionGlobalCommands, workflowRunRecordSelectionCommands, workflowRunGlobalCommands, + fallbackCommands, } = useCommandMenuCommands(); const matchingNavigateCommands = matchCommands(navigateCommands); @@ -55,5 +56,6 @@ export const useMatchingCommandMenuCommands = ({ matchingStandardActionGlobalCommands, matchingWorkflowRunGlobalCommands, matchingNavigateCommands, + fallbackCommands: noResults ? fallbackCommands : [], }; }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx index 8b41f8496..0056a8ad8 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect.tsx @@ -182,7 +182,7 @@ export const ObjectFilterDropdownOptionSelect = () => { /> ))} - {showNoResult && } + {showNoResult && } ); }; diff --git a/packages/twenty-front/src/modules/object-record/select/components/MultipleSelectDropdown.tsx b/packages/twenty-front/src/modules/object-record/select/components/MultipleSelectDropdown.tsx index bb88fbdec..5ca333f95 100644 --- a/packages/twenty-front/src/modules/object-record/select/components/MultipleSelectDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/select/components/MultipleSelectDropdown.tsx @@ -132,7 +132,7 @@ export const MultipleSelectDropdown = ({ /> ); })} - {showNoResult && } + {showNoResult && } {loadingItems && } diff --git a/packages/twenty-front/src/modules/spreadsheet-import/components/MatchColumnSelect.tsx b/packages/twenty-front/src/modules/spreadsheet-import/components/MatchColumnSelect.tsx index 22729baee..303afc38d 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/components/MatchColumnSelect.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/components/MatchColumnSelect.tsx @@ -161,7 +161,7 @@ export const MatchColumnSelect = ({ ))} {options?.length === 0 && ( - + )} diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/currency/components/CurrencyPickerDropdownSelect.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/currency/components/CurrencyPickerDropdownSelect.tsx index 14031684e..16517e31d 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/currency/components/CurrencyPickerDropdownSelect.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/currency/components/CurrencyPickerDropdownSelect.tsx @@ -42,7 +42,7 @@ export const CurrencyPickerDropdownSelect = ({ {filteredCurrencies.length === 0 ? ( - + ) : ( <> {selectedCurrency && ( diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownSelect.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownSelect.tsx index 96a620681..bc04138a4 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownSelect.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownSelect.tsx @@ -55,7 +55,7 @@ export const PhoneCountryPickerDropdownSelect = ({ {filteredCountries?.length === 0 ? ( - + ) : ( <> {selectedCountry && (