From 31003cd5f61d9a84ec59bc998d0a39c25bbf26de Mon Sep 17 00:00:00 2001 From: balibabu Date: Wed, 11 Jun 2025 14:24:43 +0800 Subject: [PATCH] Feat: Display the agent node running timeline #3221 (#8185) ### What problem does this PR solve? Feat: Display the agent node running timeline #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- web/src/components/originui/timeline.tsx | 209 +++++++++++++++++++ web/src/pages/agent/canvas/index.tsx | 15 +- web/src/pages/agent/chat/chat-sheet.tsx | 14 +- web/src/pages/agent/log-sheet/data.ts | 243 +++++++++++++++++++++++ web/src/pages/agent/log-sheet/index.tsx | 116 +++++++---- 5 files changed, 546 insertions(+), 51 deletions(-) create mode 100644 web/src/components/originui/timeline.tsx create mode 100644 web/src/pages/agent/log-sheet/data.ts diff --git a/web/src/components/originui/timeline.tsx b/web/src/components/originui/timeline.tsx new file mode 100644 index 000000000..8b4bbea42 --- /dev/null +++ b/web/src/components/originui/timeline.tsx @@ -0,0 +1,209 @@ +'use client'; + +import { cn } from '@/lib/utils'; +import { Slot } from '@radix-ui/react-slot'; +import * as React from 'react'; + +// Types +type TimelineContextValue = { + activeStep: number; + setActiveStep: (step: number) => void; +}; + +// Context +const TimelineContext = React.createContext( + undefined, +); + +const useTimeline = () => { + const context = React.useContext(TimelineContext); + if (!context) { + throw new Error('useTimeline must be used within a Timeline'); + } + return context; +}; + +// Components +interface TimelineProps extends React.HTMLAttributes { + defaultValue?: number; + value?: number; + onValueChange?: (value: number) => void; + orientation?: 'horizontal' | 'vertical'; +} + +function Timeline({ + defaultValue = 1, + value, + onValueChange, + orientation = 'vertical', + className, + ...props +}: TimelineProps) { + const [activeStep, setInternalStep] = React.useState(defaultValue); + + const setActiveStep = React.useCallback( + (step: number) => { + if (value === undefined) { + setInternalStep(step); + } + onValueChange?.(step); + }, + [value, onValueChange], + ); + + const currentStep = value ?? activeStep; + + return ( + +
+ + ); +} + +// TimelineContent +function TimelineContent({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
+ ); +} + +// TimelineDate +interface TimelineDateProps extends React.HTMLAttributes { + asChild?: boolean; +} + +function TimelineDate({ + asChild = false, + className, + ...props +}: TimelineDateProps) { + const Comp = asChild ? Slot : 'time'; + + return ( + + ); +} + +// TimelineHeader +function TimelineHeader({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
+ ); +} + +// TimelineIndicator +interface TimelineIndicatorProps extends React.HTMLAttributes { + asChild?: boolean; +} + +function TimelineIndicator({ + asChild = false, + className, + children, + ...props +}: TimelineIndicatorProps) { + return ( + + ); +} + +// TimelineItem +interface TimelineItemProps extends React.HTMLAttributes { + step: number; +} + +function TimelineItem({ step, className, ...props }: TimelineItemProps) { + const { activeStep } = useTimeline(); + + return ( +
+ ); +} + +// TimelineSeparator +function TimelineSeparator({ + className, + ...props +}: React.HTMLAttributes) { + return ( +