@@ -4,9 +4,57 @@ import { cn } from "@common/lib/cn";
4
4
import { HealthCard } from "@common/elements/HealthCard" ;
5
5
import { TimestampDistance } from "@common/elements/TimestampDistance" ;
6
6
import { Loading } from "@common/elements/Loading" ;
7
+ import { useEffect , useState } from "react" ;
8
+ import semver from "semver" ;
9
+ import { Button } from "@common/elements/Button" ;
10
+
11
+ function useLatestConvexVersion ( currentVersion : string | undefined ) {
12
+ const [ hasUpdate , setHasUpdate ] = useState ( false ) ;
13
+ const [ latestVersion , setLatestVersion ] = useState < string > ( ) ;
14
+
15
+ useEffect ( ( ) => {
16
+ let isMounted = true ;
17
+
18
+ async function checkVersion ( ) {
19
+ try {
20
+ const response = await fetch (
21
+ "https://registry.npmjs.org/convex/latest" ,
22
+ ) ;
23
+ if ( ! response . ok ) return ;
24
+
25
+ const data = await response . json ( ) ;
26
+ if ( ! isMounted ) return ;
27
+
28
+ setLatestVersion ( data . version ) ;
29
+
30
+ if ( currentVersion && data . version ) {
31
+ const hasNewVersion = semver . gt ( data . version , currentVersion ) ;
32
+ setHasUpdate ( hasNewVersion ) ;
33
+ }
34
+ } catch ( e ) {
35
+ // Swallow any errors and don't show update notice
36
+ }
37
+ }
38
+
39
+ if ( currentVersion ) {
40
+ void checkVersion ( ) ;
41
+ }
42
+
43
+ return ( ) => {
44
+ isMounted = false ;
45
+ } ;
46
+ } , [ currentVersion ] ) ;
47
+
48
+ return { hasUpdate, latestVersion } ;
49
+ }
7
50
8
51
export function LastDeployed ( ) {
9
52
const lastPushEvent = useQuery ( udfs . deploymentEvents . lastPushEvent , { } ) ;
53
+ const serverVersion = useQuery ( udfs . getVersion . default ) ;
54
+ const { hasUpdate, latestVersion } = useLatestConvexVersion (
55
+ serverVersion || undefined ,
56
+ ) ;
57
+
10
58
const content =
11
59
lastPushEvent === undefined ? (
12
60
< Loading className = "h-5 w-24" />
@@ -31,7 +79,33 @@ export function LastDeployed() {
31
79
size = "sm"
32
80
tip = "The last time functions were deployed."
33
81
>
34
- < div className = "h-full w-full grow px-2 pb-2" > { content } </ div >
82
+ < div className = "flex h-full w-full grow flex-wrap justify-between px-2 pb-2" >
83
+ { content }
84
+ < div className = "flex items-center gap-2" >
85
+ < span className = "animate-fadeInFromLoading text-sm text-content-secondary" >
86
+ Convex v{ serverVersion }
87
+ </ span >
88
+ { hasUpdate && (
89
+ < Button
90
+ tip = { `A ${
91
+ serverVersion && latestVersion
92
+ ? latestVersion . split ( "." ) [ 0 ] !== serverVersion . split ( "." ) [ 0 ]
93
+ ? "major"
94
+ : latestVersion . split ( "." ) [ 1 ] !==
95
+ serverVersion . split ( "." ) [ 1 ]
96
+ ? "minor"
97
+ : "patch"
98
+ : ""
99
+ } update is available for Convex (${ serverVersion } → ${ latestVersion } )`}
100
+ className = "bg-util-accent p-0.5 px-1 text-white"
101
+ href = "https://www.npmjs.com/package/convex?activeTab=versions"
102
+ target = "_blank"
103
+ >
104
+ Update Available
105
+ </ Button >
106
+ ) }
107
+ </ div >
108
+ </ div >
35
109
</ HealthCard >
36
110
) ;
37
111
}
0 commit comments