From 7de778ec1e284f746ef08626b8c00f723855f0eb Mon Sep 17 00:00:00 2001 From: Thomas Draier Date: Tue, 26 Nov 2024 17:05:02 +0100 Subject: [PATCH] [extension] Use dropdown menu for conversation switching (#8913) * Use dropdown menu for conversation switching * show selected conversation * add chevron --- .../conversation/ConversationContainer.tsx | 37 ++--- .../conversation/ConversationsListButton.tsx | 132 +++++++++++++-- extension/app/src/pages/ConversationPage.tsx | 31 ++-- extension/app/src/pages/ConversationsPage.tsx | 151 ------------------ extension/app/src/pages/MainPage.tsx | 120 +++++++------- extension/app/src/pages/routes.tsx | 9 -- 6 files changed, 213 insertions(+), 267 deletions(-) delete mode 100644 extension/app/src/pages/ConversationsPage.tsx diff --git a/extension/app/src/components/conversation/ConversationContainer.tsx b/extension/app/src/components/conversation/ConversationContainer.tsx index 0a975aedea4d..33aa457a855b 100644 --- a/extension/app/src/components/conversation/ConversationContainer.tsx +++ b/extension/app/src/components/conversation/ConversationContainer.tsx @@ -45,8 +45,6 @@ export function ConversationContainer({ user, }: ConversationContainerProps) { const navigate = useNavigate(); - const [activeConversationId, setActiveConversationId] = - useState(conversationId); const [includeContent, setIncludeContent] = useState(); @@ -55,17 +53,15 @@ export function ConversationContainer({ return; } void setConversationsContext({ - [activeConversationId ?? "new"]: { + [conversationId ?? "new"]: { includeCurrentPage: includeContent, }, }); - }, [includeContent]); + }, [includeContent, conversationId]); useEffect(() => { const doAsync = async () => { - const context = await getConversationContext( - activeConversationId ?? "new" - ); + const context = await getConversationContext(conversationId ?? "new"); setIncludeContent(context.includeCurrentPage); }; void doAsync(); @@ -88,20 +84,12 @@ export function ConversationContainer({ } }); - useEffect(() => { - if (activeConversationId) { - navigate(`/conversations/${activeConversationId}`, { - replace: true, - }); - } - }, [activeConversationId, navigate]); - const handlePostMessage = async ( input: string, mentions: AgentMentionType[], files: UploadedFileWithKind[] ) => { - if (!activeConversationId) { + if (!conversationId) { return null; } const messageData = { input, mentions }; @@ -115,7 +103,7 @@ export function ConversationContainer({ // Get the content fragment ID to supersede for a given file. // Only for tab contents, we re-use the content fragment ID based on the URL and conversation ID. const supersededContentFragmentId: string | undefined = - (await getFileContentFragmentId(activeConversationId, file)) ?? + (await getFileContentFragmentId(conversationId, file)) ?? undefined; contentFragmentFiles.push({ @@ -128,7 +116,7 @@ export function ConversationContainer({ const result = await postMessage({ dustAPI, - conversationId: activeConversationId, + conversationId, messageData, files: contentFragmentFiles, }); @@ -138,7 +126,7 @@ export function ConversationContainer({ // Save content fragment IDs for tab contents to the local storage. await saveFilesContentFragmentIds({ - conversationId: activeConversationId, + conversationId, uploadedFiles: files, createdContentFragments: contentFragments, }); @@ -237,10 +225,13 @@ export function ConversationContainer({ }, new: { includeCurrentPage: false }, }); - setActiveConversationId(conversationRes.value.sId); + + navigate(`/conversations/${conversationRes.value.sId}`, { + replace: true, + }); } }, - [owner, sendNotification, setActiveConversationId, includeContent] + [owner, sendNotification, includeContent] ) ); @@ -256,13 +247,13 @@ export function ConversationContainer({ setGreeting(getRandomGreetingForName(user.firstName)); }, [user]); - if (activeConversationId) { + if (conversationId) { return (
{ + const { conversations, isConversationsLoading } = useConversations(); + const { conversationId } = useParams(); + + const navigate = useNavigate(); + + const groupConversationsByDate = ( + conversations: ConversationWithoutContentPublicType[] + ) => { + const today = moment().startOf("day"); + const yesterday = moment().subtract(1, "days").startOf("day"); + const lastWeek = moment().subtract(1, "weeks").startOf("day"); + const lastMonth = moment().subtract(1, "months").startOf("day"); + const lastYear = moment().subtract(1, "years").startOf("day"); + + type GroupLabel = + | "Today" + | "Yesterday" + | "Last Week" + | "Last Month" + | "Last 12 Months" + | "Older"; + + const groups: Record = { + Today: [], + Yesterday: [], + "Last Week": [], + "Last Month": [], + "Last 12 Months": [], + Older: [], + }; + + conversations.forEach((conversation) => { + const createdDate = moment(conversation.created); + if (createdDate.isSameOrAfter(today)) { + groups["Today"].push(conversation); + } else if (createdDate.isSameOrAfter(yesterday)) { + groups["Yesterday"].push(conversation); + } else if (createdDate.isSameOrAfter(lastWeek)) { + groups["Last Week"].push(conversation); + } else if (createdDate.isSameOrAfter(lastMonth)) { + groups["Last Month"].push(conversation); + } else if (createdDate.isSameOrAfter(lastYear)) { + groups["Last 12 Months"].push(conversation); + } else { + groups["Older"].push(conversation); + } + }); + + return groups; + }; + + const conversationsByDate = conversations.length + ? groupConversationsByDate(conversations) + : ({} as Record); + + return isConversationsLoading ? ( +
+ +
+ ) : ( + + {Object.keys(conversationsByDate).map((dateLabel) => ( + <> + + {conversationsByDate[dateLabel as GroupLabel].map((conversation) => ( + { + navigate(`/conversations/${conversation.sId}`); + }} + /> + ))} + + ))} + + ); +}; export const ConversationsListButton = ({ size = "sm", }: { size?: "sm" | "md"; }) => { - const navigate = useNavigate(); return ( -
- } - /> -
- {conversationsByDate && - Object.keys(conversationsByDate).map((dateLabel) => ( - - ))} -
- - ); -}; - -const RenderConversations = ({ - conversations, - dateLabel, - navigate, -}: { - conversations: ConversationWithoutContentPublicType[]; - dateLabel: string; - navigate: NavigateFunction; -}) => { - if (!conversations.length) { - return null; - } - - const getLabel = ( - conversation: ConversationWithoutContentPublicType - ): string => { - const conversationLabel = - conversation.title || - (moment(conversation.created).isSame(moment(), "day") - ? "New Conversation" - : `Conversation from ${new Date(conversation.created).toLocaleDateString()}`); - - return conversationLabel; - }; - - return ( -
- - - {conversations.map((conversation) => ( - { - navigate(`/conversations/${conversation.sId}`, { - state: { origin: "conversations" }, - }); - }} - /> - ))} - -
- ); -}; diff --git a/extension/app/src/pages/MainPage.tsx b/extension/app/src/pages/MainPage.tsx index 7a2b92ce8aad..73ea205e4866 100644 --- a/extension/app/src/pages/MainPage.tsx +++ b/extension/app/src/pages/MainPage.tsx @@ -1,5 +1,6 @@ import { Avatar, + BarHeader, Button, DropdownMenu, DropdownMenuContent, @@ -27,34 +28,71 @@ export const MainPage = ({ return ( <> -
-
- {user.workspaces.length > 1 && ( -
-

Workspace:

- - -
+ )} +
+ } + rightActions={ +
+ + + + +
+ { + "clickable"; + }} /> - - - {user.workspaces.map((w) => { - return ( - void handleSelectWorkspace(w.sId)} - label={w.name} - /> - ); - })} - - -
- )} -
+
+ + + + + +
+ } + /> + +
@@ -62,34 +100,6 @@ export const MainPage = ({
-
- - - - <> - Open user menu - { - "clickable"; - }} - /> - - - - - - -
diff --git a/extension/app/src/pages/routes.tsx b/extension/app/src/pages/routes.tsx index 50d34a37eb52..6b73bd84de27 100644 --- a/extension/app/src/pages/routes.tsx +++ b/extension/app/src/pages/routes.tsx @@ -1,6 +1,5 @@ import { ProtectedRoute } from "@extension/components/auth/ProtectedRoute"; import { ConversationPage } from "@extension/pages/ConversationPage"; -import { ConversationsPage } from "@extension/pages/ConversationsPage"; import { LoginPage } from "@extension/pages/LoginPage"; import { MainPage } from "@extension/pages/MainPage"; import { RunPage } from "@extension/pages/RunPage"; @@ -38,14 +37,6 @@ export const routes = [ ), }, - { - path: "/conversations", - element: ( - - - - ), - }, { path: "/run", element: {() => },