fix: added empty message on file upload handling, fixed time calculation on onboarding (#316)

* fixed miscalculation of provider steps

* Handled empty message with file

* fixed same key
This commit is contained in:
Lucas Oliveira 2025-10-27 18:08:27 -03:00 committed by GitHub
parent 31681bb0d9
commit a7af519d01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 90 additions and 53 deletions

View file

@ -594,8 +594,8 @@ export function Navigation({
No documents yet
</div>
) : (
newConversationFiles?.map((file) => (
<div key={`${file}`} className="flex-1 min-w-0 px-3">
newConversationFiles?.map((file, index) => (
<div key={`${file}-${index}`} className="flex-1 min-w-0 px-3">
<div className="text-mmd font-medium text-foreground truncate">
{file}
</div>

View file

@ -6,7 +6,7 @@ import { cn } from "@/lib/utils";
import { Message } from "./message";
interface UserMessageProps {
content: string;
content: string | undefined;
isCompleted?: boolean;
animate?: boolean;
files?: string;

View file

@ -9,7 +9,7 @@ import { type EndpointType, useChat } from "@/contexts/chat-context";
import { useKnowledgeFilter } from "@/contexts/knowledge-filter-context";
import { useTask } from "@/contexts/task-context";
import { useChatStreaming } from "@/hooks/useChatStreaming";
import { FILES_REGEX } from "@/lib/constants";
import { FILE_CONFIRMATION, FILES_REGEX } from "@/lib/constants";
import { useLoadingStore } from "@/stores/loadingStore";
import { useGetNudgesQuery } from "../api/queries/useGetNudgesQuery";
import { AssistantMessage } from "./components/assistant-message";
@ -911,9 +911,9 @@ function ChatPage() {
}
// Only send message if there's input text
if (input.trim()) {
if (input.trim() || uploadedFile) {
// Pass the responseId from upload (if any) to handleSendMessage
handleSendMessage(input, uploadedResponseId || undefined);
handleSendMessage(!input.trim() ? FILE_CONFIRMATION : input, uploadedResponseId || undefined);
}
};
@ -1154,6 +1154,8 @@ function ChatPage() {
}
};
console.log(messages)
return (
<>
{/* Debug header - only show in debug mode */}
@ -1236,7 +1238,10 @@ function ChatPage() {
? message.source !== "langflow"
: false
}
content={message.content}
content={index >= 2
&& (messages[index - 2]?.content.match(
FILES_REGEX,
)?.[0] ?? undefined) && message.content === FILE_CONFIRMATION ? undefined : message.content}
files={
index >= 2
? messages[index - 2]?.content.match(

View file

@ -19,34 +19,30 @@ export function AnimatedProviderSteps({
setCurrentStep,
steps,
storageKey = "provider-steps",
processingStartTime,
}: {
currentStep: number;
isCompleted: boolean;
setCurrentStep: (step: number) => void;
steps: string[];
storageKey?: string;
processingStartTime?: number | null;
}) {
const [startTime, setStartTime] = useState<number | null>(null);
const [elapsedTime, setElapsedTime] = useState<number>(0);
// Initialize start time from local storage or set new one
// Initialize start time from prop or local storage
useEffect(() => {
const storedStartTime = localStorage.getItem(`${storageKey}-start`);
const storedElapsedTime = localStorage.getItem(`${storageKey}-elapsed`);
if (isCompleted && storedElapsedTime) {
// If completed, use stored elapsed time
setElapsedTime(parseFloat(storedElapsedTime));
} else if (storedStartTime) {
// If in progress, use stored start time
setStartTime(parseInt(storedStartTime));
} else {
// First time, set new start time
const now = Date.now();
setStartTime(now);
localStorage.setItem(`${storageKey}-start`, now.toString());
} else if (processingStartTime) {
// Use the start time passed from parent (when user clicked Complete)
setStartTime(processingStartTime);
}
}, [storageKey, isCompleted]);
}, [storageKey, isCompleted, processingStartTime]);
// Progress through steps
useEffect(() => {
@ -64,7 +60,6 @@ export function AnimatedProviderSteps({
const elapsed = Date.now() - startTime;
setElapsedTime(elapsed);
localStorage.setItem(`${storageKey}-elapsed`, elapsed.toString());
localStorage.removeItem(`${storageKey}-start`);
}
}, [isCompleted, startTime, storageKey]);

View file

@ -32,12 +32,11 @@ interface OnboardingCardProps {
setLoadingStatus?: (status: string[]) => void;
}
const STEP_LIST = [
"Setting up your model provider",
"Defining schema",
"Configuring Langflow",
"Ingesting sample data",
"Setting up your model provider",
"Defining schema",
"Configuring Langflow",
"Ingesting sample data",
];
const TOTAL_PROVIDER_STEPS = STEP_LIST.length;
@ -106,7 +105,13 @@ const OnboardingCard = ({
llm_model: "",
});
const [currentStep, setCurrentStep] = useState<number | null>(isCompleted ? TOTAL_PROVIDER_STEPS : null);
const [currentStep, setCurrentStep] = useState<number | null>(
isCompleted ? TOTAL_PROVIDER_STEPS : null,
);
const [processingStartTime, setProcessingStartTime] = useState<number | null>(
null,
);
// Query tasks to track completion
const { data: tasks } = useGetTasksQuery({
@ -131,8 +136,8 @@ const OnboardingCard = ({
// If no active tasks and we've started onboarding, complete it
if (
(!activeTasks || (activeTasks.processed_files ?? 0) > 0) &&
tasks.length > 0
&& !isCompleted
tasks.length > 0 &&
!isCompleted
) {
// Set to final step to show "Done"
setCurrentStep(TOTAL_PROVIDER_STEPS);
@ -189,6 +194,8 @@ const OnboardingCard = ({
onboardingData.project_id = settings.project_id;
}
// Record the start time when user clicks Complete
setProcessingStartTime(Date.now());
onboardingMutation.mutate(onboardingData);
setCurrentStep(0);
};
@ -211,30 +218,55 @@ const OnboardingCard = ({
onValueChange={handleSetModelProvider}
>
<TabsList className="mb-4">
<TabsTrigger
value="openai"
>
<div className={cn("flex items-center justify-center gap-2 w-8 h-8 rounded-md", modelProvider === "openai" ? "bg-white" : "bg-muted")}>
<OpenAILogo className={cn("w-4 h-4 shrink-0", modelProvider === "openai" ? "text-black" : "text-muted-foreground")} />
<TabsTrigger value="openai">
<div
className={cn(
"flex items-center justify-center gap-2 w-8 h-8 rounded-md",
modelProvider === "openai" ? "bg-white" : "bg-muted",
)}
>
<OpenAILogo
className={cn(
"w-4 h-4 shrink-0",
modelProvider === "openai"
? "text-black"
: "text-muted-foreground",
)}
/>
</div>
OpenAI
</TabsTrigger>
<TabsTrigger
value="watsonx"
>
<div className={cn("flex items-center justify-center gap-2 w-8 h-8 rounded-md", modelProvider === "watsonx" ? "bg-[#1063FE]" : "bg-muted")}>
<IBMLogo className={cn("w-4 h-4 shrink-0", modelProvider === "watsonx" ? "text-white" : "text-muted-foreground")} />
<TabsTrigger value="watsonx">
<div
className={cn(
"flex items-center justify-center gap-2 w-8 h-8 rounded-md",
modelProvider === "watsonx" ? "bg-[#1063FE]" : "bg-muted",
)}
>
<IBMLogo
className={cn(
"w-4 h-4 shrink-0",
modelProvider === "watsonx"
? "text-white"
: "text-muted-foreground",
)}
/>
</div>
IBM watsonx.ai
</TabsTrigger>
<TabsTrigger
value="ollama"
>
<div className={cn("flex items-center justify-center gap-2 w-8 h-8 rounded-md", modelProvider === "ollama" ? "bg-white" : "bg-muted")}>
<TabsTrigger value="ollama">
<div
className={cn(
"flex items-center justify-center gap-2 w-8 h-8 rounded-md",
modelProvider === "ollama" ? "bg-white" : "bg-muted",
)}
>
<OllamaLogo
className={cn(
"w-4 h-4 shrink-0",
modelProvider === "ollama" ? "text-black" : "text-muted-foreground",
modelProvider === "ollama"
? "text-black"
: "text-muted-foreground",
)}
/>
</div>
@ -285,11 +317,13 @@ const OnboardingCard = ({
</TooltipTrigger>
{!isComplete && (
<TooltipContent>
{isLoadingModels ? "Loading models..." : (!!settings.llm_model &&
!!settings.embedding_model &&
!isDoclingHealthy
? "docling-serve must be running to continue"
: "Please fill in all required fields")}
{isLoadingModels
? "Loading models..."
: !!settings.llm_model &&
!!settings.embedding_model &&
!isDoclingHealthy
? "docling-serve must be running to continue"
: "Please fill in all required fields"}
</TooltipContent>
)}
</Tooltip>
@ -303,11 +337,12 @@ const OnboardingCard = ({
transition={{ duration: 0.4, ease: "easeInOut" }}
>
<AnimatedProviderSteps
currentStep={currentStep}
isCompleted={isCompleted}
setCurrentStep={setCurrentStep}
steps={STEP_LIST}
/>
currentStep={currentStep}
isCompleted={isCompleted}
setCurrentStep={setCurrentStep}
steps={STEP_LIST}
processingStartTime={processingStartTime}
/>
</motion.div>
)}
</AnimatePresence>

View file

@ -35,4 +35,6 @@ export const TOTAL_ONBOARDING_STEPS = 3;
export const ONBOARDING_STEP_KEY = "onboarding_current_step";
export const FILES_REGEX =
/(?<=I'm uploading a document called ['"])[^'"]+\.[^.]+(?=['"]\. Here is its content:)/;
/(?<=I'm uploading a document called ['"])[^'"]+\.[^.]+(?=['"]\. Here is its content:)/;
export const FILE_CONFIRMATION = "Confirm that you received this file.";