ai-design-system 0.1.66 → 0.1.67
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/components/composites/AppHeader/AppHeader.tsx +11 -0
- package/components/composites/AppHeader/interfaces.ts +1 -1
- package/components/composites/DashboardChart/DashboardChart.tsx +65 -41
- package/components/composites/DashboardChart/index.ts +1 -1
- package/components/composites/EvalSessionDetailsPanel/EvalSessionDetailsPanel.stories.tsx +35 -0
- package/components/composites/EvalSessionDetailsPanel/EvalSessionDetailsPanel.tsx +89 -0
- package/components/composites/EvalSessionDetailsPanel/index.ts +2 -0
- package/components/composites/index.ts +4 -0
- package/components/features/DashboardFeature/DashboardFeature.tsx +15 -6
- package/components/features/DashboardFeature/useDashboardFeature.d.ts +1 -1
- package/components/features/EvalDashboardFeature/EvalDashboardFeature.behaviors.stories.tsx +40 -0
- package/components/features/EvalDashboardFeature/EvalDashboardFeature.mocks.ts +25 -0
- package/components/features/EvalDashboardFeature/EvalDashboardFeature.stories.tsx +34 -0
- package/components/features/EvalDashboardFeature/EvalDashboardFeature.tsx +182 -0
- package/components/features/EvalDashboardFeature/README.md +33 -0
- package/components/features/EvalDashboardFeature/index.ts +10 -0
- package/components/features/EvalDashboardFeature/useEvalDashboardFeature.d.ts +43 -0
- package/components/features/EvalDashboardFeature/useEvalDashboardFeature.mock.ts +22 -0
- package/components/features/index.ts +6 -0
- package/dist/index.cjs +235 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +24 -0
- package/dist/index.d.ts +109 -29
- package/dist/index.js +235 -40
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -33,6 +33,17 @@ export const AppHeader = React.memo<AppHeaderProps>(({
|
|
|
33
33
|
: title
|
|
34
34
|
)}
|
|
35
35
|
{chatToggleProps && <ChatToggleButton {...chatToggleProps} />}
|
|
36
|
+
{tabsPosition === 'left' && tabs && tabs.length > 0 && (
|
|
37
|
+
<Tabs defaultValue={defaultTab || tabs[0]?.value} onValueChange={onTabChange} className="ml-2">
|
|
38
|
+
<TabsList>
|
|
39
|
+
{tabs.map((tab) => (
|
|
40
|
+
<TabsTrigger key={tab.value} value={tab.value}>
|
|
41
|
+
{tab.label}
|
|
42
|
+
</TabsTrigger>
|
|
43
|
+
))}
|
|
44
|
+
</TabsList>
|
|
45
|
+
</Tabs>
|
|
46
|
+
)}
|
|
36
47
|
{workflowSwitcherProps && <WorkflowSwitcher {...workflowSwitcherProps} />}
|
|
37
48
|
</div>
|
|
38
49
|
|
|
@@ -13,7 +13,7 @@ export interface AppHeaderProps {
|
|
|
13
13
|
tabs?: TabItem[];
|
|
14
14
|
defaultTab?: string;
|
|
15
15
|
onTabChange?: (value: string) => void;
|
|
16
|
-
tabsPosition?: 'center' | 'right';
|
|
16
|
+
tabsPosition?: 'left' | 'center' | 'right';
|
|
17
17
|
className?: string;
|
|
18
18
|
showSidebarToggle?: boolean;
|
|
19
19
|
showTitle?: boolean;
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
SelectValue,
|
|
23
23
|
} from "@/components/primitives/Select"
|
|
24
24
|
import { ToggleGroup, ToggleGroupItem } from "@/components/primitives/ToggleGroup"
|
|
25
|
+
import { cn } from "@/lib/utils"
|
|
25
26
|
|
|
26
27
|
export interface DashboardChartPoint {
|
|
27
28
|
date: string
|
|
@@ -29,15 +30,36 @@ export interface DashboardChartPoint {
|
|
|
29
30
|
mobile: number
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
export type DashboardChartTimeRange =
|
|
33
|
+
export type DashboardChartTimeRange = string
|
|
33
34
|
|
|
34
35
|
export interface DashboardChartProps {
|
|
35
36
|
series: DashboardChartPoint[]
|
|
36
37
|
onTimeRangeChange?: (range: DashboardChartTimeRange) => void
|
|
38
|
+
title: string
|
|
39
|
+
description: string
|
|
40
|
+
shortDescription: string
|
|
41
|
+
timeRanges: { value: string, label: string, shortLabel?: string }[]
|
|
42
|
+
desktopLabel: string
|
|
43
|
+
mobileLabel: string
|
|
44
|
+
showMobile: boolean
|
|
45
|
+
className?: string
|
|
46
|
+
chartClassName?: string
|
|
37
47
|
}
|
|
38
48
|
|
|
39
|
-
export const DashboardChart = React.memo<DashboardChartProps>(({
|
|
40
|
-
|
|
49
|
+
export const DashboardChart = React.memo<DashboardChartProps>(({
|
|
50
|
+
series,
|
|
51
|
+
onTimeRangeChange,
|
|
52
|
+
title,
|
|
53
|
+
description,
|
|
54
|
+
shortDescription,
|
|
55
|
+
timeRanges,
|
|
56
|
+
desktopLabel,
|
|
57
|
+
mobileLabel,
|
|
58
|
+
showMobile,
|
|
59
|
+
className,
|
|
60
|
+
chartClassName
|
|
61
|
+
}) => {
|
|
62
|
+
const [timeRange, setTimeRange] = React.useState<DashboardChartTimeRange>(timeRanges[0]?.value)
|
|
41
63
|
|
|
42
64
|
const handleTimeRangeChange = React.useCallback(
|
|
43
65
|
(range: DashboardChartTimeRange) => {
|
|
@@ -48,29 +70,31 @@ export const DashboardChart = React.memo<DashboardChartProps>(({ series, onTimeR
|
|
|
48
70
|
)
|
|
49
71
|
|
|
50
72
|
const filteredSeries = React.useMemo(() => {
|
|
51
|
-
const referenceDate = series.length > 0 ?
|
|
73
|
+
const referenceDate = series.length > 0 ? series[series.length - 1].date : new Date().toISOString()
|
|
52
74
|
let daysToSubtract = 90
|
|
53
|
-
|
|
54
75
|
if (timeRange === "30d") {
|
|
55
76
|
daysToSubtract = 30
|
|
56
77
|
} else if (timeRange === "7d") {
|
|
57
78
|
daysToSubtract = 7
|
|
79
|
+
} else if (timeRange === "10" || timeRange === "20" || timeRange === "30") {
|
|
80
|
+
// Special logic for count-based limits if passed as timeRange
|
|
81
|
+
const limit = parseInt(timeRange, 10)
|
|
82
|
+
return series.slice(-limit)
|
|
58
83
|
}
|
|
59
84
|
|
|
60
85
|
const startDate = new Date(referenceDate)
|
|
61
86
|
startDate.setDate(startDate.getDate() - daysToSubtract)
|
|
62
|
-
|
|
63
|
-
return series.filter((point) => new Date(point.date) >= startDate)
|
|
87
|
+
return series.filter(item => new Date(item.date) >= startDate)
|
|
64
88
|
}, [series, timeRange])
|
|
65
89
|
|
|
66
90
|
return (
|
|
67
|
-
<section className="px-4 lg:px-6">
|
|
68
|
-
<Card className="@container/card">
|
|
69
|
-
<CardHeader>
|
|
70
|
-
<CardTitle>
|
|
91
|
+
<section className={cn("px-4 lg:px-6 flex flex-col h-full", className)}>
|
|
92
|
+
<Card className="@container/card flex flex-col flex-1 min-h-0 border-0 shadow-none bg-transparent">
|
|
93
|
+
<CardHeader className="shrink-0">
|
|
94
|
+
<CardTitle>{title}</CardTitle>
|
|
71
95
|
<CardDescription>
|
|
72
|
-
<span className="hidden @[540px]/card:block">
|
|
73
|
-
<span className="@[540px]/card:hidden">
|
|
96
|
+
<span className="hidden @[540px]/card:block">{description}</span>
|
|
97
|
+
<span className="@[540px]/card:hidden">{shortDescription}</span>
|
|
74
98
|
</CardDescription>
|
|
75
99
|
<CardAction>
|
|
76
100
|
<ToggleGroup
|
|
@@ -84,38 +108,34 @@ export const DashboardChart = React.memo<DashboardChartProps>(({ series, onTimeR
|
|
|
84
108
|
variant="outline"
|
|
85
109
|
className="hidden *:data-[slot=toggle-group-item]:px-4! @[767px]/card:flex"
|
|
86
110
|
>
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
111
|
+
{timeRanges.map(range => (
|
|
112
|
+
<ToggleGroupItem key={range.value} value={range.value}>{range.label}</ToggleGroupItem>
|
|
113
|
+
))}
|
|
90
114
|
</ToggleGroup>
|
|
91
115
|
<Select value={timeRange} onValueChange={(value) => handleTimeRangeChange(value as DashboardChartTimeRange)}>
|
|
92
116
|
<SelectTrigger
|
|
93
117
|
className="flex w-40 **:data-[slot=select-value]:block **:data-[slot=select-value]:truncate @[767px]/card:hidden"
|
|
94
118
|
aria-label="Select a value"
|
|
95
119
|
>
|
|
96
|
-
<SelectValue placeholder=
|
|
120
|
+
<SelectValue placeholder={timeRanges[0]?.label || "Select range"} />
|
|
97
121
|
</SelectTrigger>
|
|
98
122
|
<SelectContent className="rounded-xl">
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
</SelectItem>
|
|
105
|
-
<SelectItem value="7d" className="rounded-lg">
|
|
106
|
-
Last 7 days
|
|
107
|
-
</SelectItem>
|
|
123
|
+
{timeRanges.map(range => (
|
|
124
|
+
<SelectItem key={range.value} value={range.value} className="rounded-lg">
|
|
125
|
+
{range.shortLabel || range.label}
|
|
126
|
+
</SelectItem>
|
|
127
|
+
))}
|
|
108
128
|
</SelectContent>
|
|
109
129
|
</Select>
|
|
110
130
|
</CardAction>
|
|
111
131
|
</CardHeader>
|
|
112
|
-
<CardContent className="px-2 pt-4 sm:px-6 sm:pt-6">
|
|
132
|
+
<CardContent className="px-2 pt-4 sm:px-6 sm:pt-6 flex-1 min-h-0 flex flex-col">
|
|
113
133
|
<ChartContainer
|
|
114
134
|
config={{
|
|
115
|
-
desktop: { label:
|
|
116
|
-
mobile: { label:
|
|
135
|
+
desktop: { label: desktopLabel, color: "var(--primary)" },
|
|
136
|
+
...(showMobile ? { mobile: { label: mobileLabel, color: "var(--primary)" } } : {}),
|
|
117
137
|
}}
|
|
118
|
-
className="aspect-auto h-[250px]
|
|
138
|
+
className={cn("aspect-auto w-full", chartClassName || "h-[250px]")}
|
|
119
139
|
>
|
|
120
140
|
<AreaChart data={filteredSeries}>
|
|
121
141
|
<defs>
|
|
@@ -123,10 +143,12 @@ export const DashboardChart = React.memo<DashboardChartProps>(({ series, onTimeR
|
|
|
123
143
|
<stop offset="5%" stopColor="var(--color-desktop)" stopOpacity={1} />
|
|
124
144
|
<stop offset="95%" stopColor="var(--color-desktop)" stopOpacity={0.1} />
|
|
125
145
|
</linearGradient>
|
|
126
|
-
|
|
127
|
-
<
|
|
128
|
-
|
|
129
|
-
|
|
146
|
+
{showMobile && (
|
|
147
|
+
<linearGradient id="fillMobile" x1="0" y1="0" x2="0" y2="1">
|
|
148
|
+
<stop offset="5%" stopColor="var(--color-mobile)" stopOpacity={0.8} />
|
|
149
|
+
<stop offset="95%" stopColor="var(--color-mobile)" stopOpacity={0.1} />
|
|
150
|
+
</linearGradient>
|
|
151
|
+
)}
|
|
130
152
|
</defs>
|
|
131
153
|
<CartesianGrid vertical={false} />
|
|
132
154
|
<XAxis
|
|
@@ -157,13 +179,15 @@ export const DashboardChart = React.memo<DashboardChartProps>(({ series, onTimeR
|
|
|
157
179
|
/>
|
|
158
180
|
}
|
|
159
181
|
/>
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
182
|
+
{showMobile && (
|
|
183
|
+
<Area
|
|
184
|
+
dataKey="mobile"
|
|
185
|
+
type="natural"
|
|
186
|
+
fill="url(#fillMobile)"
|
|
187
|
+
stroke="var(--color-mobile)"
|
|
188
|
+
stackId="a"
|
|
189
|
+
/>
|
|
190
|
+
)}
|
|
167
191
|
<Area
|
|
168
192
|
dataKey="desktop"
|
|
169
193
|
type="natural"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { DashboardChart } from './DashboardChart'
|
|
2
|
-
export type { DashboardChartProps } from './DashboardChart'
|
|
2
|
+
export type { DashboardChartProps, DashboardChartPoint, DashboardChartTimeRange } from './DashboardChart'
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import { EvalSessionDetailsPanel } from "./EvalSessionDetailsPanel"
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: "Composites/EvalSessionDetailsPanel",
|
|
6
|
+
component: EvalSessionDetailsPanel,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: "padded",
|
|
9
|
+
},
|
|
10
|
+
decorators: [
|
|
11
|
+
(Story) => (
|
|
12
|
+
<div className="h-[500px] w-full border rounded-md overflow-hidden bg-background">
|
|
13
|
+
<Story />
|
|
14
|
+
</div>
|
|
15
|
+
),
|
|
16
|
+
],
|
|
17
|
+
} satisfies Meta<typeof EvalSessionDetailsPanel>
|
|
18
|
+
|
|
19
|
+
export default meta
|
|
20
|
+
type Story = StoryObj<typeof meta>
|
|
21
|
+
|
|
22
|
+
export const Default: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
activeTab: "golden-evals",
|
|
25
|
+
sessionDetails: {
|
|
26
|
+
id: "sess_1",
|
|
27
|
+
date: "2023-01-01T00:00:00.000Z",
|
|
28
|
+
goldenEvals: [
|
|
29
|
+
{ id: 1, category: "Accuracy", metric: "Correct Answer", pass: 1, reasoning: "Matched expectation." }
|
|
30
|
+
],
|
|
31
|
+
systemPrompt: "You are a helpful AI.",
|
|
32
|
+
outputTranscript: "Hello world!",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { DYNAMIC_TABLE_SCHEMA_VERSION, dynamicTableSchema } from "ui-schema-contracts"
|
|
3
|
+
import { ScrollArea } from "@/components/primitives/ScrollArea"
|
|
4
|
+
import { Tabs, TabsContent } from "@/components/primitives/Tabs"
|
|
5
|
+
import { EnhancedDataTable } from "@/components/composites/DataTable"
|
|
6
|
+
import type { DashboardRow } from "@/components/composites/DataTable"
|
|
7
|
+
import { Button } from "@/components/primitives/Button"
|
|
8
|
+
import { Icon } from "@/components/primitives/Icon"
|
|
9
|
+
|
|
10
|
+
export interface EvalSessionDetails {
|
|
11
|
+
id: string
|
|
12
|
+
date: string
|
|
13
|
+
goldenEvals: DashboardRow[]
|
|
14
|
+
systemPrompt?: string
|
|
15
|
+
outputTranscript?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface EvalSessionDetailsPanelProps {
|
|
19
|
+
sessionDetails: EvalSessionDetails
|
|
20
|
+
activeTab: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const EvalTriggerButton = ({ onClick }: { onClick: () => void }) => (
|
|
24
|
+
<Button onClick={onClick} size="sm">
|
|
25
|
+
<Icon name="Play" className="w-4 h-4 mr-2" />
|
|
26
|
+
Trigger Evaluation
|
|
27
|
+
</Button>
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
const goldenEvalTableSchema = dynamicTableSchema.parse({
|
|
31
|
+
schemaVersion: DYNAMIC_TABLE_SCHEMA_VERSION,
|
|
32
|
+
rowKey: "id",
|
|
33
|
+
enableFiltering: true,
|
|
34
|
+
enablePagination: false,
|
|
35
|
+
enableRowSelection: false,
|
|
36
|
+
columns: [
|
|
37
|
+
{ key: "category", label: "Category", renderType: "text" },
|
|
38
|
+
{ key: "metric", label: "Metric (Question)", renderType: "text" },
|
|
39
|
+
{ key: "pass", label: "Score", renderType: "badge" },
|
|
40
|
+
{ key: "reasoning", label: "Reasoning", renderType: "text" },
|
|
41
|
+
],
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
export const EvalSessionDetailsPanel = React.memo<EvalSessionDetailsPanelProps>(
|
|
45
|
+
({ sessionDetails, activeTab }) => {
|
|
46
|
+
return (
|
|
47
|
+
<div className="flex flex-col h-full bg-background">
|
|
48
|
+
<Tabs value={activeTab} className="flex-1 flex flex-col min-h-0">
|
|
49
|
+
<div className="flex-1 min-h-0 overflow-hidden relative">
|
|
50
|
+
<TabsContent value="golden-evals" className="absolute inset-0 m-0 p-0 overflow-hidden flex flex-col">
|
|
51
|
+
<div className="p-4 flex-1 min-h-0 flex flex-col">
|
|
52
|
+
{sessionDetails.goldenEvals && sessionDetails.goldenEvals.length > 0 ? (
|
|
53
|
+
<EnhancedDataTable
|
|
54
|
+
data={sessionDetails.goldenEvals}
|
|
55
|
+
tableSchema={goldenEvalTableSchema}
|
|
56
|
+
/>
|
|
57
|
+
) : (
|
|
58
|
+
<div className="text-sm text-muted-foreground flex-1 flex items-center justify-center">No evaluation data available.</div>
|
|
59
|
+
)}
|
|
60
|
+
</div>
|
|
61
|
+
</TabsContent>
|
|
62
|
+
|
|
63
|
+
<TabsContent value="prompts" className="absolute inset-0 m-0 p-0">
|
|
64
|
+
<ScrollArea className="h-full">
|
|
65
|
+
<div className="p-4">
|
|
66
|
+
<pre className="text-xs font-mono bg-muted p-4 rounded whitespace-pre-wrap">
|
|
67
|
+
{sessionDetails.systemPrompt || "No system prompt available."}
|
|
68
|
+
</pre>
|
|
69
|
+
</div>
|
|
70
|
+
</ScrollArea>
|
|
71
|
+
</TabsContent>
|
|
72
|
+
|
|
73
|
+
<TabsContent value="outputs" className="absolute inset-0 m-0 p-0">
|
|
74
|
+
<ScrollArea className="h-full">
|
|
75
|
+
<div className="p-4">
|
|
76
|
+
<pre className="text-xs font-mono bg-muted p-4 rounded whitespace-pre-wrap">
|
|
77
|
+
{sessionDetails.outputTranscript || "No transcript available."}
|
|
78
|
+
</pre>
|
|
79
|
+
</div>
|
|
80
|
+
</ScrollArea>
|
|
81
|
+
</TabsContent>
|
|
82
|
+
</div>
|
|
83
|
+
</Tabs>
|
|
84
|
+
</div>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
EvalSessionDetailsPanel.displayName = "EvalSessionDetailsPanel"
|
|
@@ -205,3 +205,7 @@ export type { SessionHeaderProps, ChatSessionInfo } from './SessionHeader'
|
|
|
205
205
|
// AppBreadcrumb Composite
|
|
206
206
|
export { AppBreadcrumb } from './AppBreadcrumb'
|
|
207
207
|
export type { AppBreadcrumbProps, BreadcrumbItemData } from './AppBreadcrumb'
|
|
208
|
+
|
|
209
|
+
// EvalSessionDetailsPanel Composite
|
|
210
|
+
export { EvalSessionDetailsPanel, EvalTriggerButton } from './EvalSessionDetailsPanel'
|
|
211
|
+
export type { EvalSessionDetailsPanelProps, EvalSessionDetails } from './EvalSessionDetailsPanel'
|
|
@@ -67,8 +67,6 @@ export const DashboardFeature = React.memo<DashboardFeatureProps>(
|
|
|
67
67
|
createEntityName = "Section",
|
|
68
68
|
createFields,
|
|
69
69
|
createButtonLabel = "Create",
|
|
70
|
-
apps,
|
|
71
|
-
currentAppId,
|
|
72
70
|
quickCreateEntityName = "App",
|
|
73
71
|
quickCreateFields,
|
|
74
72
|
quickCreateButtonLabel = "Quick Create",
|
|
@@ -98,13 +96,13 @@ export const DashboardFeature = React.memo<DashboardFeatureProps>(
|
|
|
98
96
|
setDrawerMode('table')
|
|
99
97
|
setDrawerOpen(true)
|
|
100
98
|
actionHandlers?.onCreateDrawerOpenChange?.(true)
|
|
101
|
-
}, [actionHandlers])
|
|
99
|
+
}, [actionHandlers, setDrawerOpen])
|
|
102
100
|
|
|
103
101
|
const openQuickCreateDrawer = React.useCallback(() => {
|
|
104
102
|
setDrawerMode('quick-create')
|
|
105
103
|
setDrawerOpen(true)
|
|
106
104
|
actionHandlers?.onCreateDrawerOpenChange?.(true)
|
|
107
|
-
}, [actionHandlers])
|
|
105
|
+
}, [actionHandlers, setDrawerOpen])
|
|
108
106
|
|
|
109
107
|
const handleDrawerOpenChange = React.useCallback(
|
|
110
108
|
(open: boolean) => {
|
|
@@ -114,7 +112,7 @@ export const DashboardFeature = React.memo<DashboardFeatureProps>(
|
|
|
114
112
|
}
|
|
115
113
|
actionHandlers?.onCreateDrawerOpenChange?.(open)
|
|
116
114
|
},
|
|
117
|
-
[actionHandlers]
|
|
115
|
+
[actionHandlers, setDrawerOpen]
|
|
118
116
|
)
|
|
119
117
|
|
|
120
118
|
const handleFieldChange = React.useCallback(
|
|
@@ -144,7 +142,7 @@ export const DashboardFeature = React.memo<DashboardFeatureProps>(
|
|
|
144
142
|
actionHandlers?.onCreateDrawerOpenChange?.(false)
|
|
145
143
|
setValues(buildInitialValues(createFields))
|
|
146
144
|
},
|
|
147
|
-
[actionHandlers, createFields, drawerMode]
|
|
145
|
+
[actionHandlers, createFields, drawerMode, setDrawerOpen]
|
|
148
146
|
)
|
|
149
147
|
|
|
150
148
|
return (
|
|
@@ -166,6 +164,17 @@ export const DashboardFeature = React.memo<DashboardFeatureProps>(
|
|
|
166
164
|
<DashboardChart
|
|
167
165
|
series={visitorsSeries}
|
|
168
166
|
onTimeRangeChange={actionHandlers?.onChartTimeRangeChange}
|
|
167
|
+
title="Total Visitors"
|
|
168
|
+
description="Total for the last 3 months"
|
|
169
|
+
shortDescription="Last 3 months"
|
|
170
|
+
timeRanges={[
|
|
171
|
+
{ value: "90d", label: "Last 3 months" },
|
|
172
|
+
{ value: "30d", label: "Last 30 days" },
|
|
173
|
+
{ value: "7d", label: "Last 7 days" }
|
|
174
|
+
]}
|
|
175
|
+
desktopLabel="Desktop"
|
|
176
|
+
mobileLabel="Mobile"
|
|
177
|
+
showMobile={true}
|
|
169
178
|
/>
|
|
170
179
|
</>
|
|
171
180
|
)}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import { expect, within, userEvent, fn } from "@storybook/test"
|
|
3
|
+
import { EvalDashboardFeature } from "./EvalDashboardFeature"
|
|
4
|
+
import { evalDashboardFeatureStateMock } from "./EvalDashboardFeature.mocks"
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: "Features/EvalDashboardFeature/Behaviors",
|
|
8
|
+
component: EvalDashboardFeature,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: "fullscreen",
|
|
11
|
+
},
|
|
12
|
+
render: (args) => (
|
|
13
|
+
<div className="h-screen w-full">
|
|
14
|
+
<EvalDashboardFeature {...args} />
|
|
15
|
+
</div>
|
|
16
|
+
)
|
|
17
|
+
} satisfies Meta<typeof EvalDashboardFeature>
|
|
18
|
+
|
|
19
|
+
export default meta
|
|
20
|
+
type Story = StoryObj<typeof meta>
|
|
21
|
+
|
|
22
|
+
export const Interactive: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
...evalDashboardFeatureStateMock,
|
|
25
|
+
actionHandlers: {
|
|
26
|
+
onTriggerEvaluation: fn(),
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
play: async ({ canvasElement }) => {
|
|
30
|
+
const canvas = within(canvasElement)
|
|
31
|
+
|
|
32
|
+
// Check if the tabs exist
|
|
33
|
+
const tabs = await canvas.findAllByRole("tab")
|
|
34
|
+
expect(tabs.length).toBeGreaterThan(0)
|
|
35
|
+
|
|
36
|
+
// Switch to Outputs tab
|
|
37
|
+
const outputsTab = canvas.getByRole("tab", { name: /Outputs/i })
|
|
38
|
+
await userEvent.click(outputsTab)
|
|
39
|
+
},
|
|
40
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { UseEvalDashboardFeatureReturn } from "./useEvalDashboardFeature.d"
|
|
2
|
+
|
|
3
|
+
export const evalDashboardFeatureStateMock: UseEvalDashboardFeatureReturn = {
|
|
4
|
+
inbox: {
|
|
5
|
+
items: [
|
|
6
|
+
{ id: 'sess_1', date: '2026-07-16T10:00:00Z', score: 38, total: 41, latency: '2.3s', tokens: 4500 },
|
|
7
|
+
{ id: 'sess_2', date: '2026-07-16T11:30:00Z', score: 40, total: 41, latency: '1.9s', tokens: 3200 },
|
|
8
|
+
{ id: 'sess_3', date: '2026-07-16T12:45:00Z', score: 41, total: 41, latency: '2.1s', tokens: 3800 },
|
|
9
|
+
],
|
|
10
|
+
selectedItemId: 'sess_1',
|
|
11
|
+
onSelectItem: () => {},
|
|
12
|
+
},
|
|
13
|
+
data: {
|
|
14
|
+
goldenEvals: [
|
|
15
|
+
{ id: 1, category: 'Goal Completion', metric: "Was the user's objective accomplished?", pass: 1, reasoning: "The agent successfully generated the video based on the provided topic." },
|
|
16
|
+
{ id: 2, category: 'Conversation Progress', metric: "Does every response advance the task?", pass: 1, reasoning: "Every turn advanced the task without stalling." },
|
|
17
|
+
{ id: 3, category: 'Clarification Strategy', metric: "Did clarifications resolve high-impact uncertainty efficiently?", pass: 0, reasoning: "The agent asked too many clarifying questions that could have been batched." },
|
|
18
|
+
],
|
|
19
|
+
systemPrompt: "// Raw System Prompt Input\nYou are the orchestrator...",
|
|
20
|
+
outputTranscript: "// Raw Transcript Output\nUser: hi\nAI: How can I help you today?",
|
|
21
|
+
},
|
|
22
|
+
actionHandlers: {
|
|
23
|
+
onTriggerEvaluation: () => {},
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import { EvalDashboardFeature } from "./EvalDashboardFeature"
|
|
3
|
+
import { evalDashboardFeatureStateMock } from "./EvalDashboardFeature.mocks"
|
|
4
|
+
import { useEvalDashboardFeatureMock } from "./useEvalDashboardFeature.mock"
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: "Features/EvalDashboardFeature",
|
|
8
|
+
component: EvalDashboardFeature,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: "fullscreen",
|
|
12
|
+
},
|
|
13
|
+
render: (args) => (
|
|
14
|
+
<div className="h-screen w-full">
|
|
15
|
+
<EvalDashboardFeature {...args} />
|
|
16
|
+
</div>
|
|
17
|
+
)
|
|
18
|
+
} satisfies Meta<typeof EvalDashboardFeature>
|
|
19
|
+
|
|
20
|
+
export default meta
|
|
21
|
+
type Story = StoryObj<typeof meta>
|
|
22
|
+
|
|
23
|
+
export const Default: Story = {
|
|
24
|
+
args: {
|
|
25
|
+
...evalDashboardFeatureStateMock,
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const WithStateManagement: Story = {
|
|
30
|
+
render: () => {
|
|
31
|
+
const state = useEvalDashboardFeatureMock()
|
|
32
|
+
return <EvalDashboardFeature {...state} className="h-[100dvh]" />
|
|
33
|
+
},
|
|
34
|
+
}
|