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:
20
packages/twenty-front/src/hooks/useHotkeyScopeOnMount.ts
Normal file
20
packages/twenty-front/src/hooks/useHotkeyScopeOnMount.ts
Normal 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,
|
||||||
|
]);
|
||||||
|
};
|
||||||
@ -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 { SettingsServerlessFunctionsFieldItemTableRow } from '@/settings/serverless-functions/components/SettingsServerlessFunctionsFieldItemTableRow';
|
||||||
import { ServerlessFunction } from '~/generated-metadata/graphql';
|
|
||||||
import { SettingsServerlessFunctionsTableEmpty } from '@/settings/serverless-functions/components/SettingsServerlessFunctionsTableEmpty';
|
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 { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
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)`
|
const StyledTableRow = styled(TableRow)`
|
||||||
grid-template-columns: 312px 132px 68px;
|
grid-template-columns: 312px 132px 68px;
|
||||||
@ -20,6 +25,19 @@ const StyledTableBody = styled(TableBody)`
|
|||||||
|
|
||||||
export const SettingsServerlessFunctionsTable = () => {
|
export const SettingsServerlessFunctionsTable = () => {
|
||||||
const { serverlessFunctions } = useGetManyServerlessFunctions();
|
const { serverlessFunctions } = useGetManyServerlessFunctions();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useHotkeyScopeOnMount(
|
||||||
|
SettingsServerlessFunctionHotkeyScope.ServerlessFunction,
|
||||||
|
);
|
||||||
|
|
||||||
|
useScopedHotkeys(
|
||||||
|
[Key.Enter],
|
||||||
|
() => {
|
||||||
|
navigate(getSettingsPagePath(SettingsPath.NewServerlessFunction));
|
||||||
|
},
|
||||||
|
SettingsServerlessFunctionHotkeyScope.ServerlessFunction,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{serverlessFunctions.length ? (
|
{serverlessFunctions.length ? (
|
||||||
|
|||||||
@ -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 { 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 { 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 { 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 { 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)`
|
const StyledTabList = styled(TabList)`
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
@ -76,7 +83,18 @@ export const SettingsServerlessFunctionCodeEditorTab = ({
|
|||||||
rightNodes={[ResetButton, PublishButton, TestButton]}
|
rightNodes={[ResetButton, PublishButton, TestButton]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
useHotkeyScopeOnMount(
|
||||||
|
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionEditorTab,
|
||||||
|
);
|
||||||
|
|
||||||
|
useScopedHotkeys(
|
||||||
|
[Key.Escape],
|
||||||
|
() => {
|
||||||
|
navigate(getSettingsPagePath(SettingsPath.ServerlessFunctions));
|
||||||
|
},
|
||||||
|
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionEditorTab,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title
|
<H2Title
|
||||||
|
|||||||
@ -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 { SettingsServerlessFunctionNewForm } from '@/settings/serverless-functions/components/SettingsServerlessFunctionNewForm';
|
||||||
import { useDeleteOneServerlessFunction } from '@/settings/serverless-functions/hooks/useDeleteOneServerlessFunction';
|
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 { useNavigate } from 'react-router-dom';
|
||||||
|
import { Key } from 'ts-key-enum';
|
||||||
|
import { H2Title } from 'twenty-ui';
|
||||||
|
import { useHotkeyScopeOnMount } from '~/hooks/useHotkeyScopeOnMount';
|
||||||
|
|
||||||
export const SettingsServerlessFunctionSettingsTab = ({
|
export const SettingsServerlessFunctionSettingsTab = ({
|
||||||
formValues,
|
formValues,
|
||||||
@ -26,6 +32,26 @@ export const SettingsServerlessFunctionSettingsTab = ({
|
|||||||
await deleteOneServerlessFunction({ id: serverlessFunctionId });
|
await deleteOneServerlessFunction({ id: serverlessFunctionId });
|
||||||
navigate('/settings/functions');
|
navigate('/settings/functions');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useHotkeyScopeOnMount(
|
||||||
|
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionSettingsTab,
|
||||||
|
);
|
||||||
|
|
||||||
|
useScopedHotkeys(
|
||||||
|
[Key.Delete],
|
||||||
|
() => {
|
||||||
|
setIsDeleteFunctionModalOpen(true);
|
||||||
|
},
|
||||||
|
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionSettingsTab,
|
||||||
|
);
|
||||||
|
|
||||||
|
useScopedHotkeys(
|
||||||
|
[Key.Escape],
|
||||||
|
() => {
|
||||||
|
navigate(getSettingsPagePath(SettingsPath.ServerlessFunctions));
|
||||||
|
},
|
||||||
|
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionSettingsTab,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SettingsServerlessFunctionNewForm
|
<SettingsServerlessFunctionNewForm
|
||||||
|
|||||||
@ -1,16 +1,23 @@
|
|||||||
import { H2Title, IconPlayerPlay } from 'twenty-ui';
|
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
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 { 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 { 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`
|
const StyledInputsContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -59,6 +66,18 @@ export const SettingsServerlessFunctionTestTab = ({
|
|||||||
rightNodes={[<LightCopyIconButton copyText={result} />]}
|
rightNodes={[<LightCopyIconButton copyText={result} />]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
useHotkeyScopeOnMount(
|
||||||
|
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionTestTab,
|
||||||
|
);
|
||||||
|
|
||||||
|
useScopedHotkeys(
|
||||||
|
[Key.Escape],
|
||||||
|
() => {
|
||||||
|
navigate(getSettingsPagePath(SettingsPath.ServerlessFunctions));
|
||||||
|
},
|
||||||
|
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionTestTab,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
|
|||||||
@ -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',
|
||||||
|
}
|
||||||
@ -7,11 +7,15 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { SettingsServerlessFunctionNewForm } from '@/settings/serverless-functions/components/SettingsServerlessFunctionNewForm';
|
import { SettingsServerlessFunctionNewForm } from '@/settings/serverless-functions/components/SettingsServerlessFunctionNewForm';
|
||||||
import { useCreateOneServerlessFunction } from '@/settings/serverless-functions/hooks/useCreateOneServerlessFunction';
|
import { useCreateOneServerlessFunction } from '@/settings/serverless-functions/hooks/useCreateOneServerlessFunction';
|
||||||
import { ServerlessFunctionNewFormValues } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
|
import { ServerlessFunctionNewFormValues } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
|
||||||
|
import { SettingsServerlessFunctionHotkeyScope } from '@/settings/serverless-functions/types/SettingsServerlessFunctionHotKeyScope';
|
||||||
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { DEFAULT_CODE } from '@/ui/input/code-editor/components/CodeEditor';
|
import { DEFAULT_CODE } from '@/ui/input/code-editor/components/CodeEditor';
|
||||||
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { Key } from 'ts-key-enum';
|
||||||
import { IconFunction } from 'twenty-ui';
|
import { IconFunction } from 'twenty-ui';
|
||||||
|
import { useHotkeyScopeOnMount } from '~/hooks/useHotkeyScopeOnMount';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
export const SettingsServerlessFunctionsNew = () => {
|
export const SettingsServerlessFunctionsNew = () => {
|
||||||
@ -52,6 +56,28 @@ export const SettingsServerlessFunctionsNew = () => {
|
|||||||
|
|
||||||
const canSave = !!formValues.name && createOneServerlessFunction;
|
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 (
|
return (
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
Icon={IconFunction}
|
Icon={IconFunction}
|
||||||
|
|||||||
Reference in New Issue
Block a user