From fa62afb09765be473c698d8b5561b202db28f7cb Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Mon, 8 Sep 2025 16:58:54 +0800 Subject: [PATCH 001/152] fix: do not auto submit on toggling data branch (#38479) * fix: display badge instead of tooltip * Clean up --------- Co-authored-by: Joshen Lim --- .../BranchManagement/CreateBranchModal.tsx | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/apps/studio/components/interfaces/BranchManagement/CreateBranchModal.tsx b/apps/studio/components/interfaces/BranchManagement/CreateBranchModal.tsx index 9ffa0387be7..9fb2103792b 100644 --- a/apps/studio/components/interfaces/BranchManagement/CreateBranchModal.tsx +++ b/apps/studio/components/interfaces/BranchManagement/CreateBranchModal.tsx @@ -46,9 +46,6 @@ import { Input_Shadcn_, Label_Shadcn_ as Label, Switch, - Tooltip, - TooltipContent, - TooltipTrigger, cn, } from 'ui' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' @@ -92,7 +89,11 @@ export const CreateBranchModal = () => { useCheckGithubBranchValidity({ onError: () => {}, }) - const { data: cloneBackups, error: cloneBackupsError } = useCloneBackupsQuery( + const { + data: cloneBackups, + error: cloneBackupsError, + isLoading: isLoadingCloneBackups, + } = useCloneBackupsQuery( { projectRef }, { // [Joshen] Only trigger this request when the modal is opened @@ -359,26 +360,29 @@ export const CreateBranchModal = () => { name="withData" render={({ field }) => ( + + {!disableBackupsCheck && (isLoadingCloneBackups || noPhysicalBackups) && ( + + Requires PITR + + )} + + } layout="flex-row-reverse" + className="[&>div>label]:mb-1" description="Clone production data into this branch" > - - - - - - - {!disableBackupsCheck && noPhysicalBackups && ( - - PITR is required for the project to clone data into the branch - - )} - + + + )} /> From fa4510dae74e50cbefb07f19632bf5e17911609a Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Mon, 8 Sep 2025 17:29:43 +0800 Subject: [PATCH 002/152] Update RestoreFailedState and PauseFailedState to include link to database backups upfront (#38510) * Update RestoreFailedState and PauseFailedState to include link to database backups upfront * Update tooltip text --- .../ProjectLayout/PauseFailedState.tsx | 30 +++++++++++----- .../layouts/ProjectLayout/ProjectLayout.tsx | 4 +-- .../ProjectLayout/RestoreFailedState.tsx | 34 +++++++++++++------ 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/apps/studio/components/layouts/ProjectLayout/PauseFailedState.tsx b/apps/studio/components/layouts/ProjectLayout/PauseFailedState.tsx index 0ba928c7ed5..d82d07658b7 100644 --- a/apps/studio/components/layouts/ProjectLayout/PauseFailedState.tsx +++ b/apps/studio/components/layouts/ProjectLayout/PauseFailedState.tsx @@ -7,20 +7,25 @@ import { useParams } from 'common' import { DeleteProjectModal } from 'components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectModal' import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { DropdownMenuItemTooltip } from 'components/ui/DropdownMenuItemTooltip' +import { InlineLink } from 'components/ui/InlineLink' import { useBackupDownloadMutation } from 'data/database/backup-download-mutation' import { useDownloadableBackupQuery } from 'data/database/backup-query' -import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' +import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { Button, CriticalIcon, DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from 'ui' -const PauseFailedState = () => { +export const PauseFailedState = () => { const { ref } = useParams() const { data: project } = useSelectedProjectQuery() const [visible, setVisible] = useState(false) - const canDeleteProject = useCheckPermissions(PermissionAction.UPDATE, 'projects', { - resource: { project_id: project?.id }, - }) + const { can: canDeleteProject } = useAsyncCheckProjectPermissions( + PermissionAction.UPDATE, + 'projects', + { + resource: { project_id: project?.id }, + } + ) const { data } = useDownloadableBackupQuery({ projectRef: ref }) const backups = data?.backups ?? [] @@ -57,7 +62,11 @@ const PauseFailedState = () => {

Something went wrong while pausing your project

Your project's data is intact, but your project is inaccessible due to the failure - while pausing. Please contact support for assistance. + while pausing. Database backups for this project can still be accessed{' '} + here. +

+

+ Please contact support for assistance.

@@ -78,7 +87,12 @@ const PauseFailedState = () => { tooltip={{ content: { side: 'bottom', - text: backups.length === 0 ? 'No available backups to download' : undefined, + text: + data?.status === 'physical-backups-enabled' + ? 'No available backups to download as project is on physical backups' + : backups.length === 0 + ? 'No available backups to download' + : undefined, }, }} onClick={onClickDownloadBackup} @@ -123,5 +137,3 @@ const PauseFailedState = () => { ) } - -export default PauseFailedState diff --git a/apps/studio/components/layouts/ProjectLayout/ProjectLayout.tsx b/apps/studio/components/layouts/ProjectLayout/ProjectLayout.tsx index 47e0c76f2b9..90cd9ca6892 100644 --- a/apps/studio/components/layouts/ProjectLayout/ProjectLayout.tsx +++ b/apps/studio/components/layouts/ProjectLayout/ProjectLayout.tsx @@ -24,12 +24,12 @@ import BuildingState from './BuildingState' import ConnectingState from './ConnectingState' import { LoadingState } from './LoadingState' import { ProjectPausedState } from './PausedState/ProjectPausedState' -import PauseFailedState from './PauseFailedState' +import { PauseFailedState } from './PauseFailedState' import PausingState from './PausingState' import ProductMenuBar from './ProductMenuBar' import { ResizingState } from './ResizingState' import RestartingState from './RestartingState' -import RestoreFailedState from './RestoreFailedState' +import { RestoreFailedState } from './RestoreFailedState' import RestoringState from './RestoringState' import { UpgradingState } from './UpgradingState' diff --git a/apps/studio/components/layouts/ProjectLayout/RestoreFailedState.tsx b/apps/studio/components/layouts/ProjectLayout/RestoreFailedState.tsx index 9120f3b2f4d..edb62abd66c 100644 --- a/apps/studio/components/layouts/ProjectLayout/RestoreFailedState.tsx +++ b/apps/studio/components/layouts/ProjectLayout/RestoreFailedState.tsx @@ -7,20 +7,23 @@ import { useParams } from 'common' import { DeleteProjectModal } from 'components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectModal' import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { DropdownMenuItemTooltip } from 'components/ui/DropdownMenuItemTooltip' +import { InlineLink } from 'components/ui/InlineLink' import { useBackupDownloadMutation } from 'data/database/backup-download-mutation' import { useDownloadableBackupQuery } from 'data/database/backup-query' -import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' +import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { Button, CriticalIcon, DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from 'ui' -const RestoreFailedState = () => { +export const RestoreFailedState = () => { const { ref } = useParams() const { data: project } = useSelectedProjectQuery() const [visible, setVisible] = useState(false) - const canDeleteProject = useCheckPermissions(PermissionAction.UPDATE, 'projects', { - resource: { project_id: project?.id }, - }) + const { can: canDeleteProject } = useAsyncCheckProjectPermissions( + PermissionAction.UPDATE, + 'projects', + { resource: { project_id: project?.id } } + ) const { data } = useDownloadableBackupQuery({ projectRef: ref }) const backups = data?.backups ?? [] @@ -56,8 +59,12 @@ const RestoreFailedState = () => {

Something went wrong while restoring your project

- Your project's data is intact, but your project is inaccessible due to the - restoration failure. Please contact support for assistance. + Your project's data is intact, but your project is inaccessible due to a + restoration failure. Database backups for this project can still be accessed{' '} + here. +

+

+ Please contact support for assistance.

@@ -70,6 +77,7 @@ const RestoreFailedState = () => { Contact support + } @@ -78,16 +86,22 @@ const RestoreFailedState = () => { tooltip={{ content: { side: 'bottom', - text: backups.length === 0 ? 'No available backups to download' : undefined, + text: + data?.status === 'physical-backups-enabled' + ? 'No available backups to download as project is on physical backups' + : backups.length === 0 + ? 'No available backups to download' + : undefined, }, }} onClick={onClickDownloadBackup} > Download backup + -