mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
🕑 fix: Add Suspense to Connection Error Messages (#3074)
This commit is contained in:
parent
0294cfc881
commit
2cf5228021
5 changed files with 72 additions and 8 deletions
|
|
@ -5,6 +5,7 @@ import Plugin from '~/components/Messages/Content/Plugin';
|
|||
import Error from '~/components/Messages/Content/Error';
|
||||
import { DelayedRender } from '~/components/ui';
|
||||
import EditMessage from './EditMessage';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import Container from './Container';
|
||||
import Markdown from './Markdown';
|
||||
import { cn } from '~/utils';
|
||||
|
|
@ -14,6 +15,38 @@ export const ErrorMessage = ({
|
|||
message,
|
||||
className = '',
|
||||
}: Pick<TDisplayProps, 'text' | 'className' | 'message'>) => {
|
||||
const localize = useLocalize();
|
||||
if (text === 'Error connecting to server, try refreshing the page.') {
|
||||
console.log('error message', message);
|
||||
return (
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="text-message mb-[0.625rem] mt-1 flex min-h-[20px] flex-col items-start gap-3 overflow-x-auto">
|
||||
<div className="markdown prose dark:prose-invert light w-full break-words dark:text-gray-100">
|
||||
<div className="absolute">
|
||||
<p className="relative">
|
||||
<span className="result-thinking" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<DelayedRender delay={5500}>
|
||||
<Container message={message}>
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-md border border-red-500 bg-red-500/10 px-3 py-2 text-sm text-gray-600 dark:text-gray-200',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{localize('com_ui_error_connection')}
|
||||
</div>
|
||||
</Container>
|
||||
</DelayedRender>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Container message={message}>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -58,7 +58,11 @@ export default function HoverButtons({
|
|||
return null;
|
||||
}
|
||||
|
||||
const { isCreatedByUser } = message;
|
||||
const { isCreatedByUser, error } = message;
|
||||
|
||||
if (error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const onEdit = () => {
|
||||
if (isEditing) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export default function Message(props: TMessageProps) {
|
|||
edit,
|
||||
index,
|
||||
isLast,
|
||||
assistant,
|
||||
enterEdit,
|
||||
handleScroll,
|
||||
conversation,
|
||||
|
|
@ -44,6 +45,8 @@ export default function Message(props: TMessageProps) {
|
|||
let messageLabel = '';
|
||||
if (isCreatedByUser) {
|
||||
messageLabel = UsernameDisplay ? user?.name || user?.username : localize('com_user_message');
|
||||
} else if (assistant) {
|
||||
messageLabel = assistant.name ?? 'Assistant';
|
||||
} else {
|
||||
messageLabel = message.sender;
|
||||
}
|
||||
|
|
@ -61,7 +64,7 @@ export default function Message(props: TMessageProps) {
|
|||
<div>
|
||||
<div className="pt-0.5">
|
||||
<div className="flex h-6 w-6 items-center justify-center overflow-hidden rounded-full">
|
||||
<Icon message={message} conversation={conversation} />
|
||||
<Icon message={message} conversation={conversation} assistant={assistant} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,37 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
const useDelayedRender = (delay: number) => {
|
||||
const [delayed, setDelayed] = useState(true);
|
||||
const timerPromiseRef = useRef<Promise<void> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const timeout = setTimeout(() => setDelayed(false), delay);
|
||||
return () => clearTimeout(timeout);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
return (fn: () => ReactNode) => !delayed && fn();
|
||||
if (delayed) {
|
||||
const timerPromise = new Promise<void>((resolve) => {
|
||||
const timeout = setTimeout(() => {
|
||||
setDelayed(false);
|
||||
resolve();
|
||||
}, delay);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
});
|
||||
|
||||
timerPromiseRef.current = timerPromise;
|
||||
}
|
||||
|
||||
return () => {
|
||||
timerPromiseRef.current = null;
|
||||
};
|
||||
}, [delay, delayed]);
|
||||
|
||||
return (fn: () => ReactNode) => {
|
||||
if (delayed && timerPromiseRef.current) {
|
||||
throw timerPromiseRef.current;
|
||||
}
|
||||
return fn();
|
||||
};
|
||||
};
|
||||
|
||||
export default useDelayedRender;
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ export default {
|
|||
com_ui_instructions: 'Instructions',
|
||||
com_ui_description: 'Description',
|
||||
com_ui_error: 'Error',
|
||||
com_ui_error_connection: 'Error connecting to server, try refreshing the page.',
|
||||
com_ui_select: 'Select',
|
||||
com_ui_input: 'Input',
|
||||
com_ui_close: 'Close',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue