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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,22 +1,22 @@
import { useFastMutation } from './useFastMutation';
import type { CookieJar } from '@yaakapp-internal/models';
import {useSetAtom} from "jotai";
import { useSetAtom } from 'jotai';
import { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import { useActiveWorkspace } from './useActiveWorkspace';
import {cookieJarsAtom} from "./useCookieJars";
import { getActiveWorkspaceId } from './useActiveWorkspace';
import { cookieJarsAtom } from './useCookieJars';
import { useFastMutation } from './useFastMutation';
import { usePrompt } from './usePrompt';
import {updateModelList} from "./useSyncModelStores";
import { updateModelList } from './useSyncModelStores';
export function useCreateCookieJar() {
const workspace = useActiveWorkspace();
const prompt = usePrompt();
const setCookieJars = useSetAtom(cookieJarsAtom);
return useFastMutation<CookieJar | null>({
mutationKey: ['create_cookie_jar'],
mutationFn: async () => {
if (workspace === null) {
const workspaceId = getActiveWorkspaceId();
if (workspaceId == null) {
throw new Error("Cannot create cookie jar when there's no active workspace");
}
const name = await prompt({
@@ -29,7 +29,7 @@ export function useCreateCookieJar() {
});
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) => {
if (cookieJar == null) return;

View File

@@ -11,7 +11,7 @@ import { useCreateHttpRequest } from './useCreateHttpRequest';
export function useCreateDropdownItems({
hideFolder,
hideIcons,
folderId,
folderId: folderIdOption,
}: {
hideFolder?: boolean;
hideIcons?: boolean;
@@ -21,19 +21,17 @@ export function useCreateDropdownItems({
const { mutate: createGrpcRequest } = useCreateGrpcRequest();
const { mutate: createFolder } = useCreateFolder();
return useCallback(
(): DropdownItem[] => [
return useCallback((): DropdownItem[] => {
const folderId =
folderIdOption === 'active-folder' ? getActiveRequest()?.folderId : folderIdOption;
return [
{
key: 'create-http-request',
label: 'HTTP Request',
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
onSelect: () => {
const args = { folderId };
if (folderId === 'active-folder') {
const activeRequest = getActiveRequest();
args.folderId = activeRequest?.folderId ?? undefined;
}
createHttpRequest(args);
createHttpRequest({ folderId });
},
},
{
@@ -67,7 +65,6 @@ export function useCreateDropdownItems({
onSelect: () => createFolder({ folderId }),
},
]) 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 { invokeCmd } from '../lib/tauri';
import { useActiveEnvironment } from './useActiveEnvironment';
import { useActiveWorkspace } from './useActiveWorkspace';
import { getActiveWorkspaceId } from './useActiveWorkspace';
import { environmentsAtom } from './useEnvironments';
import { useFastMutation } from './useFastMutation';
import { usePrompt } from './usePrompt';
@@ -12,7 +12,6 @@ import { updateModelList } from './useSyncModelStores';
export function useCreateEnvironment() {
const [, setActiveEnvironmentId] = useActiveEnvironment();
const prompt = usePrompt();
const workspace = useActiveWorkspace();
const setEnvironments = useSetAtom(environmentsAtom);
return useFastMutation<Environment | null, unknown, Environment | null>({
@@ -23,6 +22,7 @@ export function useCreateEnvironment() {
throw new Error('No base environment passed');
}
const workspaceId = getActiveWorkspaceId();
const name = await prompt({
id: 'new-environment',
title: 'New Environment',
@@ -37,7 +37,7 @@ export function useCreateEnvironment() {
return invokeCmd('cmd_create_environment', {
name,
variables: [],
workspaceId: workspace?.id,
workspaceId,
environmentId: baseEnvironment.id,
});
},

View File

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

View File

@@ -1,10 +1,10 @@
import { useFastMutation } from './useFastMutation';
import { useSetAtom } from 'jotai/index';
import { count } from '../lib/pluralize';
import { invokeCmd } from '../lib/tauri';
import { useActiveWorkspace } from './useActiveWorkspace';
import { getActiveWorkspaceId } from './useActiveWorkspace';
import { useAlert } from './useAlert';
import { useConfirm } from './useConfirm';
import { useFastMutation } from './useFastMutation';
import { useGrpcConnections } from './useGrpcConnections';
import { httpResponsesAtom, useHttpResponses } from './useHttpResponses';
@@ -12,7 +12,6 @@ export function useDeleteSendHistory() {
const confirm = useConfirm();
const alert = useAlert();
const setHttpResponses = useSetAtom(httpResponsesAtom);
const activeWorkspace = useActiveWorkspace();
const httpResponses = useHttpResponses();
const grpcConnections = useGrpcConnections();
const labels = [
@@ -40,13 +39,14 @@ export function useDeleteSendHistory() {
});
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;
},
onSuccess: async (confirmed) => {
if (!confirmed) return;
setHttpResponses((all) => all.filter((r) => r.workspaceId !== activeWorkspace?.id));
const activeWorkspaceId = getActiveWorkspaceId();
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 { trackEvent } from '../lib/analytics';
import { invokeCmd } from '../lib/tauri';
import { useActiveWorkspace } from './useActiveWorkspace';
import { getActiveWorkspace } from './useActiveWorkspace';
import { useConfirm } from './useConfirm';
import { useFastMutation } from './useFastMutation';
import { removeModelById } from './useSyncModelStores';
import { workspacesAtom } from './useWorkspaces';
export function useDeleteWorkspace(workspace: Workspace | null) {
const activeWorkspace = useActiveWorkspace();
const confirm = useConfirm();
const setWorkspaces = useSetAtom(workspacesAtom);
const navigate = useNavigate();
@@ -19,6 +18,7 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
return useFastMutation<Workspace | null, string>({
mutationKey: ['delete_workspace', workspace?.id],
mutationFn: async () => {
const workspace = getActiveWorkspace();
const confirmed = await confirm({
id: 'delete-workspace',
title: 'Delete Workspace',
@@ -40,8 +40,9 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
setWorkspaces(removeModelById(workspace));
const { id: workspaceId } = workspace;
const activeWorkspace = getActiveWorkspace();
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 { useActiveWorkspace } from './useActiveWorkspace';
import { jotaiStore } from '../lib/jotai';
import { getActiveWorkspace } from './useActiveWorkspace';
import { useAlert } from './useAlert';
import { useWorkspaces } from './useWorkspaces';
import { useDialog } from './useDialog';
import { useFastMutation } from './useFastMutation';
import { useToast } from './useToast';
import { workspacesAtom } from './useWorkspaces';
export function useExportData() {
const workspaces = useWorkspaces();
const activeWorkspace = useActiveWorkspace();
const alert = useAlert();
const dialog = useDialog();
const toast = useToast();
@@ -19,6 +18,9 @@ export function useExportData() {
alert({ id: 'export-failed', title: 'Export Failed', body: err });
},
mutationFn: async () => {
const activeWorkspace = getActiveWorkspace();
const workspaces = jotaiStore.get(workspacesAtom);
if (activeWorkspace == null || workspaces.length === 0) return;
dialog.show({

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,8 @@
import { useEffect, useMemo } from 'react';
import { getKeyValue } from '../lib/keyValueStore';
import { useActiveEnvironment } from './useActiveEnvironment';
import { useActiveWorkspace } from './useActiveWorkspace';
import { jotaiStore } from '../lib/jotai';
import { getKeyValue, setKeyValue } from '../lib/keyValueStore';
import { activeEnvironmentIdAtom } from './useActiveEnvironment';
import { activeWorkspaceIdAtom, useActiveWorkspace } from './useActiveWorkspace';
import { useEnvironments } from './useEnvironments';
import { useKeyValue } from './useKeyValue';
@@ -12,23 +13,12 @@ const fallback: string[] = [];
export function useRecentEnvironments() {
const { subEnvironments } = useEnvironments();
const activeWorkspace = useActiveWorkspace();
const [activeEnvironment] = useActiveEnvironment();
const kv = useKeyValue<string[]>({
key: kvKey(activeWorkspace?.id ?? 'n/a'),
namespace,
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(
() => kv.value?.filter((id) => subEnvironments.some((e) => e.id === id)) ?? [],
[kv.value, subEnvironments],
@@ -37,6 +27,26 @@ export function useRecentEnvironments() {
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) {
return getKeyValue<string[]>({
namespace,

View File

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

View File

@@ -1,6 +1,7 @@
import { useEffect, useMemo } from 'react';
import { getKeyValue } from '../lib/keyValueStore';
import { useActiveWorkspace } from './useActiveWorkspace';
import { jotaiStore } from '../lib/jotai';
import { getKeyValue, setKeyValue } from '../lib/keyValueStore';
import { activeWorkspaceIdAtom } from './useActiveWorkspace';
import { useKeyValue } from './useKeyValue';
import { useWorkspaces } from './useWorkspaces';
@@ -10,22 +11,7 @@ const fallback: string[] = [];
export function useRecentWorkspaces() {
const workspaces = useWorkspaces();
const activeWorkspace = useActiveWorkspace();
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 { value } = useKeyValue<string[]>({ key: kvKey(), namespace, fallback });
const onlyValidIds = useMemo(
() => value?.filter((id) => workspaces.some((w) => w.id === id)) ?? [],
@@ -35,10 +21,20 @@ export function useRecentWorkspaces() {
return onlyValidIds;
}
export async function getRecentWorkspaces() {
return getKeyValue<string[]>({
namespace,
key: kvKey(),
fallback: fallback,
});
export function useSubscribeRecentWorkspaces() {
useEffect(() => {
return jotaiStore.sub(activeWorkspaceIdAtom, async () => {
const activeWorkspaceId = jotaiStore.get(activeWorkspaceIdAtom);
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 });
});
}, []);
}