diff --git a/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawer.tsx b/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawer.tsx
index 8ebdd7b4424..9576b018dfb 100644
--- a/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawer.tsx
+++ b/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawer.tsx
@@ -1,17 +1,19 @@
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
+import { AIChatThreadsList } from '@/ai/components/AIChatThreadsList';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { useFavoritesByFolder } from '@/favorites/hooks/useFavoritesByFolder';
import { NavigationMenuItemFolderContentDispatcherEffect } from '@/navigation-menu-item/components/NavigationMenuItemFolderContentDispatcher';
import { useNavigationMenuItemsByFolder } from '@/navigation-menu-item/hooks/useNavigationMenuItemsByFolder';
-import { MainNavigationDrawerFixedItems } from '@/navigation/components/MainNavigationDrawerFixedItems';
import { MainNavigationDrawerScrollableItems } from '@/navigation/components/MainNavigationDrawerScrollableItems';
+import { MainNavigationDrawerTabsRow } from '@/navigation/components/MainNavigationDrawerTabsRow';
import { NavigationDrawer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
import { NavigationDrawerFixedContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerFixedContent';
import { NavigationDrawerScrollableContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerScrollableContent';
import { currentFavoriteFolderIdStateV2 } from '@/ui/navigation/navigation-drawer/states/currentFavoriteFolderIdStateV2';
import { currentNavigationMenuItemFolderIdStateV2 } from '@/ui/navigation/navigation-drawer/states/currentNavigationMenuItemFolderIdStateV2';
+import { navigationDrawerActiveTabState } from '@/ui/navigation/states/navigationDrawerActiveTabState';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { FeatureFlagKey } from '~/generated-metadata/graphql';
@@ -21,8 +23,16 @@ const StyledScrollableContent = styled.div`
min-height: 0;
`;
+const StyledAIChatThreadsListWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ min-height: 0;
+`;
+
export const MainNavigationDrawer = ({ className }: { className?: string }) => {
const currentWorkspace = useRecoilValue(currentWorkspaceState);
+ const activeTab = useRecoilValueV2(navigationDrawerActiveTabState);
const currentFavoriteFolderId = useRecoilValueV2(
currentFavoriteFolderIdStateV2,
);
@@ -55,11 +65,15 @@ export const MainNavigationDrawer = ({ className }: { className?: string }) => {
title={currentWorkspace?.displayName ?? ''}
>
-
+
- {isNavigationMenuItemEditingEnabled ? (
+ {activeTab === 'chat' ? (
+
+
+
+ ) : isNavigationMenuItemEditingEnabled ? (
{openedFolder ? (
{
- const isMobile = useIsMobile();
- const location = useLocation();
- const setNavigationMemorizedUrl = useSetRecoilStateV2(
- navigationMemorizedUrlState,
- );
-
- const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] =
- useRecoilStateV2(isNavigationDrawerExpandedState);
- const setNavigationDrawerExpandedMemorized = useSetRecoilStateV2(
- navigationDrawerExpandedMemorizedStateV2,
- );
-
- const navigate = useNavigate();
-
- const { t } = useLingui();
-
- const { openRecordsSearchPage } = useOpenRecordsSearchPageInCommandMenu();
- const { openAskAIPage } = useOpenAskAIPageInCommandMenu();
- const isAiEnabled = useIsFeatureEnabled(FeatureFlagKey.IS_AI_ENABLED);
-
- return (
- !isMobile && (
- <>
-
- {isAiEnabled && (
- openAskAIPage({ resetNavigationStack: true })}
- keyboard={['@']}
- mouseUpNavigation={true}
- />
- )}
- {
- setNavigationDrawerExpandedMemorized(isNavigationDrawerExpanded);
- setIsNavigationDrawerExpanded(true);
- setNavigationMemorizedUrl(location.pathname + location.search);
- navigate(getSettingsPath(SettingsPath.ProfilePage));
- }}
- Icon={IconSettings}
- />
- >
- )
- );
-};
diff --git a/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerTabsRow.tsx b/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerTabsRow.tsx
new file mode 100644
index 00000000000..eb8f51efbad
--- /dev/null
+++ b/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerTabsRow.tsx
@@ -0,0 +1,185 @@
+import { useTheme } from '@emotion/react';
+import styled from '@emotion/styled';
+import { t } from '@lingui/core/macro';
+import {
+ IconComment,
+ IconHome,
+ IconMessageCirclePlus,
+} from 'twenty-ui/display';
+import { useIsMobile } from 'twenty-ui/utilities';
+
+import { useCreateNewAIChatThread } from '@/ai/hooks/useCreateNewAIChatThread';
+import {
+ type NavigationDrawerActiveTab,
+ navigationDrawerActiveTabState,
+} from '@/ui/navigation/states/navigationDrawerActiveTabState';
+import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
+import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
+import { FeatureFlagKey } from '~/generated-metadata/graphql';
+
+const StyledRow = styled.div`
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+ gap: ${({ theme }) => theme.spacing(2)};
+ width: 100%;
+`;
+
+const StyledTabsPill = styled.div`
+ align-items: center;
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.pill};
+ padding: ${({ theme }) => theme.spacing(0.75)};
+ height: ${({ theme }) => theme.spacing(7)};
+ display: flex;
+ width: ${({ theme }) => theme.spacing(18)};
+ gap: ${({ theme }) => theme.spacing(0.5)};
+ box-sizing: border-box;
+`;
+
+const StyledTabWrapper = styled.div<{ isActive: boolean }>`
+ border-radius: ${({ theme }) => theme.border.radius.pill};
+ align-items: center;
+ background: ${({ theme, isActive }) =>
+ isActive ? theme.background.transparent.light : 'transparent'};
+ color: ${({ theme, isActive }) =>
+ isActive ? theme.font.color.primary : theme.font.color.tertiary};
+ cursor: pointer;
+ display: flex;
+ justify-content: center;
+ height: 100%;
+ flex: 1;
+
+ &:hover {
+ background: ${({ theme, isActive }) =>
+ isActive
+ ? theme.background.transparent.light
+ : theme.background.transparent.lighter};
+ }
+`;
+
+const StyledTabIcon = styled.div`
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ height: ${({ theme }) => theme.spacing(5)};
+ width: ${({ theme }) => theme.spacing(5)};
+`;
+
+const StyledNewChatButtonWrapper = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.pill};
+ height: ${({ theme }) => theme.spacing(7)};
+ padding: ${({ theme }) => theme.spacing(0.75)};
+ width: ${({ theme }) => theme.spacing(25.75)};
+ box-sizing: border-box;
+`;
+
+const StyledNewChatButton = styled.div`
+ align-items: center;
+ justify-content: center;
+ display: flex;
+ cursor: pointer;
+ font-size: ${({ theme }) => theme.font.size.sm};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ gap: ${({ theme }) => theme.spacing(1)};
+ height: 100%;
+ width: 100%;
+ border-radius: inherit;
+ color: ${({ theme }) => theme.font.color.secondary};
+ transition:
+ background ${({ theme }) => theme.animation.duration.fast}s ease,
+ color ${({ theme }) => theme.animation.duration.fast}s ease;
+
+ &:hover {
+ background: ${({ theme }) => theme.background.transparent.light};
+ color: ${({ theme }) => theme.font.color.primary};
+ }
+`;
+
+export const MainNavigationDrawerTabsRow = () => {
+ const theme = useTheme();
+ const isMobile = useIsMobile();
+ const [activeTab, setActiveTab] = useRecoilStateV2(
+ navigationDrawerActiveTabState,
+ );
+ const { createChatThread } = useCreateNewAIChatThread();
+ const isAiEnabled = useIsFeatureEnabled(FeatureFlagKey.IS_AI_ENABLED);
+
+ if (isMobile || !isAiEnabled) {
+ return null;
+ }
+
+ const handleTabClick = (tab: NavigationDrawerActiveTab) => () => {
+ setActiveTab(tab);
+ };
+
+ const handleTabKeyDown =
+ (tab: NavigationDrawerActiveTab) => (event: React.KeyboardEvent) => {
+ if (event.key === 'Enter' || event.key === ' ') {
+ event.preventDefault();
+ setActiveTab(tab);
+ }
+ };
+
+ const handleNewChatKeyDown = (event: React.KeyboardEvent) => {
+ if (event.key === 'Enter' || event.key === ' ') {
+ event.preventDefault();
+ createChatThread();
+ }
+ };
+
+ const getTabIconColor = (isActive: boolean) =>
+ isActive ? theme.font.color.primary : theme.font.color.tertiary;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ createChatThread()}
+ onKeyDown={handleNewChatKeyDown}
+ >
+
+ {t`New chat`}
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/MultiWorkspaceDropdownDefaultComponents.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/MultiWorkspaceDropdownDefaultComponents.tsx
index 724b47fca93..09b4d71c869 100644
--- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/MultiWorkspaceDropdownDefaultComponents.tsx
+++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/MultiWorkspaceDropdownDefaultComponents.tsx
@@ -19,13 +19,18 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { MULTI_WORKSPACE_DROPDOWN_ID } from '@/ui/navigation/navigation-drawer/constants/MultiWorkspaceDropdownId';
import { multiWorkspaceDropdownStateV2 } from '@/ui/navigation/navigation-drawer/states/multiWorkspaceDropdownStateV2';
+import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
+import { navigationDrawerExpandedMemorizedStateV2 } from '@/ui/navigation/states/navigationDrawerExpandedMemorizedStateV2';
+import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
import { useColorScheme } from '@/ui/theme/hooks/useColorScheme';
+import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { type ApolloError } from '@apollo/client';
import styled from '@emotion/styled';
import { isNonEmptyString } from '@sniptt/guards';
import { useLingui } from '@lingui/react/macro';
import { useRecoilValue } from 'recoil';
+import { useLocation, useNavigate } from 'react-router-dom';
import { AppPath, SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
import {
@@ -35,6 +40,7 @@ import {
IconLogout,
IconMessage,
IconPlus,
+ IconSettings,
IconSwitchHorizontal,
IconUserPlus,
} from 'twenty-ui/display';
@@ -79,6 +85,17 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
multiWorkspaceDropdownStateV2,
);
+ const location = useLocation();
+ const navigate = useNavigate();
+ const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] =
+ useRecoilStateV2(isNavigationDrawerExpandedState);
+ const setNavigationDrawerExpandedMemorized = useSetRecoilStateV2(
+ navigationDrawerExpandedMemorizedStateV2,
+ );
+ const setNavigationMemorizedUrl = useSetRecoilStateV2(
+ navigationMemorizedUrlState,
+ );
+
const handleSupport = () => {
window.FrontChat?.('show');
closeDropdown(MULTI_WORKSPACE_DROPDOWN_ID);
@@ -225,6 +242,18 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
>
+ {
+ setNavigationDrawerExpandedMemorized(isNavigationDrawerExpanded);
+ setIsNavigationDrawerExpanded(true);
+ setNavigationMemorizedUrl(location.pathname + location.search);
+ navigate(getSettingsPath(SettingsPath.ProfilePage));
+ closeDropdown(MULTI_WORKSPACE_DROPDOWN_ID);
+ }}
+ >
+
+
{isSupportChatConfigured && (