diff --git a/src-web/components/CommandPaletteDialog.tsx b/src-web/components/CommandPaletteDialog.tsx index c67bdcc2..036b2232 100644 --- a/src-web/components/CommandPaletteDialog.tsx +++ b/src-web/components/CommandPaletteDialog.tsx @@ -30,6 +30,7 @@ import { useWorkspaces } from '../hooks/useWorkspaces'; import { showDialog, toggleDialog } from '../lib/dialog'; import { fallbackRequestName } from '../lib/fallbackRequestName'; import { router } from '../lib/router'; +import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams'; import { CookieDialog } from './CookieDialog'; import { Button } from './core/Button'; import { Heading } from './core/Heading'; @@ -57,7 +58,7 @@ const MAX_PER_GROUP = 8; export function CommandPaletteDialog({ onClose }: { onClose: () => void }) { const [command, setCommand] = useDebouncedState('', 150); const [selectedItemKey, setSelectedItemKey] = useState(null); - const [activeEnvironment, setActiveEnvironmentId] = useActiveEnvironment(); + const activeEnvironment = useActiveEnvironment(); const httpRequestActions = useHttpRequestActions(); const workspaces = useWorkspaces(); const { subEnvironments } = useEnvironments(); @@ -300,7 +301,7 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) { environmentGroup.items.push({ key: `switch-environment-${e.id}`, label: e.name, - onSelect: () => setActiveEnvironmentId(e.id), + onSelect: () => setWorkspaceSearchParams({ environment_id: e.id }), }); } @@ -324,7 +325,6 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) { sortedRequests, sortedEnvironments, activeEnvironment?.id, - setActiveEnvironmentId, sortedWorkspaces, ]); diff --git a/src-web/components/EnvironmentActionsDropdown.tsx b/src-web/components/EnvironmentActionsDropdown.tsx index 9364ba5e..9fd1f5a6 100644 --- a/src-web/components/EnvironmentActionsDropdown.tsx +++ b/src-web/components/EnvironmentActionsDropdown.tsx @@ -3,6 +3,7 @@ import { memo, useCallback, useMemo } from 'react'; import { useActiveEnvironment } from '../hooks/useActiveEnvironment'; import { useEnvironments } from '../hooks/useEnvironments'; import { toggleDialog } from '../lib/dialog'; +import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams'; import type { ButtonProps } from './core/Button'; import { Button } from './core/Button'; import type { DropdownItem } from './core/Dropdown'; @@ -19,7 +20,7 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo ...buttonProps }: Props) { const { subEnvironments, baseEnvironment } = useEnvironments(); - const [activeEnvironment, setActiveEnvironmentId] = useActiveEnvironment(); + const activeEnvironment = useActiveEnvironment(); const showEnvironmentDialog = useCallback(() => { toggleDialog({ @@ -40,9 +41,9 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo leftSlot: e.id === activeEnvironment?.id ? : , onSelect: async () => { if (e.id !== activeEnvironment?.id) { - await setActiveEnvironmentId(e.id); + setWorkspaceSearchParams({ environment_id: e.id }); } else { - await setActiveEnvironmentId(null); + setWorkspaceSearchParams({ environment_id: null }); } }, }), @@ -59,7 +60,7 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo onSelect: showEnvironmentDialog, }, ], - [activeEnvironment?.id, subEnvironments, setActiveEnvironmentId, showEnvironmentDialog], + [activeEnvironment?.id, subEnvironments, showEnvironmentDialog], ); const hasBaseVars = diff --git a/src-web/components/WorkspaceActionsDropdown.tsx b/src-web/components/WorkspaceActionsDropdown.tsx index 5d25d0bf..1ec5ea1a 100644 --- a/src-web/components/WorkspaceActionsDropdown.tsx +++ b/src-web/components/WorkspaceActionsDropdown.tsx @@ -34,16 +34,11 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({ const workspaceMeta = useWorkspaceMeta(); const { mutate: deleteSendHistory } = useDeleteSendHistory(); - const orderedWorkspaces = useMemo( - () => [...workspaces].sort((a, b) => (a.name.localeCompare(b.name) > 0 ? 1 : -1)), - [workspaces], - ); - const { workspaceItems, extraItems } = useMemo<{ workspaceItems: RadioDropdownItem[]; extraItems: DropdownItem[]; }>(() => { - const workspaceItems: RadioDropdownItem[] = orderedWorkspaces.map((w) => ({ + const workspaceItems: RadioDropdownItem[] = workspaces.map((w) => ({ key: w.id, label: w.name, value: w.id, @@ -100,7 +95,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({ ]; return { workspaceItems, extraItems }; - }, [orderedWorkspaces, deleteSendHistory, createWorkspace, workspaceMeta, workspace?.id]); + }, [workspaces, workspaceMeta, deleteSendHistory, createWorkspace, workspace?.id]); const handleChangeWorkspace = useCallback(async (workspaceId: string | null) => { if (workspaceId == null) return; diff --git a/src-web/hooks/useActiveCookieJar.ts b/src-web/hooks/useActiveCookieJar.ts index 21cd0347..d171911f 100644 --- a/src-web/hooks/useActiveCookieJar.ts +++ b/src-web/hooks/useActiveCookieJar.ts @@ -36,6 +36,7 @@ export function useEnsureActiveCookieJar() { // Set the active cookie jar to the first one, if none set useEffect(() => { if (cookieJars == null) return; // Hasn't loaded yet + if (cookieJars.find((j) => j.id === activeCookieJarId)) { return; // There's an active jar } @@ -47,7 +48,13 @@ export function useEnsureActiveCookieJar() { } // There's no active jar, so set it to the first one - console.log('Setting active cookie jar to', cookieJars, activeCookieJarId, firstJar.id); + console.log('Defaulting active cookie jar to first jar', firstJar); setWorkspaceSearchParams({ cookie_jar_id: firstJar.id }); - }, [activeCookieJarId, cookieJars]); + + // NOTE: We only run this on cookieJars to prevent data races when switching workspaces since a lot of + // things change when switching workspaces, and we don't currently have a good way to ensure that all + // stores have updated. + // TODO: Create a global data store that can handle this case + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [cookieJars]); } diff --git a/src-web/hooks/useActiveEnvironment.ts b/src-web/hooks/useActiveEnvironment.ts index 55323ea2..285be470 100644 --- a/src-web/hooks/useActiveEnvironment.ts +++ b/src-web/hooks/useActiveEnvironment.ts @@ -2,9 +2,8 @@ import { useSearch } from '@tanstack/react-router'; import type { Environment } from '@yaakapp-internal/models'; import { useAtomValue } from 'jotai'; import { atom } from 'jotai/index'; -import { useCallback, useEffect } from 'react'; +import { useEffect } from 'react'; import { jotaiStore } from '../lib/jotai'; -import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams'; import { environmentsAtom } from './useEnvironments'; export const QUERY_ENVIRONMENT_ID = 'environment_id'; @@ -17,12 +16,7 @@ export const activeEnvironmentAtom = atom((get) => { }); export function useActiveEnvironment() { - const setId = useCallback( - (id: string | null) => setWorkspaceSearchParams({ environment_id: id }), - [], - ); - const environment = useAtomValue(activeEnvironmentAtom); - return [environment, setId] as const; + return useAtomValue(activeEnvironmentAtom); } export function getActiveEnvironment() { diff --git a/src-web/hooks/useCookieJars.ts b/src-web/hooks/useCookieJars.ts index fb307dd7..a059351a 100644 --- a/src-web/hooks/useCookieJars.ts +++ b/src-web/hooks/useCookieJars.ts @@ -3,9 +3,9 @@ import { atom, useAtomValue } from 'jotai'; export const cookieJarsAtom = atom(); -export const sortedCookieJars = atom((get) => - get(cookieJarsAtom)?.sort((a, b) => a.name.localeCompare(b.name)), -); +export const sortedCookieJars = atom((get) => { + return get(cookieJarsAtom)?.sort((a, b) => a.name.localeCompare(b.name)); +}); export function useCookieJars() { return useAtomValue(sortedCookieJars); diff --git a/src-web/hooks/useCreateEnvironment.ts b/src-web/hooks/useCreateEnvironment.ts index 8d0b4cf4..76780e92 100644 --- a/src-web/hooks/useCreateEnvironment.ts +++ b/src-web/hooks/useCreateEnvironment.ts @@ -1,14 +1,12 @@ import type { Environment } from '@yaakapp-internal/models'; import { trackEvent } from '../lib/analytics'; import { showPrompt } from '../lib/prompt'; +import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams'; import { invokeCmd } from '../lib/tauri'; -import { useActiveEnvironment } from './useActiveEnvironment'; import { getActiveWorkspaceId } from './useActiveWorkspace'; import { useFastMutation } from './useFastMutation'; export function useCreateEnvironment() { - const [, setActiveEnvironmentId] = useActiveEnvironment(); - return useFastMutation({ mutationKey: ['create_environment'], mutationFn: async (baseEnvironment) => { @@ -38,7 +36,7 @@ export function useCreateEnvironment() { onSettled: () => trackEvent('environment', 'create'), onSuccess: async (environment) => { if (environment == null) return; - await setActiveEnvironmentId(environment.id); + setWorkspaceSearchParams({ environment_id: environment.id }); }, }); } diff --git a/src-web/hooks/useGrpc.ts b/src-web/hooks/useGrpc.ts index 69cae29c..0350165d 100644 --- a/src-web/hooks/useGrpc.ts +++ b/src-web/hooks/useGrpc.ts @@ -19,7 +19,7 @@ export function useGrpc( protoFiles: string[], ) { const requestId = req?.id ?? 'n/a'; - const [environment] = useActiveEnvironment(); + const environment = useActiveEnvironment(); const go = useMutation({ mutationKey: ['grpc_go', conn?.id], diff --git a/src-web/hooks/useIntrospectGraphQL.ts b/src-web/hooks/useIntrospectGraphQL.ts index 88fcff83..58814e40 100644 --- a/src-web/hooks/useIntrospectGraphQL.ts +++ b/src-web/hooks/useIntrospectGraphQL.ts @@ -20,7 +20,7 @@ export function useIntrospectGraphQL( // Debounce the request because it can change rapidly and we don't // want to send so too many requests. const request = useDebouncedValue(baseRequest); - const [activeEnvironment] = useActiveEnvironment(); + const activeEnvironment = useActiveEnvironment(); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(); diff --git a/src-web/hooks/useRenderTemplate.ts b/src-web/hooks/useRenderTemplate.ts index f438c91d..a86c91b4 100644 --- a/src-web/hooks/useRenderTemplate.ts +++ b/src-web/hooks/useRenderTemplate.ts @@ -5,7 +5,7 @@ import { useActiveWorkspace } from './useActiveWorkspace'; export function useRenderTemplate(template: string) { const workspaceId = useActiveWorkspace()?.id ?? 'n/a'; - const environmentId = useActiveEnvironment()[0]?.id ?? null; + const environmentId = useActiveEnvironment()?.id ?? null; return useQuery({ placeholderData: (prev) => prev, // Keep previous data on refetch refetchOnWindowFocus: false, diff --git a/src-web/hooks/useSyncWorkspaceRequestTitle.ts b/src-web/hooks/useSyncWorkspaceRequestTitle.ts index 5faec9e4..ce8c3288 100644 --- a/src-web/hooks/useSyncWorkspaceRequestTitle.ts +++ b/src-web/hooks/useSyncWorkspaceRequestTitle.ts @@ -10,7 +10,7 @@ import { useOsInfo } from './useOsInfo'; export function useSyncWorkspaceRequestTitle() { const activeWorkspace = useActiveWorkspace(); - const [activeEnvironment] = useActiveEnvironment(); + const activeEnvironment = useActiveEnvironment(); const osInfo = useOsInfo(); const appInfo = useAppInfo();