Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,52 +13,82 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useState } from "react";
import type { Attribute } from "@/types/javaagent";
import { ChevronDown } from "lucide-react";

interface AttributeTableProps {
attributes: Attribute[];
expandVersion?: number;
collapseVersion?: number;
}

export function AttributeTable({ attributes }: AttributeTableProps) {
export function AttributeTable({ attributes, expandVersion = 0, collapseVersion = 0 }: AttributeTableProps) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think it makes sense to have the controls so far away from what they affect.

image

Can we add controls for metrics/ spans individually? So i can expand/collapse all the metrics or spans and the controls are right under each "Metrics" or "spans" heading?

const [isOpen, setIsOpen] = useState(false);
const [prevExpand, setPrevExpand] = useState(expandVersion);
const [prevCollapse, setPrevCollapse] = useState(collapseVersion);

if (expandVersion > prevExpand) {
setPrevExpand(expandVersion);
setIsOpen(true);
}

if (collapseVersion > prevCollapse) {
setPrevCollapse(collapseVersion);
setIsOpen(false);
}

if (attributes.length === 0) {
return null;
}

return (
<div className="border-border/30 overflow-x-auto rounded-lg border">
<table aria-label="Attributes" className="w-full min-w-[260px] border-collapse">
<thead>
<tr className="bg-white/5">
<th
scope="col"
className="text-muted-foreground p-2 text-left text-[10px] font-bold tracking-widest uppercase sm:p-3"
>
Key
</th>
<th
scope="col"
className="text-muted-foreground p-2 text-left text-[10px] font-bold tracking-widest uppercase sm:p-3"
>
Type
</th>
</tr>
</thead>
<tbody>
{attributes.map((attr, index) => (
<tr
key={attr.name}
className={`attribute-row ${index % 2 === 1 ? "bg-white/[0.03]" : ""}`}
>
<td className="p-2 font-mono text-xs sm:p-4 sm:text-sm">{attr.name}</td>
<td className="p-2 sm:p-4">
<span className="border-border/30 bg-card/80 text-muted-foreground inline-block w-fit rounded border px-2 py-1 text-xs font-bold tracking-wider uppercase">
{attr.type}
</span>
</td>
<details
open={isOpen}
onToggle={(e) => setIsOpen((e.target as HTMLDetailsElement).open)}
className="group border-border/30 bg-card/50 overflow-hidden rounded-lg border open:bg-transparent"
>
<summary className="hover:bg-card/80 flex cursor-pointer items-center justify-between p-3 text-sm font-medium transition-colors">
<span className="text-muted-foreground text-xs font-black tracking-[0.2em] uppercase">
View {attributes.length} Attribute{attributes.length === 1 ? "" : "s"}
</span>
<ChevronDown className="text-muted-foreground h-4 w-4 transition-transform group-open:rotate-180" />
</summary>
<div className="border-border/30 overflow-x-auto border-t">
<table aria-label="Attributes" className="w-full min-w-[260px] border-collapse">
<thead>
<tr className="bg-white/5">
<th
scope="col"
className="text-muted-foreground p-2 text-left text-[10px] font-bold tracking-widest uppercase sm:p-3"
>
Key
</th>
<th
scope="col"
className="text-muted-foreground p-2 text-left text-[10px] font-bold tracking-widest uppercase sm:p-3"
>
Type
</th>
</tr>
))}
</tbody>
</table>
</div>
</thead>
<tbody>
{attributes.map((attr, index) => (
<tr
key={attr.name}
className={`attribute-row ${index % 2 === 1 ? "bg-white/[0.03]" : ""}`}
>
<td className="p-2 font-mono text-xs sm:p-4 sm:text-sm">{attr.name}</td>
<td className="p-2 sm:p-4">
<span className="border-border/30 bg-card/80 text-muted-foreground inline-block w-fit rounded border px-2 py-1 text-xs font-bold tracking-wider uppercase">
{attr.type}
</span>
</td>
</tr>
))}
</tbody>
</table>
</div>
</details>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ import type { Telemetry } from "@/types/javaagent";

interface TelemetrySectionProps {
telemetry: Telemetry[];
expandVersion?: number;
collapseVersion?: number;
}

export function TelemetrySection({ telemetry }: TelemetrySectionProps) {
export function TelemetrySection({
telemetry,
expandVersion = 0,
collapseVersion = 0
}: TelemetrySectionProps) {
const [selectedWhen, setSelectedWhen] = useState(telemetry[0]?.when ?? "default");

// Validate selected value and fall back to first option if invalid
Expand Down Expand Up @@ -90,11 +96,12 @@ export function TelemetrySection({ telemetry }: TelemetrySectionProps) {

{/* Attributes section */}
{metric.attributes && metric.attributes.length > 0 && (
<div className="space-y-4">
<h4 className="text-muted-foreground text-xs font-black tracking-[0.2em] uppercase">
Attributes
</h4>
<AttributeTable attributes={metric.attributes} />
<div className="pt-2">
<AttributeTable
attributes={metric.attributes}
expandVersion={expandVersion}
collapseVersion={collapseVersion}
/>
</div>
)}
</div>
Expand Down Expand Up @@ -128,11 +135,12 @@ export function TelemetrySection({ telemetry }: TelemetrySectionProps) {

{/* Attributes section */}
{span.attributes && span.attributes.length > 0 && (
<div className="space-y-4">
<h4 className="text-muted-foreground text-xs font-black tracking-[0.2em] uppercase">
Attributes
</h4>
<AttributeTable attributes={span.attributes} />
<div className="pt-2">
<AttributeTable
attributes={span.attributes}
expandVersion={expandVersion}
collapseVersion={collapseVersion}
/>
</div>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import {
AlertCircle,
Loader2,
HelpCircle,
ChevronsDown,
ChevronsUp,
} from "lucide-react";

import { BackButton } from "@/components/ui/back-button";
Expand All @@ -39,6 +41,8 @@ import {
getSemanticConventionInfo,
getFeatureInfo,
} from "./utils/format";
import { getBadgeInfo } from "./utils/badge-info";
import { TelemetryBadges } from "./components/instrumentation-badges";
import { TelemetrySection } from "./components/telemetry-section";
import { TelemetryComparisonSection } from "./components/telemetry-comparison/telemetry-comparison-section";
import { VersionSelector } from "./components/version-selector";
Expand Down Expand Up @@ -76,6 +80,8 @@ export function InstrumentationDetailPage() {
const navigate = useNavigate();
const [showComparison, setShowComparison] = useState(false);
const [activeTab, setActiveTab] = useState("details");
const [expandVersion, setExpandVersion] = useState(0);
const [collapseVersion, setCollapseVersion] = useState(0);

const { data: versionsData, loading: versionsLoading } = useVersions();

Expand Down Expand Up @@ -156,6 +162,7 @@ export function InstrumentationDetailPage() {
const displayName = getInstrumentationDisplayName(instrumentation);
const showRawName =
instrumentation.display_name && instrumentation.display_name !== instrumentation.name;
const badgeInfo = getBadgeInfo(instrumentation);

return (
<PageContainer>
Expand Down Expand Up @@ -217,6 +224,7 @@ export function InstrumentationDetailPage() {
? "Disabled by Default"
: "Enabled by Default"}
</GlowBadge>
<TelemetryBadges badges={badgeInfo} />
</div>
</div>

Expand Down Expand Up @@ -275,6 +283,80 @@ export function InstrumentationDetailPage() {

<TabsContent value="details" className="mt-0 p-4 sm:p-6">
<div className="space-y-8">
{/* Value Proposition Summary */}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im still not sure about this, i have two remaining concerns:

  • We still aren't indicating what the glow badge values mean in the traces. At the very least we should be indicating that they are the "Span Kinds" emitted
  • Listing all the metrics on the metric panel works when there a small number of metrics, but what about a case where an isntrumentation emits dozens? I dont think that would look good

I agree this page can be improved, but I'm not sure this is an improvement. Let's remove these changes from the PR for now and stick to just introducing the expand/collapsing of the telemetry signals.

For the rest of your ideas around progressive disclosure, I think it might be best to continue the conversation / brainstorming as part of our UI/UX redesign project: #370

{(badgeInfo.hasMetrics || badgeInfo.hasSpans) && (
<div>
<SectionHeader>Telemetry Overview</SectionHeader>
<div className="grid gap-4 md:grid-cols-2">
{badgeInfo.hasSpans && (
<DetailCard withHoverEffect>
<div className="flex items-start gap-3">
<Activity
className="text-info mt-0.5 h-5 w-5 flex-shrink-0"
aria-hidden="true"
/>
<div className="flex-1 space-y-1">
<h3 className="text-foreground text-sm font-semibold">
Traces & Spans
</h3>
<p className="text-muted-foreground text-sm">
Provides visibility into application activity and execution flow across services and components.
</p>
{instrumentation.telemetry &&
instrumentation.telemetry[0] &&
instrumentation.telemetry[0].spans && (
<div className="mt-2 flex flex-wrap gap-1">
{instrumentation.telemetry[0].spans.map((span, idx) => (
<GlowBadge key={idx} variant="info" className="text-[10px]">
{span.span_kind}
</GlowBadge>
))}
</div>
)}
</div>
</div>
</DetailCard>
)}

{badgeInfo.hasMetrics && (
<DetailCard withHoverEffect>
<div className="flex items-start gap-3">
<Activity
className="text-success mt-0.5 h-5 w-5 flex-shrink-0"
aria-hidden="true"
/>
<div className="flex-1 space-y-1">
<h3 className="text-foreground text-sm font-semibold">
Metrics
</h3>
<p className="text-muted-foreground text-sm">
Gives you the big picture of system health, like total request
Comment thread
hussainjamal760 marked this conversation as resolved.
counts, error rates, and average speeds over time.
</p>
{instrumentation.telemetry &&
instrumentation.telemetry[0] &&
instrumentation.telemetry[0].metrics && (
<div className="mt-2 flex flex-wrap gap-1">
{instrumentation.telemetry[0].metrics.map((metric, idx) => (
<span
key={idx}
className="bg-success/10 text-success border-success/20 truncate rounded border px-1.5 py-0.5 font-mono text-[10px]"
title={metric.name}
>
{metric.name.length > 50
? metric.name.substring(0, 50) + "..."
: metric.name}
</span>
))}
</div>
)}
</div>
</div>
</DetailCard>
)}
</div>
</div>
)}
{((instrumentation.features && instrumentation.features.length > 0) ||
(instrumentation.semantic_conventions &&
instrumentation.semantic_conventions.length > 0)) && (
Expand Down Expand Up @@ -494,7 +576,7 @@ export function InstrumentationDetailPage() {
<TabsContent value="telemetry" className="mt-0 p-4 sm:p-6">
{instrumentation.telemetry && instrumentation.telemetry.length > 0 ? (
<div className="space-y-8">
<div className="flex justify-center">
<div className="flex flex-col items-center gap-6">
<div
className="border-border inline-flex w-full rounded-lg border bg-transparent p-1 sm:w-auto"
role="group"
Expand Down Expand Up @@ -524,10 +606,34 @@ export function InstrumentationDetailPage() {
Version Comparison
</button>
</div>

{!showComparison && instrumentation.telemetry && instrumentation.telemetry.length > 0 && (
<div className="flex items-center gap-3">
<button
onClick={() => setExpandVersion((v) => v + 1)}
className="hover:border-primary/30 hover:bg-primary/5 border-border/30 bg-card/50 text-muted-foreground hover:text-primary flex items-center gap-2 rounded-lg border px-3 py-1.5 text-[10px] font-black tracking-[0.15em] uppercase transition-all duration-200 hover:scale-[1.02] active:scale-[0.98]"
>
<ChevronsDown className="h-3.5 w-3.5" />
Expand All
</button>
<div className="bg-border/30 h-4 w-px" />
<button
onClick={() => setCollapseVersion((v) => v + 1)}
className="hover:border-primary/30 hover:bg-primary/5 border-border/30 bg-card/50 text-muted-foreground hover:text-primary flex items-center gap-2 rounded-lg border px-3 py-1.5 text-[10px] font-black tracking-[0.15em] uppercase transition-all duration-200 hover:scale-[1.02] active:scale-[0.98]"
>
<ChevronsUp className="h-3.5 w-3.5" />
Collapse All
</button>
</div>
)}
</div>

{!showComparison ? (
<TelemetrySection telemetry={instrumentation.telemetry} />
<TelemetrySection
telemetry={instrumentation.telemetry}
expandVersion={expandVersion}
collapseVersion={collapseVersion}
/>
) : (
versionsData && (
<TelemetryComparisonSection
Expand Down