mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-18 06:22:28 +03:00
Unmount history component when hidden
- history service resets as history component is unmounted - restores functionality I changed in my previous commit
This commit is contained in:
parent
ec24ffe979
commit
425289e10a
@ -7,23 +7,20 @@
|
||||
import ScrollableContainer from './ScrollableContainer.svelte';
|
||||
import SnapshotCard from './SnapshotCard.svelte';
|
||||
import emptyFolderSvg from '$lib/assets/empty-state/empty-folder.svg?raw';
|
||||
import { listen } from '$lib/backend/ipc';
|
||||
import { Project } from '$lib/backend/projects';
|
||||
import { clickOutside } from '$lib/clickOutside';
|
||||
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 } from 'svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import type { Snapshot, SnapshotDiff } from '$lib/history/types';
|
||||
|
||||
const project = getContext(Project);
|
||||
const historyService = getContext(HistoryService);
|
||||
const snapshots = historyService.snapshots;
|
||||
const dispatch = createEventDispatcher<{ hide: any }>();
|
||||
|
||||
const showHistoryView = persisted(false, 'showHistoryView');
|
||||
const loading = historyService.loading;
|
||||
|
||||
let currentFilePreview: RemoteFile | undefined = undefined;
|
||||
@ -49,142 +46,122 @@
|
||||
});
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const unsubscribe = listen<string>('menu://view/history/clicked', () => {
|
||||
$showHistoryView = !$showHistoryView;
|
||||
});
|
||||
|
||||
// TODO: Refactor somehow
|
||||
const unsubscribeHotkeys = hotkeys.on('$mod+Shift+H', () => {
|
||||
$showHistoryView = !$showHistoryView;
|
||||
});
|
||||
|
||||
return async () => {
|
||||
unsubscribe();
|
||||
unsubscribeHotkeys();
|
||||
};
|
||||
});
|
||||
|
||||
let snapshotFilesTempStore:
|
||||
| { entryId: string; diffs: { [key: string]: SnapshotDiff } }
|
||||
| undefined = undefined;
|
||||
let selectedFile: { entryId: string; path: string } | undefined = undefined;
|
||||
</script>
|
||||
|
||||
{#if $showHistoryView}
|
||||
<aside class="sideview-container" class:show-view={$showHistoryView}>
|
||||
<div
|
||||
class="sideview-content-wrap"
|
||||
use:clickOutside={{
|
||||
handler: () => {
|
||||
$showHistoryView = false;
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if currentFilePreview}
|
||||
<div class="file-preview" class:show-file-view={currentFilePreview}>
|
||||
<FileCard
|
||||
isCard={false}
|
||||
conflicted={false}
|
||||
file={currentFilePreview}
|
||||
isUnapplied={false}
|
||||
readonly={true}
|
||||
on:close={() => {
|
||||
currentFilePreview = undefined;
|
||||
selectedFile = undefined;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<aside class="sideview-container show-view">
|
||||
<div
|
||||
class="sideview-content-wrap"
|
||||
use:clickOutside={{
|
||||
handler: () => dispatch('hide')
|
||||
}}
|
||||
>
|
||||
{#if currentFilePreview}
|
||||
<div class="file-preview" class:show-file-view={currentFilePreview}>
|
||||
<FileCard
|
||||
isCard={false}
|
||||
conflicted={false}
|
||||
file={currentFilePreview}
|
||||
isUnapplied={false}
|
||||
readonly={true}
|
||||
on:close={() => {
|
||||
currentFilePreview = undefined;
|
||||
selectedFile = undefined;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="sideview">
|
||||
<div class="sideview__header" data-tauri-drag-region>
|
||||
<i class="clock-icon">
|
||||
<div class="clock-pointers" />
|
||||
</i>
|
||||
<h3 class="sideview__header-title text-base-15 text-bold">Project history</h3>
|
||||
<Button
|
||||
style="ghost"
|
||||
icon="cross"
|
||||
on:click={() => {
|
||||
dispatch('hide');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- EMPTY STATE -->
|
||||
{#if $snapshots.length == 0}
|
||||
<EmptyStatePlaceholder image={emptyFolderSvg}>
|
||||
<svelte:fragment slot="title">No snapshots yet</svelte:fragment>
|
||||
<svelte:fragment slot="caption">
|
||||
Gitbutler saves your work, including file changes, so your progress is always secure.
|
||||
Adjust snapshot settings in project settings.
|
||||
</svelte:fragment>
|
||||
</EmptyStatePlaceholder>
|
||||
{/if}
|
||||
|
||||
<div class="sideview">
|
||||
<div class="sideview__header" data-tauri-drag-region>
|
||||
<i class="clock-icon">
|
||||
<div class="clock-pointers" />
|
||||
</i>
|
||||
<h3 class="sideview__header-title text-base-15 text-bold">Project history</h3>
|
||||
<Button
|
||||
style="ghost"
|
||||
icon="cross"
|
||||
on:click={() => {
|
||||
$showHistoryView = false;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{#if $snapshots.length == 0 && $loading}
|
||||
<FullviewLoading />
|
||||
{/if}
|
||||
|
||||
<!-- EMPTY STATE -->
|
||||
{#if $snapshots.length == 0}
|
||||
<EmptyStatePlaceholder image={emptyFolderSvg}>
|
||||
<svelte:fragment slot="title">No snapshots yet</svelte:fragment>
|
||||
<svelte:fragment slot="caption">
|
||||
Gitbutler saves your work, including file changes, so your progress is always secure.
|
||||
Adjust snapshot settings in project settings.
|
||||
</svelte:fragment>
|
||||
</EmptyStatePlaceholder>
|
||||
{/if}
|
||||
|
||||
{#if $snapshots.length == 0 && $loading}
|
||||
<FullviewLoading />
|
||||
{/if}
|
||||
|
||||
<!-- SNAPSHOTS -->
|
||||
{#if $snapshots.length > 0}
|
||||
<ScrollableContainer on:bottomReached={onLastInView}>
|
||||
<div class="container">
|
||||
<!-- SNAPSHOTS FEED -->
|
||||
{#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)}
|
||||
</h4>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if entry.details}
|
||||
<SnapshotCard
|
||||
{entry}
|
||||
isCurrent={idx == 0}
|
||||
on:restoreClick={() => {
|
||||
historyService.restoreSnapshot(project.id, entry.id);
|
||||
}}
|
||||
{selectedFile}
|
||||
on:diffClick={async (filePath) => {
|
||||
const path = filePath.detail;
|
||||
|
||||
if (snapshotFilesTempStore?.entryId == entry.id) {
|
||||
updateFilePreview(entry, path);
|
||||
} else {
|
||||
snapshotFilesTempStore = {
|
||||
entryId: entry.id,
|
||||
diffs: await historyService.getSnapshotDiff(project.id, entry.id)
|
||||
};
|
||||
updateFilePreview(entry, path);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
<div class="welcome-point">
|
||||
<div class="welcome-point__icon">
|
||||
<Icon name="finish" />
|
||||
</div>
|
||||
<div class="welcome-point__content">
|
||||
<p class="text-base-13 text-semibold">Welcome to history!</p>
|
||||
<p class="welcome-point__caption text-base-body-12">
|
||||
Gitbutler saves your work, including file changes, so your progress is always
|
||||
secure. Adjust snapshot settings in project settings.
|
||||
</p>
|
||||
<!-- SNAPSHOTS -->
|
||||
{#if $snapshots.length > 0}
|
||||
<ScrollableContainer on:bottomReached={onLastInView}>
|
||||
<div class="container">
|
||||
<!-- SNAPSHOTS FEED -->
|
||||
{#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)}
|
||||
</h4>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if entry.details}
|
||||
<SnapshotCard
|
||||
{entry}
|
||||
isCurrent={idx == 0}
|
||||
on:restoreClick={() => {
|
||||
historyService.restoreSnapshot(project.id, entry.id);
|
||||
}}
|
||||
{selectedFile}
|
||||
on:diffClick={async (filePath) => {
|
||||
const path = filePath.detail;
|
||||
|
||||
if (snapshotFilesTempStore?.entryId == entry.id) {
|
||||
updateFilePreview(entry, path);
|
||||
} else {
|
||||
snapshotFilesTempStore = {
|
||||
entryId: entry.id,
|
||||
diffs: await historyService.getSnapshotDiff(project.id, entry.id)
|
||||
};
|
||||
updateFilePreview(entry, path);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
<div class="welcome-point">
|
||||
<div class="welcome-point__icon">
|
||||
<Icon name="finish" />
|
||||
</div>
|
||||
<div class="welcome-point__content">
|
||||
<p class="text-base-13 text-semibold">Welcome to history!</p>
|
||||
<p class="welcome-point__caption text-base-body-12">
|
||||
Gitbutler saves your work, including file changes, so your progress is always
|
||||
secure. Adjust snapshot settings in project settings.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollableContainer>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</ScrollableContainer>
|
||||
{/if}
|
||||
</div>
|
||||
</aside>
|
||||
{/if}
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- TODO: HANDLE LOADING STATE -->
|
||||
|
||||
|
@ -6,18 +6,33 @@ import { writable } from 'svelte/store';
|
||||
export class HistoryService {
|
||||
cursor: string | undefined = undefined;
|
||||
|
||||
snapshots = writable<Snapshot[]>([], (set) => {
|
||||
this.loadSnapshots().then((x) => set(x));
|
||||
readonly loading = writable(false);
|
||||
readonly snapshots = writable<Snapshot[]>([], (set) => {
|
||||
// Load snapshots when going from 0 -> 1 subscriber.
|
||||
this.fetch().then((x) => set(x));
|
||||
return () => {
|
||||
// Clear store when component last subscriber unsubscribes.
|
||||
set([]);
|
||||
this.cursor = undefined;
|
||||
};
|
||||
});
|
||||
loading = writable(false);
|
||||
|
||||
constructor(private projectId: string) {}
|
||||
|
||||
async loadSnapshots(after?: string) {
|
||||
async load() {
|
||||
if (this.cursor) this.cursor = undefined;
|
||||
this.snapshots.set(await this.fetch());
|
||||
this.loading.set(false);
|
||||
}
|
||||
|
||||
async loadMore() {
|
||||
if (!this.cursor) throw new Error('Unable to load more without a cursor');
|
||||
const more = await this.fetch(this.cursor);
|
||||
// TODO: Update API so we don't have to .slice()
|
||||
this.snapshots.update((snapshots) => [...snapshots, ...more.slice(1)]);
|
||||
}
|
||||
|
||||
private async fetch(after?: string) {
|
||||
this.loading.set(true);
|
||||
const resp = await invoke<Snapshot[]>('list_snapshots', {
|
||||
projectId: this.projectId,
|
||||
@ -29,10 +44,8 @@ export class HistoryService {
|
||||
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)]);
|
||||
clear() {
|
||||
this.snapshots.set([]);
|
||||
}
|
||||
|
||||
async getSnapshotDiff(projectId: string, sha: string) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { listen } from '$lib/backend/ipc';
|
||||
import { Project } from '$lib/backend/projects';
|
||||
import { BranchService } from '$lib/branches/service';
|
||||
import History from '$lib/components/History.svelte';
|
||||
@ -8,11 +9,13 @@
|
||||
import ProblemLoadingRepo from '$lib/components/ProblemLoadingRepo.svelte';
|
||||
import ProjectSettingsMenuAction from '$lib/components/ProjectSettingsMenuAction.svelte';
|
||||
import { HistoryService } from '$lib/history/history';
|
||||
import { persisted } from '$lib/persisted/persisted';
|
||||
import * as hotkeys from '$lib/utils/hotkeys';
|
||||
import { BaseBranchService, NoDefaultTarget } from '$lib/vbranches/baseBranch';
|
||||
import { BranchController } from '$lib/vbranches/branchController';
|
||||
import { BaseBranch } from '$lib/vbranches/types';
|
||||
import { VirtualBranchService } from '$lib/vbranches/virtualBranch';
|
||||
import { onDestroy, setContext } from 'svelte';
|
||||
import { onDestroy, onMount, setContext } from 'svelte';
|
||||
import type { LayoutData } from './$types';
|
||||
|
||||
export let data: LayoutData;
|
||||
@ -42,6 +45,8 @@
|
||||
$: setContext(BaseBranch, baseBranch);
|
||||
$: setContext(Project, project);
|
||||
|
||||
const showHistoryView = persisted(false, 'showHistoryView');
|
||||
|
||||
let intervalId: any;
|
||||
|
||||
// Once on load and every time the project id changes
|
||||
@ -58,6 +63,22 @@
|
||||
if (intervalId) clearInterval(intervalId);
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const unsubscribe = listen<string>('menu://view/history/clicked', () => {
|
||||
$showHistoryView = !$showHistoryView;
|
||||
});
|
||||
|
||||
// TODO: Refactor somehow
|
||||
const unsubscribeHotkeys = hotkeys.on('$mod+Shift+H', () => {
|
||||
$showHistoryView = !$showHistoryView;
|
||||
});
|
||||
|
||||
return async () => {
|
||||
unsubscribe();
|
||||
unsubscribeHotkeys();
|
||||
};
|
||||
});
|
||||
|
||||
onDestroy(() => clearFetchInterval());
|
||||
</script>
|
||||
|
||||
@ -81,8 +102,10 @@
|
||||
{:else if $baseBranch}
|
||||
<div class="view-wrap" role="group" on:dragover|preventDefault>
|
||||
<Navigation />
|
||||
{#if $showHistoryView}
|
||||
<History on:hide={() => ($showHistoryView = false)} />
|
||||
{/if}
|
||||
<slot />
|
||||
<History />
|
||||
</div>
|
||||
{/if}
|
||||
{/key}
|
||||
|
Loading…
Reference in New Issue
Block a user