[AI] Navigation panel scroll refactor + Non chat placeholder (#18999)

<img width="374" height="1319" alt="CleanShot 2026-03-26 at 16 19 34"
src="https://github.com/user-attachments/assets/bebc7f67-3e9d-47c2-8e13-b57dab83d923"
/>

<img width="438" height="1320" alt="CleanShot 2026-03-26 at 16 19 20"
src="https://github.com/user-attachments/assets/e48ae2d2-066e-402f-a04b-aba7bae776bb"
/>


https://github.com/user-attachments/assets/64a8ad9b-0030-414c-a67d-3817ac3dd6b0
This commit is contained in:
nitin
2026-03-26 19:50:48 +05:30
committed by GitHub
parent 2e015ee68d
commit 92635b960b
4 changed files with 55 additions and 45 deletions
@@ -1,4 +1,6 @@
import { styled } from '@linaria/react';
import { useLingui } from '@lingui/react/macro';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { AIChatSkeletonLoader } from '@/ai/components/internal/AIChatSkeletonLoader';
import { NavigationDrawerAIChatThreadDateSection } from '@/ai/components/NavigationDrawerAIChatThreadDateSection';
@@ -10,25 +12,39 @@ import { DATE_GROUP_KEYS } from '@/ai/utils/dateGroupKeys';
import { getDateGroupTitle } from '@/ai/utils/getDateGroupTitle';
import { groupThreadsByDate } from '@/ai/utils/groupThreadsByDate';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledScrollableList = styled.div`
const StyledContainer = styled.div`
display: flex;
flex: 1;
flex-direction: column;
height: 100%;
min-height: 0;
overflow-y: auto;
`;
const StyledThreadList = styled.div`
display: flex;
flex-direction: column;
padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[0]};
width: calc(100% - ${themeCssVariables.spacing[2]});
`;
const StyledEmptyState = styled.div`
align-items: center;
color: ${themeCssVariables.font.color.light};
display: flex;
flex: 1;
font-size: ${themeCssVariables.font.size.md};
justify-content: center;
`;
const StyledFetchMoreTrigger = styled.div`
height: 1px;
min-height: 1px;
width: 100%;
`;
export const NavigationDrawerAIChatThreadsList = () => {
export const NavigationDrawerAIChatContent = () => {
const { t } = useLingui();
const currentAIChatThread = useAtomStateValue(currentAIChatThreadState);
const { handleThreadClick } = useAIChatThreadClick({
resetNavigationStack: true,
@@ -39,26 +55,40 @@ export const NavigationDrawerAIChatThreadsList = () => {
const groupedThreads = groupThreadsByDate(threads);
if (loading && threads.length === 0) {
return <AIChatSkeletonLoader />;
return (
<StyledContainer>
<AIChatSkeletonLoader />
</StyledContainer>
);
}
if (threads.length === 0) {
return (
<StyledContainer>
<StyledEmptyState>{t`No chat`}</StyledEmptyState>
</StyledContainer>
);
}
return (
<StyledScrollableList>
{DATE_GROUP_KEYS.map((key: DateGroupKey) => {
const threadsInGroup = groupedThreads[key];
if (threadsInGroup.length === 0) return null;
<StyledContainer>
<StyledThreadList>
{DATE_GROUP_KEYS.map((key: DateGroupKey) => {
const threadsInGroup = groupedThreads[key];
if (threadsInGroup.length === 0) return null;
return (
<NavigationDrawerAIChatThreadDateSection
key={key}
title={getDateGroupTitle(key)}
threads={threadsInGroup}
currentThreadId={currentAIChatThread}
onThreadClick={handleThreadClick}
/>
);
})}
{hasNextPage ? <StyledFetchMoreTrigger ref={fetchMoreRef} /> : null}
</StyledScrollableList>
return (
<NavigationDrawerAIChatThreadDateSection
key={key}
title={getDateGroupTitle(key)}
threads={threadsInGroup}
currentThreadId={currentAIChatThread}
onThreadClick={handleThreadClick}
/>
);
})}
{hasNextPage ? <StyledFetchMoreTrigger ref={fetchMoreRef} /> : null}
</StyledThreadList>
</StyledContainer>
);
};
@@ -1,5 +1,5 @@
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { MainNavigationDrawerAIChatContent } from '@/navigation/components/MainNavigationDrawerAIChatContent';
import { NavigationDrawerAIChatContent } from '@/ai/components/NavigationDrawerAIChatContent';
import { MainNavigationDrawerNavigationContent } from '@/navigation/components/MainNavigationDrawerNavigationContent';
import { MainNavigationDrawerTabsRow } from '@/navigation/components/MainNavigationDrawerTabsRow';
import { NavigationDrawer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
@@ -27,7 +27,7 @@ export const MainNavigationDrawer = ({ className }: { className?: string }) => {
<NavigationDrawerScrollableContent>
{navigationDrawerActiveTab ===
NAVIGATION_DRAWER_TABS.AI_CHAT_HISTORY ? (
<MainNavigationDrawerAIChatContent />
<NavigationDrawerAIChatContent />
) : (
<MainNavigationDrawerNavigationContent />
)}
@@ -1,18 +0,0 @@
import { styled } from '@linaria/react';
import { NavigationDrawerAIChatThreadsList } from '@/ai/components/NavigationDrawerAIChatThreadsList';
const StyledAIChatThreadsListWrapper = styled.div`
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
`;
export const MainNavigationDrawerAIChatContent = () => {
return (
<StyledAIChatThreadsListWrapper>
<NavigationDrawerAIChatThreadsList />
</StyledAIChatThreadsListWrapper>
);
};
@@ -7,10 +7,8 @@ import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledItemsContainer = styled.div`
display: flex;
flex: 1;
flex-direction: column;
margin-bottom: auto;
overflow: hidden;
height: 100%;
`;
const StyledScrollableInnerContainer = styled.div<{ isMobile?: boolean }>`