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);
};
export const duplicateChat = async ({
id,
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 duplicateChat = async ({ id }: { id: string }): Promise<BusterChat> => {
return mainApi.post(`${CHATS_BASE}/duplicate`, { id }).then((res) => res.data);
};
export const startChatFromAsset = async ({

View File

@ -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({

View File

@ -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<typeof SaveToCollectionsDropdown>[0]['selectedCollections']
>([]);
const { mutateAsync: addDashboardToCollection } = useAddDashboardToCollection();
const { mutateAsync: removeDashboardFromCollection } = useRemoveDashboardFromCollection();
const [selectedCollections, setSelectedCollections] =
useState<Parameters<typeof SaveToCollectionsDropdown>[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 (
<SaveToCollectionsDropdown
onSaveToCollection={onSaveToCollection}
onRemoveFromCollection={onRemoveFromCollection}
selectedCollections={selectedCollections}>
<CollectionButton buttonType={buttonType} useText={useText} />
</SaveToCollectionsDropdown>
);
});
return (
<SaveToCollectionsDropdown
onSaveToCollection={onSaveToCollection}
onRemoveFromCollection={onRemoveFromCollection}
selectedCollections={selectedCollections}>
<CollectionButton buttonType={buttonType} useText={useText} />
</SaveToCollectionsDropdown>
);
}
);
SaveDashboardToCollectionButton.displayName = 'SaveDashboardToCollectionButton';

View File

@ -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);
}
});

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

View File

@ -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');
}
}
},

View File

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