mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-19 09:31:44 +03:00
Add task and note create option in comand menu (#1115)
* add task and note create option in comand menu * Re-run CIs --------- Co-authored-by: Weiko <corentin@twenty.com> Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
This commit is contained in:
parent
22b4bffcde
commit
4a388b8ed5
@ -15,7 +15,9 @@ import {
|
|||||||
import { getLogoUrlFromDomainName } from '~/utils';
|
import { getLogoUrlFromDomainName } from '~/utils';
|
||||||
|
|
||||||
import { useCommandMenu } from '../hooks/useCommandMenu';
|
import { useCommandMenu } from '../hooks/useCommandMenu';
|
||||||
|
import { commandMenuCommand } from '../states/commandMenuCommandsState';
|
||||||
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
||||||
|
import { CommandType } from '../types/Command';
|
||||||
|
|
||||||
import { CommandMenuItem } from './CommandMenuItem';
|
import { CommandMenuItem } from './CommandMenuItem';
|
||||||
import {
|
import {
|
||||||
@ -31,6 +33,8 @@ export function CommandMenu() {
|
|||||||
const openActivityRightDrawer = useOpenActivityRightDrawer();
|
const openActivityRightDrawer = useOpenActivityRightDrawer();
|
||||||
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
|
const commands = useRecoilValue(commandMenuCommand);
|
||||||
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
'ctrl+k,meta+k',
|
'ctrl+k,meta+k',
|
||||||
@ -77,36 +81,16 @@ export function CommandMenu() {
|
|||||||
});
|
});
|
||||||
const activities = activityData?.searchResults ?? [];
|
const activities = activityData?.searchResults ?? [];
|
||||||
|
|
||||||
const commands = [
|
const matchingNavigateCommand = commands.find(
|
||||||
{
|
(cmd) =>
|
||||||
to: '/people',
|
cmd.shortcuts?.join('') === search?.toUpperCase() &&
|
||||||
label: 'Go to People',
|
cmd.type === CommandType.Navigate,
|
||||||
shortcuts: ['G', 'P'],
|
);
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/companies',
|
|
||||||
label: 'Go to Companies',
|
|
||||||
shortcuts: ['G', 'C'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/opportunities',
|
|
||||||
label: 'Go to Opportunities',
|
|
||||||
shortcuts: ['G', 'O'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/settings/profile',
|
|
||||||
label: 'Go to Settings',
|
|
||||||
shortcuts: ['G', 'S'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/tasks',
|
|
||||||
label: 'Go to Tasks',
|
|
||||||
shortcuts: ['G', 'T'],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const matchingCommand = commands.find(
|
const matchingCreateCommand = commands.find(
|
||||||
(cmd) => cmd.shortcuts.join('') === search?.toUpperCase(),
|
(cmd) =>
|
||||||
|
cmd.shortcuts?.join('') === search?.toUpperCase() &&
|
||||||
|
cmd.type === CommandType.Create,
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -164,12 +148,40 @@ export function CommandMenu() {
|
|||||||
/>
|
/>
|
||||||
<StyledList>
|
<StyledList>
|
||||||
<StyledEmpty>No results found.</StyledEmpty>
|
<StyledEmpty>No results found.</StyledEmpty>
|
||||||
{matchingCommand && (
|
{!matchingCreateCommand && (
|
||||||
|
<StyledGroup heading="Create">
|
||||||
|
{commands
|
||||||
|
.filter((cmd) => cmd.type === CommandType.Create)
|
||||||
|
.map((cmd) => (
|
||||||
|
<CommandMenuItem
|
||||||
|
key={cmd.label}
|
||||||
|
to={cmd.to}
|
||||||
|
label={cmd.label}
|
||||||
|
icon={cmd.icon}
|
||||||
|
shortcuts={cmd.shortcuts || []}
|
||||||
|
onClick={cmd.onCommandClick}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</StyledGroup>
|
||||||
|
)}
|
||||||
|
{matchingCreateCommand && (
|
||||||
|
<StyledGroup heading="Create">
|
||||||
|
<CommandMenuItem
|
||||||
|
key={matchingCreateCommand.label}
|
||||||
|
to={matchingCreateCommand.to}
|
||||||
|
label={matchingCreateCommand.label}
|
||||||
|
icon={matchingCreateCommand.icon}
|
||||||
|
shortcuts={matchingCreateCommand.shortcuts || []}
|
||||||
|
onClick={matchingCreateCommand.onCommandClick}
|
||||||
|
/>
|
||||||
|
</StyledGroup>
|
||||||
|
)}
|
||||||
|
{matchingNavigateCommand && (
|
||||||
<StyledGroup heading="Navigate">
|
<StyledGroup heading="Navigate">
|
||||||
<CommandMenuItem
|
<CommandMenuItem
|
||||||
to={matchingCommand.to}
|
to={matchingNavigateCommand.to}
|
||||||
label={matchingCommand.label}
|
label={matchingNavigateCommand.label}
|
||||||
shortcuts={matchingCommand.shortcuts}
|
shortcuts={matchingNavigateCommand.shortcuts}
|
||||||
/>
|
/>
|
||||||
</StyledGroup>
|
</StyledGroup>
|
||||||
)}
|
)}
|
||||||
@ -223,17 +235,18 @@ export function CommandMenu() {
|
|||||||
))}
|
))}
|
||||||
</StyledGroup>
|
</StyledGroup>
|
||||||
)}
|
)}
|
||||||
{!matchingCommand && (
|
{!matchingNavigateCommand && (
|
||||||
<StyledGroup heading="Navigate">
|
<StyledGroup heading="Navigate">
|
||||||
{commands
|
{commands
|
||||||
.filter(
|
.filter(
|
||||||
(cmd) =>
|
(cmd) =>
|
||||||
cmd.shortcuts?.join('').includes(search?.toUpperCase()) ||
|
(cmd.shortcuts?.join('').includes(search?.toUpperCase()) ||
|
||||||
cmd.label?.toUpperCase().includes(search?.toUpperCase()),
|
cmd.label?.toUpperCase().includes(search?.toUpperCase())) &&
|
||||||
|
cmd.type === CommandType.Navigate,
|
||||||
)
|
)
|
||||||
.map((cmd) => (
|
.map((cmd) => (
|
||||||
<CommandMenuItem
|
<CommandMenuItem
|
||||||
key={cmd.shortcuts.join('')}
|
key={cmd.shortcuts?.join('')}
|
||||||
to={cmd.to}
|
to={cmd.to}
|
||||||
label={cmd.label}
|
label={cmd.label}
|
||||||
shortcuts={cmd.shortcuts}
|
shortcuts={cmd.shortcuts}
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
import { Command, CommandType } from '../types/Command';
|
||||||
|
|
||||||
|
export const commandMenuCommands: Command[] = [
|
||||||
|
{
|
||||||
|
to: '/people',
|
||||||
|
label: 'Go to People',
|
||||||
|
type: CommandType.Navigate,
|
||||||
|
shortcuts: ['G', 'P'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/companies',
|
||||||
|
label: 'Go to Companies',
|
||||||
|
type: CommandType.Navigate,
|
||||||
|
shortcuts: ['G', 'C'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/opportunities',
|
||||||
|
label: 'Go to Opportunities',
|
||||||
|
type: CommandType.Navigate,
|
||||||
|
shortcuts: ['G', 'O'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/settings/profile',
|
||||||
|
label: 'Go to Settings',
|
||||||
|
type: CommandType.Navigate,
|
||||||
|
shortcuts: ['G', 'S'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/tasks',
|
||||||
|
label: 'Go to Tasks',
|
||||||
|
type: CommandType.Navigate,
|
||||||
|
shortcuts: ['G', 'T'],
|
||||||
|
},
|
||||||
|
];
|
@ -1,14 +1,18 @@
|
|||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
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';
|
||||||
|
|
||||||
|
import { commandMenuCommands } from '../constants/commandMenuCommands';
|
||||||
|
import { commandMenuCommand } from '../states/commandMenuCommandsState';
|
||||||
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
||||||
|
import { Command } from '../types/Command';
|
||||||
|
|
||||||
export function useCommandMenu() {
|
export function useCommandMenu() {
|
||||||
const [, setIsCommandMenuOpenedState] = useRecoilState(
|
const [, setIsCommandMenuOpenedState] = useRecoilState(
|
||||||
isCommandMenuOpenedState,
|
isCommandMenuOpenedState,
|
||||||
);
|
);
|
||||||
|
const setCommands = useSetRecoilState(commandMenuCommand);
|
||||||
const {
|
const {
|
||||||
setHotkeyScopeAndMemorizePreviousScope,
|
setHotkeyScopeAndMemorizePreviousScope,
|
||||||
goBackToPreviousHotkeyScope,
|
goBackToPreviousHotkeyScope,
|
||||||
@ -24,8 +28,18 @@ export function useCommandMenu() {
|
|||||||
goBackToPreviousHotkeyScope();
|
goBackToPreviousHotkeyScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addToCommandMenu(addCommand: Command[]) {
|
||||||
|
setCommands((prev) => [...prev, ...addCommand]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setToIntitialCommandMenu() {
|
||||||
|
setCommands(commandMenuCommands);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
openCommandMenu,
|
openCommandMenu,
|
||||||
closeCommandMenu,
|
closeCommandMenu,
|
||||||
|
addToCommandMenu,
|
||||||
|
setToIntitialCommandMenu,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
import { atom } from 'recoil';
|
||||||
|
|
||||||
|
import { Command, CommandType } from '../types/Command';
|
||||||
|
|
||||||
|
export const commandMenuCommand = atom<Command[]>({
|
||||||
|
key: 'command-menu/commandMenuCommand',
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
to: '',
|
||||||
|
label: '',
|
||||||
|
type: CommandType.Navigate,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
13
front/src/modules/command-menu/types/Command.ts
Normal file
13
front/src/modules/command-menu/types/Command.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export enum CommandType {
|
||||||
|
Navigate = 'Navigate',
|
||||||
|
Create = 'Create',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Command = {
|
||||||
|
to: string;
|
||||||
|
label: string;
|
||||||
|
type: CommandType.Navigate | CommandType.Create;
|
||||||
|
icon?: JSX.Element;
|
||||||
|
shortcuts?: string[];
|
||||||
|
onCommandClick?: () => void;
|
||||||
|
};
|
@ -1,9 +1,11 @@
|
|||||||
|
import { CommandMenuHook } from './CommandMenuHook';
|
||||||
import { GotoHotkeysHooks } from './GotoHotkeysHooks';
|
import { GotoHotkeysHooks } from './GotoHotkeysHooks';
|
||||||
|
|
||||||
export function AppInternalHooks() {
|
export function AppInternalHooks() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GotoHotkeysHooks />
|
<GotoHotkeysHooks />
|
||||||
|
<CommandMenuHook />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { matchPath, useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
import { IconCheckbox, IconNotes } from '@tabler/icons-react';
|
||||||
|
|
||||||
|
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
|
||||||
import { useEventTracker } from '@/analytics/hooks/useEventTracker';
|
import { useEventTracker } from '@/analytics/hooks/useEventTracker';
|
||||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
||||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
||||||
|
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||||
|
import { CommandType } from '@/command-menu/types/Command';
|
||||||
import { AppBasePath } from '@/types/AppBasePath';
|
import { AppBasePath } from '@/types/AppBasePath';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
|
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
|
import { ActivityType, CommentableType } from '~/generated/graphql';
|
||||||
|
|
||||||
import { useIsMatchingLocation } from '../hooks/useIsMatchingLocation';
|
import { useIsMatchingLocation } from '../hooks/useIsMatchingLocation';
|
||||||
|
|
||||||
@ -27,6 +32,10 @@ export function AuthAutoRouter() {
|
|||||||
|
|
||||||
const eventTracker = useEventTracker();
|
const eventTracker = useEventTracker();
|
||||||
|
|
||||||
|
const { addToCommandMenu, setToIntitialCommandMenu } = useCommandMenu();
|
||||||
|
|
||||||
|
const openCreateActivity = useOpenCreateActivityDrawer();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!previousLocation || previousLocation !== location.pathname) {
|
if (!previousLocation || previousLocation !== location.pathname) {
|
||||||
setPreviousLocation(location.pathname);
|
setPreviousLocation(location.pathname);
|
||||||
@ -129,6 +138,75 @@ export function AuthAutoRouter() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setToIntitialCommandMenu();
|
||||||
|
switch (true) {
|
||||||
|
case isMatchingLocation(AppPath.CompanyShowPage): {
|
||||||
|
const companyId = matchPath(
|
||||||
|
{ path: '/companies/:id' },
|
||||||
|
location.pathname,
|
||||||
|
)?.params.id;
|
||||||
|
|
||||||
|
const entity = !!companyId
|
||||||
|
? { id: companyId, type: CommentableType.Company }
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
addToCommandMenu([
|
||||||
|
{
|
||||||
|
to: '',
|
||||||
|
label: 'Create Task',
|
||||||
|
type: CommandType.Create,
|
||||||
|
icon: <IconCheckbox />,
|
||||||
|
onCommandClick: () => openCreateActivity(ActivityType.Task, entity),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '',
|
||||||
|
label: 'Create Note',
|
||||||
|
type: CommandType.Create,
|
||||||
|
icon: <IconNotes />,
|
||||||
|
onCommandClick: () => openCreateActivity(ActivityType.Note, entity),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case isMatchingLocation(AppPath.PersonShowPage): {
|
||||||
|
const personId = matchPath({ path: '/person/:id' }, location.pathname)
|
||||||
|
?.params.id;
|
||||||
|
|
||||||
|
const entity = !!personId
|
||||||
|
? { id: personId, type: CommentableType.Person }
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
addToCommandMenu([
|
||||||
|
{
|
||||||
|
to: '',
|
||||||
|
label: 'Create Task',
|
||||||
|
type: CommandType.Create,
|
||||||
|
icon: <IconCheckbox />,
|
||||||
|
onCommandClick: () => openCreateActivity(ActivityType.Task, entity),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '',
|
||||||
|
label: 'Create Note',
|
||||||
|
type: CommandType.Create,
|
||||||
|
icon: <IconNotes />,
|
||||||
|
onCommandClick: () => openCreateActivity(ActivityType.Note, entity),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
addToCommandMenu([
|
||||||
|
{
|
||||||
|
to: '',
|
||||||
|
label: 'Create Task',
|
||||||
|
type: CommandType.Create,
|
||||||
|
icon: <IconCheckbox />,
|
||||||
|
onCommandClick: () => openCreateActivity(ActivityType.Task),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
eventTracker('pageview', {
|
eventTracker('pageview', {
|
||||||
location: {
|
location: {
|
||||||
@ -144,6 +222,9 @@ export function AuthAutoRouter() {
|
|||||||
location,
|
location,
|
||||||
previousLocation,
|
previousLocation,
|
||||||
eventTracker,
|
eventTracker,
|
||||||
|
addToCommandMenu,
|
||||||
|
openCreateActivity,
|
||||||
|
setToIntitialCommandMenu,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
|
13
front/src/sync-hooks/CommandMenuHook.tsx
Normal file
13
front/src/sync-hooks/CommandMenuHook.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { commandMenuCommands } from '@/command-menu/constants/commandMenuCommands';
|
||||||
|
import { commandMenuCommand } from '@/command-menu/states/commandMenuCommandsState';
|
||||||
|
|
||||||
|
export function CommandMenuHook() {
|
||||||
|
const setCommands = useSetRecoilState(commandMenuCommand);
|
||||||
|
|
||||||
|
const commands = commandMenuCommands;
|
||||||
|
setCommands(commands);
|
||||||
|
|
||||||
|
return <></>;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user