mirror of
https://github.com/supabase/supabase.git
synced 2026-10-15 06:09:08 +03:00
Merge branch 'master' into feature/assistant-mcp
This commit is contained in:
commit
b85a2e79df
14 files changed
+89
-88
No files matched your search
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
|
||||
+10
-1
@@ -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()
|
||||
|
||||
+27
-40
@@ -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'
|
||||
|
||||
@@ -35,6 +35,7 @@ allow_list = [
|
||||
"[Cc]onfigs?",
|
||||
"[Cc]onsecutiveness",
|
||||
"[Cc]ooldowns?",
|
||||
"[Cc]oroutines?",
|
||||
"[Cc]ron",
|
||||
"[Dd]atasets?",
|
||||
"[Dd]atasources?",
|
||||
|
||||
Reference in new issue
Block a user