mirror of
https://github.com/checktheroads/hyperglass
synced 2024-05-11 05:55:08 +00:00
improve DNS resolution UX [skip ci]
This commit is contained in:
@@ -9,11 +9,13 @@ description: Customize the text used in the web UI
|
||||
## `text`
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
| :--------------- | :----: | :------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| :--------------- | :----: | :-------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `cache_prefix` | String | `'Results cached for '` | Text displayed with the cache timeout countdown. |
|
||||
| `cache_icon` | String | `'Cached Response from {time}'` | Text displayed when a user hovers over the lightning bolt icon, which is displayed when a response from the server was a cached response. `{time}` is replaced with the _original_ query's timestamp. |
|
||||
| `completed_time` | String | `'Completed in {seconds}'` | Text displayed when a user hovers over the success icon for a query result. `{seconds}` will be replaced with 'n seconds' where n is the time a query took to complete. |
|
||||
| `fqdn_tooltip` | String | `'Use {protocol}'` | Text displayed when a user hovers over the IPv4 or IPv6 button on an FQDN target resolved by DNS. `{protocol}` is replaced with the relevant IP protocol. |
|
||||
| `fqdn_message` | String | `'Your browser has resolved {fqdn} to'` | Text displayed when prompting a user to select a resolve IPv4 or IPv6 address for an FQDN query. |
|
||||
| `fqdn_error` | String | `'Unable to resolve {fqdn}'` | Text displayed when an FQDN is not resolvable. |
|
||||
| `fqdn_button` | String | `'Try Again'` | Button text used when an FQDN is not resolvable. |
|
||||
| `query_location` | String | `'Location'` | Query Location (router) form label. |
|
||||
| `query_target` | String | `'Target'` | Query Target (IP/hostname/community/AS Path) form label. |
|
||||
| `query_type` | String | `'Query Type'` | Query Type (BGP Route, Ping, Traceroute, etc.) form label. |
|
||||
|
||||
@@ -127,6 +127,8 @@ class Text(HyperglassModel):
|
||||
query_vrf: StrictStr = "Routing Table"
|
||||
fqdn_tooltip: StrictStr = "Use {protocol}" # Formatted by Javascript
|
||||
fqdn_message: StrictStr = "Your browser has resolved {fqdn} to" # Formatted by Javascript
|
||||
fqdn_error: StrictStr = "Unable to resolve {fqdn}" # Formatted by Javascript
|
||||
fqdn_error_button: StrictStr = "Try Again"
|
||||
cache_prefix: StrictStr = "Results cached for "
|
||||
cache_icon: StrictStr = "Cached from {time} UTC" # Formatted by Javascript
|
||||
complete_time: StrictStr = "Completed in {seconds}" # Formatted by Javascript
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { Button, Stack, Text, VStack } from '@chakra-ui/react';
|
||||
import { FiArrowRightCircle as RightArrow } from '@meronex/icons/fi';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { Button, chakra, Icon, Stack, Text, VStack } from '@chakra-ui/react';
|
||||
import { useConfig, useColorValue } from '~/context';
|
||||
import { useStrf, useLGState, useDNSQuery } from '~/hooks';
|
||||
|
||||
const RightArrow = chakra(
|
||||
dynamic<MeronexIcon>(() => import('@meronex/icons/fa').then(i => i.FaArrowCircleRight)),
|
||||
);
|
||||
|
||||
const LeftArrow = chakra(
|
||||
dynamic<MeronexIcon>(() => import('@meronex/icons/fa').then(i => i.FaArrowCircleLeft)),
|
||||
);
|
||||
|
||||
import type { DnsOverHttps } from '~/types';
|
||||
import type { TResolvedTarget } from './types';
|
||||
|
||||
@@ -17,31 +25,38 @@ function findAnswer(data: DnsOverHttps.Response | undefined): string {
|
||||
}
|
||||
|
||||
export const ResolvedTarget = (props: TResolvedTarget) => {
|
||||
const { setTarget } = props;
|
||||
const { setTarget, errorClose } = props;
|
||||
const { web } = useConfig();
|
||||
const { displayTarget, isSubmitting, families, queryTarget } = useLGState();
|
||||
|
||||
const color = useColorValue('secondary.500', 'secondary.300');
|
||||
const errorColor = useColorValue('red.500', 'red.300');
|
||||
|
||||
const query4 = Array.from(families.value).includes(4);
|
||||
const query6 = Array.from(families.value).includes(6);
|
||||
|
||||
const tooltip4 = useStrf(web.text.fqdn_tooltip, { protocol: 'IPv4' });
|
||||
const tooltip6 = useStrf(web.text.fqdn_tooltip, { protocol: 'IPv6' });
|
||||
const [messageStart, messageEnd] = useMemo(() => web.text.fqdn_message.split('{fqdn}'), [
|
||||
web.text.fqdn_message,
|
||||
]);
|
||||
|
||||
const { data: data4, isLoading: isLoading4, isError: isError4 } = useDNSQuery(
|
||||
const [messageStart, messageEnd] = web.text.fqdn_message.split('{fqdn}');
|
||||
const [errorStart, errorEnd] = web.text.fqdn_error.split('{fqdn}');
|
||||
|
||||
const { data: data4, isLoading: isLoading4, isError: isError4, error: error4 } = useDNSQuery(
|
||||
displayTarget.value,
|
||||
4,
|
||||
);
|
||||
|
||||
const { data: data6, isLoading: isLoading6, isError: isError6 } = useDNSQuery(
|
||||
const { data: data6, isLoading: isLoading6, isError: isError6, error: error6 } = useDNSQuery(
|
||||
displayTarget.value,
|
||||
6,
|
||||
);
|
||||
|
||||
isError4 && console.error(error4);
|
||||
isError6 && console.error(error6);
|
||||
|
||||
const answer4 = useMemo(() => findAnswer(data4), [data4]);
|
||||
const answer6 = useMemo(() => findAnswer(data6), [data6]);
|
||||
|
||||
function handleOverride(value: string): void {
|
||||
setTarget({ field: 'query_target', value });
|
||||
}
|
||||
@@ -62,6 +77,7 @@ export const ResolvedTarget = (props: TResolvedTarget) => {
|
||||
|
||||
return (
|
||||
<VStack w="100%" spacing={4} justify="center">
|
||||
{(answer4 || answer6) && (
|
||||
<Text fontSize="sm" textAlign="center">
|
||||
{messageStart}
|
||||
<Text as="span" fontSize="sm" fontWeight="bold" color={color}>
|
||||
@@ -69,33 +85,52 @@ export const ResolvedTarget = (props: TResolvedTarget) => {
|
||||
</Text>
|
||||
{messageEnd}
|
||||
</Text>
|
||||
)}
|
||||
<Stack spacing={2}>
|
||||
{!isLoading4 && !isError4 && query4 && findAnswer(data4) && (
|
||||
{!isLoading4 && !isError4 && query4 && answer4 && (
|
||||
<Button
|
||||
size="sm"
|
||||
fontSize="xs"
|
||||
colorScheme="primary"
|
||||
justifyContent="space-between"
|
||||
rightIcon={<RightArrow size="18px" />}
|
||||
title={tooltip4}
|
||||
fontFamily="mono"
|
||||
onClick={() => selectTarget(findAnswer(data4))}>
|
||||
{findAnswer(data4)}
|
||||
colorScheme="primary"
|
||||
justifyContent="space-between"
|
||||
onClick={() => selectTarget(answer4)}
|
||||
rightIcon={<RightArrow boxSize="18px" />}>
|
||||
{answer4}
|
||||
</Button>
|
||||
)}
|
||||
{!isLoading6 && !isError6 && query6 && findAnswer(data6) && (
|
||||
{!isLoading6 && !isError6 && query6 && answer6 && (
|
||||
<Button
|
||||
size="sm"
|
||||
fontSize="xs"
|
||||
colorScheme="secondary"
|
||||
justifyContent="space-between"
|
||||
rightIcon={<RightArrow size="18px" />}
|
||||
title={tooltip6}
|
||||
fontFamily="mono"
|
||||
onClick={() => selectTarget(findAnswer(data6))}>
|
||||
{findAnswer(data6)}
|
||||
colorScheme="secondary"
|
||||
justifyContent="space-between"
|
||||
onClick={() => selectTarget(answer6)}
|
||||
rightIcon={<RightArrow boxSize="18px" />}>
|
||||
{answer6}
|
||||
</Button>
|
||||
)}
|
||||
{!answer4 && !answer6 && (
|
||||
<>
|
||||
<Text fontSize="sm" textAlign="center" color={errorColor}>
|
||||
{errorStart}
|
||||
<Text as="span" fontSize="sm" fontWeight="bold">
|
||||
{`${displayTarget.value}`.toLowerCase()}
|
||||
</Text>
|
||||
{errorEnd}
|
||||
</Text>
|
||||
<Button
|
||||
colorScheme="red"
|
||||
variant="outline"
|
||||
onClick={errorClose}
|
||||
leftIcon={<LeftArrow />}>
|
||||
{web.text.fqdn_error_button}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</VStack>
|
||||
);
|
||||
|
||||
@@ -40,4 +40,5 @@ export interface TQueryTarget {
|
||||
|
||||
export interface TResolvedTarget {
|
||||
setTarget(e: OnChangeArgs): void;
|
||||
errorClose(): void;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ const MSubmitButton = (props: TRSubmitButton) => {
|
||||
<ModalContent bg={bg}>
|
||||
<ModalCloseButton />
|
||||
<ModalBody px={4} py={10}>
|
||||
{isOpen && <ResolvedTarget setTarget={onChange} />}
|
||||
{isOpen && <ResolvedTarget setTarget={onChange} errorClose={onClose} />}
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
@@ -83,7 +83,9 @@ const DSubmitButton = (props: TRSubmitButton) => {
|
||||
<PopoverContent bg={bg}>
|
||||
<PopoverArrow bg={bg} />
|
||||
<PopoverCloseButton />
|
||||
<PopoverBody p={6}>{isOpen && <ResolvedTarget setTarget={onChange} />}</PopoverBody>
|
||||
<PopoverBody p={6}>
|
||||
{isOpen && <ResolvedTarget setTarget={onChange} errorClose={onClose} />}
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
|
||||
@@ -36,6 +36,8 @@ export interface IConfigWebText {
|
||||
query_vrf: string;
|
||||
fqdn_tooltip: string;
|
||||
fqdn_message: string;
|
||||
fqdn_error: string;
|
||||
fqdn_error_button: string;
|
||||
cache_prefix: string;
|
||||
cache_icon: string;
|
||||
complete_time: string;
|
||||
|
||||
Reference in New Issue
Block a user