diff --git a/src/client/components/ActivityDetail.tsx b/src/client/components/ActivityDetail.tsx index ab626a66..f9c39b08 100644 --- a/src/client/components/ActivityDetail.tsx +++ b/src/client/components/ActivityDetail.tsx @@ -28,7 +28,6 @@ export const ActivityDetails = (props: ActivityDetailProps) => { } } = props; - debugger; const [collapsibleOpen, setCollapsibleOpen] = useState(undefined); return ( @@ -62,7 +61,7 @@ export const ActivityDetails = (props: ActivityDetailProps) => { - {scrobble !== undefined ? : null} + diff --git a/src/client/components/ActivityTimeline.tsx b/src/client/components/ActivityTimeline.tsx index e5f3257e..6d446ae9 100644 --- a/src/client/components/ActivityTimeline.tsx +++ b/src/client/components/ActivityTimeline.tsx @@ -51,8 +51,6 @@ export const ActivityTimeline = (props: ActivityDetailProps) => { } = {} } = play; - const [scrobbleCollapsibleOpen, setScrobbleCollapsibleOpen] = useState(false); - return ( diff --git a/src/client/components/JsonDiff.tsx b/src/client/components/JsonDiff.tsx index e893d332..e3e7b5cd 100644 --- a/src/client/components/JsonDiff.tsx +++ b/src/client/components/JsonDiff.tsx @@ -24,18 +24,20 @@ export type JsonDiffPatchProps = MarkOptional & { export const JsonDiffPatch = (props: JsonDiffPatchProps) => { const { right, + left, diff, ...rest } = props; + const detachedLeft = JSON.parse(JSON.stringify(left)); let realRight: DiffableVal; if (right !== undefined) { - realRight = right; + realRight = JSON.parse(JSON.stringify(right)); } else if (diff !== undefined) { - realRight = jdiff.patch(props.left, diff as Delta) as DiffableVal; + realRight = jdiff.patch(JSON.parse(JSON.stringify(left)), diff as Delta) as DiffableVal; } else { throw new Error(`must provide either 'right' or 'diff'`); } return - + }; \ No newline at end of file diff --git a/src/client/components/ScrobbleActionResult.tsx b/src/client/components/ScrobbleActionResult.tsx index d1dac7ed..0221a585 100644 --- a/src/client/components/ScrobbleActionResult.tsx +++ b/src/client/components/ScrobbleActionResult.tsx @@ -15,7 +15,7 @@ import { MSCollapsible, MSCollapsibleExternalProps } from "./MSCollapsible"; import { TimelineErrorIcon } from "./timeline/TimelineIcon"; export interface ScrobbleActionResultProps extends MSCollapsibleExternalProps { - result: ScrobbleResult, + result: ScrobbleResult, scrobbler?: string, } diff --git a/src/client/components/TransformSteps.tsx b/src/client/components/TransformSteps.tsx index 03c6cb32..c2f43695 100644 --- a/src/client/components/TransformSteps.tsx +++ b/src/client/components/TransformSteps.tsx @@ -1,5 +1,5 @@ import { ComponentProps, Fragment } from "react" -import { Timeline, Icon, Span, Stack, Heading, Box } from '@chakra-ui/react'; +import { Timeline, Icon, Span, Stack, Heading, Box, Text } from '@chakra-ui/react'; import { JsonPlayObject, LifecycleStep } from "../../core/Atomic"; import { PlayData } from "./PlayData"; import { ErrorAlert } from "./ErrorAlert"; @@ -22,12 +22,8 @@ export const TransformSteps = (props: LifeycleStepsTimelineProps) => { collapsibleOpen } = props; - let currentPlay: JsonPlayObject | false = JSON.parse(JSON.stringify(original)); - if(currentPlay !== false) { - currentPlay.data.meta = { - ...(currentPlay.data.meta ?? {}), - } - } + let currentPlay: JsonPlayObject = JSON.parse(JSON.stringify(original)), + patchFailed = false; return ( @@ -39,27 +35,48 @@ export const TransformSteps = (props: LifeycleStepsTimelineProps) => { name } = x; let err: Error; - const left = currentPlay !== false ? JSON.parse(JSON.stringify(currentPlay)) : false; - if (currentPlay !== false && patch !== undefined) { + + let left: JsonPlayObject; + if(!patchFailed) { + left = JSON.parse(JSON.stringify(currentPlay)); + left.data.meta = { + ...(left.data.meta ?? {}), + brainz: { + ...(left.data.meta?.brainz ?? {}) + } + } + currentPlay.data.meta = { + ...(currentPlay.data.meta ?? {}), + brainz: { + ...(currentPlay.data.meta?.brainz ?? {}) + } + } + } + + if (!patchFailed && patch !== undefined) { try { currentPlay = jdiff.patch(currentPlay, patch) as JsonPlayObject; } catch (e) { err = new Error('Could not patch Play object', { cause: e }); - currentPlay = false; + patchFailed = true; } - } else { - currentPlay = false; } let diffElm: JSX.Element; - if(left !== false && currentPlay !== false) { - diffElm = - - ; - } else if(patch !== undefined) { - diffElm = ; + + if(err) { + diffElm = + } else if(patch === undefined) { + diffElm = Play was identical after Transform. + } else if(patchFailed) { + diffElm = + } else { + diffElm = + + ; } + const showAnyDetails = inputs !== undefined || diffElm !== undefined || err !== undefined; - return + return @@ -75,14 +92,14 @@ export const TransformSteps = (props: LifeycleStepsTimelineProps) => { {showAnyDetails ? - {err !== undefined ? : null} - {diffElm !== undefined ? Diff{diffElm} : null } + Diff + {diffElm} {inputs !== undefined ? ( Inputs - {x.inputs.map((y) => { - return + {x.inputs.map((y, inputsIndex) => { + return })} ) : null} @@ -91,7 +108,7 @@ export const TransformSteps = (props: LifeycleStepsTimelineProps) => { })} {currentPlay !== false ? ( - + diff --git a/src/core/Atomic.ts b/src/core/Atomic.ts index 7dd123be..61789966 100644 --- a/src/core/Atomic.ts +++ b/src/core/Atomic.ts @@ -288,20 +288,20 @@ export interface PlayObjectLifecycleless { export type ErrorLike = Error | ErrorObject; -export interface ScrobbleResult { - match?: PlayMatchResult +export interface ScrobbleResult { + match?: PlayMatchResult payload?: ScrobblePayload warnings?: string[] error?: Error | ErrorObject response?: ScrobbleResponse - mergedScrobble?: PlayObjectLifecycleless + mergedScrobble?: PlayObjectLifecycleless } export interface PlayLifecycle { input?: object original: PlayObjectLifecycleless steps: LifecycleStep[] - scrobble?: ScrobbleResult + scrobble?: ScrobbleResult } export interface LifecycleStep { @@ -314,10 +314,10 @@ export interface LifecycleStep { export type ScrobblePayload = object | string; export type ScrobbleResponse = object | string; -export interface ScrobbleActionResult { +export interface ScrobbleActionResult { payload: ScrobblePayload, response?: ScrobbleResponse, - mergedScrobble?: PlayObject + mergedScrobble?: AmbPlayObject warnings?: string[] } diff --git a/src/core/tests/utils/fixtures.ts b/src/core/tests/utils/fixtures.ts index 4f781b2e..9ce1bbfa 100644 --- a/src/core/tests/utils/fixtures.ts +++ b/src/core/tests/utils/fixtures.ts @@ -98,6 +98,10 @@ export interface GeneratePlayWithLifecycleOptions { data?: ObjectPlayData, meta?: MarkOptional opts?: GeneratePlayOpts + }, + lifecycleSteps?: { + preCompare?: boolean | number + postCompare?: boolean | number } } @@ -105,6 +109,10 @@ export const generatePlayWithLifecycle = (opts: GeneratePlayWithLifecycleOptions const { original: originalOpts = {}, + lifecycleSteps: { + preCompare = true, + postCompare = true + } = {} } = opts; const original = generatePlay(originalOpts.data, originalOpts.meta, originalOpts.opts); @@ -120,25 +128,42 @@ export const generatePlayWithLifecycle = (opts: GeneratePlayWithLifecycleOptions let steps: LifecycleStep[] = []; let transformedPlay = clone(original); - const firstStep = faker.datatype.boolean(0.7) ? generateLifecycleStep(transformedPlay, {name: 'preCompare'}) : undefined; - if(firstStep !== undefined) { - transformedPlay = firstStep[1]; - steps.push(firstStep[0]); - while(faker.datatype.boolean(0.2)) { - const [pc, modified] = generateLifecycleStep(transformedPlay, {name: 'preCompare'}); - steps.push(pc); - transformedPlay = modified; + + if(typeof preCompare === 'number') { + for(let i = 0; i < preCompare; i++) { + const step = generateLifecycleStep(transformedPlay, {name: 'preCompare'}); + steps.push(step[0]); + transformedPlay = step[1]; + } + } else if(preCompare === true) { + const firstStep = faker.datatype.boolean(0.7) ? generateLifecycleStep(transformedPlay, {name: 'preCompare'}) : undefined; + if(firstStep !== undefined) { + transformedPlay = firstStep[1]; + steps.push(firstStep[0]); + while(faker.datatype.boolean(0.2)) { + const [pc, modified] = generateLifecycleStep(transformedPlay, {name: 'preCompare'}); + steps.push(pc); + transformedPlay = modified; + } } } - const lastStep = faker.datatype.boolean(0.5) ? generateLifecycleStep(transformedPlay, {name: 'postCompare'}) : undefined; - if(lastStep !== undefined) { - transformedPlay = lastStep[1]; - steps.push(lastStep[0]); - while(faker.datatype.boolean(0.1)) { - const [pc, modified] = generateLifecycleStep(transformedPlay, {name: 'postCompare'}); - steps.push(pc); - transformedPlay = modified; + if(typeof postCompare === 'number') { + for(let i = 0; i < postCompare; i++) { + const step = generateLifecycleStep(transformedPlay, {name: 'postCompare'}); + steps.push(step[0]); + transformedPlay = step[1]; + } + } else if(postCompare === true) { + const lastStep = faker.datatype.boolean(0.5) ? generateLifecycleStep(transformedPlay, {name: 'postCompare'}) : undefined; + if(lastStep !== undefined) { + transformedPlay = lastStep[1]; + steps.push(lastStep[0]); + while(faker.datatype.boolean(0.1)) { + const [pc, modified] = generateLifecycleStep(transformedPlay, {name: 'postCompare'}); + steps.push(pc); + transformedPlay = modified; + } } } diff --git a/src/stories/TransformSteps.stories.tsx b/src/stories/TransformSteps.stories.tsx new file mode 100644 index 00000000..460cf295 --- /dev/null +++ b/src/stories/TransformSteps.stories.tsx @@ -0,0 +1,39 @@ +import preview from "../../.storybook/preview.js"; +import React from 'react'; + +import { fn } from 'storybook/test'; +import { Container } from '@chakra-ui/react'; +import { TransformSteps } from "../client/components/TransformSteps.js"; +import {Provider} from "../client/components/Provider"; +import { generateJsonPlays } from "../core/PlayTestUtils.js"; +import { ErrorLike, JsonPlayObject, PlayLifecycle } from "../core/Atomic.js"; +import { examplePlay, lastfmErrorExample } from "./storyUtils.js"; +import {generatePlayWithLifecycle} from '../core/tests/utils/fixtures' + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export +const meta = preview.meta({ + title: 'Examples/TransformSteps', + component: TransformSteps, + parameters: { + // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout + layout: 'padded', + }, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + // More on argTypes: https://storybook.js.org/docs/api/argtypes +decorators: [ + (Story) => (), + ] + // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args +}); + +const multiPlay = generatePlayWithLifecycle({lifecycleSteps: { preCompare: 2}}); +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Multiple = meta.story({ + args: { + steps: multiPlay.meta.lifecycle.steps, + original: multiPlay.meta.lifecycle.original, + collapsibleOpen: true + } + //render: function Render(args) { return () } +});