Home / Function/ PreviewBranchActions() — supabase Function Reference

PreviewBranchActions() — supabase Function Reference

Architecture documentation for the PreviewBranchActions() function in Overview.tsx from the supabase codebase.

Entity Profile

Relationship Graph

Source Code

apps/studio/components/interfaces/BranchManagement/Overview.tsx lines 229–526

const PreviewBranchActions = ({
  branch,
  onSelectDeleteBranch,
  generateCreatePullRequestURL,
}: {
  branch: Branch
  repo: string
  onSelectDeleteBranch: () => void
  generateCreatePullRequestURL: (branchName?: string) => string
}) => {
  const gitlessBranching = useIsBranching2Enabled()
  const queryClient = useQueryClient()
  const { project_ref: branchRef, parent_project_ref: projectRef } = branch

  const { can: canDeleteBranches } = useAsyncCheckPermissions(
    PermissionAction.DELETE,
    'preview_branches'
  )
  const { can: canUpdateBranches } = useAsyncCheckPermissions(
    PermissionAction.UPDATE,
    'preview_branches'
  )
  // If user can update branches, they can restore branches
  const canRestoreBranches = canUpdateBranches

  const { data } = useBranchQuery({ projectRef, branchRef })
  const isBranchActiveHealthy = data?.status === 'ACTIVE_HEALTHY'
  const isPersistentBranch = branch.persistent

  const { hasAccess: hasAccessToPersistentBranching } = useCheckEntitlements('branching_persistent')

  const [showConfirmResetModal, setShowConfirmResetModal] = useState(false)
  const [showBranchModeSwitch, setShowBranchModeSwitch] = useState(false)
  const [
    showPersistentBranchDeleteConfirmationModal,
    setShowPersistentBranchDeleteConfirmationModal,
  ] = useState(false)
  const [showEditBranchModal, setShowEditBranchModal] = useState(false)

  const { mutate: resetBranch, isPending: isResetting } = useBranchResetMutation({
    onSuccess() {
      toast.success('Success! Please allow a few seconds for the branch to reset.')
      setShowConfirmResetModal(false)
    },
  })

  const { mutate: updateBranch, isPending: isUpdatingBranch } = useBranchUpdateMutation({
    onSuccess() {
      toast.success('Successfully updated branch')
      setShowBranchModeSwitch(false)
      if (projectRef) {
        queryClient.invalidateQueries({ queryKey: branchKeys.list(projectRef) })
      }
    },
  })
  const { mutate: restoreBranch } = useBranchRestoreMutation({
    onSuccess() {
      toast.success('Success! Please allow a few minutes for the branch to restore.')
      setShowBranchModeSwitch(false)
    },
  })

  const onRestoreBranch = () => {
    restoreBranch({ branchRef, projectRef })
  }

  const onConfirmReset = () => {
    resetBranch({ branchRef, projectRef })
  }

  const onTogglePersistent = () => {
    updateBranch({ branchRef, projectRef, persistent: !branch.persistent })
  }

  const onDeleteBranch = (e: Event | React.MouseEvent<HTMLDivElement>) => {
    if (isPersistentBranch) {
      setShowPersistentBranchDeleteConfirmationModal(true)
    } else {
      e.stopPropagation()
      onSelectDeleteBranch()
    }
  }

  return (
    <>
      <DropdownMenu>
        <DropdownMenuTrigger asChild>
          <Button
            type="text"
            icon={<MoreVertical />}
            className="px-1"
            onClick={(e) => e.stopPropagation()}
          />
        </DropdownMenuTrigger>
        <DropdownMenuContent className="w-56" side="bottom" align="end">
          {/* Edit Branch (gitless) */}
          {gitlessBranching && (
            <DropdownMenuItemTooltip
              className="gap-x-2"
              disabled={!canUpdateBranches || !isBranchActiveHealthy || isUpdatingBranch}
              onSelect={(e) => {
                e.stopPropagation()
                setShowEditBranchModal(true)
              }}
              onClick={(e) => {
                e.stopPropagation()
                setShowEditBranchModal(true)
              }}
              tooltip={{
                content: {
                  side: 'left',
                  text: !canUpdateBranches
                    ? 'You need additional permissions to edit branches'
                    : !isBranchActiveHealthy
                      ? 'Branch is still initializing. Please wait for it to become healthy before editing.'
                      : undefined,
                },
              }}
            >
              <Pencil size={14} /> Edit branch
            </DropdownMenuItemTooltip>
          )}

          {!branch.deletion_scheduled_at && (
            <DropdownMenuItemTooltip
              className="gap-x-2"
              disabled={isResetting || !isBranchActiveHealthy}
              onSelect={(e) => {
                e.stopPropagation()
                setShowConfirmResetModal(true)
              }}
              onClick={(e) => {
                e.stopPropagation()
                setShowConfirmResetModal(true)
              }}
              tooltip={{
                content: {
                  side: 'left',
                  text: !isBranchActiveHealthy
                    ? 'Branch is still initializing. Please wait for it to become healthy before resetting.'
                    : undefined,
                },
              }}
            >
              <RefreshCw size={14} /> Reset branch
            </DropdownMenuItemTooltip>
          )}

          {!branch.deletion_scheduled_at && (
            <DropdownMenuItemTooltip
              className="gap-x-2"
              disabled={
                !isBranchActiveHealthy || (!branch.persistent && !hasAccessToPersistentBranching)
              }
              onSelect={(e) => {
                e.stopPropagation()
                setShowBranchModeSwitch(true)
              }}
              onClick={(e) => {
                e.stopPropagation()
                setShowBranchModeSwitch(true)
              }}
              tooltip={{
                content: {
                  side: 'left',
                  text: !isBranchActiveHealthy
                    ? 'Branch is still initializing. Please wait for it to become healthy before switching.'
                    : !branch.persistent && !hasAccessToPersistentBranching
                      ? 'Upgrade your plan to access persistent branches'
                      : undefined,
                },
              }}
            >
              {branch.persistent ? (
                <>
                  <Clock size={14} /> Switch to preview
                </>
              ) : (
                <>
                  <Infinity size={14} className="scale-110" /> Switch to persistent
                </>
              )}
            </DropdownMenuItemTooltip>
          )}

          {/* Create PR if applicable */}
          {branch.git_branch && branch.pr_number === undefined && (
            <DropdownMenuItem asChild className="gap-x-2">
              <a
                target="_blank"
                rel="noreferrer"
                href={generateCreatePullRequestURL(branch.git_branch)}
                onClick={(e) => e.stopPropagation()}
              >
                <ExternalLink size={14} /> Create pull request
              </a>
            </DropdownMenuItem>
          )}
          {branch.deletion_scheduled_at && (
            <DropdownMenuItemTooltip
              className="gap-x-2"
              disabled={!canRestoreBranches || branch.preview_project_status !== 'INACTIVE'}
              onSelect={(e) => {
                e.stopPropagation()
                onRestoreBranch()
              }}
              onClick={(e) => {
                e.stopPropagation()
                onRestoreBranch()
              }}
              tooltip={{
                content: {
                  side: 'left',
                  text: !canRestoreBranches
                    ? 'You need additional permissions to restore branches'
                    : branch.preview_project_status !== 'INACTIVE'
                      ? 'Preview project is not fully paused or already coming up. Please wait for it to become fully paused before restoring.'
                      : undefined,
                },
              }}
            >
              <Clock size={14} /> Restore branch
            </DropdownMenuItemTooltip>
          )}

          <DropdownMenuSeparator />

          <DropdownMenuItemTooltip
            className="gap-x-2"
            disabled={!canDeleteBranches}
            onSelect={onDeleteBranch}
            onClick={onDeleteBranch}
            tooltip={{
              content: {
                side: 'left',
                text: !canDeleteBranches
                  ? 'You need additional permissions to delete branches'
                  : undefined,
              },
            }}
          >
            <Trash2 size={14} /> Delete branch
          </DropdownMenuItemTooltip>
        </DropdownMenuContent>
      </DropdownMenu>

      <TextConfirmModal
        variant="warning"
        visible={showConfirmResetModal}
        onCancel={() => setShowConfirmResetModal(false)}
        onConfirm={onConfirmReset}
        loading={isResetting}
        title="Reset branch"
        confirmLabel="Reset branch"
        confirmPlaceholder="Type in name of branch"
        confirmString={branch?.name ?? ''}
        alert={{
          title: `Are you sure you want to reset the "${branch.name}" branch? All data will be deleted.`,
        }}
      />

      <ConfirmationModal
        variant="default"
        visible={showBranchModeSwitch}
        confirmLabel={branch.persistent ? 'Switch to preview' : 'Switch to persistent'}
        title="Confirm branch mode switch"
        loading={isUpdatingBranch}
        onCancel={() => setShowBranchModeSwitch(false)}
        onConfirm={onTogglePersistent}
      >
        <p className="text-sm text-foreground-light">
          Are you sure you want to switch the branch "{branch.name}" to{' '}
          {branch.persistent ? 'preview' : 'persistent'}?
        </p>
      </ConfirmationModal>

      <ConfirmationModal
        variant="warning"
        visible={showPersistentBranchDeleteConfirmationModal}
        confirmLabel={'Switch to preview'}
        title="Branch must be switched to preview before deletion"
        loading={isUpdatingBranch}
        onCancel={() => setShowPersistentBranchDeleteConfirmationModal(false)}
        onConfirm={onTogglePersistent}
      >
        <p className="text-sm text-foreground-light">
          You must switch the branch "{branch.name}" to preview before deleting it.
        </p>
      </ConfirmationModal>

      <EditBranchModal
        branch={branch}
        visible={showEditBranchModal}
        onClose={() => setShowEditBranchModal(false)}
      />
    </>
  )
}

Subdomains

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free