diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 87aa04c7..4bea4f00 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1564,7 +1564,7 @@ fn main() { "App Config Dir: {}", app_config_dir.as_path().to_string_lossy(), ); - info!("App Data Dir: {}", app_data_dir.as_path().to_string_lossy(),); + info!("App Data Dir: {}", app_data_dir.as_path().to_string_lossy()); let dir = match is_dev() { true => current_dir().unwrap(), false => app_data_dir, diff --git a/src-web/components/GlobalHooks.tsx b/src-web/components/GlobalHooks.tsx index 6b061a6a..88ee8f23 100644 --- a/src-web/components/GlobalHooks.tsx +++ b/src-web/components/GlobalHooks.tsx @@ -46,8 +46,6 @@ export function GlobalHooks() { }, [location.pathname]); useListenToTauriEvent('upserted_model', ({ payload, windowLabel }) => { - if (shouldIgnoreEvent(payload, windowLabel)) return; - const queryKey = payload.model === 'http_request' ? httpRequestsQueryKey(payload) @@ -74,7 +72,7 @@ export function GlobalHooks() { return; } - if (payload.model === 'http_request') { + if (payload.model === 'http_request' && windowLabel !== appWindow.label) { wasUpdatedExternally(payload.id); } @@ -82,21 +80,19 @@ export function GlobalHooks() { payload.model, ); - if (!shouldIgnoreModel(payload)) { - queryClient.setQueryData(queryKey, (values = []) => { - const index = values.findIndex((v) => modelsEq(v, payload)) ?? -1; - if (index >= 0) { - return [...values.slice(0, index), payload, ...values.slice(index + 1)]; - } else { - return pushToFront ? [payload, ...(values ?? [])] : [...(values ?? []), payload]; - } - }); - } + if (shouldIgnoreModel(payload)) return; + + queryClient.setQueryData(queryKey, (values = []) => { + const index = values.findIndex((v) => modelsEq(v, payload)) ?? -1; + if (index >= 0) { + return [...values.slice(0, index), payload, ...values.slice(index + 1)]; + } else { + return pushToFront ? [payload, ...(values ?? [])] : [...(values ?? []), payload]; + } + }); }); useListenToTauriEvent('deleted_model', ({ payload, windowLabel }) => { - if (shouldIgnoreEvent(payload, windowLabel)) return; - if (shouldIgnoreModel(payload)) return; if (payload.model === 'workspace') { @@ -142,9 +138,6 @@ function removeById(model: T) { return (entries: T[] | undefined) => entries?.filter((e) => e.id !== model.id); } -const shouldIgnoreEvent = (payload: Model, windowLabel: string) => - windowLabel === appWindow.label && payload.model !== 'http_response'; - const shouldIgnoreModel = (payload: Model) => { if (payload.model === 'key_value') { return payload.namespace === NAMESPACE_NO_SYNC; diff --git a/src-web/components/RecentRequestsDropdown.tsx b/src-web/components/RecentRequestsDropdown.tsx index 9800a819..a62fab40 100644 --- a/src-web/components/RecentRequestsDropdown.tsx +++ b/src-web/components/RecentRequestsDropdown.tsx @@ -5,6 +5,7 @@ import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId'; import { useActiveRequest } from '../hooks/useActiveRequest'; import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId'; import { useAppRoutes } from '../hooks/useAppRoutes'; +import { useGrpcRequests } from '../hooks/useGrpcRequests'; import { useHotKey } from '../hooks/useHotKey'; import { useRecentRequests } from '../hooks/useRecentRequests'; import { useHttpRequests } from '../hooks/useHttpRequests'; @@ -19,10 +20,12 @@ export function RecentRequestsDropdown({ className }: Pick allRecentRequestIds.slice(1), [allRecentRequestIds]); + const requests = useMemo(() => [...httpRequests, ...grpcRequests], [httpRequests, grpcRequests]); // Toggle the menu on Cmd+k useKey('k', (e) => { diff --git a/src-web/components/Sidebar.tsx b/src-web/components/Sidebar.tsx index 1f47b1d4..dc0246b1 100644 --- a/src-web/components/Sidebar.tsx +++ b/src-web/components/Sidebar.tsx @@ -39,6 +39,7 @@ import type { Folder, GrpcRequest, HttpRequest, Workspace } from '../lib/models' import { isResponseLoading } from '../lib/models'; import type { DropdownItem } from './core/Dropdown'; import { ContextMenu } from './core/Dropdown'; +import { HttpMethodTag } from './core/HttpMethodTag'; import { Icon } from './core/Icon'; import { InlineCode } from './core/InlineCode'; import { VStack } from './core/Stacks'; @@ -488,6 +489,13 @@ function SidebarItems({ : 'New Folder' } itemModel={child.item.model} + itemPrefix={ + child.item.model === 'http_request' ? ( + {child.item.method} + ) : child.item.model === 'grpc_request' ? ( + gRPC + ) : null + } onMove={handleMove} onEnd={handleEnd} onSelect={onSelect} @@ -531,6 +539,7 @@ type SidebarItemProps = { itemName: string; itemFallbackName: string; itemModel: string; + itemPrefix: ReactNode; useProminentStyles?: boolean; selected?: boolean; draggable?: boolean; @@ -546,6 +555,7 @@ const SidebarItem = forwardRef(function SidebarItem( itemFallbackName, itemId, itemModel, + itemPrefix, useProminentStyles, selected, onSelect, @@ -733,7 +743,7 @@ const SidebarItem = forwardRef(function SidebarItem( data-active={isActive} data-selected={selected} className={classNames( - 'w-full flex items-center text-sm h-xs px-2 rounded-md transition-colors', + 'w-full flex gap-2 items-center text-sm h-xs pl-2 rounded-md transition-colors', editing && 'ring-1 focus-within:ring-focus', isActive && 'bg-highlightSecondary text-gray-800', !isActive && @@ -746,37 +756,40 @@ const SidebarItem = forwardRef(function SidebarItem( size="sm" icon="chevronRight" className={classNames( - '-ml-0.5 mr-2 transition-transform', + '-ml-0.5 transition-transform opacity-50', !isCollapsed(itemId) && 'transform rotate-90', )} /> )} - {editing ? ( - - ) : ( - {itemName || itemFallbackName} - )} - {latestGrpcConnection ? ( -
- {latestGrpcConnection.elapsed === 0 && ( - - )} -
- ) : latestHttpResponse ? ( -
- {isResponseLoading(latestHttpResponse) ? ( - - ) : ( - - )} -
- ) : null} +
+ {itemPrefix} + {editing ? ( + + ) : ( + {itemName || itemFallbackName} + )} + {latestGrpcConnection ? ( +
+ {latestGrpcConnection.elapsed === 0 && ( + + )} +
+ ) : latestHttpResponse ? ( +
+ {isResponseLoading(latestHttpResponse) ? ( + + ) : ( + + )} +
+ ) : null} +
{children} diff --git a/src-web/components/core/HttpMethodTag.tsx b/src-web/components/core/HttpMethodTag.tsx new file mode 100644 index 00000000..2e5d51d5 --- /dev/null +++ b/src-web/components/core/HttpMethodTag.tsx @@ -0,0 +1,26 @@ +import classNames from 'classnames'; + +interface Props { + children: string; + className?: string; +} + +const methodMap: Record = { + get: 'GET', + put: 'PUT', + post: 'POST', + patch: 'PATCH', + delete: 'DELETE', + options: 'OPTIONS', + head: 'HEAD', + grpc: 'gRPC', +}; + +export function HttpMethodTag({ children: method, className }: Props) { + const m = method.toLowerCase(); + return ( + + {methodMap[m] ?? m.slice(0, 3).toUpperCase()} + + ); +} diff --git a/src-web/hooks/useGrpc.ts b/src-web/hooks/useGrpc.ts index de4ab684..c04bfd1f 100644 --- a/src-web/hooks/useGrpc.ts +++ b/src-web/hooks/useGrpc.ts @@ -57,7 +57,6 @@ export function useGrpc(req: GrpcRequest | null, conn: GrpcConnection | null) { queryKey: ['grpc_reflect', req?.id ?? 'n/a', debouncedUrl], refetchOnWindowFocus: false, queryFn: async () => { - console.log('useGrpc.reflect', { requestId }); return (await minPromiseMillis( invoke('cmd_grpc_reflect', { requestId }), 300, diff --git a/tailwind.config.cjs b/tailwind.config.cjs index dbc74c03..b180da0c 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.cjs @@ -71,11 +71,11 @@ module.exports = { red: color('red'), orange: color('orange'), yellow: color('yellow'), - gray: color('gray'), blue: color('blue'), green: color('green'), pink: color('pink'), violet: color('violet'), + gray: color('gray'), }, }, plugins: [