default file passthrough

This commit is contained in:
Nate Kelley 2025-01-24 16:59:38 -07:00
parent de0d46bb2e
commit b3af7267ef
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
14 changed files with 66 additions and 92 deletions

View File

@ -1,18 +1,12 @@
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 }) => {
export const ChatContainer: React.FC<ChatContainerProps> = React.memo(({}) => {
const chatContentRef = useRef<HTMLDivElement>(null);
const scroll = useScroll(chatContentRef);
@ -22,15 +16,12 @@ export const ChatContainer: React.FC<ChatContainerProps> = React.memo(
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} />
<ChatHeader showScrollOverflow={showScrollOverflow} />
<ChatContent chatContentRef={chatContentRef} />
</div>
);
}
);
});
ChatContainer.displayName = 'ChatContainer';

View File

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

View File

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

View File

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

View File

@ -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" />
}
]
};

View File

@ -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"

View File

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

View File

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

View File

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

View File

@ -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';

View File

@ -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';

View File

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

View File

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

View File

@ -34,8 +34,7 @@ export enum AppChatMessageFileType {
Dataset = 'dataset',
Collection = 'collection',
Metric = 'metric',
Dashboard = 'dashboard',
Chat = 'chat'
Dashboard = 'dashboard'
}
export type AppChatMessageFile = {