Files
twenty/packages/twenty-front/src/modules/ai/components/NavigationDrawerAiChatContent.tsx
T
Raphaël Bosi 9c9c34fccf Remove twenty-ui-deprecated and migrate frontend to twenty-ui (#21596)
Migrates `twenty-front`, `twenty-sdk`, and
`twenty-front-component-renderer` from `twenty-ui-deprecated` to
`twenty-ui` (mechanical import swap — the packages have API parity) and
deletes the deprecated package along with its workspace/CI/config
wiring.

Also adds `@linaria/react`/`@linaria/core` as direct deps of
`twenty-front` (it used them transitively via the deprecated package).

Note: move the required status check from `ci-ui-status-check` to
`ci-new-ui-status-check`.

Argos: the Storybook box-model/button-reset baseline shift (the bulk of
the visual diffs) is isolated in #21665 — Storybook now loads
twenty-ui's global `reset.scss`, which the production app already ships.
Once #21665 merges and this branch is rebased, the remaining Argos diffs
are component-level visual-parity items only.
2026-06-17 09:41:11 +00:00

124 lines
4.1 KiB
TypeScript

import { styled } from '@linaria/react';
import { useLingui } from '@lingui/react/macro';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { AiChatThreadDeleteConfirmationModal } from '@/ai/components/AiChatThreadDeleteConfirmationModal';
import { AiChatThreadFilterDropdown } from '@/ai/components/AiChatThreadFilterDropdown';
import { AiChatSkeletonLoader } from '@/ai/components/internal/AiChatSkeletonLoader';
import { NavigationDrawerAiChatThreadSection } from '@/ai/components/NavigationDrawerAiChatThreadSection';
import { AGENT_CHAT_THREAD_GROUP_BY } from '@/ai/constants/AgentChatThreadGroupBy';
import { AI_CHAT_THREAD_ACTIONS_SURFACE } from '@/ai/constants/AiChatThreadActionsSurface';
import { useAiChatThreadClick } from '@/ai/hooks/useAiChatThreadClick';
import { useChatThreads } from '@/ai/hooks/useChatThreads';
import { agentChatThreadGroupByState } from '@/ai/states/agentChatThreadGroupByState';
import { currentAiChatThreadState } from '@/ai/states/currentAiChatThreadState';
import { groupThreadsByDate } from '@/ai/utils/groupThreadsByDate';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
const StyledContainer = styled.div`
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
`;
const StyledThreadList = styled.div`
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
width: 100%;
`;
const StyledSectionsContainer = styled.div`
display: flex;
flex-direction: column;
gap: ${themeCssVariables.spacing[3]};
`;
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%;
`;
const AI_CHAT_RECENTS_NAVIGATION_SECTION_ID = 'AiChatRecents';
export const NavigationDrawerAiChatContent = () => {
const { t } = useLingui();
const currentAiChatThread = useAtomStateValue(currentAiChatThreadState);
const { handleThreadClick } = useAiChatThreadClick({
resetNavigationStack: true,
});
const agentChatThreadGroupBy = useAtomStateValue(agentChatThreadGroupByState);
const { threads, hasNextPage, loading, fetchMoreRef } = useChatThreads();
if (loading && threads.length === 0) {
return (
<StyledContainer>
<AiChatSkeletonLoader />
</StyledContainer>
);
}
const isGroupedByDate =
agentChatThreadGroupBy === AGENT_CHAT_THREAD_GROUP_BY.DATE;
const dateGroups = isGroupedByDate ? groupThreadsByDate(threads) : [];
const shouldRenderDateGroups = isGroupedByDate && dateGroups.length > 0;
const filterDropdown = (
<AiChatThreadFilterDropdown
surface={AI_CHAT_THREAD_ACTIONS_SURFACE.NAV_DRAWER}
/>
);
return (
<StyledContainer>
<StyledThreadList>
{shouldRenderDateGroups ? (
<StyledSectionsContainer>
{dateGroups.map((dateGroup, index) => (
<NavigationDrawerAiChatThreadSection
key={dateGroup.id}
sectionId={`AiChatDateGroup:${dateGroup.id}`}
title={dateGroup.title}
threads={dateGroup.threads}
currentThreadId={currentAiChatThread}
onThreadClick={handleThreadClick}
rightIcon={index === 0 ? filterDropdown : undefined}
/>
))}
</StyledSectionsContainer>
) : (
<NavigationDrawerAiChatThreadSection
sectionId={AI_CHAT_RECENTS_NAVIGATION_SECTION_ID}
title={t`Recents`}
threads={threads}
currentThreadId={currentAiChatThread}
onThreadClick={handleThreadClick}
rightIcon={filterDropdown}
/>
)}
{threads.length === 0 ? (
<StyledEmptyState>{t`No chat`}</StyledEmptyState>
) : null}
{hasNextPage ? <StyledFetchMoreTrigger ref={fetchMoreRef} /> : null}
</StyledThreadList>
<AiChatThreadDeleteConfirmationModal
surface={AI_CHAT_THREAD_ACTIONS_SURFACE.NAV_DRAWER}
/>
</StyledContainer>
);
};