remove dashboard/

This commit is contained in:
Francesco Sansalvadore committed 2026-03-20 01:37:55 +01:00
1 parent 25f7d8f28c
commit 32768bcdfd
61 files changed
+166 -28

No files matched your search

@@ -6,6 +6,6 @@ export default async function V2OrgProjectPage({
params: Promise<{ projectRef: string }>
}) {
const { projectRef } = await params
redirect(`/dashboard/v2/project/${projectRef}`)
redirect(`/v2/project/${projectRef}`)
}
@@ -36,7 +36,7 @@ function OrgDashboardContent() {
{projects.map((proj) => (
<li key={proj.ref}>
<Link
href={`/dashboard/v2/project/${proj.ref}`}
href={`/v2/project/${proj.ref}`}
className="text-sm text-foreground hover:underline"
>
{proj.name}
@@ -21,7 +21,7 @@ export default function TableDetailLayout({ children }: { children: React.ReactN
const { projectRef } = useV2Params()
const tableId = params?.tableId as string
const base = projectRef ? `/dashboard/v2/project/${projectRef}/data/tables/${tableId}` : ''
const base = projectRef ? `/v2/project/${projectRef}/data/tables/${tableId}` : ''
return (
<StudioDataWorkspace projectRef={projectRef} id={tableId}>
@@ -6,5 +6,5 @@ export default async function TableDetailPage({
params: Promise<{ projectRef: string; tableId: string }>
}) {
const { projectRef, tableId } = await params
redirect(`/dashboard/v2/project/${projectRef}/data/tables/${tableId}/data`)
redirect(`/v2/project/${projectRef}/data/tables/${tableId}/data`)
}
@@ -0,0 +1,138 @@
'use client'
import { useState } from 'react'
import { useParams, useRouter } from 'next/navigation'
import { Building2, ChevronRight, Search } from 'lucide-react'
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
import { useOrgProjectsInfiniteQuery } from 'data/projects/org-projects-infinite-query'
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
/**
* Disambiguation page for /v2/project/_/[...routeSlug].
*
* The literal `_` segment can never collide with a real project ref, so any
* link that doesn't yet know the target project (e.g. deep-links from docs or
* CLI output) can point here. The user picks a project and is forwarded to
* /v2/project/[projectRef]/[...routeSlug] with the same sub-path preserved.
*/
export default function V2ProjectDisambiguationPage() {
const router = useRouter()
const params = useParams()
const routeSlug = params?.routeSlug as string[] | undefined
const subPath = routeSlug?.length ? `/${routeSlug.join('/')}` : '/data/tables'
const { data: organizations = [], isPending: isLoadingOrgs } = useOrganizationsQuery()
const [selectedOrgSlug, setSelectedOrgSlug] = useState<string | undefined>(undefined)
const activeOrg =
organizations.find((o) => o.slug === selectedOrgSlug) ?? organizations[0]
const [search, setSearch] = useState('')
const { data: projectsData, isPending: isLoadingProjects } = useOrgProjectsInfiniteQuery(
{ slug: activeOrg?.slug, limit: 50 },
{ enabled: Boolean(activeOrg?.slug) }
)
const allProjects = projectsData?.pages?.flatMap((p) => p.projects) ?? []
const projects = search.trim()
? allProjects.filter((p) => p.name.toLowerCase().includes(search.toLowerCase()))
: allProjects
const handleSelectProject = (ref: string) => {
router.push(`/v2/project/${ref}${subPath}`)
}
return (
<div className="flex flex-col h-screen bg-background">
{/* Header */}
<div className="px-8 py-6 border-b border-border">
<h1 className="text-xl font-semibold text-foreground">Select a project</h1>
{subPath !== '/data/tables' && (
<p className="text-sm text-muted-foreground mt-1">
You'll be taken to <span className="font-mono text-xs">{subPath}</span> after selecting.
</p>
)}
</div>
<div className="flex flex-1 min-h-0">
{/* Org sidebar */}
<aside className="w-56 shrink-0 border-r border-border overflow-y-auto py-2">
{isLoadingOrgs ? (
<div className="space-y-1 px-3 py-2">
<ShimmeringLoader className="h-7" />
<ShimmeringLoader className="h-7 w-4/5" />
</div>
) : (
organizations.map((org) => {
const isActive = org.slug === (activeOrg?.slug)
return (
<button
key={org.slug}
type="button"
onClick={() => setSelectedOrgSlug(org.slug)}
className={`w-full flex items-center gap-2.5 px-3 py-2 text-sm text-left transition-colors ${
isActive
? 'bg-sidebar-accent text-foreground font-medium'
: 'text-muted-foreground hover:text-foreground hover:bg-sidebar-accent/50'
}`}
>
<Building2 className="h-3.5 w-3.5 shrink-0" strokeWidth={1.5} />
<span className="truncate">{org.name}</span>
</button>
)
})
)}
</aside>
{/* Project list */}
<main className="flex-1 min-w-0 flex flex-col overflow-hidden">
<div className="px-4 py-3 border-b border-border shrink-0">
<div className="relative">
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground" />
<input
type="text"
placeholder="Search projects…"
value={search}
onChange={(e) => setSearch(e.target.value)}
className="w-full pl-8 pr-3 py-1.5 text-sm bg-background border border-border rounded-md focus:outline-none focus:ring-1 focus:ring-foreground/30 placeholder:text-muted-foreground"
/>
</div>
</div>
<div className="flex-1 overflow-y-auto">
{isLoadingProjects ? (
<div className="space-y-1 p-4">
<ShimmeringLoader className="h-10" />
<ShimmeringLoader className="h-10 w-4/5" />
<ShimmeringLoader className="h-10 w-3/5" />
</div>
) : projects.length === 0 ? (
<div className="flex items-center justify-center h-32 text-sm text-muted-foreground">
{search ? 'No projects match your search.' : 'No projects in this organization.'}
</div>
) : (
<ul className="divide-y divide-border">
{projects.map((project) => (
<li key={project.ref}>
<button
type="button"
onClick={() => handleSelectProject(project.ref)}
className="w-full flex items-center justify-between px-5 py-3.5 text-left hover:bg-sidebar-accent/50 transition-colors group"
>
<div>
<div className="text-sm font-medium text-foreground">{project.name}</div>
<div className="text-xs text-muted-foreground font-mono">{project.ref}</div>
</div>
<ChevronRight className="h-4 w-4 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity shrink-0" />
</button>
</li>
))}
</ul>
)}
</div>
</main>
</div>
</div>
)
}
@@ -66,7 +66,7 @@ export const TableGridEditor = ({
const onTableCreated = useCallback(
(table: { id: number }) => {
if (variant === 'v2') {
const base = projectRef ? `/dashboard/v2/project/${projectRef}` : ''
const base = projectRef ? `/v2/project/${projectRef}` : ''
router.push(
`${base}/data/tables/${table.id}/data${
!!selectedSchema ? `?schema=${selectedSchema}` : ''
@@ -95,7 +95,7 @@ export const TableGridEditor = ({
tabs.removeTab(tabId)
setLastVisitedTable(undefined)
const base = projectRef ? `/dashboard/v2/project/${projectRef}` : ''
const base = projectRef ? `/v2/project/${projectRef}` : ''
router.push(`${base}/data/tables`)
return
}
@@ -158,7 +158,7 @@ export const TableGridEditor = ({
onClick={() => {
tabs.removeTab(tabId)
setLastVisitedTable(undefined)
const base = projectRef ? `/dashboard/v2/project/${projectRef}` : ''
const base = projectRef ? `/v2/project/${projectRef}` : ''
router.push(`${base}/data/tables`)
}}
>
@@ -172,7 +172,7 @@ export const TableGridEditor = ({
onClick={() => setLastVisitedTable(undefined)}
>
<Link
href={`/dashboard/v2/project/${projectRef}/data/tables/${openTabs[0].split('-')[1]}/data`}
href={`/v2/project/${projectRef}/data/tables/${openTabs[0].split('-')[1]}/data`}
>
Close tab
</Link>
@@ -184,7 +184,7 @@ export const TableGridEditor = ({
className="mt-2"
onClick={() => setLastVisitedTable(undefined)}
>
<Link href={`/dashboard/v2/project/${projectRef}/data/tables`}>Head back</Link>
<Link href={`/v2/project/${projectRef}/data/tables`}>Head back</Link>
</Button>
)
) : !!tabId ? (
+2 -2
View File
@@ -133,8 +133,8 @@ export function LeftActivityBar() {
const { data: lints } = useProjectLintsQuery({ projectRef })
const hasAdvisorWarnings = (lints?.length ?? 0) > 0
const base = projectRef ? `/dashboard/v2/project/${projectRef}` : '#'
const homeBase = projectRef && orgSlug ? `/dashboard/v2/project/${projectRef}` : '#'
const base = projectRef ? `/v2/project/${projectRef}` : '#'
const homeBase = projectRef && orgSlug ? `/v2/project/${projectRef}` : '#'
return (
<ActivityBar
+1 -1
View File
@@ -153,7 +153,7 @@ export function BrowserPanel({ onCollapse }: { onCollapse?: () => void }) {
const { expandedGroups, toggleGroup } = useV2DashboardStore()
const counts = useV2DataCounts(projectRef)
const base = projectRef ? `/dashboard/v2/project/${projectRef}` : ''
const base = projectRef ? `/v2/project/${projectRef}` : ''
const isData = pathname?.includes('/data/')
const isObs = pathname?.includes('/obs/')
const isSettings = pathname?.includes('/settings/')
+1 -1
View File
@@ -102,7 +102,7 @@ export function Chooser() {
const [search, setSearch] = useState('')
const lowerSearch = search.toLowerCase()
const base = projectRef ? `/dashboard/v2/project/${projectRef}` : ''
const base = projectRef ? `/v2/project/${projectRef}` : ''
const openCategory = (category: string) => {
const domain = CATEGORY_DOMAIN[category] ?? 'db'
+1 -1
View File
@@ -31,7 +31,7 @@ export function DataTabBar() {
// Don't render the bar at all when there are no detail tabs
if (detailTabs.length === 0) return null
const chooserPath = projectRef ? `/dashboard/v2/project/${projectRef}/data` : '#'
const chooserPath = projectRef ? `/v2/project/${projectRef}/data` : '#'
const handleClose = (tab: DataTab, e: React.MouseEvent) => {
e.preventDefault()
+4 -4
View File
@@ -269,19 +269,19 @@ export function HomeView() {
{[
{
title: '+ New table',
href: projectRef ? `/dashboard/v2/project/${projectRef}/data/tables` : '#',
href: projectRef ? `/v2/project/${projectRef}/data/tables` : '#',
},
{
title: '+ New bucket',
href: projectRef ? `/dashboard/v2/project/${projectRef}/data/buckets` : '#',
href: projectRef ? `/v2/project/${projectRef}/data/buckets` : '#',
},
{
title: '+ New function',
href: projectRef ? `/dashboard/v2/project/${projectRef}/data/edge-functions` : '#',
href: projectRef ? `/v2/project/${projectRef}/data/edge-functions` : '#',
},
{
title: '+ Add user',
href: projectRef ? `/dashboard/v2/project/${projectRef}/data/users` : '#',
href: projectRef ? `/v2/project/${projectRef}/data/users` : '#',
},
].map((a) => (
<button
@@ -101,7 +101,7 @@ export function ProjectBranchSelectorPopover({ onClose }: ProjectBranchSelectorP
projectCreationEnabled={projectCreationEnabled}
onSelect={(ref) => {
onClose()
router.push(`/dashboard/v2/project/${ref}/data/tables`)
router.push(`/v2/project/${ref}/data/tables`)
}}
onClose={onClose}
/>
@@ -112,7 +112,7 @@ export function ProjectBranchSelectorPopover({ onClose }: ProjectBranchSelectorP
isBranchesLoaded={isBranchesSuccess}
onSelect={(branch) => {
onClose()
router.push(`/dashboard/v2/project/${branch.project_ref}/data/tables`)
router.push(`/v2/project/${branch.project_ref}/data/tables`)
}}
onCreateBranch={() => {
onClose()
@@ -120,7 +120,7 @@ export function ProjectBranchSelectorPopover({ onClose }: ProjectBranchSelectorP
}}
onManageBranches={() => {
onClose()
router.push(`/dashboard/v2/project/${projectRef}/settings/branches`)
router.push(`/v2/project/${projectRef}/settings/branches`)
}}
onClose={onClose}
/>
+1 -1
View File
@@ -29,7 +29,7 @@ export function TabBar() {
const { projectRef } = useV2Params()
const { detailTabs, removeDetailTab } = useV2DashboardStore()
const base = projectRef ? `/dashboard/v2/project/${projectRef}` : ''
const base = projectRef ? `/v2/project/${projectRef}` : ''
const pathParts = pathname?.replace(/^\/v2\/[^/]+\/[^/]+/, '').split('/').filter(Boolean) ?? []
const activity = pathParts[0]
const category = pathParts[1]
@@ -42,13 +42,13 @@ export function V2BranchSelector() {
const handleSelectBranch = (ref: string) => {
if (!orgSlug) return
setOpen(false)
router.push(`/dashboard/v2/project/${ref}/data/tables`)
router.push(`/v2/project/${ref}/data/tables`)
}
const handleManageBranches = () => {
if (!orgSlug || !projectRef) return
setOpen(false)
router.push(`/dashboard/v2/project/${projectRef}/settings/branches`)
router.push(`/v2/project/${projectRef}/settings/branches`)
}
if (!IS_PLATFORM) {
@@ -40,12 +40,12 @@ export function V2OrgProjectSelector() {
const handleSelectProject = (ref: string) => {
if (!orgSlug) return
setOpen(false)
router.push(`/dashboard/v2/project/${ref}/data/tables`)
router.push(`/v2/project/${ref}/data/tables`)
}
const handleSelectOrg = (slug: string) => {
setOpen(false)
router.push(`/dashboard/v2/org/${slug}`)
router.push(`/v2/org/${slug}`)
}
return (
@@ -48,7 +48,7 @@ export function V2TableDetailView({ subTab }: { subTab: string }) {
type: 'detail',
category: 'tables',
domain: 'db',
path: `/dashboard/v2/project/${projectRef}/data/tables/${tableId}/data`,
path: `/v2/project/${projectRef}/data/tables/${tableId}/data`,
})
}, [table, projectRef, tableId, openDataTab])
@@ -55,7 +55,7 @@ export function V2TablesList() {
return tables.filter((t) => t.name.toLowerCase().includes(q))
}, [tables, search])
const base = projectRef ? `/dashboard/v2/project/${projectRef}` : ''
const base = projectRef ? `/v2/project/${projectRef}` : ''
const openTable = useCallback(
(table: PostgresTable) => {