diff --git a/apps/studio/src/components/organization-switcher.tsx b/apps/studio/src/components/organization-switcher.tsx index d2060e070..796217bc4 100644 --- a/apps/studio/src/components/organization-switcher.tsx +++ b/apps/studio/src/components/organization-switcher.tsx @@ -11,7 +11,7 @@ import { useMemo, useState } from 'react'; import { useNavigate } from '@tanstack/react-router'; -import { Building2, Check, ChevronsUpDown, Plus } from 'lucide-react'; +import { Check, ChevronsUpDown, Plus } from 'lucide-react'; import { DropdownMenu, DropdownMenuContent, @@ -68,7 +68,6 @@ export function OrganizationSwitcher() { className="h-8 gap-2 px-2 text-sm font-medium" disabled={switching} > - {active ? ( {active.name} ) : ( @@ -76,7 +75,7 @@ export function OrganizationSwitcher() { {loading ? 'Loading…' : 'Select organization'} )} - + diff --git a/apps/studio/src/components/project-switcher.tsx b/apps/studio/src/components/project-switcher.tsx index 9c6a14236..120d6bc2d 100644 --- a/apps/studio/src/components/project-switcher.tsx +++ b/apps/studio/src/components/project-switcher.tsx @@ -20,7 +20,7 @@ import { useMemo, useState } from 'react'; import { useNavigate, useParams } from '@tanstack/react-router'; -import { ChevronsUpDown, Layers, Plus, Search, Check } from 'lucide-react'; +import { ChevronsUpDown, Plus, Search, Check } from 'lucide-react'; import type { Project, ProjectType } from '@objectstack/spec/cloud'; import { DropdownMenu, @@ -110,7 +110,6 @@ export function ProjectSwitcher() { size="sm" className="h-8 gap-2 px-2 text-sm font-medium" > - {active ? ( <> @@ -123,7 +122,7 @@ export function ProjectSwitcher() { {loading ? 'Loading projects…' : 'Select project'} )} - + = { action: 'Actions', @@ -61,20 +59,19 @@ const META_TYPE_LABELS: Record = { theme: 'Themes', }; -interface TopBarProps { - /** List of installed packages for the PackageSwitcher dropdown */ - packages?: InstalledPackage[]; - /** Currently selected package */ - selectedPackage?: InstalledPackage | null; - /** Callback when a package is selected from the dropdown */ - onSelectPackage?: (pkg: InstalledPackage) => void; +function StudioBrand() { + return ( + + + + ); +} + +function SlashDivider() { + return /; } -export function TopBar({ - packages = [], - selectedPackage = null, - onSelectPackage = () => {}, -}: TopBarProps) { +export function TopBar() { const location = useLocation(); const params = useParams({ strict: false }) as { package?: string; @@ -130,24 +127,15 @@ export function TopBar({ items.push({ label: 'Overview' }); break; case 'package-overview': - if (selectedPackage?.manifest?.name) { - items.push({ label: selectedPackage.manifest.name }); - } items.push({ label: 'Overview' }); break; case 'object': - if (selectedPackage?.manifest?.name) { - items.push({ label: selectedPackage.manifest.name }); - } items.push({ label: 'Objects' }); if (params.name) { items.push({ label: params.name }); } break; case 'metadata': - if (selectedPackage?.manifest?.name) { - items.push({ label: selectedPackage.manifest.name }); - } if (params.type) { items.push({ label: META_TYPE_LABELS[params.type] || params.type }); } @@ -160,7 +148,7 @@ export function TopBar({ } return items; - }, [viewType, params, selectedPackage]); + }, [viewType, params]); // Compute API badge for object/metadata views const apiBadge = useMemo(() => { @@ -173,26 +161,15 @@ export function TopBar({ return null; }, [viewType, params]); - // Show PackageSwitcher only when we're in a package context - const showPackageSwitcher = params.package && packages.length > 0; - return (
- {/* Left segment: Org + Env + Package switchers */} -
+ {/* Left segment: Brand + Org + Project switchers */} +
+ + - + - {showPackageSwitcher && ( - <> - - - - )} diff --git a/apps/studio/src/routes/__root.tsx b/apps/studio/src/routes/__root.tsx index 508f66435..b75784fd7 100644 --- a/apps/studio/src/routes/__root.tsx +++ b/apps/studio/src/routes/__root.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import { createRootRoute, Outlet, useLocation, useNavigate, useParams } from '@tanstack/react-router'; -import { useEffect, useMemo } from 'react'; +import { createRootRoute, Outlet, useLocation, useNavigate } from '@tanstack/react-router'; +import { useEffect } from 'react'; import { ObjectStackProvider } from '@objectstack/client-react'; import { ErrorBoundary } from '../components/ErrorBoundary'; import { SidebarProvider } from '@/components/ui/sidebar'; @@ -13,8 +13,6 @@ import { PluginRegistryProvider } from '../plugins'; import { builtInPlugins } from '../plugins/built-in'; import { useObjectStackClient } from '../hooks/useObjectStackClient'; import { SessionProvider, useSession } from '../hooks/useSession'; -import { useEnvAwarePackages } from '../hooks/useProjectAwarePackages'; -import type { InstalledPackage } from '@objectstack/spec/kernel'; /** Routes that don't require authentication. */ const PUBLIC_ROUTES = new Set(['/login', '/register']); @@ -39,47 +37,8 @@ function RequireAuth({ children }: { children: React.ReactNode }) { const { user, loading } = useSession(); const navigate = useNavigate(); const location = useLocation(); - const params = useParams({ strict: false }) as { projectId?: string; package?: string }; const isPublic = PUBLIC_ROUTES.has(location.pathname); - // Get packages for TopBar PackageSwitcher - const { packages, selectedPackage, setSelectedPackage } = - useEnvAwarePackages(params.projectId); - - // Extract the $package segment from the URL - const activePackageId = useMemo(() => { - if (!params.package) return undefined; - // Reserved segments that are NOT package ids - if (params.package === 'packages') return undefined; - return params.package; - }, [params.package]); - - // Sync selectedPackage with URL - useEffect(() => { - if (!activePackageId) { - if (selectedPackage) setSelectedPackage(null); - return; - } - if (!packages.length) return; - const pkg = packages.find( - (p) => - p.manifest?.id === activePackageId || - p.manifest?.id?.endsWith('.' + activePackageId), - ); - if (pkg && pkg !== selectedPackage) setSelectedPackage(pkg); - }, [activePackageId, packages, selectedPackage, setSelectedPackage]); - - const handleSelectPackage = (pkg: InstalledPackage) => { - const nextId = pkg.manifest?.id; - if (!nextId) return; - if (params.projectId) { - navigate({ - to: '/projects/$projectId/$package', - params: { projectId: params.projectId, package: nextId }, - }); - } - }; - // Redirect to environment picker when the user hits a route that requires // an environment context (e.g. /$package/*) but isn't already under /projects. useEffect(() => { @@ -113,11 +72,7 @@ function RequireAuth({ children }: { children: React.ReactNode }) { return (
- +
{children}