Radish alpha
r
rad:z4D5UCArafTzTQpDZNQRuqswh3ury
Radicle desktop app
Radicle
Git
Provide a full window error if something goes wrong
Sebastian Martinez committed 10 months ago
commit 8e683cf7ce35869f6fc556bf8feebbbb5ba7a5ee
parent d68a06c
7 files changed +154 -2
modified crates/radicle-tauri/src/commands/startup.rs
@@ -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),
    )?;
modified crates/radicle-types/src/error.rs
@@ -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,
modified src/App.svelte
@@ -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}
modified src/components/Border.svelte
@@ -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}
modified src/components/Command.svelte
@@ -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>
added src/components/ExternalLink.svelte
@@ -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>
added src/components/FullWindowError.svelte
@@ -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>