- {vercelIntegration ? (
-
-
-
- {connections.length > 0 && (
-
- {connections.map((connection) => (
- li]:pb-0'
- )}
- >
-
- {isProjectScoped ? (
-
-
-
-
+
+
+
+ {connections.length > 0 && (
+
+ {connections.map((connection) => (
+ li]:pb-0'
+ )}
+ >
+
+ {isProjectScoped ? (
+
- ))}
-
- )}
-
onAddVercelConnection(vercelIntegration.id)}
- >
- Add new project connection
-
-
- ) : (
+
+ ) : null}
+
+ ))}
+
+ )}
}
- disabledTooltip="Install the Vercel integration on your project's main branch"
+ disabled={isBranch || !canCreateVercelConnection}
+ onClick={() => onAddVercelConnection(vercelIntegration.id)}
+ icon={
}
>
- Install Vercel integration
+ Add connection
- )}
+
- {vercelProjectCount > 0 && vercelIntegration !== undefined && (
+ {vercelProjectCount > 0 && (
Your Vercel connection can access {vercelProjectCount} Vercel projects. To change
which projects Supabase may use, open your organization’s{' '}
@@ -235,3 +239,40 @@ export const VercelSection = ({ isProjectScoped }: { isProjectScoped: boolean })
)
}
+
+function VercelInstallEmptyState({ href, disabled = false }: { href: string; disabled?: boolean }) {
+ return (
+
+
+
+ {disabled ? (
+ }
+ variant="default"
+ size="tiny"
+ disabled
+ tooltip={{
+ content: {
+ side: 'bottom',
+ text: "Install the Vercel integration on your project's main branch",
+ },
+ }}
+ >
+ Install Vercel integration
+
+ ) : (
+ } variant="default" size="tiny" asChild>
+
+ Install integration
+
+
+ )}
+
+
+
+ )
+}
diff --git a/apps/studio/components/layouts/AppLayout/OrganizationDropdown.test.tsx b/apps/studio/components/layouts/AppLayout/OrganizationDropdown.test.tsx
index dbe0ed14b76..c7f142acf72 100644
--- a/apps/studio/components/layouts/AppLayout/OrganizationDropdown.test.tsx
+++ b/apps/studio/components/layouts/AppLayout/OrganizationDropdown.test.tsx
@@ -29,6 +29,10 @@ vi.mock('@/components/ui/PartnerIcon', () => ({
organization.managed_by === MANAGED_BY.SUPABASE ? null :
,
}))
+vi.mock('@/components/interfaces/Settings/Integrations/AWSPrivateLink/preview', () => ({
+ usePreviewNavManagedBy: (managedBy: string | undefined) => managedBy,
+}))
+
describe('OrganizationDropdown', () => {
beforeEach(() => {
vi.clearAllMocks()
diff --git a/apps/studio/components/layouts/AppLayout/OrganizationDropdown.tsx b/apps/studio/components/layouts/AppLayout/OrganizationDropdown.tsx
index 95ababa6939..acc433b4f62 100644
--- a/apps/studio/components/layouts/AppLayout/OrganizationDropdown.tsx
+++ b/apps/studio/components/layouts/AppLayout/OrganizationDropdown.tsx
@@ -12,6 +12,7 @@ import {
} from './AppLayoutDropdown'
import { OrganizationDropdownCommandContent } from './OrganizationDropdownCommandContent'
import { useEmbeddedCloseHandler } from './useEmbeddedCloseHandler'
+import { usePreviewNavManagedBy } from '@/components/interfaces/Settings/Integrations/AWSPrivateLink/preview'
import PartnerIcon from '@/components/ui/PartnerIcon'
import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
@@ -42,6 +43,7 @@ export const OrganizationDropdown = ({
const slug = selectedOrganization?.slug
const orgName = selectedOrganization?.name
+ const navManagedBy = usePreviewNavManagedBy(selectedOrganization?.managed_by)
const [open, setOpen] = useState(false)
const close = useEmbeddedCloseHandler(embedded, onClose, setOpen)
@@ -87,7 +89,9 @@ export const OrganizationDropdown = ({
>
{orgName ?? 'Select an organization'}
- {!!selectedOrganization &&
}
+ {!!selectedOrganization && navManagedBy && (
+
+ )}
{!!selectedOrganization && (
{selectedOrganization?.plan.name}
)}
diff --git a/apps/studio/components/layouts/AppLayout/ProjectDropdown.test.tsx b/apps/studio/components/layouts/AppLayout/ProjectDropdown.test.tsx
index 667e6ab3a20..d610dd0d702 100644
--- a/apps/studio/components/layouts/AppLayout/ProjectDropdown.test.tsx
+++ b/apps/studio/components/layouts/AppLayout/ProjectDropdown.test.tsx
@@ -69,6 +69,10 @@ vi.mock('@/components/ui/PartnerIcon', () => ({
),
}))
+vi.mock('@/components/interfaces/Settings/Integrations/AWSPrivateLink/preview', () => ({
+ usePreviewNavManagedBy: (managedBy: string | undefined) => managedBy,
+}))
+
describe('ProjectDropdown', () => {
beforeEach(() => {
vi.clearAllMocks()
diff --git a/apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx b/apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx
index b5c6ec77c60..c853a2bd836 100644
--- a/apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx
+++ b/apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx
@@ -11,6 +11,7 @@ import { AppLayoutDropdownTriggerButton } from './AppLayoutDropdown'
import { sanitizeRoute } from './ProjectDropdown.utils'
import { ProjectRowLink } from './ProjectRowLink'
import { useEmbeddedCloseHandler } from './useEmbeddedCloseHandler'
+import { usePreviewNavManagedBy } from '@/components/interfaces/Settings/Integrations/AWSPrivateLink/preview'
import { OrganizationProjectSelector } from '@/components/ui/OrganizationProjectSelector'
import PartnerIcon from '@/components/ui/PartnerIcon'
import { getManagedByFromOrganizationPartner } from '@/data/organizations/managed-by-utils'
@@ -152,11 +153,13 @@ export const ProjectDropdown = ({
const [open, setOpen] = useState(false)
const close = useEmbeddedCloseHandler(embedded, onClose, setOpen)
- const selectedProjectManagedBy = selectedProject?.integration_source
- ? getManagedByFromOrganizationPartner(undefined, selectedProject.integration_source)
- : selectedOrganization?.billing_partner
- ? selectedOrganization.managed_by
- : undefined
+ const selectedProjectManagedBy = usePreviewNavManagedBy(
+ selectedProject?.integration_source
+ ? getManagedByFromOrganizationPartner(undefined, selectedProject.integration_source)
+ : selectedOrganization?.billing_partner
+ ? selectedOrganization.managed_by
+ : undefined
+ )
if (isLoadingProject || (isBranch && isLoadingParentProject) || !selectedProject) {
if (!embedded) return
diff --git a/apps/studio/components/layouts/DefaultLayout.tsx b/apps/studio/components/layouts/DefaultLayout.tsx
index 734493bb7bb..c66da57456a 100644
--- a/apps/studio/components/layouts/DefaultLayout.tsx
+++ b/apps/studio/components/layouts/DefaultLayout.tsx
@@ -16,6 +16,7 @@ import {
} from './ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import { ProjectContextProvider } from './ProjectLayout/ProjectContext'
import { AppBannerWrapper } from '@/components/interfaces/App/AppBannerWrapper'
+import { PrivateLinkPreviewPanel } from '@/components/interfaces/Settings/Integrations/AWSPrivateLink/preview'
import { Sidebar } from '@/components/interfaces/Sidebar'
import { useSyncScopedIntrospection } from '@/data/scoped-introspection'
import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization'
@@ -141,6 +142,7 @@ export const DefaultLayout = ({
+
diff --git a/apps/studio/data/aws-accounts/aws-accounts-query.ts b/apps/studio/data/aws-accounts/aws-accounts-query.ts
index ca378da61fd..24976a236d9 100644
--- a/apps/studio/data/aws-accounts/aws-accounts-query.ts
+++ b/apps/studio/data/aws-accounts/aws-accounts-query.ts
@@ -19,6 +19,9 @@ export type AWSAccount =
resource_access_manager_resource_config_id?: string
resource_access_manager_resource_config_arn?: string
resource_access_manager_share_arn?: string
+ // Prototype-only until the associations API exposes partner metadata and IAM role.
+ partner?: 'vercel'
+ destination_iam_role_arn?: string
}
async function getAWSAccounts({ projectRef }: AWSAccountsVariables, signal?: AbortSignal) {