mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-21 00:49:17 +01:00
Start on plugin ctx API (#64)
This commit is contained in:
@@ -4,9 +4,8 @@ import type { KeyboardEvent, ReactNode } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useActiveCookieJar } from '../hooks/useActiveCookieJar';
|
||||
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||
import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||
import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
|
||||
import { useCreateGrpcRequest } from '../hooks/useCreateGrpcRequest';
|
||||
@@ -56,8 +55,8 @@ const MAX_PER_GROUP = 8;
|
||||
export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
const [command, setCommand] = useDebouncedState<string>('', 150);
|
||||
const [selectedItemKey, setSelectedItemKey] = useState<string | null>(null);
|
||||
const [activeEnvironment, setActiveEnvironmentId] = useActiveEnvironment();
|
||||
const routes = useAppRoutes();
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
const workspaces = useWorkspaces();
|
||||
const environments = useEnvironments();
|
||||
const recentEnvironments = useRecentEnvironments();
|
||||
@@ -68,12 +67,11 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
const openWorkspace = useOpenWorkspace();
|
||||
const createWorkspace = useCreateWorkspace();
|
||||
const createHttpRequest = useCreateHttpRequest();
|
||||
const { activeCookieJar } = useActiveCookieJar();
|
||||
const [activeCookieJar] = useActiveCookieJar();
|
||||
const createGrpcRequest = useCreateGrpcRequest();
|
||||
const createEnvironment = useCreateEnvironment();
|
||||
const dialog = useDialog();
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const activeEnvironment = useActiveEnvironment();
|
||||
const workspace = useActiveWorkspace();
|
||||
const sendRequest = useSendAnyHttpRequest();
|
||||
const renameRequest = useRenameRequest(activeRequest?.id ?? null);
|
||||
const deleteRequest = useDeleteRequest(activeRequest?.id ?? null);
|
||||
@@ -86,9 +84,9 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
label: 'Open Settings',
|
||||
action: 'settings.show',
|
||||
onSelect: async () => {
|
||||
if (workspaceId == null) return;
|
||||
if (workspace == null) return;
|
||||
await invokeCmd('cmd_new_nested_window', {
|
||||
url: routes.paths.workspaceSettings({ workspaceId }),
|
||||
url: routes.paths.workspaceSettings({ workspaceId: workspace.id }),
|
||||
label: 'settings',
|
||||
title: 'Yaak Settings',
|
||||
});
|
||||
@@ -190,7 +188,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
routes.paths,
|
||||
sendRequest,
|
||||
setSidebarHidden,
|
||||
workspaceId,
|
||||
workspace,
|
||||
]);
|
||||
|
||||
const sortedRequests = useMemo(() => {
|
||||
@@ -271,7 +269,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
return routes.navigate('request', {
|
||||
workspaceId: r.workspaceId,
|
||||
requestId: r.id,
|
||||
environmentId: activeEnvironmentId ?? undefined,
|
||||
environmentId: activeEnvironment?.id,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -290,7 +288,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
environmentGroup.items.push({
|
||||
key: `switch-environment-${e.id}`,
|
||||
label: e.name,
|
||||
onSelect: () => routes.setEnvironment(e),
|
||||
onSelect: () => setActiveEnvironmentId(e.id),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -313,9 +311,9 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
workspaceCommands,
|
||||
sortedRequests,
|
||||
routes,
|
||||
activeEnvironmentId,
|
||||
activeEnvironment,
|
||||
sortedEnvironments,
|
||||
activeEnvironment?.id,
|
||||
setActiveEnvironmentId,
|
||||
sortedWorkspaces,
|
||||
openWorkspace,
|
||||
]);
|
||||
|
||||
@@ -12,7 +12,7 @@ interface Props {
|
||||
|
||||
export const CookieDialog = function ({ cookieJarId }: Props) {
|
||||
const updateCookieJar = useUpdateCookieJar(cookieJarId ?? null);
|
||||
const cookieJars = useCookieJars();
|
||||
const cookieJars = useCookieJars().data ?? [];
|
||||
const cookieJar = cookieJars.find((c) => c.id === cookieJarId);
|
||||
|
||||
if (cookieJar == null) {
|
||||
|
||||
@@ -12,8 +12,8 @@ import { InlineCode } from './core/InlineCode';
|
||||
import { useDialog } from './DialogContext';
|
||||
|
||||
export function CookieDropdown() {
|
||||
const cookieJars = useCookieJars();
|
||||
const { activeCookieJar, setActiveCookieJarId } = useActiveCookieJar();
|
||||
const cookieJars = useCookieJars().data ?? [];
|
||||
const [activeCookieJar, setActiveCookieJarId] = useActiveCookieJar();
|
||||
const updateCookieJar = useUpdateCookieJar(activeCookieJar?.id ?? null);
|
||||
const deleteCookieJar = useDeleteCookieJar(activeCookieJar ?? null);
|
||||
const createCookieJar = useCreateCookieJar();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import classNames from 'classnames';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||
import { useEnvironments } from '../hooks/useEnvironments';
|
||||
import type { ButtonProps } from './core/Button';
|
||||
import { Button } from './core/Button';
|
||||
@@ -20,9 +19,8 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
|
||||
...buttonProps
|
||||
}: Props) {
|
||||
const environments = useEnvironments();
|
||||
const activeEnvironment = useActiveEnvironment();
|
||||
const [activeEnvironment, setActiveEnvironmentId] = useActiveEnvironment();
|
||||
const dialog = useDialog();
|
||||
const routes = useAppRoutes();
|
||||
|
||||
const showEnvironmentDialog = useCallback(() => {
|
||||
dialog.toggle({
|
||||
@@ -43,9 +41,9 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
|
||||
leftSlot: e.id === activeEnvironment?.id ? <Icon icon="check" /> : <Icon icon="empty" />,
|
||||
onSelect: async () => {
|
||||
if (e.id !== activeEnvironment?.id) {
|
||||
routes.setEnvironment(e);
|
||||
setActiveEnvironmentId(e.id);
|
||||
} else {
|
||||
routes.setEnvironment(null);
|
||||
setActiveEnvironmentId(null);
|
||||
}
|
||||
},
|
||||
}),
|
||||
@@ -62,7 +60,7 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
|
||||
onSelect: showEnvironmentDialog,
|
||||
},
|
||||
],
|
||||
[activeEnvironment?.id, environments, routes, showEnvironmentDialog],
|
||||
[activeEnvironment?.id, environments, setActiveEnvironmentId, showEnvironmentDialog],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,7 +2,8 @@ import { useQueryClient } from '@tanstack/react-query';
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||
import type { Model } from '@yaakapp/api';
|
||||
import { useEffect } from 'react';
|
||||
import { useAtiveWorkspaceChangedToast } from '../hooks/useAtiveWorkspaceChangedToast';
|
||||
import { useEnsureActiveCookieJar, useMigrateActiveCookieJarId } from '../hooks/useActiveCookieJar';
|
||||
import { useActiveWorkspaceChangedToast } from '../hooks/useActiveWorkspaceChangedToast';
|
||||
import { cookieJarsQueryKey } from '../hooks/useCookieJars';
|
||||
import { useCopy } from '../hooks/useCopy';
|
||||
import { environmentsQueryKey } from '../hooks/useEnvironments';
|
||||
@@ -16,6 +17,7 @@ import { httpResponsesQueryKey } from '../hooks/useHttpResponses';
|
||||
import { keyValueQueryKey } from '../hooks/useKeyValue';
|
||||
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
||||
import { useNotificationToast } from '../hooks/useNotificationToast';
|
||||
import { useRecentCookieJars } from '../hooks/useRecentCookieJars';
|
||||
import { useRecentEnvironments } from '../hooks/useRecentEnvironments';
|
||||
import { useRecentRequests } from '../hooks/useRecentRequests';
|
||||
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
||||
@@ -25,6 +27,7 @@ import { useSyncThemeToDocument } from '../hooks/useSyncThemeToDocument';
|
||||
import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
|
||||
import { workspacesQueryKey } from '../hooks/useWorkspaces';
|
||||
import { useZoom } from '../hooks/useZoom';
|
||||
import { extractKeyValue } from '../lib/keyValueStore';
|
||||
import { modelsEq } from '../lib/models';
|
||||
import { catppuccinMacchiato } from '../lib/theme/themes/catppuccin';
|
||||
import { githubLight } from '../lib/theme/themes/github';
|
||||
@@ -38,12 +41,17 @@ export function GlobalHooks() {
|
||||
// Include here so they always update, even if no component references them
|
||||
useRecentWorkspaces();
|
||||
useRecentEnvironments();
|
||||
useRecentCookieJars();
|
||||
useRecentRequests();
|
||||
|
||||
// Other useful things
|
||||
useSyncThemeToDocument();
|
||||
useNotificationToast();
|
||||
useAtiveWorkspaceChangedToast();
|
||||
useActiveWorkspaceChangedToast();
|
||||
useEnsureActiveCookieJar();
|
||||
|
||||
// TODO: Remove in future version
|
||||
useMigrateActiveCookieJarId();
|
||||
|
||||
const toggleCommandPalette = useToggleCommandPalette();
|
||||
useHotKey('command_palette.toggle', toggleCommandPalette);
|
||||
@@ -96,21 +104,28 @@ export function GlobalHooks() {
|
||||
model.model,
|
||||
);
|
||||
|
||||
if (shouldIgnoreModel(model)) return;
|
||||
if (shouldIgnoreModel(model, windowLabel)) return;
|
||||
|
||||
queryClient.setQueryData<Model[]>(queryKey, (values = []) => {
|
||||
const index = values.findIndex((v) => modelsEq(v, model)) ?? -1;
|
||||
if (index >= 0) {
|
||||
return [...values.slice(0, index), model, ...values.slice(index + 1)];
|
||||
} else {
|
||||
return pushToFront ? [model, ...(values ?? [])] : [...(values ?? []), model];
|
||||
queryClient.setQueryData(queryKey, (current: unknown) => {
|
||||
if (model.model === 'key_value') {
|
||||
// Special-case for KeyValue
|
||||
return extractKeyValue(model);
|
||||
}
|
||||
|
||||
if (Array.isArray(current)) {
|
||||
const index = current.findIndex((v) => modelsEq(v, model)) ?? -1;
|
||||
if (index >= 0) {
|
||||
return [...current.slice(0, index), model, ...current.slice(index + 1)];
|
||||
} else {
|
||||
return pushToFront ? [model, ...(current ?? [])] : [...(current ?? []), model];
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
useListenToTauriEvent<ModelPayload>('deleted_model', ({ payload }) => {
|
||||
const { model } = payload;
|
||||
if (shouldIgnoreModel(model)) return;
|
||||
const { model, windowLabel } = payload;
|
||||
if (shouldIgnoreModel(model, windowLabel)) return;
|
||||
|
||||
if (model.model === 'workspace') {
|
||||
queryClient.setQueryData(workspacesQueryKey(), removeById(model));
|
||||
@@ -181,7 +196,11 @@ function removeById<T extends { id: string }>(model: T) {
|
||||
return (entries: T[] | undefined) => entries?.filter((e) => e.id !== model.id);
|
||||
}
|
||||
|
||||
const shouldIgnoreModel = (payload: Model) => {
|
||||
const shouldIgnoreModel = (payload: Model, windowLabel: string) => {
|
||||
if (windowLabel === getCurrentWebviewWindow().label) {
|
||||
// Never ignore same-window updates
|
||||
return false;
|
||||
}
|
||||
if (payload.model === 'key_value') {
|
||||
return payload.namespace === 'no_sync';
|
||||
}
|
||||
|
||||
@@ -52,12 +52,12 @@ export function MoveToWorkspaceDialog({ onDone, request, activeWorkspaceId }: Pr
|
||||
|
||||
if (request.model === 'http_request') {
|
||||
await updateHttpRequest.mutateAsync(args);
|
||||
queryClient.invalidateQueries({
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: httpRequestsQueryKey({ workspaceId: activeWorkspaceId }),
|
||||
});
|
||||
} else if (request.model === 'grpc_request') {
|
||||
await updateGrpcRequest.mutateAsync(args);
|
||||
queryClient.invalidateQueries({
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: grpcRequestsQueryKey({ workspaceId: activeWorkspaceId }),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useMemo, useRef } from 'react';
|
||||
import { useKeyPressEvent } from 'react-use';
|
||||
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||
import { useHotKey } from '../hooks/useHotKey';
|
||||
import { useRecentRequests } from '../hooks/useRecentRequests';
|
||||
@@ -18,8 +18,8 @@ import { HttpMethodTag } from './core/HttpMethodTag';
|
||||
export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'className'>) {
|
||||
const dropdownRef = useRef<DropdownRef>(null);
|
||||
const activeRequest = useActiveRequest();
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeEnvironment = useActiveEnvironment();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const [activeEnvironment] = useActiveEnvironment();
|
||||
const routes = useAppRoutes();
|
||||
const allRecentRequestIds = useRecentRequests();
|
||||
const recentRequestIds = useMemo(() => allRecentRequestIds.slice(1), [allRecentRequestIds]);
|
||||
@@ -42,7 +42,7 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
|
||||
});
|
||||
|
||||
const items = useMemo<DropdownItem[]>(() => {
|
||||
if (activeWorkspaceId === null) return [];
|
||||
if (activeWorkspace === null) return [];
|
||||
|
||||
const recentRequestItems: DropdownItem[] = [];
|
||||
for (const id of recentRequestIds) {
|
||||
@@ -58,7 +58,7 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
|
||||
routes.navigate('request', {
|
||||
requestId: request.id,
|
||||
environmentId: activeEnvironment?.id,
|
||||
workspaceId: activeWorkspaceId,
|
||||
workspaceId: activeWorkspace.id,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -76,7 +76,7 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
|
||||
}
|
||||
|
||||
return recentRequestItems.slice(0, 20);
|
||||
}, [activeWorkspaceId, activeEnvironment?.id, recentRequestIds, requests, routes]);
|
||||
}, [activeWorkspace, activeEnvironment?.id, recentRequestIds, requests, routes]);
|
||||
|
||||
return (
|
||||
<Dropdown ref={dropdownRef} items={items}>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { open } from '@tauri-apps/plugin-shell';
|
||||
import { useRef } from 'react';
|
||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
import { useAppInfo } from '../hooks/useAppInfo';
|
||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||
import { useCheckForUpdates } from '../hooks/useCheckForUpdates';
|
||||
@@ -23,12 +23,12 @@ export function SettingsDropdown() {
|
||||
const dialog = useDialog();
|
||||
const checkForUpdates = useCheckForUpdates();
|
||||
const routes = useAppRoutes();
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const workspace = useActiveWorkspace();
|
||||
|
||||
const showSettings = async () => {
|
||||
if (!workspaceId) return;
|
||||
if (!workspace) return;
|
||||
await invokeCmd('cmd_new_nested_window', {
|
||||
url: routes.paths.workspaceSettings({ workspaceId }),
|
||||
url: routes.paths.workspaceSettings({ workspaceId: workspace.id }),
|
||||
label: 'settings',
|
||||
title: 'Yaak Settings',
|
||||
});
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import type { Folder, GrpcRequest, HttpRequest, Workspace } from '@yaakapp/api';
|
||||
import classNames from 'classnames';
|
||||
import type { ReactNode } from 'react';
|
||||
import React, { Fragment, useCallback, useMemo, useRef, useState } from 'react';
|
||||
import type { XYCoord } from 'react-dnd';
|
||||
import { useDrag, useDrop } from 'react-dnd';
|
||||
import { useKey, useKeyPressEvent } from 'react-use';
|
||||
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||
|
||||
import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||
@@ -32,7 +33,6 @@ import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
||||
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||
import type { Folder, GrpcRequest, HttpRequest, Workspace } from '@yaakapp/api';
|
||||
import { isResponseLoading } from '../lib/models';
|
||||
import type { DropdownItem } from './core/Dropdown';
|
||||
import { ContextMenu } from './core/Dropdown';
|
||||
@@ -61,7 +61,7 @@ export function Sidebar({ className }: Props) {
|
||||
const [hidden, setHidden] = useSidebarHidden();
|
||||
const sidebarRef = useRef<HTMLLIElement>(null);
|
||||
const activeRequest = useActiveRequest();
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
const [activeEnvironment] = useActiveEnvironment();
|
||||
const folders = useFolders();
|
||||
const requests = useRequests();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
@@ -207,14 +207,14 @@ export function Sidebar({ className }: Props) {
|
||||
routes.navigate('request', {
|
||||
requestId: id,
|
||||
workspaceId: item.workspaceId,
|
||||
environmentId: activeEnvironmentId ?? undefined,
|
||||
environmentId: activeEnvironment?.id,
|
||||
});
|
||||
setSelectedId(id);
|
||||
setSelectedTree(tree);
|
||||
if (!opts.noFocus) focusActiveRequest({ forced: { id, tree } });
|
||||
}
|
||||
},
|
||||
[treeParentMap, collapsed, routes, activeEnvironmentId, focusActiveRequest],
|
||||
[treeParentMap, collapsed, routes, activeEnvironment, focusActiveRequest],
|
||||
);
|
||||
|
||||
const handleClearSelected = useCallback(() => {
|
||||
@@ -260,7 +260,7 @@ export function Sidebar({ className }: Props) {
|
||||
routes.navigate('request', {
|
||||
requestId: selected.id,
|
||||
workspaceId: activeWorkspace?.id,
|
||||
environmentId: activeEnvironmentId ?? undefined,
|
||||
environmentId: activeEnvironment?.id,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useWindowSize } from 'react-use';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
||||
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
|
||||
import { useImportData } from '../hooks/useImportData';
|
||||
import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar';
|
||||
@@ -16,7 +15,6 @@ import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||
import { Banner } from './core/Banner';
|
||||
import { Button } from './core/Button';
|
||||
import { HotKeyList } from './core/HotKeyList';
|
||||
import { InlineCode } from './core/InlineCode';
|
||||
import { FeedbackLink } from './core/Link';
|
||||
import { HStack } from './core/Stacks';
|
||||
import { CreateDropdown } from './CreateDropdown';
|
||||
@@ -38,7 +36,6 @@ export default function Workspace() {
|
||||
useSyncWorkspaceRequestTitle();
|
||||
const workspaces = useWorkspaces();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const { setWidth, width, resetWidth } = useSidebarWidth();
|
||||
const [sidebarHidden, setSidebarHidden] = useSidebarHidden();
|
||||
const [floatingSidebarHidden, setFloatingSidebarHidden] = useFloatingSidebarHidden();
|
||||
@@ -176,9 +173,8 @@ export default function Workspace() {
|
||||
{activeWorkspace == null ? (
|
||||
<div className="m-auto">
|
||||
<Banner color="warning" className="max-w-[30rem]">
|
||||
The active workspace{' '}
|
||||
<InlineCode className="text-warning">{activeWorkspaceId}</InlineCode> was not found.
|
||||
Select a workspace from the header menu or report this bug to <FeedbackLink />
|
||||
The active workspace was not found. Select a workspace from the header menu or report
|
||||
this bug to <FeedbackLink />
|
||||
</Banner>
|
||||
</div>
|
||||
) : activeRequest == null ? (
|
||||
|
||||
@@ -87,7 +87,7 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
||||
ref,
|
||||
) {
|
||||
const s = useSettings();
|
||||
const e = useActiveEnvironment();
|
||||
const [e] = useActiveEnvironment();
|
||||
const w = useActiveWorkspace();
|
||||
const environment = autocompleteVariables ? e : null;
|
||||
const workspace = autocompleteVariables ? w : null;
|
||||
|
||||
@@ -9,7 +9,6 @@ class PlaceholderWidget extends WidgetType {
|
||||
readonly exists: boolean,
|
||||
readonly type: 'function' | 'variable' = 'variable',
|
||||
) {
|
||||
console.log('PLACEHOLDER', { name, value });
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import classNames from 'classnames';
|
||||
import type { CSSProperties, MouseEvent as ReactMouseEvent, ReactNode } from 'react';
|
||||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useLocalStorage } from 'react-use';
|
||||
import { useActiveWorkspaceId } from '../../hooks/useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from '../../hooks/useActiveWorkspace';
|
||||
import { clamp } from '../../lib/clamp';
|
||||
import { ResizeHandle } from '../ResizeHandle';
|
||||
|
||||
@@ -42,10 +42,13 @@ export function SplitLayout({
|
||||
minWidthPx = 10,
|
||||
}: Props) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const [verticalBasedOnSize, setVerticalBasedOnSize] = useState<boolean>(false);
|
||||
const [widthRaw, setWidth] = useLocalStorage<number>(`${name}_width::${useActiveWorkspaceId()}`);
|
||||
const [widthRaw, setWidth] = useLocalStorage<number>(
|
||||
`${name}_width::${activeWorkspace?.id ?? 'n/a'}`,
|
||||
);
|
||||
const [heightRaw, setHeight] = useLocalStorage<number>(
|
||||
`${name}_height::${useActiveWorkspaceId()}`,
|
||||
`${name}_height::${activeWorkspace?.id ?? 'n/a'}`,
|
||||
);
|
||||
const width = widthRaw ?? defaultRatio;
|
||||
let height = heightRaw ?? defaultRatio;
|
||||
|
||||
@@ -1,36 +1,87 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useCookieJars } from './useCookieJars';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
|
||||
export const QUERY_COOKIE_JAR_ID = 'cookie_jar_id';
|
||||
|
||||
export function useActiveCookieJar() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const [activeCookieJarId, setActiveCookieJarId] = useActiveCookieJarId();
|
||||
const cookieJars = useCookieJars();
|
||||
|
||||
const activeCookieJar = useMemo(() => {
|
||||
if (cookieJars.data == null) return undefined;
|
||||
return cookieJars.data.find((cookieJar) => cookieJar.id === activeCookieJarId) ?? null;
|
||||
}, [activeCookieJarId, cookieJars.data]);
|
||||
|
||||
return [activeCookieJar ?? null, setActiveCookieJarId] as const;
|
||||
}
|
||||
|
||||
export function useEnsureActiveCookieJar() {
|
||||
const cookieJars = useCookieJars();
|
||||
const [activeCookieJarId, setActiveCookieJarId] = useActiveCookieJarId();
|
||||
useEffect(() => {
|
||||
if (cookieJars.data == null) return;
|
||||
|
||||
if (cookieJars.data.find((j) => j.id === activeCookieJarId)) {
|
||||
return; // There's an active jar
|
||||
}
|
||||
|
||||
const firstJar = cookieJars.data[0];
|
||||
if (firstJar == null) {
|
||||
console.log("Workspace doesn't have any cookie jars to activate");
|
||||
return;
|
||||
}
|
||||
|
||||
// There's no active jar, so set it to the first one
|
||||
console.log('Setting active cookie jar to', firstJar.id);
|
||||
setActiveCookieJarId(firstJar.id);
|
||||
}, [activeCookieJarId, cookieJars, cookieJars.data, setActiveCookieJarId]);
|
||||
}
|
||||
|
||||
export function useMigrateActiveCookieJarId() {
|
||||
const workspace = useActiveWorkspace();
|
||||
const [, setActiveCookieJarId] = useActiveCookieJarId();
|
||||
const {
|
||||
set: setActiveCookieJarId,
|
||||
value: activeCookieJarId,
|
||||
isLoading: isLoadingActiveCookieJarId,
|
||||
set: setLegacyActiveCookieJarId,
|
||||
value: legacyActiveCookieJarId,
|
||||
isLoading: isLoadingLegacyActiveCookieJarId,
|
||||
} = useKeyValue<string | null>({
|
||||
namespace: 'global',
|
||||
key: ['activeCookieJar', workspaceId ?? 'n/a'],
|
||||
key: ['activeCookieJar', workspace?.id ?? 'n/a'],
|
||||
fallback: null,
|
||||
});
|
||||
|
||||
const activeCookieJar = useMemo(
|
||||
() => cookieJars.find((cookieJar) => cookieJar.id === activeCookieJarId),
|
||||
[activeCookieJarId, cookieJars],
|
||||
useEffect(() => {
|
||||
if (legacyActiveCookieJarId == null || isLoadingLegacyActiveCookieJarId) return;
|
||||
|
||||
console.log('Migrating active cookie jar ID to query param', legacyActiveCookieJarId);
|
||||
setActiveCookieJarId(legacyActiveCookieJarId);
|
||||
setLegacyActiveCookieJarId(null).catch(console.error);
|
||||
}, [
|
||||
workspace,
|
||||
isLoadingLegacyActiveCookieJarId,
|
||||
legacyActiveCookieJarId,
|
||||
setActiveCookieJarId,
|
||||
setLegacyActiveCookieJarId,
|
||||
]);
|
||||
}
|
||||
|
||||
function useActiveCookieJarId() {
|
||||
// NOTE: This query param is accessed from Rust side, so do not change
|
||||
const [params, setParams] = useSearchParams();
|
||||
const id = params.get(QUERY_COOKIE_JAR_ID);
|
||||
|
||||
const setId = useCallback(
|
||||
(id: string) => {
|
||||
setParams((p) => {
|
||||
const existing = Object.fromEntries(p);
|
||||
return { ...existing, [QUERY_COOKIE_JAR_ID]: id };
|
||||
});
|
||||
},
|
||||
[setParams],
|
||||
);
|
||||
|
||||
// TODO: Make this not be called so many times (move to GlobalHooks?)
|
||||
useEffect(() => {
|
||||
if (!isLoadingActiveCookieJarId && activeCookieJar == null && cookieJars.length > 0) {
|
||||
setActiveCookieJarId(cookieJars[0]?.id ?? null).catch(console.error);
|
||||
}
|
||||
}, [activeCookieJar, cookieJars, isLoadingActiveCookieJarId, setActiveCookieJarId]);
|
||||
|
||||
return {
|
||||
activeCookieJar: activeCookieJar ?? null,
|
||||
setActiveCookieJarId: setActiveCookieJarId,
|
||||
};
|
||||
return [id, setId] as const;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,38 @@
|
||||
import { useMemo } from 'react';
|
||||
import type { Environment } from '@yaakapp/api';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { useEnvironments } from './useEnvironments';
|
||||
|
||||
export function useActiveEnvironment(): Environment | null {
|
||||
const id = useActiveEnvironmentId();
|
||||
export function useActiveEnvironment() {
|
||||
const [id, setId] = useActiveEnvironmentId();
|
||||
const environments = useEnvironments();
|
||||
return useMemo(() => environments.find((w) => w.id === id) ?? null, [environments, id]);
|
||||
const environment = useMemo(
|
||||
() => environments.find((w) => w.id === id) ?? null,
|
||||
[environments, id],
|
||||
);
|
||||
return [environment, setId] as const;
|
||||
}
|
||||
|
||||
export const QUERY_ENVIRONMENT_ID = 'environment_id';
|
||||
|
||||
export function useActiveEnvironmentId() {
|
||||
// NOTE: This query param is accessed from Rust side, so do not change
|
||||
const [params, setParams] = useSearchParams();
|
||||
const id = params.get(QUERY_ENVIRONMENT_ID);
|
||||
|
||||
const setId = useCallback(
|
||||
(id: string | null) => {
|
||||
setParams((p) => {
|
||||
const existing = Object.fromEntries(p);
|
||||
if (id == null) {
|
||||
delete existing[QUERY_ENVIRONMENT_ID];
|
||||
} else {
|
||||
existing[QUERY_ENVIRONMENT_ID] = id;
|
||||
}
|
||||
return existing;
|
||||
});
|
||||
},
|
||||
[setParams],
|
||||
);
|
||||
|
||||
return [id, setId] as const;
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
export const QUERY_ENVIRONMENT_ID = 'environment_id';
|
||||
|
||||
export function useActiveEnvironmentId(): string | null {
|
||||
const [params] = useSearchParams();
|
||||
const environmentId = params.get(QUERY_ENVIRONMENT_ID);
|
||||
if (environmentId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return environmentId;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useMemo } from 'react';
|
||||
import type { Workspace } from '@yaakapp/api';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import type { RouteParamsWorkspace } from './useAppRoutes';
|
||||
import { useWorkspaces } from './useWorkspaces';
|
||||
|
||||
export function useActiveWorkspace(): Workspace | null {
|
||||
@@ -11,3 +12,8 @@ export function useActiveWorkspace(): Workspace | null {
|
||||
[workspaces, workspaceId],
|
||||
);
|
||||
}
|
||||
|
||||
function useActiveWorkspaceId(): string | null {
|
||||
const { workspaceId } = useParams<RouteParamsWorkspace>();
|
||||
return workspaceId ?? null;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { InlineCode } from '../components/core/InlineCode';
|
||||
import { useToast } from '../components/ToastContext';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
|
||||
export function useAtiveWorkspaceChangedToast() {
|
||||
export function useActiveWorkspaceChangedToast() {
|
||||
const toast = useToast();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const [id, setId] = useState<string | null>(activeWorkspace?.id ?? null);
|
||||
@@ -1,7 +0,0 @@
|
||||
import { useParams } from 'react-router-dom';
|
||||
import type { RouteParamsWorkspace } from './useAppRoutes';
|
||||
|
||||
export function useActiveWorkspaceId(): string | null {
|
||||
const { workspaceId } = useParams<RouteParamsWorkspace>();
|
||||
return workspaceId ?? null;
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
import type { Environment } from '@yaakapp/api';
|
||||
import { useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import type { Environment } from '@yaakapp/api';
|
||||
import { QUERY_ENVIRONMENT_ID } from './useActiveEnvironmentId';
|
||||
import { QUERY_COOKIE_JAR_ID } from './useActiveCookieJar';
|
||||
import { QUERY_ENVIRONMENT_ID } from './useActiveEnvironment';
|
||||
import { useActiveRequestId } from './useActiveRequestId';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
|
||||
export type RouteParamsWorkspace = {
|
||||
workspaceId: string;
|
||||
environmentId?: string;
|
||||
cookieJarId?: string;
|
||||
};
|
||||
|
||||
export type RouteParamsRequest = RouteParamsWorkspace & {
|
||||
@@ -22,34 +24,35 @@ export const routePaths = {
|
||||
return `/workspaces/${workspaceId}/settings`;
|
||||
},
|
||||
workspace(
|
||||
{ workspaceId, environmentId } = {
|
||||
{ workspaceId, environmentId, cookieJarId } = {
|
||||
workspaceId: ':workspaceId',
|
||||
environmentId: ':environmentId',
|
||||
cookieJarId: ':cookieJarId',
|
||||
} as RouteParamsWorkspace,
|
||||
) {
|
||||
let path = `/workspaces/${workspaceId}`;
|
||||
if (environmentId != null) {
|
||||
path += `?${QUERY_ENVIRONMENT_ID}=${encodeURIComponent(environmentId)}`;
|
||||
}
|
||||
return path;
|
||||
const path = `/workspaces/${workspaceId}`;
|
||||
const params = new URLSearchParams();
|
||||
if (environmentId != null) params.set(QUERY_ENVIRONMENT_ID, environmentId);
|
||||
if (cookieJarId != null) params.set(QUERY_COOKIE_JAR_ID, cookieJarId);
|
||||
return `${path}?${params}`;
|
||||
},
|
||||
request(
|
||||
{ workspaceId, environmentId, requestId } = {
|
||||
{ workspaceId, environmentId, requestId, cookieJarId } = {
|
||||
workspaceId: ':workspaceId',
|
||||
environmentId: ':environmentId',
|
||||
requestId: ':requestId',
|
||||
} as RouteParamsRequest,
|
||||
) {
|
||||
let path = `/workspaces/${workspaceId}/requests/${requestId}`;
|
||||
if (environmentId != null) {
|
||||
path += `?${QUERY_ENVIRONMENT_ID}=${encodeURIComponent(environmentId)}`;
|
||||
}
|
||||
return path;
|
||||
const path = `/workspaces/${workspaceId}/requests/${requestId}`;
|
||||
const params = new URLSearchParams();
|
||||
if (environmentId != null) params.set(QUERY_ENVIRONMENT_ID, environmentId);
|
||||
if (cookieJarId != null) params.set(QUERY_COOKIE_JAR_ID, cookieJarId);
|
||||
return `${path}?${params}`;
|
||||
},
|
||||
};
|
||||
|
||||
export function useAppRoutes() {
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const requestId = useActiveRequestId();
|
||||
const nav = useNavigate();
|
||||
|
||||
@@ -66,22 +69,22 @@ export function useAppRoutes() {
|
||||
|
||||
const setEnvironment = useCallback(
|
||||
(environment: Environment | null) => {
|
||||
if (activeWorkspaceId == null) {
|
||||
if (activeWorkspace == null) {
|
||||
navigate('workspaces');
|
||||
} else if (requestId == null) {
|
||||
navigate('workspace', {
|
||||
workspaceId: activeWorkspaceId,
|
||||
workspaceId: activeWorkspace.id,
|
||||
environmentId: environment == null ? undefined : environment.id,
|
||||
});
|
||||
} else {
|
||||
navigate('request', {
|
||||
workspaceId: activeWorkspaceId,
|
||||
workspaceId: activeWorkspace.id,
|
||||
environmentId: environment == null ? undefined : environment.id,
|
||||
requestId,
|
||||
});
|
||||
}
|
||||
},
|
||||
[navigate, activeWorkspaceId, requestId],
|
||||
[navigate, activeWorkspace, requestId],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { CookieJar } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
|
||||
export function cookieJarsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
return ['cookie_jars', { workspaceId }];
|
||||
}
|
||||
|
||||
export function useCookieJars() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
return (
|
||||
useQuery({
|
||||
enabled: workspaceId != null,
|
||||
queryKey: cookieJarsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invokeCmd('cmd_list_cookie_jars', { workspaceId })) as CookieJar[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
const workspace = useActiveWorkspace();
|
||||
return useQuery({
|
||||
enabled: workspace != null,
|
||||
queryKey: cookieJarsQueryKey({ workspaceId: workspace?.id ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspace == null) return [];
|
||||
return (await invokeCmd('cmd_list_cookie_jars', {
|
||||
workspaceId: workspace.id,
|
||||
})) as CookieJar[];
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useCopy } from './useCopy';
|
||||
|
||||
export function useCopyAsCurl(requestId: string) {
|
||||
const copy = useCopy();
|
||||
const environmentId = useActiveEnvironmentId();
|
||||
const [environment] = useActiveEnvironment();
|
||||
return useMutation({
|
||||
mutationKey: ['copy_as_curl', requestId],
|
||||
mutationFn: async () => {
|
||||
const cmd: string = await invokeCmd('cmd_request_to_curl', { requestId, environmentId });
|
||||
const cmd: string = await invokeCmd('cmd_request_to_curl', {
|
||||
requestId,
|
||||
environmentId: environment?.id,
|
||||
});
|
||||
copy(cmd);
|
||||
return cmd;
|
||||
},
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { CookieJar } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { cookieJarsQueryKey } from './useCookieJars';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { usePrompt } from './usePrompt';
|
||||
|
||||
export function useCreateCookieJar() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const queryClient = useQueryClient();
|
||||
const workspace = useActiveWorkspace();
|
||||
const prompt = usePrompt();
|
||||
|
||||
return useMutation<CookieJar>({
|
||||
mutationKey: ['create_cookie_jar'],
|
||||
mutationFn: async () => {
|
||||
if (workspaceId === null) {
|
||||
if (workspace === null) {
|
||||
throw new Error("Cannot create cookie jar when there's no active workspace");
|
||||
}
|
||||
const name = await prompt({
|
||||
@@ -25,14 +23,8 @@ export function useCreateCookieJar() {
|
||||
label: 'Name',
|
||||
defaultValue: 'My Jar',
|
||||
});
|
||||
return invokeCmd('cmd_create_cookie_jar', { workspaceId, name });
|
||||
return invokeCmd('cmd_create_cookie_jar', { workspaceId: workspace.id, name });
|
||||
},
|
||||
onSettled: () => trackEvent('cookie_jar', 'create'),
|
||||
onSuccess: async (cookieJar) => {
|
||||
queryClient.setQueryData<CookieJar[]>(
|
||||
cookieJarsQueryKey({ workspaceId: cookieJar.workspaceId }),
|
||||
(items) => [...(items ?? []), cookieJar],
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { Environment } from '@yaakapp/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { environmentsQueryKey } from './useEnvironments';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { usePrompt } from './usePrompt';
|
||||
|
||||
export function useCreateEnvironment() {
|
||||
const routes = useAppRoutes();
|
||||
const [, setActiveEnvironmentId] = useActiveEnvironment();
|
||||
const prompt = usePrompt();
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const queryClient = useQueryClient();
|
||||
const workspace = useActiveWorkspace();
|
||||
|
||||
return useMutation<Environment, unknown, void>({
|
||||
mutationKey: ['create_environment'],
|
||||
@@ -25,16 +23,16 @@ export function useCreateEnvironment() {
|
||||
placeholder: 'My Environment',
|
||||
defaultValue: 'My Environment',
|
||||
});
|
||||
return invokeCmd('cmd_create_environment', { name, variables: [], workspaceId });
|
||||
return invokeCmd('cmd_create_environment', {
|
||||
name,
|
||||
variables: [],
|
||||
workspaceId: workspace?.id,
|
||||
});
|
||||
},
|
||||
onSettled: () => trackEvent('environment', 'create'),
|
||||
onSuccess: async (environment) => {
|
||||
if (workspaceId == null) return;
|
||||
routes.setEnvironment(environment);
|
||||
queryClient.setQueryData<Environment[]>(
|
||||
environmentsQueryKey({ workspaceId }),
|
||||
(environments) => [...(environments ?? []), environment],
|
||||
);
|
||||
if (workspace == null) return;
|
||||
setActiveEnvironmentId(environment.id);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { Folder } from '@yaakapp/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveRequest } from './useActiveRequest';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { foldersQueryKey } from './useFolders';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { usePrompt } from './usePrompt';
|
||||
|
||||
export function useCreateFolder() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const workspace = useActiveWorkspace();
|
||||
const activeRequest = useActiveRequest();
|
||||
const queryClient = useQueryClient();
|
||||
const prompt = usePrompt();
|
||||
|
||||
return useMutation<Folder, unknown, Partial<Pick<Folder, 'name' | 'sortPriority' | 'folderId'>>>({
|
||||
mutationKey: ['create_folder'],
|
||||
mutationFn: async (patch) => {
|
||||
if (workspaceId === null) {
|
||||
if (workspace === null) {
|
||||
throw new Error("Cannot create folder when there's no active workspace");
|
||||
}
|
||||
patch.name =
|
||||
@@ -32,13 +30,8 @@ export function useCreateFolder() {
|
||||
}));
|
||||
patch.sortPriority = patch.sortPriority || -Date.now();
|
||||
patch.folderId = patch.folderId || activeRequest?.folderId;
|
||||
return invokeCmd('cmd_create_folder', { workspaceId, ...patch });
|
||||
return invokeCmd('cmd_create_folder', { workspaceId: workspace.id, ...patch });
|
||||
},
|
||||
onSettled: () => trackEvent('folder', 'create'),
|
||||
onSuccess: async (request) => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: foldersQueryKey({ workspaceId: request.workspaceId }),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { GrpcRequest } from '@yaakapp/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useActiveRequest } from './useActiveRequest';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
|
||||
export function useCreateGrpcRequest() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
const workspace = useActiveWorkspace();
|
||||
const [activeEnvironment] = useActiveEnvironment();
|
||||
const activeRequest = useActiveRequest();
|
||||
const routes = useAppRoutes();
|
||||
|
||||
@@ -20,12 +20,12 @@ export function useCreateGrpcRequest() {
|
||||
>({
|
||||
mutationKey: ['create_grpc_request'],
|
||||
mutationFn: (patch) => {
|
||||
if (workspaceId === null) {
|
||||
if (workspace === 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
|
||||
// Place above currently active request
|
||||
patch.sortPriority = activeRequest.sortPriority + 0.0001;
|
||||
} else {
|
||||
// Place at the very top
|
||||
@@ -33,14 +33,18 @@ export function useCreateGrpcRequest() {
|
||||
}
|
||||
}
|
||||
patch.folderId = patch.folderId || activeRequest?.folderId;
|
||||
return invokeCmd('cmd_create_grpc_request', { workspaceId, name: '', ...patch });
|
||||
return invokeCmd('cmd_create_grpc_request', {
|
||||
workspaceId: workspace.id,
|
||||
name: '',
|
||||
...patch,
|
||||
});
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_request', 'create'),
|
||||
onSuccess: async (request) => {
|
||||
routes.navigate('request', {
|
||||
workspaceId: request.workspaceId,
|
||||
requestId: request.id,
|
||||
environmentId: activeEnvironmentId ?? undefined,
|
||||
environmentId: activeEnvironment?.id,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { HttpRequest } from '@yaakapp/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useActiveRequest } from './useActiveRequest';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
|
||||
export function useCreateHttpRequest() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
const workspace = useActiveWorkspace();
|
||||
const [activeEnvironment] = useActiveEnvironment();
|
||||
const activeRequest = useActiveRequest();
|
||||
const routes = useAppRoutes();
|
||||
|
||||
return useMutation<HttpRequest, unknown, Partial<HttpRequest>>({
|
||||
mutationKey: ['create_http_request'],
|
||||
mutationFn: (patch = {}) => {
|
||||
if (workspaceId === null) {
|
||||
if (workspace === null) {
|
||||
throw new Error("Cannot create request when there's no active workspace");
|
||||
}
|
||||
if (patch.sortPriority === undefined) {
|
||||
@@ -29,14 +29,16 @@ export function useCreateHttpRequest() {
|
||||
}
|
||||
}
|
||||
patch.folderId = patch.folderId || activeRequest?.folderId;
|
||||
return invokeCmd('cmd_create_http_request', { request: { workspaceId, ...patch } });
|
||||
return invokeCmd('cmd_create_http_request', {
|
||||
request: { workspaceId: workspace.id, ...patch },
|
||||
});
|
||||
},
|
||||
onSettled: () => trackEvent('http_request', 'create'),
|
||||
onSuccess: async (request) => {
|
||||
routes.navigate('request', {
|
||||
workspaceId: request.workspaceId,
|
||||
requestId: request.id,
|
||||
environmentId: activeEnvironmentId ?? undefined,
|
||||
environmentId: activeEnvironment?.id,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { GrpcRequest } from '@yaakapp/api';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||
import type { GrpcRequest } from '@yaakapp/api';
|
||||
import { getGrpcRequest } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { grpcRequestsQueryKey } from './useGrpcRequests';
|
||||
|
||||
export function useDeleteAnyGrpcRequest() {
|
||||
const queryClient = useQueryClient();
|
||||
const confirm = useConfirm();
|
||||
|
||||
return useMutation<GrpcRequest | null, string, string>({
|
||||
@@ -32,13 +30,5 @@ export function useDeleteAnyGrpcRequest() {
|
||||
return invokeCmd('cmd_delete_grpc_request', { requestId: id });
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_request', '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),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { HttpRequest } from '@yaakapp/api';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||
import type { HttpRequest } from '@yaakapp/api';
|
||||
import { getHttpRequest } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
||||
|
||||
export function useDeleteAnyHttpRequest() {
|
||||
const queryClient = useQueryClient();
|
||||
const confirm = useConfirm();
|
||||
|
||||
return useMutation<HttpRequest | null, string, string>({
|
||||
@@ -33,15 +30,5 @@ export function useDeleteAnyHttpRequest() {
|
||||
return invokeCmd('cmd_delete_http_request', { requestId: id });
|
||||
},
|
||||
onSettled: () => trackEvent('http_request', 'delete'),
|
||||
onSuccess: async (request) => {
|
||||
// Was it cancelled?
|
||||
if (request === null) return;
|
||||
|
||||
const { workspaceId, id: requestId } = request;
|
||||
queryClient.setQueryData(httpResponsesQueryKey({ requestId }), []); // Responses were deleted
|
||||
queryClient.setQueryData<HttpRequest[]>(httpRequestsQueryKey({ workspaceId }), (requests) =>
|
||||
(requests ?? []).filter((r) => r.id !== requestId),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { CookieJar } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { cookieJarsQueryKey } from './useCookieJars';
|
||||
|
||||
export function useDeleteCookieJar(cookieJar: CookieJar | null) {
|
||||
const queryClient = useQueryClient();
|
||||
const confirm = useConfirm();
|
||||
|
||||
return useMutation<CookieJar | null, string>({
|
||||
@@ -27,13 +25,5 @@ export function useDeleteCookieJar(cookieJar: CookieJar | null) {
|
||||
return invokeCmd('cmd_delete_cookie_jar', { cookieJarId: cookieJar?.id });
|
||||
},
|
||||
onSettled: () => trackEvent('cookie_jar', 'delete'),
|
||||
onSuccess: async (cookieJar) => {
|
||||
if (cookieJar === null) return;
|
||||
|
||||
const { id: cookieJarId, workspaceId } = cookieJar;
|
||||
queryClient.setQueryData<CookieJar[]>(cookieJarsQueryKey({ workspaceId }), (cookieJars) =>
|
||||
cookieJars?.filter((e) => e.id !== cookieJarId),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { Environment } from '@yaakapp/api';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { Environment, Workspace } from '@yaakapp/api';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { environmentsQueryKey } from './useEnvironments';
|
||||
|
||||
export function useDeleteEnvironment(environment: Environment | null) {
|
||||
const queryClient = useQueryClient();
|
||||
const confirm = useConfirm();
|
||||
|
||||
return useMutation<Environment | null, string>({
|
||||
@@ -27,13 +25,5 @@ export function useDeleteEnvironment(environment: Environment | null) {
|
||||
return invokeCmd('cmd_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),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { Folder } from '@yaakapp/api';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { Folder } from '@yaakapp/api';
|
||||
import { getFolder } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { foldersQueryKey } from './useFolders';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
|
||||
export function useDeleteFolder(id: string | null) {
|
||||
const queryClient = useQueryClient();
|
||||
const confirm = useConfirm();
|
||||
|
||||
return useMutation<Folder | null, string>({
|
||||
@@ -30,15 +27,5 @@ export function useDeleteFolder(id: string | null) {
|
||||
return invokeCmd('cmd_delete_folder', { folderId: id });
|
||||
},
|
||||
onSettled: () => trackEvent('folder', 'delete'),
|
||||
onSuccess: async (folder) => {
|
||||
// Was it cancelled?
|
||||
if (folder === null) return;
|
||||
|
||||
const { workspaceId } = folder;
|
||||
|
||||
// Nesting makes it hard to clean things up, so just clear everything that could have been deleted
|
||||
await queryClient.invalidateQueries({ queryKey: httpRequestsQueryKey({ workspaceId }) });
|
||||
await queryClient.invalidateQueries({ queryKey: foldersQueryKey({ workspaceId }) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { GrpcConnection } from '@yaakapp/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { grpcConnectionsQueryKey } from './useGrpcConnections';
|
||||
|
||||
export function useDeleteGrpcConnection(id: string | null) {
|
||||
const queryClient = useQueryClient();
|
||||
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: ({ requestId, id: connectionId }) => {
|
||||
queryClient.setQueryData<GrpcConnection[]>(
|
||||
grpcConnectionsQueryKey({ requestId }),
|
||||
(connections) => (connections ?? []).filter((c) => c.id !== connectionId),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { grpcConnectionsQueryKey } from './useGrpcConnections';
|
||||
|
||||
export function useDeleteGrpcConnections(requestId?: string) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationKey: ['delete_grpc_connections', requestId],
|
||||
mutationFn: async () => {
|
||||
@@ -12,9 +10,5 @@ export function useDeleteGrpcConnections(requestId?: string) {
|
||||
await invokeCmd('cmd_delete_all_grpc_connections', { requestId });
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_connection', 'delete_many'),
|
||||
onSuccess: async () => {
|
||||
if (requestId === undefined) return;
|
||||
queryClient.setQueryData(grpcConnectionsQueryKey({ requestId }), []);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,21 +1,14 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { HttpResponse } from '@yaakapp/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
||||
|
||||
export function useDeleteHttpResponse(id: string | null) {
|
||||
const queryClient = useQueryClient();
|
||||
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: ({ requestId, id: responseId }) => {
|
||||
queryClient.setQueryData<HttpResponse[]>(httpResponsesQueryKey({ requestId }), (responses) =>
|
||||
(responses ?? []).filter((response) => response.id !== responseId),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
||||
|
||||
export function useDeleteHttpResponses(requestId?: string) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationKey: ['delete_http_responses', requestId],
|
||||
mutationFn: async () => {
|
||||
@@ -12,9 +10,5 @@ export function useDeleteHttpResponses(requestId?: string) {
|
||||
await invokeCmd('cmd_delete_all_http_responses', { requestId });
|
||||
},
|
||||
onSettled: () => trackEvent('http_response', 'delete_many'),
|
||||
onSuccess: async () => {
|
||||
if (requestId === undefined) return;
|
||||
queryClient.setQueryData(httpResponsesQueryKey({ requestId }), []);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { Workspace } from '@yaakapp/api';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { Workspace } from '@yaakapp/api';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
import { workspacesQueryKey } from './useWorkspaces';
|
||||
|
||||
export function useDeleteWorkspace(workspace: Workspace | null) {
|
||||
const queryClient = useQueryClient();
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const routes = useAppRoutes();
|
||||
const confirm = useConfirm();
|
||||
|
||||
@@ -36,16 +33,9 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
|
||||
if (workspace === null) return;
|
||||
|
||||
const { id: workspaceId } = workspace;
|
||||
queryClient.setQueryData<Workspace[]>(workspacesQueryKey({}), (workspaces) =>
|
||||
workspaces?.filter((workspace) => workspace.id !== workspaceId),
|
||||
);
|
||||
if (workspaceId === activeWorkspaceId) {
|
||||
if (workspaceId === activeWorkspace?.id) {
|
||||
routes.navigate('workspaces');
|
||||
}
|
||||
|
||||
// Also clean up other things that may have been deleted
|
||||
queryClient.setQueryData(httpRequestsQueryKey({ workspaceId }), []);
|
||||
await queryClient.invalidateQueries({ queryKey: httpRequestsQueryKey({ workspaceId }) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { GrpcRequest } from '@yaakapp/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { setKeyValue } from '../lib/keyValueStore';
|
||||
import type { GrpcRequest } from '@yaakapp/api';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { protoFilesArgs, useGrpcProtoFiles } from './useGrpcProtoFiles';
|
||||
|
||||
@@ -15,8 +15,8 @@ export function useDuplicateGrpcRequest({
|
||||
id: string | null;
|
||||
navigateAfter: boolean;
|
||||
}) {
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const [activeEnvironment] = useActiveEnvironment();
|
||||
const routes = useAppRoutes();
|
||||
const protoFiles = useGrpcProtoFiles(id);
|
||||
return useMutation<GrpcRequest, string>({
|
||||
@@ -30,11 +30,11 @@ export function useDuplicateGrpcRequest({
|
||||
// Also copy proto files to new request
|
||||
await setKeyValue({ ...protoFilesArgs(request.id), value: protoFiles.value ?? [] });
|
||||
|
||||
if (navigateAfter && activeWorkspaceId !== null) {
|
||||
if (navigateAfter && activeWorkspace !== null) {
|
||||
routes.navigate('request', {
|
||||
workspaceId: activeWorkspaceId,
|
||||
workspaceId: activeWorkspace.id,
|
||||
requestId: request.id,
|
||||
environmentId: activeEnvironmentId ?? undefined,
|
||||
environmentId: activeEnvironment?.id,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { HttpRequest } from '@yaakapp/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
|
||||
export function useDuplicateHttpRequest({
|
||||
@@ -13,8 +13,8 @@ export function useDuplicateHttpRequest({
|
||||
id: string | null;
|
||||
navigateAfter: boolean;
|
||||
}) {
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const [activeEnvironment] = useActiveEnvironment();
|
||||
const routes = useAppRoutes();
|
||||
return useMutation<HttpRequest, string>({
|
||||
mutationKey: ['duplicate_http_request', id],
|
||||
@@ -24,11 +24,11 @@ export function useDuplicateHttpRequest({
|
||||
},
|
||||
onSettled: () => trackEvent('http_request', 'duplicate'),
|
||||
onSuccess: async (request) => {
|
||||
if (navigateAfter && activeWorkspaceId !== null) {
|
||||
if (navigateAfter && activeWorkspace !== null) {
|
||||
routes.navigate('request', {
|
||||
workspaceId: activeWorkspaceId,
|
||||
workspaceId: activeWorkspace.id,
|
||||
requestId: request.id,
|
||||
environmentId: activeEnvironmentId ?? undefined,
|
||||
environmentId: activeEnvironment?.id,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { Environment } from '@yaakapp/api';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
|
||||
export function environmentsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
return ['environments', { workspaceId }];
|
||||
}
|
||||
|
||||
export function useEnvironments() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const workspace = useActiveWorkspace();
|
||||
return (
|
||||
useQuery({
|
||||
enabled: workspaceId != null,
|
||||
queryKey: environmentsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
enabled: workspace != null,
|
||||
queryKey: environmentsQueryKey({ workspaceId: workspace?.id ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invokeCmd('cmd_list_environments', { workspaceId })) as Environment[];
|
||||
if (workspace == null) return [];
|
||||
return (await invokeCmd('cmd_list_environments', {
|
||||
workspaceId: workspace.id,
|
||||
})) as Environment[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
|
||||
export function useFloatingSidebarHidden() {
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const { set, value } = useKeyValue<boolean>({
|
||||
namespace: 'no_sync',
|
||||
key: ['floating_sidebar_hidden', activeWorkspaceId ?? 'n/a'],
|
||||
key: ['floating_sidebar_hidden', activeWorkspace?.id ?? 'n/a'],
|
||||
fallback: false,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { Folder } from '@yaakapp/api';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
|
||||
export function foldersQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
return ['folders', { workspaceId }];
|
||||
}
|
||||
|
||||
export function useFolders() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const workspace = useActiveWorkspace();
|
||||
return (
|
||||
useQuery({
|
||||
enabled: workspaceId != null,
|
||||
queryKey: foldersQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
enabled: workspace != null,
|
||||
queryKey: foldersQueryKey({ workspaceId: workspace?.id ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invokeCmd('cmd_list_folders', { workspaceId })) as Folder[];
|
||||
if (workspace == null) return [];
|
||||
return (await invokeCmd('cmd_list_folders', { workspaceId: workspace.id })) as Folder[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import { emit } from '@tauri-apps/api/event';
|
||||
import type { GrpcConnection, GrpcRequest } from '@yaakapp/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||
import type { GrpcConnection, GrpcRequest } from '@yaakapp/api';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useDebouncedValue } from './useDebouncedValue';
|
||||
|
||||
export interface ReflectResponseService {
|
||||
@@ -18,12 +18,12 @@ export function useGrpc(
|
||||
protoFiles: string[],
|
||||
) {
|
||||
const requestId = req?.id ?? 'n/a';
|
||||
const environmentId = useActiveEnvironmentId();
|
||||
const [environment] = useActiveEnvironment();
|
||||
|
||||
const go = useMutation<void, string>({
|
||||
mutationKey: ['grpc_go', conn?.id],
|
||||
mutationFn: async () =>
|
||||
await invokeCmd('cmd_grpc_go', { requestId, environmentId, protoFiles }),
|
||||
await invokeCmd('cmd_grpc_go', { requestId, environmentId: environment?.id, protoFiles }),
|
||||
onSettled: () => trackEvent('grpc_request', 'send'),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { GrpcRequest } from '@yaakapp/api';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
|
||||
export function grpcRequestsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
return ['grpc_requests', { workspaceId }];
|
||||
}
|
||||
|
||||
export function useGrpcRequests() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const workspace = useActiveWorkspace();
|
||||
return (
|
||||
useQuery({
|
||||
enabled: workspaceId != null,
|
||||
queryKey: grpcRequestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
enabled: workspace != null,
|
||||
queryKey: grpcRequestsQueryKey({ workspaceId: workspace?.id ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invokeCmd('cmd_list_grpc_requests', { workspaceId })) as GrpcRequest[];
|
||||
if (workspace == null) return [];
|
||||
return (await invokeCmd('cmd_list_grpc_requests', {
|
||||
workspaceId: workspace.id,
|
||||
})) as GrpcRequest[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { HttpRequest } from '@yaakapp/api';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
|
||||
export function httpRequestsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
return ['http_requests', { workspaceId }];
|
||||
}
|
||||
|
||||
export function useHttpRequests() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const workspace = useActiveWorkspace();
|
||||
return (
|
||||
useQuery({
|
||||
enabled: workspaceId != null,
|
||||
queryKey: httpRequestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
enabled: workspace != null,
|
||||
queryKey: httpRequestsQueryKey({ workspaceId: workspace?.id ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invokeCmd('cmd_list_http_requests', { workspaceId })) as HttpRequest[];
|
||||
if (workspace == null) return [];
|
||||
return (await invokeCmd('cmd_list_http_requests', {
|
||||
workspaceId: workspace.id,
|
||||
})) as HttpRequest[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { useToast } from '../components/ToastContext';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
||||
import { useRequestUpdateKey } from './useRequestUpdateKey';
|
||||
import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
|
||||
|
||||
export function useImportCurl() {
|
||||
const workspaceId = useActiveWorkspaceId();
|
||||
const workspace = useActiveWorkspace();
|
||||
const updateRequest = useUpdateAnyHttpRequest();
|
||||
const createRequest = useCreateHttpRequest();
|
||||
const { wasUpdatedExternally } = useRequestUpdateKey(null);
|
||||
@@ -24,7 +24,7 @@ export function useImportCurl() {
|
||||
}) => {
|
||||
const request: Record<string, unknown> = await invokeCmd('cmd_curl_to_request', {
|
||||
command,
|
||||
workspaceId,
|
||||
workspaceId: workspace?.id,
|
||||
});
|
||||
delete request.id;
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { Environment, Folder, GrpcRequest, HttpRequest, Workspace } from '@yaakapp/api';
|
||||
import { Button } from '../components/core/Button';
|
||||
import { FormattedError } from '../components/core/FormattedError';
|
||||
import { VStack } from '../components/core/Stacks';
|
||||
import { useDialog } from '../components/DialogContext';
|
||||
import { ImportDataDialog } from '../components/ImportDataDialog';
|
||||
import type { Environment, Folder, GrpcRequest, HttpRequest, Workspace } from '@yaakapp/api';
|
||||
import { count } from '../lib/pluralize';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useAlert } from './useAlert';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
|
||||
@@ -15,7 +15,7 @@ export function useImportData() {
|
||||
const routes = useAppRoutes();
|
||||
const dialog = useDialog();
|
||||
const alert = useAlert();
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
|
||||
const importData = async (filePath: string): Promise<boolean> => {
|
||||
const imported: {
|
||||
@@ -26,7 +26,7 @@ export function useImportData() {
|
||||
grpcRequests: GrpcRequest[];
|
||||
} = await invokeCmd('cmd_import_data', {
|
||||
filePath,
|
||||
workspaceId: activeWorkspaceId,
|
||||
workspaceId: activeWorkspace?.id,
|
||||
});
|
||||
|
||||
const importedWorkspace = imported.workspaces[0];
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { HttpRequest } from '@yaakapp/api';
|
||||
import type { IntrospectionQuery } from 'graphql';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { buildClientSchema, getIntrospectionQuery } from '../components/core/Editor';
|
||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||
import type { HttpRequest } from '@yaakapp/api';
|
||||
import { getResponseBodyText } from '../lib/responseBody';
|
||||
import { sendEphemeralRequest } from '../lib/sendEphemeralRequest';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useDebouncedValue } from './useDebouncedValue';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
|
||||
@@ -18,7 +18,7 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) {
|
||||
// Debounce the request because it can change rapidly and we don't
|
||||
// want to send so too many requests.
|
||||
const request = useDebouncedValue(baseRequest);
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
const [activeEnvironment] = useActiveEnvironment();
|
||||
const [refetchKey, setRefetchKey] = useState<number>(0);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string>();
|
||||
@@ -40,7 +40,10 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) {
|
||||
bodyType: 'application/json',
|
||||
body: { text: introspectionRequestBody },
|
||||
};
|
||||
const response = await minPromiseMillis(sendEphemeralRequest(args, activeEnvironmentId), 700);
|
||||
const response = await minPromiseMillis(
|
||||
sendEphemeralRequest(args, activeEnvironment?.id ?? null),
|
||||
700,
|
||||
);
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error);
|
||||
@@ -72,7 +75,7 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) {
|
||||
runIntrospection(); // Run immediately
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [request.id, request.url, request.method, refetchKey, activeEnvironmentId]);
|
||||
}, [request.id, request.url, request.method, refetchKey, activeEnvironment?.id]);
|
||||
|
||||
const refetch = useCallback(() => {
|
||||
setRefetchKey((k) => k + 1);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { buildKeyValueKey, getKeyValue, setKeyValue } from '../lib/keyValueStore';
|
||||
|
||||
@@ -24,7 +24,6 @@ export function useKeyValue<T extends Object | null>({
|
||||
key: string | string[];
|
||||
fallback: T;
|
||||
}) {
|
||||
const queryClient = useQueryClient();
|
||||
const query = useQuery<T>({
|
||||
queryKey: keyValueQueryKey({ namespace, key }),
|
||||
queryFn: async () => getKeyValue({ namespace, key, fallback }),
|
||||
@@ -34,8 +33,6 @@ export function useKeyValue<T extends Object | null>({
|
||||
const mutate = useMutation<void, unknown, T>({
|
||||
mutationKey: ['set_key_value', namespace, key],
|
||||
mutationFn: (value) => setKeyValue<T>({ namespace, key, value }),
|
||||
// k/v should be as fast as possible, so optimistically update the cache
|
||||
onMutate: (value) => queryClient.setQueryData<T>(keyValueQueryKey({ namespace, key }), value),
|
||||
});
|
||||
|
||||
const set = useCallback(
|
||||
|
||||
@@ -2,19 +2,19 @@ import { useMutation } from '@tanstack/react-query';
|
||||
import React from 'react';
|
||||
import { useDialog } from '../components/DialogContext';
|
||||
import { MoveToWorkspaceDialog } from '../components/MoveToWorkspaceDialog';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useRequests } from './useRequests';
|
||||
|
||||
export function useMoveToWorkspace(id: string) {
|
||||
const dialog = useDialog();
|
||||
const requests = useRequests();
|
||||
const request = requests.find((r) => r.id === id);
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
|
||||
return useMutation<void, unknown>({
|
||||
mutationKey: ['move_workspace', id],
|
||||
mutationFn: async () => {
|
||||
if (request == null || activeWorkspaceId == null) return;
|
||||
if (request == null || activeWorkspace == null) return;
|
||||
|
||||
dialog.show({
|
||||
id: 'change-workspace',
|
||||
@@ -24,7 +24,7 @@ export function useMoveToWorkspace(id: string) {
|
||||
<MoveToWorkspaceDialog
|
||||
onDone={hide}
|
||||
request={request}
|
||||
activeWorkspaceId={activeWorkspaceId}
|
||||
activeWorkspaceId={activeWorkspace.id}
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { getRecentCookieJars } from './useRecentCookieJars';
|
||||
import { getRecentEnvironments } from './useRecentEnvironments';
|
||||
import { getRecentRequests } from './useRecentRequests';
|
||||
|
||||
@@ -16,29 +17,21 @@ export function useOpenWorkspace() {
|
||||
workspaceId: string;
|
||||
inNewWindow: boolean;
|
||||
}) => {
|
||||
const environmentId = (await getRecentEnvironments(workspaceId))[0];
|
||||
const requestId = (await getRecentRequests(workspaceId))[0];
|
||||
const cookieJarId = (await getRecentCookieJars(workspaceId))[0];
|
||||
const baseArgs = { workspaceId, environmentId, cookieJarId } as const;
|
||||
if (inNewWindow) {
|
||||
const environmentId = (await getRecentEnvironments(workspaceId))[0];
|
||||
const requestId = (await getRecentRequests(workspaceId))[0];
|
||||
const path =
|
||||
requestId != null
|
||||
? routes.paths.request({
|
||||
workspaceId,
|
||||
environmentId,
|
||||
requestId,
|
||||
})
|
||||
: routes.paths.workspace({ workspaceId, environmentId });
|
||||
? routes.paths.request({ ...baseArgs, requestId })
|
||||
: routes.paths.workspace({ ...baseArgs });
|
||||
await invokeCmd('cmd_new_window', { url: path });
|
||||
} else {
|
||||
const environmentId = (await getRecentEnvironments(workspaceId))[0];
|
||||
const requestId = (await getRecentRequests(workspaceId))[0];
|
||||
if (requestId != null) {
|
||||
routes.navigate('request', {
|
||||
workspaceId: workspaceId,
|
||||
environmentId,
|
||||
requestId,
|
||||
});
|
||||
routes.navigate('request', { ...baseArgs, requestId });
|
||||
} else {
|
||||
routes.navigate('workspace', { workspaceId, environmentId });
|
||||
routes.navigate('workspace', { ...baseArgs });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import type { Appearance } from '../lib/theme/appearance';
|
||||
import {
|
||||
getCSSAppearance,
|
||||
getWindowAppearance,
|
||||
subscribeToWindowAppearanceChange,
|
||||
} from '../lib/theme/appearance';
|
||||
import { type Appearance } from '../lib/theme/window';
|
||||
|
||||
export function usePreferredAppearance() {
|
||||
const [preferredAppearance, setPreferredAppearance] = useState<Appearance>(getCSSAppearance());
|
||||
|
||||
47
src-web/hooks/useRecentCookieJars.ts
Normal file
47
src-web/hooks/useRecentCookieJars.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { getKeyValue } from '../lib/keyValueStore';
|
||||
import { useActiveCookieJar } from './useActiveCookieJar';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useCookieJars } from './useCookieJars';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
|
||||
const kvKey = (workspaceId: string) => 'recent_cookie_jars::' + workspaceId;
|
||||
const namespace = 'global';
|
||||
const fallback: string[] = [];
|
||||
|
||||
export function useRecentCookieJars() {
|
||||
const cookieJars = useCookieJars();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const [activeCookieJar] = useActiveCookieJar();
|
||||
const activeCookieJarId = activeCookieJar?.id ?? null;
|
||||
const kv = useKeyValue<string[]>({
|
||||
key: kvKey(activeWorkspace?.id ?? 'n/a'),
|
||||
namespace,
|
||||
fallback,
|
||||
});
|
||||
|
||||
// Set history when active request changes
|
||||
useEffect(() => {
|
||||
kv.set((currentHistory: string[]) => {
|
||||
if (activeCookieJarId === null) return currentHistory;
|
||||
const withoutCurrent = currentHistory.filter((id) => id !== activeCookieJarId);
|
||||
return [activeCookieJarId, ...withoutCurrent];
|
||||
}).catch(console.error);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [activeCookieJarId]);
|
||||
|
||||
const onlyValidIds = useMemo(
|
||||
() => kv.value?.filter((id) => cookieJars.data?.some((e) => e.id === id)) ?? [],
|
||||
[kv.value, cookieJars],
|
||||
);
|
||||
|
||||
return onlyValidIds;
|
||||
}
|
||||
|
||||
export async function getRecentCookieJars(workspaceId: string) {
|
||||
return getKeyValue<string[]>({
|
||||
namespace,
|
||||
key: kvKey(workspaceId),
|
||||
fallback,
|
||||
});
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { getKeyValue } from '../lib/keyValueStore';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useEnvironments } from './useEnvironments';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
|
||||
@@ -11,10 +11,10 @@ const fallback: string[] = [];
|
||||
|
||||
export function useRecentEnvironments() {
|
||||
const environments = useEnvironments();
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const [activeEnvironment] = useActiveEnvironment();
|
||||
const kv = useKeyValue<string[]>({
|
||||
key: kvKey(activeWorkspaceId ?? 'n/a'),
|
||||
key: kvKey(activeWorkspace?.id ?? 'n/a'),
|
||||
namespace,
|
||||
fallback,
|
||||
});
|
||||
@@ -22,12 +22,12 @@ export function useRecentEnvironments() {
|
||||
// Set history when active request changes
|
||||
useEffect(() => {
|
||||
kv.set((currentHistory: string[]) => {
|
||||
if (activeEnvironmentId === null) return currentHistory;
|
||||
const withoutCurrentEnvironment = currentHistory.filter((id) => id !== activeEnvironmentId);
|
||||
return [activeEnvironmentId, ...withoutCurrentEnvironment];
|
||||
if (activeEnvironment === null) return currentHistory;
|
||||
const withoutCurrentEnvironment = currentHistory.filter((id) => id !== activeEnvironment.id);
|
||||
return [activeEnvironment.id, ...withoutCurrentEnvironment];
|
||||
}).catch(console.error);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [activeEnvironmentId]);
|
||||
}, [activeEnvironment?.id]);
|
||||
|
||||
const onlyValidIds = useMemo(
|
||||
() => kv.value?.filter((id) => environments.some((e) => e.id === id)) ?? [],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { getKeyValue } from '../lib/keyValueStore';
|
||||
import { useActiveRequestId } from './useActiveRequestId';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
import { useRequests } from './useRequests';
|
||||
|
||||
@@ -11,11 +11,11 @@ const fallback: string[] = [];
|
||||
|
||||
export function useRecentRequests() {
|
||||
const requests = useRequests();
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const activeRequestId = useActiveRequestId();
|
||||
|
||||
const kv = useKeyValue<string[]>({
|
||||
key: kvKey(activeWorkspaceId ?? 'n/a'),
|
||||
key: kvKey(activeWorkspace?.id ?? 'n/a'),
|
||||
namespace,
|
||||
fallback,
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { getKeyValue } from '../lib/keyValueStore';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
import { useWorkspaces } from './useWorkspaces';
|
||||
|
||||
@@ -10,7 +10,7 @@ const fallback: string[] = [];
|
||||
|
||||
export function useRecentWorkspaces() {
|
||||
const workspaces = useWorkspaces();
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const kv = useKeyValue<string[]>({
|
||||
key: kvKey(),
|
||||
namespace,
|
||||
@@ -20,12 +20,12 @@ export function useRecentWorkspaces() {
|
||||
// Set history when active request changes
|
||||
useEffect(() => {
|
||||
kv.set((currentHistory: string[]) => {
|
||||
if (activeWorkspaceId === null) return currentHistory;
|
||||
const withoutCurrent = currentHistory.filter((id) => id !== activeWorkspaceId);
|
||||
return [activeWorkspaceId, ...withoutCurrent];
|
||||
if (activeWorkspace === null) return currentHistory;
|
||||
const withoutCurrent = currentHistory.filter((id) => id !== activeWorkspace.id);
|
||||
return [activeWorkspace.id, ...withoutCurrent];
|
||||
}).catch(console.error);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [activeWorkspaceId]);
|
||||
}, [activeWorkspace]);
|
||||
|
||||
const onlyValidIds = useMemo(
|
||||
() => kv.value?.filter((id) => workspaces.some((w) => w.id === id)) ?? [],
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { save } from '@tauri-apps/plugin-dialog';
|
||||
import slugify from 'slugify';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { HttpResponse } from '@yaakapp/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveCookieJar } from './useActiveCookieJar';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useAlert } from './useAlert';
|
||||
import { useHttpRequests } from './useHttpRequests';
|
||||
|
||||
export function useSendAnyHttpRequest(options: { download?: boolean } = {}) {
|
||||
const environment = useActiveEnvironment();
|
||||
export function useSendAnyHttpRequest() {
|
||||
const [environment] = useActiveEnvironment();
|
||||
const alert = useAlert();
|
||||
const { activeCookieJar } = useActiveCookieJar();
|
||||
const [activeCookieJar] = useActiveCookieJar();
|
||||
const requests = useHttpRequests();
|
||||
return useMutation<HttpResponse | null, string, string | null>({
|
||||
mutationKey: ['send_any_request'],
|
||||
@@ -22,21 +20,9 @@ export function useSendAnyHttpRequest(options: { download?: boolean } = {}) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let downloadDir: string | null = null;
|
||||
if (options.download) {
|
||||
downloadDir = await save({
|
||||
title: 'Select Download Destination',
|
||||
defaultPath: slugify(request.name, { lower: true, trim: true, strict: true }),
|
||||
});
|
||||
if (downloadDir == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return invokeCmd('cmd_send_http_request', {
|
||||
request,
|
||||
environmentId: environment?.id,
|
||||
downloadDir: downloadDir,
|
||||
cookieJarId: activeCookieJar?.id,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
|
||||
export function useSidebarHidden() {
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const { set, value } = useKeyValue<boolean>({
|
||||
namespace: 'no_sync',
|
||||
key: ['sidebar_hidden', activeWorkspaceId ?? 'n/a'],
|
||||
key: ['sidebar_hidden', activeWorkspace?.id ?? 'n/a'],
|
||||
fallback: false,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useLocalStorage } from 'react-use';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
|
||||
export function useSidebarWidth() {
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const [width, setWidth] = useLocalStorage<number>(`sidebar_width::${activeWorkspaceId}`, 250);
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const [width, setWidth] = useLocalStorage<number>(
|
||||
`sidebar_width::${activeWorkspace?.id ?? 'n/a'}`,
|
||||
250,
|
||||
);
|
||||
const resetWidth = useCallback(() => setWidth(250), [setWidth]);
|
||||
return useMemo(() => ({ width, setWidth, resetWidth }), [width, setWidth, resetWidth]);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,6 @@ export function useSyncThemeToDocument() {
|
||||
}
|
||||
|
||||
function emitBgChange(t: YaakTheme) {
|
||||
if (t.background == null) return;
|
||||
emit('yaak_bg_changed', t.background.hex()).catch(console.error);
|
||||
if (t.surface == null) return;
|
||||
emit('yaak_bg_changed', t.surface.hexNoAlpha()).catch(console.error);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { emit } from '@tauri-apps/api/event';
|
||||
export function useSyncWorkspaceRequestTitle() {
|
||||
const activeRequest = useActiveRequest();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const activeEnvironment = useActiveEnvironment();
|
||||
const [activeEnvironment] = useActiveEnvironment();
|
||||
const osInfo = useOsInfo();
|
||||
const appInfo = useAppInfo();
|
||||
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { Folder } from '@yaakapp/api';
|
||||
import { getFolder } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { foldersQueryKey } from './useFolders';
|
||||
|
||||
export function useUpdateAnyFolder() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<void, unknown, { id: string; update: (r: Folder) => Folder }>({
|
||||
mutationKey: ['update_any_folder'],
|
||||
mutationFn: async ({ id, update }) => {
|
||||
@@ -17,12 +14,5 @@ export function useUpdateAnyFolder() {
|
||||
|
||||
await invokeCmd('cmd_update_folder', { folder: update(folder) });
|
||||
},
|
||||
onMutate: async ({ id, update }) => {
|
||||
const folder = await getFolder(id);
|
||||
if (folder === null) return;
|
||||
queryClient.setQueryData<Folder[]>(foldersQueryKey(folder), (folders) =>
|
||||
(folders ?? []).map((f) => (f.id === folder.id ? update(f) : f)),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { GrpcRequest } from '@yaakapp/api';
|
||||
import { getGrpcRequest } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { grpcRequestsQueryKey } from './useGrpcRequests';
|
||||
|
||||
export function useUpdateAnyGrpcRequest() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<
|
||||
void,
|
||||
unknown,
|
||||
@@ -23,14 +20,5 @@ export function useUpdateAnyGrpcRequest() {
|
||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||
await invokeCmd('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,12 +1,9 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { HttpRequest } from '@yaakapp/api';
|
||||
import { getHttpRequest } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
|
||||
export function useUpdateAnyHttpRequest() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<
|
||||
void,
|
||||
unknown,
|
||||
@@ -23,14 +20,5 @@ export function useUpdateAnyHttpRequest() {
|
||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||
await invokeCmd('cmd_update_http_request', { request: patchedRequest });
|
||||
},
|
||||
onMutate: async ({ id, update }) => {
|
||||
const request = await getHttpRequest(id);
|
||||
if (request === null) return;
|
||||
const patchedRequest =
|
||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||
queryClient.setQueryData<HttpRequest[]>(httpRequestsQueryKey(request), (requests) =>
|
||||
(requests ?? []).map((r) => (r.id === patchedRequest.id ? patchedRequest : r)),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { CookieJar } from '../lib/models';
|
||||
import { getCookieJar } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { cookieJarsQueryKey } from './useCookieJars';
|
||||
|
||||
export function useUpdateCookieJar(id: string | null) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<void, unknown, Partial<CookieJar> | ((j: CookieJar) => CookieJar)>({
|
||||
mutationKey: ['update_cookie_jar', id],
|
||||
mutationFn: async (v) => {
|
||||
@@ -15,17 +13,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 invokeCmd('cmd_update_cookie_jar', { cookieJar: newCookieJar });
|
||||
},
|
||||
onMutate: async (v) => {
|
||||
const cookieJar = await getCookieJar(id);
|
||||
if (cookieJar === null) return;
|
||||
|
||||
const newCookieJar = typeof v === 'function' ? v(cookieJar) : { ...cookieJar, ...v };
|
||||
queryClient.setQueryData<CookieJar[]>(cookieJarsQueryKey(cookieJar), (cookieJars) =>
|
||||
(cookieJars ?? []).map((j) => (j.id === newCookieJar.id ? newCookieJar : j)),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { Environment } from '@yaakapp/api';
|
||||
import { getEnvironment } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { environmentsQueryKey } from './useEnvironments';
|
||||
|
||||
export function useUpdateEnvironment(id: string | null) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<void, unknown, Partial<Environment> | ((r: Environment) => Environment)>({
|
||||
mutationKey: ['update_environment', id],
|
||||
mutationFn: async (v) => {
|
||||
@@ -17,14 +15,5 @@ export function useUpdateEnvironment(id: string | null) {
|
||||
const newEnvironment = typeof v === 'function' ? v(environment) : { ...environment, ...v };
|
||||
await invokeCmd('cmd_update_environment', { environment: newEnvironment });
|
||||
},
|
||||
onMutate: async (v) => {
|
||||
const environment = await getEnvironment(id);
|
||||
if (environment === null) return;
|
||||
|
||||
const newEnvironment = typeof v === 'function' ? v(environment) : { ...environment, ...v };
|
||||
queryClient.setQueryData<Environment[]>(environmentsQueryKey(environment), (environments) =>
|
||||
(environments ?? []).map((r) => (r.id === newEnvironment.id ? newEnvironment : r)),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { Workspace } from '@yaakapp/api';
|
||||
import { getWorkspace } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { workspacesQueryKey } from './useWorkspaces';
|
||||
|
||||
export function useUpdateWorkspace(id: string | null) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<void, unknown, Partial<Workspace> | ((w: Workspace) => Workspace)>({
|
||||
mutationKey: ['update_workspace', id],
|
||||
mutationFn: async (v) => {
|
||||
@@ -17,14 +15,5 @@ export function useUpdateWorkspace(id: string | null) {
|
||||
const newWorkspace = typeof v === 'function' ? v(workspace) : { ...workspace, ...v };
|
||||
await invokeCmd('cmd_update_workspace', { workspace: newWorkspace });
|
||||
},
|
||||
onMutate: async (v) => {
|
||||
const workspace = await getWorkspace(id);
|
||||
if (workspace === null) return;
|
||||
|
||||
const newWorkspace = typeof v === 'function' ? v(workspace) : { ...workspace, ...v };
|
||||
queryClient.setQueryData<Workspace[]>(workspacesQueryKey(workspace), (workspaces) =>
|
||||
(workspaces ?? []).map((w) => (w.id === newWorkspace.id ? newWorkspace : w)),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,6 +17,20 @@ export async function setKeyValue<T>({
|
||||
});
|
||||
}
|
||||
|
||||
export async function getKeyValueRaw({
|
||||
namespace = 'global',
|
||||
key,
|
||||
}: {
|
||||
namespace?: string;
|
||||
key: string | string[];
|
||||
}) {
|
||||
const kv = (await invokeCmd('cmd_get_key_value', {
|
||||
namespace,
|
||||
key: buildKeyValueKey(key),
|
||||
})) as KeyValue | null;
|
||||
return kv;
|
||||
}
|
||||
|
||||
export async function getKeyValue<T>({
|
||||
namespace = 'global',
|
||||
key,
|
||||
@@ -26,14 +40,11 @@ export async function getKeyValue<T>({
|
||||
key: string | string[];
|
||||
fallback: T;
|
||||
}) {
|
||||
const kv = (await invokeCmd('cmd_get_key_value', {
|
||||
namespace,
|
||||
key: buildKeyValueKey(key),
|
||||
})) as KeyValue | null;
|
||||
const kv = await getKeyValueRaw({ namespace, key });
|
||||
return extractKeyValueOrFallback(kv, fallback);
|
||||
}
|
||||
|
||||
function extractKeyValue<T>(kv: KeyValue | null): T | undefined {
|
||||
export function extractKeyValue<T>(kv: KeyValue | null): T | undefined {
|
||||
if (kv === null) return undefined;
|
||||
try {
|
||||
return JSON.parse(kv.value) as T;
|
||||
|
||||
@@ -36,6 +36,9 @@ export function isResponseLoading(response: HttpResponse | GrpcConnection): bool
|
||||
}
|
||||
|
||||
export function modelsEq(a: Model, b: Model) {
|
||||
if (a.model != b.model) {
|
||||
return false;
|
||||
}
|
||||
if (a.model === 'key_value' && b.model === 'key_value') {
|
||||
return a.key === b.key && a.namespace === b.namespace;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||
|
||||
type Appearance = 'light' | 'dark';
|
||||
export type Appearance = 'light' | 'dark';
|
||||
|
||||
export function getCSSAppearance(): Appearance {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
|
||||
@@ -310,7 +310,6 @@ export function completeTheme(theme: YaakTheme): YaakTheme {
|
||||
|
||||
theme.border = theme.border ?? theme.surface?.lift(0.12);
|
||||
theme.borderSubtle = theme.borderSubtle ?? theme.border?.lower(0.08);
|
||||
console.log('HELLO', { theme });
|
||||
|
||||
theme.text = theme.text ?? theme.border?.lift(1).lower(0.2);
|
||||
theme.textSubtle = theme.textSubtle ?? theme.text?.lower(0.3);
|
||||
|
||||
@@ -104,6 +104,15 @@ export class YaakColor {
|
||||
return rgbaToHex(r, g, b, a);
|
||||
}
|
||||
|
||||
hexNoAlpha(): string {
|
||||
const h = this.hue;
|
||||
const s = this.saturation;
|
||||
const l = this.lightness;
|
||||
|
||||
const [r, g, b] = parseColor(`hsl(${h},${s}%,${l}%)`).rgb;
|
||||
return rgbaToHexNoAlpha(r, g, b);
|
||||
}
|
||||
|
||||
private _lighten(mod: number): YaakColor {
|
||||
const c = this.clone();
|
||||
c.lightness = this.lightness + (100 - this.lightness) * mod;
|
||||
@@ -125,6 +134,14 @@ function rgbaToHex(r: number, g: number, b: number, a: number): string {
|
||||
return '#' + [toHex(r), toHex(g), toHex(b), toHex(a * 255)].join('').toUpperCase();
|
||||
}
|
||||
|
||||
function rgbaToHexNoAlpha(r: number, g: number, b: number): string {
|
||||
const toHex = (n: number): string => {
|
||||
const hex = Number(Math.round(n)).toString(16);
|
||||
return hex.length === 1 ? `0${hex}` : hex;
|
||||
};
|
||||
return '#' + [toHex(r), toHex(g), toHex(b)].join('').toUpperCase();
|
||||
}
|
||||
|
||||
function hexToRgba(hex: string): [number, number, number, number] {
|
||||
const fromHex = (h: string): number => {
|
||||
if (h === '') return 255;
|
||||
|
||||
Reference in New Issue
Block a user