@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,271 @@
|
|
|
1
|
+
import { useState, useCallback, useRef, useEffect } from "react";
|
|
2
|
+
import type { LogEntry } from "../../types.js";
|
|
3
|
+
import { AttributesTab } from "./AttributesTab.js";
|
|
4
|
+
import { JsonTreeView } from "./JsonTreeView.js";
|
|
5
|
+
|
|
6
|
+
export interface LogDetailPaneProps {
|
|
7
|
+
log: LogEntry;
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
onTraceLinkClick?: (traceId: string, spanId: string) => void;
|
|
10
|
+
initialTab?: "message" | "attributes" | "resource" | "context";
|
|
11
|
+
wordWrap?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type TabType = "message" | "attributes" | "resource" | "context";
|
|
15
|
+
|
|
16
|
+
export function LogDetailPane({
|
|
17
|
+
log,
|
|
18
|
+
onClose,
|
|
19
|
+
onTraceLinkClick,
|
|
20
|
+
initialTab = "message",
|
|
21
|
+
wordWrap = true,
|
|
22
|
+
}: LogDetailPaneProps) {
|
|
23
|
+
const hasContext = !!log.traceId;
|
|
24
|
+
const [activeTab, setActiveTab] = useState<TabType>(
|
|
25
|
+
initialTab === "context" && !hasContext ? "message" : initialTab
|
|
26
|
+
);
|
|
27
|
+
const [copiedId, setCopiedId] = useState(false);
|
|
28
|
+
const detailPaneRef = useRef<HTMLDivElement>(null);
|
|
29
|
+
|
|
30
|
+
const handleCopyLogId = useCallback(async () => {
|
|
31
|
+
try {
|
|
32
|
+
await navigator.clipboard.writeText(log.logId);
|
|
33
|
+
setCopiedId(true);
|
|
34
|
+
setTimeout(() => setCopiedId(false), 2000);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.error("Failed to copy log ID:", err);
|
|
37
|
+
}
|
|
38
|
+
}, [log.logId]);
|
|
39
|
+
|
|
40
|
+
const handleKeyDown = useCallback(
|
|
41
|
+
(e: React.KeyboardEvent) => {
|
|
42
|
+
if (e.key === "Escape") onClose();
|
|
43
|
+
},
|
|
44
|
+
[onClose]
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
detailPaneRef.current?.focus();
|
|
49
|
+
}, []);
|
|
50
|
+
|
|
51
|
+
const severityColor = getSeverityColor(log.severityText);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<div
|
|
55
|
+
ref={detailPaneRef}
|
|
56
|
+
className="w-[500px] flex flex-col h-full bg-background border-l border-border outline-none"
|
|
57
|
+
onKeyDown={handleKeyDown}
|
|
58
|
+
role="complementary"
|
|
59
|
+
aria-label="Log details"
|
|
60
|
+
tabIndex={-1}
|
|
61
|
+
>
|
|
62
|
+
{/* Header */}
|
|
63
|
+
<div className="p-4 border-b border-border">
|
|
64
|
+
<div className="flex items-center justify-between mb-3">
|
|
65
|
+
<h2 className="text-lg font-semibold text-foreground">Log Details</h2>
|
|
66
|
+
<button
|
|
67
|
+
onClick={onClose}
|
|
68
|
+
className="p-2 hover:bg-muted rounded transition-colors"
|
|
69
|
+
aria-label="Close detail pane"
|
|
70
|
+
>
|
|
71
|
+
<svg
|
|
72
|
+
className="w-6 h-6 text-muted-foreground"
|
|
73
|
+
fill="none"
|
|
74
|
+
stroke="currentColor"
|
|
75
|
+
viewBox="0 0 24 24"
|
|
76
|
+
>
|
|
77
|
+
<path
|
|
78
|
+
strokeLinecap="round"
|
|
79
|
+
strokeLinejoin="round"
|
|
80
|
+
strokeWidth={2}
|
|
81
|
+
d="M6 18L18 6M6 6l12 12"
|
|
82
|
+
/>
|
|
83
|
+
</svg>
|
|
84
|
+
</button>
|
|
85
|
+
</div>
|
|
86
|
+
<div className="flex items-center gap-2 mb-2">
|
|
87
|
+
<div
|
|
88
|
+
className={`text-xs font-semibold px-2 py-0.5 rounded ${severityColor.bg} ${severityColor.text}`}
|
|
89
|
+
>
|
|
90
|
+
{log.severityText}
|
|
91
|
+
</div>
|
|
92
|
+
<div className="text-sm text-muted-foreground">{log.serviceName}</div>
|
|
93
|
+
</div>
|
|
94
|
+
<div className="text-xs font-medium text-muted-foreground mt-3 mb-1">
|
|
95
|
+
Timestamp
|
|
96
|
+
</div>
|
|
97
|
+
<div className="text-xs text-foreground font-mono">
|
|
98
|
+
{new Date(log.timeUnixMs).toISOString()}
|
|
99
|
+
</div>
|
|
100
|
+
<div className="text-xs font-medium text-muted-foreground mt-3 mb-1">
|
|
101
|
+
Log ID
|
|
102
|
+
</div>
|
|
103
|
+
<div className="flex items-center gap-2">
|
|
104
|
+
<button
|
|
105
|
+
onClick={handleCopyLogId}
|
|
106
|
+
className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground font-mono bg-muted px-2 py-1 rounded"
|
|
107
|
+
title="Click to copy log ID"
|
|
108
|
+
>
|
|
109
|
+
<span className="truncate max-w-[200px]">{log.logId}</span>
|
|
110
|
+
<svg
|
|
111
|
+
className="w-3 h-3 flex-shrink-0"
|
|
112
|
+
fill="none"
|
|
113
|
+
stroke="currentColor"
|
|
114
|
+
viewBox="0 0 24 24"
|
|
115
|
+
>
|
|
116
|
+
{copiedId ? (
|
|
117
|
+
<path
|
|
118
|
+
strokeLinecap="round"
|
|
119
|
+
strokeLinejoin="round"
|
|
120
|
+
strokeWidth={2}
|
|
121
|
+
d="M5 13l4 4L19 7"
|
|
122
|
+
/>
|
|
123
|
+
) : (
|
|
124
|
+
<path
|
|
125
|
+
strokeLinecap="round"
|
|
126
|
+
strokeLinejoin="round"
|
|
127
|
+
strokeWidth={2}
|
|
128
|
+
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"
|
|
129
|
+
/>
|
|
130
|
+
)}
|
|
131
|
+
</svg>
|
|
132
|
+
</button>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
{/* Tabs */}
|
|
137
|
+
<div className="flex border-b border-border">
|
|
138
|
+
{(
|
|
139
|
+
[
|
|
140
|
+
"message",
|
|
141
|
+
"attributes",
|
|
142
|
+
"resource",
|
|
143
|
+
...(log.traceId ? ["context" as const] : []),
|
|
144
|
+
] as TabType[]
|
|
145
|
+
).map((tab) => (
|
|
146
|
+
<button
|
|
147
|
+
key={tab}
|
|
148
|
+
onClick={() => setActiveTab(tab)}
|
|
149
|
+
className={`px-4 py-2 text-sm font-medium transition-colors ${
|
|
150
|
+
activeTab === tab
|
|
151
|
+
? "text-blue-600 dark:text-blue-400 border-b-2 border-blue-600 dark:border-blue-400"
|
|
152
|
+
: "text-muted-foreground hover:text-foreground"
|
|
153
|
+
}`}
|
|
154
|
+
>
|
|
155
|
+
{tab === "context"
|
|
156
|
+
? "Trace"
|
|
157
|
+
: tab.charAt(0).toUpperCase() + tab.slice(1)}
|
|
158
|
+
</button>
|
|
159
|
+
))}
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
{/* Content */}
|
|
163
|
+
<div className="flex-1 overflow-y-auto p-4">
|
|
164
|
+
{activeTab === "message" && (
|
|
165
|
+
<pre
|
|
166
|
+
className={`text-sm text-foreground font-mono bg-muted p-3 rounded ${
|
|
167
|
+
wordWrap
|
|
168
|
+
? "whitespace-pre-wrap break-words"
|
|
169
|
+
: "whitespace-pre overflow-x-auto"
|
|
170
|
+
}`}
|
|
171
|
+
>
|
|
172
|
+
{log.body || "No message body"}
|
|
173
|
+
</pre>
|
|
174
|
+
)}
|
|
175
|
+
{activeTab === "attributes" && <AttributesTab log={log} />}
|
|
176
|
+
{activeTab === "resource" && (
|
|
177
|
+
<div>
|
|
178
|
+
<div className="mb-3">
|
|
179
|
+
<div className="text-sm font-semibold text-foreground mb-2">
|
|
180
|
+
Service Name
|
|
181
|
+
</div>
|
|
182
|
+
<div className="text-sm text-foreground bg-muted p-2 rounded font-mono">
|
|
183
|
+
{log.serviceName}
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
{log.scopeName && (
|
|
187
|
+
<div className="mb-3">
|
|
188
|
+
<div className="text-sm font-semibold text-foreground mb-2">
|
|
189
|
+
Scope Name
|
|
190
|
+
</div>
|
|
191
|
+
<div className="text-sm text-foreground bg-muted p-2 rounded font-mono">
|
|
192
|
+
{log.scopeName}
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
)}
|
|
196
|
+
<div>
|
|
197
|
+
<div className="text-sm font-semibold text-foreground mb-2">
|
|
198
|
+
Resource Attributes
|
|
199
|
+
</div>
|
|
200
|
+
{Object.keys(log.resourceAttributes).length > 0 ? (
|
|
201
|
+
<JsonTreeView data={log.resourceAttributes} />
|
|
202
|
+
) : (
|
|
203
|
+
<div className="text-sm text-muted-foreground text-center py-4">
|
|
204
|
+
No resource attributes
|
|
205
|
+
</div>
|
|
206
|
+
)}
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
)}
|
|
210
|
+
{activeTab === "context" && log.traceId && (
|
|
211
|
+
<div className="space-y-3">
|
|
212
|
+
<div>
|
|
213
|
+
<div className="text-sm font-semibold text-foreground mb-2">
|
|
214
|
+
Trace ID
|
|
215
|
+
</div>
|
|
216
|
+
<div className="text-sm text-foreground bg-muted p-2 rounded font-mono break-all">
|
|
217
|
+
{log.traceId}
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
{log.spanId && (
|
|
221
|
+
<div>
|
|
222
|
+
<div className="text-sm font-semibold text-foreground mb-2">
|
|
223
|
+
Span ID
|
|
224
|
+
</div>
|
|
225
|
+
<div className="text-sm text-foreground bg-muted p-2 rounded font-mono break-all">
|
|
226
|
+
{log.spanId}
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
)}
|
|
230
|
+
{onTraceLinkClick && log.spanId && (
|
|
231
|
+
<button
|
|
232
|
+
onClick={() => onTraceLinkClick(log.traceId!, log.spanId!)}
|
|
233
|
+
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"
|
|
234
|
+
>
|
|
235
|
+
View Trace
|
|
236
|
+
</button>
|
|
237
|
+
)}
|
|
238
|
+
</div>
|
|
239
|
+
)}
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function getSeverityColor(severity: string): { text: string; bg: string } {
|
|
246
|
+
const s = severity.toUpperCase();
|
|
247
|
+
if (s === "FATAL" || s === "ERROR")
|
|
248
|
+
return {
|
|
249
|
+
text: "text-red-900 dark:text-red-100",
|
|
250
|
+
bg: "bg-red-100 dark:bg-red-900/30",
|
|
251
|
+
};
|
|
252
|
+
if (s === "WARN" || s === "WARNING")
|
|
253
|
+
return {
|
|
254
|
+
text: "text-orange-900 dark:text-orange-100",
|
|
255
|
+
bg: "bg-orange-100 dark:bg-orange-900/30",
|
|
256
|
+
};
|
|
257
|
+
if (s === "INFO")
|
|
258
|
+
return {
|
|
259
|
+
text: "text-blue-900 dark:text-blue-100",
|
|
260
|
+
bg: "bg-blue-100 dark:bg-blue-900/30",
|
|
261
|
+
};
|
|
262
|
+
if (s === "DEBUG")
|
|
263
|
+
return {
|
|
264
|
+
text: "text-gray-900 dark:text-gray-100",
|
|
265
|
+
bg: "bg-gray-100 dark:bg-gray-700/30",
|
|
266
|
+
};
|
|
267
|
+
return {
|
|
268
|
+
text: "text-gray-600 dark:text-gray-400",
|
|
269
|
+
bg: "bg-gray-50 dark:bg-gray-800/20",
|
|
270
|
+
};
|
|
271
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import type { dataFilterSchemas } from "@kopai/core";
|
|
4
|
+
import { LogFilter } from "./LogFilter.js";
|
|
5
|
+
import { mockLogRows } from "../__fixtures__/logs.js";
|
|
6
|
+
|
|
7
|
+
type LogsDataFilter = dataFilterSchemas.LogsDataFilter;
|
|
8
|
+
|
|
9
|
+
const meta: Meta<typeof LogFilter> = {
|
|
10
|
+
title: "Observability/LogFilter",
|
|
11
|
+
component: LogFilter,
|
|
12
|
+
decorators: [
|
|
13
|
+
(Story) => (
|
|
14
|
+
<div style={{ width: 800 }}>
|
|
15
|
+
<Story />
|
|
16
|
+
</div>
|
|
17
|
+
),
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
export default meta;
|
|
21
|
+
type Story = StoryObj<typeof LogFilter>;
|
|
22
|
+
|
|
23
|
+
function Controlled(
|
|
24
|
+
initial: Partial<LogsDataFilter>,
|
|
25
|
+
initialServices: string[] = []
|
|
26
|
+
) {
|
|
27
|
+
return function Render() {
|
|
28
|
+
const [value, setValue] = useState<Partial<LogsDataFilter>>(initial);
|
|
29
|
+
const [selectedServices, setSelectedServices] =
|
|
30
|
+
useState<string[]>(initialServices);
|
|
31
|
+
return (
|
|
32
|
+
<div className="space-y-4">
|
|
33
|
+
<LogFilter
|
|
34
|
+
value={value}
|
|
35
|
+
onChange={setValue}
|
|
36
|
+
rows={mockLogRows}
|
|
37
|
+
selectedServices={selectedServices}
|
|
38
|
+
onSelectedServicesChange={setSelectedServices}
|
|
39
|
+
/>
|
|
40
|
+
<pre className="text-xs text-muted-foreground bg-muted/50 p-3 rounded overflow-auto">
|
|
41
|
+
{JSON.stringify(
|
|
42
|
+
{ ...value, _selectedServices: selectedServices },
|
|
43
|
+
null,
|
|
44
|
+
2
|
|
45
|
+
)}
|
|
46
|
+
</pre>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const Default: Story = {
|
|
53
|
+
render: Controlled({}),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const WithValues: Story = {
|
|
57
|
+
render: Controlled(
|
|
58
|
+
{
|
|
59
|
+
severityText: "ERROR",
|
|
60
|
+
bodyContains: "timeout",
|
|
61
|
+
limit: 200,
|
|
62
|
+
sortOrder: "DESC",
|
|
63
|
+
},
|
|
64
|
+
["api-gateway"]
|
|
65
|
+
),
|
|
66
|
+
};
|