diff --git a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationPanel.tsx b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationPanel.tsx index 15ca208b799..a78e8182c1f 100644 --- a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationPanel.tsx +++ b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationPanel.tsx @@ -1,4 +1,4 @@ -import { useParams } from 'common' +import { useFeatureFlags, useParams } from 'common' import { ArrowUpRight } from 'lucide-react' import Link from 'next/link' import { parseAsInteger, parseAsStringEnum, useQueryState } from 'nuqs' @@ -6,7 +6,6 @@ import { useEffect, useRef } from 'react' import { toast } from 'sonner' import { Button, - cn, DialogSectionSeparator, Sheet, SheetContent, @@ -16,6 +15,7 @@ import { SheetTitle, } from 'ui' import { Admonition } from 'ui-patterns/Admonition' +import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' import { EnablePipelinesCallout } from '../EnablePipelinesCallout' import { PipelineStatusName } from '../Replication.constants' @@ -28,8 +28,9 @@ import { DiscardChangesConfirmationDialog } from '@/components/ui-patterns/Dialo import { DocsButton } from '@/components/ui/DocsButton' import { useReplicationDestinationsQuery } from '@/data/replication/destinations-query' import { checkLocalETLNotSetUp } from '@/data/replication/utils' +import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { useConfirmOnClose } from '@/hooks/ui/useConfirmOnClose' -import { DOCS_URL } from '@/lib/constants' +import { DOCS_URL, IS_PLATFORM } from '@/lib/constants' const DESTINATION_DOCS_PATHS: Partial> = { BigQuery: '/guides/database/replication/pipelines/bigquery#configure-bigquery-as-a-destination', @@ -41,7 +42,10 @@ const DESTINATION_DOCS_PATHS: Partial> = { export const DestinationPanel = () => { const { ref: projectRef } = useParams() + const { hasLoaded: flagsLoaded } = useFeatureFlags() + const { isPending: isOrganizationPending } = useSelectedOrganizationQuery() const enablePgReplicate = useIsETLPrivateAlpha() + const isAccessLoading = IS_PLATFORM && (!flagsLoaded || isOrganizationPending) const { error: destinationsError } = useReplicationDestinationsQuery({ projectRef }) const isLocalETLNotSetUp = checkLocalETLNotSetUp(destinationsError) @@ -80,6 +84,9 @@ export const DestinationPanel = () => { } = useDestinationInformation({ id: edit }) const destinationType = existingDestinationType ?? urlDestinationType const invalidExistingDestination = destinationFetcher.error?.code === 404 + const showAccessRequest = !isAccessLoading && !enablePgReplicate + const showEnablement = !isAccessLoading && enablePgReplicate && replicationNotEnabled + const showDestinationForm = !isAccessLoading && enablePgReplicate && !replicationNotEnabled const existingDestination = editMode ? { @@ -159,22 +166,24 @@ export const DestinationPanel = () => { /> - {!enablePgReplicate ? ( + {isAccessLoading && ( + + + + )} + {showAccessRequest && (
{pipelinesTypeSelection} -
-
-

Request Pipelines access

-

- Pipelines is in public alpha and - being rolled out gradually. Request access below to join the waitlist. -

-
-
+ } > { rel="noreferrer" href="https://forms.supabase.com/pg_replicate" > - Request Pipelines access + Request access - -
-
+ } + />
- ) : replicationNotEnabled ? ( + )} + {showEnablement && (
{pipelinesTypeSelection} - +
- ) : ( + )} + {showDestinationForm && ( { fireEvent.click(await screen.findByRole('combobox')) fireEvent.click(await screen.findByText('BigQuery')) - expect(await screen.findByText(/In public alpha and may change/)).toBeInTheDocument() + expect( + await screen.findByText( + 'Destination type cannot be changed after creation. BigQuery support is in public alpha.' + ) + ).toBeInTheDocument() }) test('disables the selector in edit mode so the destination type cannot be changed', async () => { diff --git a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationTypeSelection.tsx b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationTypeSelection.tsx index f7c2eeb0279..d8ee413d9dd 100644 --- a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationTypeSelection.tsx +++ b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationTypeSelection.tsx @@ -127,18 +127,23 @@ export const DestinationTypeSelection = () => { const selectedOption = options.find((option) => option.value === destinationType) - const STAGE_DESCRIPTIONS: Record, string> = { - 'Public Alpha': 'In public alpha and may change.', - 'Early Access': 'In early access and may change.', - Deprecated: 'This destination type is deprecated.', + const STAGE_DESCRIPTIONS: Record< + NonNullable, + (type: DestinationType) => string + > = { + 'Public Alpha': (type) => `${type} support is in public alpha.`, + 'Early Access': (type) => `${type} support is in early access.`, + Deprecated: (type) => `${type} is deprecated.`, } - const stageDescription = selectedOption?.stage ? STAGE_DESCRIPTIONS[selectedOption.stage] : null + const stageDescription = selectedOption?.stage + ? STAGE_DESCRIPTIONS[selectedOption.stage](selectedOption.value) + : null const typeDescription = !editMode || stageDescription ? ( - {!editMode && 'Cannot be changed after creation.'} + {!editMode && 'Destination type cannot be changed after creation.'} {!editMode && stageDescription ? ' ' : null} {stageDescription} diff --git a/apps/studio/components/interfaces/Database/Replication/Destinations.tsx b/apps/studio/components/interfaces/Database/Replication/Destinations.tsx index 1516ae4b5aa..a65f24d008b 100644 --- a/apps/studio/components/interfaces/Database/Replication/Destinations.tsx +++ b/apps/studio/components/interfaces/Database/Replication/Destinations.tsx @@ -300,7 +300,7 @@ export const Destinations = () => { aria-label="More actions" variant="default" icon={} - className="px-1.25" + className="w-6.5 hit-area-1" /> diff --git a/apps/studio/components/interfaces/Database/Replication/EnablePipelinesCallout.tsx b/apps/studio/components/interfaces/Database/Replication/EnablePipelinesCallout.tsx index 3a0085b9c24..a1485e9d76e 100644 --- a/apps/studio/components/interfaces/Database/Replication/EnablePipelinesCallout.tsx +++ b/apps/studio/components/interfaces/Database/Replication/EnablePipelinesCallout.tsx @@ -3,10 +3,8 @@ import { useState } from 'react' import { toast } from 'sonner' import { Button, - cn, Dialog, DialogContent, - DialogDescription, DialogFooter, DialogHeader, DialogSection, @@ -14,9 +12,9 @@ import { DialogTitle, DialogTrigger, } from 'ui' +import { Admonition } from 'ui-patterns/Admonition' import { DestinationType } from './DestinationPanel/DestinationPanel.types' -import { DocsButton } from '@/components/ui/DocsButton' import { InlineLink } from '@/components/ui/InlineLink' import { UpgradePlanButton } from '@/components/ui/UpgradePlanButton' import { useCreateTenantSourceMutation } from '@/data/replication/create-tenant-source-mutation' @@ -43,7 +41,7 @@ export const EnablePipelinesModal = ({ const { mutate: createTenantSource, isPending: creatingTenantSource } = useCreateTenantSourceMutation({ onSuccess: () => { - toast.success('Pipelines has been successfully enabled!') + toast.success('Pipelines enabled') setOpen(false) }, onError: (error) => { @@ -60,38 +58,33 @@ export const EnablePipelinesModal = ({ {!hideTrigger && ( - + )} Enable Pipelines - - {hasAccess - ? 'Enabling creates Pipelines resources for this project.' - : 'Upgrade to the Pro plan to replicate database changes to data warehouses and analytics platforms.'} - - {hasAccess && ( - <> - - + + + {hasAccess ? ( + <>

- Pipelines is in public alpha and may change as we refine it. -

-

- You’ll be billed for configured pipeline hours and for Postgres row data processed - during initial sync and ongoing replication. Review{' '} + Pipelines bills for configured pipeline hours and Postgres row data processed during + initial sync and ongoing replication. Review{' '} Pipelines pricing {' '} before enabling.

-
- - )} +

+ Pipelines is in public alpha and may change. +

+ + ) : ( +

Pipelines requires the Pro plan.

+ )} +