Fix regex help icon click-toggle and add PromQL by()/sum(rate()) grouping
RegexHelpIcon previously used a single `open` boolean driven by both hover and click, so clicking to pin the popover open was undone by the next mouseleave. Split into separate `pinned` (click) and `hovering` (mouse-over) states so a click-toggle actually persists until clicked again. The seeded `log_category` dashboard's line panel plotted the bare metric name, since `sum()`/`rate()` always collapsed all label combinations into one series and PromQL syntax had no way to preserve a label dimension through an aggregation. Added `by (label, ...)` grouping and nested `sum(rate(metric[range]))`/`avg(rate(...))` parsing, and made `rate()` compute a real windowed time series instead of a single trailing point, so a query like `sum(rate(log_category[1m])) by (category)` now renders one line per category. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d6b7f7dfb6
commit
5aa7c1bae9
@@ -23,23 +23,32 @@ const CHEAT_SHEET: { tokens: string; meaning: string }[] = [
|
||||
// "@" icon next to regex inputs; shows a compact cheat sheet for the regex flavor the server actually
|
||||
// uses (Rust `regex` crate — no lookaround/backreferences), modeled on HelpIcon's button styling.
|
||||
export function RegexHelpIcon({ label }: { label?: string }) {
|
||||
const [open, setOpen] = useState(false)
|
||||
// Click pins the popover open until clicked again; hovering shows it only while the mouse
|
||||
// stays over the icon/box, independent of the pinned state.
|
||||
const [pinned, setPinned] = useState(false)
|
||||
const [hovering, setHovering] = useState(false)
|
||||
const open = pinned || hovering
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return
|
||||
if (!pinned) return
|
||||
function onClickOutside(e: MouseEvent) {
|
||||
if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false)
|
||||
if (ref.current && !ref.current.contains(e.target as Node)) setPinned(false)
|
||||
}
|
||||
document.addEventListener('mousedown', onClickOutside)
|
||||
return () => document.removeEventListener('mousedown', onClickOutside)
|
||||
}, [open])
|
||||
}, [pinned])
|
||||
|
||||
return (
|
||||
<div ref={ref} className="relative inline-flex" onMouseEnter={() => setOpen(true)} onMouseLeave={() => setOpen(false)}>
|
||||
<div
|
||||
ref={ref}
|
||||
className="relative inline-flex"
|
||||
onMouseEnter={() => setHovering(true)}
|
||||
onMouseLeave={() => setHovering(false)}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOpen((v) => !v)}
|
||||
onClick={() => setPinned((v) => !v)}
|
||||
title="Regex syntax cheat sheet"
|
||||
aria-label={label ?? 'Regex syntax cheat sheet'}
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user