mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-18 17:12:53 +03:00
Fix/scope hotkeys (#581)
* WIP * asd * Fix * Fix lint * Removed console log * asd * Removed isDefined * Fix/debounce company card onchange (#580) * Add internal state and debounce for editable text card * Use debounce for date fields too * Update refetch * Nit * Removed comments * Ménage --------- Co-authored-by: Emilien Chauvet <emilien.chauvet.enpc@gmail.com>
This commit is contained in:
parent
1c8aaff39d
commit
5f98b70c6a
@ -42,6 +42,7 @@
|
||||
"recoil": "^0.7.7",
|
||||
"scroll-into-view": "^1.16.2",
|
||||
"ts-key-enum": "^2.0.12",
|
||||
"url": "^0.11.1",
|
||||
"uuid": "^9.0.0",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
|
@ -20,6 +20,9 @@ import { SettingsWorkspaceMembers } from '~/pages/settings/SettingsWorkspaceMemb
|
||||
import { CompanyShow } from './pages/companies/CompanyShow';
|
||||
import { PersonShow } from './pages/people/PersonShow';
|
||||
import { SettingsWorksapce } from './pages/settings/SettingsWorkspace';
|
||||
import { AppPath } from './sync-hooks/types/AppPath';
|
||||
import { AuthPath } from './sync-hooks/types/AuthPath';
|
||||
import { SettingsPath } from './sync-hooks/types/SettingsPath';
|
||||
import { AppInternalHooks } from './AppInternalHooks';
|
||||
|
||||
/**
|
||||
@ -33,11 +36,14 @@ function AuthRoutes() {
|
||||
<AuthModal>
|
||||
<AnimatePresence mode="wait">
|
||||
<Routes location={location} key={location.pathname}>
|
||||
<Route path="" element={<Index />} />
|
||||
<Route path="callback" element={<Verify />} />
|
||||
<Route path="password-login" element={<PasswordLogin />} />
|
||||
<Route path="create/workspace" element={<CreateWorkspace />} />
|
||||
<Route path="create/profile" element={<CreateProfile />} />
|
||||
<Route path={AuthPath.Index} element={<Index />} />
|
||||
<Route path={AuthPath.Callback} element={<Verify />} />
|
||||
<Route path={AuthPath.PasswordLogin} element={<PasswordLogin />} />
|
||||
<Route
|
||||
path={AuthPath.CreateWorkspace}
|
||||
element={<CreateWorkspace />}
|
||||
/>
|
||||
<Route path={AuthPath.CreateProfile} element={<CreateProfile />} />
|
||||
</Routes>
|
||||
</AnimatePresence>
|
||||
</AuthModal>
|
||||
@ -52,7 +58,7 @@ export function App() {
|
||||
<DefaultLayout>
|
||||
<Routes>
|
||||
<Route
|
||||
path="auth/*"
|
||||
path={AppPath.AuthCatchAll}
|
||||
element={
|
||||
<RequireOnboarding>
|
||||
<AuthLayout>
|
||||
@ -66,27 +72,39 @@ export function App() {
|
||||
element={
|
||||
<RequireOnboarded>
|
||||
<Routes>
|
||||
<Route path="" element={<Navigate to="/people" replace />} />
|
||||
<Route path="people" element={<People />} />
|
||||
<Route path="person/:personId" element={<PersonShow />} />
|
||||
<Route path="companies" element={<Companies />} />
|
||||
<Route
|
||||
path="companies/:companyId"
|
||||
path=""
|
||||
element={<Navigate to={AppPath.PeoplePage} replace />}
|
||||
/>
|
||||
<Route path={AppPath.PeoplePage} element={<People />} />
|
||||
<Route
|
||||
path={AppPath.PersonShowPage}
|
||||
element={<PersonShow />}
|
||||
/>
|
||||
<Route path={AppPath.CompaniesPage} element={<Companies />} />
|
||||
<Route
|
||||
path={AppPath.CompanyShowPage}
|
||||
element={<CompanyShow />}
|
||||
/>
|
||||
|
||||
<Route path="opportunities" element={<Opportunities />} />
|
||||
<Route
|
||||
path="settings/*"
|
||||
path={AppPath.OpportunitiesPage}
|
||||
element={<Opportunities />}
|
||||
/>
|
||||
<Route
|
||||
path={AppPath.SettingsCatchAll}
|
||||
element={
|
||||
<Routes>
|
||||
<Route path="profile" element={<SettingsProfile />} />
|
||||
<Route
|
||||
path="workspace-members"
|
||||
path={SettingsPath.ProfilePage}
|
||||
element={<SettingsProfile />}
|
||||
/>
|
||||
<Route
|
||||
path={SettingsPath.WorkspaceMembersPage}
|
||||
element={<SettingsWorkspaceMembers />}
|
||||
/>
|
||||
<Route
|
||||
path="workspace"
|
||||
path={SettingsPath.Workspace}
|
||||
element={<SettingsWorksapce />}
|
||||
/>
|
||||
</Routes>
|
||||
|
@ -1,13 +1,15 @@
|
||||
import { AnalyticsHook } from './sync-hooks/AnalyticsHook';
|
||||
import { GotoHotkeysHooks } from './sync-hooks/GotoHotkeysHooks';
|
||||
import { HotkeysScopeStackAutoSyncHook } from './sync-hooks/HotkeysScopeStackAutoSyncHook';
|
||||
import { HotkeysScopeAutoSyncHook } from './sync-hooks/HotkeysScopeAutoSyncHook';
|
||||
import { HotkeysScopeBrowserRouterSync } from './sync-hooks/HotkeysScopeBrowserRouterSync';
|
||||
|
||||
export function AppInternalHooks() {
|
||||
return (
|
||||
<>
|
||||
<AnalyticsHook />
|
||||
<GotoHotkeysHooks />
|
||||
<HotkeysScopeStackAutoSyncHook />
|
||||
<HotkeysScopeAutoSyncHook />
|
||||
<HotkeysScopeBrowserRouterSync />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useHotkeysScopeOnBooleanState } from '@/hotkeys/hooks/useHotkeysScopeOnBooleanState';
|
||||
import { usePreviousHotkeysScope } from '@/hotkeys/hooks/internal/usePreviousHotkeysScope';
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
|
||||
@ -13,7 +13,6 @@ import {
|
||||
StyledGroup,
|
||||
StyledInput,
|
||||
StyledList,
|
||||
// StyledSeparator,
|
||||
} from './CommandMenuStyles';
|
||||
|
||||
export function CommandMenu() {
|
||||
@ -22,16 +21,26 @@ export function CommandMenu() {
|
||||
useScopedHotkeys(
|
||||
'ctrl+k,meta+k',
|
||||
() => {
|
||||
setOpen((prevOpen) => !prevOpen);
|
||||
handleOpenChange(!open);
|
||||
},
|
||||
InternalHotkeysScope.CommandMenu,
|
||||
[setOpen],
|
||||
[setOpen, open, handleOpenChange],
|
||||
);
|
||||
|
||||
useHotkeysScopeOnBooleanState(
|
||||
{ scope: InternalHotkeysScope.CommandMenu },
|
||||
open,
|
||||
);
|
||||
const {
|
||||
setHotkeysScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeysScope,
|
||||
} = usePreviousHotkeysScope();
|
||||
|
||||
function handleOpenChange(newOpenState: boolean) {
|
||||
if (newOpenState) {
|
||||
setOpen(true);
|
||||
setHotkeysScopeAndMemorizePreviousScope(InternalHotkeysScope.CommandMenu);
|
||||
} else {
|
||||
setOpen(false);
|
||||
goBackToPreviousHotkeysScope();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Allow performing actions on page through CommandBar
|
||||
@ -73,7 +82,7 @@ export function CommandMenu() {
|
||||
return (
|
||||
<StyledDialog
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
onOpenChange={handleOpenChange}
|
||||
label="Global Command Menu"
|
||||
>
|
||||
<StyledInput placeholder="Search" />
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
import { useHandleCheckableCommentThreadTargetChange } from '@/comments/hooks/useHandleCheckableCommentThreadTargetChange';
|
||||
import { CommentableEntityForSelect } from '@/comments/types/CommentableEntityForSelect';
|
||||
import { CompanyChip } from '@/companies/components/CompanyChip';
|
||||
import { usePreviousHotkeysScope } from '@/hotkeys/hooks/internal/usePreviousHotkeysScope';
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { PersonChip } from '@/people/components/PersonChip';
|
||||
@ -120,8 +121,20 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
|
||||
searchFilter,
|
||||
});
|
||||
|
||||
const {
|
||||
setHotkeysScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeysScope,
|
||||
} = usePreviousHotkeysScope();
|
||||
|
||||
function handleRelationContainerClick() {
|
||||
setIsMenuOpen((isOpen) => !isOpen);
|
||||
if (isMenuOpen) {
|
||||
exitEditMode();
|
||||
} else {
|
||||
setIsMenuOpen(true);
|
||||
setHotkeysScopeAndMemorizePreviousScope(
|
||||
InternalHotkeysScope.RelationPicker,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Place in a scoped recoil atom family
|
||||
@ -134,6 +147,7 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
|
||||
});
|
||||
|
||||
function exitEditMode() {
|
||||
goBackToPreviousHotkeysScope();
|
||||
setIsMenuOpen(false);
|
||||
setSearchFilter('');
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { commentableEntityArrayState } from '@/comments/states/commentableEntityArrayState';
|
||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody';
|
||||
import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage';
|
||||
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
|
||||
@ -12,11 +10,6 @@ import { Timeline } from '../timeline/Timeline';
|
||||
export function RightDrawerTimeline() {
|
||||
const [commentableEntityArray] = useRecoilState(commentableEntityArrayState);
|
||||
|
||||
useHotkeysScopeOnMountOnly({
|
||||
scope: InternalHotkeysScope.RightDrawer,
|
||||
customScopes: { goto: false, 'command-menu': true },
|
||||
});
|
||||
|
||||
return (
|
||||
<RightDrawerPage>
|
||||
<RightDrawerTopBar />
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { viewableCommentThreadIdState } from '@/comments/states/viewableCommentThreadIdState';
|
||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody';
|
||||
import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage';
|
||||
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
|
||||
@ -12,11 +10,6 @@ import { CommentThread } from '../CommentThread';
|
||||
export function RightDrawerCreateCommentThread() {
|
||||
const commentThreadId = useRecoilValue(viewableCommentThreadIdState);
|
||||
|
||||
useHotkeysScopeOnMountOnly({
|
||||
scope: InternalHotkeysScope.RightDrawer,
|
||||
customScopes: { goto: false, 'command-menu': true },
|
||||
});
|
||||
|
||||
return (
|
||||
<RightDrawerPage>
|
||||
<RightDrawerTopBar title="New note" />
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { viewableCommentThreadIdState } from '@/comments/states/viewableCommentThreadIdState';
|
||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody';
|
||||
import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage';
|
||||
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
|
||||
@ -10,11 +8,8 @@ import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDraw
|
||||
import { CommentThread } from '../CommentThread';
|
||||
|
||||
export function RightDrawerEditCommentThread() {
|
||||
useHotkeysScopeOnMountOnly({
|
||||
scope: InternalHotkeysScope.RightDrawer,
|
||||
customScopes: { goto: false, 'command-menu': true },
|
||||
});
|
||||
const commentThreadId = useRecoilValue(viewableCommentThreadIdState);
|
||||
|
||||
return (
|
||||
<RightDrawerPage>
|
||||
<RightDrawerTopBar title="" />
|
||||
|
@ -4,7 +4,7 @@ import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFiltere
|
||||
import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||
import { EntityForSelect } from '@/relation-picker/types/EntityForSelect';
|
||||
import { Entity } from '@/relation-picker/types/EntityTypeForSelect';
|
||||
import { useEditableCell } from '@/ui/components/editable-cell/hooks/useCloseEditableCell';
|
||||
import { useEditableCell } from '@/ui/components/editable-cell/hooks/useEditableCell';
|
||||
import {
|
||||
Company,
|
||||
User,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { HotkeysScopeStackItem } from '../types/internal/HotkeysScopeStackItems';
|
||||
import { CustomHotkeysScopes } from '../types/internal/CustomHotkeysScope';
|
||||
import { HotkeysScope } from '../types/internal/HotkeysScope';
|
||||
import { InternalHotkeysScope } from '../types/internal/InternalHotkeysScope';
|
||||
|
||||
export const INITIAL_HOTKEYS_SCOPES: string[] = [InternalHotkeysScope.App];
|
||||
@ -8,10 +9,15 @@ export const ALWAYS_ON_HOTKEYS_SCOPES: string[] = [
|
||||
InternalHotkeysScope.App,
|
||||
];
|
||||
|
||||
export const DEFAULT_HOTKEYS_SCOPE_STACK_ITEM: HotkeysScopeStackItem = {
|
||||
export const DEFAULT_HOTKEYS_SCOPE_CUSTOM_SCOPES: CustomHotkeysScopes = {
|
||||
commandMenu: true,
|
||||
goto: false,
|
||||
};
|
||||
|
||||
export const INITIAL_HOTKEYS_SCOPE: HotkeysScope = {
|
||||
scope: InternalHotkeysScope.App,
|
||||
customScopes: {
|
||||
'command-menu': true,
|
||||
commandMenu: true,
|
||||
goto: true,
|
||||
},
|
||||
};
|
||||
|
@ -0,0 +1,29 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentHotkeysScopeState } from '@/hotkeys/states/internal/currentHotkeysScopeState';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
|
||||
import { useHotkeysScopes } from './useHotkeysScopes';
|
||||
|
||||
export function useHotkeysScopeAutoSync() {
|
||||
const { setHotkeysScopes } = useHotkeysScopes();
|
||||
|
||||
const currentHotkeysScope = useRecoilValue(currentHotkeysScopeState);
|
||||
|
||||
useEffect(() => {
|
||||
const scopesToSet: string[] = [];
|
||||
|
||||
if (currentHotkeysScope.customScopes?.commandMenu) {
|
||||
scopesToSet.push(InternalHotkeysScope.CommandMenu);
|
||||
}
|
||||
|
||||
if (currentHotkeysScope?.customScopes?.goto) {
|
||||
scopesToSet.push(InternalHotkeysScope.Goto);
|
||||
}
|
||||
|
||||
scopesToSet.push(currentHotkeysScope.scope);
|
||||
|
||||
setHotkeysScopes(scopesToSet);
|
||||
}, [setHotkeysScopes, currentHotkeysScope]);
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { customHotkeysScopesState } from '@/hotkeys/states/internal/customHotkeysScopesState';
|
||||
import { hotkeysScopeStackState } from '@/hotkeys/states/internal/hotkeysScopeStackState';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
|
||||
import { useHotkeysScope } from './useHotkeysScope';
|
||||
|
||||
export function useHotkeysScopeStackAutoSync() {
|
||||
const { setHotkeysScopes } = useHotkeysScope();
|
||||
|
||||
const hotkeysScopeStack = useRecoilValue(hotkeysScopeStackState);
|
||||
const customHotkeysScopes = useRecoilValue(customHotkeysScopesState);
|
||||
useEffect(() => {
|
||||
if (hotkeysScopeStack.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scopesToSet: string[] = [];
|
||||
|
||||
const currentHotkeysScope = hotkeysScopeStack[hotkeysScopeStack.length - 1];
|
||||
|
||||
if (currentHotkeysScope.customScopes?.['command-menu']) {
|
||||
scopesToSet.push(InternalHotkeysScope.CommandMenu);
|
||||
}
|
||||
|
||||
if (currentHotkeysScope?.customScopes?.goto) {
|
||||
scopesToSet.push(InternalHotkeysScope.Goto);
|
||||
}
|
||||
|
||||
scopesToSet.push(currentHotkeysScope.scope);
|
||||
|
||||
setHotkeysScopes(scopesToSet);
|
||||
}, [setHotkeysScopes, customHotkeysScopes, hotkeysScopeStack]);
|
||||
}
|
@ -3,7 +3,7 @@ import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { internalHotkeysEnabledScopesState } from '@/hotkeys/states/internal/internalHotkeysEnabledScopesState';
|
||||
|
||||
export function useHotkeysScope() {
|
||||
export function useHotkeysScopes() {
|
||||
const { disableScope, enableScope } = useHotkeysContext();
|
||||
|
||||
const disableAllHotkeysScopes = useRecoilCallback(
|
@ -0,0 +1,39 @@
|
||||
import { useState } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentHotkeysScopeState } from '@/hotkeys/states/internal/currentHotkeysScopeState';
|
||||
import { CustomHotkeysScopes } from '@/hotkeys/types/internal/CustomHotkeysScope';
|
||||
import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope';
|
||||
|
||||
import { useSetHotkeysScope } from '../useSetHotkeysScope';
|
||||
|
||||
export function usePreviousHotkeysScope() {
|
||||
const [previousHotkeysScope, setPreviousHotkeysScope] =
|
||||
useState<HotkeysScope | null>();
|
||||
|
||||
const setHotkeysScope = useSetHotkeysScope();
|
||||
|
||||
const currentHotkeysScope = useRecoilValue(currentHotkeysScopeState);
|
||||
|
||||
function goBackToPreviousHotkeysScope() {
|
||||
if (previousHotkeysScope) {
|
||||
setHotkeysScope(
|
||||
previousHotkeysScope.scope,
|
||||
previousHotkeysScope.customScopes,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function setHotkeysScopeAndMemorizePreviousScope(
|
||||
scope: string,
|
||||
customScopes?: CustomHotkeysScopes,
|
||||
) {
|
||||
setPreviousHotkeysScope(currentHotkeysScope);
|
||||
setHotkeysScope(scope, customScopes);
|
||||
}
|
||||
|
||||
return {
|
||||
setHotkeysScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeysScope,
|
||||
};
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
import { produce } from 'immer';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { hotkeysScopeStackState } from '../states/internal/hotkeysScopeStackState';
|
||||
import { HotkeysScopeStackItem } from '../types/internal/HotkeysScopeStackItems';
|
||||
|
||||
export function useAddToHotkeysScopeStack() {
|
||||
return useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async ({
|
||||
scope,
|
||||
customScopes = {
|
||||
'command-menu': true,
|
||||
goto: false,
|
||||
},
|
||||
ancestorScope,
|
||||
}: HotkeysScopeStackItem) => {
|
||||
const hotkeysScopeStack = await snapshot.getPromise(
|
||||
hotkeysScopeStackState,
|
||||
);
|
||||
|
||||
const currentHotkeysScope =
|
||||
hotkeysScopeStack.length > 0
|
||||
? hotkeysScopeStack[hotkeysScopeStack.length - 1]
|
||||
: null;
|
||||
|
||||
const previousHotkeysScope =
|
||||
hotkeysScopeStack.length > 1
|
||||
? hotkeysScopeStack[hotkeysScopeStack.length - 2]
|
||||
: null;
|
||||
|
||||
if (
|
||||
scope === currentHotkeysScope?.scope ||
|
||||
scope === previousHotkeysScope?.scope
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
set(
|
||||
hotkeysScopeStackState,
|
||||
produce(hotkeysScopeStack, (draft) => {
|
||||
draft.push({ scope, customScopes, ancestorScope });
|
||||
}),
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { hotkeysScopeStackState } from '../states/internal/hotkeysScopeStackState';
|
||||
|
||||
export function useCurrentHotkeysScope() {
|
||||
const hotkeysScopeStack = useRecoilValue(hotkeysScopeStackState);
|
||||
|
||||
return useMemo(() => {
|
||||
if (hotkeysScopeStack.length === 0) {
|
||||
return null;
|
||||
} else {
|
||||
return hotkeysScopeStack[hotkeysScopeStack.length - 1];
|
||||
}
|
||||
}, [hotkeysScopeStack]);
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { HotkeysScopeStackItem } from '../types/internal/HotkeysScopeStackItems';
|
||||
|
||||
import { useAddToHotkeysScopeStack } from './useAddToHotkeysScopeStack';
|
||||
import { useRemoveFromHotkeysScopeStack } from './useRemoveFromHotkeysScopeStack';
|
||||
|
||||
export function useHotkeysScopeOnBooleanState(
|
||||
hotkeysScopeStackItem: HotkeysScopeStackItem,
|
||||
booleanState: boolean,
|
||||
) {
|
||||
const addToHotkeysScopeStack = useAddToHotkeysScopeStack();
|
||||
const removeFromHotkeysScopeStack = useRemoveFromHotkeysScopeStack();
|
||||
|
||||
useEffect(() => {
|
||||
if (booleanState) {
|
||||
addToHotkeysScopeStack(hotkeysScopeStackItem);
|
||||
} else {
|
||||
removeFromHotkeysScopeStack(hotkeysScopeStackItem.scope);
|
||||
}
|
||||
}, [
|
||||
hotkeysScopeStackItem,
|
||||
removeFromHotkeysScopeStack,
|
||||
addToHotkeysScopeStack,
|
||||
booleanState,
|
||||
]);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { hotkeysScopeStackState } from '../states/internal/hotkeysScopeStackState';
|
||||
import { HotkeysScopeStackItem } from '../types/internal/HotkeysScopeStackItems';
|
||||
|
||||
import { useAddToHotkeysScopeStack } from './useAddToHotkeysScopeStack';
|
||||
|
||||
export function useHotkeysScopeOnMountOnly(
|
||||
hotkeysScopeStackItem: HotkeysScopeStackItem,
|
||||
enabled = true,
|
||||
) {
|
||||
const addToHotkeysScopeStack = useAddToHotkeysScopeStack();
|
||||
|
||||
const [hotkeysScopeStack] = useRecoilState(hotkeysScopeStackState);
|
||||
|
||||
const hotkeysScopeAlreadyInStack = hotkeysScopeStack.some(
|
||||
(hotkeysScopeStackItemToFind) =>
|
||||
hotkeysScopeStackItemToFind.scope === hotkeysScopeStackItem.scope,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hotkeysScopeAlreadyInStack && enabled) {
|
||||
addToHotkeysScopeStack(hotkeysScopeStackItem);
|
||||
}
|
||||
}, [
|
||||
enabled,
|
||||
addToHotkeysScopeStack,
|
||||
hotkeysScopeStackItem,
|
||||
hotkeysScopeAlreadyInStack,
|
||||
]);
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
import { produce } from 'immer';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { DEFAULT_HOTKEYS_SCOPE_STACK_ITEM } from '../constants';
|
||||
import { hotkeysScopeStackState } from '../states/internal/hotkeysScopeStackState';
|
||||
import { InternalHotkeysScope } from '../types/internal/InternalHotkeysScope';
|
||||
|
||||
export function useRemoveFromHotkeysScopeStack() {
|
||||
return useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (hotkeysScopeToRemove: string) => {
|
||||
const hotkeysScopeStack = await snapshot.getPromise(
|
||||
hotkeysScopeStackState,
|
||||
);
|
||||
|
||||
if (hotkeysScopeStack.length < 1) {
|
||||
set(hotkeysScopeStackState, [DEFAULT_HOTKEYS_SCOPE_STACK_ITEM]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const currentHotkeysScope =
|
||||
hotkeysScopeStack[hotkeysScopeStack.length - 1];
|
||||
|
||||
if (hotkeysScopeStack.length === 1) {
|
||||
if (currentHotkeysScope?.scope !== InternalHotkeysScope.App) {
|
||||
set(hotkeysScopeStackState, [DEFAULT_HOTKEYS_SCOPE_STACK_ITEM]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const previousHotkeysScope =
|
||||
hotkeysScopeStack[hotkeysScopeStack.length - 2];
|
||||
|
||||
if (
|
||||
previousHotkeysScope.scope === hotkeysScopeToRemove ||
|
||||
currentHotkeysScope.scope !== hotkeysScopeToRemove
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
set(
|
||||
hotkeysScopeStackState,
|
||||
produce(hotkeysScopeStack, (draft) => {
|
||||
return draft.filter(
|
||||
(hotkeysScope) => hotkeysScope.scope !== hotkeysScopeToRemove,
|
||||
);
|
||||
}),
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
import { produce } from 'immer';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { DEFAULT_HOTKEYS_SCOPE_STACK_ITEM } from '../constants';
|
||||
import { hotkeysScopeStackState } from '../states/internal/hotkeysScopeStackState';
|
||||
import { InternalHotkeysScope } from '../types/internal/InternalHotkeysScope';
|
||||
|
||||
export function useRemoveHighestHotkeysScopeStackItem() {
|
||||
return useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async () => {
|
||||
const hotkeysScopeStack = await snapshot.getPromise(
|
||||
hotkeysScopeStackState,
|
||||
);
|
||||
|
||||
if (hotkeysScopeStack.length < 1) {
|
||||
set(hotkeysScopeStackState, [DEFAULT_HOTKEYS_SCOPE_STACK_ITEM]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const currentHotkeysScope =
|
||||
hotkeysScopeStack[hotkeysScopeStack.length - 1];
|
||||
|
||||
if (hotkeysScopeStack.length === 1) {
|
||||
if (currentHotkeysScope?.scope !== InternalHotkeysScope.App) {
|
||||
set(hotkeysScopeStackState, [DEFAULT_HOTKEYS_SCOPE_STACK_ITEM]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
set(
|
||||
hotkeysScopeStackState,
|
||||
produce(hotkeysScopeStack, (draft) => {
|
||||
draft.pop();
|
||||
}),
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
import { useResetRecoilState } from 'recoil';
|
||||
|
||||
import { hotkeysScopeStackState } from '../states/internal/hotkeysScopeStackState';
|
||||
|
||||
import { useAddToHotkeysScopeStack } from './useAddToHotkeysScopeStack';
|
||||
|
||||
export function useResetHotkeysScopeStack() {
|
||||
const resetHotkeysScopeStack = useResetRecoilState(hotkeysScopeStackState);
|
||||
const addHotkeysScopedStack = useAddToHotkeysScopeStack();
|
||||
|
||||
return function reset(toFirstScope?: string) {
|
||||
resetHotkeysScopeStack();
|
||||
|
||||
if (toFirstScope) {
|
||||
addHotkeysScopedStack({ scope: toFirstScope });
|
||||
}
|
||||
};
|
||||
}
|
59
front/src/modules/hotkeys/hooks/useSetHotkeysScope.ts
Normal file
59
front/src/modules/hotkeys/hooks/useSetHotkeysScope.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { isDefined } from '@/utils/type-guards/isDefined';
|
||||
|
||||
import { DEFAULT_HOTKEYS_SCOPE_CUSTOM_SCOPES } from '../constants';
|
||||
import { currentHotkeysScopeState } from '../states/internal/currentHotkeysScopeState';
|
||||
import { CustomHotkeysScopes } from '../types/internal/CustomHotkeysScope';
|
||||
|
||||
export function useSetHotkeysScope() {
|
||||
return useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (hotkeysScopeToSet: string, customScopes?: CustomHotkeysScopes) => {
|
||||
const currentHotkeysScope = await snapshot.getPromise(
|
||||
currentHotkeysScopeState,
|
||||
);
|
||||
|
||||
function isCustomScopesEqual(
|
||||
customScopesA: CustomHotkeysScopes | undefined,
|
||||
customScopesB: CustomHotkeysScopes | undefined,
|
||||
) {
|
||||
return (
|
||||
customScopesA?.commandMenu === customScopesB?.commandMenu &&
|
||||
customScopesA?.goto === customScopesB?.goto
|
||||
);
|
||||
}
|
||||
|
||||
if (currentHotkeysScope.scope === hotkeysScopeToSet) {
|
||||
if (!isDefined(customScopes)) {
|
||||
if (
|
||||
isCustomScopesEqual(
|
||||
currentHotkeysScope?.customScopes,
|
||||
DEFAULT_HOTKEYS_SCOPE_CUSTOM_SCOPES,
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
isCustomScopesEqual(
|
||||
currentHotkeysScope?.customScopes,
|
||||
customScopes,
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set(currentHotkeysScopeState, {
|
||||
scope: hotkeysScopeToSet,
|
||||
customScopes: {
|
||||
commandMenu: customScopes?.commandMenu ?? true,
|
||||
goto: customScopes?.goto ?? false,
|
||||
},
|
||||
});
|
||||
},
|
||||
[],
|
||||
);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { INITIAL_HOTKEYS_SCOPE } from '@/hotkeys/constants';
|
||||
import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope';
|
||||
|
||||
export const currentHotkeysScopeState = atom<HotkeysScope>({
|
||||
key: 'currentHotkeysScopeState',
|
||||
default: INITIAL_HOTKEYS_SCOPE,
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { InternalHotkeysScope } from '../../types/internal/InternalHotkeysScope';
|
||||
|
||||
export type CustomHotkeysScopes = {
|
||||
[InternalHotkeysScope.Goto]: boolean;
|
||||
[InternalHotkeysScope.CommandMenu]: boolean;
|
||||
};
|
||||
|
||||
export const customHotkeysScopesState = atom<CustomHotkeysScopes>({
|
||||
key: 'customHotkeysScopesState',
|
||||
default: {
|
||||
'command-menu': true,
|
||||
goto: false,
|
||||
},
|
||||
});
|
@ -1,9 +0,0 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { DEFAULT_HOTKEYS_SCOPE_STACK_ITEM } from '@/hotkeys/constants';
|
||||
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
||||
|
||||
export const hotkeysScopeStackState = atom<HotkeysScopeStackItem[]>({
|
||||
key: 'hotkeysScopeStackState',
|
||||
default: [DEFAULT_HOTKEYS_SCOPE_STACK_ITEM],
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
export enum HotkeysScope {
|
||||
CompanyPage = 'company-page',
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
export type CustomHotkeysScopes = {
|
||||
goto?: boolean;
|
||||
commandMenu?: boolean;
|
||||
};
|
6
front/src/modules/hotkeys/types/internal/HotkeysScope.ts
Normal file
6
front/src/modules/hotkeys/types/internal/HotkeysScope.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { CustomHotkeysScopes } from './CustomHotkeysScope';
|
||||
|
||||
export type HotkeysScope = {
|
||||
scope: string;
|
||||
customScopes?: CustomHotkeysScopes;
|
||||
};
|
@ -1,7 +0,0 @@
|
||||
import { CustomHotkeysScopes } from '@/hotkeys/states/internal/customHotkeysScopesState';
|
||||
|
||||
export type HotkeysScopeStackItem = {
|
||||
scope: string;
|
||||
customScopes?: CustomHotkeysScopes;
|
||||
ancestorScope?: string | null;
|
||||
};
|
@ -11,6 +11,7 @@ export enum InternalHotkeysScope {
|
||||
TableHeaderDropdownButton = 'table-header-dropdown-button',
|
||||
RelationPicker = 'relation-picker',
|
||||
CellDoubleTextInput = 'cell-double-text-input',
|
||||
TextInput = 'text-input',
|
||||
Settings = 'settings',
|
||||
CreateWokspace = 'create-workspace',
|
||||
PasswordLogin = 'password-login',
|
||||
|
15
front/src/modules/hotkeys/types/internal/PageHotkeysScope.ts
Normal file
15
front/src/modules/hotkeys/types/internal/PageHotkeysScope.ts
Normal file
@ -0,0 +1,15 @@
|
||||
export enum PageHotkeysScope {
|
||||
Settings = 'settings',
|
||||
CreateWokspace = 'create-workspace',
|
||||
PasswordLogin = 'password-login',
|
||||
AuthIndex = 'auth-index',
|
||||
CreateProfile = 'create-profile',
|
||||
ShowPage = 'show-page',
|
||||
PersonShowPage = 'person-show-page',
|
||||
CompanyShowPage = 'company-show-page',
|
||||
CompaniesPage = 'companies-page',
|
||||
PeoplePage = 'people-page',
|
||||
OpportunitiesPage = 'opportunities-page',
|
||||
ProfilePage = 'profile-page',
|
||||
WorkspaceMemberPage = 'workspace-member-page',
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useAddToHotkeysScopeStack } from '@/hotkeys/hooks/useAddToHotkeysScopeStack';
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect';
|
||||
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
|
||||
import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||
import { useEditableCell } from '@/ui/components/editable-cell/hooks/useCloseEditableCell';
|
||||
import { useEditableCell } from '@/ui/components/editable-cell/hooks/useEditableCell';
|
||||
import { isCreateModeScopedState } from '@/ui/components/editable-cell/states/isCreateModeScopedState';
|
||||
import { getLogoUrlFromDomainName } from '@/utils/utils';
|
||||
import {
|
||||
@ -32,7 +32,7 @@ export function PeopleCompanyPicker({ people }: OwnProps) {
|
||||
|
||||
const { closeEditableCell } = useEditableCell();
|
||||
|
||||
const addToScopeStack = useAddToHotkeysScopeStack();
|
||||
const addToScopeStack = useSetHotkeysScope();
|
||||
|
||||
const companies = useFilteredSearchEntityQuery({
|
||||
queryHook: useSearchCompanyQuery,
|
||||
@ -62,7 +62,7 @@ export function PeopleCompanyPicker({ people }: OwnProps) {
|
||||
|
||||
function handleCreate() {
|
||||
setIsCreating(true);
|
||||
addToScopeStack({ scope: InternalHotkeysScope.CellDoubleTextInput });
|
||||
addToScopeStack(InternalHotkeysScope.CellDoubleTextInput);
|
||||
}
|
||||
|
||||
useScopedHotkeys(
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { useHotkeysScopeOnBooleanState } from '@/hotkeys/hooks/useHotkeysScopeOnBooleanState';
|
||||
import { usePreviousHotkeysScope } from '@/hotkeys/hooks/internal/usePreviousHotkeysScope';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
|
||||
import { Column } from '@/ui/board/components/Board';
|
||||
@ -26,16 +26,27 @@ type OwnProps = {
|
||||
};
|
||||
|
||||
export function NewButton({ pipelineId, columnId }: OwnProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [isCreatingCard, setIsCreatingCard] = useState(false);
|
||||
const [board, setBoard] = useRecoilState(boardColumnsState);
|
||||
const [boardItems, setBoardItems] = useRecoilState(boardItemsState);
|
||||
|
||||
const {
|
||||
goBackToPreviousHotkeysScope,
|
||||
setHotkeysScopeAndMemorizePreviousScope,
|
||||
} = usePreviousHotkeysScope();
|
||||
|
||||
const [createOnePipelineProgress] = useCreateOnePipelineProgressMutation({
|
||||
refetchQueries: [getOperationName(GET_PIPELINES) ?? ''],
|
||||
});
|
||||
const onEntitySelect = useCallback(
|
||||
|
||||
const handleEntitySelect = useCallback(
|
||||
async (company: Pick<Company, 'id' | 'name' | 'domainName'>) => {
|
||||
if (!company || !company.name || !company.domainName) return;
|
||||
|
||||
setIsCreatingCard(false);
|
||||
goBackToPreviousHotkeysScope();
|
||||
|
||||
const newUuid = uuidv4();
|
||||
const newBoard = JSON.parse(JSON.stringify(board));
|
||||
const destinationColumnIndex = newBoard.findIndex(
|
||||
@ -71,26 +82,35 @@ export function NewButton({ pipelineId, columnId }: OwnProps) {
|
||||
setBoard,
|
||||
boardItems,
|
||||
setBoardItems,
|
||||
goBackToPreviousHotkeysScope,
|
||||
],
|
||||
);
|
||||
|
||||
const onNewClick = useCallback(() => {
|
||||
const handleNewClick = useCallback(() => {
|
||||
setIsCreatingCard(true);
|
||||
}, [setIsCreatingCard]);
|
||||
setHotkeysScopeAndMemorizePreviousScope(
|
||||
InternalHotkeysScope.RelationPicker,
|
||||
);
|
||||
}, [setIsCreatingCard, setHotkeysScopeAndMemorizePreviousScope]);
|
||||
|
||||
useHotkeysScopeOnBooleanState(
|
||||
{ scope: InternalHotkeysScope.RelationPicker },
|
||||
isCreatingCard,
|
||||
);
|
||||
function handleCancel() {
|
||||
goBackToPreviousHotkeysScope();
|
||||
setIsCreatingCard(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isCreatingCard && (
|
||||
<RecoilScope>
|
||||
<NewCompanyBoardCard onEntitySelect={onEntitySelect} />
|
||||
<div ref={containerRef}>
|
||||
<NewCompanyBoardCard
|
||||
onEntitySelect={handleEntitySelect}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
</div>
|
||||
</RecoilScope>
|
||||
)}
|
||||
<UINewButton onClick={onNewClick} />
|
||||
<UINewButton onClick={handleNewClick} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -13,9 +13,10 @@ type OwnProps = {
|
||||
onEntitySelect: (
|
||||
company: Pick<Company, 'id' | 'name' | 'domainName'>,
|
||||
) => void;
|
||||
onCancel: () => void;
|
||||
};
|
||||
|
||||
export function NewCompanyBoardCard({ onEntitySelect }: OwnProps) {
|
||||
export function NewCompanyBoardCard({ onEntitySelect, onCancel }: OwnProps) {
|
||||
const [searchFilter] = useRecoilScopedState(
|
||||
relationPickerSearchFilterScopedState,
|
||||
);
|
||||
@ -39,6 +40,7 @@ export function NewCompanyBoardCard({ onEntitySelect }: OwnProps) {
|
||||
return (
|
||||
<SingleEntitySelect
|
||||
onEntitySelected={(value) => onEntitySelect(value)}
|
||||
onCancel={onCancel}
|
||||
entities={{
|
||||
entitiesToSelect: companies.entitiesToSelect,
|
||||
selectedEntity: companies.selectedEntities[0],
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { useRef } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { IconPlus } from '@tabler/icons-react';
|
||||
|
||||
@ -7,6 +8,7 @@ import { DropdownMenuButton } from '@/ui/components/menu/DropdownMenuButton';
|
||||
import { DropdownMenuItemContainer } from '@/ui/components/menu/DropdownMenuItemContainer';
|
||||
import { DropdownMenuSearch } from '@/ui/components/menu/DropdownMenuSearch';
|
||||
import { DropdownMenuSeparator } from '@/ui/components/menu/DropdownMenuSeparator';
|
||||
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { isDefined } from '@/utils/type-guards/isDefined';
|
||||
|
||||
import { useEntitySelectSearch } from '../hooks/useEntitySelectSearch';
|
||||
@ -27,19 +29,27 @@ export function SingleEntitySelect<
|
||||
entities,
|
||||
onEntitySelected,
|
||||
onCreate,
|
||||
onCancel,
|
||||
}: {
|
||||
onCancel?: () => void;
|
||||
onCreate?: () => void;
|
||||
entities: EntitiesForSingleEntitySelect<CustomEntityForSelect>;
|
||||
onEntitySelected: (entity: CustomEntityForSelect) => void;
|
||||
}) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const { searchFilter, handleSearchFilterChange } = useEntitySelectSearch();
|
||||
|
||||
const showCreateButton = isDefined(onCreate) && searchFilter !== '';
|
||||
|
||||
useListenClickOutsideArrayOfRef([containerRef], () => {
|
||||
onCancel?.();
|
||||
});
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenu ref={containerRef}>
|
||||
<DropdownMenuSearch
|
||||
value={searchFilter}
|
||||
onChange={handleSearchFilterChange}
|
||||
@ -60,6 +70,7 @@ export function SingleEntitySelect<
|
||||
<SingleEntitySelectBase
|
||||
entities={entities}
|
||||
onEntitySelected={onEntitySelected}
|
||||
onCancel={onCancel}
|
||||
/>
|
||||
</DropdownMenu>
|
||||
);
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { useRef } from 'react';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
@ -27,30 +28,41 @@ export function SingleEntitySelectBase<
|
||||
>({
|
||||
entities,
|
||||
onEntitySelected,
|
||||
onCancel,
|
||||
}: {
|
||||
entities: EntitiesForSingleEntitySelect<CustomEntityForSelect>;
|
||||
onEntitySelected: (entity: CustomEntityForSelect) => void;
|
||||
onCancel?: () => void;
|
||||
}) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const entitiesInDropdown = isDefined(entities.selectedEntity)
|
||||
? [entities.selectedEntity, ...(entities.entitiesToSelect ?? [])]
|
||||
: entities.entitiesToSelect ?? [];
|
||||
|
||||
const { hoveredIndex } = useEntitySelectScroll({
|
||||
const { hoveredIndex, resetScroll } = useEntitySelectScroll({
|
||||
entities: entitiesInDropdown,
|
||||
containerRef,
|
||||
});
|
||||
|
||||
// TODO: move to better place for scopping
|
||||
useScopedHotkeys(
|
||||
'enter',
|
||||
Key.Enter,
|
||||
() => {
|
||||
onEntitySelected(entitiesInDropdown[hoveredIndex]);
|
||||
resetScroll();
|
||||
},
|
||||
InternalHotkeysScope.RelationPicker,
|
||||
[entitiesInDropdown, hoveredIndex, onEntitySelected],
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
() => {
|
||||
onCancel?.();
|
||||
},
|
||||
InternalHotkeysScope.RelationPicker,
|
||||
[onCancel],
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownMenuItemContainer ref={containerRef}>
|
||||
{entities.loading ? (
|
||||
|
@ -21,6 +21,22 @@ export function useEntitySelectScroll<
|
||||
relationPickerHoverIndexScopedState,
|
||||
);
|
||||
|
||||
function resetScroll() {
|
||||
setHoveredIndex(0);
|
||||
|
||||
const currentHoveredRef = containerRef.current?.children[0] as HTMLElement;
|
||||
|
||||
scrollIntoView(currentHoveredRef, {
|
||||
align: {
|
||||
top: 0,
|
||||
},
|
||||
isScrollable: (target) => {
|
||||
return target === containerRef.current;
|
||||
},
|
||||
time: 0,
|
||||
});
|
||||
}
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.ArrowUp,
|
||||
() => {
|
||||
@ -60,7 +76,6 @@ export function useEntitySelectScroll<
|
||||
] as HTMLElement;
|
||||
|
||||
if (currentHoveredRef) {
|
||||
console.log({ currentHoveredRef, containerRef });
|
||||
scrollIntoView(currentHoveredRef, {
|
||||
align: {
|
||||
top: 0.15,
|
||||
@ -78,5 +93,6 @@ export function useEntitySelectScroll<
|
||||
|
||||
return {
|
||||
hoveredIndex,
|
||||
resetScroll,
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { useBoardCardField } from '@/ui/board-card-field/hooks/useBoardCardField';
|
||||
import { InplaceInputDateEditMode } from '@/ui/inplace-inputs/components/InplaceInputDateEditMode';
|
||||
|
||||
type OwnProps = {
|
||||
@ -10,11 +9,8 @@ export function BoardCardEditableFieldDateEditMode({
|
||||
value,
|
||||
onChange,
|
||||
}: OwnProps) {
|
||||
const { closeBoardCardField } = useBoardCardField();
|
||||
|
||||
function handleDateChange(newDate: Date) {
|
||||
onChange(newDate);
|
||||
closeBoardCardField();
|
||||
}
|
||||
|
||||
return <InplaceInputDateEditMode value={value} onChange={handleDateChange} />;
|
||||
|
@ -19,9 +19,11 @@ export function BoardCardEditableFieldText({
|
||||
editModeHorizontalAlign,
|
||||
}: OwnProps) {
|
||||
const [internalValue, setInternalValue] = useState(value);
|
||||
|
||||
const debouncedOnChange = useMemo(() => {
|
||||
return debounce(onChange, 200);
|
||||
}, [onChange]);
|
||||
|
||||
return (
|
||||
<BoardCardEditableField
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ReactElement } from 'react';
|
||||
|
||||
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
||||
import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope';
|
||||
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
|
||||
|
||||
import { BoardCardFieldContext } from '../states/BoardCardFieldContext';
|
||||
@ -12,7 +12,7 @@ type OwnProps = {
|
||||
nonEditModeContent: ReactElement;
|
||||
editModeHorizontalAlign?: 'left' | 'right';
|
||||
editModeVerticalPosition?: 'over' | 'below';
|
||||
editHotkeysScope?: HotkeysScopeStackItem;
|
||||
editHotkeysScope?: HotkeysScope;
|
||||
};
|
||||
|
||||
export function BoardCardEditableField(props: OwnProps) {
|
||||
|
@ -6,9 +6,9 @@ import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysSc
|
||||
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { overlayBackground } from '@/ui/themes/effects';
|
||||
|
||||
import { useBoardCardField } from '../hooks/useBoardCardField';
|
||||
|
||||
export const BoardCardFieldEditModeContainer = styled.div<OwnProps>`
|
||||
export const BoardCardFieldEditModeContainer = styled.div<
|
||||
Omit<OwnProps, 'onExit'>
|
||||
>`
|
||||
align-items: center;
|
||||
border: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
@ -31,38 +31,37 @@ type OwnProps = {
|
||||
children: ReactElement;
|
||||
editModeHorizontalAlign?: 'left' | 'right';
|
||||
editModeVerticalPosition?: 'over' | 'below';
|
||||
onOutsideClick?: () => void;
|
||||
onExit: () => void;
|
||||
};
|
||||
|
||||
export function BoardCardEditableFieldEditMode({
|
||||
editModeHorizontalAlign,
|
||||
editModeVerticalPosition,
|
||||
children,
|
||||
onExit,
|
||||
}: OwnProps) {
|
||||
const wrapperRef = useRef(null);
|
||||
|
||||
const { closeBoardCardField } = useBoardCardField();
|
||||
|
||||
useListenClickOutsideArrayOfRef([wrapperRef], () => {
|
||||
closeBoardCardField();
|
||||
onExit();
|
||||
});
|
||||
|
||||
useScopedHotkeys(
|
||||
'enter',
|
||||
() => {
|
||||
closeBoardCardField();
|
||||
onExit();
|
||||
},
|
||||
InternalHotkeysScope.BoardCardFieldEditMode,
|
||||
[closeBoardCardField],
|
||||
[onExit],
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
'esc',
|
||||
() => {
|
||||
closeBoardCardField();
|
||||
onExit();
|
||||
},
|
||||
InternalHotkeysScope.BoardCardFieldEditMode,
|
||||
[closeBoardCardField],
|
||||
[onExit],
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { ReactElement } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useAddToHotkeysScopeStack } from '@/hotkeys/hooks/useAddToHotkeysScopeStack';
|
||||
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
||||
import { usePreviousHotkeysScope } from '@/hotkeys/hooks/internal/usePreviousHotkeysScope';
|
||||
import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
|
||||
import { useBoardCardField } from '../hooks/useBoardCardField';
|
||||
@ -26,7 +26,7 @@ type OwnProps = {
|
||||
nonEditModeContent: ReactElement;
|
||||
editModeHorizontalAlign?: 'left' | 'right';
|
||||
editModeVerticalPosition?: 'over' | 'below';
|
||||
editHotkeysScope?: HotkeysScopeStackItem;
|
||||
editHotkeysScope?: HotkeysScope;
|
||||
};
|
||||
|
||||
export function BoardCardEditableFieldInternal({
|
||||
@ -39,25 +39,35 @@ export function BoardCardEditableFieldInternal({
|
||||
const { openBoardCardField, isBoardCardFieldInEditMode } =
|
||||
useBoardCardField();
|
||||
|
||||
const addToHotkeysScopeStack = useAddToHotkeysScopeStack();
|
||||
const { closeBoardCardField } = useBoardCardField();
|
||||
|
||||
const {
|
||||
goBackToPreviousHotkeysScope,
|
||||
setHotkeysScopeAndMemorizePreviousScope,
|
||||
} = usePreviousHotkeysScope();
|
||||
|
||||
function handleOnClick() {
|
||||
if (!isBoardCardFieldInEditMode) {
|
||||
openBoardCardField();
|
||||
addToHotkeysScopeStack(
|
||||
editHotkeysScope ?? {
|
||||
scope: InternalHotkeysScope.BoardCardFieldEditMode,
|
||||
},
|
||||
setHotkeysScopeAndMemorizePreviousScope(
|
||||
editHotkeysScope?.scope ?? InternalHotkeysScope.BoardCardFieldEditMode,
|
||||
editHotkeysScope?.customScopes ?? {},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function handleEditModeExit() {
|
||||
goBackToPreviousHotkeysScope();
|
||||
closeBoardCardField();
|
||||
}
|
||||
|
||||
return (
|
||||
<BoardCardFieldContainer onClick={handleOnClick}>
|
||||
{isBoardCardFieldInEditMode ? (
|
||||
<BoardCardEditableFieldEditMode
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
editModeVerticalPosition={editModeVerticalPosition}
|
||||
onExit={handleEditModeExit}
|
||||
>
|
||||
{editModeContent}
|
||||
</BoardCardEditableFieldEditMode>
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { ReactElement } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
||||
import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
|
||||
import { useEditableCell } from './hooks/useCloseEditableCell';
|
||||
import { useCurrentCellEditMode } from './hooks/useCurrentCellEditMode';
|
||||
import { useEditableCell } from './hooks/useEditableCell';
|
||||
import { useIsSoftFocusOnCurrentCell } from './hooks/useIsSoftFocusOnCurrentCell';
|
||||
import { useSetSoftFocusOnCurrentCell } from './hooks/useSetSoftFocusOnCurrentCell';
|
||||
import { EditableCellDisplayMode } from './EditableCellDisplayMode';
|
||||
@ -28,7 +28,7 @@ type OwnProps = {
|
||||
nonEditModeContent: ReactElement;
|
||||
editModeHorizontalAlign?: 'left' | 'right';
|
||||
editModeVerticalPosition?: 'over' | 'below';
|
||||
editHotkeysScope?: HotkeysScopeStackItem;
|
||||
editHotkeysScope?: HotkeysScope;
|
||||
};
|
||||
|
||||
export function EditableCell({
|
||||
@ -60,9 +60,9 @@ export function EditableCell({
|
||||
scope: InternalHotkeysScope.CellEditMode,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
setSoftFocusOnCurrentCell();
|
||||
}
|
||||
|
||||
setSoftFocusOnCurrentCell();
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -7,7 +7,7 @@ import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsid
|
||||
import { useMoveSoftFocus } from '@/ui/tables/hooks/useMoveSoftFocus';
|
||||
import { overlayBackground } from '@/ui/themes/effects';
|
||||
|
||||
import { useEditableCell } from './hooks/useCloseEditableCell';
|
||||
import { useEditableCell } from './hooks/useEditableCell';
|
||||
|
||||
export const EditableCellEditModeContainer = styled.div<OwnProps>`
|
||||
align-items: center;
|
||||
|
@ -1,17 +1,17 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
||||
import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { isNonTextWritingKey } from '@/utils/hotkeys/isNonTextWritingKey';
|
||||
|
||||
import { useEditableCell } from './hooks/useCloseEditableCell';
|
||||
import { useEditableCell } from './hooks/useEditableCell';
|
||||
import { EditableCellDisplayMode } from './EditableCellDisplayMode';
|
||||
|
||||
export function EditableCellSoftFocusMode({
|
||||
children,
|
||||
editHotkeysScope,
|
||||
}: React.PropsWithChildren<{ editHotkeysScope?: HotkeysScopeStackItem }>) {
|
||||
}: React.PropsWithChildren<{ editHotkeysScope?: HotkeysScope }>) {
|
||||
const { closeEditableCell, openEditableCell } = useEditableCell();
|
||||
|
||||
useScopedHotkeys(
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useAddToHotkeysScopeStack } from '@/hotkeys/hooks/useAddToHotkeysScopeStack';
|
||||
import { useRemoveHighestHotkeysScopeStackItem } from '@/hotkeys/hooks/useRemoveHighestHotkeysScopeStackItem';
|
||||
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
||||
import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope';
|
||||
import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { useCloseCurrentCellInEditMode } from '@/ui/tables/hooks/useClearCellInEditMode';
|
||||
import { isSoftFocusActiveState } from '@/ui/tables/states/isSoftFocusActiveState';
|
||||
import { isSomeInputInEditModeState } from '@/ui/tables/states/isSomeInputInEditModeState';
|
||||
@ -12,21 +12,18 @@ import { useCurrentCellEditMode } from './useCurrentCellEditMode';
|
||||
export function useEditableCell() {
|
||||
const { setCurrentCellInEditMode } = useCurrentCellEditMode();
|
||||
|
||||
const addToHotkeysScopeStack = useAddToHotkeysScopeStack();
|
||||
const setHotkeysScope = useSetHotkeysScope();
|
||||
|
||||
const closeCurrentCellInEditMode = useCloseCurrentCellInEditMode();
|
||||
|
||||
const removeHighestHotkeysScopedStackItem =
|
||||
useRemoveHighestHotkeysScopeStackItem();
|
||||
|
||||
function closeEditableCell() {
|
||||
closeCurrentCellInEditMode();
|
||||
removeHighestHotkeysScopedStackItem();
|
||||
setHotkeysScope(InternalHotkeysScope.TableSoftFocus);
|
||||
}
|
||||
|
||||
const openEditableCell = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
(hotkeysScopeStackItem: HotkeysScopeStackItem) => {
|
||||
(hotkeysScope: HotkeysScope) => {
|
||||
const isSomeInputInEditMode = snapshot
|
||||
.getLoadable(isSomeInputInEditModeState)
|
||||
.valueOrThrow();
|
||||
@ -37,10 +34,10 @@ export function useEditableCell() {
|
||||
|
||||
setCurrentCellInEditMode();
|
||||
|
||||
addToHotkeysScopeStack(hotkeysScopeStackItem);
|
||||
setHotkeysScope(hotkeysScope.scope);
|
||||
}
|
||||
},
|
||||
[setCurrentCellInEditMode, addToHotkeysScopeStack],
|
||||
[setCurrentCellInEditMode, setHotkeysScope],
|
||||
);
|
||||
|
||||
return {
|
@ -1,7 +1,7 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useAddToHotkeysScopeStack } from '@/hotkeys/hooks/useAddToHotkeysScopeStack';
|
||||
import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { useSetSoftFocusPosition } from '@/ui/tables/hooks/useSetSoftFocusPosition';
|
||||
@ -34,16 +34,16 @@ export function useSetSoftFocusOnCurrentCell() {
|
||||
|
||||
const [, setIsSoftFocusActive] = useRecoilState(isSoftFocusActiveState);
|
||||
|
||||
const addToHotkeysScopeStack = useAddToHotkeysScopeStack();
|
||||
const setHotkeysScope = useSetHotkeysScope();
|
||||
|
||||
return useCallback(() => {
|
||||
setSoftFocusPosition(currentTablePosition);
|
||||
setIsSoftFocusActive(true);
|
||||
addToHotkeysScopeStack({ scope: InternalHotkeysScope.TableSoftFocus });
|
||||
setHotkeysScope(InternalHotkeysScope.TableSoftFocus);
|
||||
}, [
|
||||
setSoftFocusPosition,
|
||||
currentTablePosition,
|
||||
setIsSoftFocusActive,
|
||||
addToHotkeysScopeStack,
|
||||
setHotkeysScope,
|
||||
]);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { InplaceInputDateEditMode } from '@/ui/inplace-inputs/components/InplaceInputDateEditMode';
|
||||
|
||||
import { useEditableCell } from '../hooks/useCloseEditableCell';
|
||||
import { useEditableCell } from '../hooks/useEditableCell';
|
||||
|
||||
export type EditableDateProps = {
|
||||
value: Date;
|
||||
|
@ -7,7 +7,7 @@ import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysSc
|
||||
import { InplaceInputTextEditMode } from '@/ui/inplace-inputs/components/InplaceInputTextEditMode';
|
||||
import { useMoveSoftFocus } from '@/ui/tables/hooks/useMoveSoftFocus';
|
||||
|
||||
import { useEditableCell } from '../hooks/useCloseEditableCell';
|
||||
import { useEditableCell } from '../hooks/useEditableCell';
|
||||
|
||||
type OwnProps = {
|
||||
firstValue: string;
|
||||
|
@ -1,5 +1,10 @@
|
||||
import { ChangeEvent } from 'react';
|
||||
import { ChangeEvent, useRef } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { usePreviousHotkeysScope } from '@/hotkeys/hooks/internal/usePreviousHotkeysScope';
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
|
||||
type OwnProps = Omit<
|
||||
React.InputHTMLAttributes<HTMLInputElement>,
|
||||
@ -52,10 +57,37 @@ export function TextInput({
|
||||
fullWidth,
|
||||
...props
|
||||
}: OwnProps): JSX.Element {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const {
|
||||
goBackToPreviousHotkeysScope,
|
||||
setHotkeysScopeAndMemorizePreviousScope,
|
||||
} = usePreviousHotkeysScope();
|
||||
|
||||
function handleFocus() {
|
||||
setHotkeysScopeAndMemorizePreviousScope(InternalHotkeysScope.TextInput);
|
||||
}
|
||||
|
||||
function handleBlur() {
|
||||
goBackToPreviousHotkeysScope();
|
||||
}
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Enter, Key.Escape],
|
||||
() => {
|
||||
inputRef.current?.blur();
|
||||
},
|
||||
InternalHotkeysScope.TextInput,
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
{label && <StyledLabel>{label}</StyledLabel>}
|
||||
<StyledInput
|
||||
ref={inputRef}
|
||||
tabIndex={props.tabIndex ?? 0}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
fullWidth={fullWidth ?? false}
|
||||
value={value}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { activeTableFiltersScopedState } from '@/filters-and-sorts/states/activeTableFiltersScopedState';
|
||||
import { filterDropdownSearchInputScopedState } from '@/filters-and-sorts/states/filterDropdownSearchInputScopedState';
|
||||
import { isFilterDropdownOperandSelectUnfoldedScopedState } from '@/filters-and-sorts/states/isFilterDropdownOperandSelectUnfoldedScopedState';
|
||||
import { selectedOperandInDropdownScopedState } from '@/filters-and-sorts/states/selectedOperandInDropdownScopedState';
|
||||
import { tableFilterDefinitionUsedInDropdownScopedState } from '@/filters-and-sorts/states/tableFilterDefinitionUsedInDropdownScopedState';
|
||||
import { useHotkeysScopeOnBooleanState } from '@/hotkeys/hooks/useHotkeysScopeOnBooleanState';
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { TableContext } from '@/ui/tables/states/TableContext';
|
||||
@ -23,11 +25,6 @@ import { FilterDropdownTextSearchInput } from './FilterDropdownTextSearchInput';
|
||||
export function FilterDropdownButton() {
|
||||
const [isUnfolded, setIsUnfolded] = useState(false);
|
||||
|
||||
useHotkeysScopeOnBooleanState(
|
||||
{ scope: InternalHotkeysScope.TableHeaderDropdownButton },
|
||||
isUnfolded,
|
||||
);
|
||||
|
||||
const [
|
||||
isFilterDropdownOperandSelectUnfolded,
|
||||
setIsFilterDropdownOperandSelectUnfolded,
|
||||
@ -71,18 +68,27 @@ export function FilterDropdownButton() {
|
||||
|
||||
const isFilterSelected = (activeTableFilters?.length ?? 0) > 0;
|
||||
|
||||
const setHotkeysScope = useSetHotkeysScope();
|
||||
|
||||
function handleIsUnfoldedChange(newIsUnfolded: boolean) {
|
||||
if (newIsUnfolded) {
|
||||
setIsUnfolded(true);
|
||||
} else {
|
||||
if (tableFilterDefinitionUsedInDropdown?.type === 'entity') {
|
||||
setHotkeysScope(InternalHotkeysScope.Table);
|
||||
}
|
||||
setIsUnfolded(false);
|
||||
resetState();
|
||||
}
|
||||
}
|
||||
|
||||
useHotkeysScopeOnBooleanState(
|
||||
{ scope: InternalHotkeysScope.RelationPicker },
|
||||
tableFilterDefinitionUsedInDropdown?.type === 'entity',
|
||||
useScopedHotkeys(
|
||||
[Key.Escape],
|
||||
() => {
|
||||
handleIsUnfoldedChange(false);
|
||||
},
|
||||
InternalHotkeysScope.RelationPicker,
|
||||
[handleIsUnfoldedChange],
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -3,6 +3,8 @@ import { filterDropdownSearchInputScopedState } from '@/filters-and-sorts/states
|
||||
import { selectedOperandInDropdownScopedState } from '@/filters-and-sorts/states/selectedOperandInDropdownScopedState';
|
||||
import { tableFilterDefinitionUsedInDropdownScopedState } from '@/filters-and-sorts/states/tableFilterDefinitionUsedInDropdownScopedState';
|
||||
import { getOperandsForFilterType } from '@/filters-and-sorts/utils/getOperandsForFilterType';
|
||||
import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { useRecoilScopedValue } from '@/recoil-scope/hooks/useRecoilScopedValue';
|
||||
import { TableContext } from '@/ui/tables/states/TableContext';
|
||||
@ -33,6 +35,8 @@ export function FilterDropdownFilterSelect() {
|
||||
TableContext,
|
||||
);
|
||||
|
||||
const setHotkeysScope = useSetHotkeysScope();
|
||||
|
||||
return (
|
||||
<DropdownMenuItemContainer style={{ maxHeight: '300px' }}>
|
||||
{availableTableFilters.map((availableTableFilter, index) => (
|
||||
@ -40,6 +44,11 @@ export function FilterDropdownFilterSelect() {
|
||||
key={`select-filter-${index}`}
|
||||
onClick={() => {
|
||||
setTableFilterDefinitionUsedInDropdown(availableTableFilter);
|
||||
|
||||
if (availableTableFilter.type === 'entity') {
|
||||
setHotkeysScope(InternalHotkeysScope.RelationPicker);
|
||||
}
|
||||
|
||||
setSelectedOperandInDropdown(
|
||||
getOperandsForFilterType(availableTableFilter.type)?.[0],
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useCurrentHotkeysScope } from '@/hotkeys/hooks/useCurrentHotkeysScope';
|
||||
import { useResetHotkeysScopeStack } from '@/hotkeys/hooks/useResetHotkeysScopeStack';
|
||||
import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope';
|
||||
import { currentHotkeysScopeState } from '@/hotkeys/states/internal/currentHotkeysScopeState';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
|
||||
import { isSoftFocusActiveState } from '../states/isSoftFocusActiveState';
|
||||
@ -11,12 +11,13 @@ import { useCloseCurrentCellInEditMode } from './useClearCellInEditMode';
|
||||
import { useDisableSoftFocus } from './useDisableSoftFocus';
|
||||
|
||||
export function useLeaveTableFocus() {
|
||||
const resetHotkeysScopeStack = useResetHotkeysScopeStack();
|
||||
const currentHotkeysScope = useCurrentHotkeysScope();
|
||||
const currentHotkeysScope = useRecoilValue(currentHotkeysScopeState);
|
||||
|
||||
const disableSoftFocus = useDisableSoftFocus();
|
||||
const closeCurrentCellInEditMode = useCloseCurrentCellInEditMode();
|
||||
|
||||
const setHotkeysScope = useSetHotkeysScope();
|
||||
|
||||
const isSoftFocusActive = useRecoilValue(isSoftFocusActiveState);
|
||||
const isSomeInputInEditMode = useRecoilValue(isSomeInputInEditModeState);
|
||||
|
||||
@ -32,6 +33,7 @@ export function useLeaveTableFocus() {
|
||||
|
||||
closeCurrentCellInEditMode();
|
||||
disableSoftFocus();
|
||||
resetHotkeysScopeStack(InternalHotkeysScope.Table);
|
||||
|
||||
setHotkeysScope(InternalHotkeysScope.Table, { goto: true });
|
||||
};
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useRemoveFromHotkeysScopeStack } from '@/hotkeys/hooks/useRemoveFromHotkeysScopeStack';
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
|
||||
import { isSomeInputInEditModeState } from '../states/isSomeInputInEditModeState';
|
||||
@ -13,8 +13,8 @@ import { useMoveSoftFocus } from './useMoveSoftFocus';
|
||||
export function useMapKeyboardToSoftFocus() {
|
||||
const { moveDown, moveLeft, moveRight, moveUp } = useMoveSoftFocus();
|
||||
|
||||
const removeFromHotkeysScopedStack = useRemoveFromHotkeysScopeStack();
|
||||
const disableSoftFocus = useDisableSoftFocus();
|
||||
const setHotkeysScope = useSetHotkeysScope();
|
||||
|
||||
const [isSomeInputInEditMode] = useRecoilState(isSomeInputInEditModeState);
|
||||
|
||||
@ -65,10 +65,10 @@ export function useMapKeyboardToSoftFocus() {
|
||||
useScopedHotkeys(
|
||||
[Key.Escape],
|
||||
() => {
|
||||
removeFromHotkeysScopedStack(InternalHotkeysScope.TableSoftFocus);
|
||||
setHotkeysScope(InternalHotkeysScope.Table, { goto: true });
|
||||
disableSoftFocus();
|
||||
},
|
||||
InternalHotkeysScope.TableSoftFocus,
|
||||
[removeFromHotkeysScopedStack, disableSoftFocus],
|
||||
[disableSoftFocus],
|
||||
);
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { isMockModeState } from '@/auth/states/isMockModeState';
|
||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { NameFields } from '@/settings/profile/components/NameFields';
|
||||
@ -39,10 +38,6 @@ const StyledButtonContainer = styled.div`
|
||||
`;
|
||||
|
||||
export function CreateProfile() {
|
||||
useHotkeysScopeOnMountOnly({
|
||||
scope: InternalHotkeysScope.CreateProfile,
|
||||
customScopes: { 'command-menu': false, goto: false },
|
||||
});
|
||||
const navigate = useNavigate();
|
||||
const [, setMockMode] = useRecoilState(isMockModeState);
|
||||
const onboardingStatus = useOnboardingStatus();
|
||||
|
@ -9,7 +9,6 @@ import { Title } from '@/auth/components/ui/Title';
|
||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
||||
import { isMockModeState } from '@/auth/states/isMockModeState';
|
||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader';
|
||||
@ -37,10 +36,6 @@ const StyledButtonContainer = styled.div`
|
||||
`;
|
||||
|
||||
export function CreateWorkspace() {
|
||||
useHotkeysScopeOnMountOnly({
|
||||
scope: InternalHotkeysScope.CreateWokspace,
|
||||
customScopes: { 'command-menu': false, goto: false },
|
||||
});
|
||||
const [, setMockMode] = useRecoilState(isMockModeState);
|
||||
const navigate = useNavigate();
|
||||
const onboardingStatus = useOnboardingStatus();
|
||||
|
@ -13,7 +13,6 @@ import { authFlowUserEmailState } from '@/auth/states/authFlowUserEmailState';
|
||||
import { isMockModeState } from '@/auth/states/isMockModeState';
|
||||
import { authProvidersState } from '@/client-config/states/authProvidersState';
|
||||
import { isDemoModeState } from '@/client-config/states/isDemoModeState';
|
||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { MainButton } from '@/ui/components/buttons/MainButton';
|
||||
@ -33,10 +32,6 @@ const StyledFooterNote = styled(FooterNote)`
|
||||
`;
|
||||
|
||||
export function Index() {
|
||||
useHotkeysScopeOnMountOnly({
|
||||
scope: InternalHotkeysScope.AuthIndex,
|
||||
customScopes: { 'command-menu': false, goto: false },
|
||||
});
|
||||
const navigate = useNavigate();
|
||||
const theme = useTheme();
|
||||
const [, setMockMode] = useRecoilState(isMockModeState);
|
||||
|
@ -11,7 +11,6 @@ import { useAuth } from '@/auth/hooks/useAuth';
|
||||
import { authFlowUserEmailState } from '@/auth/states/authFlowUserEmailState';
|
||||
import { isMockModeState } from '@/auth/states/isMockModeState';
|
||||
import { isDemoModeState } from '@/client-config/states/isDemoModeState';
|
||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { MainButton } from '@/ui/components/buttons/MainButton';
|
||||
@ -51,10 +50,6 @@ const StyledErrorContainer = styled.div`
|
||||
`;
|
||||
|
||||
export function PasswordLogin() {
|
||||
useHotkeysScopeOnMountOnly({
|
||||
scope: InternalHotkeysScope.PasswordLogin,
|
||||
customScopes: { 'command-menu': false, goto: false },
|
||||
});
|
||||
const navigate = useNavigate();
|
||||
const [isDemoMode] = useRecoilState(isDemoModeState);
|
||||
|
||||
|
@ -4,8 +4,6 @@ import styled from '@emotion/styled';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { GET_COMPANIES } from '@/companies/services';
|
||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
|
||||
import { EntityTableActionBar } from '@/ui/components/table/action-bar/EntityTableActionBar';
|
||||
import { IconBuildingSkyscraper } from '@/ui/icons/index';
|
||||
@ -26,11 +24,6 @@ const StyledTableContainer = styled.div`
|
||||
`;
|
||||
|
||||
export function Companies() {
|
||||
useHotkeysScopeOnMountOnly({
|
||||
scope: InternalHotkeysScope.Table,
|
||||
customScopes: { 'command-menu': true, goto: true },
|
||||
});
|
||||
|
||||
const [insertCompany] = useInsertCompanyMutation();
|
||||
|
||||
async function handleAddButtonClick() {
|
||||
|
@ -3,8 +3,6 @@ import { useTheme } from '@emotion/react';
|
||||
|
||||
import { Timeline } from '@/comments/components/timeline/Timeline';
|
||||
import { useCompanyQuery } from '@/companies/services';
|
||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { RawLink } from '@/ui/components/links/RawLink';
|
||||
import { PropertyBox } from '@/ui/components/property-box/PropertyBox';
|
||||
import { PropertyBoxItem } from '@/ui/components/property-box/PropertyBoxItem';
|
||||
@ -19,11 +17,6 @@ import { CommentableType } from '~/generated/graphql';
|
||||
export function CompanyShow() {
|
||||
const companyId = useParams().companyId ?? '';
|
||||
|
||||
useHotkeysScopeOnMountOnly({
|
||||
scope: InternalHotkeysScope.ShowPage,
|
||||
customScopes: { 'command-menu': true, goto: true },
|
||||
});
|
||||
|
||||
const { data } = useCompanyQuery(companyId);
|
||||
const company = data?.findUniqueCompany;
|
||||
|
||||
|
@ -3,8 +3,6 @@ import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { GET_PEOPLE } from '@/people/services';
|
||||
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
|
||||
import { EntityTableActionBar } from '@/ui/components/table/action-bar/EntityTableActionBar';
|
||||
@ -24,11 +22,6 @@ const StyledPeopleContainer = styled.div`
|
||||
`;
|
||||
|
||||
export function People() {
|
||||
useHotkeysScopeOnMountOnly({
|
||||
scope: InternalHotkeysScope.Table,
|
||||
customScopes: { 'command-menu': true, goto: true },
|
||||
});
|
||||
|
||||
const [insertPersonMutation] = useInsertPersonMutation();
|
||||
|
||||
async function handleAddButtonClick() {
|
||||
|
@ -1,7 +1,5 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { EmailField } from '@/settings/profile/components/EmailField';
|
||||
import { NameFields } from '@/settings/profile/components/NameFields';
|
||||
import { ProfilePictureUploader } from '@/settings/profile/components/ProfilePictureUploader';
|
||||
@ -27,11 +25,6 @@ const StyledSectionContainer = styled.div`
|
||||
`;
|
||||
|
||||
export function SettingsProfile() {
|
||||
useHotkeysScopeOnMountOnly({
|
||||
scope: InternalHotkeysScope.Settings,
|
||||
customScopes: { 'command-menu': true, goto: false },
|
||||
});
|
||||
|
||||
return (
|
||||
<NoTopBarContainer>
|
||||
<div>
|
||||
|
7
front/src/sync-hooks/HotkeysScopeAutoSyncHook.tsx
Normal file
7
front/src/sync-hooks/HotkeysScopeAutoSyncHook.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
import { useHotkeysScopeAutoSync } from '@/hotkeys/hooks/internal/useHotkeysScopeAutoSync';
|
||||
|
||||
export function HotkeysScopeAutoSyncHook() {
|
||||
useHotkeysScopeAutoSync();
|
||||
|
||||
return <></>;
|
||||
}
|
71
front/src/sync-hooks/HotkeysScopeBrowserRouterSync.tsx
Normal file
71
front/src/sync-hooks/HotkeysScopeBrowserRouterSync.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope';
|
||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||
import { PageHotkeysScope } from '@/hotkeys/types/internal/PageHotkeysScope';
|
||||
|
||||
import { useIsMatchingLocation } from './hooks/useIsMatchingLocation';
|
||||
import { AppBasePath } from './types/AppBasePath';
|
||||
import { AppPath } from './types/AppPath';
|
||||
import { AuthPath } from './types/AuthPath';
|
||||
import { SettingsPath } from './types/SettingsPath';
|
||||
|
||||
export function HotkeysScopeBrowserRouterSync() {
|
||||
const isMatchingLocation = useIsMatchingLocation();
|
||||
|
||||
const setHotkeysScope = useSetHotkeysScope();
|
||||
|
||||
useEffect(() => {
|
||||
switch (true) {
|
||||
case isMatchingLocation(AppBasePath.Root, AppPath.CompaniesPage): {
|
||||
setHotkeysScope(InternalHotkeysScope.Table, { goto: true });
|
||||
break;
|
||||
}
|
||||
case isMatchingLocation(AppBasePath.Root, AppPath.PeoplePage): {
|
||||
setHotkeysScope(InternalHotkeysScope.Table, { goto: true });
|
||||
break;
|
||||
}
|
||||
case isMatchingLocation(AppBasePath.Root, AppPath.CompanyShowPage): {
|
||||
setHotkeysScope(PageHotkeysScope.CompanyShowPage, { goto: true });
|
||||
break;
|
||||
}
|
||||
case isMatchingLocation(AppBasePath.Root, AppPath.PersonShowPage): {
|
||||
setHotkeysScope(PageHotkeysScope.PersonShowPage, { goto: true });
|
||||
break;
|
||||
}
|
||||
case isMatchingLocation(AppBasePath.Root, AppPath.OpportunitiesPage): {
|
||||
setHotkeysScope(PageHotkeysScope.OpportunitiesPage, { goto: true });
|
||||
break;
|
||||
}
|
||||
case isMatchingLocation(AppBasePath.Auth, AuthPath.Index): {
|
||||
setHotkeysScope(InternalHotkeysScope.AuthIndex);
|
||||
break;
|
||||
}
|
||||
case isMatchingLocation(AppBasePath.Auth, AuthPath.CreateProfile): {
|
||||
setHotkeysScope(InternalHotkeysScope.CreateProfile);
|
||||
break;
|
||||
}
|
||||
case isMatchingLocation(AppBasePath.Auth, AuthPath.CreateWorkspace): {
|
||||
setHotkeysScope(InternalHotkeysScope.CreateWokspace);
|
||||
break;
|
||||
}
|
||||
case isMatchingLocation(AppBasePath.Auth, AuthPath.PasswordLogin): {
|
||||
setHotkeysScope(InternalHotkeysScope.PasswordLogin);
|
||||
break;
|
||||
}
|
||||
case isMatchingLocation(AppBasePath.Settings, SettingsPath.ProfilePage): {
|
||||
setHotkeysScope(PageHotkeysScope.ProfilePage, { goto: true });
|
||||
break;
|
||||
}
|
||||
case isMatchingLocation(
|
||||
AppBasePath.Settings,
|
||||
SettingsPath.WorkspaceMembersPage,
|
||||
): {
|
||||
setHotkeysScope(PageHotkeysScope.WorkspaceMemberPage, { goto: true });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, [isMatchingLocation, setHotkeysScope]);
|
||||
|
||||
return <></>;
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
import { useHotkeysScopeStackAutoSync } from '@/hotkeys/hooks/internal/useHotkeysScopeStackAutoSync';
|
||||
|
||||
export function HotkeysScopeStackAutoSyncHook() {
|
||||
useHotkeysScopeStackAutoSync();
|
||||
|
||||
return <></>;
|
||||
}
|
16
front/src/sync-hooks/hooks/useIsMatchingLocation.ts
Normal file
16
front/src/sync-hooks/hooks/useIsMatchingLocation.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { matchPath, useLocation } from 'react-router-dom';
|
||||
import { parse } from 'url';
|
||||
|
||||
import { AppBasePath } from '../types/AppBasePath';
|
||||
|
||||
export function useIsMatchingLocation() {
|
||||
const location = useLocation();
|
||||
|
||||
return function isMatchingLocation(basePath: AppBasePath, path: string) {
|
||||
const constructedPath = basePath
|
||||
? parse(`${basePath}/${path}`).pathname ?? ''
|
||||
: path;
|
||||
|
||||
return !!matchPath(constructedPath, location.pathname);
|
||||
};
|
||||
}
|
5
front/src/sync-hooks/types/AppBasePath.ts
Normal file
5
front/src/sync-hooks/types/AppBasePath.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export enum AppBasePath {
|
||||
Auth = '/auth',
|
||||
Settings = '/settings',
|
||||
Root = '/',
|
||||
}
|
9
front/src/sync-hooks/types/AppPath.ts
Normal file
9
front/src/sync-hooks/types/AppPath.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export enum AppPath {
|
||||
AuthCatchAll = `/auth/*`,
|
||||
PeoplePage = '/people',
|
||||
CompaniesPage = '/companies',
|
||||
CompanyShowPage = '/companies/:companyId',
|
||||
PersonShowPage = '/person/:personId',
|
||||
OpportunitiesPage = '/opportunities',
|
||||
SettingsCatchAll = `/settings/*`,
|
||||
}
|
7
front/src/sync-hooks/types/AuthPath.ts
Normal file
7
front/src/sync-hooks/types/AuthPath.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export enum AuthPath {
|
||||
Index = '',
|
||||
Callback = 'callback',
|
||||
PasswordLogin = 'password-login',
|
||||
CreateWorkspace = 'create/workspace',
|
||||
CreateProfile = 'create/profile',
|
||||
}
|
5
front/src/sync-hooks/types/SettingsPath.ts
Normal file
5
front/src/sync-hooks/types/SettingsPath.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export enum SettingsPath {
|
||||
ProfilePage = 'profile',
|
||||
WorkspaceMembersPage = 'workspace-members',
|
||||
Workspace = 'workspace',
|
||||
}
|
@ -15589,7 +15589,7 @@ pumpify@^1.3.3:
|
||||
inherits "^2.0.3"
|
||||
pump "^2.0.0"
|
||||
|
||||
punycode@^1.3.2:
|
||||
punycode@^1.3.2, punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==
|
||||
@ -15639,7 +15639,7 @@ qs@6.11.0:
|
||||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
qs@^6.10.0, qs@^6.11.1, qs@^6.4.0:
|
||||
qs@^6.10.0, qs@^6.11.0, qs@^6.11.1, qs@^6.4.0:
|
||||
version "6.11.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9"
|
||||
integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==
|
||||
@ -18285,6 +18285,14 @@ url-parse@^1.5.3:
|
||||
querystringify "^2.1.1"
|
||||
requires-port "^1.0.0"
|
||||
|
||||
url@^0.11.1:
|
||||
version "0.11.1"
|
||||
resolved "https://registry.yarnpkg.com/url/-/url-0.11.1.tgz#26f90f615427eca1b9f4d6a28288c147e2302a32"
|
||||
integrity sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA==
|
||||
dependencies:
|
||||
punycode "^1.4.1"
|
||||
qs "^6.11.0"
|
||||
|
||||
urlpattern-polyfill@^8.0.0:
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-8.0.2.tgz#99f096e35eff8bf4b5a2aa7d58a1523d6ebc7ce5"
|
||||
|
Loading…
Reference in New Issue
Block a user