Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Handle registration update errors
Alexis Sellier committed 5 years ago
commit 4728a0ca722abddada7e7daabe5cbe6e8b809267
parent 69501e700cbf0aa25920fa9a8df63a4fbc5efc4c
4 files changed +173 -111
modified src/base/registrations/Index.svelte
@@ -1,9 +1,7 @@
<script lang="typescript">
  import { navigate } from "svelte-routing";
-
  import { registrar } from './registrar';
  import type { Config } from '@app/config';

-
  import Modal from '@app/Modal.svelte';
  import DomainInput from '@app/ens/DomainInput.svelte';

  export let config: Config;
modified src/base/registrations/Submit.svelte
@@ -20,7 +20,6 @@
  let registrationOwner = owner || session.address;

  const view = () => navigate(`/registrations/${subdomain}`)
-
  const done = () => navigate(`/registrations`)

  onMount(async () => {
    try {
added src/base/registrations/Update.svelte
@@ -0,0 +1,87 @@
+
<script lang="typescript">
+
  import { onMount, createEventDispatcher } from 'svelte';
+
  import { setRecords } from './resolver';
+
  import type { EnsRecord } from './resolver';
+
  import type { Registration } from './registrar';
+
  import type { Config } from '@app/config';
+
  import Loading from '@app/Loading.svelte';
+
  import Modal from '@app/Modal.svelte';
+

+
  enum Status {
+
    Signing,
+
    Pending,
+
    Success,
+
    Failed,
+
  }
+

+
  type State =
+
      { status: Status.Signing }
+
    | { status: Status.Pending }
+
    | { status: Status.Success }
+
    | { status: Status.Failed, error: string };
+

+
  export let subdomain: string;
+
  export let config: Config;
+
  export let records: EnsRecord[];
+
  export let registration: Registration;
+

+
  const dispatch = createEventDispatcher();
+

+
  /* let state: State = { status: Status.Signing }; */
+
  let state: State = { status: Status.Failed, error: "Error registering, something happened." };
+

+
  onMount(async () => {
+
    try {
+
      state.status = Status.Signing;
+
      const tx = await setRecords(subdomain, records, registration.resolver, config);
+
      state.status = Status.Pending;
+
      await tx.wait();
+
      state.status = Status.Success;
+
    } catch (e) {
+
      console.error(e);
+
      state = { status: Status.Failed, error: e.message };
+
    }
+
  });
+

+
  const onDone = () => {
+
    // Reload page to load updates to the registration.
+
    location.reload();
+
  };
+

+
  const onClose = () => {
+
    dispatch('close');
+
  };
+
</script>
+

+
<Modal floating error={state.status === Status.Failed}>
+
  <span slot="title">
+
    <div>🧾</div>
+
    <div>Update registration</div>
+
  </span>
+
  <span slot="subtitle">
+
    {#if state.status === Status.Signing}
+
      <p>Please confirm the transaction in your wallet</p>
+
    {:else if state.status === Status.Pending}
+
      <p>Transaction is being processed by the network...</p>
+
    {:else if state.status === Status.Success}
+
      <p>Your registration was successfully updated.</p>
+
    {:else if state.status === Status.Failed}
+
      <p class="error">
+
        <strong>Error:</strong> {state.error}
+
      </p>
+
    {/if}
+
  </span>
+
  <span slot="actions">
+
    {#if [Status.Signing, Status.Pending].includes(state.status)}
+
      <Loading center small />
+
    {:else if state.status === Status.Success}
+
      <button on:click={onDone}>
+
        Done
+
      </button>
+
    {:else if state.status === Status.Failed}
+
      <button on:click={onClose}>
+
        Close
+
      </button>
+
    {/if}
+
  </span>
+
</Modal>
modified src/base/registrations/View.svelte
@@ -1,8 +1,6 @@
<script lang="typescript">
-
  import { getRegistration } from './registrar';
-
  import { setRecords } from './resolver';
-
  import type { EnsRecord } from './resolver';
-
  import type { Registration } from './registrar';
+
  import { onMount } from 'svelte';
+
  import { navigate } from 'svelte-routing';
  import type { Config } from '@app/config';
  import { session } from '@app/session';
  import Loading from '@app/Loading.svelte';
@@ -11,72 +9,72 @@
  import Form from '@app/Form.svelte';
  import type { Field } from '@app/Form.svelte';
  import { assert } from '@app/error';
+
  import Error from '@app/Error.svelte';
+

+
  import { getRegistration } from './registrar';
+
  import type { EnsRecord } from './resolver';
+
  import type { Registration } from './registrar';
+
  import Update from './Update.svelte';

-
  enum State {
-
    Idle,
-
    Signing,
-
    Pending,
-
    Success,
+
  enum Status {
+
    Loading,
+
    Found,
+
    NotFound,
    Failed,
  }

+
  type State =
+
      { status: Status.Loading }
+
    | { status: Status.NotFound }
+
    | { status: Status.Found, registration: Registration }
+
    | { status: Status.Failed, error: string };
+

  export let subdomain: string;
  export let config: Config;

-
  let state = State.Idle;
+
  let state: State = { status: Status.Loading };
  let editable = false;
  let fields: Field[] = [];
-
  let registration: Registration | null = null;
  let name = `${subdomain}.${config.registrar.domain}`;
+
  let updateRecords: EnsRecord[] | null = null;

-
  // TODO: Handle failure (network error)
-
  const loadRegistration = getRegistration(name, config)
-
    .then(r => {
-
      if (r) {
-
        fields = [
-
          { name: "owner", placeholder: "",
-
            value: r.owner, editable: false },
-
          { name: "address", placeholder: "Not set",
-
            value: r.address, editable: true },
-
          { name: "url", label: "URL", placeholder: "Not set",
-
            value: r.url, editable: true },
-
          { name: "avatar", placeholder: "Not set",
-
            value: r.avatar, editable: true },
-
          { name: "twitter", placeholder: "Not set",
-
            value: r.twitter, editable: true },
-
          { name: "github", placeholder: "Not set",
-
            value: r.github, editable: true },
-
        ];
-
        registration = r;
-
      }
-
      return r;
+
  onMount(() => {
+
    getRegistration(name, config)
+
      .then(r => {
+
        if (r) {
+
          fields = [
+
            { name: "owner", placeholder: "",
+
              value: r.owner, editable: false },
+
            { name: "address", placeholder: "Not set",
+
              value: r.address, editable: true },
+
            { name: "url", label: "URL", placeholder: "Not set",
+
              value: r.url, editable: true },
+
            { name: "avatar", placeholder: "Not set",
+
              value: r.avatar, editable: true },
+
            { name: "twitter", placeholder: "Not set",
+
              value: r.twitter, editable: true },
+
            { name: "github", placeholder: "Not set",
+
              value: r.github, editable: true },
+
          ];
+
          state = { status: Status.Found, registration: r };
+
        } else {
+
          state = { status: Status.NotFound };
+
        }
+
        return r;
+
      }).catch(err => {
+
        state = { status: Status.Failed, error: err };
+
      });
    });

-
  const save = async (event: { detail: Field[] }) => {
-
    assert(registration, "registration was found");
+
  const onSave = async (event: { detail: Field[] }) => {
+
    assert(state.status === Status.Found, "registration must be found");

-
    const recs: EnsRecord[] = event.detail
+
    updateRecords = event.detail
      .filter(r => r.editable && r.value !== null)
      .map(f => {
        assert(f.value !== null);
        return { name: f.name, value: f.value }
      });
-

-
    try {
-
      state = State.Signing;
-
      const tx = await setRecords(subdomain, recs, registration.resolver, config);
-
      state = State.Pending;
-
      await tx.wait();
-
      state = State.Success;
-
    } catch (e) {
-
      console.error(e);
-
      state = State.Failed;
-
    }
-
  };
-

-
  const done = () => {
-
    // Reload page to load updates to the registration.
-
    location.reload();
  };

  $: isOwner = (registration: Registration): boolean => {
@@ -96,64 +94,44 @@
  }
</style>

-
{#await loadRegistration}
+
{#if state.status === Status.Loading}
  <Loading fadeIn />
-
{:then registration}
-
  {#if registration}
-
    {#if state === State.Idle}
-
      <main>
-
        <header>
-
          <h1 class="bold">{subdomain}.{config.registrar.domain}</h1>
-
          <button
-
            class="tiny primary" class:active={editable} disabled={!isOwner(registration)}
-
            on:click={() => editable = !editable}>
-
              Edit
-
          </button>
-
          <button class="tiny secondary" disabled={!isOwner(registration)}>
-
            Transfer
-
          </button>
-
        </header>
-
        <Form {editable} {fields} on:save={save} on:cancel={() => editable = false} />
-
      </main>
-
    {:else}
-
      <Modal floating>
-
        <span slot="title">
-
          <div>🧾</div>
-
          <div>Update registration</div>
-
        </span>
-
        <span slot="subtitle">
-
          {#if state === State.Signing}
-
            <p>Please confirm the transaction in your wallet</p>
-
          {:else if state === State.Pending}
-
            <p>Transaction is being processed by the network...</p>
-
          {:else if state === State.Success}
-
            <p>Your registration was successfully updated.</p>
-
          {/if}
-
        </span>
-
        <span slot="actions">
-
          {#if [State.Signing, State.Pending].includes(state)}
-
            <Loading center small />
-
          {:else if state === State.Success}
-
            <button on:click={done}>
-
              Done
-
            </button>
-
          {/if}
-
        </span>
-
      </Modal>
-
    {/if}
-
  {:else}
-
    <Modal subtle>
-
      <span slot="title">
-
        {subdomain}.{config.registrar.domain}
-
      </span>
+
{:else if state.status === Status.Failed}
+
  <Error title="Registration could not be loaded" on:close={() => navigate('/registrations')}>
+
    {state.error}
+
  </Error>
+
{:else if state.status === Status.NotFound}
+
  <Modal subtle>
+
    <span slot="title">
+
      {subdomain}.{config.registrar.domain}
+
    </span>
+

+
    <span slot="body">
+
      <p>The name <strong>{subdomain}</strong> is not registered.</p>
+
    </span>

-
      <span slot="body">
-
        <p>The name <strong>{subdomain}</strong> is not registered.</p>
-
      </span>
+
    <span slot="actions">
+
      <Link to={`/registrations/${subdomain}/form`} primary>Register &rarr;</Link>
+
    </span>
+
  </Modal>
+
{:else if state.status === Status.Found}
+
  <main>
+
    <header>
+
      <h1 class="bold">{subdomain}.{config.registrar.domain}</h1>
+
      <button
+
        class="tiny primary" class:active={editable} disabled={!isOwner(state.registration)}
+
        on:click={() => editable = !editable}>
+
          Edit
+
      </button>
+
      <button class="tiny secondary" disabled={!isOwner(state.registration)}>
+
        Transfer
+
      </button>
+
    </header>
+
    <Form {editable} {fields} on:save={onSave} on:cancel={() => editable = false} />
+
  </main>

-
      <span slot="actions">
-
        <Link to={`/registrations/${subdomain}/form`} primary>Register &rarr;</Link>
-
      </span>
-
    </Modal>
+
  {#if updateRecords}
+
    <Update {config} {subdomain} on:close={() => updateRecords = null}
+
            registration={state.registration} records={updateRecords} />
  {/if}
-
{/await}
+
{/if}