Compare commits
4
Commits
8409556158
...
2026.7.16
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ba7169efd | ||
|
|
c087171735 | ||
|
|
2d3c30b553 | ||
|
|
c8d5553214 |
Generated
+126
-9
@@ -2543,6 +2543,7 @@ dependencies = [
|
|||||||
"tauri-build",
|
"tauri-build",
|
||||||
"tauri-plugin-aptabase",
|
"tauri-plugin-aptabase",
|
||||||
"tauri-plugin-dialog",
|
"tauri-plugin-dialog",
|
||||||
|
"tauri-plugin-single-instance",
|
||||||
"tauri-plugin-updater",
|
"tauri-plugin-updater",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
@@ -3420,7 +3421,7 @@ dependencies = [
|
|||||||
"security-framework 2.11.1",
|
"security-framework 2.11.1",
|
||||||
"security-framework 3.7.0",
|
"security-framework 3.7.0",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
"zbus",
|
"zbus 4.4.0",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5895,7 +5896,7 @@ dependencies = [
|
|||||||
"rand 0.8.6",
|
"rand 0.8.6",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
"zbus",
|
"zbus 4.4.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7066,6 +7067,21 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-single-instance"
|
||||||
|
version = "2.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c8f29386f5e9fdc699182388a33ee80a56de436d91b67459e86afef426282af"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tauri",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"tracing",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
"zbus 5.17.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-updater"
|
name = "tauri-plugin-updater"
|
||||||
version = "2.10.1"
|
version = "2.10.1"
|
||||||
@@ -9126,9 +9142,44 @@ dependencies = [
|
|||||||
"uds_windows",
|
"uds_windows",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
"xdg-home",
|
"xdg-home",
|
||||||
"zbus_macros",
|
"zbus_macros 4.4.0",
|
||||||
"zbus_names",
|
"zbus_names 3.0.0",
|
||||||
"zvariant",
|
"zvariant 4.2.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus"
|
||||||
|
version = "5.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a28b97f866896a4be7aefd2b5a8e01bb6773d19a775d54ab28b4d094b9a4480e"
|
||||||
|
dependencies = [
|
||||||
|
"async-broadcast",
|
||||||
|
"async-executor",
|
||||||
|
"async-io",
|
||||||
|
"async-lock",
|
||||||
|
"async-process",
|
||||||
|
"async-recursion",
|
||||||
|
"async-task",
|
||||||
|
"async-trait",
|
||||||
|
"blocking",
|
||||||
|
"enumflags2",
|
||||||
|
"event-listener",
|
||||||
|
"futures-core",
|
||||||
|
"futures-lite",
|
||||||
|
"hex",
|
||||||
|
"libc",
|
||||||
|
"ordered-stream",
|
||||||
|
"rustix",
|
||||||
|
"serde",
|
||||||
|
"serde_repr",
|
||||||
|
"tracing",
|
||||||
|
"uds_windows",
|
||||||
|
"uuid 1.23.4",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
"winnow 1.0.3",
|
||||||
|
"zbus_macros 5.17.0",
|
||||||
|
"zbus_names 4.3.3",
|
||||||
|
"zvariant 5.13.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -9141,7 +9192,22 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.118",
|
"syn 2.0.118",
|
||||||
"zvariant_utils",
|
"zvariant_utils 2.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus_macros"
|
||||||
|
version = "5.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e05ad887425eecf5e8384dc2406a4a9313eb73468712fc1cdea362eb4fe0469"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-crate 3.5.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.118",
|
||||||
|
"zbus_names 4.3.3",
|
||||||
|
"zvariant 5.13.0",
|
||||||
|
"zvariant_utils 3.5.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -9152,7 +9218,18 @@ checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"zvariant",
|
"zvariant 4.2.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus_names"
|
||||||
|
version = "4.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1039ca249fee9559680f3a9f05b55e0761fee51af4f6c1e7d8c1f31e549721d2"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"winnow 1.0.3",
|
||||||
|
"zvariant 5.13.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -9313,7 +9390,21 @@ dependencies = [
|
|||||||
"enumflags2",
|
"enumflags2",
|
||||||
"serde",
|
"serde",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"zvariant_derive",
|
"zvariant_derive 4.2.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zvariant"
|
||||||
|
version = "5.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7cf057bb00bf5c9ad77abb6147b0ca4818236a1858416e9d988e40d6322fefa7"
|
||||||
|
dependencies = [
|
||||||
|
"endi",
|
||||||
|
"enumflags2",
|
||||||
|
"serde",
|
||||||
|
"winnow 1.0.3",
|
||||||
|
"zvariant_derive 5.13.0",
|
||||||
|
"zvariant_utils 3.5.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -9326,7 +9417,20 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.118",
|
"syn 2.0.118",
|
||||||
"zvariant_utils",
|
"zvariant_utils 2.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zvariant_derive"
|
||||||
|
version = "5.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8118ca6bda77bfc0ab51d660db0c955f2505eef854c9a449435bccb616933b31"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-crate 3.5.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.118",
|
||||||
|
"zvariant_utils 3.5.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -9339,3 +9443,16 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.118",
|
"syn 2.0.118",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zvariant_utils"
|
||||||
|
version = "3.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90cb9383f9b45290407a1258b202d3f8f01db719eb60b4e4055c6375af4fc7c7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"serde",
|
||||||
|
"syn 2.0.118",
|
||||||
|
"winnow 1.0.3",
|
||||||
|
]
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ tokio = "1.52.3"
|
|||||||
tauri-build = { version = "2", features = [] }
|
tauri-build = { version = "2", features = [] }
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||||
|
tauri-plugin-single-instance = "2"
|
||||||
tauri-plugin-updater = "2"
|
tauri-plugin-updater = "2"
|
||||||
|
|
||||||
# ── Build profiles ───────────────────────────────────────────────────────────
|
# ── Build profiles ───────────────────────────────────────────────────────────
|
||||||
|
|||||||
+20
-4
@@ -681,7 +681,14 @@ pub fn create_tag(
|
|||||||
Some(message) => {
|
Some(message) => {
|
||||||
run_git(
|
run_git(
|
||||||
&repo,
|
&repo,
|
||||||
["tag", "-a", name.as_str(), "-m", message.as_str(), target.as_str()],
|
[
|
||||||
|
"tag",
|
||||||
|
"-a",
|
||||||
|
name.as_str(),
|
||||||
|
"-m",
|
||||||
|
message.as_str(),
|
||||||
|
target.as_str(),
|
||||||
|
],
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@@ -755,7 +762,11 @@ fn validate_existing_tag_name(repo: &Path, name: &str) -> Result<String, String>
|
|||||||
|
|
||||||
fn validate_tag_ref_name(name: &str) -> Result<String, String> {
|
fn validate_tag_ref_name(name: &str) -> Result<String, String> {
|
||||||
let output = git_command()
|
let output = git_command()
|
||||||
.args(["check-ref-format", "--allow-onelevel", &format!("refs/tags/{name}")])
|
.args([
|
||||||
|
"check-ref-format",
|
||||||
|
"--allow-onelevel",
|
||||||
|
&format!("refs/tags/{name}"),
|
||||||
|
])
|
||||||
.output()
|
.output()
|
||||||
.map_err(|err| format!("Could not start Git. Is Git installed? {err}"))?;
|
.map_err(|err| format!("Could not start Git. Is Git installed? {err}"))?;
|
||||||
|
|
||||||
@@ -1096,7 +1107,11 @@ pub fn last_commit_message(path: String) -> Result<Option<String>, String> {
|
|||||||
|
|
||||||
let output = run_git(&repo, ["log", "-1", "--format=%B", "HEAD"])?;
|
let output = run_git(&repo, ["log", "-1", "--format=%B", "HEAD"])?;
|
||||||
let message = String::from_utf8_lossy(&output).trim_end().to_string();
|
let message = String::from_utf8_lossy(&output).trim_end().to_string();
|
||||||
Ok(if message.is_empty() { None } else { Some(message) })
|
Ok(if message.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(message)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -5544,7 +5559,8 @@ mod tests {
|
|||||||
fn get_file_blame_attributes_lines_to_the_commits_that_introduced_them() {
|
fn get_file_blame_attributes_lines_to_the_commits_that_introduced_them() {
|
||||||
let repo = init_temp_repo("file_blame");
|
let repo = init_temp_repo("file_blame");
|
||||||
commit_initial_file(&repo.path);
|
commit_initial_file(&repo.path);
|
||||||
fs::write(repo.path.join("old.txt"), "original\ntwo\n").expect("tracked file should change");
|
fs::write(repo.path.join("old.txt"), "original\ntwo\n")
|
||||||
|
.expect("tracked file should change");
|
||||||
run_git_test(&repo.path, ["add", "old.txt"]);
|
run_git_test(&repo.path, ["add", "old.txt"]);
|
||||||
run_git_test(&repo.path, ["commit", "-q", "-m", "add second line"]);
|
run_git_test(&repo.path, ["commit", "-q", "-m", "add second line"]);
|
||||||
|
|
||||||
|
|||||||
+15
-7
@@ -19,7 +19,7 @@ use git::{
|
|||||||
restore_to_commit, search_code_introductions, stage_files, stash_apply, stash_drop, stash_pop,
|
restore_to_commit, search_code_introductions, stage_files, stash_apply, stash_drop, stash_pop,
|
||||||
stash_push, undo_last_commit, unstage_files,
|
stash_push, undo_last_commit, unstage_files,
|
||||||
};
|
};
|
||||||
use tauri::Manager;
|
use tauri::{Manager, AppHandle};
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn close_splashscreen(app: tauri::AppHandle) -> Result<(), String> {
|
fn close_splashscreen(app: tauri::AppHandle) -> Result<(), String> {
|
||||||
@@ -43,13 +43,21 @@ fn close_splashscreen(app: tauri::AppHandle) -> Result<(), String> {
|
|||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_single_instance::init(|app, _, _| {
|
||||||
|
#[cfg(desktop)]
|
||||||
|
let _ = app.get_webview_window("main")
|
||||||
|
.expect("no main window")
|
||||||
|
.set_focus();
|
||||||
|
}))
|
||||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||||
.plugin(tauri_plugin_aptabase::Builder::new("A-SH-1344793789").with_options(
|
.plugin(
|
||||||
tauri_plugin_aptabase::InitOptions {
|
tauri_plugin_aptabase::Builder::new("A-SH-1344793789")
|
||||||
host: Some("https://aptabase.cbsk-tech.de".to_string()),
|
.with_options(tauri_plugin_aptabase::InitOptions {
|
||||||
flush_interval:None
|
host: Some("https://aptabase.cbsk-tech.de".to_string()),
|
||||||
}
|
flush_interval: None,
|
||||||
).build())
|
})
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
.manage(SearchCancellationState::default())
|
.manage(SearchCancellationState::default())
|
||||||
.manage(commit_ai::CommitAiEngine::new())
|
.manage(commit_ai::CommitAiEngine::new())
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
|
|||||||
+29
-15
@@ -377,14 +377,14 @@
|
|||||||
$: localBranchNames = localBranches.map((b) => b.name);
|
$: localBranchNames = localBranches.map((b) => b.name);
|
||||||
$: remoteBranches = branches.filter((b) => b.remote);
|
$: remoteBranches = branches.filter((b) => b.remote);
|
||||||
$: repoSearchTerm = repoSearch.trim().toLowerCase();
|
$: repoSearchTerm = repoSearch.trim().toLowerCase();
|
||||||
$: openRepoRows = repoTabs.filter(repoMatchesSearch);
|
$: openRepoRows = repoTabs.filter((repo) => repoMatchesSearch(repo, repoSearchTerm));
|
||||||
$: recentRepoRows = recentRepoPaths
|
$: recentRepoRows = recentRepoPaths
|
||||||
.filter((path) => !repoTabs.some((tab) => sameRepoPath(tab.path, path)))
|
.filter((path) => !repoTabs.some((tab) => sameRepoPath(tab.path, path)))
|
||||||
.map(repoRowFromPath)
|
.map((path) => repoRowFromPath(path, repoTabs, repoStatusCache))
|
||||||
.filter(repoMatchesSearch);
|
.filter((repo) => repoMatchesSearch(repo, repoSearchTerm));
|
||||||
$: favoriteRepoRows = favoriteRepoPaths
|
$: favoriteRepoRows = favoriteRepoPaths
|
||||||
.map(repoRowFromPath)
|
.map((path) => repoRowFromPath(path, repoTabs, repoStatusCache))
|
||||||
.filter(repoMatchesSearch);
|
.filter((repo) => repoMatchesSearch(repo, repoSearchTerm));
|
||||||
$: leftSidebarRows = buildLeftSidebarRows(branchPanelCollapsed, stashPanelCollapsed, explorerPanelCollapsed);
|
$: leftSidebarRows = buildLeftSidebarRows(branchPanelCollapsed, stashPanelCollapsed, explorerPanelCollapsed);
|
||||||
$: allLeftPanelsCollapsed = branchPanelCollapsed && stashPanelCollapsed && explorerPanelCollapsed;
|
$: allLeftPanelsCollapsed = branchPanelCollapsed && stashPanelCollapsed && explorerPanelCollapsed;
|
||||||
|
|
||||||
@@ -539,6 +539,7 @@
|
|||||||
try {
|
try {
|
||||||
await fetchRemote(activeRepoPath);
|
await fetchRemote(activeRepoPath);
|
||||||
applyStatus(await getStatus(activeRepoPath));
|
applyStatus(await getStatus(activeRepoPath));
|
||||||
|
await refreshRefsAndCommitGraph(activeRepoPath);
|
||||||
} catch {
|
} catch {
|
||||||
// ignore — see comment above
|
// ignore — see comment above
|
||||||
} finally {
|
} finally {
|
||||||
@@ -556,8 +557,10 @@
|
|||||||
try {
|
try {
|
||||||
await fetchRemote(path);
|
await fetchRemote(path);
|
||||||
const nextStatus = await getStatus(path);
|
const nextStatus = await getStatus(path);
|
||||||
if (sameRepoPath(path, activeRepoPath)) applyStatus(nextStatus);
|
if (sameRepoPath(path, activeRepoPath)) {
|
||||||
else updateRepoManagementStatus(path, nextStatus);
|
applyStatus(nextStatus);
|
||||||
|
await refreshRefsAndCommitGraph(path);
|
||||||
|
} else updateRepoManagementStatus(path, nextStatus);
|
||||||
} catch {
|
} catch {
|
||||||
// ignore; manual Fetch/Pull surfaces auth or network problems
|
// ignore; manual Fetch/Pull surfaces auth or network problems
|
||||||
} finally {
|
} finally {
|
||||||
@@ -949,11 +952,11 @@
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function repoRowFromPath(path: string): RepoTab {
|
function repoRowFromPath(path: string, tabs = repoTabs, statusCache = repoStatusCache): RepoTab {
|
||||||
const openTab = repoTabs.find((tab) => sameRepoPath(tab.path, path));
|
const openTab = tabs.find((tab) => sameRepoPath(tab.path, path));
|
||||||
if (openTab) return openTab;
|
if (openTab) return openTab;
|
||||||
|
|
||||||
const cached = repoStatusCache[repoKey(path)];
|
const cached = statusCache[repoKey(path)];
|
||||||
if (cached) return { ...cached, path, name: repoNameFromPath(path) };
|
if (cached) return { ...cached, path, name: repoNameFromPath(path) };
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -967,11 +970,11 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function repoMatchesSearch(repo: RepoTab): boolean {
|
function repoMatchesSearch(repo: RepoTab, searchTerm = repoSearchTerm): boolean {
|
||||||
if (!repoSearchTerm) return true;
|
if (!searchTerm) return true;
|
||||||
return repo.name.toLowerCase().includes(repoSearchTerm)
|
return repo.name.toLowerCase().includes(searchTerm)
|
||||||
|| repo.path.toLowerCase().includes(repoSearchTerm)
|
|| repo.path.toLowerCase().includes(searchTerm)
|
||||||
|| (repo.branch ?? "").toLowerCase().includes(repoSearchTerm);
|
|| (repo.branch ?? "").toLowerCase().includes(searchTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadRepoLists() {
|
function loadRepoLists() {
|
||||||
@@ -1629,6 +1632,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function refreshRefsAndCommitGraph(path = activeRepoPath) {
|
||||||
|
const previousHeadHash = lastFileHistoryHeadHash;
|
||||||
|
await refreshBranchList(path);
|
||||||
|
await refreshTags(path);
|
||||||
|
await refreshCommitHistory(path);
|
||||||
|
if (lastFileHistoryHeadHash !== previousHeadHash) {
|
||||||
|
await refreshFileHistory(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function isCancellationMessage(message: string): boolean {
|
function isCancellationMessage(message: string): boolean {
|
||||||
return message.toLowerCase().includes("cancelled");
|
return message.toLowerCase().includes("cancelled");
|
||||||
}
|
}
|
||||||
@@ -2329,6 +2342,7 @@
|
|||||||
errorMessage = "";
|
errorMessage = "";
|
||||||
await runOperation("Fetching", async () => {
|
await runOperation("Fetching", async () => {
|
||||||
applyStatus(await fetchRemote(activeRepoPath, username, password));
|
applyStatus(await fetchRemote(activeRepoPath, username, password));
|
||||||
|
await refreshRefsAndCommitGraph(activeRepoPath);
|
||||||
trackEvent("repository_fetched", {
|
trackEvent("repository_fetched", {
|
||||||
from_stored_credential: fromStore ? 1 : 0,
|
from_stored_credential: fromStore ? 1 : 0,
|
||||||
ahead: status?.ahead ?? 0,
|
ahead: status?.ahead ?? 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user