update how we pass inputs

This commit is contained in:
Nate Kelley 2025-02-05 09:55:09 -07:00
parent b984e9863f
commit 39d5601158
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
11 changed files with 84 additions and 53 deletions

View File

@ -1,5 +0,0 @@
import React from 'react';
export default function Layout({ children }: { children: React.ReactNode }) {
return <>{children}</>;
}

View File

@ -1,3 +1,3 @@
export default function Page() {
return <></>;
return <></>; //we need this page to be able to load the chat page
}

View File

@ -10,7 +10,6 @@ import type { BusterSearchResult } from '@/api/asset_interfaces';
import { useBusterNotifications } from '@/context/BusterNotifications';
import { NewChatModalDataSourceSelect } from './NewChatModalDatasourceSelect';
import { NoDatasets } from './NoDatasets';
import { useParams } from 'next/navigation';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import { useGetDatasets } from '@/api/buster_rest/datasets';
import { NewDatasetModal } from '../NewDatasetModal';
@ -35,11 +34,9 @@ export const NewChatModal = React.memo<{
onClose: () => void;
}>(({ open, onClose }) => {
const token = useAntToken();
const searchParams = useParams();
const onChangePage = useAppLayoutContextSelector((x) => x.onChangePage);
const { openErrorNotification } = useBusterNotifications();
const { isFetched: isFetchedDatasets, data: datasetsList } = useGetDatasets();
const onStartNewChat = useBusterNewChatContextSelector((x) => x.onStartNewChat);
const onSetSelectedChatDataSource = useBusterNewChatContextSelector(
(x) => x.onSetSelectedChatDataSource
);
@ -192,13 +189,18 @@ const NewChatInput: React.FC<{
const token = useAntToken();
const inputRef = useRef<InputRef>(null);
const loadingNewMetric = useBusterNewChatContextSelector((x) => x.loadingNewChat);
const prompt = useBusterNewChatContextSelector((x) => x.prompt);
const onStartNewChat = useBusterNewChatContextSelector((x) => x.onStartNewChat);
const onSetPrompt = useBusterNewChatContextSelector((x) => x.onSetPrompt);
const onSelectSearchAsset = useBusterNewChatContextSelector((x) => x.onSelectSearchAsset);
const [prompt, setPrompt] = useState('');
const onStartNewChatPreflight = useMemoizedFn(async () => {
await onStartNewChat(prompt);
setPrompt('');
});
const onChangeText = useMemoizedFn((e: React.ChangeEvent<HTMLTextAreaElement>) => {
const value = e.currentTarget.value;
onSetPrompt(value);
setPrompt(value);
if (value.length < 1) {
setSuggestedPrompts([]);
} else {
@ -216,7 +218,10 @@ const NewChatInput: React.FC<{
shownPrompts[activeItem]?.name &&
lastKeyPressedWasUpOrDown
) {
onStartNewChat(shownPrompts[activeItem]?.name);
const foundAsset = shownPrompts[activeItem];
if (foundAsset) {
onSelectSearchAsset(foundAsset);
}
v.stopPropagation();
v.preventDefault();
return;
@ -224,17 +229,17 @@ const NewChatInput: React.FC<{
if (v.shiftKey) {
return;
}
onStartNewChat(value);
onStartNewChatPreflight();
});
const onClickSubmitButton = useMemoizedFn(() => {
onStartNewChat(prompt);
onStartNewChatPreflight();
});
useMount(() => {
setTimeout(() => {
inputRef.current?.focus();
}, 200);
}, 175);
});
const autoSizeMemoized = useMemo(() => {

View File

@ -3,17 +3,19 @@ import { MetricFileView } from '@appLayouts/ChatLayout/ChatLayoutContext';
import { MetricViewComponents } from './config';
import { IndeterminateLinearLoader } from '@/components/loaders/IndeterminateLinearLoader';
import { useBusterMetricIndividual } from '@/context/Metrics';
import { useBusterNewChatContextSelector } from '@/context/Chats';
export const MetricViewController: React.FC<{
metricId: string;
selectedFileView: MetricFileView | undefined;
}> = React.memo(({ metricId, selectedFileView = 'chart' }) => {
const { metric, metricData } = useBusterMetricIndividual({ metricId });
const loadingNewChat = useBusterNewChatContextSelector((x) => x.loadingNewChat);
const isFetchedConfig = metric.fetched;
const isFetchedData = metricData.fetched;
const showLoader = !isFetchedConfig || !isFetchedData;
const showLoader = !isFetchedConfig || !isFetchedData || loadingNewChat;
const Component = selectedFileView ? MetricViewComponents[selectedFileView] : () => null;

View File

@ -18,7 +18,7 @@ export const useMetricControllerLayout = ({
if (side === 'metric') {
appSplitterRef.current.animateWidth('100%', 'left');
} else if (side === 'both') {
appSplitterRef.current.animateWidth('265px', 'right');
appSplitterRef.current.animateWidth('310px', 'right');
}
}
});

View File

@ -1,4 +1,4 @@
import React, { useMemo, useState } from 'react';
import React, { useMemo, useRef, useState } from 'react';
import { Input } from 'antd';
import { createStyles } from 'antd-style';
import { useMemoizedFn } from 'ahooks';
@ -7,12 +7,14 @@ import { useBusterNewChatContextSelector } from '@/context/Chats';
import { AIWarning } from './AIWarning';
import { SubmitButton } from './SubmitButton';
import { useChatInputFlow } from './useChatInputFlow';
import type { TextAreaRef } from 'antd/es/input/TextArea';
const autoSize = { minRows: 3, maxRows: 16 };
export const ChatInput: React.FC<{}> = React.memo(({}) => {
const { styles, cx } = useStyles();
const loading = useBusterNewChatContextSelector((state) => state.loadingNewChat);
const inputRef = useRef<TextAreaRef>(null);
const [inputValue, setInputValue] = useState('');
const [isFocused, setIsFocused] = React.useState(false);
@ -24,7 +26,9 @@ export const ChatInput: React.FC<{}> = React.memo(({}) => {
const { onSubmitPreflight } = useChatInputFlow({
disableSendButton,
inputValue,
setInputValue
setInputValue,
loading,
inputRef
});
const onPressEnter = useMemoizedFn((e: React.KeyboardEvent<HTMLTextAreaElement>) => {
@ -59,6 +63,7 @@ export const ChatInput: React.FC<{}> = React.memo(({}) => {
'relative flex w-full items-center overflow-hidden'
)}>
<Input.TextArea
ref={inputRef}
variant="borderless"
onBlur={onBlurInput}
onFocus={onFocusInput}

View File

@ -2,24 +2,31 @@ import { useMemo } from 'react';
import { useChatContextSelector } from '../../../ChatContext';
import { useMemoizedFn } from 'ahooks';
import { useBusterNewChatContextSelector } from '@/context/Chats';
import type { TextAreaRef } from 'antd/es/input/TextArea';
type FlowType = 'followup-chat' | 'followup-metric' | 'followup-dashboard' | 'new';
export const useChatInputFlow = ({
disableSendButton,
inputValue,
setInputValue
setInputValue,
inputRef,
loading
}: {
disableSendButton: boolean;
inputValue: string;
setInputValue: (value: string) => void;
inputRef: React.RefObject<TextAreaRef>;
loading: boolean;
}) => {
const hasChat = useChatContextSelector((x) => x.hasChat);
const chatId = useChatContextSelector((x) => x.chatId);
const selectedFileType = useChatContextSelector((x) => x.selectedFileType);
const selectedFileId = useChatContextSelector((x) => x.selectedFileId);
const onStartNewChat = useBusterNewChatContextSelector((state) => state.onStartNewChat);
const onFollowUpChat = useBusterNewChatContextSelector((state) => state.onFollowUpChat);
const onStartChatFromFile = useBusterNewChatContextSelector((state) => state.onStartChatFromFile);
const onStopChat = useBusterNewChatContextSelector((state) => state.onStopChat);
const currentMessageId = useChatContextSelector((x) => x.currentMessageId);
const flow: FlowType = useMemo(() => {
@ -32,6 +39,11 @@ export const useChatInputFlow = ({
const onSubmitPreflight = useMemoizedFn(async () => {
if (disableSendButton) return;
if (loading) {
onStopChat({ chatId: chatId! });
return;
}
switch (flow) {
case 'followup-chat':
await onFollowUpChat({ prompt: inputValue, messageId: currentMessageId! });
@ -62,6 +74,10 @@ export const useChatInputFlow = ({
}
setInputValue('');
setTimeout(() => {
inputRef.current?.focus();
}, 50);
});
return { onSubmitPreflight };

View File

@ -0,0 +1,31 @@
import { AppMaterialIcons } from '@/components/icons';
import { Button } from 'antd';
import React from 'react';
import { useChatLayoutContextSelector } from '../../ChatLayoutContext';
import { useHotkeys } from 'react-hotkeys-hook';
import { useMemoizedFn } from 'ahooks';
import { AppTooltip } from '@/components';
export const CreateChatButton = React.memo(() => {
const onCollapseFileClick = useChatLayoutContextSelector((x) => x.onCollapseFileClick);
const onCollapseFileClickPreflight = useMemoizedFn(() => {
onCollapseFileClick(false);
});
useHotkeys('e', onCollapseFileClickPreflight, { preventDefault: true });
return (
<AppTooltip title={'Start chat'} shortcuts={['e']}>
<Button
onClick={onCollapseFileClickPreflight}
color="default"
variant="solid"
type="primary"
icon={<AppMaterialIcons icon="stars" />}>
Edit
</Button>
</AppTooltip>
);
});
CreateChatButton.displayName = 'CreateChatButton';

View File

@ -10,6 +10,7 @@ import { ShareMetricButton } from '@appComponents/Buttons/ShareMetricButton';
import { useChatContextSelector } from '../../ChatContext';
import { HideButtonContainer } from './HideButtonContainer';
import { FileButtonContainer } from './FileButtonContainer';
import { CreateChatButton } from './CreateChatButtont';
export const MetricContainerHeaderButtons: React.FC<FileContainerButtonsProps> = React.memo(() => {
const selectedFileView = useChatLayoutContextSelector(
@ -78,21 +79,3 @@ const ShareMetricButtonLocal = React.memo(() => {
return <ShareMetricButton />;
});
ShareMetricButtonLocal.displayName = 'ShareMetricButtonLocal';
const CreateChatButton = React.memo(() => {
const onCollapseFileClick = useChatLayoutContextSelector((x) => x.onCollapseFileClick);
return (
<Button
onClick={() => {
onCollapseFileClick(false);
}}
color="default"
variant="solid"
type="primary"
icon={<AppMaterialIcons icon="stars" />}>
Edit
</Button>
);
});
CreateChatButton.displayName = 'CreateChatButton';

View File

@ -25,7 +25,7 @@ const TooltipShortcut: React.FC<{ shortcut: string }> = ({ shortcut }) => {
<div
className="relative flex justify-center"
style={{
lineHeight: 1.25,
lineHeight: 1,
fontSize: 12,
borderRadius: borderRadius,
border: `0.5px solid ${colorBorder}`,

View File

@ -11,18 +11,12 @@ export const useBusterNewChat = () => {
const [selectedChatDataSource, setSelectedChatDataSource] =
useState<BusterDatasetListItem | null>(null);
const [loadingNewChat, setLoadingNewChat] = useState(false);
const [prompt, setPrompt] = useState('');
const onSetPrompt = useMemoizedFn((prompt: string) => {
setPrompt(prompt);
});
const onSelectSearchAsset = useMemoizedFn(async (asset: BusterSearchResult) => {
setLoadingNewChat(true);
console.log('select search asset');
await new Promise((resolve) => setTimeout(resolve, 1000));
setLoadingNewChat(false);
onSetPrompt('');
});
const onStartNewChat = useMemoizedFn(async (prompt: string) => {
@ -30,7 +24,6 @@ export const useBusterNewChat = () => {
console.log('start new chat');
await new Promise((resolve) => setTimeout(resolve, 1000));
setLoadingNewChat(false);
onSetPrompt('');
});
const onStartChatFromFile = useMemoizedFn(
@ -39,7 +32,6 @@ export const useBusterNewChat = () => {
console.log('start chat from file');
await new Promise((resolve) => setTimeout(resolve, 1000));
setLoadingNewChat(false);
onSetPrompt('');
}
);
@ -49,7 +41,6 @@ export const useBusterNewChat = () => {
console.log('follow up chat');
await new Promise((resolve) => setTimeout(resolve, 1000));
setLoadingNewChat(false);
onSetPrompt('');
}
);
@ -59,10 +50,14 @@ export const useBusterNewChat = () => {
console.log('replace message in chat');
await new Promise((resolve) => setTimeout(resolve, 1000));
setLoadingNewChat(false);
onSetPrompt('');
}
);
const onStopChat = useMemoizedFn(({ chatId }: { chatId: string }) => {
setLoadingNewChat(false);
console.log('stop current chat');
});
const onSetSelectedChatDataSource = useMemoizedFn((dataSource: BusterDatasetListItem | null) => {
setSelectedChatDataSource(dataSource);
});
@ -73,11 +68,10 @@ export const useBusterNewChat = () => {
onSelectSearchAsset,
selectedChatDataSource,
onSetSelectedChatDataSource,
onSetPrompt,
onFollowUpChat,
prompt,
onStartChatFromFile,
onReplaceMessageInChat
onReplaceMessageInChat,
onStopChat
};
};