From 57d69454e37ec929871166a45d41efafffc4ca46 Mon Sep 17 00:00:00 2001 From: eti Date: Thu, 24 Sep 2026 17:43:28 +0200 Subject: [PATCH] web/repo: delete custom labels from repo settings Signed-off-by: eti --- web/src/lib/api/labels.ts | 18 ++++++- .../settings/RepoGeneralForm.svelte | 53 ++++++++++++++++++- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/web/src/lib/api/labels.ts b/web/src/lib/api/labels.ts index 31a9e06b8..1028fce83 100644 --- a/web/src/lib/api/labels.ts +++ b/web/src/lib/api/labels.ts @@ -1,7 +1,7 @@ import type { Datetime, Nsid, ResourceUri } from "@atcute/lexicons/syntax"; import { now as tidNow } from "@atcute/tid"; import type { OAuthUserAgent } from "@atcute/oauth-browser-client"; -import { awaitIndexedOrSaved } from "$lib/api/awaitRecord"; +import { awaitDeletedRecord, awaitIndexedOrSaved } from "$lib/api/awaitRecord"; import { createBobbinClient, type BobbinContext, type XrpcRequestInit } from "$lib/api/client"; import type * as ShTangledLabelDefinition from "$lib/api/lexicons/types/sh/tangled/label/definition"; import { collect } from "$lib/api/pagination"; @@ -91,3 +91,19 @@ export const createRepoLabel = async ( export const deleteLabelDefinition = (agent: OAuthUserAgent, uri: string): Promise => deleteRecord(agent, LABEL_DEFINITION_COLLECTION, rkeyFromUri(uri)); + +export const deleteRepoLabel = async ( + agent: OAuthUserAgent, + bobbinUrl: string, + repo: RecordView, + uri: string +): Promise => { + const labels: readonly string[] = repo.value.labels ?? []; + if (labels.includes(uri)) { + await saveRepoRecord(agent, bobbinUrl, repo, { + labels: labels.filter((candidate) => candidate !== uri) + }); + } + await deleteLabelDefinition(agent, uri); + await awaitDeletedRecord(createBobbinClient({ serviceUrl: bobbinUrl }), uri as ResourceUri); +}; diff --git a/web/src/lib/components/settings/RepoGeneralForm.svelte b/web/src/lib/components/settings/RepoGeneralForm.svelte index fe1eeb9a0..3655702e7 100644 --- a/web/src/lib/components/settings/RepoGeneralForm.svelte +++ b/web/src/lib/components/settings/RepoGeneralForm.svelte @@ -3,12 +3,18 @@ import { resolve } from "$app/paths"; import { SvelteSet } from "svelte/reactivity"; import { createAction } from "$lib/action.svelte"; - import { isBasicLabel, type LabelDefinition, type LabelView } from "$lib/api/labels"; + import { + deleteRepoLabel, + isBasicLabel, + type LabelDefinition, + type LabelView + } from "$lib/api/labels"; import type { RecordView, RepoRecord } from "$lib/api/records"; import { deleteRepo, saveRepoRecord, setDefaultBranch } from "$lib/api/repoSettings"; import { getAuth } from "$lib/auth.svelte"; import type { RepoInfo } from "$lib/components/repo/types"; 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 Input from "$lib/components/ui/Input.svelte"; import type { InputTag } from "$lib/components/ui/inputField"; @@ -119,6 +125,28 @@ } }); + let labelPendingDelete = $state(null); + let labelDeleteOpen = $state(false); + const confirmLabelDelete = (label: LabelView) => { + labelPendingDelete = label; + labelDeleteOpen = true; + }; + const removeLabel = createAction(async (label: LabelView) => { + const agent = auth.agent; + if (!agent) return; + try { + await deleteRepoLabel(agent, bobbinUrl, record, label.uri); + form.labels.delete(label.uri); + } finally { + await invalidateAll(); + } + }); + const removePendingLabel = async () => { + if (!labelPendingDelete) return; + await removeLabel.run(labelPendingDelete); + if (!removeLabel.error) labelDeleteOpen = false; + }; + let confirmDelete = $state(false); let confirmName = $state(""); const destroy = createAction(async () => { @@ -187,7 +215,7 @@ {#if owner} - +
Add custom label {/snippet} + {#if labels.custom.length === 0} {:else} @@ -262,6 +291,15 @@ title={item.value.name} description={labelMeta(item.value)} > +
+ +