From 6c994bb9e8d4e9148762ff7b75e5ed453a4ca848 Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Wed, 9 Apr 2025 17:09:06 -0600 Subject: [PATCH] =?UTF-8?q?start=20chat=20from=20asset=20=F0=9F=A6=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/buster_rest/chats/queryRequests.ts | 30 ++++++- web/src/api/buster_rest/chats/requests.ts | 15 ++++ .../buster_rest/dashboards/queryRequests.ts | 2 +- web/src/components/ui/dropdown/Dropdown.tsx | 6 +- .../context/Metrics/useUpdateMetricChart.ts | 1 - .../MetricViewChart/MetricViewChart.tsx | 4 +- .../MetricViewFile/MetricViewFile.tsx | 3 +- .../useMetricRunSQL/useMetricRunSQL.ts | 6 +- .../ChatResponseMessages.tsx | 17 ++-- .../useLayoutConfig/useLayoutConfig.ts | 2 +- .../FileContainerHeader/CreateChatButtont.tsx | 78 ++++++++++++++----- .../DashboardHeaderButtons.tsx | 2 +- .../DashboardThreeDotMenu.tsx | 6 +- .../MetricContainerHeaderButtons.tsx | 2 +- .../MetricThreeDotMenu.tsx | 1 - 15 files changed, 127 insertions(+), 48 deletions(-) diff --git a/web/src/api/buster_rest/chats/queryRequests.ts b/web/src/api/buster_rest/chats/queryRequests.ts index 2a4e5d00b..27660c9c4 100644 --- a/web/src/api/buster_rest/chats/queryRequests.ts +++ b/web/src/api/buster_rest/chats/queryRequests.ts @@ -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 = ( 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 = ( }); }; +export const useStartChatFromAsset = () => { + const queryClient = useQueryClient(); + + const mutationFn = useMemoizedFn(async (params: Parameters[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[0], queryClientProp?: QueryClient diff --git a/web/src/api/buster_rest/chats/requests.ts b/web/src/api/buster_rest/chats/requests.ts index 9ae0fb7eb..34391624f 100644 --- a/web/src/api/buster_rest/chats/requests.ts +++ b/web/src/api/buster_rest/chats/requests.ts @@ -75,3 +75,18 @@ export const duplicateChat = async ({ }): Promise => { 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 => { + return mainApi + .post(`${CHATS_BASE}`, { + asset_id, + asset_type + }) + .then((res) => res.data); +}; diff --git a/web/src/api/buster_rest/dashboards/queryRequests.ts b/web/src/api/buster_rest/dashboards/queryRequests.ts index a6d83047e..e3a40b88e 100644 --- a/web/src/api/buster_rest/dashboards/queryRequests.ts +++ b/web/src/api/buster_rest/dashboards/queryRequests.ts @@ -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 diff --git a/web/src/components/ui/dropdown/Dropdown.tsx b/web/src/components/ui/dropdown/Dropdown.tsx index 94d06c9a6..c3758baf2 100644 --- a/web/src/components/ui/dropdown/Dropdown.tsx +++ b/web/src/components/ui/dropdown/Dropdown.tsx @@ -296,7 +296,11 @@ export const DropdownContent = ({ )} - {footerContent &&
{footerContent}
} + {footerContent && ( +
+ {footerContent} +
+ )} ); }; diff --git a/web/src/context/Metrics/useUpdateMetricChart.ts b/web/src/context/Metrics/useUpdateMetricChart.ts index 2f39a222f..7c3934ccf 100644 --- a/web/src/context/Metrics/useUpdateMetricChart.ts +++ b/web/src/context/Metrics/useUpdateMetricChart.ts @@ -23,7 +23,6 @@ export const useUpdateMetricChart = (props?: { metricId?: string }) => { saveToServer: false }); const { mutateAsync: saveMetricToServer } = useUpdateMetric({ - updateVersion: true, updateOnSave: true, saveToServer: true }); diff --git a/web/src/controllers/MetricController/MetricViewChart/MetricViewChart.tsx b/web/src/controllers/MetricController/MetricViewChart/MetricViewChart.tsx index 3ac893cdc..6548a5b2c 100644 --- a/web/src/controllers/MetricController/MetricViewChart/MetricViewChart.tsx +++ b/web/src/controllers/MetricController/MetricViewChart/MetricViewChart.tsx @@ -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 || {}; diff --git a/web/src/controllers/MetricController/MetricViewFile/MetricViewFile.tsx b/web/src/controllers/MetricController/MetricViewFile/MetricViewFile.tsx index 74d73147d..7e759851f 100644 --- a/web/src/controllers/MetricController/MetricViewFile/MetricViewFile.tsx +++ b/web/src/controllers/MetricController/MetricViewFile/MetricViewFile.tsx @@ -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({ diff --git a/web/src/controllers/MetricController/MetricViewResults/useMetricRunSQL/useMetricRunSQL.ts b/web/src/controllers/MetricController/MetricViewResults/useMetricRunSQL/useMetricRunSQL.ts index d4f3453ee..70db77ed8 100644 --- a/web/src/controllers/MetricController/MetricViewResults/useMetricRunSQL/useMetricRunSQL.ts +++ b/web/src/controllers/MetricController/MetricViewResults/useMetricRunSQL/useMetricRunSQL.ts @@ -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, diff --git a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseMessages.tsx b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseMessages.tsx index 97eac903b..e15c5c69d 100644 --- a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseMessages.tsx +++ b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseMessages.tsx @@ -19,16 +19,19 @@ export const ChatResponseMessages: React.FC = 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 ( - + {showReasoningMessage && ( + + )} {responseMessageIds.map((responseMessageId, index) => ( diff --git a/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/useLayoutConfig.ts b/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/useLayoutConfig.ts index 68122205a..2acc49c12 100644 --- a/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/useLayoutConfig.ts +++ b/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/useLayoutConfig.ts @@ -163,7 +163,7 @@ export const useLayoutConfig = ({ return 'chat'; } return 'file'; - }, [selectedFileId]); + }, [selectedFileId, chatId]); useEffect(() => { if ( diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/CreateChatButtont.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/CreateChatButtont.tsx index 222763813..58391a57f 100644 --- a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/CreateChatButtont.tsx +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/CreateChatButtont.tsx @@ -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 ( - - - - ); -}); + 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 ( + + + + ); + } +); CreateChatButton.displayName = 'CreateChatButton'; diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/DashboardContainerHeaderButtons/DashboardHeaderButtons.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/DashboardContainerHeaderButtons/DashboardHeaderButtons.tsx index 1bf76d379..17b86e5b0 100644 --- a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/DashboardContainerHeaderButtons/DashboardHeaderButtons.tsx +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/DashboardContainerHeaderButtons/DashboardHeaderButtons.tsx @@ -31,7 +31,7 @@ export const DashboardHeaderButtons: React.FC<{ {isEditor && } - + ); diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/DashboardContainerHeaderButtons/DashboardThreeDotMenu.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/DashboardContainerHeaderButtons/DashboardThreeDotMenu.tsx index d8c82130e..bebbb3690 100644 --- a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/DashboardContainerHeaderButtons/DashboardThreeDotMenu.tsx +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/DashboardContainerHeaderButtons/DashboardThreeDotMenu.tsx @@ -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, diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/MetricContainerHeaderButtons.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/MetricContainerHeaderButtons.tsx index 652f09401..2e0fc08c2 100644 --- a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/MetricContainerHeaderButtons.tsx +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/MetricContainerHeaderButtons.tsx @@ -41,7 +41,7 @@ export const MetricContainerHeaderButtons: React.FC = {isEffectiveOwner && } - + ); diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/MetricThreeDotMenu.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/MetricThreeDotMenu.tsx index cff9feef9..9d41e681d 100644 --- a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/MetricThreeDotMenu.tsx +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/MetricThreeDotMenu.tsx @@ -104,7 +104,6 @@ export const ThreeDotMenuButton = React.memo(({ metricId }: { metricId: string } deleteMetricMenu, downloadCSVMenu, downloadPNGMenu, - metricId, openSuccessMessage, onSetSelectedFile, versionHistoryItems,