update some grid layout stuff

This commit is contained in:
Nate Kelley 2025-03-11 17:01:39 -06:00
parent 8c43ca0403
commit f7b8d87c01
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
22 changed files with 191 additions and 120 deletions

2
web/package-lock.json generated
View File

@ -62,7 +62,7 @@
"prettier-plugin-tailwindcss": "^0.6.11", "prettier-plugin-tailwindcss": "^0.6.11",
"react": "^18", "react": "^18",
"react-color": "^2.19.3", "react-color": "^2.19.3",
"react-data-grid": "^7.0.0-beta.48", "react-data-grid": "^7.0.0-beta.47",
"react-day-picker": "^9.6.1", "react-day-picker": "^9.6.1",
"react-dom": "^18", "react-dom": "^18",
"react-hotkeys-hook": "^4.6.1", "react-hotkeys-hook": "^4.6.1",

View File

@ -70,7 +70,7 @@
"prettier-plugin-tailwindcss": "^0.6.11", "prettier-plugin-tailwindcss": "^0.6.11",
"react": "^18", "react": "^18",
"react-color": "^2.19.3", "react-color": "^2.19.3",
"react-data-grid": "^7.0.0-beta.48", "react-data-grid": "^7.0.0-beta.47",
"react-day-picker": "^9.6.1", "react-day-picker": "^9.6.1",
"react-dom": "^18", "react-dom": "^18",
"react-hotkeys-hook": "^4.6.1", "react-hotkeys-hook": "^4.6.1",

View File

@ -14,24 +14,34 @@ import type { GetMetricParams, ListMetricsParams } from './interfaces';
import { upgradeMetricToIMetric } from '@/lib/chat'; import { upgradeMetricToIMetric } from '@/lib/chat';
import { queryKeys } from '@/api/query_keys'; import { queryKeys } from '@/api/query_keys';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useBusterAssetsContextSelector } from '@/context/Assets/BusterAssetsProvider';
export const useGetMetric = (params: GetMetricParams) => { export const useGetMetric = (params: GetMetricParams) => {
const queryClient = useQueryClient();
const setAssetPasswordError = useBusterAssetsContextSelector(
(state) => state.setAssetPasswordError
);
const queryFn = useMemoizedFn(async () => { const queryFn = useMemoizedFn(async () => {
const result = await getMetric(params); const result = await getMetric(params);
return upgradeMetricToIMetric(result, null); const oldMetric = queryClient.getQueryData(queryKeys.metricsGetMetric(params.id).queryKey);
return upgradeMetricToIMetric(result, oldMetric || null);
}); });
return useQuery({ return useQuery({
...queryKeys.useMetricsGetMetric(params.id), ...queryKeys.metricsGetMetric(params.id),
queryFn, throwOnError: (error, query) => {
enabled: false //this is handle via a socket query? maybe it should not be? setAssetPasswordError(params.id, error.message || 'An error occurred');
return false;
},
queryFn
}); });
}; };
export const prefetchGetMetric = async (params: GetMetricParams, queryClientProp?: QueryClient) => { export const prefetchGetMetric = async (params: GetMetricParams, queryClientProp?: QueryClient) => {
const queryClient = queryClientProp || new QueryClient(); const queryClient = queryClientProp || new QueryClient();
await queryClient.prefetchQuery({ await queryClient.prefetchQuery({
...queryKeys.useMetricsGetMetric(params.id), ...queryKeys.metricsGetMetric(params.id),
queryFn: async () => { queryFn: async () => {
const result = await getMetric_server(params); const result = await getMetric_server(params);
return upgradeMetricToIMetric(result, null); return upgradeMetricToIMetric(result, null);

View File

@ -9,18 +9,22 @@ import type {
export const getMetric = async ({ id, password }: GetMetricParams) => { export const getMetric = async ({ id, password }: GetMetricParams) => {
return mainApi return mainApi
.get<BusterMetric>(`/metrics/get`, { .get<BusterMetric>(`/metrics/${id}`, {
params: { id, ...(password && { password }) } params: { id, ...(password && { password }) }
}) })
.then((res) => res.data); .then((res) => res.data);
}; };
export const getMetric_server = async ({ id, password }: GetMetricParams) => { export const getMetric_server = async ({ id, password }: GetMetricParams) => {
return await serverFetch<BusterMetric>(`/metrics/get`, { return await serverFetch<BusterMetric>(`/metrics/${id}`, {
params: { id, ...(password && { password }) } params: { ...(password && { password }) }
}); });
}; };
export const getMetricData = async ({ id }: { id: string }) => {
return mainApi.get<BusterMetricData>(`/metrics/${id}/data`).then((res) => res.data);
};
export const listMetrics = async (params: ListMetricsParams) => { export const listMetrics = async (params: ListMetricsParams) => {
return mainApi.get<BusterMetricListItem[]>('/metrics/list', { params }).then((res) => res.data); return mainApi.get<BusterMetricListItem[]>('/metrics/list', { params }).then((res) => res.data);
}; };
@ -29,10 +33,6 @@ export const listMetrics_server = async (params: ListMetricsParams) => {
return await serverFetch<BusterMetricListItem[]>('/metrics/list', { params }); return await serverFetch<BusterMetricListItem[]>('/metrics/list', { params });
}; };
export const getMetricData = async ({ id }: { id: string }) => {
return mainApi.get<BusterMetricData>(`/metrics/${id}/data`).then((res) => res.data);
};
export const updateMetric = async (params: UpdateMetricParams) => { export const updateMetric = async (params: UpdateMetricParams) => {
return mainApi return mainApi
.put<BusterMetric>(`/metrics/update/${params.id}`, { params }) .put<BusterMetric>(`/metrics/update/${params.id}`, { params })

View File

@ -36,7 +36,7 @@ const chatsBlackBoxMessages = (messageId: string) =>
queryOptions<string | null>({ queryOptions<string | null>({
queryKey: ['chats', 'messages', messageId, 'black-box'] as const, queryKey: ['chats', 'messages', messageId, 'black-box'] as const,
staleTime: Infinity, staleTime: Infinity,
enabled: false, enabled: false, //this is local
queryFn: () => Promise.resolve(null) queryFn: () => Promise.resolve(null)
}); });

View File

@ -2,32 +2,16 @@
import { queryOptions } from '@tanstack/react-query'; import { queryOptions } from '@tanstack/react-query';
import type { import type {
BusterMetricData,
BusterMetricListItem, BusterMetricListItem,
IBusterMetric, IBusterMetric,
IBusterMetricData IBusterMetricData
} from '@/api/asset_interfaces/metric'; } from '@/api/asset_interfaces/metric';
import { useBusterAssetsContextSelector } from '@/context/Assets/BusterAssetsProvider';
import { ListMetricsParams } from '../buster_rest/metrics'; import { ListMetricsParams } from '../buster_rest/metrics';
export const metricsGetMetric = (metricId: string) => { export const metricsGetMetric = (metricId: string) => {
return queryOptions<IBusterMetric>({ return queryOptions<IBusterMetric>({
queryKey: ['metrics', 'get', metricId] as const, queryKey: ['metrics', 'get', metricId] as const,
staleTime: 30 * 60 * 1000, staleTime: 30 * 60 * 1000
enabled: false
});
};
export const useMetricsGetMetric = (metricId: string) => {
const setAssetPasswordError = useBusterAssetsContextSelector(
(state) => state.setAssetPasswordError
);
return queryOptions<IBusterMetric>({
...metricsGetMetric(metricId),
throwOnError: (error, query) => {
setAssetPasswordError(metricId, error.message || 'An error occurred');
return false;
}
}); });
}; };
@ -45,7 +29,6 @@ export const metricsGetData = (id: string) =>
export const metricsQueryKeys = { export const metricsQueryKeys = {
metricsGetMetric, metricsGetMetric,
useMetricsGetMetric,
metricsGetList, metricsGetList,
metricsGetData metricsGetData
}; };

View File

@ -8,9 +8,6 @@ export default async function Page(props: {
const { chatId, metricId } = params; const { chatId, metricId } = params;
console.log('chatId', chatId);
console.log('metricId', metricId);
return ( return (
<AppAssetCheckLayout metricId={metricId} type="metric"> <AppAssetCheckLayout metricId={metricId} type="metric">
<MetricController metricId={metricId} /> <MetricController metricId={metricId} />

View File

@ -13,10 +13,11 @@ export default function Page(params: { params: { chatId: string } }) {
} }
return ( return (
<StatusCard <div className="p-5">
className="text-red-500" <StatusCard
title="Error" title="Error"
message="If you are seeing this, tell Nate and screenshot this whole page including the URL and logs..." message="If you are seeing this, tell Nate and screenshot this whole page including the URL and logs..."
/> />
</div>
); );
} }

View File

@ -38,7 +38,7 @@ export const NewUserController = () => {
}); });
onChangePage({ onChangePage({
route: BusterRoutes.APP_METRIC route: BusterRoutes.APP_HOME
}); });
} catch (error) { } catch (error) {
// //
@ -81,7 +81,6 @@ export const NewUserController = () => {
placeholder="What is your full name" placeholder="What is your full name"
className="w-full" className="w-full"
value={name || ''} value={name || ''}
defaultValue={user?.name || ''}
name="name" name="name"
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}
/> />

View File

@ -38,6 +38,7 @@ export const SidebarUserFooterComponent: React.FC<{
email: string; email: string;
signOut: () => Promise<{ error: string }>; signOut: () => Promise<{ error: string }>;
}> = React.memo(({ name, avatarUrl, email, signOut }) => { }> = React.memo(({ name, avatarUrl, email, signOut }) => {
if (!name || !email) return null;
return ( return (
<SidebarUserDropdown signOut={signOut}> <SidebarUserDropdown signOut={signOut}>
<div className="flex w-full"> <div className="flex w-full">

View File

@ -0,0 +1,112 @@
import type { Meta, StoryObj } from '@storybook/react';
import { AppDataGrid } from './AppDataGrid';
const meta: Meta<typeof AppDataGrid> = {
title: 'UI/table/AppDataGrid',
component: AppDataGrid,
parameters: {
layout: 'centered'
},
tags: ['autodocs']
};
export default meta;
type Story = StoryObj<typeof AppDataGrid>;
const sampleData = [
{ id: 1, name: 'John Doe', age: 30, email: 'john@example.com', joinDate: new Date('2023-01-15') },
{
id: 2,
name: 'Jane Smith',
age: 25,
email: 'jane@example.com',
joinDate: new Date('2023-02-20')
},
{
id: 3,
name: 'Bob Johnson',
age: 35,
email: 'bob@example.com',
joinDate: new Date('2023-03-10')
},
{
id: 4,
name: 'Alice Brown',
age: 28,
email: 'alice@example.com',
joinDate: new Date('2023-04-05')
}
];
export const Default: Story = {
args: {
rows: sampleData,
animate: true,
resizable: true,
draggable: true,
sortable: true
}
};
export const NonResizable: Story = {
args: {
rows: sampleData,
resizable: false,
draggable: true,
sortable: true
}
};
export const NonDraggable: Story = {
args: {
rows: sampleData,
resizable: true,
draggable: false,
sortable: true
}
};
export const NonSortable: Story = {
args: {
rows: sampleData,
resizable: true,
draggable: true,
sortable: false
}
};
export const CustomColumnOrder: Story = {
args: {
rows: sampleData,
columnOrder: ['name', 'email', 'age', 'id', 'joinDate'],
resizable: true,
draggable: true,
sortable: true
}
};
export const CustomFormatting: Story = {
args: {
rows: sampleData,
headerFormat: (value, columnName) => columnName.toUpperCase(),
cellFormat: (value, columnName) => {
if (columnName === 'joinDate' && value instanceof Date) {
return value.toLocaleDateString();
}
return String(value);
},
resizable: true,
draggable: true,
sortable: true
}
};
export const WithInitialWidth: Story = {
args: {
rows: sampleData,
initialWidth: 800,
resizable: true,
draggable: true,
sortable: true
}
};

View File

@ -35,7 +35,6 @@ import {
defaultHeaderFormat, defaultHeaderFormat,
MIN_WIDTH MIN_WIDTH
} from './helpers'; } from './helpers';
import styles from './AppDataGrid.module.css';
type Row = Record<string, string | number | null | Date>; type Row = Record<string, string | number | null | Date>;
@ -339,6 +338,19 @@ export const AppDataGrid: React.FC<AppDataGridProps> = React.memo(
}); });
}); });
const columnsX = [
{ key: 'id', name: 'ID' },
{ key: 'title', name: 'Title' }
];
const rowsX = [
{ id: 0, title: 'Example' },
{ id: 1, title: 'Demo' }
];
console.log('columnsX', columnsX);
console.log('rowsX', rowsX);
return ( return (
<React.Fragment key={forceRenderId}> <React.Fragment key={forceRenderId}>
<ErrorBoundary onError={handleErrorBoundary}> <ErrorBoundary onError={handleErrorBoundary}>
@ -348,7 +360,9 @@ export const AppDataGrid: React.FC<AppDataGridProps> = React.memo(
style={{ style={{
transition: animate ? 'opacity 0.25s' : undefined transition: animate ? 'opacity 0.25s' : undefined
}}> }}>
<DataGrid <DataGrid columns={columnsX} rows={rowsX} />
{/* <DataGrid
className={styles.dataGrid} className={styles.dataGrid}
columns={reorderedColumns} columns={reorderedColumns}
rows={sortedRows} rows={sortedRows}
@ -363,7 +377,7 @@ export const AppDataGrid: React.FC<AppDataGridProps> = React.memo(
onColumnsReorder={onColumnsReorder} onColumnsReorder={onColumnsReorder}
defaultColumnOptions={DEFAULT_COLUMN_WIDTH} defaultColumnOptions={DEFAULT_COLUMN_WIDTH}
direction={'ltr'} direction={'ltr'}
/> /> */}
<div style={{ width: '100%' }}></div> <div style={{ width: '100%' }}></div>
</div> </div>
</ErrorBoundary> </ErrorBoundary>

View File

@ -20,7 +20,7 @@ export const AppNoPageAccess: React.FC<{
<div className="flex h-[85vh] w-full flex-col items-center justify-center space-y-6"> <div className="flex h-[85vh] w-full flex-col items-center justify-center space-y-6">
<BusterLogo className="h-16 w-16" /> <BusterLogo className="h-16 w-16" />
<div className="max-w-[340px] text-center"> <div className="max-w-[440px] text-center">
<Title <Title
as="h2" as="h2"
className="text-center">{`It looks like you dont have access to this file...`}</Title> className="text-center">{`It looks like you dont have access to this file...`}</Title>

View File

@ -63,7 +63,7 @@ const AppPasswordInputComponent: React.FC<{
style={{ style={{
marginTop: '25vh' marginTop: '25vh'
}}> }}>
<div className="flex max-w-[340px] flex-col items-center space-y-6"> <div className="flex max-w-[440px] flex-col items-center space-y-6">
<BusterLogo className="h-16 w-16" /> <BusterLogo className="h-16 w-16" />
<div className="text-center"> <div className="text-center">

View File

@ -53,7 +53,7 @@ export const MetricTitle: React.FC<{
<Title <Title
{...titleConfig} {...titleConfig}
as="h4" as="h4"
className="text-md! max-w-[calc(100%_-_22px)]" className="text-md! max-w-[calc(100%_-_22px)] whitespace-nowrap"
style={{ fontSize: '14px' }}> style={{ fontSize: '14px' }}>
{`${title}`} {`${title}`}
</Title> </Title>
@ -96,11 +96,7 @@ const ThreeDotPlaceholder: React.FC<{
}> = React.memo(({ className }) => { }> = React.memo(({ className }) => {
return ( return (
<div className={`relative h-[24px] w-[24px] ${className}`}> <div className={`relative h-[24px] w-[24px] ${className}`}>
{/* <Button <Button variant="link" prefix={<DotsVertical />} />
className="absolute top-[-2px] hidden"
type="text"
icon={<AppMaterialIcons icon="more_vert" />}
/> */}
</div> </div>
); );
}); });

View File

@ -19,7 +19,7 @@ export const MetricViewChartHeader: React.FC<{
<EditableTitle level={4} className="mb-0" inputClassName="text-md!" onChange={onSetTitle}> <EditableTitle level={4} className="mb-0" inputClassName="text-md!" onChange={onSetTitle}>
{title} {title}
</EditableTitle> </EditableTitle>
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1 whitespace-nowrap">
{!!timeFrame && ( {!!timeFrame && (
<> <>
<Text size={'sm'} variant="secondary"> <Text size={'sm'} variant="secondary">

View File

@ -1,7 +1,7 @@
'use client'; 'use client';
import { createContext, useContextSelector } from 'use-context-selector'; import { createContext, useContextSelector } from 'use-context-selector';
import React, { PropsWithChildren, useTransition } from 'react'; import React, { PropsWithChildren } from 'react';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import type { AppSplitterRef } from '@/components/ui/layouts'; import type { AppSplitterRef } from '@/components/ui/layouts';
import { DEFAULT_CHAT_OPTION_SIDEBAR_SIZE } from './config'; import { DEFAULT_CHAT_OPTION_SIDEBAR_SIZE } from './config';
@ -38,9 +38,7 @@ export const useChatLayout = ({ appSplitterRef }: UseChatSplitterProps) => {
renderViewLayoutKey renderViewLayoutKey
} = useSelectedFileAndLayout({ animateOpenSplitter }); } = useSelectedFileAndLayout({ animateOpenSplitter });
const { collapseDirection, isCollapseOpen, onCollapseFileClick } = useLayoutCollapse({ const { onCollapseFileClick } = useLayoutCollapse({
selectedFile,
selectedLayout,
animateOpenSplitter animateOpenSplitter
}); });
@ -56,8 +54,6 @@ export const useChatLayout = ({ appSplitterRef }: UseChatSplitterProps) => {
renderViewLayoutKey, renderViewLayoutKey,
selectedFileType: selectedFile?.type, selectedFileType: selectedFile?.type,
selectedFile, selectedFile,
collapseDirection,
isCollapseOpen,
onCollapseFileClick, onCollapseFileClick,
onSetSelectedFile, onSetSelectedFile,
animateOpenSplitter animateOpenSplitter

View File

@ -1,4 +1,4 @@
import { DoubleChevronRight, DoubleChevronLeft } from '@/components/ui/icons'; import { DoubleChevronRight } from '@/components/ui/icons';
import { Button } from '@/components/ui/buttons'; import { Button } from '@/components/ui/buttons';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
@ -6,30 +6,21 @@ import { useMemoizedFn } from '@/hooks';
export const CollapseFileButton: React.FC<{ export const CollapseFileButton: React.FC<{
showCollapseButton: boolean; showCollapseButton: boolean;
isOpen: boolean;
collapseDirection: 'left' | 'right';
onCollapseFileClick: (value?: boolean) => void; onCollapseFileClick: (value?: boolean) => void;
}> = React.memo(({ showCollapseButton, isOpen, collapseDirection, onCollapseFileClick }) => { }> = React.memo(({ showCollapseButton, onCollapseFileClick }) => {
const icon = useMemo(() => { const icon = <DoubleChevronRight />;
if (collapseDirection === 'left') {
return isOpen ? <DoubleChevronLeft /> : <DoubleChevronRight />;
}
return isOpen ? <DoubleChevronRight /> : <DoubleChevronLeft />;
}, [isOpen, collapseDirection]);
const onClick = useMemoizedFn(() => { const onClick = useMemoizedFn(() => {
onCollapseFileClick(); onCollapseFileClick();
}); });
const animation = useMemo(() => { const animation = useMemo(() => {
const baseAnimation = { return {
initial: { opacity: 0 }, initial: { opacity: 0 },
animate: { opacity: 1 }, animate: { opacity: 1 },
exit: { opacity: 0 } exit: { opacity: 0 }
}; };
}, []);
return baseAnimation;
}, [collapseDirection, isOpen]);
return ( return (
<AnimatePresence mode="wait" initial={false}> <AnimatePresence mode="wait" initial={false}>

View File

@ -2,7 +2,7 @@
import React from 'react'; import React from 'react';
import { CollapseFileButton } from './CollapseFileButton'; import { CollapseFileButton } from './CollapseFileButton';
import type { FileType } from '@/api/asset_interfaces'; import type { FileType } from '@/api/asset_interfaces/chat';
import { FileContainerSegmentProps, FileContainerButtonsProps } from './interfaces'; import { FileContainerSegmentProps, FileContainerButtonsProps } from './interfaces';
import { DashboardContainerHeaderButtons } from './DashboardContainerHeaderButtons'; import { DashboardContainerHeaderButtons } from './DashboardContainerHeaderButtons';
import { DashboardContainerHeaderSegment } from './DashboardContainerHeaderSegment'; import { DashboardContainerHeaderSegment } from './DashboardContainerHeaderSegment';
@ -15,8 +15,6 @@ export const FileContainerHeader: React.FC = React.memo(() => {
const selectedFileType = useChatLayoutContextSelector((x) => x.selectedFileType); const selectedFileType = useChatLayoutContextSelector((x) => x.selectedFileType);
const selectedFileView = useChatLayoutContextSelector((x) => x.selectedFileView); const selectedFileView = useChatLayoutContextSelector((x) => x.selectedFileView);
const onCollapseFileClick = useChatLayoutContextSelector((state) => state.onCollapseFileClick); const onCollapseFileClick = useChatLayoutContextSelector((state) => state.onCollapseFileClick);
const collapseDirection = useChatLayoutContextSelector((state) => state.collapseDirection);
const isCollapseOpen = useChatLayoutContextSelector((state) => state.isCollapseOpen);
const renderViewLayoutKey = useChatLayoutContextSelector((state) => state.renderViewLayoutKey); const renderViewLayoutKey = useChatLayoutContextSelector((state) => state.renderViewLayoutKey);
const showCollapseButton = renderViewLayoutKey !== 'file'; const showCollapseButton = renderViewLayoutKey !== 'file';
@ -33,7 +31,7 @@ export const FileContainerHeader: React.FC = React.memo(() => {
() => () =>
selectedFileType && SelectedFileButtonsRecord[selectedFileType] selectedFileType && SelectedFileButtonsRecord[selectedFileType]
? SelectedFileButtonsRecord[selectedFileType] ? SelectedFileButtonsRecord[selectedFileType]
: () => <>no buttons</>, : () => null,
[selectedFileType] [selectedFileType]
); );
@ -41,9 +39,7 @@ export const FileContainerHeader: React.FC = React.memo(() => {
<> <>
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<CollapseFileButton <CollapseFileButton
collapseDirection={collapseDirection}
showCollapseButton={showCollapseButton} showCollapseButton={showCollapseButton}
isOpen={isCollapseOpen}
onCollapseFileClick={onCollapseFileClick} onCollapseFileClick={onCollapseFileClick}
/> />
{selectedFileView && <SelectedFileSegment selectedFileView={selectedFileView} />} {selectedFileView && <SelectedFileSegment selectedFileView={selectedFileView} />}

View File

@ -11,6 +11,7 @@ import { useMetricIndividual } from '@/context/Metrics';
import { SaveMetricToCollectionButton } from '../../../../components/features/buttons/SaveMetricToCollectionButton'; import { SaveMetricToCollectionButton } from '../../../../components/features/buttons/SaveMetricToCollectionButton';
import { SaveMetricToDashboardButton } from '../../../../components/features/buttons/SaveMetricToDashboardButton'; import { SaveMetricToDashboardButton } from '../../../../components/features/buttons/SaveMetricToDashboardButton';
import { ShareMetricButton } from '../../../../components/features/buttons/ShareMetricButton'; import { ShareMetricButton } from '../../../../components/features/buttons/ShareMetricButton';
import { Code3, SquareChartPen } from '@/components/ui/icons';
export const MetricContainerHeaderButtons: React.FC<FileContainerButtonsProps> = React.memo(() => { export const MetricContainerHeaderButtons: React.FC<FileContainerButtonsProps> = React.memo(() => {
const renderViewLayoutKey = useChatLayoutContextSelector((x) => x.renderViewLayoutKey); const renderViewLayoutKey = useChatLayoutContextSelector((x) => x.renderViewLayoutKey);
@ -52,7 +53,7 @@ const EditChartButton = React.memo(() => {
return ( return (
<SelectableButton <SelectableButton
tooltipText="Edit chart" tooltipText="Edit chart"
icon="chart_edit" icon={<SquareChartPen />}
onClick={onClickButton} onClick={onClickButton}
selected={isSelectedView} selected={isSelectedView}
/> />
@ -76,7 +77,7 @@ const EditSQLButton = React.memo(() => {
return ( return (
<SelectableButton <SelectableButton
tooltipText="Edit SQL" tooltipText="Edit SQL"
icon="code_blocks" icon={<Code3 />}
onClick={onClickButton} onClick={onClickButton}
selected={isSelectedView} selected={isSelectedView}
/> />

View File

@ -2,7 +2,6 @@ import React from 'react';
import { Button } from '@/components/ui/buttons'; import { Button } from '@/components/ui/buttons';
import { AppTooltip } from '@/components/ui/tooltip'; import { AppTooltip } from '@/components/ui/tooltip';
import {} from '@/components/ui/icons';
export const SelectableButton = React.memo<{ export const SelectableButton = React.memo<{
tooltipText: string; tooltipText: string;

View File

@ -6,50 +6,25 @@ import { SelectedFileParams } from './useSelectedFileAndLayout';
import { ChatLayoutView } from '../interfaces'; import { ChatLayoutView } from '../interfaces';
export const useLayoutCollapse = ({ export const useLayoutCollapse = ({
selectedFile, animateOpenSplitter
animateOpenSplitter,
selectedLayout
}: { }: {
selectedFile: SelectedFileParams['selectedFile'];
selectedLayout: ChatLayoutView;
animateOpenSplitter: (side: 'left' | 'right' | 'both') => void; animateOpenSplitter: (side: 'left' | 'right' | 'both') => void;
}) => { }) => {
const isReasoningFile = selectedFile?.type === 'reasoning';
const [isCollapseOpen, setIsCollapseOpen] = useState(isReasoningFile ? true : false);
const collapseDirection: 'left' | 'right' = useMemo(() => {
if (selectedFile?.type === 'reasoning') return 'right';
return selectedLayout === 'file' ? 'left' : 'right';
}, [selectedLayout, selectedFile?.type]);
const onCollapseFileClick = useMemoizedFn((close?: boolean) => { const onCollapseFileClick = useMemoizedFn((close?: boolean) => {
const isCloseAction = close ?? isCollapseOpen; // if (selectedFile && selectedFile.type === 'reasoning') {
const isFileLayout = selectedLayout === 'file'; // animateOpenSplitter(!isCloseAction ? 'both' : 'left');
// } else if (isFileLayout) {
// // For file layout, toggle between 'both' and 'right'
// animateOpenSplitter(!isCloseAction && selectedFile ? 'both' : 'right');
// } else {
// // For other layouts, toggle between 'right' and 'both'
// animateOpenSplitter(isCloseAction ? 'left' : 'both');
// }
setIsCollapseOpen(!isCloseAction); animateOpenSplitter('left');
if (selectedFile && selectedFile.type === 'reasoning') {
animateOpenSplitter(!isCloseAction ? 'both' : 'left');
} else if (isFileLayout) {
// For file layout, toggle between 'both' and 'right'
animateOpenSplitter(!isCloseAction && selectedFile ? 'both' : 'right');
} else {
// For other layouts, toggle between 'right' and 'both'
animateOpenSplitter(isCloseAction ? 'left' : 'both');
}
}); });
useEffect(() => {
if (isReasoningFile && !isCollapseOpen) {
setIsCollapseOpen(true);
}
}, [isReasoningFile]);
return { return {
collapseDirection,
isCollapseOpen,
onCollapseFileClick onCollapseFileClick
}; };
}; };