Warning for setup

This commit is contained in:
Nate Kelley 2025-05-09 15:30:04 -06:00
parent 3656ee586c
commit 33312538e1
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
4 changed files with 188 additions and 15 deletions

View File

@ -64,7 +64,7 @@ export const InputTextAreaButton = forwardRef<HTMLTextAreaElement, InputTextArea
onClick={onClickBox}
className={cn(
inputTextAreaButtonVariants({ variant }),
'transition-all duration-500 hover:shadow-md focus:shadow-lg',
!disabled && 'transition-all duration-500 hover:shadow-md focus:shadow-lg',
loading && 'border-border!',
className
)}>

View File

@ -6,6 +6,9 @@ import { useBusterNewChatContextSelector } from '@/context/Chats';
import { inputHasText } from '@/lib/text';
import { useMemoizedFn, useMount } from '@/hooks';
import { ChangeEvent, useMemo, useState } from 'react';
import { useGetDatasets } from '@/api/buster_rest';
import { NewChatWarning } from './NewChatWarning';
import { useNewChatWarning } from './useNewChatWarning';
const autoResizeConfig = {
minRows: 3,
@ -17,10 +20,12 @@ export const NewChatInput: React.FC<{}> = () => {
const [inputValue, setInputValue] = useState('');
const [loading, setLoading] = useState(false);
const textAreaRef = useRef<HTMLTextAreaElement>(null);
const newChatWarningProps = useNewChatWarning();
const { showWarning } = newChatWarningProps;
const disabledSubmit = useMemo(() => {
return !inputHasText(inputValue);
}, [inputValue]);
return !inputHasText(inputValue) || showWarning;
}, [inputValue, showWarning]);
const onSubmit = useMemoizedFn(async (value: string) => {
if (disabledSubmit) return;
@ -49,17 +54,23 @@ export const NewChatInput: React.FC<{}> = () => {
});
return (
<InputTextAreaButton
className="transition-all duration-300 hover:shadow-lg active:shadow-md"
placeholder="Ask Buster a question..."
autoResize={autoResizeConfig}
onSubmit={onSubmit}
onChange={onChange}
onStop={onStop}
loading={loading}
disabledSubmit={disabledSubmit}
autoFocus
ref={textAreaRef}
/>
<div className="flex flex-col space-y-2">
<InputTextAreaButton
className={
!showWarning ? 'transition-all duration-300 hover:shadow-lg active:shadow-md' : ''
}
placeholder="Ask Buster a question..."
autoResize={autoResizeConfig}
onSubmit={onSubmit}
onChange={onChange}
onStop={onStop}
loading={loading}
disabled={showWarning}
disabledSubmit={disabledSubmit}
autoFocus
ref={textAreaRef}
/>
{newChatWarningProps.showWarning && <NewChatWarning {...newChatWarningProps} />}
</div>
);
};

View File

@ -0,0 +1,139 @@
import { useGetDatasets } from '@/api/buster_rest';
import { useGetDatasource, useListDatasources } from '@/api/buster_rest/data_source';
import { cn } from '@/lib/classMerge';
import React, { useMemo } from 'react';
import { useNewChatWarning } from './useNewChatWarning';
import { ArrowUpRight, CircleCheck, CircleXmark } from '@/components/ui/icons';
import { Paragraph, Text } from '@/components/ui/typography';
import { Button } from '@/components/ui/buttons';
import Link from 'next/link';
export const NewChatWarning = React.memo(({}: ReturnType<typeof useNewChatWarning>) => {
const hasDatasources = true;
const hasDatasets = false;
const allCompleted = hasDatasets && hasDatasources;
const progress = [hasDatasources, hasDatasets].filter(Boolean).length;
const progressPercentage = (progress / 2) * 100;
return (
<div className="rounded-xl border border-gray-200 bg-white p-6 shadow-sm">
<div className="mb-4 flex items-center justify-between">
<Text className="text-xl font-medium text-gray-800">Setup Checklist</Text>
<div className="flex items-center gap-2">
<div className="text-sm font-medium text-gray-500">{progress}/2 completed</div>
<div className="h-2 w-20 rounded-full bg-gray-100">
<div
className="h-full rounded-full bg-gray-500 transition-all duration-500 ease-in-out"
style={{ width: `${progressPercentage}%` }}
/>
</div>
</div>
</div>
<div className="space-y-4">
<SetupItem
number="1"
status={hasDatasources}
title="Connect a Data Source"
description="Link files, databases, or websites to enable knowledge retrieval"
link="https://docs.buster.so/docs/using-the-cli/init-command"
linkText="Go to docs"
/>
<SetupItem
number="2"
status={hasDatasets}
title="Create a Dataset"
description="Organize your information for efficient querying"
link="https://docs.buster.so/docs/using-the-cli/create-dataset"
linkText="Go to docs"
/>
</div>
<div
className={cn(
'mt-5 flex items-center rounded-lg border p-4',
allCompleted ? 'border-gray-200 bg-gray-50' : 'border-gray-200 bg-gray-50'
)}>
<div
className={cn(
'mr-3 flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full',
allCompleted ? 'bg-gray-200' : 'bg-gray-200'
)}>
{allCompleted ? (
<CircleCheck fill="#4B5563" title="Complete" />
) : (
<div className="h-4 w-4 rounded-full bg-gray-400" />
)}
</div>
<div>
<Text className="font-medium text-gray-700">
{allCompleted
? "You're all set! Ask questions to get answers from your data."
: 'Complete both steps to start querying your information.'}
</Text>
<Text className="text-sm text-gray-500">
{allCompleted
? ' Your data is ready to be explored.'
: " Without proper setup, we can't retrieve relevant information."}
</Text>
</div>
</div>
</div>
);
});
interface SetupItemProps {
number: string;
status: boolean;
title: string;
description: string;
link?: string;
linkText?: string;
}
const SetupItem = ({ number, status, title, description, link, linkText }: SetupItemProps) => {
return (
<div
className={cn(
'group relative flex items-start space-x-4 rounded-lg border p-4 transition-all duration-200',
status ? 'border-green-700/30 bg-green-50' : 'border-gray-200'
)}>
<div
className={cn(
'text-md flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full font-medium',
status ? 'bg-green-200 text-green-700' : 'bg-gray-100 text-gray-500'
)}>
{status ? <CircleCheck title="Complete" /> : number}
</div>
<div className="min-w-0 flex-1 flex-col">
<div className="flex items-center justify-between">
<Text className="font-medium text-gray-800">{title}</Text>
{status && (
<span className="rounded-full bg-green-200 px-2 py-1 text-xs font-medium text-green-700">
Complete
</span>
)}
</div>
<Paragraph className="mt-1 text-sm text-gray-600">{description}</Paragraph>
{link && (
<Link href={link} target="_blank">
<Button
className="mt-2 text-sm"
size="tall"
suffix={
<span className="text-xs">
<ArrowUpRight />
</span>
}>
{linkText}
</Button>
</Link>
)}
</div>
</div>
);
};

View File

@ -0,0 +1,23 @@
import { useGetDatasets } from '@/api/buster_rest';
import { useListDatasources } from '@/api/buster_rest/data_source';
import { useMemo } from 'react';
export const useNewChatWarning = () => {
const { data: datasets, isFetched: isDatasetsFetched } = useGetDatasets();
const { data: datasources, isFetched: isDatasourcesFetched } = useListDatasources();
const showWarning = useMemo(() => {
return true;
if (!isDatasetsFetched || !isDatasourcesFetched) return false;
if (datasets?.length === 0) return true;
if (datasources?.length === 0) return true;
return false;
}, [datasets, datasources, isDatasetsFetched, isDatasourcesFetched]);
return {
showWarning,
hasDatasets: datasets?.length > 0,
hasDatasources: datasources?.length > 0,
isFetched: isDatasetsFetched && isDatasourcesFetched
};
};