Added hotkeyScopes to serverless functions in settings (#6710)

Fixes #6656 
Is this the right way to implement keyboard listeners?
Please let me know, I'll make the changes accordingly.
:)


https://github.com/user-attachments/assets/af71d340-ead9-4659-81e6-a440522a194f

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
nitin
2024-08-23 20:24:21 +05:30
committed by GitHub
parent f9af25b57e
commit 5d8162dc09
7 changed files with 161 additions and 26 deletions

View File

@ -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,
]);
};

View File

@ -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 ? (

View File

@ -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 (
<Section>
<H2Title

View File

@ -1,12 +1,18 @@
import { H2Title } from 'twenty-ui';
import { Section } from '@/ui/layout/section/components/Section';
import { ServerlessFunctionFormValues } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
import { Button } from '@/ui/input/button/components/Button';
import { useState } from 'react';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { SettingsServerlessFunctionNewForm } from '@/settings/serverless-functions/components/SettingsServerlessFunctionNewForm';
import { useDeleteOneServerlessFunction } from '@/settings/serverless-functions/hooks/useDeleteOneServerlessFunction';
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 { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { Section } from '@/ui/layout/section/components/Section';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Key } from 'ts-key-enum';
import { H2Title } from 'twenty-ui';
import { useHotkeyScopeOnMount } from '~/hooks/useHotkeyScopeOnMount';
export const SettingsServerlessFunctionSettingsTab = ({
formValues,
@ -26,6 +32,26 @@ export const SettingsServerlessFunctionSettingsTab = ({
await deleteOneServerlessFunction({ id: serverlessFunctionId });
navigate('/settings/functions');
};
useHotkeyScopeOnMount(
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionSettingsTab,
);
useScopedHotkeys(
[Key.Delete],
() => {
setIsDeleteFunctionModalOpen(true);
},
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionSettingsTab,
);
useScopedHotkeys(
[Key.Escape],
() => {
navigate(getSettingsPagePath(SettingsPath.ServerlessFunctions));
},
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionSettingsTab,
);
return (
<>
<SettingsServerlessFunctionNewForm

View File

@ -1,16 +1,23 @@
import { H2Title, IconPlayerPlay } from 'twenty-ui';
import { Section } from '@/ui/layout/section/components/Section';
import { H2Title, IconPlayerPlay } from 'twenty-ui';
import { CodeEditor } from '@/ui/input/code-editor/components/CodeEditor';
import styled from '@emotion/styled';
import { CoreEditorHeader } from '@/ui/input/code-editor/components/CodeEditorHeader';
import { Button } from '@/ui/input/button/components/Button';
import { LightCopyIconButton } from '@/object-record/record-field/components/LightCopyIconButton';
import { useRecoilState, useRecoilValue } from 'recoil';
import { settingsServerlessFunctionOutputState } from '@/settings/serverless-functions/states/settingsServerlessFunctionOutputState';
import { settingsServerlessFunctionInputState } from '@/settings/serverless-functions/states/settingsServerlessFunctionInputState';
import { settingsServerlessFunctionCodeEditorOutputParamsState } from '@/settings/serverless-functions/states/settingsServerlessFunctionCodeEditorOutputParamsState';
import { SettingsServerlessFunctionsOutputMetadataInfo } from '@/settings/serverless-functions/components/SettingsServerlessFunctionsOutputMetadataInfo';
import { settingsServerlessFunctionCodeEditorOutputParamsState } from '@/settings/serverless-functions/states/settingsServerlessFunctionCodeEditorOutputParamsState';
import { settingsServerlessFunctionInputState } from '@/settings/serverless-functions/states/settingsServerlessFunctionInputState';
import { settingsServerlessFunctionOutputState } from '@/settings/serverless-functions/states/settingsServerlessFunctionOutputState';
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 { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import styled from '@emotion/styled';
import { useNavigate } from 'react-router-dom';
import { useRecoilState, useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import { useHotkeyScopeOnMount } from '~/hooks/useHotkeyScopeOnMount';
const StyledInputsContainer = styled.div`
display: flex;
@ -59,6 +66,18 @@ export const SettingsServerlessFunctionTestTab = ({
rightNodes={[<LightCopyIconButton copyText={result} />]}
/>
);
const navigate = useNavigate();
useHotkeyScopeOnMount(
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionTestTab,
);
useScopedHotkeys(
[Key.Escape],
() => {
navigate(getSettingsPagePath(SettingsPath.ServerlessFunctions));
},
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionTestTab,
);
return (
<Section>

View File

@ -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',
}

View File

@ -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 (
<SubMenuTopBarContainer
Icon={IconFunction}