workflow refactor

This commit is contained in:
Saxon Fletcher committed 2025-06-30 16:36:34 +10:00
1 parent 5523b3c695
commit cbd86af632
5 files changed
+240 -224

No files matched your search

@@ -17,10 +17,10 @@ import { Admonition } from 'ui-patterns'
interface OutOfDateNoticeProps {
isBranchOutOfDateMigrations: boolean
missingMigrationsCount: number
hasNewerRemovedFunctions: boolean
newerRemovedFunctionsCount: number
hasNewerModifiedFunctions: boolean
newerModifiedFunctionsCount: number
hasMissingFunctions: boolean
missingFunctionsCount: number
hasOutOfDateFunctions: boolean
outOfDateFunctionsCount: number
hasEdgeFunctionModifications: boolean
modifiedFunctionsCount: number
isPushing: boolean
@@ -30,10 +30,10 @@ interface OutOfDateNoticeProps {
export const OutOfDateNotice = ({
isBranchOutOfDateMigrations,
missingMigrationsCount,
hasNewerRemovedFunctions,
newerRemovedFunctionsCount,
hasNewerModifiedFunctions,
newerModifiedFunctionsCount,
hasMissingFunctions,
missingFunctionsCount,
hasOutOfDateFunctions,
outOfDateFunctionsCount,
hasEdgeFunctionModifications,
modifiedFunctionsCount,
isPushing,
@@ -43,29 +43,18 @@ export const OutOfDateNotice = ({
const hasOutdatedMigrations = isBranchOutOfDateMigrations && missingMigrationsCount > 0
const getTitle = () => {
if (hasOutdatedMigrations && (hasNewerRemovedFunctions || hasNewerModifiedFunctions)) {
const functionCount = newerRemovedFunctionsCount + newerModifiedFunctionsCount
return `Missing ${missingMigrationsCount} migration${missingMigrationsCount !== 1 ? 's' : ''} and ${functionCount} updated function${functionCount !== 1 ? 's' : ''} from main branch`
if (hasOutdatedMigrations && (hasMissingFunctions || hasOutOfDateFunctions)) {
return 'Your database schema and edge functions are out of date'
} else if (hasOutdatedMigrations) {
return `Missing ${missingMigrationsCount} migration${missingMigrationsCount !== 1 ? 's' : ''} from main branch`
} else if (hasNewerRemovedFunctions && hasNewerModifiedFunctions) {
const functionCount = newerRemovedFunctionsCount + newerModifiedFunctionsCount
return `Main branch has ${functionCount} updated function${functionCount !== 1 ? 's' : ''}`
} else if (hasNewerRemovedFunctions) {
return `Main branch has ${newerRemovedFunctionsCount} updated function${newerRemovedFunctionsCount !== 1 ? 's' : ''} that were removed in this branch`
} else if (hasNewerModifiedFunctions) {
return `Main branch has ${newerModifiedFunctionsCount} updated function${newerModifiedFunctionsCount !== 1 ? 's' : ''}`
return 'Your database schema is out of date'
} else if (hasMissingFunctions || hasOutOfDateFunctions) {
return 'Your functions are out of date'
}
return 'Branch is out of date'
}
const getDescription = () => {
if (hasOutdatedMigrations && (hasNewerRemovedFunctions || hasNewerModifiedFunctions)) {
return `The main branch has migrations and functions that were updated after this branch was created.`
} else if (hasNewerRemovedFunctions || hasNewerModifiedFunctions) {
return `The main branch has functions that were created or updated after this branch was created.`
}
return 'Update this branch to get the latest changes from the main branch.'
return 'Update this branch to get the latest changes from the production branch.'
}
const handleUpdateClick = () => {
@@ -103,7 +92,8 @@ export const OutOfDateNotice = ({
<AlertDialogDescription>
This branch has {modifiedFunctionsCount} modified edge function
{modifiedFunctionsCount !== 1 ? 's' : ''} that will be overwritten when updating
with the latest functions from the main branch, and this action cannot be undone.
with the latest functions from the production branch. This action cannot be
undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
@@ -2,128 +2,97 @@ import React from 'react'
import { Card, CardHeader, CardContent, CardTitle, Button } from 'ui'
import { motion } from 'framer-motion'
import { CircleDotDashed, GitMerge, X, AlertTriangle } from 'lucide-react'
import Link from 'next/link'
import { useWorkflowRunQuery } from 'data/workflow-runs/workflow-run-query'
import { useWorkflowRunsQuery } from 'data/workflow-runs/workflow-runs-query'
interface WorkflowRun {
id: string
status: string
branch_id?: string
check_run_id?: number | null
created_at?: string
updated_at?: string
workdir?: string | null
git_config?: unknown
}
interface WorkflowLogsCardProps {
workflowRunId: string
projectRef: string
workflowRun: WorkflowRun | null | undefined
logs: string | undefined
isLoading?: boolean
onClose?: () => void
onStatusChange?: (status: string, workflowRunId: string) => void
statusComplete?: string // Status that indicates completion (e.g., 'FUNCTIONS_DEPLOYED')
statusFailed?: string[] // Statuses that indicate failure (e.g., ['MIGRATIONS_FAILED', 'FUNCTIONS_FAILED'])
headerTitle?: string // Additional header title
headerDescription?: string // Additional header description
headerIcon?: React.ReactNode // Additional header icon
headerAction?: React.ReactNode // Additional header action button
// Override props for failed workflows
overrideTitle?: string
overrideDescription?: string
overrideIcon?: React.ReactNode
overrideAction?: React.ReactNode
}
const WorkflowLogsCard: React.FC<WorkflowLogsCardProps> = ({
workflowRunId,
projectRef,
workflowRun,
logs,
isLoading = false,
onClose,
onStatusChange,
statusComplete = 'FUNCTIONS_DEPLOYED',
statusFailed = ['MIGRATIONS_FAILED', 'FUNCTIONS_FAILED'],
headerTitle,
headerDescription,
headerIcon,
headerAction,
overrideTitle,
overrideDescription,
overrideIcon,
overrideAction,
}) => {
const scrollRef = React.useRef<HTMLDivElement>(null)
// Get workflow runs for the specified project to find the workflow run
const { data: workflowRuns } = useWorkflowRunsQuery(
{ projectRef },
{
enabled: !!projectRef,
refetchInterval: 3000, // Always poll
refetchOnMount: 'always',
refetchOnWindowFocus: true,
staleTime: 0,
}
)
// Find the current workflow run
const currentWorkflowRun = React.useMemo(() => {
if (!workflowRunId) return null
return workflowRuns?.find((run) => run.id === workflowRunId)
}, [workflowRuns, workflowRunId])
// Query for workflow run logs with continuous polling
const { data: workflowRunLogs } = useWorkflowRunQuery(
{ workflowRunId },
{
enabled: !!workflowRunId,
refetchInterval: 2000, // Always poll every 2 seconds
refetchOnMount: 'always',
refetchOnWindowFocus: true,
staleTime: 0, // Always fetch fresh data
}
)
// Auto-scroll to bottom when logs change
React.useEffect(() => {
if (scrollRef.current && workflowRunLogs?.logs) {
if (scrollRef.current && logs) {
scrollRef.current.scrollTop = scrollRef.current.scrollHeight
}
}, [workflowRunLogs?.logs])
}, [logs])
// Call onStatusChange when status changes
React.useEffect(() => {
if (currentWorkflowRun?.status && onStatusChange) {
onStatusChange(currentWorkflowRun.status, workflowRunId)
}
}, [currentWorkflowRun?.status, onStatusChange, workflowRunId])
const showSuccessIcon = currentWorkflowRun?.status === statusComplete
const isFailed = currentWorkflowRun?.status && statusFailed.includes(currentWorkflowRun.status)
const showSuccessIcon = workflowRun?.status === 'FUNCTIONS_DEPLOYED'
const isFailed =
workflowRun?.status && ['MIGRATIONS_FAILED', 'FUNCTIONS_FAILED'].includes(workflowRun.status)
const isPolling =
currentWorkflowRun?.status !== statusComplete &&
(!currentWorkflowRun?.status || !statusFailed.includes(currentWorkflowRun.status))
workflowRun?.status !== 'FUNCTIONS_DEPLOYED' &&
(!workflowRun?.status ||
!['MIGRATIONS_FAILED', 'FUNCTIONS_FAILED'].includes(workflowRun.status))
const displayTitle =
overrideTitle ||
(isPolling
? 'Processing...'
: showSuccessIcon
? 'Workflow completed successfully'
: isFailed
? 'Workflow failed'
: 'Workflow completed')
const displayIcon =
overrideIcon ||
(isPolling ? (
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 2, repeat: Infinity, ease: 'linear' }}
>
<CircleDotDashed size={16} strokeWidth={1.5} className="text-warning" />
</motion.div>
) : showSuccessIcon ? (
<GitMerge size={16} strokeWidth={1.5} className="text-brand" />
) : null)
return (
<Card className="bg-background overflow-hidden h-64 flex flex-col">
<CardHeader className={showSuccessIcon ? 'text-brand' : isFailed ? 'text-destructive' : ''}>
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
{/* Custom icon or activity / success indicator */}
{headerIcon ? (
headerIcon
) : isPolling ? (
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 2, repeat: Infinity, ease: 'linear' }}
>
<CircleDotDashed size={16} strokeWidth={1.5} className="text-warning" />
</motion.div>
) : (
showSuccessIcon && <GitMerge size={16} strokeWidth={1.5} className="text-brand" />
)}
{displayIcon}
<div>
{/* Custom title or default status text */}
<CardTitle className="text-sm font-medium">
{headerTitle ||
(isPolling
? 'Processing...'
: showSuccessIcon
? 'Workflow completed successfully'
: isFailed
? 'Workflow failed'
: 'Workflow completed')}
</CardTitle>
{/* Custom description */}
{headerDescription && (
<CardTitle className="text-sm font-medium">{displayTitle}</CardTitle>
{overrideDescription && (
<div className="text-sm text-foreground-light font-normal mt-0">
{headerDescription}
{overrideDescription}
</div>
)}
</div>
</div>
<div className="flex items-center gap-4">
{/* Custom action or default close button */}
{headerAction && headerAction}
{overrideAction && overrideAction}
{onClose && (
<Button
type="text"
@@ -142,13 +111,11 @@ const WorkflowLogsCard: React.FC<WorkflowLogsCardProps> = ({
>
{/* sticky gradient overlay */}
<div className="sticky top-0 -mb-8 h-8 bg-gradient-to-b from-background to-transparent pointer-events-none z-10" />
{workflowRunLogs?.logs ? (
<pre className="p-6 text-xs text-foreground-light p-0 rounded">
{workflowRunLogs.logs}
</pre>
{logs ? (
<pre className="p-6 text-xs text-foreground-light p-0 rounded">{logs}</pre>
) : (
<pre className="p-6 text-sm text-foreground-light rounded">
{isPolling ? 'Initializing workflow...' : 'Waiting for logs...'}
{isLoading || isPolling ? 'Initializing workflow...' : 'Waiting for logs...'}
</pre>
)}
</CardContent>
+14 -14
View File
@@ -32,10 +32,10 @@ export interface BranchMergeDiffResult {
// Branch state
isBranchOutOfDateMigrations: boolean
hasEdgeFunctionModifications: boolean
newerRemovedFunctionsCount: number
hasNewerRemovedFunctions: boolean
newerModifiedFunctionsCount: number
hasNewerModifiedFunctions: boolean
missingFunctionsCount: number
hasMissingFunctions: boolean
outOfDateFunctionsCount: number
hasOutOfDateFunctions: boolean
isBranchOutOfDateOverall: boolean
missingMigrationsCount: number
modifiedFunctionsCount: number
@@ -120,7 +120,7 @@ export const useBranchMergeDiff = ({
}, [currentBranchMigrations, mainBranchMigrations])
// Check if main branch has functions that are newer than the current branch versions
const newerModifiedFunctionsCount = useMemo(() => {
const outOfDateFunctionsCount = useMemo(() => {
if (!edgeFunctionsDiff.modifiedSlugs.length) return 0
return edgeFunctionsDiff.modifiedSlugs.filter((slug) => {
@@ -145,16 +145,16 @@ export const useBranchMergeDiff = ({
])
// Check if main branch has functions that are newer than the current branch versions
const hasNewerModifiedFunctions = newerModifiedFunctionsCount > 0
const hasOutOfDateFunctions = outOfDateFunctionsCount > 0
// Check if current branch has any edge function modifications (not additions/removals)
// This only includes functions where the current branch version is newer than the main branch version
const hasEdgeFunctionModifications =
edgeFunctionsDiff.modifiedSlugs.length > newerModifiedFunctionsCount
edgeFunctionsDiff.modifiedSlugs.length > outOfDateFunctionsCount
// Count of removed functions that were updated on main branch after this branch was created
// Note: For removed functions, we use branch creation date since there's no current branch version to compare to
const newerRemovedFunctionsCount = useMemo(() => {
const missingFunctionsCount = useMemo(() => {
if (!currentBranchCreatedAt || !edgeFunctionsDiff.removedSlugs.length) return 0
const branchCreatedAt = new Date(currentBranchCreatedAt).getTime()
@@ -175,11 +175,11 @@ export const useBranchMergeDiff = ({
])
// Check if main branch has functions removed from current branch that were updated after branch creation
const hasNewerRemovedFunctions = newerRemovedFunctionsCount > 0
const hasMissingFunctions = missingFunctionsCount > 0
// Update overall out-of-date check to include newer removed functions and newer modified functions
const isBranchOutOfDateOverall =
isBranchOutOfDateMigrations || hasNewerRemovedFunctions || hasNewerModifiedFunctions
isBranchOutOfDateMigrations || hasMissingFunctions || hasOutOfDateFunctions
// Get the count of migrations that the branch is missing
const missingMigrationsCount = useMemo(() => {
@@ -225,10 +225,10 @@ export const useBranchMergeDiff = ({
// Branch state
isBranchOutOfDateMigrations,
hasEdgeFunctionModifications,
newerRemovedFunctionsCount,
hasNewerRemovedFunctions,
newerModifiedFunctionsCount,
hasNewerModifiedFunctions,
missingFunctionsCount,
hasMissingFunctions,
outOfDateFunctionsCount,
hasOutOfDateFunctions,
isBranchOutOfDateOverall,
missingMigrationsCount,
modifiedFunctionsCount,
@@ -0,0 +1,66 @@
import { useState, useEffect } from 'react'
import { useWorkflowRunsQuery } from 'data/workflow-runs/workflow-runs-query'
import { useWorkflowRunQuery } from 'data/workflow-runs/workflow-run-query'
interface UseWorkflowManagementProps {
workflowRunId?: string
projectRef?: string
onWorkflowComplete?: (status: string) => void
}
export const useWorkflowManagement = ({
workflowRunId,
projectRef,
onWorkflowComplete,
}: UseWorkflowManagementProps) => {
const [hasRefetched, setHasRefetched] = useState(false)
// Get workflow runs and logs
const { data: workflowRuns } = useWorkflowRunsQuery(
{ projectRef },
{
enabled: !!projectRef && !!workflowRunId,
refetchInterval: 3000,
refetchOnMount: 'always',
staleTime: 0,
}
)
const { data: workflowRunLogs } = useWorkflowRunQuery(
{ workflowRunId },
{
enabled: !!workflowRunId,
refetchInterval: 2000,
refetchOnMount: 'always',
staleTime: 0,
}
)
// Find current workflow run
const currentWorkflowRun = workflowRuns?.find((run) => run.id === workflowRunId)
// Handle workflow completion
useEffect(() => {
if (!currentWorkflowRun?.status || !workflowRunId) return
const isComplete = ['FUNCTIONS_DEPLOYED', 'MIGRATIONS_FAILED', 'FUNCTIONS_FAILED'].includes(
currentWorkflowRun.status
)
// Only refetch once per workflow completion
if (isComplete && !hasRefetched) {
setHasRefetched(true)
onWorkflowComplete?.(currentWorkflowRun.status)
}
}, [currentWorkflowRun?.status, workflowRunId, hasRefetched, onWorkflowComplete])
// Reset refetch flag when workflow ID changes
useEffect(() => {
setHasRefetched(false)
}, [workflowRunId])
return {
currentWorkflowRun,
workflowRunLogs: workflowRunLogs?.logs,
}
}
+79 -86
View File
@@ -12,12 +12,14 @@ import { useBranchesQuery } from 'data/branches/branches-query'
import { useBranchMergeMutation } from 'data/branches/branch-merge-mutation'
import { useBranchPushMutation } from 'data/branches/branch-push-mutation'
import { useBranchMergeDiff } from 'hooks/misc/useBranchMergeDiff'
import { useWorkflowManagement } from 'hooks/misc/useWorkflowManagement'
import DatabaseDiffPanel from 'components/interfaces/BranchManagement/DatabaseDiffPanel'
import EdgeFunctionsDiffPanel from 'components/interfaces/BranchManagement/EdgeFunctionsDiffPanel'
import { OutOfDateNotice } from 'components/interfaces/BranchManagement/OutOfDateNotice'
import { Badge, Button, NavMenu, NavMenuItem, cn, Alert } from 'ui'
import { toast } from 'sonner'
import type { NextPageWithLayout } from 'types'
import { ScaffoldContainer } from 'components/layouts/Scaffold'
import { GitBranchIcon, GitMerge, Shield, ExternalLink, AlertTriangle } from 'lucide-react'
import Link from 'next/link'
@@ -34,12 +36,7 @@ const MergePage: NextPageWithLayout = () => {
const project = useSelectedProject()
const [isSubmitting, setIsSubmitting] = useState(false)
// State to track related workflow runs with their project refs
const [relatedWorkflowRunIds, setRelatedWorkflowRunIds] = useState<Record<string, string>>({})
// State to track failed workflows
const [failedWorkflowIds, setFailedWorkflowIds] = useState<Set<string>>(new Set())
const [workflowFinalStatus, setWorkflowFinalStatus] = useState<string | null>(null)
const isBranch = project?.parent_project_ref !== undefined
const parentProjectRef = project?.parent_project_ref
@@ -59,18 +56,6 @@ const MergePage: NextPageWithLayout = () => {
const currentBranch = branches?.find((branch) => branch.project_ref === ref)
const mainBranch = branches?.find((branch) => branch.is_default)
// Get workflow run ID from URL query parameter and initialize state
useEffect(() => {
const workflowRunId = router.query.workflow_run_id as string | undefined
if (workflowRunId && !relatedWorkflowRunIds[workflowRunId]) {
// Default to current branch project ref if not specified
setRelatedWorkflowRunIds((prev) => ({
...prev,
[workflowRunId]: ref || '',
}))
}
}, [router.query.workflow_run_id, ref, relatedWorkflowRunIds])
// Get combined diff data (database, edge functions, migrations, and branch state)
const {
diffContent,
@@ -81,10 +66,10 @@ const MergePage: NextPageWithLayout = () => {
edgeFunctionsDiff,
isBranchOutOfDateMigrations,
hasEdgeFunctionModifications,
newerRemovedFunctionsCount,
hasNewerRemovedFunctions,
newerModifiedFunctionsCount,
hasNewerModifiedFunctions,
missingFunctionsCount,
hasMissingFunctions,
outOfDateFunctionsCount,
hasOutOfDateFunctions,
isBranchOutOfDateOverall,
missingMigrationsCount,
modifiedFunctionsCount,
@@ -99,43 +84,74 @@ const MergePage: NextPageWithLayout = () => {
currentBranchCreatedAt: currentBranch?.created_at,
})
// Handle workflow completion - refetch diff once when workflow completes or fails
const handleWorkflowStatusChange = useCallback(
(status: string, workflowRunId: string) => {
const isComplete =
status === 'FUNCTIONS_DEPLOYED' ||
status === 'MIGRATIONS_FAILED' ||
status === 'FUNCTIONS_FAILED'
// Get workflow run ID from URL
const currentWorkflowRunId = router.query.workflow_run_id as string | undefined
const isFailed = status === 'MIGRATIONS_FAILED' || status === 'FUNCTIONS_FAILED'
// Reset workflow status when workflow ID changes
useEffect(() => {
setWorkflowFinalStatus(null)
}, [currentWorkflowRunId])
if (isFailed) {
setFailedWorkflowIds((prev) => new Set(prev).add(workflowRunId))
}
if (isComplete) {
// Refetch diff and edge functions once when workflow completes
// Try current branch first, then parent branch
const { currentWorkflowRun: currentBranchWorkflow, workflowRunLogs: currentBranchLogs } =
useWorkflowManagement({
workflowRunId: currentWorkflowRunId,
projectRef: ref,
onWorkflowComplete: (status) => {
setWorkflowFinalStatus(status)
refetchDiff()
edgeFunctionsDiff.refetchCurrentBranchFunctions()
edgeFunctionsDiff.refetchMainBranchFunctions()
}
},
})
const { currentWorkflowRun: parentBranchWorkflow, workflowRunLogs: parentBranchLogs } =
useWorkflowManagement({
workflowRunId: currentWorkflowRunId,
projectRef: parentProjectRef,
onWorkflowComplete: (status) => {
setWorkflowFinalStatus(status)
refetchDiff()
edgeFunctionsDiff.refetchCurrentBranchFunctions()
edgeFunctionsDiff.refetchMainBranchFunctions()
},
})
// Use whichever workflow run was found
const currentWorkflowRun = currentBranchWorkflow || parentBranchWorkflow
const workflowRunLogs = currentBranchLogs || parentBranchLogs
// Check if workflow failed based on final status or current status
const hasCurrentWorkflowFailed = workflowFinalStatus
? ['MIGRATIONS_FAILED', 'FUNCTIONS_FAILED'].includes(workflowFinalStatus)
: currentWorkflowRun?.status &&
['MIGRATIONS_FAILED', 'FUNCTIONS_FAILED'].includes(currentWorkflowRun.status)
// Helper functions for URL management
const addWorkflowRun = useCallback(
(workflowRunId: string) => {
router.push({
pathname: router.pathname,
query: { ...router.query, workflow_run_id: workflowRunId },
})
},
[refetchDiff, edgeFunctionsDiff]
[router]
)
const clearWorkflowRun = useCallback(() => {
const { workflow_run_id, ...queryWithoutWorkflowId } = router.query
router.push({
pathname: router.pathname,
query: queryWithoutWorkflowId,
})
}, [router])
const { mutate: pushBranch, isLoading: isPushing } = useBranchPushMutation({
onSuccess: (data) => {
toast.success('Branch update initiated!')
// Add workflow run ID to URL for persistence and track it (push workflows run on current branch)
// Add workflow run ID to URL for persistence
if (data?.workflow_run_id) {
setRelatedWorkflowRunIds((prev) => ({
...prev,
[data.workflow_run_id]: ref || '',
}))
router.push({
pathname: router.pathname,
query: { ...router.query, workflow_run_id: data.workflow_run_id },
})
addWorkflowRun(data.workflow_run_id)
}
},
onError: (error) => {
@@ -152,16 +168,9 @@ const MergePage: NextPageWithLayout = () => {
} else {
toast.success('Branch merge initiated!')
}
// Add workflow run ID to URL for persistence and track it (merge workflows run on parent branch)
// Add workflow run ID to URL for persistence
if (data.workflowRunId) {
setRelatedWorkflowRunIds((prev) => ({
...prev,
[data.workflowRunId]: parentProjectRef || '',
}))
router.push({
pathname: router.pathname,
query: { ...router.query, workflow_run_id: data.workflowRunId },
})
addWorkflowRun(data.workflowRunId)
}
} else {
toast.info('No changes to merge - branch merged successfully!')
@@ -205,13 +214,6 @@ const MergePage: NextPageWithLayout = () => {
// Determine current active tab via query param (defaults to 'database')
const currentTab = (router.query.tab as string) || 'database'
// Get the current workflow run ID from URL
const currentWorkflowRunId = router.query.workflow_run_id as string | undefined
// Check if current workflow run has failed
const hasCurrentWorkflowFailed =
currentWorkflowRunId && failedWorkflowIds.has(currentWorkflowRunId)
// Navigation items for PageLayout - updates the `tab` query param
const navigationItems = useMemo(() => {
const buildHref = (tab: string) => {
@@ -274,8 +276,7 @@ const MergePage: NextPageWithLayout = () => {
)
}
const isDataLoaded = !isCombinedDiffLoading
const isMergeDisabled = combinedHasChanges && isDataLoaded
const isMergeDisabled = !combinedHasChanges || isCombinedDiffLoading || isBranchOutOfDateOverall
// Update primary actions - remove push button if branch is out of date (it will be in the notice)
const primaryActions = (
@@ -284,7 +285,7 @@ const MergePage: NextPageWithLayout = () => {
<ButtonTooltip
tooltip={{
content: {
text: 'No changes to merge',
text: !combinedHasChanges ? 'No changes to merge' : 'Branch is out of date',
},
}}
type="primary"
@@ -354,10 +355,10 @@ const MergePage: NextPageWithLayout = () => {
<OutOfDateNotice
isBranchOutOfDateMigrations={isBranchOutOfDateMigrations}
missingMigrationsCount={missingMigrationsCount}
hasNewerRemovedFunctions={hasNewerRemovedFunctions}
newerRemovedFunctionsCount={newerRemovedFunctionsCount}
hasNewerModifiedFunctions={hasNewerModifiedFunctions}
newerModifiedFunctionsCount={newerModifiedFunctionsCount}
hasMissingFunctions={hasMissingFunctions}
missingFunctionsCount={missingFunctionsCount}
hasOutOfDateFunctions={hasOutOfDateFunctions}
outOfDateFunctionsCount={outOfDateFunctionsCount}
hasEdgeFunctionModifications={hasEdgeFunctionModifications}
modifiedFunctionsCount={modifiedFunctionsCount}
isPushing={isPushing}
@@ -366,25 +367,17 @@ const MergePage: NextPageWithLayout = () => {
) : currentWorkflowRunId ? (
<div className="my-6">
<WorkflowLogsCard
workflowRunId={currentWorkflowRunId}
projectRef={relatedWorkflowRunIds[currentWorkflowRunId] || ref || ''}
onClose={() => {
const { workflow_run_id, ...queryWithoutWorkflowId } = router.query
router.push({
pathname: router.pathname,
query: queryWithoutWorkflowId,
})
}}
onStatusChange={handleWorkflowStatusChange}
statusComplete="FUNCTIONS_DEPLOYED"
statusFailed={['MIGRATIONS_FAILED', 'FUNCTIONS_FAILED']}
headerTitle={hasCurrentWorkflowFailed ? 'Workflow failed' : undefined}
headerDescription={
workflowRun={currentWorkflowRun}
logs={workflowRunLogs}
isLoading={!workflowRunLogs && !!currentWorkflowRunId}
onClose={clearWorkflowRun}
overrideTitle={hasCurrentWorkflowFailed ? 'Workflow failed' : undefined}
overrideDescription={
hasCurrentWorkflowFailed
? 'Consider creating a fresh branch from the latest production branch to resolve potential conflicts.'
: undefined
}
headerIcon={
overrideIcon={
hasCurrentWorkflowFailed ? (
<AlertTriangle
size={16}
@@ -393,7 +386,7 @@ const MergePage: NextPageWithLayout = () => {
/>
) : undefined
}
headerAction={
overrideAction={
hasCurrentWorkflowFailed ? (
<Button
type="default"