diff --git a/web/src/app/RootLayout.tsx b/web/src/app/RootLayout.tsx index 3a5dffb12..444de4b4a 100644 --- a/web/src/app/RootLayout.tsx +++ b/web/src/app/RootLayout.tsx @@ -1,15 +1,9 @@ import { Outlet } from 'react-router-dom'; import { useDocumentTitle } from '@/hooks/useDocumentTitle'; -import { BetaBanner } from '@/components/BetaBanner'; // Top-level route layout: drives the dynamic document title from the active // route and renders the matched child route via . export default function RootLayout() { useDocumentTitle(); - return ( - <> - - - - ); + return ; } diff --git a/web/src/app/home/components/workspace-settings/cloud-plans.ts b/web/src/app/home/components/workspace-settings/cloud-plans.ts index 18dd07c62..7f5cc2cf6 100644 --- a/web/src/app/home/components/workspace-settings/cloud-plans.ts +++ b/web/src/app/home/components/workspace-settings/cloud-plans.ts @@ -104,7 +104,7 @@ export function cloudPlanCheckoutURL( ): string { const url = spaceURL(base, '/cloud'); url.search = new URLSearchParams({ - environment: 'beta', + environment: 'new', step: 'plan', workspace, plan, @@ -121,7 +121,7 @@ export function cloudSubscriptionManagementURL( ): string { const url = spaceURL(base, '/cloud'); url.search = new URLSearchParams({ - environment: 'beta', + environment: 'new', step: 'subscription', workspace, }).toString(); diff --git a/web/src/app/wizard/page.tsx b/web/src/app/wizard/page.tsx index 0409568f0..d9bb49d10 100644 --- a/web/src/app/wizard/page.tsx +++ b/web/src/app/wizard/page.tsx @@ -1059,10 +1059,7 @@ export default function WizardPage() { if (isLoading) { return ( -
+
); @@ -1076,10 +1073,7 @@ export default function WizardPage() { ]; return ( -
+
{/* Top bar: Skip button */}
diff --git a/web/src/components/BetaBanner.tsx b/web/src/components/BetaBanner.tsx deleted file mode 100644 index 87e09a2fa..000000000 --- a/web/src/components/BetaBanner.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { useTranslation } from 'react-i18next'; -import { AlertCircle, X } from 'lucide-react'; -import { useState, useEffect, useRef } from 'react'; -import { Alert, AlertDescription } from '@/components/ui/alert'; -import { backendClient } from '@/app/infra/http'; - -const RETRY_DELAYS_MS = [1000, 2000, 4000, 8000]; -const CLOUD_BETA_RETRY_LIMIT = RETRY_DELAYS_MS.length; - -export function BetaBanner() { - const { t } = useTranslation(); - const bannerRef = useRef(null); - const [show, setShow] = useState(false); - const [dismissed, setDismissed] = useState(false); - const visible = show && !dismissed; - - // Publish the banner height so the fixed app shell (sidebar + inset) starts - // below the notice instead of painting over it. - useEffect(() => { - const root = document.documentElement; - if (!visible) { - root.style.removeProperty('--beta-banner-height'); - return; - } - const element = bannerRef.current; - if (!element) { - return; - } - const sync = () => { - root.style.setProperty( - '--beta-banner-height', - `${element.getBoundingClientRect().height}px`, - ); - }; - sync(); - const observer = new ResizeObserver(sync); - observer.observe(element); - return () => { - observer.disconnect(); - root.style.removeProperty('--beta-banner-height'); - }; - }, [visible]); - - useEffect(() => { - let cancelled = false; - let retryTimer: number | undefined; - - const checkBetaStatus = async (attempt = 0) => { - try { - const info = await backendClient.getSystemInfo(); - if (cancelled) { - return; - } - setShow(info.deployment_mode === 'cloud' && info.beta === true); - } catch { - if (cancelled) { - return; - } - // A single failed probe (cold start, restarting backend, flaky - // network) must not hide the banner for the rest of the session, so - // keep the last known state and retry with backoff. - if (attempt < CLOUD_BETA_RETRY_LIMIT) { - retryTimer = window.setTimeout( - () => void checkBetaStatus(attempt + 1), - RETRY_DELAYS_MS[attempt], - ); - } - } - }; - - void checkBetaStatus(); - - const recheck = () => { - if (!cancelled) { - void checkBetaStatus(); - } - }; - window.addEventListener('focus', recheck); - - return () => { - cancelled = true; - clearTimeout(retryTimer); - window.removeEventListener('focus', recheck); - }; - }, []); - - if (!visible) { - return null; - } - - // The cloud product page opens the dedicated (paid v1) environment tab; - // space.langbot.app resolves the locale itself, so no path prefix applies. - const cloudUrl = 'https://space.langbot.app/cloud?environment=dedicated'; - const ossUrl = 'https://github.com/langbot-app/LangBot'; - - return ( - - - -
- - {t('beta_banner.message')}{' '} - - {t('beta_banner.cloud_link')} - {' '} - {t('beta_banner.or')}{' '} - - {t('beta_banner.oss_link')} - - {t('beta_banner.period')} - - -
-
-
- ); -} diff --git a/web/src/components/ui/sidebar.tsx b/web/src/components/ui/sidebar.tsx index 3ef69ff30..d142aaf03 100644 --- a/web/src/components/ui/sidebar.tsx +++ b/web/src/components/ui/sidebar.tsx @@ -203,9 +203,7 @@ function SidebarProvider({ { '--sidebar-width': `${sidebarWidth}px`, '--sidebar-width-icon': SIDEBAR_WIDTH_ICON, - // Global notices (e.g. the beta banner) publish their height so - // the shell starts below them instead of underneath. - height: 'calc(100svh - var(--beta-banner-height, 0px))', + height: '100svh', ...style, } as React.CSSProperties } @@ -302,8 +300,8 @@ function Sidebar({