From 1e6c7f29316c2276b9d7fe7c92406d9e16f66fd9 Mon Sep 17 00:00:00 2001 From: Ignacio Dobronich Date: Wed, 4 Mar 2026 13:24:34 -0300 Subject: [PATCH 1/5] chore: github integration entitlement (#43294) Adds the Github Integration entitlement to the GitHubIntegrationConnectionForm. ### Testing - Head to `/project/_/settings/integrations` with an org on the Free Plan - Assert that you see the upgrade prompt: image - Head to `/project/_/settings/integrations` with an org on the Pro Plan - Assert that you don't see the upgrade prompt and you're able to enable and make changes to the Github Integration --- .../GitHubIntegrationConnectionForm.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GitHubIntegrationConnectionForm.tsx b/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GitHubIntegrationConnectionForm.tsx index 218c82d9ca521..1d9d98afe9d6c 100644 --- a/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GitHubIntegrationConnectionForm.tsx +++ b/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GitHubIntegrationConnectionForm.tsx @@ -50,6 +50,7 @@ import { InlineLink } from 'components/ui/InlineLink' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import * as z from 'zod' +import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements' const GITHUB_ICON = ( @@ -79,8 +80,10 @@ const GitHubIntegrationConnectionForm = ({ const [repoComboBoxOpen, setRepoComboboxOpen] = useState(false) const isParentProject = !selectedProject?.parent_project_ref - const isProPlanAndUp = selectedOrganization?.plan?.id !== 'free' - const promptProPlanUpgrade = IS_PLATFORM && !isProPlanAndUp + const { hasAccess: hasAccessToGitHubIntegration, isLoading: isLoadingEntitlements } = + useCheckEntitlements('integrations.github_connections') + const promptProPlanUpgrade = + IS_PLATFORM && !isLoadingEntitlements && !hasAccessToGitHubIntegration const { can: canUpdateGitHubConnection } = useAsyncCheckPermissions( PermissionAction.UPDATE, @@ -425,7 +428,8 @@ const GitHubIntegrationConnectionForm = ({ ) } - const isLoading = isCreatingConnection || isUpdatingConnection || isDeletingConnection + const isLoading = + isLoadingEntitlements || isCreatingConnection || isUpdatingConnection || isDeletingConnection return ( <> From 7e3986df8d6a6e52ca42afb2c98b1ad070b7cac3 Mon Sep 17 00:00:00 2001 From: Ignacio Dobronich Date: Wed, 4 Mar 2026 13:25:09 -0300 Subject: [PATCH 2/5] chore: restore to new project entitlement (#43313) Adds an entitlement check to prompt upgrades for restoring backups to new projects ### Testing - Head to `/project/_/database/backups/restore-to-new-project` with a Free Project - Assert that the upgrade prompt is shown image - Head to `/project/_/database/backups/restore-to-new-project` with a Pro Project or above - Assert that the restore backups UI is shown image --- .../Backups/RestoreToNewProject/BackupsList.tsx | 10 +++------- .../CreateNewProjectDialog.tsx | 9 +++------ .../RestoreToNewProject/RestoreToNewProject.tsx | 17 ++++++++++++++--- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/studio/components/interfaces/Database/Backups/RestoreToNewProject/BackupsList.tsx b/apps/studio/components/interfaces/Database/Backups/RestoreToNewProject/BackupsList.tsx index 07265a6e2b5ff..b99a4c2e367d8 100644 --- a/apps/studio/components/interfaces/Database/Backups/RestoreToNewProject/BackupsList.tsx +++ b/apps/studio/components/interfaces/Database/Backups/RestoreToNewProject/BackupsList.tsx @@ -1,6 +1,5 @@ import Panel from 'components/ui/Panel' import { useCloneBackupsQuery } from 'data/projects/clone-query' -import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { Badge, Button } from 'ui' import { TimestampInfo } from 'ui-patterns' @@ -9,17 +8,14 @@ import { BackupsEmpty } from '../BackupsEmpty' interface BackupsListProps { onSelectRestore: (id: number) => void disabled?: boolean + hasAccess?: boolean } -export const BackupsList = ({ onSelectRestore, disabled }: BackupsListProps) => { +export const BackupsList = ({ onSelectRestore, disabled, hasAccess }: BackupsListProps) => { const { data: project } = useSelectedProjectQuery() - const { data: organization } = useSelectedOrganizationQuery() - - const isFreePlan = organization?.plan?.id === 'free' - const { data: cloneBackups } = useCloneBackupsQuery( { projectRef: project?.ref }, - { enabled: !isFreePlan } + { enabled: hasAccess } ) return ( diff --git a/apps/studio/components/interfaces/Database/Backups/RestoreToNewProject/CreateNewProjectDialog.tsx b/apps/studio/components/interfaces/Database/Backups/RestoreToNewProject/CreateNewProjectDialog.tsx index a57a29ef73829..b93a387c38293 100644 --- a/apps/studio/components/interfaces/Database/Backups/RestoreToNewProject/CreateNewProjectDialog.tsx +++ b/apps/studio/components/interfaces/Database/Backups/RestoreToNewProject/CreateNewProjectDialog.tsx @@ -7,7 +7,6 @@ import { z } from 'zod' import { PasswordStrengthBar } from 'components/ui/PasswordStrengthBar' import { useProjectCloneMutation } from 'data/projects/clone-mutation' import { useCloneBackupsQuery } from 'data/projects/clone-query' -import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { passwordStrength, PasswordStrengthScore } from 'lib/password-strength' import { generateStrongPassword } from 'lib/project' @@ -37,6 +36,7 @@ interface CreateNewProjectDialogProps { onOpenChange: (value: boolean) => void onCloneSuccess: () => void additionalMonthlySpend: NewProjectPrice + hasAccess?: boolean } export const CreateNewProjectDialog = ({ @@ -46,10 +46,9 @@ export const CreateNewProjectDialog = ({ onOpenChange, onCloneSuccess, additionalMonthlySpend, + hasAccess, }: CreateNewProjectDialogProps) => { const { data: project } = useSelectedProjectQuery() - const { data: organization } = useSelectedOrganizationQuery() - const [passwordStrengthScore, setPasswordStrengthScore] = useState(0) const [passwordStrengthMessage, setPasswordStrengthMessage] = useState('') @@ -66,11 +65,9 @@ export const CreateNewProjectDialog = ({ }, }) - const isFreePlan = organization?.plan?.id === 'free' - const { data: cloneBackups } = useCloneBackupsQuery( { projectRef: project?.ref }, - { enabled: !isFreePlan } + { enabled: hasAccess } ) const hasPITREnabled = cloneBackups?.pitr_enabled diff --git a/apps/studio/components/interfaces/Database/RestoreToNewProject/RestoreToNewProject.tsx b/apps/studio/components/interfaces/Database/RestoreToNewProject/RestoreToNewProject.tsx index 8cf054582daf7..b73c6628a5961 100644 --- a/apps/studio/components/interfaces/Database/RestoreToNewProject/RestoreToNewProject.tsx +++ b/apps/studio/components/interfaces/Database/RestoreToNewProject/RestoreToNewProject.tsx @@ -18,6 +18,7 @@ import { UpgradeToPro } from 'components/ui/UpgradeToPro' import { useDiskAttributesQuery } from 'data/config/disk-attributes-query' import { useCloneBackupsQuery } from 'data/projects/clone-query' import { useCloneStatusQuery } from 'data/projects/clone-status-query' +import { useCheckEntitlements } from 'hooks/misc/useCheckEntitlements' import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { @@ -35,7 +36,8 @@ import { PreviousRestoreItem } from './PreviousRestoreItem' export const RestoreToNewProject = () => { const { data: project } = useSelectedProjectQuery() const { data: organization } = useSelectedOrganizationQuery() - const isFreePlan = organization?.plan?.id === 'free' + const { hasAccess: hasAccessToRestoreToNewProject, isLoading: isLoadingEntitlement } = + useCheckEntitlements('backup.restore_to_new_project') const isOrioleDb = useIsOrioleDb() const isAwsK8s = useIsAwsK8sCloudProvider() @@ -50,7 +52,10 @@ export const RestoreToNewProject = () => { error, isPending: cloneBackupsLoading, isError, - } = useCloneBackupsQuery({ projectRef: project?.ref }, { enabled: !isFreePlan }) + } = useCloneBackupsQuery( + { projectRef: project?.ref }, + { enabled: hasAccessToRestoreToNewProject } + ) const isActiveHealthy = project?.status === PROJECT_STATUS.ACTIVE_HEALTHY @@ -102,7 +107,11 @@ export const RestoreToNewProject = () => { const isRestoring = previousClones?.some((c) => c.status === 'IN_PROGRESS') const restoringClone = previousClones?.find((c) => c.status === 'IN_PROGRESS') - if (isFreePlan) { + if (isLoadingEntitlement) { + return + } + + if (!hasAccessToRestoreToNewProject) { return ( { selectedBackupId={selectedBackupId} recoveryTimeTarget={recoveryTimeTarget} additionalMonthlySpend={additionalMonthlySpend} + hasAccess={hasAccessToRestoreToNewProject} onOpenChange={setShowNewProjectDialog} onCloneSuccess={() => { refetchCloneStatus() @@ -307,6 +317,7 @@ export const RestoreToNewProject = () => { ) : ( { setSelectedBackupId(id) setShowConfirmationDialog(true) From 45fd69d9cfb58bc7203cece05e8116a29688d294 Mon Sep 17 00:00:00 2001 From: Jeremias Menichelli Date: Wed, 4 Mar 2026 18:03:43 +0100 Subject: [PATCH 3/5] fix(Docs): Avoid empty URL on AI links (#43399) --- apps/docs/components/GuidesSidebar.tsx | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/apps/docs/components/GuidesSidebar.tsx b/apps/docs/components/GuidesSidebar.tsx index ee4e8c49b4be2..0fc561ff94f43 100644 --- a/apps/docs/components/GuidesSidebar.tsx +++ b/apps/docs/components/GuidesSidebar.tsx @@ -19,16 +19,10 @@ interface TOCHeader { function AiTools({ className }: { className?: string }) { const [copied, setCopied] = useState(false) - let url = '' - - // Safe check for server side rendering. - try { - const urlParts = new URL(`${window.location}`) - url = urlParts.origin + urlParts.pathname - } catch (error) {} + const path = usePathname() async function copyMarkdown() { - const mdUrl = `${url}.md` + const mdUrl = `/docs/${path}.md` try { const res = await fetch(mdUrl) @@ -62,7 +56,7 @@ function AiTools({ className }: { className?: string }) { {copied ? 'Copied!' : 'Copy as Markdown'} Date: Wed, 4 Mar 2026 10:47:35 -0700 Subject: [PATCH 4/5] chore: allow using multiple ports for next dev (#43398) ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Trying agents with multiple git worktrees, want the ability to run multiple instances of dev ## Context For agent scripts that support git worktrees, you can set STUDIO_PORT to 0 and have the OS assign a port so they don't conflict with each other --- .gitignore | 5 ++++- apps/studio/package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index a2566899919aa..6f13c135c9bb4 100644 --- a/.gitignore +++ b/.gitignore @@ -156,4 +156,7 @@ gcloud.json keys.json # Playwright MCP -.playwright-mcp/* \ No newline at end of file +.playwright-mcp/* + +# Application +**/.superset/** diff --git a/apps/studio/package.json b/apps/studio/package.json index f12464045b25c..fc98a06d6190b 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "preinstall": "npx only-allow pnpm", - "dev": "next dev -p 8082", + "dev": "next dev -p ${STUDIO_PORT:-8082}", "build": "next build && if [ \"$SKIP_ASSET_UPLOAD\" != \"1\" ]; then ./../../scripts/upload-static-assets.sh; fi", "start": "next start -p 8082", "lint": "eslint .", From 00436076bbd542f8e9593ae13811dee1cf353f19 Mon Sep 17 00:00:00 2001 From: Matt Rossman <22670878+mattrossman@users.noreply.github.com> Date: Wed, 4 Mar 2026 14:50:41 -0500 Subject: [PATCH 5/5] chore(studio): bump mcp-server-supabase to 0.7.0 and mcp-utils to 0.4.0 (#43356) Bumps `@supabase/mcp-server-supabase` from 0.6.3 to 0.7.0 and `@supabase/mcp-utils` from 0.3.2 to 0.4.0. **References** - https://github.com/supabase-community/supabase-mcp/releases/tag/v0.7.0 Closes AI-462 --- apps/studio/package.json | 4 ++-- pnpm-lock.yaml | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/studio/package.json b/apps/studio/package.json index fc98a06d6190b..e12597aec341a 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -57,8 +57,8 @@ "@stripe/react-stripe-js": "^3.7.0", "@stripe/stripe-js": "^7.5.0", "@supabase/auth-js": "catalog:", - "@supabase/mcp-server-supabase": "^0.6.3", - "@supabase/mcp-utils": "^0.3.2", + "@supabase/mcp-server-supabase": "^0.7.0", + "@supabase/mcp-utils": "^0.4.0", "@supabase/pg-meta": "workspace:*", "@supabase/realtime-js": "catalog:", "@supabase/shared-types": "0.1.84", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dfcd31ce38240..cb6c665e22330 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -835,11 +835,11 @@ importers: specifier: 'catalog:' version: 2.98.1-canary.0 '@supabase/mcp-server-supabase': - specifier: ^0.6.3 - version: 0.6.3(@modelcontextprotocol/sdk@1.27.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76) + specifier: ^0.7.0 + version: 0.7.0(@modelcontextprotocol/sdk@1.27.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76) '@supabase/mcp-utils': - specifier: ^0.3.2 - version: 0.3.2(@modelcontextprotocol/sdk@1.27.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76) + specifier: ^0.4.0 + version: 0.4.0(@modelcontextprotocol/sdk@1.27.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76) '@supabase/pg-meta': specifier: workspace:* version: link:../../packages/pg-meta @@ -8201,15 +8201,15 @@ packages: resolution: {integrity: sha512-SD9lN0ko+NEXV27qVxV2/zrMUaYLvZgIwzroZqZLHZ8bU0ahPh+Pbh/ve67PLelZ9+3lYsLKV949sJ3VhVk9Xw==} engines: {node: '>=20.0.0'} - '@supabase/mcp-server-supabase@0.6.3': - resolution: {integrity: sha512-kAnCD/OT7/0aEa58aC7Zey5N/kb3zeTjxIzvgoJNegHung9NBjojHYXjm5qr0o0If6SF61FhrG4dEdWQmtWFdw==} + '@supabase/mcp-server-supabase@0.7.0': + resolution: {integrity: sha512-t0sOS27T5mDxp6jUYSh3zuyjWhYZarbXCPUO7HTVSyPq2smY6d5UM4Lko81eawYCSRDE8qwDZOKnVkXwCS4RSg==} hasBin: true peerDependencies: '@modelcontextprotocol/sdk': ^1.25.2 zod: ^3.25.0 || ^4.0.0 - '@supabase/mcp-utils@0.3.2': - resolution: {integrity: sha512-hGenK6oEFHkWhAyKGD1gNeIsHRRCl/N/kHmwubZm+UWCj4O1iuS6XgX1Ub2+mH25qqpUHIMaVm9BEV2p1RbhNQ==} + '@supabase/mcp-utils@0.4.0': + resolution: {integrity: sha512-mJ06GYLLZGW4zfz4yl08P2wrx0ORqW5iIAFyqvWJAInIjoa3w7EfJs/h+RbvCE+x7UYuSQeDUXpLJc4lJWDBKA==} peerDependencies: '@modelcontextprotocol/sdk': ^1.25.2 zod: ^3.25.0 || ^4.0.0 @@ -25491,18 +25491,18 @@ snapshots: dependencies: tslib: 2.8.1 - '@supabase/mcp-server-supabase@0.6.3(@modelcontextprotocol/sdk@1.27.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76)': + '@supabase/mcp-server-supabase@0.7.0(@modelcontextprotocol/sdk@1.27.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76)': dependencies: '@mjackson/multipart-parser': 0.10.1 '@modelcontextprotocol/sdk': 1.27.0(supports-color@8.1.1)(zod@3.25.76) - '@supabase/mcp-utils': 0.3.2(@modelcontextprotocol/sdk@1.27.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76) + '@supabase/mcp-utils': 0.4.0(@modelcontextprotocol/sdk@1.27.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76) common-tags: 1.8.2 gqlmin: 0.3.1 graphql: 16.11.0 openapi-fetch: 0.13.8 zod: 3.25.76 - '@supabase/mcp-utils@0.3.2(@modelcontextprotocol/sdk@1.27.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76)': + '@supabase/mcp-utils@0.4.0(@modelcontextprotocol/sdk@1.27.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76)': dependencies: '@modelcontextprotocol/sdk': 1.27.0(supports-color@8.1.1)(zod@3.25.76) zod: 3.25.76