diff --git a/front/src/index.tsx b/front/src/index.tsx
index 95070ddec..ed254ed2c 100644
--- a/front/src/index.tsx
+++ b/front/src/index.tsx
@@ -27,15 +27,15 @@ root.render(
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
diff --git a/front/src/modules/hotkeys/hooks/useGoToHotkeys.ts b/front/src/modules/hotkeys/hooks/useGoToHotkeys.ts
index f097ecfb9..a13c04614 100644
--- a/front/src/modules/hotkeys/hooks/useGoToHotkeys.ts
+++ b/front/src/modules/hotkeys/hooks/useGoToHotkeys.ts
@@ -15,5 +15,11 @@ export function useGoToHotkeys(key: Keys, location: string) {
navigate(location);
},
InternalHotkeysScope.Goto,
+ {
+ enableOnContentEditable: true,
+ enableOnFormTags: true,
+ preventDefault: true,
+ },
+ [navigate],
);
}
diff --git a/front/src/modules/hotkeys/hooks/useSequenceScopedHotkeys.ts b/front/src/modules/hotkeys/hooks/useSequenceScopedHotkeys.ts
index b89f8b61f..f8eb838fa 100644
--- a/front/src/modules/hotkeys/hooks/useSequenceScopedHotkeys.ts
+++ b/front/src/modules/hotkeys/hooks/useSequenceScopedHotkeys.ts
@@ -14,6 +14,7 @@ export function useSequenceHotkeys(
enableOnFormTags: true,
preventDefault: true,
},
+ deps: any[] = [],
) {
const [pendingHotkey, setPendingHotkey] = useRecoilState(pendingHotkeyState);
@@ -23,7 +24,7 @@ export function useSequenceHotkeys(
setPendingHotkey(firstKey);
},
{ ...options, scopes: [scope] },
- [pendingHotkey],
+ [setPendingHotkey],
);
useHotkeys(
@@ -36,6 +37,6 @@ export function useSequenceHotkeys(
callback();
},
{ ...options, scopes: [scope] },
- [pendingHotkey, setPendingHotkey],
+ [pendingHotkey, setPendingHotkey, ...deps],
);
}
diff --git a/front/src/modules/hotkeys/hooks/useSetHotkeysScope.ts b/front/src/modules/hotkeys/hooks/useSetHotkeysScope.ts
index 9dc9f930e..1ff68b7dc 100644
--- a/front/src/modules/hotkeys/hooks/useSetHotkeysScope.ts
+++ b/front/src/modules/hotkeys/hooks/useSetHotkeysScope.ts
@@ -6,6 +6,16 @@ import { DEFAULT_HOTKEYS_SCOPE_CUSTOM_SCOPES } from '../constants';
import { currentHotkeysScopeState } from '../states/internal/currentHotkeysScopeState';
import { CustomHotkeysScopes } from '../types/internal/CustomHotkeysScope';
+function isCustomScopesEqual(
+ customScopesA: CustomHotkeysScopes | undefined,
+ customScopesB: CustomHotkeysScopes | undefined,
+) {
+ return (
+ customScopesA?.commandMenu === customScopesB?.commandMenu &&
+ customScopesA?.goto === customScopesB?.goto
+ );
+}
+
export function useSetHotkeysScope() {
return useRecoilCallback(
({ snapshot, set }) =>
@@ -14,16 +24,6 @@ export function useSetHotkeysScope() {
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 (
diff --git a/front/src/modules/ui/components/editable-cell/EditableCell.tsx b/front/src/modules/ui/components/editable-cell/EditableCell.tsx
index 1736323f3..f6d8a1778 100644
--- a/front/src/modules/ui/components/editable-cell/EditableCell.tsx
+++ b/front/src/modules/ui/components/editable-cell/EditableCell.tsx
@@ -2,12 +2,9 @@ import { ReactElement } from 'react';
import styled from '@emotion/styled';
import { HotkeysScope } from '@/hotkeys/types/internal/HotkeysScope';
-import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { useCurrentCellEditMode } from './hooks/useCurrentCellEditMode';
-import { useEditableCell } from './hooks/useEditableCell';
import { useIsSoftFocusOnCurrentCell } from './hooks/useIsSoftFocusOnCurrentCell';
-import { useSetSoftFocusOnCurrentCell } from './hooks/useSetSoftFocusOnCurrentCell';
import { EditableCellDisplayMode } from './EditableCellDisplayMode';
import { EditableCellEditMode } from './EditableCellEditMode';
import { EditableCellSoftFocusMode } from './EditableCellSoftFocusMode';
@@ -40,33 +37,10 @@ export function EditableCell({
}: OwnProps) {
const { isCurrentCellInEditMode } = useCurrentCellEditMode();
- const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
-
- const { openEditableCell } = useEditableCell();
-
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
- // TODO: we might have silent problematic behavior because of the setTimeout in openEditableCell, investigate
- // Maybe we could build a switchEditableCell to handle the case where we go from one cell to another.
- // See https://github.com/twentyhq/twenty/issues/446
- function handleOnClick() {
- if (isCurrentCellInEditMode) {
- return;
- }
-
- if (hasSoftFocus) {
- openEditableCell(
- editHotkeysScope ?? {
- scope: InternalHotkeysScope.CellEditMode,
- },
- );
- } else {
- setSoftFocusOnCurrentCell();
- }
- }
-
return (
-
+
{isCurrentCellInEditMode ? (
`
@@ -35,10 +35,14 @@ export const EditableCellNormalModeInnerContainer = styled.div`
export function EditableCellDisplayMode({
children,
}: React.PropsWithChildren) {
- const hasSoftFocus = useIsSoftFocusOnCurrentCell();
+ const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
+
+ function handleOnClick() {
+ setSoftFocusOnCurrentCell();
+ }
return (
-
+
{children}
diff --git a/front/src/modules/ui/components/editable-cell/EditableCellSoftFocusMode.tsx b/front/src/modules/ui/components/editable-cell/EditableCellSoftFocusMode.tsx
index dad7d19de..240db27db 100644
--- a/front/src/modules/ui/components/editable-cell/EditableCellSoftFocusMode.tsx
+++ b/front/src/modules/ui/components/editable-cell/EditableCellSoftFocusMode.tsx
@@ -6,25 +6,32 @@ import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysSc
import { isNonTextWritingKey } from '@/utils/hotkeys/isNonTextWritingKey';
import { useEditableCell } from './hooks/useEditableCell';
-import { EditableCellDisplayMode } from './EditableCellDisplayMode';
+import {
+ EditableCellNormalModeInnerContainer,
+ EditableCellNormalModeOuterContainer,
+} from './EditableCellDisplayMode';
export function EditableCellSoftFocusMode({
children,
editHotkeysScope,
}: React.PropsWithChildren<{ editHotkeysScope?: HotkeysScope }>) {
- const { closeEditableCell, openEditableCell } = useEditableCell();
+ const { openEditableCell } = useEditableCell();
+
+ function openEditMode() {
+ openEditableCell(
+ editHotkeysScope ?? {
+ scope: InternalHotkeysScope.CellEditMode,
+ },
+ );
+ }
useScopedHotkeys(
'enter',
() => {
- openEditableCell(
- editHotkeysScope ?? {
- scope: InternalHotkeysScope.CellEditMode,
- },
- );
+ openEditMode();
},
InternalHotkeysScope.TableSoftFocus,
- [closeEditableCell, editHotkeysScope],
+ [openEditMode],
);
useScopedHotkeys(
@@ -39,18 +46,27 @@ export function EditableCellSoftFocusMode({
return;
}
- openEditableCell(
- editHotkeysScope ?? {
- scope: InternalHotkeysScope.CellEditMode,
- },
- );
+ openEditMode();
},
InternalHotkeysScope.TableSoftFocus,
- [openEditableCell, editHotkeysScope],
+ [openEditMode],
{
preventDefault: false,
},
);
- return {children};
+ function handleClick() {
+ openEditMode();
+ }
+
+ return (
+
+
+ {children}
+
+
+ );
}
diff --git a/front/src/modules/ui/components/editable-cell/hooks/useSetSoftFocusOnCurrentCell.ts b/front/src/modules/ui/components/editable-cell/hooks/useSetSoftFocusOnCurrentCell.ts
index 3f5890966..4d3654799 100644
--- a/front/src/modules/ui/components/editable-cell/hooks/useSetSoftFocusOnCurrentCell.ts
+++ b/front/src/modules/ui/components/editable-cell/hooks/useSetSoftFocusOnCurrentCell.ts
@@ -1,5 +1,5 @@
-import { useCallback, useMemo } from 'react';
-import { useRecoilState } from 'recoil';
+import { useMemo } from 'react';
+import { useRecoilCallback } from 'recoil';
import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
@@ -14,6 +14,7 @@ import { CellPosition } from '@/ui/tables/types/CellPosition';
export function useSetSoftFocusOnCurrentCell() {
const setSoftFocusPosition = useSetSoftFocusPosition();
+
const [currentRowNumber] = useRecoilScopedState(
currentRowNumberScopedState,
RowContext,
@@ -32,18 +33,17 @@ export function useSetSoftFocusOnCurrentCell() {
[currentColumnNumber, currentRowNumber],
);
- const [, setIsSoftFocusActive] = useRecoilState(isSoftFocusActiveState);
-
const setHotkeysScope = useSetHotkeysScope();
- return useCallback(() => {
- setSoftFocusPosition(currentTablePosition);
- setIsSoftFocusActive(true);
- setHotkeysScope(InternalHotkeysScope.TableSoftFocus);
- }, [
- setSoftFocusPosition,
- currentTablePosition,
- setIsSoftFocusActive,
- setHotkeysScope,
- ]);
+ return useRecoilCallback(
+ ({ set }) =>
+ () => {
+ setSoftFocusPosition(currentTablePosition);
+
+ set(isSoftFocusActiveState, true);
+
+ setHotkeysScope(InternalHotkeysScope.TableSoftFocus);
+ },
+ [setHotkeysScope, currentTablePosition, setSoftFocusPosition],
+ );
}
diff --git a/front/src/modules/ui/layout/containers/FlexExpandingContainer.tsx b/front/src/modules/ui/layout/containers/FlexExpandingContainer.tsx
new file mode 100644
index 000000000..92c94466e
--- /dev/null
+++ b/front/src/modules/ui/layout/containers/FlexExpandingContainer.tsx
@@ -0,0 +1,7 @@
+import styled from '@emotion/styled';
+
+export const FlexExpandingContainer = styled.div`
+ display: flex;
+ height: 100%;
+ width: 100%;
+`;
diff --git a/front/src/modules/ui/layout/containers/NoTopBarContainer.tsx b/front/src/modules/ui/layout/containers/NoTopBarContainer.tsx
index aa9b55ee8..cde2a9ae8 100644
--- a/front/src/modules/ui/layout/containers/NoTopBarContainer.tsx
+++ b/front/src/modules/ui/layout/containers/NoTopBarContainer.tsx
@@ -1,9 +1,9 @@
import styled from '@emotion/styled';
-import { ContentContainer } from './ContentContainer';
+import { RightDrawerContainer } from './RightDrawerContainer';
type OwnProps = {
- children: JSX.Element;
+ children: JSX.Element | JSX.Element[];
};
const StyledContainer = styled.div`
@@ -15,7 +15,7 @@ const StyledContainer = styled.div`
export function NoTopBarContainer({ children }: OwnProps) {
return (
- {children}
+ {children}
);
}
diff --git a/front/src/modules/ui/layout/containers/RightDrawerContainer.tsx b/front/src/modules/ui/layout/containers/RightDrawerContainer.tsx
new file mode 100644
index 000000000..2e96d3b1f
--- /dev/null
+++ b/front/src/modules/ui/layout/containers/RightDrawerContainer.tsx
@@ -0,0 +1,43 @@
+import styled from '@emotion/styled';
+
+import { Panel } from '../Panel';
+import { RightDrawer } from '../right-drawer/components/RightDrawer';
+
+type OwnProps = {
+ children: JSX.Element | JSX.Element[];
+ topMargin?: number;
+};
+
+const StyledMainContainer = styled.div<{ topMargin: number }>`
+ background: ${({ theme }) => theme.background.noisy};
+ display: flex;
+
+ flex-direction: row;
+ gap: ${({ theme }) => theme.spacing(2)};
+ height: calc(100% - ${(props) => props.topMargin}px);
+
+ padding-bottom: ${({ theme }) => theme.spacing(3)};
+ padding-right: ${({ theme }) => theme.spacing(3)};
+ width: calc(100% - ${({ theme }) => theme.spacing(3)});
+`;
+
+type LeftContainerProps = {
+ isRightDrawerOpen?: boolean;
+};
+
+const StyledLeftContainer = styled.div`
+ display: flex;
+ position: relative;
+ width: 100%;
+`;
+
+export function RightDrawerContainer({ children, topMargin }: OwnProps) {
+ return (
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/front/src/modules/ui/layout/containers/VerticalFullWidthContainer.tsx b/front/src/modules/ui/layout/containers/VerticalFullWidthContainer.tsx
new file mode 100644
index 000000000..d7b42a9d9
--- /dev/null
+++ b/front/src/modules/ui/layout/containers/VerticalFullWidthContainer.tsx
@@ -0,0 +1,15 @@
+import styled from '@emotion/styled';
+
+const StyledContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+`;
+
+export function VerticalFullWidthContainer({
+ children,
+}: {
+ children: JSX.Element[];
+}) {
+ return {children};
+}
diff --git a/front/src/modules/ui/layout/containers/WithTopBarContainer.tsx b/front/src/modules/ui/layout/containers/WithTopBarContainer.tsx
index 02f106d72..fc2c3a1c1 100644
--- a/front/src/modules/ui/layout/containers/WithTopBarContainer.tsx
+++ b/front/src/modules/ui/layout/containers/WithTopBarContainer.tsx
@@ -1,12 +1,13 @@
import { ReactNode } from 'react';
import styled from '@emotion/styled';
+import { TopBarHotkeys } from '../top-bar/TableTopBarHotkeys';
import { TOP_BAR_MIN_HEIGHT, TopBar } from '../top-bar/TopBar';
-import { ContentContainer } from './ContentContainer';
+import { RightDrawerContainer } from './RightDrawerContainer';
type OwnProps = {
- children: JSX.Element;
+ children: JSX.Element | JSX.Element[];
title: string;
icon: ReactNode;
onAddButtonClick?: () => void;
@@ -26,10 +27,11 @@ export function WithTopBarContainer({
}: OwnProps) {
return (
+
-
+
{children}
-
+
);
}
diff --git a/front/src/modules/ui/layout/top-bar/TableTopBarHotkeys.tsx b/front/src/modules/ui/layout/top-bar/TableTopBarHotkeys.tsx
new file mode 100644
index 000000000..e6b87a808
--- /dev/null
+++ b/front/src/modules/ui/layout/top-bar/TableTopBarHotkeys.tsx
@@ -0,0 +1,17 @@
+import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
+import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
+
+type OwnProps = {
+ onAddButtonClick?: () => void;
+};
+
+export function TopBarHotkeys({ onAddButtonClick }: OwnProps) {
+ useScopedHotkeys(
+ 'c',
+ () => onAddButtonClick?.(),
+ InternalHotkeysScope.Table,
+ [onAddButtonClick],
+ );
+
+ return <>>;
+}
diff --git a/front/src/modules/ui/layout/top-bar/TopBar.tsx b/front/src/modules/ui/layout/top-bar/TopBar.tsx
index d297c91de..3b3fd85db 100644
--- a/front/src/modules/ui/layout/top-bar/TopBar.tsx
+++ b/front/src/modules/ui/layout/top-bar/TopBar.tsx
@@ -1,8 +1,6 @@
import { ReactNode } from 'react';
import styled from '@emotion/styled';
-import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
-import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { IconPlus } from '@/ui/icons/index';
import NavCollapseButton from '../navbar/NavCollapseButton';
@@ -51,8 +49,6 @@ type OwnProps = {
};
export function TopBar({ title, icon, onAddButtonClick }: OwnProps) {
- useScopedHotkeys('c', () => onAddButtonClick?.(), InternalHotkeysScope.Table);
-
return (
<>
diff --git a/front/src/modules/ui/tables/hooks/useLeaveTableFocus.ts b/front/src/modules/ui/tables/hooks/useLeaveTableFocus.ts
index 1249b8ba6..fcb3bf65b 100644
--- a/front/src/modules/ui/tables/hooks/useLeaveTableFocus.ts
+++ b/front/src/modules/ui/tables/hooks/useLeaveTableFocus.ts
@@ -1,4 +1,4 @@
-import { useRecoilValue } from 'recoil';
+import { useRecoilCallback } from 'recoil';
import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope';
import { currentHotkeysScopeState } from '@/hotkeys/states/internal/currentHotkeysScopeState';
@@ -11,29 +11,39 @@ import { useCloseCurrentCellInEditMode } from './useClearCellInEditMode';
import { useDisableSoftFocus } from './useDisableSoftFocus';
export function useLeaveTableFocus() {
- const currentHotkeysScope = useRecoilValue(currentHotkeysScopeState);
-
const disableSoftFocus = useDisableSoftFocus();
const closeCurrentCellInEditMode = useCloseCurrentCellInEditMode();
const setHotkeysScope = useSetHotkeysScope();
- const isSoftFocusActive = useRecoilValue(isSoftFocusActiveState);
- const isSomeInputInEditMode = useRecoilValue(isSomeInputInEditModeState);
+ return useRecoilCallback(
+ ({ snapshot }) =>
+ () => {
+ const isSoftFocusActive = snapshot
+ .getLoadable(isSoftFocusActiveState)
+ .valueOrThrow();
- return async function leaveTableFocus() {
- // TODO: replace with scope ancestor ?
- if (!isSoftFocusActive && !isSomeInputInEditMode) {
- return;
- }
+ const isSomeInputInEditMode = snapshot
+ .getLoadable(isSomeInputInEditModeState)
+ .valueOrThrow();
- if (currentHotkeysScope?.scope === InternalHotkeysScope.Table) {
- return;
- }
+ const currentHotkeysScope = snapshot
+ .getLoadable(currentHotkeysScopeState)
+ .valueOrThrow();
- closeCurrentCellInEditMode();
- disableSoftFocus();
+ if (!isSoftFocusActive && !isSomeInputInEditMode) {
+ return;
+ }
- setHotkeysScope(InternalHotkeysScope.Table, { goto: true });
- };
+ if (currentHotkeysScope?.scope === InternalHotkeysScope.Table) {
+ return;
+ }
+
+ closeCurrentCellInEditMode();
+ disableSoftFocus();
+
+ setHotkeysScope(InternalHotkeysScope.Table, { goto: true });
+ },
+ [setHotkeysScope, closeCurrentCellInEditMode, disableSoftFocus],
+ );
}
diff --git a/front/src/pages/people/People.tsx b/front/src/pages/people/People.tsx
index 708fc9c3e..421e35e9b 100644
--- a/front/src/pages/people/People.tsx
+++ b/front/src/pages/people/People.tsx
@@ -1,12 +1,12 @@
import { getOperationName } from '@apollo/client/utilities';
import { useTheme } from '@emotion/react';
-import styled from '@emotion/styled';
import { v4 as uuidv4 } from 'uuid';
import { GET_PEOPLE } from '@/people/services';
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
import { EntityTableActionBar } from '@/ui/components/table/action-bar/EntityTableActionBar';
-import { IconUser } from '@/ui/icons/index';
+import { IconBuildingSkyscraper } from '@/ui/icons/index';
+import { FlexExpandingContainer } from '@/ui/layout/containers/FlexExpandingContainer';
import { WithTopBarContainer } from '@/ui/layout/containers/WithTopBarContainer';
import { TableContext } from '@/ui/tables/states/TableContext';
import { useInsertPersonMutation } from '~/generated/graphql';
@@ -15,12 +15,6 @@ import { TableActionBarButtonCreateCommentThreadPeople } from './table/TableActi
import { TableActionBarButtonDeletePeople } from './table/TableActionBarButtonDeletePeople';
import { PeopleTable } from './PeopleTable';
-const StyledPeopleContainer = styled.div`
- display: flex;
- height: 100%;
- width: 100%;
-`;
-
export function People() {
const [insertPersonMutation] = useInsertPersonMutation();
@@ -42,20 +36,20 @@ export function People() {
const theme = useTheme();
return (
- }
- onAddButtonClick={handleAddButtonClick}
- >
-
-
+
+ }
+ onAddButtonClick={handleAddButtonClick}
+ >
+
-
+
-
-
+
+
);
}