mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-09-11 12:25:42 +03:00
Fix sync & delete button UI bugs
This commit is contained in:
parent
87a8f2e9ae
commit
1dbba1f9db
@ -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', {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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">
|
||||
|
@ -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}
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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');
|
||||
|
Loading…
Reference in New Issue
Block a user