mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-27 11:51:13 +01:00
gRPC Support (#20)
This commit is contained in:
@@ -30,13 +30,13 @@ export function Confirm({ onHide, onResult, variant = 'confirm' }: ConfirmProps)
|
||||
};
|
||||
|
||||
return (
|
||||
<HStack space={2} justifyContent="end" className="mt-2 mb-4">
|
||||
<HStack space={2} justifyContent="start" className="mt-2 mb-4 flex-row-reverse">
|
||||
<Button className="focus" color={colors[variant]} onClick={handleSuccess}>
|
||||
{confirmButtonTexts[variant]}
|
||||
</Button>
|
||||
<Button className="focus" color="gray" onClick={handleHide}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button autoFocus className="focus" color={colors[variant]} onClick={handleSuccess}>
|
||||
{confirmButtonTexts[variant]}
|
||||
</Button>
|
||||
</HStack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,28 @@
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { r } from 'vitest/dist/types-94cfe4b4';
|
||||
import type { GrpcRequest, HttpRequest } from '../lib/models';
|
||||
import { useActiveRequestId } from './useActiveRequestId';
|
||||
import { useRequests } from './useRequests';
|
||||
import { useGrpcRequests } from './useGrpcRequests';
|
||||
import { useHttpRequests } from './useHttpRequests';
|
||||
|
||||
export function useActiveRequest(): HttpRequest | null {
|
||||
const requestId = useActiveRequestId();
|
||||
const requests = useRequests();
|
||||
return requests.find((r) => r.id === requestId) ?? null;
|
||||
interface TypeMap {
|
||||
http_request: HttpRequest;
|
||||
grpc_request: GrpcRequest;
|
||||
}
|
||||
|
||||
export function useActiveRequest<T extends keyof TypeMap>(
|
||||
model?: T | undefined,
|
||||
): TypeMap[T] | null {
|
||||
const requestId = useActiveRequestId();
|
||||
const httpRequests = useHttpRequests();
|
||||
const grpcRequests = useGrpcRequests();
|
||||
|
||||
if (model === 'http_request') {
|
||||
return (httpRequests.find((r) => r.id === requestId) ?? null) as TypeMap[T] | null;
|
||||
} else if (model === 'grpc_request') {
|
||||
return (grpcRequests.find((r) => r.id === requestId) ?? null) as TypeMap[T] | null;
|
||||
} else {
|
||||
return (grpcRequests.find((r) => r.id === requestId) ??
|
||||
httpRequests.find((r) => r.id === requestId) ??
|
||||
null) as TypeMap[T] | null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useCallback } from 'react';
|
||||
import type { DialogProps } from '../components/core/Dialog';
|
||||
import { useDialog } from '../components/DialogContext';
|
||||
import type { AlertProps } from './Alert';
|
||||
@@ -5,20 +6,16 @@ import { Alert } from './Alert';
|
||||
|
||||
export function useAlert() {
|
||||
const dialog = useDialog();
|
||||
return ({
|
||||
id,
|
||||
title,
|
||||
body,
|
||||
}: {
|
||||
id: string;
|
||||
title: DialogProps['title'];
|
||||
body: AlertProps['body'];
|
||||
}) =>
|
||||
dialog.show({
|
||||
id,
|
||||
title,
|
||||
hideX: true,
|
||||
size: 'sm',
|
||||
render: ({ hide }) => Alert({ onHide: hide, body }),
|
||||
});
|
||||
return useCallback(
|
||||
({ id, title, body }: { id: string; title: DialogProps['title']; body: AlertProps['body'] }) =>
|
||||
dialog.show({
|
||||
id,
|
||||
title,
|
||||
hideX: true,
|
||||
size: 'sm',
|
||||
render: ({ hide }) => Alert({ onHide: hide, body }),
|
||||
}),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export function useCookieJars() {
|
||||
queryKey: cookieJarsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invoke('list_cookie_jars', { workspaceId })) as CookieJar[];
|
||||
return (await invoke('cmd_list_cookie_jars', { workspaceId })) as CookieJar[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import type { CookieJar } from '../lib/models';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { cookieJarsQueryKey } from './useCookieJars';
|
||||
import { usePrompt } from './usePrompt';
|
||||
import { requestsQueryKey } from './useRequests';
|
||||
|
||||
export function useCreateCookieJar() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const queryClient = useQueryClient();
|
||||
const prompt = usePrompt();
|
||||
|
||||
return useMutation<HttpRequest>({
|
||||
return useMutation<CookieJar>({
|
||||
mutationFn: async () => {
|
||||
if (workspaceId === null) {
|
||||
throw new Error("Cannot create cookie jar when there's no active workspace");
|
||||
@@ -23,13 +23,13 @@ export function useCreateCookieJar() {
|
||||
label: 'Name',
|
||||
defaultValue: 'My Jar',
|
||||
});
|
||||
return invoke('create_cookie_jar', { workspaceId, name });
|
||||
return invoke('cmd_create_cookie_jar', { workspaceId, name });
|
||||
},
|
||||
onSettled: () => trackEvent('CookieJar', 'Create'),
|
||||
onSuccess: async (request) => {
|
||||
queryClient.setQueryData<HttpRequest[]>(
|
||||
requestsQueryKey({ workspaceId: request.workspaceId }),
|
||||
(requests) => [...(requests ?? []), request],
|
||||
onSuccess: async (cookieJar) => {
|
||||
queryClient.setQueryData<CookieJar[]>(
|
||||
cookieJarsQueryKey({ workspaceId: cookieJar.workspaceId }),
|
||||
(items) => [...(items ?? []), cookieJar],
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ export function useCreateEnvironment() {
|
||||
label: 'Name',
|
||||
defaultValue: 'My Environment',
|
||||
});
|
||||
return invoke('create_environment', { name, variables: [], workspaceId });
|
||||
return invoke('cmd_create_environment', { name, variables: [], workspaceId });
|
||||
},
|
||||
onSettled: () => trackEvent('Environment', 'Create'),
|
||||
onSuccess: async (environment) => {
|
||||
|
||||
@@ -16,7 +16,7 @@ export function useCreateFolder() {
|
||||
}
|
||||
patch.name = patch.name || 'New Folder';
|
||||
patch.sortPriority = patch.sortPriority || -Date.now();
|
||||
return invoke('create_folder', { workspaceId, ...patch });
|
||||
return invoke('cmd_create_folder', { workspaceId, ...patch });
|
||||
},
|
||||
onSettled: () => trackEvent('Folder', 'Create'),
|
||||
onSuccess: async (request) => {
|
||||
|
||||
55
src-web/hooks/useCreateGrpcRequest.ts
Normal file
55
src-web/hooks/useCreateGrpcRequest.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { GrpcRequest, HttpRequest } from '../lib/models';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveRequest } from './useActiveRequest';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { grpcRequestsQueryKey } from './useGrpcRequests';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
|
||||
export function useCreateGrpcRequest() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
// const activeRequest = useActiveRequest();
|
||||
const activeRequest = null;
|
||||
const routes = useAppRoutes();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<
|
||||
GrpcRequest,
|
||||
unknown,
|
||||
Partial<Pick<GrpcRequest, 'name' | 'sortPriority' | 'folderId'>>
|
||||
>({
|
||||
mutationFn: (patch) => {
|
||||
if (workspaceId === null) {
|
||||
throw new Error("Cannot create grpc request when there's no active workspace");
|
||||
}
|
||||
if (patch.sortPriority === undefined) {
|
||||
if (activeRequest != null) {
|
||||
// Place above currently-active request
|
||||
// patch.sortPriority = activeRequest.sortPriority + 0.0001;
|
||||
} else {
|
||||
// Place at the very top
|
||||
patch.sortPriority = -Date.now();
|
||||
}
|
||||
}
|
||||
// patch.folderId = patch.folderId; // TODO: || activeRequest?.folderId;
|
||||
return invoke('cmd_create_grpc_request', { workspaceId, name: '', ...patch });
|
||||
},
|
||||
onSettled: () => trackEvent('GrpcRequest', 'Create'),
|
||||
onSuccess: async (request) => {
|
||||
queryClient.setQueryData<GrpcRequest[]>(
|
||||
grpcRequestsQueryKey({ workspaceId: request.workspaceId }),
|
||||
(requests) => [...(requests ?? []), request],
|
||||
);
|
||||
// TODO: This should navigate to the new request
|
||||
routes.navigate('request', {
|
||||
workspaceId: request.workspaceId,
|
||||
requestId: request.id,
|
||||
environmentId: activeEnvironmentId ?? undefined,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -6,9 +6,9 @@ import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveRequest } from './useActiveRequest';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { requestsQueryKey } from './useRequests';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
|
||||
export function useCreateRequest() {
|
||||
export function useCreateHttpRequest() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
const activeRequest = useActiveRequest();
|
||||
@@ -34,12 +34,12 @@ export function useCreateRequest() {
|
||||
}
|
||||
}
|
||||
patch.folderId = patch.folderId || activeRequest?.folderId;
|
||||
return invoke('create_request', { workspaceId, name: '', ...patch });
|
||||
return invoke('cmd_create_http_request', { workspaceId, name: '', ...patch });
|
||||
},
|
||||
onSettled: () => trackEvent('HttpRequest', 'Create'),
|
||||
onSuccess: async (request) => {
|
||||
queryClient.setQueryData<HttpRequest[]>(
|
||||
requestsQueryKey({ workspaceId: request.workspaceId }),
|
||||
httpRequestsQueryKey({ workspaceId: request.workspaceId }),
|
||||
(requests) => [...(requests ?? []), request],
|
||||
);
|
||||
routes.navigate('request', {
|
||||
@@ -10,7 +10,7 @@ export function useCreateWorkspace({ navigateAfter }: { navigateAfter: boolean }
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Workspace, unknown, Pick<Workspace, 'name'>>({
|
||||
mutationFn: (patch) => {
|
||||
return invoke('create_workspace', patch);
|
||||
return invoke('cmd_create_workspace', patch);
|
||||
},
|
||||
onSettled: () => trackEvent('Workspace', 'Create'),
|
||||
onSuccess: async (workspace) => {
|
||||
|
||||
43
src-web/hooks/useDeleteAnyGrpcRequest.tsx
Normal file
43
src-web/hooks/useDeleteAnyGrpcRequest.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||
import type { GrpcRequest } from '../lib/models';
|
||||
import { getGrpcRequest } from '../lib/store';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { grpcRequestsQueryKey } from './useGrpcRequests';
|
||||
|
||||
export function useDeleteAnyGrpcRequest() {
|
||||
const queryClient = useQueryClient();
|
||||
const confirm = useConfirm();
|
||||
|
||||
return useMutation<GrpcRequest | null, string, string>({
|
||||
mutationFn: async (id) => {
|
||||
const request = await getGrpcRequest(id);
|
||||
if (request == null) return null;
|
||||
|
||||
const confirmed = await confirm({
|
||||
id: 'delete-grpc-request',
|
||||
title: 'Delete Request',
|
||||
variant: 'delete',
|
||||
description: (
|
||||
<>
|
||||
Permanently delete <InlineCode>{fallbackRequestName(request)}</InlineCode>?
|
||||
</>
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invoke('cmd_delete_grpc_request', { requestId: id });
|
||||
},
|
||||
onSettled: () => trackEvent('GrpcRequest', 'Delete'),
|
||||
onSuccess: async (request) => {
|
||||
if (request === null) return;
|
||||
|
||||
const { workspaceId, id: requestId } = request;
|
||||
queryClient.setQueryData<GrpcRequest[]>(grpcRequestsQueryKey({ workspaceId }), (requests) =>
|
||||
(requests ?? []).filter((r) => r.id !== requestId),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -4,18 +4,20 @@ import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { getRequest } from '../lib/store';
|
||||
import { getHttpRequest } from '../lib/store';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { requestsQueryKey } from './useRequests';
|
||||
import { responsesQueryKey } from './useResponses';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
||||
|
||||
export function useDeleteAnyRequest() {
|
||||
export function useDeleteAnyHttpRequest() {
|
||||
const queryClient = useQueryClient();
|
||||
const confirm = useConfirm();
|
||||
|
||||
return useMutation<HttpRequest | null, string, string>({
|
||||
mutationFn: async (id) => {
|
||||
const request = await getRequest(id);
|
||||
const request = await getHttpRequest(id);
|
||||
if (request == null) return null;
|
||||
|
||||
const confirmed = await confirm({
|
||||
id: 'delete-request',
|
||||
title: 'Delete Request',
|
||||
@@ -27,7 +29,7 @@ export function useDeleteAnyRequest() {
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invoke('delete_request', { requestId: id });
|
||||
return invoke('cmd_delete_http_request', { requestId: id });
|
||||
},
|
||||
onSettled: () => trackEvent('HttpRequest', 'Delete'),
|
||||
onSuccess: async (request) => {
|
||||
@@ -35,8 +37,8 @@ export function useDeleteAnyRequest() {
|
||||
if (request === null) return;
|
||||
|
||||
const { workspaceId, id: requestId } = request;
|
||||
queryClient.setQueryData(responsesQueryKey({ requestId }), []); // Responses were deleted
|
||||
queryClient.setQueryData<HttpRequest[]>(requestsQueryKey({ workspaceId }), (requests) =>
|
||||
queryClient.setQueryData(httpResponsesQueryKey({ requestId }), []); // Responses were deleted
|
||||
queryClient.setQueryData<HttpRequest[]>(httpRequestsQueryKey({ workspaceId }), (requests) =>
|
||||
(requests ?? []).filter((r) => r.id !== requestId),
|
||||
);
|
||||
},
|
||||
@@ -23,7 +23,7 @@ export function useDeleteCookieJar(cookieJar: CookieJar | null) {
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invoke('delete_cookie_jar', { cookieJarId: cookieJar?.id });
|
||||
return invoke('cmd_delete_cookie_jar', { cookieJarId: cookieJar?.id });
|
||||
},
|
||||
onSettled: () => trackEvent('CookieJar', 'Delete'),
|
||||
onSuccess: async (cookieJar) => {
|
||||
|
||||
@@ -23,7 +23,7 @@ export function useDeleteEnvironment(environment: Environment | null) {
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invoke('delete_environment', { environmentId: environment?.id });
|
||||
return invoke('cmd_delete_environment', { environmentId: environment?.id });
|
||||
},
|
||||
onSettled: () => trackEvent('Environment', 'Delete'),
|
||||
onSuccess: async (environment) => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { Folder } from '../lib/models';
|
||||
import { getFolder } from '../lib/store';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { foldersQueryKey } from './useFolders';
|
||||
import { requestsQueryKey } from './useRequests';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
|
||||
export function useDeleteFolder(id: string | null) {
|
||||
const queryClient = useQueryClient();
|
||||
@@ -26,7 +26,7 @@ export function useDeleteFolder(id: string | null) {
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invoke('delete_folder', { folderId: id });
|
||||
return invoke('cmd_delete_folder', { folderId: id });
|
||||
},
|
||||
onSettled: () => trackEvent('Folder', 'Delete'),
|
||||
onSuccess: async (folder) => {
|
||||
@@ -36,7 +36,7 @@ export function useDeleteFolder(id: string | null) {
|
||||
const { workspaceId } = folder;
|
||||
|
||||
// Nesting makes it hard to clean things up, so just clear everything that could have been deleted
|
||||
await queryClient.invalidateQueries(requestsQueryKey({ workspaceId }));
|
||||
await queryClient.invalidateQueries(httpRequestsQueryKey({ workspaceId }));
|
||||
await queryClient.invalidateQueries(foldersQueryKey({ workspaceId }));
|
||||
},
|
||||
});
|
||||
|
||||
21
src-web/hooks/useDeleteGrpcConnection.ts
Normal file
21
src-web/hooks/useDeleteGrpcConnection.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { GrpcConnection } from '../lib/models';
|
||||
import { grpcConnectionsQueryKey } from './useGrpcConnections';
|
||||
|
||||
export function useDeleteGrpcConnection(id: string | null) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<GrpcConnection>({
|
||||
mutationFn: async () => {
|
||||
return await invoke('cmd_delete_grpc_connection', { id: id });
|
||||
},
|
||||
onSettled: () => trackEvent('GrpcConnection', 'Delete'),
|
||||
onSuccess: ({ requestId, id: connectionId }) => {
|
||||
queryClient.setQueryData<GrpcConnection[]>(
|
||||
grpcConnectionsQueryKey({ requestId }),
|
||||
(connections) => (connections ?? []).filter((c) => c.id !== connectionId),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
19
src-web/hooks/useDeleteGrpcConnections.ts
Normal file
19
src-web/hooks/useDeleteGrpcConnections.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { grpcConnectionsQueryKey } from './useGrpcConnections';
|
||||
|
||||
export function useDeleteGrpcConnections(requestId?: string) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
if (requestId === undefined) return;
|
||||
await invoke('cmd_delete_all_grpc_connections', { requestId });
|
||||
},
|
||||
onSettled: () => trackEvent('GrpcConnection', 'DeleteMany'),
|
||||
onSuccess: async () => {
|
||||
if (requestId === undefined) return;
|
||||
queryClient.setQueryData(grpcConnectionsQueryKey({ requestId }), []);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -2,17 +2,17 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { HttpResponse } from '../lib/models';
|
||||
import { responsesQueryKey } from './useResponses';
|
||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
||||
|
||||
export function useDeleteResponse(id: string | null) {
|
||||
export function useDeleteHttpResponse(id: string | null) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<HttpResponse>({
|
||||
mutationFn: async () => {
|
||||
return await invoke('delete_response', { id: id });
|
||||
return await invoke('cmd_delete_http_response', { id: id });
|
||||
},
|
||||
onSettled: () => trackEvent('HttpResponse', 'Delete'),
|
||||
onSuccess: ({ requestId, id: responseId }) => {
|
||||
queryClient.setQueryData<HttpResponse[]>(responsesQueryKey({ requestId }), (responses) =>
|
||||
queryClient.setQueryData<HttpResponse[]>(httpResponsesQueryKey({ requestId }), (responses) =>
|
||||
(responses ?? []).filter((response) => response.id !== responseId),
|
||||
);
|
||||
},
|
||||
@@ -1,19 +1,19 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { responsesQueryKey } from './useResponses';
|
||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
||||
|
||||
export function useDeleteResponses(requestId?: string) {
|
||||
export function useDeleteHttpResponses(requestId?: string) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
if (requestId === undefined) return;
|
||||
await invoke('delete_all_responses', { requestId });
|
||||
await invoke('cmd_delete_all_http_responses', { requestId });
|
||||
},
|
||||
onSettled: () => trackEvent('HttpResponse', 'DeleteMany'),
|
||||
onSuccess: async () => {
|
||||
if (requestId === undefined) return;
|
||||
queryClient.setQueryData(responsesQueryKey({ requestId }), []);
|
||||
queryClient.setQueryData(httpResponsesQueryKey({ requestId }), []);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { useDeleteAnyRequest } from './useDeleteAnyRequest';
|
||||
import { useDeleteAnyHttpRequest } from './useDeleteAnyHttpRequest';
|
||||
|
||||
export function useDeleteRequest(id: string | null) {
|
||||
const deleteAnyRequest = useDeleteAnyRequest();
|
||||
const deleteAnyRequest = useDeleteAnyHttpRequest();
|
||||
|
||||
return useMutation<HttpRequest | null, string>({
|
||||
mutationFn: () => deleteAnyRequest.mutateAsync(id ?? 'n/a'),
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { Workspace } from '../lib/models';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { requestsQueryKey } from './useRequests';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
import { workspacesQueryKey } from './useWorkspaces';
|
||||
|
||||
export function useDeleteWorkspace(workspace: Workspace | null) {
|
||||
@@ -28,7 +28,7 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invoke('delete_workspace', { workspaceId: workspace?.id });
|
||||
return invoke('cmd_delete_workspace', { workspaceId: workspace?.id });
|
||||
},
|
||||
onSettled: () => trackEvent('Workspace', 'Delete'),
|
||||
onSuccess: async (workspace) => {
|
||||
@@ -43,8 +43,8 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
|
||||
}
|
||||
|
||||
// Also clean up other things that may have been deleted
|
||||
queryClient.setQueryData(requestsQueryKey({ workspaceId }), []);
|
||||
await queryClient.invalidateQueries(requestsQueryKey({ workspaceId }));
|
||||
queryClient.setQueryData(httpRequestsQueryKey({ workspaceId }), []);
|
||||
await queryClient.invalidateQueries(httpRequestsQueryKey({ workspaceId }));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
41
src-web/hooks/useDuplicateGrpcRequest.ts
Normal file
41
src-web/hooks/useDuplicateGrpcRequest.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { GrpcRequest } from '../lib/models';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { grpcRequestsQueryKey } from './useGrpcRequests';
|
||||
|
||||
export function useDuplicateGrpcRequest({
|
||||
id,
|
||||
navigateAfter,
|
||||
}: {
|
||||
id: string | null;
|
||||
navigateAfter: boolean;
|
||||
}) {
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
const routes = useAppRoutes();
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<GrpcRequest, string>({
|
||||
mutationFn: async () => {
|
||||
if (id === null) throw new Error("Can't duplicate a null grpc request");
|
||||
return invoke('cmd_duplicate_grpc_request', { id });
|
||||
},
|
||||
onSettled: () => trackEvent('GrpcRequest', 'Duplicate'),
|
||||
onSuccess: async (request) => {
|
||||
queryClient.setQueryData<GrpcRequest[]>(
|
||||
grpcRequestsQueryKey({ workspaceId: request.workspaceId }),
|
||||
(requests) => [...(requests ?? []), request],
|
||||
);
|
||||
if (navigateAfter && activeWorkspaceId !== null) {
|
||||
routes.navigate('request', {
|
||||
workspaceId: activeWorkspaceId,
|
||||
requestId: request.id,
|
||||
environmentId: activeEnvironmentId ?? undefined,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -5,9 +5,9 @@ import type { HttpRequest } from '../lib/models';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { requestsQueryKey } from './useRequests';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
|
||||
export function useDuplicateRequest({
|
||||
export function useDuplicateHttpRequest({
|
||||
id,
|
||||
navigateAfter,
|
||||
}: {
|
||||
@@ -21,12 +21,12 @@ export function useDuplicateRequest({
|
||||
return useMutation<HttpRequest, string>({
|
||||
mutationFn: async () => {
|
||||
if (id === null) throw new Error("Can't duplicate a null request");
|
||||
return invoke('duplicate_request', { id });
|
||||
return invoke('cmd_duplicate_http_request', { id });
|
||||
},
|
||||
onSettled: () => trackEvent('HttpRequest', 'Duplicate'),
|
||||
onSuccess: async (request) => {
|
||||
queryClient.setQueryData<HttpRequest[]>(
|
||||
requestsQueryKey({ workspaceId: request.workspaceId }),
|
||||
httpRequestsQueryKey({ workspaceId: request.workspaceId }),
|
||||
(requests) => [...(requests ?? []), request],
|
||||
);
|
||||
if (navigateAfter && activeWorkspaceId !== null) {
|
||||
@@ -15,7 +15,7 @@ export function useEnvironments() {
|
||||
queryKey: environmentsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invoke('list_environments', { workspaceId })) as Environment[];
|
||||
return (await invoke('cmd_list_environments', { workspaceId })) as Environment[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
@@ -25,7 +25,7 @@ export function useExportData() {
|
||||
return;
|
||||
}
|
||||
|
||||
await invoke('export_data', { workspaceId: workspace.id, exportPath });
|
||||
await invoke('cmd_export_data', { workspaceId: workspace.id, exportPath });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export function useFilterResponse({
|
||||
return null;
|
||||
}
|
||||
|
||||
return (await invoke('filter_response', { responseId, filter })) as string | null;
|
||||
return (await invoke('cmd_filter_response', { responseId, filter })) as string | null;
|
||||
},
|
||||
}).data ?? null
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ export function useFolders() {
|
||||
queryKey: foldersQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invoke('list_folders', { workspaceId })) as Folder[];
|
||||
return (await invoke('cmd_list_folders', { workspaceId })) as Folder[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
79
src-web/hooks/useGrpc.ts
Normal file
79
src-web/hooks/useGrpc.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { emit } from '@tauri-apps/api/event';
|
||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||
import type { GrpcConnection, GrpcMessage, GrpcRequest } from '../lib/models';
|
||||
import { useDebouncedValue } from './useDebouncedValue';
|
||||
|
||||
export interface ReflectResponseService {
|
||||
name: string;
|
||||
methods: { name: string; schema: string; serverStreaming: boolean; clientStreaming: boolean }[];
|
||||
}
|
||||
|
||||
export function useGrpc(req: GrpcRequest | null, conn: GrpcConnection | null) {
|
||||
const requestId = req?.id ?? 'n/a';
|
||||
|
||||
const unary = useMutation<GrpcMessage, string>({
|
||||
mutationKey: ['grpc_unary', conn?.id ?? 'n/a'],
|
||||
mutationFn: async () =>
|
||||
(await invoke('cmd_grpc_call_unary', {
|
||||
requestId,
|
||||
})) as GrpcMessage,
|
||||
});
|
||||
|
||||
const clientStreaming = useMutation<void, string>({
|
||||
mutationKey: ['grpc_client_streaming', conn?.id ?? 'n/a'],
|
||||
mutationFn: async () => await invoke('cmd_grpc_client_streaming', { requestId }),
|
||||
});
|
||||
|
||||
const serverStreaming = useMutation<void, string>({
|
||||
mutationKey: ['grpc_server_streaming', conn?.id ?? 'n/a'],
|
||||
mutationFn: async () => await invoke('cmd_grpc_server_streaming', { requestId }),
|
||||
});
|
||||
|
||||
const streaming = useMutation<void, string>({
|
||||
mutationKey: ['grpc_streaming', conn?.id ?? 'n/a'],
|
||||
mutationFn: async () => await invoke('cmd_grpc_streaming', { requestId }),
|
||||
});
|
||||
|
||||
const send = useMutation({
|
||||
mutationFn: async ({ message }: { message: string }) =>
|
||||
await emit(`grpc_client_msg_${conn?.id ?? 'none'}`, { Message: message }),
|
||||
});
|
||||
|
||||
const cancel = useMutation({
|
||||
mutationKey: ['grpc_cancel', conn?.id ?? 'n/a'],
|
||||
mutationFn: async () => await emit(`grpc_client_msg_${conn?.id ?? 'none'}`, 'Cancel'),
|
||||
});
|
||||
|
||||
const commit = useMutation({
|
||||
mutationKey: ['grpc_commit', conn?.id ?? 'n/a'],
|
||||
mutationFn: async () => await emit(`grpc_client_msg_${conn?.id ?? 'none'}`, 'Commit'),
|
||||
});
|
||||
|
||||
const debouncedUrl = useDebouncedValue<string>(req?.url ?? 'n/a', 1000);
|
||||
const reflect = useQuery<ReflectResponseService[] | null, string>({
|
||||
enabled: req != 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,
|
||||
)) as ReflectResponseService[];
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
unary,
|
||||
clientStreaming,
|
||||
serverStreaming,
|
||||
streaming,
|
||||
reflect,
|
||||
cancel,
|
||||
commit,
|
||||
isStreaming: conn?.elapsed === 0,
|
||||
send,
|
||||
};
|
||||
}
|
||||
23
src-web/hooks/useGrpcConnections.ts
Normal file
23
src-web/hooks/useGrpcConnections.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import type { GrpcConnection } from '../lib/models';
|
||||
|
||||
export function grpcConnectionsQueryKey({ requestId }: { requestId: string }) {
|
||||
return ['grpc_connections', { requestId }];
|
||||
}
|
||||
|
||||
export function useGrpcConnections(requestId: string | null) {
|
||||
return (
|
||||
useQuery<GrpcConnection[]>({
|
||||
enabled: requestId !== null,
|
||||
initialData: [],
|
||||
queryKey: grpcConnectionsQueryKey({ requestId: requestId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
return (await invoke('cmd_list_grpc_connections', {
|
||||
requestId,
|
||||
limit: 200,
|
||||
})) as GrpcConnection[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
}
|
||||
23
src-web/hooks/useGrpcMessages.ts
Normal file
23
src-web/hooks/useGrpcMessages.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import type { GrpcMessage } from '../lib/models';
|
||||
|
||||
export function grpcMessagesQueryKey({ connectionId }: { connectionId: string }) {
|
||||
return ['grpc_messages', { connectionId }];
|
||||
}
|
||||
|
||||
export function useGrpcMessages(connectionId: string | null) {
|
||||
return (
|
||||
useQuery<GrpcMessage[]>({
|
||||
enabled: connectionId !== null,
|
||||
initialData: [],
|
||||
queryKey: grpcMessagesQueryKey({ connectionId: connectionId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
return (await invoke('cmd_list_grpc_messages', {
|
||||
connectionId,
|
||||
limit: 200,
|
||||
})) as GrpcMessage[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
}
|
||||
7
src-web/hooks/useGrpcRequest.ts
Normal file
7
src-web/hooks/useGrpcRequest.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { GrpcRequest } from '../lib/models';
|
||||
import { useGrpcRequests } from './useGrpcRequests';
|
||||
|
||||
export function useGrpcRequest(id: string | null): GrpcRequest | null {
|
||||
const requests = useGrpcRequests();
|
||||
return requests.find((r) => r.id === id) ?? null;
|
||||
}
|
||||
22
src-web/hooks/useGrpcRequests.ts
Normal file
22
src-web/hooks/useGrpcRequests.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import type { GrpcRequest } from '../lib/models';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
|
||||
export function grpcRequestsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
return ['grpc_requests', { workspaceId }];
|
||||
}
|
||||
|
||||
export function useGrpcRequests() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
return (
|
||||
useQuery({
|
||||
enabled: workspaceId != null,
|
||||
queryKey: grpcRequestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invoke('cmd_list_grpc_requests', { workspaceId })) as GrpcRequest[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
}
|
||||
@@ -5,44 +5,47 @@ import { debounce } from '../lib/debounce';
|
||||
import { useOsInfo } from './useOsInfo';
|
||||
|
||||
export type HotkeyAction =
|
||||
| 'request.send'
|
||||
| 'request.create'
|
||||
| 'request.duplicate'
|
||||
| 'sidebar.toggle'
|
||||
| 'sidebar.focus'
|
||||
| 'urlBar.focus'
|
||||
| 'environmentEditor.toggle'
|
||||
| 'hotkeys.showHelp'
|
||||
| 'requestSwitcher.prev'
|
||||
| 'grpc_request.send'
|
||||
| 'http_request.create'
|
||||
| 'http_request.duplicate'
|
||||
| 'http_request.send'
|
||||
| 'requestSwitcher.next'
|
||||
| 'settings.show';
|
||||
| 'requestSwitcher.prev'
|
||||
| 'settings.show'
|
||||
| 'sidebar.focus'
|
||||
| 'sidebar.toggle'
|
||||
| 'urlBar.focus';
|
||||
|
||||
const hotkeys: Record<HotkeyAction, string[]> = {
|
||||
'request.send': ['CmdCtrl+Enter', 'CmdCtrl+r'],
|
||||
'request.create': ['CmdCtrl+n'],
|
||||
'request.duplicate': ['CmdCtrl+d'],
|
||||
'sidebar.toggle': ['CmdCtrl+b'],
|
||||
'sidebar.focus': ['CmdCtrl+1'],
|
||||
'urlBar.focus': ['CmdCtrl+l'],
|
||||
'environmentEditor.toggle': ['CmdCtrl+Shift+e'],
|
||||
'grpc_request.send': ['CmdCtrl+Enter', 'CmdCtrl+r'],
|
||||
'hotkeys.showHelp': ['CmdCtrl+Shift+/'],
|
||||
'settings.show': ['CmdCtrl+,'],
|
||||
'requestSwitcher.prev': ['Control+Tab'],
|
||||
'http_request.create': ['CmdCtrl+n'],
|
||||
'http_request.duplicate': ['CmdCtrl+d'],
|
||||
'http_request.send': ['CmdCtrl+Enter', 'CmdCtrl+r'],
|
||||
'requestSwitcher.next': ['Control+Shift+Tab'],
|
||||
'requestSwitcher.prev': ['Control+Tab'],
|
||||
'settings.show': ['CmdCtrl+,'],
|
||||
'sidebar.focus': ['CmdCtrl+1'],
|
||||
'sidebar.toggle': ['CmdCtrl+b'],
|
||||
'urlBar.focus': ['CmdCtrl+l'],
|
||||
};
|
||||
|
||||
const hotkeyLabels: Record<HotkeyAction, string> = {
|
||||
'request.send': 'Send Request',
|
||||
'request.create': 'New Request',
|
||||
'request.duplicate': 'Duplicate Request',
|
||||
'sidebar.toggle': 'Toggle Sidebar',
|
||||
'sidebar.focus': 'Focus Sidebar',
|
||||
'urlBar.focus': 'Focus URL',
|
||||
'environmentEditor.toggle': 'Edit Environments',
|
||||
'grpc_request.send': 'Send Message',
|
||||
'hotkeys.showHelp': 'Show Keyboard Shortcuts',
|
||||
'requestSwitcher.prev': 'Go To Next Request',
|
||||
'http_request.create': 'New Request',
|
||||
'http_request.duplicate': 'Duplicate Request',
|
||||
'http_request.send': 'Send Request',
|
||||
'requestSwitcher.next': 'Go To Previous Request',
|
||||
'requestSwitcher.prev': 'Go To Next Request',
|
||||
'settings.show': 'Open Settings',
|
||||
'sidebar.focus': 'Focus Sidebar',
|
||||
'sidebar.toggle': 'Toggle Sidebar',
|
||||
'urlBar.focus': 'Focus URL',
|
||||
};
|
||||
|
||||
export const hotkeyActions: HotkeyAction[] = Object.keys(hotkeys) as (keyof typeof hotkeys)[];
|
||||
@@ -109,11 +112,11 @@ export function useAnyHotkey(
|
||||
}
|
||||
currentKeys.current.delete(normalizeKey(e.key, os));
|
||||
};
|
||||
window.addEventListener('keydown', down);
|
||||
window.addEventListener('keyup', up);
|
||||
document.addEventListener('keydown', down, { capture: true });
|
||||
document.addEventListener('keyup', up, { capture: true });
|
||||
return () => {
|
||||
window.removeEventListener('keydown', down);
|
||||
window.removeEventListener('keyup', up);
|
||||
document.removeEventListener('keydown', down, { capture: true });
|
||||
document.removeEventListener('keyup', up, { capture: true });
|
||||
};
|
||||
}, [options.enable, os]);
|
||||
}
|
||||
|
||||
7
src-web/hooks/useHttpRequest.ts
Normal file
7
src-web/hooks/useHttpRequest.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { useHttpRequests } from './useHttpRequests';
|
||||
|
||||
export function useHttpRequest(id: string | null): HttpRequest | null {
|
||||
const requests = useHttpRequests();
|
||||
return requests.find((r) => r.id === id) ?? null;
|
||||
}
|
||||
@@ -3,19 +3,19 @@ import { invoke } from '@tauri-apps/api';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
|
||||
export function requestsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
export function httpRequestsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
return ['http_requests', { workspaceId }];
|
||||
}
|
||||
|
||||
export function useRequests() {
|
||||
export function useHttpRequests() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
return (
|
||||
useQuery({
|
||||
enabled: workspaceId != null,
|
||||
queryKey: requestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryKey: httpRequestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invoke('list_requests', { workspaceId })) as HttpRequest[];
|
||||
return (await invoke('cmd_list_http_requests', { workspaceId })) as HttpRequest[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
@@ -2,18 +2,18 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import type { HttpResponse } from '../lib/models';
|
||||
|
||||
export function responsesQueryKey({ requestId }: { requestId: string }) {
|
||||
export function httpResponsesQueryKey({ requestId }: { requestId: string }) {
|
||||
return ['http_responses', { requestId }];
|
||||
}
|
||||
|
||||
export function useResponses(requestId: string | null) {
|
||||
export function useHttpResponses(requestId: string | null) {
|
||||
return (
|
||||
useQuery<HttpResponse[]>({
|
||||
enabled: requestId !== null,
|
||||
initialData: [],
|
||||
queryKey: responsesQueryKey({ requestId: requestId ?? 'n/a' }),
|
||||
queryKey: httpResponsesQueryKey({ requestId: requestId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
return (await invoke('list_responses', { requestId, limit: 200 })) as HttpResponse[];
|
||||
return (await invoke('cmd_list_http_responses', { requestId, limit: 200 })) as HttpResponse[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
@@ -35,7 +35,7 @@ export function useImportData() {
|
||||
environments: Environment[];
|
||||
folders: Folder[];
|
||||
requests: HttpRequest[];
|
||||
} = await invoke('import_data', {
|
||||
} = await invoke('cmd_import_data', {
|
||||
filePaths: Array.isArray(selected) ? selected : [selected],
|
||||
});
|
||||
const importedWorkspace = imported.workspaces[0];
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { isResponseLoading } from '../lib/models';
|
||||
import { useLatestResponse } from './useLatestResponse';
|
||||
import { useLatestHttpResponse } from './useLatestHttpResponse';
|
||||
|
||||
export function useIsResponseLoading(requestId: string | null): boolean {
|
||||
const response = useLatestResponse(requestId);
|
||||
const response = useLatestHttpResponse(requestId);
|
||||
if (response === null) return false;
|
||||
return isResponseLoading(response);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ export function useKeyValue<T extends Object | null>({
|
||||
const query = useQuery<T>({
|
||||
queryKey: keyValueQueryKey({ namespace, key }),
|
||||
queryFn: async () => getKeyValue({ namespace, key, fallback: defaultValue }),
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
const mutate = useMutation<void, unknown, T>({
|
||||
@@ -37,19 +38,21 @@ export function useKeyValue<T extends Object | null>({
|
||||
});
|
||||
|
||||
const set = useCallback(
|
||||
(value: ((v: T) => T) | T) => {
|
||||
async (value: ((v: T) => T) | T) => {
|
||||
if (typeof value === 'function') {
|
||||
getKeyValue({ namespace, key, fallback: defaultValue }).then((kv) => {
|
||||
mutate.mutate(value(kv));
|
||||
await getKeyValue({ namespace, key, fallback: defaultValue }).then((kv) => {
|
||||
const newV = value(kv);
|
||||
if (newV === kv) return;
|
||||
return mutate.mutateAsync(newV);
|
||||
});
|
||||
} else {
|
||||
mutate.mutate(value);
|
||||
} else if (value !== query.data) {
|
||||
await mutate.mutateAsync(value);
|
||||
}
|
||||
},
|
||||
[defaultValue, key, mutate, namespace],
|
||||
[defaultValue, key, mutate, namespace, query.data],
|
||||
);
|
||||
|
||||
const reset = useCallback(() => mutate.mutate(defaultValue), [mutate, defaultValue]);
|
||||
const reset = useCallback(async () => mutate.mutateAsync(defaultValue), [mutate, defaultValue]);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
|
||||
7
src-web/hooks/useLatestGrpcConnection.ts
Normal file
7
src-web/hooks/useLatestGrpcConnection.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { GrpcConnection } from '../lib/models';
|
||||
import { useGrpcConnections } from './useGrpcConnections';
|
||||
|
||||
export function useLatestGrpcConnection(requestId: string | null): GrpcConnection | null {
|
||||
const connections = useGrpcConnections(requestId);
|
||||
return connections[0] ?? null;
|
||||
}
|
||||
7
src-web/hooks/useLatestHttpResponse.ts
Normal file
7
src-web/hooks/useLatestHttpResponse.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { HttpResponse } from '../lib/models';
|
||||
import { useHttpResponses } from './useHttpResponses';
|
||||
|
||||
export function useLatestHttpResponse(requestId: string | null): HttpResponse | null {
|
||||
const responses = useHttpResponses(requestId);
|
||||
return responses[0] ?? null;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import type { HttpResponse } from '../lib/models';
|
||||
import { useResponses } from './useResponses';
|
||||
|
||||
export function useLatestResponse(requestId: string | null): HttpResponse | null {
|
||||
const responses = useResponses(requestId);
|
||||
return responses[0] ?? null;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { useRequests } from './useRequests';
|
||||
|
||||
export function useRequest(id: string | null): HttpRequest | null {
|
||||
const requests = useRequests();
|
||||
return requests.find((r) => r.id === id) ?? null;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { save } from '@tauri-apps/api/dialog';
|
||||
import slugify from 'slugify';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { HttpResponse } from '../lib/models';
|
||||
import { getRequest } from '../lib/store';
|
||||
import { getHttpRequest } from '../lib/store';
|
||||
import { useActiveCookieJar } from './useActiveCookieJar';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useAlert } from './useAlert';
|
||||
@@ -15,7 +15,7 @@ export function useSendAnyRequest(options: { download?: boolean } = {}) {
|
||||
const { activeCookieJar } = useActiveCookieJar();
|
||||
return useMutation<HttpResponse | null, string, string | null>({
|
||||
mutationFn: async (id) => {
|
||||
const request = await getRequest(id);
|
||||
const request = await getHttpRequest(id);
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export function useSendAnyRequest(options: { download?: boolean } = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
return invoke('send_request', {
|
||||
return invoke('cmd_send_request', {
|
||||
requestId: id,
|
||||
environmentId,
|
||||
downloadDir: downloadDir,
|
||||
|
||||
@@ -11,7 +11,7 @@ export function useSettings() {
|
||||
useQuery({
|
||||
queryKey: settingsQueryKey(),
|
||||
queryFn: async () => {
|
||||
return (await invoke('get_settings')) as Settings;
|
||||
return (await invoke('cmd_get_settings')) as Settings;
|
||||
},
|
||||
}).data ?? undefined
|
||||
);
|
||||
|
||||
@@ -14,7 +14,7 @@ export function useUpdateAnyFolder() {
|
||||
throw new Error("Can't update a null folder");
|
||||
}
|
||||
|
||||
await invoke('update_folder', { folder: update(folder) });
|
||||
await invoke('cmd_update_folder', { folder: update(folder) });
|
||||
},
|
||||
onMutate: async ({ id, update }) => {
|
||||
const folder = await getFolder(id);
|
||||
|
||||
36
src-web/hooks/useUpdateAnyGrpcRequest.ts
Normal file
36
src-web/hooks/useUpdateAnyGrpcRequest.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import type { GrpcRequest } from '../lib/models';
|
||||
import { sleep } from '../lib/sleep';
|
||||
import { getGrpcRequest } from '../lib/store';
|
||||
import { grpcRequestsQueryKey } from './useGrpcRequests';
|
||||
|
||||
export function useUpdateAnyGrpcRequest() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<
|
||||
void,
|
||||
unknown,
|
||||
{ id: string; update: Partial<GrpcRequest> | ((r: GrpcRequest) => GrpcRequest) }
|
||||
>({
|
||||
mutationFn: async ({ id, update }) => {
|
||||
const request = await getGrpcRequest(id);
|
||||
if (request === null) {
|
||||
throw new Error("Can't update a null request");
|
||||
}
|
||||
|
||||
const patchedRequest =
|
||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||
await invoke('cmd_update_grpc_request', { request: patchedRequest });
|
||||
},
|
||||
onMutate: async ({ id, update }) => {
|
||||
const request = await getGrpcRequest(id);
|
||||
if (request === null) return;
|
||||
const patchedRequest =
|
||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||
queryClient.setQueryData<GrpcRequest[]>(grpcRequestsQueryKey(request), (requests) =>
|
||||
(requests ?? []).map((r) => (r.id === patchedRequest.id ? patchedRequest : r)),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { getRequest } from '../lib/store';
|
||||
import { requestsQueryKey } from './useRequests';
|
||||
import { getHttpRequest } from '../lib/store';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
|
||||
export function useUpdateAnyRequest() {
|
||||
export function useUpdateAnyHttpRequest() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<
|
||||
@@ -13,21 +13,21 @@ export function useUpdateAnyRequest() {
|
||||
{ id: string; update: Partial<HttpRequest> | ((r: HttpRequest) => HttpRequest) }
|
||||
>({
|
||||
mutationFn: async ({ id, update }) => {
|
||||
const request = await getRequest(id);
|
||||
const request = await getHttpRequest(id);
|
||||
if (request === null) {
|
||||
throw new Error("Can't update a null request");
|
||||
}
|
||||
|
||||
const patchedRequest =
|
||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||
await invoke('update_request', { request: patchedRequest });
|
||||
await invoke('cmd_update_http_request', { request: patchedRequest });
|
||||
},
|
||||
onMutate: async ({ id, update }) => {
|
||||
const request = await getRequest(id);
|
||||
const request = await getHttpRequest(id);
|
||||
if (request === null) return;
|
||||
const patchedRequest =
|
||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||
queryClient.setQueryData<HttpRequest[]>(requestsQueryKey(request), (requests) =>
|
||||
queryClient.setQueryData<HttpRequest[]>(httpRequestsQueryKey(request), (requests) =>
|
||||
(requests ?? []).map((r) => (r.id === patchedRequest.id ? patchedRequest : r)),
|
||||
);
|
||||
},
|
||||
@@ -15,7 +15,7 @@ export function useUpdateCookieJar(id: string | null) {
|
||||
|
||||
const newCookieJar = typeof v === 'function' ? v(cookieJar) : { ...cookieJar, ...v };
|
||||
console.log('NEW COOKIE JAR', newCookieJar.cookies.length);
|
||||
await invoke('update_cookie_jar', { cookieJar: newCookieJar });
|
||||
await invoke('cmd_update_cookie_jar', { cookieJar: newCookieJar });
|
||||
},
|
||||
onMutate: async (v) => {
|
||||
const cookieJar = await getCookieJar(id);
|
||||
|
||||
@@ -14,7 +14,7 @@ export function useUpdateEnvironment(id: string | null) {
|
||||
}
|
||||
|
||||
const newEnvironment = typeof v === 'function' ? v(environment) : { ...environment, ...v };
|
||||
await invoke('update_environment', { environment: newEnvironment });
|
||||
await invoke('cmd_update_environment', { environment: newEnvironment });
|
||||
},
|
||||
onMutate: async (v) => {
|
||||
const environment = await getEnvironment(id);
|
||||
|
||||
12
src-web/hooks/useUpdateGrpcRequest.ts
Normal file
12
src-web/hooks/useUpdateGrpcRequest.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { GrpcRequest } from '../lib/models';
|
||||
import { useUpdateAnyGrpcRequest } from './useUpdateAnyGrpcRequest';
|
||||
|
||||
export function useUpdateGrpcRequest(id: string | null) {
|
||||
const updateAnyGrpcRequest = useUpdateAnyGrpcRequest();
|
||||
return useMutation<void, unknown, Partial<GrpcRequest> | ((r: GrpcRequest) => GrpcRequest)>({
|
||||
mutationFn: async (update) => {
|
||||
return updateAnyGrpcRequest.mutateAsync({ id: id ?? 'n/a', update });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { useUpdateAnyRequest } from './useUpdateAnyRequest';
|
||||
import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
|
||||
|
||||
export function useUpdateRequest(id: string | null) {
|
||||
const updateAnyRequest = useUpdateAnyRequest();
|
||||
export function useUpdateHttpRequest(id: string | null) {
|
||||
const updateAnyRequest = useUpdateAnyHttpRequest();
|
||||
return useMutation<void, unknown, Partial<HttpRequest> | ((r: HttpRequest) => HttpRequest)>({
|
||||
mutationFn: async (update) => updateAnyRequest.mutateAsync({ id: id ?? 'n/a', update }),
|
||||
});
|
||||
@@ -8,7 +8,7 @@ export function useUpdateSettings() {
|
||||
|
||||
return useMutation<void, unknown, Settings>({
|
||||
mutationFn: async (settings) => {
|
||||
await invoke('update_settings', { settings });
|
||||
await invoke('cmd_update_settings', { settings });
|
||||
},
|
||||
onMutate: async (settings) => {
|
||||
queryClient.setQueryData<Settings>(settingsQueryKey(), settings);
|
||||
|
||||
@@ -14,7 +14,7 @@ export function useUpdateWorkspace(id: string | null) {
|
||||
}
|
||||
|
||||
const newWorkspace = typeof v === 'function' ? v(workspace) : { ...workspace, ...v };
|
||||
await invoke('update_workspace', { workspace: newWorkspace });
|
||||
await invoke('cmd_update_workspace', { workspace: newWorkspace });
|
||||
},
|
||||
onMutate: async (v) => {
|
||||
const workspace = await getWorkspace(id);
|
||||
|
||||
@@ -11,7 +11,7 @@ export function useVariables({ environmentId }: { environmentId: string }) {
|
||||
useQuery({
|
||||
queryKey: variablesQueryKey({ environmentId }),
|
||||
queryFn: async () => {
|
||||
return (await invoke('list_variables', { environmentId })) as EnvironmentVariable[];
|
||||
return (await invoke('cmd_list_variables', { environmentId })) as EnvironmentVariable[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ export function workspacesQueryKey(_?: {}) {
|
||||
export function useWorkspaces() {
|
||||
return (
|
||||
useQuery(workspacesQueryKey(), async () => {
|
||||
return (await invoke('list_workspaces')) as Workspace[];
|
||||
return (await invoke('cmd_list_workspaces')) as Workspace[];
|
||||
}).data ?? []
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user