@kb-labs/studio-app 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 (168) hide show
  1. package/.env.example +10 -0
  2. package/README.md +74 -0
  3. package/UI-KIT-COMPONENTS.md +783 -0
  4. package/UI-KIT-PLAN.md +326 -0
  5. package/eslint-rules/no-direct-antd-import.js +151 -0
  6. package/eslint.config.ts +27 -0
  7. package/index.html +17 -0
  8. package/package.json +72 -0
  9. package/postcss.config.js +7 -0
  10. package/public/favicon.ico +0 -0
  11. package/public/favicon.svg +7 -0
  12. package/rspack.config.mjs +118 -0
  13. package/src/App.tsx +46 -0
  14. package/src/components/devtools/devtools-log-feed.module.css +165 -0
  15. package/src/components/devtools/devtools-log-feed.tsx +300 -0
  16. package/src/components/devtools/devtools-panel.module.css +121 -0
  17. package/src/components/devtools/devtools-panel.tsx +115 -0
  18. package/src/components/empty-state.tsx +28 -0
  19. package/src/components/error-boundary.tsx +210 -0
  20. package/src/components/health-banner.module.css +103 -0
  21. package/src/components/health-banner.tsx +134 -0
  22. package/src/components/health-indicator.tsx +12 -0
  23. package/src/components/page-header.tsx +49 -0
  24. package/src/components/page-transition.tsx +24 -0
  25. package/src/components/role-switcher.tsx +148 -0
  26. package/src/components/run-badge.tsx +13 -0
  27. package/src/components/ui/icons.tsx +509 -0
  28. package/src/components/ui/index.ts +25 -0
  29. package/src/components/ui/kb-config-provider.tsx +130 -0
  30. package/src/components/ui/kb-header.module.css +51 -0
  31. package/src/components/ui/kb-header.tsx +112 -0
  32. package/src/components/ui/kb-notification-bell.module.css +103 -0
  33. package/src/components/ui/kb-notification-bell.tsx +199 -0
  34. package/src/components/ui/kb-page-layout.tsx +66 -0
  35. package/src/components/ui/kb-quick-search.module.css +86 -0
  36. package/src/components/ui/kb-quick-search.tsx +196 -0
  37. package/src/components/ui/kb-sidebar.module.css +47 -0
  38. package/src/components/ui/kb-sidebar.tsx +196 -0
  39. package/src/components/ui/kb-stat-card.module.css +21 -0
  40. package/src/components/ui/kb-stat-card.tsx +22 -0
  41. package/src/components/ui/kb-stat-grid.tsx +22 -0
  42. package/src/components/ui/kb-status-bar.module.css +49 -0
  43. package/src/components/ui/kb-status-bar.tsx +145 -0
  44. package/src/components/ui/kb-system-health-indicator.tsx +229 -0
  45. package/src/components/ui/kb-theme-toggle.tsx +42 -0
  46. package/src/components/ui/theme-adapter.ts +812 -0
  47. package/src/components/ui/theme-transition-overlay.tsx +70 -0
  48. package/src/components/ui/utils.ts +6 -0
  49. package/src/components/widget-error-boundary.tsx +172 -0
  50. package/src/config/env.ts +5 -0
  51. package/src/config/feature-flags.ts +482 -0
  52. package/src/config/studio.config.schema.ts +88 -0
  53. package/src/config/studio.config.ts +84 -0
  54. package/src/env.d.ts +23 -0
  55. package/src/hooks/use-command-palette.ts +6 -0
  56. package/src/hooks/use-devtools-store.ts +25 -0
  57. package/src/hooks/use-feature-flags.ts +101 -0
  58. package/src/index.css +10 -0
  59. package/src/layouts/dashboard-grid.tsx +122 -0
  60. package/src/layouts/index.ts +12 -0
  61. package/src/layouts/two-pane.tsx +134 -0
  62. package/src/main.tsx +15 -0
  63. package/src/modules/analytics/components/analytics-daily-stats-chart.tsx +257 -0
  64. package/src/modules/analytics/components/analytics-date-range-picker.tsx +121 -0
  65. package/src/modules/analytics/pages/analytics-cache-page.tsx +285 -0
  66. package/src/modules/analytics/pages/analytics-embeddings-page.tsx +274 -0
  67. package/src/modules/analytics/pages/analytics-events-page.tsx +425 -0
  68. package/src/modules/analytics/pages/analytics-llm-page.tsx +434 -0
  69. package/src/modules/analytics/pages/analytics-overview-page.tsx +336 -0
  70. package/src/modules/analytics/pages/analytics-page.tsx +20 -0
  71. package/src/modules/analytics/pages/analytics-storage-page.tsx +344 -0
  72. package/src/modules/analytics/pages/analytics-vectorstore-page.tsx +279 -0
  73. package/src/modules/analytics/routes/index.tsx +133 -0
  74. package/src/modules/analytics/utils/formatters.test.ts +148 -0
  75. package/src/modules/analytics/utils/formatters.ts +100 -0
  76. package/src/modules/auth/pages/login-page.module.css +113 -0
  77. package/src/modules/auth/pages/login-page.tsx +80 -0
  78. package/src/modules/auth/routes/index.tsx +24 -0
  79. package/src/modules/dashboard/components/ActivityTimelineWidget.tsx +199 -0
  80. package/src/modules/dashboard/components/AiInsightsWidget.tsx +358 -0
  81. package/src/modules/dashboard/components/AnimatedMetricCard.css +88 -0
  82. package/src/modules/dashboard/components/AnimatedMetricCard.tsx +125 -0
  83. package/src/modules/dashboard/components/HeroMetricCard.css +114 -0
  84. package/src/modules/dashboard/components/HeroMetricCard.tsx +152 -0
  85. package/src/modules/dashboard/components/HeroMetricsWidget.tsx +146 -0
  86. package/src/modules/dashboard/components/SystemResourcesWidget.tsx +197 -0
  87. package/src/modules/dashboard/components/dashboard-empty.tsx +22 -0
  88. package/src/modules/dashboard/components/dashboard-kpis-widget.tsx +59 -0
  89. package/src/modules/dashboard/components/dashboard-kpis.tsx +13 -0
  90. package/src/modules/dashboard/components/dashboard-latency-percentiles-widget.tsx +85 -0
  91. package/src/modules/dashboard/components/dashboard-metrics-widget.tsx +78 -0
  92. package/src/modules/dashboard/components/dashboard-plugins-widget.tsx +67 -0
  93. package/src/modules/dashboard/components/dashboard-requests-widget.tsx +62 -0
  94. package/src/modules/dashboard/layouts/dashboard-layout.tsx +16 -0
  95. package/src/modules/dashboard/pages/ai-insights-page.tsx +563 -0
  96. package/src/modules/dashboard/pages/dashboard-animations.css +317 -0
  97. package/src/modules/dashboard/pages/dashboard-page.tsx +13 -0
  98. package/src/modules/dashboard/routes/index.tsx +70 -0
  99. package/src/modules/observability/pages/devkit-page.tsx +263 -0
  100. package/src/modules/observability/pages/incident-detail-page.tsx +571 -0
  101. package/src/modules/observability/pages/incidents-page.tsx +370 -0
  102. package/src/modules/observability/pages/log-detail-page.tsx +508 -0
  103. package/src/modules/observability/pages/logs-page.tsx +1129 -0
  104. package/src/modules/observability/pages/prometheus-metrics-page.tsx +486 -0
  105. package/src/modules/observability/pages/state-broker-page.tsx +229 -0
  106. package/src/modules/observability/pages/system-events-page.tsx +255 -0
  107. package/src/modules/observability/routes/index.tsx +133 -0
  108. package/src/modules/plugins/components/marketplace-card.tsx +153 -0
  109. package/src/modules/plugins/components/plugin-ai-assistant-modal.tsx +374 -0
  110. package/src/modules/plugins/components/plugin-card.tsx +136 -0
  111. package/src/modules/plugins/components/plugin-detail/capabilities-summary.tsx +101 -0
  112. package/src/modules/plugins/components/plugin-detail/cli-commands-table.tsx +101 -0
  113. package/src/modules/plugins/components/plugin-detail/index.ts +7 -0
  114. package/src/modules/plugins/components/plugin-detail/jobs-table.tsx +64 -0
  115. package/src/modules/plugins/components/plugin-detail/permissions/env-permissions.tsx +30 -0
  116. package/src/modules/plugins/components/plugin-detail/permissions/filesystem-permissions.tsx +68 -0
  117. package/src/modules/plugins/components/plugin-detail/permissions/index.ts +6 -0
  118. package/src/modules/plugins/components/plugin-detail/permissions/network-permissions.tsx +43 -0
  119. package/src/modules/plugins/components/plugin-detail/permissions/platform-services.tsx +242 -0
  120. package/src/modules/plugins/components/plugin-detail/permissions/resource-quotas.tsx +96 -0
  121. package/src/modules/plugins/components/plugin-detail/permissions/shell-permissions.tsx +55 -0
  122. package/src/modules/plugins/components/plugin-detail/permissions-view.tsx +47 -0
  123. package/src/modules/plugins/components/plugin-detail/plugin-header.tsx +169 -0
  124. package/src/modules/plugins/components/plugin-detail/rest-routes-table.tsx +159 -0
  125. package/src/modules/plugins/components/plugin-detail/workflows-table.tsx +40 -0
  126. package/src/modules/plugins/components/plugin-grid.tsx +20 -0
  127. package/src/modules/plugins/components/plugin-table.tsx +178 -0
  128. package/src/modules/plugins/pages/marketplace-page.tsx +200 -0
  129. package/src/modules/plugins/pages/plugin-detail-page.tsx +1145 -0
  130. package/src/modules/plugins/routes/index.tsx +48 -0
  131. package/src/modules/plugins/utils/index.ts +1 -0
  132. package/src/modules/plugins/utils/schema-helpers.ts +21 -0
  133. package/src/modules/settings/components/api-routes-viewer.tsx +415 -0
  134. package/src/modules/settings/components/appearance-settings.tsx +200 -0
  135. package/src/modules/settings/components/configuration-settings.tsx +321 -0
  136. package/src/modules/settings/components/data-privacy-settings.tsx +111 -0
  137. package/src/modules/settings/components/experimental-settings.tsx +243 -0
  138. package/src/modules/settings/components/navigation-settings.tsx +198 -0
  139. package/src/modules/settings/components/notifications-settings.tsx +40 -0
  140. package/src/modules/settings/pages/settings-page.tsx +298 -0
  141. package/src/modules/settings/routes/index.tsx +47 -0
  142. package/src/pages/README-assistant.md +91 -0
  143. package/src/pages/login-page.tsx +177 -0
  144. package/src/pages/not-found-page.tsx +85 -0
  145. package/src/providers/auth-provider.tsx +40 -0
  146. package/src/providers/command-palette-provider.tsx +193 -0
  147. package/src/providers/data-sources-provider.tsx +27 -0
  148. package/src/providers/devtools-provider.tsx +72 -0
  149. package/src/providers/navigation-items-provider.tsx +38 -0
  150. package/src/providers/registry-v2-provider.tsx +93 -0
  151. package/src/providers/settings-provider.tsx +158 -0
  152. package/src/router.tsx +302 -0
  153. package/src/routes/helpers.tsx +25 -0
  154. package/src/routes/plugin-page-v2.tsx +52 -0
  155. package/src/routes/types.ts +18 -0
  156. package/src/styles/antd-overrides.css +211 -0
  157. package/src/styles/base.css +190 -0
  158. package/src/styles/settings.css +75 -0
  159. package/src/styles/variables.css +94 -0
  160. package/src/utils/analytics.ts +183 -0
  161. package/src/utils/apply-navigation-categories.ts +83 -0
  162. package/src/utils/commands.ts +252 -0
  163. package/src/utils/export.ts +174 -0
  164. package/src/utils/format-date.ts +166 -0
  165. package/src/utils/logger.ts +110 -0
  166. package/tailwind.config.ts +13 -0
  167. package/tsconfig.json +13 -0
  168. package/vitest-setup.ts +1 -0
@@ -0,0 +1,370 @@
1
+ import { useState } from 'react';
2
+ import { useNavigate } from 'react-router-dom';
3
+ import { useQuery } from '@tanstack/react-query';
4
+ import {
5
+ UICard,
6
+ UIAlert,
7
+ UIBadge,
8
+ UITag,
9
+ UIRow,
10
+ UICol,
11
+ UIStatistic,
12
+ UITable,
13
+ UISelect,
14
+ UIButton,
15
+ UISpace,
16
+ UITooltip,
17
+ UIIcon,
18
+ } from '@kb-labs/studio-ui-kit';
19
+ import type {
20
+ Incident,
21
+ IncidentQuery,
22
+ IncidentSeverity,
23
+ IncidentType,
24
+ IncidentsListResponse,
25
+ } from '@kb-labs/studio-data-client';
26
+ import { useDataSources } from '../../../providers/data-sources-provider';
27
+ import dayjs from 'dayjs';
28
+ import relativeTime from 'dayjs/plugin/relativeTime';
29
+ import { UIPage, UIPageHeader } from '@kb-labs/studio-ui-kit';
30
+
31
+ dayjs.extend(relativeTime);
32
+
33
+ /**
34
+ * Format timestamp to human-readable string
35
+ */
36
+ function formatTime(timestamp: number): string {
37
+ return dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss');
38
+ }
39
+
40
+ /**
41
+ * Format duration between timestamps
42
+ */
43
+ function formatDuration(from: number, to: number): string {
44
+ const durationMs = to - from;
45
+ const minutes = Math.floor(durationMs / 60000);
46
+ const hours = Math.floor(minutes / 60);
47
+ const days = Math.floor(hours / 24);
48
+
49
+ if (days > 0) {return `${days}d ${hours % 24}h`;}
50
+ if (hours > 0) {return `${hours}h ${minutes % 60}m`;}
51
+ return `${minutes}m`;
52
+ }
53
+
54
+ /**
55
+ * Get severity icon and color
56
+ */
57
+ function getSeverityConfig(severity: IncidentSeverity): { icon: React.ReactElement; color: string } {
58
+ switch (severity) {
59
+ case 'critical':
60
+ return { icon: <UIIcon name="FireOutlined" />, color: '#ff4d4f' };
61
+ case 'warning':
62
+ return { icon: <UIIcon name="WarningOutlined" />, color: '#faad14' };
63
+ case 'info':
64
+ return { icon: <UIIcon name="InfoCircleOutlined" />, color: '#1890ff' };
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Get incident type label
70
+ */
71
+ function getTypeLabel(type: IncidentType): string {
72
+ switch (type) {
73
+ case 'error_rate':
74
+ return 'Error Rate';
75
+ case 'latency_spike':
76
+ return 'Latency Spike';
77
+ case 'plugin_failure':
78
+ return 'Plugin Failure';
79
+ case 'adapter_failure':
80
+ return 'Adapter Failure';
81
+ case 'system_health':
82
+ return 'System Health';
83
+ case 'custom':
84
+ return 'Custom';
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Incidents Management Page
90
+ *
91
+ * Shows all incidents with filters and summary statistics
92
+ */
93
+ export function IncidentsPage() {
94
+ const navigate = useNavigate();
95
+ const sources = useDataSources();
96
+ const [filters, setFilters] = useState<IncidentQuery>({
97
+ limit: 50,
98
+ includeResolved: false,
99
+ });
100
+
101
+ // Fetch incidents list
102
+ const {
103
+ data,
104
+ isLoading,
105
+ error,
106
+ refetch,
107
+ } = useQuery<IncidentsListResponse>({
108
+ queryKey: ['incidents', 'list', filters],
109
+ queryFn: async () => {
110
+ return sources.observability.listIncidents(filters);
111
+ },
112
+ refetchInterval: 30000, // Auto-refresh every 30s
113
+ });
114
+
115
+ const incidents = data?.data?.incidents ?? [];
116
+ const summary = data?.data?.summary;
117
+
118
+ // Handle filter changes
119
+ const handleSeverityChange = (value: string | number | (string | number)[]) => {
120
+ setFilters({ ...filters, severity: (value as IncidentSeverity) || undefined });
121
+ };
122
+
123
+ const handleTypeChange = (value: string | number | (string | number)[]) => {
124
+ setFilters({ ...filters, type: (value as IncidentType) || undefined });
125
+ };
126
+
127
+ const handleIncludeResolvedChange = (value: string | number | (string | number)[]) => {
128
+ setFilters({ ...filters, includeResolved: value === 'true' });
129
+ };
130
+
131
+ const handleViewIncident = (id: string) => {
132
+ navigate(`/observability/incidents/${id}`);
133
+ };
134
+
135
+ // Table columns
136
+ const columns = [
137
+ {
138
+ title: 'Severity',
139
+ dataIndex: 'severity',
140
+ key: 'severity',
141
+ width: 100,
142
+ render: (severity: IncidentSeverity) => {
143
+ const config = getSeverityConfig(severity);
144
+ return (
145
+ <UITooltip title={severity.toUpperCase()}>
146
+ <UITag color={config.color} icon={config.icon}>
147
+ {severity.toUpperCase()}
148
+ </UITag>
149
+ </UITooltip>
150
+ );
151
+ },
152
+ },
153
+ {
154
+ title: 'Type',
155
+ dataIndex: 'type',
156
+ key: 'type',
157
+ width: 140,
158
+ render: (type: IncidentType) => (
159
+ <UITag>{getTypeLabel(type)}</UITag>
160
+ ),
161
+ },
162
+ {
163
+ title: 'Title',
164
+ dataIndex: 'title',
165
+ key: 'title',
166
+ render: (title: string) => <strong>{title}</strong>,
167
+ },
168
+ {
169
+ title: 'Time',
170
+ dataIndex: 'timestamp',
171
+ key: 'timestamp',
172
+ width: 180,
173
+ render: (timestamp: number) => (
174
+ <UITooltip title={formatTime(timestamp)}>
175
+ <span>{dayjs(timestamp).fromNow()}</span>
176
+ </UITooltip>
177
+ ),
178
+ },
179
+ {
180
+ title: 'Status',
181
+ dataIndex: 'resolvedAt',
182
+ key: 'resolvedAt',
183
+ width: 120,
184
+ render: (resolvedAt: number | undefined, record: Incident) => {
185
+ if (resolvedAt) {
186
+ const duration = formatDuration(record.timestamp, resolvedAt);
187
+ return (
188
+ <UITooltip title={`Resolved in ${duration}`}>
189
+ <UITag color="success" icon={<UIIcon name="CheckCircleOutlined" />}>
190
+ RESOLVED
191
+ </UITag>
192
+ </UITooltip>
193
+ );
194
+ }
195
+ return (
196
+ <UITooltip title="Incident is still active">
197
+ <UITag color="error" icon={<UIIcon name="ClockCircleOutlined" />}>
198
+ ACTIVE
199
+ </UITag>
200
+ </UITooltip>
201
+ );
202
+ },
203
+ },
204
+ {
205
+ title: 'AI Analysis',
206
+ dataIndex: 'aiAnalysis',
207
+ key: 'aiAnalysis',
208
+ width: 100,
209
+ align: 'center' as const,
210
+ render: (aiAnalysis: any) => {
211
+ if (aiAnalysis) {
212
+ return <UIBadge variant="success">Yes</UIBadge>;
213
+ }
214
+ return <UIBadge variant="default">No</UIBadge>;
215
+ },
216
+ },
217
+ {
218
+ title: 'Actions',
219
+ key: 'actions',
220
+ width: 100,
221
+ align: 'center' as const,
222
+ render: (_: any, record: Incident) => (
223
+ <UIButton
224
+ variant="link"
225
+ icon={<UIIcon name="EyeOutlined" />}
226
+ onClick={() => handleViewIncident(record.id)}
227
+ >
228
+ View
229
+ </UIButton>
230
+ ),
231
+ },
232
+ ];
233
+
234
+ return (
235
+ <UIPage width="full">
236
+ <UIPageHeader
237
+ title="Incidents"
238
+ description="System incident history with AI-powered analysis"
239
+ actions={[
240
+ <UIButton
241
+ key="refresh"
242
+ icon={<UIIcon name="ReloadOutlined" />}
243
+ onClick={() => refetch()}
244
+ loading={isLoading}
245
+ >
246
+ Refresh
247
+ </UIButton>,
248
+ ]}
249
+ />
250
+
251
+ {error && (
252
+ <UIAlert
253
+ message="Failed to load incidents"
254
+ description={(error as Error).message}
255
+ variant="error"
256
+ showIcon
257
+ style={{ marginBottom: 24 }}
258
+ />
259
+ )}
260
+
261
+ {/* Summary Statistics */}
262
+ {summary && (
263
+ <UIRow gutter={[16, 16]} style={{ marginBottom: 24 }}>
264
+ <UICol xs={24} sm={6}>
265
+ <UICard>
266
+ <UIStatistic
267
+ title="Total Incidents"
268
+ value={summary.total}
269
+ valueStyle={{ color: '#1890ff' }}
270
+ />
271
+ </UICard>
272
+ </UICol>
273
+ <UICol xs={24} sm={6}>
274
+ <UICard>
275
+ <UIStatistic
276
+ title="Unresolved"
277
+ value={summary.unresolved}
278
+ valueStyle={{ color: summary.unresolved > 0 ? '#ff4d4f' : '#52c41a' }}
279
+ suffix={summary.unresolved > 0 ? <UIIcon name="FireOutlined" /> : <UIIcon name="CheckCircleOutlined" />}
280
+ />
281
+ </UICard>
282
+ </UICol>
283
+ <UICol xs={24} sm={4}>
284
+ <UICard>
285
+ <UIStatistic
286
+ title="Critical"
287
+ value={summary.bySeverity.critical}
288
+ valueStyle={{ color: '#ff4d4f' }}
289
+ />
290
+ </UICard>
291
+ </UICol>
292
+ <UICol xs={24} sm={4}>
293
+ <UICard>
294
+ <UIStatistic
295
+ title="Warning"
296
+ value={summary.bySeverity.warning}
297
+ valueStyle={{ color: '#faad14' }}
298
+ />
299
+ </UICard>
300
+ </UICol>
301
+ <UICol xs={24} sm={4}>
302
+ <UICard>
303
+ <UIStatistic
304
+ title="Info"
305
+ value={summary.bySeverity.info}
306
+ valueStyle={{ color: '#1890ff' }}
307
+ />
308
+ </UICard>
309
+ </UICol>
310
+ </UIRow>
311
+ )}
312
+
313
+ {/* Filters */}
314
+ <UICard style={{ marginBottom: 24 }}>
315
+ <UISpace size="middle" wrap>
316
+ <span>Filters:</span>
317
+ <UISelect
318
+ style={{ width: 140 }}
319
+ placeholder="Severity"
320
+ allowClear
321
+ value={filters.severity}
322
+ onChange={handleSeverityChange}
323
+ options={[
324
+ { label: 'Critical', value: 'critical' },
325
+ { label: 'Warning', value: 'warning' },
326
+ { label: 'Info', value: 'info' },
327
+ ]}
328
+ />
329
+ <UISelect
330
+ style={{ width: 160 }}
331
+ placeholder="Type"
332
+ allowClear
333
+ value={filters.type}
334
+ onChange={handleTypeChange}
335
+ options={[
336
+ { label: 'Error Rate', value: 'error_rate' },
337
+ { label: 'Latency Spike', value: 'latency_spike' },
338
+ { label: 'Plugin Failure', value: 'plugin_failure' },
339
+ { label: 'Adapter Failure', value: 'adapter_failure' },
340
+ { label: 'System Health', value: 'system_health' },
341
+ { label: 'Custom', value: 'custom' },
342
+ ]}
343
+ />
344
+ <UISelect
345
+ style={{ width: 180 }}
346
+ value={filters.includeResolved ? 'true' : 'false'}
347
+ onChange={handleIncludeResolvedChange}
348
+ options={[
349
+ { label: 'Active Only', value: 'false' },
350
+ { label: 'Include Resolved', value: 'true' },
351
+ ]}
352
+ />
353
+ </UISpace>
354
+ </UICard>
355
+
356
+ {/* Incidents Table */}
357
+ <UICard>
358
+ <UITable
359
+ dataSource={incidents}
360
+ columns={columns}
361
+ rowKey="id"
362
+ loading={isLoading}
363
+ pagination={{
364
+ pageSize: 20,
365
+ }}
366
+ />
367
+ </UICard>
368
+ </UIPage>
369
+ );
370
+ }