Add pop-out button to open a section in its own tab (ticket 036)
Each of the four primary sections (Log viewer, Params, Metrics, Dashboards) gets a PopOutButton next to its CollapseToggle/HelpIcon that opens `?section=<id>` in a new tab via window.open. App.tsx branches on that query param to render just the one section full-page, with no NavMenu/FilterBar/sibling chrome — Metrics/Dashboards get the range that was active at pop-out time via startMs/endMs query params (they have no LogTimeline of their own to pick one), Params gets a small self-contained params fetch since it has no LogPreview sibling to share state with, and the popped-out Log viewer owns its own copy of the log/timeline polling state. 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
7db1e0f055
commit
0c4b596e3c
@@ -1,4 +1,5 @@
|
||||
import { useState } from 'react'
|
||||
import type { TimeRange } from './LogTimeline'
|
||||
|
||||
/// localStorage key for which of the four primary sections (log viewer,
|
||||
/// params, metrics, dashboards) are collapsed (ticket 035). Mirrors
|
||||
@@ -57,3 +58,34 @@ export function CollapseToggle({ collapsed, onToggle }: { collapsed: boolean; on
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
/// The four primary sections that can be popped out into their own tab
|
||||
/// (ticket 036) — matches the `?section=` query param a standalone page reads.
|
||||
export type PopOutSectionId = 'log' | 'params' | 'metrics' | 'dashboards'
|
||||
|
||||
function popOutUrl(section: PopOutSectionId, range?: TimeRange | null): string {
|
||||
const query = new URLSearchParams({ section })
|
||||
if (range) {
|
||||
query.set('startMs', String(range.startMs))
|
||||
query.set('endMs', String(range.endMs))
|
||||
}
|
||||
return `?${query.toString()}`
|
||||
}
|
||||
|
||||
/// Opens this section, full-page and with no surrounding chrome, in a new
|
||||
/// tab. `range` is only needed for sections without their own LogTimeline —
|
||||
/// the popped-out page has no way to pick a range itself, so the current one
|
||||
/// is carried over via query params (see `App.tsx`'s standalone rendering).
|
||||
export function PopOutButton({ section, range }: { section: PopOutSectionId; range?: TimeRange | null }) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => window.open(popOutUrl(section, range), '_blank')}
|
||||
title="Open in new tab"
|
||||
aria-label="Open in new tab"
|
||||
className="flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-border-soft text-[10px] leading-none text-text-faint hover:border-border-strong hover:text-text-secondary"
|
||||
>
|
||||
↗
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
type Panel,
|
||||
type PromqlSeries,
|
||||
} from '../lib/api'
|
||||
import { CollapseToggle, useSectionCollapsed } from './CollapsibleSection'
|
||||
import { CollapseToggle, PopOutButton, useSectionCollapsed } from './CollapsibleSection'
|
||||
import { HelpIcon } from './HelpIcon'
|
||||
|
||||
const CHART_TYPES: ChartType[] = ['line', 'bar', 'pie']
|
||||
@@ -234,6 +234,7 @@ export function Dashboards({ range }: { range: TimeRange | null }) {
|
||||
<div className="flex items-center gap-1.5 border-b border-border p-3 text-xs text-text-faint">
|
||||
<HelpIcon sectionId="dashboards" label="Help: Dashboards" />
|
||||
<CollapseToggle collapsed={collapsed} onToggle={() => setCollapsed(!collapsed)} />
|
||||
<PopOutButton section="dashboards" range={range} />
|
||||
Dashboards — activate a profile (see the settings menu) to create and save dashboards.
|
||||
</div>
|
||||
)
|
||||
@@ -244,6 +245,7 @@ export function Dashboards({ range }: { range: TimeRange | null }) {
|
||||
<div className="mb-2 flex items-center gap-1.5 text-xs text-text-subtle">
|
||||
<HelpIcon sectionId="dashboards" label="Help: Dashboards" />
|
||||
<CollapseToggle collapsed={collapsed} onToggle={() => setCollapsed(!collapsed)} />
|
||||
<PopOutButton section="dashboards" range={range} />
|
||||
Dashboards — profile "{activeProfile}"
|
||||
</div>
|
||||
{error && !collapsed && (
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
type MetricDeclaration,
|
||||
type MetricParamMatcher,
|
||||
} from '../lib/api'
|
||||
import { CollapseToggle, useSectionCollapsed } from './CollapsibleSection'
|
||||
import { CollapseToggle, PopOutButton, useSectionCollapsed } from './CollapsibleSection'
|
||||
import { HelpIcon } from './HelpIcon'
|
||||
|
||||
const EMPTY_MATCHER: MetricParamMatcher = { param_name: '', capture_group: '', kind: 'string' }
|
||||
@@ -163,6 +163,7 @@ export function Metrics({ range }: { range: TimeRange | null }) {
|
||||
Metrics
|
||||
<HelpIcon sectionId="metrics" label="Help: Metrics" />
|
||||
<CollapseToggle collapsed={collapsed} onToggle={() => setCollapsed(!collapsed)} />
|
||||
<PopOutButton section="metrics" range={range} />
|
||||
</div>
|
||||
<div className="flex gap-4" hidden={collapsed}>
|
||||
<form onSubmit={handleSubmit} className="w-80 shrink-0 space-y-2">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState } from 'react'
|
||||
import { ApiError, declareParam, type ParamDeclaration } from '../lib/api'
|
||||
import { CollapseToggle, useSectionCollapsed } from './CollapsibleSection'
|
||||
import { CollapseToggle, PopOutButton, useSectionCollapsed } from './CollapsibleSection'
|
||||
import { HelpIcon } from './HelpIcon'
|
||||
|
||||
const EMPTY_KIND: ParamDeclaration['kind'] = 'string'
|
||||
@@ -38,6 +38,7 @@ export function Params({ params, onDeclared }: { params: ParamDeclaration[]; onD
|
||||
Params
|
||||
<HelpIcon sectionId="parameters" label="Help: Params" />
|
||||
<CollapseToggle collapsed={collapsed} onToggle={() => setCollapsed(!collapsed)} />
|
||||
<PopOutButton section="params" />
|
||||
</div>
|
||||
<div className="flex gap-4" hidden={collapsed}>
|
||||
<form onSubmit={handleSubmit} className="w-80 shrink-0 space-y-2">
|
||||
|
||||
Reference in New Issue
Block a user