mirror of https://github.com/buster-so/buster.git
start chat from asset 🦚
This commit is contained in:
parent
fec77bda4b
commit
6c994bb9e8
|
@ -8,7 +8,8 @@ import {
|
|||
updateChat,
|
||||
deleteChat,
|
||||
getListLogs,
|
||||
duplicateChat
|
||||
duplicateChat,
|
||||
startChatFromAsset
|
||||
} from './requests';
|
||||
import type { IBusterChat, IBusterChatMessage } from '@/api/asset_interfaces/chat';
|
||||
import { queryKeys } from '@/api/query_keys';
|
||||
|
@ -78,7 +79,6 @@ export const useGetChat = <TData = IBusterChat>(
|
|||
const queryFn = useMemoizedFn(() => {
|
||||
return getChat(params).then((chat) => {
|
||||
const { iChat, iChatMessages } = updateChatToIChat(chat, false);
|
||||
|
||||
const lastMessageId = last(iChat.message_ids);
|
||||
const lastMessage = iChatMessages[lastMessageId!];
|
||||
if (lastMessage) {
|
||||
|
@ -108,6 +108,32 @@ export const useGetChat = <TData = IBusterChat>(
|
|||
});
|
||||
};
|
||||
|
||||
export const useStartChatFromAsset = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const mutationFn = useMemoizedFn(async (params: Parameters<typeof startChatFromAsset>[0]) => {
|
||||
const chat = await startChatFromAsset(params);
|
||||
const { iChat, iChatMessages } = updateChatToIChat(chat, false);
|
||||
iChat.message_ids.forEach((messageId) => {
|
||||
queryClient.setQueryData(
|
||||
queryKeys.chatsMessages(messageId).queryKey,
|
||||
iChatMessages[messageId]
|
||||
);
|
||||
});
|
||||
queryClient.setQueryData(queryKeys.chatsGetChat(chat.id).queryKey, iChat);
|
||||
return iChat;
|
||||
});
|
||||
|
||||
return useMutation({
|
||||
mutationFn,
|
||||
onSuccess: (chat) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.chatsGetList().queryKey
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const prefetchGetChat = async (
|
||||
params: Parameters<typeof getChat>[0],
|
||||
queryClientProp?: QueryClient
|
||||
|
|
|
@ -75,3 +75,18 @@ export const duplicateChat = async ({
|
|||
}): Promise<BusterChat> => {
|
||||
return mainApi.post(`${CHATS_BASE}/duplicate`, { id, message_id }).then((res) => res.data);
|
||||
};
|
||||
|
||||
export const startChatFromAsset = async ({
|
||||
asset_id,
|
||||
asset_type
|
||||
}: {
|
||||
asset_id: string;
|
||||
asset_type: 'metric' | 'dashboard';
|
||||
}): Promise<BusterChat> => {
|
||||
return mainApi
|
||||
.post(`${CHATS_BASE}`, {
|
||||
asset_id,
|
||||
asset_type
|
||||
})
|
||||
.then((res) => res.data);
|
||||
};
|
||||
|
|
|
@ -171,7 +171,7 @@ export const useUpdateDashboardConfig = (params?: {
|
|||
saveToServer?: boolean;
|
||||
updateVersion?: boolean;
|
||||
}) => {
|
||||
const { saveToServer = false, updateVersion = true } = params || {};
|
||||
const { saveToServer = false, updateVersion = false } = params || {};
|
||||
const { mutateAsync } = useUpdateDashboard({
|
||||
saveToServer,
|
||||
updateVersion
|
||||
|
|
|
@ -296,7 +296,11 @@ export const DropdownContent = <T,>({
|
|||
)}
|
||||
</div>
|
||||
|
||||
{footerContent && <div className={cn('border-t p-1', footerClassName)}>{footerContent}</div>}
|
||||
{footerContent && (
|
||||
<div className={cn(hasShownItem && 'border-t', 'p-1', footerClassName)}>
|
||||
{footerContent}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -23,7 +23,6 @@ export const useUpdateMetricChart = (props?: { metricId?: string }) => {
|
|||
saveToServer: false
|
||||
});
|
||||
const { mutateAsync: saveMetricToServer } = useUpdateMetric({
|
||||
updateVersion: true,
|
||||
updateOnSave: true,
|
||||
saveToServer: true
|
||||
});
|
||||
|
|
|
@ -52,9 +52,7 @@ export const MetricViewChart: React.FC<{
|
|||
} = useGetMetricData({ id: metricId });
|
||||
|
||||
const { mutate: updateMetric } = useUpdateMetric({
|
||||
updateOnSave: false,
|
||||
updateVersion: true,
|
||||
saveToServer: true
|
||||
saveToServer: false
|
||||
});
|
||||
const { name, description, time_frame, evaluation_score, evaluation_summary } = metric || {};
|
||||
|
||||
|
|
|
@ -25,8 +25,7 @@ export const MetricViewFile: React.FC<{ metricId: string }> = React.memo(({ metr
|
|||
} = useUpdateMetric({
|
||||
updateOnSave: true,
|
||||
saveToServer: true,
|
||||
updateVersion: true,
|
||||
wait: 0
|
||||
updateVersion: false
|
||||
});
|
||||
|
||||
const { isReadOnly } = useIsMetricReadOnly({
|
||||
|
|
|
@ -16,8 +16,7 @@ export const useMetricRunSQL = () => {
|
|||
const { mutateAsync: stageMetric } = useUpdateMetric({
|
||||
updateVersion: false,
|
||||
saveToServer: false,
|
||||
updateOnSave: false,
|
||||
wait: 0
|
||||
updateOnSave: false
|
||||
});
|
||||
const {
|
||||
mutateAsync: saveMetric,
|
||||
|
@ -26,8 +25,7 @@ export const useMetricRunSQL = () => {
|
|||
} = useUpdateMetric({
|
||||
updateOnSave: true,
|
||||
updateVersion: true,
|
||||
saveToServer: true,
|
||||
wait: 0
|
||||
saveToServer: true
|
||||
});
|
||||
const {
|
||||
mutateAsync: runSQLMutation,
|
||||
|
|
|
@ -19,16 +19,19 @@ export const ChatResponseMessages: React.FC<ChatResponseMessagesProps> = React.m
|
|||
(x) => x?.reasoning_message_ids?.[x.reasoning_message_ids.length - 1]
|
||||
);
|
||||
const finalReasoningMessage = useGetChatMessage(messageId, (x) => x?.final_reasoning_message);
|
||||
const showReasoningMessage = !!lastReasoningMessageId || !isCompletedStream;
|
||||
|
||||
return (
|
||||
<MessageContainer className="flex w-full flex-col space-y-3 overflow-hidden">
|
||||
<ChatResponseReasoning
|
||||
reasoningMessageId={lastReasoningMessageId}
|
||||
finalReasoningMessage={finalReasoningMessage}
|
||||
isCompletedStream={isCompletedStream}
|
||||
messageId={messageId}
|
||||
chatId={chatId}
|
||||
/>
|
||||
{showReasoningMessage && (
|
||||
<ChatResponseReasoning
|
||||
reasoningMessageId={lastReasoningMessageId}
|
||||
finalReasoningMessage={finalReasoningMessage}
|
||||
isCompletedStream={isCompletedStream}
|
||||
messageId={messageId}
|
||||
chatId={chatId}
|
||||
/>
|
||||
)}
|
||||
|
||||
{responseMessageIds.map((responseMessageId, index) => (
|
||||
<React.Fragment key={responseMessageId}>
|
||||
|
|
|
@ -163,7 +163,7 @@ export const useLayoutConfig = ({
|
|||
return 'chat';
|
||||
}
|
||||
return 'file';
|
||||
}, [selectedFileId]);
|
||||
}, [selectedFileId, chatId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
|
|
|
@ -1,29 +1,67 @@
|
|||
import { Stars } from '@/components/ui/icons';
|
||||
import { Button } from '@/components/ui/buttons';
|
||||
import React from 'react';
|
||||
import { useChatLayoutContextSelector } from '../../ChatLayoutContext';
|
||||
import React, { useState } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useMemoizedFn } from '@/hooks';
|
||||
import { AppTooltip } from '@/components/ui/tooltip';
|
||||
import { useStartChatFromAsset } from '@/api/buster_rest/chats/queryRequests';
|
||||
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
|
||||
import { BusterRoutes } from '@/routes';
|
||||
import { useChatLayoutContextSelector } from '../../ChatLayoutContext';
|
||||
import { timeout } from '@/lib';
|
||||
|
||||
export const CreateChatButton = React.memo(() => {
|
||||
const onCollapseFileClickPreflight = useMemoizedFn(() => {
|
||||
// onCollapseFileClick(false);
|
||||
alert('TODO');
|
||||
});
|
||||
export const CreateChatButton = React.memo(
|
||||
({ assetId, assetType }: { assetId: string; assetType: 'metric' | 'dashboard' }) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { mutateAsync: startChatFromAsset, isPending } = useStartChatFromAsset();
|
||||
const onChangePage = useAppLayoutContextSelector((x) => x.onChangePage);
|
||||
const onSetFileView = useChatLayoutContextSelector((x) => x.onSetFileView);
|
||||
|
||||
useHotkeys('e', onCollapseFileClickPreflight, { preventDefault: true });
|
||||
const onCreateFileClick = useMemoizedFn(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await startChatFromAsset({ asset_id: assetId, asset_type: assetType });
|
||||
|
||||
return (
|
||||
<AppTooltip title={'Start chat'} shortcuts={['e']}>
|
||||
<Button
|
||||
onClick={onCollapseFileClickPreflight}
|
||||
variant="black"
|
||||
className="ml-1.5"
|
||||
prefix={<Stars />}>
|
||||
Start chat
|
||||
</Button>
|
||||
</AppTooltip>
|
||||
);
|
||||
});
|
||||
if (assetType === 'metric') {
|
||||
await onChangePage({
|
||||
route: BusterRoutes.APP_CHAT_ID_METRIC_ID_CHART,
|
||||
metricId: assetId,
|
||||
chatId: result.id
|
||||
});
|
||||
} else if (assetType === 'dashboard') {
|
||||
await onChangePage({
|
||||
route: BusterRoutes.APP_CHAT_ID_DASHBOARD_ID,
|
||||
dashboardId: assetId,
|
||||
chatId: result.id
|
||||
});
|
||||
}
|
||||
|
||||
await timeout(250); //wait for the chat to load and the file to be selected
|
||||
onSetFileView({
|
||||
fileId: assetId,
|
||||
fileView: 'chart'
|
||||
});
|
||||
} catch (error) {
|
||||
//
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
useHotkeys('e', onCreateFileClick, { preventDefault: true });
|
||||
|
||||
return (
|
||||
<AppTooltip title={'Start chat'} shortcuts={['e']} delayDuration={650}>
|
||||
<Button
|
||||
loading={isPending || loading}
|
||||
onClick={onCreateFileClick}
|
||||
variant="black"
|
||||
className="ml-1.5"
|
||||
prefix={<Stars />}>
|
||||
Start chat
|
||||
</Button>
|
||||
</AppTooltip>
|
||||
);
|
||||
}
|
||||
);
|
||||
CreateChatButton.displayName = 'CreateChatButton';
|
||||
|
|
|
@ -31,7 +31,7 @@ export const DashboardHeaderButtons: React.FC<{
|
|||
{isEditor && <AddContentToDashboardButton />}
|
||||
<DashboardThreeDotMenu dashboardId={dashboardId} />
|
||||
<HideButtonContainer show>
|
||||
<CreateChatButton />
|
||||
<CreateChatButton assetId={dashboardId} assetType="dashboard" />
|
||||
</HideButtonContainer>
|
||||
</FileButtonContainer>
|
||||
);
|
||||
|
|
|
@ -50,7 +50,7 @@ export const DashboardThreeDotMenu = React.memo(({ dashboardId }: { dashboardId:
|
|||
{ id: dashboardId },
|
||||
{ select: (x) => x.permission }
|
||||
);
|
||||
const isOwner = getIsEffectiveOwner(permission);
|
||||
const isEffectiveOwner = getIsEffectiveOwner(permission);
|
||||
const isFilter = canFilter(permission);
|
||||
const isEditor = canEdit(permission);
|
||||
|
||||
|
@ -60,13 +60,13 @@ export const DashboardThreeDotMenu = React.memo(({ dashboardId }: { dashboardId:
|
|||
isFilter && filterDashboardMenu,
|
||||
isEditor && addContentToDashboardMenu,
|
||||
{ type: 'divider' },
|
||||
isOwner && shareMenu,
|
||||
isEffectiveOwner && shareMenu,
|
||||
collectionSelectMenu,
|
||||
favoriteDashboard,
|
||||
versionHistoryItems,
|
||||
{ type: 'divider' },
|
||||
isEditor && renameDashboardMenu,
|
||||
isOwner && deleteDashboardMenu
|
||||
isEffectiveOwner && deleteDashboardMenu
|
||||
].filter(Boolean) as DropdownItems,
|
||||
[
|
||||
filterDashboardMenu,
|
||||
|
|
|
@ -41,7 +41,7 @@ export const MetricContainerHeaderButtons: React.FC<FileContainerButtonsProps> =
|
|||
{isEffectiveOwner && <ShareMetricButton metricId={metricId} />}
|
||||
<ThreeDotMenuButton metricId={metricId} />
|
||||
<HideButtonContainer show={selectedLayout === 'file'}>
|
||||
<CreateChatButton />
|
||||
<CreateChatButton assetId={metricId} assetType="metric" />
|
||||
</HideButtonContainer>
|
||||
</FileButtonContainer>
|
||||
);
|
||||
|
|
|
@ -104,7 +104,6 @@ export const ThreeDotMenuButton = React.memo(({ metricId }: { metricId: string }
|
|||
deleteMetricMenu,
|
||||
downloadCSVMenu,
|
||||
downloadPNGMenu,
|
||||
metricId,
|
||||
openSuccessMessage,
|
||||
onSetSelectedFile,
|
||||
versionHistoryItems,
|
||||
|
|
Loading…
Reference in New Issue