Sidebar methods and fix model hooks

This commit is contained in:
Gregory Schier
2024-02-09 16:09:24 -08:00
parent 017de296a0
commit 7a960574a5
7 changed files with 84 additions and 50 deletions

View File

@@ -1564,7 +1564,7 @@ fn main() {
"App Config Dir: {}", "App Config Dir: {}",
app_config_dir.as_path().to_string_lossy(), 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() { let dir = match is_dev() {
true => current_dir().unwrap(), true => current_dir().unwrap(),
false => app_data_dir, false => app_data_dir,

View File

@@ -46,8 +46,6 @@ export function GlobalHooks() {
}, [location.pathname]); }, [location.pathname]);
useListenToTauriEvent<Model>('upserted_model', ({ payload, windowLabel }) => { useListenToTauriEvent<Model>('upserted_model', ({ payload, windowLabel }) => {
if (shouldIgnoreEvent(payload, windowLabel)) return;
const queryKey = const queryKey =
payload.model === 'http_request' payload.model === 'http_request'
? httpRequestsQueryKey(payload) ? httpRequestsQueryKey(payload)
@@ -74,7 +72,7 @@ export function GlobalHooks() {
return; return;
} }
if (payload.model === 'http_request') { if (payload.model === 'http_request' && windowLabel !== appWindow.label) {
wasUpdatedExternally(payload.id); wasUpdatedExternally(payload.id);
} }
@@ -82,21 +80,19 @@ export function GlobalHooks() {
payload.model, payload.model,
); );
if (!shouldIgnoreModel(payload)) { if (shouldIgnoreModel(payload)) return;
queryClient.setQueryData<Model[]>(queryKey, (values = []) => {
const index = values.findIndex((v) => modelsEq(v, payload)) ?? -1; queryClient.setQueryData<Model[]>(queryKey, (values = []) => {
if (index >= 0) { const index = values.findIndex((v) => modelsEq(v, payload)) ?? -1;
return [...values.slice(0, index), payload, ...values.slice(index + 1)]; if (index >= 0) {
} else { return [...values.slice(0, index), payload, ...values.slice(index + 1)];
return pushToFront ? [payload, ...(values ?? [])] : [...(values ?? []), payload]; } else {
} return pushToFront ? [payload, ...(values ?? [])] : [...(values ?? []), payload];
}); }
} });
}); });
useListenToTauriEvent<Model>('deleted_model', ({ payload, windowLabel }) => { useListenToTauriEvent<Model>('deleted_model', ({ payload, windowLabel }) => {
if (shouldIgnoreEvent(payload, windowLabel)) return;
if (shouldIgnoreModel(payload)) return; if (shouldIgnoreModel(payload)) return;
if (payload.model === 'workspace') { if (payload.model === 'workspace') {
@@ -142,9 +138,6 @@ function removeById<T extends { id: string }>(model: T) {
return (entries: T[] | undefined) => entries?.filter((e) => e.id !== model.id); 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) => { const shouldIgnoreModel = (payload: Model) => {
if (payload.model === 'key_value') { if (payload.model === 'key_value') {
return payload.namespace === NAMESPACE_NO_SYNC; return payload.namespace === NAMESPACE_NO_SYNC;

View File

@@ -5,6 +5,7 @@ import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId';
import { useActiveRequest } from '../hooks/useActiveRequest'; import { useActiveRequest } from '../hooks/useActiveRequest';
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId'; import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
import { useAppRoutes } from '../hooks/useAppRoutes'; import { useAppRoutes } from '../hooks/useAppRoutes';
import { useGrpcRequests } from '../hooks/useGrpcRequests';
import { useHotKey } from '../hooks/useHotKey'; import { useHotKey } from '../hooks/useHotKey';
import { useRecentRequests } from '../hooks/useRecentRequests'; import { useRecentRequests } from '../hooks/useRecentRequests';
import { useHttpRequests } from '../hooks/useHttpRequests'; import { useHttpRequests } from '../hooks/useHttpRequests';
@@ -19,10 +20,12 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
const activeRequest = useActiveRequest(); const activeRequest = useActiveRequest();
const activeWorkspaceId = useActiveWorkspaceId(); const activeWorkspaceId = useActiveWorkspaceId();
const activeEnvironmentId = useActiveEnvironmentId(); const activeEnvironmentId = useActiveEnvironmentId();
const requests = useHttpRequests(); const httpRequests = useHttpRequests();
const grpcRequests = useGrpcRequests();
const routes = useAppRoutes(); const routes = useAppRoutes();
const allRecentRequestIds = useRecentRequests(); const allRecentRequestIds = useRecentRequests();
const recentRequestIds = useMemo(() => allRecentRequestIds.slice(1), [allRecentRequestIds]); const recentRequestIds = useMemo(() => allRecentRequestIds.slice(1), [allRecentRequestIds]);
const requests = useMemo(() => [...httpRequests, ...grpcRequests], [httpRequests, grpcRequests]);
// Toggle the menu on Cmd+k // Toggle the menu on Cmd+k
useKey('k', (e) => { useKey('k', (e) => {

View File

@@ -39,6 +39,7 @@ import type { Folder, GrpcRequest, HttpRequest, Workspace } from '../lib/models'
import { isResponseLoading } from '../lib/models'; import { isResponseLoading } from '../lib/models';
import type { DropdownItem } from './core/Dropdown'; import type { DropdownItem } from './core/Dropdown';
import { ContextMenu } from './core/Dropdown'; import { ContextMenu } from './core/Dropdown';
import { HttpMethodTag } from './core/HttpMethodTag';
import { Icon } from './core/Icon'; import { Icon } from './core/Icon';
import { InlineCode } from './core/InlineCode'; import { InlineCode } from './core/InlineCode';
import { VStack } from './core/Stacks'; import { VStack } from './core/Stacks';
@@ -488,6 +489,13 @@ function SidebarItems({
: 'New Folder' : 'New Folder'
} }
itemModel={child.item.model} itemModel={child.item.model}
itemPrefix={
child.item.model === 'http_request' ? (
<HttpMethodTag className="opacity-50">{child.item.method}</HttpMethodTag>
) : child.item.model === 'grpc_request' ? (
<HttpMethodTag className="opacity-50">gRPC</HttpMethodTag>
) : null
}
onMove={handleMove} onMove={handleMove}
onEnd={handleEnd} onEnd={handleEnd}
onSelect={onSelect} onSelect={onSelect}
@@ -531,6 +539,7 @@ type SidebarItemProps = {
itemName: string; itemName: string;
itemFallbackName: string; itemFallbackName: string;
itemModel: string; itemModel: string;
itemPrefix: ReactNode;
useProminentStyles?: boolean; useProminentStyles?: boolean;
selected?: boolean; selected?: boolean;
draggable?: boolean; draggable?: boolean;
@@ -546,6 +555,7 @@ const SidebarItem = forwardRef(function SidebarItem(
itemFallbackName, itemFallbackName,
itemId, itemId,
itemModel, itemModel,
itemPrefix,
useProminentStyles, useProminentStyles,
selected, selected,
onSelect, onSelect,
@@ -733,7 +743,7 @@ const SidebarItem = forwardRef(function SidebarItem(
data-active={isActive} data-active={isActive}
data-selected={selected} data-selected={selected}
className={classNames( 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', editing && 'ring-1 focus-within:ring-focus',
isActive && 'bg-highlightSecondary text-gray-800', isActive && 'bg-highlightSecondary text-gray-800',
!isActive && !isActive &&
@@ -746,37 +756,40 @@ const SidebarItem = forwardRef(function SidebarItem(
size="sm" size="sm"
icon="chevronRight" icon="chevronRight"
className={classNames( className={classNames(
'-ml-0.5 mr-2 transition-transform', '-ml-0.5 transition-transform opacity-50',
!isCollapsed(itemId) && 'transform rotate-90', !isCollapsed(itemId) && 'transform rotate-90',
)} )}
/> />
)} )}
{editing ? ( <div className="flex items-end gap-2 min-w-0">
<input {itemPrefix}
ref={handleFocus} {editing ? (
defaultValue={itemName} <input
className="bg-transparent outline-none w-full" ref={handleFocus}
onBlur={handleBlur} defaultValue={itemName}
onKeyDown={handleInputKeyDown} className="bg-transparent outline-none w-full"
/> onBlur={handleBlur}
) : ( onKeyDown={handleInputKeyDown}
<span className="truncate">{itemName || itemFallbackName}</span> />
)} ) : (
{latestGrpcConnection ? ( <span className="truncate">{itemName || itemFallbackName}</span>
<div className="ml-auto"> )}
{latestGrpcConnection.elapsed === 0 && ( {latestGrpcConnection ? (
<Icon spin size="sm" icon="update" className="text-gray-400" /> <div className="ml-auto">
)} {latestGrpcConnection.elapsed === 0 && (
</div> <Icon spin size="sm" icon="update" className="text-gray-400" />
) : latestHttpResponse ? ( )}
<div className="ml-auto"> </div>
{isResponseLoading(latestHttpResponse) ? ( ) : latestHttpResponse ? (
<Icon spin size="sm" icon="update" className="text-gray-400" /> <div className="ml-auto">
) : ( {isResponseLoading(latestHttpResponse) ? (
<StatusTag className="text-2xs dark:opacity-80" response={latestHttpResponse} /> <Icon spin size="sm" icon="update" className="text-gray-400" />
)} ) : (
</div> <StatusTag className="text-2xs dark:opacity-80" response={latestHttpResponse} />
) : null} )}
</div>
) : null}
</div>
</button> </button>
</div> </div>
{children} {children}

View File

@@ -0,0 +1,26 @@
import classNames from 'classnames';
interface Props {
children: string;
className?: string;
}
const methodMap: Record<string, string> = {
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 (
<span className={classNames(className, 'text-2xs font-mono')}>
{methodMap[m] ?? m.slice(0, 3).toUpperCase()}
</span>
);
}

View File

@@ -57,7 +57,6 @@ export function useGrpc(req: GrpcRequest | null, conn: GrpcConnection | null) {
queryKey: ['grpc_reflect', req?.id ?? 'n/a', debouncedUrl], queryKey: ['grpc_reflect', req?.id ?? 'n/a', debouncedUrl],
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
queryFn: async () => { queryFn: async () => {
console.log('useGrpc.reflect', { requestId });
return (await minPromiseMillis( return (await minPromiseMillis(
invoke('cmd_grpc_reflect', { requestId }), invoke('cmd_grpc_reflect', { requestId }),
300, 300,

View File

@@ -71,11 +71,11 @@ module.exports = {
red: color('red'), red: color('red'),
orange: color('orange'), orange: color('orange'),
yellow: color('yellow'), yellow: color('yellow'),
gray: color('gray'),
blue: color('blue'), blue: color('blue'),
green: color('green'), green: color('green'),
pink: color('pink'), pink: color('pink'),
violet: color('violet'), violet: color('violet'),
gray: color('gray'),
}, },
}, },
plugins: [ plugins: [