@kb-labs/studio-app 0.7.0 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/dist/index.html +1 -0
  2. package/dist/main.80b70197.css +2 -0
  3. package/dist/main.80b70197.css.map +1 -0
  4. package/dist/main.ad42ef4a.js +522 -0
  5. package/dist/main.ad42ef4a.js.map +1 -0
  6. package/dist/mf-manifest.json +241 -0
  7. package/dist/mf-stats.json +271 -0
  8. package/package.json +56 -39
  9. package/server.js +68 -0
  10. package/.env.example +0 -10
  11. package/UI-KIT-COMPONENTS.md +0 -783
  12. package/UI-KIT-PLAN.md +0 -326
  13. package/eslint-rules/no-direct-antd-import.js +0 -151
  14. package/eslint.config.ts +0 -27
  15. package/index.html +0 -17
  16. package/postcss.config.js +0 -7
  17. package/public/favicon.ico +0 -0
  18. package/rspack.config.mjs +0 -118
  19. package/src/App.tsx +0 -46
  20. package/src/components/devtools/devtools-log-feed.module.css +0 -165
  21. package/src/components/devtools/devtools-log-feed.tsx +0 -300
  22. package/src/components/devtools/devtools-panel.module.css +0 -121
  23. package/src/components/devtools/devtools-panel.tsx +0 -115
  24. package/src/components/empty-state.tsx +0 -28
  25. package/src/components/error-boundary.tsx +0 -210
  26. package/src/components/health-banner.module.css +0 -103
  27. package/src/components/health-banner.tsx +0 -134
  28. package/src/components/health-indicator.tsx +0 -12
  29. package/src/components/page-header.tsx +0 -49
  30. package/src/components/page-transition.tsx +0 -24
  31. package/src/components/role-switcher.tsx +0 -148
  32. package/src/components/run-badge.tsx +0 -13
  33. package/src/components/ui/icons.tsx +0 -509
  34. package/src/components/ui/index.ts +0 -25
  35. package/src/components/ui/kb-config-provider.tsx +0 -130
  36. package/src/components/ui/kb-header.module.css +0 -51
  37. package/src/components/ui/kb-header.tsx +0 -112
  38. package/src/components/ui/kb-notification-bell.module.css +0 -103
  39. package/src/components/ui/kb-notification-bell.tsx +0 -199
  40. package/src/components/ui/kb-page-layout.tsx +0 -66
  41. package/src/components/ui/kb-quick-search.module.css +0 -86
  42. package/src/components/ui/kb-quick-search.tsx +0 -196
  43. package/src/components/ui/kb-sidebar.module.css +0 -47
  44. package/src/components/ui/kb-sidebar.tsx +0 -196
  45. package/src/components/ui/kb-stat-card.module.css +0 -21
  46. package/src/components/ui/kb-stat-card.tsx +0 -22
  47. package/src/components/ui/kb-stat-grid.tsx +0 -22
  48. package/src/components/ui/kb-status-bar.module.css +0 -49
  49. package/src/components/ui/kb-status-bar.tsx +0 -145
  50. package/src/components/ui/kb-system-health-indicator.tsx +0 -229
  51. package/src/components/ui/kb-theme-toggle.tsx +0 -42
  52. package/src/components/ui/theme-adapter.ts +0 -812
  53. package/src/components/ui/theme-transition-overlay.tsx +0 -70
  54. package/src/components/ui/utils.ts +0 -6
  55. package/src/components/widget-error-boundary.tsx +0 -172
  56. package/src/config/env.ts +0 -5
  57. package/src/config/feature-flags.ts +0 -482
  58. package/src/config/studio.config.schema.ts +0 -88
  59. package/src/config/studio.config.ts +0 -84
  60. package/src/env.d.ts +0 -23
  61. package/src/hooks/use-command-palette.ts +0 -6
  62. package/src/hooks/use-devtools-store.ts +0 -25
  63. package/src/hooks/use-feature-flags.ts +0 -101
  64. package/src/index.css +0 -10
  65. package/src/layouts/dashboard-grid.tsx +0 -122
  66. package/src/layouts/index.ts +0 -12
  67. package/src/layouts/two-pane.tsx +0 -134
  68. package/src/main.tsx +0 -15
  69. package/src/modules/analytics/components/analytics-daily-stats-chart.tsx +0 -257
  70. package/src/modules/analytics/components/analytics-date-range-picker.tsx +0 -121
  71. package/src/modules/analytics/pages/analytics-cache-page.tsx +0 -285
  72. package/src/modules/analytics/pages/analytics-embeddings-page.tsx +0 -274
  73. package/src/modules/analytics/pages/analytics-events-page.tsx +0 -425
  74. package/src/modules/analytics/pages/analytics-llm-page.tsx +0 -434
  75. package/src/modules/analytics/pages/analytics-overview-page.tsx +0 -336
  76. package/src/modules/analytics/pages/analytics-page.tsx +0 -20
  77. package/src/modules/analytics/pages/analytics-storage-page.tsx +0 -344
  78. package/src/modules/analytics/pages/analytics-vectorstore-page.tsx +0 -279
  79. package/src/modules/analytics/routes/index.tsx +0 -133
  80. package/src/modules/analytics/utils/formatters.test.ts +0 -148
  81. package/src/modules/analytics/utils/formatters.ts +0 -100
  82. package/src/modules/auth/pages/login-page.module.css +0 -113
  83. package/src/modules/auth/pages/login-page.tsx +0 -80
  84. package/src/modules/auth/routes/index.tsx +0 -24
  85. package/src/modules/dashboard/components/ActivityTimelineWidget.tsx +0 -199
  86. package/src/modules/dashboard/components/AiInsightsWidget.tsx +0 -358
  87. package/src/modules/dashboard/components/AnimatedMetricCard.css +0 -88
  88. package/src/modules/dashboard/components/AnimatedMetricCard.tsx +0 -125
  89. package/src/modules/dashboard/components/HeroMetricCard.css +0 -114
  90. package/src/modules/dashboard/components/HeroMetricCard.tsx +0 -152
  91. package/src/modules/dashboard/components/HeroMetricsWidget.tsx +0 -146
  92. package/src/modules/dashboard/components/SystemResourcesWidget.tsx +0 -197
  93. package/src/modules/dashboard/components/dashboard-empty.tsx +0 -22
  94. package/src/modules/dashboard/components/dashboard-kpis-widget.tsx +0 -59
  95. package/src/modules/dashboard/components/dashboard-kpis.tsx +0 -13
  96. package/src/modules/dashboard/components/dashboard-latency-percentiles-widget.tsx +0 -85
  97. package/src/modules/dashboard/components/dashboard-metrics-widget.tsx +0 -78
  98. package/src/modules/dashboard/components/dashboard-plugins-widget.tsx +0 -67
  99. package/src/modules/dashboard/components/dashboard-requests-widget.tsx +0 -62
  100. package/src/modules/dashboard/layouts/dashboard-layout.tsx +0 -16
  101. package/src/modules/dashboard/pages/ai-insights-page.tsx +0 -563
  102. package/src/modules/dashboard/pages/dashboard-animations.css +0 -317
  103. package/src/modules/dashboard/pages/dashboard-page.tsx +0 -13
  104. package/src/modules/dashboard/routes/index.tsx +0 -70
  105. package/src/modules/observability/pages/devkit-page.tsx +0 -263
  106. package/src/modules/observability/pages/incident-detail-page.tsx +0 -571
  107. package/src/modules/observability/pages/incidents-page.tsx +0 -370
  108. package/src/modules/observability/pages/log-detail-page.tsx +0 -508
  109. package/src/modules/observability/pages/logs-page.tsx +0 -1129
  110. package/src/modules/observability/pages/prometheus-metrics-page.tsx +0 -486
  111. package/src/modules/observability/pages/state-broker-page.tsx +0 -229
  112. package/src/modules/observability/pages/system-events-page.tsx +0 -255
  113. package/src/modules/observability/routes/index.tsx +0 -133
  114. package/src/modules/plugins/components/marketplace-card.tsx +0 -153
  115. package/src/modules/plugins/components/plugin-ai-assistant-modal.tsx +0 -374
  116. package/src/modules/plugins/components/plugin-card.tsx +0 -136
  117. package/src/modules/plugins/components/plugin-detail/capabilities-summary.tsx +0 -101
  118. package/src/modules/plugins/components/plugin-detail/cli-commands-table.tsx +0 -101
  119. package/src/modules/plugins/components/plugin-detail/index.ts +0 -7
  120. package/src/modules/plugins/components/plugin-detail/jobs-table.tsx +0 -64
  121. package/src/modules/plugins/components/plugin-detail/permissions/env-permissions.tsx +0 -30
  122. package/src/modules/plugins/components/plugin-detail/permissions/filesystem-permissions.tsx +0 -68
  123. package/src/modules/plugins/components/plugin-detail/permissions/index.ts +0 -6
  124. package/src/modules/plugins/components/plugin-detail/permissions/network-permissions.tsx +0 -43
  125. package/src/modules/plugins/components/plugin-detail/permissions/platform-services.tsx +0 -242
  126. package/src/modules/plugins/components/plugin-detail/permissions/resource-quotas.tsx +0 -96
  127. package/src/modules/plugins/components/plugin-detail/permissions/shell-permissions.tsx +0 -55
  128. package/src/modules/plugins/components/plugin-detail/permissions-view.tsx +0 -47
  129. package/src/modules/plugins/components/plugin-detail/plugin-header.tsx +0 -169
  130. package/src/modules/plugins/components/plugin-detail/rest-routes-table.tsx +0 -159
  131. package/src/modules/plugins/components/plugin-detail/workflows-table.tsx +0 -40
  132. package/src/modules/plugins/components/plugin-grid.tsx +0 -20
  133. package/src/modules/plugins/components/plugin-table.tsx +0 -178
  134. package/src/modules/plugins/pages/marketplace-page.tsx +0 -200
  135. package/src/modules/plugins/pages/plugin-detail-page.tsx +0 -1145
  136. package/src/modules/plugins/routes/index.tsx +0 -48
  137. package/src/modules/plugins/utils/index.ts +0 -1
  138. package/src/modules/plugins/utils/schema-helpers.ts +0 -21
  139. package/src/modules/settings/components/api-routes-viewer.tsx +0 -415
  140. package/src/modules/settings/components/appearance-settings.tsx +0 -200
  141. package/src/modules/settings/components/configuration-settings.tsx +0 -321
  142. package/src/modules/settings/components/data-privacy-settings.tsx +0 -111
  143. package/src/modules/settings/components/experimental-settings.tsx +0 -243
  144. package/src/modules/settings/components/navigation-settings.tsx +0 -198
  145. package/src/modules/settings/components/notifications-settings.tsx +0 -40
  146. package/src/modules/settings/pages/settings-page.tsx +0 -298
  147. package/src/modules/settings/routes/index.tsx +0 -47
  148. package/src/pages/README-assistant.md +0 -91
  149. package/src/pages/login-page.tsx +0 -177
  150. package/src/pages/not-found-page.tsx +0 -85
  151. package/src/providers/auth-provider.tsx +0 -40
  152. package/src/providers/command-palette-provider.tsx +0 -193
  153. package/src/providers/data-sources-provider.tsx +0 -27
  154. package/src/providers/devtools-provider.tsx +0 -72
  155. package/src/providers/navigation-items-provider.tsx +0 -38
  156. package/src/providers/registry-v2-provider.tsx +0 -93
  157. package/src/providers/settings-provider.tsx +0 -158
  158. package/src/router.tsx +0 -302
  159. package/src/routes/helpers.tsx +0 -25
  160. package/src/routes/plugin-page-v2.tsx +0 -52
  161. package/src/routes/types.ts +0 -18
  162. package/src/styles/antd-overrides.css +0 -211
  163. package/src/styles/base.css +0 -190
  164. package/src/styles/settings.css +0 -75
  165. package/src/styles/variables.css +0 -94
  166. package/src/utils/analytics.ts +0 -183
  167. package/src/utils/apply-navigation-categories.ts +0 -83
  168. package/src/utils/commands.ts +0 -252
  169. package/src/utils/export.ts +0 -174
  170. package/src/utils/format-date.ts +0 -166
  171. package/src/utils/logger.ts +0 -110
  172. package/tailwind.config.ts +0 -13
  173. package/tsconfig.json +0 -13
  174. package/vitest-setup.ts +0 -1
  175. /package/{public → dist}/favicon.svg +0 -0
@@ -1,183 +0,0 @@
1
- /**
2
- * @module @kb-labs/studio-app/utils/analytics
3
- * Analytics helpers for widget events, page views, and performance tracking
4
- */
5
-
6
- import { createStudioLogger } from './logger';
7
-
8
- const analyticsLogger = createStudioLogger('analytics');
9
-
10
- /**
11
- * Analytics configuration
12
- */
13
- export interface AnalyticsConfig {
14
- enabled: boolean;
15
- trackPageViews: boolean;
16
- trackWidgetEvents: boolean;
17
- trackPerformance: boolean;
18
- trackErrors: boolean;
19
- }
20
-
21
- let analyticsConfig: AnalyticsConfig = {
22
- enabled: true,
23
- trackPageViews: true,
24
- trackWidgetEvents: true,
25
- trackPerformance: true,
26
- trackErrors: true,
27
- };
28
-
29
- /**
30
- * Set analytics configuration
31
- */
32
- export function setAnalyticsConfig(config: Partial<AnalyticsConfig>): void {
33
- analyticsConfig = { ...analyticsConfig, ...config };
34
- }
35
-
36
- /**
37
- * Get analytics configuration
38
- */
39
- export function getAnalyticsConfig(): AnalyticsConfig {
40
- return { ...analyticsConfig };
41
- }
42
-
43
- /**
44
- * Widget event types
45
- */
46
- export type WidgetEventType =
47
- | 'mounted'
48
- | 'error'
49
- | 'interaction'
50
- | 'data-loaded'
51
- | 'data-error'
52
- | 'export'
53
- | 'refresh';
54
-
55
- /**
56
- * Track widget event
57
- * Fire-and-forget, analytics failures should not break execution
58
- */
59
- export function trackWidgetEvent(
60
- event: WidgetEventType,
61
- data: {
62
- widgetId: string;
63
- pluginId: string;
64
- code?: string;
65
- event?: string;
66
- duration?: number;
67
- exportFormat?: string;
68
- }
69
- ): void {
70
- if (!analyticsConfig.enabled || !analyticsConfig.trackWidgetEvents) {
71
- return;
72
- }
73
-
74
- try {
75
- // TODO: Integrate with @kb-labs/analytics-sdk-node
76
- // For now, just log
77
- analyticsLogger.info('Widget analytic event', {
78
- event,
79
- ...data,
80
- timestamp: new Date().toISOString(),
81
- });
82
- } catch (e) {
83
- // Silently fail - analytics should not break execution
84
- analyticsLogger.warn('Failed to track widget event', {
85
- event,
86
- data,
87
- error: e instanceof Error ? e.message : String(e),
88
- });
89
- }
90
- }
91
-
92
- /**
93
- * Track page view
94
- */
95
- export function trackPageView(data: {
96
- path: string;
97
- title?: string;
98
- layoutId?: string;
99
- pluginId?: string;
100
- }): void {
101
- if (!analyticsConfig.enabled || !analyticsConfig.trackPageViews) {
102
- return;
103
- }
104
-
105
- try {
106
- analyticsLogger.info('Page view', {
107
- ...data,
108
- timestamp: new Date().toISOString(),
109
- });
110
- } catch (e) {
111
- // Silently fail
112
- analyticsLogger.warn('Failed to track page view', {
113
- data,
114
- error: e instanceof Error ? e.message : String(e),
115
- });
116
- }
117
- }
118
-
119
- /**
120
- * Track performance metric
121
- */
122
- export function trackPerformance(data: {
123
- metric: string;
124
- value: number;
125
- unit?: string;
126
- widgetId?: string;
127
- pluginId?: string;
128
- }): void {
129
- if (!analyticsConfig.enabled || !analyticsConfig.trackPerformance) {
130
- return;
131
- }
132
-
133
- try {
134
- analyticsLogger.info('Performance metric', {
135
- ...data,
136
- timestamp: new Date().toISOString(),
137
- });
138
- } catch (e) {
139
- // Silently fail
140
- analyticsLogger.warn('Failed to track performance', {
141
- data,
142
- error: e instanceof Error ? e.message : String(e),
143
- });
144
- }
145
- }
146
-
147
- /**
148
- * Track error
149
- */
150
- export function trackError(data: {
151
- error: Error | string;
152
- context?: string;
153
- widgetId?: string;
154
- pluginId?: string;
155
- metadata?: Record<string, unknown>;
156
- }): void {
157
- if (!analyticsConfig.enabled || !analyticsConfig.trackErrors) {
158
- return;
159
- }
160
-
161
- try {
162
- const errorMessage = data.error instanceof Error ? data.error.message : data.error;
163
- const errorStack = data.error instanceof Error ? data.error.stack : undefined;
164
-
165
- analyticsLogger.error('Error tracked', {
166
- error: errorMessage,
167
- stack: errorStack,
168
- context: data.context,
169
- widgetId: data.widgetId,
170
- pluginId: data.pluginId,
171
- metadata: data.metadata,
172
- timestamp: new Date().toISOString(),
173
- });
174
- } catch (e) {
175
- // Silently fail
176
- analyticsLogger.warn('Failed to track error', {
177
- data,
178
- error: e instanceof Error ? e.message : String(e),
179
- });
180
- }
181
- }
182
-
183
-
@@ -1,83 +0,0 @@
1
- /**
2
- * @module @kb-labs/studio-app/utils/apply-navigation-categories
3
- * Pure transform: flat NavigationItem[] + user categories → grouped NavigationItem[]
4
- */
5
-
6
- import type { NavigationCategory } from '../providers/settings-provider';
7
- import type { NavigationItem } from '@/components/ui';
8
-
9
- const PROTECTED_KEYS = new Set(['settings']);
10
-
11
- /**
12
- * Apply user's category configuration to the flat navigation items list.
13
- *
14
- * - Items assigned to a category are grouped under that category's header
15
- * - Items not assigned to any category remain as top-level items (original order)
16
- * - Categories sorted by `order` field
17
- * - "settings" is protected — always last, never categorized
18
- * - Missing keys (removed plugin/module) are silently skipped
19
- * - Empty categories (all items removed) are omitted
20
- */
21
- export function applyNavigationCategories(
22
- items: NavigationItem[],
23
- categories: NavigationCategory[],
24
- ): NavigationItem[] {
25
- if (categories.length === 0) {
26
- return items;
27
- }
28
-
29
- // Collect all keys assigned to any category
30
- const assignedKeys = new Set<string>();
31
- for (const cat of categories) {
32
- for (const key of cat.itemKeys) {
33
- assignedKeys.add(key);
34
- }
35
- }
36
-
37
- // Map key → item for quick lookup
38
- const itemsByKey = new Map<string, NavigationItem>();
39
- for (const item of items) {
40
- itemsByKey.set(item.key, item);
41
- }
42
-
43
- const result: NavigationItem[] = [];
44
-
45
- // 1. Uncategorized items in original order (except protected)
46
- for (const item of items) {
47
- if (!assignedKeys.has(item.key) && !PROTECTED_KEYS.has(item.key)) {
48
- result.push(item);
49
- }
50
- }
51
-
52
- // 2. Categories sorted by order
53
- const sortedCategories = [...categories].sort((a, b) => a.order - b.order);
54
- for (const cat of sortedCategories) {
55
- const groupChildren: NavigationItem[] = [];
56
- for (const key of cat.itemKeys) {
57
- const item = itemsByKey.get(key);
58
- if (item && !PROTECTED_KEYS.has(key)) {
59
- groupChildren.push(item);
60
- }
61
- }
62
-
63
- if (groupChildren.length > 0) {
64
- result.push({
65
- key: `category-${cat.id}`,
66
- label: cat.label,
67
- type: 'group',
68
- children: groupChildren,
69
- });
70
- }
71
- }
72
-
73
- // 3. Divider + protected items last (settings)
74
- const protectedItems = items.filter(item => PROTECTED_KEYS.has(item.key));
75
- if (protectedItems.length > 0) {
76
- result.push({ key: '__settings-divider', label: '', type: 'divider' });
77
- for (const item of protectedItems) {
78
- result.push(item);
79
- }
80
- }
81
-
82
- return result;
83
- }
@@ -1,252 +0,0 @@
1
- /**
2
- * @module @kb-labs/studio-app/utils/commands
3
- * Centralized command registry for Command Palette
4
- */
5
-
6
- export type CommandCategory = 'recent' | 'navigation' | 'action' | 'plugin' | 'widget' | 'setting';
7
-
8
- export interface Command {
9
- id: string;
10
- title: string;
11
- description?: string;
12
- category: CommandCategory;
13
- path: string;
14
- /** Action to execute (alternative to path for navigation) */
15
- action?: () => void | Promise<void>;
16
- /** Keyboard shortcut */
17
- shortcut?: string;
18
- /** Tags for better search */
19
- tags?: string[];
20
- /** Priority for sorting (higher = shown first) */
21
- priority?: number;
22
- }
23
-
24
- export interface CommandsConfig {
25
- navigate: (path: string) => void;
26
- toggleTheme: () => void;
27
- refreshRegistry: () => Promise<void>;
28
- invalidateCache: () => Promise<void>;
29
- openQuickSearch: () => void;
30
- }
31
-
32
- /**
33
- * Get all available commands for Command Palette
34
- */
35
- export function getCommands(config: CommandsConfig): Command[] {
36
- const { toggleTheme, refreshRegistry, invalidateCache, openQuickSearch } = config;
37
-
38
- return [
39
- // ============================================
40
- // NAVIGATION COMMANDS
41
- // ============================================
42
- {
43
- id: 'nav-dashboard',
44
- title: 'Go to Dashboard',
45
- description: 'View main dashboard',
46
- category: 'navigation' as const,
47
- path: '/',
48
- tags: ['home', 'main', 'overview'],
49
- priority: 100,
50
- },
51
- {
52
- id: 'nav-observability',
53
- title: 'Go to Observability',
54
- description: 'View system observability',
55
- category: 'navigation' as const,
56
- path: '/observability',
57
- tags: ['monitoring', 'metrics', 'logs'],
58
- priority: 90,
59
- },
60
- {
61
- id: 'nav-observability-events',
62
- title: 'Go to System Events',
63
- description: 'View system event log',
64
- category: 'navigation' as const,
65
- path: '/observability/system-events',
66
- tags: ['events', 'logs', 'history'],
67
- priority: 85,
68
- },
69
- {
70
- id: 'nav-observability-registry',
71
- title: 'Go to Registry Browser',
72
- description: 'Browse plugin registry',
73
- category: 'navigation' as const,
74
- path: '/observability/registry',
75
- tags: ['plugins', 'registry', 'browse'],
76
- priority: 80,
77
- },
78
- {
79
- id: 'nav-settings',
80
- title: 'Go to Settings',
81
- description: 'Configure application settings',
82
- category: 'navigation' as const,
83
- path: '/settings',
84
- tags: ['preferences', 'config', 'configuration'],
85
- shortcut: 'Cmd+,',
86
- priority: 95,
87
- },
88
- {
89
- id: 'nav-settings-appearance',
90
- title: 'Go to Appearance Settings',
91
- description: 'Change theme and appearance',
92
- category: 'navigation' as const,
93
- path: '/settings?tab=appearance',
94
- tags: ['theme', 'dark mode', 'colors'],
95
- priority: 70,
96
- },
97
- {
98
- id: 'nav-settings-experimental',
99
- title: 'Go to Experimental Features',
100
- description: 'Enable experimental features',
101
- category: 'navigation' as const,
102
- path: '/settings?tab=experimental',
103
- tags: ['features', 'flags', 'beta'],
104
- priority: 65,
105
- },
106
- {
107
- id: 'nav-settings-developer',
108
- title: 'Go to Developer Tools',
109
- description: 'Developer settings and tools',
110
- category: 'navigation' as const,
111
- path: '/settings?tab=developer',
112
- tags: ['dev', 'debug', 'tools'],
113
- priority: 60,
114
- },
115
-
116
- // ============================================
117
- // ACTION COMMANDS
118
- // ============================================
119
- {
120
- id: 'action-toggle-theme',
121
- title: 'Toggle Dark Mode',
122
- description: 'Switch between light and dark theme',
123
- category: 'action' as const,
124
- path: '',
125
- action: toggleTheme,
126
- tags: ['theme', 'dark', 'light', 'appearance'],
127
- shortcut: 'Cmd+Shift+T',
128
- priority: 90,
129
- },
130
- {
131
- id: 'action-refresh-registry',
132
- title: 'Refresh Registry',
133
- description: 'Fetch latest registry data',
134
- category: 'action' as const,
135
- path: '',
136
- action: refreshRegistry,
137
- tags: ['refresh', 'reload', 'update'],
138
- shortcut: 'Cmd+R',
139
- priority: 85,
140
- },
141
- {
142
- id: 'action-invalidate-cache',
143
- title: 'Invalidate Cache & Re-discover',
144
- description: 'Force full plugin re-discovery',
145
- category: 'action' as const,
146
- path: '',
147
- action: invalidateCache,
148
- tags: ['cache', 'clear', 'discover', 'plugins'],
149
- priority: 80,
150
- },
151
- {
152
- id: 'action-quick-search',
153
- title: 'Open Quick Search',
154
- description: 'Search pages and plugins',
155
- category: 'action' as const,
156
- path: '',
157
- action: openQuickSearch,
158
- tags: ['search', 'find'],
159
- shortcut: 'Cmd+K',
160
- priority: 100,
161
- },
162
- {
163
- id: 'action-copy-registry-url',
164
- title: 'Copy Registry URL',
165
- description: 'Copy REST API registry endpoint',
166
- category: 'action' as const,
167
- path: '',
168
- action: () => {
169
- const url = `${window.location.origin}/api/v1/registry`;
170
- navigator.clipboard.writeText(url);
171
- },
172
- tags: ['copy', 'url', 'api'],
173
- priority: 50,
174
- },
175
-
176
- // ============================================
177
- // SETTING COMMANDS
178
- // ============================================
179
- {
180
- id: 'setting-appearance',
181
- title: 'Appearance Settings',
182
- description: 'Theme, colors, and visual preferences',
183
- category: 'setting' as const,
184
- path: '/settings?tab=appearance',
185
- tags: ['theme', 'dark mode', 'colors', 'visual'],
186
- priority: 70,
187
- },
188
- {
189
- id: 'setting-privacy',
190
- title: 'Data & Privacy Settings',
191
- description: 'Privacy and data management',
192
- category: 'setting' as const,
193
- path: '/settings?tab=privacy',
194
- tags: ['privacy', 'data', 'security'],
195
- priority: 65,
196
- },
197
- {
198
- id: 'setting-system',
199
- title: 'System Information',
200
- description: 'View system health and status',
201
- category: 'setting' as const,
202
- path: '/settings?tab=system',
203
- tags: ['health', 'status', 'info'],
204
- priority: 60,
205
- },
206
- {
207
- id: 'setting-developer',
208
- title: 'Developer Settings',
209
- description: 'Development tools and debugging',
210
- category: 'setting' as const,
211
- path: '/settings?tab=developer',
212
- tags: ['dev', 'debug', 'tools'],
213
- priority: 55,
214
- },
215
- ];
216
- }
217
-
218
- /**
219
- * Get recent commands from localStorage
220
- */
221
- export function getRecentCommands(): string[] {
222
- try {
223
- const stored = localStorage.getItem('kb-recent-commands');
224
- return stored ? JSON.parse(stored) : [];
225
- } catch {
226
- return [];
227
- }
228
- }
229
-
230
- /**
231
- * Save command to recent history
232
- */
233
- export function saveRecentCommand(commandId: string): void {
234
- try {
235
- const recent = getRecentCommands();
236
- const updated = [commandId, ...recent.filter((id) => id !== commandId)].slice(0, 5);
237
- localStorage.setItem('kb-recent-commands', JSON.stringify(updated));
238
- } catch (error) {
239
- console.error('Failed to save recent command:', error);
240
- }
241
- }
242
-
243
- /**
244
- * Clear recent commands history
245
- */
246
- export function clearRecentCommands(): void {
247
- try {
248
- localStorage.removeItem('kb-recent-commands');
249
- } catch (error) {
250
- console.error('Failed to clear recent commands:', error);
251
- }
252
- }
@@ -1,174 +0,0 @@
1
- /**
2
- * @module @kb-labs/studio-app/utils/export
3
- * Export utilities for widget data (CSV, JSON, PNG)
4
- */
5
-
6
- /**
7
- * Export data to CSV format
8
- */
9
- export function exportToCSV(
10
- data: unknown[],
11
- filename: string = 'export.csv',
12
- options?: {
13
- headers?: string[];
14
- delimiter?: string;
15
- }
16
- ): void {
17
- if (!data || data.length === 0) {
18
- console.warn('No data to export');
19
- return;
20
- }
21
-
22
- const delimiter = options?.delimiter || ',';
23
- const rows: string[] = [];
24
-
25
- // Get headers
26
- let headers: string[] = [];
27
- if (options?.headers && options.headers.length > 0) {
28
- headers = options.headers;
29
- } else if (data.length > 0) {
30
- // Auto-detect headers from first object
31
- const firstItem = data[0];
32
- if (typeof firstItem === 'object' && firstItem !== null) {
33
- headers = Object.keys(firstItem as Record<string, unknown>);
34
- }
35
- }
36
-
37
- // Add header row
38
- if (headers.length > 0) {
39
- rows.push(headers.map((h) => escapeCSVValue(h)).join(delimiter));
40
- }
41
-
42
- // Add data rows
43
- for (const item of data) {
44
- if (typeof item === 'object' && item !== null) {
45
- const values = headers.map((header) => {
46
- const value = (item as Record<string, unknown>)[header];
47
- return escapeCSVValue(value);
48
- });
49
- rows.push(values.join(delimiter));
50
- } else {
51
- rows.push(escapeCSVValue(item));
52
- }
53
- }
54
-
55
- // Create blob and download
56
- const csvContent = rows.join('\n');
57
- const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
58
- downloadBlob(blob, filename);
59
- }
60
-
61
- /**
62
- * Export data to JSON format
63
- */
64
- export function exportToJSON(
65
- data: unknown,
66
- filename: string = 'export.json',
67
- options?: {
68
- pretty?: boolean;
69
- }
70
- ): void {
71
- const jsonContent = options?.pretty
72
- ? JSON.stringify(data, null, 2)
73
- : JSON.stringify(data);
74
-
75
- const blob = new Blob([jsonContent], { type: 'application/json;charset=utf-8;' });
76
- downloadBlob(blob, filename);
77
- }
78
-
79
- /**
80
- * Export chart/canvas to PNG
81
- */
82
- export function exportToPNG(
83
- element: HTMLElement | HTMLCanvasElement,
84
- filename: string = 'export.png',
85
- options?: {
86
- backgroundColor?: string;
87
- scale?: number;
88
- }
89
- ): void {
90
- let canvas: HTMLCanvasElement;
91
-
92
- if (element instanceof HTMLCanvasElement) {
93
- canvas = element;
94
- } else {
95
- // Try to find canvas inside element
96
- const canvasElement = element.querySelector('canvas');
97
- if (!canvasElement) {
98
- console.error('No canvas element found for PNG export');
99
- return;
100
- }
101
- canvas = canvasElement;
102
- }
103
-
104
- // Create a new canvas for export
105
- const exportCanvas = document.createElement('canvas');
106
- const scale = options?.scale || 2; // Higher scale for better quality
107
- exportCanvas.width = canvas.width * scale;
108
- exportCanvas.height = canvas.height * scale;
109
-
110
- const ctx = exportCanvas.getContext('2d');
111
- if (!ctx) {
112
- console.error('Failed to get canvas context');
113
- return;
114
- }
115
-
116
- // Fill background if specified
117
- if (options?.backgroundColor) {
118
- ctx.fillStyle = options.backgroundColor;
119
- ctx.fillRect(0, 0, exportCanvas.width, exportCanvas.height);
120
- }
121
-
122
- // Draw original canvas scaled up
123
- ctx.drawImage(canvas, 0, 0, exportCanvas.width, exportCanvas.height);
124
-
125
- // Convert to blob and download
126
- exportCanvas.toBlob((blob) => {
127
- if (blob) {
128
- downloadBlob(blob, filename);
129
- } else {
130
- console.error('Failed to create PNG blob');
131
- }
132
- }, 'image/png');
133
- }
134
-
135
- /**
136
- * Escape CSV value (handle commas, quotes, newlines)
137
- */
138
- function escapeCSVValue(value: unknown): string {
139
- if (value === null || value === undefined) {
140
- return '';
141
- }
142
-
143
- const str = String(value);
144
-
145
- // If value contains delimiter, quote, or newline, wrap in quotes and escape quotes
146
- if (str.includes(',') || str.includes('"') || str.includes('\n') || str.includes('\r')) {
147
- return `"${str.replace(/"/g, '""')}"`;
148
- }
149
-
150
- return str;
151
- }
152
-
153
- /**
154
- * Download blob as file
155
- */
156
- function downloadBlob(blob: Blob, filename: string): void {
157
- const url = URL.createObjectURL(blob);
158
- const link = document.createElement('a');
159
- link.href = url;
160
- link.download = filename;
161
- document.body.appendChild(link);
162
- link.click();
163
- document.body.removeChild(link);
164
- URL.revokeObjectURL(url);
165
- }
166
-
167
- /**
168
- * Generate filename with timestamp
169
- */
170
- export function generateFilename(prefix: string, extension: string): string {
171
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
172
- return `${prefix}-${timestamp}.${extension}`;
173
- }
174
-