A bunch of fixes

This commit is contained in:
Gregory Schier
2025-01-01 07:01:41 -08:00
parent 80119f6574
commit 4b807f221b
22 changed files with 179 additions and 152 deletions

View File

@@ -230,7 +230,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
}, [subEnvironments, recentEnvironments]); }, [subEnvironments, recentEnvironments]);
const sortedWorkspaces = useMemo(() => { const sortedWorkspaces = useMemo(() => {
return [...workspaces].sort((a, b) => { const r = [...workspaces].sort((a, b) => {
const aRecentIndex = recentWorkspaces.indexOf(a.id); const aRecentIndex = recentWorkspaces.indexOf(a.id);
const bRecentIndex = recentWorkspaces.indexOf(b.id); const bRecentIndex = recentWorkspaces.indexOf(b.id);
@@ -244,6 +244,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
return a.createdAt.localeCompare(b.createdAt); return a.createdAt.localeCompare(b.createdAt);
} }
}); });
return r;
}, [recentWorkspaces, workspaces]); }, [recentWorkspaces, workspaces]);
const groups = useMemo<CommandPaletteGroup[]>(() => { const groups = useMemo<CommandPaletteGroup[]>(() => {
@@ -308,7 +309,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
for (const w of sortedWorkspaces) { for (const w of sortedWorkspaces) {
workspaceGroup.items.push({ workspaceGroup.items.push({
key: `switch-workspace-${w.id}`, key: `switch-workspace-${w.id}`,
label: w.name, label: w.id + ' - ' + w.name,
onSelect: () => openWorkspace.mutate({ workspaceId: w.id, inNewWindow: false }), onSelect: () => openWorkspace.mutate({ workspaceId: w.id, inNewWindow: false }),
}); });
} }
@@ -377,7 +378,6 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
const handleKeyDown = useCallback( const handleKeyDown = useCallback(
(e: KeyboardEvent<HTMLInputElement>) => { (e: KeyboardEvent<HTMLInputElement>) => {
const index = filteredAllItems.findIndex((v) => v.key === selectedItem?.key); const index = filteredAllItems.findIndex((v) => v.key === selectedItem?.key);
console.log("ENDER", e.key);
if (e.key === 'ArrowDown' || (e.ctrlKey && e.key === 'n')) { if (e.key === 'ArrowDown' || (e.ctrlKey && e.key === 'n')) {
const next = filteredAllItems[index + 1] ?? filteredAllItems[0]; const next = filteredAllItems[index + 1] ?? filteredAllItems[0];

View File

@@ -1,6 +1,6 @@
import { emit } from '@tauri-apps/api/event'; import { emit } from '@tauri-apps/api/event';
import type { PromptTextRequest, PromptTextResponse } from '@yaakapp-internal/plugin'; import type { PromptTextRequest, PromptTextResponse } from '@yaakapp-internal/plugin';
import { useEnsureActiveCookieJar, useSubscribeActiveCookieJar } from '../hooks/useActiveCookieJar'; import { useEnsureActiveCookieJar, useSubscribeActiveCookieJarId } from '../hooks/useActiveCookieJar';
import { useSubscribeActiveEnvironmentId } from '../hooks/useActiveEnvironment'; import { useSubscribeActiveEnvironmentId } from '../hooks/useActiveEnvironment';
import { useActiveRequest } from '../hooks/useActiveRequest'; import { useActiveRequest } from '../hooks/useActiveRequest';
import { useSubscribeActiveRequestId } from '../hooks/useActiveRequestId'; import { useSubscribeActiveRequestId } from '../hooks/useActiveRequestId';
@@ -13,10 +13,10 @@ 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 { usePrompt } from '../hooks/usePrompt';
import { useRecentCookieJars } from '../hooks/useRecentCookieJars'; import {useRecentCookieJars, useSubscribeRecentCookieJars} from '../hooks/useRecentCookieJars';
import { useRecentEnvironments } from '../hooks/useRecentEnvironments'; import {useRecentEnvironments, useSubscribeRecentEnvironments} from '../hooks/useRecentEnvironments';
import { useSubscribeRecentRequests } from '../hooks/useRecentRequests'; import { useSubscribeRecentRequests } from '../hooks/useRecentRequests';
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces'; import {useRecentWorkspaces, 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 { useSyncWorkspaceChildModels } from '../hooks/useSyncWorkspaceChildModels'; import { useSyncWorkspaceChildModels } from '../hooks/useSyncWorkspaceChildModels';
@@ -31,18 +31,23 @@ export function GlobalHooks() {
useSyncFontSizeSetting(); useSyncFontSizeSetting();
useGenerateThemeCss(); useGenerateThemeCss();
useSyncWorkspaceRequestTitle(); useSyncWorkspaceRequestTitle();
useSubscribeActiveWorkspaceId(); useSubscribeActiveWorkspaceId();
useSubscribeActiveRequestId(); useSubscribeActiveRequestId();
useSubscribeActiveEnvironmentId();
useSubscribeActiveCookieJarId();
useSubscribeRecentRequests();
useSubscribeRecentWorkspaces();
useSubscribeRecentEnvironments();
useSubscribeRecentCookieJars();
// Include here so they always update, even if no component references them // Include here so they always update, even if no component references them
useRecentWorkspaces(); useRecentWorkspaces();
useRecentEnvironments(); useRecentEnvironments();
useRecentCookieJars(); useRecentCookieJars();
useSubscribeRecentRequests();
useSyncWorkspaceChildModels(); useSyncWorkspaceChildModels();
useSubscribeTemplateFunctions(); useSubscribeTemplateFunctions();
useSubscribeActiveEnvironmentId();
useSubscribeActiveCookieJar();
// Other useful things // Other useful things
useNotificationToast(); useNotificationToast();

View File

@@ -245,7 +245,7 @@ export const SidebarItem = memo(function SidebarItem({
'w-full flex gap-1.5 items-center h-xs px-1.5 rounded-md focus-visible:ring focus-visible:ring-border-focus outline-0', 'w-full flex gap-1.5 items-center h-xs px-1.5 rounded-md focus-visible:ring focus-visible:ring-border-focus outline-0',
editing && 'ring-1 focus-within:ring-focus', editing && 'ring-1 focus-within:ring-focus',
active && 'bg-surface-highlight text-text', active && 'bg-surface-highlight text-text',
!active && 'text-text-subtle group-hover/item:text-text', !active && 'text-text-subtle',
showContextMenu && '!text-text', // Show as "active" when the context menu is open showContextMenu && '!text-text', // Show as "active" when the context menu is open
)} )}
> >

View File

@@ -66,6 +66,7 @@ export const UrlBar = memo(function UrlBar({
return ( return (
<form onSubmit={handleSubmit} className={classNames('x-theme-urlBar', className)}> <form onSubmit={handleSubmit} className={classNames('x-theme-urlBar', className)}>
<Input <Input
ref={inputRef}
autocompleteVariables autocompleteVariables
stateKey={stateKey} stateKey={stateKey}
size="md" size="md"

View File

@@ -101,6 +101,11 @@ export const Dropdown = forwardRef<DropdownRef, DropdownProps>(function Dropdown
setDefaultSelectedIndex(undefined); setDefaultSelectedIndex(undefined);
}, [setIsOpen]); }, [setIsOpen]);
const openDropdown = useCallback(() => {
setIsOpen((o) => !o);
setItems(typeof itemsGetter === 'function' ? itemsGetter() : itemsGetter);
}, [itemsGetter, setIsOpen]);
useImperativeHandle( useImperativeHandle(
ref, ref,
() => ({ () => ({
@@ -111,18 +116,18 @@ export const Dropdown = forwardRef<DropdownRef, DropdownProps>(function Dropdown
else this.close(); else this.close();
}, },
open() { open() {
setIsOpen(true); openDropdown();
}, },
close() { close() {
handleClose(); handleClose();
}, },
}), }),
[handleClose, isOpen, setIsOpen], [handleClose, isOpen, openDropdown],
); );
useHotKey(hotKeyAction ?? null, () => { useHotKey(hotKeyAction ?? null, () => {
setDefaultSelectedIndex(0); setDefaultSelectedIndex(0);
setIsOpen(true); openDropdown();
}); });
const child = useMemo(() => { const child = useMemo(() => {
@@ -138,12 +143,11 @@ export const Dropdown = forwardRef<DropdownRef, DropdownProps>(function Dropdown
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
setDefaultSelectedIndex(undefined); setDefaultSelectedIndex(undefined);
setIsOpen((o) => !o); openDropdown();
setItems(typeof itemsGetter === 'function' ? itemsGetter() : itemsGetter);
}), }),
}; };
return cloneElement(existingChild, props); return cloneElement(existingChild, props);
}, [children, itemsGetter, setIsOpen]); }, [children, openDropdown]);
useEffect(() => { useEffect(() => {
buttonRef.current?.setAttribute('aria-expanded', isOpen.toString()); buttonRef.current?.setAttribute('aria-expanded', isOpen.toString());

View File

@@ -563,6 +563,5 @@ function getCachedEditorState(doc: string, stateKey: string | null) {
if (state == null) return null; if (state == null) return null;
if (state.doc.toString() !== doc) return null; if (state.doc.toString() !== doc) return null;
console.log('CACHED STATE', stateKey, state);
return state; return state;
} }

View File

@@ -43,12 +43,11 @@ function useActiveCookieJarId() {
return [id, setId] as const; return [id, setId] as const;
} }
export function useSubscribeActiveCookieJar() { export function useSubscribeActiveCookieJarId() {
const { cookie_jar_id } = useSearch({ strict: false }); const { cookie_jar_id } = useSearch({ strict: false });
useEffect( useEffect(() => {
() => jotaiStore.set(activeCookieJarIdAtom, cookie_jar_id ?? undefined), jotaiStore.set(activeCookieJarIdAtom, cookie_jar_id ?? undefined);
[cookie_jar_id], }, [cookie_jar_id]);
);
} }
export function getActiveCookieJar() { export function getActiveCookieJar() {

View File

@@ -21,9 +21,11 @@ export function getActiveWorkspaceId() {
return jotaiStore.get(activeWorkspaceIdAtom) ?? null; return jotaiStore.get(activeWorkspaceIdAtom) ?? null;
} }
export function getActiveWorkspace() {
return jotaiStore.get(activeWorkspaceAtom) ?? null;
}
export function useSubscribeActiveWorkspaceId() { export function useSubscribeActiveWorkspaceId() {
const { workspaceId } = useParams({ strict: false }); const { workspaceId } = useParams({ strict: false });
useEffect(() => { useEffect(() => jotaiStore.set(activeWorkspaceIdAtom, workspaceId), [workspaceId]);
jotaiStore.set(activeWorkspaceIdAtom, workspaceId);
}, [workspaceId]);
} }

View File

@@ -1,22 +1,22 @@
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 { trackEvent } from '../lib/analytics'; import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri'; import { invokeCmd } from '../lib/tauri';
import { useActiveWorkspace } from './useActiveWorkspace'; import { getActiveWorkspaceId } from './useActiveWorkspace';
import {cookieJarsAtom} from "./useCookieJars"; import { cookieJarsAtom } from './useCookieJars';
import { useFastMutation } from './useFastMutation';
import { usePrompt } from './usePrompt'; import { usePrompt } from './usePrompt';
import {updateModelList} from "./useSyncModelStores"; import { updateModelList } from './useSyncModelStores';
export function useCreateCookieJar() { export function useCreateCookieJar() {
const workspace = useActiveWorkspace();
const prompt = usePrompt(); const prompt = usePrompt();
const setCookieJars = useSetAtom(cookieJarsAtom); const setCookieJars = useSetAtom(cookieJarsAtom);
return useFastMutation<CookieJar | null>({ return useFastMutation<CookieJar | null>({
mutationKey: ['create_cookie_jar'], mutationKey: ['create_cookie_jar'],
mutationFn: async () => { mutationFn: async () => {
if (workspace === null) { const workspaceId = getActiveWorkspaceId();
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 prompt({
@@ -29,7 +29,7 @@ export function useCreateCookieJar() {
}); });
if (name == null) return null; if (name == null) return null;
return invokeCmd('cmd_create_cookie_jar', { workspaceId: workspace.id, name }); return invokeCmd('cmd_create_cookie_jar', { workspaceId, name });
}, },
onSuccess: (cookieJar) => { onSuccess: (cookieJar) => {
if (cookieJar == null) return; if (cookieJar == null) return;

View File

@@ -11,7 +11,7 @@ import { useCreateHttpRequest } from './useCreateHttpRequest';
export function useCreateDropdownItems({ export function useCreateDropdownItems({
hideFolder, hideFolder,
hideIcons, hideIcons,
folderId, folderId: folderIdOption,
}: { }: {
hideFolder?: boolean; hideFolder?: boolean;
hideIcons?: boolean; hideIcons?: boolean;
@@ -21,19 +21,17 @@ export function useCreateDropdownItems({
const { mutate: createGrpcRequest } = useCreateGrpcRequest(); const { mutate: createGrpcRequest } = useCreateGrpcRequest();
const { mutate: createFolder } = useCreateFolder(); const { mutate: createFolder } = useCreateFolder();
return useCallback( return useCallback((): DropdownItem[] => {
(): DropdownItem[] => [ const folderId =
folderIdOption === 'active-folder' ? getActiveRequest()?.folderId : folderIdOption;
return [
{ {
key: 'create-http-request', key: 'create-http-request',
label: 'HTTP Request', label: 'HTTP Request',
leftSlot: hideIcons ? undefined : <Icon icon="plus" />, leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
onSelect: () => { onSelect: () => {
const args = { folderId }; createHttpRequest({ folderId });
if (folderId === 'active-folder') {
const activeRequest = getActiveRequest();
args.folderId = activeRequest?.folderId ?? undefined;
}
createHttpRequest(args);
}, },
}, },
{ {
@@ -67,7 +65,6 @@ export function useCreateDropdownItems({
onSelect: () => createFolder({ folderId }), onSelect: () => createFolder({ folderId }),
}, },
]) as DropdownItem[]), ]) as DropdownItem[]),
], ];
[createFolder, createGrpcRequest, createHttpRequest, folderId, hideFolder, hideIcons], }, [createFolder, createGrpcRequest, createHttpRequest, folderIdOption, hideFolder, hideIcons]);
);
} }

View File

@@ -3,7 +3,7 @@ import { useSetAtom } from 'jotai';
import { trackEvent } from '../lib/analytics'; import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri'; import { invokeCmd } from '../lib/tauri';
import { useActiveEnvironment } from './useActiveEnvironment'; import { useActiveEnvironment } from './useActiveEnvironment';
import { useActiveWorkspace } from './useActiveWorkspace'; import { getActiveWorkspaceId } from './useActiveWorkspace';
import { environmentsAtom } from './useEnvironments'; import { environmentsAtom } from './useEnvironments';
import { useFastMutation } from './useFastMutation'; import { useFastMutation } from './useFastMutation';
import { usePrompt } from './usePrompt'; import { usePrompt } from './usePrompt';
@@ -12,7 +12,6 @@ import { updateModelList } from './useSyncModelStores';
export function useCreateEnvironment() { export function useCreateEnvironment() {
const [, setActiveEnvironmentId] = useActiveEnvironment(); const [, setActiveEnvironmentId] = useActiveEnvironment();
const prompt = usePrompt(); const prompt = usePrompt();
const workspace = useActiveWorkspace();
const setEnvironments = useSetAtom(environmentsAtom); const setEnvironments = useSetAtom(environmentsAtom);
return useFastMutation<Environment | null, unknown, Environment | null>({ return useFastMutation<Environment | null, unknown, Environment | null>({
@@ -23,6 +22,7 @@ export function useCreateEnvironment() {
throw new Error('No base environment passed'); throw new Error('No base environment passed');
} }
const workspaceId = getActiveWorkspaceId();
const name = await prompt({ const name = await prompt({
id: 'new-environment', id: 'new-environment',
title: 'New Environment', title: 'New Environment',
@@ -37,7 +37,7 @@ export function useCreateEnvironment() {
return invokeCmd('cmd_create_environment', { return invokeCmd('cmd_create_environment', {
name, name,
variables: [], variables: [],
workspaceId: workspace?.id, workspaceId,
environmentId: baseEnvironment.id, environmentId: baseEnvironment.id,
}); });
}, },

View File

@@ -1,26 +1,27 @@
import { useNavigate } from '@tanstack/react-router';
import type { HttpRequest } from '@yaakapp-internal/models'; import type { HttpRequest } from '@yaakapp-internal/models';
import { useSetAtom } from 'jotai/index'; import { useSetAtom } from 'jotai/index';
import { trackEvent } from '../lib/analytics'; import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri'; import { invokeCmd } from '../lib/tauri';
import { getActiveRequest } from './useActiveRequest'; import { getActiveRequest } from './useActiveRequest';
import { useActiveWorkspace } from './useActiveWorkspace'; import { getActiveWorkspaceId } from './useActiveWorkspace';
import { useFastMutation } from './useFastMutation'; import { useFastMutation } from './useFastMutation';
import { httpRequestsAtom } from './useHttpRequests'; import { httpRequestsAtom } from './useHttpRequests';
import { updateModelList } from './useSyncModelStores'; import { updateModelList } from './useSyncModelStores';
import { useNavigate } from '@tanstack/react-router';
export function useCreateHttpRequest() { export function useCreateHttpRequest() {
const activeWorkspace = useActiveWorkspace();
const setHttpRequests = useSetAtom(httpRequestsAtom); const setHttpRequests = useSetAtom(httpRequestsAtom);
const navigate = useNavigate(); const navigate = useNavigate();
return useFastMutation<HttpRequest, unknown, Partial<HttpRequest>>({ return useFastMutation<HttpRequest, unknown, Partial<HttpRequest>>({
mutationKey: ['create_http_request'], mutationKey: ['create_http_request'],
mutationFn: async (patch = {}) => { mutationFn: async (patch = {}) => {
const activeRequest = getActiveRequest(); const workspaceId = getActiveWorkspaceId();
if (activeWorkspace === null) { if (workspaceId == null) {
throw new Error("Cannot create request when there's no active workspace"); throw new Error("Cannot create request when there's no active workspace");
} }
const activeRequest = getActiveRequest();
if (patch.sortPriority === undefined) { if (patch.sortPriority === undefined) {
if (activeRequest != null) { if (activeRequest != null) {
// Place above currently active request // Place above currently active request
@@ -32,7 +33,7 @@ export function useCreateHttpRequest() {
} }
patch.folderId = patch.folderId || activeRequest?.folderId; patch.folderId = patch.folderId || activeRequest?.folderId;
return invokeCmd<HttpRequest>('cmd_create_http_request', { return invokeCmd<HttpRequest>('cmd_create_http_request', {
request: { workspaceId: activeWorkspace.id, ...patch }, request: { workspaceId, ...patch },
}); });
}, },
onSettled: () => trackEvent('http_request', 'create'), onSettled: () => trackEvent('http_request', 'create'),

View File

@@ -1,10 +1,10 @@
import { useFastMutation } from './useFastMutation';
import { useSetAtom } from 'jotai/index'; import { useSetAtom } from 'jotai/index';
import { count } from '../lib/pluralize'; import { count } from '../lib/pluralize';
import { invokeCmd } from '../lib/tauri'; import { invokeCmd } from '../lib/tauri';
import { useActiveWorkspace } from './useActiveWorkspace'; import { getActiveWorkspaceId } from './useActiveWorkspace';
import { useAlert } from './useAlert'; import { useAlert } from './useAlert';
import { useConfirm } from './useConfirm'; import { useConfirm } from './useConfirm';
import { useFastMutation } from './useFastMutation';
import { useGrpcConnections } from './useGrpcConnections'; import { useGrpcConnections } from './useGrpcConnections';
import { httpResponsesAtom, useHttpResponses } from './useHttpResponses'; import { httpResponsesAtom, useHttpResponses } from './useHttpResponses';
@@ -12,7 +12,6 @@ export function useDeleteSendHistory() {
const confirm = useConfirm(); const confirm = useConfirm();
const alert = useAlert(); const alert = useAlert();
const setHttpResponses = useSetAtom(httpResponsesAtom); const setHttpResponses = useSetAtom(httpResponsesAtom);
const activeWorkspace = useActiveWorkspace();
const httpResponses = useHttpResponses(); const httpResponses = useHttpResponses();
const grpcConnections = useGrpcConnections(); const grpcConnections = useGrpcConnections();
const labels = [ const labels = [
@@ -40,13 +39,14 @@ export function useDeleteSendHistory() {
}); });
if (!confirmed) return false; if (!confirmed) return false;
await invokeCmd('cmd_delete_send_history', { workspaceId: activeWorkspace?.id ?? 'n/a' }); const workspaceId = getActiveWorkspaceId();
await invokeCmd('cmd_delete_send_history', { workspaceId });
return true; return true;
}, },
onSuccess: async (confirmed) => { onSuccess: async (confirmed) => {
if (!confirmed) return; if (!confirmed) return;
const activeWorkspaceId = getActiveWorkspaceId();
setHttpResponses((all) => all.filter((r) => r.workspaceId !== activeWorkspace?.id)); setHttpResponses((all) => all.filter((r) => r.workspaceId !== activeWorkspaceId));
}, },
}); });
} }

View File

@@ -4,14 +4,13 @@ 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 { invokeCmd } from '../lib/tauri'; import { invokeCmd } from '../lib/tauri';
import { useActiveWorkspace } from './useActiveWorkspace'; import { getActiveWorkspace } from './useActiveWorkspace';
import { useConfirm } from './useConfirm'; import { useConfirm } from './useConfirm';
import { useFastMutation } from './useFastMutation'; import { useFastMutation } from './useFastMutation';
import { removeModelById } from './useSyncModelStores'; import { removeModelById } from './useSyncModelStores';
import { workspacesAtom } from './useWorkspaces'; import { workspacesAtom } from './useWorkspaces';
export function useDeleteWorkspace(workspace: Workspace | null) { export function useDeleteWorkspace(workspace: Workspace | null) {
const activeWorkspace = useActiveWorkspace();
const confirm = useConfirm(); const confirm = useConfirm();
const setWorkspaces = useSetAtom(workspacesAtom); const setWorkspaces = useSetAtom(workspacesAtom);
const navigate = useNavigate(); const navigate = useNavigate();
@@ -19,6 +18,7 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
return useFastMutation<Workspace | null, string>({ return useFastMutation<Workspace | null, string>({
mutationKey: ['delete_workspace', workspace?.id], mutationKey: ['delete_workspace', workspace?.id],
mutationFn: async () => { mutationFn: async () => {
const workspace = getActiveWorkspace();
const confirmed = await confirm({ const confirmed = await confirm({
id: 'delete-workspace', id: 'delete-workspace',
title: 'Delete Workspace', title: 'Delete Workspace',
@@ -40,8 +40,9 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
setWorkspaces(removeModelById(workspace)); setWorkspaces(removeModelById(workspace));
const { id: workspaceId } = workspace; const { id: workspaceId } = workspace;
const activeWorkspace = getActiveWorkspace();
if (workspaceId === activeWorkspace?.id) { if (workspaceId === activeWorkspace?.id) {
navigate({ to: '/workspaces' }); await navigate({ to: '/workspaces' });
} }
}, },
}); });

View File

@@ -1,14 +1,13 @@
import {useDialog} from "./useDialog";
import { useFastMutation } from './useFastMutation';
import { ExportDataDialog } from '../components/ExportDataDialog'; import { ExportDataDialog } from '../components/ExportDataDialog';
import { useActiveWorkspace } from './useActiveWorkspace'; import { jotaiStore } from '../lib/jotai';
import { getActiveWorkspace } from './useActiveWorkspace';
import { useAlert } from './useAlert'; import { useAlert } from './useAlert';
import { useWorkspaces } from './useWorkspaces'; import { useDialog } from './useDialog';
import { useFastMutation } from './useFastMutation';
import { useToast } from './useToast'; import { useToast } from './useToast';
import { workspacesAtom } from './useWorkspaces';
export function useExportData() { export function useExportData() {
const workspaces = useWorkspaces();
const activeWorkspace = useActiveWorkspace();
const alert = useAlert(); const alert = useAlert();
const dialog = useDialog(); const dialog = useDialog();
const toast = useToast(); const toast = useToast();
@@ -19,6 +18,9 @@ export function useExportData() {
alert({ id: 'export-failed', title: 'Export Failed', body: err }); alert({ id: 'export-failed', title: 'Export Failed', body: err });
}, },
mutationFn: async () => { mutationFn: async () => {
const activeWorkspace = getActiveWorkspace();
const workspaces = jotaiStore.get(workspacesAtom);
if (activeWorkspace == null || workspaces.length === 0) return; if (activeWorkspace == null || workspaces.length === 0) return;
dialog.show({ dialog.show({

View File

@@ -1,14 +1,13 @@
import { useFastMutation } from './useFastMutation';
import type { HttpRequest } from '@yaakapp-internal/models'; import type { HttpRequest } from '@yaakapp-internal/models';
import { useToast } from './useToast';
import { invokeCmd } from '../lib/tauri'; import { invokeCmd } from '../lib/tauri';
import { useActiveWorkspace } from './useActiveWorkspace'; import { getActiveWorkspaceId } from './useActiveWorkspace';
import { useCreateHttpRequest } from './useCreateHttpRequest'; import { useCreateHttpRequest } from './useCreateHttpRequest';
import { useFastMutation } from './useFastMutation';
import { useRequestUpdateKey } from './useRequestUpdateKey'; import { useRequestUpdateKey } from './useRequestUpdateKey';
import { useToast } from './useToast';
import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest'; import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
export function useImportCurl() { export function useImportCurl() {
const workspace = useActiveWorkspace();
const updateRequest = useUpdateAnyHttpRequest(); const updateRequest = useUpdateAnyHttpRequest();
const createRequest = useCreateHttpRequest(); const createRequest = useCreateHttpRequest();
const { wasUpdatedExternally } = useRequestUpdateKey(null); const { wasUpdatedExternally } = useRequestUpdateKey(null);
@@ -23,9 +22,10 @@ export function useImportCurl() {
overwriteRequestId?: string; overwriteRequestId?: string;
command: string; command: string;
}) => { }) => {
const workspaceId = getActiveWorkspaceId();
const request: HttpRequest = await invokeCmd('cmd_curl_to_request', { const request: HttpRequest = await invokeCmd('cmd_curl_to_request', {
command, command,
workspaceId: workspace?.id, workspaceId,
}); });
let verb; let verb;

View File

@@ -12,7 +12,7 @@ import { VStack } from '../components/core/Stacks';
import { ImportDataDialog } from '../components/ImportDataDialog'; import { ImportDataDialog } from '../components/ImportDataDialog';
import { count } from '../lib/pluralize'; import { count } from '../lib/pluralize';
import { invokeCmd } from '../lib/tauri'; import { invokeCmd } from '../lib/tauri';
import { useActiveWorkspace } from './useActiveWorkspace'; import { getActiveWorkspace } from './useActiveWorkspace';
import { useAlert } from './useAlert'; import { useAlert } from './useAlert';
import { useDialog } from './useDialog'; import { useDialog } from './useDialog';
import { useFastMutation } from './useFastMutation'; import { useFastMutation } from './useFastMutation';
@@ -20,10 +20,10 @@ import { useFastMutation } from './useFastMutation';
export function useImportData() { export function useImportData() {
const dialog = useDialog(); const dialog = useDialog();
const alert = useAlert(); const alert = useAlert();
const activeWorkspace = useActiveWorkspace();
const navigate = useNavigate(); const navigate = useNavigate();
const importData = async (filePath: string): Promise<boolean> => { const importData = async (filePath: string): Promise<boolean> => {
const activeWorkspace = getActiveWorkspace();
const imported: { const imported: {
workspaces: Workspace[]; workspaces: Workspace[];
environments: Environment[]; environments: Environment[];

View File

@@ -1,20 +1,20 @@
import {useDialog} from "./useDialog";
import { useFastMutation } from './useFastMutation';
import React from 'react'; import React from 'react';
import { MoveToWorkspaceDialog } from '../components/MoveToWorkspaceDialog'; import { MoveToWorkspaceDialog } from '../components/MoveToWorkspaceDialog';
import { useActiveWorkspace } from './useActiveWorkspace'; import { getActiveWorkspaceId } from './useActiveWorkspace';
import { useDialog } from './useDialog';
import { useFastMutation } from './useFastMutation';
import { useRequests } from './useRequests'; import { useRequests } from './useRequests';
export function useMoveToWorkspace(id: string) { export function useMoveToWorkspace(id: string) {
const dialog = useDialog(); const dialog = useDialog();
const requests = useRequests(); const requests = useRequests();
const request = requests.find((r) => r.id === id); const request = requests.find((r) => r.id === id);
const activeWorkspace = useActiveWorkspace();
return useFastMutation<void, unknown>({ return useFastMutation<void, unknown>({
mutationKey: ['move_workspace', id], mutationKey: ['move_workspace', id],
mutationFn: async () => { mutationFn: async () => {
if (request == null || activeWorkspace == null) return; const activeWorkspaceId = getActiveWorkspaceId();
if (request == null || activeWorkspaceId == null) return;
dialog.show({ dialog.show({
id: 'change-workspace', id: 'change-workspace',
@@ -24,7 +24,7 @@ export function useMoveToWorkspace(id: string) {
<MoveToWorkspaceDialog <MoveToWorkspaceDialog
onDone={hide} onDone={hide}
request={request} request={request}
activeWorkspaceId={activeWorkspace.id} activeWorkspaceId={activeWorkspaceId}
/> />
), ),
}); });

View File

@@ -1,7 +1,8 @@
import { useEffect, useMemo } from 'react'; import { useEffect, useMemo } from 'react';
import { getKeyValue } from '../lib/keyValueStore'; import { jotaiStore } from '../lib/jotai';
import { useActiveCookieJar } from './useActiveCookieJar'; import { getKeyValue, setKeyValue } from '../lib/keyValueStore';
import { useActiveWorkspace } from './useActiveWorkspace'; import { activeCookieJarIdAtom } from './useActiveCookieJar';
import { activeWorkspaceIdAtom, useActiveWorkspace } from './useActiveWorkspace';
import { useCookieJars } from './useCookieJars'; import { useCookieJars } from './useCookieJars';
import { useKeyValue } from './useKeyValue'; import { useKeyValue } from './useKeyValue';
@@ -12,24 +13,12 @@ const fallback: string[] = [];
export function useRecentCookieJars() { export function useRecentCookieJars() {
const cookieJars = useCookieJars(); const cookieJars = useCookieJars();
const activeWorkspace = useActiveWorkspace(); const activeWorkspace = useActiveWorkspace();
const [activeCookieJar] = useActiveCookieJar();
const activeCookieJarId = activeCookieJar?.id ?? null;
const kv = useKeyValue<string[]>({ const kv = useKeyValue<string[]>({
key: kvKey(activeWorkspace?.id ?? 'n/a'), key: kvKey(activeWorkspace?.id ?? 'n/a'),
namespace, namespace,
fallback, fallback,
}); });
// Set history when active request changes
useEffect(() => {
kv.set((currentHistory: string[]) => {
if (activeCookieJarId === null) return currentHistory;
const withoutCurrent = currentHistory.filter((id) => id !== activeCookieJarId);
return [activeCookieJarId, ...withoutCurrent];
}).catch(console.error);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeCookieJarId]);
const onlyValidIds = useMemo( const onlyValidIds = useMemo(
() => kv.value?.filter((id) => cookieJars?.some((e) => e.id === id)) ?? [], () => kv.value?.filter((id) => cookieJars?.some((e) => e.id === id)) ?? [],
[kv.value, cookieJars], [kv.value, cookieJars],
@@ -38,6 +27,26 @@ export function useRecentCookieJars() {
return onlyValidIds; return onlyValidIds;
} }
export function useSubscribeRecentCookieJars() {
useEffect(() => {
return jotaiStore.sub(activeCookieJarIdAtom, async () => {
const activeWorkspaceId = jotaiStore.get(activeWorkspaceIdAtom);
const activeCookieJarId = jotaiStore.get(activeCookieJarIdAtom);
if (activeWorkspaceId == null) return;
if (activeCookieJarId == null) return;
const key = kvKey(activeWorkspaceId);
const recentIds = await getKeyValue<string[]>({ namespace, key, fallback });
if (recentIds[0] === activeCookieJarId) return; // Short-circuit
const withoutActiveId = recentIds.filter((id) => id !== activeCookieJarId);
const value = [activeCookieJarId, ...withoutActiveId];
await setKeyValue({ namespace, key, value });
});
}, []);
}
export async function getRecentCookieJars(workspaceId: string) { export async function getRecentCookieJars(workspaceId: string) {
return getKeyValue<string[]>({ return getKeyValue<string[]>({
namespace, namespace,

View File

@@ -1,7 +1,8 @@
import { useEffect, useMemo } from 'react'; import { useEffect, useMemo } from 'react';
import { getKeyValue } from '../lib/keyValueStore'; import { jotaiStore } from '../lib/jotai';
import { useActiveEnvironment } from './useActiveEnvironment'; import { getKeyValue, setKeyValue } from '../lib/keyValueStore';
import { useActiveWorkspace } from './useActiveWorkspace'; import { activeEnvironmentIdAtom } from './useActiveEnvironment';
import { activeWorkspaceIdAtom, useActiveWorkspace } from './useActiveWorkspace';
import { useEnvironments } from './useEnvironments'; import { useEnvironments } from './useEnvironments';
import { useKeyValue } from './useKeyValue'; import { useKeyValue } from './useKeyValue';
@@ -12,23 +13,12 @@ const fallback: string[] = [];
export function useRecentEnvironments() { export function useRecentEnvironments() {
const { subEnvironments } = useEnvironments(); const { subEnvironments } = useEnvironments();
const activeWorkspace = useActiveWorkspace(); const activeWorkspace = useActiveWorkspace();
const [activeEnvironment] = useActiveEnvironment();
const kv = useKeyValue<string[]>({ const kv = useKeyValue<string[]>({
key: kvKey(activeWorkspace?.id ?? 'n/a'), key: kvKey(activeWorkspace?.id ?? 'n/a'),
namespace, namespace,
fallback, fallback,
}); });
// Set history when active request changes
useEffect(() => {
kv.set((currentHistory: string[]) => {
if (activeEnvironment === null) return currentHistory;
const withoutCurrentEnvironment = currentHistory.filter((id) => id !== activeEnvironment.id);
return [activeEnvironment.id, ...withoutCurrentEnvironment];
}).catch(console.error);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeEnvironment?.id]);
const onlyValidIds = useMemo( const onlyValidIds = useMemo(
() => kv.value?.filter((id) => subEnvironments.some((e) => e.id === id)) ?? [], () => kv.value?.filter((id) => subEnvironments.some((e) => e.id === id)) ?? [],
[kv.value, subEnvironments], [kv.value, subEnvironments],
@@ -37,6 +27,26 @@ export function useRecentEnvironments() {
return onlyValidIds; return onlyValidIds;
} }
export function useSubscribeRecentEnvironments() {
useEffect(() => {
return jotaiStore.sub(activeEnvironmentIdAtom, async () => {
const activeWorkspaceId = jotaiStore.get(activeWorkspaceIdAtom);
const activeEnvironmentId = jotaiStore.get(activeEnvironmentIdAtom);
if (activeWorkspaceId == null) return;
if (activeEnvironmentId == null) return;
const key = kvKey(activeWorkspaceId);
const recentIds = await getKeyValue<string[]>({ namespace, key, fallback });
if (recentIds[0] === activeEnvironmentId) return; // Short-circuit
const withoutActiveId = recentIds.filter((id) => id !== activeEnvironmentId);
const value = [activeEnvironmentId, ...withoutActiveId];
await setKeyValue({ namespace, key, value });
});
}, []);
}
export async function getRecentEnvironments(workspaceId: string) { export async function getRecentEnvironments(workspaceId: string) {
return getKeyValue<string[]>({ return getKeyValue<string[]>({
namespace, namespace,

View File

@@ -1,8 +1,8 @@
import { useEffect, useMemo } from 'react'; import { useEffect, useMemo } from 'react';
import { jotaiStore } from '../lib/jotai'; import { jotaiStore } from '../lib/jotai';
import { getKeyValue } from '../lib/keyValueStore'; import { getKeyValue, setKeyValue } from '../lib/keyValueStore';
import { activeRequestIdAtom } from './useActiveRequestId'; import { activeRequestIdAtom } from './useActiveRequestId';
import { useActiveWorkspace } from './useActiveWorkspace'; import { activeWorkspaceIdAtom, useActiveWorkspace } from './useActiveWorkspace';
import { useKeyValue } from './useKeyValue'; import { useKeyValue } from './useKeyValue';
import { useRequests } from './useRequests'; import { useRequests } from './useRequests';
@@ -29,22 +29,23 @@ export function useRecentRequests() {
} }
export function useSubscribeRecentRequests() { export function useSubscribeRecentRequests() {
const [recentRequests, setRecentRequests] = useRecentRequests();
useEffect(() => { useEffect(() => {
return jotaiStore.sub(activeRequestIdAtom, () => { return jotaiStore.sub(activeRequestIdAtom, async () => {
const activeRequestId = jotaiStore.get(activeRequestIdAtom) ?? null; const activeWorkspaceId = jotaiStore.get(activeWorkspaceIdAtom);
if (recentRequests[0] === activeRequestId) { const activeRequestId = jotaiStore.get(activeRequestIdAtom);
// Nothing to do if (activeWorkspaceId == null) return;
return; if (activeRequestId == null) return;
}
setRecentRequests((currentHistory) => { const key = kvKey(activeWorkspaceId);
if (activeRequestId === null) return currentHistory;
const withoutCurrentRequest = currentHistory.filter((id) => id !== activeRequestId); const recentIds = await getKeyValue<string[]>({ namespace, key, fallback });
return [activeRequestId, ...withoutCurrentRequest]; if (recentIds[0] === activeRequestId) return; // Short-circuit
}).catch(console.error);
const withoutActiveId = recentIds.filter((id) => id !== activeRequestId);
const value = [activeRequestId, ...withoutActiveId];
await setKeyValue({ namespace, key, value });
}); });
}, [recentRequests, setRecentRequests]); }, []);
} }
export async function getRecentRequests(workspaceId: string) { export async function getRecentRequests(workspaceId: string) {

View File

@@ -1,6 +1,7 @@
import { useEffect, useMemo } from 'react'; import { useEffect, useMemo } from 'react';
import { getKeyValue } from '../lib/keyValueStore'; import { jotaiStore } from '../lib/jotai';
import { useActiveWorkspace } from './useActiveWorkspace'; import { getKeyValue, setKeyValue } from '../lib/keyValueStore';
import { activeWorkspaceIdAtom } from './useActiveWorkspace';
import { useKeyValue } from './useKeyValue'; import { useKeyValue } from './useKeyValue';
import { useWorkspaces } from './useWorkspaces'; import { useWorkspaces } from './useWorkspaces';
@@ -10,22 +11,7 @@ const fallback: string[] = [];
export function useRecentWorkspaces() { export function useRecentWorkspaces() {
const workspaces = useWorkspaces(); const workspaces = useWorkspaces();
const activeWorkspace = useActiveWorkspace(); const { value } = useKeyValue<string[]>({ key: kvKey(), namespace, fallback });
const {value, set} = useKeyValue<string[]>({
key: kvKey(),
namespace,
fallback,
});
// Set history when active request changes
useEffect(() => {
set((currentHistory: string[]) => {
if (activeWorkspace === null) return currentHistory;
const withoutCurrent = currentHistory.filter((id) => id !== activeWorkspace.id);
return [activeWorkspace.id, ...withoutCurrent];
}).catch(console.error);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeWorkspace]);
const onlyValidIds = useMemo( const onlyValidIds = useMemo(
() => value?.filter((id) => workspaces.some((w) => w.id === id)) ?? [], () => value?.filter((id) => workspaces.some((w) => w.id === id)) ?? [],
@@ -35,10 +21,20 @@ export function useRecentWorkspaces() {
return onlyValidIds; return onlyValidIds;
} }
export async function getRecentWorkspaces() { export function useSubscribeRecentWorkspaces() {
return getKeyValue<string[]>({ useEffect(() => {
namespace, return jotaiStore.sub(activeWorkspaceIdAtom, async () => {
key: kvKey(), const activeWorkspaceId = jotaiStore.get(activeWorkspaceIdAtom);
fallback: fallback, if (activeWorkspaceId == null) return;
});
const key = kvKey();
const recentIds = await getKeyValue<string[]>({ namespace, key, fallback });
if (recentIds[0] === activeWorkspaceId) return; // Short-circuit
const withoutActiveId = recentIds.filter((id) => id !== activeWorkspaceId);
const value = [activeWorkspaceId, ...withoutActiveId];
await setKeyValue({ namespace, key, value });
});
}, []);
} }