mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-18 09:02:11 +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 { useCommandMenu } from '../hooks/useCommandMenu';
|
||||
import { commandMenuCommand } from '../states/commandMenuCommandsState';
|
||||
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
||||
import { CommandType } from '../types/Command';
|
||||
|
||||
import { CommandMenuItem } from './CommandMenuItem';
|
||||
import {
|
||||
@ -31,6 +33,8 @@ export function CommandMenu() {
|
||||
const openActivityRightDrawer = useOpenActivityRightDrawer();
|
||||
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
||||
const [search, setSearch] = useState('');
|
||||
const commands = useRecoilValue(commandMenuCommand);
|
||||
|
||||
|
||||
useScopedHotkeys(
|
||||
'ctrl+k,meta+k',
|
||||
@ -77,36 +81,16 @@ export function CommandMenu() {
|
||||
});
|
||||
const activities = activityData?.searchResults ?? [];
|
||||
|
||||
const commands = [
|
||||
{
|
||||
to: '/people',
|
||||
label: 'Go to People',
|
||||
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 matchingNavigateCommand = commands.find(
|
||||
(cmd) =>
|
||||
cmd.shortcuts?.join('') === search?.toUpperCase() &&
|
||||
cmd.type === CommandType.Navigate,
|
||||
);
|
||||
|
||||
const matchingCommand = commands.find(
|
||||
(cmd) => cmd.shortcuts.join('') === search?.toUpperCase(),
|
||||
const matchingCreateCommand = commands.find(
|
||||
(cmd) =>
|
||||
cmd.shortcuts?.join('') === search?.toUpperCase() &&
|
||||
cmd.type === CommandType.Create,
|
||||
);
|
||||
|
||||
/*
|
||||
@ -164,12 +148,40 @@ export function CommandMenu() {
|
||||
/>
|
||||
<StyledList>
|
||||
<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">
|
||||
<CommandMenuItem
|
||||
to={matchingCommand.to}
|
||||
label={matchingCommand.label}
|
||||
shortcuts={matchingCommand.shortcuts}
|
||||
to={matchingNavigateCommand.to}
|
||||
label={matchingNavigateCommand.label}
|
||||
shortcuts={matchingNavigateCommand.shortcuts}
|
||||
/>
|
||||
</StyledGroup>
|
||||
)}
|
||||
@ -223,17 +235,18 @@ export function CommandMenu() {
|
||||
))}
|
||||
</StyledGroup>
|
||||
)}
|
||||
{!matchingCommand && (
|
||||
{!matchingNavigateCommand && (
|
||||
<StyledGroup heading="Navigate">
|
||||
{commands
|
||||
.filter(
|
||||
(cmd) =>
|
||||
cmd.shortcuts?.join('').includes(search?.toUpperCase()) ||
|
||||
cmd.label?.toUpperCase().includes(search?.toUpperCase()),
|
||||
(cmd.shortcuts?.join('').includes(search?.toUpperCase()) ||
|
||||
cmd.label?.toUpperCase().includes(search?.toUpperCase())) &&
|
||||
cmd.type === CommandType.Navigate,
|
||||
)
|
||||
.map((cmd) => (
|
||||
<CommandMenuItem
|
||||
key={cmd.shortcuts.join('')}
|
||||
key={cmd.shortcuts?.join('')}
|
||||
to={cmd.to}
|
||||
label={cmd.label}
|
||||
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 { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||
|
||||
import { commandMenuCommands } from '../constants/commandMenuCommands';
|
||||
import { commandMenuCommand } from '../states/commandMenuCommandsState';
|
||||
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
||||
import { Command } from '../types/Command';
|
||||
|
||||
export function useCommandMenu() {
|
||||
const [, setIsCommandMenuOpenedState] = useRecoilState(
|
||||
isCommandMenuOpenedState,
|
||||
);
|
||||
const setCommands = useSetRecoilState(commandMenuCommand);
|
||||
const {
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeyScope,
|
||||
@ -24,8 +28,18 @@ export function useCommandMenu() {
|
||||
goBackToPreviousHotkeyScope();
|
||||
}
|
||||
|
||||
function addToCommandMenu(addCommand: Command[]) {
|
||||
setCommands((prev) => [...prev, ...addCommand]);
|
||||
}
|
||||
|
||||
function setToIntitialCommandMenu() {
|
||||
setCommands(commandMenuCommands);
|
||||
}
|
||||
|
||||
return {
|
||||
openCommandMenu,
|
||||
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';
|
||||
|
||||
export function AppInternalHooks() {
|
||||
return (
|
||||
<>
|
||||
<GotoHotkeysHooks />
|
||||
<CommandMenuHook />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,15 +1,20 @@
|
||||
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 { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
||||
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 { AppPath } from '@/types/AppPath';
|
||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
import { ActivityType, CommentableType } from '~/generated/graphql';
|
||||
|
||||
import { useIsMatchingLocation } from '../hooks/useIsMatchingLocation';
|
||||
|
||||
@ -27,6 +32,10 @@ export function AuthAutoRouter() {
|
||||
|
||||
const eventTracker = useEventTracker();
|
||||
|
||||
const { addToCommandMenu, setToIntitialCommandMenu } = useCommandMenu();
|
||||
|
||||
const openCreateActivity = useOpenCreateActivityDrawer();
|
||||
|
||||
useEffect(() => {
|
||||
if (!previousLocation || previousLocation !== 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(() => {
|
||||
eventTracker('pageview', {
|
||||
location: {
|
||||
@ -144,6 +222,9 @@ export function AuthAutoRouter() {
|
||||
location,
|
||||
previousLocation,
|
||||
eventTracker,
|
||||
addToCommandMenu,
|
||||
openCreateActivity,
|
||||
setToIntitialCommandMenu,
|
||||
]);
|
||||
|
||||
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