Skip to content

Commit fff8e43

Browse files
atrakhConvex, Inc.
authored and
Convex, Inc.
committed
dashboard: show server version # on health page (#34605)
Fixes #42 ![Screenshot 2025-02-24 at 12 51 36 PM](https://github.com/user-attachments/assets/dcc97416-8154-4e99-a2db-723e06284a62) ![Screenshot 2025-02-24 at 12 50 52 PM](https://github.com/user-attachments/assets/8450b952-38a5-48cc-934c-8ac5a49de43f) GitOrigin-RevId: 62c208b640deecc5c106a7fc08a894f4e7cc56a3
1 parent c3f9cbd commit fff8e43

File tree

1 file changed

+75
-1
lines changed

1 file changed

+75
-1
lines changed

Diff for: npm-packages/dashboard-common/src/features/health/components/LastDeployed.tsx

+75-1
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,57 @@ import { cn } from "@common/lib/cn";
44
import { HealthCard } from "@common/elements/HealthCard";
55
import { TimestampDistance } from "@common/elements/TimestampDistance";
66
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+
}
750

851
export function LastDeployed() {
952
const lastPushEvent = useQuery(udfs.deploymentEvents.lastPushEvent, {});
53+
const serverVersion = useQuery(udfs.getVersion.default);
54+
const { hasUpdate, latestVersion } = useLatestConvexVersion(
55+
serverVersion || undefined,
56+
);
57+
1058
const content =
1159
lastPushEvent === undefined ? (
1260
<Loading className="h-5 w-24" />
@@ -31,7 +79,33 @@ export function LastDeployed() {
3179
size="sm"
3280
tip="The last time functions were deployed."
3381
>
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>
35109
</HealthCard>
36110
);
37111
}

0 commit comments

Comments
 (0)