Move TimeRange types to lib/timeRange to break import cycle
CollapsibleSection.tsx and LogTimeline.tsx imported from each other (TimeRange/TimeRangePresetId one way, sectionHeaderClassName the other). Move the range types/helpers into a dependency-free webapp/src/lib/timeRange.ts and repoint all importers there. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TeyhRfMYjMditek6geDRoQ
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
a47f771087
commit
4cc9205abf
+1
-4
@@ -3,15 +3,12 @@ import { NavMenu } from './components/NavMenu'
|
|||||||
import { FilterBar } from './components/FilterBar'
|
import { FilterBar } from './components/FilterBar'
|
||||||
import {
|
import {
|
||||||
LogTimeline,
|
LogTimeline,
|
||||||
TIME_RANGE_PRESETS,
|
|
||||||
computeBucketMs,
|
computeBucketMs,
|
||||||
computePresetRange,
|
|
||||||
loadLogSortSettings,
|
loadLogSortSettings,
|
||||||
saveLogSortSettings,
|
saveLogSortSettings,
|
||||||
type LogSortSettings,
|
type LogSortSettings,
|
||||||
type TimeRange,
|
|
||||||
type TimeRangePresetId,
|
|
||||||
} from './components/LogTimeline'
|
} from './components/LogTimeline'
|
||||||
|
import { TIME_RANGE_PRESETS, computePresetRange, type TimeRange, type TimeRangePresetId } from './lib/timeRange'
|
||||||
import { LogPreview } from './components/LogPreview'
|
import { LogPreview } from './components/LogPreview'
|
||||||
import { Params } from './components/Params'
|
import { Params } from './components/Params'
|
||||||
import { Metrics } from './components/Metrics'
|
import { Metrics } from './components/Metrics'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import type { TimeRange, TimeRangePresetId } from './LogTimeline'
|
import type { TimeRange, TimeRangePresetId } from '../lib/timeRange'
|
||||||
|
|
||||||
/// Shared look for a primary section's title bar: shaded so it reads as a
|
/// 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.
|
/// distinct band rather than blending into the section body below it.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import type { TimeRange, TimeRangePresetId } from './LogTimeline'
|
import type { TimeRange, TimeRangePresetId } from '../lib/timeRange'
|
||||||
import { PanelChart } from './PanelChart'
|
import { PanelChart } from './PanelChart'
|
||||||
import {
|
import {
|
||||||
ApiError,
|
ApiError,
|
||||||
|
|||||||
@@ -1,34 +1,9 @@
|
|||||||
import { useRef, useState } from 'react'
|
import { useRef, useState } from 'react'
|
||||||
import type { TimelineBucket } from '../lib/api'
|
import type { TimelineBucket } from '../lib/api'
|
||||||
|
import { TIME_RANGE_PRESETS, type TimeRange, type TimeRangePresetId } from '../lib/timeRange'
|
||||||
import { sectionHeaderClassName, sectionHeaderLeftClassName } from './CollapsibleSection'
|
import { sectionHeaderClassName, sectionHeaderLeftClassName } from './CollapsibleSection'
|
||||||
import { HelpIcon } from './HelpIcon'
|
import { HelpIcon } from './HelpIcon'
|
||||||
|
|
||||||
export interface TimeRange {
|
|
||||||
startMs: number
|
|
||||||
endMs: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// `'all'` clears the range (the implicit default); the rest resolve to a window ending "now" at the moment they're (re-)computed — see `computePresetRange`.
|
|
||||||
export type TimeRangePresetId = 'all' | '1m' | '2m' | '5m' | '15m' | '1h' | '24h'
|
|
||||||
|
|
||||||
export const TIME_RANGE_PRESETS: { id: TimeRangePresetId; label: string; ms: number | null }[] = [
|
|
||||||
{ id: 'all', label: 'All', ms: null },
|
|
||||||
{ id: '1m', label: '1m', ms: 60 * 1000 },
|
|
||||||
{ id: '2m', label: '2m', ms: 2 * 60 * 1000 },
|
|
||||||
{ id: '5m', label: '5m', ms: 5 * 60 * 1000 },
|
|
||||||
{ id: '15m', label: '15m', ms: 15 * 60 * 1000 },
|
|
||||||
{ id: '1h', label: '1h', ms: 60 * 60 * 1000 },
|
|
||||||
{ id: '24h', label: '24h', ms: 24 * 60 * 60 * 1000 },
|
|
||||||
]
|
|
||||||
|
|
||||||
// Callers re-invoke this on their existing poll cadence (see `App.tsx`) to keep a rolling preset's window moving with time, rather than freezing it at selection time.
|
|
||||||
export function computePresetRange(id: TimeRangePresetId): TimeRange | null {
|
|
||||||
const preset = TIME_RANGE_PRESETS.find((p) => p.id === id)
|
|
||||||
if (!preset || preset.ms == null) return null
|
|
||||||
const now = Date.now()
|
|
||||||
return { startMs: now - preset.ms, endMs: now }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Buckets a fixed range into this many slots, so e.g. a rolling `5m` preset always requests a resolution fine enough to visibly slide instead of a handful of coarse, jumpy bars.
|
/// Buckets a fixed range into this many slots, so e.g. a rolling `5m` preset always requests a resolution fine enough to visibly slide instead of a handful of coarse, jumpy bars.
|
||||||
const TIMELINE_TARGET_BUCKETS = 60
|
const TIMELINE_TARGET_BUCKETS = 60
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import type { TimeRange, TimeRangePresetId } from './LogTimeline'
|
import type { TimeRange, TimeRangePresetId } from '../lib/timeRange'
|
||||||
import {
|
import {
|
||||||
ApiError,
|
ApiError,
|
||||||
declareMetric,
|
declareMetric,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
YAxis,
|
YAxis,
|
||||||
} from 'recharts'
|
} from 'recharts'
|
||||||
import type { ChartType, PromqlSeries } from '../lib/api'
|
import type { ChartType, PromqlSeries } from '../lib/api'
|
||||||
import type { TimeRange } from './LogTimeline'
|
import type { TimeRange } from '../lib/timeRange'
|
||||||
|
|
||||||
/// Renders a label combination as a series key/legend string, e.g. `{"path":"/a"}` -> `path=/a`; no labels renders as `value`.
|
/// Renders a label combination as a series key/legend string, e.g. `{"path":"/a"}` -> `path=/a`; no labels renders as `value`.
|
||||||
export function seriesLabel(labels: Record<string, string>): string {
|
export function seriesLabel(labels: Record<string, string>): string {
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
export interface TimeRange {
|
||||||
|
startMs: number
|
||||||
|
endMs: number
|
||||||
|
}
|
||||||
|
|
||||||
|
// `'all'` clears the range (the implicit default); the rest resolve to a window ending "now" at the moment they're (re-)computed — see `computePresetRange`.
|
||||||
|
export type TimeRangePresetId = 'all' | '1m' | '2m' | '5m' | '15m' | '1h' | '24h'
|
||||||
|
|
||||||
|
export const TIME_RANGE_PRESETS: { id: TimeRangePresetId; label: string; ms: number | null }[] = [
|
||||||
|
{ id: 'all', label: 'All', ms: null },
|
||||||
|
{ id: '1m', label: '1m', ms: 60 * 1000 },
|
||||||
|
{ id: '2m', label: '2m', ms: 2 * 60 * 1000 },
|
||||||
|
{ id: '5m', label: '5m', ms: 5 * 60 * 1000 },
|
||||||
|
{ id: '15m', label: '15m', ms: 15 * 60 * 1000 },
|
||||||
|
{ id: '1h', label: '1h', ms: 60 * 60 * 1000 },
|
||||||
|
{ id: '24h', label: '24h', ms: 24 * 60 * 60 * 1000 },
|
||||||
|
]
|
||||||
|
|
||||||
|
// Callers re-invoke this on their existing poll cadence (see `App.tsx`) to keep a rolling preset's window moving with time, rather than freezing it at selection time.
|
||||||
|
export function computePresetRange(id: TimeRangePresetId): TimeRange | null {
|
||||||
|
const preset = TIME_RANGE_PRESETS.find((p) => p.id === id)
|
||||||
|
if (!preset || preset.ms == null) return null
|
||||||
|
const now = Date.now()
|
||||||
|
return { startMs: now - preset.ms, endMs: now }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user