diff --git a/ecosystem-explorer/src/features/collector/collector-detail-page.tsx b/ecosystem-explorer/src/features/collector/collector-detail-page.tsx index 891f72db..db639bdc 100644 --- a/ecosystem-explorer/src/features/collector/collector-detail-page.tsx +++ b/ecosystem-explorer/src/features/collector/collector-detail-page.tsx @@ -15,7 +15,7 @@ */ import { useState } from "react"; import { useParams, useNavigate } from "react-router-dom"; -import { Info, ExternalLink, AlertCircle, Loader2, Check, Users } from "lucide-react"; +import { Info, ExternalLink, AlertCircle, Loader2, Check } from "lucide-react"; import { GitHubIcon } from "@/components/icons/github-icon"; import { BackButton } from "@/components/ui/back-button"; @@ -37,24 +37,100 @@ const COMPONENT_TYPE_DESCRIPTIONS: Record = { connector: "Connectors act as both an exporter and a receiver, joining two pipelines together.", }; +const STABILITY_DEFINITIONS: Record = { + development: { + label: "Development", + desc: "Not ready for general use. May have bugs or lack documentation.", + color: "text-blue-500", + }, + alpha: { + label: "Alpha", + desc: "Ready for testing and early feedback. Not recommended for production.", + color: "text-purple-500", + }, + beta: { + label: "Beta", + desc: "Ready for production use. Features are largely stable, though minor changes might occur.", + color: "text-green-500", + }, + stable: { + label: "Stable", + desc: "Fully supported for production use. Backwards compatibility is guaranteed.", + color: "text-emerald-600 dark:text-emerald-500", + }, + deprecated: { + label: "Deprecated", + desc: "Scheduled for removal. Should no longer be used.", + color: "text-red-500", + }, + unmaintained: { + label: "Unmaintained", + desc: "No longer actively maintained or supported.", + color: "text-red-600", + }, +}; + +const getDistributionInfo = (distroName: string) => { + const lower = distroName.toLowerCase(); + if (lower.includes("contrib")) { + return { + name: "OpenTelemetry Collector Contrib", + desc: "The community-driven distribution containing third-party plugins, specialized receivers, and experimental components.", + cmdLabel: "# Docker", + cmd: "docker pull otel/opentelemetry-collector-contrib:latest", + url: "https://github.com/open-telemetry/opentelemetry-collector-contrib", + }; + } + if (lower.includes("core")) { + return { + name: "OpenTelemetry Collector Core", + desc: "The core distribution containing only the most essential, officially supported telemetry components.", + cmdLabel: "# Docker", + cmd: "docker pull otel/opentelemetry-collector:latest", + url: "https://github.com/open-telemetry/opentelemetry-collector", + }; + } + + if (lower === "k8s" || lower.includes("kubernetes")) { + return { + name: "OpenTelemetry Operator for Kubernetes", + desc: "The official Kubernetes Operator designed to manage and provision the OpenTelemetry Collector.", + cmdLabel: "# kubectl", + cmd: "kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml", + url: "https://github.com/open-telemetry/opentelemetry-operator", + }; + } + + return { + name: distroName, + desc: "A specialized OpenTelemetry distribution.", + cmdLabel: null, + cmd: null, + url: "https://opentelemetry.io/docs/collector/installation/", + }; +}; + +const getBadgeVariant = (level: string): "success" | "info" | "warning" | "muted" => { + const lower = level.toLowerCase(); + if (lower === "stable") return "success"; + if (lower === "beta") return "info"; + if ( + lower === "alpha" || + lower === "development" || + lower === "deprecated" || + lower === "unmaintained" + ) { + return "warning"; + } + return "muted"; +}; + export function CollectorDetailPage() { const { version, id } = useParams<{ version: string; id: string }>(); const navigate = useNavigate(); const { data: component, loading, error } = useCollectorComponent(id ?? "", version ?? ""); const [activeTab, setActiveTab] = useState("details"); - const getStabilityLabel = (level: string) => { - const labels: Record = { - alpha: "Alpha", - beta: "Beta", - stable: "Stable", - deprecated: "Deprecated", - unmaintained: "Unmaintained", - development: "In Development", - }; - return labels[level.toLowerCase()] || level; - }; - if (loading) { return ( @@ -105,6 +181,22 @@ export function CollectorDetailPage() { ); } + const dynamicSignals = component.status?.stability + ? Array.from(new Set(Object.values(component.status.stability).flat() as string[])) + : []; + + const getSignalStability = (signalName: string) => { + if (!component.status?.stability) return null; + for (const [level, signals] of Object.entries(component.status.stability)) { + if ((signals as string[]).includes(signalName)) return level; + } + return null; + }; + + const activeStabilityLevels = component.status?.stability + ? Object.keys(component.status.stability) + : []; + return ( @@ -165,11 +257,6 @@ export function CollectorDetailPage() { label: "Stability", icon: