@kb-labs/studio-app 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/.env.example +10 -0
  2. package/README.md +74 -0
  3. package/UI-KIT-COMPONENTS.md +783 -0
  4. package/UI-KIT-PLAN.md +326 -0
  5. package/eslint-rules/no-direct-antd-import.js +151 -0
  6. package/eslint.config.ts +27 -0
  7. package/index.html +17 -0
  8. package/package.json +72 -0
  9. package/postcss.config.js +7 -0
  10. package/public/favicon.ico +0 -0
  11. package/public/favicon.svg +7 -0
  12. package/rspack.config.mjs +118 -0
  13. package/src/App.tsx +46 -0
  14. package/src/components/devtools/devtools-log-feed.module.css +165 -0
  15. package/src/components/devtools/devtools-log-feed.tsx +300 -0
  16. package/src/components/devtools/devtools-panel.module.css +121 -0
  17. package/src/components/devtools/devtools-panel.tsx +115 -0
  18. package/src/components/empty-state.tsx +28 -0
  19. package/src/components/error-boundary.tsx +210 -0
  20. package/src/components/health-banner.module.css +103 -0
  21. package/src/components/health-banner.tsx +134 -0
  22. package/src/components/health-indicator.tsx +12 -0
  23. package/src/components/page-header.tsx +49 -0
  24. package/src/components/page-transition.tsx +24 -0
  25. package/src/components/role-switcher.tsx +148 -0
  26. package/src/components/run-badge.tsx +13 -0
  27. package/src/components/ui/icons.tsx +509 -0
  28. package/src/components/ui/index.ts +25 -0
  29. package/src/components/ui/kb-config-provider.tsx +130 -0
  30. package/src/components/ui/kb-header.module.css +51 -0
  31. package/src/components/ui/kb-header.tsx +112 -0
  32. package/src/components/ui/kb-notification-bell.module.css +103 -0
  33. package/src/components/ui/kb-notification-bell.tsx +199 -0
  34. package/src/components/ui/kb-page-layout.tsx +66 -0
  35. package/src/components/ui/kb-quick-search.module.css +86 -0
  36. package/src/components/ui/kb-quick-search.tsx +196 -0
  37. package/src/components/ui/kb-sidebar.module.css +47 -0
  38. package/src/components/ui/kb-sidebar.tsx +196 -0
  39. package/src/components/ui/kb-stat-card.module.css +21 -0
  40. package/src/components/ui/kb-stat-card.tsx +22 -0
  41. package/src/components/ui/kb-stat-grid.tsx +22 -0
  42. package/src/components/ui/kb-status-bar.module.css +49 -0
  43. package/src/components/ui/kb-status-bar.tsx +145 -0
  44. package/src/components/ui/kb-system-health-indicator.tsx +229 -0
  45. package/src/components/ui/kb-theme-toggle.tsx +42 -0
  46. package/src/components/ui/theme-adapter.ts +812 -0
  47. package/src/components/ui/theme-transition-overlay.tsx +70 -0
  48. package/src/components/ui/utils.ts +6 -0
  49. package/src/components/widget-error-boundary.tsx +172 -0
  50. package/src/config/env.ts +5 -0
  51. package/src/config/feature-flags.ts +482 -0
  52. package/src/config/studio.config.schema.ts +88 -0
  53. package/src/config/studio.config.ts +84 -0
  54. package/src/env.d.ts +23 -0
  55. package/src/hooks/use-command-palette.ts +6 -0
  56. package/src/hooks/use-devtools-store.ts +25 -0
  57. package/src/hooks/use-feature-flags.ts +101 -0
  58. package/src/index.css +10 -0
  59. package/src/layouts/dashboard-grid.tsx +122 -0
  60. package/src/layouts/index.ts +12 -0
  61. package/src/layouts/two-pane.tsx +134 -0
  62. package/src/main.tsx +15 -0
  63. package/src/modules/analytics/components/analytics-daily-stats-chart.tsx +257 -0
  64. package/src/modules/analytics/components/analytics-date-range-picker.tsx +121 -0
  65. package/src/modules/analytics/pages/analytics-cache-page.tsx +285 -0
  66. package/src/modules/analytics/pages/analytics-embeddings-page.tsx +274 -0
  67. package/src/modules/analytics/pages/analytics-events-page.tsx +425 -0
  68. package/src/modules/analytics/pages/analytics-llm-page.tsx +434 -0
  69. package/src/modules/analytics/pages/analytics-overview-page.tsx +336 -0
  70. package/src/modules/analytics/pages/analytics-page.tsx +20 -0
  71. package/src/modules/analytics/pages/analytics-storage-page.tsx +344 -0
  72. package/src/modules/analytics/pages/analytics-vectorstore-page.tsx +279 -0
  73. package/src/modules/analytics/routes/index.tsx +133 -0
  74. package/src/modules/analytics/utils/formatters.test.ts +148 -0
  75. package/src/modules/analytics/utils/formatters.ts +100 -0
  76. package/src/modules/auth/pages/login-page.module.css +113 -0
  77. package/src/modules/auth/pages/login-page.tsx +80 -0
  78. package/src/modules/auth/routes/index.tsx +24 -0
  79. package/src/modules/dashboard/components/ActivityTimelineWidget.tsx +199 -0
  80. package/src/modules/dashboard/components/AiInsightsWidget.tsx +358 -0
  81. package/src/modules/dashboard/components/AnimatedMetricCard.css +88 -0
  82. package/src/modules/dashboard/components/AnimatedMetricCard.tsx +125 -0
  83. package/src/modules/dashboard/components/HeroMetricCard.css +114 -0
  84. package/src/modules/dashboard/components/HeroMetricCard.tsx +152 -0
  85. package/src/modules/dashboard/components/HeroMetricsWidget.tsx +146 -0
  86. package/src/modules/dashboard/components/SystemResourcesWidget.tsx +197 -0
  87. package/src/modules/dashboard/components/dashboard-empty.tsx +22 -0
  88. package/src/modules/dashboard/components/dashboard-kpis-widget.tsx +59 -0
  89. package/src/modules/dashboard/components/dashboard-kpis.tsx +13 -0
  90. package/src/modules/dashboard/components/dashboard-latency-percentiles-widget.tsx +85 -0
  91. package/src/modules/dashboard/components/dashboard-metrics-widget.tsx +78 -0
  92. package/src/modules/dashboard/components/dashboard-plugins-widget.tsx +67 -0
  93. package/src/modules/dashboard/components/dashboard-requests-widget.tsx +62 -0
  94. package/src/modules/dashboard/layouts/dashboard-layout.tsx +16 -0
  95. package/src/modules/dashboard/pages/ai-insights-page.tsx +563 -0
  96. package/src/modules/dashboard/pages/dashboard-animations.css +317 -0
  97. package/src/modules/dashboard/pages/dashboard-page.tsx +13 -0
  98. package/src/modules/dashboard/routes/index.tsx +70 -0
  99. package/src/modules/observability/pages/devkit-page.tsx +263 -0
  100. package/src/modules/observability/pages/incident-detail-page.tsx +571 -0
  101. package/src/modules/observability/pages/incidents-page.tsx +370 -0
  102. package/src/modules/observability/pages/log-detail-page.tsx +508 -0
  103. package/src/modules/observability/pages/logs-page.tsx +1129 -0
  104. package/src/modules/observability/pages/prometheus-metrics-page.tsx +486 -0
  105. package/src/modules/observability/pages/state-broker-page.tsx +229 -0
  106. package/src/modules/observability/pages/system-events-page.tsx +255 -0
  107. package/src/modules/observability/routes/index.tsx +133 -0
  108. package/src/modules/plugins/components/marketplace-card.tsx +153 -0
  109. package/src/modules/plugins/components/plugin-ai-assistant-modal.tsx +374 -0
  110. package/src/modules/plugins/components/plugin-card.tsx +136 -0
  111. package/src/modules/plugins/components/plugin-detail/capabilities-summary.tsx +101 -0
  112. package/src/modules/plugins/components/plugin-detail/cli-commands-table.tsx +101 -0
  113. package/src/modules/plugins/components/plugin-detail/index.ts +7 -0
  114. package/src/modules/plugins/components/plugin-detail/jobs-table.tsx +64 -0
  115. package/src/modules/plugins/components/plugin-detail/permissions/env-permissions.tsx +30 -0
  116. package/src/modules/plugins/components/plugin-detail/permissions/filesystem-permissions.tsx +68 -0
  117. package/src/modules/plugins/components/plugin-detail/permissions/index.ts +6 -0
  118. package/src/modules/plugins/components/plugin-detail/permissions/network-permissions.tsx +43 -0
  119. package/src/modules/plugins/components/plugin-detail/permissions/platform-services.tsx +242 -0
  120. package/src/modules/plugins/components/plugin-detail/permissions/resource-quotas.tsx +96 -0
  121. package/src/modules/plugins/components/plugin-detail/permissions/shell-permissions.tsx +55 -0
  122. package/src/modules/plugins/components/plugin-detail/permissions-view.tsx +47 -0
  123. package/src/modules/plugins/components/plugin-detail/plugin-header.tsx +169 -0
  124. package/src/modules/plugins/components/plugin-detail/rest-routes-table.tsx +159 -0
  125. package/src/modules/plugins/components/plugin-detail/workflows-table.tsx +40 -0
  126. package/src/modules/plugins/components/plugin-grid.tsx +20 -0
  127. package/src/modules/plugins/components/plugin-table.tsx +178 -0
  128. package/src/modules/plugins/pages/marketplace-page.tsx +200 -0
  129. package/src/modules/plugins/pages/plugin-detail-page.tsx +1145 -0
  130. package/src/modules/plugins/routes/index.tsx +48 -0
  131. package/src/modules/plugins/utils/index.ts +1 -0
  132. package/src/modules/plugins/utils/schema-helpers.ts +21 -0
  133. package/src/modules/settings/components/api-routes-viewer.tsx +415 -0
  134. package/src/modules/settings/components/appearance-settings.tsx +200 -0
  135. package/src/modules/settings/components/configuration-settings.tsx +321 -0
  136. package/src/modules/settings/components/data-privacy-settings.tsx +111 -0
  137. package/src/modules/settings/components/experimental-settings.tsx +243 -0
  138. package/src/modules/settings/components/navigation-settings.tsx +198 -0
  139. package/src/modules/settings/components/notifications-settings.tsx +40 -0
  140. package/src/modules/settings/pages/settings-page.tsx +298 -0
  141. package/src/modules/settings/routes/index.tsx +47 -0
  142. package/src/pages/README-assistant.md +91 -0
  143. package/src/pages/login-page.tsx +177 -0
  144. package/src/pages/not-found-page.tsx +85 -0
  145. package/src/providers/auth-provider.tsx +40 -0
  146. package/src/providers/command-palette-provider.tsx +193 -0
  147. package/src/providers/data-sources-provider.tsx +27 -0
  148. package/src/providers/devtools-provider.tsx +72 -0
  149. package/src/providers/navigation-items-provider.tsx +38 -0
  150. package/src/providers/registry-v2-provider.tsx +93 -0
  151. package/src/providers/settings-provider.tsx +158 -0
  152. package/src/router.tsx +302 -0
  153. package/src/routes/helpers.tsx +25 -0
  154. package/src/routes/plugin-page-v2.tsx +52 -0
  155. package/src/routes/types.ts +18 -0
  156. package/src/styles/antd-overrides.css +211 -0
  157. package/src/styles/base.css +190 -0
  158. package/src/styles/settings.css +75 -0
  159. package/src/styles/variables.css +94 -0
  160. package/src/utils/analytics.ts +183 -0
  161. package/src/utils/apply-navigation-categories.ts +83 -0
  162. package/src/utils/commands.ts +252 -0
  163. package/src/utils/export.ts +174 -0
  164. package/src/utils/format-date.ts +166 -0
  165. package/src/utils/logger.ts +110 -0
  166. package/tailwind.config.ts +13 -0
  167. package/tsconfig.json +13 -0
  168. package/vitest-setup.ts +1 -0
@@ -0,0 +1,96 @@
1
+ import { UICard, UIText, useUITheme } from '@kb-labs/studio-ui-kit';
2
+
3
+ interface ResourceQuotasProps {
4
+ quotas: {
5
+ timeoutMs?: number;
6
+ memoryMb?: number;
7
+ cpuMs?: number;
8
+ };
9
+ }
10
+
11
+ export function ResourceQuotas({ quotas }: ResourceQuotasProps) {
12
+ const { token } = useUITheme();
13
+
14
+ return (
15
+ <UICard title="Resource Quotas">
16
+ <UIText color="secondary" style={{ marginBottom: 16, display: 'block' }}>
17
+ Maximum resource limits for this plugin to prevent runaway processes and ensure system
18
+ stability.
19
+ </UIText>
20
+ <div
21
+ style={{
22
+ display: 'grid',
23
+ gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
24
+ gap: 16,
25
+ }}
26
+ >
27
+ {quotas.timeoutMs && (
28
+ <UICard size="small">
29
+ <div style={{ textAlign: 'center' }}>
30
+ <UIText
31
+ color="secondary"
32
+ style={{
33
+ fontSize: token.fontSizeSM,
34
+ display: 'block',
35
+ marginBottom: 8,
36
+ }}
37
+ >
38
+ Timeout
39
+ </UIText>
40
+ <UIText weight="semibold" style={{ fontSize: 20 }}>
41
+ {quotas.timeoutMs}
42
+ </UIText>
43
+ <UIText color="secondary" style={{ fontSize: token.fontSizeSM }}>
44
+ ms
45
+ </UIText>
46
+ </div>
47
+ </UICard>
48
+ )}
49
+ {quotas.memoryMb && (
50
+ <UICard size="small">
51
+ <div style={{ textAlign: 'center' }}>
52
+ <UIText
53
+ color="secondary"
54
+ style={{
55
+ fontSize: token.fontSizeSM,
56
+ display: 'block',
57
+ marginBottom: 8,
58
+ }}
59
+ >
60
+ Memory
61
+ </UIText>
62
+ <UIText weight="semibold" style={{ fontSize: 20 }}>
63
+ {quotas.memoryMb}
64
+ </UIText>
65
+ <UIText color="secondary" style={{ fontSize: token.fontSizeSM }}>
66
+ MB
67
+ </UIText>
68
+ </div>
69
+ </UICard>
70
+ )}
71
+ {quotas.cpuMs && (
72
+ <UICard size="small">
73
+ <div style={{ textAlign: 'center' }}>
74
+ <UIText
75
+ color="secondary"
76
+ style={{
77
+ fontSize: token.fontSizeSM,
78
+ display: 'block',
79
+ marginBottom: 8,
80
+ }}
81
+ >
82
+ CPU Time
83
+ </UIText>
84
+ <UIText weight="semibold" style={{ fontSize: 20 }}>
85
+ {quotas.cpuMs}
86
+ </UIText>
87
+ <UIText color="secondary" style={{ fontSize: token.fontSizeSM }}>
88
+ ms
89
+ </UIText>
90
+ </div>
91
+ </UICard>
92
+ )}
93
+ </div>
94
+ </UICard>
95
+ );
96
+ }
@@ -0,0 +1,55 @@
1
+ import { UISpace, UIAlert, UICard, UIText, UIIcon, useUITheme } from '@kb-labs/studio-ui-kit';
2
+
3
+ interface ShellPermissionsProps {
4
+ permissions: {
5
+ allow?: string[];
6
+ };
7
+ }
8
+
9
+ export function ShellPermissions({ permissions }: ShellPermissionsProps) {
10
+ const { token } = useUITheme();
11
+
12
+ return (
13
+ <UICard
14
+ title={
15
+ <UISpace>
16
+ <UIIcon name="ConsoleSqlOutlined" />
17
+ <span>Shell Permissions</span>
18
+ </UISpace>
19
+ }
20
+ >
21
+ <UIText color="secondary" style={{ marginBottom: 16, display: 'block' }}>
22
+ Shell commands that this plugin is allowed to execute. Shell access is restricted by
23
+ default for security.
24
+ </UIText>
25
+ {permissions.allow && permissions.allow.length > 0 ? (
26
+ <div>
27
+ <UIText weight="semibold">Allowed Commands:</UIText>
28
+ <div style={{ marginTop: 8 }}>
29
+ <UISpace direction="vertical" style={{ width: '100%' }}>
30
+ {permissions.allow.map((cmd: string, idx: number) => (
31
+ <div key={idx} style={{ marginBottom: 4 }}>
32
+ <UIText
33
+ style={{
34
+ fontSize: token.fontSizeSM,
35
+ fontFamily: token.fontFamilyCode,
36
+ }}
37
+ >
38
+ {cmd}
39
+ </UIText>
40
+ </div>
41
+ ))}
42
+ </UISpace>
43
+ </div>
44
+ </div>
45
+ ) : (
46
+ <UIAlert
47
+ variant="warning"
48
+ message="Shell access disabled"
49
+ description="This plugin has no shell execution permissions."
50
+ showIcon
51
+ />
52
+ )}
53
+ </UICard>
54
+ );
55
+ }
@@ -0,0 +1,47 @@
1
+ import { UISpace, UIEmptyState, UICard } from '@kb-labs/studio-ui-kit';
2
+ import { FilesystemPermissions } from './permissions/filesystem-permissions';
3
+ import { NetworkPermissions } from './permissions/network-permissions';
4
+ import { EnvPermissions } from './permissions/env-permissions';
5
+ import { ShellPermissions } from './permissions/shell-permissions';
6
+ import { PlatformServices } from './permissions/platform-services';
7
+ import { ResourceQuotas } from './permissions/resource-quotas';
8
+
9
+ interface PermissionsViewProps {
10
+ permissions: any;
11
+ }
12
+
13
+ export function PermissionsView({ permissions }: PermissionsViewProps) {
14
+ if (!permissions) {
15
+ return (
16
+ <UICard>
17
+ <UIEmptyState description="No permissions specified for this plugin" />
18
+ </UICard>
19
+ );
20
+ }
21
+
22
+ return (
23
+ <UISpace direction="vertical" size="large" style={{ width: '100%' }}>
24
+ {/* Filesystem Permissions */}
25
+ {permissions.fs && <FilesystemPermissions permissions={permissions.fs} />}
26
+
27
+ {/* Network Permissions */}
28
+ {permissions.network?.fetch && permissions.network.fetch.length > 0 && (
29
+ <NetworkPermissions permissions={permissions.network} />
30
+ )}
31
+
32
+ {/* Environment Variables */}
33
+ {permissions.env?.read && permissions.env.read.length > 0 && (
34
+ <EnvPermissions permissions={permissions.env} />
35
+ )}
36
+
37
+ {/* Shell Permissions */}
38
+ {permissions.shell && <ShellPermissions permissions={permissions.shell} />}
39
+
40
+ {/* Platform Services */}
41
+ {permissions.platform && <PlatformServices permissions={permissions.platform} />}
42
+
43
+ {/* Quotas */}
44
+ {permissions.quotas && <ResourceQuotas quotas={permissions.quotas} />}
45
+ </UISpace>
46
+ );
47
+ }
@@ -0,0 +1,169 @@
1
+ import { UISpace, UIAccordion, UICard, UIText, UITitle, UITag, UIIcon, useUITheme } from '@kb-labs/studio-ui-kit';
2
+ import type { PluginManifestEntry } from '@kb-labs/studio-data-client';
3
+
4
+ interface PluginHeaderProps {
5
+ plugin: PluginManifestEntry;
6
+ }
7
+
8
+ export function PluginHeader({ plugin }: PluginHeaderProps) {
9
+ const { token } = useUITheme();
10
+ const { manifest } = plugin;
11
+ const display = manifest.display;
12
+
13
+ return (
14
+ <UICard>
15
+ <UISpace direction="vertical" size="middle" style={{ width: '100%' }}>
16
+ {/* Icon + Name + Version */}
17
+ <UISpace align="start" size="large">
18
+ <div style={{ fontSize: 64, lineHeight: 1 }}>{display?.icon || ''}</div>
19
+ <div style={{ flex: 1 }}>
20
+ <UITitle level={2} style={{ marginBottom: 4 }}>
21
+ {display?.name || manifest.id}
22
+ </UITitle>
23
+ <UISpace size="middle">
24
+ <UIText color="secondary" style={{ fontSize: 16 }}>
25
+ v{manifest.version}
26
+ </UIText>
27
+ <UITag color="blue">
28
+ {typeof plugin.source === 'string'
29
+ ? plugin.source
30
+ : plugin.source?.kind || 'unknown'}
31
+ </UITag>
32
+ <UITag>{manifest.schema}</UITag>
33
+ </UISpace>
34
+ </div>
35
+ </UISpace>
36
+
37
+ {/* Description */}
38
+ {display?.description && (
39
+ <UIText style={{ fontSize: 15, marginBottom: 0, color: token.colorTextSecondary }}>
40
+ {display.description}
41
+ </UIText>
42
+ )}
43
+
44
+ {/* Tags */}
45
+ {display?.tags && display.tags.length > 0 && (
46
+ <UISpace wrap>
47
+ {display.tags.map((tag, idx) => (
48
+ <UITag key={typeof tag === 'string' ? tag : `tag-${idx}`} color="default">
49
+ {typeof tag === 'string' ? tag : JSON.stringify(tag)}
50
+ </UITag>
51
+ ))}
52
+ </UISpace>
53
+ )}
54
+
55
+ {/* Metadata Row */}
56
+ <div
57
+ style={{
58
+ display: 'grid',
59
+ gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
60
+ gap: 16,
61
+ marginTop: 8,
62
+ }}
63
+ >
64
+ {display?.author && (
65
+ <div>
66
+ <UIText
67
+ color="secondary"
68
+ style={{ fontSize: token.fontSizeSM, display: 'block', marginBottom: 4 }}
69
+ >
70
+ Author
71
+ </UIText>
72
+ <UISpace>
73
+ <UIIcon name="UserOutlined" />
74
+ <UIText>{display.author}</UIText>
75
+ </UISpace>
76
+ </div>
77
+ )}
78
+ <div>
79
+ <UIText
80
+ color="secondary"
81
+ style={{ fontSize: token.fontSizeSM, display: 'block', marginBottom: 4 }}
82
+ >
83
+ Plugin ID
84
+ </UIText>
85
+ <UIText style={{ fontFamily: token.fontFamilyCode }}>{manifest.id}</UIText>
86
+ </div>
87
+ </div>
88
+
89
+ {/* Links */}
90
+ {(display?.homepage || display?.repository) && (
91
+ <UISpace size="large">
92
+ {display?.homepage && (
93
+ <a href={display.homepage} target="_blank" rel="noopener noreferrer">
94
+ <UISpace>
95
+ <UIIcon name="GlobalOutlined" />
96
+ Homepage
97
+ </UISpace>
98
+ </a>
99
+ )}
100
+ {display?.repository && (
101
+ <a href={display.repository} target="_blank" rel="noopener noreferrer">
102
+ <UISpace>
103
+ <UIIcon name="LinkOutlined" />
104
+ Repository
105
+ </UISpace>
106
+ </a>
107
+ )}
108
+ </UISpace>
109
+ )}
110
+
111
+ {/* Timestamps */}
112
+ {(plugin.discoveredAt || plugin.buildTimestamp) && (
113
+ <div
114
+ style={{
115
+ display: 'grid',
116
+ gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
117
+ gap: 16,
118
+ }}
119
+ >
120
+ {plugin.discoveredAt && (
121
+ <div>
122
+ <UIText
123
+ color="secondary"
124
+ style={{ fontSize: token.fontSizeSM, display: 'block', marginBottom: 4 }}
125
+ >
126
+ Discovered At
127
+ </UIText>
128
+ <UISpace>
129
+ <UIIcon name="SearchOutlined" />
130
+ <UIText>{new Date(plugin.discoveredAt).toLocaleString()}</UIText>
131
+ </UISpace>
132
+ </div>
133
+ )}
134
+ {plugin.buildTimestamp && (
135
+ <div>
136
+ <UIText
137
+ color="secondary"
138
+ style={{ fontSize: token.fontSizeSM, display: 'block', marginBottom: 4 }}
139
+ >
140
+ Last Built
141
+ </UIText>
142
+ <UISpace>
143
+ <UIIcon name="ClockCircleOutlined" />
144
+ <UIText>{new Date(plugin.buildTimestamp).toLocaleString()}</UIText>
145
+ </UISpace>
146
+ </div>
147
+ )}
148
+ </div>
149
+ )}
150
+
151
+ {/* Plugin Root (collapsible) */}
152
+ <UIAccordion
153
+ ghost
154
+ items={[
155
+ {
156
+ key: 'root',
157
+ label: 'Plugin Root Path',
158
+ children: (
159
+ <UIText style={{ fontSize: token.fontSizeSM, fontFamily: token.fontFamilyCode }}>
160
+ {plugin.pluginRoot}
161
+ </UIText>
162
+ ),
163
+ },
164
+ ]}
165
+ />
166
+ </UISpace>
167
+ </UICard>
168
+ );
169
+ }
@@ -0,0 +1,159 @@
1
+ import { UITable, UIAlert, UICard, UIText, UITag, UITitle, useUITheme, type UITableColumn } from '@kb-labs/studio-ui-kit';
2
+
3
+ interface RestRoutesTableProps {
4
+ routes: any[];
5
+ basePath?: string;
6
+ apiBasePath?: string;
7
+ }
8
+
9
+ export function RestRoutesTable({ routes, basePath, apiBasePath }: RestRoutesTableProps) {
10
+ const { token } = useUITheme();
11
+
12
+ // Combine API base path with plugin base path, avoiding duplicate /v1
13
+ const fullBasePath =
14
+ apiBasePath && basePath
15
+ ? basePath.startsWith('/v1')
16
+ ? apiBasePath + basePath.slice(3) // Remove /v1 from plugin basePath if API already has /api/v1
17
+ : apiBasePath + basePath
18
+ : basePath || '';
19
+
20
+ const columns: UITableColumn<any>[] = [
21
+ {
22
+ title: 'Method',
23
+ dataIndex: 'method',
24
+ key: 'method',
25
+ width: 100,
26
+ render: (method) => {
27
+ const colors: Record<string, string> = {
28
+ GET: 'green',
29
+ POST: 'blue',
30
+ PUT: 'orange',
31
+ PATCH: 'purple',
32
+ DELETE: 'red',
33
+ };
34
+ return <UITag color={colors[method] || 'default'}>{method}</UITag>;
35
+ },
36
+ },
37
+ {
38
+ title: 'Path',
39
+ dataIndex: 'path',
40
+ key: 'path',
41
+ render: (path) => (
42
+ <UIText style={{ fontFamily: token.fontFamilyCode }}>
43
+ {fullBasePath}
44
+ {path}
45
+ </UIText>
46
+ ),
47
+ },
48
+ {
49
+ title: 'Description',
50
+ dataIndex: 'description',
51
+ key: 'description',
52
+ render: (desc) => (typeof desc === 'string' ? desc : desc ? JSON.stringify(desc) : '--'),
53
+ },
54
+ {
55
+ title: 'Timeout',
56
+ dataIndex: 'timeoutMs',
57
+ key: 'timeoutMs',
58
+ render: (timeout) => (timeout ? `${timeout}ms` : '--'),
59
+ },
60
+ {
61
+ title: 'Handler',
62
+ dataIndex: 'handler',
63
+ key: 'handler',
64
+ render: (handler) => (
65
+ <UIText style={{ fontSize: 11, fontFamily: token.fontFamilyCode }}>
66
+ {handler}
67
+ </UIText>
68
+ ),
69
+ },
70
+ ];
71
+
72
+ const formatSchemaRef = (schema: any): string => {
73
+ if (!schema) {
74
+ return '--';
75
+ }
76
+ if (typeof schema === 'string') {
77
+ return schema;
78
+ }
79
+ if ('$ref' in schema) {
80
+ return schema.$ref;
81
+ }
82
+ if ('zod' in schema) {
83
+ return schema.zod;
84
+ }
85
+ return JSON.stringify(schema);
86
+ };
87
+
88
+ return (
89
+ <UICard>
90
+ {fullBasePath && (
91
+ <UIAlert
92
+ message={
93
+ <span>
94
+ Base Path:{' '}
95
+ <UIText style={{ fontFamily: token.fontFamilyCode }}>
96
+ {fullBasePath}
97
+ </UIText>
98
+ </span>
99
+ }
100
+ variant="info"
101
+ style={{ marginBottom: 16 }}
102
+ />
103
+ )}
104
+ <UITable
105
+ columns={columns}
106
+ dataSource={routes}
107
+ rowKey={(record) => `${record.method} ${record.path}`}
108
+ pagination={false}
109
+ expandable={{
110
+ expandedRowRender: (record) => {
111
+ const hasInput = record.input;
112
+ const hasOutput = record.output;
113
+ const hasErrors = record.errors && record.errors.length > 0;
114
+
115
+ if (!hasInput && !hasOutput && !hasErrors) {
116
+ return null;
117
+ }
118
+
119
+ return (
120
+ <div style={{ margin: 0, paddingLeft: 48 }}>
121
+ {hasInput && (
122
+ <div style={{ marginBottom: 16 }}>
123
+ <UITitle level={5}>
124
+ {record.method === 'GET' ? 'Query Parameters' : 'Request Body'}
125
+ </UITitle>
126
+ <UIText style={{ fontFamily: token.fontFamilyCode }}>
127
+ {formatSchemaRef(record.input)}
128
+ </UIText>
129
+ </div>
130
+ )}
131
+ {hasOutput && (
132
+ <div style={{ marginBottom: 16 }}>
133
+ <UITitle level={5}>Response</UITitle>
134
+ <UIText style={{ fontFamily: token.fontFamilyCode }}>
135
+ {formatSchemaRef(record.output)}
136
+ </UIText>
137
+ </div>
138
+ )}
139
+ {hasErrors && (
140
+ <div>
141
+ <UITitle level={5}>Error Responses</UITitle>
142
+ {record.errors.map((error: any, idx: number) => (
143
+ <div key={idx} style={{ marginBottom: 8 }}>
144
+ <UITag color="red">{error.code}</UITag>
145
+ <UIText>{error.message || '--'}</UIText>
146
+ </div>
147
+ ))}
148
+ </div>
149
+ )}
150
+ </div>
151
+ );
152
+ },
153
+ rowExpandable: (record) =>
154
+ !!(record.input || record.output || (record.errors && record.errors.length > 0)),
155
+ }}
156
+ />
157
+ </UICard>
158
+ );
159
+ }
@@ -0,0 +1,40 @@
1
+ import { UITable, UICard, UIText, useUITheme, type UITableColumn } from '@kb-labs/studio-ui-kit';
2
+
3
+ interface WorkflowsTableProps {
4
+ handlers: any[];
5
+ }
6
+
7
+ export function WorkflowsTable({ handlers }: WorkflowsTableProps) {
8
+ const { token } = useUITheme();
9
+
10
+ const columns: UITableColumn<any>[] = [
11
+ {
12
+ title: 'ID',
13
+ dataIndex: 'id',
14
+ key: 'id',
15
+ render: (id) => <UIText style={{ fontFamily: token.fontFamilyCode }}>{id}</UIText>,
16
+ },
17
+ {
18
+ title: 'Description',
19
+ dataIndex: 'describe',
20
+ key: 'describe',
21
+ render: (desc) => (typeof desc === 'string' ? desc : desc ? JSON.stringify(desc) : '--'),
22
+ },
23
+ {
24
+ title: 'Handler',
25
+ dataIndex: 'handler',
26
+ key: 'handler',
27
+ render: (handler) => (
28
+ <UIText style={{ fontSize: 11, fontFamily: token.fontFamilyCode }}>
29
+ {handler}
30
+ </UIText>
31
+ ),
32
+ },
33
+ ];
34
+
35
+ return (
36
+ <UICard>
37
+ <UITable columns={columns} dataSource={handlers} rowKey="id" pagination={false} />
38
+ </UICard>
39
+ );
40
+ }
@@ -0,0 +1,20 @@
1
+ import { UIRow, UICol } from '@kb-labs/studio-ui-kit';
2
+ import type { PluginManifestEntry } from '@kb-labs/studio-data-client';
3
+ import { PluginCard } from './plugin-card';
4
+
5
+ interface PluginGridProps {
6
+ plugins: PluginManifestEntry[];
7
+ onPluginClick: (plugin: PluginManifestEntry) => void;
8
+ }
9
+
10
+ export function PluginGrid({ plugins, onPluginClick }: PluginGridProps) {
11
+ return (
12
+ <UIRow gutter={[16, 16]}>
13
+ {plugins.map((plugin) => (
14
+ <UICol key={plugin.pluginId} xs={24} sm={12} lg={8} xl={6}>
15
+ <PluginCard plugin={plugin} onClick={() => onPluginClick(plugin)} />
16
+ </UICol>
17
+ ))}
18
+ </UIRow>
19
+ );
20
+ }