mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
## Summary Adds the `O→S` / `Shift+F` / `Shift+N` / `F→C` shortcut set across every Database listing page, on top of the schema-visualizer pattern from #45386. Fixes [FE-3131](https://linear.app/supabase/issue/FE-3131). A shared `list-page.*` registry replaces what would have been a per-page registry file for each route, and `useShortcut`/`Shortcut` gain a `label` override so a single ID renders contextually in Cmd+K and hover tooltips. ## Pages and shortcuts | Page | `O→S` | `Shift+F` | `Shift+N` | `F→C` | | --- | --- | --- | --- | --- | | Tables | Open schema selector | Search tables | Create new table | Clears search + entity-type filter | | Functions | Open schema selector | Search functions | Create new function | Clears search + Return Type + Security | | Triggers — data | Open schema selector | Search triggers | Create new trigger | Clears search + Table filter | | Triggers — event | — | Search event triggers | Create new event trigger | Clears search + Owner filter | | Enumerated Types | Open schema selector | Search enumerated types | Create new enumerated type | Clears search | | Indexes | Open schema selector | Search indexes | Create new index | Clears search | | Roles | — | Search roles | Add new role | Clears search + filter type → 'all' | | Publications | — | Search publications | — | Clears search | | Extensions | — | Search extensions | — | Clears search | `Shift+N` only fires when the page-specific gate allows it (permission + unlocked schema + any other prerequisite like `hasTables` for triggers). ## Test plan - [ ] On each of the 9 pages, all four shortcuts behave as listed in the table above - [ ] Hover the wrapped controls — tooltip shows the page-specific label and the right keybind badge - [ ] Open the schema selector via `O→S` — the hover tooltip is suppressed while the popover is open - [ ] `Shift+N` is a no-op on locked schemas / when permission is missing / when a prereq fails (e.g. no tables on Triggers data) - [ ] `Shift+F` focuses the search input; while focused, Escape clears (with text) → Escape blurs (when empty) - [ ] `Cmd+K` shows the page-specific shortcut name while on each page; the entry goes away on navigation - [ ] `Mod+/` reference sheet shows one "List pages" group with 4 generic entries - [ ] No regression to existing schema-visualizer / table-editor / SQL-editor shortcut behavior <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a dedicated list-page shortcut group in the shortcuts reference. * **Improvements** * Keyboard shortcuts across database list pages: focus & select search, reset filters, and create-new-item shortcuts. * Escape now clears/searches or blurs inputs to avoid accidental popover closes. * Create/new buttons respond to shortcuts when allowed; disabled actions keep permission tooltips for clarity. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
86 lines
2.6 KiB
TypeScript
86 lines
2.6 KiB
TypeScript
import { TooltipContentProps } from '@ui/components/shadcn/ui/tooltip'
|
|
import type { ReactNode } from 'react'
|
|
|
|
import { ShortcutTooltip } from './ShortcutTooltip'
|
|
import type { ShortcutId } from '@/state/shortcuts/registry'
|
|
import type { ShortcutOptions } from '@/state/shortcuts/types'
|
|
import { useShortcut } from '@/state/shortcuts/useShortcut'
|
|
|
|
interface ShortcutProps {
|
|
/** Registered shortcut id — drives both the hotkey binding and the tooltip. */
|
|
id: ShortcutId
|
|
/** Fires on the hotkey. Usually the same handler wired to the child's `onClick`. */
|
|
onTrigger: () => void
|
|
/** Element to bind the shortcut to and wrap in the tooltip. */
|
|
children: ReactNode
|
|
/** Per-mount overrides for the shortcut — see `ShortcutOptions`. */
|
|
options?: ShortcutOptions
|
|
side?: TooltipContentProps['side']
|
|
align?: TooltipContentProps['align']
|
|
sideOffset?: number
|
|
delayDuration?: number
|
|
/**
|
|
* Override the label from the registry. Use when the wrapped element's
|
|
* action is a narrower/contextual variant of the registered shortcut.
|
|
*/
|
|
label?: string
|
|
/**
|
|
* Controlled open state for the tooltip. Pass `false` to force the tooltip
|
|
* closed (e.g. while a popover or dialog opened by the wrapped element is
|
|
* visible). Leave `undefined` for default uncontrolled behavior.
|
|
*/
|
|
tooltipOpen?: boolean
|
|
}
|
|
|
|
/**
|
|
* Bind a registered shortcut to an element AND show its keybind on hover,
|
|
* Linear-style. Single source of truth: one `id` drives both the hotkey
|
|
* listener and the tooltip, so they can't drift.
|
|
*
|
|
* The wrapped child stays fully interactive — Radix `asChild` passes clicks,
|
|
* focus, and refs through untouched.
|
|
*
|
|
* @example
|
|
* <Shortcut id={SHORTCUT_IDS.RESULTS_COPY_MARKDOWN} onTrigger={handleCopy}>
|
|
* <Button onClick={handleCopy}>Copy</Button>
|
|
* </Shortcut>
|
|
*
|
|
* @example
|
|
* // Gate the hotkey on local state; tooltip still renders:
|
|
* <Shortcut
|
|
* id={SHORTCUT_IDS.ACTION_BAR_SAVE}
|
|
* onTrigger={handleSave}
|
|
* options={{ enabled: hasUnsavedChanges }}
|
|
* >
|
|
* <Button onClick={handleSave} disabled={!hasUnsavedChanges}>Save</Button>
|
|
* </Shortcut>
|
|
*/
|
|
export const Shortcut = ({
|
|
id,
|
|
onTrigger,
|
|
children,
|
|
options,
|
|
side,
|
|
align,
|
|
sideOffset,
|
|
delayDuration,
|
|
label,
|
|
tooltipOpen,
|
|
}: ShortcutProps) => {
|
|
useShortcut(id, onTrigger, label !== undefined ? { ...options, label } : options)
|
|
|
|
return (
|
|
<ShortcutTooltip
|
|
shortcutId={id}
|
|
side={side}
|
|
align={align}
|
|
sideOffset={sideOffset}
|
|
delayDuration={delayDuration}
|
|
label={label}
|
|
open={tooltipOpen}
|
|
>
|
|
{children}
|
|
</ShortcutTooltip>
|
|
)
|
|
}
|