diff --git a/packages/twenty-front/src/hooks/useHotkeyScopeOnMount.ts b/packages/twenty-front/src/hooks/useHotkeyScopeOnMount.ts new file mode 100644 index 000000000..637b2017d --- /dev/null +++ b/packages/twenty-front/src/hooks/useHotkeyScopeOnMount.ts @@ -0,0 +1,20 @@ +import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; +import { useEffect } from 'react'; + +export const useHotkeyScopeOnMount = (hotkeyScope: string) => { + const { + goBackToPreviousHotkeyScope, + setHotkeyScopeAndMemorizePreviousScope, + } = usePreviousHotkeyScope(); + + useEffect(() => { + setHotkeyScopeAndMemorizePreviousScope(hotkeyScope); + return () => { + goBackToPreviousHotkeyScope(); + }; + }, [ + hotkeyScope, + setHotkeyScopeAndMemorizePreviousScope, + goBackToPreviousHotkeyScope, + ]); +}; diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionsTable.tsx b/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionsTable.tsx index a0afe897e..a7b857bf6 100644 --- a/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionsTable.tsx +++ b/packages/twenty-front/src/modules/settings/serverless-functions/components/SettingsServerlessFunctionsTable.tsx @@ -1,14 +1,19 @@ -import { TableHeader } from '@/ui/layout/table/components/TableHeader'; -import { Table } from '@/ui/layout/table/components/Table'; -import styled from '@emotion/styled'; -import { TableRow } from '@/ui/layout/table/components/TableRow'; -import { TableBody } from '@/ui/layout/table/components/TableBody'; -import { useGetManyServerlessFunctions } from '@/settings/serverless-functions/hooks/useGetManyServerlessFunctions'; import { SettingsServerlessFunctionsFieldItemTableRow } from '@/settings/serverless-functions/components/SettingsServerlessFunctionsFieldItemTableRow'; -import { ServerlessFunction } from '~/generated-metadata/graphql'; import { SettingsServerlessFunctionsTableEmpty } from '@/settings/serverless-functions/components/SettingsServerlessFunctionsTableEmpty'; +import { useGetManyServerlessFunctions } from '@/settings/serverless-functions/hooks/useGetManyServerlessFunctions'; +import { SettingsServerlessFunctionHotkeyScope } from '@/settings/serverless-functions/types/SettingsServerlessFunctionHotKeyScope'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; +import { Table } from '@/ui/layout/table/components/Table'; +import { TableBody } from '@/ui/layout/table/components/TableBody'; +import { TableHeader } from '@/ui/layout/table/components/TableHeader'; +import { TableRow } from '@/ui/layout/table/components/TableRow'; +import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; +import styled from '@emotion/styled'; +import { useNavigate } from 'react-router-dom'; +import { Key } from 'ts-key-enum'; +import { ServerlessFunction } from '~/generated-metadata/graphql'; +import { useHotkeyScopeOnMount } from '~/hooks/useHotkeyScopeOnMount'; const StyledTableRow = styled(TableRow)` grid-template-columns: 312px 132px 68px; @@ -20,6 +25,19 @@ const StyledTableBody = styled(TableBody)` export const SettingsServerlessFunctionsTable = () => { const { serverlessFunctions } = useGetManyServerlessFunctions(); + const navigate = useNavigate(); + + useHotkeyScopeOnMount( + SettingsServerlessFunctionHotkeyScope.ServerlessFunction, + ); + + useScopedHotkeys( + [Key.Enter], + () => { + navigate(getSettingsPagePath(SettingsPath.NewServerlessFunction)); + }, + SettingsServerlessFunctionHotkeyScope.ServerlessFunction, + ); return ( <> {serverlessFunctions.length ? ( diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionCodeEditorTab.tsx b/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionCodeEditorTab.tsx index a74892409..6329eb7ac 100644 --- a/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionCodeEditorTab.tsx +++ b/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionCodeEditorTab.tsx @@ -1,11 +1,18 @@ -import { H2Title, IconPlayerPlay, IconGitCommit, IconRestore } from 'twenty-ui'; -import { CodeEditor } from '@/ui/input/code-editor/components/CodeEditor'; -import { Section } from '@/ui/layout/section/components/Section'; import { ServerlessFunctionFormValues } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState'; +import { SettingsServerlessFunctionHotkeyScope } from '@/settings/serverless-functions/types/SettingsServerlessFunctionHotKeyScope'; +import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; +import { SettingsPath } from '@/types/SettingsPath'; import { Button } from '@/ui/input/button/components/Button'; +import { CodeEditor } from '@/ui/input/code-editor/components/CodeEditor'; import { CoreEditorHeader } from '@/ui/input/code-editor/components/CodeEditorHeader'; -import styled from '@emotion/styled'; +import { Section } from '@/ui/layout/section/components/Section'; import { TabList } from '@/ui/layout/tab/components/TabList'; +import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; +import styled from '@emotion/styled'; +import { useNavigate } from 'react-router-dom'; +import { Key } from 'ts-key-enum'; +import { H2Title, IconGitCommit, IconPlayerPlay, IconRestore } from 'twenty-ui'; +import { useHotkeyScopeOnMount } from '~/hooks/useHotkeyScopeOnMount'; const StyledTabList = styled(TabList)` border-bottom: none; @@ -76,7 +83,18 @@ export const SettingsServerlessFunctionCodeEditorTab = ({ rightNodes={[ResetButton, PublishButton, TestButton]} /> ); + const navigate = useNavigate(); + useHotkeyScopeOnMount( + SettingsServerlessFunctionHotkeyScope.ServerlessFunctionEditorTab, + ); + useScopedHotkeys( + [Key.Escape], + () => { + navigate(getSettingsPagePath(SettingsPath.ServerlessFunctions)); + }, + SettingsServerlessFunctionHotkeyScope.ServerlessFunctionEditorTab, + ); return (
{ + setIsDeleteFunctionModalOpen(true); + }, + SettingsServerlessFunctionHotkeyScope.ServerlessFunctionSettingsTab, + ); + + useScopedHotkeys( + [Key.Escape], + () => { + navigate(getSettingsPagePath(SettingsPath.ServerlessFunctions)); + }, + SettingsServerlessFunctionHotkeyScope.ServerlessFunctionSettingsTab, + ); return ( <> ]} /> ); + const navigate = useNavigate(); + useHotkeyScopeOnMount( + SettingsServerlessFunctionHotkeyScope.ServerlessFunctionTestTab, + ); + + useScopedHotkeys( + [Key.Escape], + () => { + navigate(getSettingsPagePath(SettingsPath.ServerlessFunctions)); + }, + SettingsServerlessFunctionHotkeyScope.ServerlessFunctionTestTab, + ); return (
diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/types/SettingsServerlessFunctionHotKeyScope.ts b/packages/twenty-front/src/modules/settings/serverless-functions/types/SettingsServerlessFunctionHotKeyScope.ts new file mode 100644 index 000000000..589e5118d --- /dev/null +++ b/packages/twenty-front/src/modules/settings/serverless-functions/types/SettingsServerlessFunctionHotKeyScope.ts @@ -0,0 +1,8 @@ +export enum SettingsServerlessFunctionHotkeyScope { + ServerlessFunction = 'serverless-function', + ServerlessFunctionNew = 'serverless-function-new', + ServerlessFunctionDetail = 'serverless-function-detail', + ServerlessFunctionSettingsTab = 'serverless-function-settings-tab', + ServerlessFunctionEditorTab = 'serverless-function-editor-tab', + ServerlessFunctionTestTab = 'serverless-function-test-tab', +} diff --git a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionsNew.tsx b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionsNew.tsx index c4f9eadce..9acdead88 100644 --- a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionsNew.tsx +++ b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionsNew.tsx @@ -7,11 +7,15 @@ import { useNavigate } from 'react-router-dom'; import { SettingsServerlessFunctionNewForm } from '@/settings/serverless-functions/components/SettingsServerlessFunctionNewForm'; import { useCreateOneServerlessFunction } from '@/settings/serverless-functions/hooks/useCreateOneServerlessFunction'; import { ServerlessFunctionNewFormValues } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState'; +import { SettingsServerlessFunctionHotkeyScope } from '@/settings/serverless-functions/types/SettingsServerlessFunctionHotKeyScope'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { DEFAULT_CODE } from '@/ui/input/code-editor/components/CodeEditor'; +import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { useState } from 'react'; +import { Key } from 'ts-key-enum'; import { IconFunction } from 'twenty-ui'; +import { useHotkeyScopeOnMount } from '~/hooks/useHotkeyScopeOnMount'; import { isDefined } from '~/utils/isDefined'; export const SettingsServerlessFunctionsNew = () => { @@ -52,6 +56,28 @@ export const SettingsServerlessFunctionsNew = () => { const canSave = !!formValues.name && createOneServerlessFunction; + useHotkeyScopeOnMount( + SettingsServerlessFunctionHotkeyScope.ServerlessFunctionNew, + ); + + useScopedHotkeys( + [Key.Enter], + () => { + if (canSave !== false) { + handleSave(); + } + }, + SettingsServerlessFunctionHotkeyScope.ServerlessFunctionNew, + [canSave], + ); + useScopedHotkeys( + [Key.Escape], + () => { + navigate(getSettingsPagePath(SettingsPath.ServerlessFunctions)); + }, + SettingsServerlessFunctionHotkeyScope.ServerlessFunctionNew, + ); + return (