From 41616d98b615aaa39cdbd9c52d5cbdb3f8475184 Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Thu, 17 Apr 2025 00:17:14 -0600 Subject: [PATCH] add to collection dropdown --- web/src/api/buster_rest/chats/requests.ts | 11 +-- .../buster_rest/dashboards/queryRequests.ts | 2 + .../SaveDashboardToCollectionButton.tsx | 73 +++++++++++-------- .../dropdowns/SaveToCollectionsDropdown.tsx | 5 +- .../ChatContent/ChatMessageOptions.tsx | 3 +- .../ChatHeaderOptions/ChatHeaderDropdown.tsx | 27 ++++--- .../DashboardContainerHeaderButtons.tsx | 17 ++++- 7 files changed, 81 insertions(+), 57 deletions(-) diff --git a/web/src/api/buster_rest/chats/requests.ts b/web/src/api/buster_rest/chats/requests.ts index 8d8ddff21..5b16c9b9c 100644 --- a/web/src/api/buster_rest/chats/requests.ts +++ b/web/src/api/buster_rest/chats/requests.ts @@ -74,15 +74,8 @@ export const updateChatMessageFeedback = async ({ return mainApi.put(`/messages/${message_id}`, params).then((res) => res.data); }; -export const duplicateChat = async ({ - id, - message_id -}: { - id: string; - /** The message ID to start the duplication from */ - message_id: string; -}): Promise => { - return mainApi.post(`${CHATS_BASE}/duplicate`, { id, message_id }).then((res) => res.data); +export const duplicateChat = async ({ id }: { id: string }): Promise => { + return mainApi.post(`${CHATS_BASE}/duplicate`, { id }).then((res) => res.data); }; export const startChatFromAsset = async ({ diff --git a/web/src/api/buster_rest/dashboards/queryRequests.ts b/web/src/api/buster_rest/dashboards/queryRequests.ts index 180a74898..cad29de9f 100644 --- a/web/src/api/buster_rest/dashboards/queryRequests.ts +++ b/web/src/api/buster_rest/dashboards/queryRequests.ts @@ -257,6 +257,8 @@ export const useAddDashboardToCollection = () => { const mutationFn = useMemoizedFn( async (variables: { dashboardIds: string[]; collectionIds: string[] }) => { const { dashboardIds, collectionIds } = variables; + console.log('dashboardIds', dashboardIds); + console.log('collectionIds', collectionIds); return await Promise.all( collectionIds.map((collectionId) => addAssetToCollection({ diff --git a/web/src/components/features/buttons/SaveDashboardToCollectionButton.tsx b/web/src/components/features/buttons/SaveDashboardToCollectionButton.tsx index cf370c37c..3191012e0 100644 --- a/web/src/components/features/buttons/SaveDashboardToCollectionButton.tsx +++ b/web/src/components/features/buttons/SaveDashboardToCollectionButton.tsx @@ -7,48 +7,57 @@ import { useAddDashboardToCollection, useRemoveDashboardFromCollection } from '@/api/buster_rest/dashboards'; +import uniq from 'lodash/uniq'; export const SaveDashboardToCollectionButton: React.FC<{ dashboardIds: string[]; buttonType?: 'ghost' | 'default'; useText?: boolean; -}> = React.memo(({ dashboardIds, buttonType = 'ghost', useText = false }) => { - const { openInfoMessage } = useBusterNotifications(); + selectedCollections: string[]; +}> = React.memo( + ({ + dashboardIds, + buttonType = 'ghost', + useText = false, + selectedCollections: selectedCollectionsProp + }) => { + const { openInfoMessage } = useBusterNotifications(); - const [selectedCollections, setSelectedCollections] = useState< - Parameters[0]['selectedCollections'] - >([]); - const { mutateAsync: addDashboardToCollection } = useAddDashboardToCollection(); - const { mutateAsync: removeDashboardFromCollection } = useRemoveDashboardFromCollection(); + const [selectedCollections, setSelectedCollections] = + useState[0]['selectedCollections']>( + selectedCollectionsProp + ); + const { mutateAsync: addDashboardToCollection } = useAddDashboardToCollection(); + const { mutateAsync: removeDashboardFromCollection } = useRemoveDashboardFromCollection(); - const onSaveToCollection = useMemoizedFn(async (collectionIds: string[]) => { - setSelectedCollections(collectionIds); - await addDashboardToCollection({ - dashboardIds, - collectionIds + const onSaveToCollection = useMemoizedFn(async (collectionIds: string[]) => { + setSelectedCollections((prev) => uniq([...prev, ...collectionIds])); + await addDashboardToCollection({ + dashboardIds, + collectionIds + }); + + openInfoMessage('Dashboards saved to collections'); }); - openInfoMessage('Dashboards saved to collections'); - }); - - const onRemoveFromCollection = useMemoizedFn(async (collectionId: string) => { - setSelectedCollections((prev) => prev.filter((id) => id !== collectionId)); - - await removeDashboardFromCollection({ - dashboardIds, - collectionIds: [collectionId] + const onRemoveFromCollection = useMemoizedFn(async (collectionId: string) => { + setSelectedCollections((prev) => prev.filter((id) => id !== collectionId)); + await removeDashboardFromCollection({ + dashboardIds, + collectionIds: [collectionId] + }); + openInfoMessage('Dashboards removed from collections'); }); - openInfoMessage('Dashboards removed from collections'); - }); - return ( - - - - ); -}); + return ( + + + + ); + } +); SaveDashboardToCollectionButton.displayName = 'SaveDashboardToCollectionButton'; diff --git a/web/src/components/features/dropdowns/SaveToCollectionsDropdown.tsx b/web/src/components/features/dropdowns/SaveToCollectionsDropdown.tsx index 762383616..a0d4b9dd7 100644 --- a/web/src/components/features/dropdowns/SaveToCollectionsDropdown.tsx +++ b/web/src/components/features/dropdowns/SaveToCollectionsDropdown.tsx @@ -125,7 +125,10 @@ export const useSaveToCollectionsDropdownContent = ({ onRemoveFromCollection(collection.id); } else { const allCollectionsAndSelected = selectedCollections.map((id) => id).concat(collection.id); - onSaveToCollection(allCollectionsAndSelected); + const differenceFromSelectedCollections = allCollectionsAndSelected.filter( + (id) => !selectedCollections.some((selectedId) => selectedId === id) + ); + onSaveToCollection(differenceFromSelectedCollections); } }); diff --git a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatMessageOptions.tsx b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatMessageOptions.tsx index d6999c894..44654bab5 100644 --- a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatMessageOptions.tsx +++ b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatMessageOptions.tsx @@ -35,8 +35,7 @@ export const ChatMessageOptions: React.FC<{ 'You are about to duplicate this chat from this message. This will create a new chat with the same messages. Do you want to continue?', onOk: async () => { const res = await duplicateChat({ - id: chatId, - message_id: messageId + id: chatId }); await timeout(100); await onChangePage({ diff --git a/web/src/layouts/ChatLayout/ChatContainer/ChatHeader/ChatHeaderOptions/ChatHeaderDropdown.tsx b/web/src/layouts/ChatLayout/ChatContainer/ChatHeader/ChatHeaderOptions/ChatHeaderDropdown.tsx index e97648bb5..ec372e9f1 100644 --- a/web/src/layouts/ChatLayout/ChatContainer/ChatHeader/ChatHeaderOptions/ChatHeaderDropdown.tsx +++ b/web/src/layouts/ChatLayout/ChatContainer/ChatHeader/ChatHeaderOptions/ChatHeaderDropdown.tsx @@ -8,6 +8,7 @@ import { timeout } from '@/lib'; import { BusterRoutes } from '@/routes'; import { useAppLayoutContextSelector } from '@/context/BusterAppLayout'; import { useBusterNotifications } from '@/context/BusterNotifications'; +import { assetParamsToRoute } from '@/lib/assets'; export const ChatContainerHeaderDropdown: React.FC<{ children: React.ReactNode; @@ -18,6 +19,8 @@ export const ChatContainerHeaderDropdown: React.FC<{ const { mutate: deleteChat, isPending: isDeleting } = useDeleteChat(); const { mutateAsync: duplicateChat, isPending: isDuplicating } = useDuplicateChat(); const currentMessageId = useChatIndividualContextSelector((state) => state.currentMessageId); + const selectedFileId = useChatIndividualContextSelector((state) => state.selectedFileId); + const selectedFileType = useChatIndividualContextSelector((state) => state.selectedFileType); const menuItem: DropdownItems = useMemo(() => { return [ @@ -45,15 +48,21 @@ export const ChatContainerHeaderDropdown: React.FC<{ loading: isDuplicating, onClick: async () => { if (chatId) { - duplicateChat( - { id: chatId, message_id: currentMessageId }, - { - onSuccess: (chat) => { - onChangePage({ route: BusterRoutes.APP_CHAT_ID, chatId: chat.id }); - openSuccessMessage('Chat duplicated'); - } - } - ); + const res = await duplicateChat({ id: chatId }); + await timeout(100); + if (selectedFileType && selectedFileId) { + const route = assetParamsToRoute({ + assetId: selectedFileId, + chatId: res.id, + type: selectedFileType + }); + + if (route) await onChangePage(route); + } else { + await onChangePage({ route: BusterRoutes.APP_CHAT_ID, chatId: res.id }); + } + + openSuccessMessage('Chat duplicated'); } } }, diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/DashboardContainerHeaderButtons/DashboardContainerHeaderButtons.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/DashboardContainerHeaderButtons/DashboardContainerHeaderButtons.tsx index 6b231be15..97436ebdf 100644 --- a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/DashboardContainerHeaderButtons/DashboardContainerHeaderButtons.tsx +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/DashboardContainerHeaderButtons/DashboardContainerHeaderButtons.tsx @@ -37,7 +37,7 @@ export const DashboardContainerHeaderButtons: React.FC - + {isEffectiveOwner && } {isEditor && !isViewingOldVersion && } { - const selectedFileId = useChatIndividualContextSelector((x) => x.selectedFileId)!; - return ; +const SaveToCollectionButton = React.memo(({ dashboardId }: { dashboardId: string }) => { + const { data: collections } = useGetDashboard( + { id: dashboardId }, + { select: (x) => x.collections?.map((x) => x.id) } + ); + + return ( + + ); }); SaveToCollectionButton.displayName = 'SaveToCollectionButton';