mirror of
https://github.com/supabase/supabase.git
synced 2026-05-06 14:05:05 +08:00
## Summary Adds a contextual `D + <letter>` chord pattern for jumping between Database sub-pages, mounted only while `DatabaseLayout` is active. Establishes the pattern we can repeat for other sections (Auth, Storage, Functions, etc.). Linear: [FE-3140](https://linear.app/supabase/issue/FE-3140/define-subnavigation-pattern-for-database-management-page) ## Pattern - Chords are 2-key sequences (`D`, `<letter>`) — no global leader, no `G` prefix. - Registration is contextual: `<DatabaseNavShortcuts />` lives inside `DatabaseLayout`, so the leading `D` is only "owned" while the user is under `/project/<ref>/database/*`. Doesn't burn a global key. - Hover tooltips on each sub-menu item show the chord, anchored to the label text (Linear-style). Powered by `<ShortcutTooltip>` already used in the main nav. - Items hidden by feature flags (Roles, Column Privileges, Replication) auto-disable the chord — no muscle-memory navigating to a 404. ## Shortcuts added | Sub-page | Chord | Notes | |---|---|---| | Tables | `D T` | | | Functions | `D F` | | | Triggers | `D R` | t**R**iggers — `T` taken by Tables | | Indexes | `D I` | | | Extensions | `D X` | e**X**tensions | | Schema Visualizer | `D V` | | | Enumerated Types | `D E` | | | Publications | `D U` | p**U**blications — avoids collision with Schema Visualizer's `D P` (Download as PNG) | | Column Privileges | `D C` | flag-gated | | Settings | `D ,` | mirrors global `G ,` for project settings — avoids collision with Schema Visualizer's `D S` (Download as SVG) | | Replication | `D L` | rep**L**ication — flag-gated | | Roles | `D O` | r**O**les — flag-gated | | Backups | `D B` | platform-only | | Migrations | `D M` | | External-link sub-menu items (Policies, Wrappers, Webhooks, Security Advisor, Performance Advisor, Query Performance) are intentionally not chorded — they route out of `/database/*` and don't belong to the section's namespace. ## Collision audit Other shortcuts active on database pages (table-list, schema-visualizer) were checked against the new chords: - **Schema Visualizer** (`/database/schemas`): `D P` (Download PNG), `D S` (Download SVG), `O A`, `O S`. Publications and Settings were remapped to `D U` and `D ,` to avoid the `D P` / `D S` clashes. - **List pages** (`/database/tables`, etc.): `Shift+F`, `Shift+N`, `O S`, `F C` — no overlap with `D + <letter>`. ## Files - `state/shortcuts/registry/database-nav.ts` — new registry module with the 14 chord definitions. - `state/shortcuts/registry.ts` — spreads the new IDs/definitions into the canonical registry. - `components/interfaces/DatabaseNavShortcuts.tsx` — null-rendering hook component that wires `useShortcut` for each chord, keyed off `useGenerateDatabaseMenu` so URLs and feature gating stay in sync with the sidebar. - `components/layouts/DatabaseLayout/DatabaseLayout.tsx` — mounts the component. - `components/layouts/DatabaseLayout/DatabaseMenu.utils.tsx` — tags each menu item with its `shortcutId`. - `components/ui/ProductMenu/ProductMenu.types.ts` — adds optional `shortcutId?: ShortcutId` field. - `components/ui/ProductMenu/ProductMenuItem.tsx` — renders the hover tooltip when an item has a `shortcutId`, anchored to the label span. ## Test plan - [ ] On `/project/<ref>/database/tables`, press `D F` — navigates to `/database/functions`. - [ ] On `/project/<ref>/database/schemas`, press `D P` — downloads the PNG (Schema Visualizer wins, no nav conflict). - [ ] On `/project/<ref>/database/schemas`, press `D U` — navigates to `/database/publications`. - [ ] On `/project/<ref>/database/tables`, press `D ,` — navigates to `/database/settings`. - [ ] Hover any sub-menu item with a chord — pill appears next to the label after ~1s. - [ ] On a project with the Replication flag off — `D L` does nothing. - [ ] Navigate to `/auth` — pressing `D F` does nothing (chord unmounts with the layout). - [ ] Type `D` then `F` slowly inside an input — does not navigate (input-focus guard).
37 lines
1.0 KiB
TypeScript
37 lines
1.0 KiB
TypeScript
import { useRouter } from 'next/router'
|
|
import type { PropsWithChildren } from 'react'
|
|
|
|
import { ProjectLayout } from '../ProjectLayout'
|
|
import { useGenerateDatabaseMenu } from './DatabaseMenu.utils'
|
|
import { DatabaseNavShortcuts } from '@/components/interfaces/DatabaseNavShortcuts'
|
|
import { ProductMenu } from '@/components/ui/ProductMenu'
|
|
import { withAuth } from '@/hooks/misc/withAuth'
|
|
|
|
export interface DatabaseLayoutProps {
|
|
title: string
|
|
}
|
|
|
|
export const DatabaseProductMenu = () => {
|
|
const router = useRouter()
|
|
const page = router.pathname.split('/')[4]
|
|
const menu = useGenerateDatabaseMenu()
|
|
|
|
return <ProductMenu page={page} menu={menu} />
|
|
}
|
|
|
|
const DatabaseLayout = ({ children, title }: PropsWithChildren<DatabaseLayoutProps>) => {
|
|
return (
|
|
<ProjectLayout
|
|
product="Database"
|
|
browserTitle={{ section: title }}
|
|
productMenu={<DatabaseProductMenu />}
|
|
isBlocking={false}
|
|
>
|
|
<DatabaseNavShortcuts />
|
|
{children}
|
|
</ProjectLayout>
|
|
)
|
|
}
|
|
|
|
export default withAuth(DatabaseLayout)
|