Skip to content

Commit

Permalink
Add revision commit list
Browse files Browse the repository at this point in the history
  • Loading branch information
rudolfs committed Feb 3, 2025
1 parent 4c5c73c commit a9aa8ed
Show file tree
Hide file tree
Showing 12 changed files with 449 additions and 155 deletions.
9 changes: 4 additions & 5 deletions crates/radicle-tauri/src/commands/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@ pub async fn diff_stats(
pub async fn list_commits(
ctx: tauri::State<'_, AppState>,
rid: RepoId,
parent: Option<String>,
skip: Option<usize>,
take: Option<usize>,
) -> Result<types::cobs::PaginatedQuery<Vec<types::repo::Commit>>, Error> {
ctx.list_commits(rid, parent, skip, take)
base: String,
head: String,
) -> Result<Vec<types::repo::Commit>, Error> {
ctx.list_commits(rid, base, head)
}
162 changes: 15 additions & 147 deletions crates/radicle-types/src/traits/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,158 +210,26 @@ pub trait Repo: Profile {
fn list_commits(
&self,
rid: identity::RepoId,
parent: Option<String>,
skip: Option<usize>,
take: Option<usize>,
) -> Result<cobs::PaginatedQuery<Vec<repo::Commit>>, Error> {
base: String,
head: String,
) -> Result<Vec<repo::Commit>, Error> {
let profile = self.profile();
let cursor = skip.unwrap_or(0);
let take = take.unwrap_or(20);
let repo = profile.storage.repository(rid)?;

let sha = match parent {
Some(commit) => commit,
None => repo.head()?.1.to_string(),
};

let repo = surf::Repository::open(repo.path())?;
let history = repo.history(&sha)?;

let mut commits = history
let history = repo.history(&head)?;

let commits = history
.take_while(|c| {
if let Ok(c) = c {
c.id.to_string() != base
} else {
false
}
})
.filter_map(|c| c.map(Into::into).ok())
.skip(cursor)
.take(take + 1); // Take one extra item to check if there's more.

let paginated_commits: Vec<_> = commits.by_ref().take(take).collect();
let more = commits.next().is_some();

Ok::<_, Error>(cobs::PaginatedQuery {
cursor,
more,
content: paginated_commits.to_vec(),
})
}
}

#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod test {
use std::str::FromStr;
use std::vec;

use radicle::crypto::test::signer::MockSigner;
use radicle::{git, test};
use radicle_surf::Author;

use crate::cobs;
use crate::repo;
use crate::traits::repo::Repo;
use crate::AppState;

#[test]
fn list_commits_pagination() {
let signer = MockSigner::from_seed([0xff; 32]);
let tempdir = tempfile::tempdir().unwrap();
let profile = crate::test::profile(tempdir.path(), [0xff; 32]);
let (rid, _, _, _) =
test::fixtures::project(tempdir.path().join("original"), &profile.storage, &signer)
.unwrap();
let state = AppState { profile };
let commits = Repo::list_commits(&state, rid, None, None, Some(1)).unwrap();

assert_eq!(
commits,
cobs::PaginatedQuery {
cursor: 0,
more: true,
content: vec![repo::Commit {
id: git::Oid::from_str("f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354").unwrap(),
author: Author {
name: "anonymous".to_string(),
email: "[email protected]".to_string(),
time: radicle::git::raw::Time::new(1514817556, 0).into(),
},
committer: Author {
name: "anonymous".to_string(),
email: "[email protected]".to_string(),
time: radicle::git::raw::Time::new(1514817556, 0).into(),
},
message: "Second commit".to_string(),
summary: "Second commit".to_string(),
parents: vec![
git::Oid::from_str("08c788dd1be6315de09e3fe09b5b1b7a2b8711d9").unwrap()
],
}],
}
);

let commits = Repo::list_commits(&state, rid, None, Some(1), None).unwrap();

assert_eq!(
commits,
cobs::PaginatedQuery {
cursor: 1,
more: false,
content: vec![repo::Commit {
id: git::Oid::from_str("08c788dd1be6315de09e3fe09b5b1b7a2b8711d9").unwrap(),
author: Author {
name: "anonymous".to_string(),
email: "[email protected]".to_string(),
time: radicle::git::raw::Time::new(1514817556, 0).into(),
},
committer: Author {
name: "anonymous".to_string(),
email: "[email protected]".to_string(),
time: radicle::git::raw::Time::new(1514817556, 0).into(),
},
message: "Initial commit".to_string(),
summary: "Initial commit".to_string(),
parents: vec![],
}],
}
);
}
.collect();

#[test]
fn list_commits_with_head() {
let signer = MockSigner::from_seed([0xff; 32]);
let tempdir = tempfile::tempdir().unwrap();
let profile = crate::test::profile(tempdir.path(), [0xff; 32]);
let (rid, _, _, _) =
test::fixtures::project(tempdir.path().join("original"), &profile.storage, &signer)
.unwrap();
let state = AppState { profile };
let commits = Repo::list_commits(
&state,
rid,
Some("08c788dd1be6315de09e3fe09b5b1b7a2b8711d9".to_string()),
None,
None,
)
.unwrap();

assert_eq!(
commits,
cobs::PaginatedQuery {
cursor: 0,
more: false,
content: vec![repo::Commit {
id: git::Oid::from_str("08c788dd1be6315de09e3fe09b5b1b7a2b8711d9").unwrap(),
author: Author {
name: "anonymous".to_string(),
email: "[email protected]".to_string(),
time: radicle::git::raw::Time::new(1514817556, 0).into(),
},
committer: Author {
name: "anonymous".to_string(),
email: "[email protected]".to_string(),
time: radicle::git::raw::Time::new(1514817556, 0).into(),
},
message: "Initial commit".to_string(),
summary: "Initial commit".to_string(),
parents: vec![],
}],
}
);
Ok(commits)
}
}
48 changes: 48 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@tauri-apps/cli": "^2.1.0",
"@tsconfig/svelte": "^5.0.4",
"@types/lodash": "^4.17.13",
"@types/md5": "^2.3.5",
"@types/node": "^22.10.2",
"@types/wait-on": "^5.3.4",
"@wooorm/starry-night": "^3.5.0",
Expand All @@ -61,6 +62,7 @@
"marked-footnote": "^1.2.4",
"marked-katex-extension": "^5.1.3",
"marked-linkify-it": "^3.1.12",
"md5": "^2.3.0",
"prettier": "^3.4.2",
"prettier-plugin-svelte": "^3.3.2",
"svelte": "^5.14.0",
Expand Down
84 changes: 84 additions & 0 deletions src/components/CobCommitTeaser.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<script lang="ts">
import type { Commit } from "@bindings/repo/Commit";
import { twemoji } from "@app/lib/utils";
import CompactCommitAuthorship from "@app/components/CompactCommitAuthorship.svelte";
import Icon from "@app/components/Icon.svelte";
import Id from "@app/components/Id.svelte";
import InlineTitle from "@app/components/InlineTitle.svelte";
import NakedButton from "@app/components/NakedButton.svelte";
export let commit: Commit;
let commitMessageVisible = false;
</script>

<style>
.teaser {
display: flex;
font-size: var(--font-size-small);
align-items: start;
padding: 0.125rem 0;
}
.message {
align-items: center;
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.left {
display: flex;
gap: 0.5rem;
padding: 0 0.5rem;
flex-direction: column;
}
.right {
display: flex;
align-items: center;
gap: 1rem;
margin-left: auto;
height: 21px;
}
.commit-message {
font-size: var(--font-size-tiny);
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
</style>

<div class="teaser" aria-label="commit-teaser">
<div class="left">
<div class="message">
<div class="summary" use:twemoji>
<InlineTitle fontSize="small" content={commit.summary} />
</div>
{#if commit.message.trim() !== commit.summary.trim()}
<div style="height: 21px; display: flex; align-items: center;">
<NakedButton
stylePadding="0 4px"
variant="ghost"
onclick={() => {
commitMessageVisible = !commitMessageVisible;
}}>
<Icon name="ellipsis" />
</NakedButton>
</div>
{/if}
</div>
{#if commitMessageVisible}
<div class="commit-message">
<pre>{commit.message.replace(commit.summary, "").trim()}</pre>
</div>
{/if}
</div>
<div class="right">
<div style="display: flex; gap: 0.5rem; height: 21px; align-items: center;">
<CompactCommitAuthorship {commit}>
<Id id={commit.id} variant="commit" />
</CompactCommitAuthorship>
</div>
</div>
</div>
Loading

0 comments on commit a9aa8ed

Please sign in to comment.