diff --git a/src-web/components/CommandPalette.tsx b/src-web/components/CommandPalette.tsx index 8e102ea6..03b52546 100644 --- a/src-web/components/CommandPalette.tsx +++ b/src-web/components/CommandPalette.tsx @@ -230,7 +230,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) { }, [subEnvironments, recentEnvironments]); const sortedWorkspaces = useMemo(() => { - return [...workspaces].sort((a, b) => { + const r = [...workspaces].sort((a, b) => { const aRecentIndex = recentWorkspaces.indexOf(a.id); const bRecentIndex = recentWorkspaces.indexOf(b.id); @@ -244,6 +244,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) { return a.createdAt.localeCompare(b.createdAt); } }); + return r; }, [recentWorkspaces, workspaces]); const groups = useMemo(() => { @@ -308,7 +309,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) { for (const w of sortedWorkspaces) { workspaceGroup.items.push({ key: `switch-workspace-${w.id}`, - label: w.name, + label: w.id + ' - ' + w.name, onSelect: () => openWorkspace.mutate({ workspaceId: w.id, inNewWindow: false }), }); } @@ -377,7 +378,6 @@ export function CommandPalette({ onClose }: { onClose: () => void }) { const handleKeyDown = useCallback( (e: KeyboardEvent) => { const index = filteredAllItems.findIndex((v) => v.key === selectedItem?.key); - console.log("ENDER", e.key); if (e.key === 'ArrowDown' || (e.ctrlKey && e.key === 'n')) { const next = filteredAllItems[index + 1] ?? filteredAllItems[0]; diff --git a/src-web/components/GlobalHooks.tsx b/src-web/components/GlobalHooks.tsx index 075d76ce..b2b1a325 100644 --- a/src-web/components/GlobalHooks.tsx +++ b/src-web/components/GlobalHooks.tsx @@ -1,6 +1,6 @@ import { emit } from '@tauri-apps/api/event'; import type { PromptTextRequest, PromptTextResponse } from '@yaakapp-internal/plugin'; -import { useEnsureActiveCookieJar, useSubscribeActiveCookieJar } from '../hooks/useActiveCookieJar'; +import { useEnsureActiveCookieJar, useSubscribeActiveCookieJarId } from '../hooks/useActiveCookieJar'; import { useSubscribeActiveEnvironmentId } from '../hooks/useActiveEnvironment'; import { useActiveRequest } from '../hooks/useActiveRequest'; import { useSubscribeActiveRequestId } from '../hooks/useActiveRequestId'; @@ -13,10 +13,10 @@ import { useHotKey } from '../hooks/useHotKey'; import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent'; import { useNotificationToast } from '../hooks/useNotificationToast'; import { usePrompt } from '../hooks/usePrompt'; -import { useRecentCookieJars } from '../hooks/useRecentCookieJars'; -import { useRecentEnvironments } from '../hooks/useRecentEnvironments'; +import {useRecentCookieJars, useSubscribeRecentCookieJars} from '../hooks/useRecentCookieJars'; +import {useRecentEnvironments, useSubscribeRecentEnvironments} from '../hooks/useRecentEnvironments'; import { useSubscribeRecentRequests } from '../hooks/useRecentRequests'; -import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces'; +import {useRecentWorkspaces, useSubscribeRecentWorkspaces} from '../hooks/useRecentWorkspaces'; import { useSyncFontSizeSetting } from '../hooks/useSyncFontSizeSetting'; import { useSyncModelStores } from '../hooks/useSyncModelStores'; import { useSyncWorkspaceChildModels } from '../hooks/useSyncWorkspaceChildModels'; @@ -31,18 +31,23 @@ export function GlobalHooks() { useSyncFontSizeSetting(); useGenerateThemeCss(); useSyncWorkspaceRequestTitle(); + useSubscribeActiveWorkspaceId(); useSubscribeActiveRequestId(); + useSubscribeActiveEnvironmentId(); + useSubscribeActiveCookieJarId(); + + useSubscribeRecentRequests(); + useSubscribeRecentWorkspaces(); + useSubscribeRecentEnvironments(); + useSubscribeRecentCookieJars(); // Include here so they always update, even if no component references them useRecentWorkspaces(); useRecentEnvironments(); useRecentCookieJars(); - useSubscribeRecentRequests(); useSyncWorkspaceChildModels(); useSubscribeTemplateFunctions(); - useSubscribeActiveEnvironmentId(); - useSubscribeActiveCookieJar(); // Other useful things useNotificationToast(); diff --git a/src-web/components/SidebarItem.tsx b/src-web/components/SidebarItem.tsx index 387dd0b9..95eb03e9 100644 --- a/src-web/components/SidebarItem.tsx +++ b/src-web/components/SidebarItem.tsx @@ -245,7 +245,7 @@ export const SidebarItem = memo(function SidebarItem({ 'w-full flex gap-1.5 items-center h-xs px-1.5 rounded-md focus-visible:ring focus-visible:ring-border-focus outline-0', editing && 'ring-1 focus-within:ring-focus', active && 'bg-surface-highlight text-text', - !active && 'text-text-subtle group-hover/item:text-text', + !active && 'text-text-subtle', showContextMenu && '!text-text', // Show as "active" when the context menu is open )} > diff --git a/src-web/components/UrlBar.tsx b/src-web/components/UrlBar.tsx index 92068340..66977199 100644 --- a/src-web/components/UrlBar.tsx +++ b/src-web/components/UrlBar.tsx @@ -66,6 +66,7 @@ export const UrlBar = memo(function UrlBar({ return (
(function Dropdown setDefaultSelectedIndex(undefined); }, [setIsOpen]); + const openDropdown = useCallback(() => { + setIsOpen((o) => !o); + setItems(typeof itemsGetter === 'function' ? itemsGetter() : itemsGetter); + }, [itemsGetter, setIsOpen]); + useImperativeHandle( ref, () => ({ @@ -111,18 +116,18 @@ export const Dropdown = forwardRef(function Dropdown else this.close(); }, open() { - setIsOpen(true); + openDropdown(); }, close() { handleClose(); }, }), - [handleClose, isOpen, setIsOpen], + [handleClose, isOpen, openDropdown], ); useHotKey(hotKeyAction ?? null, () => { setDefaultSelectedIndex(0); - setIsOpen(true); + openDropdown(); }); const child = useMemo(() => { @@ -138,12 +143,11 @@ export const Dropdown = forwardRef(function Dropdown e.preventDefault(); e.stopPropagation(); setDefaultSelectedIndex(undefined); - setIsOpen((o) => !o); - setItems(typeof itemsGetter === 'function' ? itemsGetter() : itemsGetter); + openDropdown(); }), }; return cloneElement(existingChild, props); - }, [children, itemsGetter, setIsOpen]); + }, [children, openDropdown]); useEffect(() => { buttonRef.current?.setAttribute('aria-expanded', isOpen.toString()); diff --git a/src-web/components/core/Editor/Editor.tsx b/src-web/components/core/Editor/Editor.tsx index 2345b5b8..1f5cef8e 100644 --- a/src-web/components/core/Editor/Editor.tsx +++ b/src-web/components/core/Editor/Editor.tsx @@ -563,6 +563,5 @@ function getCachedEditorState(doc: string, stateKey: string | null) { if (state == null) return null; if (state.doc.toString() !== doc) return null; - console.log('CACHED STATE', stateKey, state); return state; } diff --git a/src-web/hooks/useActiveCookieJar.ts b/src-web/hooks/useActiveCookieJar.ts index 901bded5..2c8c0aaf 100644 --- a/src-web/hooks/useActiveCookieJar.ts +++ b/src-web/hooks/useActiveCookieJar.ts @@ -43,12 +43,11 @@ function useActiveCookieJarId() { return [id, setId] as const; } -export function useSubscribeActiveCookieJar() { +export function useSubscribeActiveCookieJarId() { const { cookie_jar_id } = useSearch({ strict: false }); - useEffect( - () => jotaiStore.set(activeCookieJarIdAtom, cookie_jar_id ?? undefined), - [cookie_jar_id], - ); + useEffect(() => { + jotaiStore.set(activeCookieJarIdAtom, cookie_jar_id ?? undefined); + }, [cookie_jar_id]); } export function getActiveCookieJar() { diff --git a/src-web/hooks/useActiveWorkspace.ts b/src-web/hooks/useActiveWorkspace.ts index b20d80e3..1b8b8016 100644 --- a/src-web/hooks/useActiveWorkspace.ts +++ b/src-web/hooks/useActiveWorkspace.ts @@ -21,9 +21,11 @@ export function getActiveWorkspaceId() { return jotaiStore.get(activeWorkspaceIdAtom) ?? null; } +export function getActiveWorkspace() { + return jotaiStore.get(activeWorkspaceAtom) ?? null; +} + export function useSubscribeActiveWorkspaceId() { const { workspaceId } = useParams({ strict: false }); - useEffect(() => { - jotaiStore.set(activeWorkspaceIdAtom, workspaceId); - }, [workspaceId]); + useEffect(() => jotaiStore.set(activeWorkspaceIdAtom, workspaceId), [workspaceId]); } diff --git a/src-web/hooks/useCreateCookieJar.ts b/src-web/hooks/useCreateCookieJar.ts index 4630cb3b..897b32f9 100644 --- a/src-web/hooks/useCreateCookieJar.ts +++ b/src-web/hooks/useCreateCookieJar.ts @@ -1,22 +1,22 @@ -import { useFastMutation } from './useFastMutation'; import type { CookieJar } from '@yaakapp-internal/models'; -import {useSetAtom} from "jotai"; +import { useSetAtom } from 'jotai'; import { trackEvent } from '../lib/analytics'; import { invokeCmd } from '../lib/tauri'; -import { useActiveWorkspace } from './useActiveWorkspace'; -import {cookieJarsAtom} from "./useCookieJars"; +import { getActiveWorkspaceId } from './useActiveWorkspace'; +import { cookieJarsAtom } from './useCookieJars'; +import { useFastMutation } from './useFastMutation'; import { usePrompt } from './usePrompt'; -import {updateModelList} from "./useSyncModelStores"; +import { updateModelList } from './useSyncModelStores'; export function useCreateCookieJar() { - const workspace = useActiveWorkspace(); const prompt = usePrompt(); const setCookieJars = useSetAtom(cookieJarsAtom); return useFastMutation({ mutationKey: ['create_cookie_jar'], mutationFn: async () => { - if (workspace === null) { + const workspaceId = getActiveWorkspaceId(); + if (workspaceId == null) { throw new Error("Cannot create cookie jar when there's no active workspace"); } const name = await prompt({ @@ -29,7 +29,7 @@ export function useCreateCookieJar() { }); if (name == null) return null; - return invokeCmd('cmd_create_cookie_jar', { workspaceId: workspace.id, name }); + return invokeCmd('cmd_create_cookie_jar', { workspaceId, name }); }, onSuccess: (cookieJar) => { if (cookieJar == null) return; diff --git a/src-web/hooks/useCreateDropdownItems.tsx b/src-web/hooks/useCreateDropdownItems.tsx index 47597297..ae8acab4 100644 --- a/src-web/hooks/useCreateDropdownItems.tsx +++ b/src-web/hooks/useCreateDropdownItems.tsx @@ -11,7 +11,7 @@ import { useCreateHttpRequest } from './useCreateHttpRequest'; export function useCreateDropdownItems({ hideFolder, hideIcons, - folderId, + folderId: folderIdOption, }: { hideFolder?: boolean; hideIcons?: boolean; @@ -21,19 +21,17 @@ export function useCreateDropdownItems({ const { mutate: createGrpcRequest } = useCreateGrpcRequest(); const { mutate: createFolder } = useCreateFolder(); - return useCallback( - (): DropdownItem[] => [ + return useCallback((): DropdownItem[] => { + const folderId = + folderIdOption === 'active-folder' ? getActiveRequest()?.folderId : folderIdOption; + + return [ { key: 'create-http-request', label: 'HTTP Request', leftSlot: hideIcons ? undefined : , onSelect: () => { - const args = { folderId }; - if (folderId === 'active-folder') { - const activeRequest = getActiveRequest(); - args.folderId = activeRequest?.folderId ?? undefined; - } - createHttpRequest(args); + createHttpRequest({ folderId }); }, }, { @@ -67,7 +65,6 @@ export function useCreateDropdownItems({ onSelect: () => createFolder({ folderId }), }, ]) as DropdownItem[]), - ], - [createFolder, createGrpcRequest, createHttpRequest, folderId, hideFolder, hideIcons], - ); + ]; + }, [createFolder, createGrpcRequest, createHttpRequest, folderIdOption, hideFolder, hideIcons]); } diff --git a/src-web/hooks/useCreateEnvironment.ts b/src-web/hooks/useCreateEnvironment.ts index 64a9454d..9639bd7f 100644 --- a/src-web/hooks/useCreateEnvironment.ts +++ b/src-web/hooks/useCreateEnvironment.ts @@ -3,7 +3,7 @@ import { useSetAtom } from 'jotai'; import { trackEvent } from '../lib/analytics'; import { invokeCmd } from '../lib/tauri'; import { useActiveEnvironment } from './useActiveEnvironment'; -import { useActiveWorkspace } from './useActiveWorkspace'; +import { getActiveWorkspaceId } from './useActiveWorkspace'; import { environmentsAtom } from './useEnvironments'; import { useFastMutation } from './useFastMutation'; import { usePrompt } from './usePrompt'; @@ -12,7 +12,6 @@ import { updateModelList } from './useSyncModelStores'; export function useCreateEnvironment() { const [, setActiveEnvironmentId] = useActiveEnvironment(); const prompt = usePrompt(); - const workspace = useActiveWorkspace(); const setEnvironments = useSetAtom(environmentsAtom); return useFastMutation({ @@ -23,6 +22,7 @@ export function useCreateEnvironment() { throw new Error('No base environment passed'); } + const workspaceId = getActiveWorkspaceId(); const name = await prompt({ id: 'new-environment', title: 'New Environment', @@ -37,7 +37,7 @@ export function useCreateEnvironment() { return invokeCmd('cmd_create_environment', { name, variables: [], - workspaceId: workspace?.id, + workspaceId, environmentId: baseEnvironment.id, }); }, diff --git a/src-web/hooks/useCreateHttpRequest.ts b/src-web/hooks/useCreateHttpRequest.ts index 0cfcd90b..6c0436e5 100644 --- a/src-web/hooks/useCreateHttpRequest.ts +++ b/src-web/hooks/useCreateHttpRequest.ts @@ -1,26 +1,27 @@ +import { useNavigate } from '@tanstack/react-router'; import type { HttpRequest } from '@yaakapp-internal/models'; import { useSetAtom } from 'jotai/index'; import { trackEvent } from '../lib/analytics'; import { invokeCmd } from '../lib/tauri'; import { getActiveRequest } from './useActiveRequest'; -import { useActiveWorkspace } from './useActiveWorkspace'; +import { getActiveWorkspaceId } from './useActiveWorkspace'; import { useFastMutation } from './useFastMutation'; import { httpRequestsAtom } from './useHttpRequests'; import { updateModelList } from './useSyncModelStores'; -import { useNavigate } from '@tanstack/react-router'; export function useCreateHttpRequest() { - const activeWorkspace = useActiveWorkspace(); const setHttpRequests = useSetAtom(httpRequestsAtom); const navigate = useNavigate(); return useFastMutation>({ mutationKey: ['create_http_request'], mutationFn: async (patch = {}) => { - const activeRequest = getActiveRequest(); - if (activeWorkspace === null) { + const workspaceId = getActiveWorkspaceId(); + if (workspaceId == null) { throw new Error("Cannot create request when there's no active workspace"); } + + const activeRequest = getActiveRequest(); if (patch.sortPriority === undefined) { if (activeRequest != null) { // Place above currently active request @@ -32,7 +33,7 @@ export function useCreateHttpRequest() { } patch.folderId = patch.folderId || activeRequest?.folderId; return invokeCmd('cmd_create_http_request', { - request: { workspaceId: activeWorkspace.id, ...patch }, + request: { workspaceId, ...patch }, }); }, onSettled: () => trackEvent('http_request', 'create'), diff --git a/src-web/hooks/useDeleteSendHistory.tsx b/src-web/hooks/useDeleteSendHistory.tsx index 3774871c..3eb1f419 100644 --- a/src-web/hooks/useDeleteSendHistory.tsx +++ b/src-web/hooks/useDeleteSendHistory.tsx @@ -1,10 +1,10 @@ -import { useFastMutation } from './useFastMutation'; import { useSetAtom } from 'jotai/index'; import { count } from '../lib/pluralize'; import { invokeCmd } from '../lib/tauri'; -import { useActiveWorkspace } from './useActiveWorkspace'; +import { getActiveWorkspaceId } from './useActiveWorkspace'; import { useAlert } from './useAlert'; import { useConfirm } from './useConfirm'; +import { useFastMutation } from './useFastMutation'; import { useGrpcConnections } from './useGrpcConnections'; import { httpResponsesAtom, useHttpResponses } from './useHttpResponses'; @@ -12,7 +12,6 @@ export function useDeleteSendHistory() { const confirm = useConfirm(); const alert = useAlert(); const setHttpResponses = useSetAtom(httpResponsesAtom); - const activeWorkspace = useActiveWorkspace(); const httpResponses = useHttpResponses(); const grpcConnections = useGrpcConnections(); const labels = [ @@ -40,13 +39,14 @@ export function useDeleteSendHistory() { }); if (!confirmed) return false; - await invokeCmd('cmd_delete_send_history', { workspaceId: activeWorkspace?.id ?? 'n/a' }); + const workspaceId = getActiveWorkspaceId(); + await invokeCmd('cmd_delete_send_history', { workspaceId }); return true; }, onSuccess: async (confirmed) => { if (!confirmed) return; - - setHttpResponses((all) => all.filter((r) => r.workspaceId !== activeWorkspace?.id)); + const activeWorkspaceId = getActiveWorkspaceId(); + setHttpResponses((all) => all.filter((r) => r.workspaceId !== activeWorkspaceId)); }, }); } diff --git a/src-web/hooks/useDeleteWorkspace.tsx b/src-web/hooks/useDeleteWorkspace.tsx index f9d410f6..ac339bd4 100644 --- a/src-web/hooks/useDeleteWorkspace.tsx +++ b/src-web/hooks/useDeleteWorkspace.tsx @@ -4,14 +4,13 @@ import { useSetAtom } from 'jotai'; import { InlineCode } from '../components/core/InlineCode'; import { trackEvent } from '../lib/analytics'; import { invokeCmd } from '../lib/tauri'; -import { useActiveWorkspace } from './useActiveWorkspace'; +import { getActiveWorkspace } from './useActiveWorkspace'; import { useConfirm } from './useConfirm'; import { useFastMutation } from './useFastMutation'; import { removeModelById } from './useSyncModelStores'; import { workspacesAtom } from './useWorkspaces'; export function useDeleteWorkspace(workspace: Workspace | null) { - const activeWorkspace = useActiveWorkspace(); const confirm = useConfirm(); const setWorkspaces = useSetAtom(workspacesAtom); const navigate = useNavigate(); @@ -19,6 +18,7 @@ export function useDeleteWorkspace(workspace: Workspace | null) { return useFastMutation({ mutationKey: ['delete_workspace', workspace?.id], mutationFn: async () => { + const workspace = getActiveWorkspace(); const confirmed = await confirm({ id: 'delete-workspace', title: 'Delete Workspace', @@ -40,8 +40,9 @@ export function useDeleteWorkspace(workspace: Workspace | null) { setWorkspaces(removeModelById(workspace)); const { id: workspaceId } = workspace; + const activeWorkspace = getActiveWorkspace(); if (workspaceId === activeWorkspace?.id) { - navigate({ to: '/workspaces' }); + await navigate({ to: '/workspaces' }); } }, }); diff --git a/src-web/hooks/useExportData.tsx b/src-web/hooks/useExportData.tsx index 7c28b84d..43a3b93d 100644 --- a/src-web/hooks/useExportData.tsx +++ b/src-web/hooks/useExportData.tsx @@ -1,14 +1,13 @@ -import {useDialog} from "./useDialog"; -import { useFastMutation } from './useFastMutation'; import { ExportDataDialog } from '../components/ExportDataDialog'; -import { useActiveWorkspace } from './useActiveWorkspace'; +import { jotaiStore } from '../lib/jotai'; +import { getActiveWorkspace } from './useActiveWorkspace'; import { useAlert } from './useAlert'; -import { useWorkspaces } from './useWorkspaces'; +import { useDialog } from './useDialog'; +import { useFastMutation } from './useFastMutation'; import { useToast } from './useToast'; +import { workspacesAtom } from './useWorkspaces'; export function useExportData() { - const workspaces = useWorkspaces(); - const activeWorkspace = useActiveWorkspace(); const alert = useAlert(); const dialog = useDialog(); const toast = useToast(); @@ -19,6 +18,9 @@ export function useExportData() { alert({ id: 'export-failed', title: 'Export Failed', body: err }); }, mutationFn: async () => { + const activeWorkspace = getActiveWorkspace(); + const workspaces = jotaiStore.get(workspacesAtom); + if (activeWorkspace == null || workspaces.length === 0) return; dialog.show({ diff --git a/src-web/hooks/useImportCurl.ts b/src-web/hooks/useImportCurl.ts index 301a781d..a0df5331 100644 --- a/src-web/hooks/useImportCurl.ts +++ b/src-web/hooks/useImportCurl.ts @@ -1,14 +1,13 @@ -import { useFastMutation } from './useFastMutation'; import type { HttpRequest } from '@yaakapp-internal/models'; -import { useToast } from './useToast'; import { invokeCmd } from '../lib/tauri'; -import { useActiveWorkspace } from './useActiveWorkspace'; +import { getActiveWorkspaceId } from './useActiveWorkspace'; import { useCreateHttpRequest } from './useCreateHttpRequest'; +import { useFastMutation } from './useFastMutation'; import { useRequestUpdateKey } from './useRequestUpdateKey'; +import { useToast } from './useToast'; import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest'; export function useImportCurl() { - const workspace = useActiveWorkspace(); const updateRequest = useUpdateAnyHttpRequest(); const createRequest = useCreateHttpRequest(); const { wasUpdatedExternally } = useRequestUpdateKey(null); @@ -23,9 +22,10 @@ export function useImportCurl() { overwriteRequestId?: string; command: string; }) => { + const workspaceId = getActiveWorkspaceId(); const request: HttpRequest = await invokeCmd('cmd_curl_to_request', { command, - workspaceId: workspace?.id, + workspaceId, }); let verb; diff --git a/src-web/hooks/useImportData.tsx b/src-web/hooks/useImportData.tsx index 68cd1b48..3abf0161 100644 --- a/src-web/hooks/useImportData.tsx +++ b/src-web/hooks/useImportData.tsx @@ -12,7 +12,7 @@ import { VStack } from '../components/core/Stacks'; import { ImportDataDialog } from '../components/ImportDataDialog'; import { count } from '../lib/pluralize'; import { invokeCmd } from '../lib/tauri'; -import { useActiveWorkspace } from './useActiveWorkspace'; +import { getActiveWorkspace } from './useActiveWorkspace'; import { useAlert } from './useAlert'; import { useDialog } from './useDialog'; import { useFastMutation } from './useFastMutation'; @@ -20,10 +20,10 @@ import { useFastMutation } from './useFastMutation'; export function useImportData() { const dialog = useDialog(); const alert = useAlert(); - const activeWorkspace = useActiveWorkspace(); const navigate = useNavigate(); const importData = async (filePath: string): Promise => { + const activeWorkspace = getActiveWorkspace(); const imported: { workspaces: Workspace[]; environments: Environment[]; diff --git a/src-web/hooks/useMoveToWorkspace.tsx b/src-web/hooks/useMoveToWorkspace.tsx index 9fb455a0..f9f555ad 100644 --- a/src-web/hooks/useMoveToWorkspace.tsx +++ b/src-web/hooks/useMoveToWorkspace.tsx @@ -1,20 +1,20 @@ -import {useDialog} from "./useDialog"; -import { useFastMutation } from './useFastMutation'; import React from 'react'; import { MoveToWorkspaceDialog } from '../components/MoveToWorkspaceDialog'; -import { useActiveWorkspace } from './useActiveWorkspace'; +import { getActiveWorkspaceId } from './useActiveWorkspace'; +import { useDialog } from './useDialog'; +import { useFastMutation } from './useFastMutation'; import { useRequests } from './useRequests'; export function useMoveToWorkspace(id: string) { const dialog = useDialog(); const requests = useRequests(); const request = requests.find((r) => r.id === id); - const activeWorkspace = useActiveWorkspace(); return useFastMutation({ mutationKey: ['move_workspace', id], mutationFn: async () => { - if (request == null || activeWorkspace == null) return; + const activeWorkspaceId = getActiveWorkspaceId(); + if (request == null || activeWorkspaceId == null) return; dialog.show({ id: 'change-workspace', @@ -24,7 +24,7 @@ export function useMoveToWorkspace(id: string) { ), }); diff --git a/src-web/hooks/useRecentCookieJars.ts b/src-web/hooks/useRecentCookieJars.ts index 36cdf9a6..62bb88dd 100644 --- a/src-web/hooks/useRecentCookieJars.ts +++ b/src-web/hooks/useRecentCookieJars.ts @@ -1,7 +1,8 @@ import { useEffect, useMemo } from 'react'; -import { getKeyValue } from '../lib/keyValueStore'; -import { useActiveCookieJar } from './useActiveCookieJar'; -import { useActiveWorkspace } from './useActiveWorkspace'; +import { jotaiStore } from '../lib/jotai'; +import { getKeyValue, setKeyValue } from '../lib/keyValueStore'; +import { activeCookieJarIdAtom } from './useActiveCookieJar'; +import { activeWorkspaceIdAtom, useActiveWorkspace } from './useActiveWorkspace'; import { useCookieJars } from './useCookieJars'; import { useKeyValue } from './useKeyValue'; @@ -12,24 +13,12 @@ const fallback: string[] = []; export function useRecentCookieJars() { const cookieJars = useCookieJars(); const activeWorkspace = useActiveWorkspace(); - const [activeCookieJar] = useActiveCookieJar(); - const activeCookieJarId = activeCookieJar?.id ?? null; const kv = useKeyValue({ key: kvKey(activeWorkspace?.id ?? 'n/a'), namespace, fallback, }); - // Set history when active request changes - useEffect(() => { - kv.set((currentHistory: string[]) => { - if (activeCookieJarId === null) return currentHistory; - const withoutCurrent = currentHistory.filter((id) => id !== activeCookieJarId); - return [activeCookieJarId, ...withoutCurrent]; - }).catch(console.error); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [activeCookieJarId]); - const onlyValidIds = useMemo( () => kv.value?.filter((id) => cookieJars?.some((e) => e.id === id)) ?? [], [kv.value, cookieJars], @@ -38,6 +27,26 @@ export function useRecentCookieJars() { return onlyValidIds; } +export function useSubscribeRecentCookieJars() { + useEffect(() => { + return jotaiStore.sub(activeCookieJarIdAtom, async () => { + const activeWorkspaceId = jotaiStore.get(activeWorkspaceIdAtom); + const activeCookieJarId = jotaiStore.get(activeCookieJarIdAtom); + if (activeWorkspaceId == null) return; + if (activeCookieJarId == null) return; + + const key = kvKey(activeWorkspaceId); + + const recentIds = await getKeyValue({ namespace, key, fallback }); + if (recentIds[0] === activeCookieJarId) return; // Short-circuit + + const withoutActiveId = recentIds.filter((id) => id !== activeCookieJarId); + const value = [activeCookieJarId, ...withoutActiveId]; + await setKeyValue({ namespace, key, value }); + }); + }, []); +} + export async function getRecentCookieJars(workspaceId: string) { return getKeyValue({ namespace, diff --git a/src-web/hooks/useRecentEnvironments.ts b/src-web/hooks/useRecentEnvironments.ts index 15a29fb9..60dbb72d 100644 --- a/src-web/hooks/useRecentEnvironments.ts +++ b/src-web/hooks/useRecentEnvironments.ts @@ -1,7 +1,8 @@ import { useEffect, useMemo } from 'react'; -import { getKeyValue } from '../lib/keyValueStore'; -import { useActiveEnvironment } from './useActiveEnvironment'; -import { useActiveWorkspace } from './useActiveWorkspace'; +import { jotaiStore } from '../lib/jotai'; +import { getKeyValue, setKeyValue } from '../lib/keyValueStore'; +import { activeEnvironmentIdAtom } from './useActiveEnvironment'; +import { activeWorkspaceIdAtom, useActiveWorkspace } from './useActiveWorkspace'; import { useEnvironments } from './useEnvironments'; import { useKeyValue } from './useKeyValue'; @@ -12,23 +13,12 @@ const fallback: string[] = []; export function useRecentEnvironments() { const { subEnvironments } = useEnvironments(); const activeWorkspace = useActiveWorkspace(); - const [activeEnvironment] = useActiveEnvironment(); const kv = useKeyValue({ key: kvKey(activeWorkspace?.id ?? 'n/a'), namespace, fallback, }); - // Set history when active request changes - useEffect(() => { - kv.set((currentHistory: string[]) => { - if (activeEnvironment === null) return currentHistory; - const withoutCurrentEnvironment = currentHistory.filter((id) => id !== activeEnvironment.id); - return [activeEnvironment.id, ...withoutCurrentEnvironment]; - }).catch(console.error); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [activeEnvironment?.id]); - const onlyValidIds = useMemo( () => kv.value?.filter((id) => subEnvironments.some((e) => e.id === id)) ?? [], [kv.value, subEnvironments], @@ -37,6 +27,26 @@ export function useRecentEnvironments() { return onlyValidIds; } +export function useSubscribeRecentEnvironments() { + useEffect(() => { + return jotaiStore.sub(activeEnvironmentIdAtom, async () => { + const activeWorkspaceId = jotaiStore.get(activeWorkspaceIdAtom); + const activeEnvironmentId = jotaiStore.get(activeEnvironmentIdAtom); + if (activeWorkspaceId == null) return; + if (activeEnvironmentId == null) return; + + const key = kvKey(activeWorkspaceId); + + const recentIds = await getKeyValue({ namespace, key, fallback }); + if (recentIds[0] === activeEnvironmentId) return; // Short-circuit + + const withoutActiveId = recentIds.filter((id) => id !== activeEnvironmentId); + const value = [activeEnvironmentId, ...withoutActiveId]; + await setKeyValue({ namespace, key, value }); + }); + }, []); +} + export async function getRecentEnvironments(workspaceId: string) { return getKeyValue({ namespace, diff --git a/src-web/hooks/useRecentRequests.ts b/src-web/hooks/useRecentRequests.ts index 94de837e..02a09082 100644 --- a/src-web/hooks/useRecentRequests.ts +++ b/src-web/hooks/useRecentRequests.ts @@ -1,8 +1,8 @@ import { useEffect, useMemo } from 'react'; import { jotaiStore } from '../lib/jotai'; -import { getKeyValue } from '../lib/keyValueStore'; +import { getKeyValue, setKeyValue } from '../lib/keyValueStore'; import { activeRequestIdAtom } from './useActiveRequestId'; -import { useActiveWorkspace } from './useActiveWorkspace'; +import { activeWorkspaceIdAtom, useActiveWorkspace } from './useActiveWorkspace'; import { useKeyValue } from './useKeyValue'; import { useRequests } from './useRequests'; @@ -29,22 +29,23 @@ export function useRecentRequests() { } export function useSubscribeRecentRequests() { - const [recentRequests, setRecentRequests] = useRecentRequests(); - useEffect(() => { - return jotaiStore.sub(activeRequestIdAtom, () => { - const activeRequestId = jotaiStore.get(activeRequestIdAtom) ?? null; - if (recentRequests[0] === activeRequestId) { - // Nothing to do - return; - } - setRecentRequests((currentHistory) => { - if (activeRequestId === null) return currentHistory; - const withoutCurrentRequest = currentHistory.filter((id) => id !== activeRequestId); - return [activeRequestId, ...withoutCurrentRequest]; - }).catch(console.error); + return jotaiStore.sub(activeRequestIdAtom, async () => { + const activeWorkspaceId = jotaiStore.get(activeWorkspaceIdAtom); + const activeRequestId = jotaiStore.get(activeRequestIdAtom); + if (activeWorkspaceId == null) return; + if (activeRequestId == null) return; + + const key = kvKey(activeWorkspaceId); + + const recentIds = await getKeyValue({ namespace, key, fallback }); + if (recentIds[0] === activeRequestId) return; // Short-circuit + + const withoutActiveId = recentIds.filter((id) => id !== activeRequestId); + const value = [activeRequestId, ...withoutActiveId]; + await setKeyValue({ namespace, key, value }); }); - }, [recentRequests, setRecentRequests]); + }, []); } export async function getRecentRequests(workspaceId: string) { diff --git a/src-web/hooks/useRecentWorkspaces.ts b/src-web/hooks/useRecentWorkspaces.ts index 55d776b5..8c45603e 100644 --- a/src-web/hooks/useRecentWorkspaces.ts +++ b/src-web/hooks/useRecentWorkspaces.ts @@ -1,6 +1,7 @@ import { useEffect, useMemo } from 'react'; -import { getKeyValue } from '../lib/keyValueStore'; -import { useActiveWorkspace } from './useActiveWorkspace'; +import { jotaiStore } from '../lib/jotai'; +import { getKeyValue, setKeyValue } from '../lib/keyValueStore'; +import { activeWorkspaceIdAtom } from './useActiveWorkspace'; import { useKeyValue } from './useKeyValue'; import { useWorkspaces } from './useWorkspaces'; @@ -10,22 +11,7 @@ const fallback: string[] = []; export function useRecentWorkspaces() { const workspaces = useWorkspaces(); - const activeWorkspace = useActiveWorkspace(); - const {value, set} = useKeyValue({ - key: kvKey(), - namespace, - fallback, - }); - - // Set history when active request changes - useEffect(() => { - set((currentHistory: string[]) => { - if (activeWorkspace === null) return currentHistory; - const withoutCurrent = currentHistory.filter((id) => id !== activeWorkspace.id); - return [activeWorkspace.id, ...withoutCurrent]; - }).catch(console.error); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [activeWorkspace]); + const { value } = useKeyValue({ key: kvKey(), namespace, fallback }); const onlyValidIds = useMemo( () => value?.filter((id) => workspaces.some((w) => w.id === id)) ?? [], @@ -35,10 +21,20 @@ export function useRecentWorkspaces() { return onlyValidIds; } -export async function getRecentWorkspaces() { - return getKeyValue({ - namespace, - key: kvKey(), - fallback: fallback, - }); +export function useSubscribeRecentWorkspaces() { + useEffect(() => { + return jotaiStore.sub(activeWorkspaceIdAtom, async () => { + const activeWorkspaceId = jotaiStore.get(activeWorkspaceIdAtom); + if (activeWorkspaceId == null) return; + + const key = kvKey(); + + const recentIds = await getKeyValue({ namespace, key, fallback }); + if (recentIds[0] === activeWorkspaceId) return; // Short-circuit + + const withoutActiveId = recentIds.filter((id) => id !== activeWorkspaceId); + const value = [activeWorkspaceId, ...withoutActiveId]; + await setKeyValue({ namespace, key, value }); + }); + }, []); }