Skip to content

Add dashboard keyboard shortcuts - #9878

Open
rohithreddykota wants to merge 1 commit into
mainfrom
rohithreddykota/dashboard-keyboard-shortcuts
Open

rohithreddykota wants to merge 1 commit into
mainfrom
rohithreddykota/dashboard-keyboard-shortcuts

Conversation

@rohithreddykota

@rohithreddykota rohithreddykota commented Sep 10, 2026 •

Copy link
Copy Markdown
Member

Adds dashboard-scoped keyboard shortcuts and a discoverable help dialog.

  • Press ? to show or hide the keyboard-shortcuts menu.
  • Press /, ,, or . to open the filter, metric, or dimension picker.
  • Lists the existing cell inspection, selection, chart navigation, zoom, and explain shortcuts in the same menu.
  • Ignores shortcut keys while typing, when modifiers are held, or during repeated keydown events.

Tested with npm test --workspace web-common -- src/features/dashboards/shortcuts/dashboard-shortcuts.spec.ts (9 tests passing).

Checklist:

  • Covered by tests
  • Ran it and it works as intended
  • Reviewed the diff before requesting a review
  • Checked for unhandled edge cases
  • Linked the issues it closes
  • Checked if the docs need to be updated. If so, create a separate Linear DOCS issue
  • Intend to cherry-pick into the release branch
  • I'm proud of this work!

@AdityaHegde AdityaHegde left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code wise this looks good. The only thing missing is localisation and text is hardcoded in english.

Feature wise, do we need more keyboard shortcuts? Feels wierd to be able to open the filter dropdown for example and arrow keys don't work.

@nishantmonu51 nishantmonu51 added Type:Feature New feature request Area:Dashboard Size:M Medium change: 100-499 lines labels Sep 16, 2026

@nishantmonu51 nishantmonu51 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of smaller things that did not warrant their own thread:

  • The help list is unconditional, but several rows are dead in common views: , has no target in time-dimension-detail or pivot (MetricsTimeSeriesCharts.svelte:315-334 only renders the measure picker in the {:else} branch), . has no target outside the leaderboard branch (Dashboard.svelte:271-283), and ChartInteractions.svelte:65 only handles e when $explainEnabled. Hiding rows whose target is absent would keep the dialog honest.
  • Nine of the thirteen DashboardShortcutAction values exist only to key the help list, so performDashboardShortcut(DashboardShortcutAction.Zoom) type-checks but always returns false. A plain id: string on DashboardShortcut would express that split more honestly.

Comment on lines +13 to +19
function handleKeydown(event: KeyboardEvent) {
const action = getDashboardShortcutAction(event);
if (!action || !performDashboardShortcut(action)) return;

event.preventDefault();
event.stopPropagation();
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleKeydown never consults open, so the picker shortcuts stay live while the shortcuts dialog is up. Focus sits inside the body-portalled Dialog.Content, which is not an editable target, so /, , or . still resolves an action and performDashboardShortcut finds the trigger that is still mounted behind the overlay and clicks it. Both bits-ui triggers accept that synthetic click (DropdownMenuTriggerState.onclick only rejects e.detail !== 0, and PopoverTriggerState.onclick toggles on button === 0), so the dropdown opens behind the modal and the user is left with two overlapping surfaces to dismiss. The same holds for any other open modal, not just this one. Only ToggleHelp should be honoured while open is true.

Comment on lines +23 to +89
export const DASHBOARD_SHORTCUTS: DashboardShortcut[] = [
{
action: DashboardShortcutAction.ToggleHelp,
keys: ["?"],
description: "Show/hide the keyboard-shortcuts menu",
},
{
action: DashboardShortcutAction.OpenFilter,
keys: ["/"],
description: "Open the Filter menu",
},
{
action: DashboardShortcutAction.OpenMetricPicker,
keys: [","],
description: "Open the metric picker",
},
{
action: DashboardShortcutAction.OpenDimensionPicker,
keys: ["."],
description: "Open the dimension picker",
},
{
action: DashboardShortcutAction.InspectCell,
keys: ["Space"],
description: "Show/hide the cell inspector",
},
{
action: DashboardShortcutAction.LockInspector,
keys: ["L"],
description: "Lock/unlock the cell inspector",
},
{
action: DashboardShortcutAction.ClearSelection,
keys: ["Esc"],
description: "Close the inspector or clear a chart selection",
},
{
action: DashboardShortcutAction.SelectAll,
keys: ["⌘/Ctrl", "A"],
description: "Select all dimension values",
},
{
action: DashboardShortcutAction.PanLeft,
keys: ["←"],
description: "Pan the chart backward",
},
{
action: DashboardShortcutAction.PanRight,
keys: ["→"],
description: "Pan the chart forward",
},
{
action: DashboardShortcutAction.Zoom,
keys: ["Z"],
description: "Zoom into the selected range",
},
{
action: DashboardShortcutAction.UndoZoom,
keys: ["⌘/Ctrl", "Z"],
description: "Undo chart zoom",
},
{
action: DashboardShortcutAction.Explain,
keys: ["E"],
description: "Explain the selected range",
},
];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AdityaHegde already flagged the hardcoded copy; adding the specifics. All thirteen descriptions here, plus the dialog title, the description and the aria-label on the sr-only button in DashboardShortcuts.svelte:27,36-39, are literal English, while AddExpressionFilterButton.svelte already reads its copy from paraglide two lines below the hunk this PR adds (aria-label={m.dashboard_add_filter_button()}). scripts/i18n-guard.js only scans files that import the messages namespace or match MIGRATED_GLOBS, and these new files do neither, so CI will not flag it and it becomes silent migration debt. The keys need to be added to both web-common/src/lib/i18n/messages/en.json and es.json.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area:Dashboard Size:M Medium change: 100-499 lines Type:Feature New feature request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants