Extract FileDiff component from FileCard

This commit is contained in:
Mattias Granlund 2024-01-31 14:12:19 +01:00
parent 3e1a77e83a
commit d838d39600
10 changed files with 123 additions and 90 deletions

View File

@ -18,7 +18,7 @@
import { dropzone } from '$lib/dragging/dropzone';
import { persisted } from '$lib/persisted/persisted';
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/settings/userSettings';
import { computedAddedRemoved } from '$lib/vbranches/fileStatus';
import { computeAddedRemovedByFiles } from '$lib/utils/metrics';
import { filesToOwnership, type Ownership } from '$lib/vbranches/ownership';
import lscache from 'lscache';
import { getContext, onMount } from 'svelte';
@ -77,7 +77,7 @@
}
}
$: linesTouched = computedAddedRemoved(...branch.files);
$: linesTouched = computeAddedRemovedByFiles(...branch.files);
$: if (
branch.name.toLowerCase().includes('virtual branch') &&
linesTouched.added + linesTouched.removed > 4

View File

@ -1,7 +1,5 @@
<script lang="ts">
import FileCardHeader from './FileCardHeader.svelte';
import HunkViewer from './HunkViewer.svelte';
import Icon from '$lib/components/Icon.svelte';
import Resizer from '$lib/components/Resizer.svelte';
import ScrollableContainer from '$lib/components/ScrollableContainer.svelte';
import { persisted } from '$lib/persisted/persisted';
@ -15,6 +13,7 @@
import type { Ownership } from '$lib/vbranches/ownership';
import type { File } from '$lib/vbranches/types';
import type { Writable } from 'svelte/store';
import FileDiff from './FileDiff.svelte';
export let projectId: string;
export let branchId: string;
@ -59,23 +58,6 @@
.filter((section): section is HunkSection => section instanceof HunkSection)
.some((section) => section.hunk.locked);
function computedAddedRemoved(section: HunkSection | ContentSection): {
added: any;
removed: any;
} {
if (section instanceof HunkSection) {
const lines = section.hunk.diff.split('\n');
return {
added: lines.filter((l) => l.startsWith('+')).length,
removed: lines.filter((l) => l.startsWith('-')).length
};
}
return {
added: 0,
removed: 0
};
}
fileWidth = lscache.get(fileWidthKey + file.id);
</script>
@ -99,42 +81,16 @@
{/if}
<ScrollableContainer wide>
<div class="hunks">
{#if file.binary}
Binary content not shown
{:else if file.large}
Diff too large to be shown
{:else}
{#each sections as section}
{@const { added, removed } = computedAddedRemoved(section)}
{#if 'hunk' in section}
<div class="hunk-wrapper">
<div class="indicators text-base-11">
<span class="added">+{added}</span>
<span class="removed">+{removed}</span>
{#if section.hunk.locked}
<div title={section.hunk.lockedTo}>
<Icon name="locked-small" color="warn" />
</div>
{/if}
</div>
<HunkViewer
{file}
{section}
{branchId}
{selectable}
{isUnapplied}
{projectPath}
{selectedOwnership}
{branchController}
{isFileLocked}
{minWidth}
/>
</div>
{/if}
{/each}
{/if}
</div>
<FileDiff
{file}
{projectPath}
{isFileLocked}
{isUnapplied}
{branchController}
{selectable}
{branchId}
{selectedOwnership}
/>
</ScrollableContainer>
</div>

View File

@ -3,7 +3,8 @@
import Tag from './Tag.svelte';
import IconButton from '$lib/components/IconButton.svelte';
import { getVSIFileIcon } from '$lib/ext-icons';
import { computeFileStatus, computedAddedRemoved } from '$lib/vbranches/fileStatus';
import { computeFileStatus } from '$lib/utils/fileStatus';
import { computeAddedRemovedByFiles } from '$lib/utils/metrics';
import { createEventDispatcher } from 'svelte';
import type { File } from '$lib/vbranches/types';
@ -11,7 +12,7 @@
export let isFileLocked: boolean;
const dispatch = createEventDispatcher<{ close: void }>();
$: fileStats = computedAddedRemoved(file);
$: fileStats = computeAddedRemovedByFiles(file);
$: fileStatus = computeFileStatus(file);
function boldenFilename(filepath: string): { filename: string; path: string } {

View File

@ -0,0 +1,57 @@
<script lang="ts">
import HunkViewer from './HunkViewer.svelte';
import Icon from './Icon.svelte';
import { computeAddedRemovedByFiles, computeAddedRemovedByHunk } from '$lib/utils/metrics';
import type { HunkSection, ContentSection } from '$lib/utils/fileSections';
import type { BranchController } from '$lib/vbranches/branchController';
import type { Ownership } from '$lib/vbranches/ownership';
import type { File } from '$lib/vbranches/types';
import type { Writable } from 'svelte/store';
export let branchId: string;
export let file: File;
export let sections: (HunkSection | ContentSection)[] = [];
export let projectPath: string | undefined;
export let branchController: BranchController;
export let isUnapplied: boolean;
export let selectable = false;
export let selectedOwnership: Writable<Ownership>;
export let isFileLocked: boolean;
</script>
<div class="hunks">
{#if file.binary}
Binary content not shown
{:else if file.large}
Diff too large to be shown
{:else}
{#each sections as section}
{@const { added, removed } = computeAddedRemovedByHunk(section)}
{#if 'hunk' in section}
<div class="hunk-wrapper">
<div class="indicators text-base-11">
<span class="added">+{added}</span>
<span class="removed">+{removed}</span>
{#if section.hunk.locked}
<div title={section.hunk.lockedTo}>
<Icon name="locked-small" color="warn" />
</div>
{/if}
</div>
<HunkViewer
{file}
{section}
{branchId}
{selectable}
{isUnapplied}
{projectPath}
{selectedOwnership}
{branchController}
{isFileLocked}
{minWidth}
/>
</div>
{/if}
{/each}
{/if}
</div>

View File

@ -1,5 +1,5 @@
<script lang="ts">
import type { FileStatus } from '$lib/vbranches/fileStatus';
import type { FileStatus } from '$lib/utils/fileStatus';
export let status: FileStatus;
</script>

View File

@ -1,7 +1,7 @@
<script lang="ts">
import FileStatusCircle from './FileStatusCircle.svelte';
import Icon from '$lib/components/Icon.svelte';
import { computeFileStatus } from '$lib/vbranches/fileStatus';
import { computeFileStatus } from '$lib/utils/fileStatus';
import type { File } from '$lib/vbranches/types';
export let file: File;

View File

@ -1,6 +1,6 @@
<script lang="ts">
import Tag, { type TagColor } from './Tag.svelte';
import type { FileStatus } from '$lib/vbranches/fileStatus';
import type { FileStatus } from '$lib/utils/fileStatus';
export let status: FileStatus;

View File

@ -0,0 +1,15 @@
import type { File } from '$lib/vbranches/types';
export type FileStatus = 'A' | 'M' | 'D';
export function computeFileStatus(file: File): FileStatus {
if (file.hunks.length == 1) {
const changeType = file.hunks[0].changeType;
if (changeType == 'added') {
return 'A';
} else if (changeType == 'deleted') {
return 'D';
}
}
return 'M';
}

View File

@ -0,0 +1,32 @@
import { HunkSection, type ContentSection } from './fileSections';
import type { File } from '$lib/vbranches/types';
export function computeAddedRemovedByFiles(...files: File[]) {
return files
.flatMap((f) => f.hunks)
.map((h) => h.diff.split('\n'))
.reduce(
(acc, lines) => ({
added: acc.added + lines.filter((l) => l.startsWith('+')).length,
removed: acc.removed + lines.filter((l) => l.startsWith('-')).length
}),
{ added: 0, removed: 0 }
);
}
export function computeAddedRemovedByHunk(section: HunkSection | ContentSection): {
added: any;
removed: any;
} {
if (section instanceof HunkSection) {
const lines = section.hunk.diff.split('\n');
return {
added: lines.filter((l) => l.startsWith('+')).length,
removed: lines.filter((l) => l.startsWith('-')).length
};
}
return {
added: 0,
removed: 0
};
}

View File

@ -1,28 +0,0 @@
import type { File } from './types';
export type FileStatus = 'A' | 'M' | 'D';
export function computedAddedRemoved(...files: File[]) {
return files
.flatMap((f) => f.hunks)
.map((h) => h.diff.split('\n'))
.reduce(
(acc, lines) => ({
added: acc.added + lines.filter((l) => l.startsWith('+')).length,
removed: acc.removed + lines.filter((l) => l.startsWith('-')).length
}),
{ added: 0, removed: 0 }
);
}
export function computeFileStatus(file: File): FileStatus {
if (file.hunks.length == 1) {
const changeType = file.hunks[0].changeType;
if (changeType == 'added') {
return 'A';
} else if (changeType == 'deleted') {
return 'D';
}
}
return 'M';
}