@kb-labs/studio-app 0.6.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,152 +0,0 @@
1
- import React from 'react';
2
- import { UICard } from '@kb-labs/studio-ui-kit';
3
- import type { UICardVariant as UICardStatus } from '@kb-labs/studio-ui-kit';
4
- import './HeroMetricCard.css';
5
-
6
- export type MetricStatus = 'healthy' | 'warning' | 'critical' | 'live' | 'default';
7
-
8
- export interface HeroMetricCardProps {
9
- title: string;
10
- value: string | number;
11
- subtitle?: string;
12
- sparklineData?: number[];
13
- trend?: {
14
- direction: 'up' | 'down';
15
- value: number;
16
- isPositive?: boolean;
17
- };
18
- status?: MetricStatus;
19
- pulsing?: boolean;
20
- onClick?: () => void;
21
- icon?: React.ReactNode;
22
- }
23
-
24
- const statusColors: Record<MetricStatus, string> = {
25
- healthy: 'var(--success)',
26
- warning: 'var(--warning)',
27
- critical: 'var(--error)',
28
- live: 'var(--info)',
29
- default: 'var(--text-secondary)',
30
- };
31
-
32
- const statusToVariant: Record<MetricStatus, UICardStatus> = {
33
- healthy: 'success',
34
- warning: 'warning',
35
- critical: 'error',
36
- live: 'info',
37
- default: 'default',
38
- };
39
-
40
- export function HeroMetricCard({
41
- title,
42
- value,
43
- subtitle,
44
- sparklineData,
45
- trend,
46
- status = 'default',
47
- pulsing = false,
48
- onClick,
49
- icon,
50
- }: HeroMetricCardProps) {
51
- const mainColor = statusColors[status];
52
-
53
- return (
54
- <UICard
55
- className={`hero-metric-card ${onClick ? 'clickable' : ''} ${pulsing ? 'pulsing' : ''}`}
56
- status={statusToVariant[status]}
57
- onClick={onClick}
58
- styles={{ body: { padding: '20px' } }}
59
- style={{ cursor: onClick ? 'pointer' : 'default' }}
60
- >
61
- <div className="hero-metric-header">
62
- {icon && <div className="hero-metric-icon">{icon}</div>}
63
- <div className="hero-metric-title">{title}</div>
64
- {pulsing && (
65
- <div className="hero-metric-pulse" style={{ backgroundColor: mainColor }} />
66
- )}
67
- </div>
68
-
69
- <div className="hero-metric-value" style={{ color: mainColor }}>
70
- {value}
71
- </div>
72
-
73
- {/* Always render subtitle for consistent height */}
74
- <div className="hero-metric-subtitle">
75
- {subtitle || '\u00A0'}
76
- </div>
77
-
78
- {/* Always show footer for consistent card height */}
79
- <div className="hero-metric-footer">
80
- <div className="hero-metric-sparkline">
81
- {sparklineData && sparklineData.length > 1 && (
82
- <Sparkline data={sparklineData} color={mainColor} />
83
- )}
84
- </div>
85
-
86
- <div className="hero-metric-trend">
87
- {trend && (
88
- <TrendIndicator
89
- direction={trend.direction}
90
- value={trend.value}
91
- isPositive={trend.isPositive ?? trend.direction === 'up'}
92
- />
93
- )}
94
- </div>
95
- </div>
96
- </UICard>
97
- );
98
- }
99
-
100
- // Sparkline Component
101
- interface SparklineProps {
102
- data: number[];
103
- color: string;
104
- width?: number;
105
- height?: number;
106
- }
107
-
108
- function Sparkline({ data, color, width = 100, height = 30 }: SparklineProps) {
109
- if (data.length < 2) {return null;}
110
-
111
- const min = Math.min(...data);
112
- const max = Math.max(...data);
113
- const range = max - min || 1;
114
-
115
- const points = data.map((value, index) => {
116
- const x = (index / (data.length - 1)) * width;
117
- const y = height - ((value - min) / range) * height;
118
- return `${x},${y}`;
119
- }).join(' ');
120
-
121
- return (
122
- <svg width={width} height={height} className="sparkline">
123
- <polyline
124
- points={points}
125
- fill="none"
126
- stroke={color}
127
- strokeWidth="2"
128
- strokeLinecap="round"
129
- strokeLinejoin="round"
130
- />
131
- </svg>
132
- );
133
- }
134
-
135
- // TrendIndicator Component
136
- interface TrendIndicatorProps {
137
- direction: 'up' | 'down';
138
- value: number;
139
- isPositive: boolean;
140
- }
141
-
142
- function TrendIndicator({ direction, value, isPositive }: TrendIndicatorProps) {
143
- const color = isPositive ? 'var(--success)' : 'var(--error)';
144
- const arrow = direction === 'up' ? '↑' : '↓';
145
-
146
- return (
147
- <div className="trend-indicator" style={{ color }}>
148
- <span className="trend-arrow">{arrow}</span>
149
- <span className="trend-value">{Math.abs(value).toFixed(1)}%</span>
150
- </div>
151
- );
152
- }
@@ -1,146 +0,0 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { UIRow, UICol } from '@kb-labs/studio-ui-kit';
3
- import { useNavigate } from 'react-router-dom';
4
- import {
5
- RiseOutlined,
6
- ApiOutlined,
7
- ClockCircleOutlined,
8
- } from '@ant-design/icons';
9
- import { HeroMetricCard } from './HeroMetricCard';
10
- import { useDataSources } from '../../../providers/data-sources-provider';
11
- import {
12
- usePrometheusMetrics,
13
- useStateBrokerStats,
14
- } from '@kb-labs/studio-data-client';
15
-
16
- interface MetricsHistoryPoint {
17
- timestamp: number;
18
- requests: number;
19
- uptime: number;
20
- }
21
-
22
- export function HeroMetricsWidget() {
23
- const sources = useDataSources();
24
- const _navigate = useNavigate();
25
-
26
- // Data hooks with auto-refresh
27
- const metrics = usePrometheusMetrics(sources.observability);
28
- const stateBroker = useStateBrokerStats(sources.observability);
29
-
30
- // Historical data for sparklines (last 20 data points)
31
- const [metricsHistory, setMetricsHistory] = useState<MetricsHistoryPoint[]>([]);
32
-
33
- // Collect metrics history
34
- useEffect(() => {
35
- if (metrics.data) {
36
- const newPoint: MetricsHistoryPoint = {
37
- timestamp: Date.now(),
38
- requests: metrics.data.requests?.total ?? 0,
39
- uptime: calculateUptime(metrics.data),
40
- };
41
-
42
- setMetricsHistory(prev => {
43
- // Keep last 20 points
44
- return [...prev, newPoint].slice(-20);
45
- });
46
- }
47
- }, [metrics.data]);
48
-
49
- // Calculate uptime percentage
50
- const calculateUptime = (metricsData: any) => {
51
- if (!metricsData?.requests) {return 100;}
52
- const total = metricsData.requests.total ?? 0;
53
- const success = metricsData.requests.success ?? 0;
54
- return total > 0 ? (success / total) * 100 : 100;
55
- };
56
-
57
- // Calculate trend from history
58
- const calculateTrend = (data: number[]) => {
59
- if (data.length < 2) {return null;}
60
- const recent = data.slice(-5); // Last 5 points
61
- const older = data.slice(-10, -5); // Previous 5 points
62
- if (older.length === 0 || recent.length === 0) {return null;}
63
-
64
- const recentAvg = recent.reduce((a, b) => a + b, 0) / recent.length;
65
- const olderAvg = older.reduce((a, b) => a + b, 0) / older.length;
66
-
67
- if (olderAvg === 0) {return null;}
68
-
69
- const change = ((recentAvg - olderAvg) / olderAvg) * 100;
70
- return {
71
- direction: change >= 0 ? 'up' as const : 'down' as const,
72
- value: Math.abs(change),
73
- isPositive: change >= 0,
74
- };
75
- };
76
-
77
- // Format uptime seconds to human-readable
78
- const formatUptime = (seconds: number | undefined) => {
79
- if (!seconds) {return '0s';}
80
-
81
- const days = Math.floor(seconds / 86400);
82
- const hours = Math.floor((seconds % 86400) / 3600);
83
- const minutes = Math.floor((seconds % 3600) / 60);
84
-
85
- if (days > 0) {return `${days}d ${hours}h`;}
86
- if (hours > 0) {return `${hours}h ${minutes}m`;}
87
- return `${minutes}m`;
88
- };
89
-
90
- // Extract sparkline data
91
- const requestsSparkline = metricsHistory.map(p => p.requests);
92
- const uptimeSparkline = metricsHistory.map(p => p.uptime);
93
-
94
- // Calculate trends
95
- const requestsTrend = calculateTrend(requestsSparkline);
96
-
97
- // Metric values
98
- const currentUptime = calculateUptime(metrics.data);
99
- const totalRequests = metrics.data?.requests?.total ?? 0;
100
- const runtimeSeconds = metrics.data?.uptime?.seconds ?? 0;
101
-
102
- // Determine uptime status
103
- const getUptimeStatus = () => {
104
- if (currentUptime >= 99) {return 'healthy';}
105
- if (currentUptime >= 95) {return 'warning';}
106
- return 'critical';
107
- };
108
-
109
- return (
110
- <UIRow gutter={[16, 16]}>
111
- <UICol xs={24} sm={12} lg={8}>
112
- <HeroMetricCard
113
- title="Uptime"
114
- value={`${currentUptime.toFixed(2)}%`}
115
- subtitle={stateBroker.data ? `Cache: ${(stateBroker.data.hitRate * 100).toFixed(1)}%` : 'Success rate'}
116
- sparklineData={uptimeSparkline}
117
- status={getUptimeStatus()}
118
- icon={<RiseOutlined />}
119
- />
120
- </UICol>
121
-
122
- <UICol xs={24} sm={12} lg={8}>
123
- <HeroMetricCard
124
- title="Total Requests"
125
- value={totalRequests.toLocaleString()}
126
- subtitle={metrics.data ? `Success: ${metrics.data.requests.success.toLocaleString()}` : 'Loading...'}
127
- sparklineData={requestsSparkline}
128
- trend={requestsTrend ?? undefined}
129
- status="default"
130
- icon={<ApiOutlined />}
131
- />
132
- </UICol>
133
-
134
- <UICol xs={24} sm={12} lg={8}>
135
- <HeroMetricCard
136
- title="Runtime"
137
- value={formatUptime(runtimeSeconds)}
138
- subtitle="LIVE"
139
- status="live"
140
- pulsing={true}
141
- icon={<ClockCircleOutlined />}
142
- />
143
- </UICol>
144
- </UIRow>
145
- );
146
- }
@@ -1,197 +0,0 @@
1
- import React from 'react';
2
- import {
3
- UIProgress,
4
- UIStatistic,
5
- UIRow,
6
- UICol,
7
- UITag,
8
- UIEmptyState,
9
- UICard,
10
- } from '@kb-labs/studio-ui-kit';
11
- import {
12
- CloudServerOutlined,
13
- ThunderboltOutlined,
14
- DatabaseOutlined,
15
- ClockCircleOutlined,
16
- } from '@ant-design/icons';
17
- import { useHealthStatus } from '@kb-labs/studio-data-client';
18
- import { useDataSources } from '../../../providers/data-sources-provider';
19
-
20
- function formatBytes(bytes: number): string {
21
- if (bytes === 0) {return '0 B';}
22
- const k = 1024;
23
- const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
24
- const i = Math.floor(Math.log(bytes) / Math.log(k));
25
- return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
26
- }
27
-
28
- function formatUptime(seconds: number): string {
29
- const days = Math.floor(seconds / 86400);
30
- const hours = Math.floor((seconds % 86400) / 3600);
31
- const minutes = Math.floor((seconds % 3600) / 60);
32
-
33
- if (days > 0) {return `${days}d ${hours}h ${minutes}m`;}
34
- if (hours > 0) {return `${hours}h ${minutes}m`;}
35
- return `${minutes}m`;
36
- }
37
-
38
- function getMetricColor(value: number, warningThreshold: number, criticalThreshold: number): string {
39
- if (value >= criticalThreshold) {return 'var(--error)';}
40
- if (value >= warningThreshold) {return 'var(--warning)';}
41
- return 'var(--success)';
42
- }
43
-
44
- export function SystemResourcesWidget() {
45
- const sources = useDataSources();
46
- const healthQuery = useHealthStatus(sources.system);
47
- const snapshot = healthQuery.data?.snapshot;
48
- const resources = snapshot?.snapshot;
49
- const topOperations = snapshot?.topOperations ?? [];
50
- const state = snapshot?.state ?? 'insufficient_data';
51
- const cpuPercent = resources?.cpuPercent ?? 0;
52
- const rssBytes = resources?.rssBytes ?? 0;
53
- const heapUsedBytes = resources?.heapUsedBytes ?? 0;
54
- const eventLoopLagMs = resources?.eventLoopLagMs ?? 0;
55
- const activeOperations = resources?.activeOperations ?? 0;
56
-
57
- return (
58
- <UICard
59
- title={
60
- <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
61
- <CloudServerOutlined />
62
- <span>Runtime Resources</span>
63
- {snapshot && (
64
- <UITag color={state === 'active' ? 'green' : state === 'partial_observability' ? 'orange' : 'red'}>
65
- {state}
66
- </UITag>
67
- )}
68
- </div>
69
- }
70
- style={{ height: '100%' }}
71
- >
72
- {healthQuery.isLoading ? (
73
- <div style={{ height: 220, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--text-tertiary)' }}>
74
- Loading runtime resources...
75
- </div>
76
- ) : !snapshot || !resources ? (
77
- <UIEmptyState
78
- image={UIEmptyState.PRESENTED_IMAGE_SIMPLE}
79
- description="No runtime snapshot available"
80
- style={{ marginTop: 40 }}
81
- />
82
- ) : (
83
- <>
84
- <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 16 }}>
85
- <CloudServerOutlined style={{ fontSize: 18, color: 'var(--info)' }} />
86
- <span style={{ fontSize: 14, fontWeight: 500 }}>{snapshot.instanceId}</span>
87
- <UITag color={snapshot.status === 'healthy' ? 'green' : snapshot.status === 'degraded' ? 'orange' : 'red'}>
88
- {snapshot.status}
89
- </UITag>
90
- </div>
91
-
92
- <UIRow gutter={[16, 16]}>
93
- <UICol span={12}>
94
- <div>
95
- <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 8 }}>
96
- <ThunderboltOutlined style={{ color: getMetricColor(cpuPercent, 70, 90) }} />
97
- <span style={{ fontSize: 12, color: 'var(--text-secondary)' }}>CPU Usage</span>
98
- </div>
99
- <UIProgress
100
- percent={parseFloat(cpuPercent.toFixed(1))}
101
- strokeColor={getMetricColor(cpuPercent, 70, 90)}
102
- size="small"
103
- format={(percent) => `${percent}%`}
104
- />
105
- </div>
106
- </UICol>
107
-
108
- <UICol span={12}>
109
- <UIStatistic
110
- title={
111
- <span style={{ fontSize: 12, color: 'var(--text-secondary)' }}>
112
- <DatabaseOutlined style={{ marginRight: 4 }} />
113
- RSS
114
- </span>
115
- }
116
- value={formatBytes(rssBytes)}
117
- valueStyle={{ fontSize: 14 }}
118
- />
119
- </UICol>
120
-
121
- <UICol span={12}>
122
- <UIStatistic
123
- title={
124
- <span style={{ fontSize: 12, color: 'var(--text-secondary)' }}>
125
- <DatabaseOutlined style={{ marginRight: 4 }} />
126
- Heap Used
127
- </span>
128
- }
129
- value={formatBytes(heapUsedBytes)}
130
- valueStyle={{ fontSize: 14 }}
131
- />
132
- </UICol>
133
-
134
- <UICol span={12}>
135
- <UIStatistic
136
- title={
137
- <span style={{ fontSize: 12, color: 'var(--text-secondary)' }}>
138
- <ClockCircleOutlined style={{ marginRight: 4 }} />
139
- Uptime
140
- </span>
141
- }
142
- value={formatUptime(snapshot.uptimeSec)}
143
- valueStyle={{ fontSize: 14 }}
144
- />
145
- </UICol>
146
-
147
- <UICol span={12}>
148
- <UIStatistic
149
- title="Event Loop Lag"
150
- value={eventLoopLagMs.toFixed(1)}
151
- suffix="ms"
152
- valueStyle={{
153
- fontSize: 20,
154
- color: getMetricColor(eventLoopLagMs, 100, 200),
155
- }}
156
- />
157
- </UICol>
158
-
159
- <UICol span={12}>
160
- <UIStatistic
161
- title="Active Operations"
162
- value={activeOperations}
163
- valueStyle={{ fontSize: 20 }}
164
- />
165
- </UICol>
166
- </UIRow>
167
-
168
- <div style={{ marginTop: 24 }}>
169
- <div style={{ fontSize: 12, color: 'var(--text-secondary)', marginBottom: 8 }}>Top Operations</div>
170
- {topOperations.length > 0 ? (
171
- topOperations.map((operation) => (
172
- <div
173
- key={operation.operation}
174
- style={{
175
- display: 'flex',
176
- justifyContent: 'space-between',
177
- alignItems: 'center',
178
- padding: '8px 0',
179
- borderTop: '1px solid var(--border-secondary)',
180
- fontSize: 12,
181
- }}
182
- >
183
- <span style={{ color: 'var(--text-primary)' }}>{operation.operation.replace(/^http\./, '')}</span>
184
- <span style={{ color: 'var(--text-secondary)' }}>
185
- {operation.count ?? 0} req · {(operation.avgDurationMs ?? 0).toFixed(1)}ms avg
186
- </span>
187
- </div>
188
- ))
189
- ) : (
190
- <div style={{ color: 'var(--text-tertiary)', fontSize: 12 }}>No operation samples available</div>
191
- )}
192
- </div>
193
- </>
194
- )}
195
- </UICard>
196
- );
197
- }
@@ -1,22 +0,0 @@
1
- import { UIEmptyState, UIButton, UIFlex } from '@kb-labs/studio-ui-kit';
2
- import { PlusOutlined } from '@ant-design/icons';
3
-
4
- interface DashboardEmptyProps {
5
- onAddWidget: () => void;
6
- }
7
-
8
- export function DashboardEmpty({ onAddWidget }: DashboardEmptyProps) {
9
- return (
10
- <UIFlex align="center" justify="center" style={{ minHeight: '400px' }}>
11
- <UIEmptyState
12
- useDefaultImage
13
- description="No widgets added yet"
14
- action={
15
- <UIButton variant="primary" icon={<PlusOutlined />} onClick={onAddWidget}>
16
- Add Widget
17
- </UIButton>
18
- }
19
- />
20
- </UIFlex>
21
- );
22
- }
@@ -1,59 +0,0 @@
1
- import { UICard, UIBadge, UIRow, UICol } from '@kb-labs/studio-ui-kit';
2
- import { HolderOutlined } from '@ant-design/icons';
3
- import { useRegistryV2 } from '../../../providers/registry-v2-provider';
4
- import { KBStatCard } from '@/components/ui';
5
-
6
- export function DashboardKpisWidget() {
7
- const { registry } = useRegistryV2();
8
- const health = null as { pluginsMounted: number; pluginsFailed: number; ready: boolean; redisHealthy: boolean; redisEnabled: boolean } | null; // TODO: health status via separate endpoint
9
-
10
- const totalPlugins = registry.plugins?.length ?? 0;
11
- const pluginsMounted = health?.pluginsMounted ?? 0;
12
- const pluginsFailed = health?.pluginsFailed ?? 0;
13
- const systemStatus = health?.ready ? 'Healthy' : 'Degraded';
14
- const statusType = health?.ready ? 'success' : 'error';
15
-
16
- return (
17
- <UICard
18
- title={
19
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
20
- <HolderOutlined className="drag-handle" style={{ cursor: 'grab', color: 'var(--text-tertiary)' }} />
21
- <span>System Status</span>
22
- <UIBadge variant={statusType as 'success' | 'error'} />
23
- </div>
24
- }
25
- style={{ height: '100%', display: 'flex', flexDirection: 'column' }}
26
- styles={{ body: { flex: 1, padding: '16px' } }}
27
- >
28
- <UIRow gutter={[16, 16]} style={{ height: '100%' }}>
29
- <UICol span={6}>
30
- <KBStatCard
31
- label="Status"
32
- value={systemStatus}
33
- variant={health?.ready ? 'positive' : 'negative'}
34
- />
35
- </UICol>
36
- <UICol span={6}>
37
- <KBStatCard
38
- label="Plugins Mounted"
39
- value={`${pluginsMounted} of ${totalPlugins}`}
40
- />
41
- </UICol>
42
- <UICol span={6}>
43
- <KBStatCard
44
- label="Failed"
45
- value={pluginsFailed.toString()}
46
- variant={pluginsFailed > 0 ? 'negative' : 'positive'}
47
- />
48
- </UICol>
49
- <UICol span={6}>
50
- <KBStatCard
51
- label="Redis"
52
- value={health?.redisHealthy ? 'Healthy' : health?.redisEnabled ? 'Unhealthy' : 'Disabled'}
53
- variant={health?.redisHealthy ? 'positive' : health?.redisEnabled ? 'negative' : 'default'}
54
- />
55
- </UICol>
56
- </UIRow>
57
- </UICard>
58
- );
59
- }
@@ -1,13 +0,0 @@
1
- import { KBStatCard, KBStatGrid } from '@/components/ui';
2
-
3
- export function DashboardKpis() {
4
- return (
5
- <KBStatGrid columns={4}>
6
- <KBStatCard label="Audit Status" value="Unavailable" />
7
- <KBStatCard label="Packages OK" value="-" />
8
- <KBStatCard label="Failed" value="-" />
9
- <KBStatCard label="Warnings" value="-" />
10
- </KBStatGrid>
11
- );
12
- }
13
-
@@ -1,85 +0,0 @@
1
- import { UICard } from '@kb-labs/studio-ui-kit';
2
- import { HolderOutlined } from '@ant-design/icons';
3
- import { Column } from '@ant-design/plots';
4
- import { usePrometheusMetrics } from '@kb-labs/studio-data-client';
5
- import { useDataSources } from '../../../providers/data-sources-provider';
6
-
7
- export function DashboardLatencyPercentilesWidget() {
8
- const sources = useDataSources();
9
- const { data: metrics } = usePrometheusMetrics(sources.observability);
10
-
11
- const min = metrics?.latency?.min ?? 0;
12
- const average = metrics?.latency?.average ?? 0;
13
- const p50 = metrics?.latency?.p50 ?? 0;
14
- const p95 = metrics?.latency?.p95 ?? 0;
15
- const p99 = metrics?.latency?.p99 ?? 0;
16
- const max = metrics?.latency?.max ?? 0;
17
-
18
- const chartData = [
19
- { metric: 'Min', value: min, color: 'var(--success)' },
20
- { metric: 'Avg', value: average, color: 'var(--info)' },
21
- { metric: 'p50', value: p50, color: 'var(--info)' },
22
- { metric: 'p95', value: p95, color: 'var(--warning)' },
23
- { metric: 'p99', value: p99, color: 'var(--warning)' },
24
- { metric: 'Max', value: max, color: 'var(--error)' },
25
- ];
26
-
27
- const config = {
28
- data: chartData,
29
- xField: 'metric',
30
- yField: 'value',
31
- seriesField: 'metric',
32
- columnStyle: (datum: any) => {
33
- return {
34
- fill: datum.color,
35
- };
36
- },
37
- label: {
38
- position: 'top' as const,
39
- formatter: (datum: any) => `${datum.value.toFixed(1)}ms`,
40
- style: {
41
- fontSize: 12,
42
- fill: 'var(--text-secondary)',
43
- },
44
- },
45
- xAxis: {
46
- label: {
47
- style: {
48
- fontSize: 12,
49
- fill: 'var(--text-secondary)',
50
- },
51
- },
52
- },
53
- yAxis: {
54
- label: {
55
- formatter: (v: string) => `${v}ms`,
56
- style: {
57
- fontSize: 12,
58
- fill: 'var(--text-secondary)',
59
- },
60
- },
61
- },
62
- legend: false,
63
- height: 280,
64
- };
65
-
66
- return (
67
- <UICard
68
- title={
69
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
70
- <HolderOutlined className="drag-handle" style={{ cursor: 'grab', color: 'var(--text-tertiary)' }} />
71
- <span>Latency Distribution (ms)</span>
72
- </div>
73
- }
74
- style={{ height: '100%', display: 'flex', flexDirection: 'column' }}
75
- styles={{ body: { flex: 1, padding: '16px', display: 'flex', flexDirection: 'column' } }}
76
- >
77
- {metrics && <Column {...config} />}
78
- {!metrics && (
79
- <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }}>
80
- Loading...
81
- </div>
82
- )}
83
- </UICard>
84
- );
85
- }