"use client"; import Link from "next/link"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { Button } from "yt-dlp-transcript-common/components/ui/button"; import type { PublishLaneStatus, PublishPlan } from "yt-dlp-transcript-common/views/publishStatus"; import { PauseLaneButton } from "../../components/lanes/pauseControl"; import { drainPublishLaneAction, startPublishLaneAction, stopPublishLaneAction, type LaneControlResult, } from "../../sites/lib/publishActions"; import { Chip } from "../../sites/components/PublishPanel"; import { useHydrated } from "./useOperationsStatus"; // The publish lane's console (release 18): the runner and its three controls // (Start / Drain / Stop — the runner, as on every lane), the hold (the LANE's // gate: a hold stops dispatching between stages and never kills one), what the // runner last did and when it looks next, and the plan a pass would run now. // // The page is server-rendered from readPublishStatus; this refreshes it every // few seconds while it is open, and after every control. const REFRESH_MS = 5_000; function at(ms: number | null): string { return ms === null ? "—" : new Date(ms).toLocaleString(); } export function PublishLaneView({ lane, plan, }: { lane: PublishLaneStatus; plan: Pick; }) { const router = useRouter(); const hydrated = useHydrated(); const [busy, setBusy] = useState(false); const [error, setError] = useState(null); const running = lane.live.running; useEffect(() => { const t = setInterval(() => router.refresh(), REFRESH_MS); return () => clearInterval(t); }, [router]); async function control(action: () => Promise) { setBusy(true); setError(null); try { const r = await action(); if (!r.ok) setError(r.error ?? "The control failed."); } finally { setBusy(false); router.refresh(); } } return (

Publish lane

{running ? "Runner running" : "Runner stopped"} router.refresh()} />
{error && (

{error}

)}
Lane
{lane.enabled ? "on" : "off"} {lane.held ? " · held" : ""} {lane.quietNow ? " · quiet hours" : ""} {lane.blockedReason ? ` — ${lane.blockedReason}` : ""}
A pass now
{lane.due ? "due" : "not due"} — {lane.reason}
Last check
{at(lane.live.lastCheckAt)}
Next check
{at(lane.live.nextCheckAt)}
Last pass
{at(lane.live.lastPassAt)} {lane.live.lastPassSummary ? ` — ${lane.live.lastPassSummary}` : ""}
Last decision
{lane.live.lastDecision ?? "—"}
{lane.live.jobId && ( <>
Runner
job log
)}

What a pass would run now

{plan.steps.length === 0 ? (

Nothing: every target its policies cover is current.

) : (
    {plan.steps.map((s) => (
  1. {s.kind} {s.target} {s.preview ? ` --preview ${s.preview}` : ""} {" "} — {s.reason}
  2. ))}
)} {plan.skipped.length > 0 && (
    {plan.skipped.map((s) => (
  • {s.kind} {s.target} : {s.reason}
  • ))}
)}

The same plan is Publish now on{" "} /sites ; a site’s policy is set on its own page.

); }