feat(remote): Enhance remote branch management and stability
Improved handling for deleting remote branches across the application, enhancing both user experience and backend reliability. This includes adding structured logging to all Git remote operations in Rust, refining UI components to handle remote-specific deletion flows, and providing clear status/error feedback in sync settings. - Standardized styling for action toggles (Stash, Branch, Explorer) using consistent dimensions. - Implemented detailed console logging for all Git remote operations on the backend. - Refined dialogs and sync settings to provide explicit status and error messages during remote management.
This commit is contained in:
@@ -18,7 +18,8 @@
|
||||
onClose = () => {},
|
||||
}: Props = $props();
|
||||
|
||||
let title = $derived(force ? "Force delete branch?" : "Delete branch?");
|
||||
let title = $derived(branch.remote ? "Delete remote branch?" : force ? "Force delete branch?" : "Delete branch?");
|
||||
let remoteParts = $derived(branch.remote ? branch.name.split(/\/(.+)/) : []);
|
||||
|
||||
</script>
|
||||
|
||||
@@ -26,7 +27,7 @@
|
||||
<div class="dialog branch-delete-dialog" role="dialog" aria-modal="true" aria-label={title}>
|
||||
<header class="dialog-header">
|
||||
<div>
|
||||
<span class="eyebrow">{force ? "Force delete" : "Delete branch"}</span>
|
||||
<span class="eyebrow">{branch.remote ? "Remote branch" : force ? "Force delete" : "Delete branch"}</span>
|
||||
<p class="dialog-title">{title}</p>
|
||||
</div>
|
||||
<button class="btn-sm dialog-close" type="button" onclick={onClose} disabled={isBusy} aria-label="Close">
|
||||
@@ -41,7 +42,9 @@
|
||||
|
||||
<div class="discard-confirm-copy">
|
||||
<p>
|
||||
{#if force}
|
||||
{#if branch.remote}
|
||||
Delete this branch from the remote server?
|
||||
{:else if force}
|
||||
This branch is not fully merged. Force deleting removes the branch pointer even if some commits are only reachable from this branch.
|
||||
{:else}
|
||||
Delete this local branch from the repository?
|
||||
@@ -52,7 +55,9 @@
|
||||
{branch.name}
|
||||
</code>
|
||||
<p class="discard-warning-text">
|
||||
{#if force}
|
||||
{#if branch.remote}
|
||||
This affects everyone using <strong>{remoteParts[0] || "the remote"}</strong>. Your local commits and local branches are kept.
|
||||
{:else if force}
|
||||
Make sure you no longer need the unique commits on this branch.
|
||||
{:else}
|
||||
Git will refuse if the branch is not fully merged.
|
||||
@@ -69,7 +74,7 @@
|
||||
{:else}
|
||||
<Trash2 size={15} aria-hidden="true" />
|
||||
{/if}
|
||||
{force ? "Force delete" : "Delete"}
|
||||
{branch.remote ? "Delete from remote" : force ? "Force delete" : "Delete"}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
|
||||
async function deleteContextBranch() {
|
||||
const branch = contextBranch;
|
||||
if (!branch || branch.current || branch.remote || isBusy) return;
|
||||
if (!branch || branch.current || isBusy) return;
|
||||
closeBranchContextMenu();
|
||||
if (branch.remote) await onDeleteRemoteBranch(branch); else await onDeleteBranch(branch);
|
||||
}
|
||||
|
||||
@@ -23,12 +23,37 @@
|
||||
let newUrl = "";
|
||||
let editingName = "";
|
||||
let editingUrl = "";
|
||||
let actionError = "";
|
||||
let actionStatus = "";
|
||||
$: de = language === "de";
|
||||
|
||||
function beginEdit(remote: GitRemote) { editingName = remote.name; editingUrl = remote.fetch_url; }
|
||||
function beginEdit(remote: GitRemote) { actionError = ""; editingName = remote.name; editingUrl = remote.fetch_url; }
|
||||
async function requestDelete(event: MouseEvent, name: string) {
|
||||
console.log(name)
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
editingName = "";
|
||||
actionError = "";
|
||||
actionStatus = de ? `Remote „${name}“ wird entfernt …` : `Removing remote “${name}” …`;
|
||||
console.info("[Gitty remote] remove button activated", { name });
|
||||
await remove(name);
|
||||
}
|
||||
function cancelEdit() { editingName = ""; editingUrl = ""; }
|
||||
async function add() { if (!newName.trim() || !newUrl.trim()) return; await onAddRemote(newName.trim(), newUrl.trim()); newName = "origin"; newUrl = ""; }
|
||||
async function update() { if (!editingName || !editingUrl.trim()) return; await onUpdateRemote(editingName, editingUrl.trim()); cancelEdit(); }
|
||||
async function remove(name: string) {
|
||||
actionError = "";
|
||||
console.log("remove")
|
||||
try {
|
||||
await onRemoveRemote(name);
|
||||
if (draftRemote === name) draftRemote = "";
|
||||
if (draftUpstream.startsWith(`${name}/`)) draftUpstream = "";
|
||||
} catch (error) {
|
||||
actionError = error instanceof Error ? error.message : String(error);
|
||||
} finally {
|
||||
actionStatus = "";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="dialog-backdrop" role="presentation">
|
||||
@@ -59,6 +84,8 @@
|
||||
<section class="sync-settings-card">
|
||||
<div class="sync-card-heading"><div><h3>Remotes</h3><p>{de ? "Server-Verbindungen dieses Repositorys verwalten." : "Manage this repository's server connections."}</p></div><span class="count-pill">{remotes.length}</span></div>
|
||||
<div class="remote-list">
|
||||
{#if actionError}<div class="sync-action-error" role="alert"><strong>{de ? "Remote konnte nicht entfernt werden" : "Remote could not be removed"}</strong><span>{actionError}</span></div>{/if}
|
||||
{#if actionStatus}<div class="sync-action-status" role="status">{actionStatus}</div>{/if}
|
||||
{#each remotes as remote (remote.name)}
|
||||
<div class="remote-row">
|
||||
<span class="remote-mark"><GitBranch size={15} /></span>
|
||||
@@ -68,7 +95,7 @@
|
||||
<button class="btn-sm" type="button" onclick={cancelEdit} disabled={isBusy}>{de ? "Abbrechen" : "Cancel"}</button>
|
||||
{:else}
|
||||
<button class="remote-main" type="button" onclick={() => beginEdit(remote)} disabled={isBusy}><strong>{remote.name}</strong><span>{remote.fetch_url}</span></button>
|
||||
<button class="remote-delete" type="button" onclick={() => onRemoveRemote(remote.name)} disabled={isBusy} aria-label={`${de ? "Remote löschen" : "Remove remote"} ${remote.name}`}><Trash2 size={14} /></button>
|
||||
<button class="remote-delete" type="button" onclick={(event) => requestDelete(event, remote.name)} data-remote-name={remote.name} title={de ? "Remote-Verbindung sofort entfernen; lokale Daten bleiben erhalten" : "Remove remote connection now; local data is kept"}><Trash2 size={13} /><span>{de ? "Entfernen" : "Remove"}</span></button>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}<p class="remote-empty">{de ? "Noch kein Remote eingerichtet." : "No remote configured yet."}</p>{/each}
|
||||
|
||||
+3
-1
@@ -82,7 +82,9 @@ export function listBranches(path: string): Promise<GitBranch[]> {
|
||||
export function listRemotes(path: string): Promise<GitRemote[]> { return invoke("list_remotes", { path }); }
|
||||
export function addRemote(path: string, name: string, url: string): Promise<GitRemote[]> { return invoke("add_remote", { path, name, url }); }
|
||||
export function updateRemote(path: string, name: string, url: string): Promise<GitRemote[]> { return invoke("update_remote", { path, name, url }); }
|
||||
export function removeRemote(path: string, name: string): Promise<GitRemote[]> { return invoke("remove_remote", { path, name }); }
|
||||
export function removeRemote(path: string, name: string): Promise<GitRemote[]> {
|
||||
console.log("remove_remote")
|
||||
return invoke("remove_remote", { path, name }); }
|
||||
export function setBranchUpstream(path: string, branch: string, upstream?: string): Promise<GitStatus> { return invoke("set_branch_upstream", { path, branch, upstream: upstream || null }); }
|
||||
export function deleteRemoteBranch(path: string, remote: string, branch: string): Promise<GitStatus> { return invoke("delete_remote_branch", { path, remote, branch }); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user