mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-28 20:15:20 +03:00
Keep unapplied branches in the board
- disable draggables and drop zones when readonly - dim header and add tag to distinguish from other statuses
This commit is contained in:
parent
8671249176
commit
a56ea36666
@ -15,7 +15,7 @@ export class BranchService {
|
||||
remoteBranchService: RemoteBranchService,
|
||||
githubService: GitHubService
|
||||
) {
|
||||
const vbranchesWithEmpty$ = vbranchService.branches$.pipe(startWith([]));
|
||||
const vbranchesWithEmpty$ = vbranchService.activeBranches$.pipe(startWith([]));
|
||||
const branchesWithEmpty$ = remoteBranchService.branches$.pipe(startWith([]));
|
||||
const prWithEmpty$ = githubService.prs$.pipe(startWith([]));
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
$: githubService = data.githubService;
|
||||
|
||||
$: project$ = data.project$;
|
||||
$: activeBranches$ = vbranchService.activeBranches$;
|
||||
$: branches = vbranchService.branches$;
|
||||
$: error$ = vbranchService.branchesError$;
|
||||
$: githubEnabled$ = githubService.isEnabled$;
|
||||
|
||||
@ -61,7 +61,7 @@
|
||||
project={$project$}
|
||||
{cloud}
|
||||
base={$base$}
|
||||
branches={$activeBranches$}
|
||||
branches={$branches}
|
||||
projectPath={$project$?.path}
|
||||
branchesError={$error$}
|
||||
user={$user$}
|
||||
|
@ -115,6 +115,7 @@
|
||||
{projectPath}
|
||||
{user}
|
||||
{githubService}
|
||||
readonly={!branch.active}
|
||||
></BranchLane>
|
||||
</div>
|
||||
{/each}
|
||||
|
@ -168,13 +168,15 @@
|
||||
hover: 'cherrypick-dz-hover',
|
||||
active: 'cherrypick-dz-active',
|
||||
accepts: acceptCherrypick,
|
||||
onDrop: onCherrypicked
|
||||
onDrop: onCherrypicked,
|
||||
disabled: readonly
|
||||
}}
|
||||
use:dropzone={{
|
||||
hover: 'lane-dz-hover',
|
||||
active: 'lane-dz-active',
|
||||
accepts: acceptBranchDrop,
|
||||
onDrop: onBranchDrop
|
||||
onDrop: onBranchDrop,
|
||||
disabled: readonly
|
||||
}}
|
||||
>
|
||||
<DropzoneOverlay class="cherrypick-dz-marker" label="Apply here" />
|
||||
|
@ -63,7 +63,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="branch-files">
|
||||
<div class="branch-files" class:readonly>
|
||||
<div class="header" bind:this={headerElement}>
|
||||
<div class="header__left">
|
||||
{#if showCheckboxes && selectedListMode == 'list' && branch.files.length > 1}
|
||||
@ -114,6 +114,9 @@
|
||||
.branch-files {
|
||||
background: var(--clr-theme-container-light);
|
||||
border-radius: var(--radius-m) var(--radius-m) 0 0;
|
||||
&.readonly {
|
||||
border-radius: var(--radius-m);
|
||||
}
|
||||
}
|
||||
.scroll-container {
|
||||
display: flex;
|
||||
|
@ -10,6 +10,8 @@
|
||||
import type { GitHubService } from '$lib/github/service';
|
||||
import { open } from '@tauri-apps/api/shell';
|
||||
import Button from '$lib/components/Button.svelte';
|
||||
import toast from 'svelte-french-toast';
|
||||
import Tooltip from '$lib/components/Tooltip.svelte';
|
||||
|
||||
export let readonly = false;
|
||||
export let branch: Branch;
|
||||
@ -24,6 +26,7 @@
|
||||
let meatballButton: HTMLDivElement;
|
||||
let visible = false;
|
||||
let container: HTMLDivElement;
|
||||
let isApplying = false;
|
||||
|
||||
function handleBranchNameChange() {
|
||||
branchController.updateBranchName(branch.id, branch.name);
|
||||
@ -37,33 +40,57 @@
|
||||
</script>
|
||||
|
||||
<div class="header__wrapper">
|
||||
<div class="header card" bind:this={container}>
|
||||
<div class="header card" bind:this={container} class:readonly>
|
||||
<div class="header__info">
|
||||
<div class="header__label">
|
||||
<BranchLabel bind:name={branch.name} on:change={handleBranchNameChange} />
|
||||
<BranchLabel
|
||||
bind:name={branch.name}
|
||||
on:change={handleBranchNameChange}
|
||||
disabled={readonly}
|
||||
/>
|
||||
</div>
|
||||
<div class="header__remote-branch">
|
||||
{#if !branch.upstream}
|
||||
{#if hasIntegratedCommits}
|
||||
<div class="status-tag text-base-11 text-semibold integrated">
|
||||
<Icon name="pr-small" /> integrated
|
||||
</div>
|
||||
{#if !branch.active}
|
||||
<Tooltip label="These changes are stashed away. Apply the lane to bring them back.">
|
||||
<div class="status-tag text-base-11 text-semibold unapplied">
|
||||
<Icon name="removed-branch-small" /> unapplied
|
||||
</div>
|
||||
</Tooltip>
|
||||
{:else if hasIntegratedCommits}
|
||||
<Tooltip
|
||||
label="These changes have been integrated upstream, update your applied branches to make this lane disappear."
|
||||
>
|
||||
<div class="status-tag text-base-11 text-semibold integrated">
|
||||
<Icon name="removed-branch-small" /> integrated
|
||||
</div>
|
||||
</Tooltip>
|
||||
{:else}
|
||||
<div class="status-tag text-base-11 text-semibold pending">
|
||||
<Icon name="virtual-branch-small" /> virtual
|
||||
<Tooltip label="These changes are in a virtual branch.">
|
||||
<div class="status-tag text-base-11 text-semibold pending">
|
||||
<Icon name="virtual-branch-small" /> virtual
|
||||
</div>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
{#if !readonly}
|
||||
<div class="pending-name">
|
||||
<Tooltip
|
||||
label="Branch name that will be used when pushing. You can change it from the lane menu."
|
||||
>
|
||||
<span class="text-base-11 text-semibold">
|
||||
origin/{branch.upstreamName
|
||||
? branch.upstreamName
|
||||
: normalizeBranchName(branch.name)}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="pending-name">
|
||||
<span class="text-base-11 text-semibold"
|
||||
>origin/{branch.upstreamName
|
||||
? branch.upstreamName
|
||||
: normalizeBranchName(branch.name)}</span
|
||||
>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="status-tag text-base-11 text-semibold remote">
|
||||
<Icon name="remote-branch-small" /> remote
|
||||
</div>
|
||||
<Tooltip label="At least some of your changes have been pushed">
|
||||
<div class="status-tag text-base-11 text-semibold remote">
|
||||
<Icon name="remote-branch-small" /> remote
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tag
|
||||
icon="open-link"
|
||||
color="ghost"
|
||||
@ -96,50 +123,107 @@
|
||||
</Tag>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{#if !readonly}
|
||||
<div class="draggable" data-drag-handle>
|
||||
<Icon name="draggable-narrow" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if !readonly}
|
||||
<div class="header__actions">
|
||||
<div class="header__buttons">
|
||||
{#if branch.selectedForChanges}
|
||||
<Button icon="target" notClickable>Target branch</Button>
|
||||
{:else}
|
||||
<Button
|
||||
icon="target"
|
||||
kind="outlined"
|
||||
color="neutral"
|
||||
on:click={async () => {
|
||||
await branchController.setSelectedForChanges(branch.id);
|
||||
}}
|
||||
{#await branch.isMergeable then isMergeable}
|
||||
{#if !isMergeable}
|
||||
<Tooltip
|
||||
timeoutMilliseconds={100}
|
||||
label="Applying this branch will add merge conflict markers that you will have to resolve"
|
||||
>
|
||||
Make target
|
||||
</Button>
|
||||
<Tag icon="locked-small" color="warning">Conflict</Tag>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="relative" bind:this={meatballButton}>
|
||||
{/await}
|
||||
</div>
|
||||
<div class="draggable" data-drag-handle>
|
||||
<Icon name="draggable-narrow" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="header__actions">
|
||||
<div class="header__buttons">
|
||||
{#if branch.selectedForChanges}
|
||||
<Button icon="target" notClickable disabled={readonly}>Target branch</Button>
|
||||
{:else}
|
||||
<Button
|
||||
icon="kebab"
|
||||
icon="target"
|
||||
kind="outlined"
|
||||
color="neutral"
|
||||
on:click={() => (visible = !visible)}
|
||||
/>
|
||||
<div
|
||||
class="branch-popup-menu"
|
||||
use:clickOutside={{
|
||||
trigger: meatballButton,
|
||||
handler: () => (visible = false)
|
||||
disabled={readonly}
|
||||
on:click={async () => {
|
||||
await branchController.setSelectedForChanges(branch.id);
|
||||
}}
|
||||
>
|
||||
<BranchLanePopupMenu {branchController} {branch} {projectId} bind:visible on:action />
|
||||
</div>
|
||||
Make target
|
||||
</Button>
|
||||
{/if}
|
||||
{#if !readonly}
|
||||
<Button
|
||||
icon="cross-small"
|
||||
color="primary"
|
||||
kind="outlined"
|
||||
loading={isApplying}
|
||||
on:click={async () => {
|
||||
isApplying = true;
|
||||
try {
|
||||
await branchController.unapplyBranch(branch.id);
|
||||
} catch (e) {
|
||||
const err = 'Failed to apply branch';
|
||||
toast.error(err);
|
||||
console.error(err, e);
|
||||
} finally {
|
||||
isApplying = false;
|
||||
}
|
||||
}}
|
||||
>
|
||||
Unapply
|
||||
</Button>
|
||||
{:else}
|
||||
<Button
|
||||
icon="plus-small"
|
||||
color="primary"
|
||||
kind="outlined"
|
||||
loading={isApplying}
|
||||
on:click={async () => {
|
||||
isApplying = true;
|
||||
try {
|
||||
await branchController.applyBranch(branch.id);
|
||||
} catch (e) {
|
||||
const err = 'Failed to apply branch';
|
||||
toast.error(err);
|
||||
console.error(err, e);
|
||||
} finally {
|
||||
isApplying = false;
|
||||
}
|
||||
}}
|
||||
>
|
||||
Apply
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="relative" bind:this={meatballButton}>
|
||||
<Button
|
||||
icon="kebab"
|
||||
kind="outlined"
|
||||
color="neutral"
|
||||
on:click={() => (visible = !visible)}
|
||||
/>
|
||||
<div
|
||||
class="branch-popup-menu"
|
||||
use:clickOutside={{
|
||||
trigger: meatballButton,
|
||||
handler: () => (visible = false)
|
||||
}}
|
||||
>
|
||||
<BranchLanePopupMenu
|
||||
{branchController}
|
||||
{branch}
|
||||
{projectId}
|
||||
{readonly}
|
||||
bind:visible
|
||||
on:action
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="header__top-overlay" data-remove-from-draggable data-tauri-drag-region />
|
||||
</div>
|
||||
@ -161,6 +245,9 @@
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
&.readonly {
|
||||
background: var(--clr-theme-container-pale);
|
||||
}
|
||||
}
|
||||
.header__top-overlay {
|
||||
z-index: 1;
|
||||
@ -186,6 +273,10 @@
|
||||
padding: var(--space-12);
|
||||
justify-content: space-between;
|
||||
border-radius: 0 0 var(--radius-m) var(--radius-m);
|
||||
user-select: none;
|
||||
}
|
||||
.readonly .header__actions {
|
||||
background: var(--clr-theme-container-dim);
|
||||
}
|
||||
.header__buttons {
|
||||
display: flex;
|
||||
@ -281,4 +372,9 @@
|
||||
color: var(--clr-theme-scale-ntrl-100);
|
||||
background: var(--clr-theme-scale-ntrl-40);
|
||||
}
|
||||
|
||||
.unapplied {
|
||||
color: var(--clr-theme-scale-ntrl-30);
|
||||
background: var(--clr-theme-scale-ntrl-80);
|
||||
}
|
||||
</style>
|
||||
|
@ -1,10 +1,12 @@
|
||||
<script lang="ts">
|
||||
export let name: string;
|
||||
export let disabled = false;
|
||||
let inputActive = false;
|
||||
let label: HTMLDivElement;
|
||||
let input: HTMLInputElement;
|
||||
|
||||
function activateInput() {
|
||||
if (disabled) return;
|
||||
inputActive = true;
|
||||
setTimeout(() => input.select(), 0);
|
||||
}
|
||||
@ -25,6 +27,7 @@
|
||||
<span class="branch-name-mesure-el text-base-13" bind:this={mesureEl}>{name}</span>
|
||||
<input
|
||||
type="text"
|
||||
{disabled}
|
||||
bind:this={input}
|
||||
bind:value={name}
|
||||
on:change
|
||||
|
@ -60,6 +60,7 @@
|
||||
{projectPath}
|
||||
{branchController}
|
||||
{selectedOwnership}
|
||||
{readonly}
|
||||
selectable={$commitBoxOpen && !readonly}
|
||||
on:close={() => {
|
||||
const selectedId = selected?.id;
|
||||
|
@ -14,6 +14,7 @@
|
||||
export let branch: Branch;
|
||||
export let projectId: string;
|
||||
export let visible: boolean;
|
||||
export let readonly = false;
|
||||
|
||||
let deleteBranchModal: Modal;
|
||||
let renameRemoteModal: Modal;
|
||||
@ -33,10 +34,15 @@
|
||||
{#if visible}
|
||||
<ContextMenu>
|
||||
<ContextMenuSection>
|
||||
<ContextMenuItem
|
||||
label="Unapply"
|
||||
on:click={() => branch.id && branchController.unapplyBranch(branch.id)}
|
||||
/>
|
||||
{#if !readonly}
|
||||
<ContextMenuItem
|
||||
label="Unapply"
|
||||
on:click={() => {
|
||||
if (branch.id) branchController.unapplyBranch(branch.id);
|
||||
visible = false;
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<ContextMenuItem
|
||||
label="Delete"
|
||||
@ -52,13 +58,13 @@
|
||||
dispatch('action', 'generate-branch-name');
|
||||
visible = false;
|
||||
}}
|
||||
disabled={!$aiGenEnabled || branch.files?.length == 0 || !branch.active}
|
||||
disabled={readonly || !$aiGenEnabled || branch.files?.length == 0 || !branch.active}
|
||||
/>
|
||||
</ContextMenuSection>
|
||||
<ContextMenuSection>
|
||||
<ContextMenuItem
|
||||
label="Set branch name"
|
||||
disabled={hasIntegratedCommits}
|
||||
disabled={readonly || hasIntegratedCommits}
|
||||
on:click={() => {
|
||||
newRemoteName = branch.upstreamName || '';
|
||||
visible = false;
|
||||
|
@ -27,7 +27,7 @@
|
||||
export let conflicted: boolean;
|
||||
export let projectPath: string | undefined;
|
||||
export let branchController: BranchController;
|
||||
export let readonly = false;
|
||||
export let readonly: boolean;
|
||||
export let selectable = false;
|
||||
export let selectedOwnership: Writable<Ownership>;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user