mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-26 03:11:12 +01:00
Websocket Support (#159)
This commit is contained in:
@@ -1,18 +1,18 @@
|
||||
import type { GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
|
||||
import type { GrpcRequest, HttpRequest, WebsocketRequest } from '@yaakapp-internal/models';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { activeRequestIdAtom } from './useActiveRequestId';
|
||||
import { grpcRequestsAtom } from './useGrpcRequests';
|
||||
import { httpRequestsAtom } from './useHttpRequests';
|
||||
import { requestsAtom } from './useRequests';
|
||||
|
||||
interface TypeMap {
|
||||
http_request: HttpRequest;
|
||||
grpc_request: GrpcRequest;
|
||||
websocket_request: WebsocketRequest;
|
||||
}
|
||||
|
||||
export const activeRequestAtom = atom<HttpRequest | GrpcRequest | null>((get) => {
|
||||
export const activeRequestAtom = atom((get) => {
|
||||
const activeRequestId = get(activeRequestIdAtom);
|
||||
const requests = [...get(httpRequestsAtom), ...get(grpcRequestsAtom)];
|
||||
const requests = get(requestsAtom);
|
||||
return requests.find((r) => r.id === activeRequestId) ?? null;
|
||||
});
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ export function useCopy({ disableToast }: { disableToast?: boolean } = {}) {
|
||||
if (text != '' && !disableToast) {
|
||||
showToast({
|
||||
id: 'copied',
|
||||
color: 'secondary',
|
||||
color: 'success',
|
||||
icon: 'copy',
|
||||
message: 'Copied to clipboard',
|
||||
});
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { useMemo } from 'react';
|
||||
import { createFolder } from '../commands/commands';
|
||||
import { upsertWebsocketRequest } from '../commands/upsertWebsocketRequest';
|
||||
import type { DropdownItem } from '../components/core/Dropdown';
|
||||
import { Icon } from '../components/core/Icon';
|
||||
import { generateId } from '../lib/generateId';
|
||||
import { BODY_TYPE_GRAPHQL } from '../lib/model_util';
|
||||
import { getActiveRequest } from './useActiveRequest';
|
||||
import { getActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useCreateGrpcRequest } from './useCreateGrpcRequest';
|
||||
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
||||
|
||||
@@ -19,21 +21,24 @@ export function useCreateDropdownItems({
|
||||
} = {}): DropdownItem[] {
|
||||
const { mutate: createHttpRequest } = useCreateHttpRequest();
|
||||
const { mutate: createGrpcRequest } = useCreateGrpcRequest();
|
||||
const activeWorkspace = getActiveWorkspace();
|
||||
|
||||
return useMemo((): DropdownItem[] => {
|
||||
const items = useMemo((): DropdownItem[] => {
|
||||
const activeRequest = getActiveRequest();
|
||||
const folderId =
|
||||
folderIdOption === 'active-folder' ? getActiveRequest()?.folderId : folderIdOption;
|
||||
(folderIdOption === 'active-folder' ? activeRequest?.folderId : folderIdOption) ?? null;
|
||||
if (activeWorkspace == null) return [];
|
||||
|
||||
return [
|
||||
{
|
||||
label: 'HTTP Request',
|
||||
label: 'HTTP',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () => {
|
||||
createHttpRequest({ folderId });
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'GraphQL Query',
|
||||
label: 'GraphQL',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () =>
|
||||
createHttpRequest({
|
||||
@@ -44,10 +49,16 @@ export function useCreateDropdownItems({
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: 'gRPC Call',
|
||||
label: 'gRPC',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () => createGrpcRequest({ folderId }),
|
||||
},
|
||||
{
|
||||
label: 'WebSocket',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () =>
|
||||
upsertWebsocketRequest.mutate({ folderId, workspaceId: activeWorkspace.id }),
|
||||
},
|
||||
...((hideFolder
|
||||
? []
|
||||
: [
|
||||
@@ -59,5 +70,14 @@ export function useCreateDropdownItems({
|
||||
},
|
||||
]) as DropdownItem[]),
|
||||
];
|
||||
}, [createGrpcRequest, createHttpRequest, folderIdOption, hideFolder, hideIcons]);
|
||||
}, [
|
||||
activeWorkspace,
|
||||
createGrpcRequest,
|
||||
createHttpRequest,
|
||||
folderIdOption,
|
||||
hideFolder,
|
||||
hideIcons,
|
||||
]);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -5,15 +5,11 @@ import { showConfirm } from '../lib/confirm';
|
||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { getGrpcRequest } from './useGrpcRequests';
|
||||
|
||||
export function useDeleteAnyGrpcRequest() {
|
||||
return useFastMutation<GrpcRequest | null, string, string>({
|
||||
return useFastMutation<GrpcRequest | null, string, GrpcRequest>({
|
||||
mutationKey: ['delete_any_grpc_request'],
|
||||
mutationFn: async (id) => {
|
||||
const request = getGrpcRequest(id);
|
||||
if (request == null) return null;
|
||||
|
||||
mutationFn: async (request) => {
|
||||
const confirmed = await showConfirm({
|
||||
id: 'delete-grpc-request',
|
||||
title: 'Delete Request',
|
||||
@@ -24,9 +20,11 @@ export function useDeleteAnyGrpcRequest() {
|
||||
</>
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invokeCmd('cmd_delete_grpc_request', { requestId: id });
|
||||
if (!confirmed) {
|
||||
return null;
|
||||
}
|
||||
return invokeCmd('cmd_delete_grpc_request', { requestId: request.id });
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_request', 'delete'),
|
||||
onSuccess: () => trackEvent('grpc_request', 'delete'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,15 +5,11 @@ import { showConfirm } from '../lib/confirm';
|
||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { getHttpRequest } from './useHttpRequests';
|
||||
|
||||
export function useDeleteAnyHttpRequest() {
|
||||
return useFastMutation<HttpRequest | null, string, string>({
|
||||
return useFastMutation<HttpRequest | null, string, HttpRequest>({
|
||||
mutationKey: ['delete_any_http_request'],
|
||||
mutationFn: async (id) => {
|
||||
const request = getHttpRequest(id);
|
||||
if (request == null) return null;
|
||||
|
||||
mutationFn: async (request) => {
|
||||
const confirmed = await showConfirm({
|
||||
id: 'delete-request',
|
||||
title: 'Delete Request',
|
||||
@@ -24,9 +20,11 @@ export function useDeleteAnyHttpRequest() {
|
||||
</>
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invokeCmd<HttpRequest>('cmd_delete_http_request', { requestId: id });
|
||||
if (!confirmed) {
|
||||
return null;
|
||||
}
|
||||
return invokeCmd<HttpRequest>('cmd_delete_http_request', { requestId: request.id });
|
||||
},
|
||||
onSettled: () => trackEvent('http_request', 'delete'),
|
||||
onSuccess: () => trackEvent('http_request', 'delete'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { deleteWebsocketRequest } from '../commands/deleteWebsocketRequest';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { useDeleteAnyGrpcRequest } from './useDeleteAnyGrpcRequest';
|
||||
import { useDeleteAnyHttpRequest } from './useDeleteAnyHttpRequest';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { requestsAtom } from './useRequests';
|
||||
|
||||
export function useDeleteAnyRequest() {
|
||||
const deleteAnyHttpRequest = useDeleteAnyHttpRequest();
|
||||
@@ -10,9 +13,17 @@ export function useDeleteAnyRequest() {
|
||||
mutationKey: ['delete_request'],
|
||||
mutationFn: async (id) => {
|
||||
if (id == null) return;
|
||||
// We don't know what type it is based on the ID, so just try deleting both
|
||||
deleteAnyHttpRequest.mutate(id);
|
||||
deleteAnyGrpcRequest.mutate(id);
|
||||
const request = jotaiStore.get(requestsAtom).find((r) => r.id === id);
|
||||
|
||||
if (request?.model === 'websocket_request') {
|
||||
deleteWebsocketRequest.mutate(request);
|
||||
} else if (request?.model === 'http_request') {
|
||||
deleteAnyHttpRequest.mutate(request);
|
||||
} else if (request?.model === 'grpc_request') {
|
||||
deleteAnyGrpcRequest.mutate(request);
|
||||
} else {
|
||||
console.log('Failed to delete request', id, request);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,24 +7,29 @@ import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { useGrpcConnections } from './useGrpcConnections';
|
||||
import { httpResponsesAtom, useHttpResponses } from './useHttpResponses';
|
||||
import { useWebsocketConnections } from './useWebsocketConnections';
|
||||
|
||||
export function useDeleteSendHistory() {
|
||||
const setHttpResponses = useSetAtom(httpResponsesAtom);
|
||||
const httpResponses = useHttpResponses();
|
||||
const grpcConnections = useGrpcConnections();
|
||||
const websocketConnections = useWebsocketConnections();
|
||||
const labels = [
|
||||
httpResponses.length > 0 ? pluralizeCount('Http Response', httpResponses.length) : null,
|
||||
grpcConnections.length > 0 ? pluralizeCount('Grpc Connection', grpcConnections.length) : null,
|
||||
websocketConnections.length > 0
|
||||
? pluralizeCount('WebSocket Connection', websocketConnections.length)
|
||||
: null,
|
||||
].filter((l) => l != null);
|
||||
|
||||
return useFastMutation({
|
||||
mutationKey: ['delete_send_history'],
|
||||
mutationKey: ['delete_send_history', labels],
|
||||
mutationFn: async () => {
|
||||
if (labels.length === 0) {
|
||||
showAlert({
|
||||
id: 'no-responses',
|
||||
title: 'Nothing to Delete',
|
||||
body: 'There are no Http Response or Grpc Connections to delete',
|
||||
body: 'There is no Http, Grpc, or Websocket history',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -116,6 +116,16 @@ export function useHotKey(
|
||||
if (e.shiftKey) currentKeysWithModifiers.add('Shift');
|
||||
|
||||
for (const [hkAction, hkKeys] of Object.entries(hotkeys) as [HotkeyAction, string[]][]) {
|
||||
if (
|
||||
(e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) &&
|
||||
currentKeysWithModifiers.size === 1 &&
|
||||
currentKeysWithModifiers.has('Backspace')
|
||||
) {
|
||||
// Don't support Backspace-only modifiers within input fields. This is fairly brittle, so maybe there's a
|
||||
// better way to do stuff like this in the future.
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const hkKey of hkKeys) {
|
||||
if (hkAction !== action) {
|
||||
continue;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
|
||||
import type { GrpcRequest, HttpRequest, WebsocketRequest } from '@yaakapp-internal/models';
|
||||
import type { GetHttpAuthenticationConfigResponse, JsonPrimitive } from '@yaakapp-internal/plugins';
|
||||
import { md5 } from 'js-md5';
|
||||
import { useState } from 'react';
|
||||
@@ -48,7 +48,7 @@ export function useHttpAuthenticationConfig(
|
||||
...config,
|
||||
actions: config.actions?.map((a, i) => ({
|
||||
...a,
|
||||
call: async ({ id: requestId }: HttpRequest | GrpcRequest) => {
|
||||
call: async ({ id: requestId }: HttpRequest | GrpcRequest | WebsocketRequest) => {
|
||||
await invokeCmd('cmd_call_http_authentication_action', {
|
||||
pluginRefId: config.pluginRefId,
|
||||
actionIndex: i,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
import { MoveToWorkspaceDialog } from '../components/MoveToWorkspaceDialog';
|
||||
import { showDialog } from '../lib/dialog';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import { getRequests } from './useRequests';
|
||||
import { requestsAtom } from './useRequests';
|
||||
|
||||
export function useMoveToWorkspace(id: string) {
|
||||
return useFastMutation<void, unknown>({
|
||||
@@ -12,7 +13,7 @@ export function useMoveToWorkspace(id: string) {
|
||||
const activeWorkspaceId = getActiveWorkspaceId();
|
||||
if (activeWorkspaceId == null) return;
|
||||
|
||||
const request = getRequests().find((r) => r.id === id);
|
||||
const request = jotaiStore.get(requestsAtom).find((r) => r.id === id);
|
||||
if (request == null) return;
|
||||
|
||||
showDialog({
|
||||
|
||||
18
src-web/hooks/usePinnedWebsocketConnection.ts
Normal file
18
src-web/hooks/usePinnedWebsocketConnection.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { WebsocketConnection, WebsocketRequest } from '@yaakapp-internal/models';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
import { useLatestWebsocketConnection, useWebsocketConnections } from './useWebsocketConnections';
|
||||
|
||||
export function usePinnedWebsocketConnection(activeRequest: WebsocketRequest) {
|
||||
const latestConnection = useLatestWebsocketConnection(activeRequest.id);
|
||||
const { set: setPinnedConnectionId, value: pinnedConnectionId } = useKeyValue<string | null>({
|
||||
// Key on latest connection instead of activeRequest because connections change out of band of active request
|
||||
key: ['pinned_websocket_connection_id', latestConnection?.id ?? 'n/a'],
|
||||
fallback: null,
|
||||
namespace: 'global',
|
||||
});
|
||||
const connections = useWebsocketConnections().filter((c) => c.requestId === activeRequest.id);
|
||||
const activeConnection: WebsocketConnection | null =
|
||||
connections.find((r) => r.id === pinnedConnectionId) ?? latestConnection;
|
||||
|
||||
return { activeConnection, setPinnedConnectionId, pinnedConnectionId, connections } as const;
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
import { createGlobalState } from 'react-use';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import { generateId } from '../lib/generateId';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
|
||||
const useGlobalState = createGlobalState<Record<string, string>>({});
|
||||
const keyAtom = atom<Record<string, string>>({});
|
||||
|
||||
export function useRequestUpdateKey(requestId: string | null) {
|
||||
const [keys, setKeys] = useGlobalState();
|
||||
const keys = useAtomValue(keyAtom);
|
||||
const key = keys[requestId ?? 'n/a'];
|
||||
return {
|
||||
updateKey: `${requestId}::${key ?? 'default'}`,
|
||||
wasUpdatedExternally: (changedRequestId: string) => {
|
||||
setKeys((m) => ({ ...m, [changedRequestId]: generateId() }));
|
||||
jotaiStore.set(keyAtom, (m) => ({ ...m, [changedRequestId]: generateId() }));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import {jotaiStore} from "../lib/jotai";
|
||||
import { grpcRequestsAtom } from './useGrpcRequests';
|
||||
import { httpRequestsAtom } from './useHttpRequests';
|
||||
import { websocketRequestsAtom } from './useWebsocketRequests';
|
||||
|
||||
const requestsAtom = atom((get) => [...get(httpRequestsAtom), ...get(grpcRequestsAtom)]);
|
||||
export const requestsAtom = atom((get) => [
|
||||
...get(httpRequestsAtom),
|
||||
...get(grpcRequestsAtom),
|
||||
...get(websocketRequestsAtom),
|
||||
]);
|
||||
|
||||
export function useRequests() {
|
||||
return useAtomValue(requestsAtom);
|
||||
}
|
||||
|
||||
export function getRequests() {
|
||||
return jotaiStore.get(requestsAtom);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ import { useListenToTauriEvent } from './useListenToTauriEvent';
|
||||
import { pluginsAtom } from './usePlugins';
|
||||
import { useRequestUpdateKey } from './useRequestUpdateKey';
|
||||
import { settingsAtom } from './useSettings';
|
||||
import { websocketConnectionsAtom } from './useWebsocketConnections';
|
||||
import { websocketEventsQueryKey } from './useWebsocketEvents';
|
||||
import { websocketRequestsAtom } from './useWebsocketRequests';
|
||||
import { workspaceMetaAtom } from './useWorkspaceMeta';
|
||||
import { workspacesAtom } from './useWorkspaces';
|
||||
|
||||
@@ -31,13 +34,17 @@ export function useSyncModelStores() {
|
||||
const queryKey =
|
||||
payload.model.model === 'grpc_event'
|
||||
? grpcEventsQueryKey(payload.model)
|
||||
: payload.model.model === 'key_value'
|
||||
? keyValueQueryKey(payload.model)
|
||||
: null;
|
||||
: payload.model.model === 'websocket_event'
|
||||
? websocketEventsQueryKey(payload.model)
|
||||
: payload.model.model === 'key_value'
|
||||
? keyValueQueryKey(payload.model)
|
||||
: null;
|
||||
|
||||
// TODO: Move this logic to useRequestEditor() hook
|
||||
if (
|
||||
payload.model.model === 'http_request' &&
|
||||
(payload.model.model === 'http_request' ||
|
||||
payload.model.model === 'grpc_request' ||
|
||||
payload.model.model === 'websocket_request') &&
|
||||
(payload.windowLabel !== getCurrentWebviewWindow().label || payload.updateSource !== 'window')
|
||||
) {
|
||||
wasUpdatedExternally(payload.model.id);
|
||||
@@ -64,6 +71,10 @@ export function useSyncModelStores() {
|
||||
jotaiStore.set(httpResponsesAtom, updateModelList(payload.model));
|
||||
} else if (payload.model.model === 'grpc_request') {
|
||||
jotaiStore.set(grpcRequestsAtom, updateModelList(payload.model));
|
||||
} else if (payload.model.model === 'websocket_request') {
|
||||
jotaiStore.set(websocketRequestsAtom, updateModelList(payload.model));
|
||||
} else if (payload.model.model === 'websocket_connection') {
|
||||
jotaiStore.set(websocketConnectionsAtom, updateModelList(payload.model));
|
||||
} else if (payload.model.model === 'grpc_connection') {
|
||||
jotaiStore.set(grpcConnectionsAtom, updateModelList(payload.model));
|
||||
} else if (payload.model.model === 'environment') {
|
||||
@@ -103,6 +114,15 @@ export function useSyncModelStores() {
|
||||
jotaiStore.set(environmentsAtom, removeModelById(payload.model));
|
||||
} else if (payload.model.model === 'grpc_request') {
|
||||
jotaiStore.set(grpcRequestsAtom, removeModelById(payload.model));
|
||||
} else if (payload.model.model === 'websocket_request') {
|
||||
jotaiStore.set(websocketRequestsAtom, removeModelById(payload.model));
|
||||
} else if (payload.model.model === 'websocket_connection') {
|
||||
jotaiStore.set(websocketConnectionsAtom, removeModelById(payload.model));
|
||||
} else if (payload.model.model === 'websocket_event') {
|
||||
queryClient.setQueryData(
|
||||
websocketEventsQueryKey(payload.model),
|
||||
removeModelById(payload.model),
|
||||
);
|
||||
} else if (payload.model.model === 'grpc_connection') {
|
||||
jotaiStore.set(grpcConnectionsAtom, removeModelById(payload.model));
|
||||
} else if (payload.model.model === 'grpc_event') {
|
||||
@@ -117,7 +137,10 @@ export function useSyncModelStores() {
|
||||
|
||||
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';
|
||||
const pushToFront =
|
||||
model.model === 'http_response' ||
|
||||
model.model === 'grpc_connection' ||
|
||||
model.model === 'websocket_connection';
|
||||
|
||||
return (current: T[] | undefined | null): T[] => {
|
||||
const index = current?.findIndex((v) => modelsEq(v, model)) ?? -1;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import {listWebsocketConnections, listWebsocketRequests} from '@yaakapp-internal/ws';
|
||||
import { useEffect } from 'react';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
@@ -10,6 +11,8 @@ import { grpcRequestsAtom } from './useGrpcRequests';
|
||||
import { httpRequestsAtom } from './useHttpRequests';
|
||||
import { httpResponsesAtom } from './useHttpResponses';
|
||||
import { keyValuesAtom } from './useKeyValue';
|
||||
import {websocketConnectionsAtom} from "./useWebsocketConnections";
|
||||
import { websocketRequestsAtom } from './useWebsocketRequests';
|
||||
import { workspaceMetaAtom } from './useWorkspaceMeta';
|
||||
|
||||
export function useSyncWorkspaceChildModels() {
|
||||
@@ -33,11 +36,13 @@ async function sync() {
|
||||
jotaiStore.set(httpRequestsAtom, await invokeCmd('cmd_list_http_requests', args));
|
||||
jotaiStore.set(grpcRequestsAtom, await invokeCmd('cmd_list_grpc_requests', args));
|
||||
jotaiStore.set(foldersAtom, await invokeCmd('cmd_list_folders', args));
|
||||
jotaiStore.set(websocketRequestsAtom, await listWebsocketRequests(args));
|
||||
|
||||
// Then, set the rest
|
||||
jotaiStore.set(cookieJarsAtom, await invokeCmd('cmd_list_cookie_jars', args));
|
||||
jotaiStore.set(httpResponsesAtom, await invokeCmd('cmd_list_http_responses', args));
|
||||
jotaiStore.set(grpcConnectionsAtom, await invokeCmd('cmd_list_grpc_connections', args));
|
||||
jotaiStore.set(websocketConnectionsAtom, await listWebsocketConnections(args));
|
||||
jotaiStore.set(environmentsAtom, await invokeCmd('cmd_list_environments', args));
|
||||
|
||||
// Single models
|
||||
|
||||
17
src-web/hooks/useWebsocketConnections.ts
Normal file
17
src-web/hooks/useWebsocketConnections.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { WebsocketConnection } from '@yaakapp-internal/models';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
|
||||
export const websocketConnectionsAtom = atom<WebsocketConnection[]>([]);
|
||||
|
||||
export function useWebsocketConnections() {
|
||||
return useAtomValue(websocketConnectionsAtom);
|
||||
}
|
||||
|
||||
export function useLatestWebsocketConnection(requestId: string | null): WebsocketConnection | null {
|
||||
return useWebsocketConnections().find((r) => r.requestId === requestId) ?? null;
|
||||
}
|
||||
|
||||
export function getWebsocketConnection(id: string) {
|
||||
return jotaiStore.get(websocketConnectionsAtom).find((r) => r.id === id) ?? null;
|
||||
}
|
||||
21
src-web/hooks/useWebsocketEvents.ts
Normal file
21
src-web/hooks/useWebsocketEvents.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { WebsocketEvent } from '@yaakapp-internal/models';
|
||||
import { listWebsocketEvents } from '@yaakapp-internal/ws';
|
||||
|
||||
export function websocketEventsQueryKey({ connectionId }: { connectionId: string }) {
|
||||
return ['websocket_events', { connectionId }];
|
||||
}
|
||||
|
||||
export function useWebsocketEvents(connectionId: string | null) {
|
||||
return (
|
||||
useQuery<WebsocketEvent[]>({
|
||||
enabled: connectionId !== null,
|
||||
initialData: [],
|
||||
queryKey: websocketEventsQueryKey({ connectionId: connectionId ?? 'n/a' }),
|
||||
queryFn: () => {
|
||||
if (connectionId == null) return [] as WebsocketEvent[];
|
||||
return listWebsocketEvents({ connectionId });
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
}
|
||||
13
src-web/hooks/useWebsocketRequests.ts
Normal file
13
src-web/hooks/useWebsocketRequests.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { WebsocketRequest } from '@yaakapp-internal/models';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
|
||||
export const websocketRequestsAtom = atom<WebsocketRequest[]>([]);
|
||||
|
||||
export function useWebsocketRequests() {
|
||||
return useAtomValue(websocketRequestsAtom);
|
||||
}
|
||||
|
||||
export function getWebsocketRequest(id: string) {
|
||||
return jotaiStore.get(websocketRequestsAtom).find((r) => r.id === id) ?? null;
|
||||
}
|
||||
Reference in New Issue
Block a user