Files
supabase/apps/studio/components/ui/DataTable/LiveButton.tsx
Ali Waseem 2cb7f0c078 feat(studio): add keyboard shortcuts for unified logs (#46680)
Adds the final set of keyboard shortcuts to the Unified Logs page and
converts the last hardcoded `keydown` listener (detail-panel prev/next)
to the shared shortcut registry. Each action also surfaces its keybind
in a registry-driven tooltip.

Closes FE-3415.

## Shortcuts

| Action | Shortcut | Notes |
| --- | --- | --- |
| Refresh logs | `Shift+R` | new |
| Download logs | `Shift+E` | new — opens export dropdown |
| Focus filter bar | `Shift+F` | new |
| Clear filters | `F` then `C` | new |
| Copy selected as JSON | `Mod+Shift+J` | new — reuses
`results.copy-json` |
| Copy selected as Markdown | `Mod+Shift+M` | new — reuses
`results.copy-markdown` |
| Previous / next log (detail panel) | `↑` / `↓` | converted from
hardcoded listener |
| Close details panel | `Escape` | new |

Existing shared `data-table.*` shortcuts kept as-is: toggle sidebar
(`Mod+B`), live mode (`Mod+J`), reset filters (`Mod+Esc`), reset columns
(`Mod+U`), reset focus (`Mod+.`).

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

* **New Features**
* Added keyboard shortcuts for Unified Logs: copy selected rows as
JSON/Markdown, navigate rows, refresh, clear/reset filters, download,
and focus filter — shortcuts show in the command menu and display
badges/hints in menus and buttons.
* **Refactor**
* Shortcut handling unified across log controls; shortcuts
enable/disable based on context and a new "Logs" group appears in the
shortcut reference.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-05 09:21:20 -06:00

80 lines
2.2 KiB
TypeScript

import type { FetchPreviousPageOptions } from '@tanstack/react-query'
import { CirclePause, CirclePlay } from 'lucide-react'
import { useQueryStates } from 'nuqs'
import { useEffect } from 'react'
import { Button, cn } from 'ui'
import { useDataTable } from './providers/DataTableProvider'
import { ShortcutTooltip } from '@/components/ui/ShortcutTooltip'
import { SHORTCUT_IDS } from '@/state/shortcuts/registry'
import { useShortcut } from '@/state/shortcuts/useShortcut'
const REFRESH_INTERVAL = 10_000
interface LiveButtonProps {
searchParamsParser: any
fetchPreviousPage?: (options?: FetchPreviousPageOptions | undefined) => Promise<unknown>
}
export function LiveButton({ fetchPreviousPage, searchParamsParser }: LiveButtonProps) {
const [{ live, date, sort }, setSearch] = useQueryStates(searchParamsParser)
const { table } = useDataTable()
useShortcut(SHORTCUT_IDS.DATA_TABLE_TOGGLE_LIVE, handleClick, { registerInCommandMenu: true })
useEffect(() => {
let timeoutId: NodeJS.Timeout
async function fetchData() {
if (live) {
await fetchPreviousPage?.()
timeoutId = setTimeout(fetchData, REFRESH_INTERVAL)
} else {
clearTimeout(timeoutId)
}
}
fetchData()
return () => {
clearTimeout(timeoutId)
}
}, [live, fetchPreviousPage])
// REMINDER: make sure to reset live when date is set
// TODO: test properly
useEffect(() => {
if ((date || sort) && live) {
setSearch((prev) => ({ ...prev, live: null }))
}
}, [date, sort])
function handleClick() {
setSearch((prev) => ({
...prev,
live: !prev.live,
date: null,
sort: null,
}))
table.getColumn('date')?.setFilterValue(undefined)
table.resetSorting()
}
return (
<ShortcutTooltip
shortcutId={SHORTCUT_IDS.DATA_TABLE_TOGGLE_LIVE}
label={live ? 'Pause live mode' : 'Start live mode'}
side="bottom"
>
<Button
className={cn(live && 'border-info text-info hover:text-info')}
onClick={handleClick}
type={live ? 'primary' : 'default'}
size="tiny"
icon={live ? <CirclePause className="h-4 w-4" /> : <CirclePlay className="h-4 w-4" />}
>
Live
</Button>
</ShortcutTooltip>
)
}