Use same FileDiff in FileCard and CommitCard

This commit is contained in:
Mattias Granlund 2024-01-31 18:30:19 +01:00
parent d838d39600
commit 2138a5cc03
14 changed files with 149 additions and 103 deletions

View File

@ -10,6 +10,8 @@
export let base: BaseBranch;
export let projectId: string;
export let branchController: BranchController;
export let projectPath: string;
const mergeUpstreamWarningDismissed = projectMergeUpstreamWarningDismissed(
branchController.projectId
);
@ -47,7 +49,13 @@
<div class="flex h-full">
<div class="z-20 flex w-full flex-col gap-2">
{#each base.upstreamCommits as commit}
<CommitCard {commit} {projectId} commitUrl={base.commitUrl(commit.id)} />
<CommitCard
{commit}
{projectId}
commitUrl={base.commitUrl(commit.id)}
{projectPath}
{branchController}
/>
{/each}
</div>
</div>
@ -65,7 +73,13 @@
</div>
<div class="flex flex-col gap-y-2">
{#each base.recentCommits as commit}
<CommitCard {commit} {projectId} commitUrl={base.commitUrl(commit.id)} />
<CommitCard
{commit}
{projectId}
commitUrl={base.commitUrl(commit.id)}
{projectPath}
{branchController}
/>
{/each}
</div>
</div>

View File

@ -1,6 +1,5 @@
<script lang="ts">
import HunkLine from './HunkLine.svelte';
import { invoke } from '$lib/backend/ipc';
import FileDiff from './FileDiff.svelte';
import Button from '$lib/components/Button.svelte';
import Modal from '$lib/components/Modal.svelte';
import Tag from '$lib/components/Tag.svelte';
@ -8,10 +7,11 @@
import { draggable } from '$lib/dragging/draggable';
import { draggableCommit, nonDraggable } from '$lib/dragging/draggables';
import { getVSIFileIcon } from '$lib/ext-icons';
import { ContentSection, HunkSection, parseFileSections } from '$lib/utils/fileSections';
import { RemoteFile, type RemoteCommit, Commit } from '$lib/vbranches/types';
import { listRemoteCommitFiles } from '$lib/vbranches/remoteCommits';
import { RemoteCommit, Commit, RemoteFile } from '$lib/vbranches/types';
import { open } from '@tauri-apps/api/shell';
import { plainToInstance } from 'class-transformer';
import type { ContentSection, HunkSection } from '$lib/utils/fileSections';
import type { BranchController } from '$lib/vbranches/branchController';
export let commit: Commit | RemoteCommit;
export let projectId: string;
@ -19,23 +19,17 @@
export let isHeadCommit: boolean = false;
export let resetHeadCommit: () => void | undefined = () => undefined;
export let isUnapplied = false;
export let branchController: BranchController;
export let projectPath: string;
let previewCommitModal: Modal;
let minWidth = 2;
let entries: [string, (ContentSection | HunkSection)[]][] = [];
let entries: [RemoteFile, (ContentSection | HunkSection)[]][] = [];
let isLoading = false;
async function loadEntries() {
isLoading = true;
entries = plainToInstance(
RemoteFile,
await invoke<any[]>('list_remote_commit_files', { projectId, commitOid: commit.id })
)
.map(
(file) => [file.path, parseFileSections(file)] as [string, (ContentSection | HunkSection)[]]
)
.sort((a, b) => a[0].localeCompare(b[0]));
entries = await listRemoteCommitFiles(projectId, commit.id);
isLoading = false;
}
@ -119,38 +113,35 @@
<div class="border-gray-900 h-8 w-8 animate-spin rounded-full border-b-2" />
</div>
{:else}
{#each entries as [filepath, sections]}
{#each entries as [remoteFile, sections]}
<div class="commit-modal__file-section">
<div
class="text-color-3 flex flex-grow items-center overflow-hidden text-ellipsis whitespace-nowrap font-bold"
title={filepath}
title={remoteFile.path}
>
<img
src={getVSIFileIcon(filepath)}
src={getVSIFileIcon(remoteFile.path)}
alt="js"
width="13"
style="width: 0.8125rem"
class="mr-1 inline"
/>
{filepath}
{remoteFile.path}
</div>
<div class="commit-modal__code-container custom-scrollbar">
<div class="commit-modal__code-wrapper">
{#each sections as section}
{#if 'hunk' in section}
{#each section.subSections as subsection}
{#each subsection.lines.slice(0, subsection.expanded ? subsection.lines.length : 0) as line}
<HunkLine
{line}
{minWidth}
sectionType={subsection.sectionType}
filePath={filepath}
/>
{/each}
{/each}
{/if}
{/each}
<FileDiff
filePath={remoteFile.path}
isBinary={remoteFile.binary}
isLarge={false}
{projectPath}
{isUnapplied}
{branchController}
selectable={false}
branchId={commit instanceof Commit ? commit.branchId : undefined}
{sections}
/>
</div>
</div>
</div>

View File

@ -138,6 +138,8 @@
{isHeadCommit}
{resetHeadCommit}
{isUnapplied}
{branchController}
projectPath={project.path}
/>
</div>
<!-- <div class="reset-head">

View File

@ -1,5 +1,6 @@
<script lang="ts">
import FileCardHeader from './FileCardHeader.svelte';
import FileDiff from './FileDiff.svelte';
import Resizer from '$lib/components/Resizer.svelte';
import ScrollableContainer from '$lib/components/ScrollableContainer.svelte';
import { persisted } from '$lib/persisted/persisted';
@ -13,7 +14,6 @@
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;
@ -43,17 +43,6 @@
}
$: parseFile(file);
$: maxLineNumber = sections[sections.length - 1]?.maxLineNumber;
function getGutterMinWidth(max: number) {
if (max >= 1000) return 2;
if (max >= 100) return 1.5;
if (max >= 10) return 1.25;
return 1;
}
$: minWidth = getGutterMinWidth(maxLineNumber);
$: isFileLocked = sections
.filter((section): section is HunkSection => section instanceof HunkSection)
.some((section) => section.hunk.locked);
@ -82,7 +71,10 @@
<ScrollableContainer wide>
<FileDiff
{file}
filePath={file.path}
isLarge={file.large}
isBinary={file.binary}
{sections}
{projectPath}
{isFileLocked}
{isUnapplied}
@ -148,31 +140,6 @@
max-height: 100%;
flex-grow: 1;
}
.hunks {
display: flex;
flex-direction: column;
position: relative;
max-height: 100%;
flex-shrink: 0;
padding: var(--space-16);
gap: var(--space-16);
}
.hunk-wrapper {
display: flex;
flex-direction: column;
gap: var(--space-10);
}
.indicators {
display: flex;
align-items: center;
gap: var(--space-2);
}
.added {
color: #45b156;
}
.removed {
color: #ff3e00;
}
@keyframes wiggle {
0% {

View File

@ -1,28 +1,40 @@
<script lang="ts">
import HunkViewer from './HunkViewer.svelte';
import Icon from './Icon.svelte';
import { computeAddedRemovedByFiles, computeAddedRemovedByHunk } from '$lib/utils/metrics';
import { 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 branchId: string | undefined;
export let filePath: string;
export let isBinary: boolean;
export let isLarge: boolean;
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;
export let selectedOwnership: Writable<Ownership> | undefined = undefined;
export let isFileLocked = false;
function getGutterMinWidth(max: number) {
if (max >= 10000) return 2.5;
if (max >= 1000) return 2;
if (max >= 100) return 1.5;
if (max >= 10) return 1.25;
return 1;
}
$: maxLineNumber = sections[sections.length - 1]?.maxLineNumber;
$: minWidth = getGutterMinWidth(maxLineNumber);
</script>
<div class="hunks">
{#if file.binary}
{#if isBinary}
Binary content not shown
{:else if file.large}
{:else if isLarge}
Diff too large to be shown
{:else}
{#each sections as section}
@ -39,7 +51,7 @@
{/if}
</div>
<HunkViewer
{file}
{filePath}
{section}
{branchId}
{selectable}
@ -55,3 +67,31 @@
{/each}
{/if}
</div>
<style lang="postcss">
.hunks {
display: flex;
flex-direction: column;
position: relative;
max-height: 100%;
flex-shrink: 0;
padding: var(--space-16);
gap: var(--space-16);
}
.hunk-wrapper {
display: flex;
flex-direction: column;
gap: var(--space-10);
}
.indicators {
display: flex;
align-items: center;
gap: var(--space-2);
}
.added {
color: #45b156;
}
.removed {
color: #ff3e00;
}
</style>

View File

@ -5,9 +5,8 @@
import ContextMenuSection from '$lib/components/contextmenu/ContextMenuSection.svelte';
import { open } from '@tauri-apps/api/shell';
import type { BranchController } from '$lib/vbranches/branchController';
import type { File } from '$lib/vbranches/types';
export let file: File;
export let filePath: string;
export let projectPath: string | undefined;
export let branchController: BranchController;
let popupMenu: PopupMenu;
@ -27,7 +26,7 @@
<ContextMenuItem
label="Open in VS Code"
on:click={() =>
projectPath && open(`vscode://file${projectPath}/${file.path}:${item.lineNumber}`)}
projectPath && open(`vscode://file${projectPath}/${filePath}:${item.lineNumber}`)}
/>
{/if}
</ContextMenuSection>

View File

@ -81,6 +81,7 @@
.line {
flex-grow: 1;
cursor: grab;
padding-left: var(--space-4);
}
.code-line__numbers-line {
@ -92,6 +93,5 @@
.selectable-wrapper {
cursor: text;
display: inline-block;
padding-left: var(--space-4);
}
</style>

View File

@ -7,13 +7,12 @@
import type { HunkSection } 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 { Hunk } from '$lib/vbranches/types';
import type { Writable } from 'svelte/store';
export let file: File;
export let filePath: string;
export let section: HunkSection;
export let branchId: string;
export let branchId: string | undefined;
export let projectPath: string | undefined;
export let minWidth: number;
@ -22,9 +21,10 @@
export let isFileLocked: boolean;
export let branchController: BranchController;
export let selectedOwnership: Writable<Ownership>;
export let selectedOwnership: Writable<Ownership> | undefined = undefined;
function onHunkSelected(hunk: Hunk, isSelected: boolean) {
if (!selectedOwnership) return;
if (isSelected) {
selectedOwnership.update((ownership) => ownership.addHunk(hunk.filePath, hunk.id));
} else {
@ -32,15 +32,15 @@
}
}
function updateContextMenu(file: File) {
function updateContextMenu(filePath: string) {
if (popupMenu) popupMenu.$destroy();
return new HunkContextMenu({
target: document.body,
props: { projectPath, file, branchController }
props: { projectPath, filePath, branchController }
});
}
$: popupMenu = updateContextMenu(file);
$: popupMenu = updateContextMenu(filePath);
onDestroy(() => {
if (popupMenu) {
@ -54,7 +54,7 @@
role="cell"
use:draggable={{
...draggableHunk(branchId, section.hunk),
disabled: isUnapplied || section.hunk.locked
disabled: isUnapplied || section.hunk.locked || !branchId
}}
on:contextmenu|preventDefault
class="hunk"
@ -66,12 +66,12 @@
{#each subsection.lines.slice(0, subsection.expanded ? subsection.lines.length : 0) as line}
<HunkLine
{line}
{filePath}
{minWidth}
{selectable}
selected={$selectedOwnership.containsHunk(hunk.filePath, hunk.id)}
selected={$selectedOwnership?.containsHunk(hunk.filePath, hunk.id)}
on:selected={(e) => onHunkSelected(hunk, e.detail)}
sectionType={subsection.sectionType}
filePath={file.path}
on:contextmenu={(e) =>
popupMenu.openByMouse(e, {
hunk,

View File

@ -6,6 +6,7 @@
export let branch: RemoteBranch | undefined;
export let projectId: string;
export let projectPath: string;
export let branchController: BranchController;
</script>
@ -23,7 +24,7 @@
{#if branch.commits && branch.commits.length > 0}
<div class="flex w-full flex-col gap-y-2">
{#each branch.commits as commit}
<CommitCard {commit} {projectId} />
<CommitCard {commit} {projectId} {branchController} {projectPath} />
{/each}
</div>
{/if}

View File

@ -8,6 +8,7 @@
export let branchId: string;
export let projectId: string;
export let projectPath: string;
export let branchCount: number;
export let upstream: RemoteBranch | undefined;
export let branchController: BranchController;
@ -53,7 +54,13 @@
>
{#each upstream.commits as commit (commit.id)}
<div use:draggable={draggableRemoteCommit(branchId, commit)}>
<CommitCard {commit} {projectId} commitUrl={base?.commitUrl(commit.id)} />
<CommitCard
{commit}
{projectId}
commitUrl={base?.commitUrl(commit.id)}
{branchController}
{projectPath}
/>
</div>
{/each}
<div class="flex justify-end p-2">

View File

@ -13,7 +13,7 @@ export type DraggableHunk = {
hunk: Hunk;
};
export function draggableHunk(branchId: string, hunk: Hunk) {
export function draggableHunk(branchId: string | undefined, hunk: Hunk) {
return { data: { branchId, hunk } };
}

View File

@ -0,0 +1,19 @@
/**
* This file should probably not be located under ../vbranches, but the reason
* it's here is because the type is in this package.
*/
import { RemoteFile } from './types';
import { parseFileSections, type ContentSection, type HunkSection } from '$lib/utils/fileSections';
import { invoke } from '@tauri-apps/api/tauri';
import { plainToInstance } from 'class-transformer';
export async function listRemoteCommitFiles(projectId: string, commitOid: string) {
return plainToInstance(
RemoteFile,
await invoke<any[]>('list_remote_commit_files', { projectId, commitOid })
)
.map(
(file) => [file, parseFileSections(file)] as [RemoteFile, (ContentSection | HunkSection)[]]
)
.sort((a, b) => a[0].path?.localeCompare(b[0].path));
}

View File

@ -9,6 +9,7 @@
$: baseBranchService = data.baseBranchService;
$: base$ = baseBranchService.base$;
$: error$ = baseBranchService.error$;
$: project$ = data.project$;
</script>
<ScrollableContainer wide>
@ -18,7 +19,7 @@
{:else if !$base$}
<p>Loading...</p>
{:else}
<BaseBranch {projectId} base={$base$} {branchController} />
<BaseBranch {projectId} base={$base$} {branchController} projectPath={$project$.path} />
{/if}
</div>
</ScrollableContainer>

View File

@ -4,7 +4,7 @@
import { page } from '$app/stores';
export let data: PageData;
$: projectId = data.projectId;
$: project$ = data.project$;
$: branchController = data.branchController;
$: remoteBranchService = data.remoteBranchService;
$: branches$ = remoteBranchService.branches$;
@ -24,7 +24,12 @@
{:else if !$branches$}
<p>Loading...</p>
{:else if branch}
<RemoteBranchPreview {projectId} {branchController} {branch} />
<RemoteBranchPreview
projectId={$project$.id}
projectPath={$project$.path}
{branchController}
{branch}
/>
{:else}
<p>Branch doesn't seem to exist</p>
{/if}