select file update

This commit is contained in:
Nate Kelley 2025-01-27 15:48:29 -07:00
parent d5ee691de4
commit be050b3521
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
22 changed files with 274 additions and 61 deletions

View File

@ -0,0 +1,3 @@
export default function Page() {
return <></>;
}

View File

@ -0,0 +1,3 @@
export default function Page() {
return <div className="h-full w-full bg-orange-500">Dashboard swag</div>;
}

View File

@ -0,0 +1,3 @@
export default function Page() {
return <></>;
}

View File

@ -0,0 +1,3 @@
export default function Page() {
return <></>;
}

View File

@ -0,0 +1,3 @@
export default function Page() {
return <></>;
}

View File

@ -0,0 +1,3 @@
export default function Page() {
return <></>;
}

View File

@ -0,0 +1,3 @@
export default function Page() {
return <div className="h-full w-full bg-red-500">Dashboard swag</div>;
}

View File

@ -0,0 +1,3 @@
export default function Page() {
return <></>;
}

View File

@ -0,0 +1,17 @@
'use client';
import React from 'react';
import { ChatLayout, useSelectedFileByParams } from '@chatLayout/index';
export default function Layout({ children }: { children: React.ReactNode }) {
const { selectedFile, selectedLayout, chatId } = useSelectedFileByParams();
return (
<ChatLayout
chatId={chatId}
defaultSelectedLayout={selectedLayout}
defaultSelectedFile={selectedFile}>
{children}
</ChatLayout>
);
}

View File

@ -0,0 +1,3 @@
export default function Page() {
return <></>;
}

View File

@ -1,8 +1,7 @@
import React, { useMemo } from 'react';
import { useChatSplitterContextSelector } from '../../ChatLayoutContext';
import { useRouter } from 'next/navigation';
import Link from 'next/link';
import { AppChatMessageFileType } from '@/components/messages/AppChatMessageContainer';
import type { FileType } from '@/api/buster_socket/chats';
const colors = [
'red-200',
@ -49,11 +48,11 @@ const ChatContentItem = React.memo(({ index }: { index: number }) => {
const link = useMemo(() => {
if (isPureChat) {
return `/test/splitter/chat/${index}`;
return `/app/chat/${index}`;
} else if (isChat && typeOfItem !== 'chat') {
return `/test/splitter/chat/${index}/${typeOfItem}/${index}`;
return `/app/chat/${index}/${typeOfItem}/${index}`;
} else {
return `/test/splitter/${typeOfItem}/${index}`;
return `/app/chat/${typeOfItem}/${index}`;
}
}, [index, typeOfItem, isPureChat, isChat]);
@ -61,7 +60,7 @@ const ChatContentItem = React.memo(({ index }: { index: number }) => {
if (isPureChat) {
router.push(link);
} else {
onSetSelectedFile({ id: index.toString(), type: typeOfItem as AppChatMessageFileType });
onSetSelectedFile({ id: index.toString(), type: typeOfItem as FileType });
}
};

View File

@ -7,7 +7,7 @@ import { FileContainer } from './FileContainer';
import { ChatSplitterContextProvider } from './ChatLayoutContext';
import { useChatLayout } from './ChatLayoutContext';
import { SelectedFile } from './interfaces';
import { useUpdateEffect, useUpdateLayoutEffect } from 'ahooks';
import { useAutoSetLayout, useDefaultSplitterLayout } from './hooks';
export interface ChatSplitterProps {
showChatCollapse?: boolean;
@ -20,13 +20,8 @@ export interface ChatSplitterProps {
export const ChatLayout: React.FC<ChatSplitterProps> = React.memo(
({ defaultSelectedFile, defaultSelectedLayout = 'chat', children, chatId }) => {
const appSplitterRef = useRef<AppSplitterRef>(null);
const [isPureFile, setIsPureFile] = useState(defaultSelectedLayout === 'file');
const defaultSplitterLayout = useMemo(() => {
if (defaultSelectedLayout === 'chat') return ['100%', '0%'];
if (defaultSelectedLayout === 'file') return ['0%', '100%'];
return ['325px', 'auto'];
}, [defaultSelectedLayout]);
const defaultSplitterLayout = useDefaultSplitterLayout({ defaultSelectedLayout });
const useChatSplitterProps = useChatLayout({
appSplitterRef,
@ -34,24 +29,8 @@ export const ChatLayout: React.FC<ChatSplitterProps> = React.memo(
defaultSelectedLayout,
chatId
});
const { onSetSelectedFile, selectedFileType, selectedLayout, hasFile } = useChatSplitterProps;
useUpdateEffect(() => {
if (appSplitterRef.current) {
const { animateWidth, isSideClosed } = appSplitterRef.current;
if (selectedLayout === 'chat') {
animateWidth('100%', 'left');
} else if (selectedLayout === 'file') {
animateWidth('100%', 'right');
} else if (selectedLayout === 'both' && (isSideClosed('right') || isSideClosed('left'))) {
animateWidth('320px', 'left');
}
}
}, [selectedLayout]);
useUpdateLayoutEffect(() => {
if (isPureFile === true) setIsPureFile(selectedLayout === 'file');
}, [selectedLayout]);
const { hasFile, isPureChat, isPureFile } = useChatSplitterProps;
return (
<ChatSplitterContextProvider useChatSplitterProps={useChatSplitterProps}>
@ -61,12 +40,13 @@ export const ChatLayout: React.FC<ChatSplitterProps> = React.memo(
rightChildren={<FileContainer children={children} />}
autoSaveId="chat-splitter"
defaultLayout={defaultSplitterLayout}
rightHidden={isPureChat}
preserveSide="left"
leftPanelMinSize={hasFile ? 250 : undefined}
leftPanelMinSize={hasFile ? 225 : undefined}
/>
</ChatSplitterContextProvider>
);
}
);
ChatLayout.displayName = 'ChatSplitter';
ChatLayout.displayName = 'ChatLayout';

View File

@ -3,13 +3,15 @@ import {
createContext,
useContextSelector
} from '@fluentui/react-context-selector';
import React, { PropsWithChildren, useLayoutEffect, useMemo, useState } from 'react';
import React, { PropsWithChildren, useMemo, useState, useTransition } from 'react';
import type { SelectedFile } from '../interfaces';
import type { ChatSplitterProps } from '../ChatLayout';
import { useMemoizedFn } from 'ahooks';
import { useRouter } from 'next/navigation';
import type { AppSplitterRef } from '@/components/layout';
import { AppChatMessageFileType } from '@/components/messages/AppChatMessageContainer';
import { createChatAssetRoute, createFileRoute } from './helpers';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import { DEFAULT_CHAT_OPTION } from './config';
import { useAutoSetLayout } from '../hooks';
interface UseChatSplitterProps {
defaultSelectedFile: SelectedFile | undefined;
@ -24,49 +26,62 @@ export const useChatLayout = ({
appSplitterRef,
chatId
}: UseChatSplitterProps) => {
const router = useRouter();
const [isPending, startTransition] = useTransition();
const onChangePage = useAppLayoutContextSelector((state) => state.onChangePage);
const selectedLayout = defaultSelectedLayout;
const selectedFileId = defaultSelectedFile?.id;
const selectedFileType = defaultSelectedFile?.type;
const hasFile = !!selectedFileId;
const [selectedLayout, setSelectedLayout] = useState(defaultSelectedLayout);
const [selectedFile, setSelectedFile] = useState(defaultSelectedFile);
const selectedFileTitle: string = useMemo(() => {
if (!selectedFileId) return '';
return 'test';
}, [selectedFileId]);
const animateOpenSplitter = useMemoizedFn((side: 'left' | 'right' | 'both') => {
if (appSplitterRef.current) {
const { animateWidth, isSideClosed } = appSplitterRef.current;
if (side === 'left') {
animateWidth('100%', 'left');
} else if (side === 'right') {
animateWidth('100%', 'right');
} else if (side === 'both' && (isSideClosed('right') || isSideClosed('left'))) {
animateWidth(DEFAULT_CHAT_OPTION, 'left');
}
}
});
const onSetSelectedFile = useMemoizedFn((file: SelectedFile) => {
const isChatView = defaultSelectedLayout === 'chat' || defaultSelectedLayout === 'both';
const fileType = file.type;
const fileId = file.id;
if (isChatView && chatId) {
const routeRecord: Record<AppChatMessageFileType, string> = {
collection: `/test/splitter/chat/${chatId}/collection/${file.id}`,
dataset: `/test/splitter/chat/${chatId}/dataset/${file.id}`,
metric: `/test/splitter/chat/${chatId}/metric/${file.id}`,
dashboard: `/test/splitter/chat/${chatId}/dashboard/${file.id}`
};
if (routeRecord[fileType]) router.push(routeRecord[fileType]);
} else {
router.push(`/test/splitter/${fileType}/${fileId}`);
const route =
isChatView && chatId
? createChatAssetRoute({ chatId, assetId: fileId, type: fileType })
: createFileRoute({ assetId: fileId, type: fileType });
if (route) {
onChangePage(route);
setIsPureChat(false);
startTransition(() => {
animateOpenSplitter('both');
});
}
});
const onCollapseFileClick = useMemoizedFn((close?: boolean) => {
const isCloseAction = close ?? selectedLayout === 'both';
if (isCloseAction) {
setSelectedLayout('chat');
animateOpenSplitter('left');
} else {
setSelectedLayout('both');
appSplitterRef.current?.animateWidth('320px', 'left');
animateOpenSplitter('both');
}
});
useLayoutEffect(() => {
if (defaultSelectedLayout) setSelectedLayout(defaultSelectedLayout);
}, [defaultSelectedLayout]);
const { setIsPureChat, isPureFile, isPureChat } = useAutoSetLayout({
defaultSelectedLayout,
selectedLayout
});
return {
selectedFileTitle,
@ -74,9 +89,11 @@ export const useChatLayout = ({
selectedLayout,
selectedFileId,
hasFile,
isPureFile,
isPureChat,
onSetSelectedFile,
onCollapseFileClick
onCollapseFileClick,
animateOpenSplitter
};
};

View File

@ -0,0 +1 @@
export const DEFAULT_CHAT_OPTION = '320px';

View File

@ -0,0 +1,73 @@
import type { FileType } from '@/api/buster_socket/chats';
import { BusterRoutes, createBusterRoute } from '@/routes';
const chatRouteRecord: Record<FileType, (chatId: string, assetId: string) => string> = {
collection: (chatId, assetId) =>
createBusterRoute({
route: BusterRoutes.APP_CHAT_ID_COLLECTION_ID,
chatId,
collectionId: assetId
}),
dataset: (chatId, assetId) =>
createBusterRoute({
route: BusterRoutes.APP_CHAT_ID_DATASET_ID,
chatId,
datasetId: assetId
}),
metric: (chatId, assetId) =>
createBusterRoute({
route: BusterRoutes.APP_CHAT_ID_METRIC_ID,
chatId,
metricId: assetId
}),
dashboard: (chatId, assetId) =>
createBusterRoute({
route: BusterRoutes.APP_CHAT_ID_DASHBOARD_ID,
chatId,
dashboardId: assetId
}),
term: (chatId, assetId) =>
createBusterRoute({
route: BusterRoutes.APP_CHAT_ID_TERM_ID,
chatId,
termId: assetId
}),
value: (chatId, assetId) =>
createBusterRoute({
route: BusterRoutes.APP_CHAT_ID_VALUE_ID,
chatId,
valueId: assetId
})
};
export const createChatAssetRoute = ({
chatId,
assetId,
type
}: {
chatId: string;
assetId: string;
type: FileType;
}) => {
const routeBuilder = chatRouteRecord[type];
if (!routeBuilder) return '';
return routeBuilder(chatId, assetId);
};
const fileRouteRecord: Record<FileType, (assetId: string) => string> = {
collection: (assetId) =>
createBusterRoute({ route: BusterRoutes.APP_COLLECTIONS_ID, collectionId: assetId }),
dataset: (assetId) =>
createBusterRoute({ route: BusterRoutes.APP_DATASETS_ID, datasetId: assetId }),
metric: (assetId) => createBusterRoute({ route: BusterRoutes.APP_METRIC_ID, metricId: assetId }),
dashboard: (assetId) =>
createBusterRoute({ route: BusterRoutes.APP_DASHBOARD_ID, dashboardId: assetId }),
term: (assetId) => createBusterRoute({ route: BusterRoutes.APP_TERMS_ID, termId: assetId }),
value: (assetId) => createBusterRoute({ route: BusterRoutes.APP_VALUE_ID, valueId: assetId })
};
export const createFileRoute = ({ assetId, type }: { assetId: string; type: FileType }) => {
const routeBuilder = fileRouteRecord[type];
if (!routeBuilder) return '';
return routeBuilder(assetId);
};

View File

@ -1 +1,3 @@
export * from './useDefaultFile';
export * from './useAutoSetLayout';
export * from './useDefaultSplitterLayout';

View File

@ -0,0 +1,24 @@
import { useUpdateLayoutEffect } from 'ahooks';
import { useState } from 'react';
export const useAutoSetLayout = ({
defaultSelectedLayout,
selectedLayout
}: {
defaultSelectedLayout: 'chat' | 'file' | 'both' | undefined;
selectedLayout: 'chat' | 'file' | 'both' | undefined;
}): {
isPureFile: boolean;
isPureChat: boolean;
setIsPureChat: (value: boolean) => void;
} => {
const [isPureFile, setIsPureFile] = useState(defaultSelectedLayout === 'file');
const [isPureChat, setIsPureChat] = useState(defaultSelectedLayout === 'chat');
useUpdateLayoutEffect(() => {
if (isPureFile === true) setIsPureFile(selectedLayout === 'file');
if (isPureChat === true) setIsPureChat(selectedLayout === 'chat');
}, [selectedLayout]);
return { isPureFile, isPureChat, setIsPureChat };
};

View File

@ -0,0 +1,15 @@
import { useMemo } from 'react';
export const useDefaultSplitterLayout = ({
defaultSelectedLayout
}: {
defaultSelectedLayout: 'chat' | 'file' | 'both';
}) => {
const defaultSplitterLayout = useMemo(() => {
if (defaultSelectedLayout === 'chat') return ['100%', '0%'];
if (defaultSelectedLayout === 'file') return ['0%', '100%'];
return ['325px', 'auto'];
}, [defaultSelectedLayout]);
return defaultSplitterLayout;
};

View File

@ -1,6 +1,6 @@
import type { AppChatMessageFileType } from '@/components/messages/AppChatMessageContainer';
import type { FileType } from '@/api/buster_socket/chats';
export type SelectedFile = {
id: string;
type: AppChatMessageFileType;
type: FileType;
};

View File

@ -39,8 +39,12 @@ export const useAppLayout = () => {
return createBusterRoute(params);
});
const onChangePage = useMemoizedFn((params: BusterRoutesWithArgsRoute) => {
push(createBusterRoute(params));
const onChangePage = useMemoizedFn((params: BusterRoutesWithArgsRoute | string) => {
if (typeof params === 'string') {
push(params);
} else {
push(createBusterRoute(params));
}
});
return {

View File

@ -149,3 +149,13 @@ export const useBusterChatIndividual = ({ chatId }: { chatId: string }) => {
onSetSelectedAssetId
};
};
export const useBusterChatAssetIndividual = ({
chatId,
assetId,
type
}: {
chatId: string;
assetId: string;
type: FileType;
}) => {};

View File

@ -12,6 +12,7 @@ export enum BusterAppRoutes {
APP_LOGS = '/app/logs',
APP_DATASETS = '/app/datasets',
APP_DATASETS_ID = '/app/datasets/:datasetId',
APP_DATASETS_ID_OVERVIEW = '/app/datasets/:datasetId/overview',
APP_DATASETS_ID_PERMISSIONS_OVERVIEW = '/app/datasets/:datasetId/permissions/overview',
APP_DATASETS_ID_PERMISSIONS_PERMISSION_GROUPS = '/app/datasets/:datasetId/permissions/permission-groups',
@ -20,6 +21,18 @@ export enum BusterAppRoutes {
APP_DATASETS_ID_EDITOR = '/app/datasets/:datasetId/editor',
APP_TERMS = '/app/terms',
APP_TERMS_ID = '/app/terms/:termId',
//NEW CHAT
APP_CHAT_ID = '/app/chat/:chatId',
APP_CHAT_ID_METRIC_ID = '/app/chat/:chatId/metric/:metricId',
APP_CHAT_ID_COLLECTION_ID = '/app/chat/:chatId/collection/:collectionId',
APP_CHAT_ID_DASHBOARD_ID = '/app/chat/:chatId/dashboard/:dashboardId',
APP_CHAT_ID_DATASET_ID = '/app/chat/:chatId/dataset/:datasetId',
APP_CHAT_ID_TERM_ID = '/app/chat/:chatId/term/:termId',
APP_CHAT_ID_VALUE_ID = '/app/chat/:chatId/value/:valueId',
APP_METRIC_ID = '/app/metric/:metricId',
APP_VALUE_ID = '/app/value/:valueId',
SETTINGS = '/app/settings',
SETTINGS_GENERAL = '/app/settings/general',
SETTINGS_PERMISSIONS = '/app/settings/permissions',
@ -193,4 +206,35 @@ export type BusterAppRoutesWithArgs = {
};
[BusterAppRoutes.APP_SETTINGS_ATTRIBUTES]: { route: BusterAppRoutes.APP_SETTINGS_ATTRIBUTES };
[BusterAppRoutes.APP_SETTINGS_SECURITY]: { route: BusterAppRoutes.APP_SETTINGS_SECURITY };
[BusterAppRoutes.APP_CHAT_ID]: { route: BusterAppRoutes.APP_CHAT_ID; chatId: string };
[BusterAppRoutes.APP_CHAT_ID_METRIC_ID]: {
route: BusterAppRoutes.APP_CHAT_ID_METRIC_ID;
chatId: string;
metricId: string;
};
[BusterAppRoutes.APP_CHAT_ID_COLLECTION_ID]: {
route: BusterAppRoutes.APP_CHAT_ID_COLLECTION_ID;
chatId: string;
collectionId: string;
};
[BusterAppRoutes.APP_CHAT_ID_DASHBOARD_ID]: {
route: BusterAppRoutes.APP_CHAT_ID_DASHBOARD_ID;
chatId: string;
dashboardId: string;
};
[BusterAppRoutes.APP_CHAT_ID_DATASET_ID]: {
route: BusterAppRoutes.APP_CHAT_ID_DATASET_ID;
chatId: string;
datasetId: string;
};
[BusterAppRoutes.APP_CHAT_ID_TERM_ID]: {
route: BusterAppRoutes.APP_CHAT_ID_TERM_ID;
chatId: string;
termId: string;
};
[BusterAppRoutes.APP_CHAT_ID_VALUE_ID]: {
route: BusterAppRoutes.APP_CHAT_ID_VALUE_ID;
chatId: string;
valueId: string;
};
};