Files
supabase/apps/studio/components/interfaces/Linter/useAdvisorPageShortcuts.ts
Ali Waseem 6f88585a7e feat(studio): add keyboard shortcuts for Advisors (#46238)
## Summary

Adds discoverable keyboard shortcuts for the Advisors area, covering
both navigation between advisor sub-pages and in-page actions on the
Security/Performance Advisor pages. Built on the shared shortcut
registry (`apps/studio/state/shortcuts/`) so they show up in the command
menu and follow the existing chord conventions (`V` for adVisor,
mirroring auth-nav / database-nav).

Linear: [FE-3413](https://linear.app/supabase/issue/FE-3413)

### Shortcuts

| Shortcut | Action | Scope |
| --- | --- | --- |
| `V` then `S` | Go to Security Advisor | Anywhere under
`/project/<ref>/advisors/*` |
| `V` then `P` | Go to Performance Advisor | Anywhere under
`/project/<ref>/advisors/*` |
| `V` then `R` | Go to Advisor Settings (Rules) | Anywhere under
`/project/<ref>/advisors/*` |
| `1` | Switch to Errors tab | Security / Performance Advisor page |
| `2` | Switch to Warnings tab | Security / Performance Advisor page |
| `3` | Switch to Info tab | Security / Performance Advisor page |
| `Shift+R` | Refresh / rerun the advisor | Security / Performance
Advisor page |
| `Escape` | Close lint details panel | When a lint row is selected |

## Test plan

- [x] From anywhere in Advisors, `V S` / `V P` / `V R` route to Security
/ Performance / Rules
- [x] On Security and Performance Advisor pages, `1` / `2` / `3` switch
tabs and update the `preset` query param
- [x] `Shift+R` reruns the linter (disabled while a refresh is
in-flight)
- [x] `Escape` closes the lint details side panel when a lint is
selected
- [x] Digit shortcuts do not fire while typing in inputs (`ignoreInputs:
true`)
- [x] Shortcuts appear in the command menu under the Advisors group

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added keyboard shortcuts for Advisors (tab navigation, refresh/rerun,
close detail) with visible shortcut hints on tabs, refresh/rerun
buttons, close controls, and the Advisors menu; pages wire shortcuts to
tab switching, refresh, and close actions.

* **Chores**
* Registered Advisors shortcuts globally and added an Advisors
navigation group for discovery in the shortcuts reference.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46238?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com>
2026-05-22 14:46:59 +00:00

53 lines
1.7 KiB
TypeScript

import { useRouter } from 'next/router'
import { LINTER_LEVELS } from './Linter.constants'
import { SHORTCUT_IDS } from '@/state/shortcuts/registry'
import { useShortcut } from '@/state/shortcuts/useShortcut'
interface UseAdvisorPageShortcutsParams {
setCurrentTab: (level: LINTER_LEVELS) => void
refetch: () => void
hasSelectedLint: boolean
isRefreshDisabled: boolean
}
/**
* Registers shortcuts that apply across the Security and Performance Advisor
* pages:
* - 1 / 2 / 3: switch to Errors / Warnings / Info tab
* - Shift+R: rerun the linter
* - Escape: close the lint detail panel (only when a lint is selected)
*
* The tab handlers mirror the URL update that `LintPageTabs` performs on click,
* so the `preset` query stays in sync and the side panel closes.
*/
export function useAdvisorPageShortcuts({
setCurrentTab,
refetch,
hasSelectedLint,
isRefreshDisabled,
}: UseAdvisorPageShortcutsParams) {
const router = useRouter()
const switchTab = (level: LINTER_LEVELS) => {
setCurrentTab(level)
const { sort, search, id, ...rest } = router.query
router.push({ ...router, query: { ...rest, preset: level } })
}
useShortcut(SHORTCUT_IDS.ADVISORS_TAB_ERRORS, () => switchTab(LINTER_LEVELS.ERROR))
useShortcut(SHORTCUT_IDS.ADVISORS_TAB_WARNINGS, () => switchTab(LINTER_LEVELS.WARN))
useShortcut(SHORTCUT_IDS.ADVISORS_TAB_INFO, () => switchTab(LINTER_LEVELS.INFO))
useShortcut(SHORTCUT_IDS.ADVISORS_REFRESH, refetch, { enabled: !isRefreshDisabled })
useShortcut(
SHORTCUT_IDS.ADVISORS_CLOSE_DETAIL,
() => {
const { id, ...rest } = router.query
router.push({ query: rest })
},
{ enabled: hasSelectedLint }
)
}