@kb-labs/studio-app 0.7.0 → 2.8.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 (175) hide show
  1. package/dist/index.html +1 -0
  2. package/dist/main.1d68e922.js +522 -0
  3. package/dist/main.1d68e922.js.map +1 -0
  4. package/dist/main.80b70197.css +2 -0
  5. package/dist/main.80b70197.css.map +1 -0
  6. package/dist/mf-manifest.json +241 -0
  7. package/dist/mf-stats.json +271 -0
  8. package/package.json +56 -39
  9. package/server.js +68 -0
  10. package/.env.example +0 -10
  11. package/UI-KIT-COMPONENTS.md +0 -783
  12. package/UI-KIT-PLAN.md +0 -326
  13. package/eslint-rules/no-direct-antd-import.js +0 -151
  14. package/eslint.config.ts +0 -27
  15. package/index.html +0 -17
  16. package/postcss.config.js +0 -7
  17. package/public/favicon.ico +0 -0
  18. package/rspack.config.mjs +0 -118
  19. package/src/App.tsx +0 -46
  20. package/src/components/devtools/devtools-log-feed.module.css +0 -165
  21. package/src/components/devtools/devtools-log-feed.tsx +0 -300
  22. package/src/components/devtools/devtools-panel.module.css +0 -121
  23. package/src/components/devtools/devtools-panel.tsx +0 -115
  24. package/src/components/empty-state.tsx +0 -28
  25. package/src/components/error-boundary.tsx +0 -210
  26. package/src/components/health-banner.module.css +0 -103
  27. package/src/components/health-banner.tsx +0 -134
  28. package/src/components/health-indicator.tsx +0 -12
  29. package/src/components/page-header.tsx +0 -49
  30. package/src/components/page-transition.tsx +0 -24
  31. package/src/components/role-switcher.tsx +0 -148
  32. package/src/components/run-badge.tsx +0 -13
  33. package/src/components/ui/icons.tsx +0 -509
  34. package/src/components/ui/index.ts +0 -25
  35. package/src/components/ui/kb-config-provider.tsx +0 -130
  36. package/src/components/ui/kb-header.module.css +0 -51
  37. package/src/components/ui/kb-header.tsx +0 -112
  38. package/src/components/ui/kb-notification-bell.module.css +0 -103
  39. package/src/components/ui/kb-notification-bell.tsx +0 -199
  40. package/src/components/ui/kb-page-layout.tsx +0 -66
  41. package/src/components/ui/kb-quick-search.module.css +0 -86
  42. package/src/components/ui/kb-quick-search.tsx +0 -196
  43. package/src/components/ui/kb-sidebar.module.css +0 -47
  44. package/src/components/ui/kb-sidebar.tsx +0 -196
  45. package/src/components/ui/kb-stat-card.module.css +0 -21
  46. package/src/components/ui/kb-stat-card.tsx +0 -22
  47. package/src/components/ui/kb-stat-grid.tsx +0 -22
  48. package/src/components/ui/kb-status-bar.module.css +0 -49
  49. package/src/components/ui/kb-status-bar.tsx +0 -145
  50. package/src/components/ui/kb-system-health-indicator.tsx +0 -229
  51. package/src/components/ui/kb-theme-toggle.tsx +0 -42
  52. package/src/components/ui/theme-adapter.ts +0 -812
  53. package/src/components/ui/theme-transition-overlay.tsx +0 -70
  54. package/src/components/ui/utils.ts +0 -6
  55. package/src/components/widget-error-boundary.tsx +0 -172
  56. package/src/config/env.ts +0 -5
  57. package/src/config/feature-flags.ts +0 -482
  58. package/src/config/studio.config.schema.ts +0 -88
  59. package/src/config/studio.config.ts +0 -84
  60. package/src/env.d.ts +0 -23
  61. package/src/hooks/use-command-palette.ts +0 -6
  62. package/src/hooks/use-devtools-store.ts +0 -25
  63. package/src/hooks/use-feature-flags.ts +0 -101
  64. package/src/index.css +0 -10
  65. package/src/layouts/dashboard-grid.tsx +0 -122
  66. package/src/layouts/index.ts +0 -12
  67. package/src/layouts/two-pane.tsx +0 -134
  68. package/src/main.tsx +0 -15
  69. package/src/modules/analytics/components/analytics-daily-stats-chart.tsx +0 -257
  70. package/src/modules/analytics/components/analytics-date-range-picker.tsx +0 -121
  71. package/src/modules/analytics/pages/analytics-cache-page.tsx +0 -285
  72. package/src/modules/analytics/pages/analytics-embeddings-page.tsx +0 -274
  73. package/src/modules/analytics/pages/analytics-events-page.tsx +0 -425
  74. package/src/modules/analytics/pages/analytics-llm-page.tsx +0 -434
  75. package/src/modules/analytics/pages/analytics-overview-page.tsx +0 -336
  76. package/src/modules/analytics/pages/analytics-page.tsx +0 -20
  77. package/src/modules/analytics/pages/analytics-storage-page.tsx +0 -344
  78. package/src/modules/analytics/pages/analytics-vectorstore-page.tsx +0 -279
  79. package/src/modules/analytics/routes/index.tsx +0 -133
  80. package/src/modules/analytics/utils/formatters.test.ts +0 -148
  81. package/src/modules/analytics/utils/formatters.ts +0 -100
  82. package/src/modules/auth/pages/login-page.module.css +0 -113
  83. package/src/modules/auth/pages/login-page.tsx +0 -80
  84. package/src/modules/auth/routes/index.tsx +0 -24
  85. package/src/modules/dashboard/components/ActivityTimelineWidget.tsx +0 -199
  86. package/src/modules/dashboard/components/AiInsightsWidget.tsx +0 -358
  87. package/src/modules/dashboard/components/AnimatedMetricCard.css +0 -88
  88. package/src/modules/dashboard/components/AnimatedMetricCard.tsx +0 -125
  89. package/src/modules/dashboard/components/HeroMetricCard.css +0 -114
  90. package/src/modules/dashboard/components/HeroMetricCard.tsx +0 -152
  91. package/src/modules/dashboard/components/HeroMetricsWidget.tsx +0 -146
  92. package/src/modules/dashboard/components/SystemResourcesWidget.tsx +0 -197
  93. package/src/modules/dashboard/components/dashboard-empty.tsx +0 -22
  94. package/src/modules/dashboard/components/dashboard-kpis-widget.tsx +0 -59
  95. package/src/modules/dashboard/components/dashboard-kpis.tsx +0 -13
  96. package/src/modules/dashboard/components/dashboard-latency-percentiles-widget.tsx +0 -85
  97. package/src/modules/dashboard/components/dashboard-metrics-widget.tsx +0 -78
  98. package/src/modules/dashboard/components/dashboard-plugins-widget.tsx +0 -67
  99. package/src/modules/dashboard/components/dashboard-requests-widget.tsx +0 -62
  100. package/src/modules/dashboard/layouts/dashboard-layout.tsx +0 -16
  101. package/src/modules/dashboard/pages/ai-insights-page.tsx +0 -563
  102. package/src/modules/dashboard/pages/dashboard-animations.css +0 -317
  103. package/src/modules/dashboard/pages/dashboard-page.tsx +0 -13
  104. package/src/modules/dashboard/routes/index.tsx +0 -70
  105. package/src/modules/observability/pages/devkit-page.tsx +0 -263
  106. package/src/modules/observability/pages/incident-detail-page.tsx +0 -571
  107. package/src/modules/observability/pages/incidents-page.tsx +0 -370
  108. package/src/modules/observability/pages/log-detail-page.tsx +0 -508
  109. package/src/modules/observability/pages/logs-page.tsx +0 -1129
  110. package/src/modules/observability/pages/prometheus-metrics-page.tsx +0 -486
  111. package/src/modules/observability/pages/state-broker-page.tsx +0 -229
  112. package/src/modules/observability/pages/system-events-page.tsx +0 -255
  113. package/src/modules/observability/routes/index.tsx +0 -133
  114. package/src/modules/plugins/components/marketplace-card.tsx +0 -153
  115. package/src/modules/plugins/components/plugin-ai-assistant-modal.tsx +0 -374
  116. package/src/modules/plugins/components/plugin-card.tsx +0 -136
  117. package/src/modules/plugins/components/plugin-detail/capabilities-summary.tsx +0 -101
  118. package/src/modules/plugins/components/plugin-detail/cli-commands-table.tsx +0 -101
  119. package/src/modules/plugins/components/plugin-detail/index.ts +0 -7
  120. package/src/modules/plugins/components/plugin-detail/jobs-table.tsx +0 -64
  121. package/src/modules/plugins/components/plugin-detail/permissions/env-permissions.tsx +0 -30
  122. package/src/modules/plugins/components/plugin-detail/permissions/filesystem-permissions.tsx +0 -68
  123. package/src/modules/plugins/components/plugin-detail/permissions/index.ts +0 -6
  124. package/src/modules/plugins/components/plugin-detail/permissions/network-permissions.tsx +0 -43
  125. package/src/modules/plugins/components/plugin-detail/permissions/platform-services.tsx +0 -242
  126. package/src/modules/plugins/components/plugin-detail/permissions/resource-quotas.tsx +0 -96
  127. package/src/modules/plugins/components/plugin-detail/permissions/shell-permissions.tsx +0 -55
  128. package/src/modules/plugins/components/plugin-detail/permissions-view.tsx +0 -47
  129. package/src/modules/plugins/components/plugin-detail/plugin-header.tsx +0 -169
  130. package/src/modules/plugins/components/plugin-detail/rest-routes-table.tsx +0 -159
  131. package/src/modules/plugins/components/plugin-detail/workflows-table.tsx +0 -40
  132. package/src/modules/plugins/components/plugin-grid.tsx +0 -20
  133. package/src/modules/plugins/components/plugin-table.tsx +0 -178
  134. package/src/modules/plugins/pages/marketplace-page.tsx +0 -200
  135. package/src/modules/plugins/pages/plugin-detail-page.tsx +0 -1145
  136. package/src/modules/plugins/routes/index.tsx +0 -48
  137. package/src/modules/plugins/utils/index.ts +0 -1
  138. package/src/modules/plugins/utils/schema-helpers.ts +0 -21
  139. package/src/modules/settings/components/api-routes-viewer.tsx +0 -415
  140. package/src/modules/settings/components/appearance-settings.tsx +0 -200
  141. package/src/modules/settings/components/configuration-settings.tsx +0 -321
  142. package/src/modules/settings/components/data-privacy-settings.tsx +0 -111
  143. package/src/modules/settings/components/experimental-settings.tsx +0 -243
  144. package/src/modules/settings/components/navigation-settings.tsx +0 -198
  145. package/src/modules/settings/components/notifications-settings.tsx +0 -40
  146. package/src/modules/settings/pages/settings-page.tsx +0 -298
  147. package/src/modules/settings/routes/index.tsx +0 -47
  148. package/src/pages/README-assistant.md +0 -91
  149. package/src/pages/login-page.tsx +0 -177
  150. package/src/pages/not-found-page.tsx +0 -85
  151. package/src/providers/auth-provider.tsx +0 -40
  152. package/src/providers/command-palette-provider.tsx +0 -193
  153. package/src/providers/data-sources-provider.tsx +0 -27
  154. package/src/providers/devtools-provider.tsx +0 -72
  155. package/src/providers/navigation-items-provider.tsx +0 -38
  156. package/src/providers/registry-v2-provider.tsx +0 -93
  157. package/src/providers/settings-provider.tsx +0 -158
  158. package/src/router.tsx +0 -302
  159. package/src/routes/helpers.tsx +0 -25
  160. package/src/routes/plugin-page-v2.tsx +0 -52
  161. package/src/routes/types.ts +0 -18
  162. package/src/styles/antd-overrides.css +0 -211
  163. package/src/styles/base.css +0 -190
  164. package/src/styles/settings.css +0 -75
  165. package/src/styles/variables.css +0 -94
  166. package/src/utils/analytics.ts +0 -183
  167. package/src/utils/apply-navigation-categories.ts +0 -83
  168. package/src/utils/commands.ts +0 -252
  169. package/src/utils/export.ts +0 -174
  170. package/src/utils/format-date.ts +0 -166
  171. package/src/utils/logger.ts +0 -110
  172. package/tailwind.config.ts +0 -13
  173. package/tsconfig.json +0 -13
  174. package/vitest-setup.ts +0 -1
  175. /package/{public → dist}/favicon.svg +0 -0
@@ -1,425 +0,0 @@
1
- import { useState, useMemo, useCallback } from 'react';
2
- import { UITable, UIAlert, UISelect, UISpace, UIButton, UIDrawer, UIDescriptions, UIDescriptionsItem, UITag, UITooltip, UIRangePicker, UIText, UICard, UIPage, UIPageHeader } from '@kb-labs/studio-ui-kit';
3
- import {
4
- ReloadOutlined,
5
- ClearOutlined,
6
- } from '@ant-design/icons';
7
- import {
8
- useAnalyticsEvents,
9
- useAnalyticsStats,
10
- } from '@kb-labs/studio-data-client';
11
- import { useDataSources } from '../../../providers/data-sources-provider';
12
- import type { AnalyticsEvent } from '@kb-labs/studio-data-client';
13
- import { type Dayjs } from 'dayjs';
14
-
15
- const PAGE_SIZE = 50;
16
-
17
- // ─── Helpers ──────────────────────────────────────────────────────────────────
18
-
19
- function formatRelativeTime(isoString: string): string {
20
- const diffMs = Date.now() - new Date(isoString).getTime();
21
- const minutes = Math.floor(diffMs / 60000);
22
- const hours = Math.floor(diffMs / 3600000);
23
- const days = Math.floor(diffMs / 86400000);
24
- if (days > 0) {return `${days}d ago`;}
25
- if (hours > 0) {return `${hours}h ago`;}
26
- if (minutes > 0) {return `${minutes}m ago`;}
27
- return 'just now';
28
- }
29
-
30
- function formatAbsoluteTime(isoString: string): string {
31
- return new Date(isoString).toLocaleString();
32
- }
33
-
34
- function getActorColor(actorType: 'user' | 'agent' | 'ci'): string {
35
- switch (actorType) {
36
- case 'user': return 'blue';
37
- case 'agent': return 'purple';
38
- case 'ci': return 'orange';
39
- default: return 'default';
40
- }
41
- }
42
-
43
- function getTypeColor(type: string): string {
44
- if (type.startsWith('llm.')) {return 'volcano';}
45
- if (type.startsWith('mind.')) {return 'geekblue';}
46
- if (type.startsWith('workflow.')) {return 'green';}
47
- if (type.startsWith('embeddings.')) {return 'cyan';}
48
- if (type.startsWith('vectorstore.')) {return 'purple';}
49
- if (type.startsWith('commit.')) {return 'gold';}
50
- if (type.startsWith('plugin.')) {return 'magenta';}
51
- return 'default';
52
- }
53
-
54
- // ─── Event Detail Drawer ──────────────────────────────────────────────────────
55
-
56
- interface EventDrawerProps {
57
- event: AnalyticsEvent | null;
58
- onClose: () => void;
59
- }
60
-
61
- function EventDrawer({ event, onClose }: EventDrawerProps) {
62
- if (!event) {return null;}
63
-
64
- return (
65
- <UIDrawer
66
- title={
67
- <UISpace>
68
- <UITag color={getTypeColor(event.type)}>{event.type}</UITag>
69
- </UISpace>
70
- }
71
- open={!!event}
72
- onClose={onClose}
73
- width={520}
74
- styles={{ body: { padding: '16px 24px' } }}
75
- >
76
- <UIDescriptions column={1} size="small" bordered style={{ marginBottom: 20 }}>
77
- <UIDescriptionsItem label="Time">
78
- <UITooltip title={event.ts}>
79
- {formatAbsoluteTime(event.ts)}
80
- </UITooltip>
81
- </UIDescriptionsItem>
82
- <UIDescriptionsItem label="Source">
83
- {event.source.product} <UIText color="secondary">v{event.source.version}</UIText>
84
- </UIDescriptionsItem>
85
- {event.actor && (
86
- <UIDescriptionsItem label="Actor">
87
- <UITag color={getActorColor(event.actor.type)}>
88
- {event.actor.name || event.actor.type}
89
- </UITag>
90
- {event.actor.id && (
91
- <UIText color="secondary" style={{ marginLeft: 8, fontSize: 12 }}>
92
- {event.actor.id}
93
- </UIText>
94
- )}
95
- </UIDescriptionsItem>
96
- )}
97
- <UIDescriptionsItem label="Run ID">
98
- <UIText style={{ fontFamily: 'monospace', fontSize: 12 }}>{event.runId}</UIText>
99
- </UIDescriptionsItem>
100
- <UIDescriptionsItem label="Ingest">
101
- <UIText color="secondary" style={{ fontSize: 12 }}>
102
- {formatAbsoluteTime(event.ingestTs)}
103
- </UIText>
104
- </UIDescriptionsItem>
105
- </UIDescriptions>
106
-
107
- {!!event.payload && (
108
- <div style={{ marginBottom: 20 }}>
109
- <UIText weight="semibold" style={{ display: 'block', marginBottom: 8 }}>
110
- Payload
111
- </UIText>
112
- <pre
113
- style={{
114
- background: 'var(--color-fill-quaternary, #f5f5f5)',
115
- borderRadius: 6,
116
- padding: '10px 14px',
117
- fontSize: 12,
118
- lineHeight: 1.6,
119
- overflowX: 'auto',
120
- maxHeight: 320,
121
- overflowY: 'auto',
122
- margin: 0,
123
- }}
124
- >
125
- {JSON.stringify(event.payload, null, 2)}
126
- </pre>
127
- </div>
128
- )}
129
-
130
- {event.ctx && Object.keys(event.ctx).length > 0 && (
131
- <div>
132
- <UIText weight="semibold" style={{ display: 'block', marginBottom: 8 }}>
133
- Context
134
- </UIText>
135
- <pre
136
- style={{
137
- background: 'var(--color-fill-quaternary, #f5f5f5)',
138
- borderRadius: 6,
139
- padding: '10px 14px',
140
- fontSize: 12,
141
- lineHeight: 1.6,
142
- overflowX: 'auto',
143
- maxHeight: 200,
144
- overflowY: 'auto',
145
- margin: 0,
146
- }}
147
- >
148
- {JSON.stringify(event.ctx, null, 2)}
149
- </pre>
150
- </div>
151
- )}
152
- </UIDrawer>
153
- );
154
- }
155
-
156
- // ─── Main Page ────────────────────────────────────────────────────────────────
157
-
158
- export function AnalyticsEventsPage() {
159
- const sources = useDataSources();
160
-
161
- // ── Filter state
162
- const [selectedTypes, setSelectedTypes] = useState<string[]>([]);
163
- const [selectedSource, setSelectedSource] = useState<string | undefined>();
164
- const [dateRange, setDateRange] = useState<[Dayjs, Dayjs] | null>(null);
165
- const [limit, setLimit] = useState(PAGE_SIZE);
166
-
167
- // ── Drawer state
168
- const [selectedEvent, setSelectedEvent] = useState<AnalyticsEvent | null>(null);
169
-
170
- // ── Determine if any filter is active (disables auto-refresh for live tail)
171
- const hasFilters = selectedTypes.length > 0 || !!selectedSource || !!dateRange;
172
-
173
- // ── Build query
174
- const query = useMemo(() => ({
175
- type: selectedTypes.length > 0 ? selectedTypes : undefined,
176
- source: selectedSource,
177
- from: dateRange ? dateRange[0].toISOString() : undefined,
178
- to: dateRange ? dateRange[1].endOf('day').toISOString() : undefined,
179
- limit,
180
- }), [selectedTypes, selectedSource, dateRange, limit]);
181
-
182
- const {
183
- data: eventsData,
184
- isLoading: eventsLoading,
185
- isError: isEventsError,
186
- error: eventsError,
187
- refetch,
188
- dataUpdatedAt,
189
- } = useAnalyticsEvents(sources.analytics, query);
190
-
191
- // ── Stats for filter options
192
- const { data: statsData } = useAnalyticsStats(sources.analytics);
193
-
194
- const typeOptions = useMemo(() =>
195
- Object.keys(statsData?.byType ?? {})
196
- .sort()
197
- .map((t) => ({ label: t, value: t })),
198
- [statsData]
199
- );
200
-
201
- const sourceOptions = useMemo(() =>
202
- Object.keys(statsData?.bySource ?? {})
203
- .sort()
204
- .map((s) => ({ label: s, value: s })),
205
- [statsData]
206
- );
207
-
208
- // ── Handlers
209
- const handleClearFilters = useCallback(() => {
210
- setSelectedTypes([]);
211
- setSelectedSource(undefined);
212
- setDateRange(null);
213
- setLimit(PAGE_SIZE);
214
- }, []);
215
-
216
- const handleLoadMore = useCallback(() => {
217
- setLimit((prev) => prev + PAGE_SIZE);
218
- }, []);
219
-
220
- const handleRowClick = useCallback((record: AnalyticsEvent) => {
221
- setSelectedEvent(record);
222
- }, []);
223
-
224
- // ── Error: analytics not configured
225
- const analyticsNotConfigured =
226
- isEventsError &&
227
- eventsError instanceof Error &&
228
- eventsError.message.includes('not support');
229
-
230
- if (analyticsNotConfigured) {
231
- return (
232
- <UIPage>
233
- <UIPageHeader title="Event Log" description="Platform event stream" />
234
- <UIAlert
235
- message="Analytics Not Configured"
236
- description="Configure an analytics adapter in kb.config.json to view events."
237
- variant="info"
238
- showIcon
239
- />
240
- </UIPage>
241
- );
242
- }
243
-
244
- if (isEventsError) {
245
- return (
246
- <UIPage>
247
- <UIPageHeader title="Event Log" description="Platform event stream" />
248
- <UIAlert
249
- message="Failed to load events"
250
- description={eventsError instanceof Error ? eventsError.message : 'Unknown error'}
251
- variant="error"
252
- showIcon
253
- />
254
- </UIPage>
255
- );
256
- }
257
-
258
- const events = eventsData?.events ?? [];
259
- const total = eventsData?.total ?? 0;
260
- const hasMore = eventsData?.hasMore ?? false;
261
-
262
- const lastUpdated = dataUpdatedAt
263
- ? formatRelativeTime(new Date(dataUpdatedAt).toISOString())
264
- : null;
265
-
266
- return (
267
- <UIPage width="full">
268
- <UIPageHeader
269
- title="Event Log"
270
- description={
271
- hasFilters
272
- ? `${total.toLocaleString()} events matching filters`
273
- : `Live tail · auto-refresh every 30s${lastUpdated ? ` · updated ${lastUpdated}` : ''}`
274
- }
275
- />
276
-
277
- <UICard style={{ marginBottom: 16 }}>
278
- <UISpace wrap size="small" style={{ width: '100%', justifyContent: 'space-between' }}>
279
- <UISpace wrap size="small">
280
- <UISelect
281
- mode="multiple"
282
- placeholder="Event type"
283
- value={selectedTypes}
284
- onChange={(v) => setSelectedTypes(v as string[])}
285
- options={typeOptions}
286
- style={{ minWidth: 200 }}
287
- maxTagCount={2}
288
- allowClear
289
- />
290
- <UISelect
291
- placeholder="Source"
292
- value={selectedSource}
293
- onChange={(v) => setSelectedSource(v as string | undefined)}
294
- options={sourceOptions}
295
- style={{ width: 140 }}
296
- allowClear
297
- />
298
- <UIRangePicker
299
- value={dateRange}
300
- onChange={(dates) => {
301
- if (dates && dates[0] && dates[1]) {
302
- setDateRange([dates[0], dates[1]]);
303
- } else {
304
- setDateRange(null);
305
- }
306
- }}
307
- format="DD/MM/YYYY"
308
- allowClear
309
- />
310
- {hasFilters && (
311
- <UIButton
312
- icon={<ClearOutlined />}
313
- onClick={handleClearFilters}
314
- size="middle"
315
- >
316
- Clear
317
- </UIButton>
318
- )}
319
- </UISpace>
320
- <UIButton
321
- icon={<ReloadOutlined />}
322
- onClick={() => refetch()}
323
- loading={eventsLoading}
324
- size="middle"
325
- >
326
- Refresh
327
- </UIButton>
328
- </UISpace>
329
- </UICard>
330
-
331
- <UICard>
332
- <UITable<AnalyticsEvent>
333
- dataSource={events}
334
- rowKey="id"
335
- loading={eventsLoading}
336
- pagination={false}
337
- size="small"
338
- onRow={(record) => ({
339
- onClick: () => handleRowClick(record),
340
- style: { cursor: 'pointer' },
341
- })}
342
- columns={[
343
- {
344
- title: 'Time',
345
- dataIndex: 'ts',
346
- key: 'ts',
347
- width: 100,
348
- render: (ts: string) => (
349
- <UITooltip title={formatAbsoluteTime(ts)}>
350
- <UIText color="secondary" style={{ fontSize: 12, whiteSpace: 'nowrap' }}>
351
- {formatRelativeTime(ts)}
352
- </UIText>
353
- </UITooltip>
354
- ),
355
- },
356
- {
357
- title: 'Type',
358
- dataIndex: 'type',
359
- key: 'type',
360
- render: (type: string) => (
361
- <UITag color={getTypeColor(type)} style={{ fontFamily: 'monospace', fontSize: 11 }}>
362
- {type}
363
- </UITag>
364
- ),
365
- },
366
- {
367
- title: 'Source',
368
- dataIndex: 'source',
369
- key: 'source',
370
- width: 100,
371
- render: (source: { product: string; version: string }) => (
372
- <UITag>{source.product}</UITag>
373
- ),
374
- },
375
- {
376
- title: 'Actor',
377
- dataIndex: 'actor',
378
- key: 'actor',
379
- width: 120,
380
- render: (actor?: { type: 'user' | 'agent' | 'ci'; name?: string }) =>
381
- actor ? (
382
- <UITag color={getActorColor(actor.type)}>
383
- {actor.name || actor.type}
384
- </UITag>
385
- ) : (
386
- <UIText color="secondary">—</UIText>
387
- ),
388
- },
389
- {
390
- title: 'Run ID',
391
- dataIndex: 'runId',
392
- key: 'runId',
393
- width: 110,
394
- render: (runId: string) => (
395
- <UIText color="secondary" style={{ fontSize: 11, fontFamily: 'monospace' }}>
396
- {runId ? runId.slice(0, 10) : '—'}
397
- </UIText>
398
- ),
399
- },
400
- ]}
401
- />
402
- {hasMore ? (
403
- <div style={{ textAlign: 'center', paddingTop: 8 }}>
404
- <UIButton onClick={handleLoadMore} loading={eventsLoading}>
405
- Load {PAGE_SIZE} more
406
- </UIButton>
407
- <UIText color="secondary" style={{ marginLeft: 12, fontSize: 12 }}>
408
- Showing {events.length} of {total.toLocaleString()}
409
- </UIText>
410
- </div>
411
- ) : (
412
- <div style={{ textAlign: 'center', paddingTop: 4 }}>
413
- <UIText color="secondary" style={{ fontSize: 12 }}>
414
- {total > 0
415
- ? `All ${total.toLocaleString()} events loaded`
416
- : 'No events found'}
417
- </UIText>
418
- </div>
419
- )}
420
- </UICard>
421
-
422
- <EventDrawer event={selectedEvent} onClose={() => setSelectedEvent(null)} />
423
- </UIPage>
424
- );
425
- }