import { Button, Icon, Select } from "@nodedc/ui-react"; import type { ObservationTimelineMode } from "../core/runtime/contracts"; export function ObservationTimeline({ active, sourceCount, mode = "live-only", seekable = false, synchronization = "host-arrival-best-effort", rangeNs = null, currentNs = null, playing = false, onSeek, onPlayingChange, onJumpToEnd, showJumpToEnd = true, playbackRate, onPlaybackRateChange, accumulationSeconds, onAccumulationChange, onAccumulationCommit, className = "", }: { active: boolean; sourceCount: number; mode?: ObservationTimelineMode; seekable?: boolean; synchronization?: "host-arrival-best-effort" | "shared-clock" | "frame-accurate"; rangeNs?: { min: number; max: number } | null; currentNs?: number | null; playing?: boolean; onSeek?: (timeNs: number) => void; onPlayingChange?: (playing: boolean) => void; onJumpToEnd?: () => void; showJumpToEnd?: boolean; playbackRate?: number; onPlaybackRateChange?: (rate: number) => void; accumulationSeconds?: number; onAccumulationChange?: (value: number) => void; onAccumulationCommit?: () => void; className?: string; }) { const playbackRange = normalizeTimelineRange(rangeNs); const buffered = Boolean( seekable && (mode === "buffered" || mode === "recorded") && playbackRange, ); const elapsedSeconds = playbackRange ? timelineOffsetSeconds(playbackRange, currentNs ?? playbackRange.min) : 0; const durationSeconds = playbackRange ? Math.max(0, (playbackRange.max - playbackRange.min) / 1_000_000_000) : 0; const synchronizationLabel = { "host-arrival-best-effort": "Синхронизация по приходу", "shared-clock": "Общие часы", "frame-accurate": "Покадровая синхронизация", }[synchronization]; const accumulationValue = accumulationSeconds === undefined ? null : normalizeAccumulationSeconds(accumulationSeconds); return (
{formatAccumulationDuration(accumulationValue)}