Merge pull request #3716 from gitbutlerapp/list-snapshots-with-optional-sha-1

snapshot list pagination
This commit is contained in:
Kiril Videlov 2024-05-07 01:15:17 +02:00 committed by GitHub
commit 01576361aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 47 additions and 22 deletions

View File

@ -3,16 +3,19 @@
import { invoke } from '$lib/backend/ipc';
import { getContext } from '$lib/utils/context';
import { VirtualBranchService } from '$lib/vbranches/virtualBranch';
import { onMount } from 'svelte';
import { onMount, onDestroy } from 'svelte';
import { goto } from '$app/navigation';
export let projectId: string;
const snapshotsLimit = 100;
const vbranchService = getContext(VirtualBranchService);
vbranchService.activeBranches.subscribe(() => {
listSnapshots(projectId, snapshotsLimit);
// 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;
listElement?.scrollTo(0, 0);
});
});
type Trailer = {
@ -34,12 +37,13 @@
createdAt: number;
};
let snapshots: Snapshot[] = [];
async function listSnapshots(projectId: string, limit: number) {
async function listSnapshots(projectId: string, sha?: string) {
const resp = await invoke<Snapshot[]>('list_snapshots', {
projectId: projectId,
limit: limit
limit: 32,
sha: sha
});
snapshots = resp;
return resp;
}
async function restoreSnapshot(projectId: string, sha: string) {
await invoke<string>('restore_snapshot', {
@ -49,12 +53,27 @@
// 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)];
});
}
}
let listElement: HTMLElement | undefined = undefined;
onMount(async () => {
listSnapshots(projectId, snapshotsLimit);
listSnapshots(projectId).then((rsp) => {
snapshots = rsp;
});
if (listElement) listElement.addEventListener('scroll', onLastInView, true);
});
onDestroy(() => {
listElement?.removeEventListener('scroll', onLastInView, true);
});
</script>
<div class="container">
<div class="container" bind:this={listElement}>
{#each snapshots as entry, idx}
<div class="card" style="margin-bottom: 4px;">
<div class="entry" style="padding: 6px;">

View File

@ -49,7 +49,7 @@ fn main() -> Result<()> {
fn list_snapshots(repo_dir: &str) -> Result<()> {
let project = project_from_path(repo_dir);
let snapshots = project.list_snapshots(100)?;
let snapshots = project.list_snapshots(100, None)?;
for snapshot in snapshots {
let ts = chrono::DateTime::from_timestamp(snapshot.created_at / 1000, 0);
let details = snapshot.details;

View File

@ -37,7 +37,7 @@ pub trait Oplog {
/// An alternative way of retrieving the snapshots would be to manually the oplog head `git log <oplog_head>` available in `.git/gitbutler/oplog.toml`.
///
/// If there are no snapshots, an empty list is returned.
fn list_snapshots(&self, limit: usize) -> Result<Vec<Snapshot>>;
fn list_snapshots(&self, limit: usize, sha: Option<String>) -> Result<Vec<Snapshot>>;
/// Reverts to a previous state of the working directory, virtual branches and commits.
/// The provided sha must refer to a valid snapshot commit.
/// Upon success, a new snapshot is created.
@ -146,17 +146,22 @@ impl Oplog for Project {
Ok(Some(new_commit_oid.to_string()))
}
fn list_snapshots(&self, limit: usize) -> Result<Vec<Snapshot>> {
fn list_snapshots(&self, limit: usize, sha: Option<String>) -> Result<Vec<Snapshot>> {
let repo_path = self.path.as_path();
let repo = git2::Repository::init(repo_path)?;
let oplog_state = OplogHandle::new(&self.gb_dir());
let head_sha = oplog_state.get_oplog_head()?;
if head_sha.is_none() {
// there are no snapshots to return
return Ok(vec![]);
}
let head_sha = head_sha.unwrap();
let head_sha = match sha {
Some(sha) => sha,
None => {
let oplog_state = OplogHandle::new(&self.gb_dir());
if let Some(sha) = oplog_state.get_oplog_head()? {
sha
} else {
// there are no snapshots so return an empty list
return Ok(vec![]);
}
}
};
let oplog_head_commit = repo.find_commit(git2::Oid::from_str(&head_sha)?)?;
@ -525,7 +530,7 @@ mod tests {
.create_snapshot(SnapshotDetails::new(OperationType::UpdateWorkspaceBase))
.unwrap();
let initial_snapshot = &project.list_snapshots(10).unwrap()[1];
let initial_snapshot = &project.list_snapshots(10, None).unwrap()[1];
assert_eq!(
initial_snapshot.files_changed,
vec![
@ -536,7 +541,7 @@ mod tests {
);
assert_eq!(initial_snapshot.lines_added, 3);
assert_eq!(initial_snapshot.lines_removed, 0);
let second_snapshot = &project.list_snapshots(10).unwrap()[0];
let second_snapshot = &project.list_snapshots(10, None).unwrap()[0];
assert_eq!(
second_snapshot.files_changed,
vec![

View File

@ -13,12 +13,13 @@ pub async fn list_snapshots(
handle: tauri::AppHandle,
project_id: ProjectId,
limit: usize,
sha: Option<String>,
) -> Result<Vec<Snapshot>, Error> {
let project = handle
.state::<projects::Controller>()
.get(&project_id)
.context("failed to get project")?;
let snapshots = project.list_snapshots(limit)?;
let snapshots = project.list_snapshots(limit, sha)?;
Ok(snapshots)
}