From 963fce8563019f588488207cc6dc175919748d66 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Tue, 18 Aug 2026 23:44:52 +0000 Subject: [PATCH] feat(ui): Add state change timeline event --- src/client/components/ActivityTimeline.tsx | 100 ++++++++++++++++----- 1 file changed, 80 insertions(+), 20 deletions(-) diff --git a/src/client/components/ActivityTimeline.tsx b/src/client/components/ActivityTimeline.tsx index a3b9ee6f..9e3e1bcf 100644 --- a/src/client/components/ActivityTimeline.tsx +++ b/src/client/components/ActivityTimeline.tsx @@ -1,5 +1,5 @@ import type { Collapsible } from '@chakra-ui/react'; -import { Card, Icon, SkeletonCircle, SkeletonText, Span, Tabs, Timeline} from '@chakra-ui/react'; +import { Card, Text, Icon, SkeletonCircle, SkeletonText, Span, Tabs, Timeline} from '@chakra-ui/react'; import dayjs from "dayjs"; import React from "react"; import { BiWrench } from "react-icons/bi"; @@ -23,7 +23,8 @@ import { ScrobbleMatchResult } from "./ScrobbleMatchResult"; import { TimelineErrorIcon } from "./timeline/TimelineIcon"; import { diffElements, TransformSteps } from "./TransformSteps"; import { Muted } from "./Typography"; -import type { PlayEventQueueStateChange } from '../../core/PlayEvent'; +import type { PlayEventPlayStateChange, PlayEventQueueStateChange } from '../../core/PlayEvent'; +import { FaInfo } from "react-icons/fa6"; interface ActivityTimelineProps { @@ -165,24 +166,6 @@ const TransformsItem = (props: Pick ( - - - - - - - - - - - - Play was not transformed because no Transform Rules were used/configured. - - - -) - const ScrobbleMatchItem = (props: Pick & { match: PlayMatchResult }) => { const { match, @@ -345,6 +328,80 @@ const QueueTimelineItem = (props: {queueState: PlayEventQueueStateChange ); } +const StateChangeItem = (props: {event: PlayEventPlayStateChange, collapsibleOpen: boolean}) => { + const { + event: { + data: { + state, + error, + reason + }, + createdAt, + } = {}, + collapsibleOpen, + } = props; + + let color: string; + switch (state) { + case 'discarded': + case 'duped': + color = 'orange'; + break; + case 'discovered': + case 'scrobbled': + color = 'green'; + break; + case 'failed': + color = 'red'; + break; + case 'queued': + color = 'gray'; + break; + } + + const text = State was changed to {capitalizeWords(state)} at {shortTodayAwareFormat(dayjs(createdAt))}; + + let content: React.JSX.Element; + if(error !== null && error !== undefined) { + content = ( + + + {reason !== undefined && reason !== null ? {reason} : null} + + + + ) + } else { + content = (<> + + {text} + + {reason !== undefined && reason !== null ? {reason} : null} + ); + } + + return ( + + + + + + + + + {content} + + + ); + +} + export const ActivityTimeline = (props: ActivityTimelineProps) => { if(props.activity === undefined) { @@ -387,6 +444,9 @@ export const ActivityTimeline = (props: ActivityTimelineProps) => { } break; case 'scrobbleResult': timelineElements.push(); + break; + case 'playStateChange': + timelineElements.push() } } -- 2.51.2