From 0f0e61f4037d8a2221c277e764b6f1f8a83c3a0b Mon Sep 17 00:00:00 2001 From: checktheroads Date: Sun, 20 Dec 2020 01:21:24 -0700 Subject: [PATCH] continue typescript & chakra v1 migrations [skip ci] --- hyperglass/ui/components/buttons/reset.tsx | 4 +- hyperglass/ui/components/buttons/submit.tsx | 119 +++++++++---- hyperglass/ui/components/buttons/types.ts | 7 + hyperglass/ui/components/debugger.tsx | 76 ++++---- .../ui/components/form/communitySelect.tsx | 1 + hyperglass/ui/components/form/field.tsx | 38 ++-- .../ui/components/form/queryLocation.tsx | 4 + hyperglass/ui/components/form/queryTarget.tsx | 43 +---- hyperglass/ui/components/form/queryType.tsx | 3 + .../ui/components/form/resolvedTarget.tsx | 5 +- hyperglass/ui/components/form/types.ts | 28 +-- .../ui/components/greeting/greeting.tsx | 39 +++-- hyperglass/ui/components/greeting/types.ts | 4 +- hyperglass/ui/components/header/header.tsx | 6 +- hyperglass/ui/components/layout/frame.tsx | 20 +-- hyperglass/ui/components/layout/layout.tsx | 4 +- hyperglass/ui/components/lookingGlass.tsx | 162 ++++++++---------- hyperglass/ui/components/results/group.tsx | 27 ++- .../ui/components/results/individual.tsx | 11 +- hyperglass/ui/components/select/select.tsx | 8 +- hyperglass/ui/components/select/styles.tsx | 14 +- hyperglass/ui/components/select/types.ts | 2 + hyperglass/ui/components/title/title.tsx | 6 +- hyperglass/ui/hooks/useGreeting.ts | 7 +- hyperglass/ui/hooks/useLGState.ts | 19 +- hyperglass/ui/package.json | 3 +- hyperglass/ui/yarn.lock | 13 +- 27 files changed, 363 insertions(+), 310 deletions(-) diff --git a/hyperglass/ui/components/buttons/reset.tsx b/hyperglass/ui/components/buttons/reset.tsx index b2bc661..6d197ef 100644 --- a/hyperglass/ui/components/buttons/reset.tsx +++ b/hyperglass/ui/components/buttons/reset.tsx @@ -1,7 +1,7 @@ import { forwardRef } from 'react'; import dynamic from 'next/dynamic'; import { Button, Icon } from '@chakra-ui/react'; -import { useGlobalState } from '~/context'; +import { useLGState } from '~/hooks'; import type { ButtonProps } from '@chakra-ui/react'; @@ -10,7 +10,7 @@ const ChevronLeft = dynamic(() => ); export const ResetButton = forwardRef((props, ref) => { - const { isSubmitting } = useGlobalState(); + const { isSubmitting } = useLGState(); return ( - - - - - - Loaded Configuration - - - {JSON.stringify(config, null, 4)} - - - - - - - Loaded Theme - - - {JSON.stringify(theme, null, 4)} - - - + + {mediaSize} + + + + {JSON.stringify(config, null, 4)} + + + {JSON.stringify(theme, null, 4)} + ); }; diff --git a/hyperglass/ui/components/form/communitySelect.tsx b/hyperglass/ui/components/form/communitySelect.tsx index 714f219..85f45c8 100644 --- a/hyperglass/ui/components/form/communitySelect.tsx +++ b/hyperglass/ui/components/form/communitySelect.tsx @@ -20,6 +20,7 @@ const Option = (props: OptionProps) => { return ( {label} +
{data.description} diff --git a/hyperglass/ui/components/form/field.tsx b/hyperglass/ui/components/form/field.tsx index 2ffa322..80f4692 100644 --- a/hyperglass/ui/components/form/field.tsx +++ b/hyperglass/ui/components/form/field.tsx @@ -1,34 +1,24 @@ -import { useMemo } from 'react'; import { Flex, FormControl, FormLabel, FormErrorMessage } from '@chakra-ui/react'; +import { useFormContext } from 'react-hook-form'; import { If } from '~/components'; import { useColorValue } from '~/context'; import { useBooleanValue } from '~/hooks'; -import { TField } from './types'; +import { TField, TFormError } from './types'; export const FormField = (props: TField) => { - const { - name, - label, - errors, - children, - labelAddOn, - fieldAddOn, - hiddenLabels = false, - ...rest - } = props; + const { name, label, children, labelAddOn, fieldAddOn, hiddenLabels = false, ...rest } = props; const labelColor = useColorValue('blackAlpha.700', 'whiteAlpha.700'); + const errorColor = useColorValue('red.500', 'red.300'); const opacity = useBooleanValue(hiddenLabels, 0, undefined); - const error = useMemo(() => { - let result; - if (Array.isArray(errors)) { - result = errors.join(', '); - } else if (typeof errors === 'string') { - result = errors; - } - return result; - }, [errors]); + const { errors } = useFormContext(); + + const error = name in errors && (errors[name] as TFormError); + + if (error !== false) { + console.warn(`${label} Error: ${error.message}`); + } return ( { maxW="100%" flexDir="column" my={{ base: 2, lg: 4 }} - isInvalid={typeof error !== 'undefined'} + isInvalid={error !== false} flex={{ base: '1 0 100%', lg: '1 0 33.33%' }} {...rest}> { htmlFor={name} display="flex" opacity={opacity} - color={labelColor} + color={error !== false ? errorColor : labelColor} alignItems="center" justifyContent="space-between"> {label} @@ -59,7 +49,7 @@ export const FormField = (props: TField) => { {fieldAddOn} - {error} + {error && error.message} ); }; diff --git a/hyperglass/ui/components/form/queryLocation.tsx b/hyperglass/ui/components/form/queryLocation.tsx index 98b9cc3..2842f8b 100644 --- a/hyperglass/ui/components/form/queryLocation.tsx +++ b/hyperglass/ui/components/form/queryLocation.tsx @@ -1,4 +1,5 @@ import { useMemo } from 'react'; +import { useFormContext } from 'react-hook-form'; import { Select } from '~/components'; import { useConfig } from '~/context'; @@ -21,6 +22,8 @@ export const QueryLocation = (props: TQuerySelectField) => { const { onChange, label } = props; const { networks } = useConfig(); + const { errors } = useFormContext(); + const options = useMemo(() => buildOptions(networks), [networks.length]); function handleChange(e: TSelectOption | TSelectOption[]): void { @@ -44,6 +47,7 @@ export const QueryLocation = (props: TQuerySelectField) => { name="query_location" onChange={handleChange} closeMenuOnSelect={false} + isError={typeof errors.query_location !== 'undefined'} /> ); }; diff --git a/hyperglass/ui/components/form/queryTarget.tsx b/hyperglass/ui/components/form/queryTarget.tsx index 2a90222..6347552 100644 --- a/hyperglass/ui/components/form/queryTarget.tsx +++ b/hyperglass/ui/components/form/queryTarget.tsx @@ -1,69 +1,42 @@ -import { useEffect } from 'react'; import { Input } from '@chakra-ui/react'; import { useColorValue } from '~/context'; +import { useLGState } from '~/hooks'; import type { TQueryTarget } from './types'; const fqdnPattern = /^(?!:\/\/)([a-zA-Z0-9-]+\.)?[a-zA-Z0-9-][a-zA-Z0-9-]+\.[a-zA-Z-]{2,6}?$/gim; export const QueryTarget = (props: TQueryTarget) => { - const { - name, - value, - setFqdn, - register, - setTarget, - unregister, - placeholder, - displayValue, - resolveTarget, - setDisplayValue, - } = props; + const { name, register, setTarget, placeholder, resolveTarget } = props; const bg = useColorValue('white', 'whiteAlpha.100'); const color = useColorValue('gray.400', 'whiteAlpha.800'); const border = useColorValue('gray.100', 'whiteAlpha.50'); const placeholderColor = useColorValue('gray.600', 'whiteAlpha.700'); - function handleBlur(): void { - if (resolveTarget && displayValue && fqdnPattern.test(displayValue)) { - setFqdn(displayValue); - } else if (resolveTarget && !displayValue) { - setFqdn(null); - } - } + const { queryTarget, fqdnTarget, displayTarget } = useLGState(); function handleChange(e: React.ChangeEvent): void { - setDisplayValue(e.target.value); + displayTarget.set(e.target.value); setTarget({ field: name, value: e.target.value }); - } - function handleKeyDown(e: React.KeyboardEvent): void { - if (['Tab', 'NumpadEnter'].includes(e.key)) { - handleBlur(); + if (resolveTarget && displayTarget.value && fqdnPattern.test(displayTarget.value)) { + fqdnTarget.set(displayTarget.value); } } - useEffect(() => { - register({ name }); - return () => unregister(name); - }, [register, unregister, name]); - return ( <> - + { const { onChange, label } = props; const { queries } = useConfig(); + const { errors } = useFormContext(); const options = useMemo(() => buildOptions(queries.list), [queries.list.length]); @@ -30,6 +32,7 @@ export const QueryType = (props: TQuerySelectField) => { options={options} aria-label={label} onChange={handleChange} + isError={typeof errors.query_type !== 'undefined'} /> ); }; diff --git a/hyperglass/ui/components/form/resolvedTarget.tsx b/hyperglass/ui/components/form/resolvedTarget.tsx index f9d0f51..1d0cffc 100644 --- a/hyperglass/ui/components/form/resolvedTarget.tsx +++ b/hyperglass/ui/components/form/resolvedTarget.tsx @@ -2,7 +2,7 @@ import { useEffect, useMemo } from 'react'; import { Button, Stack, Text, VStack } from '@chakra-ui/react'; import { useQuery } from 'react-query'; import { FiArrowRightCircle as RightArrow } from '@meronex/icons/fi'; -import { useConfig, useColorValue, useGlobalState } from '~/context'; +import { useConfig, useColorValue } from '~/context'; import { useStrf, useLGState } from '~/hooks'; import type { DnsOverHttps } from '~/types'; @@ -20,8 +20,7 @@ function findAnswer(data: DnsOverHttps.Response | undefined): string { export const ResolvedTarget = (props: TResolvedTarget) => { const { setTarget } = props; const { web } = useConfig(); - const { isSubmitting } = useGlobalState(); - const { fqdnTarget, queryTarget, families, formData } = useLGState(); + const { fqdnTarget, isSubmitting, families, formData } = useLGState(); const color = useColorValue('secondary.500', 'secondary.300'); diff --git a/hyperglass/ui/components/form/types.ts b/hyperglass/ui/components/form/types.ts index 63acab3..fc5eada 100644 --- a/hyperglass/ui/components/form/types.ts +++ b/hyperglass/ui/components/form/types.ts @@ -1,11 +1,13 @@ import type { FormControlProps } from '@chakra-ui/react'; import type { FieldError, Control } from 'react-hook-form'; -import type { TDeviceVrf, TBGPCommunity, OnChangeArgs, TFormData } from '~/types'; +import type { TDeviceVrf, TBGPCommunity, OnChangeArgs } from '~/types'; +import type { ValidationError } from 'yup'; + +export type TFormError = Pick; export interface TField extends FormControlProps { name: string; label: string; - errors?: FieldError | FieldError[]; hiddenLabels?: boolean; labelAddOn?: React.ReactNode; fieldAddOn?: React.ReactNode; @@ -30,32 +32,12 @@ export interface TCommunitySelect { unregister: Control['unregister']; } -/** - * placeholder, - register, - unregister, - setFqdn, - - name, - value, - - setTarget, - resolveTarget, - - displayValue, - setDisplayValue, - */ export interface TQueryTarget { name: string; placeholder: string; - displayValue: string; resolveTarget: boolean; - setFqdn(f: string | null): void; - setTarget(e: OnChangeArgs): void; register: Control['register']; - value: TFormData['query_target']; - setDisplayValue(d: string): void; - unregister: Control['unregister']; + setTarget(e: OnChangeArgs): void; } export interface TResolvedTarget { diff --git a/hyperglass/ui/components/greeting/greeting.tsx b/hyperglass/ui/components/greeting/greeting.tsx index 05e44e7..0082938 100644 --- a/hyperglass/ui/components/greeting/greeting.tsx +++ b/hyperglass/ui/components/greeting/greeting.tsx @@ -11,31 +11,40 @@ import { } from '@chakra-ui/react'; import { If, Markdown } from '~/components'; import { useConfig, useColorValue } from '~/context'; +import { useGreeting, useOpposingColor } from '~/hooks'; import type { TGreeting } from './types'; export const Greeting = (props: TGreeting) => { - const { onClickThrough, ...rest } = props; const { web, content } = useConfig(); const { isOpen, onClose } = useDisclosure(); + const [greetingAck, setGreetingAck] = useGreeting(); - const bg = useColorValue('white', 'black'); - const color = useColorValue('black', 'white'); + const bg = useColorValue('white', 'gray.800'); + const color = useOpposingColor(bg); - function handleClick(): void { - onClickThrough(); - onClose(); - return; + function handleClose(ack: boolean = false): void { + if (web.greeting.required && !greetingAck && !ack) { + setGreetingAck(false); + } else if (web.greeting.required && !greetingAck && ack) { + setGreetingAck(); + onClose(); + } else if (web.greeting.required && greetingAck) { + onClose(); + } else if (!web.greeting.required) { + setGreetingAck(); + onClose(); + } } - return ( + onClose={handleClose} + motionPreset="slideInBottom" + closeOnEsc={web.greeting.required} + isOpen={!greetingAck ? true : isOpen} + closeOnOverlayClick={web.greeting.required}> { color={color} borderRadius="md" maxW={{ base: '95%', md: '75%' }} - {...rest}> + {...props}> {web.greeting.title} @@ -52,7 +61,7 @@ export const Greeting = (props: TGreeting) => { - diff --git a/hyperglass/ui/components/greeting/types.ts b/hyperglass/ui/components/greeting/types.ts index 2cc634e..1568d2a 100644 --- a/hyperglass/ui/components/greeting/types.ts +++ b/hyperglass/ui/components/greeting/types.ts @@ -1,5 +1,3 @@ import { BoxProps } from '@chakra-ui/react'; -export interface TGreeting extends BoxProps { - onClickThrough(): void; -} +export interface TGreeting extends BoxProps {} diff --git a/hyperglass/ui/components/header/header.tsx b/hyperglass/ui/components/header/header.tsx index 59ce102..22dd042 100644 --- a/hyperglass/ui/components/header/header.tsx +++ b/hyperglass/ui/components/header/header.tsx @@ -1,8 +1,8 @@ import { Flex } from '@chakra-ui/react'; import { motion, AnimatePresence } from 'framer-motion'; import { AnimatedDiv, Title, ResetButton, ColorModeToggle } from '~/components'; -import { useColorValue, useConfig, useGlobalState, useBreakpointValue } from '~/context'; -import { useBooleanValue } from '~/hooks'; +import { useColorValue, useConfig, useBreakpointValue } from '~/context'; +import { useBooleanValue, useLGState } from '~/hooks'; import type { ResponsiveValue } from '@chakra-ui/react'; import type { THeader, TTitleMode, THeaderLayout } from './types'; @@ -39,7 +39,7 @@ export const Header = (props: THeader) => { const bg = useColorValue('white', 'black'); const { web } = useConfig(); - const { isSubmitting } = useGlobalState(); + const { isSubmitting } = useLGState(); const mlResetButton = useBooleanValue(isSubmitting.value, { base: 0, md: 2 }, undefined); const titleHeight = useBooleanValue(isSubmitting.value, undefined, { md: '20vh' }); diff --git a/hyperglass/ui/components/layout/frame.tsx b/hyperglass/ui/components/layout/frame.tsx index cda345b..8252d5a 100644 --- a/hyperglass/ui/components/layout/frame.tsx +++ b/hyperglass/ui/components/layout/frame.tsx @@ -1,33 +1,31 @@ import { useRef } from 'react'; import { Flex } from '@chakra-ui/react'; -import { useConfig, useColorValue, useGlobalState } from '~/context'; +import { useConfig, useColorValue } from '~/context'; import { If, Debugger, Greeting, Footer, Header } from '~/components'; -import { useGreeting } from '~/hooks'; +import { useLGState } from '~/hooks'; import type { TFrame } from './types'; export const Frame = (props: TFrame) => { - const { web, developer_mode } = useConfig(); - const { isSubmitting, formData } = useGlobalState(); - const [greetingAck, setGreetingAck] = useGreeting(); + const { developer_mode } = useConfig(); + const { isSubmitting, resetForm } = useLGState(); const bg = useColorValue('white', 'black'); const color = useColorValue('black', 'white'); const containerRef = useRef({} as HTMLDivElement); - function resetForm(): void { + function handleReset(): void { containerRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' }); isSubmitting.set(false); - formData.set({ query_location: [], query_target: '', query_type: '', query_vrf: '' }); - return; + resetForm(); } return ( <> -
+
{ - - - + ); }; diff --git a/hyperglass/ui/components/layout/layout.tsx b/hyperglass/ui/components/layout/layout.tsx index 7e7e0c3..b0d41b4 100644 --- a/hyperglass/ui/components/layout/layout.tsx +++ b/hyperglass/ui/components/layout/layout.tsx @@ -1,13 +1,11 @@ import { AnimatePresence } from 'framer-motion'; import { If, HyperglassForm, Results } from '~/components'; -import { useGlobalState } from '~/context'; import { useLGState } from '~/hooks'; import { all } from '~/util'; import { Frame } from './frame'; export const Layout: React.FC = () => { - const { isSubmitting } = useGlobalState(); - const { formData } = useLGState(); + const { isSubmitting, formData } = useLGState(); return ( { const { web, content, messages, queries } = useConfig(); - const { isSubmitting } = useGlobalState(); const [greetingAck, setGreetingAck] = useGreeting(); const getDevice = useDevice(); @@ -42,23 +42,24 @@ export const HyperglassForm = () => { query_target: yup.string().required(noQueryTarget), }); - const { handleSubmit, register, unregister, setValue, errors, reset } = useForm({ - validationSchema: formSchema, + const formInstance = useForm({ + resolver: yupResolver(formSchema), defaultValues: { query_vrf: 'default', query_target: '', query_location: [], query_type: '' }, }); + const { handleSubmit, register, unregister, setValue, errors } = formInstance; const { queryVrf, families, + formData, queryType, availVrfs, fqdnTarget, btnLoading, queryTarget, + isSubmitting, resolvedOpen, queryLocation, - displayTarget, - formData, } = useLGState(); function submitHandler(values: TFormData) { @@ -150,96 +151,81 @@ export const HyperglassForm = () => { const isFqdnQuery = useMemo(() => { return ['bgp_route', 'ping', 'traceroute'].includes(queryType.value); - }, [queryType]); - - const fqdnQuery = useMemo(() => { - let result = null; - if (fqdnTarget && queryVrf.value === 'default' && fqdnTarget) { - result = fqdnTarget; - } - return result; - }, [queryVrf, queryType]); + }, [queryType.value]); useEffect(() => { register({ name: 'query_location', required: true }); register({ name: 'query_type', required: true }); register({ name: 'query_vrf' }); + register({ name: 'query_target', required: true }); }, [register]); - Object.keys(errors).length >= 1 && console.error(errors); - return ( - - - - - - }> - - - - - 1}> - - + + + + + - - - - + }> + + + + + 1}> + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + ); }; diff --git a/hyperglass/ui/components/results/group.tsx b/hyperglass/ui/components/results/group.tsx index 15b5a4e..c68294f 100644 --- a/hyperglass/ui/components/results/group.tsx +++ b/hyperglass/ui/components/results/group.tsx @@ -147,23 +147,16 @@ export const Results = () => { queryLocation.map((loc, i) => { const device = getDevice(loc.value); return ( - - - + ); })} diff --git a/hyperglass/ui/components/results/individual.tsx b/hyperglass/ui/components/results/individual.tsx index b5c2ec0..326c092 100644 --- a/hyperglass/ui/components/results/individual.tsx +++ b/hyperglass/ui/components/results/individual.tsx @@ -9,6 +9,7 @@ import { AccordionPanel, AccordionButton, } from '@chakra-ui/react'; +import { motion } from 'framer-motion'; import { BsLightningFill } from '@meronex/icons/bs'; import { startCase } from 'lodash'; import { BGPTable, Countdown, CopyButton, RequeryButton, TextOutput, If } from '~/components'; @@ -21,6 +22,8 @@ import { isStackError, isFetchError, isLGError } from './guards'; import type { TAccordionHeaderWrapper, TResult, TErrorLevels } from './types'; +const AnimatedAccordionItem = motion.custom(AccordionItem); + const AccordionHeaderWrapper = (props: TAccordionHeaderWrapper) => { const { hoverBg, ...rest } = props; return ( @@ -143,9 +146,13 @@ export const Result = forwardRef((props, ref) => { }, [resultsComplete, index]); return ( - ((props, ref) => { - + ); }); diff --git a/hyperglass/ui/components/select/select.tsx b/hyperglass/ui/components/select/select.tsx index 635beb1..915a444 100644 --- a/hyperglass/ui/components/select/select.tsx +++ b/hyperglass/ui/components/select/select.tsx @@ -26,12 +26,16 @@ export const useSelectContext = () => useContext(SelectContext); const ReactSelectAsBox = (props: TBoxAsReactSelect) => ; export const Select = (props: TSelectBase) => { - const { ctl, options, multi, onSelect, ...rest } = props; + const { ctl, options, multi, onSelect, isError = false, ...rest } = props; const { isOpen, onOpen, onClose } = useDisclosure(); const { colorMode } = useColorMode(); - const selectContext = useMemo(() => ({ colorMode, isOpen }), [colorMode, isOpen]); + const selectContext = useMemo(() => ({ colorMode, isOpen, isError }), [ + colorMode, + isError, + isOpen, + ]); const handleChange = (changed: TSelectOption | TSelectOption[]) => { if (!Array.isArray(changed)) { diff --git a/hyperglass/ui/components/select/styles.tsx b/hyperglass/ui/components/select/styles.tsx index efcf5d8..2ce0c59 100644 --- a/hyperglass/ui/components/select/styles.tsx +++ b/hyperglass/ui/components/select/styles.tsx @@ -20,7 +20,7 @@ import type { export const useControlStyle = (base: TStyles, state: TControl): TStyles => { const { isFocused } = state; - const { colorMode } = useSelectContext(); + const { colorMode, isError } = useSelectContext(); const borderHover = useColorValue( useToken('colors', 'gray.300'), useToken('colors', 'whiteAlpha.400'), @@ -41,14 +41,18 @@ export const useControlStyle = (base: TStyles, state: TControl): TStyles => { color, minHeight, transition: 'all 0.2s', - borderColor: isFocused ? focusBorder : borderColor, - boxShadow: isFocused ? `0 0 0 1px ${focusBorder}` : undefined, + borderColor: isError ? invalidBorder : isFocused ? focusBorder : borderColor, + boxShadow: isError + ? `0 0 0 1px ${invalidBorder}` + : isFocused + ? `0 0 0 1px ${focusBorder}` + : undefined, '&:hover': { borderColor: isFocused ? focusBorder : borderHover }, '&:hover > div > span': { backgroundColor: borderHover }, - '&:focus': { borderColor: focusBorder }, + '&:focus': { borderColor: isError ? invalidBorder : focusBorder }, '&.invalid': { borderColor: invalidBorder, boxShadow: `0 0 0 1px ${invalidBorder}` }, }; - return useMemo(() => mergeWith({}, base, styles), [colorMode, isFocused]); + return useMemo(() => mergeWith({}, base, styles), [colorMode, isFocused, isError]); }; export const useMenuStyle = (base: TStyles, state: TMenu): TStyles => { diff --git a/hyperglass/ui/components/select/types.ts b/hyperglass/ui/components/select/types.ts index 237d8d7..dbacc93 100644 --- a/hyperglass/ui/components/select/types.ts +++ b/hyperglass/ui/components/select/types.ts @@ -24,6 +24,7 @@ export type TBoxAsReactSelect = Omit void; @@ -34,6 +35,7 @@ export interface TSelectBase extends TBoxAsReactSelect { export interface TSelectContext { colorMode: 'light' | 'dark'; isOpen: boolean; + isError: boolean; } export interface TMultiValueRemoveProps { diff --git a/hyperglass/ui/components/title/title.tsx b/hyperglass/ui/components/title/title.tsx index b7684d1..3a793b3 100644 --- a/hyperglass/ui/components/title/title.tsx +++ b/hyperglass/ui/components/title/title.tsx @@ -1,8 +1,8 @@ import { forwardRef } from 'react'; import { Button, Stack } from '@chakra-ui/react'; import { If } from '~/components'; -import { useConfig, useGlobalState } from '~/context'; -import { useBooleanValue } from '~/hooks'; +import { useConfig } from '~/context'; +import { useBooleanValue, useLGState } from '~/hooks'; import { TitleOnly } from './titleOnly'; import { SubtitleOnly } from './subtitleOnly'; import { Logo } from './logo'; @@ -47,7 +47,7 @@ export const Title = forwardRef((props, ref) => { const { web } = useConfig(); const titleMode = web.text.title_mode; - const { isSubmitting } = useGlobalState(); + const { isSubmitting } = useLGState(); const justify = useBooleanValue( isSubmitting.value, diff --git a/hyperglass/ui/hooks/useGreeting.ts b/hyperglass/ui/hooks/useGreeting.ts index bd86928..20be64a 100644 --- a/hyperglass/ui/hooks/useGreeting.ts +++ b/hyperglass/ui/hooks/useGreeting.ts @@ -1,10 +1,12 @@ -import { useState } from '@hookstate/core'; +import { createState, useState } from '@hookstate/core'; import { Persistence } from '@hookstate/persistence'; import type { TUseGreetingReturn } from './types'; +const greeting = createState(false); + export function useGreeting(): TUseGreetingReturn { - const state = useState(false); + const state = useState(greeting); if (typeof window !== 'undefined') { state.attach(Persistence('hyperglass-greeting')); } @@ -13,7 +15,6 @@ export function useGreeting(): TUseGreetingReturn { if (!state.get()) { state.set(v); } - return; } return [state.value, setAck]; diff --git a/hyperglass/ui/hooks/useLGState.ts b/hyperglass/ui/hooks/useLGState.ts index 2f39f81..2d65414 100644 --- a/hyperglass/ui/hooks/useLGState.ts +++ b/hyperglass/ui/hooks/useLGState.ts @@ -4,6 +4,7 @@ import type { State } from '@hookstate/core'; import type { Families, TDeviceVrf, TQueryTypes, TFormData } from '~/types'; type TLGState = { + isSubmitting: boolean; queryVrf: string; families: Families; queryTarget: string; @@ -20,9 +21,11 @@ type TLGState = { type TLGStateHandlers = { resolvedOpen(): void; resolvedClose(): void; + resetForm(): void; }; const LGState = createState({ + isSubmitting: false, resolvedIsOpen: false, displayTarget: '', queryLocation: [], @@ -44,6 +47,20 @@ export function useLGState(): State & TLGStateHandlers { function resolvedClose() { state.resolvedIsOpen.set(false); } + function resetForm() { + state.merge({ + queryVrf: '', + families: [], + queryType: '', + queryTarget: '', + fqdnTarget: null, + queryLocation: [], + displayTarget: '', + resolvedIsOpen: false, + btnLoading: false, + formData: { query_location: [], query_target: '', query_type: '', query_vrf: '' }, + }); + } - return { resolvedOpen, resolvedClose, ...state }; + return { resetForm, resolvedOpen, resolvedClose, ...state }; } diff --git a/hyperglass/ui/package.json b/hyperglass/ui/package.json index 8f31376..623e42f 100644 --- a/hyperglass/ui/package.json +++ b/hyperglass/ui/package.json @@ -19,6 +19,7 @@ "@chakra-ui/react": "^1.0.3", "@emotion/react": "^11.1.1", "@emotion/styled": "^11.0.0", + "@hookform/resolvers": "^1.2.0", "@hookstate/core": "^3.0.1", "@hookstate/persistence": "^3.0.0", "@meronex/icons": "^4.0.0", @@ -34,7 +35,7 @@ "react-countdown": "^2.2.1", "react-dom": "^17.0.1", "react-fast-compare": "^3.2.0", - "react-hook-form": "^5.7", + "react-hook-form": "^6.13.1", "react-markdown": "^4.3.1", "react-query": "^2.26.4", "react-select": "^3.1.1", diff --git a/hyperglass/ui/yarn.lock b/hyperglass/ui/yarn.lock index a2aa489..24b202e 100644 --- a/hyperglass/ui/yarn.lock +++ b/hyperglass/ui/yarn.lock @@ -906,6 +906,11 @@ resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.1.0.tgz#6c9eafc78c1529248f8f4d92b0799a712b6052c6" integrity sha512-i9YbZPN3QgfighY/1X1Pu118VUz2Fmmhd6b2n0/O8YVgGGfw0FbUYoA97k7FkpGJ+pLCFEDLUmAPPV4D1kpeFw== +"@hookform/resolvers@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-1.2.0.tgz#3a429b4bd3ec9981764fcdcc2491202f9f72d847" + integrity sha512-YCKEj/3Kdo3uNt+zrWKV8txaiuATtvgHyz+KYmun3n5JDjxdI0HcVQgfcmJabmkBXBzKuIIrYfxaV8sRuAPZ8w== + "@hookstate/core@^3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@hookstate/core/-/core-3.0.1.tgz#dc46ea71e3bf0ab5c2dc024029c9210ed12fbb84" @@ -5487,10 +5492,10 @@ react-focus-lock@2.4.1: use-callback-ref "^1.2.1" use-sidecar "^1.0.1" -react-hook-form@^5.7: - version "5.7.2" - resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-5.7.2.tgz#a84e259e5d37dd30949af4f79c4dac31101b79ac" - integrity sha512-bJvY348vayIvEUmSK7Fvea/NgqbT2racA2IbnJz/aPlQ3GBtaTeDITH6rtCa6y++obZzG6E3Q8VuoXPir7QYUg== +react-hook-form@^6.13.1: + version "6.13.1" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-6.13.1.tgz#b9c0aa61f746db8169ed5e1050de21cacb1947d6" + integrity sha512-Q0N7MYcbA8SigYufb02h9z97ZKCpIbe62rywOTPsK4Ntvh6fRTGDXSuzWuRhLHhArLoWbGrWYSNSS4tlb+OFXg== react-input-autosize@^2.2.2: version "2.2.2"