Allow pulling repositories with unrelated commit histories when the user explicitly opts in. The pull argument construction was refactored and branch resolution made more robust so the backend can include the --allow-unrelated-histories flag when requested. - Extract pull argument logic and add support for allowing unrelated histories. - Prompt users in the UI to confirm merging separate histories and retry pull. - Restyle and improve the update toast UI for better layout and responsiveness.
147 lines
4.1 KiB
Svelte
147 lines
4.1 KiB
Svelte
<script lang="ts">
|
|
import {
|
|
AlertCircle,
|
|
Download,
|
|
LoaderCircle,
|
|
PackageCheck,
|
|
Sparkles,
|
|
X,
|
|
} from "@lucide/svelte";
|
|
|
|
type UpdateToastState = "available" | "downloading" | "installed" | "error";
|
|
|
|
interface Props {
|
|
state: UpdateToastState;
|
|
version: string;
|
|
currentVersion: string;
|
|
progress: number;
|
|
error: string;
|
|
onInstall: () => void;
|
|
onLater: () => void;
|
|
onDismiss: () => void;
|
|
}
|
|
|
|
let {
|
|
state,
|
|
version,
|
|
currentVersion = "",
|
|
progress = 0,
|
|
error = "",
|
|
onInstall,
|
|
onLater,
|
|
onDismiss,
|
|
}: Props = $props();
|
|
|
|
const clampedProgress = $derived(Math.max(0, Math.min(100, Math.round(progress))));
|
|
const title = $derived(
|
|
state === "installed"
|
|
? "Update installed"
|
|
: state === "downloading"
|
|
? "Installing update"
|
|
: state === "error"
|
|
? "Update failed"
|
|
: "Update available",
|
|
);
|
|
const description = $derived(
|
|
state === "installed"
|
|
? "Restart Gitty to use the new version."
|
|
: state === "downloading"
|
|
? "Download and installation are running in the background."
|
|
: state === "error"
|
|
? (error || "The update could not be installed.")
|
|
: "Do you want to install this version now?",
|
|
);
|
|
const versionLabel = $derived(
|
|
version && currentVersion
|
|
? `${currentVersion} → ${version}`
|
|
: version
|
|
? `Version ${version}`
|
|
: "New version",
|
|
);
|
|
const showProgress = $derived(state === "downloading" || state === "installed");
|
|
const isBusy = $derived(state === "downloading");
|
|
</script>
|
|
|
|
<section
|
|
class="update-toast"
|
|
class:error={state === "error"}
|
|
class:installed={state === "installed"}
|
|
role={state === "error" ? "alert" : "status"}
|
|
aria-live={state === "error" ? "assertive" : "polite"}
|
|
>
|
|
<header class="update-toast-header">
|
|
<div class="update-toast-icon" class:busy={isBusy}>
|
|
{#if state === "downloading"}
|
|
<LoaderCircle class="spin" size={18} aria-hidden="true" />
|
|
{:else if state === "installed"}
|
|
<PackageCheck size={18} aria-hidden="true" />
|
|
{:else if state === "error"}
|
|
<AlertCircle size={18} aria-hidden="true" />
|
|
{:else}
|
|
<Sparkles size={18} aria-hidden="true" />
|
|
{/if}
|
|
</div>
|
|
|
|
<div class="update-toast-copy">
|
|
<span class="update-toast-kicker">Gitty update · {versionLabel}</span>
|
|
<h2>{title}</h2>
|
|
</div>
|
|
|
|
{#if !isBusy}
|
|
<button class="update-toast-close" type="button" onclick={onDismiss} title="Close" aria-label="Close">
|
|
<X size={15} aria-hidden="true" />
|
|
</button>
|
|
{/if}
|
|
</header>
|
|
|
|
<div class="update-toast-body">
|
|
<p>{description}</p>
|
|
|
|
{#if showProgress}
|
|
<div
|
|
class="update-progress"
|
|
class:indeterminate={state === "downloading" && clampedProgress === 0}
|
|
role="progressbar"
|
|
aria-valuemin="0"
|
|
aria-valuemax="100"
|
|
aria-valuenow={clampedProgress}
|
|
>
|
|
<span style={`width: ${clampedProgress}%`}></span>
|
|
</div>
|
|
<div class="update-progress-label">
|
|
{state === "installed" ? "100% complete" : clampedProgress > 0 ? `${clampedProgress}%` : "Waiting for download size"}
|
|
</div>
|
|
{/if}
|
|
|
|
</div>
|
|
|
|
<footer class="update-toast-actions">
|
|
{#if state === "installed"}
|
|
<button class="update-toast-secondary" type="button" onclick={onDismiss}>
|
|
Got it
|
|
</button>
|
|
{:else if state === "error"}
|
|
<button class="update-toast-secondary" type="button" onclick={onDismiss}>
|
|
Close
|
|
</button>
|
|
<button class="update-toast-primary" type="button" onclick={onInstall}>
|
|
<Download size={14} aria-hidden="true" />
|
|
Try again
|
|
</button>
|
|
{:else}
|
|
<button class="update-toast-secondary" type="button" onclick={onLater} disabled={isBusy}>
|
|
Later
|
|
</button>
|
|
<button class="update-toast-primary" type="button" onclick={onInstall} disabled={isBusy}>
|
|
{#if isBusy}
|
|
<LoaderCircle class="spin" size={14} aria-hidden="true" />
|
|
Installing
|
|
{:else}
|
|
<Download size={14} aria-hidden="true" />
|
|
Install
|
|
{/if}
|
|
</button>
|
|
{/if}
|
|
</footer>
|
|
</section>
|