mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-18 06:22:28 +03:00
Small refactor of history component
This commit is contained in:
parent
076ff9beed
commit
c699ad4dfa
@ -1,68 +1,3 @@
|
||||
<script lang="ts" context="module">
|
||||
export type Trailer = {
|
||||
key: string;
|
||||
value: string;
|
||||
};
|
||||
export type Operation =
|
||||
| 'CreateCommit'
|
||||
| 'CreateBranch'
|
||||
| 'SetBaseBranch'
|
||||
| 'MergeUpstream'
|
||||
| 'UpdateWorkspaceBase'
|
||||
| 'MoveHunk'
|
||||
| 'UpdateBranchName'
|
||||
| 'UpdateBranchNotes'
|
||||
| 'ReorderBranches'
|
||||
| 'SelectDefaultVirtualBranch'
|
||||
| 'UpdateBranchRemoteName'
|
||||
| 'GenericBranchUpdate'
|
||||
| 'DeleteBranch'
|
||||
| 'ApplyBranch'
|
||||
| 'DiscardHunk'
|
||||
| 'DiscardFile'
|
||||
| 'AmendCommit'
|
||||
| 'UndoCommit'
|
||||
| 'UnapplyBranch'
|
||||
| 'CherryPick'
|
||||
| 'SquashCommit'
|
||||
| 'UpdateCommitMessage'
|
||||
| 'MoveCommit'
|
||||
| 'RestoreFromSnapshot'
|
||||
| 'ReorderCommit'
|
||||
| 'InsertBlankCommit'
|
||||
| 'MoveCommitFile'
|
||||
| 'FileChanges';
|
||||
export type SnapshotDetails = {
|
||||
title: string;
|
||||
operation: Operation;
|
||||
body: string | undefined;
|
||||
trailers: Trailer[];
|
||||
};
|
||||
export type Snapshot = {
|
||||
id: string;
|
||||
linesAdded: number;
|
||||
linesRemoved: number;
|
||||
filesChanged: string[];
|
||||
details: SnapshotDetails | undefined;
|
||||
createdAt: number;
|
||||
};
|
||||
|
||||
export function createdOnDay(dateNumber: number) {
|
||||
const d = new Date(dateNumber);
|
||||
const t = new Date();
|
||||
return `${t.toDateString() == d.toDateString() ? 'Today' : d.toLocaleDateString('en-US', { weekday: 'short' })}, ${d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}`;
|
||||
}
|
||||
export type SnapshotDiff = {
|
||||
binary: boolean;
|
||||
hunks: RemoteHunk[];
|
||||
newPath: string;
|
||||
newSizeBytes: number;
|
||||
oldPath: string;
|
||||
oldSizeBytes: number;
|
||||
skipped: boolean;
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import Button from './Button.svelte';
|
||||
import EmptyStatePlaceholder from './EmptyStatePlaceholder.svelte';
|
||||
@ -72,84 +7,29 @@
|
||||
import ScrollableContainer from './ScrollableContainer.svelte';
|
||||
import SnapshotCard from './SnapshotCard.svelte';
|
||||
import emptyFolderSvg from '$lib/assets/empty-state/empty-folder.svg?raw';
|
||||
import { invoke, listen } from '$lib/backend/ipc';
|
||||
import { listen } from '$lib/backend/ipc';
|
||||
import { Project } from '$lib/backend/projects';
|
||||
import { clickOutside } from '$lib/clickOutside';
|
||||
import { SETTINGS, type Settings } from '$lib/settings/userSettings';
|
||||
import { getContext, getContextStoreBySymbol } from '$lib/utils/context';
|
||||
import { type RemoteHunk, RemoteFile } from '$lib/vbranches/types';
|
||||
import { VirtualBranchService } from '$lib/vbranches/virtualBranch';
|
||||
import { HistoryService, createdOnDay } from '$lib/history/history';
|
||||
import { persisted } from '$lib/persisted/persisted';
|
||||
import { getContext } from '$lib/utils/context';
|
||||
import * as hotkeys from '$lib/utils/hotkeys';
|
||||
import { RemoteFile } from '$lib/vbranches/types';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import type { Writable } from 'svelte/store';
|
||||
import { goto } from '$app/navigation';
|
||||
import { onMount } from 'svelte';
|
||||
import type { Snapshot, SnapshotDiff } from '$lib/history/types';
|
||||
|
||||
const project = getContext(Project);
|
||||
const historyService = getContext(HistoryService);
|
||||
const snapshots = historyService.snapshots;
|
||||
|
||||
const showHistoryView = persisted(false, 'showHistoryView');
|
||||
const loading = historyService.loading;
|
||||
|
||||
export let projectId: string;
|
||||
let currentFilePreview: RemoteFile | undefined = undefined;
|
||||
|
||||
const userSettings = getContextStoreBySymbol<Settings, Writable<Settings>>(SETTINGS);
|
||||
|
||||
const vbranchService = getContext(VirtualBranchService);
|
||||
|
||||
let listElement: HTMLElement | undefined = undefined;
|
||||
|
||||
// TODO: Fires multiple times nad cause uninitialized variable error
|
||||
vbranchService.activeBranches.subscribe(() => {
|
||||
// whenever virtual branches change, we need to reload the snapshots
|
||||
// TODO: if the list has results from more pages, merge into it?
|
||||
listSnapshots(projectId)
|
||||
.then((rsp) => {
|
||||
snapshots = rsp;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error occurred while listing snapshots:', error);
|
||||
});
|
||||
});
|
||||
|
||||
let snapshots: Snapshot[] = [];
|
||||
let isSnapshotsLoading = false;
|
||||
|
||||
async function listSnapshots(projectId: string, sha?: string) {
|
||||
isSnapshotsLoading = true;
|
||||
|
||||
const resp = await invoke<Snapshot[]>('list_snapshots', {
|
||||
projectId: projectId,
|
||||
limit: 32,
|
||||
sha: sha
|
||||
});
|
||||
|
||||
isSnapshotsLoading = false;
|
||||
return resp;
|
||||
}
|
||||
|
||||
async function getSnapshotDiff(projectId: string, sha: string) {
|
||||
const resp = await invoke<{ [key: string]: SnapshotDiff }>('snapshot_diff', {
|
||||
projectId: projectId,
|
||||
sha: sha
|
||||
});
|
||||
return resp;
|
||||
}
|
||||
|
||||
async function restoreSnapshot(projectId: string, sha: string) {
|
||||
await invoke<string>('restore_snapshot', {
|
||||
projectId: projectId,
|
||||
sha: sha
|
||||
});
|
||||
|
||||
await listSnapshots(projectId).then((rsp) => {
|
||||
snapshots = rsp;
|
||||
});
|
||||
|
||||
// TODO: is there a better way to update all the state?
|
||||
await goto(window.location.href, { replaceState: true });
|
||||
}
|
||||
|
||||
function onLastInView() {
|
||||
if (!listElement) return;
|
||||
if (listElement.scrollTop + listElement.clientHeight >= listElement.scrollHeight) {
|
||||
listSnapshots(projectId, snapshots[snapshots.length - 1].id).then((rsp) => {
|
||||
snapshots = [...snapshots, ...rsp.slice(1)];
|
||||
});
|
||||
}
|
||||
async function onLastInView() {
|
||||
if (!$loading) await historyService.loadMore();
|
||||
}
|
||||
|
||||
function updateFilePreview(entry: Snapshot, path: string) {
|
||||
@ -169,60 +49,35 @@
|
||||
});
|
||||
}
|
||||
|
||||
function closeView() {
|
||||
userSettings.update((s) => ({
|
||||
...s,
|
||||
showHistoryView: false
|
||||
}));
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
if (listElement) listElement.addEventListener('scroll', onLastInView, true);
|
||||
});
|
||||
onMount(() => {
|
||||
const unsubscribe = listen<string>('menu://view/history/clicked', () => {
|
||||
userSettings.update((s) => ({
|
||||
...s,
|
||||
showHistoryView: !$userSettings.showHistoryView
|
||||
}));
|
||||
$showHistoryView = !$showHistoryView;
|
||||
});
|
||||
|
||||
return () => {
|
||||
// TODO: Refactor somehow
|
||||
const unsubscribeHotkeys = hotkeys.on('$mod+Shift+H', () => {
|
||||
$showHistoryView = !$showHistoryView;
|
||||
});
|
||||
|
||||
return async () => {
|
||||
unsubscribe();
|
||||
unsubscribeHotkeys();
|
||||
};
|
||||
});
|
||||
onDestroy(() => {
|
||||
listElement?.removeEventListener('scroll', onLastInView, true);
|
||||
});
|
||||
|
||||
// optimisation: don't fetch snapshots if the view is not visible
|
||||
$: if (!$userSettings.showHistoryView) {
|
||||
snapshots = [];
|
||||
currentFilePreview = undefined;
|
||||
selectedFile = undefined;
|
||||
} else {
|
||||
listSnapshots(projectId).then((rsp) => {
|
||||
snapshots = rsp;
|
||||
});
|
||||
}
|
||||
|
||||
let snapshotFilesTempStore:
|
||||
| { entryId: string; diffs: { [key: string]: SnapshotDiff } }
|
||||
| undefined = undefined;
|
||||
let selectedFile: { entryId: string; path: string } | undefined = undefined;
|
||||
|
||||
$: if (snapshotFilesTempStore) {
|
||||
console.log(snapshotFilesTempStore);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if $userSettings.showHistoryView}
|
||||
<aside class="sideview-container" class:show-view={$userSettings.showHistoryView}>
|
||||
{#if $showHistoryView}
|
||||
<aside class="sideview-container" class:show-view={$showHistoryView}>
|
||||
<div
|
||||
class="sideview-content-wrap"
|
||||
use:clickOutside={{
|
||||
handler: () => {
|
||||
closeView();
|
||||
$showHistoryView = false;
|
||||
}
|
||||
}}
|
||||
>
|
||||
@ -252,13 +107,13 @@
|
||||
style="ghost"
|
||||
icon="cross"
|
||||
on:click={() => {
|
||||
closeView();
|
||||
$showHistoryView = false;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- EMPTY STATE -->
|
||||
{#if snapshots.length == 0}
|
||||
{#if $snapshots.length == 0}
|
||||
<EmptyStatePlaceholder image={emptyFolderSvg}>
|
||||
<svelte:fragment slot="title">No snapshots yet</svelte:fragment>
|
||||
<svelte:fragment slot="caption">
|
||||
@ -268,17 +123,17 @@
|
||||
</EmptyStatePlaceholder>
|
||||
{/if}
|
||||
|
||||
{#if isSnapshotsLoading}
|
||||
{#if $snapshots.length == 0 && $loading}
|
||||
<FullviewLoading />
|
||||
{/if}
|
||||
|
||||
<!-- SNAPSHOTS -->
|
||||
{#if snapshots.length > 0 && !isSnapshotsLoading}
|
||||
{#if $snapshots.length > 0}
|
||||
<ScrollableContainer on:bottomReached={onLastInView}>
|
||||
<div class="container" bind:this={listElement}>
|
||||
<div class="container">
|
||||
<!-- SNAPSHOTS FEED -->
|
||||
{#each snapshots as entry, idx}
|
||||
{#if idx === 0 || createdOnDay(entry.createdAt) != createdOnDay(snapshots[idx - 1].createdAt)}
|
||||
{#each $snapshots as entry, idx (entry.id)}
|
||||
{#if idx === 0 || createdOnDay(entry.createdAt) != createdOnDay($snapshots[idx - 1].createdAt)}
|
||||
<div class="sideview__date-header">
|
||||
<h4 class="text-base-12 text-semibold">
|
||||
{createdOnDay(entry.createdAt)}
|
||||
@ -291,7 +146,7 @@
|
||||
{entry}
|
||||
isCurrent={idx == 0}
|
||||
on:restoreClick={() => {
|
||||
restoreSnapshot(projectId, entry.id);
|
||||
historyService.restoreSnapshot(project.id, entry.id);
|
||||
}}
|
||||
{selectedFile}
|
||||
on:diffClick={async (filePath) => {
|
||||
@ -302,7 +157,7 @@
|
||||
} else {
|
||||
snapshotFilesTempStore = {
|
||||
entryId: entry.id,
|
||||
diffs: await getSnapshotDiff(projectId, entry.id)
|
||||
diffs: await historyService.getSnapshotDiff(project.id, entry.id)
|
||||
};
|
||||
updateFilePreview(entry, path);
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { createdOnDay } from './History.svelte';
|
||||
import Icon from './Icon.svelte';
|
||||
import SnapshotAttachment from './SnapshotAttachment.svelte';
|
||||
import Tag from './Tag.svelte';
|
||||
import { getVSIFileIcon } from '$lib/ext-icons';
|
||||
import { createdOnDay } from '$lib/history/history';
|
||||
import { toHumanReadableTime } from '$lib/utils/time';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import type { Snapshot, SnapshotDetails } from '$lib/history/types';
|
||||
import type iconsJson from '$lib/icons/icons.json';
|
||||
import type { Snapshot, SnapshotDetails } from './History.svelte';
|
||||
|
||||
export let entry: Snapshot;
|
||||
export let isCurrent: boolean = false;
|
||||
@ -23,13 +24,9 @@
|
||||
return `#${sha.slice(0, 7)}`;
|
||||
}
|
||||
|
||||
function createdAtTime(dateNumber: number) {
|
||||
const d = new Date(dateNumber);
|
||||
return d.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false });
|
||||
}
|
||||
|
||||
function createdOnDayAndTime(dateNumber: number) {
|
||||
return `${createdOnDay(dateNumber)}, ${createdAtTime(dateNumber)}`;
|
||||
function createdOnDayAndTime(epoch: number) {
|
||||
const date = new Date(epoch);
|
||||
return `${createdOnDay(date)}, ${toHumanReadableTime(date)}`;
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher<{ restoreClick: void; diffClick: string }>();
|
||||
@ -160,7 +157,7 @@
|
||||
class:restored-snapshot={isRestoreSnapshot}
|
||||
>
|
||||
<span class="snapshot-time text-base-12">
|
||||
{createdAtTime(entry.createdAt)}
|
||||
{toHumanReadableTime(entry.createdAt)}
|
||||
</span>
|
||||
|
||||
<div class="snapshot-line">
|
||||
|
60
app/src/lib/history/history.ts
Normal file
60
app/src/lib/history/history.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { Snapshot, SnapshotDiff } from './types';
|
||||
import { invoke } from '$lib/backend/ipc';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export class HistoryService {
|
||||
cursor: string | undefined = undefined;
|
||||
|
||||
snapshots = writable<Snapshot[]>([], (set) => {
|
||||
this.loadSnapshots().then((x) => set(x));
|
||||
return () => {
|
||||
set([]);
|
||||
this.cursor = undefined;
|
||||
};
|
||||
});
|
||||
loading = writable(false);
|
||||
|
||||
constructor(private projectId: string) {}
|
||||
|
||||
async loadSnapshots(after?: string) {
|
||||
this.loading.set(true);
|
||||
const resp = await invoke<Snapshot[]>('list_snapshots', {
|
||||
projectId: this.projectId,
|
||||
sha: after,
|
||||
limit: 32
|
||||
});
|
||||
this.cursor = resp.length > 0 ? resp[resp.length - 1].id : undefined;
|
||||
this.loading.set(false);
|
||||
return plainToInstance(Snapshot, resp);
|
||||
}
|
||||
|
||||
async loadMore() {
|
||||
if (!this.cursor) throw new Error('Unable to load more without a cursor');
|
||||
const more = await this.loadSnapshots(this.cursor);
|
||||
this.snapshots.update((snapshots) => [...snapshots, ...more.slice(1)]);
|
||||
}
|
||||
|
||||
async getSnapshotDiff(projectId: string, sha: string) {
|
||||
const resp = await invoke<{ [key: string]: any }>('snapshot_diff', {
|
||||
projectId: projectId,
|
||||
sha: sha
|
||||
});
|
||||
return Object.entries(resp).reduce<{ [key: string]: SnapshotDiff }>((acc, [path, diff]) => {
|
||||
acc[path] = plainToInstance(SnapshotDiff, diff);
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
async restoreSnapshot(projectId: string, sha: string) {
|
||||
await invoke<string>('restore_snapshot', {
|
||||
projectId: projectId,
|
||||
sha: sha
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function createdOnDay(d: Date) {
|
||||
const t = new Date();
|
||||
return `${t.toDateString() == d.toDateString() ? 'Today' : d.toLocaleDateString('en-US', { weekday: 'short' })}, ${d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}`;
|
||||
}
|
66
app/src/lib/history/types.ts
Normal file
66
app/src/lib/history/types.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { RemoteHunk } from '$lib/vbranches/types';
|
||||
import { Transform, Type } from 'class-transformer';
|
||||
|
||||
export type Operation =
|
||||
| 'CreateCommit'
|
||||
| 'CreateBranch'
|
||||
| 'SetBaseBranch'
|
||||
| 'MergeUpstream'
|
||||
| 'UpdateWorkspaceBase'
|
||||
| 'MoveHunk'
|
||||
| 'UpdateBranchName'
|
||||
| 'UpdateBranchNotes'
|
||||
| 'ReorderBranches'
|
||||
| 'SelectDefaultVirtualBranch'
|
||||
| 'UpdateBranchRemoteName'
|
||||
| 'GenericBranchUpdate'
|
||||
| 'DeleteBranch'
|
||||
| 'ApplyBranch'
|
||||
| 'DiscardHunk'
|
||||
| 'DiscardFile'
|
||||
| 'AmendCommit'
|
||||
| 'UndoCommit'
|
||||
| 'UnapplyBranch'
|
||||
| 'CherryPick'
|
||||
| 'SquashCommit'
|
||||
| 'UpdateCommitMessage'
|
||||
| 'MoveCommit'
|
||||
| 'RestoreFromSnapshot'
|
||||
| 'ReorderCommit'
|
||||
| 'InsertBlankCommit'
|
||||
| 'MoveCommitFile'
|
||||
| 'FileChanges';
|
||||
|
||||
export class Trailer {
|
||||
key!: string;
|
||||
value!: string;
|
||||
}
|
||||
|
||||
export class SnapshotDiff {
|
||||
binary!: boolean;
|
||||
@Type(() => RemoteHunk)
|
||||
hunks!: RemoteHunk[];
|
||||
newPath!: string;
|
||||
newSizeBytes!: number;
|
||||
oldPath!: string;
|
||||
oldSizeBytes!: number;
|
||||
skipped!: boolean;
|
||||
}
|
||||
|
||||
export class SnapshotDetails {
|
||||
title!: string;
|
||||
operation!: Operation;
|
||||
body?: string | undefined;
|
||||
@Type(() => Trailer)
|
||||
trailers!: Trailer[];
|
||||
}
|
||||
|
||||
export class Snapshot {
|
||||
id!: string;
|
||||
linesAdded!: number;
|
||||
linesRemoved!: number;
|
||||
filesChanged!: string[];
|
||||
details?: SnapshotDetails;
|
||||
@Transform((obj) => new Date(obj.value * 1000))
|
||||
createdAt!: Date;
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
export async function on(combo: string, callback: (event: KeyboardEvent) => void) {
|
||||
import { tinykeys } from 'tinykeys';
|
||||
|
||||
export function on(combo: string, callback: (event: KeyboardEvent) => void) {
|
||||
const comboContainsControlKeys =
|
||||
combo.includes('Meta') || combo.includes('Alt') || combo.includes('Ctrl');
|
||||
|
||||
return await import('tinykeys').then(({ tinykeys }) =>
|
||||
tinykeys(window, {
|
||||
return tinykeys(window, {
|
||||
[combo]: (event) => {
|
||||
const target = event.target as HTMLElement;
|
||||
const isInput = target.tagName === 'INPUT' || target.tagName === 'TEXTAREA';
|
||||
@ -14,6 +15,5 @@ export async function on(combo: string, callback: (event: KeyboardEvent) => void
|
||||
|
||||
callback(event);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
export function toHumanReadableTime(timestamp: number) {
|
||||
return new Date(timestamp).toLocaleTimeString('en-US', {
|
||||
export function toHumanReadableTime(d: Date) {
|
||||
return d.toLocaleTimeString('en-US', {
|
||||
hour: 'numeric',
|
||||
minute: 'numeric'
|
||||
});
|
||||
}
|
||||
|
||||
export function toHumanReadableDate(timestamp: number) {
|
||||
return new Date(timestamp).toLocaleDateString('en-US', {
|
||||
dateStyle: 'short'
|
||||
export function toHumanReadableDate(d: Date) {
|
||||
return d.toLocaleDateString('en-US', {
|
||||
dateStyle: 'short',
|
||||
hour12: false
|
||||
});
|
||||
}
|
||||
|
@ -74,12 +74,6 @@
|
||||
// This prevent backspace from navigating back
|
||||
e.preventDefault();
|
||||
}),
|
||||
hotkeys.on('$mod+Shift+H', () => {
|
||||
userSettings.update((s) => ({
|
||||
...s,
|
||||
showHistoryView: !$userSettings.showHistoryView
|
||||
}));
|
||||
}),
|
||||
hotkeys.on('$mod+R', () => location.reload())
|
||||
);
|
||||
});
|
||||
|
@ -7,6 +7,7 @@
|
||||
import NotOnGitButlerBranch from '$lib/components/NotOnGitButlerBranch.svelte';
|
||||
import ProblemLoadingRepo from '$lib/components/ProblemLoadingRepo.svelte';
|
||||
import ProjectSettingsMenuAction from '$lib/components/ProjectSettingsMenuAction.svelte';
|
||||
import { HistoryService } from '$lib/history/history';
|
||||
import { BaseBranchService, NoDefaultTarget } from '$lib/vbranches/baseBranch';
|
||||
import { BranchController } from '$lib/vbranches/branchController';
|
||||
import { BaseBranch } from '$lib/vbranches/types';
|
||||
@ -33,6 +34,7 @@
|
||||
$: projectError = projectService.error;
|
||||
// const userSettings = getContextStoreBySymbol<Settings>(SETTINGS);
|
||||
|
||||
$: setContext(HistoryService, data.historyService);
|
||||
$: setContext(VirtualBranchService, vbranchService);
|
||||
$: setContext(BranchController, branchController);
|
||||
$: setContext(BranchService, branchService);
|
||||
@ -80,9 +82,7 @@
|
||||
<div class="view-wrap" role="group" on:dragover|preventDefault>
|
||||
<Navigation />
|
||||
<slot />
|
||||
<!-- {#if $userSettings.showHistoryView} -->
|
||||
<History {projectId} />
|
||||
<!-- {/if} -->
|
||||
<History />
|
||||
</div>
|
||||
{/if}
|
||||
{/key}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { invoke } from '$lib/backend/ipc';
|
||||
import { BranchService } from '$lib/branches/service';
|
||||
import { HistoryService } from '$lib/history/history';
|
||||
import { getFetchNotifications } from '$lib/stores/fetches';
|
||||
import { getHeads } from '$lib/stores/head';
|
||||
import { RemoteBranchService } from '$lib/stores/remoteBranches';
|
||||
@ -39,6 +40,7 @@ export async function load({ params, parent }) {
|
||||
const heads$ = getHeads(projectId);
|
||||
const gbBranchActive$ = heads$.pipe(map((head) => head == 'gitbutler/integration'));
|
||||
|
||||
const historyService = new HistoryService(projectId);
|
||||
const baseBranchService = new BaseBranchService(projectId, remoteUrl$, fetches$, heads$);
|
||||
const vbranchService = new VirtualBranchService(projectId, gbBranchActive$);
|
||||
|
||||
@ -67,6 +69,7 @@ export async function load({ params, parent }) {
|
||||
branchController,
|
||||
branchService,
|
||||
githubService,
|
||||
historyService,
|
||||
projectId,
|
||||
project,
|
||||
remoteBranchService,
|
||||
|
Loading…
Reference in New Issue
Block a user