mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-21 17:09:09 +01:00
query client cache and better body types
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
||||
import { persistQueryClient } from '@tanstack/react-query-persist-client';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
import { MotionConfig } from 'framer-motion';
|
||||
@@ -18,7 +20,25 @@ import type { HttpRequest, HttpResponse, KeyValue, Workspace } from '../lib/mode
|
||||
import { convertDates } from '../lib/models';
|
||||
import { AppRouter } from './AppRouter';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
cacheTime: 1000 * 60 * 60 * 24, // 24 hours
|
||||
networkMode: 'offlineFirst',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const localStoragePersister = createSyncStoragePersister({
|
||||
storage: window.localStorage,
|
||||
throttleTime: 1000,
|
||||
});
|
||||
|
||||
persistQueryClient({
|
||||
queryClient,
|
||||
persister: localStoragePersister,
|
||||
maxAge: 1000 * 60 * 60 * 24, // 24 hours
|
||||
});
|
||||
|
||||
await listen('updated_key_value', ({ payload: keyValue }: { payload: KeyValue }) => {
|
||||
queryClient.setQueryData(keyValueQueryKey(keyValue), extractKeyValue(keyValue));
|
||||
|
||||
@@ -4,7 +4,8 @@ import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { useKeyValue } from '../hooks/useKeyValue';
|
||||
import { useUpdateRequest } from '../hooks/useUpdateRequest';
|
||||
import { tryFormatJson } from '../lib/formatters';
|
||||
import type { HttpHeader } from '../lib/models';
|
||||
import type { HttpHeader, HttpRequest } from '../lib/models';
|
||||
import { HttpRequestBodyType } from '../lib/models';
|
||||
import { Editor } from './core/Editor';
|
||||
import type { TabItem } from './core/Tabs/Tabs';
|
||||
import { TabContent, Tabs } from './core/Tabs/Tabs';
|
||||
@@ -27,19 +28,25 @@ export function RequestPane({ fullHeight, className }: Props) {
|
||||
defaultValue: 'body',
|
||||
});
|
||||
|
||||
const tabs: TabItem<string | null>[] = useMemo(
|
||||
const tabs: TabItem<HttpRequest['bodyType']>[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
value: 'body',
|
||||
label: activeRequest?.bodyType ?? 'No Body',
|
||||
options: {
|
||||
onChange: (bodyType: string | null) => updateRequest.mutate({ bodyType }),
|
||||
onChange: (bodyType: HttpRequest['bodyType']) => {
|
||||
const patch: Partial<HttpRequest> = { bodyType };
|
||||
if (bodyType == HttpRequestBodyType.GraphQL) {
|
||||
patch.method = 'POST';
|
||||
}
|
||||
updateRequest.mutate(patch);
|
||||
},
|
||||
value: activeRequest?.bodyType ?? null,
|
||||
items: [
|
||||
{ label: 'No Body', value: null },
|
||||
{ label: 'JSON', value: 'json' },
|
||||
{ label: 'XML', value: 'xml' },
|
||||
{ label: 'GraphQL', value: 'graphql' },
|
||||
{ label: 'JSON', value: HttpRequestBodyType.JSON },
|
||||
{ label: 'XML', value: HttpRequestBodyType.XML },
|
||||
{ label: 'GraphQL', value: HttpRequestBodyType.GraphQL },
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -85,7 +92,7 @@ export function RequestPane({ fullHeight, className }: Props) {
|
||||
<ParametersEditor key={activeRequestId} parameters={[]} onChange={() => null} />
|
||||
</TabContent>
|
||||
<TabContent value="body" className="pl-3 mt-1">
|
||||
{activeRequest.bodyType === 'json' ? (
|
||||
{activeRequest.bodyType === HttpRequestBodyType.JSON ? (
|
||||
<Editor
|
||||
key={activeRequest.id}
|
||||
useTemplating
|
||||
@@ -96,7 +103,7 @@ export function RequestPane({ fullHeight, className }: Props) {
|
||||
onChange={handleBodyChange}
|
||||
format={(v) => tryFormatJson(v)}
|
||||
/>
|
||||
) : activeRequest.bodyType === 'xml' ? (
|
||||
) : activeRequest.bodyType === HttpRequestBodyType.XML ? (
|
||||
<Editor
|
||||
key={activeRequest.id}
|
||||
useTemplating
|
||||
@@ -106,7 +113,7 @@ export function RequestPane({ fullHeight, className }: Props) {
|
||||
contentType="text/xml"
|
||||
onChange={handleBodyChange}
|
||||
/>
|
||||
) : activeRequest.bodyType === 'graphql' ? (
|
||||
) : activeRequest.bodyType === HttpRequestBodyType.GraphQL ? (
|
||||
<GraphQLEditor
|
||||
key={activeRequest.id}
|
||||
className="!bg-gray-50"
|
||||
|
||||
@@ -26,7 +26,7 @@ export default function Workspace() {
|
||||
// TODO: Use container query subscription instead of minitoring everything
|
||||
}, [mainContentRef.current, windowSize, sidebarWidth.value]);
|
||||
|
||||
const isSideBySide = mainContentWidth > 700;
|
||||
const isSideBySide = mainContentWidth > 900;
|
||||
|
||||
if (activeWorkspace == null) {
|
||||
return null;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import classnames from 'classnames';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
||||
import { useCreateWorkspace } from '../hooks/useCreateWorkspace';
|
||||
@@ -16,12 +17,12 @@ type Props = {
|
||||
};
|
||||
|
||||
export const WorkspaceDropdown = memo(function WorkspaceDropdown({ className }: Props) {
|
||||
const routes = useRoutes();
|
||||
const workspaces = useWorkspaces();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const activeWorkspaceId = activeWorkspace?.id ?? null;
|
||||
const createWorkspace = useCreateWorkspace({ navigateAfter: true });
|
||||
const deleteWorkspace = useDeleteWorkspace(activeWorkspaceId);
|
||||
const routes = useRoutes();
|
||||
|
||||
const items: DropdownItem[] = useMemo(() => {
|
||||
const workspaceItems = workspaces.map((w) => ({
|
||||
@@ -52,7 +53,7 @@ export const WorkspaceDropdown = memo(function WorkspaceDropdown({ className }:
|
||||
return (
|
||||
<Dropdown items={items}>
|
||||
<Button size="sm" className={classnames(className, '!px-2 truncate')} forDropdown>
|
||||
{activeWorkspace?.name ?? 'Unknown'}
|
||||
{activeWorkspace?.name}
|
||||
</Button>
|
||||
</Dropdown>
|
||||
);
|
||||
|
||||
@@ -271,6 +271,7 @@ const FormRow = memo(function FormRow({
|
||||
onChange={handleChangeEnabled}
|
||||
/>
|
||||
<div
|
||||
onDragStart={(e) => e.preventDefault()}
|
||||
className={classnames(
|
||||
'grid items-center',
|
||||
'@xs:gap-2 @xs:!grid-rows-1 @xs:!grid-cols-[minmax(0,1fr)_minmax(0,1fr)]',
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
.tab-content {
|
||||
&[data-state="inactive"] {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,7 @@ import type { RadioDropdownProps } from '../RadioDropdown';
|
||||
import { RadioDropdown } from '../RadioDropdown';
|
||||
import { HStack } from '../Stacks';
|
||||
|
||||
import './Tabs.css';
|
||||
|
||||
export type TabItem<T> = {
|
||||
export type TabItem<T = string> = {
|
||||
value: string;
|
||||
label: string;
|
||||
options?: Omit<RadioDropdownProps<T>, 'children'>;
|
||||
@@ -37,14 +35,18 @@ export function Tabs<T>({
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const handleTabChange = (value: string) => {
|
||||
const tabs = ref.current?.querySelectorAll(`[data-tab]`);
|
||||
const tabs = ref.current?.querySelectorAll<HTMLDivElement>(`[data-tab]`);
|
||||
for (const tab of tabs ?? []) {
|
||||
const v = tab.getAttribute('data-tab');
|
||||
if (v === value) {
|
||||
tab.setAttribute('tabindex', '-1');
|
||||
tab.setAttribute('data-state', 'active');
|
||||
tab.setAttribute('aria-hidden', 'false');
|
||||
tab.style.display = 'block';
|
||||
} else {
|
||||
tab.setAttribute('data-state', 'inactive');
|
||||
tab.setAttribute('aria-hidden', 'true');
|
||||
tab.style.display = 'none';
|
||||
}
|
||||
}
|
||||
onChangeValue(value);
|
||||
|
||||
Reference in New Issue
Block a user