diff --git a/apps/studio/components/interfaces/Replication/DeletePublicationModal.tsx b/apps/studio/components/interfaces/Replication/DeletePublicationModal.tsx new file mode 100644 index 00000000000..1f91ad14851 --- /dev/null +++ b/apps/studio/components/interfaces/Replication/DeletePublicationModal.tsx @@ -0,0 +1,54 @@ +import { useParams } from 'common' +import { useDeletePublicationMutation } from 'data/replication/delete-publication-mutation' +import { toast } from 'sonner' +import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' + +export type DeletePublicationModalProps = { + visible: boolean + title: string + sourceId: number + publicationName: string + onClose: () => void +} + +export const DeletePublicationModal = ({ + visible, + title, + sourceId, + publicationName, + onClose, +}: DeletePublicationModalProps) => { + const { ref } = useParams() + const { mutate: deletePublication, isLoading: isCreating } = useDeletePublicationMutation({ + onSuccess: (res) => { + toast.success('Successfully deleted publication') + onClose() + }, + }) + const onConfirm = () => { + deletePublication({ + projectRef: ref!, + sourceId, + publicationName, + }) + } + return ( + { + onClose() + }} + onConfirm={onConfirm} + > +
+

+ Are you sure you want to delete the selected publication? This action cannot be undone. +

+
+
+ ) +} diff --git a/apps/studio/components/interfaces/Replication/Publications.tsx b/apps/studio/components/interfaces/Replication/Publications.tsx index b083272d55b..b9774a17aba 100644 --- a/apps/studio/components/interfaces/Replication/Publications.tsx +++ b/apps/studio/components/interfaces/Replication/Publications.tsx @@ -10,6 +10,7 @@ import { Button } from 'ui' import { useState } from 'react' import CreatePublicationModal from './CreatePublicationModal' import { toast } from 'sonner' +import { DeletePublicationModal } from './DeletePublicationModal' export const ReplicationPublications = () => { const { ref } = useParams() @@ -17,6 +18,8 @@ export const ReplicationPublications = () => { projectRef: ref, }) const [showCreatePublicationModal, setShowCreatePublicationModal] = useState(false) + const [showDeletePublicationModal, setShowDeletePublicationModal] = useState(false) + const [publicationToDelete, setPublicationToDelete] = useState('') const sources = data ?? [] let source_id = null @@ -84,10 +87,18 @@ export const ReplicationPublications = () => { {pub.name} {pub.tables.length} - + - + )) @@ -101,9 +112,16 @@ export const ReplicationPublications = () => { setShowCreatePublicationModal(false)} /> + setShowDeletePublicationModal(false)} + /> ) } diff --git a/apps/studio/data/replication/delete-publication-mutation.ts b/apps/studio/data/replication/delete-publication-mutation.ts new file mode 100644 index 00000000000..5fac136e151 --- /dev/null +++ b/apps/studio/data/replication/delete-publication-mutation.ts @@ -0,0 +1,64 @@ +import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query' +import { toast } from 'sonner' + +import type { ResponseError } from 'types' +import { replicationKeys } from './keys' +import { handleError, del } from 'data/fetchers' + +export type DeletePublicationParams = { + projectRef: string + sourceId: number + publicationName: string +} + +async function deletePublication( + { projectRef, sourceId, publicationName: publication_name }: DeletePublicationParams, + signal?: AbortSignal +) { + if (!projectRef) throw new Error('projectRef is required') + + const { data, error } = await del( + '/platform/replication/{ref}/sources/{source_id}/publications/{publication_name}', + { + params: { path: { ref: projectRef, source_id: sourceId, publication_name } }, + signal, + } + ) + if (error) { + handleError(error) + } + + return data +} + +type DeletePublicationData = Awaited> + +export const useDeletePublicationMutation = ({ + onSuccess, + onError, + ...options +}: Omit< + UseMutationOptions, + 'mutationFn' +> = {}) => { + const queryClient = useQueryClient() + + return useMutation( + (vars) => deletePublication(vars), + { + async onSuccess(data, variables, context) { + const { projectRef, sourceId } = variables + await queryClient.invalidateQueries(replicationKeys.publications(projectRef, sourceId)) + await onSuccess?.(data, variables, context) + }, + async onError(data, variables, context) { + if (onError === undefined) { + toast.error(`Failed to delete publication: ${data.message}`) + } else { + onError(data, variables, context) + } + }, + ...options, + } + ) +} diff --git a/packages/api-types/types/api.d.ts b/packages/api-types/types/api.d.ts index 2e960d6adb7..aa27b26af3e 100644 --- a/packages/api-types/types/api.d.ts +++ b/packages/api-types/types/api.d.ts @@ -3331,6 +3331,10 @@ export interface paths { /** Creates a publication */ post: operations['ReplicationSourcesController_createPublication'] } + '/platform/replication/{ref}/sources/{source_id}/publications/{publication_name}': { + /** Deletes a publication */ + delete: operations['ReplicationSourcesController_deletePublication'] + } '/platform/replication/{ref}/sources/{source_id}/tables': { /** Gets source tables */ get: operations['ReplicationSourcesController_getTables'] @@ -8642,7 +8646,6 @@ export interface components { publish_update?: boolean tables?: string[] | null } - CreatePublicationResponse: Record CreateReplicationPublicationBody: { /** @description Publication name */ name: string @@ -21680,9 +21683,7 @@ export interface operations { } responses: { 201: { - content: { - 'application/json': components['schemas']['CreatePublicationResponse'] - } + content: never } /** @description Failed to create publication */ 500: { @@ -21690,6 +21691,28 @@ export interface operations { } } } + /** Deletes a publication */ + ReplicationSourcesController_deletePublication: { + parameters: { + path: { + /** @description Project ref */ + ref: string + /** @description Source id */ + source_id: number + /** @description Publication name */ + publication_name: string + } + } + responses: { + 200: { + content: never + } + /** @description Failed to delete publication */ + 500: { + content: never + } + } + } /** Gets source tables */ ReplicationSourcesController_getTables: { parameters: {