@kopai/ui 0.0.4 → 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.
- package/README.md +137 -0
- package/dist/index.cjs +5069 -3
- package/dist/index.d.cts +301 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +302 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +5010 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +30 -12
- package/src/components/KeyboardShortcuts/KeyboardShortcutsProvider.tsx +113 -0
- package/src/components/KeyboardShortcuts/ShortcutsHelpDialog.tsx +82 -0
- package/src/components/KeyboardShortcuts/context.ts +23 -0
- package/src/components/KeyboardShortcuts/index.ts +8 -0
- package/src/components/KeyboardShortcuts/types.ts +11 -0
- package/src/components/dashboard/Badge/Badge.stories.tsx +29 -0
- package/src/components/dashboard/Badge/index.tsx +32 -0
- package/src/components/dashboard/Button/Button.stories.tsx +107 -0
- package/src/components/dashboard/Button/index.tsx +63 -0
- package/src/components/dashboard/Card/Card.stories.tsx +81 -0
- package/src/components/dashboard/Card/index.tsx +58 -0
- package/src/components/dashboard/Chart/Chart.stories.tsx +48 -0
- package/src/components/dashboard/Chart/index.tsx +74 -0
- package/src/components/dashboard/DatePicker/DatePicker.stories.tsx +33 -0
- package/src/components/dashboard/DatePicker/index.tsx +41 -0
- package/src/components/dashboard/Divider/Divider.stories.tsx +17 -0
- package/src/components/dashboard/Divider/index.tsx +49 -0
- package/src/components/dashboard/Empty/Empty.stories.tsx +48 -0
- package/src/components/dashboard/Empty/index.tsx +46 -0
- package/src/components/dashboard/Grid/Grid.stories.tsx +52 -0
- package/src/components/dashboard/Grid/index.tsx +26 -0
- package/src/components/dashboard/Heading/Heading.stories.tsx +25 -0
- package/src/components/dashboard/Heading/index.tsx +27 -0
- package/src/components/dashboard/List/List.stories.tsx +37 -0
- package/src/components/dashboard/List/index.tsx +24 -0
- package/src/components/dashboard/Metric/Metric.stories.tsx +65 -0
- package/src/components/dashboard/Metric/index.tsx +36 -0
- package/src/components/dashboard/Stack/Stack.stories.tsx +61 -0
- package/src/components/dashboard/Stack/index.tsx +33 -0
- package/src/components/dashboard/Table/Table.stories.tsx +38 -0
- package/src/components/dashboard/Table/index.tsx +104 -0
- package/src/components/dashboard/Text/Text.stories.tsx +53 -0
- package/src/components/dashboard/Text/index.tsx +18 -0
- package/src/components/dashboard/index.ts +46 -0
- package/src/components/index.ts +17 -0
- package/src/components/observability/LogTimeline/LogDetailPane/AttributesTab.tsx +56 -0
- package/src/components/observability/LogTimeline/LogDetailPane/JsonTreeView.tsx +139 -0
- package/src/components/observability/LogTimeline/LogDetailPane/index.tsx +271 -0
- package/src/components/observability/LogTimeline/LogFilter.stories.tsx +66 -0
- package/src/components/observability/LogTimeline/LogFilter.test.tsx +696 -0
- package/src/components/observability/LogTimeline/LogFilter.tsx +674 -0
- package/src/components/observability/LogTimeline/LogRow.tsx +174 -0
- package/src/components/observability/LogTimeline/LogTimeline.stories.tsx +154 -0
- package/src/components/observability/LogTimeline/index.tsx +542 -0
- package/src/components/observability/LogTimeline/shortcuts.ts +18 -0
- package/src/components/observability/MetricHistogram/MetricHistogram.stories.tsx +20 -0
- package/src/components/observability/MetricHistogram/index.tsx +303 -0
- package/src/components/observability/MetricStat/MetricStat.stories.tsx +30 -0
- package/src/components/observability/MetricStat/index.tsx +281 -0
- package/src/components/observability/MetricTable/MetricTable.stories.tsx +20 -0
- package/src/components/observability/MetricTable/index.tsx +194 -0
- package/src/components/observability/MetricTimeSeries/MetricTimeSeries.stories.tsx +28 -0
- package/src/components/observability/MetricTimeSeries/index.tsx +462 -0
- package/src/components/observability/RawDataTable/RawDataTable.stories.tsx +27 -0
- package/src/components/observability/RawDataTable/index.tsx +131 -0
- package/src/components/observability/ServiceList/ServiceList.stories.tsx +20 -0
- package/src/components/observability/ServiceList/index.tsx +60 -0
- package/src/components/observability/ServiceList/shortcuts.ts +6 -0
- package/src/components/observability/TabBar/TabBar.stories.tsx +34 -0
- package/src/components/observability/TabBar/index.tsx +46 -0
- package/src/components/observability/TraceDetail/TraceDetail.stories.tsx +51 -0
- package/src/components/observability/TraceDetail/index.tsx +53 -0
- package/src/components/observability/TraceSearch/TraceSearch.stories.tsx +49 -0
- package/src/components/observability/TraceSearch/index.tsx +292 -0
- package/src/components/observability/TraceTimeline/DetailPane/AttributesTab.tsx +152 -0
- package/src/components/observability/TraceTimeline/DetailPane/EventsTab.tsx +128 -0
- package/src/components/observability/TraceTimeline/DetailPane/LinksTab.tsx +210 -0
- package/src/components/observability/TraceTimeline/DetailPane/index.tsx +174 -0
- package/src/components/observability/TraceTimeline/SpanRow.tsx +173 -0
- package/src/components/observability/TraceTimeline/TimelineBar.tsx +41 -0
- package/src/components/observability/TraceTimeline/Tooltip.tsx +42 -0
- package/src/components/observability/TraceTimeline/TraceHeader.tsx +88 -0
- package/src/components/observability/TraceTimeline/TraceTimeline.stories.tsx +25 -0
- package/src/components/observability/TraceTimeline/index.tsx +478 -0
- package/src/components/observability/TraceTimeline/shortcuts.ts +16 -0
- package/src/components/observability/__fixtures__/logs.ts +476 -0
- package/src/components/observability/__fixtures__/metrics.ts +216 -0
- package/src/components/observability/__fixtures__/raw-table.ts +204 -0
- package/src/components/observability/__fixtures__/services.ts +8 -0
- package/src/components/observability/__fixtures__/trace-summaries.ts +81 -0
- package/src/components/observability/__fixtures__/traces.ts +396 -0
- package/src/components/observability/index.ts +66 -0
- package/src/components/observability/renderers/OtelMetricDiscovery.tsx +77 -0
- package/src/components/observability/renderers/OtelMetricHistogram.tsx +29 -0
- package/src/components/observability/renderers/OtelMetricStat.tsx +44 -0
- package/src/components/observability/renderers/OtelMetricTable.tsx +29 -0
- package/src/components/observability/renderers/OtelMetricTimeSeries.tsx +30 -0
- package/src/components/observability/renderers/index.ts +5 -0
- package/src/components/observability/shared/LoadingSkeleton.tsx +43 -0
- package/src/components/observability/types.ts +113 -0
- package/src/components/observability/utils/attributes.ts +17 -0
- package/src/components/observability/utils/colors.ts +29 -0
- package/src/components/observability/utils/flatten-tree.ts +53 -0
- package/src/components/observability/utils/lttb.ts +121 -0
- package/src/components/observability/utils/time.ts +46 -0
- package/src/hooks/use-kopai-data.test.ts +296 -0
- package/src/hooks/use-kopai-data.ts +64 -0
- package/src/hooks/use-live-logs.test.ts +193 -0
- package/src/hooks/use-live-logs.ts +113 -0
- package/src/index.ts +15 -0
- package/src/lib/__snapshots__/generate-prompt-instructions.test.ts.snap +33 -0
- package/src/lib/catalog.ts +165 -0
- package/src/lib/component-catalog.test.ts +357 -0
- package/src/lib/component-catalog.ts +171 -0
- package/src/lib/dashboard-datasource.ts +76 -0
- package/src/lib/generate-prompt-instructions.test.ts +27 -0
- package/src/lib/generate-prompt-instructions.ts +185 -0
- package/src/lib/log-buffer.test.ts +88 -0
- package/src/lib/log-buffer.ts +62 -0
- package/src/lib/observability-catalog.ts +143 -0
- package/src/lib/renderer.test.tsx +693 -0
- package/src/lib/renderer.tsx +276 -0
- package/src/pages/observability.tsx +828 -0
- package/src/providers/kopai-provider.tsx +51 -0
- package/src/styles/globals.css +46 -0
- 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
|
+
}
|