preview commit content in app instead of opening the browser

This commit is contained in:
Kiril Videlov 2023-09-08 12:53:36 +02:00 committed by Kiril Videlov
parent 3d3bb09e30
commit 8ae35c5543
6 changed files with 204 additions and 64 deletions

View File

@ -5,7 +5,6 @@
import type { BranchController } from '$lib/vbranches/branchController';
import Scrollbar from '$lib/components/Scrollbar.svelte';
import { projectMergeUpstreamWarningDismissed } from '$lib/config/config';
// import { getCommitDiff } from '$lib/api/git/diffs';
export let base: BaseBranch;
export let branchController: BranchController;
@ -24,11 +23,11 @@
<div class="relative h-full max-h-full">
<div
bind:this={viewport}
class="hide-native-scrollbar flex max-h-full flex-grow flex-col overflow-y-scroll overscroll-none dark:bg-dark-900"
class="hide-native-scrollbar dark:bg-dark-900 flex max-h-full flex-grow flex-col overflow-y-scroll overscroll-none"
>
<div bind:this={contents} class="flex flex-col gap-y-4 p-4">
<h1 class="font-bold text-light-700 dark:text-dark-100">Upstream</h1>
<div class="rounded-sm text-sm text-light-700 dark:text-dark-200">
<h1 class="text-light-700 dark:text-dark-100 font-bold">Upstream</h1>
<div class="text-light-700 dark:text-dark-200 rounded-sm text-sm">
There {multiple ? 'are' : 'is'}
{base.upstreamCommits.length} unmerged upstream
{multiple ? 'commits' : 'commit'}
@ -59,30 +58,28 @@
<div class="flex h-full">
<div class="z-20 flex w-full flex-col gap-2">
{#each base.upstreamCommits as commit}
<CommitCard {commit} url={base.commitUrl(commit.id)} />
<CommitCard
{commit}
url={base.commitUrl(commit.id)}
projectId={branchController.projectId}
/>
{/each}
</div>
</div>
<div
class="h-px w-full border-none bg-gradient-to-r from-transparent via-light-500 to-transparent dark:via-dark-400"
class="via-light-500 dark:via-dark-400 h-px w-full border-none bg-gradient-to-r from-transparent to-transparent"
/>
{/if}
<Tooltip label="This is the current base for your virtual branches.">
<h1 class="font-bold text-light-700 dark:text-dark-100">Local</h1>
<h1 class="text-light-700 dark:text-dark-100 font-bold">Local</h1>
</Tooltip>
<div class="flex flex-col gap-y-2">
{#each base.recentCommits as commit}
<CommitCard url={base.commitUrl(commit.id)} {commit} />
<!-- <button
on:click={() => {
getCommitDiff({ projectId: branchController.projectId, commitId: commit.id }).then(
(result) => {
console.log(result);
}
);
}}
class="w-full bg-red-400">{commit.id}</button
> -->
<CommitCard
url={base.commitUrl(commit.id)}
{commit}
projectId={branchController.projectId}
/>
{/each}
</div>
</div>

View File

@ -248,10 +248,10 @@
>
<div
bind:this={rsViewport}
class="flex flex-grow cursor-default flex-col overflow-x-hidden border-l border-r border-light-400 bg-light-150 dark:border-dark-600 dark:bg-dark-1000 dark:text-dark-100"
class="border-light-400 bg-light-150 dark:border-dark-600 dark:bg-dark-1000 dark:text-dark-100 flex flex-grow cursor-default flex-col overflow-x-hidden border-l border-r"
>
<div class="flex text-light-900 dark:bg-dark-800 dark:font-normal dark:text-dark-100">
<div class="flex flex-grow flex-col border-b border-light-400 dark:border-dark-600">
<div class="text-light-900 dark:bg-dark-800 dark:text-dark-100 flex dark:font-normal">
<div class="border-light-400 dark:border-dark-600 flex flex-grow flex-col border-b">
{#if !branch.mergeable}
<!-- use of relative is for tooltip rendering -->
<div class="bg-red-500 px-2 py-0.5 text-center font-bold dark:bg-red-700">
@ -283,7 +283,7 @@
bind:value={branch.name}
on:change={handleBranchNameChange}
title={branch.name}
class="w-full truncate rounded border border-transparent bg-transparent px-1 font-mono font-bold text-light-800 hover:border-light-400 dark:text-dark-100 dark:hover:border-dark-600"
class="text-light-800 hover:border-light-400 dark:text-dark-100 dark:hover:border-dark-600 w-full truncate rounded border border-transparent bg-transparent px-1 font-mono font-bold"
on:dblclick|stopPropagation
on:click={(e) => e.currentTarget.select()}
/>
@ -309,7 +309,7 @@
</Button>
{/if}
<button
class="scale-90 px-1 py-1 text-light-600 hover:text-light-800"
class="text-light-600 hover:text-light-800 scale-90 px-1 py-1"
title="Stash this branch"
on:click={() => {
if (branch.id) branchController.unapplyBranch(branch.id);
@ -341,7 +341,7 @@
{#if commitDialogShown}
<div
class="flex w-full flex-col border-t border-light-400 bg-light-200 dark:border-dark-400 dark:bg-dark-800"
class="border-light-400 bg-light-200 dark:border-dark-400 dark:bg-dark-800 flex w-full flex-col border-t"
transition:slide={{ duration: 150 }}
>
{#if annotateCommits}
@ -361,7 +361,7 @@
bind:this={textAreaInput}
bind:value={commitMessage}
on:dblclick|stopPropagation
class="flex-grow cursor-text resize-none overflow-x-auto overflow-y-auto border border-white bg-white p-2 font-mono text-dark-700 outline-none focus:border-purple-600 focus:ring-0 dark:border-dark-500 dark:bg-dark-700 dark:text-light-400"
class="text-dark-700 dark:border-dark-500 dark:bg-dark-700 dark:text-light-400 flex-grow cursor-text resize-none overflow-x-auto overflow-y-auto border border-white bg-white p-2 font-mono outline-none focus:border-purple-600 focus:ring-0"
placeholder="Your commit message here"
rows={messageRows}
required
@ -441,7 +441,7 @@
<div class="relative flex flex-grow overflow-y-hidden">
<!-- TODO: Figure out why z-10 is necessary for expand up/down to not come out on top -->
<div
class="lane-dz-marker absolute z-10 hidden h-full w-full items-center justify-center rounded bg-blue-100/70 outline-dashed outline-2 -outline-offset-8 outline-light-600 dark:bg-blue-900/60 dark:outline-dark-300"
class="lane-dz-marker outline-light-600 dark:outline-dark-300 absolute z-10 hidden h-full w-full items-center justify-center rounded bg-blue-100/70 outline-dashed outline-2 -outline-offset-8 dark:bg-blue-900/60"
>
<div class="hover-text invisible font-semibold">Move here</div>
</div>
@ -489,13 +489,13 @@
{#if branch.files.length == 0}
{#if branch.commits.length == 0}
<div
class="no-changes space-y-6 rounded p-8 text-center text-light-700 dark:border-zinc-700"
class="no-changes text-light-700 space-y-6 rounded p-8 text-center dark:border-zinc-700"
data-dnd-ignore
>
<p>Nothing on this branch yet.</p>
{#if !readonly}
<IconNewBadge class="mx-auto mt-4 h-16 w-16 text-blue-400 dark:text-dark-400" />
<p class="px-12 text-light-600">
<IconNewBadge class="dark:text-dark-400 mx-auto mt-4 h-16 w-16 text-blue-400" />
<p class="text-light-600 px-12">
Get some work done, then throw some files my way!
</p>
{/if}
@ -503,7 +503,7 @@
{:else}
<!-- attention: these markers have custom css at the bottom of thise file -->
<div
class="no-changes rounded text-center font-mono text-light-700 dark:border-zinc-700"
class="no-changes text-light-700 rounded text-center font-mono dark:border-zinc-700"
data-dnd-ignore
>
No uncommitted changes on this branch
@ -513,7 +513,7 @@
</div>
{#if localCommits.length > 0 || remoteCommits.length > 0}
<div
class="flex w-full flex-grow flex-col gap-2 border-t border-light-400 dark:border-dark-500"
class="border-light-400 dark:border-dark-500 flex w-full flex-grow flex-col gap-2 border-t"
>
{#if localCommits.length > 0}
<div
@ -522,17 +522,17 @@
transition:slide={{ duration: 150 }}
>
<div
class="dark:form-dark-600 absolute top-4 ml-[0.75rem] w-px bg-gradient-to-b from-light-400 via-light-500 via-90% dark:from-dark-600 dark:via-dark-600"
class="dark:form-dark-600 from-light-400 via-light-500 dark:from-dark-600 dark:via-dark-600 absolute top-4 ml-[0.75rem] w-px bg-gradient-to-b via-90%"
style={remoteCommits.length == 0 ? 'height: calc();' : 'height: 100%;'}
/>
<div class="relative flex flex-col gap-2">
<div
class="dark:form-dark-600 absolute top-4 ml-[0.75rem] h-px w-6 bg-gradient-to-r from-light-400 via-light-400 via-10% dark:from-dark-600 dark:via-dark-600"
class="dark:form-dark-600 from-light-400 via-light-400 dark:from-dark-600 dark:via-dark-600 absolute top-4 ml-[0.75rem] h-px w-6 bg-gradient-to-r via-10%"
/>
<div class="ml-10 mr-2 flex items-center py-2">
<div
class="ml-2 flex-grow font-mono text-sm font-bold text-dark-300 dark:text-light-300"
class="text-dark-300 dark:text-light-300 ml-2 flex-grow font-mono text-sm font-bold"
>
local
</div>
@ -558,10 +558,14 @@
>
<div class="ml-[0.4rem] mr-1.5">
<div
class="h-3 w-3 rounded-full border-2 border-light-500 bg-light-200 dark:border-dark-600 dark:bg-dark-1000"
class="border-light-500 bg-light-200 dark:border-dark-600 dark:bg-dark-1000 h-3 w-3 rounded-full border-2"
/>
</div>
<CommitCard {commit} isIntegrated={commit.isRemote} />
<CommitCard
{commit}
isIntegrated={commit.isRemote}
projectId={branchController.projectId}
/>
</div>
{/each}
</div>
@ -570,14 +574,14 @@
{#if remoteCommits.length > 0}
<div class="relative flex-grow">
<div
class="dark:form-dark-600 absolute top-4 ml-[0.75rem]
w-px bg-gradient-to-b from-light-600 via-light-600 via-90% dark:from-dark-400 dark:via-dark-400"
class="dark:form-dark-600 from-light-600 via-light-600 dark:from-dark-400
dark:via-dark-400 absolute top-4 ml-[0.75rem] w-px bg-gradient-to-b via-90%"
style="height: calc(100% - 1rem);"
/>
<div class="relative flex flex-grow flex-col gap-2">
<div
class="dark:form-dark-600 absolute top-4 ml-[0.75rem] h-px w-6 bg-gradient-to-r from-light-600 via-light-600 via-10% dark:from-dark-400 dark:via-dark-400"
class="dark:form-dark-600 from-light-600 via-light-600 dark:from-dark-400 dark:via-dark-400 absolute top-4 ml-[0.75rem] h-px w-6 bg-gradient-to-r via-10%"
/>
<div
@ -604,7 +608,7 @@
>
<div class="ml-[0.4rem] mr-1.5">
<div
class="h-3 w-3 rounded-full border-2 border-light-600 bg-light-600 dark:border-dark-400 dark:bg-dark-400"
class="border-light-600 bg-light-600 dark:border-dark-400 dark:bg-dark-400 h-3 w-3 rounded-full border-2"
class:bg-light-500={commit.isRemote}
class:dark:bg-dark-500={commit.isRemote}
/>
@ -613,6 +617,7 @@
{commit}
url={base?.commitUrl(commit.id)}
isIntegrated={commit.isIntegrated}
projectId={branchController.projectId}
/>
</div>
{/each}

View File

@ -1,31 +1,80 @@
<script lang="ts">
import { open } from '@tauri-apps/api/shell';
import type { Commit } from '$lib/vbranches/types';
import TimeAgo from '$lib/components/TimeAgo/TimeAgo.svelte';
import Tooltip from '$lib/components/Tooltip/Tooltip.svelte';
import { getCommitDiff } from '$lib/api/git/diffs';
import { getVSIFileIcon } from '$lib/ext-icons';
import { ContentSection, HunkSection, parseFileSections } from './fileSections';
import type { File, Hunk } from '$lib/vbranches/types';
import RenderedLine from './RenderedLine.svelte';
import { IconExpandUpDown, IconExpandUp, IconExpandDown } from '$lib/icons';
import { Button, Modal } from '$lib/components';
export let commit: Commit;
export let isIntegrated = false;
export let url: string | undefined = undefined;
export let projectId: string;
let previewCommitModal: Modal;
let minWidth = 2;
let fileSections: Map<string, (HunkSection | ContentSection)[]> = new Map();
function parseDiff(diff: string, filepath: string): (HunkSection | ContentSection)[] {
let hunkDiffs = diff.split(/(@@.*@@)/).filter((s) => s.trim() !== '');
hunkDiffs = hunkDiffs.reduce(function (result: string[], value, index, array) {
if (index % 2 === 0) result.push(array.slice(index, index + 2).join());
return result;
}, []);
const mockDate = new Date();
let hunks: Hunk[] = hunkDiffs.map((diff) => {
return {
id: '',
diff: diff,
modifiedAt: mockDate,
filePath: filepath,
locked: false
};
});
let file: File = {
id: '',
path: filepath,
hunks: hunks,
expanded: true,
conflicted: false,
binary: false,
modifiedAt: mockDate,
content: '',
getSummary: () => {
return { status: '', added: 0, removed: 0 };
}
};
return parseFileSections(file);
}
</script>
<div
class="w-full truncate rounded border border-light-400 bg-light-50 p-2 text-left dark:border-dark-600 dark:bg-dark-900"
class="border-light-400 bg-light-50 dark:border-dark-600 dark:bg-dark-900 w-full truncate rounded border p-2 text-left"
>
<div class="mb-1 flex justify-between">
<div class="truncate">
{#if url}
<!-- on:click required when there is a stopPropagation on a parent -->
<a
href={url}
<button
on:click={() => {
if (url) open(url);
getCommitDiff({ projectId: projectId, commitId: commit.id }).then((result) => {
let entries = Object.entries(result);
entries.forEach(([filepath, diff]) => {
fileSections.set(filepath, parseDiff(diff, filepath));
});
previewCommitModal.show();
});
}}
target="_blank"
title="Open in browser"
>
{commit.description}
</a>
</button>
{:else}
{commit.description}
{/if}
@ -39,7 +88,7 @@
{/if}
</div>
<div class="flex space-x-1 text-sm text-light-700">
<div class="text-light-700 flex space-x-1 text-sm">
<img
class="relative inline-block h-4 w-4 rounded-full ring-1 ring-white dark:ring-black"
title="Gravatar for {commit.author.email}"
@ -55,3 +104,87 @@
</div>
</div>
</div>
<Modal width="large" bind:this={previewCommitModal}>
<div class="flex w-full flex-col gap-4">
{#each fileSections.entries() as [filepath, sections]}
<div>
<div
class="text-light-800 dark:text-dark-100 flex flex-grow items-center overflow-hidden text-ellipsis whitespace-nowrap px-2 font-bold"
title={filepath}
>
<img
src={getVSIFileIcon(filepath)}
alt="js"
width="13"
style="width: 0.8125rem"
class="mr-1 inline"
/>
{filepath}
</div>
<div class="hunk-change-container flex flex-col rounded px-2">
{#each sections as section}
{#if 'hunk' in section}
<div
class="border-light-400 dark:border-dark-400 dark:bg-dark-900 my-1 flex w-full flex-col overflow-hidden rounded border bg-white"
>
<div class="dark:bg-dark-900 w-full overflow-hidden bg-white">
{#each section.subSections as subsection, sidx}
{#each subsection.lines.slice(0, subsection.expanded ? subsection.lines.length : 0) as line}
<RenderedLine
{line}
{minWidth}
sectionType={subsection.sectionType}
filePath={filepath}
/>
{/each}
{#if !subsection.expanded}
<div
class="border-light-200 dark:border-dark-400 flex w-full"
class:border-t={sidx == section.subSections.length - 1 ||
(sidx > 0 && sidx < section.subSections.length - 1)}
class:border-b={sidx == 0 ||
(sidx > 0 && sidx < section.subSections.length - 1)}
>
<div
class="border-light-200 bg-light-25 text-light-500 hover:bg-light-700 dark:border-dark-400 dark:bg-dark-500 dark:text-light-600 dark:hover:bg-dark-400 border-r text-center hover:text-white dark:hover:text-black"
style:min-width={`calc(${2 * minWidth}rem - 1px)`}
>
<button
class="flex justify-center py-0.5 text-sm"
style:width={`calc(${2 * minWidth}rem - 1px)`}
on:click={() => {
if ('expanded' in subsection) {
subsection.expanded = true;
}
}}
>
{#if sidx == 0}
<IconExpandUp />
{:else if sidx == section.subSections.length - 1}
<IconExpandDown />
{:else}
<IconExpandUpDown />
{/if}
</button>
</div>
<div class="dark:bg-dark-900 flex-grow bg-white" />
</div>
{/if}
{/each}
</div>
</div>
{/if}
{/each}
</div>
</div>
{/each}
</div>
<svelte:fragment slot="controls">
<div class="px-4">
<Button color="purple" on:click={() => previewCommitModal.close()}>Close</Button>
</div>
</svelte:fragment>
</Modal>

View File

@ -91,7 +91,7 @@
class:opacity-80={isFileLocked}
>
<div
class="flex w-full flex-col justify-center gap-2 border-b border-t border-light-300 bg-light-50 py-1 text-light-900 dark:border-dark-500 dark:bg-dark-800 dark:text-light-300"
class="border-light-300 bg-light-50 text-light-900 dark:border-dark-500 dark:bg-dark-800 dark:text-light-300 flex w-full flex-col justify-center gap-2 border-b border-t py-1"
>
<div
class="flex cursor-default pl-2"
@ -103,7 +103,7 @@
}}
>
<div
class="flex-grow overflow-hidden text-ellipsis whitespace-nowrap text-light-800 dark:text-dark-100"
class="text-light-800 dark:text-dark-100 flex-grow overflow-hidden text-ellipsis whitespace-nowrap"
title={file.path}
>
<img
@ -133,7 +133,7 @@
on:keypress={() => (expanded = !expanded)}
role="button"
tabindex="0"
class="flex-grow-0 cursor-pointer px-3 py-2 text-light-600 dark:text-dark-200"
class="text-light-600 dark:text-dark-200 flex-grow-0 cursor-pointer px-3 py-2"
>
{#if !file.binary}
{#if expanded}
@ -166,14 +166,14 @@
{#if $userSettings.aiSummariesEnabled}
{#await summarizeHunk(section.hunk.diff) then description}
<div
class="truncate whitespace-normal pb-1 pl-1 pt-2 text-light-700 dark:text-dark-200"
class="text-light-700 dark:text-dark-200 truncate whitespace-normal pb-1 pl-1 pt-2"
>
{description}
</div>
{/await}
{/if}
<div
class="my-1 flex w-full flex-col overflow-hidden rounded border border-light-400 bg-white dark:border-dark-400 dark:bg-dark-900"
class="border-light-400 dark:border-dark-400 dark:bg-dark-900 my-1 flex w-full flex-col overflow-hidden rounded border bg-white"
>
<div
draggable={!section.hunk.locked && !readonly}
@ -188,7 +188,7 @@
class="changed-hunk"
class:opacity-60={section.hunk.locked && !isFileLocked}
>
<div class="w-full overflow-hidden bg-white dark:bg-dark-900">
<div class="dark:bg-dark-900 w-full overflow-hidden bg-white">
{#each section.subSections as subsection, sidx}
{#each subsection.lines.slice(0, subsection.expanded ? subsection.lines.length : 0) as line}
<RenderedLine
@ -207,14 +207,14 @@
{/each}
{#if !subsection.expanded}
<div
class="flex w-full border-light-200 dark:border-dark-400"
class="border-light-200 dark:border-dark-400 flex w-full"
class:border-t={sidx == section.subSections.length - 1 ||
(sidx > 0 && sidx < section.subSections.length - 1)}
class:border-b={sidx == 0 ||
(sidx > 0 && sidx < section.subSections.length - 1)}
>
<div
class="border-r border-light-200 bg-light-25 text-center text-light-500 hover:bg-light-700 hover:text-white dark:border-dark-400 dark:bg-dark-500 dark:text-light-600 dark:hover:bg-dark-400 dark:hover:text-black"
class="border-light-200 bg-light-25 text-light-500 hover:bg-light-700 dark:border-dark-400 dark:bg-dark-500 dark:text-light-600 dark:hover:bg-dark-400 border-r text-center hover:text-white dark:hover:text-black"
style:min-width={`calc(${2 * minWidth}rem - 1px)`}
>
<button
@ -235,7 +235,7 @@
{/if}
</button>
</div>
<div class="flex-grow bg-white dark:bg-dark-900" />
<div class="dark:bg-dark-900 flex-grow bg-white" />
</div>
{/if}
{/each}
@ -245,7 +245,7 @@
{:else}
{#if section.expanded}
<div
class="my-1 flex w-full flex-col overflow-hidden rounded border border-light-200 bg-white dark:border-dark-400 dark:bg-dark-900"
class="border-light-200 dark:border-dark-400 dark:bg-dark-900 my-1 flex w-full flex-col overflow-hidden rounded border bg-white"
role="group"
on:dblclick
>
@ -267,7 +267,7 @@
{#if !section.expanded}
<div style:width={`calc(${2 * minWidth}rem - 1px)`} class="flex justify-center">
<button
class="px-2 py-1.5 text-sm text-light-600 hover:text-light-700 dark:text-dark-200 dark:hover:text-dark-100"
class="text-light-600 hover:text-light-700 dark:text-dark-200 dark:hover:text-dark-100 px-2 py-1.5 text-sm"
on:click={() => {
if ('expanded' in section) {
section.expanded = true;

View File

@ -29,7 +29,11 @@
{#if branch.commits && branch.commits.length > 0}
<div class="flex w-full flex-col gap-y-2">
{#each branch.commits as commit}
<CommitCard {commit} url={base?.commitUrl(commit.id)} />
<CommitCard
{commit}
url={base?.commitUrl(commit.id)}
projectId={branchController.projectId}
/>
{/each}
</div>
{/if}

View File

@ -53,7 +53,7 @@
</Tooltip>
</div>
{:else}
<div class="inline-block rounded-lg bg-light-600 px-2 py-0.5 font-bold dark:bg-dark-300">
<div class="bg-light-600 dark:bg-dark-300 inline-block rounded-lg px-2 py-0.5 font-bold">
<span class="text-white">not applied</span>
</div>
{/if}
@ -66,7 +66,7 @@
bind:value={branch.notes}
on:change={handleUpdateNotes}
name="commit-description"
class="quick-commit-input outline-none-important w-full resize-none rounded border border-light-200 bg-transparent p-2 text-light-900 dark:border-dark-200 dark:text-dark-100"
class="quick-commit-input outline-none-important border-light-200 text-light-900 dark:border-dark-200 dark:text-dark-100 w-full resize-none rounded border bg-transparent p-2"
placeholder="Branch notes (optional)"
rows={notesRows}
/>
@ -88,6 +88,7 @@
{commit}
url={base?.commitUrl(commit.id)}
isIntegrated={commit.isIntegrated}
projectId={branchController.projectId}
/>
{/each}
</div>