mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Chore/enforce pitr for enabling branching (#19303)
* Enforce PITR on dashboard to enable branching * Add warning if disabling pitr when branching is enabled * Update apps/studio/components/interfaces/Settings/Addons/PITRSidePanel.tsx Co-authored-by: Copple <10214025+kiwicopple@users.noreply.github.com> * Update apps/studio/components/layouts/AppLayout/EnableBranchingButton/EnableBranchingModal.tsx Co-authored-by: Copple <10214025+kiwicopple@users.noreply.github.com> * Update apps/studio/components/interfaces/Settings/Addons/PITRSidePanel.tsx Co-authored-by: Copple <10214025+kiwicopple@users.noreply.github.com> * Update apps/studio/components/layouts/AppLayout/EnableBranchingButton/EnableBranchingModal.tsx Co-authored-by: Copple <10214025+kiwicopple@users.noreply.github.com> * Prettier --------- Co-authored-by: Copple <10214025+kiwicopple@users.noreply.github.com>
This commit is contained in:
1 parent
0c5022c170
commit
f56bfa58cb
3 files changed
+176
-58
No files matched your search
@@ -9,13 +9,23 @@ import { useTheme } from 'next-themes'
|
||||
import { useProjectAddonRemoveMutation } from 'data/subscriptions/project-addon-remove-mutation'
|
||||
import { useProjectAddonUpdateMutation } from 'data/subscriptions/project-addon-update-mutation'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { useCheckPermissions, useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useCheckPermissions, useSelectedOrganization, useSelectedProject, useStore } from 'hooks'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
|
||||
import { useSubscriptionPageStateSnapshot } from 'state/subscription-page'
|
||||
import { Alert, Button, IconExternalLink, Radio, SidePanel } from 'ui'
|
||||
import {
|
||||
Alert,
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
Alert_Shadcn_,
|
||||
Button,
|
||||
IconExternalLink,
|
||||
Radio,
|
||||
SidePanel,
|
||||
} from 'ui'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { AlertTriangleIcon } from 'lucide-react'
|
||||
|
||||
const PITR_CATEGORY_OPTIONS: {
|
||||
id: 'off' | 'on'
|
||||
@@ -42,12 +52,15 @@ const PITRSidePanel = () => {
|
||||
const router = useRouter()
|
||||
const { ref: projectRef } = useParams()
|
||||
const { resolvedTheme } = useTheme()
|
||||
const project = useSelectedProject()
|
||||
const organization = useSelectedOrganization()
|
||||
|
||||
const [selectedCategory, setSelectedCategory] = useState<'on' | 'off'>('off')
|
||||
const [selectedOption, setSelectedOption] = useState<string>('pitr_0')
|
||||
|
||||
const canUpdatePitr = useCheckPermissions(PermissionAction.BILLING_WRITE, 'stripe.subscriptions')
|
||||
const isBranchingEnabled =
|
||||
project?.is_branch_enabled === true || project?.parent_project_ref !== undefined
|
||||
|
||||
const snap = useSubscriptionPageStateSnapshot()
|
||||
const visible = snap.panelKey === 'pitr'
|
||||
@@ -225,6 +238,19 @@ const PITRSidePanel = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{selectedCategory === 'off' && subscriptionPitr !== undefined && isBranchingEnabled && (
|
||||
<Alert_Shadcn_ variant="warning">
|
||||
<AlertTriangleIcon strokeWidth={2} />
|
||||
<AlertTitle_Shadcn_>
|
||||
Are you sure you want to disable this while using Branching?
|
||||
</AlertTitle_Shadcn_>
|
||||
<AlertDescription_Shadcn_>
|
||||
Without PITR, you might not be able to recover lost data if you accidentally merge a
|
||||
branch that deletes a column or user data. We don't recommend this.
|
||||
</AlertDescription_Shadcn_>
|
||||
</Alert_Shadcn_>
|
||||
)}
|
||||
|
||||
{selectedCategory === 'on' && (
|
||||
<div className="!mt-8 pb-4">
|
||||
{isFreePlan ? (
|
||||
|
||||
+147
-55
@@ -2,7 +2,16 @@ import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { useParams } from 'common'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { Button, Form_Shadcn_, IconFileText, IconGitBranch, Modal } from 'ui'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
Alert_Shadcn_,
|
||||
Button,
|
||||
Form_Shadcn_,
|
||||
IconFileText,
|
||||
IconGitBranch,
|
||||
Modal,
|
||||
} from 'ui'
|
||||
import * as z from 'zod'
|
||||
|
||||
import SidePanelGitHubRepoLinker from 'components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker'
|
||||
@@ -14,6 +23,10 @@ import { useOrgIntegrationsQuery } from 'data/integrations/integrations-query-or
|
||||
import { useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import GithubRepositorySelection from './GithubRepositorySelection'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { AlertCircleIcon } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
|
||||
const EnableBranchingModal = () => {
|
||||
const { ui } = useStore()
|
||||
@@ -36,6 +49,18 @@ const EnableBranchingModal = () => {
|
||||
orgSlug: selectedOrg?.slug,
|
||||
})
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: selectedOrg?.slug })
|
||||
const isFreePlan = subscription?.plan.id === 'free'
|
||||
|
||||
const {
|
||||
data: addons,
|
||||
error: addonsError,
|
||||
isLoading: isLoadingAddons,
|
||||
isError: isErrorAddons,
|
||||
} = useProjectAddonsQuery({ projectRef: ref })
|
||||
const hasPitrEnabled =
|
||||
(addons?.selected_addons ?? []).find((addon) => addon.type === 'pitr') !== undefined
|
||||
|
||||
const hasGithubIntegrationInstalled =
|
||||
integrations?.some((integration) => integration.integration.name === 'GitHub') ?? false
|
||||
const githubIntegration = integrations?.find(
|
||||
@@ -124,7 +149,7 @@ const EnableBranchingModal = () => {
|
||||
</div>
|
||||
</Modal.Content>
|
||||
|
||||
{isLoadingIntegrations && (
|
||||
{(isLoadingIntegrations || isLoadingAddons) && (
|
||||
<>
|
||||
<Modal.Separator />
|
||||
<Modal.Content className="px-7 py-6">
|
||||
@@ -134,73 +159,140 @@ const EnableBranchingModal = () => {
|
||||
</>
|
||||
)}
|
||||
|
||||
{isErrorIntegrations && (
|
||||
{isErrorAddons && (
|
||||
<>
|
||||
<Modal.Separator />
|
||||
<Modal.Content className="px-7 py-6">
|
||||
<AlertError error={integrationsError} subject="Failed to retrieve integrations" />
|
||||
<AlertError error={addonsError} subject="Failed to retrieve project addons" />
|
||||
</Modal.Content>
|
||||
<Modal.Separator />
|
||||
</>
|
||||
)}
|
||||
|
||||
{isSuccessIntegrations && (
|
||||
<GithubRepositorySelection
|
||||
form={form}
|
||||
isChecking={isChecking}
|
||||
isValid={canSubmit}
|
||||
integration={githubIntegration}
|
||||
hasGithubIntegrationInstalled={hasGithubIntegrationInstalled}
|
||||
/>
|
||||
)}
|
||||
{hasPitrEnabled ? (
|
||||
<>
|
||||
{isErrorIntegrations && (
|
||||
<>
|
||||
<Modal.Separator />
|
||||
<Modal.Content className="px-7 py-6">
|
||||
<AlertError
|
||||
error={integrationsError}
|
||||
subject="Failed to retrieve integrations"
|
||||
/>
|
||||
</Modal.Content>
|
||||
<Modal.Separator />
|
||||
</>
|
||||
)}
|
||||
|
||||
<Modal.Content className="px-7 py-6 flex flex-col gap-3">
|
||||
<p className="text-sm text-foreground-light">Please keep in mind the following:</p>
|
||||
<div className="flex flex-row gap-4">
|
||||
<div>
|
||||
<figure className="w-10 h-10 rounded-md bg-warning-200 border border-warning-300 flex items-center justify-center">
|
||||
<IconFileText className="text-amber-900" size={20} strokeWidth={2} />
|
||||
</figure>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-foreground">
|
||||
You will not be able to use the dashboard to make changes to the database
|
||||
</p>
|
||||
{isSuccessIntegrations && (
|
||||
<GithubRepositorySelection
|
||||
form={form}
|
||||
isChecking={isChecking}
|
||||
isValid={canSubmit}
|
||||
integration={githubIntegration}
|
||||
hasGithubIntegrationInstalled={hasGithubIntegrationInstalled}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Modal.Content className="px-7 py-6 flex flex-col gap-3">
|
||||
<p className="text-sm text-foreground-light">
|
||||
Schema changes for database preview branches must be done via Git. We are
|
||||
nonetheless working on allowing the dashboard to make schema changes for preview
|
||||
branches.
|
||||
Please keep in mind the following:
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
<div className="flex flex-row gap-4">
|
||||
<div>
|
||||
<figure className="w-10 h-10 rounded-md bg-warning-200 border border-warning-300 flex items-center justify-center">
|
||||
<IconFileText className="text-amber-900" size={20} strokeWidth={2} />
|
||||
</figure>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-foreground">
|
||||
You will not be able to use the dashboard to make changes to the database
|
||||
</p>
|
||||
<p className="text-sm text-foreground-light">
|
||||
Schema changes for database Preview Branches must be made using git.
|
||||
Dashboard changes to Preview Branches are coming soon.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
|
||||
<Modal.Separator />
|
||||
<Modal.Separator />
|
||||
|
||||
<Modal.Content className="px-7">
|
||||
<div className="flex items-center space-x-2 py-2 pb-4">
|
||||
<Button
|
||||
size="medium"
|
||||
block
|
||||
disabled={isCreating}
|
||||
type="default"
|
||||
onClick={() => snap.setShowEnableBranchingModal(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
block
|
||||
size="medium"
|
||||
form={formId}
|
||||
disabled={isCreating || !canSubmit}
|
||||
loading={isCreating}
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
>
|
||||
I understand, enable branching
|
||||
</Button>
|
||||
<Modal.Content className="px-7">
|
||||
<div className="flex items-center space-x-2 py-2 pb-4">
|
||||
<Button
|
||||
size="medium"
|
||||
block
|
||||
disabled={isCreating}
|
||||
type="default"
|
||||
onClick={() => snap.setShowEnableBranchingModal(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
block
|
||||
size="medium"
|
||||
form={formId}
|
||||
disabled={isCreating || !canSubmit}
|
||||
loading={isCreating}
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
>
|
||||
I understand, enable branching
|
||||
</Button>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
</>
|
||||
) : (
|
||||
<div className="">
|
||||
<Alert_Shadcn_ className="rounded-none border-r-0 border-l-0 px-7 [&>svg]:left-6">
|
||||
<AlertCircleIcon strokeWidth={2} />
|
||||
<AlertTitle_Shadcn_>
|
||||
Point in time recovery (PITR) is required for branching
|
||||
</AlertTitle_Shadcn_>
|
||||
<AlertDescription_Shadcn_>
|
||||
This is to ensure that you can always recover data if you make a "bad
|
||||
migration". For example, if you accidentally delete a column or some of your
|
||||
production data.
|
||||
</AlertDescription_Shadcn_>
|
||||
{isFreePlan && (
|
||||
<AlertDescription_Shadcn_ className="mt-2">
|
||||
To enable PITR, you may first upgrade your organization's plan to at least
|
||||
Pro, then purchase the PITR add on for your project via the{' '}
|
||||
<Link
|
||||
href={`/project/${ref}/settings/addons?panel=pitr`}
|
||||
className="text-brand"
|
||||
>
|
||||
project settings
|
||||
</Link>
|
||||
.
|
||||
</AlertDescription_Shadcn_>
|
||||
)}
|
||||
</Alert_Shadcn_>
|
||||
<Modal.Content className="px-7">
|
||||
<div className="flex items-center justify-end space-x-2 py-4 pb-4">
|
||||
<Button
|
||||
size="tiny"
|
||||
type="default"
|
||||
onClick={() => snap.setShowEnableBranchingModal(false)}
|
||||
>
|
||||
Understood
|
||||
</Button>
|
||||
<Button size="tiny">
|
||||
<Link
|
||||
href={
|
||||
isFreePlan
|
||||
? `/org/${selectedOrg?.slug}/billing?panel=subscriptionPlan`
|
||||
: `/project/${ref}/settings/addons?panel=pitr`
|
||||
}
|
||||
>
|
||||
{isFreePlan ? 'Upgrade to Pro' : 'Enable PITR'}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
)}
|
||||
</form>
|
||||
</Form_Shadcn_>
|
||||
</Modal>
|
||||
|
||||
@@ -27,7 +27,7 @@ const AlertError = ({ ref, subject, error, className }: AlertErrorProps) => {
|
||||
|
||||
return (
|
||||
<Alert_Shadcn_ className={className} variant="warning" title={subject}>
|
||||
<IconAlertCircle className="h-4 w-4" color="bg-warning-300" strokeWidth={2} />
|
||||
<IconAlertCircle className="h-4 w-4" strokeWidth={2} />
|
||||
<AlertTitle_Shadcn_>{subject}</AlertTitle_Shadcn_>
|
||||
<AlertDescription_Shadcn_ className="flex flex-col gap-3">
|
||||
<div>
|
||||
|
||||
Reference in new issue
Block a user