diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 0bb97807..373879aa 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -828,11 +828,14 @@ async fn cmd_send_http_request( .expect("Failed to get request"); let environment = match environment_id { - Some(id) => Some( - get_environment(&window, id) - .await - .expect("Failed to get environment"), - ), + Some(id) => + match get_environment(&window, id).await { + Ok(env) => Some(env), + Err(e) => { + warn!("Failed to find environment by id {id} {}", e); + None + } + }, None => None, }; diff --git a/src-web/components/RecentRequestsDropdown.tsx b/src-web/components/RecentRequestsDropdown.tsx index 40dab90f..d1903a89 100644 --- a/src-web/components/RecentRequestsDropdown.tsx +++ b/src-web/components/RecentRequestsDropdown.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import { useMemo, useRef } from 'react'; import { useKey, useKeyPressEvent } from 'react-use'; -import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId'; +import { useActiveEnvironment } from '../hooks/useActiveEnvironment'; import { useActiveRequest } from '../hooks/useActiveRequest'; import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId'; import { useAppRoutes } from '../hooks/useAppRoutes'; @@ -20,7 +20,7 @@ export function RecentRequestsDropdown({ className }: Pick(null); const activeRequest = useActiveRequest(); const activeWorkspaceId = useActiveWorkspaceId(); - const activeEnvironmentId = useActiveEnvironmentId(); + const activeEnvironment = useActiveEnvironment(); const httpRequests = useHttpRequests(); const grpcRequests = useGrpcRequests(); const routes = useAppRoutes(); @@ -68,7 +68,7 @@ export function RecentRequestsDropdown({ className }: Pick { routes.navigate('request', { requestId: request.id, - environmentId: activeEnvironmentId ?? undefined, + environmentId: activeEnvironment?.id, workspaceId: activeWorkspaceId, }); }, @@ -87,7 +87,7 @@ export function RecentRequestsDropdown({ className }: Pick diff --git a/src-web/components/core/Dialog.tsx b/src-web/components/core/Dialog.tsx index 0e24c738..8aa0ffa5 100644 --- a/src-web/components/core/Dialog.tsx +++ b/src-web/components/core/Dialog.tsx @@ -2,7 +2,7 @@ import classNames from 'classnames'; import { motion } from 'framer-motion'; import type { ReactNode } from 'react'; import { useMemo } from 'react'; -import { useHotKey } from '../../hooks/useHotKey'; +import { useKey } from 'react-use'; import { Overlay } from '../Overlay'; import { Heading } from './Heading'; import { IconButton } from './IconButton'; @@ -36,7 +36,15 @@ export function Dialog({ [description], ); - useHotKey('popup.close', onClose, { enable: open }); + useKey( + 'Escape', + () => { + if (!open) return; + onClose(); + }, + {}, + [open], + ); return ( diff --git a/src-web/components/core/Dropdown.tsx b/src-web/components/core/Dropdown.tsx index b96eda1a..7c9029b4 100644 --- a/src-web/components/core/Dropdown.tsx +++ b/src-web/components/core/Dropdown.tsx @@ -244,13 +244,15 @@ const Menu = forwardRef, MenuPro } }; - useHotKey( - 'popup.close', + useKey( + 'Escape', () => { + if (!isOpen) return; if (filter !== '') setFilter(''); else handleClose(); }, - { enable: isOpen }, + {}, + [isOpen, filter, setFilter, handleClose], ); const handlePrev = useCallback(() => { @@ -288,11 +290,13 @@ const Menu = forwardRef, MenuPro }, [items]); useKey('ArrowUp', (e) => { + if (!isOpen) return; e.preventDefault(); handlePrev(); }); useKey('ArrowDown', (e) => { + if (!isOpen) return; e.preventDefault(); handleNext(); }); diff --git a/src-web/hooks/useHotKey.ts b/src-web/hooks/useHotKey.ts index d42a7c1e..86357e96 100644 --- a/src-web/hooks/useHotKey.ts +++ b/src-web/hooks/useHotKey.ts @@ -4,10 +4,9 @@ import { capitalize } from '../lib/capitalize'; import { debounce } from '../lib/debounce'; import { useOsInfo } from './useOsInfo'; -const HOLD_KEYS = ['Shift', 'CmdCtrl', 'Alt', 'Meta']; +const HOLD_KEYS = ['Shift', 'Control', 'Command', 'Alt', 'Meta']; export type HotkeyAction = - | 'popup.close' | 'environmentEditor.toggle' | 'hotkeys.showHelp' | 'grpc_request.send' @@ -22,7 +21,6 @@ export type HotkeyAction = | 'urlBar.focus'; const hotkeys: Record = { - 'popup.close': ['Escape'], 'environmentEditor.toggle': ['CmdCtrl+Shift+e'], 'grpc_request.send': ['CmdCtrl+Enter', 'CmdCtrl+r'], 'hotkeys.showHelp': ['CmdCtrl+Shift+/'], @@ -38,7 +36,6 @@ const hotkeys: Record = { }; const hotkeyLabels: Record = { - 'popup.close': 'Close Dropdown', 'environmentEditor.toggle': 'Edit Environments', 'grpc_request.send': 'Send Message', 'hotkeys.showHelp': 'Show Keyboard Shortcuts', @@ -83,15 +80,30 @@ export function useHotKey( } const key = normalizeKey(e.key, os); + + // Don't add hold keys + if (HOLD_KEYS.includes(key)) { + return; + } + currentKeys.current.add(key); + const currentKeysWithModifiers = new Set(currentKeys.current); + if (e.altKey) currentKeysWithModifiers.add(normalizeKey('Alt', os)); + if (e.ctrlKey) currentKeysWithModifiers.add(normalizeKey('Control', os)); + if (e.metaKey) currentKeysWithModifiers.add(normalizeKey('Meta', os)); + if (e.shiftKey) currentKeysWithModifiers.add(normalizeKey('Shift', os)); + for (const [hkAction, hkKeys] of Object.entries(hotkeys) as [HotkeyAction, string[]][]) { for (const hkKey of hkKeys) { + if (hkAction !== action) { + continue; + } + const keys = hkKey.split('+'); if ( - keys.length === currentKeys.current.size && - keys.every((key) => currentKeys.current.has(key)) && - hkAction === action + keys.length === currentKeysWithModifiers.size && + keys.every((key) => currentKeysWithModifiers.has(key)) ) { e.preventDefault(); e.stopPropagation(); @@ -112,7 +124,7 @@ export function useHotKey( // Clear all keys if no longer holding modifier // HACK: This is to get around the case of DOWN SHIFT -> DOWN : -> UP SHIFT -> UP ; // As you see, the ":" is not removed because it turned into ";" when shift was released - const isHoldingModifier = HOLD_KEYS.some((k) => currentKeys.current.has(k)); + const isHoldingModifier = e.altKey || e.ctrlKey || e.metaKey || e.shiftKey; if (!isHoldingModifier) { currentKeys.current.clear(); } diff --git a/src-web/hooks/useIntrospectGraphQL.ts b/src-web/hooks/useIntrospectGraphQL.ts index b0e1c0d9..c3051494 100644 --- a/src-web/hooks/useIntrospectGraphQL.ts +++ b/src-web/hooks/useIntrospectGraphQL.ts @@ -85,6 +85,5 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) { [introspection], ); - console.log('SCHEMA', introspection); return { schema, isLoading, error, refetch }; } diff --git a/src-web/hooks/useSendAnyRequest.ts b/src-web/hooks/useSendAnyRequest.ts index 5c8c136d..9ea6cf24 100644 --- a/src-web/hooks/useSendAnyRequest.ts +++ b/src-web/hooks/useSendAnyRequest.ts @@ -6,11 +6,11 @@ import { trackEvent } from '../lib/analytics'; import type { HttpResponse } from '../lib/models'; import { getHttpRequest } from '../lib/store'; import { useActiveCookieJar } from './useActiveCookieJar'; -import { useActiveEnvironmentId } from './useActiveEnvironmentId'; +import { useActiveEnvironment } from './useActiveEnvironment'; import { useAlert } from './useAlert'; export function useSendAnyRequest(options: { download?: boolean } = {}) { - const environmentId = useActiveEnvironmentId(); + const environment = useActiveEnvironment(); const alert = useAlert(); const { activeCookieJar } = useActiveCookieJar(); return useMutation({ @@ -33,7 +33,7 @@ export function useSendAnyRequest(options: { download?: boolean } = {}) { return invoke('cmd_send_http_request', { requestId: id, - environmentId, + environmentId: environment?.id, downloadDir: downloadDir, cookieJarId: activeCookieJar?.id, });