fix(web): improve backend retry and sidebar scrolling

This commit is contained in:
Junyan Qin
2026-05-19 11:40:20 +08:00
parent 257d9d3a65
commit d80972417e
12 changed files with 220 additions and 41 deletions

View File

@@ -1,12 +1,51 @@
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import { AlertCircle, Home, RefreshCw } from 'lucide-react';
import { useLocation, useNavigate } from 'react-router-dom';
import { AlertCircle, Home, Loader2, RefreshCw } from 'lucide-react';
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { initializeSystemInfo, systemInfo } from '@/app/infra/http';
const RETURN_TO_STORAGE_KEY = 'langbot_backend_unavailable_return_to';
type BackendUnavailableLocationState = {
from?: string;
};
export default function BackendUnavailablePage() {
const { t } = useTranslation();
const navigate = useNavigate();
const location = useLocation();
const [checking, setChecking] = useState(false);
const [retryError, setRetryError] = useState<string | null>(null);
async function handleRetry() {
setChecking(true);
setRetryError(null);
try {
await initializeSystemInfo({ throwOnError: true });
const state = location.state as BackendUnavailableLocationState | null;
const storedReturnTo = sessionStorage.getItem(RETURN_TO_STORAGE_KEY);
const returnTo = state?.from || storedReturnTo || '/home';
sessionStorage.removeItem(RETURN_TO_STORAGE_KEY);
if (systemInfo.wizard_status === 'none') {
navigate('/wizard', { replace: true });
return;
}
navigate(returnTo === '/backend-unavailable' ? '/home' : returnTo, {
replace: true,
});
} catch (error) {
setRetryError(
error instanceof Error ? error.message : t('errorPage.retryFailed'),
);
} finally {
setChecking(false);
}
}
return (
<div className="flex min-h-screen items-center justify-center bg-background px-4">
@@ -27,6 +66,12 @@ export default function BackendUnavailablePage() {
{t('common.loginLoadErrorDesc')}
</p>
{retryError ? (
<p className="mt-4 rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive">
{t('errorPage.retryFailed')}
</p>
) : null}
<div className="mt-8 flex flex-col gap-3 sm:flex-row">
<Button
variant="outline"
@@ -36,9 +81,13 @@ export default function BackendUnavailablePage() {
<Home className="h-4 w-4" />
{t('errorPage.backToLogin')}
</Button>
<Button className="gap-2" onClick={() => window.location.reload()}>
<RefreshCw className="h-4 w-4" />
{t('common.retry')}
<Button className="gap-2" onClick={handleRetry} disabled={checking}>
{checking ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
<RefreshCw className="h-4 w-4" />
)}
{checking ? t('errorPage.retrying') : t('common.retry')}
</Button>
</div>
</div>

View File

@@ -374,9 +374,13 @@ function SidebarSeparator({
);
}
function SidebarContent({ className, ...props }: React.ComponentProps<'div'>) {
const SidebarContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<'div'>
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-slot="sidebar-content"
data-sidebar="content"
className={cn(
@@ -386,7 +390,8 @@ function SidebarContent({ className, ...props }: React.ComponentProps<'div'>) {
{...props}
/>
);
}
});
SidebarContent.displayName = 'SidebarContent';
function SidebarGroup({ className, ...props }: React.ComponentProps<'div'>) {
return (