From 08fb846b15a8a8ea438a021ecaa5ac594d926948 Mon Sep 17 00:00:00 2001 From: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> Date: Mon, 12 Oct 2026 12:19:20 +0800 Subject: [PATCH] fix(namespace): keep invitation labels unique and copy promptly Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> --- .../features/namespace/invitation-controls.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/web/src/features/namespace/invitation-controls.tsx b/web/src/features/namespace/invitation-controls.tsx index fc014371..e5659799 100644 --- a/web/src/features/namespace/invitation-controls.tsx +++ b/web/src/features/namespace/invitation-controls.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { useId, useState } from 'react' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useTranslation } from 'react-i18next' import { getAppBaseUrl, namespaceApi } from '@/api/client' @@ -12,22 +12,24 @@ import { Input } from '@/shared/ui/input' export function InvitationControls({ slug, compact = false }: { slug: string; compact?: boolean }) { const { t } = useTranslation() + const linkId = useId() const queryClient = useQueryClient() const [confirm, setConfirm] = useState<'replace' | 'revoke' | null>(null) const [link, setLink] = useState(null) const status = useQuery({ queryKey: ['namespace-invitation-status', slug], queryFn: () => namespaceApi.invitationStatus(slug), enabled: !compact }) const create = useMutation({ mutationFn: (replace: boolean) => namespaceApi.createInvitation(slug, replace), - onSuccess: async ({ token, replaced }) => { - await queryClient.invalidateQueries({ queryKey: ['namespace-invitation-status', slug] }) + onSuccess: ({ token, replaced }) => { const url = invitationUrl(resolvePublicRegistryUrl(getAppBaseUrl(), window.location.origin, BASE_PATH), token) setLink(url) try { - await navigator.clipboard.writeText(url) - toast.success(t(replaced ? 'invitation.replacedCopied' : 'invitation.copied')) + void navigator.clipboard.writeText(url) + .then(() => toast.success(t(replaced ? 'invitation.replacedCopied' : 'invitation.copied'))) + .catch(() => toast.info(t('invitation.manualCopy'))) } catch { toast.info(t('invitation.manualCopy')) } + void queryClient.invalidateQueries({ queryKey: ['namespace-invitation-status', slug] }) }, }) const revoke = useMutation({ @@ -51,8 +53,8 @@ export function InvitationControls({ slug, compact = false }: { slug: string; co {link ? (
- - event.currentTarget.select()} /> + + event.currentTarget.select()} />

{t('invitation.linkHint')}

) : null}