Skip to content

Commit

Permalink
Merge pull request gitbutlerapp#4963 from gitbutlerapp/factor-out-int…
Browse files Browse the repository at this point in the history
…egrate-upstream-modal

IntegrateUpstreamModal: Factor out the modal
  • Loading branch information
estib-vega authored Sep 24, 2024
2 parents 20fa6cb + adc6357 commit 3bed869
Show file tree
Hide file tree
Showing 5 changed files with 334 additions and 287 deletions.
32 changes: 17 additions & 15 deletions apps/desktop/src/lib/components/BaseBranch.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<script lang="ts">
import IntegrateUpstreamModal from './IntegrateUpstreamModal.svelte';
import Spacer from '../shared/Spacer.svelte';
import { Project } from '$lib/backend/projects';
import CommitCard from '$lib/commit/CommitCard.svelte';
import UpdateBaseButton from '$lib/components/UpdateBaseButton.svelte';
import { projectMergeUpstreamWarningDismissed } from '$lib/config/config';
import { getGitHost } from '$lib/gitHost/interface/gitHost';
import { ModeService } from '$lib/modes/service';
Expand All @@ -29,6 +29,7 @@
);
let updateTargetModal: Modal;
let integrateUpstreamModal: IntegrateUpstreamModal | undefined;
let mergeUpstreamWarningDismissedCheckbox = false;
$: multiple = base ? base.upstreamCommits.length > 1 || base.upstreamCommits.length === 0 : false;
Expand All @@ -40,7 +41,17 @@
}
}
let updateBaseButton: UpdateBaseButton | undefined;
function mergeUpstream() {
if (project.succeedingRebases) {
integrateUpstreamModal?.show();
} else {
if (mergeUpstreamWarningDismissedCheckbox) {
updateBaseBranch();
} else {
updateTargetModal.show();
}
}
}
</script>

<div class="wrapper">
Expand All @@ -51,23 +62,14 @@
</div>

{#if base.upstreamCommits?.length > 0}
<UpdateBaseButton bind:this={updateBaseButton} showButton={false} />
<IntegrateUpstreamModal bind:this={integrateUpstreamModal} />
<Button
style="pop"
kind="solid"
tooltip={`Merges the commits from ${base.branchName} into the base of all applied virtual branches`}
disabled={$mode?.type !== 'OpenWorkspace'}
onclick={() => {
if (project.succeedingRebases) {
updateBaseButton?.openModal();
} else {
if ($mergeUpstreamWarningDismissed) {
updateBaseBranch();
} else {
updateTargetModal.show();
}
}
}}
disabled={$mode?.type !== 'OpenWorkspace' || integrateUpstreamModal.imports.open}
loading={integrateUpstreamModal.imports.open}
onclick={mergeUpstream}
>
Merge into common base
</Button>
Expand Down
258 changes: 258 additions & 0 deletions apps/desktop/src/lib/components/IntegrateUpstreamModal.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
<script lang="ts">
import { BaseBranchService } from '$lib/baseBranch/baseBranchService';
import CommitCard from '$lib/commit/CommitCard.svelte';
import { getGitHost } from '$lib/gitHost/interface/gitHost';
import ScrollableContainer from '$lib/scroll/ScrollableContainer.svelte';
import Select from '$lib/select/Select.svelte';
import SelectItem from '$lib/select/SelectItem.svelte';
import { getContext } from '$lib/utils/context';
import {
getResolutionApproach,
sortStatusInfo,
UpstreamIntegrationService,
type BranchStatusesWithBranches,
type BranchStatusInfo,
type Resolution
} from '$lib/vbranches/upstreamIntegrationService';
import Button from '@gitbutler/ui/Button.svelte';
import Modal from '@gitbutler/ui/Modal.svelte';
import { tick } from 'svelte';
import { SvelteMap } from 'svelte/reactivity';
import type { Readable } from 'svelte/store';
type OperationState = 'inert' | 'loading' | 'completed';
interface Props {
onClose?: () => void;
}
const { onClose }: Props = $props();
const gitHost = getGitHost();
const upstreamIntegrationService = getContext(UpstreamIntegrationService);
let branchStatuses = $state<Readable<BranchStatusesWithBranches | undefined>>();
const baseBranchService = getContext(BaseBranchService);
const base = baseBranchService.base;
let modal = $state<Modal>();
let integratingUpstream = $state<OperationState>('inert');
let results = $state(new SvelteMap<string, Resolution>());
let statuses = $state<BranchStatusInfo[]>([]);
let expanded = $state<boolean>(false);
$effect(() => {
if ($branchStatuses?.type !== 'updatesRequired') {
statuses = [];
return;
}
const statusesTmp = [...$branchStatuses.subject];
statusesTmp.sort(sortStatusInfo);
// Side effect, refresh results
results = new SvelteMap(
statusesTmp.map((status) => {
const defaultApproach = getResolutionApproach(status);
return [
status.branch.id,
{
branchId: status.branch.id,
branchTree: status.branch.tree,
approach: defaultApproach
}
];
})
);
statuses = statusesTmp;
});
async function integrate() {
integratingUpstream = 'loading';
await tick();
await upstreamIntegrationService.integrateUpstream(Array.from(results.values()));
await baseBranchService.refresh();
integratingUpstream = 'completed';
modal?.close();
}
export async function show() {
integratingUpstream = 'inert';
expanded = false;
branchStatuses = upstreamIntegrationService.upstreamStatuses();
await tick();
modal?.show();
}
export const imports = {
get open() {
return modal?.imports.open;
}
};
</script>

<Modal bind:this={modal} title="Integrate upstream changes" {onClose} width="small" noPadding>
<ScrollableContainer maxHeight="50vh">
<div class="modal-content">
{#if $base}
<div class="upstream-commits">
{#each $base.upstreamCommits.slice(0, 2) as commit, index}
<CommitCard
{commit}
first={index === 0}
last={(() => {
if (expanded) {
return $base.upstreamCommits.length - 1 === index;
} else {
if ($base.upstreamCommits.length > 2) {
return index === 1;
} else {
return $base.upstreamCommits.length - 1 === index;
}
}
})()}
isUnapplied={true}
commitUrl={$gitHost?.commitUrl(commit.id)}
type="remote"
filesToggleable={false}
/>
{/each}
{#if $base.upstreamCommits.length > 2}
{#if expanded}
{#each $base.upstreamCommits.slice(2) as commit, index}
<CommitCard
{commit}
last={index === $base.upstreamCommits.length - 3}
isUnapplied={true}
commitUrl={$gitHost?.commitUrl(commit.id)}
type="remote"
filesToggleable={false}
/>
{/each}
<div class="commit-expand-button">
<Button wide onclick={() => (expanded = false)}>Hide</Button>
</div>
{:else}
<div class="commit-expand-button">
<Button wide onclick={() => (expanded = true)}
>Show more ({$base.upstreamCommits.length - 2})</Button
>
</div>
{/if}
{/if}
</div>
{/if}
{#if statuses.length > 0}
<div class="statuses">
{#each statuses as { branch, status }}
<div class="branch-status" class:integrated={status.type === 'fullyIntegrated'}>
<div class="description">
<h5 class="text-16">{branch?.name || 'Unknown'}</h5>
{#if status.type === 'conflicted'}
<p>Conflicted</p>
{:else if status.type === 'saflyUpdatable' || status.type === 'empty'}
<p>No Conflicts</p>
{:else if status.type === 'fullyIntegrated'}
<p>Integrated</p>
{/if}
</div>

<div class="action" class:action--centered={status.type === 'fullyIntegrated'}>
{#if status.type === 'fullyIntegrated'}
<p>Changes included in base branch</p>
{:else if results.get(branch.id)}
<Select
value={results.get(branch.id)!.approach.type}
onselect={(value) => {
const result = results.get(branch.id)!

results.set(branch.id, {...result, approach: { type: value as "rebase" | "merge" | "unapply" }})
}}
options={[
{ label: 'Rebase', value: 'rebase' },
{ label: 'Merge', value: 'merge' },
{ label: 'Stash', value: 'unapply' }
]}
>
{#snippet itemSnippet({ item, highlighted })}
<SelectItem selected={highlighted} {highlighted}>
{item.label}
</SelectItem>
{/snippet}
</Select>
{/if}
</div>
</div>
{/each}
</div>
{/if}
</div>
</ScrollableContainer>

{#snippet controls()}
<Button onclick={() => modal?.close()}>Cancel</Button>
<Button onclick={integrate} style="pop" kind="solid" loading={integratingUpstream === 'loading'}
>Integrate</Button
>
{/snippet}
</Modal>

<style>
.upstream-commits {
text-align: left;
padding: 0 16px;
}
.modal-content {
display: flex;
flex-direction: column;
gap: 14px;
padding-bottom: 14px;
}
.statuses {
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-around;
gap: 14px;
}
.branch-status {
display: flex;
justify-content: space-between;
padding: 0 14px;
&.integrated {
background-color: var(--clr-bg-2);
}
& .description {
display: flex;
flex-direction: column;
gap: 8px;
text-align: left;
}
& .action {
width: 144px;
&.action--centered {
display: flex;
align-items: center;
justify-content: center;
}
}
}
.commit-expand-button {
margin: 8px -16px;
padding: 0 16px;
padding-bottom: 8px;
border-bottom: 1px solid var(--clr-border-2);
}
</style>
Loading

0 comments on commit 3bed869

Please sign in to comment.