From ab3f897e14c6747ba29cfb66f502709ccea7d15d Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 13 May 2025 17:28:44 -0500 Subject: [PATCH 01/16] feat: default workspace proxy based on latency Auto select the proxy on first load, then defer to user selection. The auto selected proxy will not update again once set. --- site/src/contexts/ProxyContext.tsx | 34 ++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/site/src/contexts/ProxyContext.tsx b/site/src/contexts/ProxyContext.tsx index 55637e32a3069..ef0f4c87b7a1f 100644 --- a/site/src/contexts/ProxyContext.tsx +++ b/site/src/contexts/ProxyContext.tsx @@ -128,18 +128,30 @@ export const ProxyProvider: FC = ({ children }) => { // updateProxy is a helper function that when called will // update the proxy being used. const updateProxy = useCallback(() => { + const userProxy = loadUserSelectedProxy(); // Update the saved user proxy for the caller. - setUserSavedProxy(loadUserSelectedProxy()); - setProxy( - getPreferredProxy( - proxiesResp ?? [], - loadUserSelectedProxy(), - proxyLatencies, - // Do not auto select based on latencies, as inconsistent latencies can cause this - // to behave poorly. - false, - ), - ); + setUserSavedProxy(userProxy); + + // preferred proxy is the proxy that will be used. + // 1. It first selects from the user selected proxy. + // 2. If no user selected proxy is found, it will select + // the best proxy based on latency. + // 2a. The auto select is saved to local storage. So latency changes will not change + // the selected proxy, unless the user manually changes it from the auto selected. + const preferred = getPreferredProxy( + proxiesResp ?? [], + userProxy, + proxyLatencies, + // Autoselect iff the user has not selected a proxy yet. We will save this to local storage. + // If the user disagrees with the auto selected proxy, they can always change it. + true, + ) + + if(userProxy === undefined) { + setUserSavedProxy(preferred.proxy); + } + + setProxy(preferred); }, [proxiesResp, proxyLatencies]); // This useEffect ensures the proxy to be used is updated whenever the state changes. From fd172b7fb76fe8dc0d8597dbccf12a745c3379ee Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 13 May 2025 17:32:52 -0500 Subject: [PATCH 02/16] always save the proxy --- site/src/contexts/ProxyContext.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/site/src/contexts/ProxyContext.tsx b/site/src/contexts/ProxyContext.tsx index ef0f4c87b7a1f..5df88069ee195 100644 --- a/site/src/contexts/ProxyContext.tsx +++ b/site/src/contexts/ProxyContext.tsx @@ -147,9 +147,10 @@ export const ProxyProvider: FC = ({ children }) => { true, ) - if(userProxy === undefined) { - setUserSavedProxy(preferred.proxy); - } + // Always update the proxy in local storage. We do not want this changing automatically. + // It should be set with latencies on load, and then the user can change it. + // If an unhealthy proxy is selected, it will behave as if the user loaded the page for the first time. + setUserSavedProxy(preferred.proxy); setProxy(preferred); }, [proxiesResp, proxyLatencies]); From 5de9d611e86447f16786f1e3e32cd17c88021c9f Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 13 May 2025 17:53:53 -0500 Subject: [PATCH 03/16] save the first latency report back --- site/src/contexts/ProxyContext.tsx | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/site/src/contexts/ProxyContext.tsx b/site/src/contexts/ProxyContext.tsx index 5df88069ee195..1b6e31205c548 100644 --- a/site/src/contexts/ProxyContext.tsx +++ b/site/src/contexts/ProxyContext.tsx @@ -128,10 +128,7 @@ export const ProxyProvider: FC = ({ children }) => { // updateProxy is a helper function that when called will // update the proxy being used. const updateProxy = useCallback(() => { - const userProxy = loadUserSelectedProxy(); - // Update the saved user proxy for the caller. - setUserSavedProxy(userProxy); - + const userSelectedProxy = loadUserSelectedProxy(); // preferred proxy is the proxy that will be used. // 1. It first selects from the user selected proxy. // 2. If no user selected proxy is found, it will select @@ -140,7 +137,7 @@ export const ProxyProvider: FC = ({ children }) => { // the selected proxy, unless the user manually changes it from the auto selected. const preferred = getPreferredProxy( proxiesResp ?? [], - userProxy, + loadUserSelectedProxy(), proxyLatencies, // Autoselect iff the user has not selected a proxy yet. We will save this to local storage. // If the user disagrees with the auto selected proxy, they can always change it. @@ -150,7 +147,14 @@ export const ProxyProvider: FC = ({ children }) => { // Always update the proxy in local storage. We do not want this changing automatically. // It should be set with latencies on load, and then the user can change it. // If an unhealthy proxy is selected, it will behave as if the user loaded the page for the first time. - setUserSavedProxy(preferred.proxy); + if(proxyLatencies && preferred.proxy && proxyLatencies[preferred.proxy.id]) { + // This stores the first proxy to return a latency report. + saveUserSelectedProxy(preferred.proxy); + // Update the saved user proxy for the caller. + setUserSavedProxy(preferred.proxy); + } else { + setUserSavedProxy(userSelectedProxy); + } setProxy(preferred); }, [proxiesResp, proxyLatencies]); @@ -227,14 +231,16 @@ export const getPreferredProxy = ( // If no proxy is selected, or the selected proxy is unhealthy default to the primary proxy. if (!selectedProxy || !selectedProxy.healthy) { - // By default, use the primary proxy. - selectedProxy = proxies.find((proxy) => proxy.name === "primary"); - // If we have latencies, then attempt to use the best proxy by latency instead. const best = selectByLatency(proxies, latencies); if (autoSelectBasedOnLatency && best) { selectedProxy = best; } + + // Use the primary proxy if we don't have latencies + if(!best) { + selectedProxy = proxies.find((proxy) => proxy.name === "primary"); + } } return computeUsableURLS(selectedProxy); From e0b9eb3f5b2c03b1d564440e304c0da8ca49c499 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 13 May 2025 18:00:34 -0500 Subject: [PATCH 04/16] add comments --- site/src/contexts/ProxyContext.tsx | 75 ++++++++++++++++------------ site/src/contexts/useProxyLatency.ts | 5 ++ 2 files changed, 48 insertions(+), 32 deletions(-) diff --git a/site/src/contexts/ProxyContext.tsx b/site/src/contexts/ProxyContext.tsx index 1b6e31205c548..ebef914c41e4a 100644 --- a/site/src/contexts/ProxyContext.tsx +++ b/site/src/contexts/ProxyContext.tsx @@ -122,41 +122,24 @@ export const ProxyProvider: FC = ({ children }) => { // Every time we get a new proxiesResponse, update the latency check // to each workspace proxy. - const { proxyLatencies, refetch: refetchProxyLatencies } = + const { proxyLatencies, refetch: refetchProxyLatencies, loaded: latenciesLoaded } = useProxyLatency(proxiesResp); // updateProxy is a helper function that when called will // update the proxy being used. const updateProxy = useCallback(() => { - const userSelectedProxy = loadUserSelectedProxy(); - // preferred proxy is the proxy that will be used. - // 1. It first selects from the user selected proxy. - // 2. If no user selected proxy is found, it will select - // the best proxy based on latency. - // 2a. The auto select is saved to local storage. So latency changes will not change - // the selected proxy, unless the user manually changes it from the auto selected. - const preferred = getPreferredProxy( - proxiesResp ?? [], - loadUserSelectedProxy(), - proxyLatencies, - // Autoselect iff the user has not selected a proxy yet. We will save this to local storage. - // If the user disagrees with the auto selected proxy, they can always change it. - true, - ) - - // Always update the proxy in local storage. We do not want this changing automatically. - // It should be set with latencies on load, and then the user can change it. - // If an unhealthy proxy is selected, it will behave as if the user loaded the page for the first time. - if(proxyLatencies && preferred.proxy && proxyLatencies[preferred.proxy.id]) { - // This stores the first proxy to return a latency report. - saveUserSelectedProxy(preferred.proxy); - // Update the saved user proxy for the caller. - setUserSavedProxy(preferred.proxy); - } else { - setUserSavedProxy(userSelectedProxy); - } - - setProxy(preferred); + // Update the saved user proxy for the caller. + setUserSavedProxy(loadUserSelectedProxy()); + setProxy( + getPreferredProxy( + proxiesResp ?? [], + loadUserSelectedProxy(), + proxyLatencies, + // Do not auto select based on latencies, as inconsistent latencies can cause this + // to behave poorly. + false, + ), + ); }, [proxiesResp, proxyLatencies]); // This useEffect ensures the proxy to be used is updated whenever the state changes. @@ -166,6 +149,34 @@ export const ProxyProvider: FC = ({ children }) => { updateProxy(); }, [proxiesResp, proxyLatencies]); + // This useEffect will auto select the best proxy if the user has not selected one. + // It must wait until all latencies are loaded to select based on latency. This does mean + // the first time a user loads the page, the proxy will "flicker" to the best proxy. + // + // Once the page is loaded, or the user selects a proxy, this will not run again. + useEffect(() => { + if(loadUserSelectedProxy() !== undefined) { + return; // User has selected a proxy, do not auto select. + } + if(!latenciesLoaded) { + // Wait until the latencies are loaded before + return; + } + + const best = getPreferredProxy( + proxiesResp ?? [], + loadUserSelectedProxy(), + proxyLatencies, + true, + ); + + if(best?.proxy) { + saveUserSelectedProxy(best.proxy); + updateProxy(); + } + + }, [latenciesLoaded]) + return ( proxy.name === "primary"); } } diff --git a/site/src/contexts/useProxyLatency.ts b/site/src/contexts/useProxyLatency.ts index ff8be8cd66135..cd9fd6b27bd8f 100644 --- a/site/src/contexts/useProxyLatency.ts +++ b/site/src/contexts/useProxyLatency.ts @@ -48,6 +48,7 @@ export const useProxyLatency = ( // Until the new values are loaded, the old values will still be used. refetch: () => Date; proxyLatencies: Record; + loaded: boolean; } => { // maxStoredLatencies is the maximum number of latencies to store per proxy in local storage. let maxStoredLatencies = 1; @@ -73,6 +74,8 @@ export const useProxyLatency = ( new Date(new Date().getTime() - proxyIntervalSeconds * 1000).toISOString(), ); + const [loaded, setLoaded] = useState(false); + // Refetch will always set the latestFetchRequest to the current time, making all the cached latencies // stale and triggering a refetch of all proxies in the list. const refetch = () => { @@ -231,6 +234,7 @@ export const useProxyLatency = ( // Local storage cleanup garbageCollectStoredLatencies(proxies, maxStoredLatencies); + setLoaded(true); }); return () => { @@ -241,6 +245,7 @@ export const useProxyLatency = ( return { proxyLatencies, refetch, + loaded }; }; From 5427b6144b74842f8f608729bbf0a48afc96f9be Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 13 May 2025 18:01:45 -0500 Subject: [PATCH 05/16] unit test --- site/src/contexts/ProxyContext.test.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site/src/contexts/ProxyContext.test.tsx b/site/src/contexts/ProxyContext.test.tsx index 8e16e868627e3..4ff6cebfae14a 100644 --- a/site/src/contexts/ProxyContext.test.tsx +++ b/site/src/contexts/ProxyContext.test.tsx @@ -26,7 +26,7 @@ import type * as ProxyLatency from "./useProxyLatency"; // here and not inside a unit test. jest.mock("contexts/useProxyLatency", () => ({ useProxyLatency: () => { - return { proxyLatencies: hardCodedLatencies, refetch: jest.fn() }; + return { proxyLatencies: hardCodedLatencies, refetch: jest.fn(), loaded: true }; }, })); @@ -261,11 +261,11 @@ describe("ProxyContextSelection", () => { expUserProxyID: MockHealthyWildWorkspaceProxy.id, }, ], - // Latency behavior is disabled, so the primary should be selected. + // First page load defers to the proxy by latency [ "regions_default_low_latency", { - expProxyID: MockPrimaryWorkspaceProxy.id, + expProxyID: MockHealthyWildWorkspaceProxy.id, regions: MockWorkspaceProxies, storageProxy: undefined, latencies: { From dcf98d78d372330db9f834cfd5836cbe19c4b4c8 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 13 May 2025 18:03:04 -0500 Subject: [PATCH 06/16] comment --- site/src/contexts/ProxyContext.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/site/src/contexts/ProxyContext.tsx b/site/src/contexts/ProxyContext.tsx index ebef914c41e4a..969c1181829c9 100644 --- a/site/src/contexts/ProxyContext.tsx +++ b/site/src/contexts/ProxyContext.tsx @@ -136,7 +136,8 @@ export const ProxyProvider: FC = ({ children }) => { loadUserSelectedProxy(), proxyLatencies, // Do not auto select based on latencies, as inconsistent latencies can cause this - // to behave poorly. + // to change on each call. updateProxy should be stable when selecting a proxy to + // prevent flickering. false, ), ); @@ -150,7 +151,7 @@ export const ProxyProvider: FC = ({ children }) => { }, [proxiesResp, proxyLatencies]); // This useEffect will auto select the best proxy if the user has not selected one. - // It must wait until all latencies are loaded to select based on latency. This does mean + // It must wait until all latencies are loaded to select based on latency. This does mean // the first time a user loads the page, the proxy will "flicker" to the best proxy. // // Once the page is loaded, or the user selects a proxy, this will not run again. From 93bc6b372c107edcb4424ea1fb9df51a53888124 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 13 May 2025 18:13:21 -0500 Subject: [PATCH 07/16] fmt --- site/src/contexts/ProxyContext.test.tsx | 6 +++++- site/src/contexts/ProxyContext.tsx | 21 ++++++++++++--------- site/src/contexts/useProxyLatency.ts | 2 +- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/site/src/contexts/ProxyContext.test.tsx b/site/src/contexts/ProxyContext.test.tsx index 4ff6cebfae14a..addcdb09d0705 100644 --- a/site/src/contexts/ProxyContext.test.tsx +++ b/site/src/contexts/ProxyContext.test.tsx @@ -26,7 +26,11 @@ import type * as ProxyLatency from "./useProxyLatency"; // here and not inside a unit test. jest.mock("contexts/useProxyLatency", () => ({ useProxyLatency: () => { - return { proxyLatencies: hardCodedLatencies, refetch: jest.fn(), loaded: true }; + return { + proxyLatencies: hardCodedLatencies, + refetch: jest.fn(), + loaded: true, + }; }, })); diff --git a/site/src/contexts/ProxyContext.tsx b/site/src/contexts/ProxyContext.tsx index 969c1181829c9..facbc49ffd989 100644 --- a/site/src/contexts/ProxyContext.tsx +++ b/site/src/contexts/ProxyContext.tsx @@ -122,8 +122,11 @@ export const ProxyProvider: FC = ({ children }) => { // Every time we get a new proxiesResponse, update the latency check // to each workspace proxy. - const { proxyLatencies, refetch: refetchProxyLatencies, loaded: latenciesLoaded } = - useProxyLatency(proxiesResp); + const { + proxyLatencies, + refetch: refetchProxyLatencies, + loaded: latenciesLoaded, + } = useProxyLatency(proxiesResp); // updateProxy is a helper function that when called will // update the proxy being used. @@ -153,13 +156,14 @@ export const ProxyProvider: FC = ({ children }) => { // This useEffect will auto select the best proxy if the user has not selected one. // It must wait until all latencies are loaded to select based on latency. This does mean // the first time a user loads the page, the proxy will "flicker" to the best proxy. - // + // // Once the page is loaded, or the user selects a proxy, this will not run again. + // biome-ignore lint/correctness/useExhaustiveDependencies: Only update if the source data changes useEffect(() => { - if(loadUserSelectedProxy() !== undefined) { + if (loadUserSelectedProxy() !== undefined) { return; // User has selected a proxy, do not auto select. } - if(!latenciesLoaded) { + if (!latenciesLoaded) { // Wait until the latencies are loaded before return; } @@ -171,12 +175,11 @@ export const ProxyProvider: FC = ({ children }) => { true, ); - if(best?.proxy) { + if (best?.proxy) { saveUserSelectedProxy(best.proxy); updateProxy(); } - - }, [latenciesLoaded]) + }, [latenciesLoaded, proxiesResp, proxyLatencies]); return ( proxy.name === "primary"); } } diff --git a/site/src/contexts/useProxyLatency.ts b/site/src/contexts/useProxyLatency.ts index cd9fd6b27bd8f..cb92274b8286f 100644 --- a/site/src/contexts/useProxyLatency.ts +++ b/site/src/contexts/useProxyLatency.ts @@ -245,7 +245,7 @@ export const useProxyLatency = ( return { proxyLatencies, refetch, - loaded + loaded, }; }; From f5c0719526802b17cb47956d4b69eb67c593f730 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 13 May 2025 20:03:23 -0500 Subject: [PATCH 08/16] add latenciesLoaded to unit tests --- site/src/contexts/ProxyContext.test.tsx | 10 +++++++--- site/src/contexts/ProxyContext.tsx | 14 ++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/site/src/contexts/ProxyContext.test.tsx b/site/src/contexts/ProxyContext.test.tsx index addcdb09d0705..b3050c0cd3fcd 100644 --- a/site/src/contexts/ProxyContext.test.tsx +++ b/site/src/contexts/ProxyContext.test.tsx @@ -119,7 +119,7 @@ describe("ProxyContextGetURLs", () => { preferredPathAppURL, preferredWildcardHostname, ) => { - const preferred = getPreferredProxy(regions, selected, latencies); + const preferred = getPreferredProxy(regions, selected, latencies, true); expect(preferred.preferredPathAppURL).toBe(preferredPathAppURL); expect(preferred.preferredWildcardHostname).toBe( preferredWildcardHostname, @@ -142,10 +142,11 @@ const TestingComponent = () => { // TestingScreen just mounts some components that we can check in the unit test. const TestingScreen = () => { - const { proxy, userProxy, isFetched, isLoading, clearProxy, setProxy } = + const { proxy, userProxy, isFetched, isLoading, latenciesLoaded, clearProxy, setProxy } = useProxy(); return ( <> +
@@ -210,7 +211,6 @@ describe("ProxyContextSelection", () => { }; it.each([ - // Not latency behavior [ "empty", { @@ -366,6 +366,10 @@ describe("ProxyContextSelection", () => { TestingComponent(); await waitForLoaderToBeRemoved(); + await screen.findByTestId("latenciesLoaded").then((x) => { + expect(x.title).toBe("true"); + }); + if (afterLoad) { await afterLoad(); } diff --git a/site/src/contexts/ProxyContext.tsx b/site/src/contexts/ProxyContext.tsx index facbc49ffd989..b003a971ffc28 100644 --- a/site/src/contexts/ProxyContext.tsx +++ b/site/src/contexts/ProxyContext.tsx @@ -54,6 +54,9 @@ export interface ProxyContextValue { // then the latency has not been fetched yet. Calculations happen async for each proxy in the list. // Refer to the returned report for a given proxy for more information. proxyLatencies: ProxyLatencies; + // latenciesLoaded is true when the latencies have been initially loaded. + // Once set to true, it will not be set to false again. + latenciesLoaded: boolean; // refetchProxyLatencies will trigger refreshing of the proxy latencies. By default the latencies // are loaded once. refetchProxyLatencies: () => Date; @@ -189,6 +192,7 @@ export const ProxyProvider: FC = ({ children }) => { userProxy: userSavedProxy, proxy: proxy, proxies: proxiesResp, + latenciesLoaded: latenciesLoaded, isLoading: proxiesLoading, isFetched: proxiesFetched, error: proxiesError, @@ -246,16 +250,14 @@ export const getPreferredProxy = ( // If no proxy is selected, or the selected proxy is unhealthy default to the primary proxy. if (!selectedProxy || !selectedProxy.healthy) { + // Default to the primary proxy + selectedProxy = proxies.find((proxy) => proxy.name === "primary"); + // If we have latencies, then attempt to use the best proxy by latency instead. const best = selectByLatency(proxies, latencies); - if (autoSelectBasedOnLatency && best) { + if (autoSelectBasedOnLatency && best !== undefined) { selectedProxy = best; } - - // Use the primary proxy if we don't have any other options. - if (!selectedProxy) { - selectedProxy = proxies.find((proxy) => proxy.name === "primary"); - } } return computeUsableURLS(selectedProxy); From f2b5d9c4e722e45339954227616aa22e7d75e223 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 13 May 2025 20:07:39 -0500 Subject: [PATCH 09/16] fixup tests --- site/src/contexts/ProxyContext.test.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/site/src/contexts/ProxyContext.test.tsx b/site/src/contexts/ProxyContext.test.tsx index b3050c0cd3fcd..66945ef59b0a4 100644 --- a/site/src/contexts/ProxyContext.test.tsx +++ b/site/src/contexts/ProxyContext.test.tsx @@ -224,6 +224,7 @@ describe("ProxyContextSelection", () => { "regions_no_selection", { expProxyID: MockPrimaryWorkspaceProxy.id, + expUserProxyID: MockPrimaryWorkspaceProxy.id, regions: MockWorkspaceProxies, storageProxy: undefined, }, @@ -270,6 +271,7 @@ describe("ProxyContextSelection", () => { "regions_default_low_latency", { expProxyID: MockHealthyWildWorkspaceProxy.id, + expUserProxyID: MockHealthyWildWorkspaceProxy.id, regions: MockWorkspaceProxies, storageProxy: undefined, latencies: { From b3102b7d6e86b8c2732d770536643400eda1a6b8 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 13 May 2025 20:11:55 -0500 Subject: [PATCH 10/16] fixup test fixtures --- site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx | 1 + site/src/modules/dashboard/Navbar/NavbarView.test.tsx | 1 + site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx | 1 + site/src/modules/resources/AgentRow.stories.tsx | 2 ++ site/src/modules/resources/AppLink/AppLink.stories.tsx | 1 + site/src/modules/resources/ResourceCard.stories.tsx | 1 + site/src/modules/resources/Resources.stories.tsx | 1 + .../WorkspaceAppStatus/WorkspaceAppStatus.stories.tsx | 1 + site/src/pages/WorkspacePage/AppStatuses.stories.tsx | 1 + site/src/pages/WorkspacePage/Workspace.stories.tsx | 1 + site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx | 1 + 11 files changed, 12 insertions(+) diff --git a/site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx b/site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx index 058c8799c95e0..697e444ee2ab6 100644 --- a/site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx +++ b/site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx @@ -28,6 +28,7 @@ const meta: Meta = { preferredWildcardHostname: "", proxy: MockPrimaryWorkspaceProxy, }, + latenciesLoaded: true, isLoading: false, isFetched: true, setProxy: fn(), diff --git a/site/src/modules/dashboard/Navbar/NavbarView.test.tsx b/site/src/modules/dashboard/Navbar/NavbarView.test.tsx index 6739f666c2b17..87f91e8806ecb 100644 --- a/site/src/modules/dashboard/Navbar/NavbarView.test.tsx +++ b/site/src/modules/dashboard/Navbar/NavbarView.test.tsx @@ -11,6 +11,7 @@ const proxyContextValue: ProxyContextValue = { preferredWildcardHostname: "", proxy: MockPrimaryWorkspaceProxy, }, + latenciesLoaded: true, isLoading: false, isFetched: true, setProxy: jest.fn(), diff --git a/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx b/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx index 6df47684173fe..7669d9830a403 100644 --- a/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx +++ b/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx @@ -19,6 +19,7 @@ const defaultProxyContextValue = { proxy: getPreferredProxy(MockWorkspaceProxies, undefined), proxies: MockWorkspaceProxies, isLoading: false, + latenciesLoaded: true, isFetched: true, setProxy: fn(), clearProxy: fn(), diff --git a/site/src/modules/resources/AgentRow.stories.tsx b/site/src/modules/resources/AgentRow.stories.tsx index 0e80ee0a5ecd0..5c79a7e3499a2 100644 --- a/site/src/modules/resources/AgentRow.stories.tsx +++ b/site/src/modules/resources/AgentRow.stories.tsx @@ -102,6 +102,7 @@ const meta: Meta = { proxy: getPreferredProxy([], undefined), proxies: [], isLoading: false, + latenciesLoaded: true, isFetched: true, setProxy: () => { return; @@ -263,6 +264,7 @@ export const ShowingPortForward: Story = { ), proxies: M.MockWorkspaceProxies, isLoading: false, + latenciesLoaded: true, isFetched: true, setProxy: () => { return; diff --git a/site/src/modules/resources/AppLink/AppLink.stories.tsx b/site/src/modules/resources/AppLink/AppLink.stories.tsx index 8f710e818aee2..c9d85ab14e65d 100644 --- a/site/src/modules/resources/AppLink/AppLink.stories.tsx +++ b/site/src/modules/resources/AppLink/AppLink.stories.tsx @@ -28,6 +28,7 @@ const meta: Meta = { }, proxies: MockWorkspaceProxies, isLoading: false, + latenciesLoaded: true, isFetched: true, setProxy: () => { return; diff --git a/site/src/modules/resources/ResourceCard.stories.tsx b/site/src/modules/resources/ResourceCard.stories.tsx index 1ce76894a032e..93e4e2de2ea68 100644 --- a/site/src/modules/resources/ResourceCard.stories.tsx +++ b/site/src/modules/resources/ResourceCard.stories.tsx @@ -79,6 +79,7 @@ function getAgentRow(agent: WorkspaceAgent): JSX.Element { proxy: getPreferredProxy([], undefined), proxies: [], isLoading: false, + latenciesLoaded: true, isFetched: true, setProxy: () => { return; diff --git a/site/src/modules/resources/Resources.stories.tsx b/site/src/modules/resources/Resources.stories.tsx index da8ed2f249696..6d54aaf8dd16b 100644 --- a/site/src/modules/resources/Resources.stories.tsx +++ b/site/src/modules/resources/Resources.stories.tsx @@ -175,6 +175,7 @@ function getAgentRow(agent: WorkspaceAgent): JSX.Element { proxy: getPreferredProxy([], undefined), proxies: [], isLoading: false, + latenciesLoaded: true, isFetched: true, setProxy: () => { return; diff --git a/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.stories.tsx b/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.stories.tsx index 74ec70a863a08..08ee3e672d2a2 100644 --- a/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.stories.tsx +++ b/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.stories.tsx @@ -19,6 +19,7 @@ const meta: Meta = { proxyLatencies: MockProxyLatencies, proxy: getPreferredProxy([], undefined), proxies: [], + latenciesLoaded: true, isLoading: false, isFetched: true, clearProxy: () => { diff --git a/site/src/pages/WorkspacePage/AppStatuses.stories.tsx b/site/src/pages/WorkspacePage/AppStatuses.stories.tsx index 86e6f345b5e59..ca28bd922db14 100644 --- a/site/src/pages/WorkspacePage/AppStatuses.stories.tsx +++ b/site/src/pages/WorkspacePage/AppStatuses.stories.tsx @@ -21,6 +21,7 @@ const meta: Meta = { proxy: getPreferredProxy([], undefined), proxies: [], isLoading: false, + latenciesLoaded: true, isFetched: true, clearProxy: () => { return; diff --git a/site/src/pages/WorkspacePage/Workspace.stories.tsx b/site/src/pages/WorkspacePage/Workspace.stories.tsx index a59e2f78bcee2..9253995299393 100644 --- a/site/src/pages/WorkspacePage/Workspace.stories.tsx +++ b/site/src/pages/WorkspacePage/Workspace.stories.tsx @@ -53,6 +53,7 @@ const meta: Meta = { proxy: getPreferredProxy([], undefined), proxies: [], isLoading: false, + latenciesLoaded: true, isFetched: true, clearProxy: () => { return; diff --git a/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx b/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx index dc1b9c2f4fb82..6f729270af833 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx @@ -157,6 +157,7 @@ const meta: Meta = { proxy: getPreferredProxy([], undefined), proxies: [], isLoading: false, + latenciesLoaded: true, isFetched: true, clearProxy: () => { return; From d07e4727807a506c5467ad7fb1c0ecd2da9df979 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 14 May 2025 07:14:56 -0500 Subject: [PATCH 11/16] fmt --- site/src/contexts/ProxyContext.test.tsx | 18 +++++++++++++++--- site/src/contexts/ProxyContext.tsx | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/site/src/contexts/ProxyContext.test.tsx b/site/src/contexts/ProxyContext.test.tsx index 66945ef59b0a4..096bc1a8f9b5c 100644 --- a/site/src/contexts/ProxyContext.test.tsx +++ b/site/src/contexts/ProxyContext.test.tsx @@ -142,11 +142,23 @@ const TestingComponent = () => { // TestingScreen just mounts some components that we can check in the unit test. const TestingScreen = () => { - const { proxy, userProxy, isFetched, isLoading, latenciesLoaded, clearProxy, setProxy } = - useProxy(); + const { + proxy, + userProxy, + isFetched, + isLoading, + latenciesLoaded, + clearProxy, + setProxy, + } = useProxy(); + + console.log(proxy); return ( <> -
+
diff --git a/site/src/contexts/ProxyContext.tsx b/site/src/contexts/ProxyContext.tsx index b003a971ffc28..c526f1b0f3a67 100644 --- a/site/src/contexts/ProxyContext.tsx +++ b/site/src/contexts/ProxyContext.tsx @@ -54,7 +54,7 @@ export interface ProxyContextValue { // then the latency has not been fetched yet. Calculations happen async for each proxy in the list. // Refer to the returned report for a given proxy for more information. proxyLatencies: ProxyLatencies; - // latenciesLoaded is true when the latencies have been initially loaded. + // latenciesLoaded is true when the latencies have been initially loaded. // Once set to true, it will not be set to false again. latenciesLoaded: boolean; // refetchProxyLatencies will trigger refreshing of the proxy latencies. By default the latencies From abf49ae684afe665829cd0efbf64bc84423641db Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 14 May 2025 07:19:24 -0500 Subject: [PATCH 12/16] remove console log, whoops --- site/src/contexts/ProxyContext.test.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/site/src/contexts/ProxyContext.test.tsx b/site/src/contexts/ProxyContext.test.tsx index 096bc1a8f9b5c..03f2662037733 100644 --- a/site/src/contexts/ProxyContext.test.tsx +++ b/site/src/contexts/ProxyContext.test.tsx @@ -152,7 +152,6 @@ const TestingScreen = () => { setProxy, } = useProxy(); - console.log(proxy); return ( <>
Date: Wed, 14 May 2025 07:27:44 -0500 Subject: [PATCH 13/16] add comments --- site/src/contexts/ProxyContext.tsx | 2 +- site/src/contexts/useProxyLatency.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/site/src/contexts/ProxyContext.tsx b/site/src/contexts/ProxyContext.tsx index c526f1b0f3a67..c162c2c4952ff 100644 --- a/site/src/contexts/ProxyContext.tsx +++ b/site/src/contexts/ProxyContext.tsx @@ -167,7 +167,7 @@ export const ProxyProvider: FC = ({ children }) => { return; // User has selected a proxy, do not auto select. } if (!latenciesLoaded) { - // Wait until the latencies are loaded before + // Wait until the latencies are loaded first. return; } diff --git a/site/src/contexts/useProxyLatency.ts b/site/src/contexts/useProxyLatency.ts index cb92274b8286f..f5f3d2acb415c 100644 --- a/site/src/contexts/useProxyLatency.ts +++ b/site/src/contexts/useProxyLatency.ts @@ -48,6 +48,10 @@ export const useProxyLatency = ( // Until the new values are loaded, the old values will still be used. refetch: () => Date; proxyLatencies: Record; + // loaded signals all latency requests have completed. Once set to true, this will not change. + // Latencies at this point should be loaded from local storage, and updated asynchronously as needed. + // If local storage has updated latencies, then this will be set to true with 0 actual network requests. + // The loaded latencies will all be from the cache. loaded: boolean; } => { // maxStoredLatencies is the maximum number of latencies to store per proxy in local storage. From 9d9e7f3e45460e1bce79c7f267666c893e8ebe19 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 27 May 2025 13:36:45 -0500 Subject: [PATCH 14/16] revert to main --- site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx | 1 - site/src/modules/dashboard/Navbar/NavbarView.test.tsx | 1 - site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx | 1 - 3 files changed, 3 deletions(-) diff --git a/site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx b/site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx index 697e444ee2ab6..058c8799c95e0 100644 --- a/site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx +++ b/site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx @@ -28,7 +28,6 @@ const meta: Meta = { preferredWildcardHostname: "", proxy: MockPrimaryWorkspaceProxy, }, - latenciesLoaded: true, isLoading: false, isFetched: true, setProxy: fn(), diff --git a/site/src/modules/dashboard/Navbar/NavbarView.test.tsx b/site/src/modules/dashboard/Navbar/NavbarView.test.tsx index 87f91e8806ecb..6739f666c2b17 100644 --- a/site/src/modules/dashboard/Navbar/NavbarView.test.tsx +++ b/site/src/modules/dashboard/Navbar/NavbarView.test.tsx @@ -11,7 +11,6 @@ const proxyContextValue: ProxyContextValue = { preferredWildcardHostname: "", proxy: MockPrimaryWorkspaceProxy, }, - latenciesLoaded: true, isLoading: false, isFetched: true, setProxy: jest.fn(), diff --git a/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx b/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx index 7669d9830a403..6df47684173fe 100644 --- a/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx +++ b/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx @@ -19,7 +19,6 @@ const defaultProxyContextValue = { proxy: getPreferredProxy(MockWorkspaceProxies, undefined), proxies: MockWorkspaceProxies, isLoading: false, - latenciesLoaded: true, isFetched: true, setProxy: fn(), clearProxy: fn(), From 6036996a80208448353c268639e39be33b01d993 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 27 May 2025 13:37:44 -0500 Subject: [PATCH 15/16] fix js test --- site/src/testHelpers/storybook.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/site/src/testHelpers/storybook.tsx b/site/src/testHelpers/storybook.tsx index ed64c10958a0b..4b2ba94bd2577 100644 --- a/site/src/testHelpers/storybook.tsx +++ b/site/src/testHelpers/storybook.tsx @@ -167,6 +167,7 @@ export const withProxyProvider = return ( Date: Tue, 27 May 2025 15:41:04 -0500 Subject: [PATCH 16/16] fix js test --- site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx | 1 + site/src/modules/dashboard/Navbar/NavbarView.test.tsx | 1 + site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx | 1 + 3 files changed, 3 insertions(+) diff --git a/site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx b/site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx index 058c8799c95e0..cb186dcb973b0 100644 --- a/site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx +++ b/site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx @@ -23,6 +23,7 @@ const meta: Meta = { component: MobileMenu, args: { proxyContextValue: { + latenciesLoaded: true, proxy: { preferredPathAppURL: "", preferredWildcardHostname: "", diff --git a/site/src/modules/dashboard/Navbar/NavbarView.test.tsx b/site/src/modules/dashboard/Navbar/NavbarView.test.tsx index 6739f666c2b17..358b717b492a4 100644 --- a/site/src/modules/dashboard/Navbar/NavbarView.test.tsx +++ b/site/src/modules/dashboard/Navbar/NavbarView.test.tsx @@ -6,6 +6,7 @@ import { renderWithAuth } from "testHelpers/renderHelpers"; import { NavbarView } from "./NavbarView"; const proxyContextValue: ProxyContextValue = { + latenciesLoaded: true, proxy: { preferredPathAppURL: "", preferredWildcardHostname: "", diff --git a/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx b/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx index 6df47684173fe..15dbb18471c3f 100644 --- a/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx +++ b/site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx @@ -15,6 +15,7 @@ import { withDesktopViewport } from "testHelpers/storybook"; import { ProxyMenu } from "./ProxyMenu"; const defaultProxyContextValue = { + latenciesLoaded: true, proxyLatencies: MockProxyLatencies, proxy: getPreferredProxy(MockWorkspaceProxies, undefined), proxies: MockWorkspaceProxies, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy