refactor: move remote branches out of tray and into their own component

This commit is contained in:
Kiril Videlov 2023-10-18 14:09:32 +02:00 committed by Kiril Videlov
parent b916eb8afe
commit 3f74c66fb7
2 changed files with 174 additions and 135 deletions

View File

@ -0,0 +1,159 @@
<script lang="ts">
import { Link } from '$lib/components';
import { IconGitBranch, IconRemote } from '$lib/icons';
import IconHelp from '$lib/icons/IconHelp.svelte';
import Scrollbar from '$lib/components/Scrollbar.svelte';
import Tooltip from '$lib/components/Tooltip/Tooltip.svelte';
import { IconTriangleDown, IconTriangleUp } from '$lib/icons';
import TimeAgo from '$lib/components/TimeAgo/TimeAgo.svelte';
import { accordion } from './accordion';
import type { CustomStore, RemoteBranch, BaseBranch, Branch } from '$lib/vbranches/types';
import type { Readable } from '@square/svelte-store';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher<{
selection: {
branch: RemoteBranch;
i: number;
offset: number;
};
}>();
export let remoteBranchStore: CustomStore<RemoteBranch[] | undefined>;
let rbViewport: HTMLElement;
let rbContents: HTMLElement;
let rbSection: HTMLElement;
export let peekTrayExpanded = false;
export let selectedItem: Readable<Branch | RemoteBranch | BaseBranch | undefined> | undefined;
$: remoteBranchesState = remoteBranchStore?.state;
let open = false;
function select(branch: RemoteBranch, i: number) {
const element = rbContents.children[i] as HTMLDivElement;
const offset = element.offsetTop + rbSection.offsetTop - rbViewport.scrollTop;
dispatch('selection', { branch, i, offset });
}
</script>
<div
class="bg-color-4 border-color-4 flex items-center justify-between border-b border-t px-2 py-1 pr-1"
>
<div class="flex flex-row place-items-center space-x-2">
<div class="text-color-2 font-bold">Remote Branches</div>
<a
target="_blank"
rel="noreferrer"
href="https://docs.gitbutler.com/features/virtual-branches/remote-branches"
>
<IconHelp class="text-color-3 h-3 w-3" />
</a>
</div>
<div class="flex h-4 w-4 justify-around">
<button class="h-full w-full" on:click={() => (open = !open)}>
{#if open}
<IconTriangleUp />
{:else}
<IconTriangleDown />
{/if}
</button>
</div>
</div>
<div bind:this={rbSection} use:accordion={open} class="border-color-5 relative flex-grow border-b">
<div
bind:this={rbViewport}
on:scroll
class="hide-native-scrollbar flex max-h-full flex-grow flex-col overflow-y-scroll overscroll-none"
>
<div bind:this={rbContents}>
{#if $remoteBranchesState.isLoading}
<div class="px-2 py-1">loading...</div>
{:else if $remoteBranchesState.isError}
<div class="px-2 py-1">Something went wrong</div>
{:else if !$remoteBranchStore || $remoteBranchStore.length == 0}
<div class="p-4">
<p class="text-color-3 mb-2">
There are no local or remote Git branches that can be imported as virtual branches
</p>
<Link
target="_blank"
rel="noreferrer"
href="https://docs.gitbutler.com/features/virtual-branches/remote-branches"
>
Learn more
</Link>
</div>
{:else if $remoteBranchStore}
{#each $remoteBranchStore as branch, i}
<div
role="button"
tabindex="0"
on:click={() => select(branch, i)}
on:keypress={() => select(branch, i)}
class:bg-color-4={$selectedItem == branch && peekTrayExpanded}
class="border-color-4 flex flex-col justify-between gap-1 border-b px-2 py-1 pt-2 -outline-offset-2 outline-blue-200 last:border-b focus:outline-2"
>
<div class="flex flex-row items-center gap-x-2 pr-1">
<div class="text-color-3">
{#if branch.name.match('refs/remotes')}
<Tooltip
label="This is a remote branch that you don't have a virtual branch tracking yet"
>
<IconRemote class="h-4 w-4" />
</Tooltip>
{:else}
<Tooltip label="This is a local branch that is not a virtual branch yet">
<IconGitBranch class="h-4 w-4" />
</Tooltip>
{/if}
</div>
<div class="text-color-2 flex-grow truncate" title={branch.name}>
{branch.name
.replace('refs/remotes/', '')
.replace('origin/', '')
.replace('refs/heads/', '')}
</div>
</div>
<div class="flex flex-row justify-between space-x-2 rounded p-1 pr-1">
<div class="text-color-4 flex-grow-0 text-sm">
<TimeAgo date={branch.lastCommitTs()} />
</div>
<div class="flex flex-grow-0 flex-row space-x-2">
<Tooltip
label="This branch has {branch.ahead()} commits not on your base branch and your base has {branch.behind} commits not on this branch yet"
>
<div class="bg-color-3 text-color-3 rounded-lg px-2 text-sm">
{branch.ahead()} / {branch.behind}
</div>
</Tooltip>
{#await branch.isMergeable then isMergeable}
{#if !isMergeable}
<div class="font-bold text-red-500" title="Can't be merged">!</div>
{/if}
{/await}
</div>
<div
class="isolate flex flex-grow justify-end -space-x-2 overflow-hidden transition duration-300 ease-in-out hover:space-x-1 hover:transition hover:ease-in"
>
{#each branch.authors() as author}
<img
class="relative z-30 inline-block h-4 w-4 rounded-full ring-1 ring-white dark:ring-black"
title="Gravatar for {author.email}"
alt="Gravatar for {author.email}"
srcset="{author.gravatarUrl} 2x"
width="100"
height="100"
on:error
/>
{/each}
</div>
</div>
</div>
{/each}
{/if}
</div>
</div>
<Scrollbar viewport={rbViewport} contents={rbContents} width="0.5rem" />
</div>

View File

@ -1,7 +1,6 @@
<script lang="ts">
import { Link } from '$lib/components';
import { Branch, BaseBranch, RemoteBranch, type CustomStore } from '$lib/vbranches/types';
import { IconBranch, IconGitBranch, IconRemote } from '$lib/icons';
import { IconBranch } from '$lib/icons';
import { IconTriangleDown, IconTriangleUp } from '$lib/icons';
import { accordion } from './accordion';
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings';
@ -9,7 +8,6 @@
import type { BranchController } from '$lib/vbranches/branchController';
import Tooltip from '$lib/components/Tooltip/Tooltip.svelte';
import Scrollbar from '$lib/components/Scrollbar.svelte';
import IconHelp from '$lib/icons/IconHelp.svelte';
import { derived, get, type Readable } from '@square/svelte-store';
import PeekTray from './PeekTray.svelte';
import IconRefresh from '$lib/icons/IconRefresh.svelte';
@ -23,6 +21,7 @@
import IconChevronRightSmall from '$lib/icons/IconChevronRightSmall.svelte';
import { slide } from 'svelte/transition';
import { computedAddedRemoved } from '$lib/vbranches/fileStatus';
import RemoteBranches from './RemoteBranches.svelte';
export let branchesWithContentStore: CustomStore<Branch[] | undefined>;
export let remoteBranchStore: CustomStore<RemoteBranch[] | undefined>;
@ -34,27 +33,26 @@
export let peekTrayExpanded = false;
$: branchesState = branchesWithContentStore?.state;
$: remoteBranchesState = remoteBranchStore?.state;
const userSettings = getContext<SettingsStore>(SETTINGS_CONTEXT);
let yourBranchesOpen = true;
let remoteBranchesOpen = true;
let applyConflictedModal: Modal;
let vbViewport: HTMLElement;
let vbContents: HTMLElement;
let rbViewport: HTMLElement;
let rbContents: HTMLElement;
let rbSection: HTMLElement;
let baseContents: HTMLElement;
let selectedItem: Readable<Branch | RemoteBranch | BaseBranch | undefined> | undefined;
let overlayOffsetTop = 0;
let fetching = false;
function select(detail: Branch | RemoteBranch | BaseBranch | undefined, i: number): void {
function select(
detail: Branch | RemoteBranch | BaseBranch | undefined,
i: number,
offset?: number
): void {
if (peekTrayExpanded && selectedItem && detail == get(selectedItem)) {
peekTrayExpanded = false;
return;
@ -69,8 +67,7 @@
selectedItem = derived(remoteBranchStore, (branches) =>
branches?.find((remoteBranch) => remoteBranch.sha == detail.sha)
);
const element = rbContents.children[i] as HTMLDivElement;
overlayOffsetTop = element.offsetTop + rbSection.offsetTop - rbViewport.scrollTop;
overlayOffsetTop = offset || overlayOffsetTop;
} else if (detail instanceof BaseBranch) {
selectedItem = baseBranchStore;
overlayOffsetTop = baseContents.offsetTop;
@ -308,130 +305,13 @@
/>
<!-- Remote branches -->
<div
class="bg-color-4 border-color-4 flex items-center justify-between border-b border-t px-2 py-1 pr-1"
>
<div class="flex flex-row place-items-center space-x-2">
<div class="text-color-2 font-bold">Remote Branches</div>
<a
target="_blank"
rel="noreferrer"
href="https://docs.gitbutler.com/features/virtual-branches/remote-branches"
>
<IconHelp class="text-color-3 h-3 w-3" />
</a>
</div>
<div class="flex h-4 w-4 justify-around">
<button class="h-full w-full" on:click={() => (remoteBranchesOpen = !remoteBranchesOpen)}>
{#if remoteBranchesOpen}
<IconTriangleUp />
{:else}
<IconTriangleDown />
{/if}
</button>
</div>
</div>
<div
bind:this={rbSection}
use:accordion={remoteBranchesOpen}
class="border-color-5 relative flex-grow border-b"
>
<div
bind:this={rbViewport}
on:scroll={onScroll}
class="hide-native-scrollbar flex max-h-full flex-grow flex-col overflow-y-scroll overscroll-none"
>
<div bind:this={rbContents}>
{#if $remoteBranchesState.isLoading}
<div class="px-2 py-1">loading...</div>
{:else if $remoteBranchesState.isError}
<div class="px-2 py-1">Something went wrong</div>
{:else if !$remoteBranchStore || $remoteBranchStore.length == 0}
<div class="p-4">
<p class="text-color-3 mb-2">
There are no local or remote Git branches that can be imported as virtual branches
</p>
<Link
target="_blank"
rel="noreferrer"
href="https://docs.gitbutler.com/features/virtual-branches/remote-branches"
>
Learn more
</Link>
</div>
{:else if $remoteBranchStore}
{#each $remoteBranchStore as branch, i}
<div
role="button"
tabindex="0"
on:click={() => select(branch, i)}
on:keypress={() => select(branch, i)}
class:bg-color-4={$selectedItem == branch && peekTrayExpanded}
class="border-color-4 flex flex-col justify-between gap-1 border-b px-2 py-1 pt-2 -outline-offset-2 outline-blue-200 last:border-b focus:outline-2"
>
<div class="flex flex-row items-center gap-x-2 pr-1">
<div class="text-color-3">
{#if branch.name.match('refs/remotes')}
<Tooltip
label="This is a remote branch that you don't have a virtual branch tracking yet"
>
<IconRemote class="h-4 w-4" />
</Tooltip>
{:else}
<Tooltip label="This is a local branch that is not a virtual branch yet">
<IconGitBranch class="h-4 w-4" />
</Tooltip>
{/if}
</div>
<div class="text-color-2 flex-grow truncate" title={branch.name}>
{branch.name
.replace('refs/remotes/', '')
.replace('origin/', '')
.replace('refs/heads/', '')}
</div>
</div>
<div class="flex flex-row justify-between space-x-2 rounded p-1 pr-1">
<div class="text-color-4 flex-grow-0 text-sm">
<TimeAgo date={branch.lastCommitTs()} />
</div>
<div class="flex flex-grow-0 flex-row space-x-2">
<Tooltip
label="This branch has {branch.ahead()} commits not on your base branch and your base has {branch.behind} commits not on this branch yet"
>
<div class="bg-color-3 text-color-3 rounded-lg px-2 text-sm">
{branch.ahead()} / {branch.behind}
</div>
</Tooltip>
{#await branch.isMergeable then isMergeable}
{#if !isMergeable}
<div class="font-bold text-red-500" title="Can't be merged">!</div>
{/if}
{/await}
</div>
<div
class="isolate flex flex-grow justify-end -space-x-2 overflow-hidden transition duration-300 ease-in-out hover:space-x-1 hover:transition hover:ease-in"
>
{#each branch.authors() as author}
<img
class="relative z-30 inline-block h-4 w-4 rounded-full ring-1 ring-white dark:ring-black"
title="Gravatar for {author.email}"
alt="Gravatar for {author.email}"
srcset="{author.gravatarUrl} 2x"
width="100"
height="100"
on:error
/>
{/each}
</div>
</div>
</div>
{/each}
{/if}
</div>
</div>
<Scrollbar viewport={rbViewport} contents={rbContents} width="0.5rem" />
</div>
<RemoteBranches
on:scroll={onScroll}
on:selection={(e) => select(e.detail.branch, e.detail.i, e.detail.offset)}
{remoteBranchStore}
{peekTrayExpanded}
{selectedItem}
></RemoteBranches>
</div>
<Modal width="small" bind:this={applyConflictedModal}>