Fix sync & delete button UI bugs

This commit is contained in:
Mattias Granlund 2024-01-17 15:57:39 +01:00
parent 87a8f2e9ae
commit 1dbba1f9db
7 changed files with 61 additions and 51 deletions

View File

@ -1,4 +1,4 @@
import type { BaseBranch, Hunk } from './types';
import type { Hunk } from './types';
import * as toasts from '$lib/utils/toasts';
import { invoke } from '$lib/backend/ipc';
import type { BaseBranchService, VirtualBranchService } from './branchStoresCache';
@ -14,7 +14,7 @@ export class BranchController {
async setTarget(branch: string) {
try {
await invoke<BaseBranch>('set_base_branch', { projectId: this.projectId, branch });
await this.targetBranchService.setTarget(branch);
// TODO: Reloading seems to trigger 4 invocations of `list_virtual_branches`
} catch (err) {
toasts.error('Failed to set base branch');
@ -200,18 +200,6 @@ export class BranchController {
}
}
async fetchFromTarget() {
try {
await invoke<void>('fetch_from_target', { projectId: this.projectId });
} catch (err: any) {
if (err.code === 'errors.git.authentication') {
toasts.error('Failed to authenticate. Did you setup GitButler ssh keys?');
} else {
toasts.error(`Failed to fetch branch: ${err.message}`);
}
}
}
async cherryPick(branchId: string, targetCommitOid: string) {
try {
await invoke<void>('cherry_pick_onto_virtual_branch', {

View File

@ -1,3 +1,5 @@
import * as toasts from '$lib/utils/toasts';
import { BaseBranch, Branch } from './types';
import { plainToInstance } from 'class-transformer';
import { invoke, listen } from '$lib/backend/ipc';
@ -85,23 +87,54 @@ function subscribeToVirtualBranches(projectId: string, callback: (branches: Bran
}
export class BaseBranchService {
base$: Observable<BaseBranch | null>;
base$: Observable<BaseBranch | null | undefined>;
busy$ = new BehaviorSubject(false);
error$ = new BehaviorSubject<any>(undefined);
private reload$ = new BehaviorSubject<void>(undefined);
constructor(projectId: string, fetches$: Observable<unknown>, head$: Observable<string>) {
constructor(
private projectId: string,
fetches$: Observable<unknown>,
head$: Observable<string>
) {
this.base$ = combineLatest([fetches$, head$, this.reload$]).pipe(
debounceTime(100),
switchMap(() => getBaseBranch({ projectId })),
switchMap(async () => {
this.busy$.next(true);
return await getBaseBranch({ projectId });
}),
tap(() => this.busy$.next(false)),
shareReplay(1),
catchError((e) => {
this.error$.next(e);
throw e;
}),
shareReplay(1)
return of(undefined);
})
);
}
async fetchFromTarget() {
this.busy$.next(true);
try {
// Note that we expect the back end to emit new fetches event, and therefore
// trigger a base branch reload. It feels a bit awkward and should be improved.
await invoke<void>('fetch_from_target', { projectId: this.projectId });
} catch (err: any) {
if (err.code === 'errors.git.authentication') {
toasts.error('Failed to authenticate. Did you setup GitButler ssh keys?');
} else {
toasts.error(`Failed to fetch branch: ${err.message}`);
}
}
}
async setTarget(branch: string) {
this.busy$.next(true);
await invoke<BaseBranch>('set_base_branch', { projectId: this.projectId, branch });
await this.fetchFromTarget();
}
reload() {
this.busy$.next(true);
this.reload$.next();
}
}

View File

@ -28,6 +28,7 @@
$: baseBranchService = data.baseBranchService;
$: baseBranch$ = baseBranchService.base$;
$: baseError$ = baseBranchService.error$;
$: gbBranchActive$ = data.gbBranchActive$;
$: user$ = data.user$;
@ -61,7 +62,11 @@
<ProjectSetup {branchController} {userService} {projectId} {remoteBranches} />
{/if}
{/await}
{:else if !$gbBranchActive$}
{:else if $baseError$}
<ProblemLoadingRepo {projectService} {userService} project={$project$} error={$baseError$} />
{:else if $branchesError$}
<ProblemLoadingRepo {projectService} {userService} project={$project$} error={$branchesError$} />
{:else if !$gbBranchActive$ && $baseBranch$}
<NotOnGitButlerBranch
{userService}
{projectService}
@ -69,8 +74,6 @@
project={$project$}
baseBranch={$baseBranch$}
/>
{:else if $branchesError$}
<ProblemLoadingRepo {projectService} {userService} project={$project$} error={$branchesError$} />
{:else if $baseBranch$}
<div class="relative flex w-full max-w-full" role="group" on:dragover|preventDefault>
<div bind:this={trayViewport} class="flex flex-shrink">

View File

@ -6,12 +6,10 @@
import type { GitHubService } from '$lib/github/service';
import Icon from '$lib/icons/Icon.svelte';
import IconGithub from '$lib/icons/IconGithub.svelte';
import type { BranchController } from '$lib/vbranches/branchController';
import type { BaseBranchService } from '$lib/vbranches/branchStoresCache';
import SyncButton from './SyncButton.svelte';
export let project: Project;
export let branchController: BranchController;
export let baseBranchService: BaseBranchService;
export let githubService: GitHubService;
@ -44,7 +42,6 @@
{/if}
<SyncButton
projectId={project.id}
{branchController}
{baseBranchService}
{githubService}
cloudEnabled={project?.api?.sync || false}

View File

@ -55,7 +55,7 @@
<div class="domains">
<ProjectSelector {project} {projectService} />
<div class="flex flex-col gap-1">
<BaseBranchCard {project} {baseBranchService} {branchController} {githubService} />
<BaseBranchCard {project} {baseBranchService} {githubService} />
<DomainButton href={`/${project.id}/board`}>
<svg
width="16"

View File

@ -4,18 +4,15 @@
import TimeAgo from '$lib/components/TimeAgo.svelte';
import Tooltip from '$lib/components/Tooltip.svelte';
import type { GitHubService } from '$lib/github/service';
import type { BranchController } from '$lib/vbranches/branchController';
import type { BaseBranchService } from '$lib/vbranches/branchStoresCache';
export let branchController: BranchController;
export let githubService: GitHubService;
export let projectId: string;
export let baseBranchService: BaseBranchService;
export let cloudEnabled: boolean;
$: base$ = baseBranchService.base$;
let fetching = false;
$: baseServiceBusy$ = baseBranchService.busy$;
</script>
<button
@ -23,34 +20,27 @@
on:click={async (e) => {
e.preventDefault();
e.stopPropagation();
fetching = true;
try {
if (cloudEnabled) syncToCloud(projectId); // don't wait for this
await branchController.fetchFromTarget();
if (githubService.isEnabled()) {
await githubService.reload();
}
} finally {
fetching = false;
if (cloudEnabled) syncToCloud(projectId); // don't wait for this
await baseBranchService.fetchFromTarget();
if (githubService.isEnabled()) {
await githubService.reload();
}
}}
>
{#if !fetching}
{#if !$baseServiceBusy$}
<div class="sync-btn__icon">
<Icon name="update-small" />
</div>
{/if}
<Tooltip label="Last fetch from upstream">
{#if $base$?.lastFetched}
<span class="text-base-11 text-semibold sync-btn__label">
{#if fetching}
<div class="sync-btn__busy-label">busy…</div>
{:else}
<TimeAgo date={$base$?.lastFetched} />
{/if}
</span>
{/if}
<span class="text-base-11 text-semibold sync-btn__label">
{#if $baseServiceBusy$}
<div class="sync-btn__busy-label">busy…</div>
{:else if $base$?.lastFetched}
<TimeAgo date={$base$?.lastFetched} />
{/if}
</span>
</Tooltip>
</button>

View File

@ -29,7 +29,6 @@
.then(() => (isDeleting = true))
.then(() => goto('/'))
.then(() => projectService.deleteProject($project$?.id))
.then(() => deleteConfirmationModal.close())
.catch((e) => {
console.error(e);
toasts.error('Failed to delete project');