Files
go-otel/otel-ui/src/components/CommandAndQueryBar.tsx
T
mats 97743ea21c
Build and Publish / Metadata (push) Successful in 2s
Build and Publish / BuildAndDeployAmd64 (push) Successful in 1m4s
sourcemap view
2026-09-19 15:49:44 +02:00

154 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Download } from "lucide-react"
import React from "react";
import { useObservabilityData } from "../hooks/useObservabilityData";
export const CommandAndQueryBar: React.FC = () => {
const {
logs,
traces,
metrics,
searchQuery,
setSearchQuery,
showErrorsOnly,
setShowErrorsOnly,
selectedServices,
toggleService,
resetFilters,
minDurationMs,
setMinDurationMs,
timeWindow,
setTimeWindow,
} = useObservabilityData();
const totalFilteredEvents = logs.length + traces.length + metrics.length;
const exportNDJSON = () => {
const records = [
...traces.map((t) => JSON.stringify({ type: "traces", ...t })),
...logs.map((l) => JSON.stringify({ type: "logs", ...l })),
...metrics.map((m) => JSON.stringify({ type: "metrics", ...m })),
].join("\n");
const blob = new Blob([records], { type: "application/x-ndjson" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `hyperscope-filtered-telemetry-${new Date().toISOString()}.ndjson`;
a.click();
URL.revokeObjectURL(url);
};
const hasActiveFilters =
Boolean(searchQuery) ||
showErrorsOnly ||
selectedServices.size > 0 ||
minDurationMs > 0 ||
timeWindow !== "all";
return (
<div className="flex flex-col gap-2.5 mb-4 font-body">
{/* Filter and Telemetry Status Bar */}
<div className="flex flex-wrap items-center justify-between gap-2.5 p-3 rounded-xl bg-ds-bg border border-ds-line">
<div className="flex items-center gap-2 flex-wrap">
<span className="font-mono text-[10px] text-ds-text-3 uppercase tracking-wider font-semibold shrink-0">
Active Context:
</span>
<span className="font-mono text-xs text-ds-accent font-semibold">
{totalFilteredEvents} Signals ({timeWindow === "all" ? "All Time" : `Last ${timeWindow}`})
</span>
{/* Selected Service Pills */}
{Array.from(selectedServices).map((service) => (
<span
key={service}
className="inline-flex items-center gap-1 rounded-full bg-ds-accent-bg text-ds-accent border border-ds-line px-2.5 py-0.5 font-mono text-xs font-semibold"
>
<span>service:{service}</span>
<button
type="button"
onClick={() => toggleService(service)}
className="hover:text-ds-text"
>
×
</button>
</span>
))}
{/* Errors Only Pill */}
{showErrorsOnly && (
<span className="inline-flex items-center gap-1 rounded-full bg-ds-critical-bg text-ds-critical px-2.5 py-0.5 font-mono text-xs font-semibold">
<span>Errors Only</span>
<button
type="button"
onClick={() => setShowErrorsOnly(false)}
className="hover:text-ds-text"
>
×
</button>
</span>
)}
{/* Slow Spans Pill */}
{minDurationMs > 0 && (
<span className="inline-flex items-center gap-1 rounded-full bg-ds-warn-bg text-ds-warn border border-ds-warn/40 px-2.5 py-0.5 font-mono text-xs font-semibold">
<span>Latency &gt;{minDurationMs}ms</span>
<button
type="button"
onClick={() => setMinDurationMs(0)}
className="hover:text-ds-text"
>
×
</button>
</span>
)}
{/* Search Query Pill */}
{searchQuery && (
<span className="inline-flex items-center gap-1 rounded-full bg-ds-surface-2 text-ds-text border border-ds-line px-2.5 py-0.5 font-mono text-xs">
<span>query: &quot;{searchQuery}&quot;</span>
<button
type="button"
onClick={() => setSearchQuery("")}
className="hover:text-ds-text"
>
×
</button>
</span>
)}
{hasActiveFilters && (
<button
type="button"
onClick={() => {
resetFilters();
setMinDurationMs(0);
setTimeWindow("all");
}}
className="text-ds-text-3 hover:text-ds-text font-mono text-xs underline ml-1"
>
Clear all
</button>
)}
</div>
{/* Export and Action buttons */}
<div className="flex items-center gap-2">
<button
type="button"
onClick={exportNDJSON}
className="flex items-center gap-1 px-2.5 py-1 bg-ds-surface hover:bg-ds-surface-2 text-ds-text font-mono text-xs rounded-lg transition-colors border border-ds-line"
title="Export currently filtered telemetry signals as NDJSON"
>
<Download className="h-[15px] w-[15px] shrink-0" aria-hidden="true" />
<span>Export NDJSON</span>
</button>
</div>
</div>
</div>
);
};
export default CommandAndQueryBar;