11import {
22 ArrowPathIcon ,
33 ArrowUturnLeftIcon ,
4+ ArrowUturnRightIcon ,
45 BookOpenIcon ,
56 ServerStackIcon ,
67} from "@heroicons/react/20/solid" ;
@@ -41,7 +42,10 @@ import {
4142 deploymentStatuses ,
4243} from "~/components/runs/v3/DeploymentStatus" ;
4344import { RetryDeploymentIndexingDialog } from "~/components/runs/v3/RetryDeploymentIndexingDialog" ;
44- import { RollbackDeploymentDialog } from "~/components/runs/v3/RollbackDeploymentDialog" ;
45+ import {
46+ PromoteDeploymentDialog ,
47+ RollbackDeploymentDialog ,
48+ } from "~/components/runs/v3/RollbackDeploymentDialog" ;
4549import { useOrganization } from "~/hooks/useOrganizations" ;
4650import { useProject } from "~/hooks/useProject" ;
4751import { useUser } from "~/hooks/useUser" ;
@@ -58,6 +62,7 @@ import {
5862} from "~/utils/pathBuilder" ;
5963import { createSearchParams } from "~/utils/searchParams" ;
6064import { deploymentIndexingIsRetryable } from "~/v3/deploymentStatus" ;
65+ import { compareDeploymentVersions } from "~/v3/utils/deploymentVersions" ;
6166
6267export const meta : MetaFunction = ( ) => {
6368 return [
@@ -106,6 +111,8 @@ export default function Page() {
106111
107112 const { deploymentParam } = useParams ( ) ;
108113
114+ const currentDeployment = deployments . find ( ( d ) => d . isCurrent ) ;
115+
109116 return (
110117 < PageContainer >
111118 < NavBar >
@@ -234,6 +241,7 @@ export default function Page() {
234241 deployment = { deployment }
235242 path = { path }
236243 isSelected = { isSelected }
244+ currentDeployment = { currentDeployment }
237245 />
238246 </ TableRow >
239247 ) ;
@@ -320,18 +328,25 @@ function DeploymentActionsCell({
320328 deployment,
321329 path,
322330 isSelected,
331+ currentDeployment,
323332} : {
324333 deployment : DeploymentListItem ;
325334 path : string ;
326335 isSelected : boolean ;
336+ currentDeployment ?: DeploymentListItem ;
327337} ) {
328338 const location = useLocation ( ) ;
329339 const project = useProject ( ) ;
330340
331- const canRollback = ! deployment . isCurrent && deployment . isDeployed ;
341+ const canBeMadeCurrent = ! deployment . isCurrent && deployment . isDeployed ;
332342 const canRetryIndexing = deployment . isLatest && deploymentIndexingIsRetryable ( deployment ) ;
343+ const canBeRolledBack =
344+ canBeMadeCurrent &&
345+ currentDeployment ?. version &&
346+ compareDeploymentVersions ( deployment . version , currentDeployment . version ) === - 1 ;
347+ const canBePromoted = canBeMadeCurrent && ! canBeRolledBack ;
333348
334- if ( ! canRollback && ! canRetryIndexing ) {
349+ if ( ! canBeMadeCurrent && ! canRetryIndexing ) {
335350 return (
336351 < TableCell to = { path } isSelected = { isSelected } >
337352 { "" }
@@ -345,7 +360,7 @@ function DeploymentActionsCell({
345360 isSelected = { isSelected }
346361 popoverContent = {
347362 < >
348- { canRollback && (
363+ { canBeRolledBack && (
349364 < Dialog >
350365 < DialogTrigger asChild >
351366 < Button
@@ -365,6 +380,26 @@ function DeploymentActionsCell({
365380 />
366381 </ Dialog >
367382 ) }
383+ { canBePromoted && (
384+ < Dialog >
385+ < DialogTrigger asChild >
386+ < Button
387+ variant = "small-menu-item"
388+ LeadingIcon = { ArrowUturnRightIcon }
389+ leadingIconClassName = "text-blue-500"
390+ fullWidth
391+ textAlignLeft
392+ >
393+ Promote…
394+ </ Button >
395+ </ DialogTrigger >
396+ < PromoteDeploymentDialog
397+ projectId = { project . id }
398+ deploymentShortCode = { deployment . shortCode }
399+ redirectPath = { `${ location . pathname } ${ location . search } ` }
400+ />
401+ </ Dialog >
402+ ) }
368403 { canRetryIndexing && (
369404 < Dialog >
370405 < DialogTrigger asChild >
0 commit comments