diff --git a/gitbutler-ui/src/lib/branches/service.ts b/gitbutler-ui/src/lib/branches/service.ts index 6af89aaeb..1c245e847 100644 --- a/gitbutler-ui/src/lib/branches/service.ts +++ b/gitbutler-ui/src/lib/branches/service.ts @@ -83,6 +83,10 @@ export class BranchService { createPrSpan.finish(); } } + + async reloadVirtualBranches() { + await this.vbranchService.reload(); + } } function mergeBranchesAndPrs( diff --git a/gitbutler-ui/src/lib/components/BranchCard.svelte b/gitbutler-ui/src/lib/components/BranchCard.svelte index 257d74a8e..b77686a11 100644 --- a/gitbutler-ui/src/lib/components/BranchCard.svelte +++ b/gitbutler-ui/src/lib/components/BranchCard.svelte @@ -141,6 +141,7 @@ {branch} {base} {githubService} + {branchService} projectId={project.id} on:action={(e) => { if (e.detail == 'generate-branch-name') { diff --git a/gitbutler-ui/src/lib/components/BranchHeader.svelte b/gitbutler-ui/src/lib/components/BranchHeader.svelte index b5a916c42..2a3ac3a75 100644 --- a/gitbutler-ui/src/lib/components/BranchHeader.svelte +++ b/gitbutler-ui/src/lib/components/BranchHeader.svelte @@ -4,37 +4,63 @@ import Tag from './Tag.svelte'; import { clickOutside } from '$lib/clickOutside'; import Button from '$lib/components/Button.svelte'; - import Icon from '$lib/components/Icon.svelte'; + import Icon, { type IconColor } from '$lib/components/Icon.svelte'; import { normalizeBranchName } from '$lib/utils/branch'; import * as toasts from '$lib/utils/toasts'; import { tooltip } from '$lib/utils/tooltip'; import { open } from '@tauri-apps/api/shell'; import toast from 'svelte-french-toast'; + import type { BranchService } from '$lib/branches/service'; import type { GitHubService } from '$lib/github/service'; + import type { PrStatus } from '$lib/github/types'; import type { BranchController } from '$lib/vbranches/branchController'; import type { BaseBranch, Branch } from '$lib/vbranches/types'; + import type iconsJson from '../icons/icons.json'; import { goto } from '$app/navigation'; export let isUnapplied = false; export let branch: Branch; export let base: BaseBranch | undefined | null; export let branchController: BranchController; + export let branchService: BranchService; export let projectId: string; export let githubService: GitHubService; $: pr$ = githubService.get(branch.upstreamName); - // $: prStatus$ = githubService.getStatus($pr$?.targetBranch); + $: prStatus$ = githubService.getStatus($pr$?.targetBranch); let meatballButton: HTMLDivElement; let visible = false; let container: HTMLDivElement; let isApplying = false; let isDeleting = false; + let isMerging = false; function handleBranchNameChange() { branchController.updateBranchName(branch.id, branch.name); } + $: prColor = statusToColor($prStatus$); + $: prIcon = statusToIcon($prStatus$); + + function statusToColor(status: PrStatus | undefined): IconColor { + if (!status) return 'neutral'; + if (status && !status.hasChecks) return 'neutral'; + if (status.completed) { + return status.success ? 'success' : 'error'; + } + return 'warn'; + } + + function statusToIcon(status: PrStatus | undefined): keyof typeof iconsJson | undefined { + if (!status) return; + if (status && !status.hasChecks) return; + if (status.completed) { + return status.success ? 'success' : 'error'; + } + return 'warning'; + } + $: hasIntegratedCommits = branch.commits?.some((b) => b.isIntegrated); @@ -122,6 +148,9 @@ View PR {/if} + {#if prIcon} + + {/if} {/if} {#await branch.isMergeable then isMergeable} {#if !isMergeable} @@ -162,6 +191,26 @@ Set as default {/if} + {#if $prStatus$?.success} + + {/if}
{#if isUnapplied} diff --git a/gitbutler-ui/src/lib/components/CommitListHeader.svelte b/gitbutler-ui/src/lib/components/CommitListHeader.svelte index 4045e2478..57571f0a6 100644 --- a/gitbutler-ui/src/lib/components/CommitListHeader.svelte +++ b/gitbutler-ui/src/lib/components/CommitListHeader.svelte @@ -10,17 +10,6 @@ let element: HTMLButtonElement | undefined = undefined; - // $: prColor = statusToColor($prStatus$); - - // function statusToColor(status: PrStatus | undefined): TagColor { - // if (!status) return 'neutral-light'; - // if (status && !status.hasChecks) return 'neutral-light'; - // if (status.completed) { - // return status.success ? 'success' : 'error'; - // } - // return 'warning'; - // } - onMount(() => (height = element?.offsetHeight)); diff --git a/gitbutler-ui/src/lib/github/service.ts b/gitbutler-ui/src/lib/github/service.ts index bfbc107c6..860de7bfc 100644 --- a/gitbutler-ui/src/lib/github/service.ts +++ b/gitbutler-ui/src/lib/github/service.ts @@ -47,6 +47,10 @@ export class GitHubService { private ctx$: Observable; private octokit$: Observable; + // For use with user initiated actions like merging + private ctx: GitHubIntegrationContext | undefined; + private octokit: Octokit | undefined; + private enabled = false; constructor(userService: UserService, baseBranchService: BaseBranchService) { @@ -68,12 +72,14 @@ export class GitHubService { return of({ authToken, owner, repo, username }); }), distinct((val) => JSON.stringify(val)), + tap((ctx) => (this.ctx = ctx)), shareReplay(1) ); // Create a github client this.octokit$ = this.ctx$.pipe( map((ctx) => (ctx ? newClient(ctx.authToken) : undefined)), + tap((octokit) => (this.octokit = octokit)), shareReplay(1) ); @@ -243,6 +249,19 @@ export class GitHubService { }) ); } + + async merge(pullNumber: number) { + if (!this.octokit || !this.ctx) return; + try { + await this.octokit.pulls.merge({ + owner: this.ctx.owner, + repo: this.ctx.repo, + pull_number: pullNumber + }); + } finally { + this.reload(); + } + } } function loadPrs(