323 add object name inside the search (#9962)

Closes https://github.com/twentyhq/core-team-issues/issues/323

Before:
<img width="495" alt="Capture d’écran 2025-01-31 à 18 11 56"
src="https://github.com/user-attachments/assets/dd1d3ac1-6c97-4398-b233-d323eeacdbb9"
/>

After:
<img width="500" alt="Capture d’écran 2025-01-31 à 18 09 58"
src="https://github.com/user-attachments/assets/68d23990-2d0b-437d-ad2e-a686cdb320e1"
/>
This commit is contained in:
Raphaël Bosi
2025-02-01 08:18:48 +01:00
committed by GitHub
parent 58aa86cc0c
commit d9b86475d3
7 changed files with 42 additions and 1 deletions

View File

@ -8,6 +8,7 @@ import { ReactNode } from 'react';
export type CommandMenuItemProps = { export type CommandMenuItemProps = {
label: string; label: string;
description?: string;
to?: string; to?: string;
id: string; id: string;
onClick?: () => void; onClick?: () => void;
@ -19,6 +20,7 @@ export type CommandMenuItemProps = {
export const CommandMenuItem = ({ export const CommandMenuItem = ({
label, label,
description,
to, to,
id, id,
onClick, onClick,
@ -40,6 +42,7 @@ export const CommandMenuItem = ({
<MenuItemCommand <MenuItemCommand
LeftIcon={Icon} LeftIcon={Icon}
text={label} text={label}
description={description}
hotKeys={hotKeys} hotKeys={hotKeys}
onClick={() => onClick={() =>
onItemClick({ onItemClick({

View File

@ -124,6 +124,7 @@ export const CommandMenuList = ({
id={item.id} id={item.id}
Icon={item.Icon} Icon={item.Icon}
label={item.label} label={item.label}
description={item.description}
to={item.to} to={item.to}
onClick={item.onCommandClick} onClick={item.onCommandClick}
hotKeys={item.hotKeys} hotKeys={item.hotKeys}

View File

@ -123,6 +123,8 @@ export const SearchRecordsAction: Story = {
await sleep(openTimeout); await sleep(openTimeout);
await userEvent.type(searchInput, 'n'); await userEvent.type(searchInput, 'n');
expect(await canvas.findByText('Linkedin')).toBeVisible(); expect(await canvas.findByText('Linkedin')).toBeVisible();
const companyTexts = await canvas.findAllByText('Company');
expect(companyTexts[0]).toBeVisible();
expect(await canvas.findByText(companiesMock[0].name)).toBeVisible(); expect(await canvas.findByText(companiesMock[0].name)).toBeVisible();
}, },
}; };

View File

@ -77,6 +77,7 @@ export const useSearchRecords = () => {
people?.map(({ id, name: { firstName, lastName }, avatarUrl }) => ({ people?.map(({ id, name: { firstName, lastName }, avatarUrl }) => ({
id, id,
label: `${firstName} ${lastName}`, label: `${firstName} ${lastName}`,
description: 'Person',
to: `object/person/${id}`, to: `object/person/${id}`,
shouldCloseCommandMenuOnClick: true, shouldCloseCommandMenuOnClick: true,
Icon: () => ( Icon: () => (
@ -96,6 +97,7 @@ export const useSearchRecords = () => {
companies?.map((company) => ({ companies?.map((company) => ({
id: company.id, id: company.id,
label: company.name ?? '', label: company.name ?? '',
description: 'Company',
to: `object/company/${company.id}`, to: `object/company/${company.id}`,
shouldCloseCommandMenuOnClick: true, shouldCloseCommandMenuOnClick: true,
Icon: () => ( Icon: () => (
@ -116,6 +118,7 @@ export const useSearchRecords = () => {
opportunities?.map(({ id, name }) => ({ opportunities?.map(({ id, name }) => ({
id, id,
label: name ?? '', label: name ?? '',
description: 'Opportunity',
to: `object/opportunity/${id}`, to: `object/opportunity/${id}`,
shouldCloseCommandMenuOnClick: true, shouldCloseCommandMenuOnClick: true,
Icon: () => ( Icon: () => (
@ -143,6 +146,7 @@ export const useSearchRecords = () => {
notes?.map((note) => ({ notes?.map((note) => ({
id: note.id, id: note.id,
label: note.title ?? '', label: note.title ?? '',
description: 'Note',
to: '', to: '',
onCommandClick: () => openNoteRightDrawer(note.id), onCommandClick: () => openNoteRightDrawer(note.id),
shouldCloseCommandMenuOnClick: true, shouldCloseCommandMenuOnClick: true,
@ -156,6 +160,7 @@ export const useSearchRecords = () => {
tasks?.map((task) => ({ tasks?.map((task) => ({
id: task.id, id: task.id,
label: task.title ?? '', label: task.title ?? '',
description: 'Task',
to: '', to: '',
onCommandClick: () => openTaskRightDrawer(task.id), onCommandClick: () => openTaskRightDrawer(task.id),
shouldCloseCommandMenuOnClick: true, shouldCloseCommandMenuOnClick: true,
@ -182,6 +187,7 @@ export const useSearchRecords = () => {
objectRecords.map((objectRecord) => ({ objectRecords.map((objectRecord) => ({
id: objectRecord.record.id, id: objectRecord.record.id,
label: objectRecord.recordIdentifier.name, label: objectRecord.recordIdentifier.name,
description: objectRecord.objectMetadataItem.labelSingular,
to: `object/${objectRecord.objectMetadataItem.nameSingular}/${objectRecord.record.id}`, to: `object/${objectRecord.objectMetadataItem.nameSingular}/${objectRecord.record.id}`,
shouldCloseCommandMenuOnClick: true, shouldCloseCommandMenuOnClick: true,
Icon: () => ( Icon: () => (

View File

@ -16,6 +16,7 @@ export type Command = {
id: string; id: string;
to?: string; to?: string;
label: string; label: string;
description?: string;
type?: CommandType; type?: CommandType;
scope?: CommandScope; scope?: CommandScope;
Icon?: IconComponent; Icon?: IconComponent;

View File

@ -63,9 +63,24 @@ const StyledMenuItemCommandContainer = styled.div<{ isSelected?: boolean }>`
} }
`; `;
const StyledDescription = styled.span`
color: ${({ theme }) => theme.font.color.light};
&::before {
content: '·';
margin: ${({ theme }) => theme.spacing(0, 1)};
}
`;
const StyledTextContainer = styled.div`
display: flex;
flex-direction: row;
`;
export type MenuItemCommandProps = { export type MenuItemCommandProps = {
LeftIcon?: IconComponent; LeftIcon?: IconComponent;
text: string; text: string;
description?: string;
hotKeys?: string[]; hotKeys?: string[];
className?: string; className?: string;
isSelected?: boolean; isSelected?: boolean;
@ -76,6 +91,7 @@ export type MenuItemCommandProps = {
export const MenuItemCommand = ({ export const MenuItemCommand = ({
LeftIcon, LeftIcon,
text, text,
description,
hotKeys, hotKeys,
className, className,
isSelected, isSelected,
@ -97,7 +113,10 @@ export const MenuItemCommand = ({
<LeftIcon size={theme.icon.size.sm} /> <LeftIcon size={theme.icon.size.sm} />
</StyledBigIconContainer> </StyledBigIconContainer>
)} )}
<StyledMenuItemLabelText>{text}</StyledMenuItemLabelText> <StyledTextContainer>
<StyledMenuItemLabelText>{text}</StyledMenuItemLabelText>
{description && <StyledDescription>{description}</StyledDescription>}
</StyledTextContainer>
{RightComponent} {RightComponent}
</StyledMenuItemLeftContent> </StyledMenuItemLeftContent>
{!isMobile && <MenuItemCommandHotKeys hotKeys={hotKeys} />} {!isMobile && <MenuItemCommandHotKeys hotKeys={hotKeys} />}

View File

@ -35,6 +35,15 @@ export const Default: Story = {
decorators: [ComponentDecorator], decorators: [ComponentDecorator],
}; };
export const WithDescription: Story = {
args: {
text: 'Menu item',
hotKeys: ['⌘', '1'],
description: 'Description',
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof MenuItemCommand> = { export const Catalog: CatalogStory<Story, typeof MenuItemCommand> = {
args: { args: {
text: 'Menu item', text: 'Menu item',