mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-11-29 06:18:12 +03:00
Increase selection and recording functionality
- Added a button to each delta for selection - Updated the `session` store to return the first session if the sessionId is not found - Updated the `previousSession` store to return the session before the current one if it exists - Updated the `docsNext` derived store to include the `selection` store - Added an `if` statement for `files` in `+page.svelte` [src/routes/projects/[projectId]/sessions/[sessionId]/+page.ts] - Changed the import of `svelte/store` to include `writable` - Changed the `session` store to return the first session if the sessionId is not found - Changed the `previousSession` store to return the session before the current one if it exists [src/routes/projects/[projectId]/sessions/[sessionId]/+page.svelte] - Move the `Timeline` component import from `+page.svelte` - Initialize `selection` store in `+page.svelte` - Update `docsNext` derived store to include the `selection` store - Add a button to each delta for selection - Add an `if` statement for `files` in `+page.svelte` - Delete `contentWithDeltasApplied` function from `+page.
This commit is contained in:
parent
5697b204cb
commit
c5c46e8a25
@ -1,9 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { Doc } from "yjs";
|
||||
import { Timeline, CodeViewer } from "$lib/components";
|
||||
import { CodeViewer } from "$lib/components";
|
||||
import { Operation } from "$lib/deltas";
|
||||
import type { Delta } from "$lib/deltas";
|
||||
import { derived, writable } from "svelte/store";
|
||||
import { derived } from "svelte/store";
|
||||
import type { PageData } from "./$types";
|
||||
import SessionNav from "$lib/components/session/SessionNav.svelte";
|
||||
import { toHumanReadableTime } from "$lib/time";
|
||||
@ -15,21 +14,32 @@
|
||||
$: nextSession = data.nextSession;
|
||||
$: session = data.session;
|
||||
$: deltas = data.deltas;
|
||||
$: files = data.files;
|
||||
|
||||
const value = writable(new Date().getTime());
|
||||
$: selection = {} as Record<string, Record<string, number>>;
|
||||
|
||||
const docs = derived(value, (value) =>
|
||||
$: docsNext = derived([data.deltas], ([deltas]) =>
|
||||
Object.fromEntries(
|
||||
Object.entries($deltas).map(([filePath, deltas]) => {
|
||||
Object.entries(deltas).map(([filePath, deltas]) => {
|
||||
const doc = new Doc();
|
||||
const text = doc.getText();
|
||||
if (filePath in files) {
|
||||
text.insert(0, files[filePath]);
|
||||
if (filePath in data.files) {
|
||||
text.insert(0, data.files[filePath]);
|
||||
}
|
||||
const contentAtStart = text.toString();
|
||||
|
||||
if (!selection.hasOwnProperty($session?.id)) {
|
||||
selection[$session.id] = {};
|
||||
}
|
||||
if (!selection[$session.id].hasOwnProperty(filePath)) {
|
||||
selection[$session?.id][filePath] = deltas.length - 1;
|
||||
}
|
||||
|
||||
const operations = deltas
|
||||
.filter((delta) => delta.timestampMs <= value)
|
||||
.filter(
|
||||
(_, index) => index <= selection[$session.id][filePath]
|
||||
)
|
||||
.flatMap((delta) => delta.operations);
|
||||
|
||||
operations.forEach((operation) => {
|
||||
if (Operation.isInsert(operation)) {
|
||||
text.insert(operation.insert[0], operation.insert[1]);
|
||||
@ -37,36 +47,12 @@
|
||||
text.delete(operation.delete[0], operation.delete[1]);
|
||||
}
|
||||
});
|
||||
return [filePath, text.toString()];
|
||||
|
||||
const contentAfterDeltas = text.toString();
|
||||
return [filePath, { a: contentAtStart, b: contentAfterDeltas }];
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const contentWithDeltasApplied = (
|
||||
contentAtSessionStart: string,
|
||||
deltas: Delta[]
|
||||
) => {
|
||||
const doc = new Doc();
|
||||
const text = doc.getText();
|
||||
text.insert(0, contentAtSessionStart);
|
||||
const operations = deltas.flatMap((delta) => delta.operations);
|
||||
operations.forEach((operation) => {
|
||||
if (Operation.isInsert(operation)) {
|
||||
text.insert(operation.insert[0], operation.insert[1]);
|
||||
} else if (Operation.isDelete(operation)) {
|
||||
text.delete(operation.delete[0], operation.delete[1]);
|
||||
}
|
||||
});
|
||||
return text.toString();
|
||||
};
|
||||
|
||||
// const timestamps = Object.values(deltas).flatMap((deltas) =>
|
||||
// Object.values(deltas).map((delta) => delta.timestampMs)
|
||||
// );
|
||||
|
||||
// const min = Math.min(...timestamps);
|
||||
// const max = Math.max(...timestamps);
|
||||
// const showTimeline = isFinite(min) && isFinite(max);
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col w-full h-full overflow-hidden space-y-2">
|
||||
@ -78,36 +64,30 @@
|
||||
previousSesssion={$previousSesssion}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="overflow-auto h-2/3 mx-4">
|
||||
{#each Object.entries(files) as [filepath, contentAtSessionStart]}
|
||||
{#if $deltas[filepath]}
|
||||
{#each Object.entries($docsNext) as [filepath, content]}
|
||||
<details open>
|
||||
<summary>
|
||||
{filepath}
|
||||
</summary>
|
||||
<CodeViewer
|
||||
value={contentAtSessionStart}
|
||||
newValue={contentWithDeltasApplied(
|
||||
contentAtSessionStart,
|
||||
$deltas[filepath]
|
||||
)}
|
||||
/>
|
||||
</details>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<div class="flex flex-col border-t border-zinc-700 mt-2">
|
||||
{#each Object.entries($deltas) as [filepath, deltas]}
|
||||
<div class="flex">
|
||||
<div class="w-32">{filepath}</div>
|
||||
<div class="flex space-x-2 items-center">
|
||||
{#each deltas as delta}
|
||||
<div class="cursor-pointer text-center items-center justify-center text-xs rounded-full h-4 w-4 bg-zinc-400 text-zinc-600 hover:bg-zinc-200" title="{toHumanReadableTime(delta.timestampMs)}">
|
||||
<summary>{filepath}</summary>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex space-x-1">
|
||||
{#each $deltas[filepath] as delta, i}
|
||||
<button
|
||||
on:click={() => {
|
||||
selection[$session.id][filepath] = i;
|
||||
}}
|
||||
class="{selection[$session.id][filepath] == i
|
||||
? 'bg-orange-300'
|
||||
: ''} text-center items-center justify-center text-xs rounded-full h-4 w-4 bg-zinc-400 text-zinc-600 hover:bg-zinc-200"
|
||||
title={toHumanReadableTime(delta.timestampMs)}
|
||||
>
|
||||
<span>{delta.operations.length}</span>
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<CodeViewer value={content.a} newValue={content.b} />
|
||||
</div>
|
||||
</details>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
import { derived, readable } from "svelte/store";
|
||||
import { derived, readable, writable } from "svelte/store";
|
||||
import { building } from "$app/environment";
|
||||
import type { Delta } from "$lib/deltas";
|
||||
|
||||
@ -19,8 +19,10 @@ export const load: PageLoad = async ({ parent, params }) => {
|
||||
sessionId: params.sessionId,
|
||||
});
|
||||
return {
|
||||
session: derived(sessions, (sessions) =>
|
||||
sessions.find((session) => session.id === params.sessionId)
|
||||
session: derived(sessions, (sessions) => {
|
||||
const result = sessions.find((session) => session.id === params.sessionId)
|
||||
return result ? result : sessions[0];
|
||||
}
|
||||
),
|
||||
previousSesssion: derived(sessions, (sessions) => {
|
||||
const currentSessionIndex = sessions.findIndex(
|
||||
|
Loading…
Reference in New Issue
Block a user