From cec62fac33c64c90608b9de1a033fbb1437a41ec Mon Sep 17 00:00:00 2001 From: Kamlesh72 Date: Fri, 15 Aug 2025 09:16:35 +0000 Subject: [PATCH 1/2] update sidebar to handle failed api gracefully --- web-server/pages/api/internal/version.ts | 28 ++++++++++--------- .../ExtendedSidebarLayout/Sidebar/index.tsx | 10 ++++--- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/web-server/pages/api/internal/version.ts b/web-server/pages/api/internal/version.ts index 38d013195..7b66ceed7 100644 --- a/web-server/pages/api/internal/version.ts +++ b/web-server/pages/api/internal/version.ts @@ -82,15 +82,22 @@ function getProjectVersionInfo(): ProjectVersionInfo { }; } -async function fetchDockerHubTags(): Promise { - const dockerHubUrl = `https://hub.docker.com/v2/repositories/${dockerRepoName}/tags/`; +async function fetchDockerHubLatestTag(): Promise { + const dockerHubUrl = `https://hub.docker.com/v2/repositories/${dockerRepoName}/tags?ordering=last_updated&page_size=1`; const response = await axios.get(dockerHubUrl); - return response.data.results.map((tag) => ({ - name: tag.name, - digest: tag.images[0].digest, - last_updated: tag.last_updated - })); + const latestTagName = response.data.results[0].name; + + const tagUrl = `https://hub.docker.com/v2/repositories/${dockerRepoName}/tags/${latestTagName}`; + const latestTag = (await axios.get(tagUrl)).data; + + const amdArchImage = latestTag.images.find((i) => i.architecture === 'amd64'); + + return { + name: latestTag.name, + digest: amdArchImage.digest, + last_updated: latestTag.last_updated + }; } function isUpdateAvailable({ @@ -122,13 +129,8 @@ function isUpdateAvailable({ async function checkNewImageRelease(): Promise { const versionInfo = getProjectVersionInfo(); - const [dockerRemoteTags] = await Promise.all([fetchDockerHubTags()]); + const latestTag = await fetchDockerHubLatestTag(); - dockerRemoteTags.sort( - (a, b) => - new Date(b.last_updated).getTime() - new Date(a.last_updated).getTime() - ); - const latestTag = dockerRemoteTags[0]; const latestRemoteDate = new Date(latestTag.last_updated); const latestDockerImageLink = `https://hub.docker.com/layers/${dockerRepoName}/${latestTag.name}/images/${latestTag.digest}`; diff --git a/web-server/src/layouts/ExtendedSidebarLayout/Sidebar/index.tsx b/web-server/src/layouts/ExtendedSidebarLayout/Sidebar/index.tsx index bd8cf94b9..f1a3ba5c8 100644 --- a/web-server/src/layouts/ExtendedSidebarLayout/Sidebar/index.tsx +++ b/web-server/src/layouts/ExtendedSidebarLayout/Sidebar/index.tsx @@ -67,10 +67,12 @@ const SidebarContent = () => { const imageStatus = useSelector((s) => s.app.latestImageStatus); - const formattedDate = format( - new Date(imageStatus.current_docker_image_build_date), - 'dd MMM yyyy HH:mm:ss' - ); + const formattedDate = imageStatus?.current_docker_image_build_date + ? format( + new Date(imageStatus.current_docker_image_build_date), + 'dd MMM yyyy HH:mm:ss' + ) + : 'Not Available'; return ( <> From b14322ced058d7a9e3ee615f02b2f218cdccea34 Mon Sep 17 00:00:00 2001 From: Kamlesh72 Date: Fri, 15 Aug 2025 11:30:37 +0000 Subject: [PATCH 2/2] Use latest tag as most recently updated tag --- web-server/pages/api/internal/version.ts | 26 +++++++------------ .../ExtendedSidebarLayout/Sidebar/index.tsx | 10 +++---- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/web-server/pages/api/internal/version.ts b/web-server/pages/api/internal/version.ts index 7b66ceed7..ec8f1577f 100644 --- a/web-server/pages/api/internal/version.ts +++ b/web-server/pages/api/internal/version.ts @@ -5,6 +5,7 @@ import { Endpoint, nullSchema } from '@/api-helpers/global'; const dockerRepoName = 'middlewareeng/middleware'; const githubOrgName = 'middlewarehq'; const githubRepoName = 'middleware'; +const latestTagName = 'latest'; const endpoint = new Endpoint(nullSchema); @@ -26,13 +27,6 @@ type CheckNewVersionResponse = { current_docker_image_build_date: Date; }; -type DockerHubAPIResponse = { - count: number; - next: string | null; - previous: string | null; - results: TagResult[]; -}; - type TagResult = { creator: number; id: number; @@ -69,7 +63,7 @@ type DockerImage = { type TagCompressed = { name: string; last_updated: string; - digest: string; + digest?: string; }; function getProjectVersionInfo(): ProjectVersionInfo { @@ -83,19 +77,14 @@ function getProjectVersionInfo(): ProjectVersionInfo { } async function fetchDockerHubLatestTag(): Promise { - const dockerHubUrl = `https://hub.docker.com/v2/repositories/${dockerRepoName}/tags?ordering=last_updated&page_size=1`; - const response = await axios.get(dockerHubUrl); - - const latestTagName = response.data.results[0].name; - - const tagUrl = `https://hub.docker.com/v2/repositories/${dockerRepoName}/tags/${latestTagName}`; - const latestTag = (await axios.get(tagUrl)).data; + const latestTagUrl = `https://hub.docker.com/v2/repositories/${dockerRepoName}/tags/${latestTagName}`; + const latestTag = (await axios.get(latestTagUrl)).data; const amdArchImage = latestTag.images.find((i) => i.architecture === 'amd64'); return { name: latestTag.name, - digest: amdArchImage.digest, + digest: amdArchImage?.digest, last_updated: latestTag.last_updated }; } @@ -133,7 +122,10 @@ async function checkNewImageRelease(): Promise { const latestRemoteDate = new Date(latestTag.last_updated); - const latestDockerImageLink = `https://hub.docker.com/layers/${dockerRepoName}/${latestTag.name}/images/${latestTag.digest}`; + let latestDockerImageLink = `https://hub.docker.com/r/${dockerRepoName}/tags`; + if (latestTag.digest) { + latestDockerImageLink = `https://hub.docker.com/layers/${dockerRepoName}/${latestTag.name}/images/${latestTag.digest}`; + } const githubRepLink = `https://github.com/${githubOrgName}/${githubRepoName}`; diff --git a/web-server/src/layouts/ExtendedSidebarLayout/Sidebar/index.tsx b/web-server/src/layouts/ExtendedSidebarLayout/Sidebar/index.tsx index f1a3ba5c8..b08f10077 100644 --- a/web-server/src/layouts/ExtendedSidebarLayout/Sidebar/index.tsx +++ b/web-server/src/layouts/ExtendedSidebarLayout/Sidebar/index.tsx @@ -7,7 +7,7 @@ import { useTheme, lighten } from '@mui/material'; -import { format } from 'date-fns'; +import { format, isValid } from 'date-fns'; import { useContext, useMemo } from 'react'; import { FlexBox } from '@/components/FlexBox'; @@ -67,11 +67,9 @@ const SidebarContent = () => { const imageStatus = useSelector((s) => s.app.latestImageStatus); - const formattedDate = imageStatus?.current_docker_image_build_date - ? format( - new Date(imageStatus.current_docker_image_build_date), - 'dd MMM yyyy HH:mm:ss' - ) + const imageBuildDate = new Date(imageStatus?.current_docker_image_build_date); + const formattedDate = isValid(imageBuildDate) + ? format(imageBuildDate, 'dd MMM yyyy HH:mm:ss') : 'Not Available'; return (