Add repository file browser

This commit is contained in:
Georg Bauer
2026-07-31 11:25:46 +02:00
parent 4e4dfb0db9
commit 7b2b431dfd
11 changed files with 669 additions and 21 deletions

View File

@@ -222,6 +222,51 @@ pub async fn load_branches(
Ok(branches)
}
pub async fn load_repository_contents(
server: &Server,
owner: &str,
repository: &str,
path: &str,
) -> Result<Vec<models::ContentsResponse>, String> {
let client =
Client::new(&server.url, Some(&server.token)).map_err(|error| error.to_string())?;
let configuration = client.configuration();
if path.is_empty() {
apis::repository_api::repo_get_contents_list(&configuration, owner, repository, None)
.await
.map_err(|error| error.to_string())
} else {
apis::repository_api::repo_get_contents_ext(
&configuration,
owner,
repository,
path,
None,
None,
)
.await
.map(|contents| contents.dir_contents.unwrap_or_default())
.map_err(|error| error.to_string())
}
}
pub async fn load_repository_file(
server: &Server,
owner: &str,
repository: &str,
path: &str,
) -> Result<Vec<u8>, String> {
let client =
Client::new(&server.url, Some(&server.token)).map_err(|error| error.to_string())?;
apis::repository_api::repo_get_raw_file(&client.configuration(), owner, repository, path, None)
.await
.map_err(|error| error.to_string())?
.bytes()
.await
.map(|bytes| bytes.to_vec())
.map_err(|error| error.to_string())
}
pub async fn load_branch_commits(
server: &Server,
owner: &str,

View File

@@ -290,6 +290,26 @@ impl GotchaCore {
Ok(commit_page(branches, &commits, branch.is_none()))
}
pub async fn repository_contents(
&self,
owner: String,
repository: String,
path: String,
) -> Result<Vec<RepositoryContentRow>, GotchaError> {
Ok(repository_content_rows(
load_repository_contents(&self.server()?, &owner, &repository, &path).await?,
))
}
pub async fn repository_file(
&self,
owner: String,
repository: String,
path: String,
) -> Result<Vec<u8>, GotchaError> {
Ok(load_repository_file(&self.server()?, &owner, &repository, &path).await?)
}
pub async fn commit_files(
&self,
owner: String,

View File

@@ -116,6 +116,14 @@ pub struct FileRow {
pub status: String,
}
#[derive(Clone, uniffi::Record)]
pub struct RepositoryContentRow {
pub name: String,
pub path: String,
pub kind: String,
pub size: i64,
}
#[derive(Clone, uniffi::Record)]
pub struct DiffLine {
pub old_number: String,
@@ -422,6 +430,24 @@ pub fn commit_file_rows(files: Vec<models::CommitAffectedFiles>) -> Vec<FileRow>
.collect()
}
pub fn repository_content_rows(
contents: Vec<models::ContentsResponse>,
) -> Vec<RepositoryContentRow> {
let mut rows: Vec<_> = contents
.into_iter()
.filter_map(|content| {
Some(RepositoryContentRow {
name: content.name?,
path: content.path?,
kind: content.r#type.unwrap_or_else(|| "file".into()),
size: content.size.unwrap_or_default(),
})
})
.collect();
rows.sort_by_key(|row| (row.kind != "dir", row.name.to_lowercase()));
rows
}
pub fn diff_page(path: &str, diff: crate::diff::Parsed) -> DiffPage {
DiffPage {
title: path.rsplit('/').next().unwrap_or(path).into(),
@@ -758,6 +784,31 @@ pub fn compact_date(date: Option<&str>) -> String {
mod tests {
use super::*;
#[test]
fn repository_directories_sort_before_files() {
let contents = [
("z.swift", "file"),
("Sources", "dir"),
("README.md", "file"),
]
.into_iter()
.map(|(name, kind)| models::ContentsResponse {
name: Some(name.into()),
path: Some(name.into()),
r#type: Some(kind.into()),
..Default::default()
})
.collect();
assert_eq!(
repository_content_rows(contents)
.into_iter()
.map(|row| row.name)
.collect::<Vec<_>>(),
["Sources", "README.md", "z.swift"]
);
}
#[test]
fn maps_heat_levels_and_labels() {
let heatmap = vec![