diff --git a/apps/studio/components/interfaces/Replication/Publications.tsx b/apps/studio/components/interfaces/Replication/Publications.tsx index 45617918c8c..69a57160465 100644 --- a/apps/studio/components/interfaces/Replication/Publications.tsx +++ b/apps/studio/components/interfaces/Replication/Publications.tsx @@ -3,8 +3,42 @@ import { FormHeader } from 'components/ui/Forms/FormHeader' import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { Plus } from 'lucide-react' import Table from 'components/to-be-cleaned/Table' +import { useReplicationSourcesQuery } from 'data/replication/sources-query' +import { useParams } from 'common' +import { useReplicationPublicationsQuery } from 'data/replication/publications-query' +import { Button } from 'ui' export const ReplicationPublications = () => { + const { ref } = useParams() + const { data } = useReplicationSourcesQuery({ + projectRef: ref, + }) + + const sources = data ?? [] + let publication_source_id = null + + for (let i = 0; i < sources.length; i++) { + const source = sources[i] + if (source.config.Postgres!.host.startsWith(`db.${ref}`)) { + if (publication_source_id === null) { + publication_source_id = source.id + } else { + throw new Error(`multiple sources for ref ${ref}`) + } + } + } + + if (publication_source_id === null) { + throw new Error(`no sources for ref ${ref}`) + } + + const { data: pub_data } = useReplicationPublicationsQuery({ + projectRef: ref, + sourceId: publication_source_id, + }) + + const publications = pub_data ?? [] + return ( <> @@ -29,14 +63,33 @@ export const ReplicationPublications = () => {
, Name, - + Num Tables , - Edit, + Edit, + Delete, ]} - body={
No publications
} + body={ + publications.length === 0 ? ( + + No publications + + ) : ( + publications.map((pub) => ( + + {pub.name} + {pub.tables.length} + + + + + + + + )) + ) + } >
diff --git a/apps/studio/data/replication/keys.ts b/apps/studio/data/replication/keys.ts index 097695eff50..71f392cabd0 100644 --- a/apps/studio/data/replication/keys.ts +++ b/apps/studio/data/replication/keys.ts @@ -1,3 +1,5 @@ export const replicationKeys = { sources: (projectRef: string | undefined) => ['projects', projectRef, 'sources'] as const, + publications: (projectRef: string | undefined, source_id: number) => + ['projects', projectRef, 'sources', source_id, 'publications'] as const, } diff --git a/apps/studio/data/replication/publications-query.ts b/apps/studio/data/replication/publications-query.ts new file mode 100644 index 00000000000..87725429607 --- /dev/null +++ b/apps/studio/data/replication/publications-query.ts @@ -0,0 +1,42 @@ +import { UseQueryOptions, useQuery } from '@tanstack/react-query' + +import { get, handleError } from 'data/fetchers' +import { ResponseError } from 'types' +import { replicationKeys } from './keys' + +type ReplicationPublicationsParams = { projectRef?: string; sourceId: number } + +async function fetchReplicationPublications( + { projectRef, sourceId }: ReplicationPublicationsParams, + signal?: AbortSignal +) { + if (!projectRef) throw new Error('projectRef is required') + + const { data, error } = await get( + '/platform/replication/{ref}/sources/{source_id}/publications', + { + params: { path: { ref: projectRef, source_id: sourceId } }, + signal, + } + ) + if (error) { + handleError(error) + } + + return data +} + +export type ReplicationPublicationsData = Awaited> + +export const useReplicationPublicationsQuery = ( + { projectRef, sourceId }: ReplicationPublicationsParams, + { + enabled = true, + ...options + }: UseQueryOptions = {} +) => + useQuery( + replicationKeys.publications(projectRef, sourceId), + ({ signal }) => fetchReplicationPublications({ projectRef, sourceId }, signal), + { enabled: enabled && typeof projectRef !== 'undefined', ...options } + ) diff --git a/packages/api-types/types/api.d.ts b/packages/api-types/types/api.d.ts index ac90fac86ad..d19d5a82d15 100644 --- a/packages/api-types/types/api.d.ts +++ b/packages/api-types/types/api.d.ts @@ -3325,6 +3325,10 @@ export interface paths { /** Creates a replication source */ post: operations['ReplicationSourcesController_createSource'] } + '/platform/replication/{ref}/sources/{source_id}/publications': { + /** Gets source publications */ + get: operations['ReplicationSourcesController_getPublications'] + } '/platform/reset-password': { parameters: { query?: never @@ -10705,6 +10709,10 @@ export interface components { saml?: components['schemas']['SamlDescriptor'] updated_at?: string } + Publication: { + name: string + tables: components['schemas']['Table'][] + } PublicUrlOptions: { download?: boolean downloadName?: string @@ -21599,6 +21607,28 @@ export interface operations { } } } + /** Gets source publications */ + ReplicationSourcesController_getPublications: { + parameters: { + path: { + /** @description Project ref */ + ref: string + /** @description Source id */ + source_id: number + } + } + responses: { + 200: { + content: { + 'application/json': components['schemas']['Publication'][] + } + } + /** @description Failed to get source publications */ + 500: { + content: never + } + } + } /** Reset password for email */ ResetPasswordController_resetPassword: { parameters: {