Merge branch 'master' into feature/assistant-mcp

This commit is contained in:
Greg Richardson committed 2025-06-02 15:52:34 -06:00
commit b85a2e79df
14 files changed
+89 -88

No files matched your search

+4 -7
View File
@@ -45,18 +45,15 @@ jobs:
git config --global user.email 'github-docs-bot@supabase.com'
BRANCH_NAME="bot/docs-lint-fixes"
EXISTING_BRANCH=$(git ls-remote --heads origin $BRANCH_NAME)
if [ -n "$EXISTING_BRANCH" ]; then
git checkout $BRANCH_NAME
else
git checkout -b $BRANCH_NAME
if [[ -n "$EXISTING_BRANCH" ]]; then
git push origin --delete $BRANCH_NAME
fi
git checkout -b $BRANCH_NAME
supa-mdx-lint apps/docs/content --fix || FIX_FAILED=1
git add .
git commit -m '[bot] fix lint errors' || true
git push origin $BRANCH_NAME
if [ -z "$EXISTING_BRANCH" ]; then
gh pr create --title '[bot] fix lint errors' --body 'This PR fixes lint errors in the documentation.' --head $BRANCH_NAME
fi
gh pr create --title '[bot] fix lint errors' --body 'This PR fixes lint errors in the documentation.' --head $BRANCH_NAME
if [ "${FIX_FAILED:-0}" -eq 1 ]; then
echo "Fix did not correct all errors."
exit 1
@@ -182,7 +182,7 @@ val metadata = user?.userMetadata
## Deleting users
You may delete users directly or via the management console at Authentication > Users. Note that deleting a user from the `auth.users` table does not automatically sign out a user. As Supabase makes use of JSON Web Tokens (JWT), a user's JWT will remain "valid" until it has expired. Should you wish to immediately revoke access for a user, do consider making use of a Row Level Security policy as described below.
You may delete users directly or via the management console at Authentication > Users. Note that deleting a user from the `auth.users` table does not automatically sign out a user. As Supabase makes use of JSON Web Tokens (JWT), a user's JWT will remain "valid" until it has expired.
<Admonition type="caution">
@@ -10,9 +10,9 @@ sidebar_label: 'Setting up replication and CDC'
To set up replication, the following is recommended:
- Instance size of XL or greater
- [IPv4 add-on](/guides/platform/ipv4-address) enabled
- [IPv4 add-on](/docs/guides/platform/ipv4-address) enabled
To create a replication slot, you will need to use the `postgres` user and follow the instructions in our [guide](/guides/database/postgres/setup-replication-external).
To create a replication slot, you will need to use the `postgres` user and follow the instructions in our [guide](/docs/guides/database/postgres/setup-replication-external).
<Admonition type="note">
If you are running Postgres 17 or higher, you can create a new user and grant them replication
@@ -294,7 +294,7 @@ Set the secrets from the `.env` file:
supabase secrets set --env-file supabase/functions/.env
```
Now your Supabase Edge Function will be triggered anytime an Auth Email needs to be send to the user!
Now your Supabase Edge Function will be triggered anytime an Auth Email needs to be sent to the user!
## More resources
+2
View File
@@ -1678,6 +1678,8 @@ commands:
> If you do not want to be prompted for the database password, such as in a CI environment, you may specify it explicitly via the `SUPABASE_DB_PASSWORD` environment variable.
Some commands like `db dump`, `db push`, and `db pull` require your project to be linked first.
The selected project ref is stored in `supabase/.temp/project_ref`.
examples:
- id: basic-usage
name: Basic usage
@@ -78,10 +78,10 @@ const PolicyRow = ({
<div className="text-foreground-lighter text-sm">
Applied to:{' '}
{policy.roles.slice(0, 3).map((role, i) => (
<code key={`policy-${role}-${i}`} className="text-foreground-light text-xs">
{role}
{policy.roles.length > 1 ? '' : ' '}
</code>
<span key={`policy-${role}-${i}`}>
<code className="text-foreground-light text-xs">{role}</code>
{i < Math.min(policy.roles.length, 3) - 1 && ', '}
</span>
))}
{policy.roles.length > 1 ? 'roles' : 'role'}
</div>
@@ -25,20 +25,20 @@ const SERVICE_STATUS_THRESHOLD = 5 // minutes
const StatusMessage = ({
status,
isLoading,
isSuccess,
isHealthy,
isProjectNew,
}: {
isLoading: boolean
isSuccess: boolean
isHealthy: boolean
isProjectNew: boolean
status?: ProjectServiceStatus
}) => {
if (isHealthy) return 'Healthy'
if (isLoading) return 'Checking status'
if (status === 'UNHEALTHY') return 'Unhealthy'
if (status === 'COMING_UP') return 'Coming up...'
if (status === 'ACTIVE_HEALTHY') return 'Healthy'
if (isProjectNew) return 'Coming up...'
if (isSuccess) return 'Healthy'
return 'Unable to connect'
}
@@ -52,21 +52,21 @@ const CheckIcon = () => <CheckCircle2 {...iconProps} className="text-brand" />
const StatusIcon = ({
isLoading,
isSuccess,
isHealthy,
isProjectNew,
projectStatus,
}: {
isLoading: boolean
isSuccess: boolean
isHealthy: boolean
isProjectNew: boolean
projectStatus?: ProjectServiceStatus
}) => {
if (isHealthy) return <CheckIcon />
if (isLoading) return <LoaderIcon />
if (projectStatus === 'UNHEALTHY') return <AlertIcon />
if (projectStatus === 'COMING_UP') return <LoaderIcon />
if (projectStatus === 'ACTIVE_HEALTHY') return <CheckIcon />
if (isProjectNew) return <LoaderIcon />
if (isSuccess) return <CheckIcon />
return <AlertIcon />
}
@@ -124,17 +124,17 @@ export const ServiceStatus = () => {
error?: string
docsUrl?: string
isLoading: boolean
isSuccess?: boolean
isHealthy: boolean
status: ProjectServiceStatus
logsUrl: string
status?: ProjectServiceStatus
}[] = [
{
name: 'Database',
error: undefined,
docsUrl: undefined,
isLoading: isLoading,
isSuccess: dbStatus?.healthy,
status: dbStatus?.status,
isHealthy: !!dbStatus?.healthy,
status: dbStatus?.status ?? 'UNHEALTHY',
logsUrl: '/logs/postgres-logs',
},
{
@@ -142,8 +142,8 @@ export const ServiceStatus = () => {
error: restStatus?.error,
docsUrl: undefined,
isLoading,
isSuccess: restStatus?.healthy,
status: restStatus?.status,
isHealthy: !!restStatus?.healthy,
status: restStatus?.status ?? 'UNHEALTHY',
logsUrl: '/logs/postgrest-logs',
},
...(authEnabled
@@ -153,8 +153,8 @@ export const ServiceStatus = () => {
error: authStatus?.error,
docsUrl: undefined,
isLoading,
isSuccess: authStatus?.healthy,
status: authStatus?.status,
isHealthy: !!authStatus?.healthy,
status: authStatus?.status ?? 'UNHEALTHY',
logsUrl: '/logs/auth-logs',
},
]
@@ -166,8 +166,8 @@ export const ServiceStatus = () => {
error: realtimeStatus?.error,
docsUrl: undefined,
isLoading,
isSuccess: realtimeStatus?.healthy,
status: realtimeStatus?.status,
isHealthy: !!realtimeStatus?.healthy,
status: realtimeStatus?.status ?? 'UNHEALTHY',
logsUrl: '/logs/realtime-logs',
},
]
@@ -179,8 +179,8 @@ export const ServiceStatus = () => {
error: storageStatus?.error,
docsUrl: undefined,
isLoading,
isSuccess: storageStatus?.healthy,
status: storageStatus?.status,
isHealthy: !!storageStatus?.healthy,
status: storageStatus?.status ?? 'UNHEALTHY',
logsUrl: '/logs/storage-logs',
},
]
@@ -192,7 +192,12 @@ export const ServiceStatus = () => {
error: undefined,
docsUrl: 'https://supabase.com/docs/guides/functions/troubleshooting',
isLoading,
isSuccess: edgeFunctionsStatus?.healthy,
isHealthy: !!edgeFunctionsStatus?.healthy,
status: edgeFunctionsStatus?.healthy
? 'ACTIVE_HEALTHY'
: isLoading
? 'COMING_UP'
: ('UNHEALTHY' as ProjectServiceStatus),
logsUrl: '/logs/edge-functions-logs',
},
]
@@ -200,7 +205,7 @@ export const ServiceStatus = () => {
]
const isLoadingChecks = services.some((service) => service.isLoading)
const allServicesOperational = services.every((service) => service.isSuccess)
const allServicesOperational = services.every((service) => service.isHealthy)
// If the project is less than 5 minutes old, and status is not operational, then it's likely the service is still starting up
const isProjectNew =
@@ -234,7 +239,7 @@ export const ServiceStatus = () => {
<Button
type="default"
icon={
isLoadingChecks || isProjectNew ? (
isLoadingChecks || (!allServicesOperational && isProjectNew) ? (
<LoaderIcon />
) : (
<div
@@ -258,7 +263,7 @@ export const ServiceStatus = () => {
<div className="flex gap-x-2">
<StatusIcon
isLoading={service.isLoading}
isSuccess={!!service.isSuccess}
isHealthy={!!service.isHealthy}
isProjectNew={isProjectNew}
projectStatus={service.status}
/>
@@ -267,7 +272,7 @@ export const ServiceStatus = () => {
<p className="text-foreground-light flex items-center gap-1">
<StatusMessage
isLoading={service.isLoading}
isSuccess={!!service.isSuccess}
isHealthy={!!service.isHealthy}
isProjectNew={isProjectNew}
status={service.status}
/>
@@ -3,12 +3,14 @@ import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { toast } from 'sonner'
import { LOCAL_STORAGE_KEYS } from 'common'
import { CANCELLATION_REASONS } from 'components/interfaces/Billing/Billing.constants'
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
import { useSendDowngradeFeedbackMutation } from 'data/feedback/exit-survey-send'
import { useProjectDeleteMutation } from 'data/projects/project-delete-mutation'
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
import { Input } from 'ui'
import TextConfirmModal from 'ui-patterns/Dialogs/TextConfirmModal'
@@ -18,6 +20,11 @@ const DeleteProjectModal = ({ visible, onClose }: { visible: boolean; onClose: (
const { project } = useProjectContext()
const organization = useSelectedOrganization()
const [lastVisitedOrganization] = useLocalStorageQuery(
LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION,
''
)
const projectRef = project?.ref
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
const projectPlan = subscription?.plan?.id ?? 'free'
@@ -43,7 +50,9 @@ const DeleteProjectModal = ({ visible, onClose }: { visible: boolean; onClose: (
}
toast.success(`Successfully deleted ${project?.name}`)
router.push(`/projects`)
if (lastVisitedOrganization) router.push(`/org/${lastVisitedOrganization}`)
else router.push('/organizations')
},
})
const { mutateAsync: sendExitSurvey, isLoading: isSending } = useSendDowngradeFeedbackMutation()
@@ -1,18 +1,11 @@
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
import { FormHeader } from 'components/ui/Forms/FormHeader'
import Panel from 'components/ui/Panel'
import {
Alert,
Alert_Shadcn_,
AlertDescription_Shadcn_,
AlertTitle_Shadcn_,
CriticalIcon,
} from 'ui'
import DeleteProjectButton from './DeleteProjectButton'
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
import PartnerManagedResource from 'components/ui/PartnerManagedResource'
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, CriticalIcon } from 'ui'
import DeleteProjectButton from './DeleteProjectButton'
const DeleteProjectPanel = () => {
export const DeleteProjectPanel = () => {
const selectedOrganization = useSelectedOrganization()
const { project } = useProjectContext()
@@ -21,35 +14,29 @@ const DeleteProjectPanel = () => {
return (
<section id="delete-project">
<FormHeader title="Delete Project" description="" />
<Panel>
<Panel.Content>
{selectedOrganization?.managed_by !== 'vercel-marketplace' ? (
<Alert_Shadcn_ variant="destructive">
<CriticalIcon />
<AlertTitle_Shadcn_>
Deleting this project will also remove your database.
</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_>
Make sure you have made a backup if you want to keep your data.
</AlertDescription_Shadcn_>
<div className="mt-2">
<DeleteProjectButton />
</div>
</Alert_Shadcn_>
) : (
<PartnerManagedResource
partner="vercel-marketplace"
resource="Projects"
cta={{
installationId: selectedOrganization?.partner_id,
message: 'Delete project in Vercel Marketplace',
}}
/>
)}
</Panel.Content>
</Panel>
{selectedOrganization?.managed_by !== 'vercel-marketplace' ? (
<Alert_Shadcn_ variant="destructive">
<CriticalIcon />
<AlertTitle_Shadcn_>
Deleting this project will also remove your database.
</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_>
Make sure you have made a backup if you want to keep your data.
</AlertDescription_Shadcn_>
<div className="mt-2">
<DeleteProjectButton />
</div>
</Alert_Shadcn_>
) : (
<PartnerManagedResource
partner="vercel-marketplace"
resource="Projects"
cta={{
installationId: selectedOrganization?.partner_id,
message: 'Delete project in Vercel Marketplace',
}}
/>
)}
</section>
)
}
export default DeleteProjectPanel
@@ -1,7 +1,6 @@
export { default as General } from './General'
export { default as ComplianceConfig } from './ComplianceConfig/ProjectComplianceMode'
export { default as CustomDomainConfig } from './CustomDomainConfig/CustomDomainConfig'
export { default as DeleteProjectPanel } from './DeleteProjectPanel/DeleteProjectPanel'
export { default as DeleteProjectButton } from './DeleteProjectPanel/DeleteProjectButton'
export { default as General } from './General'
export { default as TransferProjectButton } from './TransferProjectPanel/TransferProjectButton'
export { default as TransferProjectPanel } from './TransferProjectPanel/TransferProjectPanel'
export { default as ComplianceConfig } from './ComplianceConfig/ProjectComplianceMode'
@@ -69,7 +69,7 @@ const DeleteConfirmationDialogs = ({
},
})
const { mutate: deleteRows } = useTableRowDeleteMutation({
const { mutate: deleteRows, isLoading: isDeletingRows } = useTableRowDeleteMutation({
onSuccess: () => {
if (snap.confirmationDialog?.type === 'row') {
snap.confirmationDialog.callback?.()
@@ -81,7 +81,7 @@ const DeleteConfirmationDialogs = ({
},
})
const { mutate: deleteAllRows } = useTableRowDeleteAllMutation({
const { mutate: deleteAllRows, isLoading: isDeletingAllRows } = useTableRowDeleteAllMutation({
onSuccess: () => {
if (snap.confirmationDialog?.type === 'row') {
snap.confirmationDialog.callback?.()
@@ -96,7 +96,7 @@ const DeleteConfirmationDialogs = ({
},
})
const { mutate: truncateRows } = useTableRowTruncateMutation({
const { mutate: truncateRows, isLoading: isTruncatingRows } = useTableRowTruncateMutation({
onSuccess: () => {
if (snap.confirmationDialog?.type === 'row') {
snap.confirmationDialog.callback?.()
@@ -310,6 +310,7 @@ const DeleteConfirmationDialogs = ({
confirmLabelLoading="Deleting"
onCancel={() => snap.closeConfirmationDialog()}
onConfirm={() => onConfirmDeleteRow()}
loading={isTruncatingRows || isDeletingRows || isDeletingAllRows}
>
<div className="space-y-4">
<p className="text-sm text-foreground-light">
@@ -160,7 +160,7 @@ export const PauseDisabledState = () => {
</DropdownMenuItem> */}
</DropdownMenuContent>
</DropdownMenu>
<Button asChild type="default" icon={<ExternalLink />}>
<Button asChild type="default" icon={<ExternalLink />} className="my-3">
<a
target="_blank"
rel="noreferrer"
@@ -169,7 +169,7 @@ export const PauseDisabledState = () => {
Restore backup to a new Supabase project guide
</a>
</Button>
<Button asChild type="default" icon={<ExternalLink />}>
<Button asChild type="default" icon={<ExternalLink />} className="mb-3">
<a
target="_blank"
rel="noreferrer"
@@ -2,10 +2,10 @@ import { subscriptionHasHipaaAddon } from 'components/interfaces/Billing/Subscri
import {
ComplianceConfig,
CustomDomainConfig,
DeleteProjectPanel,
General,
TransferProjectPanel,
} from 'components/interfaces/Settings/General'
import { DeleteProjectPanel } from 'components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectPanel'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
import SettingsLayout from 'components/layouts/ProjectSettingsLayout/SettingsLayout'
+1
View File
@@ -35,6 +35,7 @@ allow_list = [
"[Cc]onfigs?",
"[Cc]onsecutiveness",
"[Cc]ooldowns?",
"[Cc]oroutines?",
"[Cc]ron",
"[Dd]atasets?",
"[Dd]atasources?",