OutOfDateNotice.tsx142 lines · main
| 1 | // @ts-nocheck |
| 2 | import { GitBranchIcon } from 'lucide-react' |
| 3 | import { useState } from 'react' |
| 4 | import { |
| 5 | AlertDialog, |
| 6 | AlertDialogAction, |
| 7 | AlertDialogCancel, |
| 8 | AlertDialogContent, |
| 9 | AlertDialogDescription, |
| 10 | AlertDialogFooter, |
| 11 | AlertDialogHeader, |
| 12 | AlertDialogTitle, |
| 13 | AlertDialogTrigger, |
| 14 | Button, |
| 15 | } from 'ui' |
| 16 | import { Admonition } from 'ui-patterns' |
| 17 | |
| 18 | import { useSendEventMutation } from '@/data/telemetry/send-event-mutation' |
| 19 | import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' |
| 20 | import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' |
| 21 | |
| 22 | interface OutOfDateNoticeProps { |
| 23 | isBranchOutOfDateMigrations: boolean |
| 24 | missingMigrationsCount: number |
| 25 | hasMissingFunctions: boolean |
| 26 | missingFunctionsCount: number |
| 27 | hasOutOfDateFunctions: boolean |
| 28 | outOfDateFunctionsCount: number |
| 29 | hasEdgeFunctionModifications: boolean |
| 30 | modifiedFunctionsCount: number |
| 31 | isPushing: boolean |
| 32 | onPush: () => void |
| 33 | } |
| 34 | |
| 35 | export const OutOfDateNotice = ({ |
| 36 | isBranchOutOfDateMigrations, |
| 37 | missingMigrationsCount, |
| 38 | hasMissingFunctions, |
| 39 | hasOutOfDateFunctions, |
| 40 | hasEdgeFunctionModifications, |
| 41 | modifiedFunctionsCount, |
| 42 | isPushing, |
| 43 | onPush, |
| 44 | }: OutOfDateNoticeProps) => { |
| 45 | const [isDialogOpen, setIsDialogOpen] = useState(false) |
| 46 | const hasOutdatedMigrations = isBranchOutOfDateMigrations && missingMigrationsCount > 0 |
| 47 | const { data: selectedOrg } = useSelectedOrganizationQuery() |
| 48 | const { data: project } = useSelectedProjectQuery() |
| 49 | const { mutate: sendEvent } = useSendEventMutation() |
| 50 | |
| 51 | const isBranch = project?.parent_project_ref !== undefined |
| 52 | const parentProjectRef = isBranch ? project?.parent_project_ref : project?.ref |
| 53 | |
| 54 | const getTitle = () => { |
| 55 | if (hasOutdatedMigrations && (hasMissingFunctions || hasOutOfDateFunctions)) { |
| 56 | return 'Your database schema and edge functions are out of date' |
| 57 | } else if (hasOutdatedMigrations) { |
| 58 | return 'Your database schema is out of date' |
| 59 | } else if (hasMissingFunctions || hasOutOfDateFunctions) { |
| 60 | return 'Your functions are out of date' |
| 61 | } |
| 62 | return 'Branch is out of date' |
| 63 | } |
| 64 | |
| 65 | const getDescription = () => { |
| 66 | return 'Update this branch to get the latest changes from the production branch.' |
| 67 | } |
| 68 | |
| 69 | const handleUpdate = (shouldCloseDialog = false) => { |
| 70 | if (shouldCloseDialog) { |
| 71 | setIsDialogOpen(false) |
| 72 | } |
| 73 | |
| 74 | // Track branch update |
| 75 | sendEvent({ |
| 76 | action: 'branch_updated', |
| 77 | properties: { |
| 78 | modifiedEdgeFunctions: hasEdgeFunctionModifications, |
| 79 | source: 'out_of_date_notice', |
| 80 | }, |
| 81 | groups: { |
| 82 | project: parentProjectRef ?? 'Unknown', |
| 83 | organization: selectedOrg?.slug ?? 'Unknown', |
| 84 | }, |
| 85 | }) |
| 86 | |
| 87 | onPush() |
| 88 | } |
| 89 | |
| 90 | return ( |
| 91 | <Admonition type="warning" className="my-4"> |
| 92 | <div className="w-full flex items-center justify-between"> |
| 93 | <div> |
| 94 | <h3 className="text-sm font-medium">{getTitle()}</h3> |
| 95 | <p className="text-sm text-foreground-light">{getDescription()}</p> |
| 96 | </div> |
| 97 | |
| 98 | {hasEdgeFunctionModifications ? ( |
| 99 | <AlertDialog open={isDialogOpen} onOpenChange={setIsDialogOpen}> |
| 100 | <AlertDialogTrigger asChild> |
| 101 | <Button |
| 102 | type="default" |
| 103 | loading={isPushing} |
| 104 | icon={<GitBranchIcon size={16} strokeWidth={1.5} />} |
| 105 | className="shrink-0" |
| 106 | > |
| 107 | {isPushing ? 'Updating...' : 'Update branch'} |
| 108 | </Button> |
| 109 | </AlertDialogTrigger> |
| 110 | <AlertDialogContent> |
| 111 | <AlertDialogHeader> |
| 112 | <AlertDialogTitle>Update branch with modified functions</AlertDialogTitle> |
| 113 | <AlertDialogDescription> |
| 114 | This branch has {modifiedFunctionsCount} modified edge function |
| 115 | {modifiedFunctionsCount !== 1 ? 's' : ''} that will be overwritten when updating |
| 116 | with the latest functions from the production branch. This action cannot be |
| 117 | undone. |
| 118 | </AlertDialogDescription> |
| 119 | </AlertDialogHeader> |
| 120 | <AlertDialogFooter> |
| 121 | <AlertDialogCancel>Cancel</AlertDialogCancel> |
| 122 | <AlertDialogAction variant="warning" onClick={() => handleUpdate(true)}> |
| 123 | Update anyway |
| 124 | </AlertDialogAction> |
| 125 | </AlertDialogFooter> |
| 126 | </AlertDialogContent> |
| 127 | </AlertDialog> |
| 128 | ) : ( |
| 129 | <Button |
| 130 | type="default" |
| 131 | loading={isPushing} |
| 132 | onClick={() => handleUpdate()} |
| 133 | icon={<GitBranchIcon size={16} strokeWidth={1.5} />} |
| 134 | className="shrink-0" |
| 135 | > |
| 136 | {isPushing ? 'Updating...' : 'Update branch'} |
| 137 | </Button> |
| 138 | )} |
| 139 | </div> |
| 140 | </Admonition> |
| 141 | ) |
| 142 | } |