Something went wrong. Try again.
Monorepo for Tangled forked from tangled.org/core
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192<script module lang="ts"> export interface WelcomeKey { rkey: string; name: string; fingerprint?: string; createdAt: string; }</script>
<script lang="ts"> import Plus from "$icon/plus"; import Trash from "$icon/trash-2"; import KeyIcon from "$icon/key"; import X from "$icon/x"; import Button from "#lib/components/ui/Button.svelte"; import ConfirmModal from "#lib/components/ui/ConfirmModal.svelte"; import ErrorAlert from "#lib/components/ui/Error.svelte"; import Field from "#lib/components/ui/Field.svelte"; import Input from "#lib/components/ui/Input.svelte"; import Textarea from "#lib/components/ui/Textarea.svelte"; import TimeAgo from "#lib/components/ui/TimeAgo.svelte"; import SettingsEmpty from "#lib/components/settings/SettingsEmpty.svelte"; import SettingsList from "#lib/components/settings/SettingsList.svelte"; import SettingsRow from "#lib/components/settings/SettingsRow.svelte"; import SettingsToolbar from "#lib/components/settings/SettingsToolbar.svelte"; import StepHeader from "#lib/components/welcome/StepHeader.svelte";
let { keys, onAdd, onDelete }: { keys: WelcomeKey[]; onAdd: (name: string, key: string) => Promise<void>; onDelete: (rkey: string) => Promise<void>; } = $props();
let formOpen = $state(false); let name = $state(""); let key = $state(""); let adding = $state(false); let deleting = $state<string>(); let error = $state<string>(); let pendingDelete = $state<WelcomeKey>(); let confirmOpen = $state(false);
const canAdd = $derived(name.trim() !== "" && key.trim() !== "");
const closeForm = () => { formOpen = false; name = ""; key = ""; };
const add = async (event: SubmitEvent) => { event.preventDefault(); if (!canAdd || adding) return; adding = true; error = undefined; try { await onAdd(name.trim(), key.trim()); closeForm(); } catch (cause) { error = cause instanceof Error ? cause.message : "Could not add key. Try again."; } finally { adding = false; } };
const requestDelete = (pubkey: WelcomeKey) => { if (deleting) return; pendingDelete = pubkey; confirmOpen = true; };
const remove = async () => { if (!pendingDelete || deleting) return; const pubkey = pendingDelete; deleting = pubkey.rkey; error = undefined; try { await onDelete(pubkey.rkey); } catch (cause) { error = cause instanceof Error ? cause.message : "Could not delete key. Try again."; } finally { deleting = undefined; confirmOpen = false; pendingDelete = undefined; } };</script>
<div class="flex flex-col gap-xl"> <StepHeader title="Add SSH keys" subtitle="Add a public SSH key to push to your repositories over SSH." />
<div class="flex w-full flex-col gap-md"> <SettingsToolbar> {#snippet end()} {#if !formOpen} <Button icon={Plus} onclick={() => (formOpen = true)}>Add key</Button> {/if} {/snippet} </SettingsToolbar>
{#if formOpen} <form class="flex flex-col gap-md rounded-md border border-border-default bg-background-subtle p-xs" onsubmit={add} > <Field label="Key name" labelCase="normal"> {#snippet children({ id })} <Input {id} placeholder="my-laptop" required bind:value={name} /> {/snippet} </Field>
<Field label="Public key" labelCase="normal"> {#snippet children({ id })} <Textarea {id} size="small" rows={3} required placeholder="ssh-ed25519 AAAA..." bind:value={key} /> {/snippet} </Field>
<div class="flex items-center justify-end gap-2"> <Button variant="ghost" icon={X} disabled={adding} onclick={closeForm}> Cancel </Button> <Button type="submit" variant={canAdd ? "primary" : "default"} icon={Plus} disabled={!canAdd} loading={adding} > Add key </Button> </div> </form> {/if}
<ErrorAlert label={error} />
{#if keys.length === 0} <SettingsEmpty message="No keys added yet" /> {:else} <SettingsList> {#each keys as pubkey (pubkey.rkey)} <SettingsRow icon={KeyIcon} title={pubkey.name} stack> {#snippet meta()} {#if pubkey.fingerprint} <span class="typography-monospace-regular break-all text-foreground-muted" > {pubkey.fingerprint} </span> {/if} <span class="typography-paragraph-regular text-foreground-muted"> added <TimeAgo value={pubkey.createdAt} variant="full" /> </span> {/snippet} <Button variant="danger" icon={Trash} loading={deleting === pubkey.rkey} onclick={() => requestDelete(pubkey)} > Delete </Button> </SettingsRow> {/each} </SettingsList> {/if} </div></div>
<ConfirmModal bind:open={confirmOpen} title={`Delete ${pendingDelete?.name ?? "key"}?`} description="This removes the key from your account. You will need to add it again to push with it." confirmLabel="Delete key" loading={!!deleting} onconfirm={() => void remove()}/>