Update local model stores in all mutations (#129)

This commit is contained in:
Gregory Schier
2024-10-23 09:54:43 -07:00
committed by GitHub
parent c5e6d6f2cb
commit 7759649963
29 changed files with 270 additions and 79 deletions

16
package-lock.json generated
View File

@@ -2597,9 +2597,9 @@
}
},
"node_modules/@tanstack/query-core": {
"version": "5.59.6",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.59.6.tgz",
"integrity": "sha512-g58YTHe4ClRrjJ50GY9fas/0zARJVozY0Hs+hcSBOmwZaeKY+to0/LX8wKnnH/EJiLYcC1sHmE11CAS3ncfZBg==",
"version": "5.59.16",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.59.16.tgz",
"integrity": "sha512-crHn+G3ltqb5JG0oUv6q+PMz1m1YkjpASrXTU+sYWW9pLk0t2GybUHNRqYPZWhxgjPaVGC4yp92gSFEJgYEsPw==",
"license": "MIT",
"funding": {
"type": "github",
@@ -2618,12 +2618,12 @@
}
},
"node_modules/@tanstack/react-query": {
"version": "5.59.6",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.59.6.tgz",
"integrity": "sha512-sGg2sNKg8cYf6aS1dzDf4weN+Vt9PfUu+0btwerrbtYysdNBbcGD4rPe9jhPgMtpDDlvi4cbLv+j1Qo814Kf+Q==",
"version": "5.59.16",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.59.16.tgz",
"integrity": "sha512-MuyWheG47h6ERd4PKQ6V8gDyBu3ThNG22e1fRVwvq6ap3EqsFhyuxCAwhNP/03m/mLg+DAb0upgbPaX6VB+CkQ==",
"license": "MIT",
"dependencies": {
"@tanstack/query-core": "5.59.6"
"@tanstack/query-core": "5.59.16"
},
"funding": {
"type": "github",
@@ -13767,7 +13767,7 @@
"@lezer/lr": "^1.3.3",
"@react-hook/resize-observer": "^2.0.2",
"@tailwindcss/container-queries": "^0.1.1",
"@tanstack/react-query": "^5.55.4",
"@tanstack/react-query": "^5.59.16",
"@tanstack/react-virtual": "^3.10.8",
"@tauri-apps/api": "^2.0.1",
"@tauri-apps/plugin-clipboard-manager": "^2.0.0",

View File

@@ -45,6 +45,7 @@ export const EnvironmentEditDialog = function ({ initialEnvironment }: Props) {
const handleCreateEnvironment = async () => {
const e = await createEnvironment.mutateAsync();
if (e == null) return;
setSelectedEnvironmentId(e.id);
};

View File

@@ -41,7 +41,7 @@ export const RecentResponsesDropdown = function ResponsePane({
},
{
key: 'copy',
label: 'Copy to Clipboard',
label: 'Copy Body',
onSelect: copyResponse.mutate,
leftSlot: <Icon icon="copy" />,
hidden: responses.length === 0,

View File

@@ -1,15 +1,19 @@
import { useMutation } from '@tanstack/react-query';
import type { CookieJar } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai";
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import { useActiveWorkspace } from './useActiveWorkspace';
import {cookieJarsAtom} from "./useCookieJars";
import { usePrompt } from './usePrompt';
import {updateModelList} from "./useSyncModelStores";
export function useCreateCookieJar() {
const workspace = useActiveWorkspace();
const prompt = usePrompt();
const setCookieJars = useSetAtom(cookieJarsAtom);
return useMutation<CookieJar>({
return useMutation<CookieJar | null>({
mutationKey: ['create_cookie_jar'],
mutationFn: async () => {
if (workspace === null) {
@@ -23,8 +27,16 @@ export function useCreateCookieJar() {
label: 'Name',
defaultValue: 'My Jar',
});
if (name == null) return null;
return invokeCmd('cmd_create_cookie_jar', { workspaceId: workspace.id, name });
},
onSuccess: (cookieJar) => {
if (cookieJar == null) return;
// Optimistic update
setCookieJars(updateModelList(cookieJar));
},
onSettled: () => trackEvent('cookie_jar', 'create'),
});
}

View File

@@ -1,17 +1,21 @@
import { useMutation } from '@tanstack/react-query';
import type { Environment } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai";
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import { useActiveEnvironment } from './useActiveEnvironment';
import { useActiveWorkspace } from './useActiveWorkspace';
import {environmentsAtom} from "./useEnvironments";
import { usePrompt } from './usePrompt';
import {updateModelList} from "./useSyncModelStores";
export function useCreateEnvironment() {
const [, setActiveEnvironmentId] = useActiveEnvironment();
const prompt = usePrompt();
const workspace = useActiveWorkspace();
const setEnvironments = useSetAtom(environmentsAtom);
return useMutation<Environment, unknown, void>({
return useMutation<Environment | null, unknown, void>({
mutationKey: ['create_environment'],
mutationFn: async () => {
const name = await prompt({
@@ -23,6 +27,8 @@ export function useCreateEnvironment() {
defaultValue: 'My Environment',
confirmText: 'Create',
});
if (name == null) return null;
return invokeCmd('cmd_create_environment', {
name,
variables: [],
@@ -31,7 +37,11 @@ export function useCreateEnvironment() {
},
onSettled: () => trackEvent('environment', 'create'),
onSuccess: async (environment) => {
if (workspace == null) return;
if (environment == null) return;
// Optimistic update
setEnvironments(updateModelList(environment));
setActiveEnvironmentId(environment.id);
},
});

View File

@@ -1,15 +1,23 @@
import { useMutation } from '@tanstack/react-query';
import type { Folder } from '@yaakapp-internal/models';
import { useSetAtom } from 'jotai';
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import { useActiveWorkspace } from './useActiveWorkspace';
import { foldersAtom } from './useFolders';
import { usePrompt } from './usePrompt';
import { updateModelList } from './useSyncModelStores';
export function useCreateFolder() {
const workspace = useActiveWorkspace();
const prompt = usePrompt();
const setFolders = useSetAtom(foldersAtom);
return useMutation<void, unknown, Partial<Pick<Folder, 'name' | 'sortPriority' | 'folderId'>>>({
return useMutation<
Folder | null,
unknown,
Partial<Pick<Folder, 'name' | 'sortPriority' | 'folderId'>>
>({
mutationKey: ['create_folder'],
mutationFn: async (patch) => {
if (workspace === null) {
@@ -25,14 +33,19 @@ export function useCreateFolder() {
confirmText: 'Create',
placeholder: 'Name',
});
if (name == null) {
return;
}
if (name == null) return null;
patch.name = name;
}
patch.sortPriority = patch.sortPriority || -Date.now();
await invokeCmd('cmd_create_folder', { workspaceId: workspace.id, ...patch });
return await invokeCmd('cmd_create_folder', { workspaceId: workspace.id, ...patch });
},
onSuccess: (folder) => {
if (folder == null) return;
// Optimistic update
setFolders(updateModelList(folder));
},
onSettled: () => trackEvent('folder', 'create'),
});

View File

@@ -1,17 +1,21 @@
import { useMutation } from '@tanstack/react-query';
import type { GrpcRequest } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai";
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import { useActiveEnvironment } from './useActiveEnvironment';
import { useActiveRequest } from './useActiveRequest';
import { useActiveWorkspace } from './useActiveWorkspace';
import { useAppRoutes } from './useAppRoutes';
import {grpcRequestsAtom} from "./useGrpcRequests";
import {updateModelList} from "./useSyncModelStores";
export function useCreateGrpcRequest() {
const workspace = useActiveWorkspace();
const [activeEnvironment] = useActiveEnvironment();
const activeRequest = useActiveRequest();
const routes = useAppRoutes();
const setGrpcRequests = useSetAtom(grpcRequestsAtom);
return useMutation<
GrpcRequest,
@@ -33,19 +37,17 @@ export function useCreateGrpcRequest() {
}
}
patch.folderId = patch.folderId || activeRequest?.folderId;
const request = await invokeCmd<GrpcRequest>('cmd_create_grpc_request', {
return invokeCmd<GrpcRequest>('cmd_create_grpc_request', {
workspaceId: workspace.id,
name: '',
...patch,
});
// Give some time for the workspace to sync to the local store
await new Promise((resolve) => setTimeout(resolve, 100));
return request;
},
onSettled: () => trackEvent('grpc_request', 'create'),
onSuccess: async (request) => {
// Optimistic update
setGrpcRequests(updateModelList(request));
routes.navigate('request', {
workspaceId: request.workspaceId,
requestId: request.id,

View File

@@ -1,17 +1,21 @@
import { useMutation } from '@tanstack/react-query';
import type { HttpRequest } from '@yaakapp-internal/models';
import { useSetAtom } from 'jotai/index';
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import { useActiveEnvironment } from './useActiveEnvironment';
import { useActiveRequest } from './useActiveRequest';
import { useActiveWorkspace } from './useActiveWorkspace';
import { useAppRoutes } from './useAppRoutes';
import { httpRequestsAtom } from './useHttpRequests';
import { updateModelList } from './useSyncModelStores';
export function useCreateHttpRequest() {
const workspace = useActiveWorkspace();
const [activeEnvironment] = useActiveEnvironment();
const activeRequest = useActiveRequest();
const routes = useAppRoutes();
const setHttpRequests = useSetAtom(httpRequestsAtom);
return useMutation<HttpRequest, unknown, Partial<HttpRequest>>({
mutationKey: ['create_http_request'],
@@ -29,17 +33,15 @@ export function useCreateHttpRequest() {
}
}
patch.folderId = patch.folderId || activeRequest?.folderId;
const request = await invokeCmd<HttpRequest>('cmd_create_http_request', {
return invokeCmd<HttpRequest>('cmd_create_http_request', {
request: { workspaceId: workspace.id, ...patch },
});
// Give some time for the workspace to sync to the local store
await new Promise((resolve) => setTimeout(resolve, 100));
return request;
},
onSettled: () => trackEvent('http_request', 'create'),
onSuccess: async (request) => {
// Optimistic update
setHttpRequests(updateModelList(request));
routes.navigate('request', {
workspaceId: request.workspaceId,
requestId: request.id,

View File

@@ -1,13 +1,18 @@
import { useMutation } from '@tanstack/react-query';
import type { Workspace } from '@yaakapp-internal/models';
import { useSetAtom } from 'jotai/index';
import { invokeCmd } from '../lib/tauri';
import { useAppRoutes } from './useAppRoutes';
import { usePrompt } from './usePrompt';
import {updateModelList} from "./useSyncModelStores";
import { workspacesAtom } from './useWorkspaces';
export function useCreateWorkspace() {
const routes = useAppRoutes();
const prompt = usePrompt();
return useMutation<Workspace, void, void>({
const setWorkspaces = useSetAtom(workspacesAtom);
return useMutation<Workspace | null, void, void>({
mutationKey: ['create_workspace'],
mutationFn: async () => {
const name = await prompt({
@@ -18,14 +23,17 @@ export function useCreateWorkspace() {
placeholder: 'My Workspace',
confirmText: 'Create',
});
const workspace = await invokeCmd<Workspace>('cmd_create_workspace', { name });
// Give some time for the workspace to sync to the local store
await new Promise((resolve) => setTimeout(resolve, 100));
return workspace;
if (name == null) {
return null;
}
return invokeCmd<Workspace>('cmd_create_workspace', { name });
},
onSuccess: async (workspace) => {
if (workspace == null) return;
// Optimistic update
setWorkspaces(updateModelList(workspace));
routes.navigate('workspace', { workspaceId: workspace.id });
},
});

View File

@@ -1,14 +1,18 @@
import { useMutation } from '@tanstack/react-query';
import type { GrpcRequest } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai";
import { InlineCode } from '../components/core/InlineCode';
import { trackEvent } from '../lib/analytics';
import { fallbackRequestName } from '../lib/fallbackRequestName';
import { getGrpcRequest } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import { useConfirm } from './useConfirm';
import {grpcRequestsAtom} from "./useGrpcRequests";
import {removeModelById} from "./useSyncModelStores";
export function useDeleteAnyGrpcRequest() {
const confirm = useConfirm();
const setGrpcRequests = useSetAtom(grpcRequestsAtom);
return useMutation<GrpcRequest | null, string, string>({
mutationKey: ['delete_any_grpc_request'],
@@ -29,6 +33,12 @@ export function useDeleteAnyGrpcRequest() {
if (!confirmed) return null;
return invokeCmd('cmd_delete_grpc_request', { requestId: id });
},
onSuccess: (request) => {
if (request == null) return;
// Optimistic update
setGrpcRequests(removeModelById(request));
},
onSettled: () => trackEvent('grpc_request', 'delete'),
});
}

View File

@@ -1,14 +1,18 @@
import { useMutation } from '@tanstack/react-query';
import type { HttpRequest } from '@yaakapp-internal/models';
import { useSetAtom } from 'jotai';
import { InlineCode } from '../components/core/InlineCode';
import { trackEvent } from '../lib/analytics';
import { fallbackRequestName } from '../lib/fallbackRequestName';
import { getHttpRequest } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import { useConfirm } from './useConfirm';
import { httpRequestsAtom } from './useHttpRequests';
import { removeModelById } from './useSyncModelStores';
export function useDeleteAnyHttpRequest() {
const confirm = useConfirm();
const setHttpRequests = useSetAtom(httpRequestsAtom);
return useMutation<HttpRequest | null, string, string>({
mutationKey: ['delete_any_http_request'],
@@ -27,7 +31,13 @@ export function useDeleteAnyHttpRequest() {
),
});
if (!confirmed) return null;
return invokeCmd('cmd_delete_http_request', { requestId: id });
return invokeCmd<HttpRequest>('cmd_delete_http_request', { requestId: id });
},
onSuccess: (request) => {
if (request == null) return;
// Optimistic update
setHttpRequests(removeModelById(request));
},
onSettled: () => trackEvent('http_request', 'delete'),
});

View File

@@ -1,12 +1,16 @@
import { useMutation } from '@tanstack/react-query';
import type { CookieJar } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai";
import { InlineCode } from '../components/core/InlineCode';
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import { useConfirm } from './useConfirm';
import {cookieJarsAtom} from "./useCookieJars";
import {removeModelById} from "./useSyncModelStores";
export function useDeleteCookieJar(cookieJar: CookieJar | null) {
const confirm = useConfirm();
const setCookieJars = useSetAtom(cookieJarsAtom);
return useMutation<CookieJar | null, string>({
mutationKey: ['delete_cookie_jar', cookieJar?.id],
@@ -25,5 +29,10 @@ export function useDeleteCookieJar(cookieJar: CookieJar | null) {
return invokeCmd('cmd_delete_cookie_jar', { cookieJarId: cookieJar?.id });
},
onSettled: () => trackEvent('cookie_jar', 'delete'),
onSuccess: (cookieJar) => {
if (cookieJar == null) return;
setCookieJars(removeModelById(cookieJar));
}
});
}

View File

@@ -1,12 +1,16 @@
import { useMutation } from '@tanstack/react-query';
import type { Environment } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai";
import { InlineCode } from '../components/core/InlineCode';
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import { useConfirm } from './useConfirm';
import {environmentsAtom} from "./useEnvironments";
import {removeModelById} from "./useSyncModelStores";
export function useDeleteEnvironment(environment: Environment | null) {
const confirm = useConfirm();
const setEnvironments = useSetAtom(environmentsAtom);
return useMutation<Environment | null, string>({
mutationKey: ['delete_environment', environment?.id],
@@ -25,5 +29,10 @@ export function useDeleteEnvironment(environment: Environment | null) {
return invokeCmd('cmd_delete_environment', { environmentId: environment?.id });
},
onSettled: () => trackEvent('environment', 'delete'),
onSuccess: (environment) => {
if (environment == null) return;
setEnvironments(removeModelById(environment));
}
});
}

View File

@@ -1,13 +1,17 @@
import { useMutation } from '@tanstack/react-query';
import type { Folder } from '@yaakapp-internal/models';
import { useSetAtom } from 'jotai';
import { InlineCode } from '../components/core/InlineCode';
import { trackEvent } from '../lib/analytics';
import { getFolder } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import { useConfirm } from './useConfirm';
import { foldersAtom } from './useFolders';
import { removeModelById } from './useSyncModelStores';
export function useDeleteFolder(id: string | null) {
const confirm = useConfirm();
const setFolders = useSetAtom(foldersAtom);
return useMutation<Folder | null, string>({
mutationKey: ['delete_folder', id],
@@ -27,5 +31,10 @@ export function useDeleteFolder(id: string | null) {
return invokeCmd('cmd_delete_folder', { folderId: id });
},
onSettled: () => trackEvent('folder', 'delete'),
onSuccess: (folder) => {
if (folder == null) return;
setFolders(removeModelById(folder));
},
});
}

View File

@@ -1,14 +1,23 @@
import { useMutation } from '@tanstack/react-query';
import type { GrpcConnection } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai";
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import {grpcConnectionsAtom} from "./useGrpcConnections";
import {removeModelById} from "./useSyncModelStores";
export function useDeleteGrpcConnection(id: string | null) {
const setGrpcConnections = useSetAtom(grpcConnectionsAtom);
return useMutation<GrpcConnection>({
mutationKey: ['delete_grpc_connection', id],
mutationFn: async () => {
return await invokeCmd('cmd_delete_grpc_connection', { id: id });
},
onSettled: () => trackEvent('grpc_connection', 'delete'),
onSuccess: (connection) => {
if (connection == null) return;
setGrpcConnections(removeModelById(connection));
}
});
}

View File

@@ -1,8 +1,11 @@
import { useMutation } from '@tanstack/react-query';
import { useSetAtom } from 'jotai';
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import { grpcConnectionsAtom } from './useGrpcConnections';
export function useDeleteGrpcConnections(requestId?: string) {
const setGrpcConnections = useSetAtom(grpcConnectionsAtom);
return useMutation({
mutationKey: ['delete_grpc_connections', requestId],
mutationFn: async () => {
@@ -10,5 +13,8 @@ export function useDeleteGrpcConnections(requestId?: string) {
await invokeCmd('cmd_delete_all_grpc_connections', { requestId });
},
onSettled: () => trackEvent('grpc_connection', 'delete_many'),
onSuccess: () => {
setGrpcConnections((all) => all.filter((r) => r.requestId !== requestId));
},
});
}

View File

@@ -1,14 +1,21 @@
import { useMutation } from '@tanstack/react-query';
import type { HttpResponse } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai";
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import {httpResponsesAtom} from "./useHttpResponses";
import {removeModelById} from "./useSyncModelStores";
export function useDeleteHttpResponse(id: string | null) {
const setHttpResponses = useSetAtom(httpResponsesAtom);
return useMutation<HttpResponse>({
mutationKey: ['delete_http_response', id],
mutationFn: async () => {
return await invokeCmd('cmd_delete_http_response', { id: id });
},
onSettled: () => trackEvent('http_response', 'delete'),
onSuccess: (response) => {
setHttpResponses(removeModelById(response));
}
});
}

View File

@@ -1,14 +1,20 @@
import { useMutation } from '@tanstack/react-query';
import { useSetAtom } from 'jotai';
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import { httpResponsesAtom } from './useHttpResponses';
export function useDeleteHttpResponses(requestId?: string) {
const setHttpResponses = useSetAtom(httpResponsesAtom);
return useMutation({
mutationKey: ['delete_http_responses', requestId],
mutationFn: async () => {
if (requestId === undefined) return;
await invokeCmd('cmd_delete_all_http_responses', { requestId });
},
onSuccess: () => {
setHttpResponses((all) => all.filter((r) => r.requestId !== requestId));
},
onSettled: () => trackEvent('http_response', 'delete_many'),
});
}

View File

@@ -1,15 +1,17 @@
import { useMutation } from '@tanstack/react-query';
import { useSetAtom } from 'jotai/index';
import { count } from '../lib/pluralize';
import { invokeCmd } from '../lib/tauri';
import { useActiveWorkspace } from './useActiveWorkspace';
import { useAlert } from './useAlert';
import { useConfirm } from './useConfirm';
import { useGrpcConnections } from './useGrpcConnections';
import { useHttpResponses } from './useHttpResponses';
import { httpResponsesAtom, useHttpResponses } from './useHttpResponses';
export function useDeleteSendHistory() {
const confirm = useConfirm();
const alert = useAlert();
const setHttpResponses = useSetAtom(httpResponsesAtom);
const activeWorkspace = useActiveWorkspace();
const httpResponses = useHttpResponses();
const grpcConnections = useGrpcConnections();
@@ -36,8 +38,15 @@ export function useDeleteSendHistory() {
variant: 'delete',
description: <>Delete {labels.join(' and ')}?</>,
});
if (!confirmed) return;
if (!confirmed) return false;
await invokeCmd('cmd_delete_send_history', { workspaceId: activeWorkspace?.id ?? 'n/a' });
return true;
},
onSuccess: async (confirmed) => {
if (!confirmed) return;
setHttpResponses((all) => all.filter((r) => r.workspaceId !== activeWorkspace?.id));
},
});
}

View File

@@ -1,16 +1,20 @@
import { useMutation } from '@tanstack/react-query';
import type { Workspace } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai";
import { InlineCode } from '../components/core/InlineCode';
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import { useActiveWorkspace } from './useActiveWorkspace';
import { useAppRoutes } from './useAppRoutes';
import { useConfirm } from './useConfirm';
import {removeModelById} from "./useSyncModelStores";
import {workspacesAtom} from "./useWorkspaces";
export function useDeleteWorkspace(workspace: Workspace | null) {
const activeWorkspace = useActiveWorkspace();
const routes = useAppRoutes();
const confirm = useConfirm();
const setWorkspaces = useSetAtom(workspacesAtom);
return useMutation<Workspace | null, string>({
mutationKey: ['delete_workspace', workspace?.id],
@@ -32,6 +36,9 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
onSuccess: async (workspace) => {
if (workspace === null) return;
// Optimistic update
setWorkspaces(removeModelById(workspace));
const { id: workspaceId } = workspace;
if (workspaceId === activeWorkspace?.id) {
routes.navigate('workspaces');

View File

@@ -60,29 +60,26 @@ export function useSyncModelStores() {
return;
}
// Mark these models as DESC instead of ASC
const pushToFront = model.model === 'http_response' || model.model === 'grpc_connection';
if (shouldIgnoreModel(model, windowLabel)) return;
if (model.model === 'workspace') {
setWorkspaces(updateModelList(model, pushToFront));
setWorkspaces(updateModelList(model));
} else if (model.model === 'plugin') {
setPlugins(updateModelList(model, pushToFront));
setPlugins(updateModelList(model));
} else if (model.model === 'http_request') {
setHttpRequests(updateModelList(model, pushToFront));
setHttpRequests(updateModelList(model));
} else if (model.model === 'folder') {
setFolders(updateModelList(model, pushToFront));
setFolders(updateModelList(model));
} else if (model.model === 'http_response') {
setHttpResponses(updateModelList(model, pushToFront));
setHttpResponses(updateModelList(model));
} else if (model.model === 'grpc_request') {
setGrpcRequests(updateModelList(model, pushToFront));
setGrpcRequests(updateModelList(model));
} else if (model.model === 'grpc_connection') {
setGrpcConnections(updateModelList(model, pushToFront));
setGrpcConnections(updateModelList(model));
} else if (model.model === 'environment') {
setEnvironments(updateModelList(model, pushToFront));
setEnvironments(updateModelList(model));
} else if (model.model === 'cookie_jar') {
setCookieJars(updateModelList(model, pushToFront));
setCookieJars(updateModelList(model));
} else if (model.model === 'settings') {
setSettings(model);
} else if (queryKey != null) {
@@ -94,7 +91,7 @@ export function useSyncModelStores() {
}
if (Array.isArray(current)) {
return updateModelList(model, pushToFront)(current);
return updateModelList(model)(current);
}
});
}
@@ -107,32 +104,35 @@ export function useSyncModelStores() {
console.log('Delete model', payload);
if (model.model === 'workspace') {
setWorkspaces(removeById(model));
setWorkspaces(removeModelById(model));
} else if (model.model === 'plugin') {
setPlugins(removeById(model));
setPlugins(removeModelById(model));
} else if (model.model === 'http_request') {
setHttpRequests(removeById(model));
setHttpRequests(removeModelById(model));
} else if (model.model === 'http_response') {
setHttpResponses(removeById(model));
setHttpResponses(removeModelById(model));
} else if (model.model === 'folder') {
setFolders(removeById(model));
setFolders(removeModelById(model));
} else if (model.model === 'environment') {
setEnvironments(removeById(model));
setEnvironments(removeModelById(model));
} else if (model.model === 'grpc_request') {
setGrpcRequests(removeById(model));
setGrpcRequests(removeModelById(model));
} else if (model.model === 'grpc_connection') {
setGrpcConnections(removeById(model));
setGrpcConnections(removeModelById(model));
} else if (model.model === 'grpc_event') {
queryClient.setQueryData(grpcEventsQueryKey(model), removeById(model));
queryClient.setQueryData(grpcEventsQueryKey(model), removeModelById(model));
} else if (model.model === 'key_value') {
queryClient.setQueryData(keyValueQueryKey(model), undefined);
} else if (model.model === 'cookie_jar') {
setCookieJars(removeById(model));
setCookieJars(removeModelById(model));
}
});
}
function updateModelList<T extends AnyModel>(model: T, pushToFront: boolean) {
export function updateModelList<T extends AnyModel>(model: T) {
// Mark these models as DESC instead of ASC
const pushToFront = model.model === 'http_response' || model.model === 'grpc_connection';
return (current: T[] | undefined): T[] => {
const index = current?.findIndex((v) => modelsEq(v, model)) ?? -1;
if (index >= 0) {
@@ -143,7 +143,7 @@ function updateModelList<T extends AnyModel>(model: T, pushToFront: boolean) {
};
}
function removeById<T extends { id: string }>(model: T) {
export function removeModelById<T extends { id: string }>(model: T) {
return (entries: T[] | undefined) => entries?.filter((e) => e.id !== model.id) ?? [];
}

View File

@@ -1,10 +1,14 @@
import { useMutation } from '@tanstack/react-query';
import type { Folder } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai/index";
import { getFolder } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import {foldersAtom} from "./useFolders";
import {updateModelList} from "./useSyncModelStores";
export function useUpdateAnyFolder() {
return useMutation<void, unknown, { id: string; update: (r: Folder) => Folder }>({
const setFolders = useSetAtom(foldersAtom);
return useMutation<Folder, unknown, { id: string; update: (r: Folder) => Folder }>({
mutationKey: ['update_any_folder'],
mutationFn: async ({ id, update }) => {
const folder = await getFolder(id);
@@ -12,7 +16,10 @@ export function useUpdateAnyFolder() {
throw new Error("Can't update a null folder");
}
await invokeCmd('cmd_update_folder', { folder: update(folder) });
return invokeCmd<Folder>('cmd_update_folder', { folder: update(folder) });
},
onSuccess: async (folder) => {
setFolders(updateModelList(folder));
}
});
}

View File

@@ -1,11 +1,15 @@
import { useMutation } from '@tanstack/react-query';
import type { GrpcRequest } from '@yaakapp-internal/models';
import { useSetAtom } from 'jotai/index';
import { getGrpcRequest } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import { grpcRequestsAtom } from './useGrpcRequests';
import { updateModelList } from './useSyncModelStores';
export function useUpdateAnyGrpcRequest() {
const setGrpcRequests = useSetAtom(grpcRequestsAtom);
return useMutation<
void,
GrpcRequest,
unknown,
{ id: string; update: Partial<GrpcRequest> | ((r: GrpcRequest) => GrpcRequest) }
>({
@@ -18,7 +22,10 @@ export function useUpdateAnyGrpcRequest() {
const patchedRequest =
typeof update === 'function' ? update(request) : { ...request, ...update };
await invokeCmd('cmd_update_grpc_request', { request: patchedRequest });
return invokeCmd<GrpcRequest>('cmd_update_grpc_request', { request: patchedRequest });
},
onSuccess: (request) => {
setGrpcRequests(updateModelList(request));
},
});
}

View File

@@ -1,11 +1,15 @@
import { useMutation } from '@tanstack/react-query';
import type { HttpRequest } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai/index";
import { getHttpRequest } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import {httpRequestsAtom} from "./useHttpRequests";
import {updateModelList} from "./useSyncModelStores";
export function useUpdateAnyHttpRequest() {
const setHttpRequests = useSetAtom(httpRequestsAtom);
return useMutation<
void,
HttpRequest,
unknown,
{ id: string; update: Partial<HttpRequest> | ((r: HttpRequest) => HttpRequest) }
>({
@@ -18,7 +22,10 @@ export function useUpdateAnyHttpRequest() {
const patchedRequest =
typeof update === 'function' ? update(request) : { ...request, ...update };
await invokeCmd('cmd_update_http_request', { request: patchedRequest });
return invokeCmd<HttpRequest>('cmd_update_http_request', { request: patchedRequest });
},
onSuccess: async (request) => {
setHttpRequests(updateModelList(request));
}
});
}

View File

@@ -1,10 +1,14 @@
import { useMutation } from '@tanstack/react-query';
import type { CookieJar } from '@yaakapp-internal/models';
import { useSetAtom } from 'jotai/index';
import { getCookieJar } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import { cookieJarsAtom } from './useCookieJars';
import { updateModelList } from './useSyncModelStores';
export function useUpdateCookieJar(id: string | null) {
return useMutation<void, unknown, Partial<CookieJar> | ((j: CookieJar) => CookieJar)>({
const setCookieJars = useSetAtom(cookieJarsAtom);
return useMutation<CookieJar, unknown, Partial<CookieJar> | ((j: CookieJar) => CookieJar)>({
mutationKey: ['update_cookie_jar', id],
mutationFn: async (v) => {
const cookieJar = await getCookieJar(id);
@@ -13,7 +17,10 @@ export function useUpdateCookieJar(id: string | null) {
}
const newCookieJar = typeof v === 'function' ? v(cookieJar) : { ...cookieJar, ...v };
await invokeCmd('cmd_update_cookie_jar', { cookieJar: newCookieJar });
return invokeCmd<CookieJar>('cmd_update_cookie_jar', { cookieJar: newCookieJar });
},
onSuccess: (cookieJar) => {
setCookieJars(updateModelList(cookieJar));
},
});
}

View File

@@ -1,10 +1,18 @@
import { useMutation } from '@tanstack/react-query';
import type { Environment } from '@yaakapp-internal/models';
import { useSetAtom } from 'jotai/index';
import { getEnvironment } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import { environmentsAtom } from './useEnvironments';
import {updateModelList} from "./useSyncModelStores";
export function useUpdateEnvironment(id: string | null) {
return useMutation<void, unknown, Partial<Environment> | ((r: Environment) => Environment)>({
const setEnvironments = useSetAtom(environmentsAtom);
return useMutation<
Environment,
unknown,
Partial<Environment> | ((r: Environment) => Environment)
>({
mutationKey: ['update_environment', id],
mutationFn: async (v) => {
const environment = await getEnvironment(id);
@@ -13,7 +21,10 @@ export function useUpdateEnvironment(id: string | null) {
}
const newEnvironment = typeof v === 'function' ? v(environment) : { ...environment, ...v };
await invokeCmd('cmd_update_environment', { environment: newEnvironment });
return invokeCmd<Environment>('cmd_update_environment', { environment: newEnvironment });
},
onSuccess: async (environment) => {
setEnvironments(updateModelList(environment));
},
});
}

View File

@@ -1,15 +1,21 @@
import { useMutation } from '@tanstack/react-query';
import type { Settings } from '@yaakapp-internal/models';
import { useSetAtom } from 'jotai';
import { getSettings } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import { settingsAtom } from './useSettings';
export function useUpdateSettings() {
return useMutation<void, unknown, Partial<Settings>>({
const setSettings = useSetAtom(settingsAtom);
return useMutation<Settings, unknown, Partial<Settings>>({
mutationKey: ['update_settings'],
mutationFn: async (patch) => {
const settings = await getSettings();
const newSettings: Settings = { ...settings, ...patch };
await invokeCmd('cmd_update_settings', { settings: newSettings });
return invokeCmd<Settings>('cmd_update_settings', { settings: newSettings });
},
onSuccess: (settings) => {
setSettings(settings);
},
});
}

View File

@@ -1,10 +1,14 @@
import { useMutation } from '@tanstack/react-query';
import type { Workspace } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai/index";
import { getWorkspace } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import {updateModelList} from "./useSyncModelStores";
import {workspacesAtom} from "./useWorkspaces";
export function useUpdateWorkspace(id: string | null) {
return useMutation<void, unknown, Partial<Workspace> | ((w: Workspace) => Workspace)>({
const setWorkspaces = useSetAtom(workspacesAtom);
return useMutation<Workspace, unknown, Partial<Workspace> | ((w: Workspace) => Workspace)>({
mutationKey: ['update_workspace', id],
mutationFn: async (v) => {
const workspace = await getWorkspace(id);
@@ -13,7 +17,10 @@ export function useUpdateWorkspace(id: string | null) {
}
const newWorkspace = typeof v === 'function' ? v(workspace) : { ...workspace, ...v };
await invokeCmd('cmd_update_workspace', { workspace: newWorkspace });
return invokeCmd('cmd_update_workspace', { workspace: newWorkspace });
},
onSuccess: async (workspace) => {
setWorkspaces(updateModelList(workspace));
},
});
}

View File

@@ -19,7 +19,7 @@
"@lezer/lr": "^1.3.3",
"@react-hook/resize-observer": "^2.0.2",
"@tailwindcss/container-queries": "^0.1.1",
"@tanstack/react-query": "^5.55.4",
"@tanstack/react-query": "^5.59.16",
"@tanstack/react-virtual": "^3.10.8",
"@tauri-apps/api": "^2.0.1",
"@tauri-apps/plugin-clipboard-manager": "^2.0.0",