Skip to content

Commit a02499a

Browse files
snomiaoclaude
andauthored
feat: Add delete publisher functionality (#236)
* feat: Add delete publisher functionality with confirmation modal Added a dropdown menu next to the Edit details button on publisher detail pages with a delete option. The delete action triggers a confirmation modal that requires users to type the publisher ID to confirm deletion. Changes: - Created DeletePublisherModal component with confirmation input - Added dropdown menu with delete option to PublisherDetail component - Integrated useDeletePublisher hook from generated API - Added analytics tracking for delete publisher action - Redirects to /nodes page after successful deletion 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * format: Apply prettier --fix changes --------- Co-authored-by: Claude <[email protected]>
1 parent ae7c224 commit a02499a

File tree

13 files changed

+22102
-28350
lines changed

13 files changed

+22102
-28350
lines changed

bun.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"lockfileVersion": 1,
3+
"configVersion": 0,
34
"workspaces": {
45
"": {
56
"name": "comfy-org-registry-web",
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { useQueryClient } from '@tanstack/react-query'
2+
import { AxiosError } from 'axios'
3+
import { Button, Label, Modal, TextInput } from 'flowbite-react'
4+
import { useRouter } from 'next/router'
5+
import React, { useState } from 'react'
6+
import { toast } from 'react-toastify'
7+
import { customThemeTModal } from 'utils/comfyTheme'
8+
import { useDeletePublisher } from '@/src/api/generated'
9+
import { useNextTranslation } from '@/src/hooks/i18n'
10+
11+
type DeletePublisherModalProps = {
12+
openDeleteModal: boolean
13+
onClose: () => void
14+
publisherId: string
15+
}
16+
17+
export const DeletePublisherModal: React.FC<DeletePublisherModalProps> = ({
18+
openDeleteModal,
19+
onClose,
20+
publisherId,
21+
}) => {
22+
const { t } = useNextTranslation()
23+
const mutation = useDeletePublisher({})
24+
const router = useRouter()
25+
const qc = useQueryClient()
26+
const handleSubmit = async () => {
27+
return mutation.mutate(
28+
{
29+
publisherId: publisherId,
30+
},
31+
{
32+
onError: (error) => {
33+
if (error instanceof AxiosError) {
34+
toast.error(
35+
t(`Failed to delete publisher. {{message}}`, {
36+
message: error.response?.data?.message,
37+
})
38+
)
39+
} else {
40+
toast.error(t('Failed to delete publisher'))
41+
}
42+
},
43+
onSuccess: () => {
44+
toast.success(t('Publisher deleted successfully'))
45+
onClose()
46+
router.push('/nodes')
47+
},
48+
}
49+
)
50+
}
51+
52+
const validateText = publisherId
53+
const [confirmationText, setConfirmationText] = useState('')
54+
return (
55+
<Modal
56+
show={openDeleteModal}
57+
size="md"
58+
onClose={onClose}
59+
popup
60+
//@ts-ignore
61+
theme={customThemeTModal}
62+
dismissible
63+
>
64+
<Modal.Body className="!bg-gray-800 p-8 md:px-9 md:py-8 rounded-none">
65+
<Modal.Header className="!bg-gray-800">
66+
<p className="text-white">{t('Delete Publisher')}</p>
67+
</Modal.Header>
68+
<form
69+
className="space-y-6 p-2"
70+
onSubmit={async (e) => {
71+
e.preventDefault()
72+
await handleSubmit()
73+
}}
74+
>
75+
<p className="text-white">
76+
{t(
77+
'Are you sure you want to delete this publisher? This action cannot be undone.'
78+
)}
79+
</p>
80+
<div>
81+
<Label className="text-white">
82+
{t('Type')}{' '}
83+
<code className="text-red-300 inline">{validateText}</code>{' '}
84+
{t('to confirm')}:
85+
</Label>
86+
<TextInput
87+
className="input"
88+
name="confirmation"
89+
onChange={(e) => setConfirmationText(e.target.value)}
90+
/>
91+
</div>
92+
<div className="flex">
93+
<Button
94+
color="gray"
95+
className="w-full text-white bg-gray-800"
96+
onClick={onClose}
97+
>
98+
{t('Cancel')}
99+
</Button>
100+
<Button
101+
color="red"
102+
className="w-full ml-5"
103+
type="submit"
104+
disabled={validateText !== confirmationText}
105+
>
106+
{t('Delete')}
107+
</Button>
108+
</div>
109+
</form>
110+
</Modal.Body>
111+
</Modal>
112+
)
113+
}

components/publisher/PublisherDetail.tsx

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { Button } from 'flowbite-react'
1+
import { Button, Dropdown } from 'flowbite-react'
22
import { useRouter } from 'next/router'
33
import React, { useState } from 'react'
4+
import { HiDotsVertical } from 'react-icons/hi'
45
import { toast } from 'react-toastify'
56
import analytic from 'src/analytic/analytic'
67
import {
@@ -14,6 +15,7 @@ import {
1415
import { useNextTranslation } from '@/src/hooks/i18n'
1516
import { CreateSecretKeyModal } from '../AccessTokens/CreateSecretKeyModal'
1617
import PersonalAccessTokenTable from '../AccessTokens/PersonalAccessTokenTable'
18+
import { DeletePublisherModal } from '../publisher/DeletePublisherModal'
1719
import EditPublisherModal from '../publisher/EditPublisherModal'
1820
import PublisherNodes from './PublisherNodes'
1921
import PublisherStatusBadge from './PublisherStatusBadge'
@@ -38,6 +40,7 @@ const PublisherDetail: React.FC<PublisherDetailProps> = ({ publisher }) => {
3840
)
3941
const [openSecretKeyModal, setOpenSecretKeyModal] = useState(false)
4042
const [openEditModal, setOpenEditModal] = useState(false)
43+
const [openDeleteModal, setOpenDeleteModal] = useState(false)
4144

4245
const handleCreateButtonClick = () => {
4346
analytic.track('Create Publisher API Token Clicked')
@@ -76,6 +79,15 @@ const PublisherDetail: React.FC<PublisherDetailProps> = ({ publisher }) => {
7679
setOpenEditModal(false)
7780
}
7881

82+
const handleDeleteButtonClick = () => {
83+
analytic.track('Delete Publisher Clicked')
84+
setOpenDeleteModal(true)
85+
}
86+
87+
const onCloseDeleteModal = () => {
88+
setOpenDeleteModal(false)
89+
}
90+
7991
const oneMemberOfPublisher = getFirstMemberName(publisher)
8092

8193
if (publisher === undefined || publisher.id === undefined) {
@@ -118,31 +130,68 @@ const PublisherDetail: React.FC<PublisherDetailProps> = ({ publisher }) => {
118130
{publisher.name}
119131
</h1>
120132
{permissions?.canEdit && (
121-
<Button
122-
size="xs"
123-
className="h-8 p-2 px-4 font-bold text-white bg-blue-500 rounded hover:bg-blue-600"
124-
color="blue"
125-
onClick={handleEditButtonClick}
126-
>
127-
<svg
128-
className="w-5 h-5 text-white"
129-
aria-hidden="true"
130-
xmlns="http://www.w3.org/2000/svg"
131-
width="24"
132-
height="24"
133-
fill="none"
134-
viewBox="0 0 24 24"
133+
<div className="flex gap-2">
134+
<Button
135+
size="xs"
136+
className="h-8 p-2 px-4 font-bold text-white bg-blue-500 rounded hover:bg-blue-600"
137+
color="blue"
138+
onClick={handleEditButtonClick}
135139
>
136-
<path
137-
stroke="currentColor"
138-
strokeLinecap="round"
139-
strokeLinejoin="round"
140-
strokeWidth="2"
141-
d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"
142-
/>
143-
</svg>
144-
<span className="text-[10px]">{t('Edit details')}</span>
145-
</Button>
140+
<svg
141+
className="w-5 h-5 text-white"
142+
aria-hidden="true"
143+
xmlns="http://www.w3.org/2000/svg"
144+
width="24"
145+
height="24"
146+
fill="none"
147+
viewBox="0 0 24 24"
148+
>
149+
<path
150+
stroke="currentColor"
151+
strokeLinecap="round"
152+
strokeLinejoin="round"
153+
strokeWidth="2"
154+
d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"
155+
/>
156+
</svg>
157+
<span className="text-[10px]">{t('Edit details')}</span>
158+
</Button>
159+
<Dropdown
160+
label=""
161+
dismissOnClick={true}
162+
renderTrigger={() => (
163+
<Button
164+
size="xs"
165+
className="h-8 p-2 text-white bg-gray-700 rounded hover:bg-gray-600"
166+
color="gray"
167+
>
168+
<HiDotsVertical className="w-5 h-5" />
169+
</Button>
170+
)}
171+
>
172+
<Dropdown.Item
173+
onClick={handleDeleteButtonClick}
174+
className="text-red-500 hover:bg-red-100 dark:hover:bg-red-900"
175+
>
176+
<svg
177+
className="w-4 h-4 mr-2"
178+
aria-hidden="true"
179+
xmlns="http://www.w3.org/2000/svg"
180+
fill="none"
181+
viewBox="0 0 24 24"
182+
>
183+
<path
184+
stroke="currentColor"
185+
strokeLinecap="round"
186+
strokeLinejoin="round"
187+
strokeWidth="2"
188+
d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"
189+
/>
190+
</svg>
191+
{t('Delete publisher')}
192+
</Dropdown.Item>
193+
</Dropdown>
194+
</div>
146195
)}
147196
</div>
148197
<p className="text-gray-400">@{publisher.id}</p>
@@ -251,6 +300,11 @@ const PublisherDetail: React.FC<PublisherDetailProps> = ({ publisher }) => {
251300
onSubmit={handleSubmitEditPublisher}
252301
publisher={publisher}
253302
/>
303+
<DeletePublisherModal
304+
openDeleteModal={openDeleteModal}
305+
onClose={onCloseDeleteModal}
306+
publisherId={publisher.id}
307+
/>
254308
</div>
255309
)
256310
}

locales/ar/common.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"Approve Reason:": "سبب الموافقة:",
2525
"Approved by admin": "تمت الموافقة بواسطة المشرف",
2626
"Are you sure you want to delete this node? This action cannot be undone.": "هل أنت متأكد أنك تريد حذف هذه العقدة؟ لا يمكن التراجع عن هذا الإجراء.",
27+
"Are you sure you want to delete this publisher? This action cannot be undone.": "هل أنت متأكد أنك تريد حذف هذا الناشر؟ لا يمكن التراجع عن هذا الإجراء.",
2728
"Are you sure you want to delete this version? This action cannot be undone.": "هل أنت متأكد أنك تريد حذف هذا الإصدار؟ لا يمكن التراجع عن هذا الإجراء.",
2829
"Are you sure you want to unclaim this node? This will remove the publisher association, allowing the original author to claim it under a different publisher.": "هل أنت متأكد أنك تريد إلغاء المطالبة بهذه العقدة؟ هذا سيزيل ارتباط الناشر، مما يسمح للمؤلف الأصلي بالمطالبة بها تحت ناشر مختلف.",
2930
"Author": "المؤلف",
@@ -102,12 +103,13 @@
102103
"Debug info": "معلومات التصحيح",
103104
"Delete": "حذف",
104105
"Delete Node": "حذف العقدة",
106+
"Delete Publisher": "حذف الناشر",
105107
"Delete Version": "حذف الإصدار",
108+
"Delete publisher": "حذف الناشر",
106109
"Deleted": "محذوف",
107110
"Deprecate version": "إهمال الإصدار",
108111
"Description": "وصف",
109112
"Details": "التفاصيل",
110-
"Discord": "Discord",
111113
"Discover and install ComfyUI custom nodes.": "اكتشف وقم بتثبيت عقد ComfyUI المخصصة.",
112114
"Display Name": "اسم العرض",
113115
"Documentation": "توثيق",
@@ -159,6 +161,8 @@
159161
"Failed to create secret key": "فشل في إنشاء مفتاح السر",
160162
"Failed to delete node": "فشل في حذف العقدة",
161163
"Failed to delete node. {{message}}": "فشل في حذف العقدة. {{message}}",
164+
"Failed to delete publisher": "فشل في حذف الناشر",
165+
"Failed to delete publisher. {{message}}": "فشل في حذف الناشر. {{message}}",
162166
"Failed to delete version": "فشل في حذف الإصدار",
163167
"Failed to delete version: {{message}}": "فشل في حذف الإصدار: {{message}}",
164168
"Failed to get GitHub user information. Please try again.": "فشل في الحصول على معلومات مستخدم GitHub. يرجى المحاولة مرة أخرى.",
@@ -290,6 +294,7 @@
290294
"Publisher ID in repository does not match selected publisher": "معرف الناشر في المستودع لا يتطابق مع الناشر المحدد",
291295
"Publisher ID is required to update preempted comfy node names": "يلزم معرف الناشر لتحديث أسماء العقد المحجوزة لـ Comfy",
292296
"Publisher ID is required to update search ranking": "يلزم معرف الناشر لتحديث ترتيب البحث",
297+
"Publisher deleted successfully": "تم حذف الناشر بنجاح",
293298
"Publisher updated successfully": "تم تحديث الناشر بنجاح",
294299
"Publishers": "الناشرون",
295300
"Publishing Nodes - ComfyUI": "نشر العقد - ComfyUI",

locales/en/common.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"Approve Reason:": "Approve Reason:",
2525
"Approved by admin": "Approved by admin",
2626
"Are you sure you want to delete this node? This action cannot be undone.": "Are you sure you want to delete this node? This action cannot be undone.",
27+
"Are you sure you want to delete this publisher? This action cannot be undone.": "Are you sure you want to delete this publisher? This action cannot be undone.",
2728
"Are you sure you want to delete this version? This action cannot be undone.": "Are you sure you want to delete this version? This action cannot be undone.",
2829
"Are you sure you want to unclaim this node? This will remove the publisher association, allowing the original author to claim it under a different publisher.": "Are you sure you want to unclaim this node? This will remove the publisher association, allowing the original author to claim it under a different publisher.",
2930
"Author": "Author",
@@ -102,7 +103,9 @@
102103
"Debug info": "Debug info",
103104
"Delete": "Delete",
104105
"Delete Node": "Delete Node",
106+
"Delete Publisher": "Delete Publisher",
105107
"Delete Version": "Delete Version",
108+
"Delete publisher": "Delete publisher",
106109
"Deleted": "Deleted",
107110
"Deprecate version": "Deprecate version",
108111
"Description": "Description",
@@ -158,6 +161,8 @@
158161
"Failed to create secret key": "Failed to create secret key",
159162
"Failed to delete node": "Failed to delete node",
160163
"Failed to delete node. {{message}}": "Failed to delete node. {{message}}",
164+
"Failed to delete publisher": "Failed to delete publisher",
165+
"Failed to delete publisher. {{message}}": "Failed to delete publisher. {{message}}",
161166
"Failed to delete version": "Failed to delete version",
162167
"Failed to delete version: {{message}}": "Failed to delete version: {{message}}",
163168
"Failed to get GitHub user information. Please try again.": "Failed to get GitHub user information. Please try again.",
@@ -289,6 +294,7 @@
289294
"Publisher ID in repository does not match selected publisher": "Publisher ID in repository does not match selected publisher",
290295
"Publisher ID is required to update preempted comfy node names": "Publisher ID is required to update preempted comfy node names",
291296
"Publisher ID is required to update search ranking": "Publisher ID is required to update search ranking",
297+
"Publisher deleted successfully": "Publisher deleted successfully",
292298
"Publisher updated successfully": "Publisher updated successfully",
293299
"Publishers": "Publishers",
294300
"Publishing Nodes - ComfyUI": "Publishing Nodes - ComfyUI",

locales/es/common.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"Approve Reason:": "Razón de Aprobación:",
2525
"Approved by admin": "Aprobado por el administrador",
2626
"Are you sure you want to delete this node? This action cannot be undone.": "¿Estás seguro de que quieres eliminar este nodo? Esta acción no se puede deshacer.",
27+
"Are you sure you want to delete this publisher? This action cannot be undone.": "¿Está seguro de que desea eliminar este editor? Esta acción no puede deshacerse.",
2728
"Are you sure you want to delete this version? This action cannot be undone.": "¿Estás seguro de que quieres eliminar esta versión? Esta acción no puede deshacerse.",
2829
"Are you sure you want to unclaim this node? This will remove the publisher association, allowing the original author to claim it under a different publisher.": "¿Está seguro de que desea cancelar la reclamación de este nodo? Esto eliminará la asociación con el editor, permitiendo al autor original reclamarlo bajo un editor diferente.",
2930
"Author": "Autor",
@@ -102,12 +103,13 @@
102103
"Debug info": "Depuración de información",
103104
"Delete": "Eliminar",
104105
"Delete Node": "Eliminar Nodo",
106+
"Delete Publisher": "Eliminar Editor",
105107
"Delete Version": "Eliminar versión",
108+
"Delete publisher": "Eliminar Editor",
106109
"Deleted": "Eliminado",
107110
"Deprecate version": "Deprecar versión",
108111
"Description": "Descripción",
109112
"Details": "Detalles",
110-
"Discord": "Discord",
111113
"Discover and install ComfyUI custom nodes.": "Descubre e instala nodos personalizados de ComfyUI.",
112114
"Display Name": "Nombre para Mostrar",
113115
"Documentation": "Documentación",
@@ -159,6 +161,8 @@
159161
"Failed to create secret key": "Error al crear la clave secreta",
160162
"Failed to delete node": "Error al eliminar el nodo",
161163
"Failed to delete node. {{message}}": "No se pudo eliminar el nodo. {{message}}",
164+
"Failed to delete publisher": "Error al eliminar el editor",
165+
"Failed to delete publisher. {{message}}": "删除发布者失败。{{message}}",
162166
"Failed to delete version": "Error al eliminar la versión",
163167
"Failed to delete version: {{message}}": "无法删除版本:{{message}}",
164168
"Failed to get GitHub user information. Please try again.": "No se pudo obtener la información del usuario de GitHub. Por favor, inténtelo de nuevo.",
@@ -290,6 +294,7 @@
290294
"Publisher ID in repository does not match selected publisher": "El ID del editor en el repositorio no coincide con el editor seleccionado.",
291295
"Publisher ID is required to update preempted comfy node names": "Se requiere la ID del editor para actualizar los nombres de los nodos cómodos anticipados.",
292296
"Publisher ID is required to update search ranking": "Se requiere la ID del editor para actualizar la clasificación de búsqueda",
297+
"Publisher deleted successfully": "El editor se eliminó con éxito.",
293298
"Publisher updated successfully": "El editor se actualizó correctamente",
294299
"Publishers": "Editores",
295300
"Publishing Nodes - ComfyUI": "Publicando Nodos - ComfyUI",

0 commit comments

Comments
 (0)