Normalize radii, drop shadows/blur and font-black, and document the one-view-at-a-time plan in AGENTS.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
134 lines
5.3 KiB
TypeScript
134 lines
5.3 KiB
TypeScript
import { useState, useEffect, useRef } from "react";
|
|
import { AlertCircle, CloudCog, Lock } from "lucide-react";
|
|
import { useObservabilityData } from "./hooks/useObservabilityData";
|
|
import { IconRail } from "./components/layout/IconRail";
|
|
import { TopBar } from "./components/layout/TopBar";
|
|
import { CommandAndQueryBar } from "./components/CommandAndQueryBar";
|
|
import { WaveformHistogram } from "./components/WaveformHistogram";
|
|
import { EntryVisualization } from "./components/EntryVisualization";
|
|
import { handleCallback, login } from "./lib/auth";
|
|
|
|
function AuthCallbackView() {
|
|
const [error, setError] = useState<string | null>(null);
|
|
const handledRef = useRef(false);
|
|
|
|
useEffect(() => {
|
|
if (handledRef.current) return;
|
|
handledRef.current = true;
|
|
|
|
handleCallback()
|
|
.then(() => {
|
|
window.location.href = "/";
|
|
})
|
|
.catch((err) => {
|
|
console.error("Authentication callback error:", err);
|
|
setError(err instanceof Error ? err.message : String(err));
|
|
});
|
|
}, []);
|
|
|
|
return (
|
|
<div className="flex min-h-screen items-center justify-center bg-ds-bg p-6 font-body text-ds-text">
|
|
<main className="w-full max-w-md rounded-[14px] border border-ds-line bg-ds-surface p-8 text-center">
|
|
{error ? (
|
|
<div className="flex flex-col items-center gap-4">
|
|
<div className="flex h-14 w-14 items-center justify-center rounded-full bg-ds-critical-bg text-ds-critical">
|
|
<AlertCircle className="h-7 w-7" aria-hidden="true" />
|
|
</div>
|
|
<div>
|
|
<h2 className="font-[family-name:var(--font-display)] text-lg font-bold text-ds-critical">Authentication failed</h2>
|
|
<p className="mt-1 font-[family-name:var(--font-data)] text-xs text-ds-text-3">{error}</p>
|
|
</div>
|
|
<button
|
|
type="button"
|
|
onClick={() => login()}
|
|
className="mt-2 inline-flex h-9 items-center rounded-[9px] bg-ds-accent px-4 text-[13px] font-semibold text-ds-on-accent"
|
|
>
|
|
Try again
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<div className="flex flex-col items-center gap-4">
|
|
<div className="flex h-14 w-14 animate-pulse items-center justify-center rounded-full bg-ds-accent-bg text-ds-accent">
|
|
<Lock className="h-7 w-7" aria-hidden="true" />
|
|
</div>
|
|
<div>
|
|
<h2 className="font-[family-name:var(--font-display)] text-lg font-semibold text-ds-text">Completing sign in</h2>
|
|
<p className="mt-1 text-xs text-ds-text-3">Exchanging authorization code with OIDC provider…</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function App() {
|
|
const { isConnected, traces, logs, metrics, activeTab } = useObservabilityData();
|
|
|
|
const hasLoadedAnyData = traces.length > 0 || logs.length > 0 || metrics.length > 0;
|
|
const isCallback =
|
|
typeof window !== "undefined" &&
|
|
(window.location.pathname === "/auth_callback" ||
|
|
window.location.search.includes("code="));
|
|
// The Issues tab is the redesigned triage overview: it owns its own filter
|
|
// bar and cards, so the legacy anomaly banner and volume waveform above it
|
|
// would just duplicate that UI in a different visual language.
|
|
const isTriageOverview = activeTab === "tab0" || activeTab === "tab7";
|
|
|
|
if (isCallback) {
|
|
return <AuthCallbackView />;
|
|
}
|
|
|
|
return (
|
|
<div className="bg-ds-bg font-body text-ds-text min-h-screen antialiased selection:bg-ds-accent-bg selection:text-ds-accent">
|
|
{/* Fixed 72px icon rail */}
|
|
<IconRail />
|
|
|
|
{/* Main Content Area offset by the rail width */}
|
|
<div className="pl-[72px]">
|
|
{/* Fixed top bar */}
|
|
<TopBar />
|
|
|
|
{/* Main Telemetry Console View */}
|
|
<main className="relative w-full bg-ds-bg pb-12 pt-[58px]">
|
|
<div className="flex w-full flex-col px-6">
|
|
{!isTriageOverview && (
|
|
<>
|
|
{/* Real Anomaly Radar & Filter Bar */}
|
|
<CommandAndQueryBar />
|
|
|
|
{/* Ingest & Incident Waveform Histogram */}
|
|
<WaveformHistogram />
|
|
</>
|
|
)}
|
|
|
|
{/* Telemetry Visualizations & Views */}
|
|
<section className="relative flex min-h-0 flex-1 flex-col">
|
|
{isConnected || hasLoadedAnyData ? (
|
|
<EntryVisualization />
|
|
) : (
|
|
<div className="flex h-full min-h-[360px] flex-col items-center justify-center gap-4 rounded-[14px] border border-dashed border-ds-line bg-ds-surface p-12 text-center">
|
|
<div className="flex h-16 w-16 items-center justify-center rounded-full bg-ds-accent-bg text-ds-accent">
|
|
<CloudCog className="h-8 w-8 animate-pulse" aria-hidden="true" />
|
|
</div>
|
|
<div>
|
|
<p className="text-base font-semibold text-ds-text">
|
|
Establishing telemetry pipeline
|
|
</p>
|
|
<p className="mx-auto mt-1 max-w-sm text-xs text-ds-text-3">
|
|
Connecting to OTLP collector. Listening for incoming traces, logs, and metrics.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</section>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
}
|
|
|
|
export default App;
|