From 23e77dfec15dc1f4df3d9ad09ef06bdfc5ebdc60 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Sat, 28 Oct 2023 18:46:54 -0700 Subject: [PATCH] Recent requests/workspaces. Closes #1 --- src-web/components/AppRouter.tsx | 13 +++++---- src-web/components/GlobalHooks.tsx | 7 +++++ src-web/components/Workspaces.tsx | 14 +++++++-- src-web/hooks/useRecentEnvironments.ts | 40 ++++++++++++++++++++++++++ src-web/hooks/useRecentWorkspaces.ts | 35 ++++++++++++++++++++++ 5 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 src-web/hooks/useRecentEnvironments.ts create mode 100644 src-web/hooks/useRecentWorkspaces.ts diff --git a/src-web/components/AppRouter.tsx b/src-web/components/AppRouter.tsx index 14ee30de..06504696 100644 --- a/src-web/components/AppRouter.tsx +++ b/src-web/components/AppRouter.tsx @@ -7,7 +7,7 @@ import RouteError from './RouteError'; import Workspace from './Workspace'; import Workspaces from './Workspaces'; import { DialogProvider } from './DialogContext'; -import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId'; +import { useRecentEnvironments } from '../hooks/useRecentEnvironments'; const router = createBrowserRouter([ { @@ -47,8 +47,8 @@ export function AppRouter() { } function WorkspaceOrRedirect() { - const environmentId = useActiveEnvironmentId(); const recentRequests = useRecentRequests(); + const recentEnvironments = useRecentEnvironments(); const requests = useRequests(); const request = requests.find((r) => r.id === recentRequests[0]); const routes = useAppRoutes(); @@ -57,12 +57,15 @@ function WorkspaceOrRedirect() { return ; } + const environmentId = recentEnvironments[0]; + const { id: requestId, workspaceId } = request; + return ( ); diff --git a/src-web/components/GlobalHooks.tsx b/src-web/components/GlobalHooks.tsx index 174b7a7c..1cc57451 100644 --- a/src-web/components/GlobalHooks.tsx +++ b/src-web/components/GlobalHooks.tsx @@ -10,8 +10,15 @@ import { DEFAULT_FONT_SIZE } from '../lib/constants'; import { NAMESPACE_NO_SYNC } from '../lib/keyValueStore'; import type { HttpRequest, HttpResponse, Model, Workspace } from '../lib/models'; import { modelsEq } from '../lib/models'; +import { useRecentRequests } from '../hooks/useRecentRequests'; +import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces'; +import { useRecentEnvironments } from '../hooks/useRecentEnvironments'; export function GlobalHooks() { + useRecentWorkspaces(); + useRecentEnvironments(); + useRecentRequests(); + const queryClient = useQueryClient(); const { wasUpdatedExternally } = useRequestUpdateKey(null); diff --git a/src-web/components/Workspaces.tsx b/src-web/components/Workspaces.tsx index 125c2374..f2116b98 100644 --- a/src-web/components/Workspaces.tsx +++ b/src-web/components/Workspaces.tsx @@ -2,15 +2,23 @@ import { Navigate } from 'react-router-dom'; import { useAppRoutes } from '../hooks/useAppRoutes'; import { useWorkspaces } from '../hooks/useWorkspaces'; import { Heading } from './core/Heading'; +import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces'; export default function Workspaces() { const routes = useAppRoutes(); + const recentWorkspaceIds = useRecentWorkspaces(); const workspaces = useWorkspaces(); - const workspace = workspaces[0]; - if (workspace === undefined) { + const loading = workspaces.length === 0 && recentWorkspaceIds.length === 0; + if (loading) { + return null; + } + + const workspaceId = recentWorkspaceIds[0] ?? workspaces[0]?.id ?? null; + + if (workspaceId === null) { return There are no workspaces; } - return ; + return ; } diff --git a/src-web/hooks/useRecentEnvironments.ts b/src-web/hooks/useRecentEnvironments.ts new file mode 100644 index 00000000..aaa4f792 --- /dev/null +++ b/src-web/hooks/useRecentEnvironments.ts @@ -0,0 +1,40 @@ +import { useEffect } from 'react'; +import { createGlobalState, useEffectOnce, useLocalStorage } from 'react-use'; +import { useActiveRequestId } from './useActiveRequestId'; +import { useActiveWorkspaceId } from './useActiveWorkspaceId'; +import { useActiveEnvironmentId } from './useActiveEnvironmentId'; + +const useHistoryState = createGlobalState([]); + +export function useRecentEnvironments() { + const activeWorkspaceId = useActiveWorkspaceId(); + const activeEnvironmentId = useActiveEnvironmentId(); + const [history, setHistory] = useHistoryState(); + const [lsState, setLSState] = useLocalStorage( + 'recent_environments::' + activeWorkspaceId, + [], + ); + + // Load local storage state on initial render + useEffectOnce(() => { + if (lsState) { + setHistory(lsState); + } + }); + + // Update local storage state when history changes + useEffect(() => { + setLSState(history); + }, [history, setLSState]); + + // Set history when active request changes + useEffect(() => { + setHistory((currentHistory: string[]) => { + if (activeEnvironmentId === null) return currentHistory; + const withoutCurrentEnvironment = currentHistory.filter((id) => id !== activeEnvironmentId); + return [activeEnvironmentId, ...withoutCurrentEnvironment]; + }); + }, [activeEnvironmentId, setHistory]); + + return history; +} diff --git a/src-web/hooks/useRecentWorkspaces.ts b/src-web/hooks/useRecentWorkspaces.ts new file mode 100644 index 00000000..275aee27 --- /dev/null +++ b/src-web/hooks/useRecentWorkspaces.ts @@ -0,0 +1,35 @@ +import { useEffect } from 'react'; +import { createGlobalState, useEffectOnce, useLocalStorage } from 'react-use'; +import { useActiveRequestId } from './useActiveRequestId'; +import { useActiveWorkspaceId } from './useActiveWorkspaceId'; + +const useHistoryState = createGlobalState([]); + +export function useRecentWorkspaces() { + const activeWorkspaceId = useActiveWorkspaceId(); + const [history, setHistory] = useHistoryState(); + const [lsState, setLSState] = useLocalStorage('recent_workspaces', []); + + // Load local storage state on initial render + useEffectOnce(() => { + if (lsState) { + setHistory(lsState); + } + }); + + // Update local storage state when history changes + useEffect(() => { + setLSState(history); + }, [history, setLSState]); + + // Set history when active request changes + useEffect(() => { + setHistory((currentHistory: string[]) => { + if (activeWorkspaceId === null) return currentHistory; + const withoutCurrentWorkspace = currentHistory.filter((id) => id !== activeWorkspaceId); + return [activeWorkspaceId, ...withoutCurrentWorkspace]; + }); + }, [activeWorkspaceId, setHistory]); + + return history; +}