diff --git a/src/client/components/ActivityTimeline.tsx b/src/client/components/ActivityTimeline.tsx index 6d446ae9..1823e71e 100644 --- a/src/client/components/ActivityTimeline.tsx +++ b/src/client/components/ActivityTimeline.tsx @@ -1,4 +1,4 @@ -import { ComponentProps, useState } from "react" +import { ComponentProps, useState, Fragment } from "react" import { Accordion, Timeline, Icon, Span, Stack, Heading, Card, Box, Tabs } from '@chakra-ui/react'; import { ErrorLike, JsonPlayObject, PlayActivity } from "../../core/Atomic"; import { PlayData } from "./PlayData"; @@ -19,6 +19,7 @@ import { ScrobbleActionResult } from "./ScrobbleActionResult"; import { ExpandCollapse } from "./ExpandCollapse"; import { MSCollapsible } from "./MSCollapsible"; import { TimelineErrorIcon } from "./timeline/TimelineIcon"; +import { Muted } from "./Typography"; export interface ActivityDetailProps { @@ -44,13 +45,29 @@ export const ActivityTimeline = (props: ActivityDetailProps) => { scrobble: { match, payload, - error + error, + warnings = [] } = {}, scrobble }, } = {} } = play; + let scrobbleSummary: JSX.Element, + scrobbleIconProps: Record = { + color: 'green.focusRing' + }; + if (payload !== undefined) { + if (error !== undefined) { + scrobbleSummary = Scrobble attempt to Client resulted in an error. + } else if (warnings.length > 0) { + scrobbleSummary = Scrobbled to Client but response has warnings.; + scrobbleIconProps.orange = 'orange.focusRing'; + } else { + scrobbleSummary = Scrobbled to Client successfully.; + } + } + return ( @@ -64,26 +81,31 @@ export const ActivityTimeline = (props: ActivityDetailProps) => { - Discovered new (Play) activity from - {capitalize(source)} - at {shortTodayAwareFormat(dayjs(playDate))} + + Discovered new (Play) activity from {capitalize(source)} at {shortTodayAwareFormat(dayjs(playDate))} + } + defaultOpen={collapsibleOpen} + timeline + disableUntil="md"> + + + + + Play + Source Data + + + + + + + + + + + - - - - - Play - Source Data - - - - - - - - - - {steps.length > 0 ? ( @@ -98,16 +120,36 @@ export const ActivityTimeline = (props: ActivityDetailProps) => { - Transformed Play using configured Rules + Transformed Play using configured Rules} + defaultOpen={collapsibleOpen} + timeline> + + + + + + - - - - - - ) : null} + ) : ( + + + + + + + + + + + + Play was not transformed because no Transform Rules were used/configured. + + + + )} {match !== undefined ? ( @@ -120,15 +162,18 @@ export const ActivityTimeline = (props: ActivityDetailProps) => { - Found {match.match ? a duplicate Scrobble : 'no duplicate Scrobbles'} + Found {match.match ? a duplicate Scrobble : 'no duplicate Scrobbles'}} + defaultOpen={collapsibleOpen} + disableUntil="md" + timeline> + + + + + + - - - - - - - ) : null} @@ -138,7 +183,7 @@ export const ActivityTimeline = (props: ActivityDetailProps) => { {error !== undefined ? : ( - + )} @@ -146,13 +191,18 @@ export const ActivityTimeline = (props: ActivityDetailProps) => { - Attmpted to Scrobble + + + + + + + - - - - - ) : null} diff --git a/src/client/components/MSCollapsible.tsx b/src/client/components/MSCollapsible.tsx index 961c80c9..bbcb7c74 100644 --- a/src/client/components/MSCollapsible.tsx +++ b/src/client/components/MSCollapsible.tsx @@ -1,5 +1,6 @@ -import { Collapsible, Stack, Box } from "@chakra-ui/react" -import { ComponentProps, PropsWithChildren, useState, useEffect } from "react"; +import { Collapsible, Stack, Box, useBreakpointValue } from "@chakra-ui/react" +import { diff } from "jsondiffpatch"; +import { ComponentProps, PropsWithChildren, useState, useEffect, useMemo } from "react"; import { LuChevronRight } from "react-icons/lu" //padding="0" borderWidth="0px" @@ -7,39 +8,119 @@ import { LuChevronRight } from "react-icons/lu" interface MSCollapsibleInternalProps { indicator?: string | JSX.Element boxProps?: object + triggerProps?: object + indicatorProps?: object + timeline?: boolean + disableUntil?: string } export interface MSCollapsibleExternalProps { collapsibleOpen?: boolean } +export const timelineCollapsibleProps = { + indicatorProps: { paddingBottom: '4px' }, + triggerProps: { paddingBlockStart: "0.3em" } +} + export type MSCollapsibleProps = PropsWithChildren> & MSCollapsibleInternalProps; +const breakpoints = ['base','sm','md','lg','xl']; + export const MSCollapsible = (props: MSCollapsibleProps) => { const { indicator = 'Details', + disabled, + disableUntil, boxProps = {}, + triggerProps = {}, + indicatorProps = {}, + timeline = false, defaultOpen, ...rest } = props; - const [open, setOpen] = useState(defaultOpen) + const breakObj = useMemo(() => { + if(disableUntil === undefined) { + return { + base: false, + sm: false, + md: false, + lg: false, + xl: false + }; + } + const breaks: Record = {}; + let found = false; + for(const b of breakpoints) { + if(!found && disableUntil !== b) { + breaks[b] = true; + found = true; + } else { + breaks[b] = false; + } + } + return breaks; + }, [disableUntil]) + + const disableByBreakpoint = useBreakpointValue( + { + '2xl': false, + ...breakObj, + }, { + fallback: '2xl' + }); + + const currBreakpoint = useBreakpointValue( + { + base: "base", + sm: "sm", + md: "md", + lg: "lg", + xl: "xl", + ["2xl"]: "2xl" + }, { + fallback: '2xl' + }); + + const [open, setOpen] = useState(defaultOpen); + const [isDisabled, setDisabled] = useState(disabled); useEffect(() => { setOpen(defaultOpen); }, [setOpen, defaultOpen]); + useEffect(() => { + if (disabled !== undefined) { + setDisabled(disabled); + } else { + setDisabled(disableByBreakpoint); + } + }, [disableByBreakpoint, disabled]) + + const iProps = { ...(timeline ? timelineCollapsibleProps.indicatorProps : {}), ...indicatorProps }; + if (isDisabled) { + // @ts-ignore + iProps.display = 'none'; + } + + const tProps = { ...(timeline ? timelineCollapsibleProps.triggerProps : {}), ...triggerProps } + return ( - setOpen(val.open)} {...rest}> + setOpen(val.open)} flexGrow="1" disabled={isDisabled} {...rest}> @@ -52,4 +133,4 @@ export const MSCollapsible = (props: MSCollapsibleProps) => { ) -} +} \ No newline at end of file diff --git a/src/client/components/ScrobbleActionResult.tsx b/src/client/components/ScrobbleActionResult.tsx index 0221a585..4e342ea1 100644 --- a/src/client/components/ScrobbleActionResult.tsx +++ b/src/client/components/ScrobbleActionResult.tsx @@ -63,11 +63,13 @@ export const ScrobbleActionResult = (props: ScrobbleActionResultProps) => { - Sent Scrobble Payload{scrobbler !== undefined ? to {capitalize(scrobbler)} : null} + Sent Scrobble Payload{scrobbler !== undefined ? to {capitalize(scrobbler)} : null}} + defaultOpen={collapsibleOpen} + disableUntil="md" + timeline> + + - - - {response !== undefined || error !== undefined ? ( @@ -84,27 +86,30 @@ export const ScrobbleActionResult = (props: ScrobbleActionResultProps) => { - Received Response{scrobbler !== undefined ? from {capitalize(scrobbler)} : null}{responseSuffix !== undefined ? {responseSuffix} : null} + Received Response{scrobbler !== undefined ? from {capitalize(scrobbler)} : null}{responseSuffix !== undefined ? {responseSuffix} : null}} + timeline + defaultOpen={collapsibleOpen} + disableUntil="md"> + + {error !== undefined ? : null} + {response !== undefined ? : null} + {warnings.length > 0 ? ( + + + + Warnings in Response + + + {warnings.map((x) => {x})} + + + + + ) : null} + + - - - {error !== undefined ? : null} - {response !== undefined ? : null} - {warnings.length > 0 ? ( - - - - Warnings in Response - - - {warnings.map((x) => {x})} - - - - - ) : null} - - ) : null} diff --git a/src/client/components/TransformSteps.tsx b/src/client/components/TransformSteps.tsx index 9e1c4c54..1958ad3b 100644 --- a/src/client/components/TransformSteps.tsx +++ b/src/client/components/TransformSteps.tsx @@ -148,10 +148,12 @@ export const TransformSteps = (props: LifeycleStepsTimelineProps) => { - {name} with {source} {summary} - - - {error !== undefined ? : null} + {name} with {source} {summary}} + defaultOpen={collapsibleOpen} + disableUntil="md" + timeline> + {error !== undefined ? : null} {diffs[index] !== null ? ( @@ -167,7 +169,8 @@ export const TransformSteps = (props: LifeycleStepsTimelineProps) => { })} ) : null} - + + })} diff --git a/src/stories/List.stories.tsx b/src/stories/List.stories.tsx index 1440a66f..171aaa02 100644 --- a/src/stories/List.stories.tsx +++ b/src/stories/List.stories.tsx @@ -57,7 +57,7 @@ export const List = meta.story({ loaders: [ async () => { const queued = await generatePlayWithLifecycle(); - const scrobbled = await playWithLifecycleScrobble(generatePlayWithLifecycle()); + const scrobbled = await playWithLifecycleScrobble(generatePlayWithLifecycle({lifecycleSteps: {preCompare: [true, 'skipped', true]}})); const scrobbleError = await playWithLifecycleScrobble(generatePlayWithLifecycle(), {error: true}); return {data: [ {play: queued, status: 'queued'},