Provide a full window error if something goes wrong

This commit is contained in:
Sebastian Martinez
2025-06-06 15:22:08 +02:00
parent d68a06c33a
commit 8e683cf7ce
7 changed files with 154 additions and 2 deletions
@@ -48,9 +48,13 @@ pub(crate) fn check_radicle_cli(ctx: tauri::State<AppState>) -> Result<(), Error
#[tauri::command]
pub(crate) fn startup(app: AppHandle) -> Result<Config, Error> {
let profile = radicle::Profile::load()?;
let home = profile.home();
let repositories = profile.storage.repositories()?;
let public_key = profile.public_key;
let cobs_cache = radicle::cob::cache::Store::open(home.cobs().join(COBS_DB_FILE))?;
cobs_cache.check_version()?;
let inbox_db = radicle_types::outbound::sqlite::Sqlite::reader(
profile.node().join(NOTIFICATIONS_DB_FILE),
)?;
+4
View File
@@ -19,6 +19,10 @@ pub enum Error {
#[error("ssh agent not running")]
AgentNotRunning,
/// Generic Cob cache error.
#[error(transparent)]
Cache(#[from] radicle::cob::cache::Error),
/// Embeds error.
#[error("not able to save embed")]
SaveEmbedError,
+22
View File
@@ -30,6 +30,9 @@
import RepoHome from "@app/views/repo/RepoHome.svelte";
import Repos from "@app/views/home/Repos.svelte";
import Spinner from "./components/Spinner.svelte";
import FullWindowError from "./components/FullWindowError.svelte";
import ExternalLink from "./components/ExternalLink.svelte";
import Command from "./components/Command.svelte";
const activeRouteStore = router.activeRouteStore;
@@ -40,6 +43,7 @@
let showSpinner = $state(false);
delay(() => (showSpinner = true), 1000);
onMount(async () => {
try {
profile = await invoke<Config>("startup");
@@ -117,6 +121,24 @@
<CreateIdentity />
{:else if startup.error?.code === "PassphraseError.InvalidPassphrase" && profile}
<Auth profile={{ did: profile.publicKey, alias: profile.alias }} />
{:else if startup.error}
<FullWindowError title="An error occurred" error={startup.error}>
We were unable to load your Radicle identity, or your Radicle installation
is outdated.
<br />
If you have an existing Radicle installation, make sure you have
<ExternalLink href="https://radicle.xyz/download">
the latest version.
</ExternalLink>
<br />
<br />
<div
style="display: flex; flex-direction: column; align-items: center; gap: 0.5rem;">
To migrate your Radicle storage, make sure to restart your radicle-node
or run:
<Command styleWidth="30rem" command="rad cob migrate" />
</div>
</FullWindowError>
{:else if showSpinner}
<div class="spinner"><Spinner /></div>
{/if}
+3
View File
@@ -10,6 +10,7 @@
stylePadding?: string;
styleHeight?: string;
styleMaxHeight?: string;
styleMaxWidth?: string;
styleMinHeight?: string;
styleMinWidth?: string;
styleWidth?: string;
@@ -33,6 +34,7 @@
stylePadding,
styleHeight,
styleMaxHeight,
styleMaxWidth,
styleMinHeight,
stylePosition,
styleWidth,
@@ -221,6 +223,7 @@
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
style:width={styleWidth}
style:max-width={styleMaxWidth}
style:cursor={styleCursor}
class="container"
class:flat-top={flatTop}
+3 -2
View File
@@ -5,9 +5,10 @@
interface Props {
command: string;
styleWidth: string;
showPrompt?: boolean;
}
const { command, styleWidth }: Props = $props();
const { command, styleWidth, showPrompt = true }: Props = $props();
let clipboard: Clipboard;
</script>
@@ -33,7 +34,7 @@
{styleWidth}
variant="ghost">
<span class="txt-overflow">
$ {command}
{showPrompt ? "$ " : ""}{command}
</span>
<Clipboard bind:this={clipboard} text={command} />
</Border>
+42
View File
@@ -0,0 +1,42 @@
<script lang="ts">
import type { Snippet } from "svelte";
import Icon from "./Icon.svelte";
const { href, children }: { href: string; children?: Snippet } = $props();
</script>
<style>
a {
font-weight: var(--font-weight-semibold);
color: inherit;
display: inline-flex;
align-items: center;
gap: 0.25rem;
text-decoration: none;
}
a:hover {
text-decoration: underline;
text-underline-offset: 2px;
color: var(--color-fill-secondary);
}
.icon {
color: var(--color-foreground-dim);
position: relative;
bottom: 1px;
}
a:hover .icon {
color: var(--color-fill-secondary-hover);
}
</style>
<a {href} target="_blank" rel="noreferrer">
{#if children}
{@render children()}
{:else}
{href}
{/if}
<span class="icon"><Icon name="open-external" /></span>
</a>
+76
View File
@@ -0,0 +1,76 @@
<script lang="ts">
import type { Snippet } from "svelte";
import type { ErrorWrapper } from "@bindings/error/ErrorWrapper";
import ExternalLink from "./ExternalLink.svelte";
import Border from "./Border.svelte";
import Icon from "./Icon.svelte";
import Command from "./Command.svelte";
const {
title = "An error occurred",
children,
error,
}: { title?: string; children?: Snippet; error?: ErrorWrapper } = $props();
</script>
<style>
.error-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
}
.error-icon {
color: var(--color-fill-);
margin-bottom: 1rem;
}
.error-title {
font-size: var(--font-size-large);
font-weight: var(--font-weight-bold);
margin: 0 0 0.75rem 0;
}
.error-support {
padding: 0 2rem;
margin-bottom: 0;
}
</style>
<div class="error-container txt-small">
<Border
styleMaxWidth="45rem"
variant="float"
styleJustifyContent="center"
styleBackgroundColor="var(--color-background-float)"
styleDisplay="flex"
styleFlexDirection="column"
stylePadding="1.5rem">
<div class="error-icon">
<Icon size="32" name="warning" />
</div>
<h2 class="error-title">{title}</h2>
{#if children}
<p class="error-support" style:text-align="center">
{@render children()}
</p>
{/if}
<p class="error-support">
If this problem persists, please contact
<ExternalLink
href="https://radicle.zulipchat.com/#narrow/channel/444463-desktop/topic/support">
support{error ? " with the error details below." : "."}
</ExternalLink>
</p>
{#if error?.message}
<Command styleWidth="30rem" showPrompt={false} command={error.message} />
{/if}
</Border>
</div>