From 5dc19be8fecc1d215f3d11d5b56bab7fd281582a Mon Sep 17 00:00:00 2001 From: Mattias Granlund Date: Thu, 12 Oct 2023 21:24:28 +0200 Subject: [PATCH] Fix the rewind functionality - Shift+Cmd+R when viewing virtual branches to switch to rewind - Same combo to switch back to virtual branches - Not everything is great, but it's a start --- .../src/lib/components/Differ/Differ.svelte | 12 +- packages/ui/src/lib/stores/bookmarks.ts | 51 +++---- packages/ui/src/lib/stores/deltas.ts | 20 +-- packages/ui/src/lib/stores/files.ts | 37 ----- .../projects/[projectId]/+layout.svelte | 4 +- .../routes/projects/[projectId]/+layout.ts | 3 +- .../routes/projects/[projectId]/+page.svelte | 20 +-- .../projects/[projectId]/FileSummaries.svelte | 35 +++-- .../[projectId]/player/+layout.svelte | 13 +- .../projects/[projectId]/player/+page.ts | 4 +- .../[projectId]/player/[date]/+layout.svelte | 66 +++------ .../[projectId]/player/[date]/+layout.ts | 140 +++++++++++++++++- .../player/[date]/SessionCard.svelte | 37 +++-- .../player/[date]/SessionNavigations.svelte | 86 +++++------ .../player/[date]/SessionsList.svelte | 38 ++--- .../player/[date]/[sessionId]/+page.svelte | 130 ++++------------ .../player/[date]/[sessionId]/Frame.svelte | 36 ++--- .../player/[date]/[sessionId]/Info.svelte | 24 +-- .../player/[date]/[sessionId]/Playback.svelte | 20 +-- .../player/[date]/[sessionId]/Slider.svelte | 36 ++--- .../src/routes/repo/[projectId]/+page.svelte | 14 +- .../routes/repo/[projectId]/FileCard.svelte | 2 - 22 files changed, 382 insertions(+), 446 deletions(-) delete mode 100644 packages/ui/src/lib/stores/files.ts diff --git a/packages/ui/src/lib/components/Differ/Differ.svelte b/packages/ui/src/lib/components/Differ/Differ.svelte index acd6d904d..55d6d2069 100644 --- a/packages/ui/src/lib/components/Differ/Differ.svelte +++ b/packages/ui/src/lib/components/Differ/Differ.svelte @@ -199,7 +199,7 @@
{#each rows as row} @@ -211,24 +211,20 @@ row.type === RowType.Equal || row.type === RowType.Addition ? String(row.currentLineNumber) : ''} - +
{baseNumber}
- +
{curNumber}
{#each row.render.html as content} diff --git a/packages/ui/src/lib/stores/bookmarks.ts b/packages/ui/src/lib/stores/bookmarks.ts index 01d9c39f5..f99649e3b 100644 --- a/packages/ui/src/lib/stores/bookmarks.ts +++ b/packages/ui/src/lib/stores/bookmarks.ts @@ -1,36 +1,29 @@ -import { writable, type Loadable, derived, Loaded } from 'svelte-loadable-store'; import * as bookmarks from '$lib/api/ipc/bookmarks'; -import { get as getValue, type Readable } from '@square/svelte-store'; +import { type Loadable, asyncWritable, asyncDerived } from '@square/svelte-store'; -const stores: Partial>>> = {}; - -export function getBookmarksStore(params: { - projectId: string; -}): Readable> { - const cached = stores[params.projectId]; - if (cached) return cached; - - const store = writable(bookmarks.list(params), (set) => { - const unsubscribe = bookmarks.subscribe(params, (bookmark) => { - const oldValue = getValue(store); - if (oldValue.isLoading) { - bookmarks.list(params).then(set); - } else if (Loaded.isError(oldValue)) { - bookmarks.list(params).then(set); - } else { - set(oldValue.value.filter((b) => b.timestampMs !== bookmark.timestampMs).concat(bookmark)); - } - }); - return () => { - Promise.resolve(unsubscribe).then((unsubscribe) => unsubscribe()); - }; - }); - stores[params.projectId] = store; - return store as Readable>; +export function getBookmarksStore(params: { projectId: string }): Loadable { + return asyncWritable( + [], + async () => await bookmarks.list(params), + undefined, + { trackState: true }, + (set, update) => { + const unsubscribe = bookmarks.subscribe(params, (bookmark) => { + update((oldValue) => + oldValue.filter((b) => b.timestampMs !== bookmark.timestampMs).concat(bookmark) + ); + }); + return () => { + Promise.resolve(unsubscribe).then((unsubscribe) => unsubscribe()); + }; + } + ); } export function getBookmark(params: { projectId: string; timestampMs: number }) { - return derived(getBookmarksStore({ projectId: params.projectId }), (bookmarks) => - bookmarks.find((b) => b.timestampMs === params.timestampMs) + return asyncDerived( + getBookmarksStore({ projectId: params.projectId }), + async (bookmarks) => bookmarks.find((b) => b.timestampMs === params.timestampMs), + { trackState: true } ); } diff --git a/packages/ui/src/lib/stores/deltas.ts b/packages/ui/src/lib/stores/deltas.ts index 109b3b263..778b3064b 100644 --- a/packages/ui/src/lib/stores/deltas.ts +++ b/packages/ui/src/lib/stores/deltas.ts @@ -1,6 +1,5 @@ -import { asyncWritable, isReloadable } from '@square/svelte-store'; +import { asyncWritable, isReloadable, type AsyncWritable, type Stores } from '@square/svelte-store'; import { subscribeToDeltas, type Delta, listDeltas } from '$lib/api/ipc/deltas'; -import type { Stores, Writable } from 'svelte/store'; /** * We have a special situation here where we use deltas to know when to re-run @@ -10,20 +9,23 @@ import type { Stores, Writable } from 'svelte/store'; */ export function getDeltasStore( projectId: string, - sessionId: string | undefined = undefined -): Writable>> & { setSessionId: (sid: string) => void } { + sessionId: string | undefined = undefined, + subscribe = false +): AsyncWritable>> & { setSessionId: (sid: string) => void } { let unsubscribe: () => void; const store = asyncWritable>>( [], async () => { if (!sessionId) return {}; if (unsubscribe) unsubscribe(); - unsubscribe = subscribeToDeltas(projectId, sessionId, ({ filePath, deltas }) => { - store.update((storeValue) => { - storeValue[filePath] = [...(storeValue[filePath] || []), ...deltas]; - return storeValue; + if (subscribe) { + unsubscribe = subscribeToDeltas(projectId, sessionId, ({ filePath, deltas }) => { + store.update((storeValue) => { + storeValue[filePath] = [...(storeValue[filePath] || []), ...deltas]; + return storeValue; + }); }); - }); + } return await listDeltas({ projectId, sessionId }); }, undefined, diff --git a/packages/ui/src/lib/stores/files.ts b/packages/ui/src/lib/stores/files.ts deleted file mode 100644 index 087e50ad3..000000000 --- a/packages/ui/src/lib/stores/files.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { writable, type Loadable, Loaded } from 'svelte-loadable-store'; -import * as files from '$lib/api/ipc/files'; -import { get, type Readable } from '@square/svelte-store'; - -type Files = Partial>; - -const stores: Partial>>> = {}; - -export function getFilesStore(params: { - projectId: string; - sessionId: string; -}): Readable> { - const key = `${params.projectId}/${params.sessionId}`; - const cached = stores[key]; - if (cached) return cached; - - const store = writable(files.list(params), (set) => { - const unsubscribe = files.subscribe(params, ({ filePath, contents }) => { - const oldValue = get(store); - if (oldValue.isLoading) { - files.list(params).then(set); - } else if (Loaded.isError(oldValue)) { - files.list(params).then(set); - } else { - set({ - ...oldValue.value, - [filePath]: contents || undefined - }); - } - }); - return () => { - Promise.resolve(unsubscribe).then((unsubscribe) => unsubscribe()); - }; - }); - stores[key] = store; - return store as Readable>; -} diff --git a/packages/ui/src/routes/projects/[projectId]/+layout.svelte b/packages/ui/src/routes/projects/[projectId]/+layout.svelte index e66e13f41..ed67cf5ce 100644 --- a/packages/ui/src/routes/projects/[projectId]/+layout.svelte +++ b/packages/ui/src/routes/projects/[projectId]/+layout.svelte @@ -63,7 +63,7 @@
  • -
    +
    diff --git a/packages/ui/src/routes/projects/[projectId]/FileSummaries.svelte b/packages/ui/src/routes/projects/[projectId]/FileSummaries.svelte index 0be63ce20..0e79580a1 100644 --- a/packages/ui/src/routes/projects/[projectId]/FileSummaries.svelte +++ b/packages/ui/src/routes/projects/[projectId]/FileSummaries.svelte @@ -2,7 +2,6 @@ import { format, startOfDay } from 'date-fns'; import type { Delta } from '$lib/api/ipc/deltas'; import { generateBuckets } from './histogram'; - import { derived, Loaded } from 'svelte-loadable-store'; import FileActivity from './FileActivity.svelte'; import { page } from '$app/stores'; import { Link } from '$lib/components'; @@ -10,13 +9,14 @@ import { collapse } from '$lib/paths'; import type { Session } from '$lib/api/ipc/sessions'; import { getDeltasStore } from '$lib/stores/deltas'; + import { asyncDerived } from '@square/svelte-store'; export let sessions: Session[]; $: sessionDeltas = (sessions ?? []).map(({ id, projectId }) => getDeltasStore(projectId, id)); - $: deltasByDate = derived(sessionDeltas, (sessionDeltas) => - sessionDeltas.reduce( + $: deltasByDate = asyncDerived(sessionDeltas, async (sessionDeltas) => { + return sessionDeltas.reduce( (acc, sessionDelta) => { Object.entries(sessionDelta).forEach(([filepath, deltas]) => { if (!deltas) return; @@ -28,10 +28,11 @@ return acc; }, {} as Record> - ) - ); + ); + }); + $: deltasByDateState = deltasByDate?.state; - $: buckets = derived(sessionDeltas, (sessionDeltas) => { + $: buckets = asyncDerived(sessionDeltas, async (sessionDeltas) => { const deltas = sessionDeltas.flatMap((deltas) => Object.values(deltas).flat() as Delta[]); const timestamps = deltas.map((delta) => delta.timestampMs); return generateBuckets(timestamps, 18); @@ -39,14 +40,14 @@