diff --git a/web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/collection/[collectionId]/page.tsx b/web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/collections/[collectionId]/page.tsx similarity index 100% rename from web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/collection/[collectionId]/page.tsx rename to web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/collections/[collectionId]/page.tsx diff --git a/web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/dashboard/[dashboardId]/page.tsx b/web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/dashboards/[dashboardId]/page.tsx similarity index 100% rename from web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/dashboard/[dashboardId]/page.tsx rename to web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/dashboards/[dashboardId]/page.tsx diff --git a/web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/dataset/[datasetId]/page.tsx b/web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/datasets/[datasetId]/page.tsx similarity index 100% rename from web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/dataset/[datasetId]/page.tsx rename to web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/datasets/[datasetId]/page.tsx diff --git a/web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/metric/[metricId]/page.tsx b/web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/metrics/[metricId]/page.tsx similarity index 100% rename from web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/metric/[metricId]/page.tsx rename to web/src/app/app/(primary_layout)/(chat_experience)/chats/[chatId]/metrics/[metricId]/page.tsx diff --git a/web/src/hooks/index.ts b/web/src/hooks/index.ts index 0b8811100..c1a4ca807 100644 --- a/web/src/hooks/index.ts +++ b/web/src/hooks/index.ts @@ -20,3 +20,4 @@ export * from './useSet'; export * from './useUpdateLayoutEffect'; export * from './useScroll'; export * from './useUpdateEffect'; +export * from './useWhyDidYouUpdate'; diff --git a/web/src/hooks/useWhyDidYouUpdate.ts b/web/src/hooks/useWhyDidYouUpdate.ts new file mode 100644 index 000000000..c8328574f --- /dev/null +++ b/web/src/hooks/useWhyDidYouUpdate.ts @@ -0,0 +1,31 @@ +'use client'; + +import { useEffect, useRef } from 'react'; + +export type IProps = Record; + +export function useWhyDidYouUpdate(componentName: string, props: IProps) { + const prevProps = useRef({}); + + useEffect(() => { + if (prevProps.current) { + const allKeys = Object.keys({ ...prevProps.current, ...props }); + const changedProps: IProps = {}; + + allKeys.forEach((key) => { + if (!Object.is(prevProps.current[key], props[key])) { + changedProps[key] = { + from: prevProps.current[key], + to: props[key] + }; + } + }); + + if (Object.keys(changedProps).length) { + console.log('[why-did-you-update]', componentName, changedProps); + } + } + + prevProps.current = props; + }); +} diff --git a/web/src/layouts/ChatLayout/ChatContext/ChatContext.tsx b/web/src/layouts/ChatLayout/ChatContext/ChatContext.tsx index b4ca43148..737ea6088 100644 --- a/web/src/layouts/ChatLayout/ChatContext/ChatContext.tsx +++ b/web/src/layouts/ChatLayout/ChatContext/ChatContext.tsx @@ -13,7 +13,7 @@ const useChatIndividualContext = ({ onSetSelectedFile }: { chatId?: string; - selectedFile?: SelectedFile; + selectedFile: SelectedFile | null; onSetSelectedFile: (file: SelectedFile) => void; }) => { const selectedFileId = selectedFile?.id; @@ -90,7 +90,7 @@ export const ChatContextProvider = React.memo( children }: PropsWithChildren<{ chatId: string | undefined; - selectedFile: SelectedFile | undefined; + selectedFile: SelectedFile | null; onSetSelectedFile: (file: SelectedFile) => void; }>) => { const useChatContextValue = useChatIndividualContext({ diff --git a/web/src/layouts/ChatLayout/hooks/useSelectedFileAndLayout/parsePathnameSegments.ts b/web/src/layouts/ChatLayout/hooks/useSelectedFileAndLayout/parsePathnameSegments.ts index 5db862d7d..0f7ff5b44 100644 --- a/web/src/layouts/ChatLayout/hooks/useSelectedFileAndLayout/parsePathnameSegments.ts +++ b/web/src/layouts/ChatLayout/hooks/useSelectedFileAndLayout/parsePathnameSegments.ts @@ -7,6 +7,10 @@ export interface ChatURLParsed { messageId?: string; } +/* +This file is a hack because nextjs was not parsing the params with the useParams hook. Maybe future nextjs will fix this. +*/ + export const parsePathnameSegments = (pathname: string): ChatURLParsed => { const params: ChatURLParsed = {}; diff --git a/web/src/layouts/ChatLayout/hooks/useSelectedFileAndLayout/useSelectedFileAndLayout.ts b/web/src/layouts/ChatLayout/hooks/useSelectedFileAndLayout/useSelectedFileAndLayout.ts index 59d5cba5d..7b0bb6631 100644 --- a/web/src/layouts/ChatLayout/hooks/useSelectedFileAndLayout/useSelectedFileAndLayout.ts +++ b/web/src/layouts/ChatLayout/hooks/useSelectedFileAndLayout/useSelectedFileAndLayout.ts @@ -40,27 +40,34 @@ export const useSelectedFileAndLayout = ({ ); const onSetSelectedFile = useMemoizedFn(async (file: SelectedFile | null) => { - const fileType = file?.type; - const fileId = file?.id; - const isSameAsCurrentFile = selectedFile?.id === fileId; + const isSameAsCurrentFile = file?.id === selectedFile?.id; + + // Handle file deselection or invalid file data + if (!file?.type || !file?.id || !chatId || isSameAsCurrentFile) { + const route = chatId + ? createChatRoute(chatId) + : createBusterRoute({ route: BusterRoutes.APP_HOME }); + + setSelectedFile(null); + await onChangePage(route); - if (!file || !fileType || !fileId || !chatId) { if (chatId) { - await onChangePage(createChatRoute(chatId)); - setSelectedFile(null); animateOpenSplitter('left'); - } else { - await onChangePage(createBusterRoute({ route: BusterRoutes.APP_HOME })); } return; } - const route = isSameAsCurrentFile - ? createChatRoute(chatId) - : createChatAssetRoute({ chatId, assetId: fileId, type: fileType }); + // Handle valid file selection + const route = createChatAssetRoute({ + chatId, + assetId: file.id, + type: file.type + }); + setRenderViewLayoutKey('both'); - setSelectedFile(isSameAsCurrentFile ? null : file); + setSelectedFile(file); await onChangePage(route); + startTransition(() => { onChangePage(route); //this is hack for now... animateOpenSplitter(isSameAsCurrentFile ? 'left' : 'both'); diff --git a/web/src/routes/busterRoutes/busterAppRoutes.ts b/web/src/routes/busterRoutes/busterAppRoutes.ts index d48add01b..b6a63fe7f 100644 --- a/web/src/routes/busterRoutes/busterAppRoutes.ts +++ b/web/src/routes/busterRoutes/busterAppRoutes.ts @@ -27,10 +27,10 @@ export enum BusterAppRoutes { APP_CHAT = '/app/chats', APP_CHAT_ID = '/app/chats/:chatId', APP_CHAT_ID_REASONING_ID = '/app/chats/:chatId/reasoning/:messageId', - APP_CHAT_ID_METRIC_ID = '/app/chats/:chatId/metric/:metricId', - APP_CHAT_ID_COLLECTION_ID = '/app/chats/:chatId/collection/:collectionId', - APP_CHAT_ID_DASHBOARD_ID = '/app/chats/:chatId/dashboard/:dashboardId', - APP_CHAT_ID_DATASET_ID = '/app/chats/:chatId/dataset/:datasetId', + APP_CHAT_ID_METRIC_ID = '/app/chats/:chatId/metrics/:metricId', + APP_CHAT_ID_COLLECTION_ID = '/app/chats/:chatId/collections/:collectionId', + APP_CHAT_ID_DASHBOARD_ID = '/app/chats/:chatId/dashboards/:dashboardId', + APP_CHAT_ID_DATASET_ID = '/app/chats/:chatId/datasets/:datasetId', APP_CHAT_ID_TERM_ID = '/app/chats/:chatId/term/:termId', APP_CHAT_ID_VALUE_ID = '/app/chats/:chatId/value/:valueId', APP_VALUE_ID = '/app/value/:valueId',