Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export default function QuotaSharePageClient() {
const [apiKeys, setApiKeys] = useState<ApiKey[]>([]);
const [plans, setPlans] = useState<Record<string, PlanInfo>>({});
const [createOpen, setCreateOpen] = useState(false);
const [removeError, setRemoveError] = useState<string | null>(null);
const [editing, setEditing] = useState<QuotaPool | null>(null);

// ── Group state ───────────────────────────────────────────────────────────
Expand Down Expand Up @@ -376,10 +377,31 @@ export default function QuotaSharePageClient() {

// ── Mutations ─────────────────────────────────────────────────────────────

/**
* A failed delete must never look like a click that did nothing. Without the
* response check the page just revalidated and left the card in place, so a
* 401 from an expired session, a 500 or a dropped request were all
* indistinguishable from "I misclicked" — and the operator would click again.
*/
const handleRemovePool = useCallback(
async (id: string) => {
if (!confirm(t("removeConfirm"))) return;
await fetch(`/api/quota/pools/${id}`, { method: "DELETE" });
setRemoveError(null);
try {
const res = await fetch(`/api/quota/pools/${id}`, { method: "DELETE" });
if (!res.ok) {
const detail = await res
.json()
.then((b) => b?.error?.message || b?.error || b?.message)
.catch(() => null);
setRemoveError(detail ? `${t("removeFailed")} — ${detail}` : t("removeFailed"));
return;
}
} catch {
// Network-level failure: there is no response to read.
setRemoveError(t("removeFailed"));
return;
}
await mutate();
},
[mutate, t]
Expand All @@ -389,6 +411,25 @@ export default function QuotaSharePageClient() {

return (
<div className="flex flex-col gap-4">
{/* Falha ao remover: dispensável, mas nunca silenciosa. */}
{removeError && (
<div
role="alert"
className="flex items-start gap-2 rounded-lg border border-red-500/40 bg-red-500/10 px-3 py-2 text-[12px] text-red-700 dark:text-red-200"
>
<span className="material-symbols-outlined text-[16px] text-red-500 shrink-0">error</span>
<span className="flex-1">{removeError}</span>
<button
type="button"
onClick={() => setRemoveError(null)}
aria-label={t("dismiss")}
className="shrink-0 text-red-500 hover:text-red-400 cursor-pointer"
>
<span className="material-symbols-outlined text-[16px]">close</span>
</button>
</div>
)}

{/* Header */}
<div className="flex items-start justify-between flex-wrap gap-3">
<div>
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "هل تريد حذف هذه المجموعة؟ يجب إعادة تعيين مجمعاتها أو إزالتها أولاً.",
"deleteGroupHasPools": "لا تزال هذه المجموعة تحتوي على مجمعات — أعد تعيينها أو احذفها أولاً.",
"ungroupedTitle": "غير مجمع",
"ungroupedHint": "هذه المجمعات غير مخصصة لمجموعة معروفة. قم بتحرير مجمع لنقله إلى مجموعة حقيقية."
"ungroupedHint": "هذه المجمعات غير مخصصة لمجموعة معروفة. قم بتحرير مجمع لنقله إلى مجموعة حقيقية.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "الإضافات",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/az.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "Bu qrup silinsin? İlk öncə onun hovuzları yenidən təyin edilməli və ya silinməlidir.",
"deleteGroupHasPools": "Bu qrupda hələ də hovuzlar var — ilk öncə onları yenidən təyin edin və ya silin.",
"ungroupedTitle": "Qruplaşdırılmamış",
"ungroupedHint": "Bu hovuzlar məlum bir qrupa təyin edilməyib. Hovuzu real qrupa köçürmək üçün onu redaktə edin."
"ungroupedHint": "Bu hovuzlar məlum bir qrupa təyin edilməyib. Hovuzu real qrupa köçürmək üçün onu redaktə edin.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/bg.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "Изтриване на тази група? Нейните пулове трябва първо да бъдат преназначени или премахнати.",
"deleteGroupHasPools": "Тази група все още има пулове — първо ги преназначете или изтрийте.",
"ungroupedTitle": "Негрупирани",
"ungroupedHint": "Тези пулове не са присвоени към позната група. Редактирайте пул, за да го преместите в реална група."
"ungroupedHint": "Тези пулове не са присвоени към позната група. Редактирайте пул, за да го преместите в реална група.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/bn.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "এই গ্রুপটি মুছবেন? এর পুলগুলো প্রথমে পুনরায় বরাদ্দ বা অপসারণ করতে হবে।",
"deleteGroupHasPools": "এই গ্রুপে এখনও পুল রয়েছে — প্রথমে সেগুলো পুনরায় বরাদ্দ করুন বা মুছুন।",
"ungroupedTitle": "গ্রুপবিহীন",
"ungroupedHint": "এই পুলগুলো কোনো পরিচিত গ্রুপে বরাদ্দ করা নেই। একটি পুলকে কোনো বাস্তব গ্রুপে স্থানান্তর করতে সেটি সম্পাদনা করুন।"
"ungroupedHint": "এই পুলগুলো কোনো পরিচিত গ্রুপে বরাদ্দ করা নেই। একটি পুলকে কোনো বাস্তব গ্রুপে স্থানান্তর করতে সেটি সম্পাদনা করুন।",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "Smazat tuto skupinu? Její pooly musí být nejprve znovu přiřazeny nebo odstraněny.",
"deleteGroupHasPools": "Tato skupina stále obsahuje pooly — nejprve je znovu přiřaďte nebo smažte.",
"ungroupedTitle": "Bez skupiny",
"ungroupedHint": "Tyto pooly nejsou přiřazeny k žádné známé skupině. Upravte pool a přesuňte jej do skutečné skupiny."
"ungroupedHint": "Tyto pooly nejsou přiřazeny k žádné známé skupině. Upravte pool a přesuňte jej do skutečné skupiny.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/da.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "Slet denne gruppe? Dens puljer skal tildeles igen eller fjernes først.",
"deleteGroupHasPools": "Denne gruppe har stadig puljer — tildel dem igen eller slet dem først.",
"ungroupedTitle": "Ikke grupperet",
"ungroupedHint": "Disse puljer er ikke tildelt en kendt gruppe. Rediger en pulje for at flytte den til en rigtig gruppe."
"ungroupedHint": "Disse puljer er ikke tildelt en kendt gruppe. Rediger en pulje for at flytte den til en rigtig gruppe.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "Diese Gruppe löschen? Ihre Pools müssen zuerst neu zugewiesen oder entfernt werden.",
"deleteGroupHasPools": "Diese Gruppe enthält noch Pools — weisen Sie diese zuerst neu zu oder löschen Sie sie.",
"ungroupedTitle": "Nicht gruppiert",
"ungroupedHint": "Diese Pools sind keiner bekannten Gruppe zugewiesen. Bearbeiten Sie einen Pool, um ihn in eine echte Gruppe zu verschieben."
"ungroupedHint": "Diese Pools sind keiner bekannten Gruppe zugewiesen. Bearbeiten Sie einen Pool, um ihn in eine echte Gruppe zu verschieben.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -10544,7 +10544,9 @@
"deleteGroupConfirm": "Delete this group? Its pools must be reassigned or removed first.",
"deleteGroupHasPools": "This group still has pools — reassign or delete them first.",
"ungroupedTitle": "Ungrouped",
"ungroupedHint": "These pools are not assigned to a known group. Edit a pool to move it into a real group."
"ungroupedHint": "These pools are not assigned to a known group. Edit a pool to move it into a real group.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "Delete this group? Its pools must be reassigned or removed first.",
"deleteGroupHasPools": "This group still has pools — reassign or delete them first.",
"ungroupedTitle": "Ungrouped",
"ungroupedHint": "These pools are not assigned to a known group. Edit a pool to move it into a real group."
"ungroupedHint": "These pools are not assigned to a known group. Edit a pool to move it into a real group.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/fa.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "این گروه حذف شود؟ استخرهای آن ابتدا باید دوباره تخصیص داده شوند یا حذف شوند.",
"deleteGroupHasPools": "این گروه هنوز دارای استخر است — ابتدا آن‌ها را دوباره تخصیص دهید یا حذف کنید.",
"ungroupedTitle": "گروه‌بندی‌نشده",
"ungroupedHint": "این استخرها به هیچ گروه شناخته‌شده‌ای تخصیص داده نشده‌اند. یک استخر را ویرایش کنید تا آن را به یک گروه واقعی منتقل کنید."
"ungroupedHint": "این استخرها به هیچ گروه شناخته‌شده‌ای تخصیص داده نشده‌اند. یک استخر را ویرایش کنید تا آن را به یک گروه واقعی منتقل کنید.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "Poistetaanko tämä ryhmä? Sen poolit on ensin määritettävä uudelleen tai poistettava.",
"deleteGroupHasPools": "Tässä ryhmässä on vielä pooleja — määritä ne uudelleen tai poista ne ensin.",
"ungroupedTitle": "Ryhmittelemättömät",
"ungroupedHint": "Näitä pooleja ei ole määritetty tunnettuun ryhmään. Muokkaa poolia siirtääksesi sen oikeaan ryhmään."
"ungroupedHint": "Näitä pooleja ei ole määritetty tunnettuun ryhmään. Muokkaa poolia siirtääksesi sen oikeaan ryhmään.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "Supprimer ce groupe ? Ses pools doivent d'abord être réassignés ou supprimés.",
"deleteGroupHasPools": "Ce groupe contient encore des pools — réassignez-les ou supprimez-les d'abord.",
"ungroupedTitle": "Sans groupe",
"ungroupedHint": "Ces pools ne sont pas assignés à un groupe connu. Modifiez un pool pour le déplacer dans un vrai groupe."
"ungroupedHint": "Ces pools ne sont pas assignés à un groupe connu. Modifiez un pool pour le déplacer dans un vrai groupe.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/gu.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "આ ગ્રૂપ કાઢી નાખવું છે? તેના પૂલ પહેલા ફરીથી સોંપવા અથવા દૂર કરવા આવશ્યક છે.",
"deleteGroupHasPools": "આ ગ્રૂપમાં હજી પણ પૂલ છે — પહેલા તેમને ફરીથી સોંપો અથવા કાઢી નાખો.",
"ungroupedTitle": "અનગ્રૂપ કરેલ",
"ungroupedHint": "આ પૂલ કોઈ જાણીતા ગ્રૂપમાં સોંપાયેલ નથી. પૂલને વાસ્તવિક ગ્રૂપમાં ખસેડવા માટે તેને સંપાદિત કરો."
"ungroupedHint": "આ પૂલ કોઈ જાણીતા ગ્રૂપમાં સોંપાયેલ નથી. પૂલને વાસ્તવિક ગ્રૂપમાં ખસેડવા માટે તેને સંપાદિત કરો.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/he.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "למחוק קבוצה זו? יש להקצות מחדש או להסיר את הבריכות שלה תחילה.",
"deleteGroupHasPools": "קבוצה זו עדיין מכילה בריכות — הקצה מחדש או מחק אותן תחילה.",
"ungroupedTitle": "ללא קבוצה",
"ungroupedHint": "בריכות אלו אינן משויכות לקבוצה מוכרת. ערוך בריכה כדי להעביר אותה לקבוצה אמיתית."
"ungroupedHint": "בריכות אלו אינן משויכות לקבוצה מוכרת. ערוך בריכה כדי להעביר אותה לקבוצה אמיתית.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/hi.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "इस समूह को हटाएं? इसके पूल को पहले पुन: असाइन या हटाया जाना चाहिए।",
"deleteGroupHasPools": "इस समूह में अभी भी पूल हैं — पहले उन्हें पुन: असाइन करें या हटाएं।",
"ungroupedTitle": "बिना समूह वाले",
"ungroupedHint": "ये पूल किसी ज्ञात समूह को असाइन नहीं किए गए हैं। किसी पूल को वास्तविक समूह में ले जाने के लिए उसे संपादित करें।"
"ungroupedHint": "ये पूल किसी ज्ञात समूह को असाइन नहीं किए गए हैं। किसी पूल को वास्तविक समूह में ले जाने के लिए उसे संपादित करें।",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/hu.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "Törlöd ezt a csoportot? A pooljait előbb át kell rendelni vagy el kell távolítani.",
"deleteGroupHasPools": "Ez a csoport még tartalmaz poolokat — előbb rendeld át vagy töröld őket.",
"ungroupedTitle": "Csoportosítatlan",
"ungroupedHint": "Ezek a poolok nincsenek ismert csoporthoz rendelve. Szerkessz egy poolt, hogy áthelyezd egy valódi csoportba."
"ungroupedHint": "Ezek a poolok nincsenek ismert csoporthoz rendelve. Szerkessz egy poolt, hogy áthelyezd egy valódi csoportba.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/id.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "Hapus grup ini? Pool di dalamnya harus dialihkan atau dihapus terlebih dahulu.",
"deleteGroupHasPools": "Grup ini masih memiliki pool — alihkan atau hapus terlebih dahulu.",
"ungroupedTitle": "Tanpa Grup",
"ungroupedHint": "Pool ini tidak ditetapkan ke grup yang dikenal. Edit pool untuk memindahkannya ke grup yang sebenarnya."
"ungroupedHint": "Pool ini tidak ditetapkan ke grup yang dikenal. Edit pool untuk memindahkannya ke grup yang sebenarnya.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/in.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "Hapus grup ini? Pool di dalamnya harus dialihkan atau dihapus terlebih dahulu.",
"deleteGroupHasPools": "Grup ini masih memiliki pool — alihkan atau hapus terlebih dahulu.",
"ungroupedTitle": "Tanpa grup",
"ungroupedHint": "Pool ini tidak ditetapkan ke grup yang dikenal. Edit pool untuk memindahkannya ke grup yang sebenarnya."
"ungroupedHint": "Pool ini tidak ditetapkan ke grup yang dikenal. Edit pool untuk memindahkannya ke grup yang sebenarnya.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "Eliminare questo gruppo? I suoi pool devono prima essere riassegnati o rimossi.",
"deleteGroupHasPools": "Questo gruppo ha ancora dei pool — riassegnali o eliminali prima.",
"ungroupedTitle": "Non raggruppati",
"ungroupedHint": "Questi pool non sono assegnati a un gruppo noto. Modifica un pool per spostarlo in un gruppo reale."
"ungroupedHint": "Questi pool non sono assegnati a un gruppo noto. Modifica un pool per spostarlo in un gruppo reale.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "このグループを削除しますか?先にプールを再割り当てするか削除する必要があります。",
"deleteGroupHasPools": "このグループにはまだプールがあります — 先に再割り当てするか削除してください。",
"ungroupedTitle": "未グループ化",
"ungroupedHint": "これらのプールは既知のグループに割り当てられていません。プールを編集して実際のグループに移動してください。"
"ungroupedHint": "これらのプールは既知のグループに割り当てられていません。プールを編集して実際のグループに移動してください。",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/messages/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -10522,7 +10522,9 @@
"deleteGroupConfirm": "이 그룹을 삭제하시겠습니까? 먼저 해당 그룹의 풀을 재할당하거나 제거해야 합니다.",
"deleteGroupHasPools": "이 그룹에 아직 풀이 있습니다. 먼저 재할당하거나 삭제하세요.",
"ungroupedTitle": "그룹 없음",
"ungroupedHint": "이 풀들은 알려진 그룹에 할당되지 않았습니다. 풀을 편집하여 실제 그룹으로 이동하세요."
"ungroupedHint": "이 풀들은 알려진 그룹에 할당되지 않았습니다. 풀을 편집하여 실제 그룹으로 이동하세요.",
"removeFailed": "Could not remove this pool.",
"dismiss": "Dismiss"
},
"plugins": {
"title": "Plugins",
Expand Down
Loading
Loading