// CIL[BEGIN chunk_id="ServicesPage_module_header_1785000051" type="module_header" identity="module_header" parent="none"] // CIL[DOC-MACRO purpose="Render the Workbench Services observability page"] // CIL[DOC-RESPONSIBILITY responsibility="Show service health derived from trace root_span_name aggregates"] // CIL[DOC-CONTEXT module="workbench.pages.observe.ServicesPage" layer="frontend-page" related_files="[\"custom/apps/workbench/functions/custom_workbench-observability.ts\",\"custom/apps/workbench/pages/observe/UptimePage.tsx\"]"] // CIL[DOC-CONTRACT inputs="none" outputs="JSX Services page" errors="fetch errors rendered inline" side_effects="calls /api/custom_workbench-observability"] // CIL[DOC-MICRO logic_summary="Provides a time range selector, fetches trace stats, aggregates health by root_span_name, and renders summary cards and a service health table" notable_decisions=["Treats each distinct root_span_name as a service","Health is based on error rate thresholds"]] // CIL[DOC-CONFIDENCE pass="first" score="0.90" flags="none"] // CIL[DOC-STABILITY stability="experimental"] // CIL[DOC-AUDIENCE audience="developer"] import { useEffect, useMemo, useState, Fragment } from 'react' import { apiFetch } from '@core/lib/api' import { formatDateTime, formatNumber } from '@core/lib/utils' import { Card, CardContent, CardHeader, CardTitle } from '@core/components/ui/card' import { NativeSelect } from '@core/components/ui/native-select' import { LoadingSpinner } from '@core/components/ui/LoadingSpinner' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@core/components/ui/table' import { Pagination } from '../../components/Pagination' import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell, CartesianGrid, } from 'recharts' import { Server, Activity, AlertTriangle, CheckCircle, ChevronDown, ChevronRight } from 'lucide-react' // CIL[END chunk_id="ServicesPage_module_header_1785000051"] // CIL[BEGIN chunk_id="ServicesPage_servicesPage_1785000051" type="function" identity="ServicesPage" parent="ServicesPage_module_header_1785000051"] // CIL[DOC-MACRO purpose="Services observability page implementation"] // CIL[DOC-RESPONSIBILITY responsibility="Aggregate trace stats by service and display health"] // CIL[DOC-CONTEXT module="workbench.pages.observe.ServicesPage" layer="frontend-page" related_files="[\"custom/apps/workbench/functions/custom_workbench-observability.ts\"]"] // CIL[DOC-CONTRACT inputs="none" outputs="JSX" errors="fetch errors rendered inline" side_effects="network requests on mount and range change"] // CIL[DOC-MICRO logic_summary="Fetches trace stats for the selected range, aggregates counts and durations by root_span_name, and renders health cards and a sorted service table" notable_decisions=["Services with >5% error rate are degraded, >20% are erroring"]] // CIL[DOC-CONFIDENCE pass="first" score="0.90" flags="none"] // CIL[DOC-STABILITY stability="experimental"] // CIL[DOC-AUDIENCE audience="developer"] const RANGE_OPTIONS = [ { label: 'Last hour', value: '1h', ms: 60 * 60 * 1000 }, { label: 'Last 24 hours', value: '24h', ms: 24 * 60 * 60 * 1000 }, { label: 'Last 7 days', value: '7d', ms: 7 * 24 * 60 * 60 * 1000 }, { label: 'Last 30 days', value: '30d', ms: 30 * 24 * 60 * 60 * 1000 }, ] function rangeDates(value: string) { const now = new Date() const option = RANGE_OPTIONS.find((o) => o.value === value) || RANGE_OPTIONS[1] return { from: new Date(now.getTime() - option.ms).toISOString(), to: now.toISOString(), } } interface TraceRow { trace_id: string root_span_name: string started_at: string duration_ms: number span_count: number error_count: number outcome: string } interface ServiceHealth { name: string traces: number errors: number avg_duration_ms: number last_started_at: string error_rate: number } function ServiceTraces({ serviceName, traces }: { serviceName: string; traces: TraceRow[] }) { const serviceTraces = traces .filter((t) => (t.root_span_name || 'unknown') === serviceName) .sort((a, b) => new Date(b.started_at).getTime() - new Date(a.started_at).getTime()) .slice(0, 10) if (serviceTraces.length === 0) { return
No recent traces for this service.
} return (Service health and trace aggregates
No service data for the selected range.
) : (No services recorded in the selected range.
) : (