allow launching existing or installing new if either fails

This commit is contained in:
llama 2025-10-31 23:03:52 +08:00
parent 04332f36b5
commit 934d11aebb
No known key found for this signature in database
GPG key ID: 0B7543854B9413C3
2 changed files with 87 additions and 56 deletions

View file

@ -7,32 +7,39 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type { ExistingVersions, Versions } from "@generated/anki/launcher_pb"; import type { ExistingVersions, Versions } from "@generated/anki/launcher_pb";
import Row from "$lib/components/Row.svelte"; import Row from "$lib/components/Row.svelte";
import EnumSelector from "$lib/components/EnumSelector.svelte"; import EnumSelector from "$lib/components/EnumSelector.svelte";
import Warning from "./Warning.svelte";
import Spinner from "./Spinner.svelte";
let { let {
releases, releasesPromise,
existing, existingPromise,
allowBetas, allowBetas,
choose, choose,
uninstall, uninstall,
}: { }: {
releases: Versions; releasesPromise: Promise<Versions>;
existing: ExistingVersions; existingPromise: Promise<ExistingVersions>;
allowBetas: boolean; allowBetas: boolean;
choose: (version: string, existing: boolean, current?: string) => void; choose: (version: string, existing: boolean, current?: string) => void;
uninstall: (() => void) | null; uninstall: (() => void) | null;
} = $props(); } = $props();
// TODO: replace once svelte's experimental async mode is on
let releases = $state(undefined as Versions | undefined);
let existing = $state(undefined as ExistingVersions | undefined);
releasesPromise.then((r) => (releases = r));
existingPromise.then((r) => (existing = r));
let availableVersions = $derived( let availableVersions = $derived(
releases.all releases?.all
.filter((v) => allowBetas || !v.isPrerelease) .filter((v) => allowBetas || !v.isPrerelease)
.map((v) => ({ label: v.version, value: v.version })), .map((v) => ({ label: v.version, value: v.version })),
); );
let latest = $derived(availableVersions[0]?.value ?? null); let latest = $derived(availableVersions?.[0]?.value);
let selected = $derived(availableVersions[0]?.value ?? null); let selected = $derived(availableVersions?.[0]?.value);
let current = $derived(existing.current?.version); let current = $derived(existing!?.current?.version);
let pyprojectModified = $derived(existing?.pyprojectModifiedByUser);
let pyprojectModified = $derived(existing.pyprojectModifiedByUser);
function _choose(version: string, keepExisting: boolean = false) { function _choose(version: string, keepExisting: boolean = false) {
choose(version, keepExisting, current); choose(version, keepExisting, current);
@ -40,45 +47,57 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</script> </script>
<div class="group"> <div class="group">
{#if latest != null && latest != current} {#await releasesPromise}
<Spinner label={$tr.launcherLoadingVersions()} />
{:then}
{#if latest != null && latest != current}
<Row class="centre m-3">
<button class="btn btn-primary" onclick={() => _choose(latest)}>
{#if latest == null}
{$tr.launcherLatestAnki()}
{:else}
{$tr.launcherLatestAnkiVersion({
version: latest!,
})}
{/if}
</button>
</Row>
{/if}
{:catch}
<Warning warning={$tr.launcherFailedToGetReleases()} className="alert-danger" />
{/await}
{#await existingPromise}
<Spinner label={$tr.launcherCheckingExisting()} />
{:then}
{#if current != null}
<Row class="centre m-3">
<button class="btn btn-primary" onclick={() => _choose(current, true)}>
{#if pyprojectModified}
{$tr.launcherSyncProjectChanges()}
{:else}
{$tr.launcherKeepExistingVersion({ current })}
{/if}
</button>
</Row>
{/if}
{/await}
{#if availableVersions}
<Row class="centre m-3"> <Row class="centre m-3">
<button class="btn btn-primary" onclick={() => _choose(latest)}> <button
{#if latest == null} class="btn btn-primary"
{$tr.launcherLatestAnki()} onclick={() => _choose(selected!)}
{:else} disabled={selected == null}
{$tr.launcherLatestAnkiVersion({ >
version: latest!, {$tr.launcherChooseAVersion()}
})}
{/if}
</button> </button>
<div class="m-2">
{"->"}
</div>
<div style="width: 100px">
<EnumSelector bind:value={selected} choices={availableVersions} />
</div>
</Row> </Row>
{/if} {/if}
{#if current != null}
<Row class="centre m-3">
<button class="btn btn-primary" onclick={() => _choose(current, true)}>
{#if pyprojectModified}
{$tr.launcherSyncProjectChanges()}
{:else}
{$tr.launcherKeepExistingVersion({ current })}
{/if}
</button>
</Row>
{/if}
<Row class="centre m-3">
<button
class="btn btn-primary"
onclick={() => _choose(selected!)}
disabled={selected == null}
>
{$tr.launcherChooseAVersion()}
</button>
<div class="m-2">
{"->"}
</div>
<div style="width: 100px">
<EnumSelector bind:value={selected} choices={availableVersions} />
</div>
</Row>
{#if uninstall != null} {#if uninstall != null}
<Row class="centre m-3"> <Row class="centre m-3">
<button class="btn btn-primary" onclick={uninstall}> <button class="btn btn-primary" onclick={uninstall}>

View file

@ -23,7 +23,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import Term from "./Term.svelte"; import Term from "./Term.svelte";
import AnkiWillStart from "./AnkiWillStart.svelte"; import AnkiWillStart from "./AnkiWillStart.svelte";
import type { Terminal } from "@xterm/xterm"; import type { Terminal } from "@xterm/xterm";
import { tick } from "svelte";
let { let {
options, options,
@ -39,9 +38,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
footer = _footer; footer = _footer;
let releasesPromise = $state(getAvailableVersions({}, { alertOnError: false })); let releasesPromise = $state(getAvailableVersions({}));
let existingPromise = $state(getExistingVersions({}, { alertOnError: false })); let existingPromise = $state(getExistingVersions({}));
let loadPromise = $derived(Promise.all([releasesPromise, existingPromise])); let loadPromise = $derived(Promise.any([releasesPromise, existingPromise]));
let allowBetas = $state(options.allowBetas); let allowBetas = $state(options.allowBetas);
let downloadCaching = $state(options.downloadCaching); let downloadCaching = $state(options.downloadCaching);
@ -77,16 +76,29 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<Row class="centre m-3"> <Row class="centre m-3">
<Spinner label={$tr.launcherLoadingVersions()} /> <Spinner label={$tr.launcherLoadingVersions()} />
</Row> </Row>
{:then [releases, existing]} {:then}
<Action {releases} {existing} {allowBetas} {choose} {uninstall} /> <Action
{:catch e} {releasesPromise}
{existingPromise}
{allowBetas}
{choose}
{uninstall}
/>
{#await releasesPromise catch e}
<Row>
<pre>{e.message}</pre>
</Row>
{/await}
{:catch e: AggregateError}
<Warning <Warning
warning={$tr.lauuncherFailedToLoadVersions()} warning={$tr.launcherFailedToGetExistingAndAvailable()}
className="alert-danger" className="alert-danger"
/> />
<Row> {#each e.errors as err}
<pre>{e.message}</pre> <Row>
</Row> <pre>{err.message}</pre>
</Row>
{/each}
{/await} {/await}
{:else} {:else}
<Row class="centre m-3"> <Row class="centre m-3">