mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-24 01:28:35 +02:00
A bunch of changes, including moving prompt/confirm out of context
This commit is contained in:
@@ -6,7 +6,7 @@ import { SyncOp } from './bindings/sync';
|
|||||||
import { WatchEvent, WatchResult } from './bindings/watch';
|
import { WatchEvent, WatchResult } from './bindings/watch';
|
||||||
|
|
||||||
export async function calculateSync(workspace: Workspace) {
|
export async function calculateSync(workspace: Workspace) {
|
||||||
if (!workspace.settingSyncDir) throw new Error('Workspace sync dir not configured');
|
if (!workspace.settingSyncDir) return;
|
||||||
|
|
||||||
return invoke<SyncOp[]>('plugin:yaak-sync|calculate', {
|
return invoke<SyncOp[]>('plugin:yaak-sync|calculate', {
|
||||||
workspaceId: workspace.id,
|
workspaceId: workspace.id,
|
||||||
@@ -15,6 +15,8 @@ export async function calculateSync(workspace: Workspace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function applySync(workspace: Workspace, syncOps: SyncOp[]) {
|
export async function applySync(workspace: Workspace, syncOps: SyncOp[]) {
|
||||||
|
if (!workspace.settingSyncDir) return;
|
||||||
|
|
||||||
return invoke<void>('plugin:yaak-sync|apply', {
|
return invoke<void>('plugin:yaak-sync|apply', {
|
||||||
workspaceId: workspace.id,
|
workspaceId: workspace.id,
|
||||||
dir: workspace.settingSyncDir,
|
dir: workspace.settingSyncDir,
|
||||||
@@ -23,22 +25,24 @@ export async function applySync(workspace: Workspace, syncOps: SyncOp[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useWatchWorkspace(workspace: Workspace | null, callback: (e: WatchEvent) => void) {
|
export function useWatchWorkspace(workspace: Workspace | null, callback: (e: WatchEvent) => void) {
|
||||||
const workspaceId = workspace?.id ?? null;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (workspaceId == null) return;
|
if (workspace == null) return;
|
||||||
|
if (!workspace.settingSyncDir) return;
|
||||||
|
|
||||||
const channel = new Channel<WatchEvent>();
|
const channel = new Channel<WatchEvent>();
|
||||||
channel.onmessage = callback;
|
channel.onmessage = callback;
|
||||||
const promise = invoke<WatchResult>('plugin:yaak-sync|watch', { workspaceId, channel });
|
const promise = invoke<WatchResult>('plugin:yaak-sync|watch', {
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
channel,
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
promise
|
promise
|
||||||
.then(({ unlistenEvent }) => {
|
.then(({ unlistenEvent }) => {
|
||||||
console.log('Cancelling workspace watch', workspaceId, unlistenEvent);
|
console.log('Cancelling workspace watch', workspace.id, unlistenEvent);
|
||||||
return emit(unlistenEvent);
|
return emit(unlistenEvent);
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
};
|
};
|
||||||
}, [workspaceId]);
|
}, [workspace]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|||||||
import { useActiveCookieJar } from '../hooks/useActiveCookieJar';
|
import { useActiveCookieJar } from '../hooks/useActiveCookieJar';
|
||||||
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||||
import { useCommands } from '../hooks/useCommands';
|
|
||||||
import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
|
import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
|
||||||
import { useCreateGrpcRequest } from '../hooks/useCreateGrpcRequest';
|
import { useCreateGrpcRequest } from '../hooks/useCreateGrpcRequest';
|
||||||
import { useCreateHttpRequest } from '../hooks/useCreateHttpRequest';
|
import { useCreateHttpRequest } from '../hooks/useCreateHttpRequest';
|
||||||
@@ -27,6 +26,7 @@ import { useScrollIntoView } from '../hooks/useScrollIntoView';
|
|||||||
import { useSendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
|
import { useSendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
|
||||||
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
|
import { createFolder } from '../lib/commands';
|
||||||
import { showDialog, toggleDialog } from '../lib/dialog';
|
import { showDialog, toggleDialog } from '../lib/dialog';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import { router } from '../lib/router';
|
import { router } from '../lib/router';
|
||||||
@@ -69,7 +69,6 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
|
|||||||
const [recentRequests] = useRecentRequests();
|
const [recentRequests] = useRecentRequests();
|
||||||
const openWorkspace = useOpenWorkspace();
|
const openWorkspace = useOpenWorkspace();
|
||||||
const createHttpRequest = useCreateHttpRequest();
|
const createHttpRequest = useCreateHttpRequest();
|
||||||
const { createFolder } = useCommands();
|
|
||||||
const activeCookieJar = useActiveCookieJar();
|
const activeCookieJar = useActiveCookieJar();
|
||||||
const createGrpcRequest = useCreateGrpcRequest();
|
const createGrpcRequest = useCreateGrpcRequest();
|
||||||
const createEnvironment = useCreateEnvironment();
|
const createEnvironment = useCreateEnvironment();
|
||||||
@@ -188,7 +187,6 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
|
|||||||
activeRequest,
|
activeRequest,
|
||||||
baseEnvironment,
|
baseEnvironment,
|
||||||
createEnvironment,
|
createEnvironment,
|
||||||
createFolder,
|
|
||||||
createGrpcRequest,
|
createGrpcRequest,
|
||||||
createHttpRequest,
|
createHttpRequest,
|
||||||
createWorkspace,
|
createWorkspace,
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
|
import { useAtomValue } from 'jotai';
|
||||||
import { memo, useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import { setActiveCookieJar, useActiveCookieJar } from '../hooks/useActiveCookieJar';
|
import { useActiveCookieJar } from '../hooks/useActiveCookieJar';
|
||||||
import { cookieJarsAtom } from '../hooks/useCookieJars';
|
import { cookieJarsAtom } from '../hooks/useCookieJars';
|
||||||
import { useCreateCookieJar } from '../hooks/useCreateCookieJar';
|
import { useCreateCookieJar } from '../hooks/useCreateCookieJar';
|
||||||
import { useDeleteCookieJar } from '../hooks/useDeleteCookieJar';
|
import { useDeleteCookieJar } from '../hooks/useDeleteCookieJar';
|
||||||
import { usePrompt } from '../hooks/usePrompt';
|
|
||||||
import { useUpdateCookieJar } from '../hooks/useUpdateCookieJar';
|
import { useUpdateCookieJar } from '../hooks/useUpdateCookieJar';
|
||||||
import { showDialog } from '../lib/dialog';
|
import { showDialog } from '../lib/dialog';
|
||||||
import { jotaiStore } from '../lib/jotai';
|
import { showPrompt } from '../lib/prompt';
|
||||||
|
import {setWorkspaceSearchParams} from "../lib/setWorkspaceSearchParams";
|
||||||
import { CookieDialog } from './CookieDialog';
|
import { CookieDialog } from './CookieDialog';
|
||||||
import { Dropdown, type DropdownItem } from './core/Dropdown';
|
import { Dropdown, type DropdownItem } from './core/Dropdown';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
@@ -18,18 +19,19 @@ export const CookieDropdown = memo(function CookieDropdown() {
|
|||||||
const updateCookieJar = useUpdateCookieJar(activeCookieJar?.id ?? null);
|
const updateCookieJar = useUpdateCookieJar(activeCookieJar?.id ?? null);
|
||||||
const deleteCookieJar = useDeleteCookieJar(activeCookieJar ?? null);
|
const deleteCookieJar = useDeleteCookieJar(activeCookieJar ?? null);
|
||||||
const createCookieJar = useCreateCookieJar();
|
const createCookieJar = useCreateCookieJar();
|
||||||
const prompt = usePrompt();
|
const cookieJars = useAtomValue(cookieJarsAtom);
|
||||||
|
|
||||||
const items = useMemo((): DropdownItem[] => {
|
const items = useMemo((): DropdownItem[] => {
|
||||||
const cookieJars = jotaiStore.get(cookieJarsAtom) ?? [];
|
|
||||||
return [
|
return [
|
||||||
...cookieJars.map((j) => ({
|
...(cookieJars ?? []).map((j) => ({
|
||||||
key: j.id,
|
key: j.id,
|
||||||
label: j.name,
|
label: j.name,
|
||||||
leftSlot: <Icon icon={j.id === activeCookieJar?.id ? 'check' : 'empty'} />,
|
leftSlot: <Icon icon={j.id === activeCookieJar?.id ? 'check' : 'empty'} />,
|
||||||
onSelect: () => setActiveCookieJar(j),
|
onSelect: () => {
|
||||||
|
setWorkspaceSearchParams({ cookie_jar_id: j.id });
|
||||||
|
},
|
||||||
})),
|
})),
|
||||||
...((cookieJars.length > 0 && activeCookieJar != null
|
...(((cookieJars ?? []).length > 0 && activeCookieJar != null
|
||||||
? [
|
? [
|
||||||
{ type: 'separator', label: activeCookieJar.name },
|
{ type: 'separator', label: activeCookieJar.name },
|
||||||
{
|
{
|
||||||
@@ -51,7 +53,7 @@ export const CookieDropdown = memo(function CookieDropdown() {
|
|||||||
label: 'Rename',
|
label: 'Rename',
|
||||||
leftSlot: <Icon icon="pencil" />,
|
leftSlot: <Icon icon="pencil" />,
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
const name = await prompt({
|
const name = await showPrompt({
|
||||||
id: 'rename-cookie-jar',
|
id: 'rename-cookie-jar',
|
||||||
title: 'Rename Cookie Jar',
|
title: 'Rename Cookie Jar',
|
||||||
description: (
|
description: (
|
||||||
@@ -68,7 +70,7 @@ export const CookieDropdown = memo(function CookieDropdown() {
|
|||||||
updateCookieJar.mutate({ name });
|
updateCookieJar.mutate({ name });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...((cookieJars.length > 1 // Never delete the last one
|
...(((cookieJars ?? []).length > 1 // Never delete the last one
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
key: 'delete',
|
key: 'delete',
|
||||||
@@ -89,7 +91,7 @@ export const CookieDropdown = memo(function CookieDropdown() {
|
|||||||
onSelect: () => createCookieJar.mutate(),
|
onSelect: () => createCookieJar.mutate(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}, [activeCookieJar, createCookieJar, deleteCookieJar, prompt, updateCookieJar]);
|
}, [activeCookieJar, cookieJars, createCookieJar, deleteCookieJar, updateCookieJar]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown items={items}>
|
<Dropdown items={items}>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useCommands } from '../hooks/useCommands';
|
import {createWorkspace} from "../lib/commands";
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { PlainInput } from './core/PlainInput';
|
import { PlainInput } from './core/PlainInput';
|
||||||
import { VStack } from './core/Stacks';
|
import { VStack } from './core/Stacks';
|
||||||
@@ -14,7 +14,6 @@ export function CreateWorkspaceDialog({ hide }: Props) {
|
|||||||
const [name, setName] = useState<string>('');
|
const [name, setName] = useState<string>('');
|
||||||
const [description, setDescription] = useState<string>('');
|
const [description, setDescription] = useState<string>('');
|
||||||
const [settingSyncDir, setSettingSyncDir] = useState<string | null>(null);
|
const [settingSyncDir, setSettingSyncDir] = useState<string | null>(null);
|
||||||
const { createWorkspace } = useCommands();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack
|
<VStack
|
||||||
|
|||||||
@@ -12,19 +12,26 @@ export function Dialogs() {
|
|||||||
const dialogs = useAtomValue(dialogsAtom);
|
const dialogs = useAtomValue(dialogsAtom);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{dialogs.map(({ render, onClose, id, ...props }: DialogInstance) => (
|
{dialogs.map(({ id, ...props }) => (
|
||||||
<Dialog
|
<DialogInstance key={id} id={id} {...props} />
|
||||||
open
|
|
||||||
key={id}
|
|
||||||
onClose={() => {
|
|
||||||
onClose?.();
|
|
||||||
hideDialog(id);
|
|
||||||
}}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{render({ hide: () => hideDialog(id) })}
|
|
||||||
</Dialog>
|
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function DialogInstance({ render, onClose, id, ...props }: DialogInstance) {
|
||||||
|
const children = render({ hide: () => hideDialog(id) });
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open
|
||||||
|
key={id}
|
||||||
|
onClose={() => {
|
||||||
|
onClose?.();
|
||||||
|
hideDialog(id);
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
|
|||||||
import { useDeleteEnvironment } from '../hooks/useDeleteEnvironment';
|
import { useDeleteEnvironment } from '../hooks/useDeleteEnvironment';
|
||||||
import { useEnvironments } from '../hooks/useEnvironments';
|
import { useEnvironments } from '../hooks/useEnvironments';
|
||||||
import { useKeyValue } from '../hooks/useKeyValue';
|
import { useKeyValue } from '../hooks/useKeyValue';
|
||||||
import { usePrompt } from '../hooks/usePrompt';
|
|
||||||
import { useUpdateEnvironment } from '../hooks/useUpdateEnvironment';
|
import { useUpdateEnvironment } from '../hooks/useUpdateEnvironment';
|
||||||
|
import { showPrompt } from '../lib/prompt';
|
||||||
import { Banner } from './core/Banner';
|
import { Banner } from './core/Banner';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { ContextMenu } from './core/Dropdown';
|
import { ContextMenu } from './core/Dropdown';
|
||||||
@@ -212,7 +212,6 @@ function SidebarButton({
|
|||||||
rightSlot?: ReactNode;
|
rightSlot?: ReactNode;
|
||||||
environment: Environment | null;
|
environment: Environment | null;
|
||||||
}) {
|
}) {
|
||||||
const prompt = usePrompt();
|
|
||||||
const updateEnvironment = useUpdateEnvironment(environment?.id ?? null);
|
const updateEnvironment = useUpdateEnvironment(environment?.id ?? null);
|
||||||
const deleteEnvironment = useDeleteEnvironment(environment);
|
const deleteEnvironment = useDeleteEnvironment(environment);
|
||||||
const [showContextMenu, setShowContextMenu] = useState<{
|
const [showContextMenu, setShowContextMenu] = useState<{
|
||||||
@@ -260,7 +259,7 @@ function SidebarButton({
|
|||||||
label: 'Rename',
|
label: 'Rename',
|
||||||
leftSlot: <Icon icon="pencil" size="sm" />,
|
leftSlot: <Icon icon="pencil" size="sm" />,
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
const name = await prompt({
|
const name = await showPrompt({
|
||||||
id: 'rename-environment',
|
id: 'rename-environment',
|
||||||
title: 'Rename Environment',
|
title: 'Rename Environment',
|
||||||
description: (
|
description: (
|
||||||
|
|||||||
@@ -2,34 +2,18 @@ import { emit } from '@tauri-apps/api/event';
|
|||||||
import type { PromptTextRequest, PromptTextResponse } from '@yaakapp-internal/plugins';
|
import type { PromptTextRequest, PromptTextResponse } from '@yaakapp-internal/plugins';
|
||||||
import { useWatchWorkspace } from '@yaakapp-internal/sync';
|
import { useWatchWorkspace } from '@yaakapp-internal/sync';
|
||||||
import type { ShowToastRequest } from '@yaakapp/api';
|
import type { ShowToastRequest } from '@yaakapp/api';
|
||||||
import {
|
|
||||||
useEnsureActiveCookieJar,
|
|
||||||
useSubscribeActiveCookieJarId,
|
|
||||||
} from '../hooks/useActiveCookieJar';
|
|
||||||
import { useSubscribeActiveEnvironmentId } from '../hooks/useActiveEnvironment';
|
|
||||||
import { getActiveRequest, useActiveRequest } from '../hooks/useActiveRequest';
|
|
||||||
import { useSubscribeActiveRequestId } from '../hooks/useActiveRequestId';
|
|
||||||
import { useActiveWorkspace, useSubscribeActiveWorkspaceId } from '../hooks/useActiveWorkspace';
|
import { useActiveWorkspace, useSubscribeActiveWorkspaceId } from '../hooks/useActiveWorkspace';
|
||||||
import { useActiveWorkspaceChangedToast } from '../hooks/useActiveWorkspaceChangedToast';
|
import { useActiveWorkspaceChangedToast } from '../hooks/useActiveWorkspaceChangedToast';
|
||||||
import { useDuplicateGrpcRequest } from '../hooks/useDuplicateGrpcRequest';
|
|
||||||
import { useDuplicateHttpRequest } from '../hooks/useDuplicateHttpRequest';
|
|
||||||
import { useGenerateThemeCss } from '../hooks/useGenerateThemeCss';
|
import { useGenerateThemeCss } from '../hooks/useGenerateThemeCss';
|
||||||
import { useHotKey } from '../hooks/useHotKey';
|
|
||||||
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
||||||
import { useNotificationToast } from '../hooks/useNotificationToast';
|
import { useNotificationToast } from '../hooks/useNotificationToast';
|
||||||
import { usePrompt } from '../hooks/usePrompt';
|
|
||||||
import { useSubscribeRecentCookieJars } from '../hooks/useRecentCookieJars';
|
|
||||||
import { useSubscribeRecentEnvironments } from '../hooks/useRecentEnvironments';
|
|
||||||
import { useSubscribeRecentRequests } from '../hooks/useRecentRequests';
|
|
||||||
import { useSubscribeRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
|
||||||
import { useSyncFontSizeSetting } from '../hooks/useSyncFontSizeSetting';
|
import { useSyncFontSizeSetting } from '../hooks/useSyncFontSizeSetting';
|
||||||
import { useSyncModelStores } from '../hooks/useSyncModelStores';
|
import { useSyncModelStores } from '../hooks/useSyncModelStores';
|
||||||
import { useSyncWorkspace } from '../hooks/useSyncWorkspace';
|
import { useSyncWorkspace } from '../hooks/useSyncWorkspace';
|
||||||
import { useSyncWorkspaceChildModels } from '../hooks/useSyncWorkspaceChildModels';
|
import { useSyncWorkspaceChildModels } from '../hooks/useSyncWorkspaceChildModels';
|
||||||
import { useSyncWorkspaceRequestTitle } from '../hooks/useSyncWorkspaceRequestTitle';
|
|
||||||
import { useSyncZoomSetting } from '../hooks/useSyncZoomSetting';
|
import { useSyncZoomSetting } from '../hooks/useSyncZoomSetting';
|
||||||
import { useSubscribeTemplateFunctions } from '../hooks/useTemplateFunctions';
|
import { useSubscribeTemplateFunctions } from '../hooks/useTemplateFunctions';
|
||||||
import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
|
import { showPrompt } from '../lib/prompt';
|
||||||
import { showToast } from '../lib/toast';
|
import { showToast } from '../lib/toast';
|
||||||
|
|
||||||
export function GlobalHooks() {
|
export function GlobalHooks() {
|
||||||
@@ -37,17 +21,8 @@ export function GlobalHooks() {
|
|||||||
useSyncZoomSetting();
|
useSyncZoomSetting();
|
||||||
useSyncFontSizeSetting();
|
useSyncFontSizeSetting();
|
||||||
useGenerateThemeCss();
|
useGenerateThemeCss();
|
||||||
useSyncWorkspaceRequestTitle();
|
|
||||||
|
|
||||||
useSubscribeActiveWorkspaceId();
|
useSubscribeActiveWorkspaceId();
|
||||||
useSubscribeActiveRequestId();
|
|
||||||
useSubscribeActiveEnvironmentId();
|
|
||||||
useSubscribeActiveCookieJarId();
|
|
||||||
|
|
||||||
useSubscribeRecentRequests();
|
|
||||||
useSubscribeRecentWorkspaces();
|
|
||||||
useSubscribeRecentEnvironments();
|
|
||||||
useSubscribeRecentCookieJars();
|
|
||||||
|
|
||||||
useSyncWorkspaceChildModels();
|
useSyncWorkspaceChildModels();
|
||||||
useSubscribeTemplateFunctions();
|
useSubscribeTemplateFunctions();
|
||||||
@@ -55,7 +30,6 @@ export function GlobalHooks() {
|
|||||||
// Other useful things
|
// Other useful things
|
||||||
useNotificationToast();
|
useNotificationToast();
|
||||||
useActiveWorkspaceChangedToast();
|
useActiveWorkspaceChangedToast();
|
||||||
useEnsureActiveCookieJar();
|
|
||||||
|
|
||||||
// Listen for toasts
|
// Listen for toasts
|
||||||
useListenToTauriEvent<ShowToastRequest>('show_toast', (event) => {
|
useListenToTauriEvent<ShowToastRequest>('show_toast', (event) => {
|
||||||
@@ -68,32 +42,10 @@ export function GlobalHooks() {
|
|||||||
useListenToTauriEvent('upserted_model', debouncedSync);
|
useListenToTauriEvent('upserted_model', debouncedSync);
|
||||||
useWatchWorkspace(activeWorkspace, debouncedSync);
|
useWatchWorkspace(activeWorkspace, debouncedSync);
|
||||||
|
|
||||||
const activeRequest = useActiveRequest();
|
|
||||||
const duplicateHttpRequest = useDuplicateHttpRequest({
|
|
||||||
id: activeRequest?.id ?? null,
|
|
||||||
navigateAfter: true,
|
|
||||||
});
|
|
||||||
const duplicateGrpcRequest = useDuplicateGrpcRequest({
|
|
||||||
id: activeRequest?.id ?? null,
|
|
||||||
navigateAfter: true,
|
|
||||||
});
|
|
||||||
useHotKey('http_request.duplicate', async () => {
|
|
||||||
const activeRequest = getActiveRequest();
|
|
||||||
if (activeRequest?.model === 'http_request') {
|
|
||||||
await duplicateHttpRequest.mutateAsync();
|
|
||||||
} else {
|
|
||||||
await duplicateGrpcRequest.mutateAsync();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const toggleCommandPalette = useToggleCommandPalette();
|
|
||||||
useHotKey('command_palette.toggle', toggleCommandPalette);
|
|
||||||
|
|
||||||
const prompt = usePrompt();
|
|
||||||
useListenToTauriEvent<{ replyId: string; args: PromptTextRequest }>(
|
useListenToTauriEvent<{ replyId: string; args: PromptTextRequest }>(
|
||||||
'show_prompt',
|
'show_prompt',
|
||||||
async (event) => {
|
async (event) => {
|
||||||
const value = await prompt(event.payload.args);
|
const value = await showPrompt(event.payload.args);
|
||||||
const result: PromptTextResponse = { value };
|
const result: PromptTextResponse = { value };
|
||||||
await emit(event.payload.replyId, result);
|
await emit(event.payload.replyId, result);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export function MarkdownEditor({ className, defaultValue, onChange, name, ...edi
|
|||||||
<Editor
|
<Editor
|
||||||
hideGutter
|
hideGutter
|
||||||
wrapLines
|
wrapLines
|
||||||
className="max-w-2xl max-h-full"
|
className="max-w-2xl max-h-full"
|
||||||
language="markdown"
|
language="markdown"
|
||||||
defaultValue={defaultValue}
|
defaultValue={defaultValue}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { memo, useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import { usePrompt } from '../hooks/usePrompt';
|
import { showPrompt } from '../lib/prompt';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import type { DropdownItem } from './core/Dropdown';
|
import type { DropdownItem } from './core/Dropdown';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
@@ -32,7 +32,6 @@ export const RequestMethodDropdown = memo(function RequestMethodDropdown({
|
|||||||
onChange,
|
onChange,
|
||||||
className,
|
className,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const prompt = usePrompt();
|
|
||||||
const extraItems = useMemo<DropdownItem[]>(
|
const extraItems = useMemo<DropdownItem[]>(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
@@ -40,7 +39,7 @@ export const RequestMethodDropdown = memo(function RequestMethodDropdown({
|
|||||||
label: 'CUSTOM',
|
label: 'CUSTOM',
|
||||||
leftSlot: <Icon icon="sparkles" />,
|
leftSlot: <Icon icon="sparkles" />,
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
const newMethod = await prompt({
|
const newMethod = await showPrompt({
|
||||||
id: 'custom-method',
|
id: 'custom-method',
|
||||||
label: 'Http Method',
|
label: 'Http Method',
|
||||||
defaultValue: '',
|
defaultValue: '',
|
||||||
@@ -54,7 +53,7 @@ export const RequestMethodDropdown = memo(function RequestMethodDropdown({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[onChange, prompt],
|
[onChange],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -298,7 +298,6 @@ export const RequestPane = memo(function RequestPane({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const activeTab = activeTabs?.[activeRequestId];
|
const activeTab = activeTabs?.[activeRequestId];
|
||||||
console.log('ACTIVE TAB', activeTab);
|
|
||||||
const setActiveTab = useCallback(
|
const setActiveTab = useCallback(
|
||||||
(tab: string) => {
|
(tab: string) => {
|
||||||
setActiveTabs((r) => ({ ...r, [activeRequest.id]: tab }));
|
setActiveTabs((r) => ({ ...r, [activeRequest.id]: tab }));
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { useUpdateAnyFolder } from '../hooks/useUpdateAnyFolder';
|
|||||||
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
||||||
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
||||||
import { router } from '../lib/router';
|
import { router } from '../lib/router';
|
||||||
|
import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams';
|
||||||
import { ContextMenu } from './core/Dropdown';
|
import { ContextMenu } from './core/Dropdown';
|
||||||
import { sidebarSelectedIdAtom, sidebarTreeAtom } from './SidebarAtoms';
|
import { sidebarSelectedIdAtom, sidebarTreeAtom } from './SidebarAtoms';
|
||||||
import type { SidebarItemProps } from './SidebarItem';
|
import type { SidebarItemProps } from './SidebarItem';
|
||||||
@@ -151,11 +152,7 @@ export function Sidebar({ className }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await router.navigate({
|
setWorkspaceSearchParams({ request_id: selected.id });
|
||||||
to: '/workspaces/$workspaceId',
|
|
||||||
params: { workspaceId: activeWorkspace?.id ?? null },
|
|
||||||
search: (prev) => ({ ...prev, request_id: selected.id }),
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
useKey(
|
useKey(
|
||||||
|
|||||||
@@ -2,13 +2,25 @@ import classNames from 'classnames';
|
|||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';
|
import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';
|
||||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
import {useEnsureActiveCookieJar, useSubscribeActiveCookieJarId} from "../hooks/useActiveCookieJar";
|
||||||
|
import {useSubscribeActiveEnvironmentId} from "../hooks/useActiveEnvironment";
|
||||||
|
import {getActiveRequest, useActiveRequest} from '../hooks/useActiveRequest';
|
||||||
|
import {useSubscribeActiveRequestId} from "../hooks/useActiveRequestId";
|
||||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||||
|
import {useDuplicateGrpcRequest} from "../hooks/useDuplicateGrpcRequest";
|
||||||
|
import {useDuplicateHttpRequest} from "../hooks/useDuplicateHttpRequest";
|
||||||
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
|
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
|
||||||
|
import {useHotKey} from "../hooks/useHotKey";
|
||||||
import { useImportData } from '../hooks/useImportData';
|
import { useImportData } from '../hooks/useImportData';
|
||||||
|
import {useSubscribeRecentCookieJars} from "../hooks/useRecentCookieJars";
|
||||||
|
import {useSubscribeRecentEnvironments} from "../hooks/useRecentEnvironments";
|
||||||
|
import {useSubscribeRecentRequests} from "../hooks/useRecentRequests";
|
||||||
|
import {useSubscribeRecentWorkspaces} from "../hooks/useRecentWorkspaces";
|
||||||
import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar';
|
import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar';
|
||||||
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
||||||
import { useSidebarWidth } from '../hooks/useSidebarWidth';
|
import { useSidebarWidth } from '../hooks/useSidebarWidth';
|
||||||
|
import {useSyncWorkspaceRequestTitle} from "../hooks/useSyncWorkspaceRequestTitle";
|
||||||
|
import {useToggleCommandPalette} from "../hooks/useToggleCommandPalette";
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
import { Banner } from './core/Banner';
|
import { Banner } from './core/Banner';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
@@ -31,6 +43,9 @@ const body = { gridArea: 'body' };
|
|||||||
const drag = { gridArea: 'drag' };
|
const drag = { gridArea: 'drag' };
|
||||||
|
|
||||||
export function Workspace() {
|
export function Workspace() {
|
||||||
|
// First, subscribe to some things applicable to workspaces
|
||||||
|
useGlobalWorkspaceHooks();
|
||||||
|
|
||||||
const workspaces = useWorkspaces();
|
const workspaces = useWorkspaces();
|
||||||
const { setWidth, width, resetWidth } = useSidebarWidth();
|
const { setWidth, width, resetWidth } = useSidebarWidth();
|
||||||
const [sidebarHidden, setSidebarHidden] = useSidebarHidden();
|
const [sidebarHidden, setSidebarHidden] = useSidebarHidden();
|
||||||
@@ -202,3 +217,40 @@ function WorkspaceBody() {
|
|||||||
|
|
||||||
return <HttpRequestLayout activeRequest={activeRequest} style={body} />;
|
return <HttpRequestLayout activeRequest={activeRequest} style={body} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useGlobalWorkspaceHooks() {
|
||||||
|
useEnsureActiveCookieJar();
|
||||||
|
|
||||||
|
useSubscribeActiveRequestId();
|
||||||
|
useSubscribeActiveEnvironmentId();
|
||||||
|
useSubscribeActiveCookieJarId();
|
||||||
|
|
||||||
|
useSubscribeRecentRequests();
|
||||||
|
useSubscribeRecentWorkspaces();
|
||||||
|
useSubscribeRecentEnvironments();
|
||||||
|
useSubscribeRecentCookieJars();
|
||||||
|
|
||||||
|
useSyncWorkspaceRequestTitle();
|
||||||
|
|
||||||
|
const toggleCommandPalette = useToggleCommandPalette();
|
||||||
|
useHotKey('command_palette.toggle', toggleCommandPalette);
|
||||||
|
|
||||||
|
const activeRequest = useActiveRequest();
|
||||||
|
const duplicateHttpRequest = useDuplicateHttpRequest({
|
||||||
|
id: activeRequest?.id ?? null,
|
||||||
|
navigateAfter: true,
|
||||||
|
});
|
||||||
|
const duplicateGrpcRequest = useDuplicateGrpcRequest({
|
||||||
|
id: activeRequest?.id ?? null,
|
||||||
|
navigateAfter: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
useHotKey('http_request.duplicate', async () => {
|
||||||
|
const activeRequest = getActiveRequest();
|
||||||
|
if (activeRequest?.model === 'http_request') {
|
||||||
|
await duplicateHttpRequest.mutateAsync();
|
||||||
|
} else {
|
||||||
|
await duplicateGrpcRequest.mutateAsync();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { useCreateWorkspace } from '../hooks/useCreateWorkspace';
|
|||||||
import { useDeleteSendHistory } from '../hooks/useDeleteSendHistory';
|
import { useDeleteSendHistory } from '../hooks/useDeleteSendHistory';
|
||||||
import { useOpenWorkspace } from '../hooks/useOpenWorkspace';
|
import { useOpenWorkspace } from '../hooks/useOpenWorkspace';
|
||||||
import { useSettings } from '../hooks/useSettings';
|
import { useSettings } from '../hooks/useSettings';
|
||||||
import { useSyncWorkspace } from '../hooks/useSyncWorkspace';
|
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
import { showDialog } from '../lib/dialog';
|
import { showDialog } from '../lib/dialog';
|
||||||
import { getWorkspace } from '../lib/store';
|
import { getWorkspace } from '../lib/store';
|
||||||
@@ -31,7 +30,6 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
|||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
const openWorkspace = useOpenWorkspace();
|
const openWorkspace = useOpenWorkspace();
|
||||||
const openWorkspaceNewWindow = settings?.openWorkspaceNewWindow ?? null;
|
const openWorkspaceNewWindow = settings?.openWorkspaceNewWindow ?? null;
|
||||||
const { sync } = useSyncWorkspace(activeWorkspace);
|
|
||||||
|
|
||||||
const orderedWorkspaces = useMemo(
|
const orderedWorkspaces = useMemo(
|
||||||
() => [...workspaces].sort((a, b) => (a.name.localeCompare(b.name) > 0 ? 1 : -1)),
|
() => [...workspaces].sort((a, b) => (a.name.localeCompare(b.name) > 0 ? 1 : -1)),
|
||||||
@@ -66,13 +64,6 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: 'sync',
|
|
||||||
label: 'Sync Workspace',
|
|
||||||
leftSlot: <Icon icon="folder_sync" />,
|
|
||||||
hidden: !activeWorkspace?.settingSyncDir,
|
|
||||||
onSelect: sync,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: 'delete-responses',
|
key: 'delete-responses',
|
||||||
label: 'Clear Send History',
|
label: 'Clear Send History',
|
||||||
@@ -89,14 +80,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
|||||||
];
|
];
|
||||||
|
|
||||||
return { workspaceItems, extraItems };
|
return { workspaceItems, extraItems };
|
||||||
}, [
|
}, [orderedWorkspaces, activeWorkspace?.id, deleteSendHistory, createWorkspace]);
|
||||||
orderedWorkspaces,
|
|
||||||
activeWorkspace?.settingSyncDir,
|
|
||||||
activeWorkspace?.id,
|
|
||||||
sync,
|
|
||||||
deleteSendHistory,
|
|
||||||
createWorkspace,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
async (workspaceId: string | null) => {
|
async (workspaceId: string | null) => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import { Button } from '../components/core/Button';
|
import { Button } from './Button';
|
||||||
import { HStack, VStack } from '../components/core/Stacks';
|
import { HStack, VStack } from './Stacks';
|
||||||
|
|
||||||
export interface AlertProps {
|
export interface AlertProps {
|
||||||
onHide: () => void;
|
onHide: () => void;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { ButtonProps } from '../components/core/Button';
|
import type { ButtonProps } from './Button';
|
||||||
import { Button } from '../components/core/Button';
|
import { Button } from './Button';
|
||||||
import { HStack } from '../components/core/Stacks';
|
import { HStack } from './Stacks';
|
||||||
|
|
||||||
export interface ConfirmProps {
|
export interface ConfirmProps {
|
||||||
onHide: () => void;
|
onHide: () => void;
|
||||||
@@ -12,9 +12,9 @@ import {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import type { XYCoord } from 'react-dnd';
|
import type { XYCoord } from 'react-dnd';
|
||||||
import { useDrag, useDrop } from 'react-dnd';
|
import { useDrag, useDrop } from 'react-dnd';
|
||||||
import { usePrompt } from '../../hooks/usePrompt';
|
|
||||||
import { useToggle } from '../../hooks/useToggle';
|
import { useToggle } from '../../hooks/useToggle';
|
||||||
import { generateId } from '../../lib/generateId';
|
import { generateId } from '../../lib/generateId';
|
||||||
|
import { showPrompt } from '../../lib/prompt';
|
||||||
import { DropMarker } from '../DropMarker';
|
import { DropMarker } from '../DropMarker';
|
||||||
import { SelectFile } from '../SelectFile';
|
import { SelectFile } from '../SelectFile';
|
||||||
import { Button } from './Button';
|
import { Button } from './Button';
|
||||||
@@ -556,7 +556,6 @@ function FileActionsDropdown({
|
|||||||
onChangeContentType: (contentType: string) => void;
|
onChangeContentType: (contentType: string) => void;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
}) {
|
}) {
|
||||||
const prompt = usePrompt();
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: string) => {
|
(v: string) => {
|
||||||
if (v === 'file') onChangeFile({ filePath: '' });
|
if (v === 'file') onChangeFile({ filePath: '' });
|
||||||
@@ -573,7 +572,7 @@ function FileActionsDropdown({
|
|||||||
leftSlot: <Icon icon="pencil" />,
|
leftSlot: <Icon icon="pencil" />,
|
||||||
hidden: !pair.isFile,
|
hidden: !pair.isFile,
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
const contentType = await prompt({
|
const contentType = await showPrompt({
|
||||||
id: 'content-type',
|
id: 'content-type',
|
||||||
require: false,
|
require: false,
|
||||||
title: 'Override Content-Type',
|
title: 'Override Content-Type',
|
||||||
@@ -604,7 +603,7 @@ function FileActionsDropdown({
|
|||||||
leftSlot: <Icon icon="trash" />,
|
leftSlot: <Icon icon="trash" />,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[onChangeContentType, onChangeFile, onDelete, pair.contentType, pair.isFile, prompt],
|
[onChangeContentType, onChangeFile, onDelete, pair.contentType, pair.isFile],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { PromptTextRequest } from '@yaakapp-internal/plugins';
|
import type { PromptTextRequest } from '@yaakapp-internal/plugins';
|
||||||
import type { FormEvent, ReactNode } from 'react';
|
import type { FormEvent, ReactNode } from 'react';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { Button } from '../components/core/Button';
|
import {PlainInput} from "./PlainInput";
|
||||||
import { PlainInput } from '../components/core/PlainInput';
|
import { HStack } from './Stacks';
|
||||||
import { HStack } from '../components/core/Stacks';
|
import { Button } from './Button';
|
||||||
|
|
||||||
export type PromptProps = Omit<PromptTextRequest, 'id' | 'title' | 'description'> & {
|
export type PromptProps = Omit<PromptTextRequest, 'id' | 'title' | 'description'> & {
|
||||||
description?: ReactNode;
|
description?: ReactNode;
|
||||||
@@ -3,34 +3,26 @@ import type { CookieJar } from '@yaakapp-internal/models';
|
|||||||
import { atom, useAtomValue } from 'jotai/index';
|
import { atom, useAtomValue } from 'jotai/index';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { jotaiStore } from '../lib/jotai';
|
import { jotaiStore } from '../lib/jotai';
|
||||||
import { router } from '../lib/router';
|
import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams';
|
||||||
import { cookieJarsAtom, useCookieJars } from './useCookieJars';
|
import { cookieJarsAtom, useCookieJars } from './useCookieJars';
|
||||||
|
|
||||||
export const QUERY_COOKIE_JAR_ID = 'cookie_jar_id';
|
export const QUERY_COOKIE_JAR_ID = 'cookie_jar_id';
|
||||||
|
|
||||||
export const activeCookieJarIdAtom = atom<string>();
|
export const activeCookieJarAtom = atom<CookieJar | null>(null);
|
||||||
|
|
||||||
export const activeCookieJarAtom = atom<CookieJar | null>((get) => {
|
|
||||||
const activeId = get(activeCookieJarIdAtom);
|
|
||||||
return get(cookieJarsAtom)?.find((e) => e.id === activeId) ?? null;
|
|
||||||
});
|
|
||||||
|
|
||||||
export function setActiveCookieJar(cookieJar: CookieJar) {
|
|
||||||
router.navigate({
|
|
||||||
from: '/workspaces/$workspaceId',
|
|
||||||
search: (prev) => ({ ...prev, cookie_jar_id: cookieJar.id }),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useActiveCookieJar() {
|
export function useActiveCookieJar() {
|
||||||
return useAtomValue(activeCookieJarAtom);
|
return useAtomValue(activeCookieJarAtom);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useSubscribeActiveCookieJarId() {
|
export function useSubscribeActiveCookieJarId() {
|
||||||
const { cookie_jar_id } = useSearch({ strict: false });
|
const search = useSearch({ strict: false });
|
||||||
|
const cookieJarId = search.cookie_jar_id;
|
||||||
|
const cookieJars = useAtomValue(cookieJarsAtom);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
jotaiStore.set(activeCookieJarIdAtom, cookie_jar_id ?? undefined);
|
if (search == null) return; // Happens during Vite hot reload
|
||||||
}, [cookie_jar_id]);
|
const activeCookieJar = cookieJars?.find((j) => j.id == cookieJarId) ?? null;
|
||||||
|
jotaiStore.set(activeCookieJarAtom, activeCookieJar);
|
||||||
|
}, [cookieJarId, cookieJars, search]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getActiveCookieJar() {
|
export function getActiveCookieJar() {
|
||||||
@@ -39,12 +31,12 @@ export function getActiveCookieJar() {
|
|||||||
|
|
||||||
export function useEnsureActiveCookieJar() {
|
export function useEnsureActiveCookieJar() {
|
||||||
const cookieJars = useCookieJars();
|
const cookieJars = useCookieJars();
|
||||||
const activeCookieJar = useActiveCookieJar();
|
const { cookie_jar_id: activeCookieJarId } = useSearch({ from: '/workspaces/$workspaceId/' });
|
||||||
|
|
||||||
// Set the active cookie jar to the first one, if none set
|
// Set the active cookie jar to the first one, if none set
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cookieJars == null) return; // Hasn't loaded yet
|
if (cookieJars == null) return; // Hasn't loaded yet
|
||||||
if (cookieJars.find((j) => j.id === activeCookieJar?.id)) {
|
if (cookieJars.find((j) => j.id === activeCookieJarId)) {
|
||||||
return; // There's an active jar
|
return; // There's an active jar
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +47,7 @@ export function useEnsureActiveCookieJar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// There's no active jar, so set it to the first one
|
// There's no active jar, so set it to the first one
|
||||||
console.log('Setting active cookie jar to', firstJar.id);
|
console.log('Setting active cookie jar to', cookieJars, activeCookieJarId, firstJar.id);
|
||||||
setActiveCookieJar(firstJar);
|
setWorkspaceSearchParams({ cookie_jar_id: firstJar.id });
|
||||||
}, [activeCookieJar?.id, cookieJars]);
|
}, [activeCookieJarId, cookieJars]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useAtomValue } from 'jotai';
|
|||||||
import { atom } from 'jotai/index';
|
import { atom } from 'jotai/index';
|
||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
import { jotaiStore } from '../lib/jotai';
|
import { jotaiStore } from '../lib/jotai';
|
||||||
import { router } from '../lib/router';
|
import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams';
|
||||||
import { environmentsAtom } from './useEnvironments';
|
import { environmentsAtom } from './useEnvironments';
|
||||||
|
|
||||||
export const QUERY_ENVIRONMENT_ID = 'environment_id';
|
export const QUERY_ENVIRONMENT_ID = 'environment_id';
|
||||||
@@ -18,11 +18,7 @@ export const activeEnvironmentAtom = atom<Environment | null>((get) => {
|
|||||||
|
|
||||||
export function useActiveEnvironment() {
|
export function useActiveEnvironment() {
|
||||||
const setId = useCallback(
|
const setId = useCallback(
|
||||||
(id: string | null) =>
|
(id: string | null) => setWorkspaceSearchParams({ environment_id: id }),
|
||||||
router.navigate({
|
|
||||||
from: '/workspaces/$workspaceId',
|
|
||||||
search: (prev) => ({ ...prev, environment_id: id }),
|
|
||||||
}),
|
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
const environment = useAtomValue(activeEnvironmentAtom);
|
const environment = useAtomValue(activeEnvironmentAtom);
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
import type { Folder, Workspace } from '@yaakapp-internal/models';
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { trackEvent } from '../lib/analytics';
|
|
||||||
import { router } from '../lib/router';
|
|
||||||
import { invokeCmd } from '../lib/tauri';
|
|
||||||
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
|
||||||
import { createFastMutation } from './useFastMutation';
|
|
||||||
import { usePrompt } from './usePrompt';
|
|
||||||
|
|
||||||
function makeCommands({ prompt }: { prompt: ReturnType<typeof usePrompt> }) {
|
|
||||||
return {
|
|
||||||
createWorkspace: createFastMutation<Workspace, void, Partial<Workspace>>({
|
|
||||||
mutationKey: ['create_workspace'],
|
|
||||||
mutationFn: (patch) => invokeCmd<Workspace>('cmd_update_workspace', { workspace: patch }),
|
|
||||||
onSuccess: async (workspace) => {
|
|
||||||
await router.navigate({
|
|
||||||
to: '/workspaces/$workspaceId',
|
|
||||||
params: { workspaceId: workspace.id },
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onSettled: () => trackEvent('workspace', 'create'),
|
|
||||||
}),
|
|
||||||
|
|
||||||
createFolder: createFastMutation<
|
|
||||||
Folder | null,
|
|
||||||
void,
|
|
||||||
Partial<Pick<Folder, 'name' | 'sortPriority' | 'folderId'>>
|
|
||||||
>({
|
|
||||||
mutationKey: ['create_folder'],
|
|
||||||
mutationFn: async (patch) => {
|
|
||||||
const workspaceId = getActiveWorkspaceId();
|
|
||||||
if (workspaceId == null) {
|
|
||||||
throw new Error("Cannot create folder when there's no active workspace");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!patch.name) {
|
|
||||||
const name = await prompt({
|
|
||||||
id: 'new-folder',
|
|
||||||
label: 'Name',
|
|
||||||
defaultValue: 'Folder',
|
|
||||||
title: 'New Folder',
|
|
||||||
confirmText: 'Create',
|
|
||||||
placeholder: 'Name',
|
|
||||||
});
|
|
||||||
if (name == null) return null;
|
|
||||||
|
|
||||||
patch.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
patch.sortPriority = patch.sortPriority || -Date.now();
|
|
||||||
return invokeCmd<Folder>('cmd_update_folder', { folder: { workspaceId, ...patch } });
|
|
||||||
},
|
|
||||||
onSettled: () => trackEvent('folder', 'create'),
|
|
||||||
}),
|
|
||||||
} as const;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useCommands() {
|
|
||||||
const prompt = usePrompt();
|
|
||||||
return useMemo(() => makeCommands({ prompt }), [prompt]);
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import { useCallback } from 'react';
|
|
||||||
import type { DialogProps } from '../components/core/Dialog';
|
|
||||||
import { showDialog } from '../lib/dialog';
|
|
||||||
import type { ConfirmProps } from './Confirm';
|
|
||||||
import { Confirm } from './Confirm';
|
|
||||||
|
|
||||||
export function useConfirm() {
|
|
||||||
return useCallback(
|
|
||||||
({
|
|
||||||
id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
variant,
|
|
||||||
confirmText,
|
|
||||||
}: {
|
|
||||||
id: string;
|
|
||||||
title: DialogProps['title'];
|
|
||||||
description?: DialogProps['description'];
|
|
||||||
variant?: ConfirmProps['variant'];
|
|
||||||
confirmText?: ConfirmProps['confirmText'];
|
|
||||||
}) =>
|
|
||||||
new Promise((onResult: ConfirmProps['onResult']) => {
|
|
||||||
showDialog({
|
|
||||||
id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
hideX: true,
|
|
||||||
size: 'sm',
|
|
||||||
render: ({ hide }) => Confirm({ onHide: hide, variant, onResult, confirmText }),
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
import type { CookieJar } from '@yaakapp-internal/models';
|
import type { CookieJar } from '@yaakapp-internal/models';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { showPrompt } from '../lib/prompt';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { usePrompt } from './usePrompt';
|
|
||||||
|
|
||||||
export function useCreateCookieJar() {
|
export function useCreateCookieJar() {
|
||||||
const prompt = usePrompt();
|
|
||||||
|
|
||||||
return useFastMutation<CookieJar | null>({
|
return useFastMutation<CookieJar | null>({
|
||||||
mutationKey: ['create_cookie_jar'],
|
mutationKey: ['create_cookie_jar'],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
@@ -15,7 +13,7 @@ export function useCreateCookieJar() {
|
|||||||
if (workspaceId == null) {
|
if (workspaceId == null) {
|
||||||
throw new Error("Cannot create cookie jar when there's no active workspace");
|
throw new Error("Cannot create cookie jar when there's no active workspace");
|
||||||
}
|
}
|
||||||
const name = await prompt({
|
const name = await showPrompt({
|
||||||
id: 'new-cookie-jar',
|
id: 'new-cookie-jar',
|
||||||
title: 'New CookieJar',
|
title: 'New CookieJar',
|
||||||
placeholder: 'My Jar',
|
placeholder: 'My Jar',
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import type { DropdownItem } from '../components/core/Dropdown';
|
import type { DropdownItem } from '../components/core/Dropdown';
|
||||||
import { Icon } from '../components/core/Icon';
|
import { Icon } from '../components/core/Icon';
|
||||||
|
import { createFolder } from '../lib/commands';
|
||||||
import { generateId } from '../lib/generateId';
|
import { generateId } from '../lib/generateId';
|
||||||
import { BODY_TYPE_GRAPHQL } from '../lib/model_util';
|
import { BODY_TYPE_GRAPHQL } from '../lib/model_util';
|
||||||
import { getActiveRequest } from './useActiveRequest';
|
import { getActiveRequest } from './useActiveRequest';
|
||||||
import { useCommands } from './useCommands';
|
|
||||||
import { useCreateGrpcRequest } from './useCreateGrpcRequest';
|
import { useCreateGrpcRequest } from './useCreateGrpcRequest';
|
||||||
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
||||||
|
|
||||||
@@ -19,7 +19,6 @@ export function useCreateDropdownItems({
|
|||||||
} = {}): DropdownItem[] {
|
} = {}): DropdownItem[] {
|
||||||
const { mutate: createHttpRequest } = useCreateHttpRequest();
|
const { mutate: createHttpRequest } = useCreateHttpRequest();
|
||||||
const { mutate: createGrpcRequest } = useCreateGrpcRequest();
|
const { mutate: createGrpcRequest } = useCreateGrpcRequest();
|
||||||
const { createFolder } = useCommands();
|
|
||||||
|
|
||||||
return useMemo((): DropdownItem[] => {
|
return useMemo((): DropdownItem[] => {
|
||||||
const folderId =
|
const folderId =
|
||||||
@@ -66,5 +65,5 @@ export function useCreateDropdownItems({
|
|||||||
},
|
},
|
||||||
]) as DropdownItem[]),
|
]) as DropdownItem[]),
|
||||||
];
|
];
|
||||||
}, [createFolder, createGrpcRequest, createHttpRequest, folderIdOption, hideFolder, hideIcons]);
|
}, [createGrpcRequest, createHttpRequest, folderIdOption, hideFolder, hideIcons]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import type { Environment } from '@yaakapp-internal/models';
|
import type { Environment } from '@yaakapp-internal/models';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { showPrompt } from '../lib/prompt';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||||
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { usePrompt } from './usePrompt';
|
|
||||||
|
|
||||||
export function useCreateEnvironment() {
|
export function useCreateEnvironment() {
|
||||||
const [, setActiveEnvironmentId] = useActiveEnvironment();
|
const [, setActiveEnvironmentId] = useActiveEnvironment();
|
||||||
const prompt = usePrompt();
|
|
||||||
|
|
||||||
return useFastMutation<Environment | null, unknown, Environment | null>({
|
return useFastMutation<Environment | null, unknown, Environment | null>({
|
||||||
mutationKey: ['create_environment'],
|
mutationKey: ['create_environment'],
|
||||||
@@ -18,7 +17,7 @@ export function useCreateEnvironment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const workspaceId = getActiveWorkspaceId();
|
const workspaceId = getActiveWorkspaceId();
|
||||||
const name = await prompt({
|
const name = await showPrompt({
|
||||||
id: 'new-environment',
|
id: 'new-environment',
|
||||||
title: 'New Environment',
|
title: 'New Environment',
|
||||||
description: 'Create multiple environments with different sets of variables',
|
description: 'Create multiple environments with different sets of variables',
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
import type { Workspace } from '@yaakapp-internal/models';
|
import type { Workspace } from '@yaakapp-internal/models';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { showConfirm } from '../lib/confirm';
|
||||||
import { router } from '../lib/router';
|
import { router } from '../lib/router';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { getActiveWorkspace } from './useActiveWorkspace';
|
import { getActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useConfirm } from './useConfirm';
|
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
|
|
||||||
export function useDeleteActiveWorkspace() {
|
export function useDeleteActiveWorkspace() {
|
||||||
const confirm = useConfirm();
|
|
||||||
|
|
||||||
return useFastMutation<Workspace | null, string>({
|
return useFastMutation<Workspace | null, string>({
|
||||||
mutationKey: ['delete_workspace'],
|
mutationKey: ['delete_workspace'],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
const workspace = getActiveWorkspace();
|
const workspace = getActiveWorkspace();
|
||||||
const confirmed = await confirm({
|
const confirmed = await showConfirm({
|
||||||
id: 'delete-workspace',
|
id: 'delete-workspace',
|
||||||
title: 'Delete Workspace',
|
title: 'Delete Workspace',
|
||||||
variant: 'delete',
|
variant: 'delete',
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { showConfirm } from '../lib/confirm';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import { getGrpcRequest } from '../lib/store';
|
import { getGrpcRequest } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useConfirm } from './useConfirm';
|
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
|
|
||||||
export function useDeleteAnyGrpcRequest() {
|
export function useDeleteAnyGrpcRequest() {
|
||||||
const confirm = useConfirm();
|
|
||||||
|
|
||||||
return useFastMutation<GrpcRequest | null, string, string>({
|
return useFastMutation<GrpcRequest | null, string, string>({
|
||||||
mutationKey: ['delete_any_grpc_request'],
|
mutationKey: ['delete_any_grpc_request'],
|
||||||
mutationFn: async (id) => {
|
mutationFn: async (id) => {
|
||||||
const request = await getGrpcRequest(id);
|
const request = await getGrpcRequest(id);
|
||||||
if (request == null) return null;
|
if (request == null) return null;
|
||||||
|
|
||||||
const confirmed = await confirm({
|
const confirmed = await showConfirm({
|
||||||
id: 'delete-grpc-request',
|
id: 'delete-grpc-request',
|
||||||
title: 'Delete Request',
|
title: 'Delete Request',
|
||||||
variant: 'delete',
|
variant: 'delete',
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { showConfirm } from '../lib/confirm';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import { getHttpRequest } from '../lib/store';
|
import { getHttpRequest } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useConfirm } from './useConfirm';
|
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
|
|
||||||
export function useDeleteAnyHttpRequest() {
|
export function useDeleteAnyHttpRequest() {
|
||||||
const confirm = useConfirm();
|
|
||||||
|
|
||||||
return useFastMutation<HttpRequest | null, string, string>({
|
return useFastMutation<HttpRequest | null, string, string>({
|
||||||
mutationKey: ['delete_any_http_request'],
|
mutationKey: ['delete_any_http_request'],
|
||||||
mutationFn: async (id) => {
|
mutationFn: async (id) => {
|
||||||
const request = await getHttpRequest(id);
|
const request = await getHttpRequest(id);
|
||||||
if (request == null) return null;
|
if (request == null) return null;
|
||||||
|
|
||||||
const confirmed = await confirm({
|
const confirmed = await showConfirm({
|
||||||
id: 'delete-request',
|
id: 'delete-request',
|
||||||
title: 'Delete Request',
|
title: 'Delete Request',
|
||||||
variant: 'delete',
|
variant: 'delete',
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
|
||||||
import type { CookieJar } from '@yaakapp-internal/models';
|
import type { CookieJar } from '@yaakapp-internal/models';
|
||||||
import { useSetAtom } from 'jotai';
|
import { useSetAtom } from 'jotai';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { showConfirm } from '../lib/confirm';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useConfirm } from './useConfirm';
|
|
||||||
import { cookieJarsAtom } from './useCookieJars';
|
import { cookieJarsAtom } from './useCookieJars';
|
||||||
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { removeModelById } from './useSyncModelStores';
|
import { removeModelById } from './useSyncModelStores';
|
||||||
|
|
||||||
export function useDeleteCookieJar(cookieJar: CookieJar | null) {
|
export function useDeleteCookieJar(cookieJar: CookieJar | null) {
|
||||||
const confirm = useConfirm();
|
|
||||||
const setCookieJars = useSetAtom(cookieJarsAtom);
|
const setCookieJars = useSetAtom(cookieJarsAtom);
|
||||||
|
|
||||||
return useFastMutation<CookieJar | null, string>({
|
return useFastMutation<CookieJar | null, string>({
|
||||||
mutationKey: ['delete_cookie_jar', cookieJar?.id],
|
mutationKey: ['delete_cookie_jar', cookieJar?.id],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
const confirmed = await confirm({
|
const confirmed = await showConfirm({
|
||||||
id: 'delete-cookie-jar',
|
id: 'delete-cookie-jar',
|
||||||
title: 'Delete CookieJar',
|
title: 'Delete CookieJar',
|
||||||
variant: 'delete',
|
variant: 'delete',
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
|
||||||
import type { Environment } from '@yaakapp-internal/models';
|
import type { Environment } from '@yaakapp-internal/models';
|
||||||
import {useSetAtom} from "jotai";
|
import { useSetAtom } from 'jotai';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { showConfirm } from '../lib/confirm';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useConfirm } from './useConfirm';
|
import { environmentsAtom } from './useEnvironments';
|
||||||
import {environmentsAtom} from "./useEnvironments";
|
import { useFastMutation } from './useFastMutation';
|
||||||
import {removeModelById} from "./useSyncModelStores";
|
import { removeModelById } from './useSyncModelStores';
|
||||||
|
|
||||||
export function useDeleteEnvironment(environment: Environment | null) {
|
export function useDeleteEnvironment(environment: Environment | null) {
|
||||||
const confirm = useConfirm();
|
|
||||||
const setEnvironments = useSetAtom(environmentsAtom);
|
const setEnvironments = useSetAtom(environmentsAtom);
|
||||||
|
|
||||||
return useFastMutation<Environment | null, string>({
|
return useFastMutation<Environment | null, string>({
|
||||||
mutationKey: ['delete_environment', environment?.id],
|
mutationKey: ['delete_environment', environment?.id],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
const confirmed = await confirm({
|
const confirmed = await showConfirm({
|
||||||
id: 'delete-environment',
|
id: 'delete-environment',
|
||||||
title: 'Delete Environment',
|
title: 'Delete Environment',
|
||||||
variant: 'delete',
|
variant: 'delete',
|
||||||
@@ -33,6 +32,6 @@ export function useDeleteEnvironment(environment: Environment | null) {
|
|||||||
if (environment == null) return;
|
if (environment == null) return;
|
||||||
|
|
||||||
setEnvironments(removeModelById(environment));
|
setEnvironments(removeModelById(environment));
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,22 +2,21 @@ import type { Folder } from '@yaakapp-internal/models';
|
|||||||
import { useSetAtom } from 'jotai';
|
import { useSetAtom } from 'jotai';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { showConfirm } from '../lib/confirm';
|
||||||
import { getFolder } from '../lib/store';
|
import { getFolder } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useConfirm } from './useConfirm';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { foldersAtom } from './useFolders';
|
import { foldersAtom } from './useFolders';
|
||||||
import { removeModelById } from './useSyncModelStores';
|
import { removeModelById } from './useSyncModelStores';
|
||||||
import { useFastMutation } from './useFastMutation';
|
|
||||||
|
|
||||||
export function useDeleteFolder(id: string | null) {
|
export function useDeleteFolder(id: string | null) {
|
||||||
const confirm = useConfirm();
|
|
||||||
const setFolders = useSetAtom(foldersAtom);
|
const setFolders = useSetAtom(foldersAtom);
|
||||||
|
|
||||||
return useFastMutation<Folder | null, string>({
|
return useFastMutation<Folder | null, string>({
|
||||||
mutationKey: ['delete_folder', id],
|
mutationKey: ['delete_folder', id],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
const folder = await getFolder(id);
|
const folder = await getFolder(id);
|
||||||
const confirmed = await confirm({
|
const confirmed = await showConfirm({
|
||||||
id: 'delete-folder',
|
id: 'delete-folder',
|
||||||
title: 'Delete Folder',
|
title: 'Delete Folder',
|
||||||
variant: 'delete',
|
variant: 'delete',
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import { useSetAtom } from 'jotai/index';
|
import { useSetAtom } from 'jotai/index';
|
||||||
import { showAlert } from '../lib/alert';
|
import { showAlert } from '../lib/alert';
|
||||||
|
import { showConfirm } from '../lib/confirm';
|
||||||
import { pluralizeCount } from '../lib/pluralize';
|
import { pluralizeCount } from '../lib/pluralize';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||||
import { useConfirm } from './useConfirm';
|
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { useGrpcConnections } from './useGrpcConnections';
|
import { useGrpcConnections } from './useGrpcConnections';
|
||||||
import { httpResponsesAtom, useHttpResponses } from './useHttpResponses';
|
import { httpResponsesAtom, useHttpResponses } from './useHttpResponses';
|
||||||
|
|
||||||
export function useDeleteSendHistory() {
|
export function useDeleteSendHistory() {
|
||||||
const confirm = useConfirm();
|
|
||||||
const setHttpResponses = useSetAtom(httpResponsesAtom);
|
const setHttpResponses = useSetAtom(httpResponsesAtom);
|
||||||
const httpResponses = useHttpResponses();
|
const httpResponses = useHttpResponses();
|
||||||
const grpcConnections = useGrpcConnections();
|
const grpcConnections = useGrpcConnections();
|
||||||
@@ -30,7 +29,7 @@ export function useDeleteSendHistory() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmed = await confirm({
|
const confirmed = await showConfirm({
|
||||||
id: 'delete-send-history',
|
id: 'delete-send-history',
|
||||||
title: 'Clear Send History',
|
title: 'Clear Send History',
|
||||||
variant: 'delete',
|
variant: 'delete',
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
import type { DialogProps } from '../components/core/Dialog';
|
|
||||||
import { showDialog } from '../lib/dialog';
|
|
||||||
import type { PromptProps } from './Prompt';
|
|
||||||
import { Prompt } from './Prompt';
|
|
||||||
|
|
||||||
type Props = Pick<DialogProps, 'title' | 'description'> &
|
|
||||||
Omit<PromptProps, 'onClose' | 'onCancel' | 'onResult'> & { id: string };
|
|
||||||
|
|
||||||
export function usePrompt() {
|
|
||||||
return ({ id, title, description, ...props }: Props) =>
|
|
||||||
new Promise((resolve: PromptProps['onResult']) => {
|
|
||||||
showDialog({
|
|
||||||
id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
hideX: true,
|
|
||||||
size: 'sm',
|
|
||||||
onClose: () => {
|
|
||||||
// Click backdrop, close, or escape
|
|
||||||
resolve(null);
|
|
||||||
},
|
|
||||||
render: ({ hide }) =>
|
|
||||||
Prompt({
|
|
||||||
onCancel: () => {
|
|
||||||
// Click cancel button within dialog
|
|
||||||
resolve(null);
|
|
||||||
hide();
|
|
||||||
},
|
|
||||||
onResult: (v) => {
|
|
||||||
resolve(v);
|
|
||||||
hide();
|
|
||||||
},
|
|
||||||
...props,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import { jotaiStore } from '../lib/jotai';
|
import { jotaiStore } from '../lib/jotai';
|
||||||
import { getKeyValue, setKeyValue } from '../lib/keyValueStore';
|
import { getKeyValue, setKeyValue } from '../lib/keyValueStore';
|
||||||
import { activeCookieJarIdAtom } from './useActiveCookieJar';
|
import {activeCookieJarAtom} from "./useActiveCookieJar";
|
||||||
import { activeWorkspaceIdAtom, useActiveWorkspace } from './useActiveWorkspace';
|
import { activeWorkspaceIdAtom, useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useCookieJars } from './useCookieJars';
|
import { useCookieJars } from './useCookieJars';
|
||||||
import { useKeyValue } from './useKeyValue';
|
import { useKeyValue } from './useKeyValue';
|
||||||
@@ -29,9 +29,9 @@ export function useRecentCookieJars() {
|
|||||||
|
|
||||||
export function useSubscribeRecentCookieJars() {
|
export function useSubscribeRecentCookieJars() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return jotaiStore.sub(activeCookieJarIdAtom, async () => {
|
return jotaiStore.sub(activeCookieJarAtom, async () => {
|
||||||
const activeWorkspaceId = jotaiStore.get(activeWorkspaceIdAtom);
|
const activeWorkspaceId = jotaiStore.get(activeWorkspaceIdAtom);
|
||||||
const activeCookieJarId = jotaiStore.get(activeCookieJarIdAtom);
|
const activeCookieJarId = jotaiStore.get(activeCookieJarAtom)?.id ?? null;
|
||||||
if (activeWorkspaceId == null) return;
|
if (activeWorkspaceId == null) return;
|
||||||
if (activeCookieJarId == null) return;
|
if (activeCookieJarId == null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
|
||||||
import type { GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
|
import type { GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { usePrompt } from './usePrompt';
|
import {showPrompt} from "../lib/prompt";
|
||||||
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { useRequests } from './useRequests';
|
import { useRequests } from './useRequests';
|
||||||
import { useUpdateAnyGrpcRequest } from './useUpdateAnyGrpcRequest';
|
import { useUpdateAnyGrpcRequest } from './useUpdateAnyGrpcRequest';
|
||||||
import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
|
||||||
|
|
||||||
export function useRenameRequest(requestId: string | null) {
|
export function useRenameRequest(requestId: string | null) {
|
||||||
const prompt = usePrompt();
|
|
||||||
const updateHttpRequest = useUpdateAnyHttpRequest();
|
const updateHttpRequest = useUpdateAnyHttpRequest();
|
||||||
const updateGrpcRequest = useUpdateAnyGrpcRequest();
|
const updateGrpcRequest = useUpdateAnyGrpcRequest();
|
||||||
const requests = useRequests();
|
const requests = useRequests();
|
||||||
@@ -18,7 +17,7 @@ export function useRenameRequest(requestId: string | null) {
|
|||||||
const request = requests.find((r) => r.id === requestId);
|
const request = requests.find((r) => r.id === requestId);
|
||||||
if (request == null) return;
|
if (request == null) return;
|
||||||
|
|
||||||
const name = await prompt({
|
const name = await showPrompt({
|
||||||
id: 'rename-request',
|
id: 'rename-request',
|
||||||
title: 'Rename Request',
|
title: 'Rename Request',
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import { applySync, calculateSync } from '@yaakapp-internal/sync';
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { VStack } from '../components/core/Stacks';
|
import { VStack } from '../components/core/Stacks';
|
||||||
|
import {showConfirm} from "../lib/confirm";
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import { pluralizeCount } from '../lib/pluralize';
|
import { pluralizeCount } from '../lib/pluralize';
|
||||||
import { useConfirm } from './useConfirm';
|
|
||||||
|
|
||||||
export function useSyncWorkspace(
|
export function useSyncWorkspace(
|
||||||
workspace: Workspace | null,
|
workspace: Workspace | null,
|
||||||
@@ -16,12 +16,10 @@ export function useSyncWorkspace(
|
|||||||
debounceMillis?: number;
|
debounceMillis?: number;
|
||||||
} = {},
|
} = {},
|
||||||
) {
|
) {
|
||||||
const confirm = useConfirm();
|
|
||||||
|
|
||||||
const sync = useCallback(async () => {
|
const sync = useCallback(async () => {
|
||||||
if (workspace == null) return;
|
if (workspace == null || workspace.settingSyncDir) return;
|
||||||
|
|
||||||
const ops = await calculateSync(workspace);
|
const ops = await calculateSync(workspace) ?? [];
|
||||||
if (ops.length === 0) {
|
if (ops.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -33,7 +31,7 @@ export function useSyncWorkspace(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmed = await confirm({
|
const confirmed = await showConfirm({
|
||||||
id: 'commit-sync',
|
id: 'commit-sync',
|
||||||
title: 'Filesystem Changes Detected',
|
title: 'Filesystem Changes Detected',
|
||||||
confirmText: 'Apply Changes',
|
confirmText: 'Apply Changes',
|
||||||
@@ -92,7 +90,7 @@ export function useSyncWorkspace(
|
|||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
await applySync(workspace, ops);
|
await applySync(workspace, ops);
|
||||||
}
|
}
|
||||||
}, [confirm, workspace]);
|
}, [workspace]);
|
||||||
|
|
||||||
const debouncedSync = useMemo(() => {
|
const debouncedSync = useMemo(() => {
|
||||||
return debounce(sync, debounceMillis);
|
return debounce(sync, debounceMillis);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import type { AlertProps } from '../components/core/Alert';
|
||||||
|
import { Alert } from '../components/core/Alert';
|
||||||
import type { DialogProps } from '../components/core/Dialog';
|
import type { DialogProps } from '../components/core/Dialog';
|
||||||
import type { AlertProps } from '../hooks/Alert';
|
|
||||||
import { Alert } from '../hooks/Alert';
|
|
||||||
import { showDialog } from './dialog';
|
import { showDialog } from './dialog';
|
||||||
|
|
||||||
interface AlertArgs {
|
interface AlertArgs {
|
||||||
|
|||||||
51
src-web/lib/commands.ts
Normal file
51
src-web/lib/commands.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import type { Folder, Workspace } from '@yaakapp-internal/models';
|
||||||
|
import { getActiveWorkspaceId } from '../hooks/useActiveWorkspace';
|
||||||
|
import { createFastMutation } from '../hooks/useFastMutation';
|
||||||
|
import { trackEvent } from './analytics';
|
||||||
|
import { showPrompt } from './prompt';
|
||||||
|
import { router } from './router';
|
||||||
|
import { invokeCmd } from './tauri';
|
||||||
|
|
||||||
|
export const createWorkspace = createFastMutation<Workspace, void, Partial<Workspace>>({
|
||||||
|
mutationKey: ['create_workspace'],
|
||||||
|
mutationFn: (patch) => invokeCmd<Workspace>('cmd_update_workspace', { workspace: patch }),
|
||||||
|
onSuccess: async (workspace) => {
|
||||||
|
await router.navigate({
|
||||||
|
to: '/workspaces/$workspaceId',
|
||||||
|
params: { workspaceId: workspace.id },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onSettled: () => trackEvent('workspace', 'create'),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createFolder = createFastMutation<
|
||||||
|
Folder | null,
|
||||||
|
void,
|
||||||
|
Partial<Pick<Folder, 'name' | 'sortPriority' | 'folderId'>>
|
||||||
|
>({
|
||||||
|
mutationKey: ['create_folder'],
|
||||||
|
mutationFn: async (patch) => {
|
||||||
|
const workspaceId = getActiveWorkspaceId();
|
||||||
|
if (workspaceId == null) {
|
||||||
|
throw new Error("Cannot create folder when there's no active workspace");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!patch.name) {
|
||||||
|
const name = await showPrompt({
|
||||||
|
id: 'new-folder',
|
||||||
|
label: 'Name',
|
||||||
|
defaultValue: 'Folder',
|
||||||
|
title: 'New Folder',
|
||||||
|
confirmText: 'Create',
|
||||||
|
placeholder: 'Name',
|
||||||
|
});
|
||||||
|
if (name == null) return null;
|
||||||
|
|
||||||
|
patch.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
patch.sortPriority = patch.sortPriority || -Date.now();
|
||||||
|
return invokeCmd<Folder>('cmd_update_folder', { folder: { workspaceId, ...patch } });
|
||||||
|
},
|
||||||
|
onSettled: () => trackEvent('folder', 'create'),
|
||||||
|
});
|
||||||
25
src-web/lib/confirm.ts
Normal file
25
src-web/lib/confirm.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import type { ConfirmProps } from '../components/core/Confirm';
|
||||||
|
import { Confirm } from '../components/core/Confirm';
|
||||||
|
import type { DialogProps } from '../components/core/Dialog';
|
||||||
|
import { showDialog } from './dialog';
|
||||||
|
|
||||||
|
interface ConfirmArgs {
|
||||||
|
id: string;
|
||||||
|
title: DialogProps['title'];
|
||||||
|
description?: DialogProps['description'];
|
||||||
|
variant?: ConfirmProps['variant'];
|
||||||
|
confirmText?: ConfirmProps['confirmText'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function showConfirm({ id, title, description, variant, confirmText }: ConfirmArgs) {
|
||||||
|
return new Promise((onResult: ConfirmProps['onResult']) => {
|
||||||
|
showDialog({
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
hideX: true,
|
||||||
|
size: 'sm',
|
||||||
|
render: ({ hide }) => Confirm({ onHide: hide, variant, onResult, confirmText }),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
36
src-web/lib/prompt.ts
Normal file
36
src-web/lib/prompt.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import type { DialogProps } from '../components/core/Dialog';
|
||||||
|
import type { PromptProps } from '../components/core/Prompt';
|
||||||
|
import { Prompt } from '../components/core/Prompt';
|
||||||
|
import { showDialog } from './dialog';
|
||||||
|
|
||||||
|
type PromptArgs = Pick<DialogProps, 'title' | 'description'> &
|
||||||
|
Omit<PromptProps, 'onClose' | 'onCancel' | 'onResult'> & { id: string };
|
||||||
|
|
||||||
|
export async function showPrompt({ id, title, description, ...props }: PromptArgs) {
|
||||||
|
return new Promise((resolve: PromptProps['onResult']) => {
|
||||||
|
showDialog({
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
hideX: true,
|
||||||
|
size: 'sm',
|
||||||
|
onClose: () => {
|
||||||
|
// Click backdrop, close, or escape
|
||||||
|
resolve(null);
|
||||||
|
},
|
||||||
|
render: ({ hide }) =>
|
||||||
|
Prompt({
|
||||||
|
onCancel: () => {
|
||||||
|
// Click cancel button within dialog
|
||||||
|
resolve(null);
|
||||||
|
hide();
|
||||||
|
},
|
||||||
|
onResult: (v) => {
|
||||||
|
resolve(v);
|
||||||
|
hide();
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
20
src-web/lib/setWorkspaceSearchParams.ts
Normal file
20
src-web/lib/setWorkspaceSearchParams.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { router } from './router.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setting search params using "from" on the global router instance in tanstack router does not
|
||||||
|
* currently behave very well, so this is a wrapper function that gives a typesafe interface
|
||||||
|
* for the same thing.
|
||||||
|
*/
|
||||||
|
export function setWorkspaceSearchParams(
|
||||||
|
search: Partial<{
|
||||||
|
cookie_jar_id: string | null;
|
||||||
|
environment_id: string | null;
|
||||||
|
request_id: string | null;
|
||||||
|
}>,
|
||||||
|
) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
(router as any).navigate({
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
search: (prev: any) => ({ ...prev, ...search }),
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router'
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
import { Workspace } from '../../../components/Workspace'
|
import { Workspace } from '../../../components/Workspace';
|
||||||
|
|
||||||
interface WorkspaceSearchSchema {
|
interface WorkspaceSearchSchema {
|
||||||
request_id?: string | null
|
request_id?: string | null;
|
||||||
environment_id?: string | null
|
environment_id?: string | null;
|
||||||
cookie_jar_id?: string | null
|
cookie_jar_id?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Route = createFileRoute('/workspaces/$workspaceId/')({
|
export const Route = createFileRoute('/workspaces/$workspaceId/')({
|
||||||
@@ -14,8 +14,8 @@ export const Route = createFileRoute('/workspaces/$workspaceId/')({
|
|||||||
environment_id: search.environment_id as string,
|
environment_id: search.environment_id as string,
|
||||||
cookie_jar_id: search.cookie_jar_id as string,
|
cookie_jar_id: search.cookie_jar_id as string,
|
||||||
}),
|
}),
|
||||||
})
|
});
|
||||||
|
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
return <Workspace />
|
return <Workspace />;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user