diff --git a/site/src/components/AppLink/AppLink.stories.tsx b/site/src/components/AppLink/AppLink.stories.tsx index 0df7ac73a7..47f89bfb9d 100644 --- a/site/src/components/AppLink/AppLink.stories.tsx +++ b/site/src/components/AppLink/AppLink.stories.tsx @@ -29,8 +29,8 @@ const Template: Story = (args) => ( clearProxy: () => { return }, - refetchProxyLatencies: () => { - return + refetchProxyLatencies: (): Date => { + return new Date() }, }} > diff --git a/site/src/components/Navbar/NavbarView.tsx b/site/src/components/Navbar/NavbarView.tsx index 618ad7d6cc..2f78fd47cb 100644 --- a/site/src/components/Navbar/NavbarView.tsx +++ b/site/src/components/Navbar/NavbarView.tsx @@ -188,6 +188,7 @@ const ProxyMenu: FC<{ proxyContextValue: ProxyContextValue }> = ({ }) => { const buttonRef = useRef(null) const [isOpen, setIsOpen] = useState(false) + const [refetchDate, setRefetchDate] = useState() const selectedProxy = proxyContextValue.proxy.proxy const refreshLatencies = proxyContextValue.refetchProxyLatencies const closeMenu = () => setIsOpen(false) @@ -196,6 +197,26 @@ const ProxyMenu: FC<{ proxyContextValue: ProxyContextValue }> = ({ const isLoadingLatencies = Object.keys(latencies).length === 0 const isLoading = proxyContextValue.isLoading || isLoadingLatencies const permissions = usePermissions() + const proxyLatencyLoading = (proxy: TypesGen.Region): boolean => { + if (!refetchDate) { + // Only show loading if the user manually requested a refetch + return false + } + + const latency = latencies?.[proxy.id] + // Only show a loading spinner if: + // - A latency exists. This means the latency was fetched at some point, so the + // loader *should* be resolved. + // - The proxy is healthy. If it is not, the loader might never resolve. + // - The latency reported is older than the refetch date. This means the latency + // is stale and we should show a loading spinner until the new latency is + // fetched. + if (proxy.healthy && latency && latency.at < refetchDate) { + return true + } + + return false + } if (isLoading) { return ( @@ -234,6 +255,7 @@ const ProxyMenu: FC<{ proxyContextValue: ProxyContextValue }> = ({ {selectedProxy.display_name} ) : ( @@ -277,7 +299,10 @@ const ProxyMenu: FC<{ proxyContextValue: ProxyContextValue }> = ({ /> {proxy.display_name} - + ))} @@ -298,7 +323,8 @@ const ProxyMenu: FC<{ proxyContextValue: ProxyContextValue }> = ({ // Stop the menu from closing e.stopPropagation() // Refresh the latencies. - refreshLatencies() + const refetchDate = refreshLatencies() + setRefetchDate(refetchDate) }} > Refresh Latencies diff --git a/site/src/components/ProxyStatusLatency/ProxyStatusLatency.tsx b/site/src/components/ProxyStatusLatency/ProxyStatusLatency.tsx index 6988050e55..301efe990c 100644 --- a/site/src/components/ProxyStatusLatency/ProxyStatusLatency.tsx +++ b/site/src/components/ProxyStatusLatency/ProxyStatusLatency.tsx @@ -4,11 +4,29 @@ import Box from "@mui/material/Box" import Tooltip from "@mui/material/Tooltip" import { FC } from "react" import { getLatencyColor } from "utils/latency" +import CircularProgress from "@mui/material/CircularProgress" -export const ProxyStatusLatency: FC<{ latency?: number }> = ({ latency }) => { +export const ProxyStatusLatency: FC<{ + latency?: number + isLoading?: boolean +}> = ({ latency, isLoading }) => { const theme = useTheme() const color = getLatencyColor(theme, latency) + if (isLoading) { + return ( + + + + ) + } + if (!latency) { return ( diff --git a/site/src/components/Resources/AgentRow.stories.tsx b/site/src/components/Resources/AgentRow.stories.tsx index 7ffef16e04..522fe37cb0 100644 --- a/site/src/components/Resources/AgentRow.stories.tsx +++ b/site/src/components/Resources/AgentRow.stories.tsx @@ -68,8 +68,8 @@ const TemplateFC = ( clearProxy: () => { return }, - refetchProxyLatencies: () => { - return + refetchProxyLatencies: (): Date => { + return new Date() }, }} > diff --git a/site/src/components/Resources/ResourceCard.stories.tsx b/site/src/components/Resources/ResourceCard.stories.tsx index 8de2c49b1e..4b8a33c90e 100644 --- a/site/src/components/Resources/ResourceCard.stories.tsx +++ b/site/src/components/Resources/ResourceCard.stories.tsx @@ -33,8 +33,8 @@ Example.args = { clearProxy: () => { return }, - refetchProxyLatencies: () => { - return + refetchProxyLatencies: (): Date => { + return new Date() }, }} > @@ -106,8 +106,8 @@ BunchOfMetadata.args = { clearProxy: () => { return }, - refetchProxyLatencies: () => { - return + refetchProxyLatencies: (): Date => { + return new Date() }, }} > diff --git a/site/src/components/Workspace/Workspace.stories.tsx b/site/src/components/Workspace/Workspace.stories.tsx index 2b2df5e5f6..70b022f1ec 100644 --- a/site/src/components/Workspace/Workspace.stories.tsx +++ b/site/src/components/Workspace/Workspace.stories.tsx @@ -42,8 +42,8 @@ const meta: Meta = { setProxy: () => { return }, - refetchProxyLatencies: () => { - return + refetchProxyLatencies: (): Date => { + return new Date() }, }} > diff --git a/site/src/contexts/ProxyContext.tsx b/site/src/contexts/ProxyContext.tsx index 82d83506dd..913b605f48 100644 --- a/site/src/contexts/ProxyContext.tsx +++ b/site/src/contexts/ProxyContext.tsx @@ -53,7 +53,7 @@ export interface ProxyContextValue { proxyLatencies: Record // refetchProxyLatencies will trigger refreshing of the proxy latencies. By default the latencies // are loaded once. - refetchProxyLatencies: () => void + refetchProxyLatencies: () => Date // setProxy is a function that sets the user's selected proxy. This function should // only be called if the user is manually selecting a proxy. This value is stored in local // storage and will persist across reloads and tabs.