@@ -22,6 +22,7 @@ import { getOperationsUrlForCluster } from '@/lib/urls/getOperationsUrlForCluste
2222import { Link } from '@tanstack/react-router' ;
2323import { Ellipsis } from 'lucide-react' ;
2424import { useCallback , useMemo , useState } from 'react' ;
25+ import { toast } from 'sonner' ;
2526
2627const activeClusterStatuses = [ 'RUNNING' ] ;
2728const deletedClusterStatuses = [ 'TERMINATING' , 'TERMINATED' , 'REMOVED' ] ;
@@ -37,14 +38,17 @@ export function ClusterCard({
3738 const auth = useInstanceAuth ( cluster . id ) ;
3839
3940 const isActive = useMemo ( ( ) => cluster . status && activeClusterStatuses . includes ( cluster . status ) , [ cluster . status ] ) ;
40- const isTerminated = useMemo ( ( ) => cluster . status && deletedClusterStatuses . includes ( cluster . status ) , [ cluster . status ] ) ;
41+ const isTerminated = useMemo (
42+ ( ) => cluster . status && deletedClusterStatuses . includes ( cluster . status ) ,
43+ [ cluster . status ]
44+ ) ;
4145 const operationsUrl = useMemo ( ( ) => getOperationsUrlForCluster ( cluster ) , [ cluster ] ) ;
4246 const instanceClient = useInstanceClient ( operationsUrl ) ;
4347 const [ signingOut , setSigningOut ] = useState ( false ) ;
4448
4549 const onSignOutClick = useCallback ( async ( ) => {
4650 setSigningOut ( true ) ;
47- const fullCluster = await getClusterInfo ( cluster . id ) . catch ( err => {
51+ const fullCluster = await getClusterInfo ( cluster . id ) . catch ( ( err ) => {
4852 console . error ( 'Failed to lookup cluster details, proceeding without checking instances.' , err ) ;
4953 return null ;
5054 } ) ;
@@ -61,17 +65,34 @@ export function ClusterCard({
6165 onTerminateClusterModal ( cluster ) ;
6266 } , [ cluster , onTerminateClusterModal ] ) ;
6367
68+ const onCopyFQDNClick = useCallback ( ( ) => {
69+ navigator . clipboard . writeText ( cluster . fqdn || '' ) ;
70+ toast . info ( 'FQDN url copied to clipboard' ) ;
71+ } , [ cluster . fqdn ] ) ;
72+
6473 const menuItems = [
6574 isActive && update && (
66- < Link to = { `${ cluster . id } /edit` } disabled = { signingOut } > < DropdownMenuItem > Edit</ DropdownMenuItem > </ Link > ) ,
75+ < Link to = { `${ cluster . id } /edit` } disabled = { signingOut } >
76+ < DropdownMenuItem > Edit</ DropdownMenuItem >
77+ </ Link >
78+ ) ,
79+ isActive && view && (
80+ < Link to = { `${ cluster . id } /instances` } disabled = { signingOut } >
81+ < DropdownMenuItem > Instances</ DropdownMenuItem >
82+ </ Link >
83+ ) ,
6784 isActive && view && (
68- < Link to = { `${ cluster . id } /instances` } disabled = { signingOut } > < DropdownMenuItem > Instances</ DropdownMenuItem > </ Link > ) ,
85+ < DropdownMenuItem onClick = { onCopyFQDNClick } disabled = { signingOut } >
86+ Copy FQDN Url
87+ </ DropdownMenuItem >
88+ ) ,
6989 isActive && view && ! ! operationsUrl && ! auth . isLoading && auth . user && (
70- < DropdownMenuItem onClick = { onSignOutClick } disabled = { signingOut } > Sign Out</ DropdownMenuItem > ) ,
90+ < DropdownMenuItem onClick = { onSignOutClick } disabled = { signingOut } >
91+ Sign Out
92+ </ DropdownMenuItem >
93+ ) ,
7194 ! isTerminated && remove && (
72- < DropdownMenuItem
73- className = "bg-red focus:bg-red/70 focus:text-white"
74- onClick = { onTerminateClick } >
95+ < DropdownMenuItem className = "bg-red focus:bg-red/70 focus:text-white" onClick = { onTerminateClick } >
7596 Terminate
7697 </ DropdownMenuItem >
7798 ) ,
@@ -82,35 +103,40 @@ export function ClusterCard({
82103 < CardHeader >
83104 < CardDescription className = "flex items-center justify-between" >
84105 < span className = "truncate" > { cluster . id } </ span >
85- { ! isTerminated && ( < DropdownMenu >
86- < DropdownMenuTrigger >
87- < Ellipsis aria-label = "Cluster options" />
88- </ DropdownMenuTrigger >
89- < DropdownMenuContent >
90- < DropdownMenuLabel className = "text-gray-600 text-xs" > Plans</ DropdownMenuLabel >
91- { cluster . plans ?. map ( plan => (
92- < DropdownMenuLabel key = { plan . planId } >
93- { plan . planId } / { plan . regionId } < br />
94- Auto Renewal { plan . autoRenew
95- ? < Badge variant = "success" > ON</ Badge >
96- : < Badge variant = "warning" > OFF</ Badge > }
97- </ DropdownMenuLabel >
98- ) ) }
99- { menuItems . length > 0 && ( < >
100- < DropdownMenuSeparator />
101- { ...menuItems }
102- </ > ) }
103- </ DropdownMenuContent >
104- </ DropdownMenu > ) }
106+ { ! isTerminated && (
107+ < DropdownMenu >
108+ < DropdownMenuTrigger >
109+ < Ellipsis aria-label = "Cluster options" />
110+ </ DropdownMenuTrigger >
111+ < DropdownMenuContent >
112+ < DropdownMenuLabel className = "text-gray-600 text-xs" > Plans</ DropdownMenuLabel >
113+ { cluster . plans ?. map ( ( plan ) => (
114+ < DropdownMenuLabel key = { plan . planId } >
115+ { plan . planId } / { plan . regionId }
116+ < br />
117+ Auto Renewal{ ' ' }
118+ { plan . autoRenew ? < Badge variant = "success" > ON</ Badge > : < Badge variant = "warning" > OFF</ Badge > }
119+ </ DropdownMenuLabel >
120+ ) ) }
121+ { menuItems . length > 0 && (
122+ < >
123+ < DropdownMenuSeparator />
124+ { ...menuItems }
125+ </ >
126+ ) }
127+ </ DropdownMenuContent >
128+ </ DropdownMenu >
129+ ) }
105130 </ CardDescription >
106131 < CardTitle >
107132 < h2 > { cluster . name } </ h2 >
108133 </ CardTitle >
109134 </ CardHeader >
110135 < CardContent className = "flex justify-between" >
111136 { cluster . status && (
112- < Badge variant = { renderBadgeStatusVariant ( cluster . status ) } > { renderBadgeStatusText ( cluster . status ) } </ Badge > ) }
113- { isActive && view && ( < ClusterCardAction cluster = { cluster } /> ) }
137+ < Badge variant = { renderBadgeStatusVariant ( cluster . status ) } > { renderBadgeStatusText ( cluster . status ) } </ Badge >
138+ ) }
139+ { isActive && view && < ClusterCardAction cluster = { cluster } /> }
114140 </ CardContent >
115141 </ Card >
116142 ) ;
0 commit comments