Collapse sections by clicking their title bar (ticket 006)

Alerts, Metrics, Params, and Dashboards now toggle collapsed state when
their header row is clicked, instead of requiring a dedicated collapse
button. The chevron (CollapseToggle) becomes a purely visual, non-focusable
indicator for these sections; HelpIcon and PopOutButton now stop
propagation so they keep working without also collapsing the section.

The log viewer's toggle (App.tsx/FilterBar) keeps its dedicated button,
since that row is a filter toolbar with an editable input rather than a
plain title bar, so CollapseToggle's onToggle prop stays available for
that case.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
This commit is contained in:
Hugh Kaznowski
2026-09-05 18:48:59 +01:00
co-authored by Claude Sonnet 5
parent 01eadf415c
commit 5038295554
7 changed files with 113 additions and 25 deletions
+39 -2
View File
@@ -3,9 +3,15 @@ import type { TimeRange } from './LogTimeline'
/// Shared look for a primary section's title bar: shaded so it reads as a
/// distinct band rather than blending into the section body below it.
/// The bar itself is the collapse/expand click target (see `sectionHeaderInteractiveClassName`) —
/// this className alone (no click handling) is for the rare header that stays static.
export const sectionHeaderClassName =
'flex items-center justify-between gap-2 border-b border-border-soft bg-surface-1 px-3 py-1.5'
/// `sectionHeaderClassName` plus the affordance for a header row that toggles collapse on click:
/// pointer cursor and a hover tint so the whole bar reads as clickable, not just the chevron.
export const sectionHeaderInteractiveClassName = `${sectionHeaderClassName} cursor-pointer select-none hover:bg-surface-2`
/// Left-hand cluster of a section header: title text, help icon, collapse/pop-out controls.
export const sectionHeaderLeftClassName = 'flex items-center gap-1.5 text-sm font-medium text-text-secondary'
@@ -46,7 +52,24 @@ export function useSectionCollapsed(sectionId: string): [boolean, (next: boolean
return [collapsed, setCollapsed]
}
export function CollapseToggle({ collapsed, onToggle }: { collapsed: boolean; onToggle: () => void }) {
/// Chevron indicator for a section's collapsed/expanded state. For the title-bar sections
/// (Alerts/Metrics/Params/Dashboards), the whole header row is the click target (see
/// `sectionHeaderInteractiveClassName`) and `onToggle` is omitted — this renders as a
/// non-interactive, decorative `span` rather than a nested `<button>`, with `aria-expanded`
/// living on the header row itself. `onToggle` stays available for the log viewer's toggle
/// (`App.tsx`), which sits in a filter toolbar rather than a plain title bar — there the
/// chevron itself remains a dedicated button.
export function CollapseToggle({ collapsed, onToggle }: { collapsed: boolean; onToggle?: () => void }) {
if (!onToggle) {
return (
<span
aria-hidden="true"
className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-border-soft bg-surface-2 text-xs leading-none text-text-muted"
>
{collapsed ? '▸' : '▾'}
</span>
)
}
return (
<button
type="button"
@@ -61,6 +84,17 @@ export function CollapseToggle({ collapsed, onToggle }: { collapsed: boolean; on
)
}
/// Keyboard handler for a header row using `sectionHeaderInteractiveClassName`: Enter/Space
/// activate it like a button, matching the `role="button"` semantics on the row.
export function handleSectionHeaderKeyDown(onToggle: () => void) {
return (e: React.KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
onToggle()
}
}
}
/// The four primary sections poppable into their own tab; matches the `?section=` query param a standalone page reads.
export type PopOutSectionId = 'log' | 'params' | 'metrics' | 'dashboards'
@@ -78,7 +112,10 @@ export function PopOutButton({ section, range }: { section: PopOutSectionId; ran
return (
<button
type="button"
onClick={() => window.open(popOutUrl(section, range), '_blank')}
onClick={(e) => {
e.stopPropagation()
window.open(popOutUrl(section, range), '_blank')
}}
title="Open in new tab"
aria-label="Open in new tab"
className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-border-soft bg-surface-2 text-xs leading-none text-text-muted hover:border-border-strong hover:text-text-secondary"