Add basic analytics

This commit is contained in:
Gregory Schier
2023-11-07 09:53:59 -08:00
parent 0f6e4b641a
commit a793ece1a5
21 changed files with 133 additions and 78 deletions

View File

@@ -1,9 +1,10 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api';
import { trackEvent } from '../lib/analytics';
import type { Environment } from '../lib/models';
import { environmentsQueryKey, useEnvironments } from './useEnvironments';
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
import { useAppRoutes } from './useAppRoutes';
import { environmentsQueryKey, useEnvironments } from './useEnvironments';
import { usePrompt } from './usePrompt';
import { useWorkspaces } from './useWorkspaces';
@@ -29,6 +30,7 @@ export function useCreateEnvironment() {
: [];
return invoke('create_environment', { name, variables, workspaceId });
},
onSettled: () => trackEvent('environment', 'create'),
onSuccess: async (environment) => {
if (workspaceId == null) return;
routes.setEnvironment(environment);

View File

@@ -1,5 +1,6 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api';
import { trackEvent } from '../lib/analytics';
import type { Folder } from '../lib/models';
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
import { foldersQueryKey } from './useFolders';
@@ -17,6 +18,7 @@ export function useCreateFolder() {
patch.sortPriority = patch.sortPriority || Date.now();
return invoke('create_folder', { workspaceId, ...patch });
},
onSettled: () => trackEvent('folder', 'create'),
onSuccess: async (request) => {
await queryClient.invalidateQueries(foldersQueryKey({ workspaceId: request.workspaceId }));
},

View File

@@ -1,5 +1,6 @@
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 { useActiveEnvironmentId } from './useActiveEnvironmentId';
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
@@ -26,6 +27,7 @@ export function useCreateRequest() {
patch.sortPriority = patch.sortPriority || maxSortPriority(requests) + 1000;
return invoke('create_request', { workspaceId, ...patch });
},
onSettled: () => trackEvent('http_request', 'create'),
onSuccess: async (request) => {
queryClient.setQueryData<HttpRequest[]>(
requestsQueryKey({ workspaceId: request.workspaceId }),

View File

@@ -1,5 +1,6 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api';
import { trackEvent } from '../lib/analytics';
import type { Workspace } from '../lib/models';
import { useAppRoutes } from './useAppRoutes';
import { workspacesQueryKey } from './useWorkspaces';
@@ -11,6 +12,7 @@ export function useCreateWorkspace({ navigateAfter }: { navigateAfter: boolean }
mutationFn: (patch) => {
return invoke('create_workspace', patch);
},
onSettled: () => trackEvent('workspace', 'create'),
onSuccess: async (workspace) => {
queryClient.setQueryData<Workspace[]>(workspacesQueryKey({}), (workspaces) => [
...(workspaces ?? []),

View File

@@ -1,6 +1,7 @@
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 type { HttpRequest } from '../lib/models';
import { getRequest } from '../lib/store';
import { useConfirm } from './useConfirm';
@@ -26,6 +27,7 @@ export function useDeleteAnyRequest() {
if (!confirmed) return null;
return invoke('delete_request', { requestId: id });
},
onSettled: () => trackEvent('http_request', 'delete'),
onSuccess: async (request) => {
// Was it cancelled?
if (request === null) return;

View File

@@ -1,6 +1,7 @@
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 type { Environment, Workspace } from '../lib/models';
import { useConfirm } from './useConfirm';
import { environmentsQueryKey } from './useEnvironments';
@@ -23,13 +24,13 @@ export function useDeleteEnvironment(environment: Environment | null) {
if (!confirmed) return null;
return invoke('delete_environment', { environmentId: environment?.id });
},
onSettled: () => trackEvent('environment', 'delete'),
onSuccess: async (environment) => {
if (environment === null) return;
const { id: environmentId, workspaceId } = environment;
queryClient.setQueryData<Workspace[]>(
environmentsQueryKey({ workspaceId }),
(environments) => environments?.filter((e) => e.id !== environmentId),
queryClient.setQueryData<Workspace[]>(environmentsQueryKey({ workspaceId }), (environments) =>
environments?.filter((e) => e.id !== environmentId),
);
},
});

View File

@@ -1,6 +1,7 @@
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 type { Folder } from '../lib/models';
import { getFolder } from '../lib/store';
import { useConfirm } from './useConfirm';
@@ -26,6 +27,7 @@ export function useDeleteFolder(id: string | null) {
if (!confirmed) return null;
return invoke('delete_folder', { folderId: id });
},
onSettled: () => trackEvent('folder', 'delete'),
onSuccess: async (folder) => {
// Was it cancelled?
if (folder === null) return;

View File

@@ -1,40 +1,11 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api';
import { InlineCode } from '../components/core/InlineCode';
import { useMutation } from '@tanstack/react-query';
import type { HttpRequest } from '../lib/models';
import { getRequest } from '../lib/store';
import { useConfirm } from './useConfirm';
import { requestsQueryKey } from './useRequests';
import { responsesQueryKey } from './useResponses';
import { useDeleteAnyRequest } from './useDeleteAnyRequest';
export function useDeleteRequest(id: string | null) {
const queryClient = useQueryClient();
const confirm = useConfirm();
const deleteAnyRequest = useDeleteAnyRequest();
return useMutation<HttpRequest | null, string>({
mutationFn: async () => {
const request = await getRequest(id);
const confirmed = await confirm({
title: 'Delete Request',
variant: 'delete',
description: (
<>
Permanently delete <InlineCode>{request?.name}</InlineCode>?
</>
),
});
if (!confirmed) return null;
return invoke('delete_request', { requestId: id });
},
onSuccess: async (request) => {
// Was it cancelled?
if (request === null) return;
const { workspaceId, id: requestId } = request;
queryClient.setQueryData(responsesQueryKey({ requestId }), []); // Responses were deleted
queryClient.setQueryData<HttpRequest[]>(requestsQueryKey({ workspaceId }), (requests) =>
(requests ?? []).filter((r) => r.id !== requestId),
);
},
mutationFn: () => deleteAnyRequest.mutateAsync(id ?? 'n/a'),
});
}

View File

@@ -1,5 +1,6 @@
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';
@@ -9,6 +10,7 @@ export function useDeleteResponse(id: string | null) {
mutationFn: async () => {
return await invoke('delete_response', { id: id });
},
onSettled: () => trackEvent('http_response', 'delete'),
onSuccess: ({ requestId, id: responseId }) => {
queryClient.setQueryData<HttpResponse[]>(responsesQueryKey({ requestId }), (responses) =>
(responses ?? []).filter((response) => response.id !== responseId),

View File

@@ -1,5 +1,6 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api';
import { trackEvent } from '../lib/analytics';
import { responsesQueryKey } from './useResponses';
export function useDeleteResponses(requestId?: string) {
@@ -9,6 +10,7 @@ export function useDeleteResponses(requestId?: string) {
if (requestId === undefined) return;
await invoke('delete_all_responses', { requestId });
},
onSettled: () => trackEvent('http_response', 'delete_many'),
onSuccess: async () => {
if (requestId === undefined) return;
queryClient.setQueryData(responsesQueryKey({ requestId }), []);

View File

@@ -1,6 +1,7 @@
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 type { Workspace } from '../lib/models';
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
import { useAppRoutes } from './useAppRoutes';
@@ -28,6 +29,7 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
if (!confirmed) return null;
return invoke('delete_workspace', { workspaceId: workspace?.id });
},
onSettled: () => trackEvent('workspace', 'delete'),
onSuccess: async (workspace) => {
if (workspace === null) return;

View File

@@ -1,10 +1,11 @@
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 { useActiveEnvironmentId } from './useActiveEnvironmentId';
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
import { useAppRoutes } from './useAppRoutes';
import { requestsQueryKey } from './useRequests';
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
export function useDuplicateRequest({
id,
@@ -22,6 +23,7 @@ export function useDuplicateRequest({
if (id === null) throw new Error("Can't duplicate a null request");
return invoke('duplicate_request', { id });
},
onSettled: () => trackEvent('http_request', 'duplicate'),
onSuccess: async (request) => {
queryClient.setQueryData<HttpRequest[]>(
requestsQueryKey({ workspaceId: request.workspaceId }),

View File

@@ -6,8 +6,8 @@ import { minPromiseMillis } from '../lib/minPromiseMillis';
import type { HttpRequest } from '../lib/models';
import { getResponseBodyText } from '../lib/responseBody';
import { sendEphemeralRequest } from '../lib/sendEphemeralRequest';
import { useDebouncedValue } from './useDebouncedValue';
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
import { useDebouncedValue } from './useDebouncedValue';
const introspectionRequestBody = JSON.stringify({
query: getIntrospectionQuery(),
@@ -66,7 +66,7 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) {
runIntrospection(); // Run immediately
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [request.id, request.url, request.method, refetchKey]);
}, [request.id, request.url, request.method, refetchKey, activeEnvironmentId]);
const refetch = useCallback(() => {
setRefetchKey((k) => k + 1);

View File

@@ -1,5 +1,6 @@
import { useMutation } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api';
import { trackEvent } from '../lib/analytics';
import type { HttpResponse } from '../lib/models';
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
@@ -7,5 +8,6 @@ export function useSendAnyRequest() {
const environmentId = useActiveEnvironmentId();
return useMutation<HttpResponse, string, string | null>({
mutationFn: (id) => invoke('send_request', { requestId: id, environmentId }),
onSettled: () => trackEvent('http_request', 'send'),
});
}

View File

@@ -7,20 +7,28 @@ import { requestsQueryKey } from './useRequests';
export function useUpdateAnyRequest() {
const queryClient = useQueryClient();
return useMutation<void, unknown, { id: string; update: (r: HttpRequest) => HttpRequest }>({
return useMutation<
void,
unknown,
{ id: string; update: Partial<HttpRequest> | ((r: HttpRequest) => HttpRequest) }
>({
mutationFn: async ({ id, update }) => {
const request = await getRequest(id);
if (request === null) {
throw new Error("Can't update a null request");
}
await invoke('update_request', { request: update(request) });
const patchedRequest =
typeof update === 'function' ? update(request) : { ...request, ...update };
await invoke('update_request', { request: patchedRequest });
},
onMutate: async ({ id, update }) => {
const request = await getRequest(id);
if (request === null) return;
const patchedRequest =
typeof update === 'function' ? update(request) : { ...request, ...update };
queryClient.setQueryData<HttpRequest[]>(requestsQueryKey(request), (requests) =>
(requests ?? []).map((r) => (r.id === request.id ? update(r) : r)),
(requests ?? []).map((r) => (r.id === patchedRequest.id ? patchedRequest : r)),
);
},
});

View File

@@ -1,29 +1,10 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api';
import { useMutation } from '@tanstack/react-query';
import type { HttpRequest } from '../lib/models';
import { getRequest } from '../lib/store';
import { requestsQueryKey } from './useRequests';
import { useUpdateAnyRequest } from './useUpdateAnyRequest';
export function useUpdateRequest(id: string | null) {
const queryClient = useQueryClient();
const updateAnyRequest = useUpdateAnyRequest();
return useMutation<void, unknown, Partial<HttpRequest> | ((r: HttpRequest) => HttpRequest)>({
mutationFn: async (v) => {
const request = await getRequest(id);
if (request == null) {
throw new Error("Can't update a null request");
}
const newRequest = typeof v === 'function' ? v(request) : { ...request, ...v };
await invoke('update_request', { request: newRequest });
},
onMutate: async (v) => {
const request = await getRequest(id);
if (request === null) return;
const patchedRequest = typeof v === 'function' ? v(request) : { ...request, ...v };
queryClient.setQueryData<HttpRequest[]>(requestsQueryKey(request), (requests) =>
(requests ?? []).map((r) => (r.id === patchedRequest.id ? patchedRequest : r)),
);
},
mutationFn: async (update) => updateAnyRequest.mutateAsync({ id: id ?? 'n/a', update }),
});
}