mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-18 23:43:55 +01:00
Better tauri listeners and stuff
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
import { useRef } from 'react';
|
||||
import { useMount } from 'react-use';
|
||||
import { Button } from '../components/core/Button';
|
||||
import { HStack } from '../components/core/Stacks';
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ export function useDeleteRequest(id: string | null) {
|
||||
},
|
||||
onSuccess: async () => {
|
||||
if (workspaceId === null || id === null) return;
|
||||
await queryClient.invalidateQueries(requestsQueryKey(workspaceId));
|
||||
await queryClient.invalidateQueries(requestsQueryKey({ workspaceId }));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export function useDeleteResponses(requestId?: string) {
|
||||
},
|
||||
onSuccess: async () => {
|
||||
if (!requestId) return;
|
||||
await queryClient.invalidateQueries(responsesQueryKey(requestId));
|
||||
await queryClient.invalidateQueries(responsesQueryKey({ requestId }));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { invoke } from '@tauri-apps/api';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
|
||||
export function requestsQueryKey(workspaceId: string) {
|
||||
export function requestsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
return ['http_requests', { workspaceId }];
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export function useRequests() {
|
||||
return (
|
||||
useQuery({
|
||||
enabled: workspaceId != null,
|
||||
queryKey: requestsQueryKey(workspaceId ?? 'n/a'),
|
||||
queryKey: requestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invoke('requests', { workspaceId })) as HttpRequest[];
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import type { HttpResponse } from '../lib/models';
|
||||
|
||||
export function responsesQueryKey(requestId: string) {
|
||||
export function responsesQueryKey({ requestId }: { requestId: string }) {
|
||||
return ['http_responses', { requestId }];
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export function useResponses(requestId: string | null) {
|
||||
useQuery<HttpResponse[]>({
|
||||
enabled: requestId !== null,
|
||||
initialData: [],
|
||||
queryKey: responsesQueryKey(requestId ?? 'n/a'),
|
||||
queryKey: responsesQueryKey({ requestId: requestId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
return (await invoke('responses', {
|
||||
requestId,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useCallback } from 'react';
|
||||
import { NAMESPACE_NO_SYNC } from '../lib/keyValueStore';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
|
||||
const START_WIDTH = 200;
|
||||
@@ -15,6 +16,7 @@ export interface SidebarDisplay {
|
||||
|
||||
export function useSidebarDisplay() {
|
||||
const display = useKeyValue<SidebarDisplay>({
|
||||
namespace: NAMESPACE_NO_SYNC,
|
||||
key: sidebarDisplayKey,
|
||||
defaultValue: sidebarDisplayDefaultValue,
|
||||
});
|
||||
|
||||
@@ -1,70 +1,136 @@
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import type { EventCallback } from '@tauri-apps/api/event';
|
||||
import { appWindow } from '@tauri-apps/api/window';
|
||||
import { useEffect } from 'react';
|
||||
import { matchPath } from 'react-router-dom';
|
||||
import { useEffectOnce } from 'react-use';
|
||||
import { DEFAULT_FONT_SIZE } from '../lib/constants';
|
||||
import { debounce } from '../lib/debounce';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { extractKeyValue, NAMESPACE_NO_SYNC } from '../lib/keyValueStore';
|
||||
import type { HttpRequest, HttpResponse, KeyValue, Model, Workspace } from '../lib/models';
|
||||
import { modelsEq } from '../lib/models';
|
||||
import { keyValueQueryKey } from './useKeyValue';
|
||||
import { requestsQueryKey } from './useRequests';
|
||||
import { useRequestUpdateKey } from './useRequestUpdateKey';
|
||||
import { responsesQueryKey } from './useResponses';
|
||||
import { routePaths } from './useRoutes';
|
||||
import { useSidebarDisplay } from './useSidebarDisplay';
|
||||
import { workspacesQueryKey } from './useWorkspaces';
|
||||
|
||||
const unsubFns: (() => void)[] = [];
|
||||
export const UPDATE_DEBOUNCE_MILLIS = 1000;
|
||||
export const UPDATE_DEBOUNCE_MILLIS = 100;
|
||||
|
||||
export function useTauriListeners() {
|
||||
const sidebarDisplay = useSidebarDisplay();
|
||||
const queryClient = useQueryClient();
|
||||
const { wasUpdatedExternally } = useRequestUpdateKey(null);
|
||||
|
||||
useEffect(() => {
|
||||
useEffectOnce(() => {
|
||||
let unmounted = false;
|
||||
|
||||
appWindow
|
||||
.listen('toggle_sidebar', async () => {
|
||||
sidebarDisplay.toggle();
|
||||
})
|
||||
.then((unsub) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
function listen<T>(event: string, fn: EventCallback<T>) {
|
||||
appWindow.listen(event, fn).then((unsub) => {
|
||||
if (unmounted) unsub();
|
||||
else unsubFns.push(unsub);
|
||||
});
|
||||
}
|
||||
|
||||
listen('refresh', () => {
|
||||
location.reload();
|
||||
}).then((unsub) => {
|
||||
if (unmounted) unsub();
|
||||
else unsubFns.push(unsub);
|
||||
function listenDebounced<T>(event: string, fn: EventCallback<T>) {
|
||||
listen(event, debounce(fn, UPDATE_DEBOUNCE_MILLIS));
|
||||
}
|
||||
|
||||
listen('toggle_sidebar', sidebarDisplay.toggle);
|
||||
listen('refresh', () => location.reload());
|
||||
|
||||
listenDebounced('updated_key_value', ({ payload: keyValue }: { payload: KeyValue }) => {
|
||||
if (keyValue.namespace !== NAMESPACE_NO_SYNC) {
|
||||
queryClient.setQueryData(keyValueQueryKey(keyValue), extractKeyValue(keyValue));
|
||||
}
|
||||
});
|
||||
|
||||
appWindow
|
||||
.listen(
|
||||
'updated_request',
|
||||
debounce(({ payload: request }: { payload: HttpRequest }) => {
|
||||
queryClient.setQueryData(
|
||||
requestsQueryKey(request.workspaceId),
|
||||
(requests: HttpRequest[] = []) => {
|
||||
const newRequests = [];
|
||||
let found = false;
|
||||
for (const r of requests) {
|
||||
if (r.id === request.id) {
|
||||
found = true;
|
||||
newRequests.push(request);
|
||||
} else {
|
||||
newRequests.push(r);
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
newRequests.push(request);
|
||||
}
|
||||
setTimeout(() => wasUpdatedExternally(request.id), 50);
|
||||
return newRequests;
|
||||
},
|
||||
);
|
||||
}, UPDATE_DEBOUNCE_MILLIS),
|
||||
)
|
||||
.then((unsub) => {
|
||||
if (unmounted) unsub();
|
||||
else unsubFns.push(unsub);
|
||||
});
|
||||
listenDebounced('updated_model', ({ payload }: { payload: Model }) => {
|
||||
const queryKey =
|
||||
payload.model === 'http_request'
|
||||
? requestsQueryKey(payload)
|
||||
: payload.model === 'http_response'
|
||||
? responsesQueryKey(payload)
|
||||
: payload.model === 'workspace'
|
||||
? workspacesQueryKey(payload)
|
||||
: payload.model === 'key_value'
|
||||
? keyValueQueryKey(payload)
|
||||
: null;
|
||||
|
||||
if (queryKey === null) {
|
||||
throw new Error('Unrecognized updated model ' + payload.model);
|
||||
}
|
||||
|
||||
const skipSync = payload.model === 'key_value' && payload.namespace === NAMESPACE_NO_SYNC;
|
||||
|
||||
if (!skipSync) {
|
||||
queryClient.setQueryData(queryKey, (values: Model[] = []) => {
|
||||
const newValues = [];
|
||||
let found = false;
|
||||
for (const v of values) {
|
||||
if (modelsEq(v, payload)) {
|
||||
found = true;
|
||||
newValues.push(payload);
|
||||
} else {
|
||||
newValues.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
// Doesn't exist already, so add it to the list
|
||||
if (!found) newValues.push(payload);
|
||||
|
||||
if (payload.model === 'http_request') {
|
||||
setTimeout(() => wasUpdatedExternally(payload.id), 50);
|
||||
}
|
||||
|
||||
return newValues;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
listen('deleted_model', ({ payload: model }: { payload: Model }) => {
|
||||
function removeById<T extends { id: string }>(model: T) {
|
||||
return (entries: T[] | undefined) => entries?.filter((e) => e.id !== model.id);
|
||||
}
|
||||
|
||||
if (model.model === 'workspace') {
|
||||
queryClient.setQueryData(workspacesQueryKey(), removeById<Workspace>(model));
|
||||
} else if (model.model === 'http_request') {
|
||||
queryClient.setQueryData(requestsQueryKey(model), removeById<HttpRequest>(model));
|
||||
} else if (model.model === 'http_response') {
|
||||
queryClient.setQueryData(responsesQueryKey(model), removeById<HttpResponse>(model));
|
||||
} else if (model.model === 'key_value') {
|
||||
queryClient.setQueryData(keyValueQueryKey(model), undefined);
|
||||
}
|
||||
});
|
||||
|
||||
listen('send_request', async () => {
|
||||
const params = matchPath(routePaths.request(), window.location.pathname);
|
||||
const requestId = params?.params.requestId;
|
||||
if (typeof requestId !== 'string') {
|
||||
return;
|
||||
}
|
||||
await invoke('send_request', { requestId });
|
||||
});
|
||||
|
||||
listen('zoom', ({ payload: zoomDelta }: { payload: number }) => {
|
||||
const fontSize = parseFloat(window.getComputedStyle(document.documentElement).fontSize);
|
||||
|
||||
let newFontSize;
|
||||
if (zoomDelta === 0) {
|
||||
newFontSize = DEFAULT_FONT_SIZE;
|
||||
} else if (zoomDelta > 0) {
|
||||
newFontSize = Math.min(fontSize * 1.1, DEFAULT_FONT_SIZE * 5);
|
||||
} else if (zoomDelta < 0) {
|
||||
newFontSize = Math.max(fontSize * 0.9, DEFAULT_FONT_SIZE * 0.4);
|
||||
}
|
||||
|
||||
document.documentElement.style.fontSize = `${newFontSize}px`;
|
||||
});
|
||||
|
||||
return () => {
|
||||
unmounted = true;
|
||||
@@ -72,5 +138,5 @@ export function useTauriListeners() {
|
||||
unsub();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
export function useUniqueKey(len = 10): { key: string; regenerate: () => void } {
|
||||
const [key, setKey] = useState<string>(() => generate(len));
|
||||
return { key, wasUpdatedExternally: () => setKey(generate(len)) };
|
||||
}
|
||||
|
||||
const CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
|
||||
function generate(len: number): string {
|
||||
const chars = [];
|
||||
for (let i = 0; i < len; i++) {
|
||||
chars.push(CHARS[Math.floor(Math.random() * CHARS.length)]);
|
||||
}
|
||||
return chars.join('');
|
||||
}
|
||||
@@ -19,10 +19,8 @@ export function useUpdateAnyRequest() {
|
||||
onMutate: async ({ id, update }) => {
|
||||
const request = await getRequest(id);
|
||||
if (request === null) return;
|
||||
queryClient.setQueryData(
|
||||
requestsQueryKey(request?.workspaceId),
|
||||
(requests: HttpRequest[] | undefined) =>
|
||||
requests?.map((r) => (r.id === request.id ? update(r) : r)),
|
||||
queryClient.setQueryData(requestsQueryKey(request), (requests: HttpRequest[] | undefined) =>
|
||||
requests?.map((r) => (r.id === request.id ? update(r) : r)),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { appWindow } from '@tauri-apps/api/window';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { getRequest } from '../lib/store';
|
||||
import { requestsQueryKey } from './useRequests';
|
||||
@@ -21,14 +20,9 @@ export function useUpdateRequest(id: string | null) {
|
||||
const request = await getRequest(id);
|
||||
if (request === null) return;
|
||||
|
||||
// Sync updatedBy so that the UI doesn't think the update is coming from elsewhere
|
||||
request.updatedBy = appWindow.label;
|
||||
|
||||
const newRequest = typeof v === 'function' ? v(request) : { ...request, ...v };
|
||||
queryClient.setQueryData(
|
||||
requestsQueryKey(request?.workspaceId),
|
||||
(requests: HttpRequest[] | undefined) =>
|
||||
requests?.map((r) => (r.id === newRequest.id ? newRequest : r)),
|
||||
queryClient.setQueryData(requestsQueryKey(request), (requests: HttpRequest[] | undefined) =>
|
||||
requests?.map((r) => (r.id === newRequest.id ? newRequest : r)),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import type { Workspace } from '../lib/models';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
export function workspacesQueryKey() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/ban-types
|
||||
export function workspacesQueryKey(_?: {}) {
|
||||
return ['workspaces'];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user