## What kind of change does this PR introduce? Feature. Resolves FE-3418 ## What is the current behaviour? Platform webhooks (org and project) have no keyboard shortcut coverage. Every action requires a mouse click. ## What is the new behaviour? Adds seven shortcuts across the four UI states of the platform webhooks pages: **List page** | Shortcut | Action | |---|---| | `Shift+F` | Focus search input | | `Shift+N` | Open "New endpoint" sheet | **Endpoint detail page** (when viewing a specific endpoint) | Shortcut | Action | |---|---| | `Shift+E` | Open the edit sheet | | `Shift+U` | Copy the endpoint URL | **Create / edit form sheet** | Shortcut | Action | |---|---| | `Mod+Enter` | Submit the form (create or save) | **Delivery details sheet** (when a delivery row is open) | Shortcut | Action | |---|---| | `Shift+R` | Retry the delivery (only active for non-success deliveries) | | `Shift+C` | Copy the active tab's payload (switches label between "Copy event payload" / "Copy response payload") | All shortcuts: - Are surfaced via `ShortcutTooltip` / `Shortcut` tooltips on their buttons - Appear in the keyboard shortcuts reference sheet (`Mod+/`) under a new **Platform Webhooks** group - Are gated so they only fire in the appropriate UI state (e.g. `Shift+E` is disabled while the edit sheet is already open) - Apply to both the org-level (`/org/[slug]/webhooks`) and project-level (`/project/[ref]/settings/webhooks`) pages as both use the same `PlatformWebhooksPage` component **Shared shortcuts reused** (no new IDs): `LIST_PAGE_FOCUS_SEARCH`, `LIST_PAGE_NEW_ITEM`, `ACTION_BAR_SAVE`. ## To test The platform webhooks UI is behind a feature flag for internal folks. Enable it in Studio via **Account → Feature Previews → Platform Webhooks**. The backend is not yet integrated, so you can test all the shortcuts on the 1–2 mock endpoints (and their deliveries) that appear. **List page** (`/org/[slug]/webhooks` or `/project/[ref]/settings/webhooks`): - [ ] `Shift+F` moves focus to the search input - [ ] `Shift+N` opens the "New endpoint" sheet (tooltip visible on hover of the button) **New endpoint sheet**: - [ ] Fill in a name and a valid URL, select at least one event type - [ ] `Mod+Enter` submits and creates the endpoint **Endpoint detail page**: - [ ] `Shift+E` opens the edit sheet (tooltip visible on the Edit button) - [ ] `Shift+U` copies the endpoint URL and shows a toast (tooltip visible on the copy icon next to the URL) **Edit sheet**: - [ ] `Mod+Enter` saves changes **Delivery details sheet** (click a delivery row to open): - [ ] `Shift+R` retries a failed/pending delivery (button and shortcut absent for successful deliveries) - [ ] On the **Event** tab: `Shift+C` copies the event payload, toast reads "Copied event payload" - [ ] On the **Response** tab: `Shift+C` copies the response payload, toast reads "Copied response payload" - [ ] Tooltip on both Copy buttons reflects the active tab label **Shortcuts reference sheet** (`Mod+/`): - [ ] A **Platform Webhooks** group appears when on an endpoint detail page or with the delivery sheet open with the relevant shortcuts listed - [ ] The basic shortcuts are shown under **List pages** when on the root Webhooks page --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
3.0 KiB
applyTo
| applyTo |
|---|
| apps/studio/** |
Studio Shortcut Review Rules
All comments are advisory.
Core Principle
When Studio UI changes introduce or materially alter repeated user actions, consider whether keyboard shortcut coverage should be added or updated. Shortcuts should use the shared Studio shortcut system and be discoverable from the visible UI.
When to Flag
- PR adds a primary repeated action, toolbar action, list/table operation, or sub-page navigation without considering shortcut coverage.
- PR adds a one-off
keydownlistener for a normal Studio action instead of using the shortcut registry anduseShortcut. - PR registers a shortcut but does not expose it via
ShortcutTooltip,ShortcutBadge, or command-menu badge where the action is visible. - PR uses
G then ...for a non-navigation action. - PR adds a broad
Mod+lettershortcut that overlaps common browser, editor, system, copy/save/search, or devtools behaviour. - PR adds a shortcut without checking existing registry and non-registry listeners for collisions.
- PR adds a search/filter
<Input>withoutonKeyDown={onSearchInputEscape(...)}— see Search Inputs below.
Preferred Pattern
- Add definitions in
apps/studio/state/shortcuts/registry.tsorapps/studio/state/shortcuts/registry/*. - Register with
useShortcut. - Gate availability with
enabled. - Surface visible actions with
ShortcutTooltiporShortcutBadge. - Prefer scoped, mnemonic sequential chords over global modifier chords.
- Set
showInSettings: falseon contextual shortcuts (scoped to a specific page state, sheet, or panel). - When a shortcut group should appear in the reference sheet (
Mod+/), add the group key toSHORTCUT_REFERENCE_GROUP_ORDERinapps/studio/state/shortcuts/referenceGroups.tsand a human label toGROUP_LABELSinShortcutsReferenceSheet.tsx. - For sheet-scoped shortcuts (active only while a
<Sheet>is open), mountuseShortcutinside the sheet component gated by theopenprop — seeapps/studio/components/interfaces/ConnectSheet/useConnectSheetShortcut.tsas the canonical example.
Search Inputs
Every <Input> used as a search or filter field must include the staged-Escape handler from apps/studio/lib/keyboard.ts:
import { onSearchInputEscape } from '@/lib/keyboard'
;<Input
value={query}
onChange={(e) => setQuery(e.target.value)}
onKeyDown={onSearchInputEscape(query, setQuery)}
/>
Behaviour:
- Escape while the input has a value → clears the value, keeps focus (so a second Escape then blurs)
- Escape while the input is empty → blurs the input
- Stops propagation on Escape so the keystroke does not accidentally close a parent dialog or sheet
When pairing with useShortcut(LIST_PAGE_FOCUS_SEARCH, ...) to focus a search input via keyboard, always also add onSearchInputEscape on the same input — focus and escape-to-blur are always a pair.
Canonical implementation context: apps/studio/state/shortcuts/registry.ts, apps/studio/state/shortcuts/useShortcut.tsx, and apps/studio/components/ui/Shortcut*.tsx