@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
package/UI-KIT-PLAN.md ADDED
@@ -0,0 +1,326 @@
1
+ # KB Labs Studio UI Kit - Component Plan
2
+
3
+ ## 🎯 Goal
4
+ Create a unified UI Kit using design tokens from `@kb-labs/studio-ui-core` and Ant Design theme tokens.
5
+
6
+ **Critical Requirements:**
7
+ - ✅ NO hardcoded colors (no `#DC2626`, `rgb()`, etc.)
8
+ - ✅ Use ONLY Ant Design tokens via `theme.useToken()`
9
+ - ✅ Use design tokens from `@kb-labs/studio-ui-core` for spacing/typography
10
+ - ✅ NO inline styles in widget components
11
+
12
+ ## 📊 Current Analysis
13
+
14
+ ### Inline Styles Usage
15
+ - **Total inline styles found**: 98 instances
16
+ - **Most common patterns**:
17
+ - Font sizes: `fontSize: '0.85em'`, `fontSize: '1.5rem'`
18
+ - Colors: `color: 'var(--text-secondary)'`, `color: 'var(--error-color)'`
19
+ - Spacing: `marginBottom: 16`, `padding: '12px 16px'`
20
+ - Font weights: `fontWeight: 700`
21
+
22
+ ### Most Used Ant Design Components
23
+ Based on current widget implementation:
24
+
25
+ 1. **Typography** - Text, Title, Paragraph (used in ~10 places)
26
+ 2. **Space** - Spacing layout (used in ~10 places)
27
+ 3. **Button** - Actions (used in ~7 places)
28
+ 4. **Card** - Container (used in ~6 places)
29
+ 5. **Tag** - Labels/badges (used in ~5 places)
30
+ 6. **Badge** - Status indicators (used in ~4 places)
31
+ 7. **Form** - Form elements (used in ~4 places)
32
+ 8. **Typography.Text** - Inline text (used in ~4 places)
33
+
34
+ ## 🏗️ UI Kit Component Hierarchy
35
+
36
+ ### Tier 1: Primitives (Foundation)
37
+ **Status: ✅ Complete**
38
+
39
+ These are the building blocks - lowest level components.
40
+
41
+ - ✅ **Text** - Typography primitive with semantic colors
42
+ - Sizes: xs, sm, base, lg, xl, 2xl
43
+ - Weights: normal, medium, semibold, bold
44
+ - Colors: primary, secondary, success, warning, error, info
45
+ - Uses: `typography.fontSize`, `typography.fontWeight`, `token.colorText`
46
+
47
+ - ✅ **Box** - Layout primitive with spacing
48
+ - Props: p, pt, pr, pb, pl, m, mt, mr, mb, ml
49
+ - Uses: `spacing` tokens from `@kb-labs/studio-ui-core`
50
+
51
+ - ✅ **Flex** - Flexbox layout primitive
52
+ - Props: direction, justify, align, gap, wrap
53
+ - Uses: `spacing` tokens for gap
54
+
55
+ ### Tier 2: Basic Components
56
+ **Status: 🔄 In Progress**
57
+
58
+ Built on primitives, add semantic meaning.
59
+
60
+ - ✅ **MetricCard** - Metric display with trend
61
+ - Uses: Text, Flex, Box, Ant Card
62
+ - Status: Complete, used in Metric and MetricGroup widgets
63
+
64
+ - 🔄 **Badge** - Status indicator
65
+ - Variants: success, warning, error, info, default
66
+ - Uses: Ant Badge with token colors
67
+ - Status: Created, needs export and usage
68
+
69
+ - ⏳ **Tag** - Label/category indicator (NEXT)
70
+ - Variants: success, warning, error, info, default, neutral
71
+ - Uses: Ant Tag with token colors
72
+ - Usage: Card widget (4 instances), Timeline (2 instances)
73
+
74
+ - ⏳ **Button** - Action button (NEXT)
75
+ - Variants: primary, default, text, link, danger
76
+ - Sizes: small, default, large
77
+ - Uses: Ant Button with consistent styling
78
+ - Usage: Alert, Confirm, ErrorState, Form (~7 instances)
79
+
80
+ - ⏳ **Stack** - Vertical/horizontal spacing layout
81
+ - Props: direction, spacing, align
82
+ - Uses: Box/Flex with consistent gap tokens
83
+ - Usage: Multiple widgets for consistent spacing
84
+
85
+ ### Tier 3: Complex Components
86
+ **Status: ⏳ Not Started**
87
+
88
+ Domain-specific components built from Tier 1 + 2.
89
+
90
+ - ⏳ **CardContent** - Enhanced card with header/footer/sections
91
+ - Uses: Box, Text, Tag, Badge, Ant Card
92
+ - Usage: Card widget (6 inline styles)
93
+
94
+ - ⏳ **TimelineItem** - Timeline entry with status
95
+ - Uses: Badge, Text, Stack
96
+ - Usage: Timeline widget (6 inline styles)
97
+
98
+ - ⏳ **LogEntry** - Log line with level badge
99
+ - Uses: Badge, Text, Flex
100
+ - Usage: Logs widget (7 inline styles)
101
+
102
+ - ⏳ **JsonView** - JSON display with syntax highlighting
103
+ - Uses: Box, Text
104
+ - Usage: Json widget (8 inline styles)
105
+
106
+ ## 📋 Implementation Plan
107
+
108
+ ### Phase 1: Complete Basic Components (Current Phase)
109
+ **Goal**: Build foundation layer of reusable components
110
+
111
+ #### Step 1.1: Export Badge ✅
112
+ - [x] Badge.tsx created
113
+ - [ ] Add to ui/index.ts
114
+ - [ ] Test in isolation
115
+
116
+ #### Step 1.2: Create Tag Component
117
+ ```typescript
118
+ // apps/studio/src/ui/Tag.tsx
119
+ export type TagVariant = 'success' | 'warning' | 'error' | 'info' | 'default' | 'neutral';
120
+
121
+ export function Tag({ variant, children, closable, onClose }: TagProps) {
122
+ const { token } = useToken();
123
+
124
+ const colorMap: Record<TagVariant, string> = {
125
+ success: token.colorSuccess,
126
+ warning: token.colorWarning,
127
+ error: token.colorError,
128
+ info: token.colorInfo,
129
+ default: token.colorPrimary,
130
+ neutral: token.colorTextSecondary,
131
+ };
132
+
133
+ return <AntTag color={colorMap[variant]} closable={closable} onClose={onClose}>{children}</AntTag>;
134
+ }
135
+ ```
136
+
137
+ #### Step 1.3: Create Button Component
138
+ ```typescript
139
+ // apps/studio/src/ui/Button.tsx
140
+ export type ButtonVariant = 'primary' | 'default' | 'text' | 'link' | 'danger';
141
+ export type ButtonSize = 'small' | 'default' | 'large';
142
+
143
+ export function Button({ variant, size, children, icon, loading, disabled, onClick }: ButtonProps) {
144
+ return (
145
+ <AntButton
146
+ type={variantMap[variant]}
147
+ size={size}
148
+ icon={icon}
149
+ loading={loading}
150
+ disabled={disabled}
151
+ onClick={onClick}
152
+ >
153
+ {children}
154
+ </AntButton>
155
+ );
156
+ }
157
+ ```
158
+
159
+ #### Step 1.4: Create Stack Component
160
+ ```typescript
161
+ // apps/studio/src/ui/Stack.tsx
162
+ export type StackDirection = 'vertical' | 'horizontal';
163
+ export type StackSpacing = SpacingValue;
164
+
165
+ export function Stack({ direction = 'vertical', spacing = 2, align, children }: StackProps) {
166
+ return (
167
+ <Flex
168
+ direction={direction === 'vertical' ? 'column' : 'row'}
169
+ gap={spacing}
170
+ align={align}
171
+ >
172
+ {children}
173
+ </Flex>
174
+ );
175
+ }
176
+ ```
177
+
178
+ ### Phase 2: Migrate High-Priority Widgets
179
+ **Goal**: Eliminate most inline styles by migrating top offenders
180
+
181
+ Priority order by inline style count:
182
+
183
+ 1. **Json** (8 styles) - needs JsonView component
184
+ 2. **Logs** (7 styles) - needs LogEntry component
185
+ 3. **Timeline** (6 styles) - needs TimelineItem component
186
+ 4. **Card** (6 styles) - needs CardContent component or direct Tag/Badge usage
187
+ 5. **MetricGroup** ✅ (5 styles) - DONE
188
+ 6. **Metric** ✅ (5 styles) - DONE
189
+
190
+ ### Phase 3: Create Complex Components
191
+ **Goal**: Domain-specific components for remaining widgets
192
+
193
+ #### CardContent Component
194
+ ```typescript
195
+ // apps/studio/src/ui/CardContent.tsx
196
+ export interface CardContentProps {
197
+ title?: string;
198
+ subtitle?: string;
199
+ tags?: { label: string; variant: TagVariant }[];
200
+ badges?: { label: string; variant: BadgeVariant }[];
201
+ extra?: React.ReactNode;
202
+ footer?: React.ReactNode;
203
+ children: React.ReactNode;
204
+ }
205
+
206
+ export function CardContent({ title, subtitle, tags, badges, extra, footer, children }: CardContentProps) {
207
+ // Uses: Box, Text, Tag, Badge, Stack
208
+ }
209
+ ```
210
+
211
+ #### TimelineItem Component
212
+ ```typescript
213
+ // apps/studio/src/ui/TimelineItem.tsx
214
+ export interface TimelineItemProps {
215
+ timestamp: string;
216
+ title: string;
217
+ description?: string;
218
+ status?: 'success' | 'warning' | 'error' | 'info';
219
+ icon?: React.ReactNode;
220
+ }
221
+
222
+ export function TimelineItem({ timestamp, title, description, status, icon }: TimelineItemProps) {
223
+ // Uses: Badge, Text, Stack, Flex
224
+ }
225
+ ```
226
+
227
+ ### Phase 4: Complete Migration
228
+ **Goal**: Eliminate ALL inline styles from widget components
229
+
230
+ Remaining widgets (~20 widgets) with <5 inline styles each.
231
+
232
+ ## 🎨 Design Token Usage
233
+
234
+ ### Colors (from Ant Design theme.useToken())
235
+ ```typescript
236
+ const { token } = useToken();
237
+
238
+ // Semantic colors
239
+ token.colorPrimary // Primary brand color
240
+ token.colorSuccess // Success/positive
241
+ token.colorWarning // Warning/caution
242
+ token.colorError // Error/danger
243
+ token.colorInfo // Info/neutral
244
+
245
+ // Text colors
246
+ token.colorText // Primary text
247
+ token.colorTextSecondary // Secondary text
248
+ token.colorTextDisabled // Disabled text
249
+
250
+ // Background colors
251
+ token.colorBgContainer // Container background
252
+ token.colorBgElevated // Elevated background
253
+ token.colorBorder // Border color
254
+ ```
255
+
256
+ ### Spacing (from @kb-labs/studio-ui-core)
257
+ ```typescript
258
+ import { spacing } from '@kb-labs/studio-ui-core';
259
+
260
+ spacing[0] // 0
261
+ spacing[1] // 0.25rem
262
+ spacing[2] // 0.5rem
263
+ spacing[3] // 0.75rem
264
+ spacing[4] // 1rem
265
+ spacing[6] // 1.5rem
266
+ spacing[8] // 2rem
267
+ ```
268
+
269
+ ### Typography (from @kb-labs/studio-ui-core)
270
+ ```typescript
271
+ import { typography } from '@kb-labs/studio-ui-core';
272
+
273
+ typography.fontSize.xs // ['0.75rem', { lineHeight: '1rem' }]
274
+ typography.fontSize.sm // ['0.875rem', { lineHeight: '1.25rem' }]
275
+ typography.fontSize.base // ['1rem', { lineHeight: '1.5rem' }]
276
+ typography.fontSize.lg // ['1.125rem', { lineHeight: '1.75rem' }]
277
+ typography.fontSize.xl // ['1.25rem', { lineHeight: '1.75rem' }]
278
+ typography.fontSize['2xl'] // ['1.5rem', { lineHeight: '2rem' }]
279
+
280
+ typography.fontWeight.normal // 400
281
+ typography.fontWeight.medium // 500
282
+ typography.fontWeight.semibold // 600
283
+ typography.fontWeight.bold // 700
284
+ ```
285
+
286
+ ## ✅ Success Criteria
287
+
288
+ ### Component Quality
289
+ - [ ] All components use ONLY design tokens (no hardcoded values)
290
+ - [ ] All components have proper TypeScript types
291
+ - [ ] All components are documented with examples
292
+ - [ ] All components are exported from ui/index.ts
293
+
294
+ ### Widget Migration
295
+ - [ ] Zero inline styles in widget components
296
+ - [ ] All colors use Ant Design tokens
297
+ - [ ] All spacing uses spacing tokens
298
+ - [ ] All typography uses typography tokens
299
+
300
+ ### Code Quality
301
+ - [ ] Build passes without errors
302
+ - [ ] Type check passes
303
+ - [ ] Lint passes
304
+ - [ ] No CSS variables (var(--*)) - use tokens instead
305
+
306
+ ## 📝 Notes
307
+
308
+ ### DO ✅
309
+ - Use `theme.useToken()` for ALL colors
310
+ - Use `spacing` tokens for ALL margins/paddings/gaps
311
+ - Use `typography` tokens for ALL font sizes/weights
312
+ - Build components incrementally (primitives → basic → complex)
313
+ - Test each component in isolation before using in widgets
314
+
315
+ ### DON'T ❌
316
+ - Hardcode colors like `#DC2626` or `rgb(220, 38, 38)`
317
+ - Use CSS variables like `var(--success)` or `var(--text-secondary)`
318
+ - Use magic numbers for spacing (`marginBottom: 16`)
319
+ - Use string literals for font sizes (`fontSize: '1.5rem'`)
320
+ - Skip token usage in favor of inline styles
321
+
322
+ ---
323
+
324
+ **Created**: 2026-01-27
325
+ **Status**: Phase 1 in progress
326
+ **Next Step**: Export Badge, create Tag component
@@ -0,0 +1,151 @@
1
+ /**
2
+ * ESLint rule: no-direct-antd-import
3
+ *
4
+ * Prevents direct imports from 'antd' or 'antd/*' in the studio app.
5
+ * Provides specific component-level suggestions to use @kb-labs/studio-ui-kit equivalents.
6
+ */
7
+
8
+ /** @type {Map<string, string>} */
9
+ const COMPONENT_MAP = {
10
+ // Core
11
+ Card: 'UICard',
12
+ Button: 'UIButton',
13
+ Tag: 'UITag',
14
+ Badge: 'UIBadge',
15
+ Spin: 'UISpin',
16
+ Divider: 'UIDivider',
17
+ // Layout
18
+ Row: 'UIRow',
19
+ Col: 'UICol',
20
+ Space: 'UISpace',
21
+ Flex: 'UIFlex',
22
+ Grid: 'UIGrid',
23
+ // Data display
24
+ Table: 'UITable',
25
+ List: 'UIList',
26
+ Descriptions: 'UIDescriptions',
27
+ Statistic: 'UIStatistic',
28
+ Timeline: 'UITimeline',
29
+ Avatar: 'UIAvatar',
30
+ Tooltip: 'UITooltip',
31
+ Progress: 'UIProgress',
32
+ // Feedback
33
+ Alert: 'UIAlert',
34
+ Modal: 'UIModal',
35
+ Drawer: 'UIDrawer',
36
+ Popconfirm: 'UIPopconfirm',
37
+ Empty: 'UIEmptyState',
38
+ Skeleton: 'UISkeleton',
39
+ // Navigation
40
+ Tabs: 'UITabs',
41
+ Menu: 'UIMenu',
42
+ Segmented: 'UISegmented',
43
+ Breadcrumb: 'UIBreadcrumb',
44
+ // Form
45
+ Form: 'UIForm',
46
+ Input: 'UIInput',
47
+ InputNumber: 'UIInputNumber',
48
+ Select: 'UISelect',
49
+ Checkbox: 'UICheckbox',
50
+ Radio: 'UIRadio',
51
+ Switch: 'UISwitch',
52
+ DatePicker: 'UIDatePicker',
53
+ TimePicker: 'UITimePicker',
54
+ Slider: 'UISlider',
55
+ Upload: 'UIUpload',
56
+ // Layout structural
57
+ Collapse: 'UIAccordion',
58
+ // Typography
59
+ Typography: 'UIText / UITitle (use UITypographyText, UITypographyParagraph, UITitle)',
60
+ };
61
+
62
+ /** @type {Record<string, string>} */
63
+ const HOOK_MAP = {
64
+ theme: 'useUITheme from @kb-labs/studio-ui-kit',
65
+ message: 'UIMessage or useUIMessage from @kb-labs/studio-ui-kit',
66
+ };
67
+
68
+ /** @param {string[]} names */
69
+ function buildSuggestion(names) {
70
+ const mapped = [];
71
+ const unknown = [];
72
+
73
+ for (const name of names) {
74
+ if (COMPONENT_MAP[name]) {
75
+ mapped.push(`${name} → ${COMPONENT_MAP[name]}`);
76
+ } else if (HOOK_MAP[name]) {
77
+ mapped.push(`${name} → ${HOOK_MAP[name]}`);
78
+ } else {
79
+ unknown.push(name);
80
+ }
81
+ }
82
+
83
+ const parts = [];
84
+ if (mapped.length > 0) {
85
+ parts.push(`Use from @kb-labs/studio-ui-kit: ${mapped.join(', ')}.`);
86
+ }
87
+ if (unknown.length > 0) {
88
+ parts.push(
89
+ `No UI Kit equivalent found for: ${unknown.join(', ')}. ` +
90
+ `Add a wrapper in packages/studio-ui-kit/src/ and export it from the index.`,
91
+ );
92
+ }
93
+ return parts.join(' ');
94
+ }
95
+
96
+ /** @type {import('eslint').Rule.RuleModule} */
97
+ const rule = {
98
+ meta: {
99
+ type: 'problem',
100
+ docs: {
101
+ description: 'Disallow direct imports from antd — use @kb-labs/studio-ui-kit instead.',
102
+ url: 'https://github.com/kb-labs/kb-labs-studio/blob/main/ANTD-MIGRATION-GUIDE.md',
103
+ },
104
+ messages: {
105
+ noDirectAntd:
106
+ 'Direct antd import is not allowed. {{ suggestion }}',
107
+ noAntdSubpath:
108
+ 'Direct antd subpath import is not allowed. Use @kb-labs/studio-ui-kit instead.',
109
+ noAntdIcons:
110
+ 'Import @ant-design/icons directly is not allowed. ' +
111
+ 'Use <UIIcon name="IconName" /> from @kb-labs/studio-ui-kit or ' +
112
+ 'renderIcon() from @kb-labs/studio-ui-react.',
113
+ },
114
+ schema: [],
115
+ },
116
+
117
+ create(context) {
118
+ return {
119
+ ImportDeclaration(node) {
120
+ const source = node.source.value;
121
+
122
+ // antd/es/... or antd/lib/... subpath imports — allow type-only imports
123
+ if (typeof source === 'string' && source.startsWith('antd/')) {
124
+ if (node.importKind === 'type') return;
125
+ context.report({ node, messageId: 'noAntdSubpath' });
126
+ return;
127
+ }
128
+
129
+ // direct 'antd' import
130
+ if (source !== 'antd') return;
131
+
132
+ // Collect imported names (skip type-only imports of unknown types)
133
+ const names = node.specifiers
134
+ .filter((s) => s.type === 'ImportSpecifier')
135
+ .map((s) => s.imported.name);
136
+
137
+ const suggestion = names.length > 0
138
+ ? buildSuggestion(names)
139
+ : 'Use @kb-labs/studio-ui-kit instead.';
140
+
141
+ context.report({
142
+ node,
143
+ messageId: 'noDirectAntd',
144
+ data: { suggestion },
145
+ });
146
+ },
147
+ };
148
+ },
149
+ };
150
+
151
+ module.exports = rule;
@@ -0,0 +1,27 @@
1
+ import reactPreset from '@kb-labs/devkit/eslint/react.js';
2
+ import noDirectAntdImport from './eslint-rules/no-direct-antd-import.js';
3
+
4
+ export default [
5
+ ...reactPreset,
6
+ {
7
+ ignores: ['dist/**', 'coverage/**', 'eslint-rules/**', '.__mf__temp/**', '*.mjs']
8
+ },
9
+ {
10
+ files: ['src/**/*.{ts,tsx}'],
11
+ plugins: {
12
+ 'studio-rules': {
13
+ rules: { 'no-direct-antd-import': noDirectAntdImport },
14
+ },
15
+ },
16
+ rules: {
17
+ 'studio-rules/no-direct-antd-import': 'error',
18
+ },
19
+ },
20
+ {
21
+ // Low-level UI wrappers are allowed to import directly from antd / @ant-design
22
+ files: ['src/components/ui/**/*.{ts,tsx}', 'src/ui/**/*.{ts,tsx}'],
23
+ rules: {
24
+ 'studio-rules/no-direct-antd-import': 'off',
25
+ },
26
+ },
27
+ ];
package/index.html ADDED
@@ -0,0 +1,17 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <base href="/" />
6
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
+ <link rel="icon" type="image/x-icon" href="/favicon.ico" />
8
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
9
+ <title>KB Labs Studio</title>
10
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
11
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
12
+ <link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,400;0,14..32,500;0,14..32,600;0,14..32,700&family=Plus+Jakarta+Sans:wght@600;700&display=swap" rel="stylesheet" />
13
+ </head>
14
+ <body>
15
+ <div id="root"></div>
16
+ </body>
17
+ </html>
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@kb-labs/studio-app",
3
+ "version": "0.6.0",
4
+ "description": "KB Labs Studio application",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "rspack serve",
8
+ "build": "rspack build",
9
+ "preview": "rspack serve --mode production",
10
+ "clean": "rimraf dist",
11
+ "type-check": "tsc --noEmit",
12
+ "lint": "eslint . --max-warnings=0",
13
+ "test": "vitest run --passWithNoTests",
14
+ "test:watch": "vitest --passWithNoTests"
15
+ },
16
+ "dependencies": {
17
+ "@ant-design/icons": "^5.4.0",
18
+ "@ant-design/plots": "^2.6.6",
19
+ "@kb-labs/agent-contracts": "^0.1.0",
20
+ "@kb-labs/qa-contracts": "^0.1.0",
21
+ "@kb-labs/quality-contracts": "^0.1.0",
22
+ "@kb-labs/release-manager-contracts": "^0.1.0",
23
+ "@kb-labs/rest-api-contracts": "^1.3.0",
24
+ "@kb-labs/studio-data-client": "^0.6.0",
25
+ "@kb-labs/studio-devtools": "^0.6.0",
26
+ "@kb-labs/studio-federation": "^0.6.0",
27
+ "@kb-labs/studio-hooks": "^0.6.0",
28
+ "@kb-labs/studio-event-bus": "^0.6.0",
29
+ "@kb-labs/studio-ui-core": "^0.6.0",
30
+ "@kb-labs/studio-plugin-tools": "^0.6.0",
31
+ "@kb-labs/studio-ui-kit": "^0.6.0",
32
+ "@kb-labs/workflow-contracts": "^1.4.0",
33
+ "@ant-design/charts": "^2.6.6",
34
+ "clsx": "^2.1.1",
35
+ "@tanstack/react-query": "^5.62.23",
36
+ "@tanstack/react-query-devtools": "^5.62.23",
37
+ "@types/react-grid-layout": "^1.3.6",
38
+ "antd": "^5.21.0",
39
+ "dayjs": "^1.11.19",
40
+ "dompurify": "^3.3.1",
41
+ "lucide-react": "^0.468.0",
42
+ "marked": "^17.0.1",
43
+ "react": "^18.3.1",
44
+ "react-dom": "^18.3.1",
45
+ "react-grid-layout": "^2.1.0",
46
+ "react-resizable": "^3.0.5",
47
+ "react-router-dom": "^7.1.4",
48
+ "reactflow": "^11.11.4",
49
+ "zod": "^3.23.8",
50
+ "zustand": "^5.0.2"
51
+ },
52
+ "devDependencies": {
53
+ "@kb-labs/devkit": "link:../../../../infra/kb-labs-devkit",
54
+ "@types/dompurify": "^3.2.0",
55
+ "@types/node": "^22.10.0",
56
+ "@types/react": "^18.3.18",
57
+ "@types/react-dom": "^18.3.5",
58
+ "@rspack/cli": "^1.7.0",
59
+ "@rspack/core": "^1.7.0",
60
+ "@rspack/plugin-react-refresh": "^1.6.0",
61
+ "@module-federation/enhanced": "^0.8.0",
62
+ "autoprefixer": "^10.4.21",
63
+ "eslint": "^9",
64
+ "jiti": "^2.6.1",
65
+ "postcss": "^8.4.49",
66
+ "rimraf": "^6",
67
+ "tailwindcss": "^3.4.17",
68
+ "typescript": "^5",
69
+ "postcss-loader": "^8.1.0",
70
+ "vitest": "^3.2.4"
71
+ }
72
+ }
@@ -0,0 +1,7 @@
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
7
+
Binary file
@@ -0,0 +1,7 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Lab flask favicon icon">
2
+ <rect x="4" y="4" width="56" height="56" rx="14" fill="#0B1320" />
3
+ <path d="M27 10h10v7l-1.6 2.3v8.4c0 2.2.9 4.4 2.4 6.1l6.4 9c2.8 3.9.1 9.2-4.7 9.2H24.5c-4.8 0-7.5-5.3-4.7-9.2l6.4-9c1.5-1.7 2.4-3.9 2.4-6.1v-8.4L27 17z" fill="#EAF3FF" />
4
+ <path d="M21.8 43.2c2.2-2.8 18.2-2.8 20.4 0l2 2.8c1.8 2.6-.1 6-3.2 6H23c-3.1 0-5-3.4-3.2-6z" fill="#3B82F6" />
5
+ <ellipse cx="28" cy="35.2" rx="3.3" ry="5.4" fill="#FFFFFF" opacity="0.48" />
6
+ <circle cx="35.5" cy="46.2" r="1.6" fill="#BFDBFE" />
7
+ </svg>