@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,48 +0,0 @@
1
- /**
2
- * @module @kb-labs/studio-app/modules/plugins/routes
3
- * Plugins module routing configuration
4
- */
5
-
6
- import type { RouteObject } from 'react-router-dom';
7
- import { PluginsPage } from '../pages/marketplace-page';
8
- import { PluginDetailPage } from '../pages/plugin-detail-page';
9
- import { ErrorBoundary } from '../../../components/error-boundary';
10
- import { renderIcon } from '../../../routes/helpers';
11
- import type { NavigationItem } from '@/components/ui';
12
-
13
- // Route paths
14
- const PATHS = {
15
- ROOT: '/marketplace',
16
- DETAIL: '/marketplace/:pluginId',
17
- } as const;
18
-
19
- // Route keys
20
- const KEYS = {
21
- MODULE: 'plugins',
22
- } as const;
23
-
24
- /**
25
- * Plugins routes
26
- */
27
- export const pluginsRoutes: RouteObject[] = [
28
- {
29
- path: PATHS.ROOT,
30
- element: <PluginsPage />,
31
- errorElement: <ErrorBoundary />,
32
- },
33
- {
34
- path: PATHS.DETAIL,
35
- element: <PluginDetailPage />,
36
- errorElement: <ErrorBoundary />,
37
- },
38
- ];
39
-
40
- /**
41
- * Plugins navigation item for sidebar
42
- */
43
- export const pluginsNavigation: NavigationItem = {
44
- key: KEYS.MODULE,
45
- label: 'Marketplace',
46
- icon: renderIcon('AppstoreOutlined'),
47
- path: PATHS.ROOT,
48
- };
@@ -1 +0,0 @@
1
- export { renderSchema } from './schema-helpers';
@@ -1,21 +0,0 @@
1
- /**
2
- * Helper to safely render schema objects
3
- */
4
- export function renderSchema(schema: any): string {
5
- if (!schema) {
6
- return '—';
7
- }
8
- if (typeof schema === 'string') {
9
- return schema;
10
- }
11
- if (typeof schema === 'object') {
12
- if ('$ref' in schema) {
13
- return schema.$ref;
14
- }
15
- if ('zod' in schema) {
16
- return schema.zod;
17
- }
18
- return JSON.stringify(schema);
19
- }
20
- return String(schema);
21
- }
@@ -1,415 +0,0 @@
1
- import * as React from 'react';
2
- import { useState, useEffect, useMemo, useCallback } from 'react';
3
- import {
4
- UIInput,
5
- UITag,
6
- UISpace,
7
- UIButton,
8
- UITypographyText,
9
- UITitle,
10
- UITypographyParagraph,
11
- UIAlert,
12
- UISpin,
13
- UIEmptyState,
14
- UITooltip,
15
- UISelect,
16
- UITree,
17
- UISegmented,
18
- UIIcon,
19
- } from '@kb-labs/studio-ui-kit';
20
- import type { DataNode } from 'antd/es/tree';
21
- import { useDataSources } from '../../../providers/data-sources-provider';
22
- import type { RoutesResponse, RouteInfo } from '@kb-labs/studio-data-client';
23
-
24
- const METHOD_COLORS: Record<string, string> = {
25
- GET: 'green',
26
- POST: 'blue',
27
- PUT: 'orange',
28
- PATCH: 'purple',
29
- DELETE: 'red',
30
- HEAD: 'cyan',
31
- OPTIONS: 'default',
32
- };
33
-
34
- type ViewMode = 'tree' | 'list';
35
-
36
- interface RouteTreeNode {
37
- segment: string;
38
- fullPath: string;
39
- routes: RouteInfo[];
40
- children: Map<string, RouteTreeNode>;
41
- }
42
-
43
- function buildRouteTree(routes: RouteInfo[]): RouteTreeNode {
44
- const root: RouteTreeNode = {
45
- segment: '',
46
- fullPath: '',
47
- routes: [],
48
- children: new Map(),
49
- };
50
-
51
- for (const route of routes) {
52
- // Split URL into segments, e.g., /api/v1/plugins/:id -> ['api', 'v1', 'plugins', ':id']
53
- const segments = route.url.split('/').filter(Boolean);
54
- let current = root;
55
- let pathSoFar = '';
56
-
57
- for (const segment of segments) {
58
- pathSoFar += '/' + segment;
59
-
60
- if (!current.children.has(segment)) {
61
- current.children.set(segment, {
62
- segment,
63
- fullPath: pathSoFar,
64
- routes: [],
65
- children: new Map(),
66
- });
67
- }
68
- current = current.children.get(segment)!;
69
- }
70
-
71
- // Add route to the leaf node
72
- current.routes.push(route);
73
- }
74
-
75
- return root;
76
- }
77
-
78
- function treeNodeToAntdNode(
79
- node: RouteTreeNode,
80
- baseUrl: string,
81
- copiedUrl: string | null,
82
- onCopy: (url: string) => void
83
- ): DataNode[] {
84
- const results: DataNode[] = [];
85
-
86
- // Sort children alphabetically
87
- const sortedChildren = Array.from(node.children.entries()).sort((a, b) =>
88
- a[0].localeCompare(b[0])
89
- );
90
-
91
- for (const [segment, child] of sortedChildren) {
92
- const hasChildren = child.children.size > 0;
93
- const hasRoutes = child.routes.length > 0;
94
-
95
- // Determine if this is a parameter segment
96
- const isParam = segment.startsWith(':') || segment.startsWith('*');
97
-
98
- const childNodes = treeNodeToAntdNode(child, baseUrl, copiedUrl, onCopy);
99
-
100
- // Create route entries for this node
101
- const routeNodes: DataNode[] = child.routes.map((route) => {
102
- const fullUrl = `${baseUrl}${route.url}`;
103
-
104
- return {
105
- key: `${route.method}-${route.url}`,
106
- title: (
107
- <UISpace size="small">
108
- {route.method.split(',').map((m) => (
109
- <UITag key={m} color={METHOD_COLORS[m.trim()] || 'default'} style={{ margin: 0 }}>
110
- {m.trim()}
111
- </UITag>
112
- ))}
113
- <UITypographyText code style={{ fontSize: 12 }}>
114
- {route.url}
115
- </UITypographyText>
116
- <UITooltip title={copiedUrl === fullUrl ? 'Copied!' : 'Copy full URL'}>
117
- <UIButton
118
- variant="text"
119
- size="small"
120
- icon={
121
- copiedUrl === fullUrl ? (
122
- <UIIcon name="CheckOutlined" style={{ color: '#52c41a' }} />
123
- ) : (
124
- <UIIcon name="CopyOutlined" />
125
- )
126
- }
127
- onClick={(e) => {
128
- e.stopPropagation();
129
- onCopy(fullUrl);
130
- }}
131
- />
132
- </UITooltip>
133
- </UISpace>
134
- ),
135
- isLeaf: true,
136
- icon: <UIIcon name="FileOutlined" />,
137
- };
138
- });
139
-
140
- if (hasChildren || hasRoutes) {
141
- results.push({
142
- key: child.fullPath,
143
- title: (
144
- <UISpace size="small">
145
- <UITypographyText strong={hasChildren} type={isParam ? 'warning' : undefined}>
146
- {segment}
147
- </UITypographyText>
148
- {hasRoutes && !hasChildren && (
149
- <UITypographyText type="secondary" style={{ fontSize: 11 }}>
150
- ({child.routes.length})
151
- </UITypographyText>
152
- )}
153
- </UISpace>
154
- ),
155
- icon: hasChildren ? <UIIcon name="FolderOutlined" /> : undefined,
156
- children: [...routeNodes, ...childNodes],
157
- isLeaf: !hasChildren && routeNodes.length === 0,
158
- });
159
- }
160
- }
161
-
162
- return results;
163
- }
164
-
165
- export function ApiRoutesViewer() {
166
- const { system } = useDataSources();
167
- const [loading, setLoading] = useState(false);
168
- const [error, setError] = useState<string | null>(null);
169
- const [data, setData] = useState<RoutesResponse | null>(null);
170
- const [searchQuery, setSearchQuery] = useState('');
171
- const [methodFilter, setMethodFilter] = useState<string | null>(null);
172
- const [copiedUrl, setCopiedUrl] = useState<string | null>(null);
173
- const [viewMode, setViewMode] = useState<ViewMode>('tree');
174
- const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
175
-
176
- const baseUrl = system.getBaseUrl();
177
-
178
- const fetchRoutes = useCallback(async () => {
179
- setLoading(true);
180
- setError(null);
181
- try {
182
- const result = await system.getRoutes();
183
- setData(result);
184
-
185
- // Auto-expand first two levels
186
- if (result.routes.length > 0) {
187
- const tree = buildRouteTree(result.routes);
188
- const keysToExpand: string[] = [];
189
- for (const [, child] of tree.children) {
190
- keysToExpand.push(child.fullPath);
191
- for (const [, grandChild] of child.children) {
192
- keysToExpand.push(grandChild.fullPath);
193
- }
194
- }
195
- setExpandedKeys(keysToExpand);
196
- }
197
- } catch (err) {
198
- setError(err instanceof Error ? err.message : String(err));
199
- } finally {
200
- setLoading(false);
201
- }
202
- }, [system]);
203
-
204
- useEffect(() => {
205
- fetchRoutes();
206
- }, [fetchRoutes]);
207
-
208
- const handleCopyUrl = (url: string) => {
209
- navigator.clipboard.writeText(url);
210
- setCopiedUrl(url);
211
- setTimeout(() => setCopiedUrl(null), 2000);
212
- };
213
-
214
- // Get unique methods for filter
215
- const availableMethods = useMemo(() => {
216
- if (!data?.routes) {return [];}
217
- const methods = new Set<string>();
218
- data.routes.forEach((route) => {
219
- route.method.split(',').forEach((m) => methods.add(m.trim()));
220
- });
221
- return Array.from(methods).sort();
222
- }, [data]);
223
-
224
- // Filter routes
225
- const filteredRoutes = useMemo(() => {
226
- if (!data?.routes) {return [];}
227
- return data.routes.filter((route) => {
228
- // Search filter
229
- const matchesSearch =
230
- !searchQuery ||
231
- route.url.toLowerCase().includes(searchQuery.toLowerCase()) ||
232
- route.method.toLowerCase().includes(searchQuery.toLowerCase());
233
-
234
- // Method filter
235
- const matchesMethod = !methodFilter || route.method.includes(methodFilter);
236
-
237
- return matchesSearch && matchesMethod;
238
- });
239
- }, [data, searchQuery, methodFilter]);
240
-
241
- // Build tree structure
242
- const treeData = useMemo(() => {
243
- if (filteredRoutes.length === 0) {return [];}
244
- const tree = buildRouteTree(filteredRoutes);
245
- return treeNodeToAntdNode(tree, baseUrl, copiedUrl, handleCopyUrl);
246
- }, [filteredRoutes, baseUrl, copiedUrl]);
247
-
248
- // Flat list for list view
249
- const sortedRoutes = useMemo(() => {
250
- return [...filteredRoutes].sort((a, b) => {
251
- const urlCompare = a.url.localeCompare(b.url);
252
- if (urlCompare !== 0) {return urlCompare;}
253
- return a.method.localeCompare(b.method);
254
- });
255
- }, [filteredRoutes]);
256
-
257
- return (
258
- <UISpace direction="vertical" style={{ width: '100%' }} size="middle">
259
- <div>
260
- <UITitle level={5}>
261
- <UIIcon name="ApiOutlined" /> API Routes Explorer
262
- </UITitle>
263
- <UITypographyParagraph type="secondary">
264
- Browse all available REST API endpoints from the backend. Use search and filters to find
265
- specific routes.
266
- </UITypographyParagraph>
267
- </div>
268
-
269
- {/* Controls */}
270
- <UISpace wrap>
271
- <UIInput
272
- placeholder="Search routes..."
273
- prefix={<UIIcon name="SearchOutlined" />}
274
- value={searchQuery}
275
- onChange={(value) => setSearchQuery(value)}
276
- style={{ width: 300 }}
277
- allowClear
278
- />
279
- <UISelect
280
- placeholder="Filter by method"
281
- allowClear
282
- style={{ width: 150 }}
283
- value={methodFilter ?? undefined}
284
- onChange={(v) => setMethodFilter(v as string | null)}
285
- options={availableMethods.map((m) => ({ label: m, value: m }))}
286
- />
287
- <UISegmented
288
- value={viewMode}
289
- onChange={(v) => setViewMode(v as ViewMode)}
290
- options={[
291
- { label: 'Tree', value: 'tree', icon: <UIIcon name="ApartmentOutlined" /> },
292
- { label: 'List', value: 'list', icon: <UIIcon name="UnorderedListOutlined" /> },
293
- ]}
294
- />
295
- <UIButton icon={<UIIcon name="ReloadOutlined" />} onClick={fetchRoutes} loading={loading}>
296
- Refresh
297
- </UIButton>
298
- </UISpace>
299
-
300
- {/* Stats */}
301
- {data && (
302
- <UIAlert
303
- variant="info"
304
- showIcon={false}
305
- message={
306
- <UISpace split={<span style={{ color: '#d9d9d9' }}>|</span>}>
307
- <span>
308
- <UITypographyText strong>{data.count}</UITypographyText> total routes
309
- </span>
310
- <span>
311
- <UITypographyText strong>{filteredRoutes.length}</UITypographyText> shown
312
- </span>
313
- <span>
314
- <UITypographyText type="secondary">
315
- Last fetched: {new Date(data.ts).toLocaleTimeString()}
316
- </UITypographyText>
317
- </span>
318
- <span>
319
- <UITypographyText type="secondary">Base: {baseUrl}</UITypographyText>
320
- </span>
321
- </UISpace>
322
- }
323
- />
324
- )}
325
-
326
- {/* Error */}
327
- {error && (
328
- <UIAlert variant="error" message="Failed to load routes" description={error} showIcon />
329
- )}
330
-
331
- {/* Loading */}
332
- {loading && !data && (
333
- <div style={{ textAlign: 'center', padding: 40 }}>
334
- <UISpin size="large" />
335
- </div>
336
- )}
337
-
338
- {/* Tree View */}
339
- {data && viewMode === 'tree' && treeData.length > 0 && (
340
- <UITree
341
- treeData={treeData}
342
- showIcon
343
- showLine={{ showLeafIcon: false }}
344
- expandedKeys={expandedKeys}
345
- onExpand={(keys) => setExpandedKeys(keys)}
346
- style={{
347
- background: 'transparent',
348
- padding: '8px 0',
349
- }}
350
- />
351
- )}
352
-
353
- {/* List View */}
354
- {data && viewMode === 'list' && (
355
- <div style={{ maxHeight: 500, overflow: 'auto' }}>
356
- <UISpace direction="vertical" size="small" style={{ width: '100%' }}>
357
- {sortedRoutes.map((route) => {
358
- const fullUrl = route.url.startsWith('/api')
359
- ? `http://localhost:5050${route.url}`
360
- : `${baseUrl}${route.url}`;
361
-
362
- return (
363
- <div
364
- key={`${route.method}-${route.url}`}
365
- style={{
366
- display: 'flex',
367
- alignItems: 'center',
368
- gap: 8,
369
- padding: '4px 8px',
370
- borderRadius: 4,
371
- background: 'rgba(0,0,0,0.02)',
372
- }}
373
- >
374
- <UISpace size={4}>
375
- {route.method.split(',').map((m) => (
376
- <UITag
377
- key={m}
378
- color={METHOD_COLORS[m.trim()] || 'default'}
379
- style={{ margin: 0, minWidth: 50, textAlign: 'center' }}
380
- >
381
- {m.trim()}
382
- </UITag>
383
- ))}
384
- </UISpace>
385
- <UITypographyText code style={{ fontSize: 12, flex: 1 }}>
386
- {route.url}
387
- </UITypographyText>
388
- <UITooltip title={copiedUrl === fullUrl ? 'Copied!' : 'Copy full URL'}>
389
- <UIButton
390
- variant="text"
391
- size="small"
392
- icon={
393
- copiedUrl === fullUrl ? (
394
- <UIIcon name="CheckOutlined" style={{ color: '#52c41a' }} />
395
- ) : (
396
- <UIIcon name="CopyOutlined" />
397
- )
398
- }
399
- onClick={() => handleCopyUrl(fullUrl)}
400
- />
401
- </UITooltip>
402
- </div>
403
- );
404
- })}
405
- </UISpace>
406
- </div>
407
- )}
408
-
409
- {/* Empty */}
410
- {!loading && !error && filteredRoutes.length === 0 && data && (
411
- <UIEmptyState description="No routes match your search" />
412
- )}
413
- </UISpace>
414
- );
415
- }
@@ -1,200 +0,0 @@
1
- import * as React from 'react';
2
- import {
3
- UIRadio,
4
- UIRadioGroup,
5
- UISwitch,
6
- UISpace,
7
- UICard,
8
- UITypographyText,
9
- UITypographyParagraph,
10
- } from '@kb-labs/studio-ui-kit';
11
- import { Sun, Moon, Monitor } from 'lucide-react';
12
- import { useSettings } from '@/providers/settings-provider';
13
- import { useKBTheme } from '@/components/ui';
14
-
15
- const FONT_SIZES = [
16
- { value: 'small' as const, label: 'Small', description: '13px - Compact view' },
17
- { value: 'medium' as const, label: 'Medium', description: '14px - Default' },
18
- { value: 'large' as const, label: 'Large', description: '16px - Better readability' },
19
- ];
20
-
21
- export function AppearanceSettings() {
22
- const { theme, setTheme } = useKBTheme();
23
- const { settings, updateSettings } = useSettings();
24
-
25
- const handleThemeChange = (newTheme: 'light' | 'dark' | 'auto') => {
26
- setTheme(newTheme);
27
- updateSettings({
28
- appearance: {
29
- ...settings.appearance,
30
- theme: newTheme,
31
- },
32
- });
33
- };
34
-
35
- const handleCompactModeChange = (checked: boolean) => {
36
- updateSettings({
37
- appearance: {
38
- ...settings.appearance,
39
- compactMode: checked,
40
- },
41
- });
42
- };
43
-
44
- const handleFontSizeChange = (e: any) => {
45
- updateSettings({
46
- appearance: {
47
- ...settings.appearance,
48
- fontSize: e.target.value,
49
- },
50
- });
51
- };
52
-
53
- return (
54
- <UISpace direction="vertical" size="large" style={{ width: '100%' }}>
55
- {/* Theme Selection */}
56
- <div>
57
- <UITypographyText strong style={{ fontSize: 16, display: 'block', marginBottom: 12 }}>
58
- Theme
59
- </UITypographyText>
60
- <UITypographyParagraph type="secondary" style={{ marginBottom: 16 }}>
61
- Choose how KB Studio looks to you. Select a single theme, or sync with your system.
62
- </UITypographyParagraph>
63
-
64
- <UISpace direction="horizontal" size="middle" style={{ width: '100%' }}>
65
- <UICard
66
- hoverable
67
- onClick={() => handleThemeChange('light')}
68
- style={{
69
- width: 200,
70
- border: theme === 'light' ? '2px solid var(--link)' : '1px solid var(--border-primary)',
71
- cursor: 'pointer',
72
- }}
73
- styles={{ body: { padding: 16 } }}
74
- >
75
- <div style={{ textAlign: 'center' }}>
76
- <Sun size={32} style={{ marginBottom: 8, color: '#F59E0B' }} />
77
- <div style={{ fontWeight: 600, marginBottom: 4 }}>Light</div>
78
- <UITypographyText type="secondary" style={{ fontSize: 12 }}>
79
- Bright and clean
80
- </UITypographyText>
81
- </div>
82
- <div
83
- style={{
84
- marginTop: 12,
85
- height: 40,
86
- background: 'linear-gradient(to right, #F9FAFB, #FFFFFF)',
87
- border: '1px solid #E5E7EB',
88
- borderRadius: 4,
89
- }}
90
- />
91
- </UICard>
92
-
93
- <UICard
94
- hoverable
95
- onClick={() => handleThemeChange('dark')}
96
- style={{
97
- width: 200,
98
- border: theme === 'dark' ? '2px solid var(--link)' : '1px solid var(--border-primary)',
99
- cursor: 'pointer',
100
- }}
101
- styles={{ body: { padding: 16 } }}
102
- >
103
- <div style={{ textAlign: 'center' }}>
104
- <Moon size={32} style={{ marginBottom: 8, color: '#6366F1' }} />
105
- <div style={{ fontWeight: 600, marginBottom: 4 }}>Dark</div>
106
- <UITypographyText type="secondary" style={{ fontSize: 12 }}>
107
- Easy on the eyes
108
- </UITypographyText>
109
- </div>
110
- <div
111
- style={{
112
- marginTop: 12,
113
- height: 40,
114
- background: 'linear-gradient(to right, #0D0D0F, #1A1A1C)',
115
- border: '1px solid #3F3F46',
116
- borderRadius: 4,
117
- }}
118
- />
119
- </UICard>
120
-
121
- <UICard
122
- hoverable
123
- onClick={() => handleThemeChange('auto')}
124
- style={{
125
- width: 200,
126
- border: theme === 'auto' ? '2px solid var(--link)' : '1px solid var(--border-primary)',
127
- cursor: 'pointer',
128
- }}
129
- styles={{ body: { padding: 16 } }}
130
- >
131
- <div style={{ textAlign: 'center' }}>
132
- <Monitor size={32} style={{ marginBottom: 8, color: '#8B5CF6' }} />
133
- <div style={{ fontWeight: 600, marginBottom: 4 }}>Auto</div>
134
- <UITypographyText type="secondary" style={{ fontSize: 12 }}>
135
- Sync with system
136
- </UITypographyText>
137
- </div>
138
- <div
139
- style={{
140
- marginTop: 12,
141
- height: 40,
142
- background: 'linear-gradient(to right, #F9FAFB 50%, #1A1A1C 50%)',
143
- border: '1px solid var(--border-primary)',
144
- borderRadius: 4,
145
- }}
146
- />
147
- </UICard>
148
- </UISpace>
149
- </div>
150
-
151
- {/* Compact Mode */}
152
- <div>
153
- <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
154
- <div>
155
- <UITypographyText strong style={{ fontSize: 16, display: 'block' }}>
156
- Compact Mode
157
- </UITypographyText>
158
- <UITypographyParagraph type="secondary" style={{ marginBottom: 0, marginTop: 4 }}>
159
- Reduce spacing and padding for a denser layout
160
- </UITypographyParagraph>
161
- </div>
162
- <UISwitch
163
- checked={settings.appearance.compactMode}
164
- onChange={handleCompactModeChange}
165
- />
166
- </div>
167
- </div>
168
-
169
- {/* Font Size */}
170
- <div>
171
- <UITypographyText strong style={{ fontSize: 16, display: 'block', marginBottom: 12 }}>
172
- Font Size
173
- </UITypographyText>
174
- <UITypographyParagraph type="secondary" style={{ marginBottom: 16 }}>
175
- Adjust the base font size across the application
176
- </UITypographyParagraph>
177
-
178
- <UIRadioGroup
179
- value={settings.appearance.fontSize}
180
- onChange={handleFontSizeChange}
181
- style={{ width: '100%' }}
182
- >
183
- <UISpace direction="vertical" style={{ width: '100%' }}>
184
- {FONT_SIZES.map((size) => (
185
- <UIRadio key={size.value} value={size.value} style={{ display: 'flex', alignItems: 'center' }}>
186
- <div>
187
- <UITypographyText strong>{size.label}</UITypographyText>
188
- <br />
189
- <UITypographyText type="secondary" style={{ fontSize: 12 }}>
190
- {size.description}
191
- </UITypographyText>
192
- </div>
193
- </UIRadio>
194
- ))}
195
- </UISpace>
196
- </UIRadioGroup>
197
- </div>
198
- </UISpace>
199
- );
200
- }