Finish up loading states
This commit is contained in:
parent
3ebb1adac7
commit
8c2d58183c
4 changed files with 79 additions and 32 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { StickToBottom } from "use-stick-to-bottom";
|
import { StickToBottom } from "use-stick-to-bottom";
|
||||||
import { AssistantMessage } from "@/app/chat/components/assistant-message";
|
import { AssistantMessage } from "@/app/chat/components/assistant-message";
|
||||||
import { UserMessage } from "@/app/chat/components/user-message";
|
import { UserMessage } from "@/app/chat/components/user-message";
|
||||||
|
|
@ -59,6 +59,12 @@ export function OnboardingContent({
|
||||||
// Determine which message to show (streaming takes precedence)
|
// Determine which message to show (streaming takes precedence)
|
||||||
const displayMessage = streamingMessage || assistantMessage;
|
const displayMessage = streamingMessage || assistantMessage;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentStep === 1 && !isLoading && !!displayMessage) {
|
||||||
|
handleStepComplete();
|
||||||
|
}
|
||||||
|
}, [isLoading, displayMessage, handleStepComplete]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StickToBottom
|
<StickToBottom
|
||||||
className="flex h-full flex-1 flex-col"
|
className="flex h-full flex-1 flex-col"
|
||||||
|
|
@ -68,6 +74,7 @@ export function OnboardingContent({
|
||||||
>
|
>
|
||||||
<StickToBottom.Content className="flex flex-col min-h-full overflow-x-hidden px-8 py-6">
|
<StickToBottom.Content className="flex flex-col min-h-full overflow-x-hidden px-8 py-6">
|
||||||
<div className="flex flex-col place-self-center w-full space-y-6">
|
<div className="flex flex-col place-self-center w-full space-y-6">
|
||||||
|
{/* Step 1 */}
|
||||||
<OnboardingStep
|
<OnboardingStep
|
||||||
isVisible={currentStep >= 0}
|
isVisible={currentStep >= 0}
|
||||||
isCompleted={currentStep > 0}
|
isCompleted={currentStep > 0}
|
||||||
|
|
@ -76,6 +83,7 @@ export function OnboardingContent({
|
||||||
<OnboardingCard onComplete={handleStepComplete} />
|
<OnboardingCard onComplete={handleStepComplete} />
|
||||||
</OnboardingStep>
|
</OnboardingStep>
|
||||||
|
|
||||||
|
{/* Step 2 */}
|
||||||
<OnboardingStep
|
<OnboardingStep
|
||||||
isVisible={currentStep >= 1}
|
isVisible={currentStep >= 1}
|
||||||
isCompleted={currentStep > 1 || !!selectedNudge}
|
isCompleted={currentStep > 1 || !!selectedNudge}
|
||||||
|
|
@ -94,7 +102,7 @@ export function OnboardingContent({
|
||||||
{currentStep >= 1 && !!selectedNudge && (
|
{currentStep >= 1 && !!selectedNudge && (
|
||||||
<UserMessage
|
<UserMessage
|
||||||
content={selectedNudge}
|
content={selectedNudge}
|
||||||
isCompleted={currentStep > 1}
|
isCompleted={currentStep > 2}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -109,13 +117,13 @@ export function OnboardingContent({
|
||||||
expandedFunctionCalls={new Set()}
|
expandedFunctionCalls={new Set()}
|
||||||
onToggle={() => {}}
|
onToggle={() => {}}
|
||||||
isStreaming={!!streamingMessage}
|
isStreaming={!!streamingMessage}
|
||||||
isCompleted={currentStep > 1}
|
isCompleted={currentStep > 2}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Still kind of part of step 2 */}
|
{/* Step 3 */}
|
||||||
<OnboardingStep
|
<OnboardingStep
|
||||||
isVisible={currentStep === 1 && !isLoading && !!displayMessage}
|
isVisible={currentStep >= 2 && !isLoading && !!displayMessage}
|
||||||
isCompleted={currentStep > 2}
|
isCompleted={currentStep > 2}
|
||||||
text="Now, let's add your data."
|
text="Now, let's add your data."
|
||||||
hideIcon={true}
|
hideIcon={true}
|
||||||
|
|
@ -123,9 +131,10 @@ export function OnboardingContent({
|
||||||
<OnboardingUpload onComplete={handleStepComplete} />
|
<OnboardingUpload onComplete={handleStepComplete} />
|
||||||
</OnboardingStep>
|
</OnboardingStep>
|
||||||
|
|
||||||
|
{/* Step 4 */}
|
||||||
<OnboardingStep
|
<OnboardingStep
|
||||||
isVisible={currentStep >= 2}
|
isVisible={currentStep >= 3}
|
||||||
isCompleted={currentStep > 2}
|
isCompleted={currentStep > 3}
|
||||||
text="Step 3: You're all set!"
|
text="Step 3: You're all set!"
|
||||||
>
|
>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import { ChangeEvent, useRef, useState } from "react";
|
import { ChangeEvent, useRef, useState } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { duplicateCheck, uploadFile } from "@/lib/upload-utils";
|
import { duplicateCheck, uploadFile } from "@/lib/upload-utils";
|
||||||
|
import { AnimatePresence, motion } from "motion/react";
|
||||||
|
import { AnimatedProviderSteps } from "@/app/onboarding/components/animated-provider-steps";
|
||||||
|
|
||||||
interface OnboardingUploadProps {
|
interface OnboardingUploadProps {
|
||||||
onComplete: () => void;
|
onComplete: () => void;
|
||||||
|
|
@ -9,6 +11,12 @@ interface OnboardingUploadProps {
|
||||||
const OnboardingUpload = ({ onComplete }: OnboardingUploadProps) => {
|
const OnboardingUpload = ({ onComplete }: OnboardingUploadProps) => {
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
const [isUploading, setIsUploading] = useState(false);
|
const [isUploading, setIsUploading] = useState(false);
|
||||||
|
const [currentStep, setCurrentStep] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const STEP_LIST = [
|
||||||
|
"Analyzing your document",
|
||||||
|
"Ingesting your document",
|
||||||
|
];
|
||||||
|
|
||||||
const resetFileInput = () => {
|
const resetFileInput = () => {
|
||||||
if (fileInputRef.current) {
|
if (fileInputRef.current) {
|
||||||
|
|
@ -24,12 +32,14 @@ const OnboardingUpload = ({ onComplete }: OnboardingUploadProps) => {
|
||||||
const performUpload = async (file: File, replace = false) => {
|
const performUpload = async (file: File, replace = false) => {
|
||||||
setIsUploading(true);
|
setIsUploading(true);
|
||||||
try {
|
try {
|
||||||
|
setCurrentStep(1);
|
||||||
await uploadFile(file, replace);
|
await uploadFile(file, replace);
|
||||||
console.log("Document uploaded successfully");
|
console.log("Document uploaded successfully");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Upload failed", (error as Error).message);
|
console.error("Upload failed", (error as Error).message);
|
||||||
} finally {
|
} finally {
|
||||||
setIsUploading(false);
|
setIsUploading(false);
|
||||||
|
setCurrentStep(STEP_LIST.length);
|
||||||
onComplete();
|
onComplete();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -42,6 +52,7 @@ const OnboardingUpload = ({ onComplete }: OnboardingUploadProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
setCurrentStep(0);
|
||||||
const duplicateInfo = await duplicateCheck(selectedFile);
|
const duplicateInfo = await duplicateCheck(selectedFile);
|
||||||
if (duplicateInfo.exists) {
|
if (duplicateInfo.exists) {
|
||||||
console.log("Duplicate file detected");
|
console.log("Duplicate file detected");
|
||||||
|
|
@ -58,23 +69,45 @@ const OnboardingUpload = ({ onComplete }: OnboardingUploadProps) => {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<AnimatePresence mode="wait">
|
||||||
<Button
|
{currentStep === null ? (
|
||||||
size="sm"
|
<motion.div
|
||||||
variant="outline"
|
key="user-ingest"
|
||||||
onClick={handleUploadClick}
|
initial={{ opacity: 1, y: 0 }}
|
||||||
disabled={isUploading}
|
exit={{ opacity: 0, y: -24 }}
|
||||||
>
|
transition={{ duration: 0.4, ease: "easeInOut" }}
|
||||||
{isUploading ? "Uploading..." : "Add a Document"}
|
>
|
||||||
</Button>
|
<Button
|
||||||
<input
|
size="sm"
|
||||||
ref={fileInputRef}
|
variant="outline"
|
||||||
type="file"
|
onClick={handleUploadClick}
|
||||||
onChange={handleFileChange}
|
disabled={isUploading}
|
||||||
className="hidden"
|
>
|
||||||
accept=".pdf,.doc,.docx,.txt,.md,.rtf,.odt"
|
{isUploading ? "Uploading..." : "Add a Document"}
|
||||||
/>
|
</Button>
|
||||||
</div>
|
<input
|
||||||
|
ref={fileInputRef}
|
||||||
|
type="file"
|
||||||
|
onChange={handleFileChange}
|
||||||
|
className="hidden"
|
||||||
|
accept=".pdf,.doc,.docx,.txt,.md,.rtf,.odt"
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
) : (
|
||||||
|
<motion.div
|
||||||
|
key="ingest-steps"
|
||||||
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.4, ease: "easeInOut" }}
|
||||||
|
>
|
||||||
|
<AnimatedProviderSteps
|
||||||
|
currentStep={currentStep}
|
||||||
|
setCurrentStep={setCurrentStep}
|
||||||
|
steps={STEP_LIST}
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,12 @@ import { cn } from "@/lib/utils";
|
||||||
export function AnimatedProviderSteps({
|
export function AnimatedProviderSteps({
|
||||||
currentStep,
|
currentStep,
|
||||||
setCurrentStep,
|
setCurrentStep,
|
||||||
|
steps,
|
||||||
}: {
|
}: {
|
||||||
currentStep: number;
|
currentStep: number;
|
||||||
setCurrentStep: (step: number) => void;
|
setCurrentStep: (step: number) => void;
|
||||||
|
steps: string[];
|
||||||
}) {
|
}) {
|
||||||
const steps = [
|
|
||||||
"Setting up your model provider",
|
|
||||||
"Defining schema",
|
|
||||||
"Configuring Langflow",
|
|
||||||
"Ingesting sample data",
|
|
||||||
];
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentStep < steps.length - 1) {
|
if (currentStep < steps.length - 1) {
|
||||||
|
|
@ -27,7 +23,7 @@ export function AnimatedProviderSteps({
|
||||||
}, 1000);
|
}, 1000);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}
|
}
|
||||||
}, [currentStep, setCurrentStep]);
|
}, [currentStep, setCurrentStep, steps]);
|
||||||
|
|
||||||
const isDone = currentStep >= steps.length;
|
const isDone = currentStep >= steps.length;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,15 @@ interface OnboardingCardProps {
|
||||||
onComplete: () => void;
|
onComplete: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TOTAL_PROVIDER_STEPS = 4;
|
|
||||||
|
const STEP_LIST = [
|
||||||
|
"Setting up your model provider",
|
||||||
|
"Defining schema",
|
||||||
|
"Configuring Langflow",
|
||||||
|
"Ingesting sample data",
|
||||||
|
];
|
||||||
|
|
||||||
|
const TOTAL_PROVIDER_STEPS = STEP_LIST.length;
|
||||||
|
|
||||||
const OnboardingCard = ({ onComplete }: OnboardingCardProps) => {
|
const OnboardingCard = ({ onComplete }: OnboardingCardProps) => {
|
||||||
const updatedOnboarding = process.env.UPDATED_ONBOARDING === "true";
|
const updatedOnboarding = process.env.UPDATED_ONBOARDING === "true";
|
||||||
|
|
@ -245,6 +253,7 @@ const OnboardingCard = ({ onComplete }: OnboardingCardProps) => {
|
||||||
<AnimatedProviderSteps
|
<AnimatedProviderSteps
|
||||||
currentStep={currentStep}
|
currentStep={currentStep}
|
||||||
setCurrentStep={setCurrentStep}
|
setCurrentStep={setCurrentStep}
|
||||||
|
steps={STEP_LIST}
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue