ai-design-system 0.1.68 → 0.1.69

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.
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react"
2
2
  import { EvalSessionDetailsPanel } from "./EvalSessionDetailsPanel"
3
3
 
4
4
  const meta = {
5
- title: "Composites/EvalSessionDetailsPanel",
5
+ title: "Blocks/EvalSessionDetailsPanel",
6
6
  component: EvalSessionDetailsPanel,
7
7
  parameters: {
8
8
  layout: "padded",
@@ -18,12 +18,14 @@ export interface EvalSessionDetails {
18
18
  export interface EvalSessionDetailsPanelProps {
19
19
  sessionDetails: EvalSessionDetails
20
20
  activeTab: string
21
+ actionHandlers?: { onTriggerEvaluation?: () => void }
22
+ workflowContent?: React.ReactNode
21
23
  }
22
24
 
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
25
+ export const EvalTriggerButton = ({ onClick, loading }: { onClick: () => void; loading?: boolean }) => (
26
+ <Button onClick={onClick} variant="default" size="sm" className="h-8" disabled={loading}>
27
+ <Icon name={loading ? 'loader-2' : 'play'} className={`w-4 h-4 mr-2${loading ? ' animate-spin' : ''}`} />
28
+ {loading ? 'Evaluating...' : 'Trigger'}
27
29
  </Button>
28
30
  )
29
31
 
@@ -42,7 +44,7 @@ const goldenEvalTableSchema = dynamicTableSchema.parse({
42
44
  })
43
45
 
44
46
  export const EvalSessionDetailsPanel = React.memo<EvalSessionDetailsPanelProps>(
45
- ({ sessionDetails, activeTab }) => {
47
+ ({ sessionDetails, activeTab, actionHandlers, workflowContent }) => {
46
48
  return (
47
49
  <div className="flex flex-col h-full bg-background">
48
50
  <Tabs value={activeTab} className="flex-1 flex flex-col min-h-0">
@@ -79,6 +81,14 @@ export const EvalSessionDetailsPanel = React.memo<EvalSessionDetailsPanelProps>(
79
81
  </div>
80
82
  </ScrollArea>
81
83
  </TabsContent>
84
+
85
+ <TabsContent value="workflow" className="absolute inset-0 m-0 p-0">
86
+ {workflowContent || (
87
+ <div className="flex items-center justify-center h-full text-muted-foreground">
88
+ No workflow data available.
89
+ </div>
90
+ )}
91
+ </TabsContent>
82
92
  </div>
83
93
  </Tabs>
84
94
  </div>
@@ -2,8 +2,9 @@ import type { Connection, EdgeChange, Node, NodeChange, OnConnectStartParams } f
2
2
  import type React from "react";
3
3
  import type { StateNodeData } from "@/components/composites/StateNode";
4
4
  import type { TransitionNodeData } from "@/components/composites/TransitionNode";
5
+ import type { TriggerNodeData } from "@/components/composites/TriggerNode";
5
6
 
6
- export type WorkflowNodeData = StateNodeData | TransitionNodeData;
7
+ export type WorkflowNodeData = StateNodeData | TransitionNodeData | TriggerNodeData;
7
8
  export type WorkflowNode = Node<WorkflowNodeData>;
8
9
 
9
10
  export interface WorkflowEdge {
@@ -27,3 +27,7 @@ export type { FormReportsSectionProps } from './FormReportsSection'
27
27
 
28
28
  export { InboxPanel } from './InboxPanel'
29
29
  export type { InboxPanelProps } from './InboxPanel'
30
+
31
+ // EvalSessionDetailsPanel Block
32
+ export { EvalSessionDetailsPanel, EvalTriggerButton } from './EvalSessionDetailsPanel'
33
+ export type { EvalSessionDetailsPanelProps, EvalSessionDetails } from './EvalSessionDetailsPanel'
@@ -506,10 +506,12 @@ export function EnhancedDataTable({
506
506
  ))}
507
507
  </DropdownMenuContent>
508
508
  </DropdownMenu>
509
- <Button variant="outline" size="sm" className="h-8" onClick={onCreateClick}>
510
- <Icon name="plus" size="sm" />
511
- <span>{createButtonLabel}</span>
512
- </Button>
509
+ {onCreateClick && (
510
+ <Button variant="outline" size="sm" className="h-8" onClick={onCreateClick}>
511
+ <Icon name="plus" size="sm" />
512
+ <span>{createButtonLabel}</span>
513
+ </Button>
514
+ )}
513
515
  {rightActions}
514
516
  </div>
515
517
  </div>
@@ -34,7 +34,7 @@ export const ProjectSwitcher = React.memo<ProjectSwitcherProps>(
34
34
  ({ projects, selectedProjectId, onSelectProject, onCreateProject, className }) => {
35
35
  const [open, setOpen] = React.useState(false)
36
36
 
37
- const selectedProject = projects.find((p) => p.id === selectedProjectId)
37
+ const selectedProject = projects.find((p) => String(p.id) === String(selectedProjectId))
38
38
  const displayLabel = selectedProject ? selectedProject.name : "Select Project..."
39
39
 
40
40
  const defaultValue = selectedProject ? `${selectedProject.name}-${selectedProject.id}` : undefined
@@ -86,7 +86,7 @@ export const ProjectSwitcher = React.memo<ProjectSwitcherProps>(
86
86
  </div>
87
87
  <Icon name="check"
88
88
  className={`h-4 w-4 ${
89
- selectedProjectId === project.id ? "opacity-100" : "opacity-0"
89
+ String(selectedProjectId) === String(project.id) ? "opacity-100" : "opacity-0"
90
90
  }`}
91
91
  />
92
92
  </CommandItem>
@@ -206,6 +206,4 @@ export type { SessionHeaderProps, ChatSessionInfo } from './SessionHeader'
206
206
  export { AppBreadcrumb } from './AppBreadcrumb'
207
207
  export type { AppBreadcrumbProps, BreadcrumbItemData } from './AppBreadcrumb'
208
208
 
209
- // EvalSessionDetailsPanel Composite
210
- export { EvalSessionDetailsPanel, EvalTriggerButton } from './EvalSessionDetailsPanel'
211
- export type { EvalSessionDetailsPanelProps, EvalSessionDetails } from './EvalSessionDetailsPanel'
209
+
@@ -1,7 +1,13 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react"
2
+ import * as React from "react"
2
3
  import { expect, within, userEvent, fn } from "@storybook/test"
3
4
  import { EvalDashboardFeature } from "./EvalDashboardFeature"
4
- import { evalDashboardFeatureStateMock } from "./EvalDashboardFeature.mocks"
5
+ import { evalDashboardFeatureStateMock, workflowMockNodes, workflowMockEdges } from "./EvalDashboardFeature.mocks"
6
+ import { NodeEditor } from "@/components/features/NodeEditor"
7
+
8
+ const workflowMock = (
9
+ <NodeEditor nodes={workflowMockNodes} edges={workflowMockEdges} showMinimap={false} interactive={false} />
10
+ )
5
11
 
6
12
  const meta = {
7
13
  title: "Features/EvalDashboardFeature/Behaviors",
@@ -25,16 +31,17 @@ export const Interactive: Story = {
25
31
  actionHandlers: {
26
32
  onTriggerEvaluation: fn(),
27
33
  },
34
+ workflowContent: workflowMock,
28
35
  },
29
36
  play: async ({ canvasElement }) => {
30
37
  const canvas = within(canvasElement)
31
38
 
32
- // Check if the tabs exist
39
+ // 4 tabs: Golden Evals, System Prompts, Outputs, Workflow
33
40
  const tabs = await canvas.findAllByRole("tab")
34
- expect(tabs.length).toBeGreaterThan(0)
41
+ expect(tabs.length).toBe(4)
35
42
 
36
- // Switch to Outputs tab
37
- const outputsTab = canvas.getByRole("tab", { name: /Outputs/i })
38
- await userEvent.click(outputsTab)
43
+ // Switch to Workflow tab
44
+ const workflowTab = canvas.getByRole("tab", { name: /Workflow/i })
45
+ await userEvent.click(workflowTab)
39
46
  },
40
47
  }
@@ -1,4 +1,34 @@
1
1
  import type { UseEvalDashboardFeatureReturn } from "./useEvalDashboardFeature.d"
2
+ import type { WorkflowNode, WorkflowEdge } from "@/components/blocks/WorkflowCanvas"
3
+
4
+ export const workflowMockNodes: WorkflowNode[] = [
5
+ { id: 'trigger-1', type: 'trigger', position: { x: 100, y: 20 }, data: { label: 'Agentic Eval', type: 'trigger', status: 'idle' } },
6
+ { id: 'state-1', type: 'state', position: { x: 250, y: 20 }, data: { label: 'Initialize Eval', type: 'state', description: 'Parse session messages and config', status: 'idle' } },
7
+ { id: 'transition-1', type: 'transition', position: { x: 400, y: 20 }, data: { label: 'Parse Session', type: 'transition', status: 'idle' } },
8
+ { id: 'state-2', type: 'state', position: { x: 250, y: 140 }, data: { label: 'Fetch System Prompt', type: 'state', description: 'Load system prompt from session', status: 'idle' } },
9
+ { id: 'transition-2', type: 'transition', position: { x: 400, y: 140 }, data: { label: 'Check Config', type: 'transition', description: 'Check if multi-agent config exists', status: 'idle' } },
10
+ { id: 'state-2b', type: 'state', position: { x: 250, y: 260 }, data: { label: 'Fetch Config Prompt', type: 'state', description: 'Load agent config system prompt', status: 'idle' } },
11
+ { id: 'transition-2b', type: 'transition', position: { x: 400, y: 260 }, data: { label: 'Format Prompt', type: 'transition', description: 'Build multi-agent system prompt', status: 'idle' } },
12
+ { id: 'state-3', type: 'state', position: { x: 250, y: 380 }, data: { label: 'Build Messages', type: 'state', description: 'Construct LLM message payload', status: 'idle' } },
13
+ { id: 'transition-3', type: 'transition', position: { x: 400, y: 380 }, data: { label: 'LLM Call', type: 'transition', status: 'idle' } },
14
+ { id: 'state-4', type: 'state', position: { x: 250, y: 500 }, data: { label: 'Parse Eval', type: 'state', description: 'Parse LLM eval response', status: 'idle' } },
15
+ { id: 'transition-4', type: 'transition', position: { x: 400, y: 500 }, data: { label: 'Persist', type: 'transition', status: 'idle' } },
16
+ { id: 'state-5', type: 'state', position: { x: 250, y: 620 }, data: { label: 'Complete', type: 'state', description: 'Eval finished', status: 'idle', isTerminal: true } },
17
+ ]
18
+
19
+ export const workflowMockEdges: WorkflowEdge[] = [
20
+ { id: 'e-trigger-1', source: 'trigger-1', target: 'state-1' },
21
+ { id: 'e-1-transition-1', source: 'state-1', target: 'transition-1' },
22
+ { id: 'e-transition-1-2', source: 'transition-1', target: 'state-2' },
23
+ { id: 'e-2-transition-2', source: 'state-2', target: 'transition-2' },
24
+ { id: 'e-transition-2-2b', source: 'transition-2', target: 'state-2b' },
25
+ { id: 'e-2b-transition-2b', source: 'state-2b', target: 'transition-2b' },
26
+ { id: 'e-transition-2b-3', source: 'transition-2b', target: 'state-3' },
27
+ { id: 'e-3-transition-3', source: 'state-3', target: 'transition-3' },
28
+ { id: 'e-transition-3-4', source: 'transition-3', target: 'state-4' },
29
+ { id: 'e-4-transition-4', source: 'state-4', target: 'transition-4' },
30
+ { id: 'e-transition-4-5', source: 'transition-4', target: 'state-5' },
31
+ ]
2
32
 
3
33
  export const evalDashboardFeatureStateMock: UseEvalDashboardFeatureReturn = {
4
34
  inbox: {
@@ -1,7 +1,13 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react"
2
+ import * as React from "react"
2
3
  import { EvalDashboardFeature } from "./EvalDashboardFeature"
3
- import { evalDashboardFeatureStateMock } from "./EvalDashboardFeature.mocks"
4
+ import { evalDashboardFeatureStateMock, workflowMockNodes, workflowMockEdges } from "./EvalDashboardFeature.mocks"
4
5
  import { useEvalDashboardFeatureMock } from "./useEvalDashboardFeature.mock"
6
+ import { NodeEditor } from "@/components/features/NodeEditor"
7
+
8
+ const workflowMock = (
9
+ <NodeEditor nodes={workflowMockNodes} edges={workflowMockEdges} showMinimap={false} interactive={false} />
10
+ )
5
11
 
6
12
  const meta = {
7
13
  title: "Features/EvalDashboardFeature",
@@ -23,12 +29,13 @@ type Story = StoryObj<typeof meta>
23
29
  export const Default: Story = {
24
30
  args: {
25
31
  ...evalDashboardFeatureStateMock,
32
+ workflowContent: workflowMock,
26
33
  },
27
34
  }
28
35
 
29
36
  export const WithStateManagement: Story = {
30
37
  render: () => {
31
38
  const state = useEvalDashboardFeatureMock()
32
- return <EvalDashboardFeature {...state} className="h-[100dvh]" />
39
+ return <EvalDashboardFeature {...state} workflowContent={workflowMock} className="h-[100dvh]" />
33
40
  },
34
41
  }
@@ -2,7 +2,7 @@ import * as React from "react"
2
2
  import { InboxPanel } from "@/components/blocks/InboxPanel"
3
3
  import { SectionLayout } from "@/components/blocks/SectionLayout"
4
4
  import { DashboardChart } from "@/components/composites/DashboardChart"
5
- import { EvalSessionDetailsPanel, EvalTriggerButton } from "@/components/composites/EvalSessionDetailsPanel"
5
+ import { EvalSessionDetailsPanel, EvalTriggerButton } from "@/components/blocks/EvalSessionDetailsPanel"
6
6
  import type { DashboardRow } from "@/components/composites/DataTable"
7
7
  import { cn } from "@/lib/utils"
8
8
  import type {
@@ -17,10 +17,11 @@ export interface EvalDashboardFeatureProps {
17
17
  data: EvalDashboardFeatureData | null
18
18
  actionHandlers?: EvalDashboardFeatureActionHandlers
19
19
  className?: string
20
+ workflowContent?: React.ReactNode
20
21
  }
21
22
 
22
23
  export const EvalDashboardFeature = React.memo<EvalDashboardFeatureProps>(
23
- ({ inbox, data, actionHandlers, className }) => {
24
+ ({ inbox, data, actionHandlers, className, workflowContent }) => {
24
25
  const [showInbox, setShowInbox] = React.useState(true)
25
26
  const [activeTab, setActiveTab] = React.useState("golden-evals")
26
27
 
@@ -144,7 +145,8 @@ export const EvalDashboardFeature = React.memo<EvalDashboardFeatureProps>(
144
145
  tabs: [
145
146
  { label: "Golden Evals", value: "golden-evals" },
146
147
  { label: "System Prompts", value: "prompts" },
147
- { label: "Outputs", value: "outputs" }
148
+ { label: "Outputs", value: "outputs" },
149
+ ...(workflowContent ? [{ label: "Workflow", value: "workflow" }] : []),
148
150
  ],
149
151
  defaultTab: activeTab,
150
152
  onTabChange: setActiveTab,
@@ -154,13 +156,15 @@ export const EvalDashboardFeature = React.memo<EvalDashboardFeatureProps>(
154
156
  onClick: () => setShowInbox(!showInbox)
155
157
  },
156
158
  actions: actionHandlers?.onTriggerEvaluation ? (
157
- <EvalTriggerButton onClick={actionHandlers.onTriggerEvaluation} />
158
- ) : undefined
159
+ <EvalTriggerButton onClick={actionHandlers.onTriggerEvaluation} loading={actionHandlers.isTriggering} />
160
+ ) : undefined,
159
161
  } : undefined,
160
162
  content: sessionDetails ? (
161
163
  <EvalSessionDetailsPanel
162
164
  sessionDetails={sessionDetails}
163
165
  activeTab={activeTab}
166
+ actionHandlers={actionHandlers}
167
+ workflowContent={workflowContent}
164
168
  />
165
169
  ) : (
166
170
  <div className="flex-1 flex items-center justify-center text-muted-foreground bg-background h-full">
@@ -32,6 +32,7 @@ export interface EvalDashboardFeatureData {
32
32
 
33
33
  export interface EvalDashboardFeatureActionHandlers {
34
34
  onTriggerEvaluation?: () => void;
35
+ isTriggering?: boolean;
35
36
  }
36
37
 
37
38
  export interface UseEvalDashboardFeatureReturn {
@@ -9,9 +9,9 @@ import {
9
9
  mockPageLayoutRefinementMessages,
10
10
  mockSidebarConfig,
11
11
  } from './PageLayout.mocks'
12
- import { NodeEditor } from '../NodeEditor/NodeEditor'
12
+ import { NodeEditor } from '@/components/features/NodeEditor'
13
13
  import { RefinementPanel } from '../RefinementPanel/RefinementPanel'
14
- import { mockEdges, mockNodes, mockVersions } from '../NodeEditor/NodeEditor.mocks'
14
+ import { mockEdges, mockNodes, mockVersions } from '@/components/features/NodeEditor/NodeEditor.mocks'
15
15
  import { DashboardFeature } from '../DashboardFeature/DashboardFeature'
16
16
  import { useDashboardIntegrationMock } from './useDashboardIntegration.mock'
17
17
 
@@ -17,13 +17,14 @@ export type { RefinementPanelProps, RefinementMessage } from "./RefinementPanel"
17
17
  export { SpecNavigator } from "./SpecNavigator";
18
18
  export type { SpecNavigatorProps } from "./SpecNavigator";
19
19
 
20
+ // NodeEditor Feature
21
+ export { NodeEditor } from "./NodeEditor";
22
+ export type { NodeEditorProps } from "./NodeEditor";
23
+
20
24
  // TextEditor Feature
21
25
  export { TextEditor } from "./TextEditor";
22
26
  export type { TextEditorProps } from "./TextEditor";
23
27
 
24
- // NodeEditor Feature
25
- export { NodeEditor } from "./NodeEditor";
26
- export type { NodeEditorProps } from "./NodeEditor";
27
28
 
28
29
  // DashboardFeature Feature
29
30
  export { DashboardFeature } from "./DashboardFeature";