From b617df24d18d90b5bab5823d3a25e77e7e699432 Mon Sep 17 00:00:00 2001 From: thatmattlove Date: Sun, 30 Jun 2024 22:22:44 -0400 Subject: [PATCH] fixes #267: fix response caching --- hyperglass/api/routes.py | 8 +++--- hyperglass/ui/components/header/title.tsx | 2 +- hyperglass/ui/components/layout.tsx | 6 ++--- hyperglass/ui/components/path/path.tsx | 4 ++- hyperglass/ui/components/submit-button.tsx | 26 +++++++++---------- hyperglass/ui/context/hyperglass-provider.tsx | 4 +-- hyperglass/ui/hooks/use-form-state.ts | 15 ++++++++--- hyperglass/ui/hooks/use-lg-query.ts | 2 -- 8 files changed, 39 insertions(+), 28 deletions(-) diff --git a/hyperglass/api/routes.py b/hyperglass/api/routes.py index cc48199..9e17c9a 100644 --- a/hyperglass/api/routes.py +++ b/hyperglass/api/routes.py @@ -1,6 +1,7 @@ """API Routes.""" # Standard Library +import json import time import typing as t from datetime import UTC, datetime @@ -119,7 +120,10 @@ async def query(_state: HyperglassState, request: Request, data: Query) -> Query json_output = is_type(output, OutputDataModel) if json_output: - raw_output = output.export_dict() + # Export structured output as JSON string to guarantee value + # is serializable, then convert it back to a dict. + as_json = output.export_json() + raw_output = json.loads(as_json) else: raw_output = str(output) @@ -138,8 +142,6 @@ async def query(_state: HyperglassState, request: Request, data: Query) -> Query response_format = "text/plain" if json_output: - if cache_response.get("level") != "success": - cache.delete(cache_key) response_format = "application/json" _log.info("Execution completed") diff --git a/hyperglass/ui/components/header/title.tsx b/hyperglass/ui/components/header/title.tsx index 57331a3..c69b036 100644 --- a/hyperglass/ui/components/header/title.tsx +++ b/hyperglass/ui/components/header/title.tsx @@ -144,7 +144,7 @@ export const Title = (props: FlexProps): JSX.Element => { variant="link" flexWrap="wrap" flexDir="column" - onClick={() => reset()} + onClick={async () => await reset()} _focus={{ boxShadow: 'none' }} _hover={{ textDecoration: 'none' }} > diff --git a/hyperglass/ui/components/layout.tsx b/hyperglass/ui/components/layout.tsx index c90d307..585a73a 100644 --- a/hyperglass/ui/components/layout.tsx +++ b/hyperglass/ui/components/layout.tsx @@ -1,8 +1,8 @@ -import { useCallback, useRef } from 'react'; import { Flex } from '@chakra-ui/react'; +import { useCallback, useRef } from 'react'; import { isSafari } from 'react-device-detect'; import { If, Then } from 'react-if'; -import { Debugger, Greeting, Footer, Header, ResetButton } from '~/components'; +import { Debugger, Footer, Greeting, Header, ResetButton } from '~/components'; import { useConfig } from '~/context'; import { motionChakra } from '~/elements'; import { useFormState } from '~/hooks'; @@ -31,7 +31,7 @@ export const Layout = (props: FlexProps): JSX.Element => { const containerRef = useRef({} as HTMLDivElement); - function handleReset(): void { + async function handleReset() { containerRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' }); setStatus('form'); reset(); diff --git a/hyperglass/ui/components/path/path.tsx b/hyperglass/ui/components/path/path.tsx index a6a797f..0fd3d74 100644 --- a/hyperglass/ui/components/path/path.tsx +++ b/hyperglass/ui/components/path/path.tsx @@ -40,7 +40,9 @@ export const Path = (props: PathProps): JSX.Element => { {`Path to ${displayTarget}`} - {response !== null ? : } + + + diff --git a/hyperglass/ui/components/submit-button.tsx b/hyperglass/ui/components/submit-button.tsx index f85fc01..ef4cbd5 100644 --- a/hyperglass/ui/components/submit-button.tsx +++ b/hyperglass/ui/components/submit-button.tsx @@ -1,23 +1,23 @@ -import { forwardRef } from 'react'; import { - Modal, - Popover, - ModalBody, IconButton, - PopoverBody, - ModalOverlay, - ModalContent, - PopoverArrow, - PopoverTrigger, - PopoverContent, + Modal, + ModalBody, ModalCloseButton, + ModalContent, + ModalOverlay, + Popover, + PopoverArrow, + PopoverBody, PopoverCloseButton, + PopoverContent, + PopoverTrigger, } from '@chakra-ui/react'; +import { forwardRef } from 'react'; import { useFormContext } from 'react-hook-form'; -import { If, Then, Else } from 'react-if'; +import { Else, If, Then } from 'react-if'; import { ResolvedTarget } from '~/components'; import { DynamicIcon } from '~/elements'; -import { useFormState, useMobile, useColorValue } from '~/hooks'; +import { useColorValue, useFormState, useMobile } from '~/hooks'; import type { IconButtonProps } from '@chakra-ui/react'; @@ -114,7 +114,7 @@ export const SubmitButton = (props: SubmitButtonProps): JSX.Element => { const { reset } = useFormContext(); - function handleClose(): void { + async function handleClose() { reset(); resetForm(); resolvedClose(); diff --git a/hyperglass/ui/context/hyperglass-provider.tsx b/hyperglass/ui/context/hyperglass-provider.tsx index 24180b2..eca4625 100644 --- a/hyperglass/ui/context/hyperglass-provider.tsx +++ b/hyperglass/ui/context/hyperglass-provider.tsx @@ -1,6 +1,6 @@ -import { createContext, useContext, useMemo } from 'react'; import { ChakraProvider, localStorageManager } from '@chakra-ui/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { createContext, useContext, useMemo } from 'react'; import { makeTheme } from '~/util'; import type { Config } from '~/types'; @@ -12,7 +12,7 @@ interface HyperglassProviderProps { export const HyperglassContext = createContext({} as Config); -const queryClient = new QueryClient(); +export const queryClient = new QueryClient(); export const HyperglassProvider = (props: HyperglassProviderProps): JSX.Element => { const { config, children } = props; diff --git a/hyperglass/ui/hooks/use-form-state.ts b/hyperglass/ui/hooks/use-form-state.ts index f9cdd05..5afebaf 100644 --- a/hyperglass/ui/hooks/use-form-state.ts +++ b/hyperglass/ui/hooks/use-form-state.ts @@ -3,6 +3,7 @@ import plur from 'plur'; import { useMemo } from 'react'; import isEqual from 'react-fast-compare'; import create from 'zustand'; +import { queryClient } from '~/context'; import { all, andJoin, dedupObjectArray, withDev } from '~/util'; import type { UseFormClearErrors, UseFormSetError } from 'react-hook-form'; @@ -61,10 +62,13 @@ interface FormStateType { setSelection< Opt extends SingleOption, K extends keyof FormSelections = keyof FormSelections, - >(field: K, value: FormSelections[K]): void; + >( + field: K, + value: FormSelections[K], + ): void; setTarget(update: Partial): void; getDirective(): Directive | null; - reset(): void; + reset(): Promise; setFormValue(field: K, value: FormValues[K]): void; locationChange( locations: string[], @@ -198,7 +202,8 @@ const formState: StateCreator = (set, get) => ({ return null; }, - reset(): void { + async reset(): Promise { + const { form } = get(); set({ filtered: { types: [], groups: [] }, form: { queryLocation: [], queryTarget: [], queryType: '' }, @@ -209,6 +214,10 @@ const formState: StateCreator = (set, get) => ({ target: { display: '' }, resolvedIsOpen: false, }); + for (const queryLocation of form.queryLocation) { + const query = { queryLocation, queryTarget: form.queryTarget, queryType: form.queryType }; + queryClient.removeQueries({ queryKey: ['/api/query', query] }); + } }, }); diff --git a/hyperglass/ui/hooks/use-lg-query.ts b/hyperglass/ui/hooks/use-lg-query.ts index d03cf88..09b9f3e 100644 --- a/hyperglass/ui/hooks/use-lg-query.ts +++ b/hyperglass/ui/hooks/use-lg-query.ts @@ -72,8 +72,6 @@ export function useLGQuery( return useQuery({ queryKey: ['/api/query', query], queryFn: runQuery, - // Invalidate react-query's cache just shy of the configured cache timeout. - cacheTime: cache.timeout * 1000 * 0.95, // Don't refetch when window refocuses. refetchOnWindowFocus: false, // Don't automatically refetch query data (queries should be on-off).