diff --git a/frontend/javascripts/libs/react_helpers.tsx b/frontend/javascripts/libs/react_helpers.tsx index 37331844da..fa0f47d676 100644 --- a/frontend/javascripts/libs/react_helpers.tsx +++ b/frontend/javascripts/libs/react_helpers.tsx @@ -5,6 +5,7 @@ import type { OxalisState } from "oxalis/store"; export function useInterval( callback: (...args: Array) => any, delay: number | null | undefined, + ...additionalDependencies: Array ) { const savedCallback = useRef(); // Remember the latest callback. @@ -25,7 +26,7 @@ export function useInterval( } return undefined; - }, [delay]); + }, [delay, ...additionalDependencies]); } export function useFetch( fetchFn: () => Promise, diff --git a/frontend/javascripts/navbar.tsx b/frontend/javascripts/navbar.tsx index 9552193f76..7ab0d631bf 100644 --- a/frontend/javascripts/navbar.tsx +++ b/frontend/javascripts/navbar.tsx @@ -27,7 +27,7 @@ import { } from "admin/admin_rest_api"; import { logoutUserAction, setActiveUserAction } from "oxalis/model/actions/user_actions"; import { trackVersion } from "oxalis/model/helpers/analytics"; -import { useFetch } from "libs/react_helpers"; +import { useFetch, useInterval } from "libs/react_helpers"; import LoginForm from "admin/auth/login_form"; import Request from "libs/request"; import type { OxalisState } from "oxalis/store"; @@ -36,8 +36,12 @@ import * as Utils from "libs/utils"; import window, { document, location } from "libs/window"; import features from "features"; import { setThemeAction } from "oxalis/model/actions/ui_actions"; + const { SubMenu } = Menu; const { Header } = Layout; + +const HELP_MENU_KEY = "helpMenu"; + type OwnProps = { isAuthenticated: boolean; }; @@ -298,11 +302,13 @@ function getTimeTrackingMenu({ collapse }: { collapse: boolean }) { function HelpSubMenu({ isAdminOrTeamManager, version, + polledVersion, collapse, ...other }: { isAdminOrTeamManager: boolean; version: string | null; + polledVersion: string | null; collapse: boolean; } & SubMenuProps) { return ( @@ -355,6 +361,9 @@ function HelpSubMenu({ {version !== "" ? ( Version: {version} + {polledVersion != null && polledVersion !== version + ? ` (Server is currently at ${polledVersion}!)` + : null} ) : null} @@ -582,10 +591,12 @@ function AnonymousAvatar() { ); } -async function getAndTrackVersion() { +async function getAndTrackVersion(dontTrack: boolean = false) { const buildInfo = await getBuildInfo(); const { version } = buildInfo.webknossos; - trackVersion(version); + if (dontTrack) { + trackVersion(version); + } return version; } @@ -601,6 +612,17 @@ function Navbar({ activeUser, isAuthenticated, isInAnnotationView, hasOrganizati }; const version = useFetch(getAndTrackVersion, null, []); + const [isHelpMenuOpen, setIsHelpMenuOpen] = useState(false); + const [polledVersion, setPolledVersion] = useState(null); + useInterval( + async () => { + if (isHelpMenuOpen) { + setPolledVersion(await getAndTrackVersion(true)); + } + }, + 2000, + isHelpMenuOpen, + ); const navbarStyle: Record = { padding: 0, overflowX: "auto", @@ -661,8 +683,9 @@ function Navbar({ activeUser, isAuthenticated, isInAnnotationView, hasOrganizati menuItems.push( , @@ -681,6 +704,7 @@ function Navbar({ activeUser, isAuthenticated, isInAnnotationView, hasOrganizati setIsHelpMenuOpen(openKeys.includes(HELP_MENU_KEY))} style={{ lineHeight: "48px", }}