add to collection dropdown

This commit is contained in:
Nate Kelley 2025-04-17 00:17:14 -06:00
parent 95805195e0
commit 41616d98b6
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
7 changed files with 81 additions and 57 deletions

View File

@ -74,15 +74,8 @@ export const updateChatMessageFeedback = async ({
return mainApi.put(`/messages/${message_id}`, params).then((res) => res.data); return mainApi.put(`/messages/${message_id}`, params).then((res) => res.data);
}; };
export const duplicateChat = async ({ export const duplicateChat = async ({ id }: { id: string }): Promise<BusterChat> => {
id, return mainApi.post(`${CHATS_BASE}/duplicate`, { id }).then((res) => res.data);
message_id
}: {
id: string;
/** The message ID to start the duplication from */
message_id: string;
}): Promise<BusterChat> => {
return mainApi.post(`${CHATS_BASE}/duplicate`, { id, message_id }).then((res) => res.data);
}; };
export const startChatFromAsset = async ({ export const startChatFromAsset = async ({

View File

@ -257,6 +257,8 @@ export const useAddDashboardToCollection = () => {
const mutationFn = useMemoizedFn( const mutationFn = useMemoizedFn(
async (variables: { dashboardIds: string[]; collectionIds: string[] }) => { async (variables: { dashboardIds: string[]; collectionIds: string[] }) => {
const { dashboardIds, collectionIds } = variables; const { dashboardIds, collectionIds } = variables;
console.log('dashboardIds', dashboardIds);
console.log('collectionIds', collectionIds);
return await Promise.all( return await Promise.all(
collectionIds.map((collectionId) => collectionIds.map((collectionId) =>
addAssetToCollection({ addAssetToCollection({

View File

@ -7,48 +7,57 @@ import {
useAddDashboardToCollection, useAddDashboardToCollection,
useRemoveDashboardFromCollection useRemoveDashboardFromCollection
} from '@/api/buster_rest/dashboards'; } from '@/api/buster_rest/dashboards';
import uniq from 'lodash/uniq';
export const SaveDashboardToCollectionButton: React.FC<{ export const SaveDashboardToCollectionButton: React.FC<{
dashboardIds: string[]; dashboardIds: string[];
buttonType?: 'ghost' | 'default'; buttonType?: 'ghost' | 'default';
useText?: boolean; useText?: boolean;
}> = React.memo(({ dashboardIds, buttonType = 'ghost', useText = false }) => { selectedCollections: string[];
const { openInfoMessage } = useBusterNotifications(); }> = React.memo(
({
dashboardIds,
buttonType = 'ghost',
useText = false,
selectedCollections: selectedCollectionsProp
}) => {
const { openInfoMessage } = useBusterNotifications();
const [selectedCollections, setSelectedCollections] = useState< const [selectedCollections, setSelectedCollections] =
Parameters<typeof SaveToCollectionsDropdown>[0]['selectedCollections'] useState<Parameters<typeof SaveToCollectionsDropdown>[0]['selectedCollections']>(
>([]); selectedCollectionsProp
const { mutateAsync: addDashboardToCollection } = useAddDashboardToCollection(); );
const { mutateAsync: removeDashboardFromCollection } = useRemoveDashboardFromCollection(); const { mutateAsync: addDashboardToCollection } = useAddDashboardToCollection();
const { mutateAsync: removeDashboardFromCollection } = useRemoveDashboardFromCollection();
const onSaveToCollection = useMemoizedFn(async (collectionIds: string[]) => { const onSaveToCollection = useMemoizedFn(async (collectionIds: string[]) => {
setSelectedCollections(collectionIds); setSelectedCollections((prev) => uniq([...prev, ...collectionIds]));
await addDashboardToCollection({ await addDashboardToCollection({
dashboardIds, dashboardIds,
collectionIds 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({
const onRemoveFromCollection = useMemoizedFn(async (collectionId: string) => { dashboardIds,
setSelectedCollections((prev) => prev.filter((id) => id !== collectionId)); collectionIds: [collectionId]
});
await removeDashboardFromCollection({ openInfoMessage('Dashboards removed from collections');
dashboardIds,
collectionIds: [collectionId]
}); });
openInfoMessage('Dashboards removed from collections');
});
return ( return (
<SaveToCollectionsDropdown <SaveToCollectionsDropdown
onSaveToCollection={onSaveToCollection} onSaveToCollection={onSaveToCollection}
onRemoveFromCollection={onRemoveFromCollection} onRemoveFromCollection={onRemoveFromCollection}
selectedCollections={selectedCollections}> selectedCollections={selectedCollections}>
<CollectionButton buttonType={buttonType} useText={useText} /> <CollectionButton buttonType={buttonType} useText={useText} />
</SaveToCollectionsDropdown> </SaveToCollectionsDropdown>
); );
}); }
);
SaveDashboardToCollectionButton.displayName = 'SaveDashboardToCollectionButton'; SaveDashboardToCollectionButton.displayName = 'SaveDashboardToCollectionButton';

View File

@ -125,7 +125,10 @@ export const useSaveToCollectionsDropdownContent = ({
onRemoveFromCollection(collection.id); onRemoveFromCollection(collection.id);
} else { } else {
const allCollectionsAndSelected = selectedCollections.map((id) => id).concat(collection.id); const allCollectionsAndSelected = selectedCollections.map((id) => id).concat(collection.id);
onSaveToCollection(allCollectionsAndSelected); const differenceFromSelectedCollections = allCollectionsAndSelected.filter(
(id) => !selectedCollections.some((selectedId) => selectedId === id)
);
onSaveToCollection(differenceFromSelectedCollections);
} }
}); });

View File

@ -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?', '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 () => { onOk: async () => {
const res = await duplicateChat({ const res = await duplicateChat({
id: chatId, id: chatId
message_id: messageId
}); });
await timeout(100); await timeout(100);
await onChangePage({ await onChangePage({

View File

@ -8,6 +8,7 @@ import { timeout } from '@/lib';
import { BusterRoutes } from '@/routes'; import { BusterRoutes } from '@/routes';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout'; import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import { useBusterNotifications } from '@/context/BusterNotifications'; import { useBusterNotifications } from '@/context/BusterNotifications';
import { assetParamsToRoute } from '@/lib/assets';
export const ChatContainerHeaderDropdown: React.FC<{ export const ChatContainerHeaderDropdown: React.FC<{
children: React.ReactNode; children: React.ReactNode;
@ -18,6 +19,8 @@ export const ChatContainerHeaderDropdown: React.FC<{
const { mutate: deleteChat, isPending: isDeleting } = useDeleteChat(); const { mutate: deleteChat, isPending: isDeleting } = useDeleteChat();
const { mutateAsync: duplicateChat, isPending: isDuplicating } = useDuplicateChat(); const { mutateAsync: duplicateChat, isPending: isDuplicating } = useDuplicateChat();
const currentMessageId = useChatIndividualContextSelector((state) => state.currentMessageId); const currentMessageId = useChatIndividualContextSelector((state) => state.currentMessageId);
const selectedFileId = useChatIndividualContextSelector((state) => state.selectedFileId);
const selectedFileType = useChatIndividualContextSelector((state) => state.selectedFileType);
const menuItem: DropdownItems = useMemo(() => { const menuItem: DropdownItems = useMemo(() => {
return [ return [
@ -45,15 +48,21 @@ export const ChatContainerHeaderDropdown: React.FC<{
loading: isDuplicating, loading: isDuplicating,
onClick: async () => { onClick: async () => {
if (chatId) { if (chatId) {
duplicateChat( const res = await duplicateChat({ id: chatId });
{ id: chatId, message_id: currentMessageId }, await timeout(100);
{ if (selectedFileType && selectedFileId) {
onSuccess: (chat) => { const route = assetParamsToRoute({
onChangePage({ route: BusterRoutes.APP_CHAT_ID, chatId: chat.id }); assetId: selectedFileId,
openSuccessMessage('Chat duplicated'); chatId: res.id,
} type: selectedFileType
} });
);
if (route) await onChangePage(route);
} else {
await onChangePage({ route: BusterRoutes.APP_CHAT_ID, chatId: res.id });
}
openSuccessMessage('Chat duplicated');
} }
} }
}, },

View File

@ -37,7 +37,7 @@ export const DashboardContainerHeaderButtons: React.FC<FileContainerButtonsProps
return ( return (
<FileButtonContainer> <FileButtonContainer>
<SaveToCollectionButton /> <SaveToCollectionButton dashboardId={dashboardId} />
{isEffectiveOwner && <ShareDashboardButton dashboardId={dashboardId} />} {isEffectiveOwner && <ShareDashboardButton dashboardId={dashboardId} />}
{isEditor && !isViewingOldVersion && <AddContentToDashboardButton />} {isEditor && !isViewingOldVersion && <AddContentToDashboardButton />}
<DashboardThreeDotMenu <DashboardThreeDotMenu
@ -54,9 +54,18 @@ export const DashboardContainerHeaderButtons: React.FC<FileContainerButtonsProps
DashboardContainerHeaderButtons.displayName = 'DashboardContainerHeaderButtons'; DashboardContainerHeaderButtons.displayName = 'DashboardContainerHeaderButtons';
const SaveToCollectionButton = React.memo(() => { const SaveToCollectionButton = React.memo(({ dashboardId }: { dashboardId: string }) => {
const selectedFileId = useChatIndividualContextSelector((x) => x.selectedFileId)!; const { data: collections } = useGetDashboard(
return <SaveDashboardToCollectionButton dashboardIds={[selectedFileId]} />; { id: dashboardId },
{ select: (x) => x.collections?.map((x) => x.id) }
);
return (
<SaveDashboardToCollectionButton
dashboardIds={[dashboardId]}
selectedCollections={collections || []}
/>
);
}); });
SaveToCollectionButton.displayName = 'SaveToCollectionButton'; SaveToCollectionButton.displayName = 'SaveToCollectionButton';