A bunch of changes, including moving prompt/confirm out of context

This commit is contained in:
Gregory Schier
2025-01-07 06:56:51 -08:00
parent 4776bbc753
commit 2f7b66fc92
41 changed files with 315 additions and 353 deletions

View File

@@ -6,7 +6,7 @@ import { SyncOp } from './bindings/sync';
import { WatchEvent, WatchResult } from './bindings/watch';
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', {
workspaceId: workspace.id,
@@ -15,6 +15,8 @@ export async function calculateSync(workspace: Workspace) {
}
export async function applySync(workspace: Workspace, syncOps: SyncOp[]) {
if (!workspace.settingSyncDir) return;
return invoke<void>('plugin:yaak-sync|apply', {
workspaceId: workspace.id,
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) {
const workspaceId = workspace?.id ?? null;
useEffect(() => {
if (workspaceId == null) return;
if (workspace == null) return;
if (!workspace.settingSyncDir) return;
const channel = new Channel<WatchEvent>();
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 () => {
promise
.then(({ unlistenEvent }) => {
console.log('Cancelling workspace watch', workspaceId, unlistenEvent);
console.log('Cancelling workspace watch', workspace.id, unlistenEvent);
return emit(unlistenEvent);
})
.catch(console.error);
};
}, [workspaceId]);
}, [workspace]);
}

View File

@@ -5,7 +5,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useActiveCookieJar } from '../hooks/useActiveCookieJar';
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
import { useActiveRequest } from '../hooks/useActiveRequest';
import { useCommands } from '../hooks/useCommands';
import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
import { useCreateGrpcRequest } from '../hooks/useCreateGrpcRequest';
import { useCreateHttpRequest } from '../hooks/useCreateHttpRequest';
@@ -27,6 +26,7 @@ import { useScrollIntoView } from '../hooks/useScrollIntoView';
import { useSendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
import { useSidebarHidden } from '../hooks/useSidebarHidden';
import { useWorkspaces } from '../hooks/useWorkspaces';
import { createFolder } from '../lib/commands';
import { showDialog, toggleDialog } from '../lib/dialog';
import { fallbackRequestName } from '../lib/fallbackRequestName';
import { router } from '../lib/router';
@@ -69,7 +69,6 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
const [recentRequests] = useRecentRequests();
const openWorkspace = useOpenWorkspace();
const createHttpRequest = useCreateHttpRequest();
const { createFolder } = useCommands();
const activeCookieJar = useActiveCookieJar();
const createGrpcRequest = useCreateGrpcRequest();
const createEnvironment = useCreateEnvironment();
@@ -188,7 +187,6 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
activeRequest,
baseEnvironment,
createEnvironment,
createFolder,
createGrpcRequest,
createHttpRequest,
createWorkspace,

View File

@@ -1,12 +1,13 @@
import { useAtomValue } from 'jotai';
import { memo, useMemo } from 'react';
import { setActiveCookieJar, useActiveCookieJar } from '../hooks/useActiveCookieJar';
import { useActiveCookieJar } from '../hooks/useActiveCookieJar';
import { cookieJarsAtom } from '../hooks/useCookieJars';
import { useCreateCookieJar } from '../hooks/useCreateCookieJar';
import { useDeleteCookieJar } from '../hooks/useDeleteCookieJar';
import { usePrompt } from '../hooks/usePrompt';
import { useUpdateCookieJar } from '../hooks/useUpdateCookieJar';
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 { Dropdown, type DropdownItem } from './core/Dropdown';
import { Icon } from './core/Icon';
@@ -18,18 +19,19 @@ export const CookieDropdown = memo(function CookieDropdown() {
const updateCookieJar = useUpdateCookieJar(activeCookieJar?.id ?? null);
const deleteCookieJar = useDeleteCookieJar(activeCookieJar ?? null);
const createCookieJar = useCreateCookieJar();
const prompt = usePrompt();
const cookieJars = useAtomValue(cookieJarsAtom);
const items = useMemo((): DropdownItem[] => {
const cookieJars = jotaiStore.get(cookieJarsAtom) ?? [];
return [
...cookieJars.map((j) => ({
...(cookieJars ?? []).map((j) => ({
key: j.id,
label: j.name,
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 },
{
@@ -51,7 +53,7 @@ export const CookieDropdown = memo(function CookieDropdown() {
label: 'Rename',
leftSlot: <Icon icon="pencil" />,
onSelect: async () => {
const name = await prompt({
const name = await showPrompt({
id: 'rename-cookie-jar',
title: 'Rename Cookie Jar',
description: (
@@ -68,7 +70,7 @@ export const CookieDropdown = memo(function CookieDropdown() {
updateCookieJar.mutate({ name });
},
},
...((cookieJars.length > 1 // Never delete the last one
...(((cookieJars ?? []).length > 1 // Never delete the last one
? [
{
key: 'delete',
@@ -89,7 +91,7 @@ export const CookieDropdown = memo(function CookieDropdown() {
onSelect: () => createCookieJar.mutate(),
},
];
}, [activeCookieJar, createCookieJar, deleteCookieJar, prompt, updateCookieJar]);
}, [activeCookieJar, cookieJars, createCookieJar, deleteCookieJar, updateCookieJar]);
return (
<Dropdown items={items}>

View File

@@ -1,5 +1,5 @@
import { useState } from 'react';
import { useCommands } from '../hooks/useCommands';
import {createWorkspace} from "../lib/commands";
import { Button } from './core/Button';
import { PlainInput } from './core/PlainInput';
import { VStack } from './core/Stacks';
@@ -14,7 +14,6 @@ export function CreateWorkspaceDialog({ hide }: Props) {
const [name, setName] = useState<string>('');
const [description, setDescription] = useState<string>('');
const [settingSyncDir, setSettingSyncDir] = useState<string | null>(null);
const { createWorkspace } = useCommands();
return (
<VStack

View File

@@ -12,19 +12,26 @@ export function Dialogs() {
const dialogs = useAtomValue(dialogsAtom);
return (
<>
{dialogs.map(({ render, onClose, id, ...props }: DialogInstance) => (
<Dialog
open
key={id}
onClose={() => {
onClose?.();
hideDialog(id);
}}
{...props}
>
{render({ hide: () => hideDialog(id) })}
</Dialog>
{dialogs.map(({ id, ...props }) => (
<DialogInstance key={id} id={id} {...props} />
))}
</>
);
}
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>
);
}

View File

@@ -6,8 +6,8 @@ import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
import { useDeleteEnvironment } from '../hooks/useDeleteEnvironment';
import { useEnvironments } from '../hooks/useEnvironments';
import { useKeyValue } from '../hooks/useKeyValue';
import { usePrompt } from '../hooks/usePrompt';
import { useUpdateEnvironment } from '../hooks/useUpdateEnvironment';
import { showPrompt } from '../lib/prompt';
import { Banner } from './core/Banner';
import { Button } from './core/Button';
import { ContextMenu } from './core/Dropdown';
@@ -212,7 +212,6 @@ function SidebarButton({
rightSlot?: ReactNode;
environment: Environment | null;
}) {
const prompt = usePrompt();
const updateEnvironment = useUpdateEnvironment(environment?.id ?? null);
const deleteEnvironment = useDeleteEnvironment(environment);
const [showContextMenu, setShowContextMenu] = useState<{
@@ -260,7 +259,7 @@ function SidebarButton({
label: 'Rename',
leftSlot: <Icon icon="pencil" size="sm" />,
onSelect: async () => {
const name = await prompt({
const name = await showPrompt({
id: 'rename-environment',
title: 'Rename Environment',
description: (

View File

@@ -2,34 +2,18 @@ import { emit } from '@tauri-apps/api/event';
import type { PromptTextRequest, PromptTextResponse } from '@yaakapp-internal/plugins';
import { useWatchWorkspace } from '@yaakapp-internal/sync';
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 { useActiveWorkspaceChangedToast } from '../hooks/useActiveWorkspaceChangedToast';
import { useDuplicateGrpcRequest } from '../hooks/useDuplicateGrpcRequest';
import { useDuplicateHttpRequest } from '../hooks/useDuplicateHttpRequest';
import { useGenerateThemeCss } from '../hooks/useGenerateThemeCss';
import { useHotKey } from '../hooks/useHotKey';
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
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 { useSyncModelStores } from '../hooks/useSyncModelStores';
import { useSyncWorkspace } from '../hooks/useSyncWorkspace';
import { useSyncWorkspaceChildModels } from '../hooks/useSyncWorkspaceChildModels';
import { useSyncWorkspaceRequestTitle } from '../hooks/useSyncWorkspaceRequestTitle';
import { useSyncZoomSetting } from '../hooks/useSyncZoomSetting';
import { useSubscribeTemplateFunctions } from '../hooks/useTemplateFunctions';
import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
import { showPrompt } from '../lib/prompt';
import { showToast } from '../lib/toast';
export function GlobalHooks() {
@@ -37,17 +21,8 @@ export function GlobalHooks() {
useSyncZoomSetting();
useSyncFontSizeSetting();
useGenerateThemeCss();
useSyncWorkspaceRequestTitle();
useSubscribeActiveWorkspaceId();
useSubscribeActiveRequestId();
useSubscribeActiveEnvironmentId();
useSubscribeActiveCookieJarId();
useSubscribeRecentRequests();
useSubscribeRecentWorkspaces();
useSubscribeRecentEnvironments();
useSubscribeRecentCookieJars();
useSyncWorkspaceChildModels();
useSubscribeTemplateFunctions();
@@ -55,7 +30,6 @@ export function GlobalHooks() {
// Other useful things
useNotificationToast();
useActiveWorkspaceChangedToast();
useEnsureActiveCookieJar();
// Listen for toasts
useListenToTauriEvent<ShowToastRequest>('show_toast', (event) => {
@@ -68,32 +42,10 @@ export function GlobalHooks() {
useListenToTauriEvent('upserted_model', 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 }>(
'show_prompt',
async (event) => {
const value = await prompt(event.payload.args);
const value = await showPrompt(event.payload.args);
const result: PromptTextResponse = { value };
await emit(event.payload.replyId, result);
},

View File

@@ -42,7 +42,7 @@ export function MarkdownEditor({ className, defaultValue, onChange, name, ...edi
<Editor
hideGutter
wrapLines
className="max-w-2xl max-h-full"
className="max-w-2xl max-h-full"
language="markdown"
defaultValue={defaultValue}
onChange={onChange}

View File

@@ -1,6 +1,6 @@
import classNames from 'classnames';
import { memo, useMemo } from 'react';
import { usePrompt } from '../hooks/usePrompt';
import { showPrompt } from '../lib/prompt';
import { Button } from './core/Button';
import type { DropdownItem } from './core/Dropdown';
import { Icon } from './core/Icon';
@@ -32,7 +32,6 @@ export const RequestMethodDropdown = memo(function RequestMethodDropdown({
onChange,
className,
}: Props) {
const prompt = usePrompt();
const extraItems = useMemo<DropdownItem[]>(
() => [
{
@@ -40,7 +39,7 @@ export const RequestMethodDropdown = memo(function RequestMethodDropdown({
label: 'CUSTOM',
leftSlot: <Icon icon="sparkles" />,
onSelect: async () => {
const newMethod = await prompt({
const newMethod = await showPrompt({
id: 'custom-method',
label: 'Http Method',
defaultValue: '',
@@ -54,7 +53,7 @@ export const RequestMethodDropdown = memo(function RequestMethodDropdown({
},
},
],
[onChange, prompt],
[onChange],
);
return (

View File

@@ -298,7 +298,6 @@ export const RequestPane = memo(function RequestPane({
);
const activeTab = activeTabs?.[activeRequestId];
console.log('ACTIVE TAB', activeTab);
const setActiveTab = useCallback(
(tab: string) => {
setActiveTabs((r) => ({ ...r, [activeRequest.id]: tab }));

View File

@@ -15,6 +15,7 @@ import { useUpdateAnyFolder } from '../hooks/useUpdateAnyFolder';
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
import { router } from '../lib/router';
import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams';
import { ContextMenu } from './core/Dropdown';
import { sidebarSelectedIdAtom, sidebarTreeAtom } from './SidebarAtoms';
import type { SidebarItemProps } from './SidebarItem';
@@ -151,11 +152,7 @@ export function Sidebar({ className }: Props) {
}
e.preventDefault();
await router.navigate({
to: '/workspaces/$workspaceId',
params: { workspaceId: activeWorkspace?.id ?? null },
search: (prev) => ({ ...prev, request_id: selected.id }),
});
setWorkspaceSearchParams({ request_id: selected.id });
});
useKey(

View File

@@ -2,13 +2,25 @@ import classNames from 'classnames';
import { motion } from 'framer-motion';
import type { CSSProperties, MouseEvent as ReactMouseEvent } 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 {useDuplicateGrpcRequest} from "../hooks/useDuplicateGrpcRequest";
import {useDuplicateHttpRequest} from "../hooks/useDuplicateHttpRequest";
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
import {useHotKey} from "../hooks/useHotKey";
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 { useSidebarHidden } from '../hooks/useSidebarHidden';
import { useSidebarWidth } from '../hooks/useSidebarWidth';
import {useSyncWorkspaceRequestTitle} from "../hooks/useSyncWorkspaceRequestTitle";
import {useToggleCommandPalette} from "../hooks/useToggleCommandPalette";
import { useWorkspaces } from '../hooks/useWorkspaces';
import { Banner } from './core/Banner';
import { Button } from './core/Button';
@@ -31,6 +43,9 @@ const body = { gridArea: 'body' };
const drag = { gridArea: 'drag' };
export function Workspace() {
// First, subscribe to some things applicable to workspaces
useGlobalWorkspaceHooks();
const workspaces = useWorkspaces();
const { setWidth, width, resetWidth } = useSidebarWidth();
const [sidebarHidden, setSidebarHidden] = useSidebarHidden();
@@ -202,3 +217,40 @@ function WorkspaceBody() {
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();
}
});
}

View File

@@ -5,7 +5,6 @@ import { useCreateWorkspace } from '../hooks/useCreateWorkspace';
import { useDeleteSendHistory } from '../hooks/useDeleteSendHistory';
import { useOpenWorkspace } from '../hooks/useOpenWorkspace';
import { useSettings } from '../hooks/useSettings';
import { useSyncWorkspace } from '../hooks/useSyncWorkspace';
import { useWorkspaces } from '../hooks/useWorkspaces';
import { showDialog } from '../lib/dialog';
import { getWorkspace } from '../lib/store';
@@ -31,7 +30,6 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
const settings = useSettings();
const openWorkspace = useOpenWorkspace();
const openWorkspaceNewWindow = settings?.openWorkspaceNewWindow ?? null;
const { sync } = useSyncWorkspace(activeWorkspace);
const orderedWorkspaces = useMemo(
() => [...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',
label: 'Clear Send History',
@@ -89,14 +80,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
];
return { workspaceItems, extraItems };
}, [
orderedWorkspaces,
activeWorkspace?.settingSyncDir,
activeWorkspace?.id,
sync,
deleteSendHistory,
createWorkspace,
]);
}, [orderedWorkspaces, activeWorkspace?.id, deleteSendHistory, createWorkspace]);
const handleChange = useCallback(
async (workspaceId: string | null) => {

View File

@@ -1,6 +1,6 @@
import type { ReactNode } from 'react';
import { Button } from '../components/core/Button';
import { HStack, VStack } from '../components/core/Stacks';
import { Button } from './Button';
import { HStack, VStack } from './Stacks';
export interface AlertProps {
onHide: () => void;

View File

@@ -1,6 +1,6 @@
import type { ButtonProps } from '../components/core/Button';
import { Button } from '../components/core/Button';
import { HStack } from '../components/core/Stacks';
import type { ButtonProps } from './Button';
import { Button } from './Button';
import { HStack } from './Stacks';
export interface ConfirmProps {
onHide: () => void;

View File

@@ -12,9 +12,9 @@ import {
} from 'react';
import type { XYCoord } from 'react-dnd';
import { useDrag, useDrop } from 'react-dnd';
import { usePrompt } from '../../hooks/usePrompt';
import { useToggle } from '../../hooks/useToggle';
import { generateId } from '../../lib/generateId';
import { showPrompt } from '../../lib/prompt';
import { DropMarker } from '../DropMarker';
import { SelectFile } from '../SelectFile';
import { Button } from './Button';
@@ -556,7 +556,6 @@ function FileActionsDropdown({
onChangeContentType: (contentType: string) => void;
onDelete: () => void;
}) {
const prompt = usePrompt();
const onChange = useCallback(
(v: string) => {
if (v === 'file') onChangeFile({ filePath: '' });
@@ -573,7 +572,7 @@ function FileActionsDropdown({
leftSlot: <Icon icon="pencil" />,
hidden: !pair.isFile,
onSelect: async () => {
const contentType = await prompt({
const contentType = await showPrompt({
id: 'content-type',
require: false,
title: 'Override Content-Type',
@@ -604,7 +603,7 @@ function FileActionsDropdown({
leftSlot: <Icon icon="trash" />,
},
],
[onChangeContentType, onChangeFile, onDelete, pair.contentType, pair.isFile, prompt],
[onChangeContentType, onChangeFile, onDelete, pair.contentType, pair.isFile],
);
return (

View File

@@ -1,9 +1,9 @@
import type { PromptTextRequest } from '@yaakapp-internal/plugins';
import type { FormEvent, ReactNode } from 'react';
import { useCallback, useState } from 'react';
import { Button } from '../components/core/Button';
import { PlainInput } from '../components/core/PlainInput';
import { HStack } from '../components/core/Stacks';
import {PlainInput} from "./PlainInput";
import { HStack } from './Stacks';
import { Button } from './Button';
export type PromptProps = Omit<PromptTextRequest, 'id' | 'title' | 'description'> & {
description?: ReactNode;

View File

@@ -3,34 +3,26 @@ import type { CookieJar } from '@yaakapp-internal/models';
import { atom, useAtomValue } from 'jotai/index';
import { useEffect } from 'react';
import { jotaiStore } from '../lib/jotai';
import { router } from '../lib/router';
import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams';
import { cookieJarsAtom, useCookieJars } from './useCookieJars';
export const QUERY_COOKIE_JAR_ID = 'cookie_jar_id';
export const activeCookieJarIdAtom = atom<string>();
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 const activeCookieJarAtom = atom<CookieJar | null>(null);
export function useActiveCookieJar() {
return useAtomValue(activeCookieJarAtom);
}
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(() => {
jotaiStore.set(activeCookieJarIdAtom, cookie_jar_id ?? undefined);
}, [cookie_jar_id]);
if (search == null) return; // Happens during Vite hot reload
const activeCookieJar = cookieJars?.find((j) => j.id == cookieJarId) ?? null;
jotaiStore.set(activeCookieJarAtom, activeCookieJar);
}, [cookieJarId, cookieJars, search]);
}
export function getActiveCookieJar() {
@@ -39,12 +31,12 @@ export function getActiveCookieJar() {
export function useEnsureActiveCookieJar() {
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
useEffect(() => {
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
}
@@ -55,7 +47,7 @@ export function useEnsureActiveCookieJar() {
}
// There's no active jar, so set it to the first one
console.log('Setting active cookie jar to', firstJar.id);
setActiveCookieJar(firstJar);
}, [activeCookieJar?.id, cookieJars]);
console.log('Setting active cookie jar to', cookieJars, activeCookieJarId, firstJar.id);
setWorkspaceSearchParams({ cookie_jar_id: firstJar.id });
}, [activeCookieJarId, cookieJars]);
}

View File

@@ -4,7 +4,7 @@ import { useAtomValue } from 'jotai';
import { atom } from 'jotai/index';
import { useCallback, useEffect } from 'react';
import { jotaiStore } from '../lib/jotai';
import { router } from '../lib/router';
import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams';
import { environmentsAtom } from './useEnvironments';
export const QUERY_ENVIRONMENT_ID = 'environment_id';
@@ -18,11 +18,7 @@ export const activeEnvironmentAtom = atom<Environment | null>((get) => {
export function useActiveEnvironment() {
const setId = useCallback(
(id: string | null) =>
router.navigate({
from: '/workspaces/$workspaceId',
search: (prev) => ({ ...prev, environment_id: id }),
}),
(id: string | null) => setWorkspaceSearchParams({ environment_id: id }),
[],
);
const environment = useAtomValue(activeEnvironmentAtom);

View File

@@ -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]);
}

View File

@@ -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 }),
});
}),
[],
);
}

View File

@@ -1,13 +1,11 @@
import type { CookieJar } from '@yaakapp-internal/models';
import { trackEvent } from '../lib/analytics';
import { showPrompt } from '../lib/prompt';
import { invokeCmd } from '../lib/tauri';
import { getActiveWorkspaceId } from './useActiveWorkspace';
import { useFastMutation } from './useFastMutation';
import { usePrompt } from './usePrompt';
export function useCreateCookieJar() {
const prompt = usePrompt();
return useFastMutation<CookieJar | null>({
mutationKey: ['create_cookie_jar'],
mutationFn: async () => {
@@ -15,7 +13,7 @@ export function useCreateCookieJar() {
if (workspaceId == null) {
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',
title: 'New CookieJar',
placeholder: 'My Jar',

View File

@@ -1,10 +1,10 @@
import { useMemo } from 'react';
import type { DropdownItem } from '../components/core/Dropdown';
import { Icon } from '../components/core/Icon';
import { createFolder } from '../lib/commands';
import { generateId } from '../lib/generateId';
import { BODY_TYPE_GRAPHQL } from '../lib/model_util';
import { getActiveRequest } from './useActiveRequest';
import { useCommands } from './useCommands';
import { useCreateGrpcRequest } from './useCreateGrpcRequest';
import { useCreateHttpRequest } from './useCreateHttpRequest';
@@ -19,7 +19,6 @@ export function useCreateDropdownItems({
} = {}): DropdownItem[] {
const { mutate: createHttpRequest } = useCreateHttpRequest();
const { mutate: createGrpcRequest } = useCreateGrpcRequest();
const { createFolder } = useCommands();
return useMemo((): DropdownItem[] => {
const folderId =
@@ -66,5 +65,5 @@ export function useCreateDropdownItems({
},
]) as DropdownItem[]),
];
}, [createFolder, createGrpcRequest, createHttpRequest, folderIdOption, hideFolder, hideIcons]);
}, [createGrpcRequest, createHttpRequest, folderIdOption, hideFolder, hideIcons]);
}

View File

@@ -1,14 +1,13 @@
import type { Environment } from '@yaakapp-internal/models';
import { trackEvent } from '../lib/analytics';
import { showPrompt } from '../lib/prompt';
import { invokeCmd } from '../lib/tauri';
import { useActiveEnvironment } from './useActiveEnvironment';
import { getActiveWorkspaceId } from './useActiveWorkspace';
import { useFastMutation } from './useFastMutation';
import { usePrompt } from './usePrompt';
export function useCreateEnvironment() {
const [, setActiveEnvironmentId] = useActiveEnvironment();
const prompt = usePrompt();
return useFastMutation<Environment | null, unknown, Environment | null>({
mutationKey: ['create_environment'],
@@ -18,7 +17,7 @@ export function useCreateEnvironment() {
}
const workspaceId = getActiveWorkspaceId();
const name = await prompt({
const name = await showPrompt({
id: 'new-environment',
title: 'New Environment',
description: 'Create multiple environments with different sets of variables',

View File

@@ -1,20 +1,18 @@
import type { Workspace } from '@yaakapp-internal/models';
import { InlineCode } from '../components/core/InlineCode';
import { trackEvent } from '../lib/analytics';
import { showConfirm } from '../lib/confirm';
import { router } from '../lib/router';
import { invokeCmd } from '../lib/tauri';
import { getActiveWorkspace } from './useActiveWorkspace';
import { useConfirm } from './useConfirm';
import { useFastMutation } from './useFastMutation';
export function useDeleteActiveWorkspace() {
const confirm = useConfirm();
return useFastMutation<Workspace | null, string>({
mutationKey: ['delete_workspace'],
mutationFn: async () => {
const workspace = getActiveWorkspace();
const confirmed = await confirm({
const confirmed = await showConfirm({
id: 'delete-workspace',
title: 'Delete Workspace',
variant: 'delete',

View File

@@ -1,22 +1,20 @@
import type { GrpcRequest } from '@yaakapp-internal/models';
import { InlineCode } from '../components/core/InlineCode';
import { trackEvent } from '../lib/analytics';
import { showConfirm } from '../lib/confirm';
import { fallbackRequestName } from '../lib/fallbackRequestName';
import { getGrpcRequest } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import { useConfirm } from './useConfirm';
import { useFastMutation } from './useFastMutation';
export function useDeleteAnyGrpcRequest() {
const confirm = useConfirm();
return useFastMutation<GrpcRequest | null, string, string>({
mutationKey: ['delete_any_grpc_request'],
mutationFn: async (id) => {
const request = await getGrpcRequest(id);
if (request == null) return null;
const confirmed = await confirm({
const confirmed = await showConfirm({
id: 'delete-grpc-request',
title: 'Delete Request',
variant: 'delete',

View File

@@ -1,22 +1,20 @@
import type { HttpRequest } from '@yaakapp-internal/models';
import { InlineCode } from '../components/core/InlineCode';
import { trackEvent } from '../lib/analytics';
import { showConfirm } from '../lib/confirm';
import { fallbackRequestName } from '../lib/fallbackRequestName';
import { getHttpRequest } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import { useConfirm } from './useConfirm';
import { useFastMutation } from './useFastMutation';
export function useDeleteAnyHttpRequest() {
const confirm = useConfirm();
return useFastMutation<HttpRequest | null, string, string>({
mutationKey: ['delete_any_http_request'],
mutationFn: async (id) => {
const request = await getHttpRequest(id);
if (request == null) return null;
const confirmed = await confirm({
const confirmed = await showConfirm({
id: 'delete-request',
title: 'Delete Request',
variant: 'delete',

View File

@@ -1,21 +1,20 @@
import { useFastMutation } from './useFastMutation';
import type { CookieJar } from '@yaakapp-internal/models';
import { useSetAtom } from 'jotai';
import { InlineCode } from '../components/core/InlineCode';
import { trackEvent } from '../lib/analytics';
import { showConfirm } from '../lib/confirm';
import { invokeCmd } from '../lib/tauri';
import { useConfirm } from './useConfirm';
import { cookieJarsAtom } from './useCookieJars';
import { useFastMutation } from './useFastMutation';
import { removeModelById } from './useSyncModelStores';
export function useDeleteCookieJar(cookieJar: CookieJar | null) {
const confirm = useConfirm();
const setCookieJars = useSetAtom(cookieJarsAtom);
return useFastMutation<CookieJar | null, string>({
mutationKey: ['delete_cookie_jar', cookieJar?.id],
mutationFn: async () => {
const confirmed = await confirm({
const confirmed = await showConfirm({
id: 'delete-cookie-jar',
title: 'Delete CookieJar',
variant: 'delete',

View File

@@ -1,21 +1,20 @@
import { useFastMutation } from './useFastMutation';
import type { Environment } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai";
import { useSetAtom } from 'jotai';
import { InlineCode } from '../components/core/InlineCode';
import { trackEvent } from '../lib/analytics';
import { showConfirm } from '../lib/confirm';
import { invokeCmd } from '../lib/tauri';
import { useConfirm } from './useConfirm';
import {environmentsAtom} from "./useEnvironments";
import {removeModelById} from "./useSyncModelStores";
import { environmentsAtom } from './useEnvironments';
import { useFastMutation } from './useFastMutation';
import { removeModelById } from './useSyncModelStores';
export function useDeleteEnvironment(environment: Environment | null) {
const confirm = useConfirm();
const setEnvironments = useSetAtom(environmentsAtom);
return useFastMutation<Environment | null, string>({
mutationKey: ['delete_environment', environment?.id],
mutationFn: async () => {
const confirmed = await confirm({
const confirmed = await showConfirm({
id: 'delete-environment',
title: 'Delete Environment',
variant: 'delete',
@@ -33,6 +32,6 @@ export function useDeleteEnvironment(environment: Environment | null) {
if (environment == null) return;
setEnvironments(removeModelById(environment));
}
},
});
}

View File

@@ -2,22 +2,21 @@ import type { Folder } from '@yaakapp-internal/models';
import { useSetAtom } from 'jotai';
import { InlineCode } from '../components/core/InlineCode';
import { trackEvent } from '../lib/analytics';
import { showConfirm } from '../lib/confirm';
import { getFolder } from '../lib/store';
import { invokeCmd } from '../lib/tauri';
import { useConfirm } from './useConfirm';
import { useFastMutation } from './useFastMutation';
import { foldersAtom } from './useFolders';
import { removeModelById } from './useSyncModelStores';
import { useFastMutation } from './useFastMutation';
export function useDeleteFolder(id: string | null) {
const confirm = useConfirm();
const setFolders = useSetAtom(foldersAtom);
return useFastMutation<Folder | null, string>({
mutationKey: ['delete_folder', id],
mutationFn: async () => {
const folder = await getFolder(id);
const confirmed = await confirm({
const confirmed = await showConfirm({
id: 'delete-folder',
title: 'Delete Folder',
variant: 'delete',

View File

@@ -1,15 +1,14 @@
import { useSetAtom } from 'jotai/index';
import { showAlert } from '../lib/alert';
import { showConfirm } from '../lib/confirm';
import { pluralizeCount } from '../lib/pluralize';
import { invokeCmd } from '../lib/tauri';
import { getActiveWorkspaceId } from './useActiveWorkspace';
import { useConfirm } from './useConfirm';
import { useFastMutation } from './useFastMutation';
import { useGrpcConnections } from './useGrpcConnections';
import { httpResponsesAtom, useHttpResponses } from './useHttpResponses';
export function useDeleteSendHistory() {
const confirm = useConfirm();
const setHttpResponses = useSetAtom(httpResponsesAtom);
const httpResponses = useHttpResponses();
const grpcConnections = useGrpcConnections();
@@ -30,7 +29,7 @@ export function useDeleteSendHistory() {
return;
}
const confirmed = await confirm({
const confirmed = await showConfirm({
id: 'delete-send-history',
title: 'Clear Send History',
variant: 'delete',

View File

@@ -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,
}),
});
});
}

View File

@@ -1,7 +1,7 @@
import { useEffect, useMemo } from 'react';
import { jotaiStore } from '../lib/jotai';
import { getKeyValue, setKeyValue } from '../lib/keyValueStore';
import { activeCookieJarIdAtom } from './useActiveCookieJar';
import {activeCookieJarAtom} from "./useActiveCookieJar";
import { activeWorkspaceIdAtom, useActiveWorkspace } from './useActiveWorkspace';
import { useCookieJars } from './useCookieJars';
import { useKeyValue } from './useKeyValue';
@@ -29,9 +29,9 @@ export function useRecentCookieJars() {
export function useSubscribeRecentCookieJars() {
useEffect(() => {
return jotaiStore.sub(activeCookieJarIdAtom, async () => {
return jotaiStore.sub(activeCookieJarAtom, async () => {
const activeWorkspaceId = jotaiStore.get(activeWorkspaceIdAtom);
const activeCookieJarId = jotaiStore.get(activeCookieJarIdAtom);
const activeCookieJarId = jotaiStore.get(activeCookieJarAtom)?.id ?? null;
if (activeWorkspaceId == null) return;
if (activeCookieJarId == null) return;

View File

@@ -1,13 +1,12 @@
import { useFastMutation } from './useFastMutation';
import type { GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
import { InlineCode } from '../components/core/InlineCode';
import { usePrompt } from './usePrompt';
import {showPrompt} from "../lib/prompt";
import { useFastMutation } from './useFastMutation';
import { useRequests } from './useRequests';
import { useUpdateAnyGrpcRequest } from './useUpdateAnyGrpcRequest';
import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
export function useRenameRequest(requestId: string | null) {
const prompt = usePrompt();
const updateHttpRequest = useUpdateAnyHttpRequest();
const updateGrpcRequest = useUpdateAnyGrpcRequest();
const requests = useRequests();
@@ -18,7 +17,7 @@ export function useRenameRequest(requestId: string | null) {
const request = requests.find((r) => r.id === requestId);
if (request == null) return;
const name = await prompt({
const name = await showPrompt({
id: 'rename-request',
title: 'Rename Request',
description:

View File

@@ -4,9 +4,9 @@ import { applySync, calculateSync } from '@yaakapp-internal/sync';
import { useCallback, useMemo } from 'react';
import { InlineCode } from '../components/core/InlineCode';
import { VStack } from '../components/core/Stacks';
import {showConfirm} from "../lib/confirm";
import { fallbackRequestName } from '../lib/fallbackRequestName';
import { pluralizeCount } from '../lib/pluralize';
import { useConfirm } from './useConfirm';
export function useSyncWorkspace(
workspace: Workspace | null,
@@ -16,12 +16,10 @@ export function useSyncWorkspace(
debounceMillis?: number;
} = {},
) {
const confirm = useConfirm();
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) {
return;
}
@@ -33,7 +31,7 @@ export function useSyncWorkspace(
return;
}
const confirmed = await confirm({
const confirmed = await showConfirm({
id: 'commit-sync',
title: 'Filesystem Changes Detected',
confirmText: 'Apply Changes',
@@ -92,7 +90,7 @@ export function useSyncWorkspace(
if (confirmed) {
await applySync(workspace, ops);
}
}, [confirm, workspace]);
}, [workspace]);
const debouncedSync = useMemo(() => {
return debounce(sync, debounceMillis);

View File

@@ -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 { AlertProps } from '../hooks/Alert';
import { Alert } from '../hooks/Alert';
import { showDialog } from './dialog';
interface AlertArgs {

51
src-web/lib/commands.ts Normal file
View 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
View 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
View 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,
}),
});
});
}

View 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 }),
});
}

View File

@@ -1,10 +1,10 @@
import { createFileRoute } from '@tanstack/react-router'
import { Workspace } from '../../../components/Workspace'
import { createFileRoute } from '@tanstack/react-router';
import { Workspace } from '../../../components/Workspace';
interface WorkspaceSearchSchema {
request_id?: string | null
environment_id?: string | null
cookie_jar_id?: string | null
request_id?: string | null;
environment_id?: string | null;
cookie_jar_id?: string | null;
}
export const Route = createFileRoute('/workspaces/$workspaceId/')({
@@ -14,8 +14,8 @@ export const Route = createFileRoute('/workspaces/$workspaceId/')({
environment_id: search.environment_id as string,
cookie_jar_id: search.cookie_jar_id as string,
}),
})
});
function RouteComponent() {
return <Workspace />
return <Workspace />;
}