@kopai/ui 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +23 -0
  2. package/dist/index.cjs +1598 -233
  3. package/dist/index.d.cts +566 -4
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.mts +565 -3
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +1597 -209
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +13 -12
  10. package/src/components/observability/DynamicDashboard/DynamicDashboard.test.tsx +234 -0
  11. package/src/components/observability/DynamicDashboard/index.tsx +64 -0
  12. package/src/components/observability/MetricHistogram/MetricHistogram.stories.tsx +10 -1
  13. package/src/components/observability/MetricHistogram/index.tsx +85 -19
  14. package/src/components/observability/MetricStat/MetricStat.stories.tsx +2 -1
  15. package/src/components/observability/MetricTimeSeries/MetricTimeSeries.stories.tsx +23 -1
  16. package/src/components/observability/MetricTimeSeries/index.tsx +70 -27
  17. package/src/components/observability/__fixtures__/metrics.ts +97 -0
  18. package/src/components/observability/index.ts +3 -0
  19. package/src/components/observability/renderers/OtelLogTimeline.tsx +28 -0
  20. package/src/components/observability/renderers/OtelMetricHistogram.tsx +2 -0
  21. package/src/components/observability/renderers/OtelMetricStat.tsx +1 -13
  22. package/src/components/observability/renderers/OtelMetricTimeSeries.tsx +2 -0
  23. package/src/components/observability/renderers/OtelTraceDetail.tsx +35 -0
  24. package/src/components/observability/renderers/index.ts +2 -0
  25. package/src/components/observability/utils/attributes.ts +7 -0
  26. package/src/components/observability/utils/units.test.ts +116 -0
  27. package/src/components/observability/utils/units.ts +132 -0
  28. package/src/index.ts +1 -0
  29. package/src/lib/__snapshots__/generate-prompt-instructions.test.ts.snap +7 -1
  30. package/src/lib/generate-prompt-instructions.test.ts +1 -1
  31. package/src/lib/generate-prompt-instructions.ts +18 -6
  32. package/src/lib/observability-catalog.ts +7 -1
  33. package/src/lib/renderer.tsx +1 -1
  34. package/src/pages/observability.test.tsx +124 -0
  35. package/src/pages/observability.tsx +71 -36
  36. package/src/lib/dashboard-datasource.ts +0 -76
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["formatTimestamp","LOOKBACK_OPTIONS","formatTimestamp","formatTimestamp","AttributesTab","formatRelativeTime","AttributesTab","getSeverityColor"],"sources":["../src/providers/kopai-provider.tsx","../src/hooks/use-kopai-data.ts","../src/lib/log-buffer.ts","../src/hooks/use-live-logs.ts","../src/lib/component-catalog.ts","../src/lib/observability-catalog.ts","../src/lib/renderer.tsx","../src/components/observability/TabBar/index.tsx","../src/components/observability/utils/colors.ts","../src/components/observability/ServiceList/index.tsx","../src/components/observability/utils/time.ts","../src/components/observability/TraceSearch/index.tsx","../src/components/observability/utils/flatten-tree.ts","../src/components/observability/TraceTimeline/TraceHeader.tsx","../src/components/observability/TraceTimeline/Tooltip.tsx","../src/components/observability/TraceTimeline/TimelineBar.tsx","../src/components/observability/TraceTimeline/SpanRow.tsx","../src/components/observability/utils/attributes.ts","../src/components/observability/TraceTimeline/DetailPane/AttributesTab.tsx","../src/components/observability/TraceTimeline/DetailPane/EventsTab.tsx","../src/components/observability/TraceTimeline/DetailPane/LinksTab.tsx","../src/components/observability/TraceTimeline/DetailPane/index.tsx","../src/components/observability/shared/LoadingSkeleton.tsx","../src/components/KeyboardShortcuts/context.ts","../src/components/KeyboardShortcuts/ShortcutsHelpDialog.tsx","../src/components/KeyboardShortcuts/KeyboardShortcutsProvider.tsx","../src/components/observability/TraceTimeline/shortcuts.ts","../src/components/observability/TraceTimeline/index.tsx","../src/components/observability/TraceDetail/index.tsx","../src/components/observability/LogTimeline/LogRow.tsx","../src/components/observability/LogTimeline/LogDetailPane/AttributesTab.tsx","../src/components/observability/LogTimeline/LogDetailPane/JsonTreeView.tsx","../src/components/observability/LogTimeline/LogDetailPane/index.tsx","../src/components/observability/LogTimeline/shortcuts.ts","../src/components/observability/LogTimeline/index.tsx","../src/components/observability/LogTimeline/LogFilter.tsx","../src/components/observability/ServiceList/shortcuts.ts","../src/components/observability/renderers/OtelMetricDiscovery.tsx","../src/lib/catalog.ts","../src/components/dashboard/Badge/index.tsx","../src/components/dashboard/Card/index.tsx","../src/components/dashboard/Divider/index.tsx","../src/components/dashboard/Empty/index.tsx","../src/components/dashboard/Grid/index.tsx","../src/components/dashboard/Heading/index.tsx","../src/components/dashboard/Stack/index.tsx","../src/components/dashboard/Text/index.tsx","../src/pages/observability.tsx","../src/lib/generate-prompt-instructions.ts"],"sourcesContent":["import { createContext, useContext, type ReactNode } from \"react\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport type { KopaiClient as SDKClient } from \"@kopai/sdk\";\n\nexport type KopaiClient = Pick<\n SDKClient,\n | \"searchTracesPage\"\n | \"searchLogsPage\"\n | \"searchMetricsPage\"\n | \"getTrace\"\n | \"discoverMetrics\"\n>;\n\ninterface KopaiSDKContextValue {\n client: KopaiClient;\n}\n\nconst KopaiSDKContext = createContext<KopaiSDKContextValue | null>(null);\n\nexport const queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 30_000,\n refetchOnWindowFocus: false,\n retry: false,\n },\n },\n});\n\ninterface KopaiSDKProviderProps {\n client: KopaiClient;\n children: ReactNode;\n}\n\nexport function KopaiSDKProvider({ client, children }: KopaiSDKProviderProps) {\n return (\n <QueryClientProvider client={queryClient}>\n <KopaiSDKContext.Provider value={{ client }}>\n {children}\n </KopaiSDKContext.Provider>\n </QueryClientProvider>\n );\n}\n\nexport function useKopaiSDK(): KopaiClient {\n const ctx = useContext(KopaiSDKContext);\n if (!ctx) {\n throw new Error(\"useKopaiSDK must be used within KopaiSDKProvider\");\n }\n return ctx.client;\n}\n","import { useQuery } from \"@tanstack/react-query\";\nimport type { DataSource } from \"../lib/component-catalog.js\";\nimport { useKopaiSDK } from \"../providers/kopai-provider.js\";\n\nexport interface UseKopaiDataResult<T> {\n data: T | null;\n loading: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\nfunction fetchForDataSource(\n client: ReturnType<typeof useKopaiSDK>,\n dataSource: DataSource,\n signal: AbortSignal\n): Promise<unknown> {\n switch (dataSource.method) {\n case \"searchTracesPage\":\n return client.searchTracesPage(\n dataSource.params as Parameters<typeof client.searchTracesPage>[0],\n { signal }\n );\n case \"searchLogsPage\":\n return client.searchLogsPage(\n dataSource.params as Parameters<typeof client.searchLogsPage>[0],\n { signal }\n );\n case \"searchMetricsPage\":\n return client.searchMetricsPage(\n dataSource.params as Parameters<typeof client.searchMetricsPage>[0],\n { signal }\n );\n case \"getTrace\":\n return client.getTrace(dataSource.params.traceId, { signal });\n case \"discoverMetrics\":\n return client.discoverMetrics({ signal });\n default: {\n const exhaustiveCheck: never = dataSource;\n throw new Error(\n `Unknown method: ${(exhaustiveCheck as DataSource).method}`\n );\n }\n }\n}\n\nexport function useKopaiData<T = unknown>(\n dataSource: DataSource | undefined\n): UseKopaiDataResult<T> {\n const client = useKopaiSDK();\n\n const { data, isFetching, error, refetch } = useQuery<unknown, Error>({\n queryKey: [\"kopai\", dataSource?.method, dataSource?.params],\n queryFn: ({ signal }) => fetchForDataSource(client, dataSource!, signal),\n enabled: !!dataSource,\n refetchInterval: dataSource?.refetchIntervalMs,\n });\n\n return {\n data: (data as T) ?? null,\n loading: isFetching,\n error: error ?? null,\n refetch,\n };\n}\n","import type { denormalizedSignals } from \"@kopai/core\";\n\ntype OtelLogsRow = denormalizedSignals.OtelLogsRow;\n\nfunction logKey(row: OtelLogsRow): string {\n const body = row.Body ?? \"\";\n let hash = 0;\n for (let i = 0; i < body.length; i++) {\n hash = (hash << 5) - hash + body.charCodeAt(i);\n hash = hash & hash;\n }\n return `${row.Timestamp}-${row.ServiceName ?? \"\"}-${Math.abs(hash).toString(36)}`;\n}\n\nexport class LogBuffer {\n private readonly maxSize: number;\n private rows: OtelLogsRow[] = [];\n private keys = new Set<string>();\n\n constructor(maxSize = 1000) {\n this.maxSize = maxSize;\n }\n\n /** Merge new rows, dedup, sort by timestamp, trim oldest when over max. */\n merge(incoming: OtelLogsRow[]): void {\n for (const row of incoming) {\n const k = logKey(row);\n if (this.keys.has(k)) continue;\n this.keys.add(k);\n this.rows.push(row);\n }\n // Sort ascending by timestamp\n this.rows.sort((a, b) => {\n if (a.Timestamp < b.Timestamp) return -1;\n if (a.Timestamp > b.Timestamp) return 1;\n return 0;\n });\n // Trim oldest\n if (this.rows.length > this.maxSize) {\n const removed = this.rows.splice(0, this.rows.length - this.maxSize);\n for (const r of removed) this.keys.delete(logKey(r));\n }\n }\n\n getAll(): OtelLogsRow[] {\n return this.rows.slice();\n }\n\n getNewestTimestamp(): string | undefined {\n if (this.rows.length === 0) return undefined;\n return this.rows[this.rows.length - 1]!.Timestamp;\n }\n\n get size(): number {\n return this.rows.length;\n }\n\n clear(): void {\n this.rows = [];\n this.keys.clear();\n }\n}\n","import { useState, useRef, useCallback, useEffect } from \"react\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport type { denormalizedSignals, dataFilterSchemas } from \"@kopai/core\";\nimport { useKopaiSDK } from \"../providers/kopai-provider.js\";\nimport { LogBuffer } from \"../lib/log-buffer.js\";\n\ntype OtelLogsRow = denormalizedSignals.OtelLogsRow;\ntype LogsDataFilter = dataFilterSchemas.LogsDataFilter;\n\nexport interface UseLiveLogsOptions {\n params: LogsDataFilter;\n pollIntervalMs?: number;\n maxLogs?: number;\n enabled?: boolean;\n}\n\nexport interface UseLiveLogsResult {\n logs: OtelLogsRow[];\n isLive: boolean;\n totalReceived: number;\n loading: boolean;\n error: Error | null;\n setLive: (live: boolean) => void;\n}\n\nexport function useLiveLogs({\n params,\n pollIntervalMs = 3_000,\n maxLogs = 1_000,\n enabled = true,\n}: UseLiveLogsOptions): UseLiveLogsResult {\n const client = useKopaiSDK();\n const bufferRef = useRef(new LogBuffer(maxLogs));\n const [version, setVersion] = useState(0);\n const [isLive, setIsLiveState] = useState(true);\n const totalReceivedRef = useRef(0);\n const hasFetchedOnce = useRef(false);\n\n // Reset buffer when params change so stale data from a previous filter\n // doesn't persist while the new query is in flight.\n const paramsKey = JSON.stringify(params);\n const prevParamsKey = useRef(paramsKey);\n useEffect(() => {\n if (prevParamsKey.current !== paramsKey) {\n prevParamsKey.current = paramsKey;\n bufferRef.current.clear();\n hasFetchedOnce.current = false;\n totalReceivedRef.current = 0;\n setVersion((v) => v + 1);\n }\n }, [paramsKey]);\n\n const { isFetching, error, refetch } = useQuery<\n { data: OtelLogsRow[]; nextCursor: string | null },\n Error\n >({\n queryKey: [\"live-logs\", params],\n queryFn: async ({ signal }) => {\n const fetchParams: LogsDataFilter = { ...params };\n\n // If params changed since queryFn was scheduled, treat as first fetch\n if (prevParamsKey.current !== JSON.stringify(params)) {\n hasFetchedOnce.current = false;\n }\n\n // After first fetch, only get newer logs\n if (hasFetchedOnce.current) {\n const newest = bufferRef.current.getNewestTimestamp();\n if (newest) {\n // Add 1ns to avoid re-fetching the same row\n fetchParams.timestampMin = String(BigInt(newest) + 1n);\n }\n }\n\n const result = await client.searchLogsPage(fetchParams, { signal });\n hasFetchedOnce.current = true;\n\n if (result.data.length > 0) {\n totalReceivedRef.current += result.data.length;\n bufferRef.current.merge(result.data);\n setVersion((v) => v + 1);\n }\n\n return result;\n },\n enabled: enabled,\n refetchInterval: isLive ? pollIntervalMs : false,\n });\n\n const setLive = useCallback(\n (live: boolean) => {\n setIsLiveState(live);\n if (live) {\n // Immediate refetch on resume\n refetch();\n }\n },\n [refetch]\n );\n\n // Read buffer (version forces re-render)\n void version;\n const logs = bufferRef.current.getAll();\n\n return {\n logs,\n isLive,\n totalReceived: totalReceivedRef.current,\n loading: isFetching,\n error: error ?? null,\n setLive,\n };\n}\n","import { z } from \"zod\";\nimport { dataFilterSchemas } from \"@kopai/core\";\nimport type { ReactNode } from \"react\";\n\n// DataSource schema - discriminated union with type-safe params per method\nexport const dataSourceSchema = z.discriminatedUnion(\"method\", [\n z.object({\n method: z.literal(\"searchTracesPage\"),\n params: dataFilterSchemas.tracesDataFilterSchema,\n refetchIntervalMs: z.number().optional(),\n }),\n z.object({\n method: z.literal(\"searchLogsPage\"),\n params: dataFilterSchemas.logsDataFilterSchema,\n refetchIntervalMs: z.number().optional(),\n }),\n z.object({\n method: z.literal(\"searchMetricsPage\"),\n params: dataFilterSchemas.metricsDataFilterSchema,\n refetchIntervalMs: z.number().optional(),\n }),\n z.object({\n method: z.literal(\"getTrace\"),\n params: z.object({ traceId: z.string() }),\n refetchIntervalMs: z.number().optional(),\n }),\n z.object({\n method: z.literal(\"discoverMetrics\"),\n params: z.object({}).optional(),\n refetchIntervalMs: z.number().optional(),\n }),\n]);\n\nexport type DataSource = z.infer<typeof dataSourceSchema>;\n\nexport const componentDefinitionSchema = z\n .object({\n hasChildren: z.boolean(),\n description: z\n .string()\n .describe(\n \"Component description to be displayed by the prompt generator\"\n ),\n props: z.unknown(),\n })\n .describe(\n \"All options and properties necessary to render the React component with renderer\"\n );\n\nexport const catalogConfigSchema = z.object({\n name: z.string().describe(\"catalog name\"),\n components: z.record(\n z.string().describe(\"React component name\"),\n componentDefinitionSchema\n ),\n});\n\n// Union of all element types with literal type discriminator\nexport type InferredElement<C extends Record<string, { props: unknown }>> = {\n [K in keyof C & string]: {\n key: string;\n type: K;\n children: string[];\n parentKey: string;\n dataSource?: z.infer<typeof dataSourceSchema>;\n props: C[K][\"props\"] extends z.ZodTypeAny\n ? z.infer<C[K][\"props\"]>\n : unknown;\n };\n}[keyof C & string];\n\n// Zod schema type for a single element variant (preserves K-to-props mapping)\ntype ElementVariantSchema<\n K extends string,\n Props extends z.ZodTypeAny,\n> = z.ZodObject<{\n key: z.ZodString;\n type: z.ZodLiteral<K>;\n children: z.ZodArray<z.ZodString>;\n parentKey: z.ZodString;\n dataSource: z.ZodOptional<typeof dataSourceSchema>;\n props: Props;\n}>;\n\n// Union of all element variant schemas\ntype ElementVariantSchemas<C extends Record<string, { props: unknown }>> = {\n [K in keyof C & string]: ElementVariantSchema<\n K,\n C[K][\"props\"] extends z.ZodTypeAny ? C[K][\"props\"] : z.ZodUnknown\n >;\n}[keyof C & string];\n\n/**\n * Creates a component catalog with typed UI tree schema for validation.\n *\n * @param catalogConfig - Catalog configuration with name and component definitions\n * @returns Catalog object with name, components, and generated uiTreeSchema\n *\n * @example\n * ```ts\n * const catalog = createCatalog({\n * name: \"my-catalog\",\n * components: {\n * Card: {\n * hasChildren: true,\n * description: \"Container card\",\n * props: z.object({ title: z.string() }),\n * },\n * },\n * });\n * ```\n */\nexport function createCatalog<\n C extends Record<string, z.infer<typeof componentDefinitionSchema>>,\n>(catalogConfig: { name: string; components: C }) {\n const elementVariants = (\n Object.keys(catalogConfig.components) as (keyof C & string)[]\n )\n .map((catalogItemName) => ({\n catalogItemName,\n component: catalogConfig.components[catalogItemName],\n }))\n .filter(\n (\n itemConfig\n ): itemConfig is typeof itemConfig & { component: C[keyof C] } =>\n !!itemConfig.component\n )\n .map(({ catalogItemName, component }) =>\n z.object({\n key: z.string(),\n type: z.literal(catalogItemName),\n children: z.array(z.string()),\n parentKey: z.string(),\n dataSource: dataSourceSchema.optional(),\n props: component.props,\n })\n );\n\n type Schemas = ElementVariantSchemas<C>;\n const elementsUnion = z.discriminatedUnion(\n \"type\",\n elementVariants as unknown as [Schemas, ...Schemas[]]\n );\n\n // TODO: implement a mechanism for validating there are no circular references\n const uiTreeSchema = z.object({\n root: z.string().describe(\"root uiElement key in the elements array\"),\n elements: z.record(\n z.string().describe(\"equal to the element key\"),\n elementsUnion\n ),\n });\n\n return {\n name: catalogConfig.name,\n components: catalogConfig.components,\n uiTreeSchema,\n };\n}\n\nexport type ComponentDefinition = z.infer<typeof componentDefinitionSchema>;\n\nexport type InferProps<P> = P extends z.ZodTypeAny ? z.infer<P> : P;\n\nexport type CatalogueComponentProps<CD extends ComponentDefinition> =\n CD extends { hasChildren: true; props: infer P }\n ? { element: { props: InferProps<P> }; children: ReactNode }\n : CD extends { props: infer P }\n ? { element: { props: InferProps<P> } }\n : never;\n","import { createCatalog } from \"./component-catalog.js\";\nimport { z } from \"zod\";\n\nexport const observabilityCatalog = createCatalog({\n name: \"observability\",\n components: {\n // Layout Components\n Card: {\n props: z.object({\n title: z.string().nullable(),\n description: z.string().nullable(),\n padding: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n }),\n hasChildren: true,\n description: \"A card container with optional title\",\n },\n\n Grid: {\n props: z.object({\n columns: z.number().min(1).max(4).nullable(),\n gap: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n }),\n hasChildren: true,\n description: \"Grid layout with configurable columns\",\n },\n\n Stack: {\n props: z.object({\n direction: z.enum([\"horizontal\", \"vertical\"]).nullable(),\n gap: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n align: z.enum([\"start\", \"center\", \"end\", \"stretch\"]).nullable(),\n }),\n hasChildren: true,\n description: \"Flex stack for horizontal or vertical layouts\",\n },\n\n // Typography\n Heading: {\n props: z.object({\n text: z.string(),\n level: z.enum([\"h1\", \"h2\", \"h3\", \"h4\"]).nullable(),\n }),\n hasChildren: false,\n description: \"Section heading\",\n },\n\n Text: {\n props: z.object({\n content: z.string(),\n variant: z.enum([\"body\", \"caption\", \"label\"]).nullable(),\n color: z\n .enum([\"default\", \"muted\", \"success\", \"warning\", \"danger\"])\n .nullable(),\n }),\n hasChildren: false,\n description: \"Text paragraph\",\n },\n\n // Status Components\n Badge: {\n props: z.object({\n text: z.string(),\n variant: z\n .enum([\"default\", \"success\", \"warning\", \"danger\", \"info\"])\n .nullable(),\n }),\n hasChildren: false,\n description: \"Small status badge\",\n },\n\n Divider: {\n props: z.object({\n label: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Visual divider\",\n },\n\n Empty: {\n props: z.object({\n title: z.string(),\n description: z.string().nullable(),\n action: z.string().nullable(),\n actionLabel: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Empty state placeholder\",\n },\n\n // Observability Components\n LogTimeline: {\n props: z.object({ height: z.number().nullable() }),\n hasChildren: false,\n description:\n \"Log timeline with virtual scroll, severity filtering, detail pane\",\n },\n\n TraceDetail: {\n props: z.object({ height: z.number().nullable() }),\n hasChildren: false,\n description:\n \"Trace detail with traceId input field and waterfall timeline\",\n },\n\n MetricTimeSeries: {\n props: z.object({\n height: z.number().nullable(),\n showBrush: z.boolean().nullable(),\n }),\n hasChildren: false,\n description: \"Time series line chart for Gauge/Sum metrics\",\n },\n\n MetricHistogram: {\n props: z.object({ height: z.number().nullable() }),\n hasChildren: false,\n description: \"Histogram bar chart for distribution metrics\",\n },\n\n MetricStat: {\n props: z.object({\n label: z.string().nullable(),\n showSparkline: z.boolean().nullable(),\n }),\n hasChildren: false,\n description:\n \"Single metric KPI card with sparkline and threshold coloring\",\n },\n\n MetricTable: {\n props: z.object({ maxRows: z.number().nullable() }),\n hasChildren: false,\n description: \"Tabular display of metric data points\",\n },\n\n MetricDiscovery: {\n props: z.object({}),\n hasChildren: false,\n description:\n \"Table of discovered metric names, types, units and descriptions\",\n },\n },\n});\n","import {\n useState,\n useMemo,\n useCallback,\n type ReactNode,\n type ComponentType,\n} from \"react\";\nimport {\n createCatalog,\n type InferProps,\n type ComponentDefinition,\n} from \"./component-catalog.js\";\nimport z from \"zod\";\nimport { useKopaiData } from \"../hooks/use-kopai-data.js\";\nimport type { DataSource } from \"./component-catalog.js\";\n\ntype RegistryFromCatalog<\n C extends { components: Record<string, ComponentDefinition> },\n> = {\n [K in keyof C[\"components\"]]: ComponentType<\n RendererComponentProps<C[\"components\"][K]>\n >;\n};\n\ntype Catalog = ReturnType<typeof createCatalog>;\n\ntype UITree = z.infer<Catalog[\"uiTreeSchema\"]>;\n\ntype UIElement = UITree[\"elements\"][string];\n\n// Simplified - renderer just passes through to useKopaiData\ntype RendererDataSource = {\n method: string;\n params?: Record<string, unknown>;\n};\n\ntype BaseElement<Props> = {\n key: string;\n type: string;\n children: string[];\n parentKey: string;\n dataSource?: RendererDataSource;\n props: Props;\n};\n\ntype WithData = {\n hasData: true;\n data: unknown;\n loading: boolean;\n error: Error | null;\n refetch: () => void;\n updateParams: (params: Record<string, unknown>) => void;\n};\n\ntype WithoutData = {\n hasData: false;\n};\n\nexport type RendererComponentProps<CD extends ComponentDefinition> =\n CD extends {\n hasChildren: true;\n props: infer P;\n }\n ?\n | ({\n element: BaseElement<InferProps<P>>;\n children: ReactNode;\n } & WithoutData)\n | ({\n element: BaseElement<InferProps<P>>;\n children: ReactNode;\n } & WithData)\n : CD extends { props: infer P }\n ?\n | ({ element: BaseElement<InferProps<P>> } & WithoutData)\n | ({ element: BaseElement<InferProps<P>> } & WithData)\n : never;\n\n/**\n * Base props (no dataSource)\n */\nexport interface ComponentRenderPropsBase {\n element: UIElement;\n children?: ReactNode;\n hasData: false;\n}\n\n/**\n * Props with dataSource\n */\nexport interface ComponentRenderPropsWithData {\n element: UIElement;\n children?: ReactNode;\n hasData: true;\n data: unknown;\n loading: boolean;\n error: Error | null;\n refetch: () => void;\n updateParams: (params: Record<string, unknown>) => void;\n}\n\n/**\n * Discriminated union for component render props\n */\nexport type ComponentRenderProps =\n | ComponentRenderPropsBase\n | ComponentRenderPropsWithData;\n\n/**\n * Component renderer type\n */\nexport type ComponentRenderer = ComponentType<ComponentRenderProps>;\n\n/**\n * Registry mapping component type names to React components\n */\ntype ComponentRegistry = Record<string, ComponentRenderer>;\n\n/**\n * Creates a typed Renderer component bound to a catalog and component implementations.\n *\n * @param _catalog - The catalog created via createCatalog (used for type inference)\n * @param components - React component implementations matching catalog definitions\n * @returns A Renderer component that only needs `tree` and optional `fallback`\n *\n * @example\n * ```tsx\n * const DashboardRenderer = createRendererFromCatalog(catalog, {\n * Card: ({ element, children }) => <div className=\"card\">{children}</div>,\n * Table: ({ element, data }) => <table>...</table>,\n * });\n *\n * <DashboardRenderer tree={uiTree} />\n * ```\n */\nexport function createRendererFromCatalog<\n C extends { components: Record<string, ComponentDefinition> },\n>(_catalog: C, components: RegistryFromCatalog<C>) {\n return function CatalogRenderer({\n tree,\n fallback,\n }: {\n tree: UITree | null;\n fallback?: ComponentRenderer;\n }) {\n return <Renderer tree={tree} registry={components} fallback={fallback} />;\n };\n}\n\n/**\n * Wrapper component for elements with dataSource\n */\nfunction DataSourceElement({\n element,\n Component,\n children,\n}: {\n element: UIElement;\n Component: ComponentRenderer;\n children?: ReactNode;\n}) {\n const [paramsOverride, setParamsOverride] = useState<Record<string, unknown>>(\n {}\n );\n\n const effectiveDataSource = useMemo(() => {\n if (!element.dataSource) return undefined;\n const merged = {\n ...element.dataSource,\n params: { ...element.dataSource.params, ...paramsOverride },\n };\n return merged as DataSource;\n }, [element.dataSource, paramsOverride]);\n\n const { data, loading, error, refetch } = useKopaiData(effectiveDataSource);\n\n const updateParams = useCallback((params: Record<string, unknown>) => {\n setParamsOverride((prev) => ({ ...prev, ...params }));\n }, []);\n\n return (\n <Component\n element={element}\n hasData={true}\n data={data}\n loading={loading}\n error={error}\n refetch={refetch}\n updateParams={updateParams}\n >\n {children}\n </Component>\n );\n}\n\n/**\n * Internal element renderer - recursively renders elements and children\n */\nfunction ElementRenderer({\n element,\n tree,\n registry,\n fallback,\n}: {\n element: UIElement;\n tree: UITree;\n registry: ComponentRegistry;\n fallback?: ComponentRenderer;\n}) {\n const Component = registry[element.type] ?? fallback;\n\n if (!Component) {\n console.warn(`No renderer for component type: ${element.type}`);\n return null;\n }\n\n const children = element.children?.map((childKey) => {\n const childElement = tree.elements[childKey];\n if (!childElement) return null;\n return (\n <ElementRenderer\n key={childKey}\n element={childElement}\n tree={tree}\n registry={registry}\n fallback={fallback}\n />\n );\n });\n\n // If element has dataSource, wrap with data fetching\n if (element.dataSource) {\n return (\n <DataSourceElement element={element} Component={Component}>\n {children}\n </DataSourceElement>\n );\n }\n\n // Otherwise render directly (no data)\n return (\n <Component element={element} hasData={false}>\n {children}\n </Component>\n );\n}\n\n/**\n * Renders a UITree using a component registry.\n * Prefer using {@link createRendererFromCatalog} for type-safe rendering.\n */\nexport function Renderer<\n C extends { components: Record<string, ComponentDefinition> },\n>({\n tree,\n registry,\n fallback,\n}: {\n tree: z.infer<ReturnType<typeof createCatalog>[\"uiTreeSchema\"]> | null;\n registry: RegistryFromCatalog<C>;\n fallback?: ComponentRenderer;\n}) {\n if (!tree || !tree.root) return null;\n\n const rootElement = tree.elements[tree.root];\n if (!rootElement) return null;\n\n return (\n <ElementRenderer\n element={rootElement}\n tree={tree}\n registry={registry as ComponentRegistry}\n fallback={fallback}\n />\n );\n}\n","export interface Tab {\n key: string;\n label: string;\n shortcutKey?: string;\n}\n\nexport interface TabBarProps {\n tabs: Tab[];\n active: string;\n onChange: (key: string) => void;\n}\n\nfunction renderLabel(label: string, shortcutKey?: string) {\n if (!shortcutKey) return label;\n const idx = label.toLowerCase().indexOf(shortcutKey.toLowerCase());\n if (idx === -1) return label;\n return (\n <>\n {label.slice(0, idx)}\n <span className=\"underline underline-offset-4\">{label[idx]}</span>\n {label.slice(idx + 1)}\n </>\n );\n}\n\nexport function TabBar({ tabs, active, onChange }: TabBarProps) {\n return (\n <div role=\"tablist\" className=\"flex border-b border-border mb-6\">\n {tabs.map((t) => (\n <button\n key={t.key}\n role=\"tab\"\n aria-selected={active === t.key}\n onClick={() => onChange(t.key)}\n className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${\n active === t.key\n ? \"border-foreground text-foreground\"\n : \"border-transparent text-muted-foreground hover:text-foreground\"\n }`}\n >\n {renderLabel(t.label, t.shortcutKey)}\n </button>\n ))}\n </div>\n );\n}\n","/**\n * Color palette utilities for trace visualization\n * Generates consistent colors for service names using HSL color space\n */\n\nfunction hashString(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n }\n return Math.abs(hash);\n}\n\nexport function getServiceColor(serviceName: string): string {\n const hash = hashString(serviceName);\n const hue = hash % 360;\n const saturation = 70;\n const lightness = 50;\n return `hsl(${hue}, ${saturation}%, ${lightness}%)`;\n}\n\nexport const ERROR_COLOR = \"#ef4444\";\n\nexport function getSpanBarColor(serviceName: string, isError: boolean): string {\n if (isError) {\n return ERROR_COLOR;\n }\n return getServiceColor(serviceName);\n}\n","import { getServiceColor } from \"../utils/colors.js\";\n\nexport interface ServiceEntry {\n name: string;\n}\n\nexport interface ServiceListProps {\n services: ServiceEntry[];\n isLoading?: boolean;\n error?: Error;\n onSelect: (name: string) => void;\n}\n\nexport function ServiceList({\n services,\n isLoading,\n error,\n onSelect,\n}: ServiceListProps) {\n if (isLoading) {\n return (\n <div className=\"flex items-center gap-2 text-muted-foreground py-8\">\n <div className=\"w-4 h-4 border-2 border-muted-foreground border-t-transparent rounded-full animate-spin\" />\n Loading services...\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"text-red-400 py-4\">\n Error loading services: {error.message}\n </div>\n );\n }\n\n if (services.length === 0) {\n return <div className=\"text-muted-foreground py-8\">No services found</div>;\n }\n\n return (\n <div className=\"space-y-1\">\n {services.map((svc) => (\n <button\n key={svc.name}\n onClick={() => onSelect(svc.name)}\n className=\"w-full text-left px-4 py-3 rounded-lg border border-border hover:border-foreground/30 hover:bg-muted/50 transition-colors group\"\n >\n <span className=\"flex items-center gap-2 font-medium text-foreground\">\n <span\n className=\"inline-block w-2.5 h-2.5 rounded-full shrink-0\"\n style={{ backgroundColor: getServiceColor(svc.name) }}\n />\n {svc.name}\n </span>\n </button>\n ))}\n </div>\n );\n}\n","/**\n * Time formatting utilities for trace visualization\n */\n\nexport function formatDuration(durationMs: number): string {\n if (durationMs < 1) {\n const microseconds = durationMs * 1000;\n return `${microseconds.toFixed(2)}μs`;\n } else if (durationMs < 1000) {\n return `${durationMs.toFixed(2)}ms`;\n } else {\n const seconds = durationMs / 1000;\n return `${seconds.toFixed(2)}s`;\n }\n}\n\nexport function formatTimestamp(timestampMs: number): string {\n const date = new Date(timestampMs);\n return date.toLocaleString(\"en-US\", {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n timeZoneName: \"short\",\n });\n}\n\nexport function calculateRelativeTime(\n timeMs: number,\n minTimeMs: number,\n maxTimeMs: number\n): number {\n const totalDuration = maxTimeMs - minTimeMs;\n if (totalDuration === 0) return 0;\n return (timeMs - minTimeMs) / totalDuration;\n}\n\nexport function calculateRelativeDuration(\n durationMs: number,\n totalDurationMs: number\n): number {\n if (totalDurationMs === 0) return 0;\n return durationMs / totalDurationMs;\n}\n","import { useState } from \"react\";\nimport { formatDuration, formatTimestamp } from \"../utils/time.js\";\nimport { getServiceColor } from \"../utils/colors.js\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport interface TraceSummary {\n traceId: string;\n rootSpanName: string;\n serviceName: string;\n durationMs: number;\n statusCode: string;\n timestampMs: number;\n spanCount: number;\n services: { name: string; count: number; hasError: boolean }[];\n errorCount: number;\n}\n\nexport interface TraceSearchFilters {\n operation?: string;\n lookbackMs?: number;\n minDuration?: string;\n maxDuration?: string;\n limit: number;\n}\n\nexport interface TraceSearchProps {\n service: string;\n traces: TraceSummary[];\n operations?: string[];\n isLoading?: boolean;\n error?: Error;\n onSelectTrace: (traceId: string) => void;\n onBack: () => void;\n onSearch?: (filters: TraceSearchFilters) => void;\n}\n\n// ---------------------------------------------------------------------------\n// Lookback presets\n// ---------------------------------------------------------------------------\n\nconst LOOKBACK_OPTIONS = [\n { label: \"Last 5 Minutes\", ms: 5 * 60_000 },\n { label: \"Last 15 Minutes\", ms: 15 * 60_000 },\n { label: \"Last 30 Minutes\", ms: 30 * 60_000 },\n { label: \"Last 1 Hour\", ms: 60 * 60_000 },\n { label: \"Last 2 Hours\", ms: 2 * 60 * 60_000 },\n { label: \"Last 6 Hours\", ms: 6 * 60 * 60_000 },\n { label: \"Last 12 Hours\", ms: 12 * 60 * 60_000 },\n { label: \"Last 24 Hours\", ms: 24 * 60 * 60_000 },\n] as const;\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function TraceSearch({\n service,\n traces,\n operations = [],\n isLoading,\n error,\n onSelectTrace,\n onBack,\n onSearch,\n}: TraceSearchProps) {\n const [operation, setOperation] = useState(\"all\");\n const [lookbackIdx, setLookbackIdx] = useState<number>(-1);\n const [minDuration, setMinDuration] = useState(\"\");\n const [maxDuration, setMaxDuration] = useState(\"\");\n const [limit, setLimit] = useState(20);\n const [filtersOpen, setFiltersOpen] = useState(true);\n\n const handleFindTraces = () => {\n onSearch?.({\n operation: operation !== \"all\" ? operation : undefined,\n lookbackMs:\n lookbackIdx >= 0 ? LOOKBACK_OPTIONS[lookbackIdx]!.ms : undefined,\n minDuration: minDuration || undefined,\n maxDuration: maxDuration || undefined,\n limit,\n });\n };\n\n return (\n <div>\n {/* Breadcrumb */}\n <div className=\"flex items-center gap-1.5 text-sm text-muted-foreground mb-4\">\n <button\n onClick={onBack}\n className=\"hover:text-foreground transition-colors\"\n >\n Services\n </button>\n <span>/</span>\n <span className=\"text-foreground\">{service}</span>\n </div>\n\n {/* Filter panel */}\n {onSearch && (\n <div className=\"border border-border rounded-lg mb-4\">\n <button\n onClick={() => setFiltersOpen((v) => !v)}\n className=\"w-full flex items-center justify-between px-4 py-2.5 text-sm font-medium text-foreground hover:bg-muted/30 transition-colors\"\n >\n <span>Filters</span>\n <span className=\"text-muted-foreground text-xs\">\n {filtersOpen ? \"▲\" : \"▼\"}\n </span>\n </button>\n {filtersOpen && (\n <div className=\"px-4 pb-4 pt-1 border-t border-border space-y-3\">\n <div className=\"grid grid-cols-2 md:grid-cols-3 gap-3\">\n {/* Operation */}\n <label className=\"space-y-1\">\n <span className=\"text-xs text-muted-foreground\">\n Operation\n </span>\n <select\n value={operation}\n onChange={(e) => setOperation(e.target.value)}\n className=\"w-full bg-muted/50 border border-border rounded px-2 py-1.5 text-sm text-foreground\"\n >\n <option value=\"all\">All</option>\n {operations.map((op) => (\n <option key={op} value={op}>\n {op}\n </option>\n ))}\n </select>\n </label>\n\n {/* Lookback */}\n <label className=\"space-y-1\">\n <span className=\"text-xs text-muted-foreground\">\n Lookback\n </span>\n <select\n value={lookbackIdx}\n onChange={(e) => setLookbackIdx(Number(e.target.value))}\n className=\"w-full bg-muted/50 border border-border rounded px-2 py-1.5 text-sm text-foreground\"\n >\n <option value={-1}>All time</option>\n {LOOKBACK_OPTIONS.map((opt, i) => (\n <option key={i} value={i}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n\n {/* Limit */}\n <label className=\"space-y-1\">\n <span className=\"text-xs text-muted-foreground\">Limit</span>\n <input\n type=\"number\"\n min={1}\n max={1000}\n value={limit}\n onChange={(e) => {\n const n = Number(e.target.value);\n setLimit(\n Number.isNaN(n) ? 20 : Math.max(1, Math.min(1000, n))\n );\n }}\n className=\"w-full bg-muted/50 border border-border rounded px-2 py-1.5 text-sm text-foreground\"\n />\n </label>\n\n {/* Min Duration */}\n <label className=\"space-y-1\">\n <span className=\"text-xs text-muted-foreground\">\n Min Duration\n </span>\n <input\n type=\"text\"\n placeholder=\"e.g. 100ms\"\n value={minDuration}\n onChange={(e) => setMinDuration(e.target.value)}\n className=\"w-full bg-muted/50 border border-border rounded px-2 py-1.5 text-sm text-foreground placeholder:text-muted-foreground/50\"\n />\n </label>\n\n {/* Max Duration */}\n <label className=\"space-y-1\">\n <span className=\"text-xs text-muted-foreground\">\n Max Duration\n </span>\n <input\n type=\"text\"\n placeholder=\"e.g. 5s\"\n value={maxDuration}\n onChange={(e) => setMaxDuration(e.target.value)}\n className=\"w-full bg-muted/50 border border-border rounded px-2 py-1.5 text-sm text-foreground placeholder:text-muted-foreground/50\"\n />\n </label>\n </div>\n\n <button\n onClick={handleFindTraces}\n className=\"px-4 py-1.5 text-sm font-medium bg-foreground text-background rounded hover:bg-foreground/90 transition-colors\"\n >\n Find Traces\n </button>\n </div>\n )}\n </div>\n )}\n\n {/* Results */}\n {isLoading && (\n <div className=\"flex items-center gap-2 text-muted-foreground py-8\">\n <div className=\"w-4 h-4 border-2 border-muted-foreground border-t-transparent rounded-full animate-spin\" />\n Loading traces...\n </div>\n )}\n\n {error && (\n <div className=\"text-red-400 py-4\">\n Error loading traces: {error.message}\n </div>\n )}\n\n {!isLoading && !error && traces.length === 0 && (\n <div className=\"text-muted-foreground py-8\">\n No traces found for {service}\n </div>\n )}\n\n {traces.length > 0 && (\n <div className=\"space-y-2\">\n {traces.map((t) => (\n <div\n key={t.traceId}\n onClick={() => onSelectTrace(t.traceId)}\n className=\"border border-border rounded-lg px-4 py-3 hover:border-foreground/30 hover:bg-muted/30 cursor-pointer transition-colors\"\n >\n {/* Title line */}\n <div className=\"flex items-baseline justify-between gap-2\">\n <div className=\"flex items-baseline gap-1.5 min-w-0\">\n <span className=\"font-medium text-foreground truncate\">\n {t.serviceName}: {t.rootSpanName}\n </span>\n <span className=\"text-xs font-mono text-muted-foreground shrink-0\">\n {t.traceId.slice(0, 7)}\n </span>\n </div>\n <span className=\"text-sm text-foreground/80 shrink-0\">\n {formatDuration(t.durationMs)}\n </span>\n </div>\n\n {/* Tags line */}\n <div className=\"flex items-center flex-wrap gap-1.5 mt-1.5\">\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-muted text-muted-foreground\">\n {t.spanCount} Span{t.spanCount !== 1 ? \"s\" : \"\"}\n </span>\n {t.errorCount > 0 && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-red-500/20 text-red-400\">\n {t.errorCount} Error{t.errorCount !== 1 ? \"s\" : \"\"}\n </span>\n )}\n {t.services.map((svc) => (\n <span\n key={svc.name}\n className=\"inline-flex items-center gap-1 text-xs px-1.5 py-0.5 rounded\"\n style={{\n backgroundColor: `${getServiceColor(svc.name)}20`,\n color: getServiceColor(svc.name),\n }}\n >\n {svc.hasError && (\n <span className=\"w-1.5 h-1.5 rounded-full bg-red-500 shrink-0\" />\n )}\n {svc.name} ({svc.count})\n </span>\n ))}\n </div>\n\n {/* Timestamp */}\n <div className=\"text-xs text-muted-foreground mt-1 text-right\">\n {formatTimestamp(t.timestampMs)}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n","/**\n * Tree flattening utilities for virtual scrolling\n */\n\nimport type { SpanNode } from \"../types.js\";\n\nexport interface FlattenedSpan {\n span: SpanNode;\n level: number;\n}\n\nexport function flattenTree(\n rootSpans: SpanNode[],\n collapsedIds: Set<string>\n): FlattenedSpan[] {\n const result: FlattenedSpan[] = [];\n\n function traverse(span: SpanNode, level: number) {\n result.push({ span, level });\n if (!collapsedIds.has(span.spanId)) {\n span.children.forEach((child) => traverse(child, level + 1));\n }\n }\n\n rootSpans.forEach((root) => traverse(root, 0));\n return result;\n}\n\nexport function getAllDescendantIds(span: SpanNode): string[] {\n const ids: string[] = [span.spanId];\n\n function traverse(s: SpanNode) {\n s.children.forEach((child) => {\n ids.push(child.spanId);\n traverse(child);\n });\n }\n\n traverse(span);\n return ids;\n}\n\nexport function getAllSpanIds(rootSpans: SpanNode[]): string[] {\n const ids: string[] = [];\n\n function traverse(span: SpanNode) {\n ids.push(span.spanId);\n span.children.forEach((child) => traverse(child));\n }\n\n rootSpans.forEach((root) => traverse(root));\n return ids;\n}\n","import { useState } from \"react\";\nimport type { ParsedTrace } from \"../types.js\";\nimport { formatDuration, formatTimestamp } from \"../utils/time.js\";\n\nexport interface TraceHeaderProps {\n trace: ParsedTrace;\n}\n\nexport function TraceHeader({ trace }: TraceHeaderProps) {\n const [copied, setCopied] = useState(false);\n\n const rootSpan = trace.rootSpans[0];\n const rootServiceName = rootSpan?.serviceName ?? \"unknown\";\n const rootSpanName = rootSpan?.name ?? \"unknown\";\n const totalDuration = trace.maxTimeMs - trace.minTimeMs;\n\n const handleCopyTraceId = async () => {\n try {\n await navigator.clipboard.writeText(trace.traceId);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch (err) {\n console.error(\"Failed to copy trace ID:\", err);\n }\n };\n\n return (\n <div className=\"bg-background border-b border-border px-4 py-3\">\n <div className=\"flex items-center gap-6 flex-wrap\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n Trace ID:\n </span>\n <button\n onClick={handleCopyTraceId}\n className=\"text-sm font-mono bg-muted px-2 py-1 rounded hover:bg-muted/80 transition-colors text-foreground\"\n title=\"Click to copy\"\n >\n {trace.traceId.slice(0, 16)}...\n </button>\n {copied && (\n <span className=\"text-xs text-green-600 dark:text-green-400 font-medium\">\n Copied!\n </span>\n )}\n </div>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n Root:\n </span>\n <span className=\"text-sm\">\n <span className=\"text-muted-foreground\">{rootServiceName}</span>\n <span className=\"mx-1 text-muted-foreground/70\">/</span>\n <span className=\"font-medium text-foreground\">{rootSpanName}</span>\n </span>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n Duration:\n </span>\n <span className=\"text-sm font-medium text-foreground\">\n {formatDuration(totalDuration)}\n </span>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n Spans:\n </span>\n <span className=\"text-sm font-medium text-foreground\">\n {trace.totalSpanCount}\n </span>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n Started:\n </span>\n <span className=\"text-sm text-foreground\">\n {formatTimestamp(trace.minTimeMs)}\n </span>\n </div>\n </div>\n </div>\n );\n}\n","import { useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nexport interface TooltipProps {\n content: string;\n children: React.ReactNode;\n}\n\nexport function Tooltip({ content, children }: TooltipProps) {\n const [isVisible, setIsVisible] = useState(false);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n\n const handleMouseMove = (e: React.MouseEvent) => {\n setPosition({ x: e.clientX + 5, y: e.clientY + 5 });\n };\n\n return (\n <>\n <div\n onMouseEnter={() => setIsVisible(true)}\n onMouseLeave={() => setIsVisible(false)}\n onMouseMove={handleMouseMove}\n className=\"inline-block\"\n >\n {children}\n </div>\n {isVisible &&\n createPortal(\n <div\n className=\"fixed z-50 px-2 py-1 text-xs text-primary-foreground bg-primary rounded shadow-lg pointer-events-none whitespace-pre-line\"\n style={{\n left: `${position.x}px`,\n top: `${position.y}px`,\n }}\n >\n {content}\n </div>,\n document.body\n )}\n </>\n );\n}\n","import type { SpanNode } from \"../types.js\";\nimport { getSpanBarColor } from \"../utils/colors.js\";\nimport { formatDuration } from \"../utils/time.js\";\nimport { Tooltip } from \"./Tooltip.js\";\n\nexport interface TimelineBarProps {\n span: SpanNode;\n relativeStart: number;\n relativeDuration: number;\n}\n\nexport function TimelineBar({\n span,\n relativeStart,\n relativeDuration,\n}: TimelineBarProps) {\n const isError = span.status === \"ERROR\";\n const barColor = getSpanBarColor(span.serviceName, isError);\n\n const leftPercent = relativeStart * 100;\n const widthPercent = Math.max(0.2, relativeDuration * 100);\n\n const tooltipText = `${span.name}\\n${formatDuration(span.durationMs)}\\nStatus: ${isError ? \"ERROR\" : \"OK\"}`;\n\n return (\n <div className=\"relative h-full\">\n <Tooltip content={tooltipText}>\n <div className=\"absolute inset-0\">\n <div\n className=\"absolute top-1/2 -translate-y-1/2 h-2 rounded-sm cursor-pointer hover:opacity-80 transition-opacity\"\n style={{\n left: `${leftPercent}%`,\n width: `max(2px, ${widthPercent}%)`,\n backgroundColor: barColor,\n }}\n />\n </div>\n </Tooltip>\n </div>\n );\n}\n","import { memo } from \"react\";\nimport type { SpanNode } from \"../types.js\";\nimport { TimelineBar } from \"./TimelineBar.js\";\nimport { formatDuration } from \"../utils/time.js\";\n\nexport interface SpanRowProps {\n span: SpanNode;\n level: number;\n isCollapsed: boolean;\n isSelected: boolean;\n isHovered?: boolean;\n isParentOfHovered?: boolean;\n relativeStart: number;\n relativeDuration: number;\n onClick: () => void;\n onToggleCollapse: () => void;\n onMouseEnter?: () => void;\n onMouseLeave?: () => void;\n}\n\nfunction getHttpContext(span: SpanNode): string | null {\n const attrs = span.attributes;\n const method = attrs[\"http.method\"];\n const url = attrs[\"http.url\"] || attrs[\"http.target\"];\n const statusCode = attrs[\"http.status_code\"];\n\n if (!method && !url) return null;\n\n const parts: string[] = [];\n if (method) parts.push(String(method));\n if (url) parts.push(String(url));\n if (statusCode) parts.push(`[${statusCode}]`);\n\n return parts.join(\" \");\n}\n\nexport const SpanRow = memo(function SpanRow({\n span,\n level,\n isCollapsed,\n isSelected,\n isParentOfHovered = false,\n relativeStart,\n relativeDuration,\n onClick,\n onToggleCollapse,\n onMouseEnter,\n onMouseLeave,\n}: SpanRowProps) {\n const hasChildren = span.children.length > 0;\n const isError = span.status === \"ERROR\";\n const httpContext = getHttpContext(span);\n\n return (\n <div\n className={`flex h-8 border-b border-border hover:bg-muted cursor-pointer ${\n isSelected\n ? \"bg-blue-100 dark:bg-blue-900/30 hover:bg-blue-100 dark:hover:bg-blue-900/30\"\n : \"\"\n }`}\n onClick={onClick}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n role=\"treeitem\"\n aria-expanded={hasChildren ? !isCollapsed : undefined}\n aria-selected={isSelected}\n aria-label={`${span.name}, ${span.serviceName}, ${formatDuration(span.durationMs)}${isError ? \", error\" : \"\"}`}\n aria-level={level + 1}\n >\n {/* Left side: Service name + span name with indentation */}\n <div className=\"flex items-center min-w-0 flex-shrink-0 w-96 px-2 relative z-10\">\n {Array.from({ length: level }).map((_, i) => (\n <div\n key={i}\n className={`w-4 h-full border-l flex-shrink-0 ${\n isParentOfHovered ? \"border-blue-500 border-l-2\" : \"border-border\"\n }`}\n />\n ))}\n\n {hasChildren ? (\n <button\n className=\"w-4 h-4 flex items-center justify-center flex-shrink-0 text-muted-foreground hover:text-foreground\"\n onClick={(e) => {\n e.stopPropagation();\n onToggleCollapse();\n }}\n aria-label={isCollapsed ? \"Expand\" : \"Collapse\"}\n >\n {isCollapsed ? (\n <svg\n className=\"w-3 h-3\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 5l7 7-7 7\"\n />\n </svg>\n ) : (\n <svg\n className=\"w-3 h-3\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n )}\n </button>\n ) : (\n <div className=\"w-4 flex-shrink-0\" />\n )}\n\n {isError && (\n <svg\n className=\"w-4 h-4 text-red-500 flex-shrink-0 mr-1\"\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\"\n clipRule=\"evenodd\"\n />\n </svg>\n )}\n\n <span className=\"text-xs text-muted-foreground flex-shrink-0 mr-2\">\n {span.serviceName}\n </span>\n\n <span className=\"text-sm font-medium truncate flex-1 min-w-0 text-foreground\">\n {span.name}\n </span>\n\n {hasChildren && (\n <span className=\"text-xs text-muted-foreground flex-shrink-0 ml-1\">\n ({span.children.length})\n </span>\n )}\n\n {httpContext && (\n <span className=\"text-xs text-muted-foreground truncate ml-2 flex-shrink-0 max-w-xs\">\n {httpContext}\n </span>\n )}\n\n <span className=\"text-xs text-muted-foreground flex-shrink-0 ml-2\">\n {formatDuration(span.durationMs)}\n </span>\n </div>\n\n {/* Right side: Timeline bar */}\n <div className=\"flex-1 min-w-0 px-2\">\n <TimelineBar\n span={span}\n relativeStart={relativeStart}\n relativeDuration={relativeDuration}\n />\n </div>\n </div>\n );\n});\n","export function formatAttributeValue(value: unknown): string {\n if (value === null || value === undefined) return \"null\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"boolean\" || typeof value === \"number\")\n return String(value);\n if (Array.isArray(value) || typeof value === \"object\")\n return JSON.stringify(value, null, 2);\n return String(value);\n}\n\nexport function isComplexValue(value: unknown): boolean {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (Array.isArray(value) || Object.keys(value).length > 0)\n );\n}\n","import { useMemo } from \"react\";\nimport type { SpanNode } from \"../../types.js\";\nimport {\n formatAttributeValue,\n isComplexValue,\n} from \"../../utils/attributes.js\";\n\nexport interface AttributesTabProps {\n span: SpanNode;\n}\n\nconst HTTP_SEMANTIC_CONVENTIONS = new Set([\n \"http.method\",\n \"http.url\",\n \"http.status_code\",\n \"http.target\",\n \"http.host\",\n \"http.scheme\",\n \"http.route\",\n \"http.user_agent\",\n \"http.request_content_length\",\n \"http.response_content_length\",\n]);\n\nexport function AttributesTab({ span }: AttributesTabProps) {\n const { httpAttributes, otherAttributes, resourceAttributes } =\n useMemo(() => {\n const http: Array<[string, unknown]> = [];\n const other: Array<[string, unknown]> = [];\n const resource: Array<[string, unknown]> = [];\n\n if (span.attributes) {\n Object.entries(span.attributes).forEach(([key, value]) => {\n if (HTTP_SEMANTIC_CONVENTIONS.has(key)) {\n http.push([key, value]);\n } else {\n other.push([key, value]);\n }\n });\n }\n\n if (span.resourceAttributes) {\n Object.entries(span.resourceAttributes).forEach(([key, value]) => {\n resource.push([key, value]);\n });\n }\n\n http.sort(([a], [b]) => a.localeCompare(b));\n other.sort(([a], [b]) => a.localeCompare(b));\n resource.sort(([a], [b]) => a.localeCompare(b));\n\n return {\n httpAttributes: http,\n otherAttributes: other,\n resourceAttributes: resource,\n };\n }, [span]);\n\n const hasAttributes =\n httpAttributes.length > 0 ||\n otherAttributes.length > 0 ||\n resourceAttributes.length > 0;\n\n if (!hasAttributes) {\n return (\n <div className=\"text-sm text-muted-foreground text-center py-8\">\n No attributes available\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6\">\n {httpAttributes.length > 0 && (\n <section>\n <h3 className=\"text-sm font-semibold text-foreground mb-3 flex items-center\">\n <span className=\"w-2 h-2 bg-blue-500 rounded-full mr-2\" />\n HTTP Attributes\n </h3>\n <div className=\"space-y-2\">\n {httpAttributes.map(([key, value]) => (\n <AttributeRow key={key} attrKey={key} value={value} highlighted />\n ))}\n </div>\n </section>\n )}\n\n {otherAttributes.length > 0 && (\n <section>\n <h3 className=\"text-sm font-semibold text-foreground mb-3\">\n Span Attributes\n </h3>\n <div className=\"space-y-2\">\n {otherAttributes.map(([key, value]) => (\n <AttributeRow key={key} attrKey={key} value={value} />\n ))}\n </div>\n </section>\n )}\n\n {resourceAttributes.length > 0 && (\n <section>\n <h3 className=\"text-sm font-semibold text-foreground mb-3\">\n Resource Attributes\n </h3>\n <div className=\"space-y-2\">\n {resourceAttributes.map(([key, value]) => (\n <AttributeRow key={key} attrKey={key} value={value} />\n ))}\n </div>\n </section>\n )}\n </div>\n );\n}\n\ninterface AttributeRowProps {\n attrKey: string;\n value: unknown;\n highlighted?: boolean;\n}\n\nfunction AttributeRow({ attrKey, value, highlighted }: AttributeRowProps) {\n const isComplex = isComplexValue(value);\n const formattedValue = formatAttributeValue(value);\n\n return (\n <div\n className={`grid grid-cols-[minmax(150px,1fr)_2fr] gap-4 p-2 rounded text-sm ${\n highlighted\n ? \"bg-blue-50 dark:bg-blue-950 border-l-2 border-blue-500\"\n : \"bg-muted\"\n }`}\n >\n <div\n className={`font-mono font-medium break-words ${highlighted ? \"text-blue-700 dark:text-blue-300\" : \"text-foreground\"}`}\n title={attrKey}\n >\n {attrKey}\n </div>\n <div className=\"break-words\">\n {isComplex ? (\n <pre className=\"text-xs text-foreground bg-background p-2 rounded border border-border overflow-x-auto\">\n {formattedValue}\n </pre>\n ) : (\n <span className=\"text-foreground\">{formattedValue}</span>\n )}\n </div>\n </div>\n );\n}\n","import { useState } from \"react\";\nimport type { SpanNode } from \"../../types.js\";\nimport { formatDuration } from \"../../utils/time.js\";\nimport { formatAttributeValue } from \"../../utils/attributes.js\";\n\nexport interface EventsTabProps {\n span: SpanNode;\n}\n\nfunction formatRelativeTime(eventTimeMs: number, spanStartMs: number): string {\n const relativeMs = eventTimeMs - spanStartMs;\n const prefix = relativeMs < 0 ? \"-\" : \"+\";\n return `${prefix}${formatDuration(Math.abs(relativeMs))}`;\n}\n\nexport function EventsTab({ span }: EventsTabProps) {\n const [expandedEvents, setExpandedEvents] = useState<Set<number>>(new Set());\n\n const toggleEventExpanded = (index: number) => {\n setExpandedEvents((prev) => {\n const next = new Set(prev);\n if (next.has(index)) next.delete(index);\n else next.add(index);\n return next;\n });\n };\n\n if (!span.events || span.events.length === 0) {\n return (\n <div className=\"text-sm text-muted-foreground text-center py-8\">\n No events available\n </div>\n );\n }\n\n return (\n <div className=\"space-y-3\">\n {span.events.map((event, index) => {\n const isExpanded = expandedEvents.has(index);\n const hasAttributes =\n event.attributes && Object.keys(event.attributes).length > 0;\n const relativeTime = formatRelativeTime(\n event.timeUnixMs,\n span.startTimeUnixMs\n );\n\n return (\n <div\n key={index}\n className=\"border border-border rounded-lg overflow-hidden\"\n >\n <div className=\"bg-muted p-3\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"font-medium text-sm text-foreground truncate\">\n {event.name}\n </div>\n <div className=\"text-xs text-muted-foreground mt-1 font-mono\">\n {relativeTime} from span start\n </div>\n </div>\n {hasAttributes && (\n <button\n onClick={() => toggleEventExpanded(index)}\n className=\"p-1 hover:bg-muted/80 rounded transition-colors\"\n aria-label={\n isExpanded ? \"Collapse attributes\" : \"Expand attributes\"\n }\n aria-expanded={isExpanded}\n >\n <svg\n className={`w-4 h-4 text-muted-foreground transition-transform ${isExpanded ? \"rotate-180\" : \"\"}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n </button>\n )}\n </div>\n </div>\n\n {hasAttributes && isExpanded && (\n <div className=\"p-3 bg-background border-t border-border\">\n <div className=\"text-xs font-semibold text-foreground mb-2\">\n Attributes\n </div>\n <div className=\"space-y-2\">\n {Object.entries(event.attributes).map(([key, value]) => (\n <div\n key={key}\n className=\"grid grid-cols-[minmax(100px,1fr)_2fr] gap-3 text-xs\"\n >\n <div className=\"font-mono font-medium text-foreground break-words\">\n {key}\n </div>\n <div className=\"text-foreground break-words\">\n {typeof value === \"object\" ? (\n <pre className=\"text-xs bg-muted p-2 rounded border border-border overflow-x-auto\">\n {formatAttributeValue(value)}\n </pre>\n ) : (\n <span>{formatAttributeValue(value)}</span>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {!hasAttributes && (\n <div className=\"px-3 pb-3 text-xs text-muted-foreground italic\">\n No attributes\n </div>\n )}\n </div>\n );\n })}\n </div>\n );\n}\n","import { useState } from \"react\";\nimport type { SpanNode } from \"../../types.js\";\nimport { formatAttributeValue } from \"../../utils/attributes.js\";\n\nexport interface LinksTabProps {\n span: SpanNode;\n onLinkClick?: (traceId: string, spanId: string) => void;\n}\n\nfunction truncateId(id: string): string {\n return id.length > 8 ? `${id.substring(0, 8)}...` : id;\n}\n\nexport function LinksTab({ span, onLinkClick }: LinksTabProps) {\n const [expandedLinks, setExpandedLinks] = useState<Set<number>>(new Set());\n const [copiedId, setCopiedId] = useState<string | null>(null);\n\n const toggleLinkExpanded = (index: number) => {\n setExpandedLinks((prev) => {\n const next = new Set(prev);\n if (next.has(index)) next.delete(index);\n else next.add(index);\n return next;\n });\n };\n\n const copyToClipboard = async (text: string, type: string, index: number) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopiedId(`${type}-${index}-${text}`);\n setTimeout(() => setCopiedId(null), 2000);\n } catch (err) {\n console.error(\"Failed to copy:\", err);\n }\n };\n\n if (!span.links || span.links.length === 0) {\n return (\n <div className=\"text-sm text-muted-foreground text-center py-8\">\n No links available\n </div>\n );\n }\n\n return (\n <div className=\"space-y-3\">\n {span.links.map((link, index) => {\n const isExpanded = expandedLinks.has(index);\n const hasAttributes =\n link.attributes && Object.keys(link.attributes).length > 0;\n\n return (\n <div\n key={index}\n className=\"border border-border rounded-lg overflow-hidden\"\n >\n <div className=\"bg-muted p-3\">\n <div className=\"mb-2\">\n <div className=\"text-xs font-semibold text-muted-foreground mb-1\">\n Trace ID\n </div>\n <div className=\"flex items-center gap-2\">\n <code\n className=\"text-xs font-mono text-foreground bg-background px-2 py-1 rounded border border-border flex-1 truncate\"\n title={link.traceId}\n >\n {truncateId(link.traceId)}\n </code>\n <button\n onClick={() =>\n copyToClipboard(link.traceId, \"trace\", index)\n }\n className=\"p-1 hover:bg-muted/80 rounded transition-colors\"\n aria-label=\"Copy trace ID\"\n >\n <svg\n className={`w-4 h-4 ${copiedId === `trace-${index}-${link.traceId}` ? \"text-green-600\" : \"text-muted-foreground\"}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n {copiedId === `trace-${index}-${link.traceId}` ? (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n ) : (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\"\n />\n )}\n </svg>\n </button>\n </div>\n </div>\n\n <div className=\"mb-2\">\n <div className=\"text-xs font-semibold text-muted-foreground mb-1\">\n Span ID\n </div>\n <div className=\"flex items-center gap-2\">\n <code\n className=\"text-xs font-mono text-foreground bg-background px-2 py-1 rounded border border-border flex-1 truncate\"\n title={link.spanId}\n >\n {truncateId(link.spanId)}\n </code>\n <button\n onClick={() => copyToClipboard(link.spanId, \"span\", index)}\n className=\"p-1 hover:bg-muted/80 rounded transition-colors\"\n aria-label=\"Copy span ID\"\n >\n <svg\n className={`w-4 h-4 ${copiedId === `span-${index}-${link.spanId}` ? \"text-green-600\" : \"text-muted-foreground\"}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n {copiedId === `span-${index}-${link.spanId}` ? (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n ) : (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\"\n />\n )}\n </svg>\n </button>\n </div>\n </div>\n\n {onLinkClick && (\n <button\n onClick={() => onLinkClick(link.traceId, link.spanId)}\n className=\"w-full mt-2 px-3 py-2 bg-primary text-primary-foreground text-sm font-medium rounded hover:bg-primary/90 transition-colors\"\n >\n Navigate to Span\n </button>\n )}\n\n {hasAttributes && (\n <button\n onClick={() => toggleLinkExpanded(index)}\n className=\"w-full mt-2 px-3 py-1.5 text-xs text-foreground bg-background border border-border rounded hover:bg-muted transition-colors flex items-center justify-center gap-1\"\n aria-expanded={isExpanded}\n >\n <span>\n {isExpanded ? \"Hide\" : \"Show\"} Attributes (\n {Object.keys(link.attributes).length})\n </span>\n <svg\n className={`w-3 h-3 transition-transform ${isExpanded ? \"rotate-180\" : \"\"}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n </button>\n )}\n </div>\n\n {hasAttributes && isExpanded && (\n <div className=\"p-3 bg-background border-t border-border\">\n <div className=\"space-y-2\">\n {Object.entries(link.attributes).map(([key, value]) => (\n <div\n key={key}\n className=\"grid grid-cols-[minmax(100px,1fr)_2fr] gap-3 text-xs\"\n >\n <div className=\"font-mono font-medium text-foreground break-words\">\n {key}\n </div>\n <div className=\"text-foreground break-words\">\n {typeof value === \"object\" ? (\n <pre className=\"text-xs bg-muted p-2 rounded border border-border overflow-x-auto\">\n {formatAttributeValue(value)}\n </pre>\n ) : (\n <span>{formatAttributeValue(value)}</span>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n })}\n </div>\n );\n}\n","import { useState, useCallback } from \"react\";\nimport type { SpanNode } from \"../../types.js\";\nimport { AttributesTab } from \"./AttributesTab.js\";\nimport { EventsTab } from \"./EventsTab.js\";\nimport { LinksTab } from \"./LinksTab.js\";\n\nexport interface DetailPaneProps {\n span: SpanNode;\n onClose: () => void;\n onLinkClick?: (traceId: string, spanId: string) => void;\n initialTab?: \"attributes\" | \"events\" | \"links\";\n}\n\ntype TabType = \"attributes\" | \"events\" | \"links\";\n\nexport function DetailPane({\n span,\n onClose,\n onLinkClick,\n initialTab = \"attributes\",\n}: DetailPaneProps) {\n const [activeTab, setActiveTab] = useState<TabType>(initialTab);\n const [copiedId, setCopiedId] = useState(false);\n\n const handleTabChange = useCallback((tab: TabType) => {\n setActiveTab(tab);\n }, []);\n\n const handleCopySpanId = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(span.spanId);\n setCopiedId(true);\n setTimeout(() => setCopiedId(false), 2000);\n } catch (err) {\n console.error(\"Failed to copy span ID:\", err);\n }\n }, [span.spanId]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n },\n [onClose]\n );\n\n return (\n <div\n className=\"flex flex-col h-full bg-background border-l border-border\"\n onKeyDown={handleKeyDown}\n tabIndex={-1}\n role=\"complementary\"\n aria-label=\"Span details\"\n >\n {/* Header */}\n <div className=\"p-4 border-b border-border\">\n <div className=\"flex items-center justify-between mb-3\">\n <h2 className=\"text-lg font-semibold text-foreground truncate\">\n Span Details\n </h2>\n <button\n onClick={onClose}\n className=\"p-1 hover:bg-muted rounded transition-colors\"\n aria-label=\"Close detail pane\"\n title=\"Close (Esc)\"\n >\n <svg\n className=\"w-5 h-5 text-muted-foreground\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n <div className=\"mb-2\">\n <div\n className=\"text-sm font-medium text-foreground truncate\"\n title={span.name}\n >\n {span.name}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-muted-foreground\">Span ID:</span>\n <code\n className=\"text-xs font-mono text-foreground bg-muted px-2 py-1 rounded flex-1 truncate\"\n title={span.spanId}\n >\n {span.spanId}\n </code>\n <button\n onClick={handleCopySpanId}\n className=\"p-1 hover:bg-muted rounded transition-colors\"\n aria-label=\"Copy span ID\"\n >\n <svg\n className={`w-4 h-4 ${copiedId ? \"text-green-600 dark:text-green-400\" : \"text-muted-foreground\"}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n {copiedId ? (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n ) : (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\"\n />\n )}\n </svg>\n </button>\n </div>\n </div>\n\n {/* Tabs */}\n <div\n className=\"flex border-b border-border\"\n role=\"tablist\"\n aria-label=\"Span detail tabs\"\n >\n {([\"attributes\", \"events\", \"links\"] as const).map((tab) => {\n const count =\n tab === \"attributes\"\n ? Object.keys(span.attributes).length\n : tab === \"events\"\n ? span.events.length\n : span.links.length;\n return (\n <button\n key={tab}\n role=\"tab\"\n aria-selected={activeTab === tab}\n onClick={() => handleTabChange(tab)}\n className={`px-4 py-2 text-sm font-medium transition-colors ${\n activeTab === tab\n ? \"text-blue-600 dark:text-blue-400 border-b-2 border-blue-600 dark:border-blue-400\"\n : \"text-muted-foreground hover:text-foreground\"\n }`}\n >\n {tab.charAt(0).toUpperCase() + tab.slice(1)}\n {count > 0 && (\n <span className=\"ml-1 text-xs text-muted-foreground\">\n ({count})\n </span>\n )}\n </button>\n );\n })}\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-auto p-4\">\n {activeTab === \"attributes\" && <AttributesTab span={span} />}\n {activeTab === \"events\" && <EventsTab span={span} />}\n {activeTab === \"links\" && (\n <LinksTab span={span} onLinkClick={onLinkClick} />\n )}\n </div>\n </div>\n );\n}\n","export function LoadingSkeleton() {\n return (\n <div className=\"flex flex-col h-full bg-background animate-pulse\">\n <div className=\"border-b border-border p-4\">\n <div className=\"h-4 bg-muted rounded w-1/4 mb-3\"></div>\n <div className=\"flex gap-4\">\n <div className=\"h-3 bg-muted rounded w-32\"></div>\n <div className=\"h-3 bg-muted rounded w-24\"></div>\n <div className=\"h-3 bg-muted rounded w-20\"></div>\n </div>\n </div>\n <div className=\"flex-1 p-4 space-y-2\">\n {Array.from({ length: 15 }).map((_, i) => (\n <div key={i} className=\"flex items-start gap-3\">\n <div className=\"h-4 bg-muted rounded w-32\"></div>\n <div\n className=\"h-4 rounded w-16\"\n style={{\n backgroundColor:\n i % 4 === 0\n ? \"#ef4444\"\n : i % 4 === 1\n ? \"#f97316\"\n : i % 4 === 2\n ? \"#3b82f6\"\n : \"#6b7280\",\n opacity: 0.3,\n }}\n ></div>\n <div\n className=\"h-4 bg-muted rounded\"\n style={{ width: `${80 + ((i * 7) % 40)}px` }}\n ></div>\n <div\n className=\"h-4 bg-muted/80 rounded flex-1\"\n style={{ maxWidth: `${300 + ((i * 13) % 200)}px` }}\n ></div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n","import { createContext, useContext, useEffect } from \"react\";\nimport type { ShortcutGroup } from \"./types.js\";\n\ninterface KeyboardShortcutsContextValue {\n register: (id: string, group: ShortcutGroup) => void;\n unregister: (id: string) => void;\n}\n\nconst noop = () => {};\n\nexport const KeyboardShortcutsContext =\n createContext<KeyboardShortcutsContextValue>({\n register: noop,\n unregister: noop,\n });\n\nexport function useRegisterShortcuts(id: string, group: ShortcutGroup) {\n const { register, unregister } = useContext(KeyboardShortcutsContext);\n useEffect(() => {\n register(id, group);\n return () => unregister(id);\n }, [id, group, register, unregister]);\n}\n","import type { ShortcutGroup } from \"./types.js\";\n\ninterface ShortcutsHelpDialogProps {\n open: boolean;\n onClose: () => void;\n groups: ShortcutGroup[];\n}\n\nexport function ShortcutsHelpDialog({\n open,\n onClose,\n groups,\n}: ShortcutsHelpDialogProps) {\n if (!open) return null;\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n onClose();\n }\n };\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60\"\n onClick={onClose}\n onKeyDown={handleKeyDown}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Keyboard Shortcuts\"\n className=\"bg-zinc-900 border border-zinc-700 rounded-lg shadow-xl max-w-2xl w-full mx-4 max-h-[80vh] overflow-y-auto\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-zinc-700\">\n <h2 className=\"text-lg font-semibold text-zinc-100\">\n Keyboard Shortcuts\n </h2>\n <button\n onClick={onClose}\n aria-label=\"Close\"\n className=\"text-zinc-400 hover:text-zinc-200 text-xl leading-none\"\n >\n &times;\n </button>\n </div>\n <div className=\"p-6 grid grid-cols-1 sm:grid-cols-2 gap-6\">\n {groups.map((group) => (\n <div key={group.name}>\n <h3 className=\"text-sm font-medium text-zinc-400 mb-3\">\n {group.name}\n </h3>\n <ul className=\"space-y-2\">\n {group.shortcuts.map((shortcut) => (\n <li\n key={shortcut.keys.join(\"+\")}\n className=\"flex items-center justify-between text-sm\"\n >\n <span className=\"text-zinc-300\">\n {shortcut.description}\n </span>\n <span className=\"flex gap-1 ml-4\">\n {shortcut.keys.map((key) => (\n <kbd\n key={key}\n className=\"px-1.5 py-0.5 text-xs font-mono bg-zinc-800 border border-zinc-600 rounded text-zinc-300\"\n >\n {key}\n </kbd>\n ))}\n </span>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n","import { useState, useCallback, useEffect, useMemo } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { ShortcutGroup, ShortcutsRegistry } from \"./types.js\";\nimport { KeyboardShortcutsContext } from \"./context.js\";\nimport { ShortcutsHelpDialog } from \"./ShortcutsHelpDialog.js\";\n\nconst GENERAL_GROUP: ShortcutGroup = {\n name: \"General\",\n shortcuts: [\n { keys: [\"Shift\", \"?\"], description: \"Toggle shortcuts help\" },\n { keys: [\"Shift\", \"S\"], description: \"Services tab\" },\n { keys: [\"Shift\", \"L\"], description: \"Logs tab\" },\n { keys: [\"Shift\", \"M\"], description: \"Metrics tab\" },\n ],\n};\n\ninterface KeyboardShortcutsProviderProps {\n children: ReactNode;\n onNavigateServices: () => void;\n onNavigateLogs: () => void;\n onNavigateMetrics: () => void;\n}\n\nexport function KeyboardShortcutsProvider({\n children,\n onNavigateServices,\n onNavigateLogs,\n onNavigateMetrics,\n}: KeyboardShortcutsProviderProps) {\n const [registry, setRegistry] = useState<ShortcutsRegistry>(() => new Map());\n const [isOpen, setIsOpen] = useState(false);\n\n const register = useCallback((id: string, group: ShortcutGroup) => {\n setRegistry((prev) => {\n const next = new Map(prev);\n next.set(id, group);\n return next;\n });\n }, []);\n\n const unregister = useCallback((id: string) => {\n setRegistry((prev) => {\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n\n useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n const target = e.target as HTMLElement;\n if (\n target.tagName === \"INPUT\" ||\n target.tagName === \"TEXTAREA\" ||\n target.tagName === \"SELECT\" ||\n target.isContentEditable\n ) {\n return;\n }\n\n if (e.shiftKey && e.key === \"?\") {\n e.preventDefault();\n setIsOpen((v) => !v);\n return;\n }\n\n if (e.key === \"Escape\" && isOpen) {\n e.preventDefault();\n setIsOpen(false);\n return;\n }\n\n if (e.shiftKey && e.key === \"S\") {\n e.preventDefault();\n onNavigateServices();\n return;\n }\n if (e.shiftKey && e.key === \"L\") {\n e.preventDefault();\n onNavigateLogs();\n return;\n }\n if (e.shiftKey && e.key === \"M\") {\n e.preventDefault();\n onNavigateMetrics();\n return;\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, onNavigateServices, onNavigateLogs, onNavigateMetrics]);\n\n const groups = useMemo(() => {\n return [GENERAL_GROUP, ...registry.values()];\n }, [registry]);\n\n const contextValue = useMemo(\n () => ({ register, unregister }),\n [register, unregister]\n );\n\n return (\n <KeyboardShortcutsContext.Provider value={contextValue}>\n {children}\n <ShortcutsHelpDialog\n open={isOpen}\n onClose={() => setIsOpen(false)}\n groups={groups}\n />\n </KeyboardShortcutsContext.Provider>\n );\n}\n","import type { ShortcutGroup } from \"../../KeyboardShortcuts/types.js\";\n\nexport const TRACE_VIEWER_SHORTCUTS: ShortcutGroup = {\n name: \"Trace Viewer\",\n shortcuts: [\n { keys: [\"↑/K\"], description: \"Previous span\" },\n { keys: [\"↓/J\"], description: \"Next span\" },\n { keys: [\"←\"], description: \"Collapse span\" },\n { keys: [\"→\"], description: \"Expand span\" },\n { keys: [\"Enter\"], description: \"Focus detail pane\" },\n { keys: [\"C\"], description: \"Copy span name\" },\n { keys: [\"Esc\"], description: \"Deselect span\" },\n { keys: [\"Ctrl\", \"Shift\", \"E\"], description: \"Expand all\" },\n { keys: [\"Ctrl\", \"Shift\", \"C\"], description: \"Collapse all\" },\n ],\n};\n","/**\n * TraceTimeline - Accepts OtelTracesRow[] and renders trace visualization.\n * Transforms denormalized rows to SpanNode tree internally.\n */\n\nimport { useMemo, useState, useRef, useEffect, useCallback } from \"react\";\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\nimport type { denormalizedSignals } from \"@kopai/core\";\ntype OtelTracesRow = denormalizedSignals.OtelTracesRow;\nimport type { SpanNode, ParsedTrace } from \"../types.js\";\nimport { flattenTree, getAllSpanIds } from \"../utils/flatten-tree.js\";\nimport {\n calculateRelativeTime,\n calculateRelativeDuration,\n formatDuration,\n} from \"../utils/time.js\";\nimport { TraceHeader } from \"./TraceHeader.js\";\nimport { SpanRow } from \"./SpanRow.js\";\nimport { DetailPane } from \"./DetailPane/index.js\";\nimport { LoadingSkeleton } from \"../shared/LoadingSkeleton.js\";\nimport { useRegisterShortcuts } from \"../../KeyboardShortcuts/index.js\";\nimport { TRACE_VIEWER_SHORTCUTS } from \"./shortcuts.js\";\n\nexport interface TraceTimelineProps {\n rows: OtelTracesRow[];\n onSpanClick?: (span: SpanNode) => void;\n selectedSpanId?: string;\n isLoading?: boolean;\n error?: Error;\n}\n\n/** Transform OtelTracesRow[] to ParsedTrace */\nfunction buildTrace(rows: OtelTracesRow[]): ParsedTrace | null {\n if (rows.length === 0) return null;\n\n // Pass 1: Build SpanNode lookup + trace bounds\n const spanById = new Map<string, SpanNode>();\n let minTimeMs = Infinity;\n let maxTimeMs = -Infinity;\n let traceId = \"\";\n\n for (const row of rows) {\n const startMs = parseInt(row.Timestamp, 10) / 1e6;\n const durationNs = row.Duration ? parseInt(row.Duration, 10) : 0;\n const durationMs = durationNs / 1e6;\n const endMs = startMs + durationMs;\n\n // Zip parallel arrays for events\n const events: SpanNode[\"events\"] = [];\n const eventNames = row[\"Events.Name\"] ?? [];\n const eventTimestamps = row[\"Events.Timestamp\"] ?? [];\n const eventAttributes = row[\"Events.Attributes\"] ?? [];\n for (let i = 0; i < eventNames.length; i++) {\n events.push({\n timeUnixMs: eventTimestamps[i]\n ? parseInt(eventTimestamps[i]!, 10) / 1e6\n : startMs,\n name: eventNames[i] ?? \"\",\n attributes: (eventAttributes[i] as Record<string, unknown>) ?? {},\n });\n }\n\n // Zip parallel arrays for links\n const links: SpanNode[\"links\"] = [];\n const linkTraceIds = row[\"Links.TraceId\"] ?? [];\n const linkSpanIds = row[\"Links.SpanId\"] ?? [];\n const linkAttributes = row[\"Links.Attributes\"] ?? [];\n for (let i = 0; i < linkTraceIds.length; i++) {\n links.push({\n traceId: linkTraceIds[i] ?? \"\",\n spanId: linkSpanIds[i] ?? \"\",\n attributes: (linkAttributes[i] as Record<string, unknown>) ?? {},\n });\n }\n\n const span: SpanNode = {\n spanId: row.SpanId,\n parentSpanId: row.ParentSpanId || undefined,\n traceId: row.TraceId,\n name: row.SpanName ?? \"\",\n startTimeUnixMs: startMs,\n endTimeUnixMs: endMs,\n durationMs,\n kind: row.SpanKind ?? \"INTERNAL\",\n status: row.StatusCode ?? \"UNSET\",\n statusMessage: row.StatusMessage,\n serviceName: row.ServiceName ?? \"unknown\",\n attributes: row.SpanAttributes ?? {},\n resourceAttributes: row.ResourceAttributes ?? {},\n events,\n links,\n children: [],\n };\n\n spanById.set(span.spanId, span);\n minTimeMs = Math.min(minTimeMs, startMs);\n maxTimeMs = Math.max(maxTimeMs, endMs);\n if (!traceId) traceId = span.traceId;\n }\n\n if (spanById.size === 0) return null;\n\n // Pass 2: Build tree\n const rootSpans: SpanNode[] = [];\n for (const [, span] of spanById) {\n if (span.parentSpanId === span.spanId) {\n rootSpans.push(span);\n continue;\n }\n if (!span.parentSpanId || !spanById.has(span.parentSpanId)) {\n rootSpans.push(span);\n } else {\n spanById.get(span.parentSpanId)!.children.push(span);\n }\n }\n\n // Sort children by start time\n for (const [, span] of spanById) {\n span.children.sort((a, b) => a.startTimeUnixMs - b.startTimeUnixMs);\n }\n rootSpans.sort((a, b) => a.startTimeUnixMs - b.startTimeUnixMs);\n\n return {\n traceId,\n rootSpans,\n minTimeMs,\n maxTimeMs,\n totalSpanCount: spanById.size,\n };\n}\n\nfunction isSpanAncestorOf(\n potentialAncestor: SpanNode,\n descendantId: string,\n flattenedSpans: Array<{ span: SpanNode; level: number }>\n): boolean {\n const descendantItem = flattenedSpans.find(\n (item) => item.span.spanId === descendantId\n );\n if (!descendantItem) return false;\n\n let current: SpanNode | undefined = descendantItem.span;\n while (current?.parentSpanId) {\n if (current.parentSpanId === potentialAncestor.spanId) return true;\n const parentItem = flattenedSpans.find(\n (item) => item.span.spanId === current!.parentSpanId\n );\n current = parentItem?.span;\n }\n return false;\n}\n\nexport function TraceTimeline({\n rows,\n onSpanClick,\n selectedSpanId: externalSelectedSpanId,\n isLoading,\n error,\n}: TraceTimelineProps) {\n useRegisterShortcuts(\"trace-viewer\", TRACE_VIEWER_SHORTCUTS);\n\n const [collapsedIds, setCollapsedIds] = useState<Set<string>>(new Set());\n const [internalSelectedSpanId, setInternalSelectedSpanId] = useState<\n string | null\n >(null);\n const [hoveredSpanId, setHoveredSpanId] = useState<string | null>(null);\n const selectedSpanId = externalSelectedSpanId ?? internalSelectedSpanId;\n const scrollRef = useRef<HTMLDivElement>(null);\n const announcementRef = useRef<HTMLDivElement>(null);\n\n const parsedTrace = useMemo(() => buildTrace(rows), [rows]);\n\n const flattenedSpans = useMemo(() => {\n if (!parsedTrace) return [];\n return flattenTree(parsedTrace.rootSpans, collapsedIds);\n }, [parsedTrace, collapsedIds]);\n\n const virtualizer = useVirtualizer({\n count: flattenedSpans.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => 32,\n overscan: 5,\n });\n\n const handleToggleCollapse = (spanId: string) => {\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n if (next.has(spanId)) next.delete(spanId);\n else next.add(spanId);\n return next;\n });\n };\n\n const handleSpanClick = useCallback(\n (span: SpanNode) => {\n setInternalSelectedSpanId(span.spanId);\n onSpanClick?.(span);\n if (announcementRef.current) {\n announcementRef.current.textContent = `Selected span: ${span.name}, duration: ${formatDuration(span.durationMs)}`;\n }\n },\n [onSpanClick]\n );\n\n const handleExpandAll = useCallback(() => {\n setCollapsedIds(new Set());\n }, []);\n\n const handleCollapseAll = useCallback(() => {\n if (!parsedTrace) return;\n setCollapsedIds(new Set(getAllSpanIds(parsedTrace.rootSpans)));\n }, [parsedTrace]);\n\n const handleNavigateUp = useCallback(() => {\n if (flattenedSpans.length === 0) return;\n const currentIndex = flattenedSpans.findIndex(\n (item) => item.span.spanId === selectedSpanId\n );\n if (currentIndex > 0) {\n const prevItem = flattenedSpans[currentIndex - 1];\n if (prevItem) handleSpanClick(prevItem.span);\n } else if (currentIndex === -1 && flattenedSpans.length > 0) {\n const lastItem = flattenedSpans[flattenedSpans.length - 1];\n if (lastItem) handleSpanClick(lastItem.span);\n }\n }, [flattenedSpans, selectedSpanId, handleSpanClick]);\n\n const handleNavigateDown = useCallback(() => {\n if (flattenedSpans.length === 0) return;\n const currentIndex = flattenedSpans.findIndex(\n (item) => item.span.spanId === selectedSpanId\n );\n if (currentIndex >= 0 && currentIndex < flattenedSpans.length - 1) {\n const nextItem = flattenedSpans[currentIndex + 1];\n if (nextItem) handleSpanClick(nextItem.span);\n } else if (currentIndex === -1 && flattenedSpans.length > 0) {\n const firstItem = flattenedSpans[0];\n if (firstItem) handleSpanClick(firstItem.span);\n }\n }, [flattenedSpans, selectedSpanId, handleSpanClick]);\n\n const handleCollapseExpand = useCallback(\n (collapse: boolean) => {\n if (!selectedSpanId) return;\n const selectedItem = flattenedSpans.find(\n (item) => item.span.spanId === selectedSpanId\n );\n if (!selectedItem || selectedItem.span.children.length === 0) return;\n if (collapse) {\n setCollapsedIds((prev) => new Set([...prev, selectedItem.span.spanId]));\n } else {\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n next.delete(selectedItem.span.spanId);\n return next;\n });\n }\n },\n [selectedSpanId, flattenedSpans]\n );\n\n const handleDeselect = useCallback(() => {\n setInternalSelectedSpanId(null);\n }, []);\n\n useEffect(() => {\n if (!selectedSpanId) return;\n const selectedIndex = flattenedSpans.findIndex(\n (item) => item.span.spanId === selectedSpanId\n );\n if (selectedIndex !== -1) {\n virtualizer.scrollToIndex(selectedIndex, {\n align: \"center\",\n behavior: \"smooth\",\n });\n }\n }, [selectedSpanId, flattenedSpans, virtualizer]);\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n const timelineElement = scrollRef.current?.parentElement;\n if (!timelineElement?.contains(document.activeElement)) return;\n\n switch (e.key) {\n case \"ArrowUp\":\n case \"k\":\n case \"K\":\n e.preventDefault();\n handleNavigateUp();\n break;\n case \"ArrowDown\":\n case \"j\":\n case \"J\":\n e.preventDefault();\n handleNavigateDown();\n break;\n case \"ArrowLeft\":\n e.preventDefault();\n handleCollapseExpand(true);\n break;\n case \"ArrowRight\":\n e.preventDefault();\n handleCollapseExpand(false);\n break;\n case \"Escape\":\n e.preventDefault();\n handleDeselect();\n break;\n case \"Enter\": {\n if (selectedSpanId) {\n e.preventDefault();\n const detailPane = document.querySelector(\n '[role=\"complementary\"][aria-label=\"Span details\"]'\n );\n if (detailPane) {\n detailPane.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n (detailPane as HTMLElement).focus?.();\n }\n }\n break;\n }\n case \"e\":\n case \"E\":\n if (e.ctrlKey && e.shiftKey) {\n e.preventDefault();\n handleExpandAll();\n }\n break;\n case \"c\":\n case \"C\":\n if (e.ctrlKey && e.shiftKey) {\n e.preventDefault();\n handleCollapseAll();\n } else if (!e.ctrlKey && !e.metaKey) {\n e.preventDefault();\n const selected = flattenedSpans.find(\n (item) => item.span.spanId === selectedSpanId\n );\n if (selected) {\n navigator.clipboard.writeText(selected.span.name).catch(() => {});\n }\n }\n break;\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [\n handleNavigateUp,\n handleNavigateDown,\n handleCollapseExpand,\n handleDeselect,\n handleExpandAll,\n handleCollapseAll,\n selectedSpanId,\n flattenedSpans,\n ]);\n\n if (isLoading) return <LoadingSkeleton />;\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center h-64 bg-background\">\n <div className=\"text-red-600 dark:text-red-400\">\n <div className=\"font-semibold\">Error loading trace</div>\n <div className=\"text-sm\">{error.message}</div>\n </div>\n </div>\n );\n }\n\n if (rows.length === 0 || !parsedTrace) {\n return (\n <div className=\"flex items-center justify-center h-64 bg-background\">\n <div className=\"text-muted-foreground\">No trace data available</div>\n </div>\n );\n }\n\n const totalDurationMs = parsedTrace.maxTimeMs - parsedTrace.minTimeMs;\n const selectedSpan =\n selectedSpanId && flattenedSpans.length > 0\n ? flattenedSpans.find((item) => item.span.spanId === selectedSpanId)?.span\n : null;\n\n return (\n <div className=\"flex h-full bg-background\">\n <div className=\"flex flex-col flex-1 min-w-0\">\n <div\n ref={announcementRef}\n className=\"sr-only\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n />\n <TraceHeader trace={parsedTrace} />\n <div\n ref={scrollRef}\n className=\"flex-1 overflow-auto outline-none\"\n role=\"tree\"\n aria-label=\"Trace timeline\"\n tabIndex={0}\n >\n <div\n style={{\n height: `${virtualizer.getTotalSize()}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {virtualizer.getVirtualItems().map((virtualItem) => {\n const item = flattenedSpans[virtualItem.index];\n if (!item) return null;\n\n const { span, level } = item;\n const isCollapsed = collapsedIds.has(span.spanId);\n const isSelected = span.spanId === selectedSpanId;\n const isHovered = span.spanId === hoveredSpanId;\n const isParentOfHovered = hoveredSpanId\n ? isSpanAncestorOf(span, hoveredSpanId, flattenedSpans)\n : false;\n\n const relativeStart = calculateRelativeTime(\n span.startTimeUnixMs,\n parsedTrace.minTimeMs,\n parsedTrace.maxTimeMs\n );\n const relativeDuration = calculateRelativeDuration(\n span.durationMs,\n totalDurationMs\n );\n\n return (\n <div\n key={span.spanId}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: `${virtualItem.size}px`,\n transform: `translateY(${virtualItem.start}px)`,\n }}\n >\n <SpanRow\n span={span}\n level={level}\n isCollapsed={isCollapsed}\n isSelected={isSelected}\n isHovered={isHovered}\n isParentOfHovered={isParentOfHovered}\n relativeStart={relativeStart}\n relativeDuration={relativeDuration}\n onClick={() => handleSpanClick(span)}\n onToggleCollapse={() => handleToggleCollapse(span.spanId)}\n onMouseEnter={() => setHoveredSpanId(span.spanId)}\n onMouseLeave={() => setHoveredSpanId(null)}\n />\n </div>\n );\n })}\n </div>\n </div>\n </div>\n\n {selectedSpan && (\n <div className=\"w-96 h-full flex-shrink-0\">\n <DetailPane\n span={selectedSpan}\n onClose={handleDeselect}\n // TODO: wire up cross-trace navigation\n onLinkClick={undefined}\n />\n </div>\n )}\n </div>\n );\n}\n","import type { denormalizedSignals } from \"@kopai/core\";\nimport { TraceTimeline } from \"../TraceTimeline/index.js\";\nimport type { SpanNode } from \"../types.js\";\n\ntype OtelTracesRow = denormalizedSignals.OtelTracesRow;\n\nexport interface TraceDetailProps {\n service: string;\n traceId: string;\n rows: OtelTracesRow[];\n isLoading?: boolean;\n error?: Error;\n selectedSpanId?: string;\n onSpanClick?: (span: SpanNode) => void;\n onBack: () => void;\n}\n\nexport function TraceDetail({\n service,\n traceId,\n rows,\n isLoading,\n error,\n selectedSpanId,\n onSpanClick,\n onBack,\n}: TraceDetailProps) {\n return (\n <div>\n {/* Breadcrumb */}\n <div className=\"flex items-center gap-1.5 text-sm text-muted-foreground mb-4\">\n <button\n onClick={onBack}\n className=\"hover:text-foreground transition-colors\"\n >\n Services / {service}\n </button>\n <span>/</span>\n <span className=\"text-foreground font-mono text-xs\">\n {traceId.slice(0, 16)}...\n </span>\n </div>\n\n <TraceTimeline\n rows={rows}\n isLoading={isLoading}\n error={error}\n selectedSpanId={selectedSpanId}\n onSpanClick={onSpanClick}\n />\n </div>\n );\n}\n","import { memo, useMemo } from \"react\";\nimport type { LogEntry } from \"../types.js\";\nimport { getServiceColor } from \"../utils/colors.js\";\n\nexport interface LogRowProps {\n log: LogEntry;\n isSelected: boolean;\n onClick: () => void;\n searchText?: string;\n relativeTime?: boolean;\n referenceTimeMs?: number;\n}\n\nfunction formatTimestamp(timeMs: number): string {\n const date = new Date(timeMs);\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n const ms = String(date.getMilliseconds()).padStart(3, \"0\");\n return `${hours}:${minutes}:${seconds}.${ms}`;\n}\n\nfunction formatRelativeTime(timeMs: number, referenceMs: number): string {\n const diffMs = timeMs - referenceMs;\n const sign = diffMs >= 0 ? \"+\" : \"-\";\n const abs = Math.abs(diffMs);\n if (abs < 1000) return `${sign}${abs.toFixed(4)}ms`;\n if (abs < 60_000) return `${sign}${(abs / 1000).toFixed(4)}s`;\n const mins = Math.floor(abs / 60_000);\n const secs = ((abs % 60_000) / 1000).toFixed(4);\n return `${sign}${mins}m${secs}s`;\n}\n\nfunction truncateMessage(message: string, maxLength = 120): string {\n if (message.length <= maxLength) return message;\n return message.slice(0, maxLength) + \"...\";\n}\n\nfunction getSeverityColor(severity: string): { text: string; bg: string } {\n const s = severity.toUpperCase();\n if (s === \"FATAL\" || s === \"ERROR\")\n return {\n text: \"text-red-900 dark:text-red-100\",\n bg: \"bg-red-100 dark:bg-red-900/30\",\n };\n if (s === \"WARN\" || s === \"WARNING\")\n return {\n text: \"text-orange-900 dark:text-orange-100\",\n bg: \"bg-orange-100 dark:bg-orange-900/30\",\n };\n if (s === \"INFO\")\n return {\n text: \"text-blue-900 dark:text-blue-100\",\n bg: \"bg-blue-100 dark:bg-blue-900/30\",\n };\n if (s === \"DEBUG\")\n return {\n text: \"text-gray-900 dark:text-gray-100\",\n bg: \"bg-gray-100 dark:bg-gray-700/30\",\n };\n if (s === \"TRACE\")\n return {\n text: \"text-gray-700 dark:text-gray-300\",\n bg: \"bg-gray-50 dark:bg-gray-800/30\",\n };\n return {\n text: \"text-gray-600 dark:text-gray-400\",\n bg: \"bg-gray-50 dark:bg-gray-800/20\",\n };\n}\n\nfunction highlightSearchText(\n text: string,\n searchText: string\n): React.ReactNode {\n if (!searchText || !text) return text;\n\n const parts: React.ReactNode[] = [];\n let lastIndex = 0;\n const searchLower = searchText.toLowerCase();\n const textLower = text.toLowerCase();\n let index = textLower.indexOf(searchLower);\n\n while (index !== -1) {\n if (index > lastIndex) parts.push(text.slice(lastIndex, index));\n const matchText = text.slice(index, index + searchText.length);\n parts.push(\n <mark\n key={`${index}-${matchText}`}\n className=\"bg-yellow-200 dark:bg-yellow-700 text-foreground\"\n >\n {matchText}\n </mark>\n );\n lastIndex = index + searchText.length;\n index = textLower.indexOf(searchLower, lastIndex);\n }\n\n if (lastIndex < text.length) parts.push(text.slice(lastIndex));\n return parts.length > 0 ? <>{parts}</> : text;\n}\n\nexport const LogRow = memo(function LogRow({\n log,\n isSelected,\n onClick,\n searchText,\n relativeTime,\n referenceTimeMs,\n}: LogRowProps) {\n const severityColor = getSeverityColor(log.severityText);\n const message = useMemo(() => log.body || \"\", [log.body]);\n const timestamp =\n relativeTime && referenceTimeMs != null\n ? formatRelativeTime(log.timeUnixMs, referenceTimeMs)\n : formatTimestamp(log.timeUnixMs);\n const lineCount = message.split(\"\\n\").length;\n const hasMultipleLines = lineCount > 1;\n\n return (\n <div\n style={{ contain: \"layout style paint\" }}\n className={`flex items-center gap-3 px-4 h-[44px] border-b border-border cursor-pointer overflow-hidden outline-none ${\n isSelected\n ? \"bg-blue-50 dark:bg-blue-900/30 border-l-4 border-l-blue-500\"\n : \"hover:bg-muted\"\n }`}\n onClick={onClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }}\n >\n <div className=\"flex-shrink-0 w-28 font-mono text-xs text-muted-foreground\">\n {timestamp}\n </div>\n <div\n className={`flex-shrink-0 w-24 text-xs font-semibold px-2 py-0.5 rounded truncate ${severityColor.bg} ${severityColor.text}`}\n >\n {log.severityText}\n </div>\n <div\n className=\"flex-shrink-0 w-32 text-xs truncate\"\n style={{ color: getServiceColor(log.serviceName) }}\n >\n {log.serviceName}\n </div>\n <div className=\"flex-1 min-w-0 flex items-center gap-2\">\n <div className=\"text-sm text-foreground truncate\">\n {searchText\n ? highlightSearchText(\n truncateMessage(message.split(\"\\n\")[0] || \"\", 100),\n searchText\n )\n : truncateMessage(message.split(\"\\n\")[0] || \"\", 100)}\n </div>\n {hasMultipleLines && (\n <span className=\"flex-shrink-0 text-xs text-muted-foreground\">\n +{lineCount - 1} lines\n </span>\n )}\n {log.traceId && (\n <span className=\"flex-shrink-0 text-xs text-indigo-600 dark:text-indigo-400\">\n trace: {log.traceId.slice(0, 16)}...\n </span>\n )}\n </div>\n </div>\n );\n});\n","import { useMemo } from \"react\";\nimport type { LogEntry } from \"../../types.js\";\nimport {\n formatAttributeValue,\n isComplexValue,\n} from \"../../utils/attributes.js\";\n\nexport interface AttributesTabProps {\n log: LogEntry;\n}\n\nexport function AttributesTab({ log }: AttributesTabProps) {\n const sortedAttributes = useMemo(() => {\n return Object.entries(log.attributes).sort(([a], [b]) =>\n a.localeCompare(b)\n );\n }, [log.attributes]);\n\n if (sortedAttributes.length === 0) {\n return (\n <div className=\"text-sm text-muted-foreground text-center py-8\">\n No attributes available\n </div>\n );\n }\n\n return (\n <div className=\"space-y-2\">\n {sortedAttributes.map(([key, value]) => {\n const isComplex = isComplexValue(value);\n const formattedValue = formatAttributeValue(value);\n return (\n <div key={key} className=\"p-2 rounded bg-muted\">\n <div\n className=\"font-mono font-medium text-xs text-foreground mb-1\"\n title={key}\n >\n {key}\n </div>\n <div>\n {isComplex ? (\n <pre className=\"text-xs text-foreground bg-background p-2 rounded border border-border overflow-x-auto\">\n {formattedValue}\n </pre>\n ) : (\n <span className=\"text-sm text-foreground break-words\">\n {formattedValue}\n </span>\n )}\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n","import { useState } from \"react\";\n\nexport interface JsonTreeViewProps {\n data: Record<string, unknown> | unknown[];\n level?: number;\n}\n\nexport function JsonTreeView({ data, level = 0 }: JsonTreeViewProps) {\n return (\n <div className=\"font-mono text-sm\">\n {Array.isArray(data) ? (\n <ArrayView items={data} level={level} />\n ) : (\n <ObjectView obj={data} level={level} />\n )}\n </div>\n );\n}\n\nfunction ObjectView({\n obj,\n level,\n}: {\n obj: Record<string, unknown>;\n level: number;\n}) {\n const entries = Object.entries(obj);\n if (entries.length === 0)\n return <span className=\"text-muted-foreground\">{\"{}\"}</span>;\n return (\n <div>\n {entries.map(([key, value]) => (\n <JsonTreeNode key={key} objKey={key} value={value} level={level} />\n ))}\n </div>\n );\n}\n\nfunction ArrayView({ items, level }: { items: unknown[]; level: number }) {\n if (items.length === 0)\n return <span className=\"text-muted-foreground\">[]</span>;\n return (\n <div>\n {items.map((item, index) => (\n <JsonTreeNode\n key={index}\n objKey={String(index)}\n value={item}\n level={level}\n isArrayItem\n />\n ))}\n </div>\n );\n}\n\nfunction JsonTreeNode({\n objKey,\n value,\n level,\n isArrayItem = false,\n}: {\n objKey: string;\n value: unknown;\n level: number;\n isArrayItem?: boolean;\n}) {\n const [isExpanded, setIsExpanded] = useState(level < 2);\n\n const isExpandable =\n value !== null &&\n typeof value === \"object\" &&\n (Array.isArray(value) ? value.length > 0 : Object.keys(value).length > 0);\n\n const indent = level * 16;\n\n if (!isExpandable) {\n return (\n <div\n style={{ paddingLeft: `${indent}px` }}\n className=\"py-0.5 hover:bg-muted\"\n >\n {!isArrayItem && (\n <span className=\"text-blue-600 dark:text-blue-400\">\n {objKey}\n {\": \"}\n </span>\n )}\n <span className=\"text-foreground\">{formatPrimitiveValue(value)}</span>\n </div>\n );\n }\n\n return (\n <div>\n <div\n style={{ paddingLeft: `${indent}px` }}\n className=\"py-0.5 hover:bg-muted cursor-pointer\"\n onClick={() => setIsExpanded(!isExpanded)}\n >\n <span className=\"inline-block w-4 text-muted-foreground\">\n {isExpanded ? \"▼\" : \"▶\"}\n </span>\n {!isArrayItem && (\n <span className=\"text-blue-600 dark:text-blue-400\">\n {objKey}\n {\": \"}\n </span>\n )}\n <span className=\"text-muted-foreground\">\n {Array.isArray(value)\n ? `Array(${value.length})`\n : `Object(${Object.keys(value).length})`}\n </span>\n </div>\n {isExpanded && (\n <div>\n {Array.isArray(value) ? (\n <ArrayView items={value} level={level + 1} />\n ) : (\n <ObjectView\n obj={value as Record<string, unknown>}\n level={level + 1}\n />\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction formatPrimitiveValue(value: unknown): string {\n if (value === null) return \"null\";\n if (value === undefined) return \"undefined\";\n if (typeof value === \"string\") return `\"${value}\"`;\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\";\n if (typeof value === \"number\") return String(value);\n return String(value);\n}\n","import { useState, useCallback, useRef, useEffect } from \"react\";\nimport type { LogEntry } from \"../../types.js\";\nimport { AttributesTab } from \"./AttributesTab.js\";\nimport { JsonTreeView } from \"./JsonTreeView.js\";\n\nexport interface LogDetailPaneProps {\n log: LogEntry;\n onClose: () => void;\n onTraceLinkClick?: (traceId: string, spanId: string) => void;\n initialTab?: \"message\" | \"attributes\" | \"resource\" | \"context\";\n wordWrap?: boolean;\n}\n\ntype TabType = \"message\" | \"attributes\" | \"resource\" | \"context\";\n\nexport function LogDetailPane({\n log,\n onClose,\n onTraceLinkClick,\n initialTab = \"message\",\n wordWrap = true,\n}: LogDetailPaneProps) {\n const hasContext = !!log.traceId;\n const [activeTab, setActiveTab] = useState<TabType>(\n initialTab === \"context\" && !hasContext ? \"message\" : initialTab\n );\n const [copiedId, setCopiedId] = useState(false);\n const detailPaneRef = useRef<HTMLDivElement>(null);\n\n const handleCopyLogId = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(log.logId);\n setCopiedId(true);\n setTimeout(() => setCopiedId(false), 2000);\n } catch (err) {\n console.error(\"Failed to copy log ID:\", err);\n }\n }, [log.logId]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n },\n [onClose]\n );\n\n useEffect(() => {\n detailPaneRef.current?.focus();\n }, []);\n\n const severityColor = getSeverityColor(log.severityText);\n\n return (\n <div\n ref={detailPaneRef}\n className=\"w-[500px] flex flex-col h-full bg-background border-l border-border outline-none\"\n onKeyDown={handleKeyDown}\n role=\"complementary\"\n aria-label=\"Log details\"\n tabIndex={-1}\n >\n {/* Header */}\n <div className=\"p-4 border-b border-border\">\n <div className=\"flex items-center justify-between mb-3\">\n <h2 className=\"text-lg font-semibold text-foreground\">Log Details</h2>\n <button\n onClick={onClose}\n className=\"p-2 hover:bg-muted rounded transition-colors\"\n aria-label=\"Close detail pane\"\n >\n <svg\n className=\"w-6 h-6 text-muted-foreground\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n <div className=\"flex items-center gap-2 mb-2\">\n <div\n className={`text-xs font-semibold px-2 py-0.5 rounded ${severityColor.bg} ${severityColor.text}`}\n >\n {log.severityText}\n </div>\n <div className=\"text-sm text-muted-foreground\">{log.serviceName}</div>\n </div>\n <div className=\"text-xs font-medium text-muted-foreground mt-3 mb-1\">\n Timestamp\n </div>\n <div className=\"text-xs text-foreground font-mono\">\n {new Date(log.timeUnixMs).toISOString()}\n </div>\n <div className=\"text-xs font-medium text-muted-foreground mt-3 mb-1\">\n Log ID\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={handleCopyLogId}\n className=\"flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground font-mono bg-muted px-2 py-1 rounded\"\n title=\"Click to copy log ID\"\n >\n <span className=\"truncate max-w-[200px]\">{log.logId}</span>\n <svg\n className=\"w-3 h-3 flex-shrink-0\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n {copiedId ? (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n ) : (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\"\n />\n )}\n </svg>\n </button>\n </div>\n </div>\n\n {/* Tabs */}\n <div className=\"flex border-b border-border\">\n {(\n [\n \"message\",\n \"attributes\",\n \"resource\",\n ...(log.traceId ? [\"context\" as const] : []),\n ] as TabType[]\n ).map((tab) => (\n <button\n key={tab}\n onClick={() => setActiveTab(tab)}\n className={`px-4 py-2 text-sm font-medium transition-colors ${\n activeTab === tab\n ? \"text-blue-600 dark:text-blue-400 border-b-2 border-blue-600 dark:border-blue-400\"\n : \"text-muted-foreground hover:text-foreground\"\n }`}\n >\n {tab === \"context\"\n ? \"Trace\"\n : tab.charAt(0).toUpperCase() + tab.slice(1)}\n </button>\n ))}\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-4\">\n {activeTab === \"message\" && (\n <pre\n className={`text-sm text-foreground font-mono bg-muted p-3 rounded ${\n wordWrap\n ? \"whitespace-pre-wrap break-words\"\n : \"whitespace-pre overflow-x-auto\"\n }`}\n >\n {log.body || \"No message body\"}\n </pre>\n )}\n {activeTab === \"attributes\" && <AttributesTab log={log} />}\n {activeTab === \"resource\" && (\n <div>\n <div className=\"mb-3\">\n <div className=\"text-sm font-semibold text-foreground mb-2\">\n Service Name\n </div>\n <div className=\"text-sm text-foreground bg-muted p-2 rounded font-mono\">\n {log.serviceName}\n </div>\n </div>\n {log.scopeName && (\n <div className=\"mb-3\">\n <div className=\"text-sm font-semibold text-foreground mb-2\">\n Scope Name\n </div>\n <div className=\"text-sm text-foreground bg-muted p-2 rounded font-mono\">\n {log.scopeName}\n </div>\n </div>\n )}\n <div>\n <div className=\"text-sm font-semibold text-foreground mb-2\">\n Resource Attributes\n </div>\n {Object.keys(log.resourceAttributes).length > 0 ? (\n <JsonTreeView data={log.resourceAttributes} />\n ) : (\n <div className=\"text-sm text-muted-foreground text-center py-4\">\n No resource attributes\n </div>\n )}\n </div>\n </div>\n )}\n {activeTab === \"context\" && log.traceId && (\n <div className=\"space-y-3\">\n <div>\n <div className=\"text-sm font-semibold text-foreground mb-2\">\n Trace ID\n </div>\n <div className=\"text-sm text-foreground bg-muted p-2 rounded font-mono break-all\">\n {log.traceId}\n </div>\n </div>\n {log.spanId && (\n <div>\n <div className=\"text-sm font-semibold text-foreground mb-2\">\n Span ID\n </div>\n <div className=\"text-sm text-foreground bg-muted p-2 rounded font-mono break-all\">\n {log.spanId}\n </div>\n </div>\n )}\n {onTraceLinkClick && log.spanId && (\n <button\n onClick={() => onTraceLinkClick(log.traceId!, log.spanId!)}\n className=\"w-full px-4 py-2 bg-blue-600 dark:bg-blue-500 text-white rounded hover:bg-blue-700 dark:hover:bg-blue-600 transition-colors text-sm\"\n >\n View Trace\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction getSeverityColor(severity: string): { text: string; bg: string } {\n const s = severity.toUpperCase();\n if (s === \"FATAL\" || s === \"ERROR\")\n return {\n text: \"text-red-900 dark:text-red-100\",\n bg: \"bg-red-100 dark:bg-red-900/30\",\n };\n if (s === \"WARN\" || s === \"WARNING\")\n return {\n text: \"text-orange-900 dark:text-orange-100\",\n bg: \"bg-orange-100 dark:bg-orange-900/30\",\n };\n if (s === \"INFO\")\n return {\n text: \"text-blue-900 dark:text-blue-100\",\n bg: \"bg-blue-100 dark:bg-blue-900/30\",\n };\n if (s === \"DEBUG\")\n return {\n text: \"text-gray-900 dark:text-gray-100\",\n bg: \"bg-gray-100 dark:bg-gray-700/30\",\n };\n return {\n text: \"text-gray-600 dark:text-gray-400\",\n bg: \"bg-gray-50 dark:bg-gray-800/20\",\n };\n}\n","import type { ShortcutGroup } from \"../../KeyboardShortcuts/types.js\";\n\nexport const LOG_VIEWER_SHORTCUTS: ShortcutGroup = {\n name: \"Log Viewer\",\n shortcuts: [\n { keys: [\"↑/K\"], description: \"Previous log\" },\n { keys: [\"↓/J\"], description: \"Next log\" },\n { keys: [\"G\"], description: \"Scroll to bottom\" },\n { keys: [\"Home\"], description: \"First log\" },\n { keys: [\"/\"], description: \"Focus search\" },\n { keys: [\"F\"], description: \"Toggle filters\" },\n { keys: [\"Enter\"], description: \"Open log detail\" },\n { keys: [\"C\"], description: \"Copy log body\" },\n { keys: [\"W\"], description: \"Toggle word wrap\" },\n { keys: [\"T\"], description: \"Toggle timestamps\" },\n { keys: [\"Esc\"], description: \"Close detail/filter pane\" },\n ],\n};\n","/**\n * LogTimeline - Accepts OtelLogsRow[] and renders log visualization.\n * Transforms denormalized rows to LogEntry[] internally.\n */\n\nimport { useMemo, useState, useRef, useCallback, useEffect } from \"react\";\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\nimport type { denormalizedSignals } from \"@kopai/core\";\nimport type { LogEntry } from \"../types.js\";\nimport { LogRow } from \"./LogRow.js\";\nimport { LogDetailPane } from \"./LogDetailPane/index.js\";\nimport { LoadingSkeleton } from \"../shared/LoadingSkeleton.js\";\nimport { useRegisterShortcuts } from \"../../KeyboardShortcuts/index.js\";\nimport { LOG_VIEWER_SHORTCUTS } from \"./shortcuts.js\";\n\ntype OtelLogsRow = denormalizedSignals.OtelLogsRow;\n\nconst LOG_ROW_HEIGHT = 44;\nconst OVERSCAN_COUNT = 20;\nconst DEFAULT_MAX_LOGS = 1000;\nconst BOTTOM_THRESHOLD_PX = 50;\n\nconst VIRTUAL_ROW_STYLE_BASE = {\n position: \"absolute\" as const,\n top: 0,\n left: 0,\n width: \"100%\",\n};\n\nexport interface LogTimelineProps {\n rows: OtelLogsRow[];\n onLogClick?: (log: LogEntry) => void;\n onTraceLinkClick?: (traceId: string, spanId: string) => void;\n selectedLogId?: string;\n isLoading?: boolean;\n error?: Error;\n streaming?: boolean;\n maxLogs?: number;\n searchText?: string;\n onAtBottomChange?: (isAtBottom: boolean) => void;\n}\n\nfunction simpleHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n return Math.abs(hash).toString(36);\n}\n\nfunction getSeverityText(\n severityNumber: number | undefined,\n severityText: string | undefined\n): string {\n if (severityText) return severityText;\n const n = severityNumber ?? 0;\n if (n >= 21) return \"FATAL\";\n if (n >= 17) return \"ERROR\";\n if (n >= 13) return \"WARN\";\n if (n >= 9) return \"INFO\";\n if (n >= 5) return \"DEBUG\";\n if (n >= 1) return \"TRACE\";\n return \"UNSPECIFIED\";\n}\n\n/** Transform OtelLogsRow[] to LogEntry[] */\nfunction buildLogs(rows: OtelLogsRow[]): LogEntry[] {\n return rows\n .map((row) => {\n const timeUnixMs = parseInt(row.Timestamp, 10) / 1e6;\n const body = row.Body ?? \"\";\n const severityText = getSeverityText(\n row.SeverityNumber,\n row.SeverityText\n );\n const logId = `${row.Timestamp}-${row.ServiceName ?? \"unknown\"}-${simpleHash(body)}`;\n\n return {\n logId,\n timeUnixMs,\n body,\n severityText,\n severityNumber: row.SeverityNumber ?? 0,\n serviceName: row.ServiceName ?? \"unknown\",\n traceId: row.TraceId,\n spanId: row.SpanId,\n attributes: row.LogAttributes ?? {},\n resourceAttributes: row.ResourceAttributes ?? {},\n scopeName: row.ScopeName,\n };\n })\n .sort((a, b) => a.timeUnixMs - b.timeUnixMs);\n}\n\nexport function LogTimeline({\n rows,\n onLogClick,\n onTraceLinkClick,\n selectedLogId: externalSelectedLogId,\n isLoading,\n error,\n streaming = false,\n maxLogs = DEFAULT_MAX_LOGS,\n searchText = \"\",\n onAtBottomChange,\n}: LogTimelineProps) {\n useRegisterShortcuts(\"log-viewer\", LOG_VIEWER_SHORTCUTS);\n\n const [internalSelectedLogId, setInternalSelectedLogId] = useState<\n string | null\n >(null);\n const [isDetailPaneOpen, setIsDetailPaneOpen] = useState(false);\n const [isAtBottom, setIsAtBottom] = useState(true);\n const [wordWrap, setWordWrap] = useState(true);\n const [relativeTime, setRelativeTime] = useState(false);\n const selectedLogId = externalSelectedLogId ?? internalSelectedLogId;\n const scrollRef = useRef<HTMLDivElement>(null);\n const announcementRef = useRef<HTMLDivElement>(null);\n const wasAtBottomRef = useRef(true);\n const hasScrolledToInitialRef = useRef(false);\n\n const allLogs = useMemo(() => buildLogs(rows), [rows]);\n\n const boundedLogs = useMemo(() => {\n if (streaming && allLogs.length > maxLogs)\n return allLogs.slice(allLogs.length - maxLogs);\n return allLogs;\n }, [allLogs, streaming, maxLogs]);\n\n const selectedLog = useMemo(() => {\n return boundedLogs.find((log) => log.logId === selectedLogId) ?? null;\n }, [boundedLogs, selectedLogId]);\n\n const referenceTimeMs = useMemo(() => {\n if (selectedLog) return selectedLog.timeUnixMs;\n const first = boundedLogs[0];\n return first ? first.timeUnixMs : 0;\n }, [selectedLog, boundedLogs]);\n\n useEffect(() => {\n if (externalSelectedLogId) setIsDetailPaneOpen(true);\n }, [externalSelectedLogId]);\n\n const checkIfAtBottom = useCallback(() => {\n if (!scrollRef.current) return true;\n const { scrollTop, scrollHeight, clientHeight } = scrollRef.current;\n if (scrollHeight <= clientHeight) return true;\n return scrollHeight - scrollTop - clientHeight < BOTTOM_THRESHOLD_PX;\n }, []);\n\n const prevAtBottomRef = useRef(true);\n\n const handleScroll = useCallback(() => {\n const atBottom = checkIfAtBottom();\n wasAtBottomRef.current = atBottom;\n setIsAtBottom(atBottom);\n if (atBottom !== prevAtBottomRef.current) {\n prevAtBottomRef.current = atBottom;\n onAtBottomChange?.(atBottom);\n }\n }, [checkIfAtBottom, onAtBottomChange]);\n\n useEffect(() => {\n const atBottom = checkIfAtBottom();\n wasAtBottomRef.current = atBottom;\n setIsAtBottom(atBottom);\n }, [boundedLogs.length, checkIfAtBottom]);\n\n useEffect(() => {\n if (streaming && wasAtBottomRef.current && scrollRef.current) {\n scrollRef.current.scrollTop = scrollRef.current.scrollHeight;\n }\n }, [boundedLogs, streaming]);\n\n const virtualizer = useVirtualizer({\n count: boundedLogs.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => LOG_ROW_HEIGHT,\n overscan: OVERSCAN_COUNT,\n });\n\n // Scroll to externally-selected log on initial data load\n useEffect(() => {\n if (hasScrolledToInitialRef.current) return;\n if (!externalSelectedLogId || boundedLogs.length === 0) return;\n const idx = boundedLogs.findIndex((l) => l.logId === externalSelectedLogId);\n if (idx === -1) return;\n hasScrolledToInitialRef.current = true;\n virtualizer.scrollToIndex(idx, { align: \"center\" });\n }, [externalSelectedLogId, boundedLogs, virtualizer]);\n\n const handleLogClick = useCallback(\n (log: LogEntry) => {\n setInternalSelectedLogId(log.logId);\n setIsDetailPaneOpen(true);\n onLogClick?.(log);\n if (announcementRef.current) {\n announcementRef.current.textContent = `Selected log from ${log.serviceName}: ${log.body.slice(0, 100)}`;\n }\n },\n [onLogClick]\n );\n\n const logClickHandlers = useMemo(() => {\n const handlers = new Map<string, () => void>();\n boundedLogs.forEach((log) => {\n handlers.set(log.logId, () => handleLogClick(log));\n });\n return handlers;\n }, [boundedLogs, handleLogClick]);\n\n const handleCloseDetailPane = useCallback(() => {\n setIsDetailPaneOpen(false);\n setInternalSelectedLogId(null);\n }, []);\n\n const handleScrollToBottom = useCallback(() => {\n if (scrollRef.current) {\n scrollRef.current.scrollTop = scrollRef.current.scrollHeight;\n wasAtBottomRef.current = true;\n setIsAtBottom(true);\n if (!prevAtBottomRef.current) {\n prevAtBottomRef.current = true;\n onAtBottomChange?.(true);\n }\n }\n }, [onAtBottomChange]);\n\n const navigateUp = useCallback(() => {\n const idx = boundedLogs.findIndex((l) => l.logId === selectedLogId);\n if (idx > 0) {\n const prev = boundedLogs[idx - 1];\n if (prev) {\n handleLogClick(prev);\n virtualizer.scrollToIndex(idx - 1, { align: \"auto\" });\n }\n } else if (idx === -1 && boundedLogs.length > 0) {\n const targetIdx = boundedLogs.length - 1;\n const last = boundedLogs[targetIdx];\n if (last) {\n handleLogClick(last);\n virtualizer.scrollToIndex(targetIdx, { align: \"auto\" });\n }\n }\n }, [boundedLogs, selectedLogId, handleLogClick, virtualizer]);\n\n const navigateDown = useCallback(() => {\n const idx = boundedLogs.findIndex((l) => l.logId === selectedLogId);\n if (idx >= 0 && idx < boundedLogs.length - 1) {\n const next = boundedLogs[idx + 1];\n if (next) {\n handleLogClick(next);\n virtualizer.scrollToIndex(idx + 1, { align: \"auto\" });\n }\n } else if (idx === -1 && boundedLogs.length > 0) {\n const first = boundedLogs[0];\n if (first) {\n handleLogClick(first);\n virtualizer.scrollToIndex(0, { align: \"auto\" });\n }\n }\n }, [boundedLogs, selectedLogId, handleLogClick, virtualizer]);\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n const isFormField =\n e.target instanceof HTMLInputElement ||\n e.target instanceof HTMLTextAreaElement ||\n e.target instanceof HTMLSelectElement;\n if (isFormField && e.key === \"Escape\") {\n (e.target as HTMLElement).blur();\n return;\n }\n if (isFormField) return;\n switch (e.key) {\n case \"ArrowUp\":\n case \"k\":\n case \"K\":\n e.preventDefault();\n navigateUp();\n break;\n case \"ArrowDown\":\n case \"j\":\n case \"J\":\n e.preventDefault();\n navigateDown();\n break;\n case \"Escape\":\n if (isDetailPaneOpen) {\n e.preventDefault();\n handleCloseDetailPane();\n } else {\n const panel = document.querySelector('[data-testid=\"log-filter\"]');\n const toggle = panel?.querySelector<HTMLButtonElement>(\n '[data-testid=\"log-filter-toggle\"]'\n );\n if (toggle && panel?.querySelector(\".border-t\")) {\n e.preventDefault();\n toggle.click();\n }\n }\n break;\n case \"g\":\n case \"G\":\n e.preventDefault();\n handleScrollToBottom();\n break;\n case \"/\": {\n e.preventDefault();\n const input = document.querySelector<HTMLInputElement>(\n '[data-testid=\"filter-bodyContains\"]'\n );\n if (input) {\n // Ensure filter panel is open first\n const panel = document.querySelector('[data-testid=\"log-filter\"]');\n const toggle = panel?.querySelector<HTMLButtonElement>(\n '[data-testid=\"log-filter-toggle\"]'\n );\n // Check if panel content is visible (has more than just the toggle button)\n if (toggle && !panel?.querySelector(\".border-t\")) {\n toggle.click();\n // Focus after panel opens\n requestAnimationFrame(() => {\n document\n .querySelector<HTMLInputElement>(\n '[data-testid=\"filter-bodyContains\"]'\n )\n ?.focus();\n });\n } else {\n input.focus();\n }\n }\n break;\n }\n case \"f\":\n case \"F\": {\n e.preventDefault();\n const toggle = document.querySelector<HTMLButtonElement>(\n '[data-testid=\"log-filter-toggle\"]'\n );\n toggle?.click();\n break;\n }\n case \"Enter\": {\n if (selectedLogId && !isDetailPaneOpen) {\n e.preventDefault();\n const log = boundedLogs.find((l) => l.logId === selectedLogId);\n if (log) handleLogClick(log);\n }\n break;\n }\n case \"Home\": {\n e.preventDefault();\n if (boundedLogs.length > 0) {\n const first = boundedLogs[0];\n if (first) {\n handleLogClick(first);\n virtualizer.scrollToIndex(0);\n }\n }\n break;\n }\n case \"c\":\n case \"C\": {\n if (e.ctrlKey || e.metaKey) break;\n e.preventDefault();\n if (selectedLog) {\n navigator.clipboard.writeText(selectedLog.body).catch(() => {});\n }\n break;\n }\n case \"w\":\n case \"W\":\n e.preventDefault();\n setWordWrap((v) => !v);\n break;\n case \"t\":\n case \"T\":\n e.preventDefault();\n setRelativeTime((v) => !v);\n break;\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [\n boundedLogs,\n selectedLogId,\n selectedLog,\n navigateUp,\n navigateDown,\n handleLogClick,\n handleCloseDetailPane,\n handleScrollToBottom,\n isDetailPaneOpen,\n virtualizer,\n ]);\n\n if (isLoading && !boundedLogs.length) return <LoadingSkeleton />;\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center h-full bg-background\">\n <div className=\"text-center p-6\">\n <div className=\"text-red-600 dark:text-red-400 mb-2\">\n Failed to load logs\n </div>\n <div className=\"text-sm text-muted-foreground\">{error.message}</div>\n </div>\n </div>\n );\n }\n\n if (boundedLogs.length === 0) {\n return (\n <div className=\"flex items-center justify-center h-full bg-background\">\n <div className=\"text-center p-6\">\n <div className=\"text-muted-foreground mb-2\">No logs</div>\n <div className=\"text-sm text-muted-foreground\">\n {streaming ? \"Waiting for logs...\" : \"No log data available\"}\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full min-h-0 bg-background\">\n <div\n ref={announcementRef}\n className=\"sr-only\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n />\n <div className=\"flex flex-1 min-h-0\">\n <div className=\"flex-1 flex flex-col min-w-0\">\n {/* Header */}\n <div className=\"border-b border-border px-4 py-3\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex items-center gap-1.5 px-2 py-1 bg-muted rounded-md text-sm font-medium text-muted-foreground\">\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 6h16M4 12h16M4 18h7\"\n />\n </svg>\n {boundedLogs.length}{\" \"}\n {boundedLogs.length === 1 ? \"log\" : \"logs\"}\n </div>\n </div>\n </div>\n </div>\n\n {/* Virtual Scroll */}\n <div className=\"flex-1 relative\">\n <div\n ref={scrollRef}\n className=\"absolute inset-0 overflow-auto\"\n onScroll={handleScroll}\n >\n <div\n style={{\n height: `${virtualizer.getTotalSize()}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {virtualizer.getVirtualItems().map((virtualRow) => {\n const log = boundedLogs[virtualRow.index];\n if (!log) return null;\n return (\n <div\n key={virtualRow.index}\n style={{\n ...VIRTUAL_ROW_STYLE_BASE,\n height: LOG_ROW_HEIGHT,\n transform: `translateY(${virtualRow.start}px)`,\n }}\n >\n <LogRow\n log={log}\n isSelected={log.logId === selectedLogId}\n onClick={logClickHandlers.get(log.logId)!}\n searchText={searchText}\n relativeTime={relativeTime}\n referenceTimeMs={referenceTimeMs}\n />\n </div>\n );\n })}\n </div>\n </div>\n {!isAtBottom && (\n <button\n onClick={handleScrollToBottom}\n className=\"absolute bottom-4 right-4 px-3 py-1.5 text-xs font-medium rounded-md bg-primary hover:bg-primary/90 text-primary-foreground shadow-lg transition-colors z-10\"\n aria-label=\"Scroll to bottom\"\n >\n <span className=\"flex items-center gap-1\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n className=\"w-3 h-3\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M8 2a.75.75 0 0 1 .75.75v8.69l3.22-3.22a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.22 3.22V2.75A.75.75 0 0 1 8 2Z\"\n clipRule=\"evenodd\"\n />\n </svg>\n (<span className=\"underline underline-offset-4\">G</span>)\n </span>\n </button>\n )}\n </div>\n </div>\n\n {isDetailPaneOpen && selectedLog && (\n <LogDetailPane\n log={selectedLog}\n onClose={handleCloseDetailPane}\n onTraceLinkClick={onTraceLinkClick}\n wordWrap={wordWrap}\n />\n )}\n </div>\n </div>\n );\n}\n","/**\n * LogFilter – collapsible filter panel for LogsDataFilter params.\n * Follows the same visual pattern as TraceSearch filters.\n */\n\nimport { useState, useEffect, useRef, useCallback, useMemo } from \"react\";\nimport type { dataFilterSchemas, denormalizedSignals } from \"@kopai/core\";\n\ntype LogsDataFilter = dataFilterSchemas.LogsDataFilter;\ntype OtelLogsRow = denormalizedSignals.OtelLogsRow;\ntype FilterValue = Partial<LogsDataFilter>;\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst LOOKBACK_OPTIONS = [\n { label: \"Last 5 Minutes\", ms: 5 * 60_000 },\n { label: \"Last 15 Minutes\", ms: 15 * 60_000 },\n { label: \"Last 30 Minutes\", ms: 30 * 60_000 },\n { label: \"Last 1 Hour\", ms: 60 * 60_000 },\n { label: \"Last 2 Hours\", ms: 2 * 60 * 60_000 },\n { label: \"Last 6 Hours\", ms: 6 * 60 * 60_000 },\n { label: \"Last 12 Hours\", ms: 12 * 60 * 60_000 },\n { label: \"Last 24 Hours\", ms: 24 * 60 * 60_000 },\n] as const;\n\nconst DEBOUNCE_MS = 500;\n\ntype TimeMode = \"lookback\" | \"absolute\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Convert ms epoch to nanosecond string */\nfunction msToNs(ms: number): string {\n return String(BigInt(Math.floor(ms)) * 1_000_000n);\n}\n\n/** Parse comma-separated \"key=value\" pairs into a record, or undefined if all invalid */\nfunction parseKeyValues(input: string): Record<string, string> | undefined {\n const result: Record<string, string> = {};\n let hasAny = false;\n for (const part of input.split(\",\")) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n const eqIdx = trimmed.indexOf(\"=\");\n if (eqIdx < 1) continue;\n const key = trimmed.slice(0, eqIdx).trim();\n const val = trimmed.slice(eqIdx + 1).trim();\n if (!key) continue;\n result[key] = val;\n hasAny = true;\n }\n return hasAny ? result : undefined;\n}\n\n/** Format a datetime-local string from a nanosecond timestamp */\nfunction nsToDatetimeLocal(ns: string | undefined): string {\n if (!ns) return \"\";\n const ms = Number(BigInt(ns) / 1_000_000n);\n const d = new Date(ms);\n const pad = (n: number) => String(n).padStart(2, \"0\");\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n}\n\n/** Build compact summary of active filters */\nfunction buildFilterSummary(\n value: FilterValue,\n selectedServices: string[]\n): string {\n const parts: string[] = [];\n if (selectedServices.length === 1) {\n parts.push(`service:${selectedServices[0]}`);\n } else if (selectedServices.length > 1) {\n parts.push(`services:${selectedServices.length}`);\n }\n if (value.severityText) parts.push(`severity:${value.severityText}`);\n if (value.scopeName) parts.push(`scope:${value.scopeName}`);\n if (value.bodyContains) parts.push(`body:\"${value.bodyContains}\"`);\n if (value.traceId) parts.push(`trace:${value.traceId.slice(0, 8)}…`);\n if (value.spanId) parts.push(`span:${value.spanId.slice(0, 8)}…`);\n if (value.limit != null) parts.push(`limit:${value.limit}`);\n if (value.sortOrder === \"ASC\") parts.push(\"sort:oldest\");\n return parts.join(\" | \");\n}\n\n// ---------------------------------------------------------------------------\n// Shared input classes\n// ---------------------------------------------------------------------------\n\nconst INPUT_CLS =\n \"w-full bg-muted/50 border border-border rounded px-2 py-1.5 text-sm text-foreground placeholder:text-muted-foreground/50\";\n\nconst LABEL_CLS = \"text-xs text-muted-foreground\";\n\n// ---------------------------------------------------------------------------\n// Debounce hook\n// ---------------------------------------------------------------------------\n\nfunction useDebouncedValue<T>(value: T, delayMs: number): T {\n const [debounced, setDebounced] = useState(value);\n useEffect(() => {\n const id = setTimeout(() => setDebounced(value), delayMs);\n return () => clearTimeout(id);\n }, [value, delayMs]);\n return debounced;\n}\n\n// ---------------------------------------------------------------------------\n// MultiSelect dropdown\n// ---------------------------------------------------------------------------\n\nfunction MultiSelect({\n options,\n selected,\n onChange,\n testId,\n}: {\n options: string[];\n selected: string[];\n onChange: (next: string[]) => void;\n testId?: string;\n}) {\n const [dropOpen, setDropOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n // Close on click outside\n useEffect(() => {\n if (!dropOpen) return;\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setDropOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [dropOpen]);\n\n const toggle = (val: string) => {\n if (selected.includes(val)) {\n onChange(selected.filter((s) => s !== val));\n } else {\n onChange([...selected, val]);\n }\n };\n\n const label =\n selected.length === 0\n ? \"All\"\n : selected.length === 1\n ? selected[0]\n : `${selected.length} selected`;\n\n return (\n <div ref={ref} className=\"relative\" data-testid={testId}>\n <button\n type=\"button\"\n onClick={() => setDropOpen((v) => !v)}\n className={`${INPUT_CLS} text-left flex items-center justify-between`}\n data-testid={testId ? `${testId}-trigger` : undefined}\n >\n <span className=\"truncate\">{label}</span>\n <span className=\"text-muted-foreground text-xs ml-1\">\n {dropOpen ? \"▲\" : \"▼\"}\n </span>\n </button>\n {dropOpen && (\n <div\n className=\"absolute z-10 mt-1 w-full bg-background border border-border rounded shadow-lg max-h-48 overflow-y-auto\"\n data-testid={testId ? `${testId}-dropdown` : undefined}\n >\n {options.length === 0 && (\n <div className=\"px-2 py-1.5 text-xs text-muted-foreground\">\n No options\n </div>\n )}\n {options.map((opt) => (\n <label\n key={opt}\n className=\"flex items-center gap-2 px-2 py-1.5 hover:bg-muted/30 cursor-pointer text-sm\"\n >\n <input\n type=\"checkbox\"\n checked={selected.includes(opt)}\n onChange={() => toggle(opt)}\n className=\"accent-foreground\"\n data-testid={testId ? `${testId}-option-${opt}` : undefined}\n />\n <span className=\"truncate\">{opt}</span>\n </label>\n ))}\n {selected.length > 0 && (\n <button\n type=\"button\"\n onClick={() => onChange([])}\n className=\"w-full px-2 py-1.5 text-xs text-muted-foreground hover:bg-muted/30 border-t border-border\"\n data-testid={testId ? `${testId}-clear` : undefined}\n >\n Clear all\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport interface LogFilterProps {\n value: FilterValue;\n onChange: (filters: FilterValue) => void;\n rows?: OtelLogsRow[];\n /** Controlled multi-select for services (empty = all). */\n selectedServices?: string[];\n onSelectedServicesChange?: (services: string[]) => void;\n}\n\nexport function LogFilter({\n value,\n onChange,\n rows = [],\n selectedServices = [],\n onSelectedServicesChange,\n}: LogFilterProps) {\n const [open, setOpen] = useState(false);\n const [timeMode, setTimeMode] = useState<TimeMode>(\"lookback\");\n const [lookbackIdx, setLookbackIdx] = useState(-1);\n\n // -- Derive filterable options from rows (sticky — accumulates over time) --\n const svcRef = useRef(new Set<string>());\n const sevRef = useRef(new Set<string>());\n const scopeRef = useRef(new Set<string>());\n\n const serviceNames = useMemo(() => {\n for (const r of rows) if (r.ServiceName) svcRef.current.add(r.ServiceName);\n return Array.from(svcRef.current).sort();\n }, [rows]);\n\n const severityTexts = useMemo(() => {\n for (const r of rows)\n if (r.SeverityText) sevRef.current.add(r.SeverityText);\n return Array.from(sevRef.current).sort();\n }, [rows]);\n\n const scopeNames = useMemo(() => {\n for (const r of rows) if (r.ScopeName) scopeRef.current.add(r.ScopeName);\n return Array.from(scopeRef.current).sort();\n }, [rows]);\n\n // -- Debounced text fields ------------------------------------------------\n const [bodyContains, setBodyContains] = useState(value.bodyContains ?? \"\");\n const [traceId, setTraceId] = useState(value.traceId ?? \"\");\n const [spanId, setSpanId] = useState(value.spanId ?? \"\");\n const [logAttrsText, setLogAttrsText] = useState(\"\");\n const [resAttrsText, setResAttrsText] = useState(\"\");\n const [scopeAttrsText, setScopeAttrsText] = useState(\"\");\n\n const dBodyContains = useDebouncedValue(bodyContains, DEBOUNCE_MS);\n const dTraceId = useDebouncedValue(traceId, DEBOUNCE_MS);\n const dSpanId = useDebouncedValue(spanId, DEBOUNCE_MS);\n const dLogAttrs = useDebouncedValue(logAttrsText, DEBOUNCE_MS);\n const dResAttrs = useDebouncedValue(resAttrsText, DEBOUNCE_MS);\n const dScopeAttrs = useDebouncedValue(scopeAttrsText, DEBOUNCE_MS);\n\n // Prevent calling onChange on first render\n const isFirstRender = useRef(true);\n\n // -- Sync debounced text values to parent ---------------------------------\n useEffect(() => {\n if (isFirstRender.current) {\n isFirstRender.current = false;\n return;\n }\n const next: FilterValue = { ...value };\n\n if (dBodyContains) next.bodyContains = dBodyContains;\n else delete next.bodyContains;\n\n if (dTraceId) next.traceId = dTraceId;\n else delete next.traceId;\n\n if (dSpanId) next.spanId = dSpanId;\n else delete next.spanId;\n\n const la = parseKeyValues(dLogAttrs);\n if (la) next.logAttributes = la;\n else delete next.logAttributes;\n\n const ra = parseKeyValues(dResAttrs);\n if (ra) next.resourceAttributes = ra;\n else delete next.resourceAttributes;\n\n const sa = parseKeyValues(dScopeAttrs);\n if (sa) next.scopeAttributes = sa;\n else delete next.scopeAttributes;\n\n onChange(next);\n }, [dBodyContains, dTraceId, dSpanId, dLogAttrs, dResAttrs, dScopeAttrs]);\n\n // -- Immediate change helper (selects / numbers) --------------------------\n const emitImmediate = useCallback(\n (patch: Partial<FilterValue>) => {\n const next: FilterValue = { ...value };\n for (const [k, v] of Object.entries(patch)) {\n if (v === undefined || v === \"\") {\n delete (next as Record<string, unknown>)[k];\n } else {\n (next as Record<string, unknown>)[k] = v;\n }\n }\n // Re-apply current debounced text fields so they don't get lost\n if (dBodyContains) next.bodyContains = dBodyContains;\n if (dTraceId) next.traceId = dTraceId;\n if (dSpanId) next.spanId = dSpanId;\n const la = parseKeyValues(dLogAttrs);\n if (la) next.logAttributes = la;\n const ra = parseKeyValues(dResAttrs);\n if (ra) next.resourceAttributes = ra;\n const sa = parseKeyValues(dScopeAttrs);\n if (sa) next.scopeAttributes = sa;\n onChange(next);\n },\n [\n value,\n onChange,\n dBodyContains,\n dTraceId,\n dSpanId,\n dLogAttrs,\n dResAttrs,\n dScopeAttrs,\n ]\n );\n\n // Wire up the service handler to use emitImmediate via ref\n const emitRef = useRef(emitImmediate);\n emitRef.current = emitImmediate;\n const handleServicesChangeSynced = useCallback(\n (next: string[]) => {\n onSelectedServicesChange?.(next);\n if (next.length === 1) {\n emitRef.current({ serviceName: next[0] });\n } else {\n emitRef.current({ serviceName: undefined });\n }\n },\n [onSelectedServicesChange]\n );\n\n // -- Lookback handler -----------------------------------------------------\n const handleLookback = useCallback(\n (idx: number) => {\n setLookbackIdx(idx);\n if (idx < 0) {\n emitImmediate({ timestampMin: undefined, timestampMax: undefined });\n } else {\n const opt = LOOKBACK_OPTIONS[idx];\n if (opt) {\n const tsMin = msToNs(Date.now() - opt.ms);\n emitImmediate({ timestampMin: tsMin, timestampMax: undefined });\n }\n }\n },\n [emitImmediate]\n );\n\n // -- Absolute time handlers -----------------------------------------------\n const handleAbsoluteMin = useCallback(\n (dtStr: string) => {\n if (!dtStr) {\n emitImmediate({ timestampMin: undefined });\n return;\n }\n const ms = new Date(dtStr).getTime();\n emitImmediate({ timestampMin: msToNs(ms) });\n },\n [emitImmediate]\n );\n\n const handleAbsoluteMax = useCallback(\n (dtStr: string) => {\n if (!dtStr) {\n emitImmediate({ timestampMax: undefined });\n return;\n }\n const ms = new Date(dtStr).getTime();\n emitImmediate({ timestampMax: msToNs(ms) });\n },\n [emitImmediate]\n );\n\n // -- Time mode switch -----------------------------------------------------\n const switchTimeMode = useCallback(\n (mode: TimeMode) => {\n setTimeMode(mode);\n setLookbackIdx(-1);\n emitImmediate({ timestampMin: undefined, timestampMax: undefined });\n },\n [emitImmediate]\n );\n\n // -- Filter summary for collapsed state -----------------------------------\n const summary = buildFilterSummary(value, selectedServices);\n\n return (\n <div className=\"border border-border rounded-lg\" data-testid=\"log-filter\">\n <button\n onClick={() => setOpen((v) => !v)}\n className=\"w-full flex items-center justify-between px-4 py-2.5 text-sm font-medium text-foreground hover:bg-muted/30 transition-colors\"\n data-testid=\"log-filter-toggle\"\n >\n <span className=\"flex items-center gap-2\">\n <span>\n <span className=\"underline underline-offset-4\">F</span>ilters\n </span>\n {!open && summary && (\n <span\n className=\"text-xs text-muted-foreground truncate max-w-md\"\n data-testid=\"filter-summary\"\n >\n {summary}\n </span>\n )}\n </span>\n <span className=\"text-muted-foreground text-xs\">\n {open ? \"▲\" : \"▼\"}\n </span>\n </button>\n\n {open && (\n <div className=\"px-4 pb-4 pt-1 border-t border-border space-y-3\">\n <div className=\"grid grid-cols-2 md:grid-cols-3 gap-3\">\n {/* Service Name — multi-select */}\n <div className=\"space-y-1\">\n <span className={LABEL_CLS}>Service</span>\n <MultiSelect\n options={serviceNames}\n selected={selectedServices}\n onChange={handleServicesChangeSynced}\n testId=\"filter-serviceName\"\n />\n </div>\n\n {/* Severity */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Severity</span>\n <select\n value={value.severityText ?? \"\"}\n onChange={(e) =>\n emitImmediate({\n severityText: e.target.value || undefined,\n })\n }\n className={INPUT_CLS}\n data-testid=\"filter-severityText\"\n >\n <option value=\"\">All</option>\n {severityTexts.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n </label>\n\n {/* Body Contains */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Body contains</span>\n <input\n type=\"text\"\n placeholder=\"Search log body... (/)\"\n value={bodyContains}\n onChange={(e) => setBodyContains(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-bodyContains\"\n />\n </label>\n\n {/* Sort Order */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Sort</span>\n <select\n value={value.sortOrder ?? \"DESC\"}\n onChange={(e) =>\n emitImmediate({\n sortOrder: e.target.value as \"ASC\" | \"DESC\",\n })\n }\n className={INPUT_CLS}\n data-testid=\"filter-sortOrder\"\n >\n <option value=\"DESC\">Newest first</option>\n <option value=\"ASC\">Oldest first</option>\n </select>\n </label>\n\n {/* Limit */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Limit</span>\n <input\n type=\"number\"\n min={1}\n max={1000}\n value={value.limit ?? \"\"}\n onChange={(e) => {\n const n = Number(e.target.value);\n emitImmediate({\n limit: n >= 1 && n <= 1000 ? n : undefined,\n });\n }}\n className={INPUT_CLS}\n data-testid=\"filter-limit\"\n />\n </label>\n\n {/* Trace ID */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Trace ID</span>\n <input\n type=\"text\"\n placeholder=\"Trace ID\"\n value={traceId}\n onChange={(e) => setTraceId(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-traceId\"\n />\n </label>\n\n {/* Span ID */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Span ID</span>\n <input\n type=\"text\"\n placeholder=\"Span ID\"\n value={spanId}\n onChange={(e) => setSpanId(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-spanId\"\n />\n </label>\n\n {/* Scope Name */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Scope</span>\n <select\n value={value.scopeName ?? \"\"}\n onChange={(e) =>\n emitImmediate({\n scopeName: e.target.value || undefined,\n })\n }\n className={INPUT_CLS}\n data-testid=\"filter-scopeName\"\n >\n <option value=\"\">All</option>\n {scopeNames.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n </label>\n\n {/* Log Attributes */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Log attributes</span>\n <input\n type=\"text\"\n placeholder=\"key1=val1, key2=val2\"\n value={logAttrsText}\n onChange={(e) => setLogAttrsText(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-logAttributes\"\n />\n </label>\n\n {/* Resource Attributes */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Resource attributes</span>\n <input\n type=\"text\"\n placeholder=\"key1=val1, key2=val2\"\n value={resAttrsText}\n onChange={(e) => setResAttrsText(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-resourceAttributes\"\n />\n </label>\n\n {/* Scope Attributes */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Scope attributes</span>\n <input\n type=\"text\"\n placeholder=\"key1=val1, key2=val2\"\n value={scopeAttrsText}\n onChange={(e) => setScopeAttrsText(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-scopeAttributes\"\n />\n </label>\n </div>\n\n {/* Time range */}\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\">\n <span className={LABEL_CLS}>Time range</span>\n <div className=\"flex rounded-md border border-border overflow-hidden text-xs\">\n <button\n className={`px-2 py-1 ${timeMode === \"lookback\" ? \"bg-muted text-foreground\" : \"text-muted-foreground hover:bg-muted/30\"}`}\n onClick={() => switchTimeMode(\"lookback\")}\n data-testid=\"time-mode-lookback\"\n >\n Lookback\n </button>\n <button\n className={`px-2 py-1 ${timeMode === \"absolute\" ? \"bg-muted text-foreground\" : \"text-muted-foreground hover:bg-muted/30\"}`}\n onClick={() => switchTimeMode(\"absolute\")}\n data-testid=\"time-mode-absolute\"\n >\n Absolute\n </button>\n </div>\n </div>\n\n {timeMode === \"lookback\" ? (\n <select\n value={lookbackIdx}\n onChange={(e) => handleLookback(Number(e.target.value))}\n className={`${INPUT_CLS} max-w-xs`}\n data-testid=\"filter-lookback\"\n >\n <option value={-1}>All time</option>\n {LOOKBACK_OPTIONS.map((opt, i) => (\n <option key={i} value={i}>\n {opt.label}\n </option>\n ))}\n </select>\n ) : (\n <div className=\"flex items-center gap-2\">\n <label className=\"space-y-1 flex-1\">\n <span className={LABEL_CLS}>From</span>\n <input\n type=\"datetime-local\"\n value={nsToDatetimeLocal(value.timestampMin)}\n onChange={(e) => handleAbsoluteMin(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-timestampMin\"\n />\n </label>\n <label className=\"space-y-1 flex-1\">\n <span className={LABEL_CLS}>To</span>\n <input\n type=\"datetime-local\"\n value={nsToDatetimeLocal(value.timestampMax)}\n onChange={(e) => handleAbsoluteMax(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-timestampMax\"\n />\n </label>\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n );\n}\n","import type { ShortcutGroup } from \"../../KeyboardShortcuts/types.js\";\n\nexport const SERVICES_SHORTCUTS: ShortcutGroup = {\n name: \"Services\",\n shortcuts: [{ keys: [\"Backspace\"], description: \"Go back\" }],\n};\n","import { useMemo } from \"react\";\nimport { observabilityCatalog } from \"../../../lib/observability-catalog.js\";\nimport type { RendererComponentProps } from \"../../../lib/renderer.js\";\nimport type { MetricsDiscoveryResult } from \"@kopai/sdk\";\n\ntype Props = RendererComponentProps<\n typeof observabilityCatalog.components.MetricDiscovery\n>;\n\nconst TYPE_ORDER: Record<string, number> = {\n Gauge: 0,\n Sum: 1,\n Histogram: 2,\n ExponentialHistogram: 3,\n Summary: 4,\n};\n\nexport function OtelMetricDiscovery(props: Props) {\n const data = props.hasData\n ? (props.data as MetricsDiscoveryResult | null)\n : null;\n const loading = props.hasData ? props.loading : false;\n const error = props.hasData ? props.error : null;\n\n const sorted = useMemo(() => {\n if (!data?.metrics) return [];\n return [...data.metrics].sort(\n (a, b) =>\n a.name.localeCompare(b.name) ||\n (TYPE_ORDER[a.type] ?? 99) - (TYPE_ORDER[b.type] ?? 99)\n );\n }, [data]);\n\n if (loading && !sorted.length) {\n return <p className=\"text-muted-foreground py-4\">Loading metrics…</p>;\n }\n if (error) {\n return <p className=\"text-red-400 py-4\">Error: {error.message}</p>;\n }\n if (!sorted.length) {\n return <p className=\"text-muted-foreground py-4\">No metrics discovered.</p>;\n }\n\n return (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm text-left text-foreground border-collapse\">\n <thead className=\"text-xs uppercase text-muted-foreground border-b border-border\">\n <tr>\n <th className=\"px-3 py-2\">Name</th>\n <th className=\"px-3 py-2\">Type</th>\n <th className=\"px-3 py-2\">Unit</th>\n <th className=\"px-3 py-2\">Description</th>\n </tr>\n </thead>\n <tbody>\n {sorted.map((m) => (\n <tr\n key={`${m.name}-${m.type}`}\n className=\"border-b border-border/50 hover:bg-muted/40\"\n >\n <td className=\"px-3 py-2 font-mono whitespace-nowrap\">\n {m.name}\n </td>\n <td className=\"px-3 py-2 text-muted-foreground\">{m.type}</td>\n <td className=\"px-3 py-2 text-muted-foreground\">\n {m.unit || \"–\"}\n </td>\n <td className=\"px-3 py-2 text-muted-foreground\">\n {m.description || \"–\"}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n","import { createCatalog } from \"./component-catalog.js\";\nimport { z } from \"zod\";\n\nexport const dashboardCatalog = createCatalog({\n name: \"dashboard\",\n components: {\n // Layout Components\n Card: {\n props: z.object({\n title: z.string().nullable(),\n description: z.string().nullable(),\n padding: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n }),\n hasChildren: true,\n description: \"A card container with optional title\",\n },\n\n Grid: {\n props: z.object({\n columns: z.number().min(1).max(4).nullable(),\n gap: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n }),\n hasChildren: true,\n description: \"Grid layout with configurable columns\",\n },\n\n Stack: {\n props: z.object({\n direction: z.enum([\"horizontal\", \"vertical\"]).nullable(),\n gap: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n align: z.enum([\"start\", \"center\", \"end\", \"stretch\"]).nullable(),\n }),\n hasChildren: true,\n description: \"Flex stack for horizontal or vertical layouts\",\n },\n\n // Data Display Components\n Metric: {\n props: z.object({\n label: z.string(),\n valuePath: z.string(),\n format: z.enum([\"number\", \"currency\", \"percent\"]).nullable(),\n trend: z.enum([\"up\", \"down\", \"neutral\"]).nullable(),\n trendValue: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Display a single metric with optional trend indicator\",\n },\n\n Chart: {\n props: z.object({\n type: z.enum([\"bar\", \"line\", \"pie\", \"area\"]),\n dataPath: z.string(),\n title: z.string().nullable(),\n height: z.number().nullable(),\n }),\n hasChildren: false,\n description: \"Display a chart from array data\",\n },\n\n Table: {\n props: z.object({\n dataPath: z.string(),\n columns: z.array(\n z.object({\n key: z.string(),\n label: z.string(),\n format: z.enum([\"text\", \"currency\", \"date\", \"badge\"]).nullable(),\n })\n ),\n }),\n hasChildren: false,\n description: \"Display tabular data\",\n },\n\n List: {\n props: z.object({\n dataPath: z.string(),\n emptyMessage: z.string().nullable(),\n }),\n hasChildren: true,\n description: \"Render a list from array data\",\n },\n\n // Interactive Components\n Button: {\n props: z.object({\n label: z.string(),\n variant: z.enum([\"primary\", \"secondary\", \"danger\", \"ghost\"]).nullable(),\n size: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n action: z.string(),\n disabled: z.boolean().nullable(),\n }),\n hasChildren: false,\n description: \"Clickable button with action\",\n },\n\n DatePicker: {\n props: z.object({\n label: z.string().nullable(),\n bindPath: z.string(),\n placeholder: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Date picker input\",\n },\n\n // Typography\n Heading: {\n props: z.object({\n text: z.string(),\n level: z.enum([\"h1\", \"h2\", \"h3\", \"h4\"]).nullable(),\n }),\n hasChildren: false,\n description: \"Section heading\",\n },\n\n Text: {\n props: z.object({\n content: z.string(),\n variant: z.enum([\"body\", \"caption\", \"label\"]).nullable(),\n color: z\n .enum([\"default\", \"muted\", \"success\", \"warning\", \"danger\"])\n .nullable(),\n }),\n hasChildren: false,\n description: \"Text paragraph\",\n },\n\n // Status Components\n Badge: {\n props: z.object({\n text: z.string(),\n variant: z\n .enum([\"default\", \"success\", \"warning\", \"danger\", \"info\"])\n .nullable(),\n }),\n hasChildren: false,\n description: \"Small status badge\",\n },\n\n // Special Components\n Divider: {\n props: z.object({\n label: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Visual divider\",\n },\n\n Empty: {\n props: z.object({\n title: z.string(),\n description: z.string().nullable(),\n action: z.string().nullable(),\n actionLabel: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Empty state placeholder\",\n },\n },\n});\n\n// Export the component list for the AI prompt\nexport const componentList = Object.keys(dashboardCatalog.components);\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Badge({\n element,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Badge>) {\n const { text, variant } = element.props;\n\n const colors: Record<string, string> = {\n default: \"hsl(var(--foreground))\",\n success: \"#22c55e\",\n warning: \"#eab308\",\n danger: \"#ef4444\",\n info: \"hsl(var(--muted-foreground))\",\n };\n\n return (\n <span\n style={{\n display: \"inline-block\",\n padding: \"2px 8px\",\n borderRadius: 12,\n fontSize: 12,\n fontWeight: 500,\n background: \"hsl(var(--border))\",\n color: colors[variant || \"default\"],\n }}\n >\n {text}\n </span>\n );\n}\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { RendererComponentProps } from \"../../../lib/renderer.js\";\n\nexport function Card({\n element,\n children,\n}: RendererComponentProps<typeof dashboardCatalog.components.Card>) {\n const { title, description, padding } = element.props as {\n title?: string | null;\n description?: string | null;\n padding?: string | null;\n };\n\n const paddings: Record<string, string> = {\n sm: \"12px\",\n md: \"16px\",\n lg: \"24px\",\n };\n\n return (\n <div\n style={{\n background: \"hsl(var(--card))\",\n border: \"1px solid hsl(var(--border))\",\n borderRadius: \"var(--radius)\",\n }}\n >\n {(title || description) && (\n <div\n style={{\n padding: \"16px 20px\",\n borderBottom: \"1px solid hsl(var(--border))\",\n }}\n >\n {title && (\n <h3 style={{ margin: 0, fontSize: 16, fontWeight: 600 }}>\n {title}\n </h3>\n )}\n {description && (\n <p\n style={{\n margin: \"4px 0 0\",\n fontSize: 14,\n color: \"hsl(var(--muted-foreground))\",\n }}\n >\n {description}\n </p>\n )}\n </div>\n )}\n <div style={{ padding: paddings[padding || \"\"] || \"16px\" }}>\n {children}\n </div>\n </div>\n );\n}\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Divider({\n element,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Divider>) {\n const { label } = element.props;\n\n if (label) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 16,\n margin: \"16px 0\",\n }}\n >\n <hr\n style={{\n flex: 1,\n border: \"none\",\n borderTop: \"1px solid hsl(var(--border))\",\n }}\n />\n <span style={{ fontSize: 12, color: \"hsl(var(--muted-foreground))\" }}>\n {label}\n </span>\n <hr\n style={{\n flex: 1,\n border: \"none\",\n borderTop: \"1px solid hsl(var(--border))\",\n }}\n />\n </div>\n );\n }\n\n return (\n <hr\n style={{\n border: \"none\",\n borderTop: \"1px solid hsl(var(--border))\",\n margin: \"16px 0\",\n }}\n />\n );\n}\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Empty({\n element,\n onAction,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Empty> & {\n onAction?: (action: string) => void;\n}) {\n const { title, description, action, actionLabel } = element.props;\n\n return (\n <div style={{ textAlign: \"center\", padding: \"40px 20px\" }}>\n <h3 style={{ margin: \"0 0 8px\", fontSize: 16, fontWeight: 600 }}>\n {title}\n </h3>\n {description && (\n <p\n style={{\n margin: \"0 0 16px\",\n fontSize: 14,\n color: \"hsl(var(--muted-foreground))\",\n }}\n >\n {description}\n </p>\n )}\n {action && actionLabel && (\n <button\n onClick={() => onAction?.(action)}\n style={{\n padding: \"8px 16px\",\n borderRadius: \"var(--radius)\",\n border: \"1px solid hsl(var(--border))\",\n background: \"hsl(var(--card))\",\n color: \"hsl(var(--foreground))\",\n fontSize: 14,\n cursor: \"pointer\",\n }}\n >\n {actionLabel}\n </button>\n )}\n </div>\n );\n}\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Grid({\n element,\n children,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Grid>) {\n const { columns, gap } = element.props;\n const gaps: Record<string, string> = {\n sm: \"8px\",\n md: \"16px\",\n lg: \"24px\",\n };\n\n return (\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(${columns || 2}, 1fr)`,\n gap: gaps[gap || \"md\"],\n }}\n >\n {children}\n </div>\n );\n}\n","import React from \"react\";\nimport { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Heading({\n element,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Heading>) {\n const { text, level } = element.props;\n const Tag = (level || \"h2\") as keyof React.JSX.IntrinsicElements;\n const sizes: Record<string, string> = {\n h1: \"28px\",\n h2: \"24px\",\n h3: \"20px\",\n h4: \"16px\",\n };\n return (\n <Tag\n style={{\n margin: \"0 0 16px\",\n fontSize: sizes[level || \"h2\"],\n fontWeight: 600,\n }}\n >\n {text}\n </Tag>\n );\n}\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Stack({\n element,\n children,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Stack>) {\n const { direction, gap, align } = element.props;\n const gaps: Record<string, string> = {\n sm: \"8px\",\n md: \"16px\",\n lg: \"24px\",\n };\n const alignments: Record<string, string> = {\n start: \"flex-start\",\n center: \"center\",\n end: \"flex-end\",\n stretch: \"stretch\",\n };\n\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: direction === \"horizontal\" ? \"row\" : \"column\",\n gap: gaps[gap || \"md\"],\n alignItems: alignments[align || \"stretch\"],\n }}\n >\n {children}\n </div>\n );\n}\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Text({\n element,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Text>) {\n const { content, color } = element.props;\n const colors: Record<string, string> = {\n default: \"hsl(var(--foreground))\",\n muted: \"hsl(var(--muted-foreground))\",\n success: \"#22c55e\",\n warning: \"#eab308\",\n danger: \"#ef4444\",\n };\n return (\n <p style={{ margin: 0, color: colors[color || \"default\"] }}>{content}</p>\n );\n}\n","import {\n useState,\n useMemo,\n useEffect,\n useCallback,\n useSyncExternalStore,\n useRef,\n} from \"react\";\nimport { KopaiSDKProvider, useKopaiSDK } from \"../providers/kopai-provider.js\";\nimport { KopaiClient } from \"@kopai/sdk\";\nimport { useKopaiData } from \"../hooks/use-kopai-data.js\";\nimport { useLiveLogs } from \"../hooks/use-live-logs.js\";\nimport type { denormalizedSignals, dataFilterSchemas } from \"@kopai/core\";\nimport type { DataSource } from \"../lib/component-catalog.js\";\nimport { observabilityCatalog } from \"../lib/observability-catalog.js\";\nimport { createRendererFromCatalog } from \"../lib/renderer.js\";\n\n// Observability components\nimport {\n LogTimeline,\n LogFilter,\n TabBar,\n ServiceList,\n TraceSearch,\n TraceDetail,\n KeyboardShortcutsProvider,\n useRegisterShortcuts,\n} from \"../components/observability/index.js\";\nimport type {\n TraceSummary,\n TraceSearchFilters,\n} from \"../components/observability/index.js\";\n\nimport { SERVICES_SHORTCUTS } from \"../components/observability/ServiceList/shortcuts.js\";\nimport { OtelMetricDiscovery } from \"../components/observability/renderers/index.js\";\nimport {\n Heading,\n Text,\n Card,\n Stack,\n Grid,\n Badge,\n Divider,\n Empty,\n} from \"../components/dashboard/index.js\";\n\ntype OtelTracesRow = denormalizedSignals.OtelTracesRow;\n\n// ---------------------------------------------------------------------------\n// Tab config\n// ---------------------------------------------------------------------------\n\ntype Tab = \"logs\" | \"services\" | \"metrics\";\n\nconst TABS: { key: Tab; label: string; shortcutKey: string }[] = [\n { key: \"services\", label: \"Services\", shortcutKey: \"S\" },\n { key: \"logs\", label: \"Logs\", shortcutKey: \"L\" },\n { key: \"metrics\", label: \"Metrics\", shortcutKey: \"M\" },\n];\n\n// ---------------------------------------------------------------------------\n// URL state helpers\n// ---------------------------------------------------------------------------\n\ninterface URLState {\n tab: Tab;\n service: string | null;\n trace: string | null;\n span: string | null;\n}\n\nfunction readURLState(): URLState {\n const params = new URLSearchParams(window.location.search);\n const service = params.get(\"service\");\n const trace = params.get(\"trace\");\n const span = params.get(\"span\");\n const rawTab = params.get(\"tab\");\n const tab = service\n ? \"services\"\n : rawTab === \"logs\" || rawTab === \"metrics\"\n ? rawTab\n : \"services\";\n return { tab, service, trace, span };\n}\n\nfunction pushURLState(\n state: {\n tab: Tab;\n service?: string | null;\n trace?: string | null;\n span?: string | null;\n },\n { replace = false }: { replace?: boolean } = {}\n) {\n const params = new URLSearchParams();\n if (state.tab !== \"services\") params.set(\"tab\", state.tab);\n if (state.service) params.set(\"service\", state.service);\n if (state.trace) params.set(\"trace\", state.trace);\n if (state.span) params.set(\"span\", state.span);\n const qs = params.toString();\n const url = `${window.location.pathname}${qs ? `?${qs}` : \"\"}`;\n if (replace) {\n history.replaceState(null, \"\", url);\n } else {\n history.pushState(null, \"\", url);\n }\n dispatchEvent(new PopStateEvent(\"popstate\"));\n}\n\nfunction subscribeURL(cb: () => void) {\n window.addEventListener(\"popstate\", cb);\n return () => window.removeEventListener(\"popstate\", cb);\n}\n\nlet _cachedSearch = \"\";\nlet _cachedState: URLState = {\n tab: \"services\",\n service: null,\n trace: null,\n span: null,\n};\n\nfunction getURLSnapshot(): URLState {\n const search = window.location.search;\n if (search !== _cachedSearch) {\n _cachedSearch = search;\n _cachedState = readURLState();\n }\n return _cachedState;\n}\n\nfunction useURLState(): URLState {\n return useSyncExternalStore(subscribeURL, getURLSnapshot);\n}\n\n// ---------------------------------------------------------------------------\n// Log filter URL helpers\n// ---------------------------------------------------------------------------\n\nfunction parseKeyValuesFromURL(\n raw: string\n): Record<string, string> | undefined {\n const result: Record<string, string> = {};\n let hasAny = false;\n for (const part of raw.split(\",\")) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n const eqIdx = trimmed.indexOf(\"=\");\n if (eqIdx < 1) continue;\n result[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);\n hasAny = true;\n }\n return hasAny ? result : undefined;\n}\n\nfunction serializeKeyValues(rec: Record<string, string> | undefined): string {\n if (!rec) return \"\";\n return Object.entries(rec)\n .map(([k, v]) => `${k}=${v}`)\n .join(\",\");\n}\n\ninterface LogURLState {\n filters: Partial<dataFilterSchemas.LogsDataFilter>;\n selectedServices: string[];\n selectedLogId: string | null;\n}\n\nfunction readLogFilters(): LogURLState {\n const p = new URLSearchParams(window.location.search);\n const filters: Partial<dataFilterSchemas.LogsDataFilter> = {\n limit: 200,\n sortOrder: \"DESC\",\n };\n\n const severity = p.get(\"severity\");\n if (severity) filters.severityText = severity;\n\n const body = p.get(\"body\");\n if (body) filters.bodyContains = body;\n\n const sort = p.get(\"sort\");\n if (sort === \"ASC\" || sort === \"DESC\") filters.sortOrder = sort;\n\n const limit = p.get(\"limit\");\n if (limit) {\n const n = parseInt(limit, 10);\n if (n >= 1 && n <= 1000) filters.limit = n;\n }\n\n const traceId = p.get(\"traceId\");\n if (traceId) filters.traceId = traceId;\n\n const spanId = p.get(\"spanId\");\n if (spanId) filters.spanId = spanId;\n\n const scope = p.get(\"scope\");\n if (scope) filters.scopeName = scope;\n\n const tsMin = p.get(\"tsMin\");\n if (tsMin) filters.timestampMin = tsMin;\n\n const tsMax = p.get(\"tsMax\");\n if (tsMax) filters.timestampMax = tsMax;\n\n const logAttrs = p.get(\"logAttrs\");\n if (logAttrs) filters.logAttributes = parseKeyValuesFromURL(logAttrs);\n\n const resAttrs = p.get(\"resAttrs\");\n if (resAttrs) filters.resourceAttributes = parseKeyValuesFromURL(resAttrs);\n\n const scopeAttrs = p.get(\"scopeAttrs\");\n if (scopeAttrs) filters.scopeAttributes = parseKeyValuesFromURL(scopeAttrs);\n\n const services = p.get(\"services\");\n const selectedServices = services ? services.split(\",\").filter(Boolean) : [];\n\n if (selectedServices.length === 1) filters.serviceName = selectedServices[0];\n\n const selectedLogId = p.get(\"log\") || null;\n\n return { filters, selectedServices, selectedLogId };\n}\n\nfunction writeLogFiltersToURL(\n filters: Partial<dataFilterSchemas.LogsDataFilter>,\n selectedServices: string[],\n selectedLogId: string | null\n) {\n const p = new URLSearchParams();\n p.set(\"tab\", \"logs\");\n\n if (filters.severityText) p.set(\"severity\", filters.severityText);\n if (filters.bodyContains) p.set(\"body\", filters.bodyContains);\n if (selectedServices.length) p.set(\"services\", selectedServices.join(\",\"));\n if (filters.sortOrder && filters.sortOrder !== \"DESC\")\n p.set(\"sort\", filters.sortOrder);\n if (filters.limit != null && filters.limit !== 200)\n p.set(\"limit\", String(filters.limit));\n if (filters.traceId) p.set(\"traceId\", filters.traceId);\n if (filters.spanId) p.set(\"spanId\", filters.spanId);\n if (filters.scopeName) p.set(\"scope\", filters.scopeName);\n if (filters.timestampMin) p.set(\"tsMin\", filters.timestampMin);\n if (filters.timestampMax) p.set(\"tsMax\", filters.timestampMax);\n\n const la = serializeKeyValues(filters.logAttributes);\n if (la) p.set(\"logAttrs\", la);\n const ra = serializeKeyValues(filters.resourceAttributes);\n if (ra) p.set(\"resAttrs\", ra);\n const sa = serializeKeyValues(filters.scopeAttributes);\n if (sa) p.set(\"scopeAttrs\", sa);\n\n if (selectedLogId) p.set(\"log\", selectedLogId);\n\n const qs = p.toString();\n const url = `${window.location.pathname}${qs ? `?${qs}` : \"\"}`;\n history.replaceState(null, \"\", url);\n}\n\n// ---------------------------------------------------------------------------\n// Duration parser — \"100ms\" → nanosecond string\n// ---------------------------------------------------------------------------\n\nfunction parseDuration(input: string): string | undefined {\n const trimmed = input.trim();\n if (!trimmed) return undefined;\n const match = trimmed.match(/^(\\d+(?:\\.\\d+)?)\\s*(us|ms|s)$/i);\n if (!match) return undefined;\n const value = parseFloat(match[1]!);\n const unit = match[2]!.toLowerCase();\n const multipliers: Record<string, number> = {\n us: 1_000,\n ms: 1_000_000,\n s: 1_000_000_000,\n };\n return String(Math.round(value * multipliers[unit]!));\n}\n\n// ---------------------------------------------------------------------------\n// Logs tab (live-tailing)\n// ---------------------------------------------------------------------------\n\nfunction LogsTab() {\n const [initState] = useState(() => readLogFilters());\n const [filters, setFilters] = useState<\n Partial<dataFilterSchemas.LogsDataFilter>\n >(initState.filters);\n const [selectedServices, setSelectedServices] = useState<string[]>(\n initState.selectedServices\n );\n const [selectedLogId, setSelectedLogId] = useState<string | null>(\n initState.selectedLogId\n );\n\n // Sync filter state to URL\n useEffect(() => {\n writeLogFiltersToURL(filters, selectedServices, selectedLogId);\n }, [filters, selectedServices, selectedLogId]);\n\n const { logs, isLive, loading, error, setLive } = useLiveLogs({\n params: filters,\n pollIntervalMs: 3_000,\n });\n\n // Client-side multi-service filter (API only supports single serviceName)\n const filteredLogs = useMemo(() => {\n if (selectedServices.length <= 1) return logs;\n const set = new Set(selectedServices);\n return logs.filter((r) => set.has(r.ServiceName ?? \"\"));\n }, [logs, selectedServices]);\n\n const handleLogClick = useCallback((log: { logId: string }) => {\n setSelectedLogId(log.logId);\n }, []);\n\n const handleTraceLinkClick = useCallback(\n (traceId: string, spanId: string) => {\n const log = filteredLogs.find((l) => l.TraceId === traceId);\n pushURLState({\n tab: \"services\",\n service: log?.ServiceName ?? undefined,\n trace: traceId,\n span: spanId,\n });\n },\n [filteredLogs]\n );\n\n return (\n <div style={{ height: \"calc(100vh - 160px)\" }} className=\"flex flex-col\">\n <div className=\"shrink-0 mb-3\">\n <LogFilter\n value={filters}\n onChange={setFilters}\n rows={logs}\n selectedServices={selectedServices}\n onSelectedServicesChange={setSelectedServices}\n />\n </div>\n <div className=\"flex-1 min-h-0\">\n <LogTimeline\n rows={filteredLogs}\n isLoading={loading}\n error={error ?? undefined}\n streaming={isLive}\n selectedLogId={selectedLogId ?? undefined}\n onLogClick={handleLogClick}\n onTraceLinkClick={handleTraceLinkClick}\n onAtBottomChange={(atBottom) => setLive(atBottom)}\n />\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Services tab — data-fetching wrappers around extracted UI components\n// ---------------------------------------------------------------------------\n\nconst SERVICES_DS: DataSource = {\n method: \"searchTracesPage\",\n params: { limit: 1000, sortOrder: \"DESC\" },\n};\n\nfunction ServiceListView({\n onSelect,\n}: {\n onSelect: (service: string) => void;\n}) {\n const { data, loading, error } = useKopaiData<{\n data: OtelTracesRow[];\n nextCursor: string | null;\n }>(SERVICES_DS);\n\n const services = useMemo(() => {\n if (!data?.data) return [];\n const names = new Set<string>();\n for (const row of data.data) {\n names.add(row.ServiceName ?? \"unknown\");\n }\n return Array.from(names)\n .sort()\n .map((name) => ({ name }));\n }, [data]);\n\n return (\n <ServiceList\n services={services}\n isLoading={loading}\n error={error ?? undefined}\n onSelect={onSelect}\n />\n );\n}\n\nfunction TraceSearchView({\n service,\n onBack,\n onSelectTrace,\n}: {\n service: string;\n onBack: () => void;\n onSelectTrace: (traceId: string) => void;\n}) {\n const [ds, setDs] = useState<DataSource>(() => ({\n method: \"searchTracesPage\",\n params: { serviceName: service, limit: 20, sortOrder: \"DESC\" as const },\n }));\n\n const handleSearch = useCallback(\n (filters: TraceSearchFilters) => {\n const params: Record<string, unknown> = {\n serviceName: service,\n limit: filters.limit,\n sortOrder: \"DESC\",\n };\n if (filters.operation) params.spanName = filters.operation;\n if (filters.lookbackMs) {\n params.timestampMin = String((Date.now() - filters.lookbackMs) * 1e6);\n }\n if (filters.minDuration) {\n const parsed = parseDuration(filters.minDuration);\n if (parsed) params.durationMin = parsed;\n }\n if (filters.maxDuration) {\n const parsed = parseDuration(filters.maxDuration);\n if (parsed) params.durationMax = parsed;\n }\n setDs({\n method: \"searchTracesPage\",\n params,\n } as DataSource);\n },\n [service]\n );\n\n const { data, loading, error } = useKopaiData<{\n data: OtelTracesRow[];\n nextCursor: string | null;\n }>(ds);\n\n // Fetch full traces for each unique traceId so service breakdown is complete\n const client = useKopaiSDK();\n const [fullTraces, setFullTraces] = useState<Map<string, OtelTracesRow[]>>(\n () => new Map()\n );\n\n useEffect(() => {\n if (!data?.data?.length) {\n setFullTraces(new Map());\n return;\n }\n const traceIds = [...new Set(data.data.map((r) => r.TraceId))];\n const ac = new AbortController();\n\n Promise.allSettled(\n traceIds.map((tid) =>\n client\n .getTrace(tid, { signal: ac.signal })\n .then((spans) => [tid, spans] as const)\n )\n )\n .then((results) => {\n if (!ac.signal.aborted) {\n const entries = results\n .filter(\n (\n r\n ): r is PromiseFulfilledResult<\n readonly [string, OtelTracesRow[]]\n > => r.status === \"fulfilled\"\n )\n .map((r) => r.value);\n setFullTraces(new Map(entries));\n }\n })\n .catch((err) => {\n if (!ac.signal.aborted)\n console.error(\"Failed to fetch full traces\", err);\n });\n\n return () => ac.abort();\n }, [data, client]);\n\n // Derive unique operations for filter dropdown\n const operations = useMemo(() => {\n if (!data?.data) return [];\n const set = new Set<string>();\n for (const row of data.data) {\n if (row.SpanName) set.add(row.SpanName);\n }\n return Array.from(set).sort();\n }, [data]);\n\n const traces = useMemo<TraceSummary[]>(() => {\n if (!data?.data) return [];\n const grouped = new Map<string, OtelTracesRow[]>();\n for (const row of data.data) {\n const tid = row.TraceId;\n if (!grouped.has(tid)) grouped.set(tid, []);\n grouped.get(tid)!.push(row);\n }\n\n return Array.from(grouped.entries()).map(([traceId, searchSpans]) => {\n const fullSpans = fullTraces.get(traceId);\n const spans = fullSpans ?? searchSpans;\n\n const root = spans.find((s) => !s.ParentSpanId) ?? spans[0]!;\n const durationNs = root.Duration ? parseInt(root.Duration, 10) : 0;\n\n const svcMap = new Map<string, { count: number; hasError: boolean }>();\n let errorCount = 0;\n for (const s of spans) {\n const svcName = s.ServiceName ?? \"unknown\";\n const entry = svcMap.get(svcName) ?? { count: 0, hasError: false };\n entry.count++;\n if (s.StatusCode === \"ERROR\") {\n entry.hasError = true;\n errorCount++;\n }\n svcMap.set(svcName, entry);\n }\n const services = Array.from(svcMap.entries())\n .map(([name, v]) => ({ name, count: v.count, hasError: v.hasError }))\n .sort((a, b) => b.count - a.count);\n\n return {\n traceId,\n rootSpanName: root.SpanName ?? \"unknown\",\n serviceName: root.ServiceName ?? \"unknown\",\n durationMs: durationNs / 1e6,\n statusCode: root.StatusCode ?? \"UNSET\",\n timestampMs: parseInt(root.Timestamp, 10) / 1e6,\n spanCount: spans.length,\n services,\n errorCount,\n };\n });\n }, [data, fullTraces]);\n\n return (\n <TraceSearch\n service={service}\n traces={traces}\n operations={operations}\n isLoading={loading}\n error={error ?? undefined}\n onSelectTrace={onSelectTrace}\n onBack={onBack}\n onSearch={handleSearch}\n />\n );\n}\n\nfunction TraceDetailView({\n service,\n traceId,\n selectedSpanId,\n onSelectSpan,\n onBack,\n}: {\n service: string;\n traceId: string;\n selectedSpanId: string | null;\n onSelectSpan: (spanId: string) => void;\n onBack: () => void;\n}) {\n const ds = useMemo<DataSource>(\n () => ({\n method: \"getTrace\",\n params: { traceId },\n }),\n [traceId]\n );\n\n const { data, loading, error } = useKopaiData<OtelTracesRow[]>(ds);\n\n return (\n <TraceDetail\n service={service}\n traceId={traceId}\n rows={data ?? []}\n isLoading={loading}\n error={error ?? undefined}\n selectedSpanId={selectedSpanId ?? undefined}\n onSpanClick={(span) => onSelectSpan(span.spanId)}\n onBack={onBack}\n />\n );\n}\n\nfunction ServicesTab({\n selectedService,\n selectedTraceId,\n selectedSpanId,\n onSelectService,\n onSelectTrace,\n onSelectSpan,\n onBackToServices,\n onBackToTraceList,\n}: {\n selectedService: string | null;\n selectedTraceId: string | null;\n selectedSpanId: string | null;\n onSelectService: (service: string) => void;\n onSelectTrace: (traceId: string) => void;\n onSelectSpan: (spanId: string) => void;\n onBackToServices: () => void;\n onBackToTraceList: () => void;\n}) {\n useRegisterShortcuts(\"services-tab\", SERVICES_SHORTCUTS);\n\n // Backspace → navigate back based on drill-down depth\n const backToServicesRef = useRef(onBackToServices);\n backToServicesRef.current = onBackToServices;\n const backToTraceListRef = useRef(onBackToTraceList);\n backToTraceListRef.current = onBackToTraceList;\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (\n e.target instanceof HTMLInputElement ||\n e.target instanceof HTMLTextAreaElement ||\n e.target instanceof HTMLSelectElement\n )\n return;\n if (e.key === \"Backspace\") {\n e.preventDefault();\n if (selectedTraceId && selectedService) {\n backToTraceListRef.current();\n } else if (selectedService) {\n backToServicesRef.current();\n }\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [selectedService, selectedTraceId]);\n\n if (selectedTraceId && selectedService) {\n return (\n <TraceDetailView\n service={selectedService}\n traceId={selectedTraceId}\n selectedSpanId={selectedSpanId}\n onSelectSpan={onSelectSpan}\n onBack={onBackToTraceList}\n />\n );\n }\n if (selectedService) {\n return (\n <TraceSearchView\n service={selectedService}\n onBack={onBackToServices}\n onSelectTrace={onSelectTrace}\n />\n );\n }\n return <ServiceListView onSelect={onSelectService} />;\n}\n\n// ---------------------------------------------------------------------------\n// Metrics tab — renderer + catalog\n// ---------------------------------------------------------------------------\n\nconst MetricsRenderer = createRendererFromCatalog(observabilityCatalog, {\n Card,\n Grid,\n Stack,\n Heading,\n Text,\n Badge,\n Divider,\n Empty,\n LogTimeline: () => null,\n TraceDetail: () => null,\n MetricTimeSeries: () => null,\n MetricHistogram: () => null,\n MetricStat: () => null,\n MetricTable: () => null,\n MetricDiscovery: OtelMetricDiscovery,\n});\n\nconst METRICS_TREE = {\n root: \"root\",\n elements: {\n root: {\n key: \"root\",\n type: \"Stack\" as const,\n children: [\"heading\", \"description\", \"discovery-card\"],\n parentKey: \"\",\n props: {\n direction: \"vertical\" as const,\n gap: \"md\" as const,\n align: null,\n },\n },\n heading: {\n key: \"heading\",\n type: \"Heading\" as const,\n children: [],\n parentKey: \"root\",\n props: { text: \"Metrics\", level: \"h2\" as const },\n },\n description: {\n key: \"description\",\n type: \"Text\" as const,\n children: [],\n parentKey: \"root\",\n props: {\n content: \"Discovered OpenTelemetry metrics\",\n variant: \"body\" as const,\n color: \"muted\" as const,\n },\n },\n \"discovery-card\": {\n key: \"discovery-card\",\n type: \"Card\" as const,\n children: [\"metric-discovery\"],\n parentKey: \"root\",\n props: { title: null, description: null, padding: null },\n },\n \"metric-discovery\": {\n key: \"metric-discovery\",\n type: \"MetricDiscovery\" as const,\n children: [],\n parentKey: \"discovery-card\",\n dataSource: { method: \"discoverMetrics\" as const },\n props: {},\n },\n },\n};\n\nfunction MetricsTab() {\n return <MetricsRenderer tree={METRICS_TREE} />;\n}\n\n// ---------------------------------------------------------------------------\n// Page\n// ---------------------------------------------------------------------------\n\nconst client = new KopaiClient({ baseUrl: \"/signals\" });\n\nexport default function ObservabilityPage() {\n const {\n tab: activeTab,\n service: selectedService,\n trace: selectedTraceId,\n span: selectedSpanId,\n } = useURLState();\n\n const handleTabChange = useCallback((tab: Tab) => {\n pushURLState({ tab });\n }, []);\n\n const handleSelectService = useCallback((service: string) => {\n pushURLState({ tab: \"services\", service });\n }, []);\n\n const handleSelectTrace = useCallback(\n (traceId: string) => {\n pushURLState({\n tab: \"services\",\n service: selectedService,\n trace: traceId,\n });\n },\n [selectedService]\n );\n\n const handleSelectSpan = useCallback(\n (spanId: string) => {\n pushURLState(\n {\n tab: \"services\",\n service: selectedService,\n trace: selectedTraceId,\n span: spanId,\n },\n { replace: true }\n );\n },\n [selectedService, selectedTraceId]\n );\n\n const handleBackToServices = useCallback(() => {\n pushURLState({ tab: \"services\" });\n }, []);\n\n const handleBackToTraceList = useCallback(() => {\n pushURLState({ tab: \"services\", service: selectedService });\n }, [selectedService]);\n\n return (\n <KopaiSDKProvider client={client}>\n <KeyboardShortcutsProvider\n onNavigateServices={() => pushURLState({ tab: \"services\" })}\n onNavigateLogs={() => pushURLState({ tab: \"logs\" })}\n onNavigateMetrics={() => pushURLState({ tab: \"metrics\" })}\n >\n <div>\n <TabBar\n tabs={TABS}\n active={activeTab}\n onChange={handleTabChange as (key: string) => void}\n />\n {activeTab === \"logs\" && <LogsTab />}\n {activeTab === \"services\" && (\n <ServicesTab\n selectedService={selectedService}\n selectedTraceId={selectedTraceId}\n selectedSpanId={selectedSpanId}\n onSelectService={handleSelectService}\n onSelectTrace={handleSelectTrace}\n onSelectSpan={handleSelectSpan}\n onBackToServices={handleBackToServices}\n onBackToTraceList={handleBackToTraceList}\n />\n )}\n {activeTab === \"metrics\" && <MetricsTab />}\n </div>\n </KeyboardShortcutsProvider>\n </KopaiSDKProvider>\n );\n}\n","import { z } from \"zod\";\nimport { dataSourceSchema } from \"./component-catalog.js\";\n\ntype Catalog = {\n name: string;\n components: Record<\n string,\n { hasChildren: boolean; description: string; props: unknown }\n >;\n uiTreeSchema: z.ZodTypeAny;\n};\n\n// Helper to format prop type from JSON schema property\nfunction formatPropType(prop: {\n type?: string | string[];\n enum?: string[];\n items?: object;\n}): string {\n if (prop.enum) return prop.enum.map((v) => `\"${v}\"`).join(\" | \");\n if (Array.isArray(prop.type))\n return prop.type.filter((t) => t !== \"null\").join(\" | \");\n if (prop.type === \"array\" && prop.items)\n return `array of ${formatPropType(prop.items as Parameters<typeof formatPropType>[0])}`;\n return prop.type ?? \"unknown\";\n}\n\n// Helper to format props from JSON schema\nfunction formatPropsFromJsonSchema(jsonSchema: object): string {\n const schema = jsonSchema as {\n properties?: Record<string, unknown>;\n required?: string[];\n };\n if (!schema.properties) return \"(no props)\";\n\n const required = new Set(schema.required ?? []);\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(schema.properties)) {\n const prop = value as {\n type?: string | string[];\n enum?: string[];\n description?: string;\n items?: object;\n };\n const isRequired = required.has(key);\n const typeStr = formatPropType(prop);\n const reqStr = isRequired ? \" (required)\" : \" (optional)\";\n const descStr = prop.description ? ` - ${prop.description}` : \"\";\n lines.push(`- ${key}: ${typeStr}${reqStr}${descStr}`);\n }\n return lines.join(\"\\n\");\n}\n\n// Helper to build example UI tree\nfunction buildExampleElements(\n names: string[],\n components: Record<string, { hasChildren: boolean }>\n): { root: string; elements: Record<string, unknown> } {\n const containerName =\n names.find((n) => components[n]?.hasChildren) ?? names[0];\n const containerKey = `${String(containerName).toLowerCase()}-1`;\n\n const childKeys: string[] = [];\n const elements: Record<string, unknown> = {};\n\n elements[containerKey] = {\n key: containerKey,\n type: String(containerName),\n props: {},\n children: childKeys,\n };\n\n const otherNames = names.filter((n) => n !== containerName).slice(0, 2);\n for (const name of otherNames) {\n const key = `${String(name).toLowerCase()}-1`;\n childKeys.push(key);\n elements[key] = {\n key,\n type: String(name),\n props: {},\n parentKey: containerKey,\n dataSource: {\n method: \"searchTracesPage\",\n params: { limit: 10 },\n },\n };\n }\n\n return { root: containerKey, elements };\n}\n\n// Helper to check if a value looks like the dataSource schema\nfunction isDataSourceSchema(value: unknown): boolean {\n if (!value || typeof value !== \"object\") return false;\n const obj = value as Record<string, unknown>;\n if (!Array.isArray(obj.oneOf)) return false;\n const first = obj.oneOf[0] as Record<string, unknown> | undefined;\n if (!first?.properties) return false;\n const props = first.properties as Record<string, unknown>;\n const method = props.method as Record<string, unknown> | undefined;\n return method?.const === \"searchTracesPage\";\n}\n\n// Helper to recursively replace dataSource schema with $ref\nfunction replaceDataSourceWithRef(obj: unknown): void {\n if (!obj || typeof obj !== \"object\") return;\n\n const record = obj as Record<string, unknown>;\n for (const key of Object.keys(record)) {\n const value = record[key];\n if (key === \"dataSource\" && isDataSourceSchema(value)) {\n record[key] = { $ref: \"#/$defs/DataSource\" };\n } else if (value && typeof value === \"object\") {\n replaceDataSourceWithRef(value);\n }\n }\n}\n\n// Helper to build unified schema with $defs\nfunction buildUnifiedSchema(treeSchema: z.ZodTypeAny): object {\n const dataSourceJsonSchema = z.toJSONSchema(dataSourceSchema);\n const treeJsonSchema = z.toJSONSchema(treeSchema) as Record<string, unknown>;\n\n replaceDataSourceWithRef(treeJsonSchema);\n treeJsonSchema.$defs = { DataSource: dataSourceJsonSchema };\n\n return treeJsonSchema;\n}\n\n/**\n * Generates LLM prompt instructions from a catalog.\n * Includes component docs, JSON schema, and usage examples.\n *\n * @param catalog - The catalog created via createCatalog\n * @returns Markdown string with component docs, schema, and examples\n *\n * @example\n * ```ts\n * const instructions = generatePromptInstructions(catalog);\n * const prompt = `Build a dashboard UI.\\n\\n${instructions}`;\n * ```\n */\nexport function generatePromptInstructions(catalog: Catalog): string {\n const componentNames = Object.keys(catalog.components);\n\n const componentSections = componentNames\n .map((name) => {\n const def = catalog.components[name]!;\n const propsSchema = z.toJSONSchema(def.props as z.ZodTypeAny);\n const propsFormatted = formatPropsFromJsonSchema(propsSchema);\n const roleLine = def.hasChildren\n ? \"Accepts children: yes\"\n : \"Accepts dataSource: yes\";\n\n return `### ${name}\n${def.description ?? \"No description\"}\n\nProps:\n${propsFormatted}\n${roleLine}`;\n })\n .join(\"\\n\\n---\\n\\n\");\n\n const unifiedSchema = buildUnifiedSchema(catalog.uiTreeSchema);\n const exampleElements = buildExampleElements(\n componentNames,\n catalog.components\n );\n\n return `## Available Components\n\n${componentSections}\n\n---\n\n## Output Schema\n\n${JSON.stringify(unifiedSchema)}\n\n---\n\n## Example\n\n${JSON.stringify(exampleElements)}`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["formatTimestamp","LOOKBACK_OPTIONS","formatTimestamp","formatTimestamp","Tooltip","Tooltip","AttributesTab","formatRelativeTime","AttributesTab","getSeverityColor","COLORS","defaultFormatValue","defaultFormatValue"],"sources":["../src/providers/kopai-provider.tsx","../src/hooks/use-kopai-data.ts","../src/lib/log-buffer.ts","../src/hooks/use-live-logs.ts","../src/lib/component-catalog.ts","../src/lib/observability-catalog.ts","../src/components/observability/TabBar/index.tsx","../src/components/observability/utils/colors.ts","../src/components/observability/ServiceList/index.tsx","../src/components/observability/utils/time.ts","../src/components/observability/TraceSearch/index.tsx","../src/components/observability/utils/flatten-tree.ts","../src/components/observability/TraceTimeline/TraceHeader.tsx","../src/components/observability/TraceTimeline/Tooltip.tsx","../src/components/observability/TraceTimeline/TimelineBar.tsx","../src/components/observability/TraceTimeline/SpanRow.tsx","../src/components/observability/utils/attributes.ts","../src/components/observability/TraceTimeline/DetailPane/AttributesTab.tsx","../src/components/observability/TraceTimeline/DetailPane/EventsTab.tsx","../src/components/observability/TraceTimeline/DetailPane/LinksTab.tsx","../src/components/observability/TraceTimeline/DetailPane/index.tsx","../src/components/observability/shared/LoadingSkeleton.tsx","../src/components/KeyboardShortcuts/context.ts","../src/components/KeyboardShortcuts/ShortcutsHelpDialog.tsx","../src/components/KeyboardShortcuts/KeyboardShortcutsProvider.tsx","../src/components/observability/TraceTimeline/shortcuts.ts","../src/components/observability/TraceTimeline/index.tsx","../src/components/observability/TraceDetail/index.tsx","../src/components/observability/LogTimeline/LogRow.tsx","../src/components/observability/LogTimeline/LogDetailPane/AttributesTab.tsx","../src/components/observability/LogTimeline/LogDetailPane/JsonTreeView.tsx","../src/components/observability/LogTimeline/LogDetailPane/index.tsx","../src/components/observability/LogTimeline/shortcuts.ts","../src/components/observability/LogTimeline/index.tsx","../src/components/observability/LogTimeline/LogFilter.tsx","../src/components/observability/utils/lttb.ts","../src/components/observability/utils/units.ts","../src/components/observability/MetricTimeSeries/index.tsx","../src/components/observability/MetricHistogram/index.tsx","../src/components/observability/MetricStat/index.tsx","../src/components/observability/MetricTable/index.tsx","../src/lib/renderer.tsx","../src/lib/catalog.ts","../src/components/dashboard/Badge/index.tsx","../src/components/dashboard/Card/index.tsx","../src/components/dashboard/Divider/index.tsx","../src/components/dashboard/Empty/index.tsx","../src/components/dashboard/Grid/index.tsx","../src/components/dashboard/Heading/index.tsx","../src/components/dashboard/Stack/index.tsx","../src/components/dashboard/Text/index.tsx","../src/components/observability/renderers/OtelLogTimeline.tsx","../src/components/observability/renderers/OtelMetricDiscovery.tsx","../src/components/observability/renderers/OtelMetricHistogram.tsx","../src/components/observability/renderers/OtelMetricStat.tsx","../src/components/observability/renderers/OtelMetricTable.tsx","../src/components/observability/renderers/OtelMetricTimeSeries.tsx","../src/components/observability/renderers/OtelTraceDetail.tsx","../src/components/observability/DynamicDashboard/index.tsx","../src/components/observability/ServiceList/shortcuts.ts","../src/pages/observability.tsx","../src/lib/generate-prompt-instructions.ts"],"sourcesContent":["import { createContext, useContext, type ReactNode } from \"react\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport type { KopaiClient as SDKClient } from \"@kopai/sdk\";\n\nexport type KopaiClient = Pick<\n SDKClient,\n | \"searchTracesPage\"\n | \"searchLogsPage\"\n | \"searchMetricsPage\"\n | \"getTrace\"\n | \"discoverMetrics\"\n>;\n\ninterface KopaiSDKContextValue {\n client: KopaiClient;\n}\n\nconst KopaiSDKContext = createContext<KopaiSDKContextValue | null>(null);\n\nexport const queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 30_000,\n refetchOnWindowFocus: false,\n retry: false,\n },\n },\n});\n\ninterface KopaiSDKProviderProps {\n client: KopaiClient;\n children: ReactNode;\n}\n\nexport function KopaiSDKProvider({ client, children }: KopaiSDKProviderProps) {\n return (\n <QueryClientProvider client={queryClient}>\n <KopaiSDKContext.Provider value={{ client }}>\n {children}\n </KopaiSDKContext.Provider>\n </QueryClientProvider>\n );\n}\n\nexport function useKopaiSDK(): KopaiClient {\n const ctx = useContext(KopaiSDKContext);\n if (!ctx) {\n throw new Error(\"useKopaiSDK must be used within KopaiSDKProvider\");\n }\n return ctx.client;\n}\n","import { useQuery } from \"@tanstack/react-query\";\nimport type { DataSource } from \"../lib/component-catalog.js\";\nimport { useKopaiSDK } from \"../providers/kopai-provider.js\";\n\nexport interface UseKopaiDataResult<T> {\n data: T | null;\n loading: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\nfunction fetchForDataSource(\n client: ReturnType<typeof useKopaiSDK>,\n dataSource: DataSource,\n signal: AbortSignal\n): Promise<unknown> {\n switch (dataSource.method) {\n case \"searchTracesPage\":\n return client.searchTracesPage(\n dataSource.params as Parameters<typeof client.searchTracesPage>[0],\n { signal }\n );\n case \"searchLogsPage\":\n return client.searchLogsPage(\n dataSource.params as Parameters<typeof client.searchLogsPage>[0],\n { signal }\n );\n case \"searchMetricsPage\":\n return client.searchMetricsPage(\n dataSource.params as Parameters<typeof client.searchMetricsPage>[0],\n { signal }\n );\n case \"getTrace\":\n return client.getTrace(dataSource.params.traceId, { signal });\n case \"discoverMetrics\":\n return client.discoverMetrics({ signal });\n default: {\n const exhaustiveCheck: never = dataSource;\n throw new Error(\n `Unknown method: ${(exhaustiveCheck as DataSource).method}`\n );\n }\n }\n}\n\nexport function useKopaiData<T = unknown>(\n dataSource: DataSource | undefined\n): UseKopaiDataResult<T> {\n const client = useKopaiSDK();\n\n const { data, isFetching, error, refetch } = useQuery<unknown, Error>({\n queryKey: [\"kopai\", dataSource?.method, dataSource?.params],\n queryFn: ({ signal }) => fetchForDataSource(client, dataSource!, signal),\n enabled: !!dataSource,\n refetchInterval: dataSource?.refetchIntervalMs,\n });\n\n return {\n data: (data as T) ?? null,\n loading: isFetching,\n error: error ?? null,\n refetch,\n };\n}\n","import type { denormalizedSignals } from \"@kopai/core\";\n\ntype OtelLogsRow = denormalizedSignals.OtelLogsRow;\n\nfunction logKey(row: OtelLogsRow): string {\n const body = row.Body ?? \"\";\n let hash = 0;\n for (let i = 0; i < body.length; i++) {\n hash = (hash << 5) - hash + body.charCodeAt(i);\n hash = hash & hash;\n }\n return `${row.Timestamp}-${row.ServiceName ?? \"\"}-${Math.abs(hash).toString(36)}`;\n}\n\nexport class LogBuffer {\n private readonly maxSize: number;\n private rows: OtelLogsRow[] = [];\n private keys = new Set<string>();\n\n constructor(maxSize = 1000) {\n this.maxSize = maxSize;\n }\n\n /** Merge new rows, dedup, sort by timestamp, trim oldest when over max. */\n merge(incoming: OtelLogsRow[]): void {\n for (const row of incoming) {\n const k = logKey(row);\n if (this.keys.has(k)) continue;\n this.keys.add(k);\n this.rows.push(row);\n }\n // Sort ascending by timestamp\n this.rows.sort((a, b) => {\n if (a.Timestamp < b.Timestamp) return -1;\n if (a.Timestamp > b.Timestamp) return 1;\n return 0;\n });\n // Trim oldest\n if (this.rows.length > this.maxSize) {\n const removed = this.rows.splice(0, this.rows.length - this.maxSize);\n for (const r of removed) this.keys.delete(logKey(r));\n }\n }\n\n getAll(): OtelLogsRow[] {\n return this.rows.slice();\n }\n\n getNewestTimestamp(): string | undefined {\n if (this.rows.length === 0) return undefined;\n return this.rows[this.rows.length - 1]!.Timestamp;\n }\n\n get size(): number {\n return this.rows.length;\n }\n\n clear(): void {\n this.rows = [];\n this.keys.clear();\n }\n}\n","import { useState, useRef, useCallback, useEffect } from \"react\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport type { denormalizedSignals, dataFilterSchemas } from \"@kopai/core\";\nimport { useKopaiSDK } from \"../providers/kopai-provider.js\";\nimport { LogBuffer } from \"../lib/log-buffer.js\";\n\ntype OtelLogsRow = denormalizedSignals.OtelLogsRow;\ntype LogsDataFilter = dataFilterSchemas.LogsDataFilter;\n\nexport interface UseLiveLogsOptions {\n params: LogsDataFilter;\n pollIntervalMs?: number;\n maxLogs?: number;\n enabled?: boolean;\n}\n\nexport interface UseLiveLogsResult {\n logs: OtelLogsRow[];\n isLive: boolean;\n totalReceived: number;\n loading: boolean;\n error: Error | null;\n setLive: (live: boolean) => void;\n}\n\nexport function useLiveLogs({\n params,\n pollIntervalMs = 3_000,\n maxLogs = 1_000,\n enabled = true,\n}: UseLiveLogsOptions): UseLiveLogsResult {\n const client = useKopaiSDK();\n const bufferRef = useRef(new LogBuffer(maxLogs));\n const [version, setVersion] = useState(0);\n const [isLive, setIsLiveState] = useState(true);\n const totalReceivedRef = useRef(0);\n const hasFetchedOnce = useRef(false);\n\n // Reset buffer when params change so stale data from a previous filter\n // doesn't persist while the new query is in flight.\n const paramsKey = JSON.stringify(params);\n const prevParamsKey = useRef(paramsKey);\n useEffect(() => {\n if (prevParamsKey.current !== paramsKey) {\n prevParamsKey.current = paramsKey;\n bufferRef.current.clear();\n hasFetchedOnce.current = false;\n totalReceivedRef.current = 0;\n setVersion((v) => v + 1);\n }\n }, [paramsKey]);\n\n const { isFetching, error, refetch } = useQuery<\n { data: OtelLogsRow[]; nextCursor: string | null },\n Error\n >({\n queryKey: [\"live-logs\", params],\n queryFn: async ({ signal }) => {\n const fetchParams: LogsDataFilter = { ...params };\n\n // If params changed since queryFn was scheduled, treat as first fetch\n if (prevParamsKey.current !== JSON.stringify(params)) {\n hasFetchedOnce.current = false;\n }\n\n // After first fetch, only get newer logs\n if (hasFetchedOnce.current) {\n const newest = bufferRef.current.getNewestTimestamp();\n if (newest) {\n // Add 1ns to avoid re-fetching the same row\n fetchParams.timestampMin = String(BigInt(newest) + 1n);\n }\n }\n\n const result = await client.searchLogsPage(fetchParams, { signal });\n hasFetchedOnce.current = true;\n\n if (result.data.length > 0) {\n totalReceivedRef.current += result.data.length;\n bufferRef.current.merge(result.data);\n setVersion((v) => v + 1);\n }\n\n return result;\n },\n enabled: enabled,\n refetchInterval: isLive ? pollIntervalMs : false,\n });\n\n const setLive = useCallback(\n (live: boolean) => {\n setIsLiveState(live);\n if (live) {\n // Immediate refetch on resume\n refetch();\n }\n },\n [refetch]\n );\n\n // Read buffer (version forces re-render)\n void version;\n const logs = bufferRef.current.getAll();\n\n return {\n logs,\n isLive,\n totalReceived: totalReceivedRef.current,\n loading: isFetching,\n error: error ?? null,\n setLive,\n };\n}\n","import { z } from \"zod\";\nimport { dataFilterSchemas } from \"@kopai/core\";\nimport type { ReactNode } from \"react\";\n\n// DataSource schema - discriminated union with type-safe params per method\nexport const dataSourceSchema = z.discriminatedUnion(\"method\", [\n z.object({\n method: z.literal(\"searchTracesPage\"),\n params: dataFilterSchemas.tracesDataFilterSchema,\n refetchIntervalMs: z.number().optional(),\n }),\n z.object({\n method: z.literal(\"searchLogsPage\"),\n params: dataFilterSchemas.logsDataFilterSchema,\n refetchIntervalMs: z.number().optional(),\n }),\n z.object({\n method: z.literal(\"searchMetricsPage\"),\n params: dataFilterSchemas.metricsDataFilterSchema,\n refetchIntervalMs: z.number().optional(),\n }),\n z.object({\n method: z.literal(\"getTrace\"),\n params: z.object({ traceId: z.string() }),\n refetchIntervalMs: z.number().optional(),\n }),\n z.object({\n method: z.literal(\"discoverMetrics\"),\n params: z.object({}).optional(),\n refetchIntervalMs: z.number().optional(),\n }),\n]);\n\nexport type DataSource = z.infer<typeof dataSourceSchema>;\n\nexport const componentDefinitionSchema = z\n .object({\n hasChildren: z.boolean(),\n description: z\n .string()\n .describe(\n \"Component description to be displayed by the prompt generator\"\n ),\n props: z.unknown(),\n })\n .describe(\n \"All options and properties necessary to render the React component with renderer\"\n );\n\nexport const catalogConfigSchema = z.object({\n name: z.string().describe(\"catalog name\"),\n components: z.record(\n z.string().describe(\"React component name\"),\n componentDefinitionSchema\n ),\n});\n\n// Union of all element types with literal type discriminator\nexport type InferredElement<C extends Record<string, { props: unknown }>> = {\n [K in keyof C & string]: {\n key: string;\n type: K;\n children: string[];\n parentKey: string;\n dataSource?: z.infer<typeof dataSourceSchema>;\n props: C[K][\"props\"] extends z.ZodTypeAny\n ? z.infer<C[K][\"props\"]>\n : unknown;\n };\n}[keyof C & string];\n\n// Zod schema type for a single element variant (preserves K-to-props mapping)\ntype ElementVariantSchema<\n K extends string,\n Props extends z.ZodTypeAny,\n> = z.ZodObject<{\n key: z.ZodString;\n type: z.ZodLiteral<K>;\n children: z.ZodArray<z.ZodString>;\n parentKey: z.ZodString;\n dataSource: z.ZodOptional<typeof dataSourceSchema>;\n props: Props;\n}>;\n\n// Union of all element variant schemas\ntype ElementVariantSchemas<C extends Record<string, { props: unknown }>> = {\n [K in keyof C & string]: ElementVariantSchema<\n K,\n C[K][\"props\"] extends z.ZodTypeAny ? C[K][\"props\"] : z.ZodUnknown\n >;\n}[keyof C & string];\n\n/**\n * Creates a component catalog with typed UI tree schema for validation.\n *\n * @param catalogConfig - Catalog configuration with name and component definitions\n * @returns Catalog object with name, components, and generated uiTreeSchema\n *\n * @example\n * ```ts\n * const catalog = createCatalog({\n * name: \"my-catalog\",\n * components: {\n * Card: {\n * hasChildren: true,\n * description: \"Container card\",\n * props: z.object({ title: z.string() }),\n * },\n * },\n * });\n * ```\n */\nexport function createCatalog<\n C extends Record<string, z.infer<typeof componentDefinitionSchema>>,\n>(catalogConfig: { name: string; components: C }) {\n const elementVariants = (\n Object.keys(catalogConfig.components) as (keyof C & string)[]\n )\n .map((catalogItemName) => ({\n catalogItemName,\n component: catalogConfig.components[catalogItemName],\n }))\n .filter(\n (\n itemConfig\n ): itemConfig is typeof itemConfig & { component: C[keyof C] } =>\n !!itemConfig.component\n )\n .map(({ catalogItemName, component }) =>\n z.object({\n key: z.string(),\n type: z.literal(catalogItemName),\n children: z.array(z.string()),\n parentKey: z.string(),\n dataSource: dataSourceSchema.optional(),\n props: component.props,\n })\n );\n\n type Schemas = ElementVariantSchemas<C>;\n const elementsUnion = z.discriminatedUnion(\n \"type\",\n elementVariants as unknown as [Schemas, ...Schemas[]]\n );\n\n // TODO: implement a mechanism for validating there are no circular references\n const uiTreeSchema = z.object({\n root: z.string().describe(\"root uiElement key in the elements array\"),\n elements: z.record(\n z.string().describe(\"equal to the element key\"),\n elementsUnion\n ),\n });\n\n return {\n name: catalogConfig.name,\n components: catalogConfig.components,\n uiTreeSchema,\n };\n}\n\nexport type ComponentDefinition = z.infer<typeof componentDefinitionSchema>;\n\nexport type InferProps<P> = P extends z.ZodTypeAny ? z.infer<P> : P;\n\nexport type CatalogueComponentProps<CD extends ComponentDefinition> =\n CD extends { hasChildren: true; props: infer P }\n ? { element: { props: InferProps<P> }; children: ReactNode }\n : CD extends { props: infer P }\n ? { element: { props: InferProps<P> } }\n : never;\n","import { createCatalog } from \"./component-catalog.js\";\nimport { z } from \"zod\";\n\nexport const observabilityCatalog = createCatalog({\n name: \"observability\",\n components: {\n // Layout Components\n Card: {\n props: z.object({\n title: z.string().nullable(),\n description: z.string().nullable(),\n padding: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n }),\n hasChildren: true,\n description: \"A card container with optional title\",\n },\n\n Grid: {\n props: z.object({\n columns: z.number().min(1).max(4).nullable(),\n gap: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n }),\n hasChildren: true,\n description: \"Grid layout with configurable columns\",\n },\n\n Stack: {\n props: z.object({\n direction: z.enum([\"horizontal\", \"vertical\"]).nullable(),\n gap: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n align: z.enum([\"start\", \"center\", \"end\", \"stretch\"]).nullable(),\n }),\n hasChildren: true,\n description: \"Flex stack for horizontal or vertical layouts\",\n },\n\n // Typography\n Heading: {\n props: z.object({\n text: z.string(),\n level: z.enum([\"h1\", \"h2\", \"h3\", \"h4\"]).nullable(),\n }),\n hasChildren: false,\n description: \"Section heading\",\n },\n\n Text: {\n props: z.object({\n content: z.string(),\n variant: z.enum([\"body\", \"caption\", \"label\"]).nullable(),\n color: z\n .enum([\"default\", \"muted\", \"success\", \"warning\", \"danger\"])\n .nullable(),\n }),\n hasChildren: false,\n description: \"Text paragraph\",\n },\n\n // Status Components\n Badge: {\n props: z.object({\n text: z.string(),\n variant: z\n .enum([\"default\", \"success\", \"warning\", \"danger\", \"info\"])\n .nullable(),\n }),\n hasChildren: false,\n description: \"Small status badge\",\n },\n\n Divider: {\n props: z.object({\n label: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Visual divider\",\n },\n\n Empty: {\n props: z.object({\n title: z.string(),\n description: z.string().nullable(),\n action: z.string().nullable(),\n actionLabel: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Empty state placeholder\",\n },\n\n // Observability Components\n LogTimeline: {\n props: z.object({ height: z.number().nullable() }),\n hasChildren: false,\n description:\n \"Log timeline with virtual scroll, severity filtering, detail pane\",\n },\n\n TraceDetail: {\n props: z.object({ height: z.number().nullable() }),\n hasChildren: false,\n description:\n \"Trace detail with traceId input field and waterfall timeline\",\n },\n\n MetricTimeSeries: {\n props: z.object({\n height: z.number().nullable(),\n showBrush: z.boolean().nullable(),\n yAxisLabel: z.string().nullable(),\n unit: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Time series line chart for Gauge/Sum metrics\",\n },\n\n MetricHistogram: {\n props: z.object({\n height: z.number().nullable(),\n yAxisLabel: z.string().nullable(),\n unit: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Histogram bar chart for distribution metrics\",\n },\n\n MetricStat: {\n props: z.object({\n label: z.string().nullable(),\n showSparkline: z.boolean().nullable(),\n }),\n hasChildren: false,\n description:\n \"Single metric KPI card with sparkline and threshold coloring\",\n },\n\n MetricTable: {\n props: z.object({ maxRows: z.number().nullable() }),\n hasChildren: false,\n description: \"Tabular display of metric data points\",\n },\n\n MetricDiscovery: {\n props: z.object({}),\n hasChildren: false,\n description:\n \"Table of discovered metric names, types, units and descriptions\",\n },\n },\n});\n","export interface Tab {\n key: string;\n label: string;\n shortcutKey?: string;\n}\n\nexport interface TabBarProps {\n tabs: Tab[];\n active: string;\n onChange: (key: string) => void;\n}\n\nfunction renderLabel(label: string, shortcutKey?: string) {\n if (!shortcutKey) return label;\n const idx = label.toLowerCase().indexOf(shortcutKey.toLowerCase());\n if (idx === -1) return label;\n return (\n <>\n {label.slice(0, idx)}\n <span className=\"underline underline-offset-4\">{label[idx]}</span>\n {label.slice(idx + 1)}\n </>\n );\n}\n\nexport function TabBar({ tabs, active, onChange }: TabBarProps) {\n return (\n <div role=\"tablist\" className=\"flex border-b border-border mb-6\">\n {tabs.map((t) => (\n <button\n key={t.key}\n role=\"tab\"\n aria-selected={active === t.key}\n onClick={() => onChange(t.key)}\n className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${\n active === t.key\n ? \"border-foreground text-foreground\"\n : \"border-transparent text-muted-foreground hover:text-foreground\"\n }`}\n >\n {renderLabel(t.label, t.shortcutKey)}\n </button>\n ))}\n </div>\n );\n}\n","/**\n * Color palette utilities for trace visualization\n * Generates consistent colors for service names using HSL color space\n */\n\nfunction hashString(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n }\n return Math.abs(hash);\n}\n\nexport function getServiceColor(serviceName: string): string {\n const hash = hashString(serviceName);\n const hue = hash % 360;\n const saturation = 70;\n const lightness = 50;\n return `hsl(${hue}, ${saturation}%, ${lightness}%)`;\n}\n\nexport const ERROR_COLOR = \"#ef4444\";\n\nexport function getSpanBarColor(serviceName: string, isError: boolean): string {\n if (isError) {\n return ERROR_COLOR;\n }\n return getServiceColor(serviceName);\n}\n","import { getServiceColor } from \"../utils/colors.js\";\n\nexport interface ServiceEntry {\n name: string;\n}\n\nexport interface ServiceListProps {\n services: ServiceEntry[];\n isLoading?: boolean;\n error?: Error;\n onSelect: (name: string) => void;\n}\n\nexport function ServiceList({\n services,\n isLoading,\n error,\n onSelect,\n}: ServiceListProps) {\n if (isLoading) {\n return (\n <div className=\"flex items-center gap-2 text-muted-foreground py-8\">\n <div className=\"w-4 h-4 border-2 border-muted-foreground border-t-transparent rounded-full animate-spin\" />\n Loading services...\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"text-red-400 py-4\">\n Error loading services: {error.message}\n </div>\n );\n }\n\n if (services.length === 0) {\n return <div className=\"text-muted-foreground py-8\">No services found</div>;\n }\n\n return (\n <div className=\"space-y-1\">\n {services.map((svc) => (\n <button\n key={svc.name}\n onClick={() => onSelect(svc.name)}\n className=\"w-full text-left px-4 py-3 rounded-lg border border-border hover:border-foreground/30 hover:bg-muted/50 transition-colors group\"\n >\n <span className=\"flex items-center gap-2 font-medium text-foreground\">\n <span\n className=\"inline-block w-2.5 h-2.5 rounded-full shrink-0\"\n style={{ backgroundColor: getServiceColor(svc.name) }}\n />\n {svc.name}\n </span>\n </button>\n ))}\n </div>\n );\n}\n","/**\n * Time formatting utilities for trace visualization\n */\n\nexport function formatDuration(durationMs: number): string {\n if (durationMs < 1) {\n const microseconds = durationMs * 1000;\n return `${microseconds.toFixed(2)}μs`;\n } else if (durationMs < 1000) {\n return `${durationMs.toFixed(2)}ms`;\n } else {\n const seconds = durationMs / 1000;\n return `${seconds.toFixed(2)}s`;\n }\n}\n\nexport function formatTimestamp(timestampMs: number): string {\n const date = new Date(timestampMs);\n return date.toLocaleString(\"en-US\", {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n timeZoneName: \"short\",\n });\n}\n\nexport function calculateRelativeTime(\n timeMs: number,\n minTimeMs: number,\n maxTimeMs: number\n): number {\n const totalDuration = maxTimeMs - minTimeMs;\n if (totalDuration === 0) return 0;\n return (timeMs - minTimeMs) / totalDuration;\n}\n\nexport function calculateRelativeDuration(\n durationMs: number,\n totalDurationMs: number\n): number {\n if (totalDurationMs === 0) return 0;\n return durationMs / totalDurationMs;\n}\n","import { useState } from \"react\";\nimport { formatDuration, formatTimestamp } from \"../utils/time.js\";\nimport { getServiceColor } from \"../utils/colors.js\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport interface TraceSummary {\n traceId: string;\n rootSpanName: string;\n serviceName: string;\n durationMs: number;\n statusCode: string;\n timestampMs: number;\n spanCount: number;\n services: { name: string; count: number; hasError: boolean }[];\n errorCount: number;\n}\n\nexport interface TraceSearchFilters {\n operation?: string;\n lookbackMs?: number;\n minDuration?: string;\n maxDuration?: string;\n limit: number;\n}\n\nexport interface TraceSearchProps {\n service: string;\n traces: TraceSummary[];\n operations?: string[];\n isLoading?: boolean;\n error?: Error;\n onSelectTrace: (traceId: string) => void;\n onBack: () => void;\n onSearch?: (filters: TraceSearchFilters) => void;\n}\n\n// ---------------------------------------------------------------------------\n// Lookback presets\n// ---------------------------------------------------------------------------\n\nconst LOOKBACK_OPTIONS = [\n { label: \"Last 5 Minutes\", ms: 5 * 60_000 },\n { label: \"Last 15 Minutes\", ms: 15 * 60_000 },\n { label: \"Last 30 Minutes\", ms: 30 * 60_000 },\n { label: \"Last 1 Hour\", ms: 60 * 60_000 },\n { label: \"Last 2 Hours\", ms: 2 * 60 * 60_000 },\n { label: \"Last 6 Hours\", ms: 6 * 60 * 60_000 },\n { label: \"Last 12 Hours\", ms: 12 * 60 * 60_000 },\n { label: \"Last 24 Hours\", ms: 24 * 60 * 60_000 },\n] as const;\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function TraceSearch({\n service,\n traces,\n operations = [],\n isLoading,\n error,\n onSelectTrace,\n onBack,\n onSearch,\n}: TraceSearchProps) {\n const [operation, setOperation] = useState(\"all\");\n const [lookbackIdx, setLookbackIdx] = useState<number>(-1);\n const [minDuration, setMinDuration] = useState(\"\");\n const [maxDuration, setMaxDuration] = useState(\"\");\n const [limit, setLimit] = useState(20);\n const [filtersOpen, setFiltersOpen] = useState(true);\n\n const handleFindTraces = () => {\n onSearch?.({\n operation: operation !== \"all\" ? operation : undefined,\n lookbackMs:\n lookbackIdx >= 0 ? LOOKBACK_OPTIONS[lookbackIdx]!.ms : undefined,\n minDuration: minDuration || undefined,\n maxDuration: maxDuration || undefined,\n limit,\n });\n };\n\n return (\n <div>\n {/* Breadcrumb */}\n <div className=\"flex items-center gap-1.5 text-sm text-muted-foreground mb-4\">\n <button\n onClick={onBack}\n className=\"hover:text-foreground transition-colors\"\n >\n Services\n </button>\n <span>/</span>\n <span className=\"text-foreground\">{service}</span>\n </div>\n\n {/* Filter panel */}\n {onSearch && (\n <div className=\"border border-border rounded-lg mb-4\">\n <button\n onClick={() => setFiltersOpen((v) => !v)}\n className=\"w-full flex items-center justify-between px-4 py-2.5 text-sm font-medium text-foreground hover:bg-muted/30 transition-colors\"\n >\n <span>Filters</span>\n <span className=\"text-muted-foreground text-xs\">\n {filtersOpen ? \"▲\" : \"▼\"}\n </span>\n </button>\n {filtersOpen && (\n <div className=\"px-4 pb-4 pt-1 border-t border-border space-y-3\">\n <div className=\"grid grid-cols-2 md:grid-cols-3 gap-3\">\n {/* Operation */}\n <label className=\"space-y-1\">\n <span className=\"text-xs text-muted-foreground\">\n Operation\n </span>\n <select\n value={operation}\n onChange={(e) => setOperation(e.target.value)}\n className=\"w-full bg-muted/50 border border-border rounded px-2 py-1.5 text-sm text-foreground\"\n >\n <option value=\"all\">All</option>\n {operations.map((op) => (\n <option key={op} value={op}>\n {op}\n </option>\n ))}\n </select>\n </label>\n\n {/* Lookback */}\n <label className=\"space-y-1\">\n <span className=\"text-xs text-muted-foreground\">\n Lookback\n </span>\n <select\n value={lookbackIdx}\n onChange={(e) => setLookbackIdx(Number(e.target.value))}\n className=\"w-full bg-muted/50 border border-border rounded px-2 py-1.5 text-sm text-foreground\"\n >\n <option value={-1}>All time</option>\n {LOOKBACK_OPTIONS.map((opt, i) => (\n <option key={i} value={i}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n\n {/* Limit */}\n <label className=\"space-y-1\">\n <span className=\"text-xs text-muted-foreground\">Limit</span>\n <input\n type=\"number\"\n min={1}\n max={1000}\n value={limit}\n onChange={(e) => {\n const n = Number(e.target.value);\n setLimit(\n Number.isNaN(n) ? 20 : Math.max(1, Math.min(1000, n))\n );\n }}\n className=\"w-full bg-muted/50 border border-border rounded px-2 py-1.5 text-sm text-foreground\"\n />\n </label>\n\n {/* Min Duration */}\n <label className=\"space-y-1\">\n <span className=\"text-xs text-muted-foreground\">\n Min Duration\n </span>\n <input\n type=\"text\"\n placeholder=\"e.g. 100ms\"\n value={minDuration}\n onChange={(e) => setMinDuration(e.target.value)}\n className=\"w-full bg-muted/50 border border-border rounded px-2 py-1.5 text-sm text-foreground placeholder:text-muted-foreground/50\"\n />\n </label>\n\n {/* Max Duration */}\n <label className=\"space-y-1\">\n <span className=\"text-xs text-muted-foreground\">\n Max Duration\n </span>\n <input\n type=\"text\"\n placeholder=\"e.g. 5s\"\n value={maxDuration}\n onChange={(e) => setMaxDuration(e.target.value)}\n className=\"w-full bg-muted/50 border border-border rounded px-2 py-1.5 text-sm text-foreground placeholder:text-muted-foreground/50\"\n />\n </label>\n </div>\n\n <button\n onClick={handleFindTraces}\n className=\"px-4 py-1.5 text-sm font-medium bg-foreground text-background rounded hover:bg-foreground/90 transition-colors\"\n >\n Find Traces\n </button>\n </div>\n )}\n </div>\n )}\n\n {/* Results */}\n {isLoading && (\n <div className=\"flex items-center gap-2 text-muted-foreground py-8\">\n <div className=\"w-4 h-4 border-2 border-muted-foreground border-t-transparent rounded-full animate-spin\" />\n Loading traces...\n </div>\n )}\n\n {error && (\n <div className=\"text-red-400 py-4\">\n Error loading traces: {error.message}\n </div>\n )}\n\n {!isLoading && !error && traces.length === 0 && (\n <div className=\"text-muted-foreground py-8\">\n No traces found for {service}\n </div>\n )}\n\n {traces.length > 0 && (\n <div className=\"space-y-2\">\n {traces.map((t) => (\n <div\n key={t.traceId}\n onClick={() => onSelectTrace(t.traceId)}\n className=\"border border-border rounded-lg px-4 py-3 hover:border-foreground/30 hover:bg-muted/30 cursor-pointer transition-colors\"\n >\n {/* Title line */}\n <div className=\"flex items-baseline justify-between gap-2\">\n <div className=\"flex items-baseline gap-1.5 min-w-0\">\n <span className=\"font-medium text-foreground truncate\">\n {t.serviceName}: {t.rootSpanName}\n </span>\n <span className=\"text-xs font-mono text-muted-foreground shrink-0\">\n {t.traceId.slice(0, 7)}\n </span>\n </div>\n <span className=\"text-sm text-foreground/80 shrink-0\">\n {formatDuration(t.durationMs)}\n </span>\n </div>\n\n {/* Tags line */}\n <div className=\"flex items-center flex-wrap gap-1.5 mt-1.5\">\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-muted text-muted-foreground\">\n {t.spanCount} Span{t.spanCount !== 1 ? \"s\" : \"\"}\n </span>\n {t.errorCount > 0 && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-red-500/20 text-red-400\">\n {t.errorCount} Error{t.errorCount !== 1 ? \"s\" : \"\"}\n </span>\n )}\n {t.services.map((svc) => (\n <span\n key={svc.name}\n className=\"inline-flex items-center gap-1 text-xs px-1.5 py-0.5 rounded\"\n style={{\n backgroundColor: `${getServiceColor(svc.name)}20`,\n color: getServiceColor(svc.name),\n }}\n >\n {svc.hasError && (\n <span className=\"w-1.5 h-1.5 rounded-full bg-red-500 shrink-0\" />\n )}\n {svc.name} ({svc.count})\n </span>\n ))}\n </div>\n\n {/* Timestamp */}\n <div className=\"text-xs text-muted-foreground mt-1 text-right\">\n {formatTimestamp(t.timestampMs)}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n","/**\n * Tree flattening utilities for virtual scrolling\n */\n\nimport type { SpanNode } from \"../types.js\";\n\nexport interface FlattenedSpan {\n span: SpanNode;\n level: number;\n}\n\nexport function flattenTree(\n rootSpans: SpanNode[],\n collapsedIds: Set<string>\n): FlattenedSpan[] {\n const result: FlattenedSpan[] = [];\n\n function traverse(span: SpanNode, level: number) {\n result.push({ span, level });\n if (!collapsedIds.has(span.spanId)) {\n span.children.forEach((child) => traverse(child, level + 1));\n }\n }\n\n rootSpans.forEach((root) => traverse(root, 0));\n return result;\n}\n\nexport function getAllDescendantIds(span: SpanNode): string[] {\n const ids: string[] = [span.spanId];\n\n function traverse(s: SpanNode) {\n s.children.forEach((child) => {\n ids.push(child.spanId);\n traverse(child);\n });\n }\n\n traverse(span);\n return ids;\n}\n\nexport function getAllSpanIds(rootSpans: SpanNode[]): string[] {\n const ids: string[] = [];\n\n function traverse(span: SpanNode) {\n ids.push(span.spanId);\n span.children.forEach((child) => traverse(child));\n }\n\n rootSpans.forEach((root) => traverse(root));\n return ids;\n}\n","import { useState } from \"react\";\nimport type { ParsedTrace } from \"../types.js\";\nimport { formatDuration, formatTimestamp } from \"../utils/time.js\";\n\nexport interface TraceHeaderProps {\n trace: ParsedTrace;\n}\n\nexport function TraceHeader({ trace }: TraceHeaderProps) {\n const [copied, setCopied] = useState(false);\n\n const rootSpan = trace.rootSpans[0];\n const rootServiceName = rootSpan?.serviceName ?? \"unknown\";\n const rootSpanName = rootSpan?.name ?? \"unknown\";\n const totalDuration = trace.maxTimeMs - trace.minTimeMs;\n\n const handleCopyTraceId = async () => {\n try {\n await navigator.clipboard.writeText(trace.traceId);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch (err) {\n console.error(\"Failed to copy trace ID:\", err);\n }\n };\n\n return (\n <div className=\"bg-background border-b border-border px-4 py-3\">\n <div className=\"flex items-center gap-6 flex-wrap\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n Trace ID:\n </span>\n <button\n onClick={handleCopyTraceId}\n className=\"text-sm font-mono bg-muted px-2 py-1 rounded hover:bg-muted/80 transition-colors text-foreground\"\n title=\"Click to copy\"\n >\n {trace.traceId.slice(0, 16)}...\n </button>\n {copied && (\n <span className=\"text-xs text-green-600 dark:text-green-400 font-medium\">\n Copied!\n </span>\n )}\n </div>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n Root:\n </span>\n <span className=\"text-sm\">\n <span className=\"text-muted-foreground\">{rootServiceName}</span>\n <span className=\"mx-1 text-muted-foreground/70\">/</span>\n <span className=\"font-medium text-foreground\">{rootSpanName}</span>\n </span>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n Duration:\n </span>\n <span className=\"text-sm font-medium text-foreground\">\n {formatDuration(totalDuration)}\n </span>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n Spans:\n </span>\n <span className=\"text-sm font-medium text-foreground\">\n {trace.totalSpanCount}\n </span>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs font-semibold text-muted-foreground\">\n Started:\n </span>\n <span className=\"text-sm text-foreground\">\n {formatTimestamp(trace.minTimeMs)}\n </span>\n </div>\n </div>\n </div>\n );\n}\n","import { useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nexport interface TooltipProps {\n content: string;\n children: React.ReactNode;\n}\n\nexport function Tooltip({ content, children }: TooltipProps) {\n const [isVisible, setIsVisible] = useState(false);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n\n const handleMouseMove = (e: React.MouseEvent) => {\n setPosition({ x: e.clientX + 5, y: e.clientY + 5 });\n };\n\n return (\n <>\n <div\n onMouseEnter={() => setIsVisible(true)}\n onMouseLeave={() => setIsVisible(false)}\n onMouseMove={handleMouseMove}\n className=\"inline-block\"\n >\n {children}\n </div>\n {isVisible &&\n createPortal(\n <div\n className=\"fixed z-50 px-2 py-1 text-xs text-primary-foreground bg-primary rounded shadow-lg pointer-events-none whitespace-pre-line\"\n style={{\n left: `${position.x}px`,\n top: `${position.y}px`,\n }}\n >\n {content}\n </div>,\n document.body\n )}\n </>\n );\n}\n","import type { SpanNode } from \"../types.js\";\nimport { getSpanBarColor } from \"../utils/colors.js\";\nimport { formatDuration } from \"../utils/time.js\";\nimport { Tooltip } from \"./Tooltip.js\";\n\nexport interface TimelineBarProps {\n span: SpanNode;\n relativeStart: number;\n relativeDuration: number;\n}\n\nexport function TimelineBar({\n span,\n relativeStart,\n relativeDuration,\n}: TimelineBarProps) {\n const isError = span.status === \"ERROR\";\n const barColor = getSpanBarColor(span.serviceName, isError);\n\n const leftPercent = relativeStart * 100;\n const widthPercent = Math.max(0.2, relativeDuration * 100);\n\n const tooltipText = `${span.name}\\n${formatDuration(span.durationMs)}\\nStatus: ${isError ? \"ERROR\" : \"OK\"}`;\n\n return (\n <div className=\"relative h-full\">\n <Tooltip content={tooltipText}>\n <div className=\"absolute inset-0\">\n <div\n className=\"absolute top-1/2 -translate-y-1/2 h-2 rounded-sm cursor-pointer hover:opacity-80 transition-opacity\"\n style={{\n left: `${leftPercent}%`,\n width: `max(2px, ${widthPercent}%)`,\n backgroundColor: barColor,\n }}\n />\n </div>\n </Tooltip>\n </div>\n );\n}\n","import { memo } from \"react\";\nimport type { SpanNode } from \"../types.js\";\nimport { TimelineBar } from \"./TimelineBar.js\";\nimport { formatDuration } from \"../utils/time.js\";\n\nexport interface SpanRowProps {\n span: SpanNode;\n level: number;\n isCollapsed: boolean;\n isSelected: boolean;\n isHovered?: boolean;\n isParentOfHovered?: boolean;\n relativeStart: number;\n relativeDuration: number;\n onClick: () => void;\n onToggleCollapse: () => void;\n onMouseEnter?: () => void;\n onMouseLeave?: () => void;\n}\n\nfunction getHttpContext(span: SpanNode): string | null {\n const attrs = span.attributes;\n const method = attrs[\"http.method\"];\n const url = attrs[\"http.url\"] || attrs[\"http.target\"];\n const statusCode = attrs[\"http.status_code\"];\n\n if (!method && !url) return null;\n\n const parts: string[] = [];\n if (method) parts.push(String(method));\n if (url) parts.push(String(url));\n if (statusCode) parts.push(`[${statusCode}]`);\n\n return parts.join(\" \");\n}\n\nexport const SpanRow = memo(function SpanRow({\n span,\n level,\n isCollapsed,\n isSelected,\n isParentOfHovered = false,\n relativeStart,\n relativeDuration,\n onClick,\n onToggleCollapse,\n onMouseEnter,\n onMouseLeave,\n}: SpanRowProps) {\n const hasChildren = span.children.length > 0;\n const isError = span.status === \"ERROR\";\n const httpContext = getHttpContext(span);\n\n return (\n <div\n className={`flex h-8 border-b border-border hover:bg-muted cursor-pointer ${\n isSelected\n ? \"bg-blue-100 dark:bg-blue-900/30 hover:bg-blue-100 dark:hover:bg-blue-900/30\"\n : \"\"\n }`}\n onClick={onClick}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n role=\"treeitem\"\n aria-expanded={hasChildren ? !isCollapsed : undefined}\n aria-selected={isSelected}\n aria-label={`${span.name}, ${span.serviceName}, ${formatDuration(span.durationMs)}${isError ? \", error\" : \"\"}`}\n aria-level={level + 1}\n >\n {/* Left side: Service name + span name with indentation */}\n <div className=\"flex items-center min-w-0 flex-shrink-0 w-96 px-2 relative z-10\">\n {Array.from({ length: level }).map((_, i) => (\n <div\n key={i}\n className={`w-4 h-full border-l flex-shrink-0 ${\n isParentOfHovered ? \"border-blue-500 border-l-2\" : \"border-border\"\n }`}\n />\n ))}\n\n {hasChildren ? (\n <button\n className=\"w-4 h-4 flex items-center justify-center flex-shrink-0 text-muted-foreground hover:text-foreground\"\n onClick={(e) => {\n e.stopPropagation();\n onToggleCollapse();\n }}\n aria-label={isCollapsed ? \"Expand\" : \"Collapse\"}\n >\n {isCollapsed ? (\n <svg\n className=\"w-3 h-3\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 5l7 7-7 7\"\n />\n </svg>\n ) : (\n <svg\n className=\"w-3 h-3\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n )}\n </button>\n ) : (\n <div className=\"w-4 flex-shrink-0\" />\n )}\n\n {isError && (\n <svg\n className=\"w-4 h-4 text-red-500 flex-shrink-0 mr-1\"\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\"\n clipRule=\"evenodd\"\n />\n </svg>\n )}\n\n <span className=\"text-xs text-muted-foreground flex-shrink-0 mr-2\">\n {span.serviceName}\n </span>\n\n <span className=\"text-sm font-medium truncate flex-1 min-w-0 text-foreground\">\n {span.name}\n </span>\n\n {hasChildren && (\n <span className=\"text-xs text-muted-foreground flex-shrink-0 ml-1\">\n ({span.children.length})\n </span>\n )}\n\n {httpContext && (\n <span className=\"text-xs text-muted-foreground truncate ml-2 flex-shrink-0 max-w-xs\">\n {httpContext}\n </span>\n )}\n\n <span className=\"text-xs text-muted-foreground flex-shrink-0 ml-2\">\n {formatDuration(span.durationMs)}\n </span>\n </div>\n\n {/* Right side: Timeline bar */}\n <div className=\"flex-1 min-w-0 px-2\">\n <TimelineBar\n span={span}\n relativeStart={relativeStart}\n relativeDuration={relativeDuration}\n />\n </div>\n </div>\n );\n});\n","export function formatAttributeValue(value: unknown): string {\n if (value === null || value === undefined) return \"null\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"boolean\" || typeof value === \"number\")\n return String(value);\n if (Array.isArray(value) || typeof value === \"object\")\n return JSON.stringify(value, null, 2);\n return String(value);\n}\n\nexport function formatSeriesLabel(labels: Record<string, string>): string {\n const entries = Object.entries(labels);\n if (entries.length === 0) return \"\";\n if (entries.length === 1) return String(entries[0]![1]);\n return entries.map(([k, v]) => `${k}=${v}`).join(\", \");\n}\n\nexport function isComplexValue(value: unknown): boolean {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (Array.isArray(value) || Object.keys(value).length > 0)\n );\n}\n","import { useMemo } from \"react\";\nimport type { SpanNode } from \"../../types.js\";\nimport {\n formatAttributeValue,\n isComplexValue,\n} from \"../../utils/attributes.js\";\n\nexport interface AttributesTabProps {\n span: SpanNode;\n}\n\nconst HTTP_SEMANTIC_CONVENTIONS = new Set([\n \"http.method\",\n \"http.url\",\n \"http.status_code\",\n \"http.target\",\n \"http.host\",\n \"http.scheme\",\n \"http.route\",\n \"http.user_agent\",\n \"http.request_content_length\",\n \"http.response_content_length\",\n]);\n\nexport function AttributesTab({ span }: AttributesTabProps) {\n const { httpAttributes, otherAttributes, resourceAttributes } =\n useMemo(() => {\n const http: Array<[string, unknown]> = [];\n const other: Array<[string, unknown]> = [];\n const resource: Array<[string, unknown]> = [];\n\n if (span.attributes) {\n Object.entries(span.attributes).forEach(([key, value]) => {\n if (HTTP_SEMANTIC_CONVENTIONS.has(key)) {\n http.push([key, value]);\n } else {\n other.push([key, value]);\n }\n });\n }\n\n if (span.resourceAttributes) {\n Object.entries(span.resourceAttributes).forEach(([key, value]) => {\n resource.push([key, value]);\n });\n }\n\n http.sort(([a], [b]) => a.localeCompare(b));\n other.sort(([a], [b]) => a.localeCompare(b));\n resource.sort(([a], [b]) => a.localeCompare(b));\n\n return {\n httpAttributes: http,\n otherAttributes: other,\n resourceAttributes: resource,\n };\n }, [span]);\n\n const hasAttributes =\n httpAttributes.length > 0 ||\n otherAttributes.length > 0 ||\n resourceAttributes.length > 0;\n\n if (!hasAttributes) {\n return (\n <div className=\"text-sm text-muted-foreground text-center py-8\">\n No attributes available\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6\">\n {httpAttributes.length > 0 && (\n <section>\n <h3 className=\"text-sm font-semibold text-foreground mb-3 flex items-center\">\n <span className=\"w-2 h-2 bg-blue-500 rounded-full mr-2\" />\n HTTP Attributes\n </h3>\n <div className=\"space-y-2\">\n {httpAttributes.map(([key, value]) => (\n <AttributeRow key={key} attrKey={key} value={value} highlighted />\n ))}\n </div>\n </section>\n )}\n\n {otherAttributes.length > 0 && (\n <section>\n <h3 className=\"text-sm font-semibold text-foreground mb-3\">\n Span Attributes\n </h3>\n <div className=\"space-y-2\">\n {otherAttributes.map(([key, value]) => (\n <AttributeRow key={key} attrKey={key} value={value} />\n ))}\n </div>\n </section>\n )}\n\n {resourceAttributes.length > 0 && (\n <section>\n <h3 className=\"text-sm font-semibold text-foreground mb-3\">\n Resource Attributes\n </h3>\n <div className=\"space-y-2\">\n {resourceAttributes.map(([key, value]) => (\n <AttributeRow key={key} attrKey={key} value={value} />\n ))}\n </div>\n </section>\n )}\n </div>\n );\n}\n\ninterface AttributeRowProps {\n attrKey: string;\n value: unknown;\n highlighted?: boolean;\n}\n\nfunction AttributeRow({ attrKey, value, highlighted }: AttributeRowProps) {\n const isComplex = isComplexValue(value);\n const formattedValue = formatAttributeValue(value);\n\n return (\n <div\n className={`grid grid-cols-[minmax(150px,1fr)_2fr] gap-4 p-2 rounded text-sm ${\n highlighted\n ? \"bg-blue-50 dark:bg-blue-950 border-l-2 border-blue-500\"\n : \"bg-muted\"\n }`}\n >\n <div\n className={`font-mono font-medium break-words ${highlighted ? \"text-blue-700 dark:text-blue-300\" : \"text-foreground\"}`}\n title={attrKey}\n >\n {attrKey}\n </div>\n <div className=\"break-words\">\n {isComplex ? (\n <pre className=\"text-xs text-foreground bg-background p-2 rounded border border-border overflow-x-auto\">\n {formattedValue}\n </pre>\n ) : (\n <span className=\"text-foreground\">{formattedValue}</span>\n )}\n </div>\n </div>\n );\n}\n","import { useState } from \"react\";\nimport type { SpanNode } from \"../../types.js\";\nimport { formatDuration } from \"../../utils/time.js\";\nimport { formatAttributeValue } from \"../../utils/attributes.js\";\n\nexport interface EventsTabProps {\n span: SpanNode;\n}\n\nfunction formatRelativeTime(eventTimeMs: number, spanStartMs: number): string {\n const relativeMs = eventTimeMs - spanStartMs;\n const prefix = relativeMs < 0 ? \"-\" : \"+\";\n return `${prefix}${formatDuration(Math.abs(relativeMs))}`;\n}\n\nexport function EventsTab({ span }: EventsTabProps) {\n const [expandedEvents, setExpandedEvents] = useState<Set<number>>(new Set());\n\n const toggleEventExpanded = (index: number) => {\n setExpandedEvents((prev) => {\n const next = new Set(prev);\n if (next.has(index)) next.delete(index);\n else next.add(index);\n return next;\n });\n };\n\n if (!span.events || span.events.length === 0) {\n return (\n <div className=\"text-sm text-muted-foreground text-center py-8\">\n No events available\n </div>\n );\n }\n\n return (\n <div className=\"space-y-3\">\n {span.events.map((event, index) => {\n const isExpanded = expandedEvents.has(index);\n const hasAttributes =\n event.attributes && Object.keys(event.attributes).length > 0;\n const relativeTime = formatRelativeTime(\n event.timeUnixMs,\n span.startTimeUnixMs\n );\n\n return (\n <div\n key={index}\n className=\"border border-border rounded-lg overflow-hidden\"\n >\n <div className=\"bg-muted p-3\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"font-medium text-sm text-foreground truncate\">\n {event.name}\n </div>\n <div className=\"text-xs text-muted-foreground mt-1 font-mono\">\n {relativeTime} from span start\n </div>\n </div>\n {hasAttributes && (\n <button\n onClick={() => toggleEventExpanded(index)}\n className=\"p-1 hover:bg-muted/80 rounded transition-colors\"\n aria-label={\n isExpanded ? \"Collapse attributes\" : \"Expand attributes\"\n }\n aria-expanded={isExpanded}\n >\n <svg\n className={`w-4 h-4 text-muted-foreground transition-transform ${isExpanded ? \"rotate-180\" : \"\"}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n </button>\n )}\n </div>\n </div>\n\n {hasAttributes && isExpanded && (\n <div className=\"p-3 bg-background border-t border-border\">\n <div className=\"text-xs font-semibold text-foreground mb-2\">\n Attributes\n </div>\n <div className=\"space-y-2\">\n {Object.entries(event.attributes).map(([key, value]) => (\n <div\n key={key}\n className=\"grid grid-cols-[minmax(100px,1fr)_2fr] gap-3 text-xs\"\n >\n <div className=\"font-mono font-medium text-foreground break-words\">\n {key}\n </div>\n <div className=\"text-foreground break-words\">\n {typeof value === \"object\" ? (\n <pre className=\"text-xs bg-muted p-2 rounded border border-border overflow-x-auto\">\n {formatAttributeValue(value)}\n </pre>\n ) : (\n <span>{formatAttributeValue(value)}</span>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {!hasAttributes && (\n <div className=\"px-3 pb-3 text-xs text-muted-foreground italic\">\n No attributes\n </div>\n )}\n </div>\n );\n })}\n </div>\n );\n}\n","import { useState } from \"react\";\nimport type { SpanNode } from \"../../types.js\";\nimport { formatAttributeValue } from \"../../utils/attributes.js\";\n\nexport interface LinksTabProps {\n span: SpanNode;\n onLinkClick?: (traceId: string, spanId: string) => void;\n}\n\nfunction truncateId(id: string): string {\n return id.length > 8 ? `${id.substring(0, 8)}...` : id;\n}\n\nexport function LinksTab({ span, onLinkClick }: LinksTabProps) {\n const [expandedLinks, setExpandedLinks] = useState<Set<number>>(new Set());\n const [copiedId, setCopiedId] = useState<string | null>(null);\n\n const toggleLinkExpanded = (index: number) => {\n setExpandedLinks((prev) => {\n const next = new Set(prev);\n if (next.has(index)) next.delete(index);\n else next.add(index);\n return next;\n });\n };\n\n const copyToClipboard = async (text: string, type: string, index: number) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopiedId(`${type}-${index}-${text}`);\n setTimeout(() => setCopiedId(null), 2000);\n } catch (err) {\n console.error(\"Failed to copy:\", err);\n }\n };\n\n if (!span.links || span.links.length === 0) {\n return (\n <div className=\"text-sm text-muted-foreground text-center py-8\">\n No links available\n </div>\n );\n }\n\n return (\n <div className=\"space-y-3\">\n {span.links.map((link, index) => {\n const isExpanded = expandedLinks.has(index);\n const hasAttributes =\n link.attributes && Object.keys(link.attributes).length > 0;\n\n return (\n <div\n key={index}\n className=\"border border-border rounded-lg overflow-hidden\"\n >\n <div className=\"bg-muted p-3\">\n <div className=\"mb-2\">\n <div className=\"text-xs font-semibold text-muted-foreground mb-1\">\n Trace ID\n </div>\n <div className=\"flex items-center gap-2\">\n <code\n className=\"text-xs font-mono text-foreground bg-background px-2 py-1 rounded border border-border flex-1 truncate\"\n title={link.traceId}\n >\n {truncateId(link.traceId)}\n </code>\n <button\n onClick={() =>\n copyToClipboard(link.traceId, \"trace\", index)\n }\n className=\"p-1 hover:bg-muted/80 rounded transition-colors\"\n aria-label=\"Copy trace ID\"\n >\n <svg\n className={`w-4 h-4 ${copiedId === `trace-${index}-${link.traceId}` ? \"text-green-600\" : \"text-muted-foreground\"}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n {copiedId === `trace-${index}-${link.traceId}` ? (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n ) : (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\"\n />\n )}\n </svg>\n </button>\n </div>\n </div>\n\n <div className=\"mb-2\">\n <div className=\"text-xs font-semibold text-muted-foreground mb-1\">\n Span ID\n </div>\n <div className=\"flex items-center gap-2\">\n <code\n className=\"text-xs font-mono text-foreground bg-background px-2 py-1 rounded border border-border flex-1 truncate\"\n title={link.spanId}\n >\n {truncateId(link.spanId)}\n </code>\n <button\n onClick={() => copyToClipboard(link.spanId, \"span\", index)}\n className=\"p-1 hover:bg-muted/80 rounded transition-colors\"\n aria-label=\"Copy span ID\"\n >\n <svg\n className={`w-4 h-4 ${copiedId === `span-${index}-${link.spanId}` ? \"text-green-600\" : \"text-muted-foreground\"}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n {copiedId === `span-${index}-${link.spanId}` ? (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n ) : (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\"\n />\n )}\n </svg>\n </button>\n </div>\n </div>\n\n {onLinkClick && (\n <button\n onClick={() => onLinkClick(link.traceId, link.spanId)}\n className=\"w-full mt-2 px-3 py-2 bg-primary text-primary-foreground text-sm font-medium rounded hover:bg-primary/90 transition-colors\"\n >\n Navigate to Span\n </button>\n )}\n\n {hasAttributes && (\n <button\n onClick={() => toggleLinkExpanded(index)}\n className=\"w-full mt-2 px-3 py-1.5 text-xs text-foreground bg-background border border-border rounded hover:bg-muted transition-colors flex items-center justify-center gap-1\"\n aria-expanded={isExpanded}\n >\n <span>\n {isExpanded ? \"Hide\" : \"Show\"} Attributes (\n {Object.keys(link.attributes).length})\n </span>\n <svg\n className={`w-3 h-3 transition-transform ${isExpanded ? \"rotate-180\" : \"\"}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n </button>\n )}\n </div>\n\n {hasAttributes && isExpanded && (\n <div className=\"p-3 bg-background border-t border-border\">\n <div className=\"space-y-2\">\n {Object.entries(link.attributes).map(([key, value]) => (\n <div\n key={key}\n className=\"grid grid-cols-[minmax(100px,1fr)_2fr] gap-3 text-xs\"\n >\n <div className=\"font-mono font-medium text-foreground break-words\">\n {key}\n </div>\n <div className=\"text-foreground break-words\">\n {typeof value === \"object\" ? (\n <pre className=\"text-xs bg-muted p-2 rounded border border-border overflow-x-auto\">\n {formatAttributeValue(value)}\n </pre>\n ) : (\n <span>{formatAttributeValue(value)}</span>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n })}\n </div>\n );\n}\n","import { useState, useCallback } from \"react\";\nimport type { SpanNode } from \"../../types.js\";\nimport { AttributesTab } from \"./AttributesTab.js\";\nimport { EventsTab } from \"./EventsTab.js\";\nimport { LinksTab } from \"./LinksTab.js\";\n\nexport interface DetailPaneProps {\n span: SpanNode;\n onClose: () => void;\n onLinkClick?: (traceId: string, spanId: string) => void;\n initialTab?: \"attributes\" | \"events\" | \"links\";\n}\n\ntype TabType = \"attributes\" | \"events\" | \"links\";\n\nexport function DetailPane({\n span,\n onClose,\n onLinkClick,\n initialTab = \"attributes\",\n}: DetailPaneProps) {\n const [activeTab, setActiveTab] = useState<TabType>(initialTab);\n const [copiedId, setCopiedId] = useState(false);\n\n const handleTabChange = useCallback((tab: TabType) => {\n setActiveTab(tab);\n }, []);\n\n const handleCopySpanId = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(span.spanId);\n setCopiedId(true);\n setTimeout(() => setCopiedId(false), 2000);\n } catch (err) {\n console.error(\"Failed to copy span ID:\", err);\n }\n }, [span.spanId]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n },\n [onClose]\n );\n\n return (\n <div\n className=\"flex flex-col h-full bg-background border-l border-border\"\n onKeyDown={handleKeyDown}\n tabIndex={-1}\n role=\"complementary\"\n aria-label=\"Span details\"\n >\n {/* Header */}\n <div className=\"p-4 border-b border-border\">\n <div className=\"flex items-center justify-between mb-3\">\n <h2 className=\"text-lg font-semibold text-foreground truncate\">\n Span Details\n </h2>\n <button\n onClick={onClose}\n className=\"p-1 hover:bg-muted rounded transition-colors\"\n aria-label=\"Close detail pane\"\n title=\"Close (Esc)\"\n >\n <svg\n className=\"w-5 h-5 text-muted-foreground\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n <div className=\"mb-2\">\n <div\n className=\"text-sm font-medium text-foreground truncate\"\n title={span.name}\n >\n {span.name}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-muted-foreground\">Span ID:</span>\n <code\n className=\"text-xs font-mono text-foreground bg-muted px-2 py-1 rounded flex-1 truncate\"\n title={span.spanId}\n >\n {span.spanId}\n </code>\n <button\n onClick={handleCopySpanId}\n className=\"p-1 hover:bg-muted rounded transition-colors\"\n aria-label=\"Copy span ID\"\n >\n <svg\n className={`w-4 h-4 ${copiedId ? \"text-green-600 dark:text-green-400\" : \"text-muted-foreground\"}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n {copiedId ? (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n ) : (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\"\n />\n )}\n </svg>\n </button>\n </div>\n </div>\n\n {/* Tabs */}\n <div\n className=\"flex border-b border-border\"\n role=\"tablist\"\n aria-label=\"Span detail tabs\"\n >\n {([\"attributes\", \"events\", \"links\"] as const).map((tab) => {\n const count =\n tab === \"attributes\"\n ? Object.keys(span.attributes).length\n : tab === \"events\"\n ? span.events.length\n : span.links.length;\n return (\n <button\n key={tab}\n role=\"tab\"\n aria-selected={activeTab === tab}\n onClick={() => handleTabChange(tab)}\n className={`px-4 py-2 text-sm font-medium transition-colors ${\n activeTab === tab\n ? \"text-blue-600 dark:text-blue-400 border-b-2 border-blue-600 dark:border-blue-400\"\n : \"text-muted-foreground hover:text-foreground\"\n }`}\n >\n {tab.charAt(0).toUpperCase() + tab.slice(1)}\n {count > 0 && (\n <span className=\"ml-1 text-xs text-muted-foreground\">\n ({count})\n </span>\n )}\n </button>\n );\n })}\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-auto p-4\">\n {activeTab === \"attributes\" && <AttributesTab span={span} />}\n {activeTab === \"events\" && <EventsTab span={span} />}\n {activeTab === \"links\" && (\n <LinksTab span={span} onLinkClick={onLinkClick} />\n )}\n </div>\n </div>\n );\n}\n","export function LoadingSkeleton() {\n return (\n <div className=\"flex flex-col h-full bg-background animate-pulse\">\n <div className=\"border-b border-border p-4\">\n <div className=\"h-4 bg-muted rounded w-1/4 mb-3\"></div>\n <div className=\"flex gap-4\">\n <div className=\"h-3 bg-muted rounded w-32\"></div>\n <div className=\"h-3 bg-muted rounded w-24\"></div>\n <div className=\"h-3 bg-muted rounded w-20\"></div>\n </div>\n </div>\n <div className=\"flex-1 p-4 space-y-2\">\n {Array.from({ length: 15 }).map((_, i) => (\n <div key={i} className=\"flex items-start gap-3\">\n <div className=\"h-4 bg-muted rounded w-32\"></div>\n <div\n className=\"h-4 rounded w-16\"\n style={{\n backgroundColor:\n i % 4 === 0\n ? \"#ef4444\"\n : i % 4 === 1\n ? \"#f97316\"\n : i % 4 === 2\n ? \"#3b82f6\"\n : \"#6b7280\",\n opacity: 0.3,\n }}\n ></div>\n <div\n className=\"h-4 bg-muted rounded\"\n style={{ width: `${80 + ((i * 7) % 40)}px` }}\n ></div>\n <div\n className=\"h-4 bg-muted/80 rounded flex-1\"\n style={{ maxWidth: `${300 + ((i * 13) % 200)}px` }}\n ></div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n","import { createContext, useContext, useEffect } from \"react\";\nimport type { ShortcutGroup } from \"./types.js\";\n\ninterface KeyboardShortcutsContextValue {\n register: (id: string, group: ShortcutGroup) => void;\n unregister: (id: string) => void;\n}\n\nconst noop = () => {};\n\nexport const KeyboardShortcutsContext =\n createContext<KeyboardShortcutsContextValue>({\n register: noop,\n unregister: noop,\n });\n\nexport function useRegisterShortcuts(id: string, group: ShortcutGroup) {\n const { register, unregister } = useContext(KeyboardShortcutsContext);\n useEffect(() => {\n register(id, group);\n return () => unregister(id);\n }, [id, group, register, unregister]);\n}\n","import type { ShortcutGroup } from \"./types.js\";\n\ninterface ShortcutsHelpDialogProps {\n open: boolean;\n onClose: () => void;\n groups: ShortcutGroup[];\n}\n\nexport function ShortcutsHelpDialog({\n open,\n onClose,\n groups,\n}: ShortcutsHelpDialogProps) {\n if (!open) return null;\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n onClose();\n }\n };\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60\"\n onClick={onClose}\n onKeyDown={handleKeyDown}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Keyboard Shortcuts\"\n className=\"bg-zinc-900 border border-zinc-700 rounded-lg shadow-xl max-w-2xl w-full mx-4 max-h-[80vh] overflow-y-auto\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-zinc-700\">\n <h2 className=\"text-lg font-semibold text-zinc-100\">\n Keyboard Shortcuts\n </h2>\n <button\n onClick={onClose}\n aria-label=\"Close\"\n className=\"text-zinc-400 hover:text-zinc-200 text-xl leading-none\"\n >\n &times;\n </button>\n </div>\n <div className=\"p-6 grid grid-cols-1 sm:grid-cols-2 gap-6\">\n {groups.map((group) => (\n <div key={group.name}>\n <h3 className=\"text-sm font-medium text-zinc-400 mb-3\">\n {group.name}\n </h3>\n <ul className=\"space-y-2\">\n {group.shortcuts.map((shortcut) => (\n <li\n key={shortcut.keys.join(\"+\")}\n className=\"flex items-center justify-between text-sm\"\n >\n <span className=\"text-zinc-300\">\n {shortcut.description}\n </span>\n <span className=\"flex gap-1 ml-4\">\n {shortcut.keys.map((key) => (\n <kbd\n key={key}\n className=\"px-1.5 py-0.5 text-xs font-mono bg-zinc-800 border border-zinc-600 rounded text-zinc-300\"\n >\n {key}\n </kbd>\n ))}\n </span>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n","import { useState, useCallback, useEffect, useMemo } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { ShortcutGroup, ShortcutsRegistry } from \"./types.js\";\nimport { KeyboardShortcutsContext } from \"./context.js\";\nimport { ShortcutsHelpDialog } from \"./ShortcutsHelpDialog.js\";\n\nconst GENERAL_GROUP: ShortcutGroup = {\n name: \"General\",\n shortcuts: [\n { keys: [\"Shift\", \"?\"], description: \"Toggle shortcuts help\" },\n { keys: [\"Shift\", \"S\"], description: \"Services tab\" },\n { keys: [\"Shift\", \"L\"], description: \"Logs tab\" },\n { keys: [\"Shift\", \"M\"], description: \"Metrics tab\" },\n ],\n};\n\ninterface KeyboardShortcutsProviderProps {\n children: ReactNode;\n onNavigateServices: () => void;\n onNavigateLogs: () => void;\n onNavigateMetrics: () => void;\n}\n\nexport function KeyboardShortcutsProvider({\n children,\n onNavigateServices,\n onNavigateLogs,\n onNavigateMetrics,\n}: KeyboardShortcutsProviderProps) {\n const [registry, setRegistry] = useState<ShortcutsRegistry>(() => new Map());\n const [isOpen, setIsOpen] = useState(false);\n\n const register = useCallback((id: string, group: ShortcutGroup) => {\n setRegistry((prev) => {\n const next = new Map(prev);\n next.set(id, group);\n return next;\n });\n }, []);\n\n const unregister = useCallback((id: string) => {\n setRegistry((prev) => {\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n\n useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n const target = e.target as HTMLElement;\n if (\n target.tagName === \"INPUT\" ||\n target.tagName === \"TEXTAREA\" ||\n target.tagName === \"SELECT\" ||\n target.isContentEditable\n ) {\n return;\n }\n\n if (e.shiftKey && e.key === \"?\") {\n e.preventDefault();\n setIsOpen((v) => !v);\n return;\n }\n\n if (e.key === \"Escape\" && isOpen) {\n e.preventDefault();\n setIsOpen(false);\n return;\n }\n\n if (e.shiftKey && e.key === \"S\") {\n e.preventDefault();\n onNavigateServices();\n return;\n }\n if (e.shiftKey && e.key === \"L\") {\n e.preventDefault();\n onNavigateLogs();\n return;\n }\n if (e.shiftKey && e.key === \"M\") {\n e.preventDefault();\n onNavigateMetrics();\n return;\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, onNavigateServices, onNavigateLogs, onNavigateMetrics]);\n\n const groups = useMemo(() => {\n return [GENERAL_GROUP, ...registry.values()];\n }, [registry]);\n\n const contextValue = useMemo(\n () => ({ register, unregister }),\n [register, unregister]\n );\n\n return (\n <KeyboardShortcutsContext.Provider value={contextValue}>\n {children}\n <ShortcutsHelpDialog\n open={isOpen}\n onClose={() => setIsOpen(false)}\n groups={groups}\n />\n </KeyboardShortcutsContext.Provider>\n );\n}\n","import type { ShortcutGroup } from \"../../KeyboardShortcuts/types.js\";\n\nexport const TRACE_VIEWER_SHORTCUTS: ShortcutGroup = {\n name: \"Trace Viewer\",\n shortcuts: [\n { keys: [\"↑/K\"], description: \"Previous span\" },\n { keys: [\"↓/J\"], description: \"Next span\" },\n { keys: [\"←\"], description: \"Collapse span\" },\n { keys: [\"→\"], description: \"Expand span\" },\n { keys: [\"Enter\"], description: \"Focus detail pane\" },\n { keys: [\"C\"], description: \"Copy span name\" },\n { keys: [\"Esc\"], description: \"Deselect span\" },\n { keys: [\"Ctrl\", \"Shift\", \"E\"], description: \"Expand all\" },\n { keys: [\"Ctrl\", \"Shift\", \"C\"], description: \"Collapse all\" },\n ],\n};\n","/**\n * TraceTimeline - Accepts OtelTracesRow[] and renders trace visualization.\n * Transforms denormalized rows to SpanNode tree internally.\n */\n\nimport { useMemo, useState, useRef, useEffect, useCallback } from \"react\";\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\nimport type { denormalizedSignals } from \"@kopai/core\";\ntype OtelTracesRow = denormalizedSignals.OtelTracesRow;\nimport type { SpanNode, ParsedTrace } from \"../types.js\";\nimport { flattenTree, getAllSpanIds } from \"../utils/flatten-tree.js\";\nimport {\n calculateRelativeTime,\n calculateRelativeDuration,\n formatDuration,\n} from \"../utils/time.js\";\nimport { TraceHeader } from \"./TraceHeader.js\";\nimport { SpanRow } from \"./SpanRow.js\";\nimport { DetailPane } from \"./DetailPane/index.js\";\nimport { LoadingSkeleton } from \"../shared/LoadingSkeleton.js\";\nimport { useRegisterShortcuts } from \"../../KeyboardShortcuts/index.js\";\nimport { TRACE_VIEWER_SHORTCUTS } from \"./shortcuts.js\";\n\nexport interface TraceTimelineProps {\n rows: OtelTracesRow[];\n onSpanClick?: (span: SpanNode) => void;\n selectedSpanId?: string;\n isLoading?: boolean;\n error?: Error;\n}\n\n/** Transform OtelTracesRow[] to ParsedTrace */\nfunction buildTrace(rows: OtelTracesRow[]): ParsedTrace | null {\n if (rows.length === 0) return null;\n\n // Pass 1: Build SpanNode lookup + trace bounds\n const spanById = new Map<string, SpanNode>();\n let minTimeMs = Infinity;\n let maxTimeMs = -Infinity;\n let traceId = \"\";\n\n for (const row of rows) {\n const startMs = parseInt(row.Timestamp, 10) / 1e6;\n const durationNs = row.Duration ? parseInt(row.Duration, 10) : 0;\n const durationMs = durationNs / 1e6;\n const endMs = startMs + durationMs;\n\n // Zip parallel arrays for events\n const events: SpanNode[\"events\"] = [];\n const eventNames = row[\"Events.Name\"] ?? [];\n const eventTimestamps = row[\"Events.Timestamp\"] ?? [];\n const eventAttributes = row[\"Events.Attributes\"] ?? [];\n for (let i = 0; i < eventNames.length; i++) {\n events.push({\n timeUnixMs: eventTimestamps[i]\n ? parseInt(eventTimestamps[i]!, 10) / 1e6\n : startMs,\n name: eventNames[i] ?? \"\",\n attributes: (eventAttributes[i] as Record<string, unknown>) ?? {},\n });\n }\n\n // Zip parallel arrays for links\n const links: SpanNode[\"links\"] = [];\n const linkTraceIds = row[\"Links.TraceId\"] ?? [];\n const linkSpanIds = row[\"Links.SpanId\"] ?? [];\n const linkAttributes = row[\"Links.Attributes\"] ?? [];\n for (let i = 0; i < linkTraceIds.length; i++) {\n links.push({\n traceId: linkTraceIds[i] ?? \"\",\n spanId: linkSpanIds[i] ?? \"\",\n attributes: (linkAttributes[i] as Record<string, unknown>) ?? {},\n });\n }\n\n const span: SpanNode = {\n spanId: row.SpanId,\n parentSpanId: row.ParentSpanId || undefined,\n traceId: row.TraceId,\n name: row.SpanName ?? \"\",\n startTimeUnixMs: startMs,\n endTimeUnixMs: endMs,\n durationMs,\n kind: row.SpanKind ?? \"INTERNAL\",\n status: row.StatusCode ?? \"UNSET\",\n statusMessage: row.StatusMessage,\n serviceName: row.ServiceName ?? \"unknown\",\n attributes: row.SpanAttributes ?? {},\n resourceAttributes: row.ResourceAttributes ?? {},\n events,\n links,\n children: [],\n };\n\n spanById.set(span.spanId, span);\n minTimeMs = Math.min(minTimeMs, startMs);\n maxTimeMs = Math.max(maxTimeMs, endMs);\n if (!traceId) traceId = span.traceId;\n }\n\n if (spanById.size === 0) return null;\n\n // Pass 2: Build tree\n const rootSpans: SpanNode[] = [];\n for (const [, span] of spanById) {\n if (span.parentSpanId === span.spanId) {\n rootSpans.push(span);\n continue;\n }\n if (!span.parentSpanId || !spanById.has(span.parentSpanId)) {\n rootSpans.push(span);\n } else {\n spanById.get(span.parentSpanId)!.children.push(span);\n }\n }\n\n // Sort children by start time\n for (const [, span] of spanById) {\n span.children.sort((a, b) => a.startTimeUnixMs - b.startTimeUnixMs);\n }\n rootSpans.sort((a, b) => a.startTimeUnixMs - b.startTimeUnixMs);\n\n return {\n traceId,\n rootSpans,\n minTimeMs,\n maxTimeMs,\n totalSpanCount: spanById.size,\n };\n}\n\nfunction isSpanAncestorOf(\n potentialAncestor: SpanNode,\n descendantId: string,\n flattenedSpans: Array<{ span: SpanNode; level: number }>\n): boolean {\n const descendantItem = flattenedSpans.find(\n (item) => item.span.spanId === descendantId\n );\n if (!descendantItem) return false;\n\n let current: SpanNode | undefined = descendantItem.span;\n while (current?.parentSpanId) {\n if (current.parentSpanId === potentialAncestor.spanId) return true;\n const parentItem = flattenedSpans.find(\n (item) => item.span.spanId === current!.parentSpanId\n );\n current = parentItem?.span;\n }\n return false;\n}\n\nexport function TraceTimeline({\n rows,\n onSpanClick,\n selectedSpanId: externalSelectedSpanId,\n isLoading,\n error,\n}: TraceTimelineProps) {\n useRegisterShortcuts(\"trace-viewer\", TRACE_VIEWER_SHORTCUTS);\n\n const [collapsedIds, setCollapsedIds] = useState<Set<string>>(new Set());\n const [internalSelectedSpanId, setInternalSelectedSpanId] = useState<\n string | null\n >(null);\n const [hoveredSpanId, setHoveredSpanId] = useState<string | null>(null);\n const selectedSpanId = externalSelectedSpanId ?? internalSelectedSpanId;\n const scrollRef = useRef<HTMLDivElement>(null);\n const announcementRef = useRef<HTMLDivElement>(null);\n\n const parsedTrace = useMemo(() => buildTrace(rows), [rows]);\n\n const flattenedSpans = useMemo(() => {\n if (!parsedTrace) return [];\n return flattenTree(parsedTrace.rootSpans, collapsedIds);\n }, [parsedTrace, collapsedIds]);\n\n const virtualizer = useVirtualizer({\n count: flattenedSpans.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => 32,\n overscan: 5,\n });\n\n const handleToggleCollapse = (spanId: string) => {\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n if (next.has(spanId)) next.delete(spanId);\n else next.add(spanId);\n return next;\n });\n };\n\n const handleSpanClick = useCallback(\n (span: SpanNode) => {\n setInternalSelectedSpanId(span.spanId);\n onSpanClick?.(span);\n if (announcementRef.current) {\n announcementRef.current.textContent = `Selected span: ${span.name}, duration: ${formatDuration(span.durationMs)}`;\n }\n },\n [onSpanClick]\n );\n\n const handleExpandAll = useCallback(() => {\n setCollapsedIds(new Set());\n }, []);\n\n const handleCollapseAll = useCallback(() => {\n if (!parsedTrace) return;\n setCollapsedIds(new Set(getAllSpanIds(parsedTrace.rootSpans)));\n }, [parsedTrace]);\n\n const handleNavigateUp = useCallback(() => {\n if (flattenedSpans.length === 0) return;\n const currentIndex = flattenedSpans.findIndex(\n (item) => item.span.spanId === selectedSpanId\n );\n if (currentIndex > 0) {\n const prevItem = flattenedSpans[currentIndex - 1];\n if (prevItem) handleSpanClick(prevItem.span);\n } else if (currentIndex === -1 && flattenedSpans.length > 0) {\n const lastItem = flattenedSpans[flattenedSpans.length - 1];\n if (lastItem) handleSpanClick(lastItem.span);\n }\n }, [flattenedSpans, selectedSpanId, handleSpanClick]);\n\n const handleNavigateDown = useCallback(() => {\n if (flattenedSpans.length === 0) return;\n const currentIndex = flattenedSpans.findIndex(\n (item) => item.span.spanId === selectedSpanId\n );\n if (currentIndex >= 0 && currentIndex < flattenedSpans.length - 1) {\n const nextItem = flattenedSpans[currentIndex + 1];\n if (nextItem) handleSpanClick(nextItem.span);\n } else if (currentIndex === -1 && flattenedSpans.length > 0) {\n const firstItem = flattenedSpans[0];\n if (firstItem) handleSpanClick(firstItem.span);\n }\n }, [flattenedSpans, selectedSpanId, handleSpanClick]);\n\n const handleCollapseExpand = useCallback(\n (collapse: boolean) => {\n if (!selectedSpanId) return;\n const selectedItem = flattenedSpans.find(\n (item) => item.span.spanId === selectedSpanId\n );\n if (!selectedItem || selectedItem.span.children.length === 0) return;\n if (collapse) {\n setCollapsedIds((prev) => new Set([...prev, selectedItem.span.spanId]));\n } else {\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n next.delete(selectedItem.span.spanId);\n return next;\n });\n }\n },\n [selectedSpanId, flattenedSpans]\n );\n\n const handleDeselect = useCallback(() => {\n setInternalSelectedSpanId(null);\n }, []);\n\n useEffect(() => {\n if (!selectedSpanId) return;\n const selectedIndex = flattenedSpans.findIndex(\n (item) => item.span.spanId === selectedSpanId\n );\n if (selectedIndex !== -1) {\n virtualizer.scrollToIndex(selectedIndex, {\n align: \"center\",\n behavior: \"smooth\",\n });\n }\n }, [selectedSpanId, flattenedSpans, virtualizer]);\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n const timelineElement = scrollRef.current?.parentElement;\n if (!timelineElement?.contains(document.activeElement)) return;\n\n switch (e.key) {\n case \"ArrowUp\":\n case \"k\":\n case \"K\":\n e.preventDefault();\n handleNavigateUp();\n break;\n case \"ArrowDown\":\n case \"j\":\n case \"J\":\n e.preventDefault();\n handleNavigateDown();\n break;\n case \"ArrowLeft\":\n e.preventDefault();\n handleCollapseExpand(true);\n break;\n case \"ArrowRight\":\n e.preventDefault();\n handleCollapseExpand(false);\n break;\n case \"Escape\":\n e.preventDefault();\n handleDeselect();\n break;\n case \"Enter\": {\n if (selectedSpanId) {\n e.preventDefault();\n const detailPane = document.querySelector(\n '[role=\"complementary\"][aria-label=\"Span details\"]'\n );\n if (detailPane) {\n detailPane.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n (detailPane as HTMLElement).focus?.();\n }\n }\n break;\n }\n case \"e\":\n case \"E\":\n if (e.ctrlKey && e.shiftKey) {\n e.preventDefault();\n handleExpandAll();\n }\n break;\n case \"c\":\n case \"C\":\n if (e.ctrlKey && e.shiftKey) {\n e.preventDefault();\n handleCollapseAll();\n } else if (!e.ctrlKey && !e.metaKey) {\n e.preventDefault();\n const selected = flattenedSpans.find(\n (item) => item.span.spanId === selectedSpanId\n );\n if (selected) {\n navigator.clipboard.writeText(selected.span.name).catch(() => {});\n }\n }\n break;\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [\n handleNavigateUp,\n handleNavigateDown,\n handleCollapseExpand,\n handleDeselect,\n handleExpandAll,\n handleCollapseAll,\n selectedSpanId,\n flattenedSpans,\n ]);\n\n if (isLoading) return <LoadingSkeleton />;\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center h-64 bg-background\">\n <div className=\"text-red-600 dark:text-red-400\">\n <div className=\"font-semibold\">Error loading trace</div>\n <div className=\"text-sm\">{error.message}</div>\n </div>\n </div>\n );\n }\n\n if (rows.length === 0 || !parsedTrace) {\n return (\n <div className=\"flex items-center justify-center h-64 bg-background\">\n <div className=\"text-muted-foreground\">No trace data available</div>\n </div>\n );\n }\n\n const totalDurationMs = parsedTrace.maxTimeMs - parsedTrace.minTimeMs;\n const selectedSpan =\n selectedSpanId && flattenedSpans.length > 0\n ? flattenedSpans.find((item) => item.span.spanId === selectedSpanId)?.span\n : null;\n\n return (\n <div className=\"flex h-full bg-background\">\n <div className=\"flex flex-col flex-1 min-w-0\">\n <div\n ref={announcementRef}\n className=\"sr-only\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n />\n <TraceHeader trace={parsedTrace} />\n <div\n ref={scrollRef}\n className=\"flex-1 overflow-auto outline-none\"\n role=\"tree\"\n aria-label=\"Trace timeline\"\n tabIndex={0}\n >\n <div\n style={{\n height: `${virtualizer.getTotalSize()}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {virtualizer.getVirtualItems().map((virtualItem) => {\n const item = flattenedSpans[virtualItem.index];\n if (!item) return null;\n\n const { span, level } = item;\n const isCollapsed = collapsedIds.has(span.spanId);\n const isSelected = span.spanId === selectedSpanId;\n const isHovered = span.spanId === hoveredSpanId;\n const isParentOfHovered = hoveredSpanId\n ? isSpanAncestorOf(span, hoveredSpanId, flattenedSpans)\n : false;\n\n const relativeStart = calculateRelativeTime(\n span.startTimeUnixMs,\n parsedTrace.minTimeMs,\n parsedTrace.maxTimeMs\n );\n const relativeDuration = calculateRelativeDuration(\n span.durationMs,\n totalDurationMs\n );\n\n return (\n <div\n key={span.spanId}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: `${virtualItem.size}px`,\n transform: `translateY(${virtualItem.start}px)`,\n }}\n >\n <SpanRow\n span={span}\n level={level}\n isCollapsed={isCollapsed}\n isSelected={isSelected}\n isHovered={isHovered}\n isParentOfHovered={isParentOfHovered}\n relativeStart={relativeStart}\n relativeDuration={relativeDuration}\n onClick={() => handleSpanClick(span)}\n onToggleCollapse={() => handleToggleCollapse(span.spanId)}\n onMouseEnter={() => setHoveredSpanId(span.spanId)}\n onMouseLeave={() => setHoveredSpanId(null)}\n />\n </div>\n );\n })}\n </div>\n </div>\n </div>\n\n {selectedSpan && (\n <div className=\"w-96 h-full flex-shrink-0\">\n <DetailPane\n span={selectedSpan}\n onClose={handleDeselect}\n // TODO: wire up cross-trace navigation\n onLinkClick={undefined}\n />\n </div>\n )}\n </div>\n );\n}\n","import type { denormalizedSignals } from \"@kopai/core\";\nimport { TraceTimeline } from \"../TraceTimeline/index.js\";\nimport type { SpanNode } from \"../types.js\";\n\ntype OtelTracesRow = denormalizedSignals.OtelTracesRow;\n\nexport interface TraceDetailProps {\n service: string;\n traceId: string;\n rows: OtelTracesRow[];\n isLoading?: boolean;\n error?: Error;\n selectedSpanId?: string;\n onSpanClick?: (span: SpanNode) => void;\n onBack: () => void;\n}\n\nexport function TraceDetail({\n service,\n traceId,\n rows,\n isLoading,\n error,\n selectedSpanId,\n onSpanClick,\n onBack,\n}: TraceDetailProps) {\n return (\n <div>\n {/* Breadcrumb */}\n <div className=\"flex items-center gap-1.5 text-sm text-muted-foreground mb-4\">\n <button\n onClick={onBack}\n className=\"hover:text-foreground transition-colors\"\n >\n Services / {service}\n </button>\n <span>/</span>\n <span className=\"text-foreground font-mono text-xs\">\n {traceId.slice(0, 16)}...\n </span>\n </div>\n\n <TraceTimeline\n rows={rows}\n isLoading={isLoading}\n error={error}\n selectedSpanId={selectedSpanId}\n onSpanClick={onSpanClick}\n />\n </div>\n );\n}\n","import { memo, useMemo } from \"react\";\nimport type { LogEntry } from \"../types.js\";\nimport { getServiceColor } from \"../utils/colors.js\";\n\nexport interface LogRowProps {\n log: LogEntry;\n isSelected: boolean;\n onClick: () => void;\n searchText?: string;\n relativeTime?: boolean;\n referenceTimeMs?: number;\n}\n\nfunction formatTimestamp(timeMs: number): string {\n const date = new Date(timeMs);\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n const ms = String(date.getMilliseconds()).padStart(3, \"0\");\n return `${hours}:${minutes}:${seconds}.${ms}`;\n}\n\nfunction formatRelativeTime(timeMs: number, referenceMs: number): string {\n const diffMs = timeMs - referenceMs;\n const sign = diffMs >= 0 ? \"+\" : \"-\";\n const abs = Math.abs(diffMs);\n if (abs < 1000) return `${sign}${abs.toFixed(4)}ms`;\n if (abs < 60_000) return `${sign}${(abs / 1000).toFixed(4)}s`;\n const mins = Math.floor(abs / 60_000);\n const secs = ((abs % 60_000) / 1000).toFixed(4);\n return `${sign}${mins}m${secs}s`;\n}\n\nfunction truncateMessage(message: string, maxLength = 120): string {\n if (message.length <= maxLength) return message;\n return message.slice(0, maxLength) + \"...\";\n}\n\nfunction getSeverityColor(severity: string): { text: string; bg: string } {\n const s = severity.toUpperCase();\n if (s === \"FATAL\" || s === \"ERROR\")\n return {\n text: \"text-red-900 dark:text-red-100\",\n bg: \"bg-red-100 dark:bg-red-900/30\",\n };\n if (s === \"WARN\" || s === \"WARNING\")\n return {\n text: \"text-orange-900 dark:text-orange-100\",\n bg: \"bg-orange-100 dark:bg-orange-900/30\",\n };\n if (s === \"INFO\")\n return {\n text: \"text-blue-900 dark:text-blue-100\",\n bg: \"bg-blue-100 dark:bg-blue-900/30\",\n };\n if (s === \"DEBUG\")\n return {\n text: \"text-gray-900 dark:text-gray-100\",\n bg: \"bg-gray-100 dark:bg-gray-700/30\",\n };\n if (s === \"TRACE\")\n return {\n text: \"text-gray-700 dark:text-gray-300\",\n bg: \"bg-gray-50 dark:bg-gray-800/30\",\n };\n return {\n text: \"text-gray-600 dark:text-gray-400\",\n bg: \"bg-gray-50 dark:bg-gray-800/20\",\n };\n}\n\nfunction highlightSearchText(\n text: string,\n searchText: string\n): React.ReactNode {\n if (!searchText || !text) return text;\n\n const parts: React.ReactNode[] = [];\n let lastIndex = 0;\n const searchLower = searchText.toLowerCase();\n const textLower = text.toLowerCase();\n let index = textLower.indexOf(searchLower);\n\n while (index !== -1) {\n if (index > lastIndex) parts.push(text.slice(lastIndex, index));\n const matchText = text.slice(index, index + searchText.length);\n parts.push(\n <mark\n key={`${index}-${matchText}`}\n className=\"bg-yellow-200 dark:bg-yellow-700 text-foreground\"\n >\n {matchText}\n </mark>\n );\n lastIndex = index + searchText.length;\n index = textLower.indexOf(searchLower, lastIndex);\n }\n\n if (lastIndex < text.length) parts.push(text.slice(lastIndex));\n return parts.length > 0 ? <>{parts}</> : text;\n}\n\nexport const LogRow = memo(function LogRow({\n log,\n isSelected,\n onClick,\n searchText,\n relativeTime,\n referenceTimeMs,\n}: LogRowProps) {\n const severityColor = getSeverityColor(log.severityText);\n const message = useMemo(() => log.body || \"\", [log.body]);\n const timestamp =\n relativeTime && referenceTimeMs != null\n ? formatRelativeTime(log.timeUnixMs, referenceTimeMs)\n : formatTimestamp(log.timeUnixMs);\n const lineCount = message.split(\"\\n\").length;\n const hasMultipleLines = lineCount > 1;\n\n return (\n <div\n style={{ contain: \"layout style paint\" }}\n className={`flex items-center gap-3 px-4 h-[44px] border-b border-border cursor-pointer overflow-hidden outline-none ${\n isSelected\n ? \"bg-blue-50 dark:bg-blue-900/30 border-l-4 border-l-blue-500\"\n : \"hover:bg-muted\"\n }`}\n onClick={onClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }}\n >\n <div className=\"flex-shrink-0 w-28 font-mono text-xs text-muted-foreground\">\n {timestamp}\n </div>\n <div\n className={`flex-shrink-0 w-24 text-xs font-semibold px-2 py-0.5 rounded truncate ${severityColor.bg} ${severityColor.text}`}\n >\n {log.severityText}\n </div>\n <div\n className=\"flex-shrink-0 w-32 text-xs truncate\"\n style={{ color: getServiceColor(log.serviceName) }}\n >\n {log.serviceName}\n </div>\n <div className=\"flex-1 min-w-0 flex items-center gap-2\">\n <div className=\"text-sm text-foreground truncate\">\n {searchText\n ? highlightSearchText(\n truncateMessage(message.split(\"\\n\")[0] || \"\", 100),\n searchText\n )\n : truncateMessage(message.split(\"\\n\")[0] || \"\", 100)}\n </div>\n {hasMultipleLines && (\n <span className=\"flex-shrink-0 text-xs text-muted-foreground\">\n +{lineCount - 1} lines\n </span>\n )}\n {log.traceId && (\n <span className=\"flex-shrink-0 text-xs text-indigo-600 dark:text-indigo-400\">\n trace: {log.traceId.slice(0, 16)}...\n </span>\n )}\n </div>\n </div>\n );\n});\n","import { useMemo } from \"react\";\nimport type { LogEntry } from \"../../types.js\";\nimport {\n formatAttributeValue,\n isComplexValue,\n} from \"../../utils/attributes.js\";\n\nexport interface AttributesTabProps {\n log: LogEntry;\n}\n\nexport function AttributesTab({ log }: AttributesTabProps) {\n const sortedAttributes = useMemo(() => {\n return Object.entries(log.attributes).sort(([a], [b]) =>\n a.localeCompare(b)\n );\n }, [log.attributes]);\n\n if (sortedAttributes.length === 0) {\n return (\n <div className=\"text-sm text-muted-foreground text-center py-8\">\n No attributes available\n </div>\n );\n }\n\n return (\n <div className=\"space-y-2\">\n {sortedAttributes.map(([key, value]) => {\n const isComplex = isComplexValue(value);\n const formattedValue = formatAttributeValue(value);\n return (\n <div key={key} className=\"p-2 rounded bg-muted\">\n <div\n className=\"font-mono font-medium text-xs text-foreground mb-1\"\n title={key}\n >\n {key}\n </div>\n <div>\n {isComplex ? (\n <pre className=\"text-xs text-foreground bg-background p-2 rounded border border-border overflow-x-auto\">\n {formattedValue}\n </pre>\n ) : (\n <span className=\"text-sm text-foreground break-words\">\n {formattedValue}\n </span>\n )}\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n","import { useState } from \"react\";\n\nexport interface JsonTreeViewProps {\n data: Record<string, unknown> | unknown[];\n level?: number;\n}\n\nexport function JsonTreeView({ data, level = 0 }: JsonTreeViewProps) {\n return (\n <div className=\"font-mono text-sm\">\n {Array.isArray(data) ? (\n <ArrayView items={data} level={level} />\n ) : (\n <ObjectView obj={data} level={level} />\n )}\n </div>\n );\n}\n\nfunction ObjectView({\n obj,\n level,\n}: {\n obj: Record<string, unknown>;\n level: number;\n}) {\n const entries = Object.entries(obj);\n if (entries.length === 0)\n return <span className=\"text-muted-foreground\">{\"{}\"}</span>;\n return (\n <div>\n {entries.map(([key, value]) => (\n <JsonTreeNode key={key} objKey={key} value={value} level={level} />\n ))}\n </div>\n );\n}\n\nfunction ArrayView({ items, level }: { items: unknown[]; level: number }) {\n if (items.length === 0)\n return <span className=\"text-muted-foreground\">[]</span>;\n return (\n <div>\n {items.map((item, index) => (\n <JsonTreeNode\n key={index}\n objKey={String(index)}\n value={item}\n level={level}\n isArrayItem\n />\n ))}\n </div>\n );\n}\n\nfunction JsonTreeNode({\n objKey,\n value,\n level,\n isArrayItem = false,\n}: {\n objKey: string;\n value: unknown;\n level: number;\n isArrayItem?: boolean;\n}) {\n const [isExpanded, setIsExpanded] = useState(level < 2);\n\n const isExpandable =\n value !== null &&\n typeof value === \"object\" &&\n (Array.isArray(value) ? value.length > 0 : Object.keys(value).length > 0);\n\n const indent = level * 16;\n\n if (!isExpandable) {\n return (\n <div\n style={{ paddingLeft: `${indent}px` }}\n className=\"py-0.5 hover:bg-muted\"\n >\n {!isArrayItem && (\n <span className=\"text-blue-600 dark:text-blue-400\">\n {objKey}\n {\": \"}\n </span>\n )}\n <span className=\"text-foreground\">{formatPrimitiveValue(value)}</span>\n </div>\n );\n }\n\n return (\n <div>\n <div\n style={{ paddingLeft: `${indent}px` }}\n className=\"py-0.5 hover:bg-muted cursor-pointer\"\n onClick={() => setIsExpanded(!isExpanded)}\n >\n <span className=\"inline-block w-4 text-muted-foreground\">\n {isExpanded ? \"▼\" : \"▶\"}\n </span>\n {!isArrayItem && (\n <span className=\"text-blue-600 dark:text-blue-400\">\n {objKey}\n {\": \"}\n </span>\n )}\n <span className=\"text-muted-foreground\">\n {Array.isArray(value)\n ? `Array(${value.length})`\n : `Object(${Object.keys(value).length})`}\n </span>\n </div>\n {isExpanded && (\n <div>\n {Array.isArray(value) ? (\n <ArrayView items={value} level={level + 1} />\n ) : (\n <ObjectView\n obj={value as Record<string, unknown>}\n level={level + 1}\n />\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction formatPrimitiveValue(value: unknown): string {\n if (value === null) return \"null\";\n if (value === undefined) return \"undefined\";\n if (typeof value === \"string\") return `\"${value}\"`;\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\";\n if (typeof value === \"number\") return String(value);\n return String(value);\n}\n","import { useState, useCallback, useRef, useEffect } from \"react\";\nimport type { LogEntry } from \"../../types.js\";\nimport { AttributesTab } from \"./AttributesTab.js\";\nimport { JsonTreeView } from \"./JsonTreeView.js\";\n\nexport interface LogDetailPaneProps {\n log: LogEntry;\n onClose: () => void;\n onTraceLinkClick?: (traceId: string, spanId: string) => void;\n initialTab?: \"message\" | \"attributes\" | \"resource\" | \"context\";\n wordWrap?: boolean;\n}\n\ntype TabType = \"message\" | \"attributes\" | \"resource\" | \"context\";\n\nexport function LogDetailPane({\n log,\n onClose,\n onTraceLinkClick,\n initialTab = \"message\",\n wordWrap = true,\n}: LogDetailPaneProps) {\n const hasContext = !!log.traceId;\n const [activeTab, setActiveTab] = useState<TabType>(\n initialTab === \"context\" && !hasContext ? \"message\" : initialTab\n );\n const [copiedId, setCopiedId] = useState(false);\n const detailPaneRef = useRef<HTMLDivElement>(null);\n\n const handleCopyLogId = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(log.logId);\n setCopiedId(true);\n setTimeout(() => setCopiedId(false), 2000);\n } catch (err) {\n console.error(\"Failed to copy log ID:\", err);\n }\n }, [log.logId]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n },\n [onClose]\n );\n\n useEffect(() => {\n detailPaneRef.current?.focus();\n }, []);\n\n const severityColor = getSeverityColor(log.severityText);\n\n return (\n <div\n ref={detailPaneRef}\n className=\"w-[500px] flex flex-col h-full bg-background border-l border-border outline-none\"\n onKeyDown={handleKeyDown}\n role=\"complementary\"\n aria-label=\"Log details\"\n tabIndex={-1}\n >\n {/* Header */}\n <div className=\"p-4 border-b border-border\">\n <div className=\"flex items-center justify-between mb-3\">\n <h2 className=\"text-lg font-semibold text-foreground\">Log Details</h2>\n <button\n onClick={onClose}\n className=\"p-2 hover:bg-muted rounded transition-colors\"\n aria-label=\"Close detail pane\"\n >\n <svg\n className=\"w-6 h-6 text-muted-foreground\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n <div className=\"flex items-center gap-2 mb-2\">\n <div\n className={`text-xs font-semibold px-2 py-0.5 rounded ${severityColor.bg} ${severityColor.text}`}\n >\n {log.severityText}\n </div>\n <div className=\"text-sm text-muted-foreground\">{log.serviceName}</div>\n </div>\n <div className=\"text-xs font-medium text-muted-foreground mt-3 mb-1\">\n Timestamp\n </div>\n <div className=\"text-xs text-foreground font-mono\">\n {new Date(log.timeUnixMs).toISOString()}\n </div>\n <div className=\"text-xs font-medium text-muted-foreground mt-3 mb-1\">\n Log ID\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={handleCopyLogId}\n className=\"flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground font-mono bg-muted px-2 py-1 rounded\"\n title=\"Click to copy log ID\"\n >\n <span className=\"truncate max-w-[200px]\">{log.logId}</span>\n <svg\n className=\"w-3 h-3 flex-shrink-0\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n {copiedId ? (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n ) : (\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\"\n />\n )}\n </svg>\n </button>\n </div>\n </div>\n\n {/* Tabs */}\n <div className=\"flex border-b border-border\">\n {(\n [\n \"message\",\n \"attributes\",\n \"resource\",\n ...(log.traceId ? [\"context\" as const] : []),\n ] as TabType[]\n ).map((tab) => (\n <button\n key={tab}\n onClick={() => setActiveTab(tab)}\n className={`px-4 py-2 text-sm font-medium transition-colors ${\n activeTab === tab\n ? \"text-blue-600 dark:text-blue-400 border-b-2 border-blue-600 dark:border-blue-400\"\n : \"text-muted-foreground hover:text-foreground\"\n }`}\n >\n {tab === \"context\"\n ? \"Trace\"\n : tab.charAt(0).toUpperCase() + tab.slice(1)}\n </button>\n ))}\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-4\">\n {activeTab === \"message\" && (\n <pre\n className={`text-sm text-foreground font-mono bg-muted p-3 rounded ${\n wordWrap\n ? \"whitespace-pre-wrap break-words\"\n : \"whitespace-pre overflow-x-auto\"\n }`}\n >\n {log.body || \"No message body\"}\n </pre>\n )}\n {activeTab === \"attributes\" && <AttributesTab log={log} />}\n {activeTab === \"resource\" && (\n <div>\n <div className=\"mb-3\">\n <div className=\"text-sm font-semibold text-foreground mb-2\">\n Service Name\n </div>\n <div className=\"text-sm text-foreground bg-muted p-2 rounded font-mono\">\n {log.serviceName}\n </div>\n </div>\n {log.scopeName && (\n <div className=\"mb-3\">\n <div className=\"text-sm font-semibold text-foreground mb-2\">\n Scope Name\n </div>\n <div className=\"text-sm text-foreground bg-muted p-2 rounded font-mono\">\n {log.scopeName}\n </div>\n </div>\n )}\n <div>\n <div className=\"text-sm font-semibold text-foreground mb-2\">\n Resource Attributes\n </div>\n {Object.keys(log.resourceAttributes).length > 0 ? (\n <JsonTreeView data={log.resourceAttributes} />\n ) : (\n <div className=\"text-sm text-muted-foreground text-center py-4\">\n No resource attributes\n </div>\n )}\n </div>\n </div>\n )}\n {activeTab === \"context\" && log.traceId && (\n <div className=\"space-y-3\">\n <div>\n <div className=\"text-sm font-semibold text-foreground mb-2\">\n Trace ID\n </div>\n <div className=\"text-sm text-foreground bg-muted p-2 rounded font-mono break-all\">\n {log.traceId}\n </div>\n </div>\n {log.spanId && (\n <div>\n <div className=\"text-sm font-semibold text-foreground mb-2\">\n Span ID\n </div>\n <div className=\"text-sm text-foreground bg-muted p-2 rounded font-mono break-all\">\n {log.spanId}\n </div>\n </div>\n )}\n {onTraceLinkClick && log.spanId && (\n <button\n onClick={() => onTraceLinkClick(log.traceId!, log.spanId!)}\n className=\"w-full px-4 py-2 bg-blue-600 dark:bg-blue-500 text-white rounded hover:bg-blue-700 dark:hover:bg-blue-600 transition-colors text-sm\"\n >\n View Trace\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction getSeverityColor(severity: string): { text: string; bg: string } {\n const s = severity.toUpperCase();\n if (s === \"FATAL\" || s === \"ERROR\")\n return {\n text: \"text-red-900 dark:text-red-100\",\n bg: \"bg-red-100 dark:bg-red-900/30\",\n };\n if (s === \"WARN\" || s === \"WARNING\")\n return {\n text: \"text-orange-900 dark:text-orange-100\",\n bg: \"bg-orange-100 dark:bg-orange-900/30\",\n };\n if (s === \"INFO\")\n return {\n text: \"text-blue-900 dark:text-blue-100\",\n bg: \"bg-blue-100 dark:bg-blue-900/30\",\n };\n if (s === \"DEBUG\")\n return {\n text: \"text-gray-900 dark:text-gray-100\",\n bg: \"bg-gray-100 dark:bg-gray-700/30\",\n };\n return {\n text: \"text-gray-600 dark:text-gray-400\",\n bg: \"bg-gray-50 dark:bg-gray-800/20\",\n };\n}\n","import type { ShortcutGroup } from \"../../KeyboardShortcuts/types.js\";\n\nexport const LOG_VIEWER_SHORTCUTS: ShortcutGroup = {\n name: \"Log Viewer\",\n shortcuts: [\n { keys: [\"↑/K\"], description: \"Previous log\" },\n { keys: [\"↓/J\"], description: \"Next log\" },\n { keys: [\"G\"], description: \"Scroll to bottom\" },\n { keys: [\"Home\"], description: \"First log\" },\n { keys: [\"/\"], description: \"Focus search\" },\n { keys: [\"F\"], description: \"Toggle filters\" },\n { keys: [\"Enter\"], description: \"Open log detail\" },\n { keys: [\"C\"], description: \"Copy log body\" },\n { keys: [\"W\"], description: \"Toggle word wrap\" },\n { keys: [\"T\"], description: \"Toggle timestamps\" },\n { keys: [\"Esc\"], description: \"Close detail/filter pane\" },\n ],\n};\n","/**\n * LogTimeline - Accepts OtelLogsRow[] and renders log visualization.\n * Transforms denormalized rows to LogEntry[] internally.\n */\n\nimport { useMemo, useState, useRef, useCallback, useEffect } from \"react\";\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\nimport type { denormalizedSignals } from \"@kopai/core\";\nimport type { LogEntry } from \"../types.js\";\nimport { LogRow } from \"./LogRow.js\";\nimport { LogDetailPane } from \"./LogDetailPane/index.js\";\nimport { LoadingSkeleton } from \"../shared/LoadingSkeleton.js\";\nimport { useRegisterShortcuts } from \"../../KeyboardShortcuts/index.js\";\nimport { LOG_VIEWER_SHORTCUTS } from \"./shortcuts.js\";\n\ntype OtelLogsRow = denormalizedSignals.OtelLogsRow;\n\nconst LOG_ROW_HEIGHT = 44;\nconst OVERSCAN_COUNT = 20;\nconst DEFAULT_MAX_LOGS = 1000;\nconst BOTTOM_THRESHOLD_PX = 50;\n\nconst VIRTUAL_ROW_STYLE_BASE = {\n position: \"absolute\" as const,\n top: 0,\n left: 0,\n width: \"100%\",\n};\n\nexport interface LogTimelineProps {\n rows: OtelLogsRow[];\n onLogClick?: (log: LogEntry) => void;\n onTraceLinkClick?: (traceId: string, spanId: string) => void;\n selectedLogId?: string;\n isLoading?: boolean;\n error?: Error;\n streaming?: boolean;\n maxLogs?: number;\n searchText?: string;\n onAtBottomChange?: (isAtBottom: boolean) => void;\n}\n\nfunction simpleHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n return Math.abs(hash).toString(36);\n}\n\nfunction getSeverityText(\n severityNumber: number | undefined,\n severityText: string | undefined\n): string {\n if (severityText) return severityText;\n const n = severityNumber ?? 0;\n if (n >= 21) return \"FATAL\";\n if (n >= 17) return \"ERROR\";\n if (n >= 13) return \"WARN\";\n if (n >= 9) return \"INFO\";\n if (n >= 5) return \"DEBUG\";\n if (n >= 1) return \"TRACE\";\n return \"UNSPECIFIED\";\n}\n\n/** Transform OtelLogsRow[] to LogEntry[] */\nfunction buildLogs(rows: OtelLogsRow[]): LogEntry[] {\n return rows\n .map((row) => {\n const timeUnixMs = parseInt(row.Timestamp, 10) / 1e6;\n const body = row.Body ?? \"\";\n const severityText = getSeverityText(\n row.SeverityNumber,\n row.SeverityText\n );\n const logId = `${row.Timestamp}-${row.ServiceName ?? \"unknown\"}-${simpleHash(body)}`;\n\n return {\n logId,\n timeUnixMs,\n body,\n severityText,\n severityNumber: row.SeverityNumber ?? 0,\n serviceName: row.ServiceName ?? \"unknown\",\n traceId: row.TraceId,\n spanId: row.SpanId,\n attributes: row.LogAttributes ?? {},\n resourceAttributes: row.ResourceAttributes ?? {},\n scopeName: row.ScopeName,\n };\n })\n .sort((a, b) => a.timeUnixMs - b.timeUnixMs);\n}\n\nexport function LogTimeline({\n rows,\n onLogClick,\n onTraceLinkClick,\n selectedLogId: externalSelectedLogId,\n isLoading,\n error,\n streaming = false,\n maxLogs = DEFAULT_MAX_LOGS,\n searchText = \"\",\n onAtBottomChange,\n}: LogTimelineProps) {\n useRegisterShortcuts(\"log-viewer\", LOG_VIEWER_SHORTCUTS);\n\n const [internalSelectedLogId, setInternalSelectedLogId] = useState<\n string | null\n >(null);\n const [isDetailPaneOpen, setIsDetailPaneOpen] = useState(false);\n const [isAtBottom, setIsAtBottom] = useState(true);\n const [wordWrap, setWordWrap] = useState(true);\n const [relativeTime, setRelativeTime] = useState(false);\n const selectedLogId = externalSelectedLogId ?? internalSelectedLogId;\n const scrollRef = useRef<HTMLDivElement>(null);\n const announcementRef = useRef<HTMLDivElement>(null);\n const wasAtBottomRef = useRef(true);\n const hasScrolledToInitialRef = useRef(false);\n\n const allLogs = useMemo(() => buildLogs(rows), [rows]);\n\n const boundedLogs = useMemo(() => {\n if (streaming && allLogs.length > maxLogs)\n return allLogs.slice(allLogs.length - maxLogs);\n return allLogs;\n }, [allLogs, streaming, maxLogs]);\n\n const selectedLog = useMemo(() => {\n return boundedLogs.find((log) => log.logId === selectedLogId) ?? null;\n }, [boundedLogs, selectedLogId]);\n\n const referenceTimeMs = useMemo(() => {\n if (selectedLog) return selectedLog.timeUnixMs;\n const first = boundedLogs[0];\n return first ? first.timeUnixMs : 0;\n }, [selectedLog, boundedLogs]);\n\n useEffect(() => {\n if (externalSelectedLogId) setIsDetailPaneOpen(true);\n }, [externalSelectedLogId]);\n\n const checkIfAtBottom = useCallback(() => {\n if (!scrollRef.current) return true;\n const { scrollTop, scrollHeight, clientHeight } = scrollRef.current;\n if (scrollHeight <= clientHeight) return true;\n return scrollHeight - scrollTop - clientHeight < BOTTOM_THRESHOLD_PX;\n }, []);\n\n const prevAtBottomRef = useRef(true);\n\n const handleScroll = useCallback(() => {\n const atBottom = checkIfAtBottom();\n wasAtBottomRef.current = atBottom;\n setIsAtBottom(atBottom);\n if (atBottom !== prevAtBottomRef.current) {\n prevAtBottomRef.current = atBottom;\n onAtBottomChange?.(atBottom);\n }\n }, [checkIfAtBottom, onAtBottomChange]);\n\n useEffect(() => {\n const atBottom = checkIfAtBottom();\n wasAtBottomRef.current = atBottom;\n setIsAtBottom(atBottom);\n }, [boundedLogs.length, checkIfAtBottom]);\n\n useEffect(() => {\n if (streaming && wasAtBottomRef.current && scrollRef.current) {\n scrollRef.current.scrollTop = scrollRef.current.scrollHeight;\n }\n }, [boundedLogs, streaming]);\n\n const virtualizer = useVirtualizer({\n count: boundedLogs.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => LOG_ROW_HEIGHT,\n overscan: OVERSCAN_COUNT,\n });\n\n // Scroll to externally-selected log on initial data load\n useEffect(() => {\n if (hasScrolledToInitialRef.current) return;\n if (!externalSelectedLogId || boundedLogs.length === 0) return;\n const idx = boundedLogs.findIndex((l) => l.logId === externalSelectedLogId);\n if (idx === -1) return;\n hasScrolledToInitialRef.current = true;\n virtualizer.scrollToIndex(idx, { align: \"center\" });\n }, [externalSelectedLogId, boundedLogs, virtualizer]);\n\n const handleLogClick = useCallback(\n (log: LogEntry) => {\n setInternalSelectedLogId(log.logId);\n setIsDetailPaneOpen(true);\n onLogClick?.(log);\n if (announcementRef.current) {\n announcementRef.current.textContent = `Selected log from ${log.serviceName}: ${log.body.slice(0, 100)}`;\n }\n },\n [onLogClick]\n );\n\n const logClickHandlers = useMemo(() => {\n const handlers = new Map<string, () => void>();\n boundedLogs.forEach((log) => {\n handlers.set(log.logId, () => handleLogClick(log));\n });\n return handlers;\n }, [boundedLogs, handleLogClick]);\n\n const handleCloseDetailPane = useCallback(() => {\n setIsDetailPaneOpen(false);\n setInternalSelectedLogId(null);\n }, []);\n\n const handleScrollToBottom = useCallback(() => {\n if (scrollRef.current) {\n scrollRef.current.scrollTop = scrollRef.current.scrollHeight;\n wasAtBottomRef.current = true;\n setIsAtBottom(true);\n if (!prevAtBottomRef.current) {\n prevAtBottomRef.current = true;\n onAtBottomChange?.(true);\n }\n }\n }, [onAtBottomChange]);\n\n const navigateUp = useCallback(() => {\n const idx = boundedLogs.findIndex((l) => l.logId === selectedLogId);\n if (idx > 0) {\n const prev = boundedLogs[idx - 1];\n if (prev) {\n handleLogClick(prev);\n virtualizer.scrollToIndex(idx - 1, { align: \"auto\" });\n }\n } else if (idx === -1 && boundedLogs.length > 0) {\n const targetIdx = boundedLogs.length - 1;\n const last = boundedLogs[targetIdx];\n if (last) {\n handleLogClick(last);\n virtualizer.scrollToIndex(targetIdx, { align: \"auto\" });\n }\n }\n }, [boundedLogs, selectedLogId, handleLogClick, virtualizer]);\n\n const navigateDown = useCallback(() => {\n const idx = boundedLogs.findIndex((l) => l.logId === selectedLogId);\n if (idx >= 0 && idx < boundedLogs.length - 1) {\n const next = boundedLogs[idx + 1];\n if (next) {\n handleLogClick(next);\n virtualizer.scrollToIndex(idx + 1, { align: \"auto\" });\n }\n } else if (idx === -1 && boundedLogs.length > 0) {\n const first = boundedLogs[0];\n if (first) {\n handleLogClick(first);\n virtualizer.scrollToIndex(0, { align: \"auto\" });\n }\n }\n }, [boundedLogs, selectedLogId, handleLogClick, virtualizer]);\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n const isFormField =\n e.target instanceof HTMLInputElement ||\n e.target instanceof HTMLTextAreaElement ||\n e.target instanceof HTMLSelectElement;\n if (isFormField && e.key === \"Escape\") {\n (e.target as HTMLElement).blur();\n return;\n }\n if (isFormField) return;\n switch (e.key) {\n case \"ArrowUp\":\n case \"k\":\n case \"K\":\n e.preventDefault();\n navigateUp();\n break;\n case \"ArrowDown\":\n case \"j\":\n case \"J\":\n e.preventDefault();\n navigateDown();\n break;\n case \"Escape\":\n if (isDetailPaneOpen) {\n e.preventDefault();\n handleCloseDetailPane();\n } else {\n const panel = document.querySelector('[data-testid=\"log-filter\"]');\n const toggle = panel?.querySelector<HTMLButtonElement>(\n '[data-testid=\"log-filter-toggle\"]'\n );\n if (toggle && panel?.querySelector(\".border-t\")) {\n e.preventDefault();\n toggle.click();\n }\n }\n break;\n case \"g\":\n case \"G\":\n e.preventDefault();\n handleScrollToBottom();\n break;\n case \"/\": {\n e.preventDefault();\n const input = document.querySelector<HTMLInputElement>(\n '[data-testid=\"filter-bodyContains\"]'\n );\n if (input) {\n // Ensure filter panel is open first\n const panel = document.querySelector('[data-testid=\"log-filter\"]');\n const toggle = panel?.querySelector<HTMLButtonElement>(\n '[data-testid=\"log-filter-toggle\"]'\n );\n // Check if panel content is visible (has more than just the toggle button)\n if (toggle && !panel?.querySelector(\".border-t\")) {\n toggle.click();\n // Focus after panel opens\n requestAnimationFrame(() => {\n document\n .querySelector<HTMLInputElement>(\n '[data-testid=\"filter-bodyContains\"]'\n )\n ?.focus();\n });\n } else {\n input.focus();\n }\n }\n break;\n }\n case \"f\":\n case \"F\": {\n e.preventDefault();\n const toggle = document.querySelector<HTMLButtonElement>(\n '[data-testid=\"log-filter-toggle\"]'\n );\n toggle?.click();\n break;\n }\n case \"Enter\": {\n if (selectedLogId && !isDetailPaneOpen) {\n e.preventDefault();\n const log = boundedLogs.find((l) => l.logId === selectedLogId);\n if (log) handleLogClick(log);\n }\n break;\n }\n case \"Home\": {\n e.preventDefault();\n if (boundedLogs.length > 0) {\n const first = boundedLogs[0];\n if (first) {\n handleLogClick(first);\n virtualizer.scrollToIndex(0);\n }\n }\n break;\n }\n case \"c\":\n case \"C\": {\n if (e.ctrlKey || e.metaKey) break;\n e.preventDefault();\n if (selectedLog) {\n navigator.clipboard.writeText(selectedLog.body).catch(() => {});\n }\n break;\n }\n case \"w\":\n case \"W\":\n e.preventDefault();\n setWordWrap((v) => !v);\n break;\n case \"t\":\n case \"T\":\n e.preventDefault();\n setRelativeTime((v) => !v);\n break;\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [\n boundedLogs,\n selectedLogId,\n selectedLog,\n navigateUp,\n navigateDown,\n handleLogClick,\n handleCloseDetailPane,\n handleScrollToBottom,\n isDetailPaneOpen,\n virtualizer,\n ]);\n\n if (isLoading && !boundedLogs.length) return <LoadingSkeleton />;\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center h-full bg-background\">\n <div className=\"text-center p-6\">\n <div className=\"text-red-600 dark:text-red-400 mb-2\">\n Failed to load logs\n </div>\n <div className=\"text-sm text-muted-foreground\">{error.message}</div>\n </div>\n </div>\n );\n }\n\n if (boundedLogs.length === 0) {\n return (\n <div className=\"flex items-center justify-center h-full bg-background\">\n <div className=\"text-center p-6\">\n <div className=\"text-muted-foreground mb-2\">No logs</div>\n <div className=\"text-sm text-muted-foreground\">\n {streaming ? \"Waiting for logs...\" : \"No log data available\"}\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full min-h-0 bg-background\">\n <div\n ref={announcementRef}\n className=\"sr-only\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n />\n <div className=\"flex flex-1 min-h-0\">\n <div className=\"flex-1 flex flex-col min-w-0\">\n {/* Header */}\n <div className=\"border-b border-border px-4 py-3\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex items-center gap-1.5 px-2 py-1 bg-muted rounded-md text-sm font-medium text-muted-foreground\">\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 6h16M4 12h16M4 18h7\"\n />\n </svg>\n {boundedLogs.length}{\" \"}\n {boundedLogs.length === 1 ? \"log\" : \"logs\"}\n </div>\n </div>\n </div>\n </div>\n\n {/* Virtual Scroll */}\n <div className=\"flex-1 relative\">\n <div\n ref={scrollRef}\n className=\"absolute inset-0 overflow-auto\"\n onScroll={handleScroll}\n >\n <div\n style={{\n height: `${virtualizer.getTotalSize()}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {virtualizer.getVirtualItems().map((virtualRow) => {\n const log = boundedLogs[virtualRow.index];\n if (!log) return null;\n return (\n <div\n key={virtualRow.index}\n style={{\n ...VIRTUAL_ROW_STYLE_BASE,\n height: LOG_ROW_HEIGHT,\n transform: `translateY(${virtualRow.start}px)`,\n }}\n >\n <LogRow\n log={log}\n isSelected={log.logId === selectedLogId}\n onClick={logClickHandlers.get(log.logId)!}\n searchText={searchText}\n relativeTime={relativeTime}\n referenceTimeMs={referenceTimeMs}\n />\n </div>\n );\n })}\n </div>\n </div>\n {!isAtBottom && (\n <button\n onClick={handleScrollToBottom}\n className=\"absolute bottom-4 right-4 px-3 py-1.5 text-xs font-medium rounded-md bg-primary hover:bg-primary/90 text-primary-foreground shadow-lg transition-colors z-10\"\n aria-label=\"Scroll to bottom\"\n >\n <span className=\"flex items-center gap-1\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n className=\"w-3 h-3\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M8 2a.75.75 0 0 1 .75.75v8.69l3.22-3.22a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.22 3.22V2.75A.75.75 0 0 1 8 2Z\"\n clipRule=\"evenodd\"\n />\n </svg>\n (<span className=\"underline underline-offset-4\">G</span>)\n </span>\n </button>\n )}\n </div>\n </div>\n\n {isDetailPaneOpen && selectedLog && (\n <LogDetailPane\n log={selectedLog}\n onClose={handleCloseDetailPane}\n onTraceLinkClick={onTraceLinkClick}\n wordWrap={wordWrap}\n />\n )}\n </div>\n </div>\n );\n}\n","/**\n * LogFilter – collapsible filter panel for LogsDataFilter params.\n * Follows the same visual pattern as TraceSearch filters.\n */\n\nimport { useState, useEffect, useRef, useCallback, useMemo } from \"react\";\nimport type { dataFilterSchemas, denormalizedSignals } from \"@kopai/core\";\n\ntype LogsDataFilter = dataFilterSchemas.LogsDataFilter;\ntype OtelLogsRow = denormalizedSignals.OtelLogsRow;\ntype FilterValue = Partial<LogsDataFilter>;\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst LOOKBACK_OPTIONS = [\n { label: \"Last 5 Minutes\", ms: 5 * 60_000 },\n { label: \"Last 15 Minutes\", ms: 15 * 60_000 },\n { label: \"Last 30 Minutes\", ms: 30 * 60_000 },\n { label: \"Last 1 Hour\", ms: 60 * 60_000 },\n { label: \"Last 2 Hours\", ms: 2 * 60 * 60_000 },\n { label: \"Last 6 Hours\", ms: 6 * 60 * 60_000 },\n { label: \"Last 12 Hours\", ms: 12 * 60 * 60_000 },\n { label: \"Last 24 Hours\", ms: 24 * 60 * 60_000 },\n] as const;\n\nconst DEBOUNCE_MS = 500;\n\ntype TimeMode = \"lookback\" | \"absolute\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Convert ms epoch to nanosecond string */\nfunction msToNs(ms: number): string {\n return String(BigInt(Math.floor(ms)) * 1_000_000n);\n}\n\n/** Parse comma-separated \"key=value\" pairs into a record, or undefined if all invalid */\nfunction parseKeyValues(input: string): Record<string, string> | undefined {\n const result: Record<string, string> = {};\n let hasAny = false;\n for (const part of input.split(\",\")) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n const eqIdx = trimmed.indexOf(\"=\");\n if (eqIdx < 1) continue;\n const key = trimmed.slice(0, eqIdx).trim();\n const val = trimmed.slice(eqIdx + 1).trim();\n if (!key) continue;\n result[key] = val;\n hasAny = true;\n }\n return hasAny ? result : undefined;\n}\n\n/** Format a datetime-local string from a nanosecond timestamp */\nfunction nsToDatetimeLocal(ns: string | undefined): string {\n if (!ns) return \"\";\n const ms = Number(BigInt(ns) / 1_000_000n);\n const d = new Date(ms);\n const pad = (n: number) => String(n).padStart(2, \"0\");\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n}\n\n/** Build compact summary of active filters */\nfunction buildFilterSummary(\n value: FilterValue,\n selectedServices: string[]\n): string {\n const parts: string[] = [];\n if (selectedServices.length === 1) {\n parts.push(`service:${selectedServices[0]}`);\n } else if (selectedServices.length > 1) {\n parts.push(`services:${selectedServices.length}`);\n }\n if (value.severityText) parts.push(`severity:${value.severityText}`);\n if (value.scopeName) parts.push(`scope:${value.scopeName}`);\n if (value.bodyContains) parts.push(`body:\"${value.bodyContains}\"`);\n if (value.traceId) parts.push(`trace:${value.traceId.slice(0, 8)}…`);\n if (value.spanId) parts.push(`span:${value.spanId.slice(0, 8)}…`);\n if (value.limit != null) parts.push(`limit:${value.limit}`);\n if (value.sortOrder === \"ASC\") parts.push(\"sort:oldest\");\n return parts.join(\" | \");\n}\n\n// ---------------------------------------------------------------------------\n// Shared input classes\n// ---------------------------------------------------------------------------\n\nconst INPUT_CLS =\n \"w-full bg-muted/50 border border-border rounded px-2 py-1.5 text-sm text-foreground placeholder:text-muted-foreground/50\";\n\nconst LABEL_CLS = \"text-xs text-muted-foreground\";\n\n// ---------------------------------------------------------------------------\n// Debounce hook\n// ---------------------------------------------------------------------------\n\nfunction useDebouncedValue<T>(value: T, delayMs: number): T {\n const [debounced, setDebounced] = useState(value);\n useEffect(() => {\n const id = setTimeout(() => setDebounced(value), delayMs);\n return () => clearTimeout(id);\n }, [value, delayMs]);\n return debounced;\n}\n\n// ---------------------------------------------------------------------------\n// MultiSelect dropdown\n// ---------------------------------------------------------------------------\n\nfunction MultiSelect({\n options,\n selected,\n onChange,\n testId,\n}: {\n options: string[];\n selected: string[];\n onChange: (next: string[]) => void;\n testId?: string;\n}) {\n const [dropOpen, setDropOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n // Close on click outside\n useEffect(() => {\n if (!dropOpen) return;\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setDropOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [dropOpen]);\n\n const toggle = (val: string) => {\n if (selected.includes(val)) {\n onChange(selected.filter((s) => s !== val));\n } else {\n onChange([...selected, val]);\n }\n };\n\n const label =\n selected.length === 0\n ? \"All\"\n : selected.length === 1\n ? selected[0]\n : `${selected.length} selected`;\n\n return (\n <div ref={ref} className=\"relative\" data-testid={testId}>\n <button\n type=\"button\"\n onClick={() => setDropOpen((v) => !v)}\n className={`${INPUT_CLS} text-left flex items-center justify-between`}\n data-testid={testId ? `${testId}-trigger` : undefined}\n >\n <span className=\"truncate\">{label}</span>\n <span className=\"text-muted-foreground text-xs ml-1\">\n {dropOpen ? \"▲\" : \"▼\"}\n </span>\n </button>\n {dropOpen && (\n <div\n className=\"absolute z-10 mt-1 w-full bg-background border border-border rounded shadow-lg max-h-48 overflow-y-auto\"\n data-testid={testId ? `${testId}-dropdown` : undefined}\n >\n {options.length === 0 && (\n <div className=\"px-2 py-1.5 text-xs text-muted-foreground\">\n No options\n </div>\n )}\n {options.map((opt) => (\n <label\n key={opt}\n className=\"flex items-center gap-2 px-2 py-1.5 hover:bg-muted/30 cursor-pointer text-sm\"\n >\n <input\n type=\"checkbox\"\n checked={selected.includes(opt)}\n onChange={() => toggle(opt)}\n className=\"accent-foreground\"\n data-testid={testId ? `${testId}-option-${opt}` : undefined}\n />\n <span className=\"truncate\">{opt}</span>\n </label>\n ))}\n {selected.length > 0 && (\n <button\n type=\"button\"\n onClick={() => onChange([])}\n className=\"w-full px-2 py-1.5 text-xs text-muted-foreground hover:bg-muted/30 border-t border-border\"\n data-testid={testId ? `${testId}-clear` : undefined}\n >\n Clear all\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport interface LogFilterProps {\n value: FilterValue;\n onChange: (filters: FilterValue) => void;\n rows?: OtelLogsRow[];\n /** Controlled multi-select for services (empty = all). */\n selectedServices?: string[];\n onSelectedServicesChange?: (services: string[]) => void;\n}\n\nexport function LogFilter({\n value,\n onChange,\n rows = [],\n selectedServices = [],\n onSelectedServicesChange,\n}: LogFilterProps) {\n const [open, setOpen] = useState(false);\n const [timeMode, setTimeMode] = useState<TimeMode>(\"lookback\");\n const [lookbackIdx, setLookbackIdx] = useState(-1);\n\n // -- Derive filterable options from rows (sticky — accumulates over time) --\n const svcRef = useRef(new Set<string>());\n const sevRef = useRef(new Set<string>());\n const scopeRef = useRef(new Set<string>());\n\n const serviceNames = useMemo(() => {\n for (const r of rows) if (r.ServiceName) svcRef.current.add(r.ServiceName);\n return Array.from(svcRef.current).sort();\n }, [rows]);\n\n const severityTexts = useMemo(() => {\n for (const r of rows)\n if (r.SeverityText) sevRef.current.add(r.SeverityText);\n return Array.from(sevRef.current).sort();\n }, [rows]);\n\n const scopeNames = useMemo(() => {\n for (const r of rows) if (r.ScopeName) scopeRef.current.add(r.ScopeName);\n return Array.from(scopeRef.current).sort();\n }, [rows]);\n\n // -- Debounced text fields ------------------------------------------------\n const [bodyContains, setBodyContains] = useState(value.bodyContains ?? \"\");\n const [traceId, setTraceId] = useState(value.traceId ?? \"\");\n const [spanId, setSpanId] = useState(value.spanId ?? \"\");\n const [logAttrsText, setLogAttrsText] = useState(\"\");\n const [resAttrsText, setResAttrsText] = useState(\"\");\n const [scopeAttrsText, setScopeAttrsText] = useState(\"\");\n\n const dBodyContains = useDebouncedValue(bodyContains, DEBOUNCE_MS);\n const dTraceId = useDebouncedValue(traceId, DEBOUNCE_MS);\n const dSpanId = useDebouncedValue(spanId, DEBOUNCE_MS);\n const dLogAttrs = useDebouncedValue(logAttrsText, DEBOUNCE_MS);\n const dResAttrs = useDebouncedValue(resAttrsText, DEBOUNCE_MS);\n const dScopeAttrs = useDebouncedValue(scopeAttrsText, DEBOUNCE_MS);\n\n // Prevent calling onChange on first render\n const isFirstRender = useRef(true);\n\n // -- Sync debounced text values to parent ---------------------------------\n useEffect(() => {\n if (isFirstRender.current) {\n isFirstRender.current = false;\n return;\n }\n const next: FilterValue = { ...value };\n\n if (dBodyContains) next.bodyContains = dBodyContains;\n else delete next.bodyContains;\n\n if (dTraceId) next.traceId = dTraceId;\n else delete next.traceId;\n\n if (dSpanId) next.spanId = dSpanId;\n else delete next.spanId;\n\n const la = parseKeyValues(dLogAttrs);\n if (la) next.logAttributes = la;\n else delete next.logAttributes;\n\n const ra = parseKeyValues(dResAttrs);\n if (ra) next.resourceAttributes = ra;\n else delete next.resourceAttributes;\n\n const sa = parseKeyValues(dScopeAttrs);\n if (sa) next.scopeAttributes = sa;\n else delete next.scopeAttributes;\n\n onChange(next);\n }, [dBodyContains, dTraceId, dSpanId, dLogAttrs, dResAttrs, dScopeAttrs]);\n\n // -- Immediate change helper (selects / numbers) --------------------------\n const emitImmediate = useCallback(\n (patch: Partial<FilterValue>) => {\n const next: FilterValue = { ...value };\n for (const [k, v] of Object.entries(patch)) {\n if (v === undefined || v === \"\") {\n delete (next as Record<string, unknown>)[k];\n } else {\n (next as Record<string, unknown>)[k] = v;\n }\n }\n // Re-apply current debounced text fields so they don't get lost\n if (dBodyContains) next.bodyContains = dBodyContains;\n if (dTraceId) next.traceId = dTraceId;\n if (dSpanId) next.spanId = dSpanId;\n const la = parseKeyValues(dLogAttrs);\n if (la) next.logAttributes = la;\n const ra = parseKeyValues(dResAttrs);\n if (ra) next.resourceAttributes = ra;\n const sa = parseKeyValues(dScopeAttrs);\n if (sa) next.scopeAttributes = sa;\n onChange(next);\n },\n [\n value,\n onChange,\n dBodyContains,\n dTraceId,\n dSpanId,\n dLogAttrs,\n dResAttrs,\n dScopeAttrs,\n ]\n );\n\n // Wire up the service handler to use emitImmediate via ref\n const emitRef = useRef(emitImmediate);\n emitRef.current = emitImmediate;\n const handleServicesChangeSynced = useCallback(\n (next: string[]) => {\n onSelectedServicesChange?.(next);\n if (next.length === 1) {\n emitRef.current({ serviceName: next[0] });\n } else {\n emitRef.current({ serviceName: undefined });\n }\n },\n [onSelectedServicesChange]\n );\n\n // -- Lookback handler -----------------------------------------------------\n const handleLookback = useCallback(\n (idx: number) => {\n setLookbackIdx(idx);\n if (idx < 0) {\n emitImmediate({ timestampMin: undefined, timestampMax: undefined });\n } else {\n const opt = LOOKBACK_OPTIONS[idx];\n if (opt) {\n const tsMin = msToNs(Date.now() - opt.ms);\n emitImmediate({ timestampMin: tsMin, timestampMax: undefined });\n }\n }\n },\n [emitImmediate]\n );\n\n // -- Absolute time handlers -----------------------------------------------\n const handleAbsoluteMin = useCallback(\n (dtStr: string) => {\n if (!dtStr) {\n emitImmediate({ timestampMin: undefined });\n return;\n }\n const ms = new Date(dtStr).getTime();\n emitImmediate({ timestampMin: msToNs(ms) });\n },\n [emitImmediate]\n );\n\n const handleAbsoluteMax = useCallback(\n (dtStr: string) => {\n if (!dtStr) {\n emitImmediate({ timestampMax: undefined });\n return;\n }\n const ms = new Date(dtStr).getTime();\n emitImmediate({ timestampMax: msToNs(ms) });\n },\n [emitImmediate]\n );\n\n // -- Time mode switch -----------------------------------------------------\n const switchTimeMode = useCallback(\n (mode: TimeMode) => {\n setTimeMode(mode);\n setLookbackIdx(-1);\n emitImmediate({ timestampMin: undefined, timestampMax: undefined });\n },\n [emitImmediate]\n );\n\n // -- Filter summary for collapsed state -----------------------------------\n const summary = buildFilterSummary(value, selectedServices);\n\n return (\n <div className=\"border border-border rounded-lg\" data-testid=\"log-filter\">\n <button\n onClick={() => setOpen((v) => !v)}\n className=\"w-full flex items-center justify-between px-4 py-2.5 text-sm font-medium text-foreground hover:bg-muted/30 transition-colors\"\n data-testid=\"log-filter-toggle\"\n >\n <span className=\"flex items-center gap-2\">\n <span>\n <span className=\"underline underline-offset-4\">F</span>ilters\n </span>\n {!open && summary && (\n <span\n className=\"text-xs text-muted-foreground truncate max-w-md\"\n data-testid=\"filter-summary\"\n >\n {summary}\n </span>\n )}\n </span>\n <span className=\"text-muted-foreground text-xs\">\n {open ? \"▲\" : \"▼\"}\n </span>\n </button>\n\n {open && (\n <div className=\"px-4 pb-4 pt-1 border-t border-border space-y-3\">\n <div className=\"grid grid-cols-2 md:grid-cols-3 gap-3\">\n {/* Service Name — multi-select */}\n <div className=\"space-y-1\">\n <span className={LABEL_CLS}>Service</span>\n <MultiSelect\n options={serviceNames}\n selected={selectedServices}\n onChange={handleServicesChangeSynced}\n testId=\"filter-serviceName\"\n />\n </div>\n\n {/* Severity */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Severity</span>\n <select\n value={value.severityText ?? \"\"}\n onChange={(e) =>\n emitImmediate({\n severityText: e.target.value || undefined,\n })\n }\n className={INPUT_CLS}\n data-testid=\"filter-severityText\"\n >\n <option value=\"\">All</option>\n {severityTexts.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n </label>\n\n {/* Body Contains */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Body contains</span>\n <input\n type=\"text\"\n placeholder=\"Search log body... (/)\"\n value={bodyContains}\n onChange={(e) => setBodyContains(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-bodyContains\"\n />\n </label>\n\n {/* Sort Order */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Sort</span>\n <select\n value={value.sortOrder ?? \"DESC\"}\n onChange={(e) =>\n emitImmediate({\n sortOrder: e.target.value as \"ASC\" | \"DESC\",\n })\n }\n className={INPUT_CLS}\n data-testid=\"filter-sortOrder\"\n >\n <option value=\"DESC\">Newest first</option>\n <option value=\"ASC\">Oldest first</option>\n </select>\n </label>\n\n {/* Limit */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Limit</span>\n <input\n type=\"number\"\n min={1}\n max={1000}\n value={value.limit ?? \"\"}\n onChange={(e) => {\n const n = Number(e.target.value);\n emitImmediate({\n limit: n >= 1 && n <= 1000 ? n : undefined,\n });\n }}\n className={INPUT_CLS}\n data-testid=\"filter-limit\"\n />\n </label>\n\n {/* Trace ID */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Trace ID</span>\n <input\n type=\"text\"\n placeholder=\"Trace ID\"\n value={traceId}\n onChange={(e) => setTraceId(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-traceId\"\n />\n </label>\n\n {/* Span ID */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Span ID</span>\n <input\n type=\"text\"\n placeholder=\"Span ID\"\n value={spanId}\n onChange={(e) => setSpanId(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-spanId\"\n />\n </label>\n\n {/* Scope Name */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Scope</span>\n <select\n value={value.scopeName ?? \"\"}\n onChange={(e) =>\n emitImmediate({\n scopeName: e.target.value || undefined,\n })\n }\n className={INPUT_CLS}\n data-testid=\"filter-scopeName\"\n >\n <option value=\"\">All</option>\n {scopeNames.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n </label>\n\n {/* Log Attributes */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Log attributes</span>\n <input\n type=\"text\"\n placeholder=\"key1=val1, key2=val2\"\n value={logAttrsText}\n onChange={(e) => setLogAttrsText(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-logAttributes\"\n />\n </label>\n\n {/* Resource Attributes */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Resource attributes</span>\n <input\n type=\"text\"\n placeholder=\"key1=val1, key2=val2\"\n value={resAttrsText}\n onChange={(e) => setResAttrsText(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-resourceAttributes\"\n />\n </label>\n\n {/* Scope Attributes */}\n <label className=\"space-y-1\">\n <span className={LABEL_CLS}>Scope attributes</span>\n <input\n type=\"text\"\n placeholder=\"key1=val1, key2=val2\"\n value={scopeAttrsText}\n onChange={(e) => setScopeAttrsText(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-scopeAttributes\"\n />\n </label>\n </div>\n\n {/* Time range */}\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\">\n <span className={LABEL_CLS}>Time range</span>\n <div className=\"flex rounded-md border border-border overflow-hidden text-xs\">\n <button\n className={`px-2 py-1 ${timeMode === \"lookback\" ? \"bg-muted text-foreground\" : \"text-muted-foreground hover:bg-muted/30\"}`}\n onClick={() => switchTimeMode(\"lookback\")}\n data-testid=\"time-mode-lookback\"\n >\n Lookback\n </button>\n <button\n className={`px-2 py-1 ${timeMode === \"absolute\" ? \"bg-muted text-foreground\" : \"text-muted-foreground hover:bg-muted/30\"}`}\n onClick={() => switchTimeMode(\"absolute\")}\n data-testid=\"time-mode-absolute\"\n >\n Absolute\n </button>\n </div>\n </div>\n\n {timeMode === \"lookback\" ? (\n <select\n value={lookbackIdx}\n onChange={(e) => handleLookback(Number(e.target.value))}\n className={`${INPUT_CLS} max-w-xs`}\n data-testid=\"filter-lookback\"\n >\n <option value={-1}>All time</option>\n {LOOKBACK_OPTIONS.map((opt, i) => (\n <option key={i} value={i}>\n {opt.label}\n </option>\n ))}\n </select>\n ) : (\n <div className=\"flex items-center gap-2\">\n <label className=\"space-y-1 flex-1\">\n <span className={LABEL_CLS}>From</span>\n <input\n type=\"datetime-local\"\n value={nsToDatetimeLocal(value.timestampMin)}\n onChange={(e) => handleAbsoluteMin(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-timestampMin\"\n />\n </label>\n <label className=\"space-y-1 flex-1\">\n <span className={LABEL_CLS}>To</span>\n <input\n type=\"datetime-local\"\n value={nsToDatetimeLocal(value.timestampMax)}\n onChange={(e) => handleAbsoluteMax(e.target.value)}\n className={INPUT_CLS}\n data-testid=\"filter-timestampMax\"\n />\n </label>\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n );\n}\n","/**\n * Largest Triangle Three Buckets (LTTB) downsampling algorithm\n */\n\nexport interface LTTBPoint {\n x: number;\n y: number;\n}\n\nfunction triangleArea(p1: LTTBPoint, p2: LTTBPoint, p3: LTTBPoint): number {\n return (\n Math.abs((p1.x - p3.x) * (p2.y - p1.y) - (p1.x - p2.x) * (p3.y - p1.y)) / 2\n );\n}\n\nexport function downsampleLTTB(\n data: LTTBPoint[],\n targetPoints: number\n): LTTBPoint[] {\n if (data.length <= 2 || targetPoints >= data.length) {\n return data.slice();\n }\n if (targetPoints <= 2) {\n return [data[0]!, data[data.length - 1]!];\n }\n\n const sampled: LTTBPoint[] = [];\n const bucketSize = (data.length - 2) / (targetPoints - 2);\n\n const firstPoint = data[0];\n if (!firstPoint) return data;\n sampled.push(firstPoint);\n\n let prevSelectedIndex = 0;\n\n for (let i = 0; i < targetPoints - 2; i++) {\n const bucketStart = Math.floor((i + 0) * bucketSize) + 1;\n const bucketEnd = Math.min(\n Math.floor((i + 1) * bucketSize) + 1,\n data.length - 1\n );\n\n const nextBucketStart = Math.floor((i + 1) * bucketSize) + 1;\n const nextBucketEnd = Math.min(\n Math.floor((i + 2) * bucketSize) + 1,\n data.length - 1\n );\n\n let avgX = 0;\n let avgY = 0;\n let nextBucketCount = 0;\n\n for (let j = nextBucketStart; j < nextBucketEnd; j++) {\n const point = data[j];\n if (point) {\n avgX += point.x;\n avgY += point.y;\n nextBucketCount++;\n }\n }\n\n if (nextBucketCount > 0) {\n avgX /= nextBucketCount;\n avgY /= nextBucketCount;\n } else {\n const lastPoint = data[data.length - 1];\n if (lastPoint) {\n avgX = lastPoint.x;\n avgY = lastPoint.y;\n }\n }\n\n const avgPoint: LTTBPoint = { x: avgX, y: avgY };\n\n let maxArea = -1;\n let maxAreaIndex = bucketStart;\n\n const prevPoint = data[prevSelectedIndex];\n if (!prevPoint) continue;\n\n for (let j = bucketStart; j < bucketEnd; j++) {\n const currentPoint = data[j];\n if (!currentPoint) continue;\n const area = triangleArea(prevPoint, currentPoint, avgPoint);\n if (area > maxArea) {\n maxArea = area;\n maxAreaIndex = j;\n }\n }\n\n const selectedPoint = data[maxAreaIndex];\n if (selectedPoint) {\n sampled.push(selectedPoint);\n }\n prevSelectedIndex = maxAreaIndex;\n }\n\n const lastPoint = data[data.length - 1];\n if (lastPoint) {\n sampled.push(lastPoint);\n }\n\n return sampled;\n}\n\nexport function downsampleTimeSeries<\n T extends { timestamp: number; value: number },\n>(data: T[], targetPoints: number): T[] {\n if (targetPoints >= data.length) {\n return data;\n }\n\n const points: LTTBPoint[] = data.map((d) => ({\n x: d.timestamp,\n y: d.value,\n }));\n\n const sampled = downsampleLTTB(points, targetPoints);\n const sampledTimestamps = new Set(sampled.map((p) => p.x));\n return data.filter((d) => sampledTimestamps.has(d.timestamp));\n}\n","export interface ResolvedScale {\n divisor: number;\n suffix: string;\n label: string;\n isPercent: boolean;\n}\n\ninterface ScaleEntry {\n threshold: number;\n divisor: number;\n suffix: string;\n}\n\nconst BYTE_SCALES: ScaleEntry[] = [\n { threshold: 1e12, divisor: 1e12, suffix: \"TB\" },\n { threshold: 1e9, divisor: 1e9, suffix: \"GB\" },\n { threshold: 1e6, divisor: 1e6, suffix: \"MB\" },\n { threshold: 1e3, divisor: 1e3, suffix: \"KB\" },\n { threshold: 0, divisor: 1, suffix: \"B\" },\n];\n\nconst SECOND_SCALES: ScaleEntry[] = [\n { threshold: 3600, divisor: 3600, suffix: \"h\" },\n { threshold: 60, divisor: 60, suffix: \"min\" },\n { threshold: 1, divisor: 1, suffix: \"s\" },\n { threshold: 0, divisor: 0.001, suffix: \"ms\" },\n];\n\nconst MS_SCALES: ScaleEntry[] = [\n { threshold: 1000, divisor: 1000, suffix: \"s\" },\n { threshold: 0, divisor: 1, suffix: \"ms\" },\n];\n\nconst US_SCALES: ScaleEntry[] = [\n { threshold: 1e6, divisor: 1e6, suffix: \"s\" },\n { threshold: 1000, divisor: 1000, suffix: \"ms\" },\n { threshold: 0, divisor: 1, suffix: \"\\u03BCs\" },\n];\n\nconst GENERIC_SCALES: ScaleEntry[] = [\n { threshold: 1e9, divisor: 1e9, suffix: \"B\" },\n { threshold: 1e6, divisor: 1e6, suffix: \"M\" },\n { threshold: 1e3, divisor: 1e3, suffix: \"K\" },\n { threshold: 0, divisor: 1, suffix: \"\" },\n];\n\nconst BRACE_UNIT_PATTERN = /^\\{(.+)\\}$/;\n\nconst UNIT_SCALE_MAP: Record<string, ScaleEntry[]> = {\n By: BYTE_SCALES,\n s: SECOND_SCALES,\n ms: MS_SCALES,\n us: US_SCALES,\n};\n\nfunction pickScale(scales: ScaleEntry[], maxValue: number): ScaleEntry {\n const abs = Math.abs(maxValue);\n for (const s of scales) {\n if (abs >= s.threshold && s.threshold > 0) return s;\n }\n return scales[scales.length - 1]!;\n}\n\nexport function resolveUnitScale(\n unit: string | null | undefined,\n maxValue: number\n): ResolvedScale {\n if (!unit) {\n const s = pickScale(GENERIC_SCALES, maxValue);\n return {\n divisor: s.divisor,\n suffix: s.suffix,\n label: \"\",\n isPercent: false,\n };\n }\n\n // Dimensionless ratio → percent\n if (unit === \"1\") {\n return { divisor: 0.01, suffix: \"%\", label: \"Percent\", isPercent: true };\n }\n\n // Known unit families\n const scales = UNIT_SCALE_MAP[unit];\n if (scales) {\n const s = pickScale(scales, maxValue);\n return {\n divisor: s.divisor,\n suffix: s.suffix,\n label: s.suffix,\n isPercent: false,\n };\n }\n\n // Curly-brace units like {requests}\n const braceMatch = BRACE_UNIT_PATTERN.exec(unit);\n if (braceMatch) {\n const cleaned = braceMatch[1]!;\n const s = pickScale(GENERIC_SCALES, maxValue);\n const suffix = s.suffix ? `${s.suffix} ${cleaned}` : cleaned;\n return { divisor: s.divisor, suffix, label: cleaned, isPercent: false };\n }\n\n // Unknown unit — generic scaling + append unit\n const s = pickScale(GENERIC_SCALES, maxValue);\n const suffix = s.suffix ? `${s.suffix} ${unit}` : unit;\n return { divisor: s.divisor, suffix, label: unit, isPercent: false };\n}\n\nexport function formatTickValue(value: number, scale: ResolvedScale): string {\n const scaled = value / scale.divisor;\n if (scale.isPercent) return `${scaled.toFixed(1)}`;\n if (Number.isInteger(scaled) && Math.abs(scaled) < 1e4)\n return scaled.toString();\n return scaled.toFixed(1);\n}\n\nexport function formatDisplayValue(\n value: number,\n scale: ResolvedScale\n): string {\n const tick = formatTickValue(value, scale);\n if (!scale.suffix) return tick;\n if (scale.isPercent) return `${tick}${scale.suffix}`;\n return `${tick} ${scale.suffix}`;\n}\n\n/** Convenience: resolve + format in one call (for MetricStat) */\nexport function formatOtelValue(value: number, unit: string): string {\n const scale = resolveUnitScale(unit, Math.abs(value));\n return formatDisplayValue(value, scale);\n}\n","/**\n * MetricTimeSeries - Accepts OtelMetricsRow[] and renders line charts.\n */\n\nimport { useMemo, useState, useCallback } from \"react\";\nimport {\n LineChart,\n Line,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n Legend,\n ResponsiveContainer,\n Brush,\n ReferenceLine,\n} from \"recharts\";\nimport type { denormalizedSignals } from \"@kopai/core\";\nimport type {\n ParsedMetricGroup,\n MetricSeries,\n RechartsDataPoint,\n} from \"../types.js\";\nimport { downsampleLTTB, type LTTBPoint } from \"../utils/lttb.js\";\nimport { formatSeriesLabel } from \"../utils/attributes.js\";\nimport {\n resolveUnitScale,\n formatTickValue,\n formatDisplayValue,\n} from \"../utils/units.js\";\n\ntype OtelMetricsRow = denormalizedSignals.OtelMetricsRow;\n\nconst COLORS = [\n \"#8884d8\",\n \"#82ca9d\",\n \"#ffc658\",\n \"#ff7300\",\n \"#00C49F\",\n \"#0088FE\",\n \"#FFBB28\",\n \"#FF8042\",\n \"#a4de6c\",\n \"#d0ed57\",\n];\n\nexport interface ThresholdLine {\n value: number;\n color: string;\n label?: string;\n style?: \"solid\" | \"dashed\" | \"dotted\";\n}\n\nexport interface MetricTimeSeriesProps {\n rows: OtelMetricsRow[];\n isLoading?: boolean;\n error?: Error;\n maxDataPoints?: number;\n showBrush?: boolean;\n height?: number;\n unit?: string;\n yAxisLabel?: string;\n formatTime?: (timestamp: number) => string;\n formatValue?: (value: number) => string;\n onBrushChange?: (startTime: number, endTime: number) => void;\n legendMaxLength?: number;\n thresholdLines?: ThresholdLine[];\n}\n\nconst defaultFormatTime = (timestamp: number): string => {\n const date = new Date(timestamp);\n return date.toLocaleTimeString(\"en-US\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hour12: false,\n });\n};\n\nfunction getStrokeDashArray(\n style?: \"solid\" | \"dashed\" | \"dotted\"\n): string | undefined {\n if (style === \"solid\") return undefined;\n if (style === \"dotted\") return \"2 2\";\n return \"5 5\";\n}\n\n/** Build metrics from denormalized rows */\nfunction buildMetrics(rows: OtelMetricsRow[]): ParsedMetricGroup[] {\n const metricMap = new Map<string, Map<string, MetricSeries>>();\n const metricMeta = new Map<\n string,\n { description: string; unit: string; type: string; serviceName: string }\n >();\n\n for (const row of rows) {\n const name = row.MetricName ?? \"unknown\";\n const type = row.MetricType;\n if (\n type === \"Histogram\" ||\n type === \"ExponentialHistogram\" ||\n type === \"Summary\"\n )\n continue; // TimeSeries only handles Gauge/Sum\n\n if (!metricMap.has(name)) metricMap.set(name, new Map());\n if (!metricMeta.has(name))\n metricMeta.set(name, {\n description: row.MetricDescription ?? \"\",\n unit: row.MetricUnit ?? \"\",\n type,\n serviceName: row.ServiceName ?? \"unknown\",\n });\n\n const seriesKey = row.Attributes\n ? JSON.stringify(\n Object.fromEntries(\n Object.entries(row.Attributes).sort(([a], [b]) =>\n a.localeCompare(b)\n )\n )\n )\n : \"__default__\";\n const seriesMap = metricMap.get(name)!;\n\n if (!seriesMap.has(seriesKey)) {\n const labels: Record<string, string> = {};\n if (row.Attributes) {\n for (const [k, v] of Object.entries(row.Attributes))\n labels[k] = String(v);\n }\n seriesMap.set(seriesKey, {\n key: seriesKey === \"__default__\" ? name : seriesKey,\n labels,\n dataPoints: [],\n });\n }\n\n if (!(\"Value\" in row)) continue;\n const value = row.Value;\n const timestamp = parseInt(row.TimeUnix, 10) / 1e6;\n seriesMap.get(seriesKey)!.dataPoints.push({ timestamp, value });\n }\n\n const results: ParsedMetricGroup[] = [];\n for (const [name, seriesMap] of metricMap) {\n const meta = metricMeta.get(name)!;\n const series = Array.from(seriesMap.values());\n for (const s of series)\n s.dataPoints.sort((a, b) => a.timestamp - b.timestamp);\n results.push({\n name,\n description: meta.description,\n unit: meta.unit,\n type: meta.type as ParsedMetricGroup[\"type\"],\n series,\n serviceName: meta.serviceName,\n });\n }\n return results;\n}\n\nfunction toRechartsData(metrics: ParsedMetricGroup[]): RechartsDataPoint[] {\n const timestampMap = new Map<number, RechartsDataPoint>();\n for (const metric of metrics) {\n for (const series of metric.series) {\n const seriesName =\n series.key === \"__default__\" ? metric.name : series.key;\n for (const dp of series.dataPoints) {\n if (!timestampMap.has(dp.timestamp))\n timestampMap.set(dp.timestamp, { timestamp: dp.timestamp });\n timestampMap.get(dp.timestamp)![seriesName] = dp.value;\n }\n }\n }\n return Array.from(timestampMap.values()).sort(\n (a, b) => a.timestamp - b.timestamp\n );\n}\n\nfunction getSeriesKeys(metrics: ParsedMetricGroup[]): string[] {\n const keys = new Set<string>();\n for (const m of metrics)\n for (const s of m.series)\n keys.add(s.key === \"__default__\" ? m.name : s.key);\n return Array.from(keys);\n}\n\nfunction buildDisplayLabelMap(\n metrics: ParsedMetricGroup[]\n): Map<string, string> {\n const map = new Map<string, string>();\n for (const m of metrics) {\n for (const s of m.series) {\n const dataKey = s.key === \"__default__\" ? m.name : s.key;\n const label = formatSeriesLabel(s.labels);\n map.set(dataKey, label || m.name);\n }\n }\n return map;\n}\n\nfunction downsampleRechartsData(\n data: RechartsDataPoint[],\n seriesKeys: string[],\n maxPoints: number\n): RechartsDataPoint[] {\n if (data.length <= maxPoints) return data;\n const timestamps = new Set<number>();\n for (const key of seriesKeys) {\n const pts: LTTBPoint[] = [];\n for (const d of data) {\n const v = d[key];\n if (v !== undefined) pts.push({ x: d.timestamp, y: v });\n }\n if (pts.length === 0) continue;\n const ds = downsampleLTTB(pts, Math.ceil(maxPoints / seriesKeys.length));\n for (const p of ds) timestamps.add(p.x);\n }\n return data.filter((d) => timestamps.has(d.timestamp));\n}\n\nexport function MetricTimeSeries({\n rows,\n isLoading = false,\n error,\n maxDataPoints = 500,\n showBrush = true,\n height = 400,\n unit: unitProp,\n yAxisLabel,\n formatTime = defaultFormatTime,\n formatValue,\n onBrushChange,\n legendMaxLength = 30,\n thresholdLines,\n}: MetricTimeSeriesProps) {\n const [hiddenSeries, setHiddenSeries] = useState<Set<string>>(new Set());\n\n const parsedMetrics = useMemo(() => buildMetrics(rows), [rows]);\n const effectiveUnit = unitProp ?? parsedMetrics[0]?.unit ?? \"\";\n const chartData = useMemo(\n () => toRechartsData(parsedMetrics),\n [parsedMetrics]\n );\n const seriesKeys = useMemo(\n () => getSeriesKeys(parsedMetrics),\n [parsedMetrics]\n );\n const displayLabelMap = useMemo(\n () => buildDisplayLabelMap(parsedMetrics),\n [parsedMetrics]\n );\n const displayData = useMemo(\n () => downsampleRechartsData(chartData, seriesKeys, maxDataPoints),\n [chartData, seriesKeys, maxDataPoints]\n );\n\n const { tickFormatter, displayFormatter, resolvedYAxisLabel } =\n useMemo(() => {\n let max = 0;\n for (const dp of displayData) {\n for (const key of seriesKeys) {\n const v = dp[key];\n if (v !== undefined && Math.abs(v) > max) max = Math.abs(v);\n }\n }\n const scale = resolveUnitScale(effectiveUnit, max);\n return {\n tickFormatter:\n formatValue ?? ((v: number) => formatTickValue(v, scale)),\n displayFormatter:\n formatValue ?? ((v: number) => formatDisplayValue(v, scale)),\n resolvedYAxisLabel: yAxisLabel ?? (scale.label || undefined),\n };\n }, [displayData, seriesKeys, effectiveUnit, formatValue, yAxisLabel]);\n\n const handleLegendClick = useCallback((dataKey: string) => {\n setHiddenSeries((prev) => {\n const next = new Set(prev);\n if (next.has(dataKey)) next.delete(dataKey);\n else next.add(dataKey);\n return next;\n });\n }, []);\n\n const handleBrushChange = useCallback(\n (brushData: { startIndex?: number; endIndex?: number }) => {\n if (!onBrushChange || !displayData.length) return;\n const { startIndex, endIndex } = brushData;\n if (startIndex === undefined || endIndex === undefined) return;\n const sp = displayData[startIndex],\n ep = displayData[endIndex];\n if (sp && ep) onBrushChange(sp.timestamp, ep.timestamp);\n },\n [displayData, onBrushChange]\n );\n\n if (isLoading) return <MetricLoadingSkeleton height={height} />;\n\n if (error) {\n return (\n <div\n className=\"flex items-center justify-center bg-background rounded-lg border border-red-800\"\n style={{ height }}\n >\n <div className=\"text-center p-4\">\n <p className=\"text-red-400 font-medium\">Error loading metrics</p>\n <p className=\"text-gray-500 text-sm mt-1\">{error.message}</p>\n </div>\n </div>\n );\n }\n\n if (rows.length === 0 || displayData.length === 0) {\n return (\n <div\n className=\"flex items-center justify-center bg-background rounded-lg border border-gray-800\"\n style={{ height }}\n >\n <p className=\"text-gray-500\">No metric data available</p>\n </div>\n );\n }\n\n return (\n <div\n className=\"bg-background rounded-lg p-4\"\n style={{ height }}\n data-testid=\"metric-time-series\"\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <LineChart\n data={displayData}\n margin={{ top: 5, right: 30, left: 20, bottom: 5 }}\n >\n <CartesianGrid strokeDasharray=\"3 3\" stroke=\"#374151\" />\n <XAxis\n dataKey=\"timestamp\"\n tickFormatter={formatTime}\n stroke=\"#9CA3AF\"\n tick={{ fill: \"#9CA3AF\", fontSize: 12 }}\n />\n <YAxis\n tickFormatter={tickFormatter}\n stroke=\"#9CA3AF\"\n tick={{ fill: \"#9CA3AF\", fontSize: 12 }}\n label={\n resolvedYAxisLabel\n ? {\n value: resolvedYAxisLabel,\n angle: -90,\n position: \"insideLeft\",\n fill: \"#9CA3AF\",\n }\n : undefined\n }\n />\n <Tooltip\n content={(props) => (\n <CustomTooltip\n {...props}\n formatTime={formatTime}\n formatValue={displayFormatter}\n displayLabelMap={displayLabelMap}\n />\n )}\n />\n <Legend\n onClick={(e) => {\n const dk = e?.dataKey;\n if (typeof dk === \"string\") handleLegendClick(dk);\n }}\n formatter={(value: string) => {\n const label = displayLabelMap.get(value) ?? value;\n const truncated =\n label.length > legendMaxLength\n ? label.slice(0, legendMaxLength - 3) + \"...\"\n : label;\n const isHidden = hiddenSeries.has(value);\n return (\n <span\n style={{\n color: isHidden ? \"#6B7280\" : \"#E5E7EB\",\n textDecoration: isHidden ? \"line-through\" : \"none\",\n cursor: \"pointer\",\n }}\n title={truncated !== label ? label : undefined}\n >\n {truncated}\n </span>\n );\n }}\n />\n {thresholdLines?.map((t, i) => (\n <ReferenceLine\n key={`t-${i}`}\n y={t.value}\n stroke={t.color}\n strokeDasharray={getStrokeDashArray(t.style)}\n strokeWidth={1.5}\n label={\n t.label\n ? {\n value: t.label,\n position: \"right\",\n fill: t.color,\n fontSize: 11,\n }\n : undefined\n }\n />\n ))}\n {seriesKeys.map((key, i) => (\n <Line\n key={key}\n type=\"monotone\"\n dataKey={key}\n stroke={COLORS[i % COLORS.length]}\n strokeWidth={2}\n dot={false}\n activeDot={{ r: 4 }}\n hide={hiddenSeries.has(key)}\n connectNulls\n />\n ))}\n {showBrush && displayData.length > 10 && (\n <Brush\n dataKey=\"timestamp\"\n height={30}\n stroke=\"#6B7280\"\n fill=\"#1F2937\"\n tickFormatter={formatTime}\n onChange={handleBrushChange}\n />\n )}\n </LineChart>\n </ResponsiveContainer>\n </div>\n );\n}\n\nfunction CustomTooltip({\n active,\n payload,\n label,\n formatTime,\n formatValue,\n displayLabelMap,\n}: {\n active?: boolean;\n payload?: readonly { dataKey: string; value: number; color: string }[];\n label?: string | number;\n formatTime: (ts: number) => string;\n formatValue: (val: number) => string;\n displayLabelMap: Map<string, string>;\n}) {\n if (!active || !payload || label == null) return null;\n const ts = typeof label === \"number\" ? label : Number(label);\n return (\n <div className=\"bg-background border border-gray-700 rounded-lg p-3 shadow-lg\">\n <p className=\"text-gray-400 text-xs mb-2\">{formatTime(ts)}</p>\n {payload.map((entry, i) => (\n <p key={i} className=\"text-sm\" style={{ color: entry.color }}>\n <span className=\"font-medium\">\n {displayLabelMap.get(entry.dataKey) ?? entry.dataKey}:\n </span>{\" \"}\n {formatValue(entry.value)}\n </p>\n ))}\n </div>\n );\n}\n\nfunction MetricLoadingSkeleton({ height = 400 }: { height?: number }) {\n return (\n <div\n className=\"bg-background rounded-lg p-4 animate-pulse\"\n style={{ height }}\n data-testid=\"metric-time-series-loading\"\n >\n <div className=\"h-full flex flex-col\">\n <div className=\"flex flex-1 gap-2\">\n <div className=\"flex flex-col justify-between w-12\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-3 w-8 bg-gray-700 rounded\" />\n ))}\n </div>\n <div className=\"flex-1 relative\">\n <div className=\"absolute inset-0 flex flex-col justify-between\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-px bg-gray-800\" />\n ))}\n </div>\n </div>\n </div>\n <div className=\"flex justify-between mt-2 px-14\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-3 w-12 bg-gray-700 rounded\" />\n ))}\n </div>\n </div>\n </div>\n );\n}\n","/**\n * MetricHistogram - Accepts OtelMetricsRow[] and renders histogram bar charts.\n */\n\nimport { useMemo } from \"react\";\nimport {\n BarChart,\n Bar,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n Legend,\n ResponsiveContainer,\n Cell,\n} from \"recharts\";\nimport type { denormalizedSignals } from \"@kopai/core\";\nimport { formatSeriesLabel } from \"../utils/attributes.js\";\nimport {\n resolveUnitScale,\n formatDisplayValue,\n type ResolvedScale,\n} from \"../utils/units.js\";\n\ntype OtelMetricsRow = denormalizedSignals.OtelMetricsRow;\n\nconst COLORS = [\n \"#8884d8\",\n \"#82ca9d\",\n \"#ffc658\",\n \"#ff7300\",\n \"#00C49F\",\n \"#0088FE\",\n];\n\nexport interface MetricHistogramProps {\n rows: OtelMetricsRow[];\n isLoading?: boolean;\n error?: Error;\n height?: number;\n unit?: string;\n yAxisLabel?: string;\n showLegend?: boolean;\n formatBucketLabel?: (\n bound: number,\n index: number,\n bounds: number[]\n ) => string;\n formatValue?: (value: number) => string;\n labelStyle?: \"rotated\" | \"staggered\" | \"abbreviated\";\n}\n\ninterface BucketData {\n bucket: string;\n lowerBound: number;\n upperBound: number;\n [seriesKey: string]: number | string;\n}\n\nconst defaultFormatBucketLabel = (\n bound: number,\n index: number,\n bounds: number[]\n): string => {\n if (index === 0) return `≤${bound}`;\n if (index === bounds.length) return `>${bounds[bounds.length - 1]}`;\n return `${bounds[index - 1]}-${bound}`;\n};\n\nconst defaultFormatValue = (value: number): string => {\n if (value >= 1e6) return `${(value / 1e6).toFixed(1)}M`;\n if (value >= 1e3) return `${(value / 1e3).toFixed(1)}K`;\n return value.toFixed(0);\n};\n\nfunction buildHistogramData(\n rows: OtelMetricsRow[],\n formatLabel = defaultFormatBucketLabel\n): {\n buckets: BucketData[];\n seriesKeys: string[];\n displayLabelMap: Map<string, string>;\n unit: string;\n} {\n const buckets: BucketData[] = [];\n const seriesKeysSet = new Set<string>();\n const displayLabelMap = new Map<string, string>();\n let unit = \"\";\n\n for (const row of rows) {\n if (row.MetricType !== \"Histogram\") continue;\n if (!unit && row.MetricUnit) unit = row.MetricUnit;\n const name = row.MetricName ?? \"count\";\n const key = row.Attributes ? JSON.stringify(row.Attributes) : \"__default__\";\n const seriesName = key === \"__default__\" ? name : key;\n seriesKeysSet.add(seriesName);\n\n if (!displayLabelMap.has(seriesName)) {\n if (key === \"__default__\") {\n displayLabelMap.set(seriesName, name);\n } else {\n const labels: Record<string, string> = {};\n if (row.Attributes) {\n for (const [k, v] of Object.entries(row.Attributes))\n labels[k] = String(v);\n }\n displayLabelMap.set(seriesName, formatSeriesLabel(labels) || name);\n }\n }\n\n const bounds = row.ExplicitBounds ?? [];\n const counts = row.BucketCounts ?? [];\n\n for (let i = 0; i < counts.length; i++) {\n const count = counts[i] ?? 0;\n const upperBound = i < bounds.length ? bounds[i]! : Infinity;\n const bucketLabel = formatLabel(upperBound, i, bounds);\n\n let bucket = buckets.find((b) => b.bucket === bucketLabel);\n if (!bucket) {\n bucket = {\n bucket: bucketLabel,\n lowerBound: i === 0 ? 0 : (bounds[i - 1] ?? 0),\n upperBound: bounds[i] ?? Infinity,\n };\n buckets.push(bucket);\n }\n bucket[seriesName] = ((bucket[seriesName] as number) ?? 0) + count;\n }\n }\n\n buckets.sort((a, b) => a.lowerBound - b.lowerBound);\n return {\n buckets,\n seriesKeys: Array.from(seriesKeysSet),\n displayLabelMap,\n unit,\n };\n}\n\nexport function MetricHistogram({\n rows,\n isLoading = false,\n error,\n height = 400,\n unit: unitProp,\n yAxisLabel,\n showLegend = true,\n formatBucketLabel,\n formatValue = defaultFormatValue,\n labelStyle = \"staggered\",\n}: MetricHistogramProps) {\n const bucketLabelFormatter = formatBucketLabel ?? defaultFormatBucketLabel;\n\n const { buckets, seriesKeys, displayLabelMap, unit } = useMemo(() => {\n if (rows.length === 0)\n return {\n buckets: [],\n seriesKeys: [],\n displayLabelMap: new Map(),\n unit: \"\",\n };\n return buildHistogramData(rows, bucketLabelFormatter);\n }, [rows, bucketLabelFormatter]);\n\n const effectiveUnit = unitProp ?? unit;\n\n const boundsScale = useMemo(() => {\n if (!effectiveUnit || buckets.length === 0) return null;\n // Buckets are sorted by lowerBound — walk backwards to find last finite upperBound\n for (let i = buckets.length - 1; i >= 0; i--) {\n if (buckets[i]!.upperBound !== Infinity)\n return resolveUnitScale(effectiveUnit, buckets[i]!.upperBound);\n }\n return null;\n }, [effectiveUnit, buckets]);\n\n if (isLoading) return <HistogramLoadingSkeleton height={height} />;\n\n if (error) {\n return (\n <div\n className=\"flex items-center justify-center bg-background rounded-lg border border-red-800\"\n style={{ height }}\n >\n <div className=\"text-center p-4\">\n <p className=\"text-red-400 font-medium\">Error loading histogram</p>\n <p className=\"text-gray-500 text-sm mt-1\">{error.message}</p>\n </div>\n </div>\n );\n }\n\n if (rows.length === 0 || buckets.length === 0) {\n return (\n <div\n className=\"flex items-center justify-center bg-background rounded-lg border border-gray-800\"\n style={{ height }}\n >\n <p className=\"text-gray-500\">No histogram data available</p>\n </div>\n );\n }\n\n return (\n <div\n className=\"bg-background rounded-lg p-4\"\n style={{ height }}\n data-testid=\"metric-histogram\"\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart\n data={buckets}\n margin={{ top: 5, right: 30, left: 20, bottom: 5 }}\n >\n <CartesianGrid strokeDasharray=\"3 3\" stroke=\"#374151\" />\n <XAxis\n dataKey=\"bucket\"\n stroke=\"#9CA3AF\"\n tick={\n labelStyle === \"staggered\"\n ? (props: {\n x?: string | number;\n y?: string | number;\n payload?: { value: string; index: number };\n }) => {\n if (!props.payload) return <g />;\n const yOffset = props.payload.index % 2 === 0 ? 0 : 12;\n return (\n <g transform={`translate(${props.x},${props.y})`}>\n <text\n x={0}\n y={yOffset}\n dy={12}\n textAnchor=\"middle\"\n fill=\"#9CA3AF\"\n fontSize={11}\n >\n {props.payload.value}\n </text>\n </g>\n );\n }\n : { fill: \"#9CA3AF\", fontSize: 11 }\n }\n angle={labelStyle === \"rotated\" ? -45 : 0}\n textAnchor={labelStyle === \"rotated\" ? \"end\" : \"middle\"}\n height={labelStyle === \"staggered\" ? 50 : 60}\n interval={0}\n />\n <YAxis\n tickFormatter={formatValue}\n stroke=\"#9CA3AF\"\n tick={{ fill: \"#9CA3AF\", fontSize: 12 }}\n label={\n yAxisLabel\n ? {\n value: yAxisLabel,\n angle: -90,\n position: \"insideLeft\",\n fill: \"#9CA3AF\",\n }\n : undefined\n }\n />\n <Tooltip\n content={(props) => (\n <HistogramTooltip\n {...props}\n formatValue={formatValue}\n boundsScale={boundsScale}\n displayLabelMap={displayLabelMap}\n />\n )}\n />\n {showLegend && seriesKeys.length > 1 && (\n <Legend\n formatter={(value: string) => displayLabelMap.get(value) ?? value}\n />\n )}\n {seriesKeys.map((key, i) => (\n <Bar\n key={key}\n dataKey={key}\n fill={COLORS[i % COLORS.length]}\n radius={[4, 4, 0, 0]}\n >\n {buckets.map((_, bi) => (\n <Cell key={`cell-${bi}`} fill={COLORS[i % COLORS.length]} />\n ))}\n </Bar>\n ))}\n </BarChart>\n </ResponsiveContainer>\n </div>\n );\n}\n\nfunction HistogramTooltip({\n active,\n payload,\n formatValue,\n boundsScale,\n displayLabelMap,\n}: {\n active?: boolean;\n payload?: readonly {\n dataKey: string;\n value: number;\n color: string;\n payload: BucketData;\n }[];\n formatValue: (val: number) => string;\n boundsScale: ResolvedScale | null;\n displayLabelMap: Map<string, string>;\n}) {\n if (!active || !payload?.length) return null;\n const bucket = payload[0]?.payload;\n if (!bucket) return null;\n\n const boundsLabel = boundsScale\n ? `${formatDisplayValue(bucket.lowerBound, boundsScale)} – ${bucket.upperBound === Infinity ? \"∞\" : formatDisplayValue(bucket.upperBound, boundsScale)}`\n : bucket.bucket;\n\n return (\n <div className=\"bg-background border border-gray-700 rounded-lg p-3 shadow-lg\">\n <p className=\"text-gray-300 text-sm font-medium mb-2\">\n Bucket: {boundsLabel}\n </p>\n {payload.map((entry, i) => (\n <p key={i} className=\"text-sm\" style={{ color: entry.color }}>\n <span className=\"font-medium\">\n {displayLabelMap.get(entry.dataKey) ?? entry.dataKey}:\n </span>{\" \"}\n {formatValue(entry.value)}\n </p>\n ))}\n </div>\n );\n}\n\nfunction HistogramLoadingSkeleton({ height = 400 }: { height?: number }) {\n return (\n <div\n className=\"bg-background rounded-lg p-4 animate-pulse\"\n style={{ height }}\n data-testid=\"metric-histogram-loading\"\n >\n <div className=\"h-full flex flex-col\">\n <div className=\"flex flex-1 gap-2\">\n <div className=\"flex flex-col justify-between w-12\">\n {[1, 2, 3, 4].map((i) => (\n <div key={i} className=\"h-3 w-8 bg-gray-700 rounded\" />\n ))}\n </div>\n <div className=\"flex-1 flex items-end justify-around gap-2 pb-8\">\n {[30, 50, 80, 65, 45, 25, 15, 8].map((h, i) => (\n <div\n key={i}\n className=\"w-8 bg-gray-700 rounded-t\"\n style={{ height: `${h}%` }}\n />\n ))}\n </div>\n </div>\n </div>\n </div>\n );\n}\n","/**\n * MetricStat - Accepts OtelMetricsRow[] and renders stat cards with optional sparklines.\n */\n\nimport { useMemo } from \"react\";\nimport { AreaChart, Area, ResponsiveContainer, YAxis } from \"recharts\";\nimport type { denormalizedSignals } from \"@kopai/core\";\nimport type { MetricDataPoint } from \"../types.js\";\n\ntype OtelMetricsRow = denormalizedSignals.OtelMetricsRow;\n\nexport interface ThresholdConfig {\n value: number;\n color: \"green\" | \"yellow\" | \"red\" | string;\n}\n\nexport interface MetricStatProps {\n rows: OtelMetricsRow[];\n isLoading?: boolean;\n error?: Error;\n label?: string;\n formatValue?: (value: number, unit: string) => string;\n showTimestamp?: boolean;\n trend?: \"up\" | \"down\" | \"neutral\";\n trendValue?: number;\n className?: string;\n showSparkline?: boolean;\n sparklinePoints?: number;\n sparklineHeight?: number;\n thresholds?: ThresholdConfig[];\n colorBackground?: boolean;\n colorValue?: boolean;\n}\n\nconst THRESHOLD_COLORS: Record<\n string,\n { bg: string; border: string; text: string; stroke: string; fill: string }\n> = {\n green: {\n bg: \"bg-green-900/20\",\n border: \"border-green-700\",\n text: \"text-green-400\",\n stroke: \"#4ade80\",\n fill: \"#22c55e\",\n },\n yellow: {\n bg: \"bg-yellow-900/20\",\n border: \"border-yellow-700\",\n text: \"text-yellow-400\",\n stroke: \"#facc15\",\n fill: \"#eab308\",\n },\n red: {\n bg: \"bg-red-900/20\",\n border: \"border-red-700\",\n text: \"text-red-400\",\n stroke: \"#f87171\",\n fill: \"#ef4444\",\n },\n gray: {\n bg: \"bg-background\",\n border: \"border-gray-800\",\n text: \"text-gray-400\",\n stroke: \"#9ca3af\",\n fill: \"#6b7280\",\n },\n};\n\nfunction getColorConfig(color: string) {\n return (\n THRESHOLD_COLORS[color] ?? {\n bg: \"bg-background\",\n border: \"border-gray-800\",\n text: \"text-gray-400\",\n stroke: color,\n fill: color,\n }\n );\n}\n\nfunction getThresholdColor(\n value: number,\n thresholds: ThresholdConfig[]\n): string {\n const sorted = [...thresholds].sort((a, b) => a.value - b.value);\n for (const t of sorted) if (value < t.value) return t.color;\n return sorted[sorted.length - 1]?.color ?? \"gray\";\n}\n\nconst defaultFormatValue = (value: number, unit: string): string => {\n let formatted: string;\n if (Math.abs(value) >= 1e6) formatted = `${(value / 1e6).toFixed(1)}M`;\n else if (Math.abs(value) >= 1e3) formatted = `${(value / 1e3).toFixed(1)}K`;\n else if (Number.isInteger(value)) formatted = value.toString();\n else formatted = value.toFixed(2);\n return unit ? `${formatted} ${unit}` : formatted;\n};\n\nfunction buildStatData(rows: OtelMetricsRow[]): {\n latestValue: number | null;\n unit: string;\n timestamp: number;\n dataPoints: MetricDataPoint[];\n metricName: string;\n} {\n let latestTimestamp = 0;\n let latestValue: number | null = null;\n let unit = \"\";\n let metricName = \"Metric\";\n const dataPoints: MetricDataPoint[] = [];\n\n for (const row of rows) {\n if (\n row.MetricType === \"Histogram\" ||\n row.MetricType === \"ExponentialHistogram\" ||\n row.MetricType === \"Summary\"\n )\n continue;\n const timestamp = parseInt(row.TimeUnix, 10) / 1e6;\n const value = \"Value\" in row ? row.Value : 0;\n if (!unit && row.MetricUnit) unit = row.MetricUnit;\n if (!metricName || metricName === \"Metric\")\n metricName = row.MetricName ?? \"Metric\";\n dataPoints.push({ timestamp, value });\n if (timestamp > latestTimestamp) {\n latestTimestamp = timestamp;\n latestValue = value;\n }\n }\n\n dataPoints.sort((a, b) => a.timestamp - b.timestamp);\n return {\n latestValue,\n unit,\n timestamp: latestTimestamp,\n dataPoints,\n metricName,\n };\n}\n\nexport function MetricStat({\n rows,\n isLoading = false,\n error,\n label,\n formatValue = defaultFormatValue,\n showTimestamp = false,\n trend,\n trendValue,\n className = \"\",\n showSparkline = false,\n sparklinePoints = 20,\n sparklineHeight = 40,\n thresholds,\n colorBackground,\n colorValue = false,\n}: MetricStatProps) {\n const { latestValue, unit, timestamp, dataPoints, metricName } = useMemo(\n () => buildStatData(rows),\n [rows]\n );\n\n const sparklineData = useMemo(() => {\n if (!showSparkline || dataPoints.length === 0) return [];\n return dataPoints\n .slice(-sparklinePoints)\n .map((dp) => ({ value: dp.value }));\n }, [dataPoints, showSparkline, sparklinePoints]);\n\n const thresholdColor = useMemo(() => {\n if (!thresholds || latestValue === null) return \"gray\";\n return getThresholdColor(latestValue, thresholds);\n }, [thresholds, latestValue]);\n\n const colorConfig = getColorConfig(thresholdColor);\n const shouldColorBackground = colorBackground ?? thresholds !== undefined;\n const displayLabel = label ?? metricName;\n const bgClass = shouldColorBackground ? colorConfig.bg : \"bg-background\";\n const borderClass = shouldColorBackground\n ? `border ${colorConfig.border}`\n : \"\";\n const valueClass = colorValue ? colorConfig.text : \"text-white\";\n\n if (isLoading) {\n return (\n <div\n className={`bg-background rounded-lg p-4 animate-pulse ${className}`}\n data-testid=\"metric-stat-loading\"\n >\n <div className=\"h-4 w-24 bg-gray-700 rounded mb-2\" />\n <div className=\"h-10 w-32 bg-gray-700 rounded\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div\n className={`bg-background rounded-lg p-4 border border-red-800 ${className}`}\n data-testid=\"metric-stat-error\"\n >\n <p className=\"text-red-400 text-sm\">{error.message}</p>\n </div>\n );\n }\n\n if (latestValue === null) {\n return (\n <div\n className={`bg-background rounded-lg p-4 border border-gray-800 ${className}`}\n data-testid=\"metric-stat-empty\"\n >\n <p className=\"text-gray-500 text-sm\">{displayLabel}</p>\n <p className=\"text-gray-600 text-2xl font-semibold\">--</p>\n </div>\n );\n }\n\n return (\n <div\n className={`${bgClass} ${borderClass} rounded-lg p-4 ${className}`}\n data-testid=\"metric-stat\"\n >\n <div className=\"flex items-center justify-between mb-1\">\n <p className=\"text-gray-400 text-sm font-medium\">{displayLabel}</p>\n {trend && <TrendIndicator direction={trend} value={trendValue} />}\n </div>\n <p className={`${valueClass} text-3xl font-bold`}>\n {formatValue(latestValue, unit)}\n </p>\n {showTimestamp && (\n <p className=\"text-gray-500 text-xs mt-1\">\n {new Date(timestamp).toLocaleTimeString()}\n </p>\n )}\n {showSparkline && sparklineData.length > 0 && (\n <div className=\"mt-2\" style={{ height: sparklineHeight }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart\n data={sparklineData}\n margin={{ top: 0, right: 0, left: 0, bottom: 0 }}\n >\n <YAxis domain={[\"dataMin\", \"dataMax\"]} hide />\n <Area\n type=\"monotone\"\n dataKey=\"value\"\n stroke={colorConfig.stroke}\n fill={colorConfig.fill}\n fillOpacity={0.3}\n strokeWidth={1.5}\n isAnimationActive={false}\n />\n </AreaChart>\n </ResponsiveContainer>\n </div>\n )}\n </div>\n );\n}\n\nfunction TrendIndicator({\n direction,\n value,\n}: {\n direction: \"up\" | \"down\" | \"neutral\";\n value?: number;\n}) {\n const colorClass =\n direction === \"up\"\n ? \"text-green-400\"\n : direction === \"down\"\n ? \"text-red-400\"\n : \"text-gray-400\";\n const arrow = direction === \"up\" ? \"↑\" : direction === \"down\" ? \"↓\" : \"→\";\n return (\n <span className={`text-sm font-medium ${colorClass}`}>\n {arrow}\n {value !== undefined && ` ${Math.abs(value).toFixed(1)}%`}\n </span>\n );\n}\n","/**\n * MetricTable - Accepts OtelMetricsRow[] and renders tabular metric data.\n */\n\nimport { useMemo } from \"react\";\nimport type { denormalizedSignals } from \"@kopai/core\";\n\ntype OtelMetricsRow = denormalizedSignals.OtelMetricsRow;\n\nexport interface MetricTableProps {\n rows: OtelMetricsRow[];\n isLoading?: boolean;\n error?: Error;\n maxRows?: number;\n formatValue?: (value: number) => string;\n formatTimestamp?: (timestamp: number) => string;\n columns?: (\"timestamp\" | \"metric\" | \"labels\" | \"value\")[];\n className?: string;\n}\n\ninterface TableRow {\n id: string;\n timestamp: number;\n metricName: string;\n labels: Record<string, string>;\n value: number;\n unit: string;\n}\n\nconst defaultFormatValue = (value: number): string => {\n if (Number.isInteger(value)) return value.toLocaleString();\n return value.toFixed(2);\n};\n\nconst defaultFormatTimestamp = (timestamp: number): string => {\n return new Date(timestamp).toLocaleString();\n};\n\nfunction formatLabels(labels: Record<string, string>): string {\n const entries = Object.entries(labels);\n if (entries.length === 0) return \"-\";\n return entries.map(([k, v]) => `${k}=${v}`).join(\", \");\n}\n\nfunction buildTableRows(rows: OtelMetricsRow[], maxRows: number): TableRow[] {\n const result: TableRow[] = [];\n\n for (const row of rows) {\n if (\n row.MetricType === \"Histogram\" ||\n row.MetricType === \"ExponentialHistogram\" ||\n row.MetricType === \"Summary\"\n )\n continue;\n\n const timestamp = Number(BigInt(row.TimeUnix) / 1_000_000n);\n const value = \"Value\" in row ? row.Value : 0;\n const labels: Record<string, string> = {};\n if (row.Attributes) {\n for (const [k, v] of Object.entries(row.Attributes))\n labels[k] = String(v);\n }\n const key = row.Attributes ? JSON.stringify(row.Attributes) : \"__default__\";\n\n result.push({\n id: `${row.MetricName}-${key}-${timestamp}`,\n timestamp,\n metricName: row.MetricName ?? \"unknown\",\n labels,\n value,\n unit: row.MetricUnit ?? \"\",\n });\n }\n\n return result.sort((a, b) => b.timestamp - a.timestamp).slice(0, maxRows);\n}\n\nexport function MetricTable({\n rows,\n isLoading = false,\n error,\n maxRows = 100,\n formatValue = defaultFormatValue,\n formatTimestamp = defaultFormatTimestamp,\n columns = [\"timestamp\", \"metric\", \"labels\", \"value\"],\n className = \"\",\n}: MetricTableProps) {\n const tableRows = useMemo(\n () => buildTableRows(rows, maxRows),\n [rows, maxRows]\n );\n\n if (isLoading) {\n return (\n <div className={`bg-background rounded-lg p-4 ${className}`}>\n <div className=\"animate-pulse\" data-testid=\"metric-table-loading\">\n <div className=\"h-10 bg-gray-800 rounded mb-2\" />\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-12 bg-gray-800/50 rounded mb-1\" />\n ))}\n </div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div\n className={`bg-background rounded-lg p-4 border border-red-800 ${className}`}\n data-testid=\"metric-table-error\"\n >\n <p className=\"text-red-400\">Error loading metrics: {error.message}</p>\n </div>\n );\n }\n\n if (tableRows.length === 0) {\n return (\n <div\n className={`bg-background rounded-lg p-4 border border-gray-800 ${className}`}\n data-testid=\"metric-table-empty\"\n >\n <p className=\"text-gray-500 text-center py-4\">\n No metric data available\n </p>\n </div>\n );\n }\n\n return (\n <div\n className={`bg-background rounded-lg overflow-hidden ${className}`}\n data-testid=\"metric-table\"\n >\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"bg-gray-800 text-gray-300 text-left\">\n {columns.includes(\"timestamp\") && (\n <th className=\"px-4 py-3 font-medium\">Timestamp</th>\n )}\n {columns.includes(\"metric\") && (\n <th className=\"px-4 py-3 font-medium\">Metric</th>\n )}\n {columns.includes(\"labels\") && (\n <th className=\"px-4 py-3 font-medium\">Labels</th>\n )}\n {columns.includes(\"value\") && (\n <th className=\"px-4 py-3 font-medium text-right\">Value</th>\n )}\n </tr>\n </thead>\n <tbody className=\"divide-y divide-gray-800\">\n {tableRows.map((row) => (\n <tr\n key={row.id}\n className=\"hover:bg-gray-800/50 transition-colors\"\n >\n {columns.includes(\"timestamp\") && (\n <td className=\"px-4 py-3 text-gray-400 whitespace-nowrap\">\n {formatTimestamp(row.timestamp)}\n </td>\n )}\n {columns.includes(\"metric\") && (\n <td className=\"px-4 py-3 text-gray-200 font-mono\">\n {row.metricName}\n </td>\n )}\n {columns.includes(\"labels\") && (\n <td className=\"px-4 py-3 text-gray-400 font-mono text-xs\">\n {formatLabels(row.labels)}\n </td>\n )}\n {columns.includes(\"value\") && (\n <td className=\"px-4 py-3 text-white font-medium text-right whitespace-nowrap\">\n {formatValue(row.value)}\n {row.unit && (\n <span className=\"text-gray-500 ml-1\">{row.unit}</span>\n )}\n </td>\n )}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {tableRows.length === maxRows && (\n <div className=\"px-4 py-2 bg-gray-800 text-gray-500 text-xs text-center\">\n Showing first {maxRows} rows\n </div>\n )}\n </div>\n );\n}\n","import {\n useState,\n useMemo,\n useCallback,\n type ReactNode,\n type ComponentType,\n} from \"react\";\nimport {\n createCatalog,\n type InferProps,\n type ComponentDefinition,\n} from \"./component-catalog.js\";\nimport z from \"zod\";\nimport { useKopaiData } from \"../hooks/use-kopai-data.js\";\nimport type { DataSource } from \"./component-catalog.js\";\n\ntype RegistryFromCatalog<\n C extends { components: Record<string, ComponentDefinition> },\n> = {\n [K in keyof C[\"components\"]]: ComponentType<\n RendererComponentProps<C[\"components\"][K]>\n >;\n};\n\ntype Catalog = ReturnType<typeof createCatalog>;\n\nexport type UITree = z.infer<Catalog[\"uiTreeSchema\"]>;\n\ntype UIElement = UITree[\"elements\"][string];\n\n// Simplified - renderer just passes through to useKopaiData\ntype RendererDataSource = {\n method: string;\n params?: Record<string, unknown>;\n};\n\ntype BaseElement<Props> = {\n key: string;\n type: string;\n children: string[];\n parentKey: string;\n dataSource?: RendererDataSource;\n props: Props;\n};\n\ntype WithData = {\n hasData: true;\n data: unknown;\n loading: boolean;\n error: Error | null;\n refetch: () => void;\n updateParams: (params: Record<string, unknown>) => void;\n};\n\ntype WithoutData = {\n hasData: false;\n};\n\nexport type RendererComponentProps<CD extends ComponentDefinition> =\n CD extends {\n hasChildren: true;\n props: infer P;\n }\n ?\n | ({\n element: BaseElement<InferProps<P>>;\n children: ReactNode;\n } & WithoutData)\n | ({\n element: BaseElement<InferProps<P>>;\n children: ReactNode;\n } & WithData)\n : CD extends { props: infer P }\n ?\n | ({ element: BaseElement<InferProps<P>> } & WithoutData)\n | ({ element: BaseElement<InferProps<P>> } & WithData)\n : never;\n\n/**\n * Base props (no dataSource)\n */\nexport interface ComponentRenderPropsBase {\n element: UIElement;\n children?: ReactNode;\n hasData: false;\n}\n\n/**\n * Props with dataSource\n */\nexport interface ComponentRenderPropsWithData {\n element: UIElement;\n children?: ReactNode;\n hasData: true;\n data: unknown;\n loading: boolean;\n error: Error | null;\n refetch: () => void;\n updateParams: (params: Record<string, unknown>) => void;\n}\n\n/**\n * Discriminated union for component render props\n */\nexport type ComponentRenderProps =\n | ComponentRenderPropsBase\n | ComponentRenderPropsWithData;\n\n/**\n * Component renderer type\n */\nexport type ComponentRenderer = ComponentType<ComponentRenderProps>;\n\n/**\n * Registry mapping component type names to React components\n */\ntype ComponentRegistry = Record<string, ComponentRenderer>;\n\n/**\n * Creates a typed Renderer component bound to a catalog and component implementations.\n *\n * @param _catalog - The catalog created via createCatalog (used for type inference)\n * @param components - React component implementations matching catalog definitions\n * @returns A Renderer component that only needs `tree` and optional `fallback`\n *\n * @example\n * ```tsx\n * const DashboardRenderer = createRendererFromCatalog(catalog, {\n * Card: ({ element, children }) => <div className=\"card\">{children}</div>,\n * Table: ({ element, data }) => <table>...</table>,\n * });\n *\n * <DashboardRenderer tree={uiTree} />\n * ```\n */\nexport function createRendererFromCatalog<\n C extends { components: Record<string, ComponentDefinition> },\n>(_catalog: C, components: RegistryFromCatalog<C>) {\n return function CatalogRenderer({\n tree,\n fallback,\n }: {\n tree: UITree | null;\n fallback?: ComponentRenderer;\n }) {\n return <Renderer tree={tree} registry={components} fallback={fallback} />;\n };\n}\n\n/**\n * Wrapper component for elements with dataSource\n */\nfunction DataSourceElement({\n element,\n Component,\n children,\n}: {\n element: UIElement;\n Component: ComponentRenderer;\n children?: ReactNode;\n}) {\n const [paramsOverride, setParamsOverride] = useState<Record<string, unknown>>(\n {}\n );\n\n const effectiveDataSource = useMemo(() => {\n if (!element.dataSource) return undefined;\n const merged = {\n ...element.dataSource,\n params: { ...element.dataSource.params, ...paramsOverride },\n };\n return merged as DataSource;\n }, [element.dataSource, paramsOverride]);\n\n const { data, loading, error, refetch } = useKopaiData(effectiveDataSource);\n\n const updateParams = useCallback((params: Record<string, unknown>) => {\n setParamsOverride((prev) => ({ ...prev, ...params }));\n }, []);\n\n return (\n <Component\n element={element}\n hasData={true}\n data={data}\n loading={loading}\n error={error}\n refetch={refetch}\n updateParams={updateParams}\n >\n {children}\n </Component>\n );\n}\n\n/**\n * Internal element renderer - recursively renders elements and children\n */\nfunction ElementRenderer({\n element,\n tree,\n registry,\n fallback,\n}: {\n element: UIElement;\n tree: UITree;\n registry: ComponentRegistry;\n fallback?: ComponentRenderer;\n}) {\n const Component = registry[element.type] ?? fallback;\n\n if (!Component) {\n console.warn(`No renderer for component type: ${element.type}`);\n return null;\n }\n\n const children = element.children?.map((childKey) => {\n const childElement = tree.elements[childKey];\n if (!childElement) return null;\n return (\n <ElementRenderer\n key={childKey}\n element={childElement}\n tree={tree}\n registry={registry}\n fallback={fallback}\n />\n );\n });\n\n // If element has dataSource, wrap with data fetching\n if (element.dataSource) {\n return (\n <DataSourceElement element={element} Component={Component}>\n {children}\n </DataSourceElement>\n );\n }\n\n // Otherwise render directly (no data)\n return (\n <Component element={element} hasData={false}>\n {children}\n </Component>\n );\n}\n\n/**\n * Renders a UITree using a component registry.\n * Prefer using {@link createRendererFromCatalog} for type-safe rendering.\n */\nexport function Renderer<\n C extends { components: Record<string, ComponentDefinition> },\n>({\n tree,\n registry,\n fallback,\n}: {\n tree: z.infer<ReturnType<typeof createCatalog>[\"uiTreeSchema\"]> | null;\n registry: RegistryFromCatalog<C>;\n fallback?: ComponentRenderer;\n}) {\n if (!tree || !tree.root) return null;\n\n const rootElement = tree.elements[tree.root];\n if (!rootElement) return null;\n\n return (\n <ElementRenderer\n element={rootElement}\n tree={tree}\n registry={registry as ComponentRegistry}\n fallback={fallback}\n />\n );\n}\n","import { createCatalog } from \"./component-catalog.js\";\nimport { z } from \"zod\";\n\nexport const dashboardCatalog = createCatalog({\n name: \"dashboard\",\n components: {\n // Layout Components\n Card: {\n props: z.object({\n title: z.string().nullable(),\n description: z.string().nullable(),\n padding: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n }),\n hasChildren: true,\n description: \"A card container with optional title\",\n },\n\n Grid: {\n props: z.object({\n columns: z.number().min(1).max(4).nullable(),\n gap: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n }),\n hasChildren: true,\n description: \"Grid layout with configurable columns\",\n },\n\n Stack: {\n props: z.object({\n direction: z.enum([\"horizontal\", \"vertical\"]).nullable(),\n gap: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n align: z.enum([\"start\", \"center\", \"end\", \"stretch\"]).nullable(),\n }),\n hasChildren: true,\n description: \"Flex stack for horizontal or vertical layouts\",\n },\n\n // Data Display Components\n Metric: {\n props: z.object({\n label: z.string(),\n valuePath: z.string(),\n format: z.enum([\"number\", \"currency\", \"percent\"]).nullable(),\n trend: z.enum([\"up\", \"down\", \"neutral\"]).nullable(),\n trendValue: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Display a single metric with optional trend indicator\",\n },\n\n Chart: {\n props: z.object({\n type: z.enum([\"bar\", \"line\", \"pie\", \"area\"]),\n dataPath: z.string(),\n title: z.string().nullable(),\n height: z.number().nullable(),\n }),\n hasChildren: false,\n description: \"Display a chart from array data\",\n },\n\n Table: {\n props: z.object({\n dataPath: z.string(),\n columns: z.array(\n z.object({\n key: z.string(),\n label: z.string(),\n format: z.enum([\"text\", \"currency\", \"date\", \"badge\"]).nullable(),\n })\n ),\n }),\n hasChildren: false,\n description: \"Display tabular data\",\n },\n\n List: {\n props: z.object({\n dataPath: z.string(),\n emptyMessage: z.string().nullable(),\n }),\n hasChildren: true,\n description: \"Render a list from array data\",\n },\n\n // Interactive Components\n Button: {\n props: z.object({\n label: z.string(),\n variant: z.enum([\"primary\", \"secondary\", \"danger\", \"ghost\"]).nullable(),\n size: z.enum([\"sm\", \"md\", \"lg\"]).nullable(),\n action: z.string(),\n disabled: z.boolean().nullable(),\n }),\n hasChildren: false,\n description: \"Clickable button with action\",\n },\n\n DatePicker: {\n props: z.object({\n label: z.string().nullable(),\n bindPath: z.string(),\n placeholder: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Date picker input\",\n },\n\n // Typography\n Heading: {\n props: z.object({\n text: z.string(),\n level: z.enum([\"h1\", \"h2\", \"h3\", \"h4\"]).nullable(),\n }),\n hasChildren: false,\n description: \"Section heading\",\n },\n\n Text: {\n props: z.object({\n content: z.string(),\n variant: z.enum([\"body\", \"caption\", \"label\"]).nullable(),\n color: z\n .enum([\"default\", \"muted\", \"success\", \"warning\", \"danger\"])\n .nullable(),\n }),\n hasChildren: false,\n description: \"Text paragraph\",\n },\n\n // Status Components\n Badge: {\n props: z.object({\n text: z.string(),\n variant: z\n .enum([\"default\", \"success\", \"warning\", \"danger\", \"info\"])\n .nullable(),\n }),\n hasChildren: false,\n description: \"Small status badge\",\n },\n\n // Special Components\n Divider: {\n props: z.object({\n label: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Visual divider\",\n },\n\n Empty: {\n props: z.object({\n title: z.string(),\n description: z.string().nullable(),\n action: z.string().nullable(),\n actionLabel: z.string().nullable(),\n }),\n hasChildren: false,\n description: \"Empty state placeholder\",\n },\n },\n});\n\n// Export the component list for the AI prompt\nexport const componentList = Object.keys(dashboardCatalog.components);\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Badge({\n element,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Badge>) {\n const { text, variant } = element.props;\n\n const colors: Record<string, string> = {\n default: \"hsl(var(--foreground))\",\n success: \"#22c55e\",\n warning: \"#eab308\",\n danger: \"#ef4444\",\n info: \"hsl(var(--muted-foreground))\",\n };\n\n return (\n <span\n style={{\n display: \"inline-block\",\n padding: \"2px 8px\",\n borderRadius: 12,\n fontSize: 12,\n fontWeight: 500,\n background: \"hsl(var(--border))\",\n color: colors[variant || \"default\"],\n }}\n >\n {text}\n </span>\n );\n}\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { RendererComponentProps } from \"../../../lib/renderer.js\";\n\nexport function Card({\n element,\n children,\n}: RendererComponentProps<typeof dashboardCatalog.components.Card>) {\n const { title, description, padding } = element.props as {\n title?: string | null;\n description?: string | null;\n padding?: string | null;\n };\n\n const paddings: Record<string, string> = {\n sm: \"12px\",\n md: \"16px\",\n lg: \"24px\",\n };\n\n return (\n <div\n style={{\n background: \"hsl(var(--card))\",\n border: \"1px solid hsl(var(--border))\",\n borderRadius: \"var(--radius)\",\n }}\n >\n {(title || description) && (\n <div\n style={{\n padding: \"16px 20px\",\n borderBottom: \"1px solid hsl(var(--border))\",\n }}\n >\n {title && (\n <h3 style={{ margin: 0, fontSize: 16, fontWeight: 600 }}>\n {title}\n </h3>\n )}\n {description && (\n <p\n style={{\n margin: \"4px 0 0\",\n fontSize: 14,\n color: \"hsl(var(--muted-foreground))\",\n }}\n >\n {description}\n </p>\n )}\n </div>\n )}\n <div style={{ padding: paddings[padding || \"\"] || \"16px\" }}>\n {children}\n </div>\n </div>\n );\n}\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Divider({\n element,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Divider>) {\n const { label } = element.props;\n\n if (label) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 16,\n margin: \"16px 0\",\n }}\n >\n <hr\n style={{\n flex: 1,\n border: \"none\",\n borderTop: \"1px solid hsl(var(--border))\",\n }}\n />\n <span style={{ fontSize: 12, color: \"hsl(var(--muted-foreground))\" }}>\n {label}\n </span>\n <hr\n style={{\n flex: 1,\n border: \"none\",\n borderTop: \"1px solid hsl(var(--border))\",\n }}\n />\n </div>\n );\n }\n\n return (\n <hr\n style={{\n border: \"none\",\n borderTop: \"1px solid hsl(var(--border))\",\n margin: \"16px 0\",\n }}\n />\n );\n}\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Empty({\n element,\n onAction,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Empty> & {\n onAction?: (action: string) => void;\n}) {\n const { title, description, action, actionLabel } = element.props;\n\n return (\n <div style={{ textAlign: \"center\", padding: \"40px 20px\" }}>\n <h3 style={{ margin: \"0 0 8px\", fontSize: 16, fontWeight: 600 }}>\n {title}\n </h3>\n {description && (\n <p\n style={{\n margin: \"0 0 16px\",\n fontSize: 14,\n color: \"hsl(var(--muted-foreground))\",\n }}\n >\n {description}\n </p>\n )}\n {action && actionLabel && (\n <button\n onClick={() => onAction?.(action)}\n style={{\n padding: \"8px 16px\",\n borderRadius: \"var(--radius)\",\n border: \"1px solid hsl(var(--border))\",\n background: \"hsl(var(--card))\",\n color: \"hsl(var(--foreground))\",\n fontSize: 14,\n cursor: \"pointer\",\n }}\n >\n {actionLabel}\n </button>\n )}\n </div>\n );\n}\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Grid({\n element,\n children,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Grid>) {\n const { columns, gap } = element.props;\n const gaps: Record<string, string> = {\n sm: \"8px\",\n md: \"16px\",\n lg: \"24px\",\n };\n\n return (\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(${columns || 2}, 1fr)`,\n gap: gaps[gap || \"md\"],\n }}\n >\n {children}\n </div>\n );\n}\n","import React from \"react\";\nimport { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Heading({\n element,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Heading>) {\n const { text, level } = element.props;\n const Tag = (level || \"h2\") as keyof React.JSX.IntrinsicElements;\n const sizes: Record<string, string> = {\n h1: \"28px\",\n h2: \"24px\",\n h3: \"20px\",\n h4: \"16px\",\n };\n return (\n <Tag\n style={{\n margin: \"0 0 16px\",\n fontSize: sizes[level || \"h2\"],\n fontWeight: 600,\n }}\n >\n {text}\n </Tag>\n );\n}\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Stack({\n element,\n children,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Stack>) {\n const { direction, gap, align } = element.props;\n const gaps: Record<string, string> = {\n sm: \"8px\",\n md: \"16px\",\n lg: \"24px\",\n };\n const alignments: Record<string, string> = {\n start: \"flex-start\",\n center: \"center\",\n end: \"flex-end\",\n stretch: \"stretch\",\n };\n\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: direction === \"horizontal\" ? \"row\" : \"column\",\n gap: gaps[gap || \"md\"],\n alignItems: alignments[align || \"stretch\"],\n }}\n >\n {children}\n </div>\n );\n}\n","import { dashboardCatalog } from \"../../../lib/catalog.js\";\nimport type { CatalogueComponentProps } from \"../../../lib/component-catalog.js\";\n\nexport function Text({\n element,\n}: CatalogueComponentProps<typeof dashboardCatalog.components.Text>) {\n const { content, color } = element.props;\n const colors: Record<string, string> = {\n default: \"hsl(var(--foreground))\",\n muted: \"hsl(var(--muted-foreground))\",\n success: \"#22c55e\",\n warning: \"#eab308\",\n danger: \"#ef4444\",\n };\n return (\n <p style={{ margin: 0, color: colors[color || \"default\"] }}>{content}</p>\n );\n}\n","import { observabilityCatalog } from \"../../../lib/observability-catalog.js\";\nimport type { RendererComponentProps } from \"../../../lib/renderer.js\";\nimport { LogTimeline } from \"../index.js\";\nimport type { denormalizedSignals } from \"@kopai/core\";\n\ntype OtelLogsRow = denormalizedSignals.OtelLogsRow;\n\ntype Props = RendererComponentProps<\n typeof observabilityCatalog.components.LogTimeline\n>;\n\nexport function OtelLogTimeline(props: Props) {\n if (!props.hasData) {\n return (\n <div style={{ padding: 24, color: \"var(--muted)\" }}>No data source</div>\n );\n }\n\n const response = props.data as { data?: OtelLogsRow[] } | null;\n\n return (\n <LogTimeline\n rows={response?.data ?? []}\n isLoading={props.loading}\n error={props.error ?? undefined}\n />\n );\n}\n","import { useMemo } from \"react\";\nimport { observabilityCatalog } from \"../../../lib/observability-catalog.js\";\nimport type { RendererComponentProps } from \"../../../lib/renderer.js\";\nimport type { MetricsDiscoveryResult } from \"@kopai/sdk\";\n\ntype Props = RendererComponentProps<\n typeof observabilityCatalog.components.MetricDiscovery\n>;\n\nconst TYPE_ORDER: Record<string, number> = {\n Gauge: 0,\n Sum: 1,\n Histogram: 2,\n ExponentialHistogram: 3,\n Summary: 4,\n};\n\nexport function OtelMetricDiscovery(props: Props) {\n const data = props.hasData\n ? (props.data as MetricsDiscoveryResult | null)\n : null;\n const loading = props.hasData ? props.loading : false;\n const error = props.hasData ? props.error : null;\n\n const sorted = useMemo(() => {\n if (!data?.metrics) return [];\n return [...data.metrics].sort(\n (a, b) =>\n a.name.localeCompare(b.name) ||\n (TYPE_ORDER[a.type] ?? 99) - (TYPE_ORDER[b.type] ?? 99)\n );\n }, [data]);\n\n if (loading && !sorted.length) {\n return <p className=\"text-muted-foreground py-4\">Loading metrics…</p>;\n }\n if (error) {\n return <p className=\"text-red-400 py-4\">Error: {error.message}</p>;\n }\n if (!sorted.length) {\n return <p className=\"text-muted-foreground py-4\">No metrics discovered.</p>;\n }\n\n return (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm text-left text-foreground border-collapse\">\n <thead className=\"text-xs uppercase text-muted-foreground border-b border-border\">\n <tr>\n <th className=\"px-3 py-2\">Name</th>\n <th className=\"px-3 py-2\">Type</th>\n <th className=\"px-3 py-2\">Unit</th>\n <th className=\"px-3 py-2\">Description</th>\n </tr>\n </thead>\n <tbody>\n {sorted.map((m) => (\n <tr\n key={`${m.name}-${m.type}`}\n className=\"border-b border-border/50 hover:bg-muted/40\"\n >\n <td className=\"px-3 py-2 font-mono whitespace-nowrap\">\n {m.name}\n </td>\n <td className=\"px-3 py-2 text-muted-foreground\">{m.type}</td>\n <td className=\"px-3 py-2 text-muted-foreground\">\n {m.unit || \"–\"}\n </td>\n <td className=\"px-3 py-2 text-muted-foreground\">\n {m.description || \"–\"}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n","import { observabilityCatalog } from \"../../../lib/observability-catalog.js\";\nimport type { RendererComponentProps } from \"../../../lib/renderer.js\";\nimport { MetricHistogram } from \"../index.js\";\nimport type { denormalizedSignals } from \"@kopai/core\";\n\ntype OtelMetricsRow = denormalizedSignals.OtelMetricsRow;\n\ntype Props = RendererComponentProps<\n typeof observabilityCatalog.components.MetricHistogram\n>;\n\nexport function OtelMetricHistogram(props: Props) {\n if (!props.hasData) {\n return (\n <div style={{ padding: 24, color: \"var(--muted)\" }}>No data source</div>\n );\n }\n\n const response = props.data as { data?: OtelMetricsRow[] } | null;\n\n return (\n <MetricHistogram\n rows={response?.data ?? []}\n isLoading={props.loading}\n error={props.error ?? undefined}\n height={props.element.props.height ?? 400}\n yAxisLabel={props.element.props.yAxisLabel ?? undefined}\n unit={props.element.props.unit ?? undefined}\n />\n );\n}\n","import { observabilityCatalog } from \"../../../lib/observability-catalog.js\";\nimport type { RendererComponentProps } from \"../../../lib/renderer.js\";\nimport { MetricStat } from \"../index.js\";\nimport { formatOtelValue } from \"../utils/units.js\";\nimport type { denormalizedSignals } from \"@kopai/core\";\n\ntype OtelMetricsRow = denormalizedSignals.OtelMetricsRow;\n\ntype Props = RendererComponentProps<\n typeof observabilityCatalog.components.MetricStat\n>;\n\nexport function OtelMetricStat(props: Props) {\n if (!props.hasData) {\n return (\n <div style={{ padding: 24, color: \"var(--muted)\" }}>No data source</div>\n );\n }\n\n const response = props.data as { data?: OtelMetricsRow[] } | null;\n\n return (\n <MetricStat\n rows={response?.data ?? []}\n isLoading={props.loading}\n error={props.error ?? undefined}\n label={props.element.props.label ?? undefined}\n showSparkline={props.element.props.showSparkline ?? false}\n formatValue={formatOtelValue}\n />\n );\n}\n","import { observabilityCatalog } from \"../../../lib/observability-catalog.js\";\nimport type { RendererComponentProps } from \"../../../lib/renderer.js\";\nimport { MetricTable } from \"../index.js\";\nimport type { denormalizedSignals } from \"@kopai/core\";\n\ntype OtelMetricsRow = denormalizedSignals.OtelMetricsRow;\n\ntype Props = RendererComponentProps<\n typeof observabilityCatalog.components.MetricTable\n>;\n\nexport function OtelMetricTable(props: Props) {\n if (!props.hasData) {\n return (\n <div style={{ padding: 24, color: \"var(--muted)\" }}>No data source</div>\n );\n }\n\n const response = props.data as { data?: OtelMetricsRow[] } | null;\n\n return (\n <MetricTable\n rows={response?.data ?? []}\n isLoading={props.loading}\n error={props.error ?? undefined}\n maxRows={props.element.props.maxRows ?? 100}\n />\n );\n}\n","import { observabilityCatalog } from \"../../../lib/observability-catalog.js\";\nimport type { RendererComponentProps } from \"../../../lib/renderer.js\";\nimport { MetricTimeSeries } from \"../index.js\";\nimport type { denormalizedSignals } from \"@kopai/core\";\n\ntype OtelMetricsRow = denormalizedSignals.OtelMetricsRow;\n\ntype Props = RendererComponentProps<\n typeof observabilityCatalog.components.MetricTimeSeries\n>;\n\nexport function OtelMetricTimeSeries(props: Props) {\n if (!props.hasData) {\n return (\n <div style={{ padding: 24, color: \"var(--muted)\" }}>No data source</div>\n );\n }\n\n const response = props.data as { data?: OtelMetricsRow[] } | null;\n\n return (\n <MetricTimeSeries\n rows={response?.data ?? []}\n isLoading={props.loading}\n error={props.error ?? undefined}\n height={props.element.props.height ?? 400}\n showBrush={props.element.props.showBrush ?? true}\n yAxisLabel={props.element.props.yAxisLabel ?? undefined}\n unit={props.element.props.unit ?? undefined}\n />\n );\n}\n","import { observabilityCatalog } from \"../../../lib/observability-catalog.js\";\nimport type { RendererComponentProps } from \"../../../lib/renderer.js\";\nimport { TraceDetail } from \"../index.js\";\nimport type { denormalizedSignals } from \"@kopai/core\";\n\ntype OtelTracesRow = denormalizedSignals.OtelTracesRow;\n\ntype Props = RendererComponentProps<\n typeof observabilityCatalog.components.TraceDetail\n>;\n\nexport function OtelTraceDetail(props: Props) {\n if (!props.hasData) {\n return (\n <div style={{ padding: 24, color: \"var(--muted)\" }}>No data source</div>\n );\n }\n\n const response = props.data as { data?: OtelTracesRow[] } | null;\n const rows = response?.data ?? [];\n const firstRow = rows[0];\n const service = firstRow?.ServiceName ?? \"unknown\";\n const traceId = firstRow?.TraceId ?? \"\";\n\n return (\n <TraceDetail\n rows={rows}\n isLoading={props.loading}\n error={props.error ?? undefined}\n service={service}\n traceId={traceId}\n onBack={() => {}}\n />\n );\n}\n","import {\n createRendererFromCatalog,\n type UITree,\n} from \"../../../lib/renderer.js\";\nimport {\n KopaiSDKProvider,\n type KopaiClient,\n} from \"../../../providers/kopai-provider.js\";\nimport { observabilityCatalog } from \"../../../lib/observability-catalog.js\";\nimport {\n Heading,\n Text,\n Card,\n Stack,\n Grid,\n Badge,\n Divider,\n Empty,\n} from \"../../dashboard/index.js\";\nimport {\n OtelLogTimeline,\n OtelMetricDiscovery,\n OtelMetricHistogram,\n OtelMetricStat,\n OtelMetricTable,\n OtelMetricTimeSeries,\n OtelTraceDetail,\n} from \"../renderers/index.js\";\n\nconst MetricsRenderer = createRendererFromCatalog(observabilityCatalog, {\n Card,\n Grid,\n Stack,\n Heading,\n Text,\n Badge,\n Divider,\n Empty,\n LogTimeline: OtelLogTimeline,\n TraceDetail: OtelTraceDetail,\n MetricTimeSeries: OtelMetricTimeSeries,\n MetricHistogram: OtelMetricHistogram,\n MetricStat: OtelMetricStat,\n MetricTable: OtelMetricTable,\n MetricDiscovery: OtelMetricDiscovery,\n});\n\nexport { type UITree };\n\nexport interface DynamicDashboardProps {\n kopaiClient: KopaiClient;\n uiTree: UITree;\n}\n\nexport function DynamicDashboard({\n kopaiClient,\n uiTree,\n}: DynamicDashboardProps) {\n return (\n <KopaiSDKProvider client={kopaiClient}>\n <MetricsRenderer tree={uiTree} />\n </KopaiSDKProvider>\n );\n}\n","import type { ShortcutGroup } from \"../../KeyboardShortcuts/types.js\";\n\nexport const SERVICES_SHORTCUTS: ShortcutGroup = {\n name: \"Services\",\n shortcuts: [{ keys: [\"Backspace\"], description: \"Go back\" }],\n};\n","import {\n useState,\n useMemo,\n useEffect,\n useCallback,\n useSyncExternalStore,\n useRef,\n} from \"react\";\nimport { KopaiSDKProvider, useKopaiSDK } from \"../providers/kopai-provider.js\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { KopaiClient } from \"@kopai/sdk\";\nimport { useKopaiData } from \"../hooks/use-kopai-data.js\";\nimport { useLiveLogs } from \"../hooks/use-live-logs.js\";\nimport type { denormalizedSignals, dataFilterSchemas } from \"@kopai/core\";\nimport type { DataSource } from \"../lib/component-catalog.js\";\nimport { observabilityCatalog } from \"../lib/observability-catalog.js\";\n// Observability components\nimport {\n LogTimeline,\n LogFilter,\n TabBar,\n ServiceList,\n TraceSearch,\n TraceDetail,\n KeyboardShortcutsProvider,\n useRegisterShortcuts,\n DynamicDashboard,\n} from \"../components/observability/index.js\";\nimport type { UITree } from \"../components/observability/DynamicDashboard/index.js\";\nimport type {\n TraceSummary,\n TraceSearchFilters,\n} from \"../components/observability/index.js\";\n\nimport { SERVICES_SHORTCUTS } from \"../components/observability/ServiceList/shortcuts.js\";\n\ntype OtelTracesRow = denormalizedSignals.OtelTracesRow;\n\n// ---------------------------------------------------------------------------\n// Tab config\n// ---------------------------------------------------------------------------\n\ntype Tab = \"logs\" | \"services\" | \"metrics\";\n\nconst TABS: { key: Tab; label: string; shortcutKey: string }[] = [\n { key: \"services\", label: \"Services\", shortcutKey: \"S\" },\n { key: \"logs\", label: \"Logs\", shortcutKey: \"L\" },\n { key: \"metrics\", label: \"Metrics\", shortcutKey: \"M\" },\n];\n\n// ---------------------------------------------------------------------------\n// URL state helpers\n// ---------------------------------------------------------------------------\n\ninterface URLState {\n tab: Tab;\n service: string | null;\n trace: string | null;\n span: string | null;\n dashboardId: string | null;\n}\n\nfunction readURLState(): URLState {\n const params = new URLSearchParams(window.location.search);\n const service = params.get(\"service\");\n const trace = params.get(\"trace\");\n const span = params.get(\"span\");\n const dashboardId = params.get(\"dashboardId\");\n const rawTab = params.get(\"tab\");\n const tab = service\n ? \"services\"\n : rawTab === \"logs\" || rawTab === \"metrics\"\n ? rawTab\n : \"services\";\n return { tab, service, trace, span, dashboardId };\n}\n\nfunction pushURLState(\n state: {\n tab: Tab;\n service?: string | null;\n trace?: string | null;\n span?: string | null;\n dashboardId?: string | null;\n },\n { replace = false }: { replace?: boolean } = {}\n) {\n const params = new URLSearchParams();\n if (state.tab !== \"services\") params.set(\"tab\", state.tab);\n if (state.service) params.set(\"service\", state.service);\n if (state.trace) params.set(\"trace\", state.trace);\n if (state.span) params.set(\"span\", state.span);\n // Preserve dashboardId from current URL if not explicitly provided\n const dashboardId =\n state.dashboardId !== undefined\n ? state.dashboardId\n : new URLSearchParams(window.location.search).get(\"dashboardId\");\n if (dashboardId) params.set(\"dashboardId\", dashboardId);\n const qs = params.toString();\n const url = `${window.location.pathname}${qs ? `?${qs}` : \"\"}`;\n if (replace) {\n history.replaceState(null, \"\", url);\n } else {\n history.pushState(null, \"\", url);\n }\n dispatchEvent(new PopStateEvent(\"popstate\"));\n}\n\nfunction subscribeURL(cb: () => void) {\n window.addEventListener(\"popstate\", cb);\n return () => window.removeEventListener(\"popstate\", cb);\n}\n\nlet _cachedSearch = \"\";\nlet _cachedState: URLState = {\n tab: \"services\",\n service: null,\n trace: null,\n span: null,\n dashboardId: null,\n};\n\nfunction getURLSnapshot(): URLState {\n const search = window.location.search;\n if (search !== _cachedSearch) {\n _cachedSearch = search;\n _cachedState = readURLState();\n }\n return _cachedState;\n}\n\nfunction useURLState(): URLState {\n return useSyncExternalStore(subscribeURL, getURLSnapshot);\n}\n\n// ---------------------------------------------------------------------------\n// Log filter URL helpers\n// ---------------------------------------------------------------------------\n\nfunction parseKeyValuesFromURL(\n raw: string\n): Record<string, string> | undefined {\n const result: Record<string, string> = {};\n let hasAny = false;\n for (const part of raw.split(\",\")) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n const eqIdx = trimmed.indexOf(\"=\");\n if (eqIdx < 1) continue;\n result[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);\n hasAny = true;\n }\n return hasAny ? result : undefined;\n}\n\nfunction serializeKeyValues(rec: Record<string, string> | undefined): string {\n if (!rec) return \"\";\n return Object.entries(rec)\n .map(([k, v]) => `${k}=${v}`)\n .join(\",\");\n}\n\ninterface LogURLState {\n filters: Partial<dataFilterSchemas.LogsDataFilter>;\n selectedServices: string[];\n selectedLogId: string | null;\n}\n\nfunction readLogFilters(): LogURLState {\n const p = new URLSearchParams(window.location.search);\n const filters: Partial<dataFilterSchemas.LogsDataFilter> = {\n limit: 200,\n sortOrder: \"DESC\",\n };\n\n const severity = p.get(\"severity\");\n if (severity) filters.severityText = severity;\n\n const body = p.get(\"body\");\n if (body) filters.bodyContains = body;\n\n const sort = p.get(\"sort\");\n if (sort === \"ASC\" || sort === \"DESC\") filters.sortOrder = sort;\n\n const limit = p.get(\"limit\");\n if (limit) {\n const n = parseInt(limit, 10);\n if (n >= 1 && n <= 1000) filters.limit = n;\n }\n\n const traceId = p.get(\"traceId\");\n if (traceId) filters.traceId = traceId;\n\n const spanId = p.get(\"spanId\");\n if (spanId) filters.spanId = spanId;\n\n const scope = p.get(\"scope\");\n if (scope) filters.scopeName = scope;\n\n const tsMin = p.get(\"tsMin\");\n if (tsMin) filters.timestampMin = tsMin;\n\n const tsMax = p.get(\"tsMax\");\n if (tsMax) filters.timestampMax = tsMax;\n\n const logAttrs = p.get(\"logAttrs\");\n if (logAttrs) filters.logAttributes = parseKeyValuesFromURL(logAttrs);\n\n const resAttrs = p.get(\"resAttrs\");\n if (resAttrs) filters.resourceAttributes = parseKeyValuesFromURL(resAttrs);\n\n const scopeAttrs = p.get(\"scopeAttrs\");\n if (scopeAttrs) filters.scopeAttributes = parseKeyValuesFromURL(scopeAttrs);\n\n const services = p.get(\"services\");\n const selectedServices = services ? services.split(\",\").filter(Boolean) : [];\n\n if (selectedServices.length === 1) filters.serviceName = selectedServices[0];\n\n const selectedLogId = p.get(\"log\") || null;\n\n return { filters, selectedServices, selectedLogId };\n}\n\nfunction writeLogFiltersToURL(\n filters: Partial<dataFilterSchemas.LogsDataFilter>,\n selectedServices: string[],\n selectedLogId: string | null\n) {\n const p = new URLSearchParams();\n p.set(\"tab\", \"logs\");\n\n if (filters.severityText) p.set(\"severity\", filters.severityText);\n if (filters.bodyContains) p.set(\"body\", filters.bodyContains);\n if (selectedServices.length) p.set(\"services\", selectedServices.join(\",\"));\n if (filters.sortOrder && filters.sortOrder !== \"DESC\")\n p.set(\"sort\", filters.sortOrder);\n if (filters.limit != null && filters.limit !== 200)\n p.set(\"limit\", String(filters.limit));\n if (filters.traceId) p.set(\"traceId\", filters.traceId);\n if (filters.spanId) p.set(\"spanId\", filters.spanId);\n if (filters.scopeName) p.set(\"scope\", filters.scopeName);\n if (filters.timestampMin) p.set(\"tsMin\", filters.timestampMin);\n if (filters.timestampMax) p.set(\"tsMax\", filters.timestampMax);\n\n const la = serializeKeyValues(filters.logAttributes);\n if (la) p.set(\"logAttrs\", la);\n const ra = serializeKeyValues(filters.resourceAttributes);\n if (ra) p.set(\"resAttrs\", ra);\n const sa = serializeKeyValues(filters.scopeAttributes);\n if (sa) p.set(\"scopeAttrs\", sa);\n\n if (selectedLogId) p.set(\"log\", selectedLogId);\n\n const qs = p.toString();\n const url = `${window.location.pathname}${qs ? `?${qs}` : \"\"}`;\n history.replaceState(null, \"\", url);\n}\n\n// ---------------------------------------------------------------------------\n// Duration parser — \"100ms\" → nanosecond string\n// ---------------------------------------------------------------------------\n\nfunction parseDuration(input: string): string | undefined {\n const trimmed = input.trim();\n if (!trimmed) return undefined;\n const match = trimmed.match(/^(\\d+(?:\\.\\d+)?)\\s*(us|ms|s)$/i);\n if (!match) return undefined;\n const value = parseFloat(match[1]!);\n const unit = match[2]!.toLowerCase();\n const multipliers: Record<string, number> = {\n us: 1_000,\n ms: 1_000_000,\n s: 1_000_000_000,\n };\n return String(Math.round(value * multipliers[unit]!));\n}\n\n// ---------------------------------------------------------------------------\n// Logs tab (live-tailing)\n// ---------------------------------------------------------------------------\n\nfunction LogsTab() {\n const [initState] = useState(() => readLogFilters());\n const [filters, setFilters] = useState<\n Partial<dataFilterSchemas.LogsDataFilter>\n >(initState.filters);\n const [selectedServices, setSelectedServices] = useState<string[]>(\n initState.selectedServices\n );\n const [selectedLogId, setSelectedLogId] = useState<string | null>(\n initState.selectedLogId\n );\n\n // Sync filter state to URL\n useEffect(() => {\n writeLogFiltersToURL(filters, selectedServices, selectedLogId);\n }, [filters, selectedServices, selectedLogId]);\n\n const { logs, isLive, loading, error, setLive } = useLiveLogs({\n params: filters,\n pollIntervalMs: 3_000,\n });\n\n // Client-side multi-service filter (API only supports single serviceName)\n const filteredLogs = useMemo(() => {\n if (selectedServices.length <= 1) return logs;\n const set = new Set(selectedServices);\n return logs.filter((r) => set.has(r.ServiceName ?? \"\"));\n }, [logs, selectedServices]);\n\n const handleLogClick = useCallback((log: { logId: string }) => {\n setSelectedLogId(log.logId);\n }, []);\n\n const handleTraceLinkClick = useCallback(\n (traceId: string, spanId: string) => {\n const log = filteredLogs.find((l) => l.TraceId === traceId);\n pushURLState({\n tab: \"services\",\n service: log?.ServiceName ?? undefined,\n trace: traceId,\n span: spanId,\n });\n },\n [filteredLogs]\n );\n\n return (\n <div style={{ height: \"calc(100vh - 160px)\" }} className=\"flex flex-col\">\n <div className=\"shrink-0 mb-3\">\n <LogFilter\n value={filters}\n onChange={setFilters}\n rows={logs}\n selectedServices={selectedServices}\n onSelectedServicesChange={setSelectedServices}\n />\n </div>\n <div className=\"flex-1 min-h-0\">\n <LogTimeline\n rows={filteredLogs}\n isLoading={loading}\n error={error ?? undefined}\n streaming={isLive}\n selectedLogId={selectedLogId ?? undefined}\n onLogClick={handleLogClick}\n onTraceLinkClick={handleTraceLinkClick}\n onAtBottomChange={(atBottom) => setLive(atBottom)}\n />\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Services tab — data-fetching wrappers around extracted UI components\n// ---------------------------------------------------------------------------\n\nconst SERVICES_DS: DataSource = {\n method: \"searchTracesPage\",\n params: { limit: 1000, sortOrder: \"DESC\" },\n};\n\nfunction ServiceListView({\n onSelect,\n}: {\n onSelect: (service: string) => void;\n}) {\n const { data, loading, error } = useKopaiData<{\n data: OtelTracesRow[];\n nextCursor: string | null;\n }>(SERVICES_DS);\n\n const services = useMemo(() => {\n if (!data?.data) return [];\n const names = new Set<string>();\n for (const row of data.data) {\n names.add(row.ServiceName ?? \"unknown\");\n }\n return Array.from(names)\n .sort()\n .map((name) => ({ name }));\n }, [data]);\n\n return (\n <ServiceList\n services={services}\n isLoading={loading}\n error={error ?? undefined}\n onSelect={onSelect}\n />\n );\n}\n\nfunction TraceSearchView({\n service,\n onBack,\n onSelectTrace,\n}: {\n service: string;\n onBack: () => void;\n onSelectTrace: (traceId: string) => void;\n}) {\n const [ds, setDs] = useState<DataSource>(() => ({\n method: \"searchTracesPage\",\n params: { serviceName: service, limit: 20, sortOrder: \"DESC\" as const },\n }));\n\n const handleSearch = useCallback(\n (filters: TraceSearchFilters) => {\n const params: Record<string, unknown> = {\n serviceName: service,\n limit: filters.limit,\n sortOrder: \"DESC\",\n };\n if (filters.operation) params.spanName = filters.operation;\n if (filters.lookbackMs) {\n params.timestampMin = String((Date.now() - filters.lookbackMs) * 1e6);\n }\n if (filters.minDuration) {\n const parsed = parseDuration(filters.minDuration);\n if (parsed) params.durationMin = parsed;\n }\n if (filters.maxDuration) {\n const parsed = parseDuration(filters.maxDuration);\n if (parsed) params.durationMax = parsed;\n }\n setDs({\n method: \"searchTracesPage\",\n params,\n } as DataSource);\n },\n [service]\n );\n\n const { data, loading, error } = useKopaiData<{\n data: OtelTracesRow[];\n nextCursor: string | null;\n }>(ds);\n\n // Fetch full traces for each unique traceId so service breakdown is complete\n const client = useKopaiSDK();\n const [fullTraces, setFullTraces] = useState<Map<string, OtelTracesRow[]>>(\n () => new Map()\n );\n\n useEffect(() => {\n if (!data?.data?.length) {\n setFullTraces(new Map());\n return;\n }\n const traceIds = [...new Set(data.data.map((r) => r.TraceId))];\n const ac = new AbortController();\n\n Promise.allSettled(\n traceIds.map((tid) =>\n client\n .getTrace(tid, { signal: ac.signal })\n .then((spans) => [tid, spans] as const)\n )\n )\n .then((results) => {\n if (!ac.signal.aborted) {\n const entries = results\n .filter(\n (\n r\n ): r is PromiseFulfilledResult<\n readonly [string, OtelTracesRow[]]\n > => r.status === \"fulfilled\"\n )\n .map((r) => r.value);\n setFullTraces(new Map(entries));\n }\n })\n .catch((err) => {\n if (!ac.signal.aborted)\n console.error(\"Failed to fetch full traces\", err);\n });\n\n return () => ac.abort();\n }, [data, client]);\n\n // Derive unique operations for filter dropdown\n const operations = useMemo(() => {\n if (!data?.data) return [];\n const set = new Set<string>();\n for (const row of data.data) {\n if (row.SpanName) set.add(row.SpanName);\n }\n return Array.from(set).sort();\n }, [data]);\n\n const traces = useMemo<TraceSummary[]>(() => {\n if (!data?.data) return [];\n const grouped = new Map<string, OtelTracesRow[]>();\n for (const row of data.data) {\n const tid = row.TraceId;\n if (!grouped.has(tid)) grouped.set(tid, []);\n grouped.get(tid)!.push(row);\n }\n\n return Array.from(grouped.entries()).map(([traceId, searchSpans]) => {\n const fullSpans = fullTraces.get(traceId);\n const spans = fullSpans ?? searchSpans;\n\n const root = spans.find((s) => !s.ParentSpanId) ?? spans[0]!;\n const durationNs = root.Duration ? parseInt(root.Duration, 10) : 0;\n\n const svcMap = new Map<string, { count: number; hasError: boolean }>();\n let errorCount = 0;\n for (const s of spans) {\n const svcName = s.ServiceName ?? \"unknown\";\n const entry = svcMap.get(svcName) ?? { count: 0, hasError: false };\n entry.count++;\n if (s.StatusCode === \"ERROR\") {\n entry.hasError = true;\n errorCount++;\n }\n svcMap.set(svcName, entry);\n }\n const services = Array.from(svcMap.entries())\n .map(([name, v]) => ({ name, count: v.count, hasError: v.hasError }))\n .sort((a, b) => b.count - a.count);\n\n return {\n traceId,\n rootSpanName: root.SpanName ?? \"unknown\",\n serviceName: root.ServiceName ?? \"unknown\",\n durationMs: durationNs / 1e6,\n statusCode: root.StatusCode ?? \"UNSET\",\n timestampMs: parseInt(root.Timestamp, 10) / 1e6,\n spanCount: spans.length,\n services,\n errorCount,\n };\n });\n }, [data, fullTraces]);\n\n return (\n <TraceSearch\n service={service}\n traces={traces}\n operations={operations}\n isLoading={loading}\n error={error ?? undefined}\n onSelectTrace={onSelectTrace}\n onBack={onBack}\n onSearch={handleSearch}\n />\n );\n}\n\nfunction TraceDetailView({\n service,\n traceId,\n selectedSpanId,\n onSelectSpan,\n onBack,\n}: {\n service: string;\n traceId: string;\n selectedSpanId: string | null;\n onSelectSpan: (spanId: string) => void;\n onBack: () => void;\n}) {\n const ds = useMemo<DataSource>(\n () => ({\n method: \"getTrace\",\n params: { traceId },\n }),\n [traceId]\n );\n\n const { data, loading, error } = useKopaiData<OtelTracesRow[]>(ds);\n\n return (\n <TraceDetail\n service={service}\n traceId={traceId}\n rows={data ?? []}\n isLoading={loading}\n error={error ?? undefined}\n selectedSpanId={selectedSpanId ?? undefined}\n onSpanClick={(span) => onSelectSpan(span.spanId)}\n onBack={onBack}\n />\n );\n}\n\nfunction ServicesTab({\n selectedService,\n selectedTraceId,\n selectedSpanId,\n onSelectService,\n onSelectTrace,\n onSelectSpan,\n onBackToServices,\n onBackToTraceList,\n}: {\n selectedService: string | null;\n selectedTraceId: string | null;\n selectedSpanId: string | null;\n onSelectService: (service: string) => void;\n onSelectTrace: (traceId: string) => void;\n onSelectSpan: (spanId: string) => void;\n onBackToServices: () => void;\n onBackToTraceList: () => void;\n}) {\n useRegisterShortcuts(\"services-tab\", SERVICES_SHORTCUTS);\n\n // Backspace → navigate back based on drill-down depth\n const backToServicesRef = useRef(onBackToServices);\n backToServicesRef.current = onBackToServices;\n const backToTraceListRef = useRef(onBackToTraceList);\n backToTraceListRef.current = onBackToTraceList;\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (\n e.target instanceof HTMLInputElement ||\n e.target instanceof HTMLTextAreaElement ||\n e.target instanceof HTMLSelectElement\n )\n return;\n if (e.key === \"Backspace\") {\n e.preventDefault();\n if (selectedTraceId && selectedService) {\n backToTraceListRef.current();\n } else if (selectedService) {\n backToServicesRef.current();\n }\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [selectedService, selectedTraceId]);\n\n if (selectedTraceId && selectedService) {\n return (\n <TraceDetailView\n service={selectedService}\n traceId={selectedTraceId}\n selectedSpanId={selectedSpanId}\n onSelectSpan={onSelectSpan}\n onBack={onBackToTraceList}\n />\n );\n }\n if (selectedService) {\n return (\n <TraceSearchView\n service={selectedService}\n onBack={onBackToServices}\n onSelectTrace={onSelectTrace}\n />\n );\n }\n return <ServiceListView onSelect={onSelectService} />;\n}\n\n// ---------------------------------------------------------------------------\n// Metrics tab — DynamicDashboard\n// ---------------------------------------------------------------------------\n\nconst DASHBOARDS_API_BASE = \"/dashboards\";\n\nconst METRICS_TREE = {\n root: \"root\",\n elements: {\n root: {\n key: \"root\",\n type: \"Stack\" as const,\n children: [\"heading\", \"description\", \"discovery-card\"],\n parentKey: \"\",\n props: {\n direction: \"vertical\" as const,\n gap: \"md\" as const,\n align: null,\n },\n },\n heading: {\n key: \"heading\",\n type: \"Heading\" as const,\n children: [],\n parentKey: \"root\",\n props: { text: \"Metrics\", level: \"h2\" as const },\n },\n description: {\n key: \"description\",\n type: \"Text\" as const,\n children: [],\n parentKey: \"root\",\n props: {\n content: \"Discovered OpenTelemetry metrics\",\n variant: \"body\" as const,\n color: \"muted\" as const,\n },\n },\n \"discovery-card\": {\n key: \"discovery-card\",\n type: \"Card\" as const,\n children: [\"metric-discovery\"],\n parentKey: \"root\",\n props: { title: null, description: null, padding: null },\n },\n \"metric-discovery\": {\n key: \"metric-discovery\",\n type: \"MetricDiscovery\" as const,\n children: [],\n parentKey: \"discovery-card\",\n dataSource: { method: \"discoverMetrics\" as const },\n props: {},\n },\n },\n};\n\nfunction useDashboardTree(dashboardId: string | null) {\n const { data, isFetching, error } = useQuery<UITree, Error>({\n queryKey: [\"dashboard-tree\", dashboardId],\n queryFn: async ({ signal }) => {\n const res = await fetch(`${DASHBOARDS_API_BASE}/${dashboardId}`, {\n signal,\n });\n if (!res.ok) throw new Error(`Failed to load dashboard: ${res.status}`);\n const json = await res.json();\n const parsed = observabilityCatalog.uiTreeSchema.safeParse(json.uiTree);\n if (!parsed.success) {\n const issue = parsed.error.issues[0];\n const path = issue?.path.length ? issue.path.join(\".\") + \": \" : \"\";\n throw new Error(\n `Dashboard has an invalid layout: ${path}${issue?.message}`\n );\n }\n return parsed.data;\n },\n enabled: !!dashboardId,\n });\n\n return {\n loading: isFetching,\n error: error?.message ?? null,\n tree: data ?? null,\n };\n}\n\nfunction MetricsTab() {\n const kopaiClient = useKopaiSDK();\n const { dashboardId } = useURLState();\n const { loading, error, tree } = useDashboardTree(dashboardId);\n\n if (loading)\n return (\n <p className=\"text-muted-foreground text-sm\">Loading dashboard...</p>\n );\n if (error)\n return <p className=\"text-muted-foreground text-sm\">Error: {error}</p>;\n\n return (\n <DynamicDashboard kopaiClient={kopaiClient} uiTree={tree ?? METRICS_TREE} />\n );\n}\n\n// ---------------------------------------------------------------------------\n// Page\n// ---------------------------------------------------------------------------\n\nlet _defaultClient: KopaiClient | undefined;\nfunction getDefaultClient() {\n _defaultClient ??= new KopaiClient({ baseUrl: \"\" });\n return _defaultClient;\n}\n\ninterface ObservabilityPageProps {\n client?: KopaiClient;\n}\n\nexport default function ObservabilityPage({ client }: ObservabilityPageProps) {\n const activeClient = client ?? getDefaultClient();\n const {\n tab: activeTab,\n service: selectedService,\n trace: selectedTraceId,\n span: selectedSpanId,\n } = useURLState();\n\n const handleTabChange = useCallback((tab: Tab) => {\n pushURLState({ tab });\n }, []);\n\n const handleSelectService = useCallback((service: string) => {\n pushURLState({ tab: \"services\", service });\n }, []);\n\n const handleSelectTrace = useCallback(\n (traceId: string) => {\n pushURLState({\n tab: \"services\",\n service: selectedService,\n trace: traceId,\n });\n },\n [selectedService]\n );\n\n const handleSelectSpan = useCallback(\n (spanId: string) => {\n pushURLState(\n {\n tab: \"services\",\n service: selectedService,\n trace: selectedTraceId,\n span: spanId,\n },\n { replace: true }\n );\n },\n [selectedService, selectedTraceId]\n );\n\n const handleBackToServices = useCallback(() => {\n pushURLState({ tab: \"services\" });\n }, []);\n\n const handleBackToTraceList = useCallback(() => {\n pushURLState({ tab: \"services\", service: selectedService });\n }, [selectedService]);\n\n return (\n <KopaiSDKProvider client={activeClient}>\n <KeyboardShortcutsProvider\n onNavigateServices={() => pushURLState({ tab: \"services\" })}\n onNavigateLogs={() => pushURLState({ tab: \"logs\" })}\n onNavigateMetrics={() => pushURLState({ tab: \"metrics\" })}\n >\n <div>\n <TabBar\n tabs={TABS}\n active={activeTab}\n onChange={handleTabChange as (key: string) => void}\n />\n {activeTab === \"logs\" && <LogsTab />}\n {activeTab === \"services\" && (\n <ServicesTab\n selectedService={selectedService}\n selectedTraceId={selectedTraceId}\n selectedSpanId={selectedSpanId}\n onSelectService={handleSelectService}\n onSelectTrace={handleSelectTrace}\n onSelectSpan={handleSelectSpan}\n onBackToServices={handleBackToServices}\n onBackToTraceList={handleBackToTraceList}\n />\n )}\n {activeTab === \"metrics\" && <MetricsTab />}\n </div>\n </KeyboardShortcutsProvider>\n </KopaiSDKProvider>\n );\n}\n","import { z } from \"zod\";\nimport { dataSourceSchema } from \"./component-catalog.js\";\n\ntype Catalog = {\n name: string;\n components: Record<\n string,\n { hasChildren: boolean; description: string; props: unknown }\n >;\n uiTreeSchema: z.ZodTypeAny;\n};\n\n// Helper to format prop type from JSON schema property\nfunction formatPropType(prop: {\n type?: string | string[];\n enum?: string[];\n items?: object;\n}): string {\n if (prop.enum) return prop.enum.map((v) => `\"${v}\"`).join(\" | \");\n if (Array.isArray(prop.type))\n return prop.type.filter((t) => t !== \"null\").join(\" | \");\n if (prop.type === \"array\" && prop.items)\n return `array of ${formatPropType(prop.items as Parameters<typeof formatPropType>[0])}`;\n return prop.type ?? \"unknown\";\n}\n\n// Helper to format props from JSON schema\nfunction formatPropsFromJsonSchema(jsonSchema: object): string {\n const schema = jsonSchema as {\n properties?: Record<string, unknown>;\n required?: string[];\n };\n if (!schema.properties) return \"(no props)\";\n\n const required = new Set(schema.required ?? []);\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(schema.properties)) {\n const prop = value as {\n type?: string | string[];\n enum?: string[];\n description?: string;\n items?: object;\n };\n const isRequired = required.has(key);\n const typeStr = formatPropType(prop);\n const reqStr = isRequired ? \" (required)\" : \" (optional)\";\n const descStr = prop.description ? ` - ${prop.description}` : \"\";\n lines.push(`- ${key}: ${typeStr}${reqStr}${descStr}`);\n }\n return lines.join(\"\\n\");\n}\n\n// Helper to build example UI tree\nfunction buildExampleElements(\n names: string[],\n components: Record<string, { hasChildren: boolean }>\n): { root: string; elements: Record<string, unknown> } {\n const containerName =\n names.find((n) => components[n]?.hasChildren) ?? names[0];\n const containerKey = `${String(containerName).toLowerCase()}-1`;\n\n const childKeys: string[] = [];\n const elements: Record<string, unknown> = {};\n\n elements[containerKey] = {\n key: containerKey,\n type: String(containerName),\n props: {},\n children: childKeys,\n };\n\n const otherNames = names.filter((n) => n !== containerName).slice(0, 2);\n for (const name of otherNames) {\n const key = `${String(name).toLowerCase()}-1`;\n childKeys.push(key);\n const element: Record<string, unknown> = {\n key,\n type: String(name),\n props: {},\n parentKey: containerKey,\n };\n if (!components[name]?.hasChildren) {\n element.dataSource = {\n method: \"searchTracesPage\",\n params: { limit: 10 },\n };\n }\n elements[key] = element;\n }\n\n return { root: containerKey, elements };\n}\n\n// Helper to check if a value looks like the dataSource schema\nfunction isDataSourceSchema(value: unknown): boolean {\n if (!value || typeof value !== \"object\") return false;\n const obj = value as Record<string, unknown>;\n if (!Array.isArray(obj.oneOf)) return false;\n const first = obj.oneOf[0] as Record<string, unknown> | undefined;\n if (!first?.properties) return false;\n const props = first.properties as Record<string, unknown>;\n const method = props.method as Record<string, unknown> | undefined;\n return method?.const === \"searchTracesPage\";\n}\n\n// Helper to recursively replace dataSource schema with $ref\nfunction replaceDataSourceWithRef(obj: unknown): void {\n if (!obj || typeof obj !== \"object\") return;\n\n const record = obj as Record<string, unknown>;\n for (const key of Object.keys(record)) {\n const value = record[key];\n if (key === \"dataSource\" && isDataSourceSchema(value)) {\n record[key] = { $ref: \"#/$defs/DataSource\" };\n } else if (value && typeof value === \"object\") {\n replaceDataSourceWithRef(value);\n }\n }\n}\n\n// Helper to build unified schema with $defs\nfunction buildUnifiedSchema(treeSchema: z.ZodTypeAny): object {\n const dataSourceJsonSchema = z.toJSONSchema(dataSourceSchema);\n const treeJsonSchema = z.toJSONSchema(treeSchema) as Record<string, unknown>;\n\n replaceDataSourceWithRef(treeJsonSchema);\n treeJsonSchema.$defs = { DataSource: dataSourceJsonSchema };\n\n return treeJsonSchema;\n}\n\n/**\n * Generates LLM prompt instructions from a catalog.\n * Includes component docs, JSON schema, and usage examples.\n *\n * @param catalog - The catalog created via createCatalog\n * @returns Markdown string with component docs, schema, and examples\n *\n * @example\n * ```ts\n * const instructions = generatePromptInstructions(catalog);\n * const prompt = `Build a dashboard UI.\\n\\n${instructions}`;\n * ```\n */\nexport function generatePromptInstructions(\n catalog: Catalog,\n uiTreeVersion: string\n): string {\n const componentNames = Object.keys(catalog.components);\n\n const componentSections = componentNames\n .map((name) => {\n const def = catalog.components[name]!;\n const propsSchema = z.toJSONSchema(def.props as z.ZodTypeAny);\n const propsFormatted = formatPropsFromJsonSchema(propsSchema);\n const roleLine = def.hasChildren\n ? \"Accepts children: yes\"\n : \"Accepts dataSource: yes\";\n\n return `### ${name}\n${def.description ?? \"No description\"}\n\nProps:\n${propsFormatted}\n${roleLine}`;\n })\n .join(\"\\n\\n---\\n\\n\");\n\n const unifiedSchema = buildUnifiedSchema(catalog.uiTreeSchema);\n const exampleElements = buildExampleElements(\n componentNames,\n catalog.components\n );\n\n return `## UI Tree Version\n\nUse uiTreeVersion: \"${uiTreeVersion}\" when creating dashboards.\n\n---\n\n## Available Components\n\n${componentSections}\n\n---\n\n## Output Schema\n\n${JSON.stringify(unifiedSchema)}\n\n---\n\n## Example\n\n${JSON.stringify(exampleElements)}`;\n}\n"],"mappings":"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"}