diff --git a/client/src/client/internal.ts b/client/src/client/internal.ts index 4e6f494..4c16236 100644 --- a/client/src/client/internal.ts +++ b/client/src/client/internal.ts @@ -76,7 +76,6 @@ export const internal: Dictionary = { const map = find(maps, { id: params?.id }); if (map) { const file = await fetch(map.path); - console.log(map); return { ...map, content: await file.text(), diff --git a/client/src/components/renderer/parser-v140/parseTrace.ts b/client/src/components/renderer/parser-v140/parseTrace.ts index 0f78477..d3abff3 100644 --- a/client/src/components/renderer/parser-v140/parseTrace.ts +++ b/client/src/components/renderer/parser-v140/parseTrace.ts @@ -1,7 +1,7 @@ import { useSnackbar } from "components/generic/Snackbar"; import { get } from "lodash"; import pluralize from "pluralize"; -import { useCallback } from "react"; +import { useCallback, useMemo } from "react"; import { useLoadingState } from "slices/loading"; import { usingMemoizedWorkerTask } from "workers/usingWorker"; import parseTraceWorkerLegacyUrl from "../parser/parseTrace.worker.ts?worker&url"; @@ -37,14 +37,15 @@ export const parseTraceLegacyAsync = usingMemoizedWorkerTask< >(ParseTraceWorkerLegacy); export function useTraceParser( - params: ParseTraceWorkerParameters | ParseTraceWorkerLegacyParameters + params: ParseTraceWorkerParameters | ParseTraceWorkerLegacyParameters, + deps: any[] ) { const push = useSnackbar(); const usingLoadingState = useLoadingState("specimen"); - return useCallback( - () => - usingLoadingState(async () => { - if (params?.trace) { + return useMemo(() => { + if (params.trace) { + return () => + usingLoadingState(async () => { push("Processing trace..."); try { const output = @@ -63,8 +64,9 @@ export function useTraceParser( push("Error parsing", get(e, "message")); return { error: get(e, "message") }; } - } - }), - [params] - ); + }); + } else { + return undefined; + } + }, deps); } diff --git a/client/src/hooks/useEffectWhen.tsx b/client/src/hooks/useEffectWhen.tsx index bf3f4da..c5e8bf2 100644 --- a/client/src/hooks/useEffectWhen.tsx +++ b/client/src/hooks/useEffectWhen.tsx @@ -1,26 +1,22 @@ import { zip } from "lodash"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useState } from "react"; import { useAsyncAbortable } from "react-async-hook"; +import { usePrevious } from "react-use"; export const useEffectWhen = ( effect: () => void, deps: any[], - whenDeps: any[] + watch: any[] ) => { - const whenRef = useRef(whenDeps || []); - const initial = whenRef.current === whenDeps; - const whenDepsChanged = - initial || !whenRef.current.every((w, i) => w === whenDeps[i]); - whenRef.current = whenDeps; - const nullDeps = deps.map(() => null); - - return useEffect( - whenDepsChanged ? () => void effect() : () => {}, - whenDepsChanged ? deps : nullDeps - ); + const prev = usePrevious(watch); + return useEffect(() => { + if (!allSame(watch, prev)) { + effect(); + } + }, [deps]); }; -function allSame(a: any[], b: any[]) { +function allSame(a?: any[], b?: any[]) { return zip(a, b).every(([x, y]) => x === y); } diff --git a/client/src/hooks/useTraceContent.tsx b/client/src/hooks/useTraceContent.tsx index 209bdd1..4d499a3 100644 --- a/client/src/hooks/useTraceContent.tsx +++ b/client/src/hooks/useTraceContent.tsx @@ -1,12 +1,12 @@ import { useSnackbar } from "components/generic/Snackbar"; +import { find } from "lodash"; import memo from "memoizee"; import { useMemo } from "react"; import { useAsync } from "react-async-hook"; import { UploadedTrace } from "slices/UIState"; +import { useFeatures } from "slices/features"; import { useLoadingState } from "slices/loading"; import { useConnectionResolver } from "./useConnectionResolver"; -import { find } from "lodash"; -import { useFeatures } from "slices/features"; export function useTraceContent(trace?: UploadedTrace) { const notify = useSnackbar(); @@ -34,7 +34,7 @@ export function useTraceContent(trace?: UploadedTrace) { [resolve, notify] ); - const { content, source, id } = trace ?? {}; + const { content, source, id, key } = trace ?? {}; const { lastModified } = find(traces, { id, source }) ?? {}; return useAsync( @@ -48,6 +48,6 @@ export function useTraceContent(trace?: UploadedTrace) { : await getTrace({ source, id, lastModified }), }; }), - [getTrace, content, source, id, lastModified] + [getTrace, !!content, key, source, id, lastModified] ); } diff --git a/client/src/layers/trace/index.tsx b/client/src/layers/trace/index.tsx index b93886e..a10cda5 100644 --- a/client/src/layers/trace/index.tsx +++ b/client/src/layers/trace/index.tsx @@ -237,39 +237,47 @@ export const controller = { }), service: withProduce(({ value, produce }) => { const { palette } = useTheme(); - const { result: trace } = useTraceContent(value?.source?.trace); - const parseTrace = useTraceParser({ - trace: trace?.content, - context: { - theme: { - foreground: palette.text.primary, - background: palette.background.paper, - accent: palette.primary.main, - }, - color: { - ...colorsHex, - ...mapValues(accentColors, (_, v: AccentColor) => - getShade(v, palette.mode, 500, 400) - ), - }, - themeAccent: palette.primary.main, - themeTextPrimary: palette.text.primary, - themeBackground: palette.background.paper, - }, - view: "main", - }); + const { result: trace, loading } = useTraceContent(value?.source?.trace); + // Set playback useEffect(() => { produce((l) => { return set(l, "source.playbackTo", trace?.content?.events?.length ?? 0); }); - }, [trace?.key, trace?.lastModified]); + }, [trace?.key]); + // Make the trace parser + const parseTrace = useTraceParser( + { + trace: trace?.content, + context: { + theme: { + foreground: palette.text.primary, + background: palette.background.paper, + accent: palette.primary.main, + }, + color: { + ...colorsHex, + ...mapValues(accentColors, (_, v: AccentColor) => + getShade(v, palette.mode, 500, 400) + ), + }, + themeAccent: palette.primary.main, + themeTextPrimary: palette.text.primary, + themeBackground: palette.background.paper, + }, + view: "main", + }, + [trace?.key, palette.mode] + ); + // Parse the trace useAsync(async () => { - const parsedTrace = await parseTrace(); - produce((l) => { - set(l, "source.parsedTrace", parsedTrace); - set(l, "viewKey", id()); - }); - }, [trace?.key, palette.mode]); + if (parseTrace && !loading) { + const parsedTrace = await parseTrace(); + produce((l) => { + set(l, "source.parsedTrace", parsedTrace); + // set(l, "viewKey", id()); + }); + } + }, [loading, parseTrace]); return ( <> diff --git a/client/src/services/SyncParticipant.tsx b/client/src/services/SyncParticipant.tsx index 1af4e95..70e173e 100644 --- a/client/src/services/SyncParticipant.tsx +++ b/client/src/services/SyncParticipant.tsx @@ -52,6 +52,7 @@ export class SyncParticipant extends EventEmitter<"sync"> { constructor() { super(); const checkChannels = throttle(async () => { + // TODO: Fix subtle race condition issues const getChannel = async (peer: string) => { if (peer !== instance) { try { diff --git a/client/src/services/SyncService.tsx b/client/src/services/SyncService.tsx index 42628b1..6fdf5e1 100644 --- a/client/src/services/SyncService.tsx +++ b/client/src/services/SyncService.tsx @@ -79,7 +79,7 @@ export function SyncService() { // Any changes useEffectWhen( () => { - if (previous && participants.length) { + if (previous && participants.length && c2 !== previous) { broadCastLayers("layers", { initiator: instance, state: { layers }, @@ -87,7 +87,7 @@ export function SyncService() { }); } }, - [c2, participants.length], + [layers, c2, participants.length], [previous, c2] ); // Primary broadcasts to new @@ -101,7 +101,7 @@ export function SyncService() { }); } }, - [c2, participants.length, isOnly, isPrimary], + [layers, c2, participants.length, isOnly, isPrimary], [participants.length] );