feat(ui): surface updates center across dashboard

- add /updates route and sidebar navigation entry

- show updates spotlight on Home, API Profiles, and CLIProxy pages

- export Updates page for lazy route loading consistency
This commit is contained in:
Tam Nhu Tran
2026-02-25 18:05:35 +07:00
parent e9d2515a7f
commit c7c4c87fb4
7 changed files with 74 additions and 0 deletions
+9
View File
@@ -35,6 +35,7 @@ const SettingsPage = lazy(() =>
);
const HealthPage = lazy(() => import('@/pages/health').then((m) => ({ default: m.HealthPage })));
const SharedPage = lazy(() => import('@/pages/shared').then((m) => ({ default: m.SharedPage })));
const UpdatesPage = lazy(() => import('@/pages/updates').then((m) => ({ default: m.UpdatesPage })));
// Loading fallback for lazy components
function PageLoader() {
@@ -68,6 +69,14 @@ export default function App() {
</Suspense>
}
/>
<Route
path="/updates"
element={
<Suspense fallback={<PageLoader />}>
<UpdatesPage />
</Suspense>
}
/>
<Route
path="/providers"
element={
+2
View File
@@ -11,6 +11,7 @@ import {
BarChart3,
Gauge,
Github,
Megaphone,
} from 'lucide-react';
import type { LucideIcon } from 'lucide-react';
import {
@@ -67,6 +68,7 @@ const navGroups: SidebarGroupDef[] = [
title: 'General',
items: [
{ path: '/', icon: Home, label: 'Home' },
{ path: '/updates', icon: Megaphone, label: 'Updates Center' },
{ path: '/analytics', icon: BarChart3, label: 'Analytics' },
],
},
@@ -0,0 +1,51 @@
import { Link } from 'react-router-dom';
import { BellRing, ExternalLink } from 'lucide-react';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { formatCatalogDate, getLatestSupportNotice } from '@/lib/support-updates-catalog';
import { cn } from '@/lib/utils';
export function UpdatesSpotlight({
className,
compact = false,
}: {
className?: string;
compact?: boolean;
}) {
const latest = getLatestSupportNotice();
if (!latest) {
return null;
}
const primaryCommand = latest.commands[0];
return (
<Alert variant="info" className={cn('border-dashed', className)}>
<BellRing className="h-4 w-4" />
<AlertTitle className="flex flex-wrap items-center gap-2">
<span>{latest.title}</span>
<span className="text-xs font-normal text-blue-700/80 dark:text-blue-300/80">
{formatCatalogDate(latest.publishedAt)}
</span>
</AlertTitle>
<AlertDescription className="space-y-2">
<p>{latest.summary}</p>
<div className="flex flex-wrap items-center gap-3 text-xs">
<Link
to="/updates"
className="inline-flex items-center gap-1 font-medium text-blue-700 hover:underline dark:text-blue-300"
>
Open Updates Center
<ExternalLink className="h-3.5 w-3.5" />
</Link>
{!compact && primaryCommand && (
<code className="rounded bg-blue-100/70 px-1.5 py-0.5 font-mono text-blue-800 dark:bg-blue-900/40 dark:text-blue-200">
{primaryCommand}
</code>
)}
</div>
</AlertDescription>
</Alert>
);
}
+5
View File
@@ -23,6 +23,7 @@ import { ProfileCreateDialog } from '@/components/profiles/profile-create-dialog
import { OpenRouterBanner } from '@/components/profiles/openrouter-banner';
import { OpenRouterQuickStart } from '@/components/profiles/openrouter-quick-start';
import { OpenRouterPromoCard } from '@/components/profiles/openrouter-promo-card';
import { UpdatesSpotlight } from '@/components/updates/updates-spotlight';
import { useProfiles, useDeleteProfile } from '@/hooks/use-profiles';
import { useOpenRouterModels } from '@/hooks/use-openrouter-models';
import { ConfirmDialog } from '@/components/shared/confirm-dialog';
@@ -96,6 +97,10 @@ export function ApiPage() {
{/* OpenRouter Announcement Banner */}
<OpenRouterBanner onCreateClick={() => setCreateDialogOpen(true)} />
<div className="px-4 pt-4">
<UpdatesSpotlight compact />
</div>
{/* Main Content */}
<div className="flex-1 flex min-h-0">
{/* Left Panel - Profiles List */}
+2
View File
@@ -17,6 +17,7 @@ import { AccountSafetyWarningCard } from '@/components/account/account-safety-wa
import { ProviderEditor } from '@/components/cliproxy/provider-editor';
import { ProviderLogo } from '@/components/cliproxy/provider-logo';
import { ProxyStatusWidget } from '@/components/monitoring/proxy-status-widget';
import { UpdatesSpotlight } from '@/components/updates/updates-spotlight';
import {
useCliproxy,
useCliproxyAuth,
@@ -397,6 +398,7 @@ export function CliproxyPage() {
{/* Right Panel */}
<div className="flex-1 flex flex-col min-w-0 bg-background">
<UpdatesSpotlight className="mx-4 mt-4" compact />
{showAccountSafetyWarning && <AccountSafetyWarningCard className="mx-4 mt-4" />}
{selectedVariantData && parentAuthForVariant ? (
+3
View File
@@ -7,6 +7,7 @@ import { Skeleton } from '@/components/ui/skeleton';
import { Key, Zap, Users, Activity, AlertTriangle } from 'lucide-react';
import { useOverview } from '@/hooks/use-overview';
import { useSharedSummary } from '@/hooks/use-shared';
import { UpdatesSpotlight } from '@/components/updates/updates-spotlight';
import { cn } from '@/lib/utils';
import type { LucideIcon } from 'lucide-react';
@@ -165,6 +166,8 @@ export function HomePage() {
</div>
</div>
<UpdatesSpotlight />
{/* Configuration Warning */}
{shared?.symlinkStatus && !shared.symlinkStatus.valid && (
<Alert variant="warning">
+2
View File
@@ -15,3 +15,5 @@ export { SharedPage } from './shared';
export { AnalyticsPage } from './analytics';
export { CursorPage } from './cursor';
export { UpdatesPage } from './updates';