mirror of https://github.com/buster-so/buster.git
default file passthrough
This commit is contained in:
parent
de0d46bb2e
commit
b3af7267ef
|
@ -1,36 +1,27 @@
|
|||
import React, { useMemo, useRef } from 'react';
|
||||
import type { ChatSplitterProps } from '../ChatLayout';
|
||||
import { ChatHeader } from './ChatHeader';
|
||||
import { SelectedFile } from '../interfaces';
|
||||
import { ChatContent } from './ChatContent';
|
||||
import { useScroll } from 'ahooks';
|
||||
|
||||
interface ChatContainerProps {
|
||||
chatContent: ChatSplitterProps['chatContent'];
|
||||
selectedFile: SelectedFile | undefined;
|
||||
isPureFile: boolean;
|
||||
}
|
||||
interface ChatContainerProps {}
|
||||
|
||||
export const ChatContainer: React.FC<ChatContainerProps> = React.memo(
|
||||
({ chatContent, selectedFile, isPureFile }) => {
|
||||
const chatContentRef = useRef<HTMLDivElement>(null);
|
||||
const scroll = useScroll(chatContentRef);
|
||||
export const ChatContainer: React.FC<ChatContainerProps> = React.memo(({}) => {
|
||||
const chatContentRef = useRef<HTMLDivElement>(null);
|
||||
const scroll = useScroll(chatContentRef);
|
||||
|
||||
const showScrollOverflow = useMemo(() => {
|
||||
if (!chatContentRef.current || !scroll) return false;
|
||||
const trigger = 50;
|
||||
return scroll.top > trigger;
|
||||
}, [chatContentRef, scroll?.top]);
|
||||
const showScrollOverflow = useMemo(() => {
|
||||
if (!chatContentRef.current || !scroll) return false;
|
||||
const trigger = 50;
|
||||
return scroll.top > trigger;
|
||||
}, [chatContentRef, scroll?.top]);
|
||||
|
||||
if (isPureFile) return null;
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col">
|
||||
<ChatHeader selectedFile={selectedFile} showScrollOverflow={showScrollOverflow} />
|
||||
<ChatContent chatContentRef={chatContentRef} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col">
|
||||
<ChatHeader showScrollOverflow={showScrollOverflow} />
|
||||
<ChatContent chatContentRef={chatContentRef} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
ChatContainer.displayName = 'ChatContainer';
|
||||
|
|
|
@ -21,12 +21,10 @@ const colors = [
|
|||
export const ChatContent: React.FC<{ chatContentRef: React.RefObject<HTMLDivElement> }> = ({
|
||||
chatContentRef
|
||||
}) => {
|
||||
const hasFile = useChatSplitterContextSelector((state) => state.hasFile);
|
||||
|
||||
return (
|
||||
<div ref={chatContentRef} className="h-full w-full overflow-y-auto">
|
||||
<div className="mx-auto max-w-[600px]">
|
||||
{Array.from({ length: 350 }).map((_, index) => (
|
||||
{Array.from({ length: 150 }).map((_, index) => (
|
||||
<ChatContentItem key={index} index={index} />
|
||||
))}
|
||||
</div>
|
||||
|
|
|
@ -7,9 +7,8 @@ import { ChatHeaderOptions } from './ChatHeaderOptions';
|
|||
import { ChatHeaderTitle } from './ChatHeaderTitle';
|
||||
|
||||
export const ChatHeader: React.FC<{
|
||||
selectedFile: SelectedFile | undefined;
|
||||
showScrollOverflow: boolean;
|
||||
}> = React.memo(({ selectedFile, showScrollOverflow }) => {
|
||||
}> = React.memo(({ showScrollOverflow }) => {
|
||||
const { cx, styles } = useStyles();
|
||||
const hasFile = useChatSplitterContextSelector((state) => state.hasFile);
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ export const ChatContainerHeaderDropdown: React.FC<{
|
|||
const selectedFileType = useChatSplitterContextSelector((state) => state.selectedFileType);
|
||||
|
||||
const menuItem: MenuProps['items'] = useMemo(() => {
|
||||
if (!selectedFileType) return [] as MenuProps['items'];
|
||||
if (!selectedFileType || !(selectedFileType in HeaderOptionsRecord))
|
||||
return [] as MenuProps['items'];
|
||||
return HeaderOptionsRecord[selectedFileType]();
|
||||
}, [selectedFileType]);
|
||||
|
||||
|
|
|
@ -30,12 +30,5 @@ export const HeaderOptionsRecord: Record<AppChatMessageFileType, () => MenuProps
|
|||
key: 'delete',
|
||||
icon: <AppMaterialIcons icon="delete" />
|
||||
}
|
||||
],
|
||||
chat: () => [
|
||||
{
|
||||
label: 'Delete',
|
||||
key: 'delete',
|
||||
icon: <AppMaterialIcons icon="delete" />
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
|
@ -10,56 +10,52 @@ import { SelectedFile } from './interfaces';
|
|||
import { useUpdateEffect, useUpdateLayoutEffect } from 'ahooks';
|
||||
|
||||
export interface ChatSplitterProps {
|
||||
chatContent?: React.ReactNode;
|
||||
showChatCollapse?: boolean;
|
||||
defaultShowLayout?: 'chat' | 'file' | 'both';
|
||||
defaultSelectedFile?: SelectedFile;
|
||||
selectedLayout?: 'chat' | 'file' | 'both';
|
||||
selectedFile?: SelectedFile;
|
||||
}
|
||||
|
||||
export const ChatLayout: React.FC<ChatSplitterProps> = React.memo(
|
||||
({ defaultSelectedFile, defaultShowLayout = 'chat', chatContent }) => {
|
||||
({ selectedFile, selectedLayout = 'chat' }) => {
|
||||
const appSplitterRef = useRef<AppSplitterRef>(null);
|
||||
const [isPureFile, setIsPureFile] = useState(defaultShowLayout === 'file');
|
||||
const [isPureFile, setIsPureFile] = useState(selectedLayout === 'file');
|
||||
|
||||
const defaultSplitterLayout = useMemo(() => {
|
||||
if (defaultShowLayout === 'chat') return ['100%', '0%'];
|
||||
if (defaultShowLayout === 'file') return ['0%', '100%'];
|
||||
if (selectedLayout === 'chat') return ['100%', '0%'];
|
||||
if (selectedLayout === 'file') return ['0%', '100%'];
|
||||
return ['325px', 'auto'];
|
||||
}, [defaultShowLayout]);
|
||||
}, [selectedLayout]);
|
||||
|
||||
const useChatSplitterProps = useChatLayout({ defaultSelectedFile });
|
||||
const { onSetSelectedFile, selectedFile, hasFile } = useChatSplitterProps;
|
||||
const useChatSplitterProps = useChatLayout({ selectedFile });
|
||||
const { onSetSelectedFile, hasFile, selectedFileId } = useChatSplitterProps;
|
||||
|
||||
useUpdateEffect(() => {
|
||||
if (defaultSelectedFile && appSplitterRef.current) {
|
||||
if (defaultShowLayout === 'chat') {
|
||||
if (appSplitterRef.current) {
|
||||
if (selectedLayout === 'chat') {
|
||||
appSplitterRef.current?.animateWidth('100%', 'left');
|
||||
} else if (defaultShowLayout === 'file') {
|
||||
} else if (selectedLayout === 'file') {
|
||||
appSplitterRef.current?.animateWidth('100%', 'right');
|
||||
} else if (appSplitterRef.current.isRightClosed || appSplitterRef.current.isLeftClosed) {
|
||||
} else if (
|
||||
selectedLayout === 'both' &&
|
||||
(appSplitterRef.current.isRightClosed || appSplitterRef.current.isLeftClosed)
|
||||
) {
|
||||
appSplitterRef.current?.animateWidth('320px', 'left');
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultSelectedFile) onSetSelectedFile(defaultSelectedFile);
|
||||
}, [defaultSelectedFile, defaultShowLayout]);
|
||||
if (selectedFile) onSetSelectedFile(selectedFile);
|
||||
}, [selectedFile, selectedLayout]);
|
||||
|
||||
useUpdateLayoutEffect(() => {
|
||||
if (isPureFile === true) setIsPureFile(defaultShowLayout === 'file');
|
||||
}, [defaultShowLayout]);
|
||||
if (isPureFile === true) setIsPureFile(selectedLayout === 'file');
|
||||
}, [selectedLayout]);
|
||||
|
||||
return (
|
||||
<ChatSplitterContextProvider useChatSplitterProps={useChatSplitterProps}>
|
||||
<AppSplitter
|
||||
ref={appSplitterRef}
|
||||
leftChildren={
|
||||
<ChatContainer
|
||||
selectedFile={selectedFile}
|
||||
chatContent={chatContent}
|
||||
isPureFile={isPureFile}
|
||||
/>
|
||||
}
|
||||
rightChildren={<FileContainer selectedFile={selectedFile} />}
|
||||
leftChildren={isPureFile ? null : <ChatContainer />}
|
||||
rightChildren={!selectedFileId ? null : <FileContainer />}
|
||||
autoSaveId="chat-splitter"
|
||||
defaultLayout={defaultSplitterLayout}
|
||||
preserveSide="left"
|
||||
|
|
|
@ -7,31 +7,31 @@ import React, { PropsWithChildren, useMemo, useState } from 'react';
|
|||
import { SelectedFile } from '../interfaces';
|
||||
|
||||
interface UseChatSplitterProps {
|
||||
defaultSelectedFile: SelectedFile | undefined;
|
||||
selectedFile: SelectedFile | undefined;
|
||||
}
|
||||
|
||||
export const useChatLayout = ({ defaultSelectedFile }: UseChatSplitterProps) => {
|
||||
const [selectedFile, setSelectedFile] =
|
||||
useState<UseChatSplitterProps['defaultSelectedFile']>(defaultSelectedFile);
|
||||
export const useChatLayout = ({ selectedFile: selectedFileProp }: UseChatSplitterProps) => {
|
||||
const [selectedFileId, setSelectedFileId] = useState<string | undefined>(selectedFileProp?.id);
|
||||
|
||||
const hasFile = !!selectedFile;
|
||||
const hasFile = !!selectedFileId;
|
||||
|
||||
const selectedFileTitle: string = useMemo(() => {
|
||||
if (!selectedFile) return '';
|
||||
return selectedFile.type;
|
||||
}, [selectedFile]);
|
||||
console.log('selectedFileId', selectedFileId);
|
||||
if (!selectedFileId) return '';
|
||||
return 'test';
|
||||
}, [selectedFileId]);
|
||||
|
||||
const selectedFileType = selectedFile?.type || null;
|
||||
const selectedFileType = selectedFileProp?.type;
|
||||
|
||||
const onSetSelectedFile = (file: SelectedFile) => {
|
||||
setSelectedFile(file);
|
||||
// setSelectedFileId(file.id);
|
||||
};
|
||||
|
||||
return {
|
||||
selectedFileTitle,
|
||||
selectedFileType,
|
||||
selectedFileId,
|
||||
hasFile,
|
||||
selectedFile,
|
||||
onSetSelectedFile
|
||||
};
|
||||
};
|
||||
|
|
|
@ -2,11 +2,9 @@ import React from 'react';
|
|||
import type { ChatSplitterProps } from '../ChatLayout';
|
||||
import { SelectedFile } from '../interfaces';
|
||||
|
||||
interface FileContainerProps {
|
||||
selectedFile: SelectedFile | undefined;
|
||||
}
|
||||
interface FileContainerProps {}
|
||||
|
||||
export const FileContainer: React.FC<FileContainerProps> = React.memo(({ selectedFile }) => {
|
||||
export const FileContainer: React.FC<FileContainerProps> = React.memo(({}) => {
|
||||
return <div className="h-full w-full bg-green-500">FileContainer</div>;
|
||||
});
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { useParams } from 'next/navigation';
|
|||
import { AppChatMessageFileType } from '@/components/messages/AppChatMessageContainer';
|
||||
import { ChatSplitterProps } from '../ChatLayout';
|
||||
|
||||
export const useDefaultFile = () => {
|
||||
export const useSelectedFileByParams = () => {
|
||||
const { metricId, collectionId, datasetId, dashboardId, chatId } = useParams() as {
|
||||
metricId?: string;
|
||||
collectionId?: string;
|
||||
|
@ -15,15 +15,14 @@ export const useDefaultFile = () => {
|
|||
chatId?: string;
|
||||
};
|
||||
|
||||
const defaultFile: SelectedFile | undefined = useMemo(() => {
|
||||
const selectedFile: SelectedFile | undefined = useMemo(() => {
|
||||
if (metricId) return { id: metricId, type: AppChatMessageFileType.Metric };
|
||||
if (collectionId) return { id: collectionId, type: AppChatMessageFileType.Collection };
|
||||
if (datasetId) return { id: datasetId, type: AppChatMessageFileType.Dataset };
|
||||
if (dashboardId) return { id: dashboardId, type: AppChatMessageFileType.Dashboard };
|
||||
if (chatId) return { id: chatId, type: AppChatMessageFileType.Chat };
|
||||
}, [metricId, collectionId, datasetId, dashboardId, chatId]);
|
||||
|
||||
const defaultLayout: ChatSplitterProps['defaultShowLayout'] = useMemo(() => {
|
||||
const selectedLayout: ChatSplitterProps['selectedLayout'] = useMemo(() => {
|
||||
const hasFileId = metricId || collectionId || datasetId || dashboardId;
|
||||
|
||||
if (chatId) {
|
||||
|
@ -36,5 +35,5 @@ export const useDefaultFile = () => {
|
|||
return 'chat';
|
||||
}, [metricId, collectionId, datasetId, dashboardId, chatId]);
|
||||
|
||||
return { defaultFile, defaultLayout };
|
||||
return { selectedFile, selectedLayout };
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ThreadContentController } from '@/app/app/_controllers/ThreadController';
|
||||
import { AppAssetCheckLayout } from '@/app/app/_layouts';
|
||||
import { AppAssetCheckLayout } from '../../../../_layouts/AppAssetCheckLayout';
|
||||
import { getAppSplitterLayout } from '@/components/layout';
|
||||
import React from 'react';
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ThreadContentController } from '@/app/app/_controllers/ThreadController';
|
||||
import { AppAssetCheckLayout } from '@/app/app/_layouts';
|
||||
import { AppAssetCheckLayout } from '../../../../_layouts/AppAssetCheckLayout';
|
||||
import { getAppSplitterLayout } from '@/components/layout';
|
||||
import React from 'react';
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { DashboardIndividualHeader } from './_DashboardIndividualHeader';
|
||||
import { DashboardIndividualContent } from './_DashboardIndividualContent';
|
||||
import { AppAssetCheckLayout } from '../../_layouts';
|
||||
import { AppAssetCheckLayout } from '../../_layouts/AppAssetCheckLayout';
|
||||
|
||||
export default function DashboardPage({
|
||||
params: { dashboardId }
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
'use client';
|
||||
|
||||
import { ChatLayout, useDefaultFile } from '@chatLayout/index';
|
||||
import { ChatLayout, useSelectedFileByParams } from '@chatLayout/index';
|
||||
import { AppChatMessageFileType } from '@/components/messages/AppChatMessageContainer';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
|
||||
export default function Layout({}: {}) {
|
||||
const { defaultFile, defaultLayout } = useDefaultFile();
|
||||
const { selectedFile, selectedLayout } = useSelectedFileByParams();
|
||||
const router = useRouter();
|
||||
|
||||
useHotkeys('m', () => {
|
||||
|
@ -31,7 +31,7 @@ export default function Layout({}: {}) {
|
|||
|
||||
return (
|
||||
<div className="h-screen w-screen">
|
||||
<ChatLayout defaultShowLayout={defaultLayout} defaultSelectedFile={defaultFile} />
|
||||
<ChatLayout selectedLayout={selectedLayout} selectedFile={selectedFile} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -34,8 +34,7 @@ export enum AppChatMessageFileType {
|
|||
Dataset = 'dataset',
|
||||
Collection = 'collection',
|
||||
Metric = 'metric',
|
||||
Dashboard = 'dashboard',
|
||||
Chat = 'chat'
|
||||
Dashboard = 'dashboard'
|
||||
}
|
||||
|
||||
export type AppChatMessageFile = {
|
||||
|
|
Loading…
Reference in New Issue