@kb-labs/studio-app 0.6.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.html +1 -0
- package/dist/main.1d68e922.js +522 -0
- package/dist/main.1d68e922.js.map +1 -0
- package/dist/main.80b70197.css +2 -0
- package/dist/main.80b70197.css.map +1 -0
- package/dist/mf-manifest.json +241 -0
- package/dist/mf-stats.json +271 -0
- package/package.json +56 -39
- package/server.js +68 -0
- package/.env.example +0 -10
- package/UI-KIT-COMPONENTS.md +0 -783
- package/UI-KIT-PLAN.md +0 -326
- package/eslint-rules/no-direct-antd-import.js +0 -151
- package/eslint.config.ts +0 -27
- package/index.html +0 -17
- package/postcss.config.js +0 -7
- package/public/favicon.ico +0 -0
- package/rspack.config.mjs +0 -118
- package/src/App.tsx +0 -46
- package/src/components/devtools/devtools-log-feed.module.css +0 -165
- package/src/components/devtools/devtools-log-feed.tsx +0 -300
- package/src/components/devtools/devtools-panel.module.css +0 -121
- package/src/components/devtools/devtools-panel.tsx +0 -115
- package/src/components/empty-state.tsx +0 -28
- package/src/components/error-boundary.tsx +0 -210
- package/src/components/health-banner.module.css +0 -103
- package/src/components/health-banner.tsx +0 -134
- package/src/components/health-indicator.tsx +0 -12
- package/src/components/page-header.tsx +0 -49
- package/src/components/page-transition.tsx +0 -24
- package/src/components/role-switcher.tsx +0 -148
- package/src/components/run-badge.tsx +0 -13
- package/src/components/ui/icons.tsx +0 -509
- package/src/components/ui/index.ts +0 -25
- package/src/components/ui/kb-config-provider.tsx +0 -130
- package/src/components/ui/kb-header.module.css +0 -51
- package/src/components/ui/kb-header.tsx +0 -112
- package/src/components/ui/kb-notification-bell.module.css +0 -103
- package/src/components/ui/kb-notification-bell.tsx +0 -199
- package/src/components/ui/kb-page-layout.tsx +0 -66
- package/src/components/ui/kb-quick-search.module.css +0 -86
- package/src/components/ui/kb-quick-search.tsx +0 -196
- package/src/components/ui/kb-sidebar.module.css +0 -47
- package/src/components/ui/kb-sidebar.tsx +0 -196
- package/src/components/ui/kb-stat-card.module.css +0 -21
- package/src/components/ui/kb-stat-card.tsx +0 -22
- package/src/components/ui/kb-stat-grid.tsx +0 -22
- package/src/components/ui/kb-status-bar.module.css +0 -49
- package/src/components/ui/kb-status-bar.tsx +0 -145
- package/src/components/ui/kb-system-health-indicator.tsx +0 -229
- package/src/components/ui/kb-theme-toggle.tsx +0 -42
- package/src/components/ui/theme-adapter.ts +0 -812
- package/src/components/ui/theme-transition-overlay.tsx +0 -70
- package/src/components/ui/utils.ts +0 -6
- package/src/components/widget-error-boundary.tsx +0 -172
- package/src/config/env.ts +0 -5
- package/src/config/feature-flags.ts +0 -482
- package/src/config/studio.config.schema.ts +0 -88
- package/src/config/studio.config.ts +0 -84
- package/src/env.d.ts +0 -23
- package/src/hooks/use-command-palette.ts +0 -6
- package/src/hooks/use-devtools-store.ts +0 -25
- package/src/hooks/use-feature-flags.ts +0 -101
- package/src/index.css +0 -10
- package/src/layouts/dashboard-grid.tsx +0 -122
- package/src/layouts/index.ts +0 -12
- package/src/layouts/two-pane.tsx +0 -134
- package/src/main.tsx +0 -15
- package/src/modules/analytics/components/analytics-daily-stats-chart.tsx +0 -257
- package/src/modules/analytics/components/analytics-date-range-picker.tsx +0 -121
- package/src/modules/analytics/pages/analytics-cache-page.tsx +0 -285
- package/src/modules/analytics/pages/analytics-embeddings-page.tsx +0 -274
- package/src/modules/analytics/pages/analytics-events-page.tsx +0 -425
- package/src/modules/analytics/pages/analytics-llm-page.tsx +0 -434
- package/src/modules/analytics/pages/analytics-overview-page.tsx +0 -336
- package/src/modules/analytics/pages/analytics-page.tsx +0 -20
- package/src/modules/analytics/pages/analytics-storage-page.tsx +0 -344
- package/src/modules/analytics/pages/analytics-vectorstore-page.tsx +0 -279
- package/src/modules/analytics/routes/index.tsx +0 -133
- package/src/modules/analytics/utils/formatters.test.ts +0 -148
- package/src/modules/analytics/utils/formatters.ts +0 -100
- package/src/modules/auth/pages/login-page.module.css +0 -113
- package/src/modules/auth/pages/login-page.tsx +0 -80
- package/src/modules/auth/routes/index.tsx +0 -24
- package/src/modules/dashboard/components/ActivityTimelineWidget.tsx +0 -199
- package/src/modules/dashboard/components/AiInsightsWidget.tsx +0 -358
- package/src/modules/dashboard/components/AnimatedMetricCard.css +0 -88
- package/src/modules/dashboard/components/AnimatedMetricCard.tsx +0 -125
- package/src/modules/dashboard/components/HeroMetricCard.css +0 -114
- package/src/modules/dashboard/components/HeroMetricCard.tsx +0 -152
- package/src/modules/dashboard/components/HeroMetricsWidget.tsx +0 -146
- package/src/modules/dashboard/components/SystemResourcesWidget.tsx +0 -197
- package/src/modules/dashboard/components/dashboard-empty.tsx +0 -22
- package/src/modules/dashboard/components/dashboard-kpis-widget.tsx +0 -59
- package/src/modules/dashboard/components/dashboard-kpis.tsx +0 -13
- package/src/modules/dashboard/components/dashboard-latency-percentiles-widget.tsx +0 -85
- package/src/modules/dashboard/components/dashboard-metrics-widget.tsx +0 -78
- package/src/modules/dashboard/components/dashboard-plugins-widget.tsx +0 -67
- package/src/modules/dashboard/components/dashboard-requests-widget.tsx +0 -62
- package/src/modules/dashboard/layouts/dashboard-layout.tsx +0 -16
- package/src/modules/dashboard/pages/ai-insights-page.tsx +0 -563
- package/src/modules/dashboard/pages/dashboard-animations.css +0 -317
- package/src/modules/dashboard/pages/dashboard-page.tsx +0 -13
- package/src/modules/dashboard/routes/index.tsx +0 -70
- package/src/modules/observability/pages/devkit-page.tsx +0 -263
- package/src/modules/observability/pages/incident-detail-page.tsx +0 -571
- package/src/modules/observability/pages/incidents-page.tsx +0 -370
- package/src/modules/observability/pages/log-detail-page.tsx +0 -508
- package/src/modules/observability/pages/logs-page.tsx +0 -1129
- package/src/modules/observability/pages/prometheus-metrics-page.tsx +0 -486
- package/src/modules/observability/pages/state-broker-page.tsx +0 -229
- package/src/modules/observability/pages/system-events-page.tsx +0 -255
- package/src/modules/observability/routes/index.tsx +0 -133
- package/src/modules/plugins/components/marketplace-card.tsx +0 -153
- package/src/modules/plugins/components/plugin-ai-assistant-modal.tsx +0 -374
- package/src/modules/plugins/components/plugin-card.tsx +0 -136
- package/src/modules/plugins/components/plugin-detail/capabilities-summary.tsx +0 -101
- package/src/modules/plugins/components/plugin-detail/cli-commands-table.tsx +0 -101
- package/src/modules/plugins/components/plugin-detail/index.ts +0 -7
- package/src/modules/plugins/components/plugin-detail/jobs-table.tsx +0 -64
- package/src/modules/plugins/components/plugin-detail/permissions/env-permissions.tsx +0 -30
- package/src/modules/plugins/components/plugin-detail/permissions/filesystem-permissions.tsx +0 -68
- package/src/modules/plugins/components/plugin-detail/permissions/index.ts +0 -6
- package/src/modules/plugins/components/plugin-detail/permissions/network-permissions.tsx +0 -43
- package/src/modules/plugins/components/plugin-detail/permissions/platform-services.tsx +0 -242
- package/src/modules/plugins/components/plugin-detail/permissions/resource-quotas.tsx +0 -96
- package/src/modules/plugins/components/plugin-detail/permissions/shell-permissions.tsx +0 -55
- package/src/modules/plugins/components/plugin-detail/permissions-view.tsx +0 -47
- package/src/modules/plugins/components/plugin-detail/plugin-header.tsx +0 -169
- package/src/modules/plugins/components/plugin-detail/rest-routes-table.tsx +0 -159
- package/src/modules/plugins/components/plugin-detail/workflows-table.tsx +0 -40
- package/src/modules/plugins/components/plugin-grid.tsx +0 -20
- package/src/modules/plugins/components/plugin-table.tsx +0 -178
- package/src/modules/plugins/pages/marketplace-page.tsx +0 -200
- package/src/modules/plugins/pages/plugin-detail-page.tsx +0 -1145
- package/src/modules/plugins/routes/index.tsx +0 -48
- package/src/modules/plugins/utils/index.ts +0 -1
- package/src/modules/plugins/utils/schema-helpers.ts +0 -21
- package/src/modules/settings/components/api-routes-viewer.tsx +0 -415
- package/src/modules/settings/components/appearance-settings.tsx +0 -200
- package/src/modules/settings/components/configuration-settings.tsx +0 -321
- package/src/modules/settings/components/data-privacy-settings.tsx +0 -111
- package/src/modules/settings/components/experimental-settings.tsx +0 -243
- package/src/modules/settings/components/navigation-settings.tsx +0 -198
- package/src/modules/settings/components/notifications-settings.tsx +0 -40
- package/src/modules/settings/pages/settings-page.tsx +0 -298
- package/src/modules/settings/routes/index.tsx +0 -47
- package/src/pages/README-assistant.md +0 -91
- package/src/pages/login-page.tsx +0 -177
- package/src/pages/not-found-page.tsx +0 -85
- package/src/providers/auth-provider.tsx +0 -40
- package/src/providers/command-palette-provider.tsx +0 -193
- package/src/providers/data-sources-provider.tsx +0 -27
- package/src/providers/devtools-provider.tsx +0 -72
- package/src/providers/navigation-items-provider.tsx +0 -38
- package/src/providers/registry-v2-provider.tsx +0 -93
- package/src/providers/settings-provider.tsx +0 -158
- package/src/router.tsx +0 -302
- package/src/routes/helpers.tsx +0 -25
- package/src/routes/plugin-page-v2.tsx +0 -52
- package/src/routes/types.ts +0 -18
- package/src/styles/antd-overrides.css +0 -211
- package/src/styles/base.css +0 -190
- package/src/styles/settings.css +0 -75
- package/src/styles/variables.css +0 -94
- package/src/utils/analytics.ts +0 -183
- package/src/utils/apply-navigation-categories.ts +0 -83
- package/src/utils/commands.ts +0 -252
- package/src/utils/export.ts +0 -174
- package/src/utils/format-date.ts +0 -166
- package/src/utils/logger.ts +0 -110
- package/tailwind.config.ts +0 -13
- package/tsconfig.json +0 -13
- package/vitest-setup.ts +0 -1
- /package/{public → dist}/favicon.svg +0 -0
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react';
|
|
2
|
-
import { devToolsStore } from '@kb-labs/studio-devtools';
|
|
3
|
-
import type { DevToolsChannel } from '@kb-labs/studio-devtools';
|
|
4
|
-
|
|
5
|
-
export interface UseDevToolsStoreReturn {
|
|
6
|
-
channels: readonly DevToolsChannel[];
|
|
7
|
-
clear(): void;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Subscribe to the DevTools store and re-render on any change.
|
|
12
|
-
* Uses the same forceUpdate pattern as ReactQueryDevtools.
|
|
13
|
-
*/
|
|
14
|
-
export function useDevToolsStore(): UseDevToolsStoreReturn {
|
|
15
|
-
const [, forceUpdate] = useState(0);
|
|
16
|
-
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
return devToolsStore.subscribe(() => { forceUpdate((n) => n + 1); });
|
|
19
|
-
}, []);
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
channels: devToolsStore.getChannels(),
|
|
23
|
-
clear: () => { devToolsStore.clear(); },
|
|
24
|
-
};
|
|
25
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module @kb-labs/studio-app/hooks/use-feature-flags
|
|
3
|
-
* Hook to access and toggle feature flags
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { useCallback, useMemo } from 'react';
|
|
7
|
-
import { useSettings } from '@/providers/settings-provider';
|
|
8
|
-
import type { FeatureId } from '@/config/feature-flags';
|
|
9
|
-
import { isFeatureEnabled as isEnabled, areDependenciesMet } from '@/config/feature-flags';
|
|
10
|
-
|
|
11
|
-
export interface UseFeatureFlagsReturn {
|
|
12
|
-
/** Check if a feature is enabled */
|
|
13
|
-
isEnabled: (featureId: FeatureId) => boolean;
|
|
14
|
-
/** Toggle a feature on/off */
|
|
15
|
-
toggleFeature: (featureId: FeatureId) => void;
|
|
16
|
-
/** Enable a feature */
|
|
17
|
-
enableFeature: (featureId: FeatureId) => void;
|
|
18
|
-
/** Disable a feature */
|
|
19
|
-
disableFeature: (featureId: FeatureId) => void;
|
|
20
|
-
/** Get all enabled feature IDs */
|
|
21
|
-
enabledFeatures: FeatureId[];
|
|
22
|
-
/** Check if feature dependencies are met */
|
|
23
|
-
areDependenciesMet: (featureId: FeatureId) => boolean;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function useFeatureFlags(): UseFeatureFlagsReturn {
|
|
27
|
-
const { settings, updateSettings } = useSettings();
|
|
28
|
-
const enabledFeatures = useMemo(() => settings.experimental?.enabledFeatures ?? [], [settings.experimental?.enabledFeatures]);
|
|
29
|
-
|
|
30
|
-
// Create a preferences map for efficient lookup
|
|
31
|
-
const preferences = useMemo(() => {
|
|
32
|
-
const map: Record<FeatureId, boolean> = {} as Record<FeatureId, boolean>;
|
|
33
|
-
enabledFeatures.forEach((id) => {
|
|
34
|
-
map[id] = true;
|
|
35
|
-
});
|
|
36
|
-
return map;
|
|
37
|
-
}, [enabledFeatures]);
|
|
38
|
-
|
|
39
|
-
const isFeatureEnabled = useCallback(
|
|
40
|
-
(featureId: FeatureId): boolean => {
|
|
41
|
-
return isEnabled(featureId, preferences);
|
|
42
|
-
},
|
|
43
|
-
[preferences]
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
const toggleFeature = useCallback(
|
|
47
|
-
(featureId: FeatureId) => {
|
|
48
|
-
const currentlyEnabled = enabledFeatures.includes(featureId);
|
|
49
|
-
const newFeatures = currentlyEnabled
|
|
50
|
-
? enabledFeatures.filter((id) => id !== featureId)
|
|
51
|
-
: [...enabledFeatures, featureId];
|
|
52
|
-
|
|
53
|
-
updateSettings({
|
|
54
|
-
experimental: {
|
|
55
|
-
enabledFeatures: newFeatures,
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
},
|
|
59
|
-
[enabledFeatures, updateSettings]
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
const enableFeature = useCallback(
|
|
63
|
-
(featureId: FeatureId) => {
|
|
64
|
-
if (!enabledFeatures.includes(featureId)) {
|
|
65
|
-
updateSettings({
|
|
66
|
-
experimental: {
|
|
67
|
-
enabledFeatures: [...enabledFeatures, featureId],
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
[enabledFeatures, updateSettings]
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
const disableFeature = useCallback(
|
|
76
|
-
(featureId: FeatureId) => {
|
|
77
|
-
updateSettings({
|
|
78
|
-
experimental: {
|
|
79
|
-
enabledFeatures: enabledFeatures.filter((id) => id !== featureId),
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
},
|
|
83
|
-
[enabledFeatures, updateSettings]
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
const checkDependencies = useCallback(
|
|
87
|
-
(featureId: FeatureId): boolean => {
|
|
88
|
-
return areDependenciesMet(featureId, preferences);
|
|
89
|
-
},
|
|
90
|
-
[preferences]
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
isEnabled: isFeatureEnabled,
|
|
95
|
-
toggleFeature,
|
|
96
|
-
enableFeature,
|
|
97
|
-
disableFeature,
|
|
98
|
-
enabledFeatures,
|
|
99
|
-
areDependenciesMet: checkDependencies,
|
|
100
|
-
};
|
|
101
|
-
}
|
package/src/index.css
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/* Theme variables and base styles - must be first */
|
|
2
|
-
@import './styles/variables.css';
|
|
3
|
-
@import './styles/base.css';
|
|
4
|
-
@import './styles/antd-overrides.css';
|
|
5
|
-
@import './styles/settings.css';
|
|
6
|
-
|
|
7
|
-
@tailwind base;
|
|
8
|
-
@tailwind components;
|
|
9
|
-
@tailwind utilities;
|
|
10
|
-
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module @kb-labs/studio-app/layouts/DashboardGrid
|
|
3
|
-
* Dashboard Grid layout - responsive CSS Grid using design tokens
|
|
4
|
-
*
|
|
5
|
-
* Refactored to use spacing tokens and remove inline styles where possible.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import * as React from 'react';
|
|
9
|
-
import { spacing } from '@kb-labs/studio-ui-core';
|
|
10
|
-
import { useUITheme } from '@kb-labs/studio-ui-kit';
|
|
11
|
-
|
|
12
|
-
export interface DashboardGridProps {
|
|
13
|
-
children: React.ReactNode;
|
|
14
|
-
cols?: {
|
|
15
|
-
sm: number;
|
|
16
|
-
md: number;
|
|
17
|
-
lg: number;
|
|
18
|
-
};
|
|
19
|
-
rowHeight?: number;
|
|
20
|
-
gap?: number;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function DashboardGrid({
|
|
24
|
-
children,
|
|
25
|
-
cols = { sm: 4, md: 8, lg: 12 },
|
|
26
|
-
rowHeight = 8,
|
|
27
|
-
gap = 16
|
|
28
|
-
}: DashboardGridProps) {
|
|
29
|
-
const { token } = useUITheme();
|
|
30
|
-
const childrenArray = React.Children.toArray(children);
|
|
31
|
-
|
|
32
|
-
// Use spacing tokens for gap if available
|
|
33
|
-
const gridGap = gap === 16 ? spacing[4] : gap === 8 ? spacing[2] : `${gap}px`;
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<div
|
|
37
|
-
className="widget-dashboard-grid"
|
|
38
|
-
style={
|
|
39
|
-
{
|
|
40
|
-
'--cols-sm': cols.sm,
|
|
41
|
-
'--cols-md': cols.md,
|
|
42
|
-
'--cols-lg': cols.lg,
|
|
43
|
-
'--row-height': `${rowHeight * 8}px`,
|
|
44
|
-
'--gap': gridGap,
|
|
45
|
-
'--border-color': token.colorBorder,
|
|
46
|
-
} as React.CSSProperties
|
|
47
|
-
}
|
|
48
|
-
>
|
|
49
|
-
{childrenArray.map((child, index) => {
|
|
50
|
-
// Extract layoutHint from child props if available
|
|
51
|
-
const layoutHint = (child as React.ReactElement)?.props?.layoutHint || { w: 4, h: 4 };
|
|
52
|
-
const { w, h, minW, minH, height } = layoutHint;
|
|
53
|
-
|
|
54
|
-
// Calculate height based on layoutHint.height
|
|
55
|
-
let itemHeight: string | undefined;
|
|
56
|
-
let itemMaxHeight: string | undefined;
|
|
57
|
-
let itemMinHeight: string | undefined;
|
|
58
|
-
|
|
59
|
-
if (height === 'fit-content') {
|
|
60
|
-
itemHeight = 'fit-content';
|
|
61
|
-
} else if (typeof height === 'number') {
|
|
62
|
-
itemHeight = `${height}px`;
|
|
63
|
-
} else if (height === 'auto' || height === undefined) {
|
|
64
|
-
// Auto height: use grid rows but allow content to expand
|
|
65
|
-
itemMinHeight = minH ? `${minH * rowHeight * 8}px` : `${h * rowHeight * 8}px`;
|
|
66
|
-
} else {
|
|
67
|
-
// Fallback: use grid-based height calculation
|
|
68
|
-
itemMinHeight = minH ? `${minH * rowHeight * 8}px` : `${h * rowHeight * 8}px`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return (
|
|
72
|
-
<div
|
|
73
|
-
key={index}
|
|
74
|
-
className="widget-dashboard-grid__item"
|
|
75
|
-
style={
|
|
76
|
-
{
|
|
77
|
-
gridColumn: `span ${w}`,
|
|
78
|
-
gridRow: height === 'fit-content' ? 'span 1' : `span ${h}`,
|
|
79
|
-
minWidth: minW ? `${minW * (100 / cols.lg)}%` : undefined,
|
|
80
|
-
minHeight: itemMinHeight,
|
|
81
|
-
height: itemHeight,
|
|
82
|
-
maxHeight: itemMaxHeight,
|
|
83
|
-
} as React.CSSProperties
|
|
84
|
-
}
|
|
85
|
-
>
|
|
86
|
-
{child}
|
|
87
|
-
</div>
|
|
88
|
-
);
|
|
89
|
-
})}
|
|
90
|
-
<style>{`
|
|
91
|
-
.widget-dashboard-grid {
|
|
92
|
-
display: grid;
|
|
93
|
-
grid-template-columns: repeat(var(--cols-sm), 1fr);
|
|
94
|
-
gap: var(--gap);
|
|
95
|
-
grid-auto-rows: minmax(var(--row-height), auto);
|
|
96
|
-
align-items: start;
|
|
97
|
-
}
|
|
98
|
-
@media (min-width: 768px) {
|
|
99
|
-
.widget-dashboard-grid {
|
|
100
|
-
grid-template-columns: repeat(var(--cols-md), 1fr);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
@media (min-width: 1024px) {
|
|
104
|
-
.widget-dashboard-grid {
|
|
105
|
-
grid-template-columns: repeat(var(--cols-lg), 1fr);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
.widget-dashboard-grid__item {
|
|
109
|
-
min-height: var(--row-height);
|
|
110
|
-
display: flex;
|
|
111
|
-
flex-direction: column;
|
|
112
|
-
}
|
|
113
|
-
.widget-dashboard-grid__item > * {
|
|
114
|
-
flex: 1;
|
|
115
|
-
min-height: 0;
|
|
116
|
-
}
|
|
117
|
-
`}</style>
|
|
118
|
-
</div>
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
package/src/layouts/index.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module @kb-labs/studio-app/layouts
|
|
3
|
-
* Layout components
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export { DashboardGrid } from './dashboard-grid';
|
|
7
|
-
export type { DashboardGridProps } from './dashboard-grid';
|
|
8
|
-
|
|
9
|
-
export { TwoPane } from './two-pane';
|
|
10
|
-
export type { TwoPaneProps } from './two-pane';
|
|
11
|
-
|
|
12
|
-
|
package/src/layouts/two-pane.tsx
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module @kb-labs/studio-app/layouts/TwoPane
|
|
3
|
-
* Two Pane layout - flex-based with optional resizer using design tokens
|
|
4
|
-
*
|
|
5
|
-
* Refactored to use Ant Design theme tokens for colors and transitions.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import * as React from 'react';
|
|
9
|
-
import { useUITheme } from '@kb-labs/studio-ui-kit';
|
|
10
|
-
|
|
11
|
-
export interface TwoPaneProps {
|
|
12
|
-
left: React.ReactNode;
|
|
13
|
-
right: React.ReactNode;
|
|
14
|
-
leftWidth?: string;
|
|
15
|
-
resizable?: boolean;
|
|
16
|
-
minLeftWidth?: string;
|
|
17
|
-
maxLeftWidth?: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function TwoPane({
|
|
21
|
-
left,
|
|
22
|
-
right,
|
|
23
|
-
leftWidth = '50%',
|
|
24
|
-
resizable = false,
|
|
25
|
-
minLeftWidth = '20%',
|
|
26
|
-
maxLeftWidth = '80%',
|
|
27
|
-
}: TwoPaneProps) {
|
|
28
|
-
const { token } = useUITheme();
|
|
29
|
-
const [leftWidthState, setLeftWidthState] = React.useState(leftWidth);
|
|
30
|
-
const [isResizing, setIsResizing] = React.useState(false);
|
|
31
|
-
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
32
|
-
|
|
33
|
-
const handleMouseDown = () => {
|
|
34
|
-
if (!resizable) {return;}
|
|
35
|
-
setIsResizing(true);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const handleMouseMove = React.useCallback(
|
|
39
|
-
(e: MouseEvent) => {
|
|
40
|
-
if (!isResizing || !containerRef.current) {return;}
|
|
41
|
-
|
|
42
|
-
const container = containerRef.current;
|
|
43
|
-
const rect = container.getBoundingClientRect();
|
|
44
|
-
const newLeftWidth = ((e.clientX - rect.left) / rect.width) * 100;
|
|
45
|
-
|
|
46
|
-
// Apply min/max constraints
|
|
47
|
-
const min = parseFloat(minLeftWidth);
|
|
48
|
-
const max = parseFloat(maxLeftWidth);
|
|
49
|
-
const clamped = Math.max(min, Math.min(max, newLeftWidth));
|
|
50
|
-
|
|
51
|
-
setLeftWidthState(`${clamped}%`);
|
|
52
|
-
},
|
|
53
|
-
[isResizing, minLeftWidth, maxLeftWidth]
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const handleMouseUp = () => {
|
|
57
|
-
setIsResizing(false);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
React.useEffect(() => {
|
|
61
|
-
if (isResizing) {
|
|
62
|
-
document.addEventListener('mousemove', handleMouseMove);
|
|
63
|
-
document.addEventListener('mouseup', handleMouseUp);
|
|
64
|
-
return () => {
|
|
65
|
-
document.removeEventListener('mousemove', handleMouseMove);
|
|
66
|
-
document.removeEventListener('mouseup', handleMouseUp);
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
}, [isResizing, handleMouseMove]);
|
|
70
|
-
|
|
71
|
-
return (
|
|
72
|
-
<div
|
|
73
|
-
className="widget-two-pane"
|
|
74
|
-
ref={containerRef}
|
|
75
|
-
style={
|
|
76
|
-
{
|
|
77
|
-
'--border-color': token.colorBorder,
|
|
78
|
-
'--link-color': token.colorLink,
|
|
79
|
-
'--transition-duration': `${token.motionDurationMid}`,
|
|
80
|
-
} as React.CSSProperties
|
|
81
|
-
}
|
|
82
|
-
>
|
|
83
|
-
<div
|
|
84
|
-
className="widget-two-pane__left"
|
|
85
|
-
style={
|
|
86
|
-
{
|
|
87
|
-
width: leftWidthState,
|
|
88
|
-
minWidth: minLeftWidth,
|
|
89
|
-
maxWidth: maxLeftWidth,
|
|
90
|
-
} as React.CSSProperties
|
|
91
|
-
}
|
|
92
|
-
>
|
|
93
|
-
{left}
|
|
94
|
-
</div>
|
|
95
|
-
{resizable && (
|
|
96
|
-
<div
|
|
97
|
-
className="widget-two-pane__resizer"
|
|
98
|
-
onMouseDown={handleMouseDown}
|
|
99
|
-
data-resizing={isResizing}
|
|
100
|
-
/>
|
|
101
|
-
)}
|
|
102
|
-
<div className="widget-two-pane__right">{right}</div>
|
|
103
|
-
<style>{`
|
|
104
|
-
.widget-two-pane {
|
|
105
|
-
display: flex;
|
|
106
|
-
height: 100%;
|
|
107
|
-
width: 100%;
|
|
108
|
-
}
|
|
109
|
-
.widget-two-pane__left {
|
|
110
|
-
flex-shrink: 0;
|
|
111
|
-
overflow: auto;
|
|
112
|
-
border-right: 1px solid var(--border-color);
|
|
113
|
-
}
|
|
114
|
-
.widget-two-pane__resizer {
|
|
115
|
-
width: 4px;
|
|
116
|
-
background: var(--border-color);
|
|
117
|
-
cursor: col-resize;
|
|
118
|
-
flex-shrink: 0;
|
|
119
|
-
transition: background var(--transition-duration);
|
|
120
|
-
}
|
|
121
|
-
.widget-two-pane__resizer:hover,
|
|
122
|
-
.widget-two-pane__resizer[data-resizing="true"] {
|
|
123
|
-
background: var(--link-color);
|
|
124
|
-
}
|
|
125
|
-
.widget-two-pane__right {
|
|
126
|
-
flex: 1;
|
|
127
|
-
overflow: auto;
|
|
128
|
-
}
|
|
129
|
-
`}</style>
|
|
130
|
-
</div>
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
package/src/main.tsx
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import ReactDOM from 'react-dom/client';
|
|
3
|
-
import { App } from './App';
|
|
4
|
-
import '@kb-labs/studio-ui-kit/dist/index.css';
|
|
5
|
-
import { registerIconRenderer } from '@kb-labs/studio-ui-kit';
|
|
6
|
-
import { renderIcon } from './components/ui/icons';
|
|
7
|
-
import './index.css';
|
|
8
|
-
|
|
9
|
-
registerIconRenderer(renderIcon);
|
|
10
|
-
|
|
11
|
-
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
12
|
-
<React.StrictMode>
|
|
13
|
-
<App />
|
|
14
|
-
</React.StrictMode>
|
|
15
|
-
);
|
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
import { UIText, UICard, UIAreaChart, useChartColors } from '@kb-labs/studio-ui-kit';
|
|
3
|
-
import type { DailyStats } from '@kb-labs/studio-data-client';
|
|
4
|
-
import dayjs from 'dayjs';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Configuration for chart metrics
|
|
8
|
-
*/
|
|
9
|
-
export interface ChartMetricConfig {
|
|
10
|
-
/**
|
|
11
|
-
* Metric key from DailyStats.metrics
|
|
12
|
-
*/
|
|
13
|
-
key: string;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Display label for the metric
|
|
17
|
-
*/
|
|
18
|
-
label: string;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Optional transformer function to convert raw value to display value
|
|
22
|
-
* Example: (v) => v / 1000 to convert tokens to K tokens
|
|
23
|
-
*/
|
|
24
|
-
transform?: (value: number) => number;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Optional formatter for tooltip
|
|
28
|
-
*/
|
|
29
|
-
format?: (value: number) => string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface AnalyticsDailyStatsChartProps {
|
|
33
|
-
/**
|
|
34
|
-
* Daily statistics data
|
|
35
|
-
*/
|
|
36
|
-
data: DailyStats[] | undefined;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Loading state
|
|
40
|
-
*/
|
|
41
|
-
loading?: boolean;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Chart title
|
|
45
|
-
*/
|
|
46
|
-
title: string;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Metrics to display on the chart
|
|
50
|
-
* Each metric will be shown as a separate line
|
|
51
|
-
*/
|
|
52
|
-
metrics: ChartMetricConfig[];
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Optional card style
|
|
56
|
-
*/
|
|
57
|
-
style?: React.CSSProperties;
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Chart height in pixels
|
|
61
|
-
*/
|
|
62
|
-
height?: number;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Reusable daily statistics chart component
|
|
67
|
-
*
|
|
68
|
-
* Displays time-series chart with multiple metrics for analytics pages.
|
|
69
|
-
* Used across LLM, Embeddings, VectorStore, Cache, and Storage analytics.
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* ```tsx
|
|
73
|
-
* <AnalyticsDailyStatsChart
|
|
74
|
-
* data={dailyStats}
|
|
75
|
-
* loading={isLoading}
|
|
76
|
-
* title="Daily LLM Usage Trend"
|
|
77
|
-
* metrics={[
|
|
78
|
-
* { key: 'count', label: 'Requests' },
|
|
79
|
-
* { key: 'totalTokens', label: 'Tokens (K)', transform: (v) => v / 1000 },
|
|
80
|
-
* { key: 'totalCost', label: 'Cost ($)', format: (v) => `$${v.toFixed(2)}` },
|
|
81
|
-
* ]}
|
|
82
|
-
* />
|
|
83
|
-
* ```
|
|
84
|
-
*/
|
|
85
|
-
export function AnalyticsDailyStatsChart({
|
|
86
|
-
data,
|
|
87
|
-
loading = false,
|
|
88
|
-
title,
|
|
89
|
-
metrics,
|
|
90
|
-
style,
|
|
91
|
-
height = 350,
|
|
92
|
-
}: AnalyticsDailyStatsChartProps) {
|
|
93
|
-
const palette = useChartColors();
|
|
94
|
-
|
|
95
|
-
// Memoize chart colors to ensure stability across renders
|
|
96
|
-
const chartColors = useMemo(() => {
|
|
97
|
-
console.log('[useMemo] Input:', {
|
|
98
|
-
paletteColors: palette.colors,
|
|
99
|
-
isArray: Array.isArray(palette.colors),
|
|
100
|
-
length: palette.colors?.length,
|
|
101
|
-
first3: palette.colors.slice(0, 3),
|
|
102
|
-
metricsLength: metrics.length,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
const result = palette.colors.slice(0, metrics.length);
|
|
106
|
-
|
|
107
|
-
console.log('[useMemo] Output:', {
|
|
108
|
-
result,
|
|
109
|
-
isArray: Array.isArray(result),
|
|
110
|
-
length: result.length,
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
return result;
|
|
114
|
-
}, [palette.colors, metrics.length]);
|
|
115
|
-
|
|
116
|
-
console.log('[AnalyticsDailyStatsChart] Colors:', {
|
|
117
|
-
metricsCount: metrics.length,
|
|
118
|
-
chartColors,
|
|
119
|
-
paletteColors: palette.colors,
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// Transform data for chart
|
|
123
|
-
const chartData =
|
|
124
|
-
data?.flatMap((stat) => {
|
|
125
|
-
const rows: Array<{ date: string; category: string; value: number }> = [];
|
|
126
|
-
|
|
127
|
-
for (const metric of metrics) {
|
|
128
|
-
let value: number;
|
|
129
|
-
|
|
130
|
-
if (metric.key === 'count') {
|
|
131
|
-
// Special case: count is top-level field
|
|
132
|
-
value = stat.count;
|
|
133
|
-
} else {
|
|
134
|
-
// Extract from metrics object
|
|
135
|
-
value = stat.metrics?.[metric.key] ?? 0;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Apply transformation if provided
|
|
139
|
-
if (metric.transform) {
|
|
140
|
-
value = metric.transform(value);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
rows.push({
|
|
144
|
-
date: dayjs(stat.date).format('YYYY-MM-DD'), // Ensure consistent date format
|
|
145
|
-
category: metric.label,
|
|
146
|
-
value,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return rows;
|
|
151
|
-
}) ?? [];
|
|
152
|
-
|
|
153
|
-
console.log('[AnalyticsDailyStatsChart] Chart data:', {
|
|
154
|
-
dataLength: chartData.length,
|
|
155
|
-
uniqueCategories: [...new Set(chartData.map(d => d.category))],
|
|
156
|
-
sampleData: chartData.slice(0, 3),
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const cardStyle = { marginTop: 16, ...style } as any;
|
|
161
|
-
return (
|
|
162
|
-
<UICard title={title} style={cardStyle}>
|
|
163
|
-
{loading && (
|
|
164
|
-
<div style={{ textAlign: 'center', padding: '40px 0' }}>
|
|
165
|
-
<UIText color="secondary">Loading chart data...</UIText>
|
|
166
|
-
</div>
|
|
167
|
-
)}
|
|
168
|
-
|
|
169
|
-
{!loading && chartData.length > 0 && (
|
|
170
|
-
<div>
|
|
171
|
-
{/* Custom Legend */}
|
|
172
|
-
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 12, gap: 16 }}>
|
|
173
|
-
{metrics.map((metric, index) => (
|
|
174
|
-
<div key={metric.label} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
|
175
|
-
<span
|
|
176
|
-
style={{
|
|
177
|
-
display: 'inline-block',
|
|
178
|
-
width: 10,
|
|
179
|
-
height: 10,
|
|
180
|
-
borderRadius: '50%',
|
|
181
|
-
backgroundColor: chartColors[index % chartColors.length],
|
|
182
|
-
}}
|
|
183
|
-
/>
|
|
184
|
-
<span style={{ fontSize: 13, fontWeight: 500 }}>{metric.label}</span>
|
|
185
|
-
</div>
|
|
186
|
-
))}
|
|
187
|
-
</div>
|
|
188
|
-
|
|
189
|
-
<UIAreaChart
|
|
190
|
-
data={chartData}
|
|
191
|
-
xField="date"
|
|
192
|
-
yField="value"
|
|
193
|
-
colorField="category"
|
|
194
|
-
colors={chartColors}
|
|
195
|
-
height={height}
|
|
196
|
-
axis={{
|
|
197
|
-
x: {
|
|
198
|
-
label: {
|
|
199
|
-
autoRotate: false,
|
|
200
|
-
},
|
|
201
|
-
},
|
|
202
|
-
y: {
|
|
203
|
-
label: {
|
|
204
|
-
formatter: (v: string) => {
|
|
205
|
-
const num = Number(v);
|
|
206
|
-
if (num >= 1000000) {return `${(num / 1000000).toFixed(1)}M`;}
|
|
207
|
-
if (num >= 1000) {return `${(num / 1000).toFixed(1)}K`;}
|
|
208
|
-
return num.toLocaleString();
|
|
209
|
-
},
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
}}
|
|
213
|
-
style={{
|
|
214
|
-
fillOpacity: 0.3,
|
|
215
|
-
}}
|
|
216
|
-
legend={false}
|
|
217
|
-
tooltip={{
|
|
218
|
-
title: (d: any) => d.date,
|
|
219
|
-
items: [
|
|
220
|
-
(d: any) => {
|
|
221
|
-
const metric = metrics.find((m) => m.label === d.category);
|
|
222
|
-
const metricIndex = metrics.findIndex((m) => m.label === d.category);
|
|
223
|
-
let formattedValue = d.value?.toLocaleString() || '0';
|
|
224
|
-
|
|
225
|
-
if (metric?.format && d.value != null) {
|
|
226
|
-
formattedValue = metric.format(d.value);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const tooltipColor = chartColors[metricIndex >= 0 ? metricIndex : 0];
|
|
230
|
-
|
|
231
|
-
console.log('[Tooltip] Color:', {
|
|
232
|
-
category: d.category,
|
|
233
|
-
metricIndex,
|
|
234
|
-
tooltipColor,
|
|
235
|
-
chartColors,
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
return {
|
|
239
|
-
name: d.category,
|
|
240
|
-
value: formattedValue,
|
|
241
|
-
color: tooltipColor,
|
|
242
|
-
};
|
|
243
|
-
},
|
|
244
|
-
],
|
|
245
|
-
}}
|
|
246
|
-
/>
|
|
247
|
-
</div>
|
|
248
|
-
)}
|
|
249
|
-
|
|
250
|
-
{!loading && chartData.length === 0 && (
|
|
251
|
-
<div style={{ textAlign: 'center', padding: '40px 0' }}>
|
|
252
|
-
<UIText color="secondary">No data available for the selected date range</UIText>
|
|
253
|
-
</div>
|
|
254
|
-
)}
|
|
255
|
-
</UICard>
|
|
256
|
-
);
|
|
257
|
-
}
|