Skip to content

Commit b6071bc

Browse files
kamilogorekibixler
authored andcommitted
Enable branching for vercel marketplace (supabase#32396)
* feat: Add support for branching for Vercel Marketplace resources * docs: Remove Vercel Marketplace branching support note
1 parent fdc5a6c commit b6071bc

File tree

7 files changed

+111
-121
lines changed

7 files changed

+111
-121
lines changed

apps/docs/content/guides/deployment/branching.mdx

-6
Original file line numberDiff line numberDiff line change
@@ -627,12 +627,6 @@ With the Supabase branching integration, you can sync the Git branch used by the
627627

628628
### Vercel
629629

630-
<Admonition type="note" label="Vercel Marketplace support.">
631-
632-
The Vercel Integration for Supabase branching is working only with Supabase managed projects. There is currently no support for Vercel Marketplace managed resources, however the support is planned in the future.
633-
634-
</Admonition>
635-
636630
Install the Vercel integration:
637631

638632
- From the [Vercel marketplace](https://vercel.com/integrations/supabase) or

apps/studio/components/interfaces/Integrations/VercelGithub/IntegrationConnection.tsx

+5-4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
DropdownMenuTrigger,
2222
} from 'ui'
2323
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
24+
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
2425

2526
interface IntegrationConnectionItemProps extends IntegrationConnectionProps {
2627
disabled?: boolean
@@ -30,6 +31,7 @@ interface IntegrationConnectionItemProps extends IntegrationConnectionProps {
3031
const IntegrationConnectionItem = forwardRef<HTMLLIElement, IntegrationConnectionItemProps>(
3132
({ disabled, onDeleteConnection, ...props }, ref) => {
3233
const router = useRouter()
34+
const org = useSelectedOrganization()
3335

3436
const { type, connection } = props
3537
const { data: projects } = useProjectsQuery()
@@ -113,7 +115,7 @@ const IntegrationConnectionItem = forwardRef<HTMLLIElement, IntegrationConnectio
113115
</Link>
114116
</DropdownMenuItem>
115117
)}
116-
{type === 'Vercel' && (
118+
{type === 'Vercel' && org?.managed_by !== 'vercel-marketplace' && (
117119
<DropdownMenuItem
118120
className="space-x-2"
119121
onSelect={(event) => {
@@ -130,9 +132,8 @@ const IntegrationConnectionItem = forwardRef<HTMLLIElement, IntegrationConnectio
130132
<p>Resync environment variables</p>
131133
</DropdownMenuItem>
132134
)}
133-
{(type === 'Vercel' || router.pathname !== projectIntegrationUrl) && (
134-
<DropdownMenuSeparator />
135-
)}
135+
{((type === 'Vercel' && org?.managed_by !== 'vercel-marketplace') ||
136+
router.pathname !== projectIntegrationUrl) && <DropdownMenuSeparator />}
136137
<DropdownMenuItem className="space-x-2" onSelect={() => setIsOpen(true)}>
137138
<Trash size={14} />
138139
<p>Delete connection</p>

apps/studio/components/interfaces/Settings/Integrations/VercelIntegration/VercelIntegrationConnectionForm.tsx

+104-70
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import type {
1111
} from 'data/integrations/integrations.types'
1212
import { useVercelConnectionUpdateMutation } from 'data/integrations/vercel-connection-update-mutate'
1313
import {
14+
AlertDescription_Shadcn_,
15+
AlertTitle_Shadcn_,
16+
Alert_Shadcn_,
1417
FormControl_Shadcn_,
1518
FormDescription_Shadcn_,
1619
FormField_Shadcn_,
@@ -21,6 +24,8 @@ import {
2124
Input_Shadcn_,
2225
Switch,
2326
} from 'ui'
27+
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
28+
import Link from 'next/link'
2429

2530
const VercelIntegrationConnectionForm = ({
2631
disabled,
@@ -31,7 +36,11 @@ const VercelIntegrationConnectionForm = ({
3136
connection: IntegrationProjectConnection
3237
integration: Integration
3338
}) => {
34-
const envSyncTargets = connection.env_sync_targets ?? []
39+
// NOTE(kamil): Ignore sync targets for Vercel Marketplace as it's not synchronized using integration,
40+
// but through a separate marketplace mechanism. It's not theoretically necessary, but we might have some stale data.
41+
const org = useSelectedOrganization()
42+
const envSyncTargets =
43+
org?.managed_by === 'vercel-marketplace' ? [] : connection.env_sync_targets ?? []
3544

3645
const FormSchema = z.object({
3746
environmentVariablesProduction: z.boolean().default(envSyncTargets.includes('production')),
@@ -88,76 +97,101 @@ const VercelIntegrationConnectionForm = ({
8897
className={'w-full space-y-6'}
8998
>
9099
<div className="px-6 py-4 flex flex-col gap-y-4">
91-
<h5 className="text-foreground text-sm">
92-
Sync environment variables for selected target environments
93-
</h5>
94100
<div className="flex flex-col gap-4">
95-
<FormField_Shadcn_
96-
control={form.control}
97-
name="environmentVariablesProduction"
98-
render={({ field }) => (
99-
<FormItem_Shadcn_ className="space-y-0 flex gap-x-4">
100-
<FormControl_Shadcn_>
101-
<Switch
102-
disabled={disabled}
103-
className="mt-1"
104-
checked={field.value}
105-
onCheckedChange={field.onChange}
106-
/>
107-
</FormControl_Shadcn_>
108-
<div>
109-
<FormLabel_Shadcn_ className="!text">Production</FormLabel_Shadcn_>
110-
<FormDescription_Shadcn_ className="text-xs text-foreground-lighter">
111-
Sync environment variables for <code>production</code> environment.
112-
</FormDescription_Shadcn_>
113-
</div>
114-
</FormItem_Shadcn_>
115-
)}
116-
/>
117-
<FormField_Shadcn_
118-
control={form.control}
119-
name="environmentVariablesPreview"
120-
render={({ field }) => (
121-
<FormItem_Shadcn_ className="space-y-0 flex gap-x-4">
122-
<FormControl_Shadcn_>
123-
<Switch
124-
disabled={disabled}
125-
className="mt-1"
126-
checked={field.value}
127-
onCheckedChange={field.onChange}
128-
/>
129-
</FormControl_Shadcn_>
130-
<div>
131-
<FormLabel_Shadcn_ className="!text">Preview</FormLabel_Shadcn_>
132-
<FormDescription_Shadcn_ className="text-xs text-foreground-lighter">
133-
Sync environment variables for <code>preview</code> environment.
134-
</FormDescription_Shadcn_>
135-
</div>
136-
</FormItem_Shadcn_>
137-
)}
138-
/>
139-
<FormField_Shadcn_
140-
control={form.control}
141-
name="environmentVariablesDevelopment"
142-
render={({ field }) => (
143-
<FormItem_Shadcn_ className="space-y-0 flex gap-x-4">
144-
<FormControl_Shadcn_>
145-
<Switch
146-
disabled={disabled}
147-
className="mt-1"
148-
checked={field.value}
149-
onCheckedChange={field.onChange}
150-
/>
151-
</FormControl_Shadcn_>
152-
<div>
153-
<FormLabel_Shadcn_ className="!text">Development</FormLabel_Shadcn_>
154-
<FormDescription_Shadcn_ className="text-xs text-foreground-lighter">
155-
Sync environment variables for <code>development</code> environment.
156-
</FormDescription_Shadcn_>
157-
</div>
158-
</FormItem_Shadcn_>
159-
)}
160-
/>
101+
{org?.managed_by === 'vercel-marketplace' ? (
102+
<Alert_Shadcn_>
103+
<AlertTitle_Shadcn_ className="text-sm">
104+
Vercel Marketplace managed project
105+
</AlertTitle_Shadcn_>
106+
<AlertDescription_Shadcn_ className="text-xs">
107+
This project is managed via Vercel Marketplace. Environment variables are
108+
automatically synchronized for your connected Vercel projects. This integration
109+
purpose is synchronizing preview deployments environment variables with our{' '}
110+
<Link
111+
target="_blank"
112+
rel="noreferrer"
113+
href="https://supabase.com/docs/guides/platform/branching"
114+
className="underline"
115+
>
116+
Branching
117+
</Link>{' '}
118+
feature.
119+
</AlertDescription_Shadcn_>
120+
</Alert_Shadcn_>
121+
) : (
122+
<div>
123+
<h5 className="text-foreground text-sm">
124+
Sync environment variables for selected target environments
125+
</h5>
126+
127+
<FormField_Shadcn_
128+
control={form.control}
129+
name="environmentVariablesProduction"
130+
render={({ field }) => (
131+
<FormItem_Shadcn_ className="space-y-0 flex gap-x-4">
132+
<FormControl_Shadcn_>
133+
<Switch
134+
disabled={disabled}
135+
className="mt-1"
136+
checked={field.value}
137+
onCheckedChange={field.onChange}
138+
/>
139+
</FormControl_Shadcn_>
140+
<div>
141+
<FormLabel_Shadcn_ className="!text">Production</FormLabel_Shadcn_>
142+
<FormDescription_Shadcn_ className="text-xs text-foreground-lighter">
143+
Sync environment variables for <code>production</code> environment.
144+
</FormDescription_Shadcn_>
145+
</div>
146+
</FormItem_Shadcn_>
147+
)}
148+
/>
149+
<FormField_Shadcn_
150+
control={form.control}
151+
name="environmentVariablesPreview"
152+
render={({ field }) => (
153+
<FormItem_Shadcn_ className="space-y-0 flex gap-x-4">
154+
<FormControl_Shadcn_>
155+
<Switch
156+
disabled={disabled}
157+
className="mt-1"
158+
checked={field.value}
159+
onCheckedChange={field.onChange}
160+
/>
161+
</FormControl_Shadcn_>
162+
<div>
163+
<FormLabel_Shadcn_ className="!text">Preview</FormLabel_Shadcn_>
164+
<FormDescription_Shadcn_ className="text-xs text-foreground-lighter">
165+
Sync environment variables for <code>preview</code> environment.
166+
</FormDescription_Shadcn_>
167+
</div>
168+
</FormItem_Shadcn_>
169+
)}
170+
/>
171+
<FormField_Shadcn_
172+
control={form.control}
173+
name="environmentVariablesDevelopment"
174+
render={({ field }) => (
175+
<FormItem_Shadcn_ className="space-y-0 flex gap-x-4">
176+
<FormControl_Shadcn_>
177+
<Switch
178+
disabled={disabled}
179+
className="mt-1"
180+
checked={field.value}
181+
onCheckedChange={field.onChange}
182+
/>
183+
</FormControl_Shadcn_>
184+
<div>
185+
<FormLabel_Shadcn_ className="!text">Development</FormLabel_Shadcn_>
186+
<FormDescription_Shadcn_ className="text-xs text-foreground-lighter">
187+
Sync environment variables for <code>development</code> environment.
188+
</FormDescription_Shadcn_>
189+
</div>
190+
</FormItem_Shadcn_>
191+
)}
192+
/>
193+
</div>
194+
)}
161195
</div>
162196
<h5 className="mt-2 text-foreground text-sm">
163197
Customize public environment variable prefix

apps/studio/components/interfaces/Settings/Integrations/VercelIntegration/VercelSection.tsx

-12
Original file line numberDiff line numberDiff line change
@@ -166,18 +166,6 @@ You can change the scope of the access for Supabase by configuring
166166
<ScaffoldSectionContent>
167167
{!canReadVercelConnection ? (
168168
<NoPermission resourceText="view this organization's Vercel connections" />
169-
) : org?.managed_by === 'vercel-marketplace' ? (
170-
<Alert_Shadcn_ className="flex flex-col items-center gap-y-2 border-0 rounded-none">
171-
<PartnerIcon
172-
organization={{ managed_by: 'vercel-marketplace' }}
173-
showTooltip={false}
174-
size="large"
175-
/>
176-
177-
<AlertTitle_Shadcn_ className="text-sm">
178-
Vercel Integration is not available for Vercel Marketplace managed projects.
179-
</AlertTitle_Shadcn_>
180-
</Alert_Shadcn_>
181169
) : (
182170
<>
183171
<Markdown content={VercelContentSectionTop} />

apps/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx

-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import { ScaffoldColumn, ScaffoldContainer } from 'components/layouts/Scaffold'
1111
import PasswordStrengthBar from 'components/ui/PasswordStrengthBar'
1212
import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
1313
import { useIntegrationsQuery } from 'data/integrations/integrations-query'
14-
import { useIntegrationsVercelConnectionSyncEnvsMutation } from 'data/integrations/integrations-vercel-connection-sync-envs-mutation'
1514
import { useIntegrationVercelConnectionsCreateMutation } from 'data/integrations/integrations-vercel-connections-create-mutation'
1615
import { useVercelProjectsQuery } from 'data/integrations/integrations-vercel-projects-query'
1716
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
@@ -72,7 +71,6 @@ const CreateProject = () => {
7271
const { slug, next, currentProjectId: foreignProjectId, externalId } = useParams()
7372

7473
const { mutateAsync: createConnections } = useIntegrationVercelConnectionsCreateMutation()
75-
const { mutateAsync: syncEnvs } = useIntegrationsVercelConnectionSyncEnvsMutation()
7674

7775
const { data: organizationData } = useOrganizationsQuery()
7876
const organization = organizationData?.find((x) => x.slug === slug)
@@ -195,8 +193,6 @@ const CreateProject = () => {
195193
},
196194
orgSlug: selectedOrganization?.slug,
197195
})
198-
199-
await syncEnvs({ connectionId })
200196
} catch (error) {
201197
console.error('An error occurred during createConnections:', error)
202198
return

apps/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx

+1-10
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import VercelIntegrationWindowLayout from 'components/layouts/IntegrationsLayout
1212
import { ScaffoldColumn, ScaffoldContainer } from 'components/layouts/Scaffold'
1313
import { vercelIcon } from 'components/to-be-cleaned/ListIcons'
1414
import { useOrgIntegrationsQuery } from 'data/integrations/integrations-query-org-only'
15-
import { useIntegrationsVercelConnectionSyncEnvsMutation } from 'data/integrations/integrations-vercel-connection-sync-envs-mutation'
1615
import { useIntegrationVercelConnectionsCreateMutation } from 'data/integrations/integrations-vercel-connections-create-mutation'
1716
import { useVercelProjectsQuery } from 'data/integrations/integrations-vercel-projects-query'
1817
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
@@ -104,17 +103,9 @@ const VercelIntegration: NextPageWithLayout = () => {
104103

105104
const snapshot = useIntegrationInstallationSnapshot()
106105

107-
const { mutateAsync: syncEnvs } = useIntegrationsVercelConnectionSyncEnvsMutation()
108106
const { mutate: createConnections, isLoading: isCreatingConnection } =
109107
useIntegrationVercelConnectionsCreateMutation({
110-
async onSuccess({ id }) {
111-
try {
112-
await syncEnvs({ connectionId: id })
113-
} catch (error: any) {
114-
snapshot.setLoading(false)
115-
toast.error('Failed to sync environment variables: ', error.message)
116-
}
117-
108+
onSuccess() {
118109
if (next) {
119110
snapshot.setLoading(false)
120111
window.location.href = next

apps/studio/pages/integrations/vercel/install.tsx

+1-15
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,6 @@ const VercelIntegration: NextPageWithLayout = () => {
175175
: false
176176
}, [installed, selectedOrg, source, dataLoading])
177177

178-
const hasVercelManagedOrgSelected = useMemo(() => {
179-
return !!selectedOrg && selectedOrg.managed_by === 'vercel-marketplace'
180-
}, [selectedOrg])
181-
182178
const disableInstallationForm =
183179
(isLoadingVercelIntegrationCreateMutation && !dataLoading) ||
184180
// disables installation button if integration is already installed and it is Marketplace flow
@@ -231,21 +227,11 @@ const VercelIntegration: NextPageWithLayout = () => {
231227
</AlertDescription_Shadcn_>
232228
</Alert_Shadcn_>
233229
)}
234-
{hasVercelManagedOrgSelected && (
235-
<p className="prose text-sm text-red-900">
236-
Vercel Integration cannot be used with Vercel-managed organizations. Choose a
237-
different organization or create a Vercel resource directly.
238-
</p>
239-
)}
240230
<div className="flex flex-row w-full justify-end">
241231
<Button
242232
size="medium"
243233
className="self-end"
244-
disabled={
245-
disableInstallationForm ||
246-
isLoadingVercelIntegrationCreateMutation ||
247-
hasVercelManagedOrgSelected
248-
}
234+
disabled={disableInstallationForm || isLoadingVercelIntegrationCreateMutation}
249235
loading={isLoadingVercelIntegrationCreateMutation}
250236
onClick={onInstall}
251237
>

0 commit comments

Comments
 (0)