mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-24 01:51:57 +03:00
show added/removed status in sessions list
This commit is contained in:
parent
3cf1532138
commit
a1da5ba8bc
23
src/lib/components/Stats.svelte
Normal file
23
src/lib/components/Stats.svelte
Normal file
@ -0,0 +1,23 @@
|
||||
<script lang="ts">
|
||||
export let added = 0;
|
||||
export let removed = 0;
|
||||
|
||||
$: diffStatRatio = added / (added + removed);
|
||||
$: diffStatAdded = Math.floor(4 * diffStatRatio);
|
||||
$: diffStatRemoved = 4 - diffStatAdded;
|
||||
</script>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<div id="diffstat-lines" class="flex items-center gap-1">
|
||||
<span class="text-green-400">+{added}</span>
|
||||
<span class="text-red-500">-{removed}</span>
|
||||
</div>
|
||||
<div id="diffstat-squares" class="flex items-center gap-0.5">
|
||||
{#each { length: diffStatAdded } as _}
|
||||
<div class="h-2 w-2 rounded-sm bg-green-400" />
|
||||
{/each}
|
||||
{#each { length: diffStatRemoved } as _}
|
||||
<div class="h-2 w-2 rounded-sm bg-red-500" />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
@ -11,3 +11,4 @@ export { default as Differ } from './Differ';
|
||||
export { default as DeltasViewer } from './DeltasViewer.svelte';
|
||||
export { default as DiffContext } from './DiffContext.svelte';
|
||||
export { default as Checkbox } from './Checkbox';
|
||||
export { default as Stats } from './Stats.svelte';
|
||||
|
@ -3,6 +3,7 @@
|
||||
import { Status, type Project, git, type CloudApi, type User } from '$lib/api';
|
||||
import { Button, Overlay, Link } from '$lib/components';
|
||||
import { IconGitBranch, IconSparkle } from '$lib/icons';
|
||||
import { Stats } from '$lib/components';
|
||||
|
||||
export const show = () => modal.show();
|
||||
|
||||
@ -29,7 +30,7 @@
|
||||
});
|
||||
};
|
||||
|
||||
let [linesAdded, linesRemoved] = Object.values(diffs)
|
||||
$: [linesAdded, linesRemoved] = Object.values(diffs)
|
||||
.map((diff) => {
|
||||
let added = 0;
|
||||
let removed = 0;
|
||||
@ -50,10 +51,6 @@
|
||||
})
|
||||
.reduce((a, b) => [a[0] + b[0], a[1] + b[1]], [0, 0]);
|
||||
|
||||
let diffStatRatio = linesAdded / (linesAdded + linesRemoved);
|
||||
let diffStatAdded = Math.floor(4 * diffStatRatio);
|
||||
let diffStatRemoved = 4 - diffStatAdded;
|
||||
|
||||
const reset = () => {
|
||||
summary = '';
|
||||
description = '';
|
||||
@ -180,22 +177,8 @@
|
||||
href="/projects/{project.id}/commit/"
|
||||
>
|
||||
{Object.keys(statuses).length} files changed
|
||||
<Stats added={linesAdded} removed={linesRemoved} />
|
||||
</Link>
|
||||
|
||||
<div id="diffstat" class="flex items-center gap-2">
|
||||
<div id="diffstat-lines" class="flex items-center gap-1">
|
||||
<span class="text-green-400">+{linesAdded}</span>
|
||||
<span class="text-red-500">-{linesRemoved}</span>
|
||||
</div>
|
||||
<div id="diffstat-squares" class="flex items-center gap-0.5">
|
||||
{#each { length: diffStatAdded } as _}
|
||||
<div class="h-2 w-2 rounded-sm bg-green-400" />
|
||||
{/each}
|
||||
{#each { length: diffStatRemoved } as _}
|
||||
<div class="h-2 w-2 rounded-sm bg-red-500" />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
|
@ -31,6 +31,11 @@
|
||||
Object.fromEntries(
|
||||
Object.entries(deltas).filter(([path]) => (filter ? path === filter : true))
|
||||
)
|
||||
),
|
||||
files: derived(stores.files({ projectId, sessionId: session.id }), (files) =>
|
||||
Object.fromEntries(
|
||||
Object.entries(files).filter(([path]) => (filter ? path === filter : true))
|
||||
)
|
||||
)
|
||||
}))
|
||||
);
|
||||
|
@ -1,16 +1,55 @@
|
||||
<script lang="ts">
|
||||
import type { Delta, Session } from '$lib/api';
|
||||
import { Operation, type Delta, type Session } from '$lib/api';
|
||||
import { page } from '$app/stores';
|
||||
import { collapse } from '$lib/paths';
|
||||
import { derived } from '@square/svelte-store';
|
||||
import { stores } from '$lib';
|
||||
import { IconBookmarkFilled } from '$lib/icons';
|
||||
import { Value } from 'svelte-loadable-store';
|
||||
import { line } from '$lib/diff';
|
||||
import { Stats } from '$lib/components';
|
||||
|
||||
export let isCurrent: boolean;
|
||||
export let session: Session;
|
||||
export let currentFilepath: string;
|
||||
export let deltas: Record<string, Delta[]>;
|
||||
export let files: Record<string, string>;
|
||||
|
||||
const applyDeltas = (text: string, deltas: Delta[]) => {
|
||||
const operations = deltas.flatMap((delta) => delta.operations);
|
||||
|
||||
operations.forEach((operation) => {
|
||||
if (Operation.isInsert(operation)) {
|
||||
text =
|
||||
text.slice(0, operation.insert[0]) +
|
||||
operation.insert[1] +
|
||||
text.slice(operation.insert[0]);
|
||||
} else if (Operation.isDelete(operation)) {
|
||||
text =
|
||||
text.slice(0, operation.delete[0]) +
|
||||
text.slice(operation.delete[0] + operation.delete[1]);
|
||||
}
|
||||
});
|
||||
return text;
|
||||
};
|
||||
|
||||
$: stats = Object.entries(deltas)
|
||||
.map(([path, deltas]) => {
|
||||
const doc = files[path] ?? '';
|
||||
const left = deltas.length > 0 ? applyDeltas(doc, deltas.slice(0, deltas.length - 1)) : doc;
|
||||
const right = deltas.length > 0 ? applyDeltas(left, deltas.slice(deltas.length - 1)) : left;
|
||||
const diff = line(left.split('\n'), right.split('\n'));
|
||||
const linesAdded = diff
|
||||
.filter((d) => d[0] === 1)
|
||||
.map((d) => d[1].length)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
const linesRemoved = diff
|
||||
.filter((d) => d[0] === -1)
|
||||
.map((d) => d[1].length)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
return [linesAdded, linesRemoved];
|
||||
})
|
||||
.reduce((a, b) => [a[0] + b[0], a[1] + b[1]], [0, 0]);
|
||||
|
||||
$: bookmarks = derived(stores.bookmarks.list({ projectId: session.projectId }), (bookmarks) => {
|
||||
if (bookmarks.isLoading) return [];
|
||||
@ -88,6 +127,8 @@
|
||||
<span class="flex flex-row justify-between px-3 pb-3">
|
||||
{changedFiles.length}
|
||||
{changedFiles.length !== 1 ? 'files' : 'file'}
|
||||
|
||||
<Stats added={stats[0]} removed={stats[1]} />
|
||||
</span>
|
||||
|
||||
{#if isCurrent}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
export let sessions: (Session & {
|
||||
deltas: Readable<Loadable<Record<string, Delta[]>>>;
|
||||
files: Readable<Loadable<Record<string, string>>>;
|
||||
})[];
|
||||
export let currentSession: Session | undefined;
|
||||
export let currentFilepath: string;
|
||||
@ -16,6 +17,11 @@
|
||||
(deltas) => deltas.map((delta) => Object.fromEntries(Object.entries(delta ?? {})))
|
||||
);
|
||||
|
||||
$: visibleFiles = derived(
|
||||
sessions.map(({ files }) => files),
|
||||
(files) => files.map((file) => Object.fromEntries(Object.entries(file ?? {})))
|
||||
);
|
||||
|
||||
$: visibleSessions = sessions?.map((session, i) => ({
|
||||
...session,
|
||||
visible:
|
||||
@ -42,8 +48,14 @@
|
||||
>
|
||||
{#each visibleSessions as session, i}
|
||||
{@const isCurrent = session.id === currentSession?.id}
|
||||
{#if session.visible && !$visibleDeltas.isLoading && !Value.isError($visibleDeltas.value)}
|
||||
<SessionCard {isCurrent} {session} deltas={$visibleDeltas.value[i]} {currentFilepath} />
|
||||
{#if session.visible && !$visibleDeltas.isLoading && !Value.isError($visibleDeltas.value) && !$visibleFiles.isLoading && !Value.isError($visibleFiles.value)}
|
||||
<SessionCard
|
||||
{isCurrent}
|
||||
{session}
|
||||
deltas={$visibleDeltas.value[i]}
|
||||
files={$visibleFiles.value[i]}
|
||||
{currentFilepath}
|
||||
/>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="mt-4 text-center text-zinc-300">No activities found</div>
|
||||
|
Loading…
Reference in New Issue
Block a user