Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
3.7 kB · 131 lines
Svelte
at next-dev
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132<script lang="ts"> import { onMount } from "svelte"; import { getAuth } from "#lib/auth.svelte.ts"; import { missingPermissions } from "#lib/auth/scopes.ts"; import { ATTESTATION_COLLECTION, dismissAttestations, failedAttestations, flushAttestations, pendingAttestations, type PendingAttestation } from "#lib/api/attestation.ts"; import { didOf } from "#lib/api/syntax.ts"; import Button from "#lib/components/ui/Button.svelte";
const auth = getAuth();
let pending = $state<readonly PendingAttestation[]>([]); let failure = $state<string | null>(null); let retrying = $state(false);
const ungranted = $derived( auth?.agent ? missingPermissions(auth.agent.session.token.scope, [ { resource: "repo", collection: ATTESTATION_COLLECTION, actions: ["create", "update"] } ]) : [] );
const queuedAccounts = () => (auth?.accounts ?? []).filter( (account) => pendingAttestations(didOf(account.did)).length > 0 );
const refresh = () => { pending = queuedAccounts().flatMap((account) => failedAttestations(didOf(account.did))); }; const messageOf = (cause: unknown): string => cause instanceof Error ? cause.message : String(cause);
const retry = async () => { if (!auth?.currentUser || retrying) return; retrying = true; failure = null; try { const failures = ( await Promise.all( queuedAccounts().map(async (account) => { const who = auth.accounts.find((one) => one.did === account.did)?.handle ?? account.did; try { const agent = await auth.agentFor(account.did, { relogin: false }); return (await flushAttestations(agent)).map((one) => `${who}: ${one}`); } catch (cause) { return [`${who}: ${messageOf(cause)}`]; } }) ) ).flat(); failure = failures[0] ?? null; } finally { retrying = false; refresh(); } };
const reauthorize = async () => { const did = auth?.currentDid; if (!did || retrying) return; retrying = true; try { await auth?.signIn(did, location.pathname + location.search + location.hash); } catch { retrying = false; } };
$effect(() => { if (!auth?.currentUser) return; refresh(); if (queuedAccounts().length > 0) void retry(); });
onMount(() => { const onChange = () => refresh(); window.addEventListener("tangled:attestations", onChange); window.addEventListener("storage", onChange); return () => { window.removeEventListener("tangled:attestations", onChange); window.removeEventListener("storage", onChange); }; });
const dismiss = () => { queuedAccounts().forEach((account) => dismissAttestations(didOf(account.did))); failure = null; refresh(); };</script>
{#if pending.length > 0} <div class="flex flex-wrap items-center justify-center gap-xs border-b border-border-warning bg-background-subtle px-md py-2xs" role="status" > <span class="typography-paragraph-small text-foreground-default"> {pending.length} {pending.length === 1 ? "contribution isn't" : "contributions aren't"} attested on your PDS yet. </span> {#if failure} <span class="typography-paragraph-small text-foreground-danger">{failure}</span> {/if} {#if ungranted.length > 0} <Button size="small" loading={retrying} onclick={() => void reauthorize()}> Sign in again </Button> <span class="typography-paragraph-small text-foreground-muted"> Attestations were added after you signed in. </span> {:else} <Button size="small" loading={retrying} onclick={() => void retry()}>Retry</Button> {/if} <Button size="small" variant="default" onclick={dismiss}>Dismiss</Button> </div>{/if}