@kopai/ui 0.0.5 → 0.1.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 (125) hide show
  1. package/README.md +137 -0
  2. package/dist/index.cjs +5069 -3
  3. package/dist/index.d.cts +301 -3
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.mts +302 -3
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +5010 -3
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +25 -7
  10. package/src/components/KeyboardShortcuts/KeyboardShortcutsProvider.tsx +113 -0
  11. package/src/components/KeyboardShortcuts/ShortcutsHelpDialog.tsx +82 -0
  12. package/src/components/KeyboardShortcuts/context.ts +23 -0
  13. package/src/components/KeyboardShortcuts/index.ts +8 -0
  14. package/src/components/KeyboardShortcuts/types.ts +11 -0
  15. package/src/components/dashboard/Badge/Badge.stories.tsx +29 -0
  16. package/src/components/dashboard/Badge/index.tsx +32 -0
  17. package/src/components/dashboard/Button/Button.stories.tsx +107 -0
  18. package/src/components/dashboard/Button/index.tsx +63 -0
  19. package/src/components/dashboard/Card/Card.stories.tsx +81 -0
  20. package/src/components/dashboard/Card/index.tsx +58 -0
  21. package/src/components/dashboard/Chart/Chart.stories.tsx +48 -0
  22. package/src/components/dashboard/Chart/index.tsx +74 -0
  23. package/src/components/dashboard/DatePicker/DatePicker.stories.tsx +33 -0
  24. package/src/components/dashboard/DatePicker/index.tsx +41 -0
  25. package/src/components/dashboard/Divider/Divider.stories.tsx +17 -0
  26. package/src/components/dashboard/Divider/index.tsx +49 -0
  27. package/src/components/dashboard/Empty/Empty.stories.tsx +48 -0
  28. package/src/components/dashboard/Empty/index.tsx +46 -0
  29. package/src/components/dashboard/Grid/Grid.stories.tsx +52 -0
  30. package/src/components/dashboard/Grid/index.tsx +26 -0
  31. package/src/components/dashboard/Heading/Heading.stories.tsx +25 -0
  32. package/src/components/dashboard/Heading/index.tsx +27 -0
  33. package/src/components/dashboard/List/List.stories.tsx +37 -0
  34. package/src/components/dashboard/List/index.tsx +24 -0
  35. package/src/components/dashboard/Metric/Metric.stories.tsx +65 -0
  36. package/src/components/dashboard/Metric/index.tsx +36 -0
  37. package/src/components/dashboard/Stack/Stack.stories.tsx +61 -0
  38. package/src/components/dashboard/Stack/index.tsx +33 -0
  39. package/src/components/dashboard/Table/Table.stories.tsx +38 -0
  40. package/src/components/dashboard/Table/index.tsx +104 -0
  41. package/src/components/dashboard/Text/Text.stories.tsx +53 -0
  42. package/src/components/dashboard/Text/index.tsx +18 -0
  43. package/src/components/dashboard/index.ts +46 -0
  44. package/src/components/index.ts +17 -0
  45. package/src/components/observability/LogTimeline/LogDetailPane/AttributesTab.tsx +56 -0
  46. package/src/components/observability/LogTimeline/LogDetailPane/JsonTreeView.tsx +139 -0
  47. package/src/components/observability/LogTimeline/LogDetailPane/index.tsx +271 -0
  48. package/src/components/observability/LogTimeline/LogFilter.stories.tsx +66 -0
  49. package/src/components/observability/LogTimeline/LogFilter.test.tsx +696 -0
  50. package/src/components/observability/LogTimeline/LogFilter.tsx +674 -0
  51. package/src/components/observability/LogTimeline/LogRow.tsx +174 -0
  52. package/src/components/observability/LogTimeline/LogTimeline.stories.tsx +154 -0
  53. package/src/components/observability/LogTimeline/index.tsx +542 -0
  54. package/src/components/observability/LogTimeline/shortcuts.ts +18 -0
  55. package/src/components/observability/MetricHistogram/MetricHistogram.stories.tsx +20 -0
  56. package/src/components/observability/MetricHistogram/index.tsx +303 -0
  57. package/src/components/observability/MetricStat/MetricStat.stories.tsx +30 -0
  58. package/src/components/observability/MetricStat/index.tsx +281 -0
  59. package/src/components/observability/MetricTable/MetricTable.stories.tsx +20 -0
  60. package/src/components/observability/MetricTable/index.tsx +194 -0
  61. package/src/components/observability/MetricTimeSeries/MetricTimeSeries.stories.tsx +28 -0
  62. package/src/components/observability/MetricTimeSeries/index.tsx +462 -0
  63. package/src/components/observability/RawDataTable/RawDataTable.stories.tsx +27 -0
  64. package/src/components/observability/RawDataTable/index.tsx +131 -0
  65. package/src/components/observability/ServiceList/ServiceList.stories.tsx +20 -0
  66. package/src/components/observability/ServiceList/index.tsx +60 -0
  67. package/src/components/observability/ServiceList/shortcuts.ts +6 -0
  68. package/src/components/observability/TabBar/TabBar.stories.tsx +34 -0
  69. package/src/components/observability/TabBar/index.tsx +46 -0
  70. package/src/components/observability/TraceDetail/TraceDetail.stories.tsx +51 -0
  71. package/src/components/observability/TraceDetail/index.tsx +53 -0
  72. package/src/components/observability/TraceSearch/TraceSearch.stories.tsx +49 -0
  73. package/src/components/observability/TraceSearch/index.tsx +292 -0
  74. package/src/components/observability/TraceTimeline/DetailPane/AttributesTab.tsx +152 -0
  75. package/src/components/observability/TraceTimeline/DetailPane/EventsTab.tsx +128 -0
  76. package/src/components/observability/TraceTimeline/DetailPane/LinksTab.tsx +210 -0
  77. package/src/components/observability/TraceTimeline/DetailPane/index.tsx +174 -0
  78. package/src/components/observability/TraceTimeline/SpanRow.tsx +173 -0
  79. package/src/components/observability/TraceTimeline/TimelineBar.tsx +41 -0
  80. package/src/components/observability/TraceTimeline/Tooltip.tsx +42 -0
  81. package/src/components/observability/TraceTimeline/TraceHeader.tsx +88 -0
  82. package/src/components/observability/TraceTimeline/TraceTimeline.stories.tsx +25 -0
  83. package/src/components/observability/TraceTimeline/index.tsx +478 -0
  84. package/src/components/observability/TraceTimeline/shortcuts.ts +16 -0
  85. package/src/components/observability/__fixtures__/logs.ts +476 -0
  86. package/src/components/observability/__fixtures__/metrics.ts +216 -0
  87. package/src/components/observability/__fixtures__/raw-table.ts +204 -0
  88. package/src/components/observability/__fixtures__/services.ts +8 -0
  89. package/src/components/observability/__fixtures__/trace-summaries.ts +81 -0
  90. package/src/components/observability/__fixtures__/traces.ts +396 -0
  91. package/src/components/observability/index.ts +66 -0
  92. package/src/components/observability/renderers/OtelMetricDiscovery.tsx +77 -0
  93. package/src/components/observability/renderers/OtelMetricHistogram.tsx +29 -0
  94. package/src/components/observability/renderers/OtelMetricStat.tsx +44 -0
  95. package/src/components/observability/renderers/OtelMetricTable.tsx +29 -0
  96. package/src/components/observability/renderers/OtelMetricTimeSeries.tsx +30 -0
  97. package/src/components/observability/renderers/index.ts +5 -0
  98. package/src/components/observability/shared/LoadingSkeleton.tsx +43 -0
  99. package/src/components/observability/types.ts +113 -0
  100. package/src/components/observability/utils/attributes.ts +17 -0
  101. package/src/components/observability/utils/colors.ts +29 -0
  102. package/src/components/observability/utils/flatten-tree.ts +53 -0
  103. package/src/components/observability/utils/lttb.ts +121 -0
  104. package/src/components/observability/utils/time.ts +46 -0
  105. package/src/hooks/use-kopai-data.test.ts +296 -0
  106. package/src/hooks/use-kopai-data.ts +64 -0
  107. package/src/hooks/use-live-logs.test.ts +193 -0
  108. package/src/hooks/use-live-logs.ts +113 -0
  109. package/src/index.ts +15 -0
  110. package/src/lib/__snapshots__/generate-prompt-instructions.test.ts.snap +33 -0
  111. package/src/lib/catalog.ts +165 -0
  112. package/src/lib/component-catalog.test.ts +357 -0
  113. package/src/lib/component-catalog.ts +171 -0
  114. package/src/lib/dashboard-datasource.ts +76 -0
  115. package/src/lib/generate-prompt-instructions.test.ts +27 -0
  116. package/src/lib/generate-prompt-instructions.ts +185 -0
  117. package/src/lib/log-buffer.test.ts +88 -0
  118. package/src/lib/log-buffer.ts +62 -0
  119. package/src/lib/observability-catalog.ts +143 -0
  120. package/src/lib/renderer.test.tsx +693 -0
  121. package/src/lib/renderer.tsx +276 -0
  122. package/src/pages/observability.tsx +828 -0
  123. package/src/providers/kopai-provider.tsx +51 -0
  124. package/src/styles/globals.css +46 -0
  125. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,276 @@
1
+ import {
2
+ useState,
3
+ useMemo,
4
+ useCallback,
5
+ type ReactNode,
6
+ type ComponentType,
7
+ } from "react";
8
+ import {
9
+ createCatalog,
10
+ type InferProps,
11
+ type ComponentDefinition,
12
+ } from "./component-catalog.js";
13
+ import z from "zod";
14
+ import { useKopaiData } from "../hooks/use-kopai-data.js";
15
+ import type { DataSource } from "./component-catalog.js";
16
+
17
+ type RegistryFromCatalog<
18
+ C extends { components: Record<string, ComponentDefinition> },
19
+ > = {
20
+ [K in keyof C["components"]]: ComponentType<
21
+ RendererComponentProps<C["components"][K]>
22
+ >;
23
+ };
24
+
25
+ type Catalog = ReturnType<typeof createCatalog>;
26
+
27
+ type UITree = z.infer<Catalog["uiTreeSchema"]>;
28
+
29
+ type UIElement = UITree["elements"][string];
30
+
31
+ // Simplified - renderer just passes through to useKopaiData
32
+ type RendererDataSource = {
33
+ method: string;
34
+ params?: Record<string, unknown>;
35
+ };
36
+
37
+ type BaseElement<Props> = {
38
+ key: string;
39
+ type: string;
40
+ children: string[];
41
+ parentKey: string;
42
+ dataSource?: RendererDataSource;
43
+ props: Props;
44
+ };
45
+
46
+ type WithData = {
47
+ hasData: true;
48
+ data: unknown;
49
+ loading: boolean;
50
+ error: Error | null;
51
+ refetch: () => void;
52
+ updateParams: (params: Record<string, unknown>) => void;
53
+ };
54
+
55
+ type WithoutData = {
56
+ hasData: false;
57
+ };
58
+
59
+ export type RendererComponentProps<CD extends ComponentDefinition> =
60
+ CD extends {
61
+ hasChildren: true;
62
+ props: infer P;
63
+ }
64
+ ?
65
+ | ({
66
+ element: BaseElement<InferProps<P>>;
67
+ children: ReactNode;
68
+ } & WithoutData)
69
+ | ({
70
+ element: BaseElement<InferProps<P>>;
71
+ children: ReactNode;
72
+ } & WithData)
73
+ : CD extends { props: infer P }
74
+ ?
75
+ | ({ element: BaseElement<InferProps<P>> } & WithoutData)
76
+ | ({ element: BaseElement<InferProps<P>> } & WithData)
77
+ : never;
78
+
79
+ /**
80
+ * Base props (no dataSource)
81
+ */
82
+ export interface ComponentRenderPropsBase {
83
+ element: UIElement;
84
+ children?: ReactNode;
85
+ hasData: false;
86
+ }
87
+
88
+ /**
89
+ * Props with dataSource
90
+ */
91
+ export interface ComponentRenderPropsWithData {
92
+ element: UIElement;
93
+ children?: ReactNode;
94
+ hasData: true;
95
+ data: unknown;
96
+ loading: boolean;
97
+ error: Error | null;
98
+ refetch: () => void;
99
+ updateParams: (params: Record<string, unknown>) => void;
100
+ }
101
+
102
+ /**
103
+ * Discriminated union for component render props
104
+ */
105
+ export type ComponentRenderProps =
106
+ | ComponentRenderPropsBase
107
+ | ComponentRenderPropsWithData;
108
+
109
+ /**
110
+ * Component renderer type
111
+ */
112
+ export type ComponentRenderer = ComponentType<ComponentRenderProps>;
113
+
114
+ /**
115
+ * Registry mapping component type names to React components
116
+ */
117
+ type ComponentRegistry = Record<string, ComponentRenderer>;
118
+
119
+ /**
120
+ * Creates a typed Renderer component bound to a catalog and component implementations.
121
+ *
122
+ * @param _catalog - The catalog created via createCatalog (used for type inference)
123
+ * @param components - React component implementations matching catalog definitions
124
+ * @returns A Renderer component that only needs `tree` and optional `fallback`
125
+ *
126
+ * @example
127
+ * ```tsx
128
+ * const DashboardRenderer = createRendererFromCatalog(catalog, {
129
+ * Card: ({ element, children }) => <div className="card">{children}</div>,
130
+ * Table: ({ element, data }) => <table>...</table>,
131
+ * });
132
+ *
133
+ * <DashboardRenderer tree={uiTree} />
134
+ * ```
135
+ */
136
+ export function createRendererFromCatalog<
137
+ C extends { components: Record<string, ComponentDefinition> },
138
+ >(_catalog: C, components: RegistryFromCatalog<C>) {
139
+ return function CatalogRenderer({
140
+ tree,
141
+ fallback,
142
+ }: {
143
+ tree: UITree | null;
144
+ fallback?: ComponentRenderer;
145
+ }) {
146
+ return <Renderer tree={tree} registry={components} fallback={fallback} />;
147
+ };
148
+ }
149
+
150
+ /**
151
+ * Wrapper component for elements with dataSource
152
+ */
153
+ function DataSourceElement({
154
+ element,
155
+ Component,
156
+ children,
157
+ }: {
158
+ element: UIElement;
159
+ Component: ComponentRenderer;
160
+ children?: ReactNode;
161
+ }) {
162
+ const [paramsOverride, setParamsOverride] = useState<Record<string, unknown>>(
163
+ {}
164
+ );
165
+
166
+ const effectiveDataSource = useMemo(() => {
167
+ if (!element.dataSource) return undefined;
168
+ const merged = {
169
+ ...element.dataSource,
170
+ params: { ...element.dataSource.params, ...paramsOverride },
171
+ };
172
+ return merged as DataSource;
173
+ }, [element.dataSource, paramsOverride]);
174
+
175
+ const { data, loading, error, refetch } = useKopaiData(effectiveDataSource);
176
+
177
+ const updateParams = useCallback((params: Record<string, unknown>) => {
178
+ setParamsOverride((prev) => ({ ...prev, ...params }));
179
+ }, []);
180
+
181
+ return (
182
+ <Component
183
+ element={element}
184
+ hasData={true}
185
+ data={data}
186
+ loading={loading}
187
+ error={error}
188
+ refetch={refetch}
189
+ updateParams={updateParams}
190
+ >
191
+ {children}
192
+ </Component>
193
+ );
194
+ }
195
+
196
+ /**
197
+ * Internal element renderer - recursively renders elements and children
198
+ */
199
+ function ElementRenderer({
200
+ element,
201
+ tree,
202
+ registry,
203
+ fallback,
204
+ }: {
205
+ element: UIElement;
206
+ tree: UITree;
207
+ registry: ComponentRegistry;
208
+ fallback?: ComponentRenderer;
209
+ }) {
210
+ const Component = registry[element.type] ?? fallback;
211
+
212
+ if (!Component) {
213
+ console.warn(`No renderer for component type: ${element.type}`);
214
+ return null;
215
+ }
216
+
217
+ const children = element.children?.map((childKey) => {
218
+ const childElement = tree.elements[childKey];
219
+ if (!childElement) return null;
220
+ return (
221
+ <ElementRenderer
222
+ key={childKey}
223
+ element={childElement}
224
+ tree={tree}
225
+ registry={registry}
226
+ fallback={fallback}
227
+ />
228
+ );
229
+ });
230
+
231
+ // If element has dataSource, wrap with data fetching
232
+ if (element.dataSource) {
233
+ return (
234
+ <DataSourceElement element={element} Component={Component}>
235
+ {children}
236
+ </DataSourceElement>
237
+ );
238
+ }
239
+
240
+ // Otherwise render directly (no data)
241
+ return (
242
+ <Component element={element} hasData={false}>
243
+ {children}
244
+ </Component>
245
+ );
246
+ }
247
+
248
+ /**
249
+ * Renders a UITree using a component registry.
250
+ * Prefer using {@link createRendererFromCatalog} for type-safe rendering.
251
+ */
252
+ export function Renderer<
253
+ C extends { components: Record<string, ComponentDefinition> },
254
+ >({
255
+ tree,
256
+ registry,
257
+ fallback,
258
+ }: {
259
+ tree: z.infer<ReturnType<typeof createCatalog>["uiTreeSchema"]> | null;
260
+ registry: RegistryFromCatalog<C>;
261
+ fallback?: ComponentRenderer;
262
+ }) {
263
+ if (!tree || !tree.root) return null;
264
+
265
+ const rootElement = tree.elements[tree.root];
266
+ if (!rootElement) return null;
267
+
268
+ return (
269
+ <ElementRenderer
270
+ element={rootElement}
271
+ tree={tree}
272
+ registry={registry as ComponentRegistry}
273
+ fallback={fallback}
274
+ />
275
+ );
276
+ }