@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,28 +0,0 @@
1
- import * as React from 'react';
2
- import { UIEmptyState as UIEmptyStateBase, UIButton } from '@kb-labs/studio-ui-kit';
3
-
4
- export interface EmptyStateProps {
5
- icon?: React.ReactNode;
6
- title: string;
7
- description: string;
8
- action?: { label: string; onClick: () => void };
9
- }
10
-
11
- export function EmptyState({ icon, title, description, action }: EmptyStateProps) {
12
- // Convert icon component to React element if it's a component
13
- const iconElement = React.isValidElement(icon)
14
- ? icon
15
- : icon && typeof icon === 'function'
16
- ? React.createElement(icon as React.ComponentType)
17
- : icon;
18
-
19
- return (
20
- <UIEmptyStateBase
21
- icon={iconElement}
22
- title={title}
23
- description={description}
24
- action={action ? <UIButton onClick={action.onClick}>{action.label}</UIButton> : undefined}
25
- />
26
- );
27
- }
28
-
@@ -1,210 +0,0 @@
1
- /**
2
- * @module @kb-labs/studio-app/components/ErrorBoundary
3
- * Custom error boundary for React Router with friendly UI
4
- */
5
-
6
- import * as React from 'react';
7
- import { useRouteError, isRouteErrorResponse, Link } from 'react-router-dom';
8
- import {
9
- UIResult, UIButton, UICard, UITypographyText, UITypographyParagraph,
10
- UISpace, UIAccordion, UITag, UIMessage, UIIcon,
11
- } from '@kb-labs/studio-ui-kit';
12
-
13
- export function ErrorBoundary() {
14
- const error = useRouteError();
15
- const [copied, setCopied] = React.useState(false);
16
-
17
- let title = 'Упс! Что-то пошло не так';
18
- let description = 'Произошла непредвиденная ошибка';
19
- let status: 'error' | 'warning' | '404' | '500' | 'info' = 'error';
20
- let suggestion = 'Попробуйте перезагрузить страницу или вернуться на главную';
21
-
22
- if (isRouteErrorResponse(error)) {
23
- // React Router error response
24
- if (error.status === 404) {
25
- status = '404';
26
- title = 'Страница не найдена';
27
- description = 'К сожалению, запрошенная страница не существует';
28
- suggestion = 'Проверьте адрес или вернитесь на главную страницу';
29
- } else {
30
- status = '500';
31
- title = `Ошибка ${error.status}`;
32
- description = error.statusText || error.data?.message || description;
33
- }
34
- } else if (error instanceof Error) {
35
- // JavaScript error
36
- description = error.message;
37
-
38
- // Friendly message for common errors
39
- if (error.message.includes('Unsupported data source')) {
40
- title = 'Ошибка конфигурации виджета';
41
- description = 'Виджет имеет некорректную настройку источника данных';
42
- suggestion = 'Это ошибка в манифесте плагина. Обратитесь к разработчику.';
43
- status = 'warning';
44
- } else if (error.message.includes('not found') || error.message.includes('404')) {
45
- title = 'Ресурс не найден';
46
- description = 'Запрошенный ресурс не существует';
47
- suggestion = 'Проверьте настройки плагина или обратитесь к администратору';
48
- status = '404';
49
- } else if (error.message.includes('Failed to fetch')) {
50
- title = 'Ошибка сети';
51
- description = 'Не удалось подключиться к серверу';
52
- suggestion = 'Проверьте подключение к интернету и попробуйте снова';
53
- status = 'warning';
54
- }
55
- }
56
-
57
- // Extract error details
58
- const errorDetails = error instanceof Error ? {
59
- name: error.name,
60
- message: error.message,
61
- stack: error.stack,
62
- } : null;
63
-
64
- return (
65
- <div style={{
66
- display: 'flex',
67
- alignItems: 'center',
68
- justifyContent: 'center',
69
- minHeight: '100vh',
70
- padding: '2rem',
71
- backgroundColor: 'var(--bg-tertiary)',
72
- }}>
73
- <UICard
74
- style={{
75
- maxWidth: '800px',
76
- width: '100%',
77
- borderRadius: '16px',
78
- boxShadow: '0 20px 60px rgba(0,0,0,0.3)',
79
- backgroundColor: 'var(--bg-secondary)',
80
- }}
81
- styles={{ body: { padding: '3rem' } }}
82
- >
83
- <UIResult
84
- status={status}
85
- title={<span style={{ fontSize: '1.5rem', fontWeight: 600 }}>{title}</span>}
86
- subTitle={
87
- <UISpace direction="vertical" size="middle" style={{ width: '100%', marginTop: '1rem' }}>
88
- <UITypographyParagraph style={{ fontSize: '1rem', color: 'var(--text-secondary)', margin: 0 }}>
89
- {description}
90
- </UITypographyParagraph>
91
- <UITypographyText type="secondary" style={{ fontSize: '0.875rem' }}>
92
- 💡 {suggestion}
93
- </UITypographyText>
94
- </UISpace>
95
- }
96
- extra={
97
- <UISpace direction="vertical" size="large" style={{ width: '100%', marginTop: '1.5rem' }}>
98
- <UISpace size="middle">
99
- <Link to="/">
100
- <UIButton variant="primary" size="large" icon={<UIIcon name="HomeOutlined" />}>
101
- На главную
102
- </UIButton>
103
- </Link>
104
- <UIButton
105
- size="large"
106
- icon={<UIIcon name="ReloadOutlined" />}
107
- onClick={() => window.location.reload()}
108
- >
109
- Перезагрузить
110
- </UIButton>
111
- </UISpace>
112
-
113
- {/* Error Details Accordion */}
114
- {errorDetails && (
115
- <UIAccordion
116
- ghost
117
- style={{ width: '100%', textAlign: 'left' }}
118
- items={[
119
- {
120
- key: 'details',
121
- label: 'Детали ошибки (для разработчиков)',
122
- children: (
123
- <UISpace direction="vertical" size="middle" style={{ width: '100%' }}>
124
- {/* Error Type */}
125
- <div>
126
- <UITypographyText type="secondary" style={{ fontSize: '0.75rem' }}>Тип ошибки:</UITypographyText>
127
- <div style={{ marginTop: 4 }}>
128
- <UITag variant="error" icon={<UIIcon name="CodeOutlined" />}>
129
- {errorDetails.name}
130
- </UITag>
131
- </div>
132
- </div>
133
-
134
- {/* Error Message */}
135
- <div>
136
- <UITypographyText type="secondary" style={{ fontSize: '0.75rem' }}>Сообщение:</UITypographyText>
137
- <div
138
- style={{
139
- marginTop: 4,
140
- padding: '12px',
141
- background: 'var(--bg-secondary)',
142
- borderRadius: '8px',
143
- fontFamily: 'monospace',
144
- fontSize: '0.875rem',
145
- wordBreak: 'break-word',
146
- }}
147
- >
148
- <UITypographyText code>{errorDetails.message}</UITypographyText>
149
- </div>
150
- </div>
151
-
152
- {/* Stack Trace */}
153
- {errorDetails.stack && (
154
- <div>
155
- <UITypographyText type="secondary" style={{ fontSize: '0.75rem' }}>Stack Trace:</UITypographyText>
156
- <div
157
- style={{
158
- marginTop: 4,
159
- padding: '12px',
160
- background: '#1e1e1e',
161
- borderRadius: '8px',
162
- maxHeight: '300px',
163
- overflow: 'auto',
164
- }}
165
- >
166
- <pre
167
- style={{
168
- margin: 0,
169
- fontFamily: 'Monaco, Menlo, "Courier New", monospace',
170
- fontSize: '0.75rem',
171
- lineHeight: 1.5,
172
- color: '#d4d4d4',
173
- whiteSpace: 'pre-wrap',
174
- wordBreak: 'break-word',
175
- }}
176
- >
177
- {errorDetails.stack}
178
- </pre>
179
- </div>
180
- </div>
181
- )}
182
-
183
- {/* Copy to Clipboard */}
184
- <UIButton
185
- size="small"
186
- variant={copied ? 'primary' : 'default'}
187
- icon={copied ? <UIIcon name="CheckOutlined" /> : <UIIcon name="CopyOutlined" />}
188
- onClick={() => {
189
- const text = `${errorDetails.name}: ${errorDetails.message}\n\n${errorDetails.stack || 'No stack trace'}`;
190
- navigator.clipboard.writeText(text);
191
- setCopied(true);
192
- UIMessage.success('Ошибка скопирована в буфер обмена');
193
- setTimeout(() => setCopied(false), 2000);
194
- }}
195
- >
196
- {copied ? 'Скопировано!' : 'Скопировать в буфер обмена'}
197
- </UIButton>
198
- </UISpace>
199
- ),
200
- },
201
- ]}
202
- />
203
- )}
204
- </UISpace>
205
- }
206
- />
207
- </UICard>
208
- </div>
209
- );
210
- }
@@ -1,103 +0,0 @@
1
- /* ── Health banner — compact top strip ───────────────────────────────── */
2
-
3
- .strip {
4
- display: flex;
5
- align-items: center;
6
- gap: 8px;
7
- padding: 6px 16px;
8
- font-size: 12px;
9
- line-height: 1.4;
10
- border-bottom: 1px solid transparent;
11
- }
12
-
13
- .stripError {
14
- background: rgba(220, 38, 38, 0.07);
15
- border-color: rgba(220, 38, 38, 0.2);
16
- color: var(--error);
17
- }
18
-
19
- .stripWarning {
20
- background: rgba(245, 158, 11, 0.07);
21
- border-color: rgba(245, 158, 11, 0.2);
22
- color: var(--warning);
23
- }
24
-
25
- .stripInfo {
26
- background: rgba(14, 165, 233, 0.07);
27
- border-color: rgba(14, 165, 233, 0.2);
28
- color: var(--info);
29
- }
30
-
31
- .icon {
32
- flex-shrink: 0;
33
- display: flex;
34
- align-items: center;
35
- }
36
-
37
- .message {
38
- font-weight: 600;
39
- flex-shrink: 0;
40
- }
41
-
42
- .description {
43
- color: var(--text-secondary);
44
- flex: 1;
45
- overflow: hidden;
46
- text-overflow: ellipsis;
47
- white-space: nowrap;
48
- }
49
-
50
- .detailsBtn {
51
- background: none;
52
- border: none;
53
- cursor: pointer;
54
- font-size: 12px;
55
- color: inherit;
56
- opacity: 0.75;
57
- padding: 0 4px;
58
- flex-shrink: 0;
59
- text-decoration: underline;
60
- text-underline-offset: 2px;
61
- }
62
-
63
- .detailsBtn:hover {
64
- opacity: 1;
65
- }
66
-
67
- .retryBtn {
68
- background: none;
69
- border: none;
70
- cursor: pointer;
71
- padding: 2px;
72
- display: flex;
73
- align-items: center;
74
- color: inherit;
75
- opacity: 0.6;
76
- flex-shrink: 0;
77
- border-radius: 3px;
78
- }
79
-
80
- .retryBtn:hover {
81
- opacity: 1;
82
- background: rgba(0, 0, 0, 0.06);
83
- }
84
-
85
- /* ── Expanded details panel ──────────────────────────────────────────── */
86
-
87
- .details {
88
- padding: 8px 16px 10px 40px;
89
- font-size: 12px;
90
- border-bottom: 1px solid var(--border-primary);
91
- background: var(--bg-tertiary);
92
- }
93
-
94
- .detailsList {
95
- margin: 4px 0 0 12px;
96
- padding: 0;
97
- list-style: disc;
98
- color: var(--text-secondary);
99
- }
100
-
101
- .detailsList li {
102
- margin-bottom: 2px;
103
- }
@@ -1,134 +0,0 @@
1
- import { useDataSources } from '../providers/data-sources-provider';
2
- import { useHealthStatus, useReadyStatus } from '@kb-labs/studio-data-client';
3
- import { studioConfig } from '@/config/studio.config';
4
- import { RefreshCw, AlertCircle, AlertTriangle, Info } from 'lucide-react';
5
- import { useEffect, useMemo, useRef, useState } from 'react';
6
- import { useRegistryV2 } from '../providers/registry-v2-provider';
7
- import type { HealthStatus } from '@kb-labs/studio-data-client';
8
- import styles from './health-banner.module.css';
9
-
10
- export function HealthBanner() {
11
- const sources = useDataSources();
12
- const _registry = useRegistryV2();
13
- const sseHealth = null as { status: string; ts?: string; ready: boolean; reason?: string } | null;
14
- const { data: healthRaw, error, refetch } = useHealthStatus(sources.system);
15
- const { data: ready } = useReadyStatus(sources.system);
16
- const [showDetails, setShowDetails] = useState(false);
17
- const lastRefetchedTs = useRef<string | null>(null);
18
-
19
- useEffect(() => {
20
- if (!sseHealth) {return;}
21
- const shouldRefetch =
22
- (!sseHealth.ready || sseHealth.status === 'degraded') &&
23
- sseHealth.ts &&
24
- sseHealth.ts !== lastRefetchedTs.current;
25
- if (shouldRefetch) {
26
- lastRefetchedTs.current = sseHealth.ts ?? null;
27
- void refetch();
28
- }
29
- }, [sseHealth, refetch]);
30
-
31
- const healthSnapshot = (healthRaw as Record<string, unknown> | undefined)?.snapshot as
32
- | HealthStatus['snapshot']
33
- | undefined;
34
-
35
- const fallbackStatus =
36
- healthSnapshot?.status ?? ((healthRaw as { ok?: boolean } | undefined)?.ok ? 'healthy' : 'unknown');
37
- const healthStatus = sseHealth?.status ?? fallbackStatus;
38
- const readyStatus = sseHealth?.ready ?? ready?.ready ?? true;
39
- const readyReason = !readyStatus ? sseHealth?.reason ?? ready?.reason : undefined;
40
-
41
- const impactedComponents = (healthSnapshot?.checks ?? [])
42
- .filter((check) => check.status !== 'ok')
43
- .map((check) => ({ id: check.id, lastError: check.message ?? 'unknown issue' }));
44
-
45
- const pluginMetrics = useMemo(() => {
46
- const meta = healthSnapshot?.meta as Record<string, unknown> | undefined;
47
- const pluginMounts = meta?.pluginMounts as Record<string, unknown> | undefined;
48
- const succeeded =
49
- pluginMounts && typeof pluginMounts.succeeded === 'number'
50
- ? (pluginMounts.succeeded as number)
51
- : undefined;
52
- const failed =
53
- pluginMounts && typeof pluginMounts.failed === 'number'
54
- ? (pluginMounts.failed as number)
55
- : undefined;
56
- if (succeeded === undefined && failed === undefined) {return null;}
57
- return { succeeded: succeeded ?? 0, failed: failed ?? 0 };
58
- }, [healthSnapshot]);
59
-
60
- const isDegraded =
61
- (healthStatus === 'degraded' || healthSnapshot?.state === 'partial_observability') && readyStatus;
62
- const isDown = !!error || !readyStatus;
63
- const isMockMode =
64
- studioConfig.dataSourceMode === 'mock' ||
65
- (studioConfig.dataSourceMode === 'http' && !healthSnapshot && error);
66
-
67
- if (!isDegraded && !isDown && !isMockMode) {return null;}
68
-
69
- const variant = isDown ? 'error' : isDegraded ? 'warning' : 'info';
70
-
71
- const stripCls = {
72
- error: styles.stripError,
73
- warning: styles.stripWarning,
74
- info: styles.stripInfo,
75
- }[variant];
76
-
77
- const IconComponent = { error: AlertCircle, warning: AlertTriangle, info: Info }[variant];
78
- const iconSize = 14;
79
-
80
- const message = isDown
81
- ? 'REST API unavailable'
82
- : isDegraded
83
- ? 'REST API degraded'
84
- : 'Mock mode';
85
-
86
- const description = isDown
87
- ? `Not ready at ${studioConfig.apiBaseUrl}${readyReason ? ` — ${readyReason}` : ''}`
88
- : isDegraded
89
- ? `Some services may be unavailable${pluginMetrics?.failed ? ` · ${pluginMetrics.failed} plugin mount(s) failed` : ''}`
90
- : 'Using mock data for development';
91
-
92
- const hasDetails = isDegraded && impactedComponents.length > 0;
93
-
94
- return (
95
- <>
96
- <div className={`${styles.strip} ${stripCls}`}>
97
- <span className={styles.icon}>
98
- <IconComponent size={iconSize} />
99
- </span>
100
- <span className={styles.message}>{message}</span>
101
- <span className={styles.description}>{description}</span>
102
- {hasDetails && (
103
- <button
104
- type="button"
105
- className={styles.detailsBtn}
106
- onClick={() => setShowDetails((v) => !v)}
107
- >
108
- {showDetails ? 'Hide details' : 'Details'}
109
- </button>
110
- )}
111
- <button
112
- type="button"
113
- className={styles.retryBtn}
114
- onClick={() => refetch()}
115
- title="Retry"
116
- >
117
- <RefreshCw size={13} />
118
- </button>
119
- </div>
120
-
121
- {showDetails && hasDetails && (
122
- <div className={styles.details}>
123
- <ul className={styles.detailsList}>
124
- {impactedComponents.map((c) => (
125
- <li key={c.id}>
126
- <strong>{c.id}</strong>: {c.lastError}
127
- </li>
128
- ))}
129
- </ul>
130
- </div>
131
- )}
132
- </>
133
- );
134
- }
@@ -1,12 +0,0 @@
1
- import { UIBadge } from '@kb-labs/studio-ui-kit';
2
-
3
- export function HealthIndicator({ status }: { status: 'ok' | 'degraded' | 'down' }) {
4
- const variantMap = {
5
- ok: 'success' as const,
6
- degraded: 'warning' as const,
7
- down: 'error' as const,
8
- };
9
-
10
- return <UIBadge variant={variantMap[status]}>{status.toUpperCase()}</UIBadge>;
11
- }
12
-
@@ -1,49 +0,0 @@
1
- /**
2
- * @module @kb-labs/studio-app/components/page-header
3
- * Page header component with title, description, and optional actions
4
- */
5
-
6
- import * as React from 'react';
7
- import { UITitle, UITypographyText } from '@kb-labs/studio-ui-kit';
8
- import type { ReactNode } from 'react';
9
-
10
- export interface PageHeaderProps {
11
- title: string;
12
- description?: string;
13
- actions?: ReactNode;
14
- breadcrumbs?: ReactNode;
15
- className?: string;
16
- style?: React.CSSProperties;
17
- }
18
-
19
- export function PageHeader({
20
- title,
21
- description,
22
- actions,
23
- breadcrumbs,
24
- className,
25
- style,
26
- }: PageHeaderProps): React.ReactElement {
27
- return (
28
- <div className={className} style={{ marginBottom: '24px', ...style }}>
29
- {breadcrumbs && <div style={{ marginBottom: '12px' }}>{breadcrumbs}</div>}
30
- <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: '16px', flexWrap: 'wrap' }}>
31
- <div style={{ flex: 1, minWidth: 0 }}>
32
- <UITitle level={1} className="typo-page-title" style={{ margin: 0, marginBottom: description ? '8px' : 0, color: 'var(--text-primary)' }}>
33
- {title}
34
- </UITitle>
35
- {description && (
36
- <UITypographyText className="typo-description" style={{ color: 'var(--text-secondary)', display: 'block' }}>
37
- {description}
38
- </UITypographyText>
39
- )}
40
- </div>
41
- {actions && (
42
- <div style={{ display: 'flex', gap: '8px', alignItems: 'flex-start', flexWrap: 'wrap' }}>
43
- {actions}
44
- </div>
45
- )}
46
- </div>
47
- </div>
48
- );
49
- }
@@ -1,24 +0,0 @@
1
- /**
2
- * @module @kb-labs/studio-app/components/page-transition
3
- * Page transition wrapper with configurable animation types
4
- *
5
- * NOTE: Animation logic temporarily disabled.
6
- * Infrastructure kept for future UI animation features.
7
- */
8
-
9
- import * as React from 'react';
10
-
11
- export interface PageTransitionProps {
12
- children: React.ReactNode;
13
- }
14
-
15
- /**
16
- * Page transition wrapper component.
17
- * Currently renders children directly without animations.
18
- * The feature flag and settings infrastructure remain in place for future animation features.
19
- */
20
- export function PageTransition({ children }: PageTransitionProps) {
21
- // Animation logic temporarily disabled - instant navigation preferred for SaaS
22
- // Infrastructure kept for potential future use with other UI animations
23
- return <>{children}</>;
24
- }