mirror of https://github.com/buster-so/buster.git
update how we pass inputs
This commit is contained in:
parent
b984e9863f
commit
39d5601158
|
@ -1,5 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
export default function Page() {
|
||||
return <></>;
|
||||
return <></>; //we need this page to be able to load the chat page
|
||||
}
|
||||
|
|
|
@ -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(() => {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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';
|
|
@ -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';
|
||||
|
|
|
@ -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}`,
|
||||
|
|
|
@ -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
|
||||
};
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue