@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.
- package/.env.example +10 -0
- package/README.md +74 -0
- package/UI-KIT-COMPONENTS.md +783 -0
- package/UI-KIT-PLAN.md +326 -0
- package/eslint-rules/no-direct-antd-import.js +151 -0
- package/eslint.config.ts +27 -0
- package/index.html +17 -0
- package/package.json +72 -0
- package/postcss.config.js +7 -0
- package/public/favicon.ico +0 -0
- package/public/favicon.svg +7 -0
- package/rspack.config.mjs +118 -0
- package/src/App.tsx +46 -0
- package/src/components/devtools/devtools-log-feed.module.css +165 -0
- package/src/components/devtools/devtools-log-feed.tsx +300 -0
- package/src/components/devtools/devtools-panel.module.css +121 -0
- package/src/components/devtools/devtools-panel.tsx +115 -0
- package/src/components/empty-state.tsx +28 -0
- package/src/components/error-boundary.tsx +210 -0
- package/src/components/health-banner.module.css +103 -0
- package/src/components/health-banner.tsx +134 -0
- package/src/components/health-indicator.tsx +12 -0
- package/src/components/page-header.tsx +49 -0
- package/src/components/page-transition.tsx +24 -0
- package/src/components/role-switcher.tsx +148 -0
- package/src/components/run-badge.tsx +13 -0
- package/src/components/ui/icons.tsx +509 -0
- package/src/components/ui/index.ts +25 -0
- package/src/components/ui/kb-config-provider.tsx +130 -0
- package/src/components/ui/kb-header.module.css +51 -0
- package/src/components/ui/kb-header.tsx +112 -0
- package/src/components/ui/kb-notification-bell.module.css +103 -0
- package/src/components/ui/kb-notification-bell.tsx +199 -0
- package/src/components/ui/kb-page-layout.tsx +66 -0
- package/src/components/ui/kb-quick-search.module.css +86 -0
- package/src/components/ui/kb-quick-search.tsx +196 -0
- package/src/components/ui/kb-sidebar.module.css +47 -0
- package/src/components/ui/kb-sidebar.tsx +196 -0
- package/src/components/ui/kb-stat-card.module.css +21 -0
- package/src/components/ui/kb-stat-card.tsx +22 -0
- package/src/components/ui/kb-stat-grid.tsx +22 -0
- package/src/components/ui/kb-status-bar.module.css +49 -0
- package/src/components/ui/kb-status-bar.tsx +145 -0
- package/src/components/ui/kb-system-health-indicator.tsx +229 -0
- package/src/components/ui/kb-theme-toggle.tsx +42 -0
- package/src/components/ui/theme-adapter.ts +812 -0
- package/src/components/ui/theme-transition-overlay.tsx +70 -0
- package/src/components/ui/utils.ts +6 -0
- package/src/components/widget-error-boundary.tsx +172 -0
- package/src/config/env.ts +5 -0
- package/src/config/feature-flags.ts +482 -0
- package/src/config/studio.config.schema.ts +88 -0
- package/src/config/studio.config.ts +84 -0
- package/src/env.d.ts +23 -0
- package/src/hooks/use-command-palette.ts +6 -0
- package/src/hooks/use-devtools-store.ts +25 -0
- package/src/hooks/use-feature-flags.ts +101 -0
- package/src/index.css +10 -0
- package/src/layouts/dashboard-grid.tsx +122 -0
- package/src/layouts/index.ts +12 -0
- package/src/layouts/two-pane.tsx +134 -0
- package/src/main.tsx +15 -0
- package/src/modules/analytics/components/analytics-daily-stats-chart.tsx +257 -0
- package/src/modules/analytics/components/analytics-date-range-picker.tsx +121 -0
- package/src/modules/analytics/pages/analytics-cache-page.tsx +285 -0
- package/src/modules/analytics/pages/analytics-embeddings-page.tsx +274 -0
- package/src/modules/analytics/pages/analytics-events-page.tsx +425 -0
- package/src/modules/analytics/pages/analytics-llm-page.tsx +434 -0
- package/src/modules/analytics/pages/analytics-overview-page.tsx +336 -0
- package/src/modules/analytics/pages/analytics-page.tsx +20 -0
- package/src/modules/analytics/pages/analytics-storage-page.tsx +344 -0
- package/src/modules/analytics/pages/analytics-vectorstore-page.tsx +279 -0
- package/src/modules/analytics/routes/index.tsx +133 -0
- package/src/modules/analytics/utils/formatters.test.ts +148 -0
- package/src/modules/analytics/utils/formatters.ts +100 -0
- package/src/modules/auth/pages/login-page.module.css +113 -0
- package/src/modules/auth/pages/login-page.tsx +80 -0
- package/src/modules/auth/routes/index.tsx +24 -0
- package/src/modules/dashboard/components/ActivityTimelineWidget.tsx +199 -0
- package/src/modules/dashboard/components/AiInsightsWidget.tsx +358 -0
- package/src/modules/dashboard/components/AnimatedMetricCard.css +88 -0
- package/src/modules/dashboard/components/AnimatedMetricCard.tsx +125 -0
- package/src/modules/dashboard/components/HeroMetricCard.css +114 -0
- package/src/modules/dashboard/components/HeroMetricCard.tsx +152 -0
- package/src/modules/dashboard/components/HeroMetricsWidget.tsx +146 -0
- package/src/modules/dashboard/components/SystemResourcesWidget.tsx +197 -0
- package/src/modules/dashboard/components/dashboard-empty.tsx +22 -0
- package/src/modules/dashboard/components/dashboard-kpis-widget.tsx +59 -0
- package/src/modules/dashboard/components/dashboard-kpis.tsx +13 -0
- package/src/modules/dashboard/components/dashboard-latency-percentiles-widget.tsx +85 -0
- package/src/modules/dashboard/components/dashboard-metrics-widget.tsx +78 -0
- package/src/modules/dashboard/components/dashboard-plugins-widget.tsx +67 -0
- package/src/modules/dashboard/components/dashboard-requests-widget.tsx +62 -0
- package/src/modules/dashboard/layouts/dashboard-layout.tsx +16 -0
- package/src/modules/dashboard/pages/ai-insights-page.tsx +563 -0
- package/src/modules/dashboard/pages/dashboard-animations.css +317 -0
- package/src/modules/dashboard/pages/dashboard-page.tsx +13 -0
- package/src/modules/dashboard/routes/index.tsx +70 -0
- package/src/modules/observability/pages/devkit-page.tsx +263 -0
- package/src/modules/observability/pages/incident-detail-page.tsx +571 -0
- package/src/modules/observability/pages/incidents-page.tsx +370 -0
- package/src/modules/observability/pages/log-detail-page.tsx +508 -0
- package/src/modules/observability/pages/logs-page.tsx +1129 -0
- package/src/modules/observability/pages/prometheus-metrics-page.tsx +486 -0
- package/src/modules/observability/pages/state-broker-page.tsx +229 -0
- package/src/modules/observability/pages/system-events-page.tsx +255 -0
- package/src/modules/observability/routes/index.tsx +133 -0
- package/src/modules/plugins/components/marketplace-card.tsx +153 -0
- package/src/modules/plugins/components/plugin-ai-assistant-modal.tsx +374 -0
- package/src/modules/plugins/components/plugin-card.tsx +136 -0
- package/src/modules/plugins/components/plugin-detail/capabilities-summary.tsx +101 -0
- package/src/modules/plugins/components/plugin-detail/cli-commands-table.tsx +101 -0
- package/src/modules/plugins/components/plugin-detail/index.ts +7 -0
- package/src/modules/plugins/components/plugin-detail/jobs-table.tsx +64 -0
- package/src/modules/plugins/components/plugin-detail/permissions/env-permissions.tsx +30 -0
- package/src/modules/plugins/components/plugin-detail/permissions/filesystem-permissions.tsx +68 -0
- package/src/modules/plugins/components/plugin-detail/permissions/index.ts +6 -0
- package/src/modules/plugins/components/plugin-detail/permissions/network-permissions.tsx +43 -0
- package/src/modules/plugins/components/plugin-detail/permissions/platform-services.tsx +242 -0
- package/src/modules/plugins/components/plugin-detail/permissions/resource-quotas.tsx +96 -0
- package/src/modules/plugins/components/plugin-detail/permissions/shell-permissions.tsx +55 -0
- package/src/modules/plugins/components/plugin-detail/permissions-view.tsx +47 -0
- package/src/modules/plugins/components/plugin-detail/plugin-header.tsx +169 -0
- package/src/modules/plugins/components/plugin-detail/rest-routes-table.tsx +159 -0
- package/src/modules/plugins/components/plugin-detail/workflows-table.tsx +40 -0
- package/src/modules/plugins/components/plugin-grid.tsx +20 -0
- package/src/modules/plugins/components/plugin-table.tsx +178 -0
- package/src/modules/plugins/pages/marketplace-page.tsx +200 -0
- package/src/modules/plugins/pages/plugin-detail-page.tsx +1145 -0
- package/src/modules/plugins/routes/index.tsx +48 -0
- package/src/modules/plugins/utils/index.ts +1 -0
- package/src/modules/plugins/utils/schema-helpers.ts +21 -0
- package/src/modules/settings/components/api-routes-viewer.tsx +415 -0
- package/src/modules/settings/components/appearance-settings.tsx +200 -0
- package/src/modules/settings/components/configuration-settings.tsx +321 -0
- package/src/modules/settings/components/data-privacy-settings.tsx +111 -0
- package/src/modules/settings/components/experimental-settings.tsx +243 -0
- package/src/modules/settings/components/navigation-settings.tsx +198 -0
- package/src/modules/settings/components/notifications-settings.tsx +40 -0
- package/src/modules/settings/pages/settings-page.tsx +298 -0
- package/src/modules/settings/routes/index.tsx +47 -0
- package/src/pages/README-assistant.md +91 -0
- package/src/pages/login-page.tsx +177 -0
- package/src/pages/not-found-page.tsx +85 -0
- package/src/providers/auth-provider.tsx +40 -0
- package/src/providers/command-palette-provider.tsx +193 -0
- package/src/providers/data-sources-provider.tsx +27 -0
- package/src/providers/devtools-provider.tsx +72 -0
- package/src/providers/navigation-items-provider.tsx +38 -0
- package/src/providers/registry-v2-provider.tsx +93 -0
- package/src/providers/settings-provider.tsx +158 -0
- package/src/router.tsx +302 -0
- package/src/routes/helpers.tsx +25 -0
- package/src/routes/plugin-page-v2.tsx +52 -0
- package/src/routes/types.ts +18 -0
- package/src/styles/antd-overrides.css +211 -0
- package/src/styles/base.css +190 -0
- package/src/styles/settings.css +75 -0
- package/src/styles/variables.css +94 -0
- package/src/utils/analytics.ts +183 -0
- package/src/utils/apply-navigation-categories.ts +83 -0
- package/src/utils/commands.ts +252 -0
- package/src/utils/export.ts +174 -0
- package/src/utils/format-date.ts +166 -0
- package/src/utils/logger.ts +110 -0
- package/tailwind.config.ts +13 -0
- package/tsconfig.json +13 -0
- 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;
|
package/eslint.config.ts
ADDED
|
@@ -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
|
+
}
|
|
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>
|