mirror of
https://github.com/checktheroads/hyperglass
synced 2024-05-11 05:55:08 +00:00
continue typescript & chakra v1 migrations [skip ci]
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { Flex, Icon, Text } from '@chakra-ui/react';
|
||||
import { usePagination, useSortBy, useTable } from 'react-table';
|
||||
@@ -68,18 +69,18 @@ export function Table(props: TTable) {
|
||||
const instance = useTable<TRoute>(options, ...plugins);
|
||||
|
||||
const {
|
||||
getTableProps,
|
||||
headerGroups,
|
||||
prepareRow,
|
||||
page,
|
||||
canPreviousPage,
|
||||
canNextPage,
|
||||
pageOptions,
|
||||
pageCount,
|
||||
gotoPage,
|
||||
nextPage,
|
||||
previousPage,
|
||||
pageCount,
|
||||
prepareRow,
|
||||
canNextPage,
|
||||
pageOptions,
|
||||
setPageSize,
|
||||
headerGroups,
|
||||
previousPage,
|
||||
getTableProps,
|
||||
canPreviousPage,
|
||||
state: { pageIndex, pageSize },
|
||||
} = instance;
|
||||
|
||||
@@ -116,7 +117,6 @@ export function Table(props: TTable) {
|
||||
<TableBody>
|
||||
{page.map((row, key) => {
|
||||
prepareRow(row);
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
index={key}
|
||||
@@ -131,7 +131,8 @@ export function Table(props: TTable) {
|
||||
align={cell.column.align}
|
||||
bordersVertical={[bordersVertical, i]}
|
||||
{...cell.getCellProps()}>
|
||||
{cellRender ?? cell.render('Cell')}
|
||||
{/* {cellRender ?? cell.render('Cell')} */}
|
||||
{React.createElement(cellRender, cell)}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -5,6 +5,10 @@ import type { TCell } from './types';
|
||||
export const Cell = (props: TCell) => {
|
||||
const { data, rawData } = props;
|
||||
const cellId = data.column.id as keyof TRoute;
|
||||
console.group(cellId);
|
||||
console.dir(data);
|
||||
console.dir(rawData);
|
||||
console.groupEnd();
|
||||
const component = {
|
||||
med: <MonoField v={data.value} />,
|
||||
age: <Age inSeconds={data.value} />,
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import dynamic from 'next/dynamic';
|
||||
import {
|
||||
Icon,
|
||||
Text,
|
||||
Popover,
|
||||
Tooltip,
|
||||
PopoverArrow,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@chakra-ui/react';
|
||||
import { MdLastPage } from '@meronex/icons/md';
|
||||
import { Icon, Text, Box, Tooltip, Menu, MenuButton, MenuList } from '@chakra-ui/react';
|
||||
import { CgMoreO as More } from '@meronex/icons/cg';
|
||||
import { BisError as Warning } from '@meronex/icons/bi';
|
||||
import { MdNotInterested as NotAllowed, MdLastPage } from '@meronex/icons/md';
|
||||
import { BsQuestionCircleFill as Question } from '@meronex/icons/bs';
|
||||
import { FaCheckCircle as Check, FaChevronRight as ChevronRight } from '@meronex/icons/fa';
|
||||
import dayjs from 'dayjs';
|
||||
import relativeTimePlugin from 'dayjs/plugin/relativeTime';
|
||||
import utcPlugin from 'dayjs/plugin/utc';
|
||||
@@ -28,19 +23,6 @@ import type {
|
||||
dayjs.extend(relativeTimePlugin);
|
||||
dayjs.extend(utcPlugin);
|
||||
|
||||
const Check = dynamic<MeronexIcon>(() => import('@meronex/icons/fa').then(i => i.FaCheckCircle));
|
||||
const More = dynamic<MeronexIcon>(() => import('@meronex/icons/cg').then(i => i.CgMoreO));
|
||||
const NotAllowed = dynamic<MeronexIcon>(() =>
|
||||
import('@meronex/icons/md').then(i => i.MdNotInterested),
|
||||
);
|
||||
const Question = dynamic<MeronexIcon>(() =>
|
||||
import('@meronex/icons/bs').then(i => i.BsQuestionCircleFill),
|
||||
);
|
||||
const Warning = dynamic<MeronexIcon>(() => import('@meronex/icons/bi').then(i => i.BisError));
|
||||
const ChevronRight = dynamic<MeronexIcon>(() =>
|
||||
import('@meronex/icons/fa').then(i => i.FaChevronRight),
|
||||
);
|
||||
|
||||
export const MonoField = (props: TMonoField) => {
|
||||
const { v, ...rest } = props;
|
||||
return (
|
||||
@@ -128,22 +110,21 @@ export const Communities = (props: TCommunities) => {
|
||||
</Tooltip>
|
||||
</If>
|
||||
<If c={communities.length !== 0}>
|
||||
<Popover trigger="hover" placement="right">
|
||||
<PopoverTrigger>
|
||||
<Menu>
|
||||
<MenuButton>
|
||||
<Icon as={More} />
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
p={4}
|
||||
</MenuButton>
|
||||
<MenuList
|
||||
p={3}
|
||||
width="unset"
|
||||
color={color}
|
||||
textAlign="left"
|
||||
fontFamily="mono"
|
||||
fontWeight="normal"
|
||||
whiteSpace="pre-wrap">
|
||||
<PopoverArrow />
|
||||
{communities.join('\n')}
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</If>
|
||||
</>
|
||||
);
|
||||
@@ -173,7 +154,7 @@ export const RPKIState = (props: TRPKIState) => {
|
||||
|
||||
return (
|
||||
<Tooltip hasArrow placement="right" label={text[state] ?? text[3]}>
|
||||
<Icon icon={icon[state]} color={color[+active][state]} />
|
||||
<Box as={icon[state]} color={color[+active][state]} />
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
11
hyperglass/ui/components/results/guards.ts
Normal file
11
hyperglass/ui/components/results/guards.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export function isStackError(error: any): error is Error {
|
||||
return error !== null && 'message' in error;
|
||||
}
|
||||
|
||||
export function isFetchError(error: any): error is Response {
|
||||
return error !== null && 'statusText' in error;
|
||||
}
|
||||
|
||||
export function isLGError(error: any): error is TQueryResponse {
|
||||
return error !== null && 'output' in error;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { forwardRef, useMemo } from 'react';
|
||||
import { AccordionIcon, Box, Spinner, Stack, Text, Tooltip } from '@chakra-ui/react';
|
||||
import { useMemo } from 'react';
|
||||
import { AccordionIcon, Box, Spinner, HStack, Text, Tooltip } from '@chakra-ui/react';
|
||||
import { BisError as Warning } from '@meronex/icons/bi';
|
||||
import { FaCheckCircle as Check } from '@meronex/icons/fa';
|
||||
import { useConfig, useColorValue } from '~/context';
|
||||
@@ -15,8 +15,8 @@ const runtimeText = (runtime: number, text: string): string => {
|
||||
return `${text} ${unit}`;
|
||||
};
|
||||
|
||||
export const ResultHeader = forwardRef<HTMLDivElement, TResultHeader>((props, ref) => {
|
||||
const { title, loading, error, errorMsg, errorLevel, runtime } = props;
|
||||
export const ResultHeader = (props: TResultHeader) => {
|
||||
const { title, loading, isError, errorMsg, errorLevel, runtime } = props;
|
||||
|
||||
const status = useColorValue('primary.500', 'primary.300');
|
||||
const warning = useColorValue(`${errorLevel}.500`, `${errorLevel}.300`);
|
||||
@@ -27,20 +27,27 @@ export const ResultHeader = forwardRef<HTMLDivElement, TResultHeader>((props, re
|
||||
const label = useMemo(() => runtimeText(runtime, text), [runtime]);
|
||||
|
||||
return (
|
||||
<Stack ref={ref} isInline alignItems="center" w="100%">
|
||||
<HStack alignItems="center" w="100%">
|
||||
<Tooltip
|
||||
hasArrow
|
||||
placement="top"
|
||||
isDisabled={loading}
|
||||
label={isError ? errorMsg : label}
|
||||
colorScheme={isError ? errorLevel : 'success'}>
|
||||
{loading ? (
|
||||
<Spinner size="sm" mr={4} color={status} />
|
||||
) : error ? (
|
||||
<Tooltip hasArrow label={errorMsg} placement="top">
|
||||
<Box as={Warning} color={warning} mr={4} boxSize={6} />
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip hasArrow label={label} placement="top">
|
||||
<Box as={Check} color={defaultStatus} mr={4} boxSize={6} />
|
||||
</Tooltip>
|
||||
<Box
|
||||
as={isError ? Warning : Check}
|
||||
color={isError ? warning : defaultStatus}
|
||||
mr={4}
|
||||
boxSize={6}
|
||||
/>
|
||||
)}
|
||||
</Tooltip>
|
||||
|
||||
<Text fontSize="lg">{title}</Text>
|
||||
<AccordionIcon ml="auto" />
|
||||
</Stack>
|
||||
</HStack>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -10,17 +10,16 @@ import {
|
||||
AccordionButton,
|
||||
} from '@chakra-ui/react';
|
||||
import { BsLightningFill } from '@meronex/icons/bs';
|
||||
import useAxios from 'axios-hooks';
|
||||
import { startCase } from 'lodash';
|
||||
import { BGPTable, Countdown, CopyButton, RequeryButton, TextOutput, If } from '~/components';
|
||||
import { useColorValue, useConfig, useMobile } from '~/context';
|
||||
import { useStrf, useTableToString } from '~/hooks';
|
||||
import { useStrf, useLGQuery, useTableToString } from '~/hooks';
|
||||
import { isStructuredOutput, isStringOutput } from '~/types';
|
||||
import { FormattedError } from './error';
|
||||
import { ResultHeader } from './header';
|
||||
import { isStackError, isFetchError, isLGError } from './guards';
|
||||
|
||||
import type { TAccordionHeaderWrapper, TResult } from './types';
|
||||
|
||||
type TErrorLevels = 'success' | 'warning' | 'error';
|
||||
import type { TAccordionHeaderWrapper, TResult, TErrorLevels } from './types';
|
||||
|
||||
const AccordionHeaderWrapper = (props: TAccordionHeaderWrapper) => {
|
||||
const { hoverBg, ...rest } = props;
|
||||
@@ -38,7 +37,6 @@ export const Result = forwardRef<HTMLDivElement, TResult>((props, ref) => {
|
||||
const {
|
||||
index,
|
||||
device,
|
||||
timeout,
|
||||
queryVrf,
|
||||
queryType,
|
||||
queryTarget,
|
||||
@@ -54,20 +52,12 @@ export const Result = forwardRef<HTMLDivElement, TResult>((props, ref) => {
|
||||
const scrollbarHover = useColorValue('blackAlpha.400', 'whiteAlpha.400');
|
||||
const scrollbarBg = useColorValue('blackAlpha.50', 'whiteAlpha.50');
|
||||
|
||||
let [{ data, loading, error }, refetch] = useAxios(
|
||||
{
|
||||
url: '/api/query/',
|
||||
method: 'post',
|
||||
data: {
|
||||
query_vrf: queryVrf,
|
||||
query_type: queryType,
|
||||
query_target: queryTarget,
|
||||
query_location: queryLocation,
|
||||
},
|
||||
timeout,
|
||||
},
|
||||
{ useCache: false },
|
||||
);
|
||||
const { data, error, isError, isLoading, refetch } = useLGQuery({
|
||||
queryLocation,
|
||||
queryTarget,
|
||||
queryType,
|
||||
queryVrf,
|
||||
});
|
||||
|
||||
const cacheLabel = useStrf(web.text.cache_icon, { time: data?.timestamp }, [data?.timestamp]);
|
||||
|
||||
@@ -79,16 +69,23 @@ export const Result = forwardRef<HTMLDivElement, TResult>((props, ref) => {
|
||||
setOverride(true);
|
||||
};
|
||||
|
||||
const errorKw = (error && error.response?.data?.keywords) || [];
|
||||
const errorKeywords = useMemo(() => {
|
||||
let kw = [] as string[];
|
||||
if (isLGError(error)) {
|
||||
kw = error.keywords;
|
||||
}
|
||||
return kw;
|
||||
}, [isError]);
|
||||
|
||||
let errorMsg;
|
||||
if (error && error.response?.data?.output) {
|
||||
errorMsg = error.response.data.output;
|
||||
} else if (error && error.message.startsWith('timeout')) {
|
||||
|
||||
if (isLGError(error)) {
|
||||
errorMsg = error.output as string;
|
||||
} else if (isFetchError(error)) {
|
||||
errorMsg = startCase(error.statusText);
|
||||
} else if (isStackError(error) && error.message.toLowerCase().startsWith('timeout')) {
|
||||
errorMsg = messages.request_timeout;
|
||||
} else if (error?.response?.statusText) {
|
||||
errorMsg = startCase(error.response.statusText);
|
||||
} else if (error && error.message) {
|
||||
} else if (isStackError(error)) {
|
||||
errorMsg = startCase(error.message);
|
||||
} else {
|
||||
errorMsg = messages.general;
|
||||
@@ -96,7 +93,7 @@ export const Result = forwardRef<HTMLDivElement, TResult>((props, ref) => {
|
||||
|
||||
error && console.error(error);
|
||||
|
||||
const getErrorLevel = (): TErrorLevels => {
|
||||
const errorLevel = useMemo<TErrorLevels>(() => {
|
||||
const statusMap = {
|
||||
success: 'success',
|
||||
warning: 'warning',
|
||||
@@ -106,18 +103,22 @@ export const Result = forwardRef<HTMLDivElement, TResult>((props, ref) => {
|
||||
|
||||
let e: TErrorLevels = 'error';
|
||||
|
||||
if (error?.response?.data?.level) {
|
||||
const idx = error.response.data.level as TResponseLevel;
|
||||
if (isLGError(error)) {
|
||||
const idx = error.level as TResponseLevel;
|
||||
e = statusMap[idx];
|
||||
}
|
||||
return e;
|
||||
};
|
||||
}, [error]);
|
||||
|
||||
const errorLevel = useMemo(() => getErrorLevel(), [error]);
|
||||
const tableComponent = useMemo<boolean>(() => {
|
||||
let result = false;
|
||||
if (typeof queryType.match(/^bgp_\w+$/) !== null && data?.format === 'application/json') {
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}, [queryType, data?.format]);
|
||||
|
||||
const tableComponent = useMemo(() => typeof queryType.match(/^bgp_\w+$/) !== null, [queryType]);
|
||||
|
||||
let copyValue = data?.output;
|
||||
let copyValue = data?.output as string;
|
||||
|
||||
const formatData = useTableToString(queryTarget, data, [data?.format]);
|
||||
|
||||
@@ -130,18 +131,22 @@ export const Result = forwardRef<HTMLDivElement, TResult>((props, ref) => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
!loading && resultsComplete === null && setComplete(index);
|
||||
}, [loading, resultsComplete]);
|
||||
if (isLoading && resultsComplete === null) {
|
||||
setComplete(index);
|
||||
}
|
||||
}, [isLoading, resultsComplete]);
|
||||
|
||||
useEffect(() => {
|
||||
resultsComplete === index && !hasOverride && setOpen(true);
|
||||
if (resultsComplete === index && !hasOverride) {
|
||||
setOpen(true);
|
||||
}
|
||||
}, [resultsComplete, index]);
|
||||
|
||||
return (
|
||||
<AccordionItem
|
||||
ref={ref}
|
||||
isOpen={isOpen}
|
||||
isDisabled={loading}
|
||||
isDisabled={isLoading}
|
||||
css={{
|
||||
'&:last-of-type': { borderBottom: 'none' },
|
||||
'&:first-of-type': { borderTop: 'none' },
|
||||
@@ -155,17 +160,17 @@ export const Result = forwardRef<HTMLDivElement, TResult>((props, ref) => {
|
||||
flex="1 0 auto"
|
||||
onClick={handleToggle}>
|
||||
<ResultHeader
|
||||
error={error}
|
||||
loading={loading}
|
||||
isError={isError}
|
||||
loading={isLoading}
|
||||
errorMsg={errorMsg}
|
||||
errorLevel={errorLevel}
|
||||
runtime={data?.runtime}
|
||||
runtime={data?.runtime ?? 0}
|
||||
title={device.display_name}
|
||||
/>
|
||||
</AccordionButton>
|
||||
<ButtonGroup px={[1, 1, 3, 3]} py={2}>
|
||||
<CopyButton copyValue={copyValue} isDisabled={loading} />
|
||||
<RequeryButton requery={refetch} variant="ghost" isDisabled={loading} />
|
||||
<CopyButton copyValue={copyValue} isDisabled={isLoading} />
|
||||
<RequeryButton requery={refetch} variant="ghost" isDisabled={isLoading} />
|
||||
</ButtonGroup>
|
||||
</AccordionHeaderWrapper>
|
||||
<AccordionPanel
|
||||
@@ -188,20 +193,16 @@ export const Result = forwardRef<HTMLDivElement, TResult>((props, ref) => {
|
||||
}}>
|
||||
<Flex direction="column" flexWrap="wrap">
|
||||
<Flex direction="column" flex="1 0 auto" maxW={error ? '100%' : undefined}>
|
||||
<If c={!error && data}>
|
||||
<If c={tableComponent}>
|
||||
<BGPTable>{data?.output}</BGPTable>
|
||||
</If>
|
||||
<If c={!tableComponent}>
|
||||
<TextOutput>{data?.output}</TextOutput>
|
||||
</If>
|
||||
</If>
|
||||
|
||||
{error && (
|
||||
<Alert rounded="lg" my={2} py={4} status={errorLevel}>
|
||||
<FormattedError keywords={errorKw} message={errorMsg} />
|
||||
</Alert>
|
||||
{!isError && typeof data !== 'undefined' && (
|
||||
<>
|
||||
{isStructuredOutput(data) && tableComponent ? (
|
||||
<BGPTable>{data.output}</BGPTable>
|
||||
) : isStringOutput(data) && !tableComponent ? (
|
||||
<TextOutput>{data.output}</TextOutput>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
{isError && <Alert rounded="lg" my={2} py={4} status={errorLevel}></Alert>}
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { BoxProps, FlexProps } from '@chakra-ui/react';
|
||||
import type { TDevice, TQueryTypes } from '~/types';
|
||||
import type { TDevice, TQueryTypes, TFormState } from '~/types';
|
||||
|
||||
export interface TResultHeader {
|
||||
title: string;
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
isError?: boolean;
|
||||
errorMsg: string;
|
||||
errorLevel: 'success' | 'warning' | 'error';
|
||||
runtime: number;
|
||||
@@ -22,18 +22,14 @@ export interface TAccordionHeaderWrapper extends FlexProps {
|
||||
export interface TResult {
|
||||
index: number;
|
||||
device: TDevice;
|
||||
timeout: number;
|
||||
queryVrf: string;
|
||||
queryType: TQueryTypes;
|
||||
queryTarget: string;
|
||||
setComplete(v: number | null): void;
|
||||
queryLocation: string;
|
||||
queryLocation: string[];
|
||||
resultsComplete: number | null;
|
||||
}
|
||||
|
||||
export interface TResults extends BoxProps {
|
||||
queryType: TQueryTypes;
|
||||
queryLocation: string[];
|
||||
queryTarget: string;
|
||||
queryVrf: string;
|
||||
}
|
||||
export type TResults = TFormState & BoxProps;
|
||||
|
||||
export type TErrorLevels = 'success' | 'warning' | 'error';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export * from './useBooleanValue';
|
||||
export * from './useDevice';
|
||||
export * from './useGreeting';
|
||||
export * from './useLGQuery';
|
||||
export * from './useOpposingColor';
|
||||
export * from './useSessionStorage';
|
||||
export * from './useStrf';
|
||||
|
||||
@@ -3,8 +3,4 @@ export interface TOpposingOptions {
|
||||
dark?: string;
|
||||
}
|
||||
|
||||
export interface TStringTableData extends Omit<TQueryResponse, 'output'> {
|
||||
output: TStructuredResponse;
|
||||
}
|
||||
|
||||
export type TUseGreetingReturn = [boolean, (v?: boolean) => void];
|
||||
|
||||
62
hyperglass/ui/hooks/useLGQuery.ts
Normal file
62
hyperglass/ui/hooks/useLGQuery.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { useQuery } from 'react-query';
|
||||
import { useConfig } from '~/context';
|
||||
|
||||
import type { TFormState } from '~/types';
|
||||
|
||||
/**
|
||||
* Fetch Wrapper that incorporates a timeout via a passed AbortController instance.
|
||||
*
|
||||
* Adapted from: https://lowmess.com/blog/fetch-with-timeout
|
||||
*/
|
||||
export async function fetchWithTimeout(
|
||||
uri: string,
|
||||
options: RequestInit = {},
|
||||
timeout: number,
|
||||
controller: AbortController,
|
||||
): Promise<Response> {
|
||||
/**
|
||||
* Lets set up our `AbortController`, and create a request options object that includes the
|
||||
* controller's `signal` to pass to `fetch`.
|
||||
*/
|
||||
const { signal = new AbortController().signal, ...allOptions } = options;
|
||||
const config = { ...allOptions, signal };
|
||||
/**
|
||||
* Set a timeout limit for the request using `setTimeout`. If the body of this timeout is
|
||||
* reached before the request is completed, it will be cancelled.
|
||||
*/
|
||||
setTimeout(() => {
|
||||
controller.abort();
|
||||
}, timeout);
|
||||
return await fetch(uri, config);
|
||||
}
|
||||
|
||||
export function useLGQuery(query: TFormState) {
|
||||
const { request_timeout } = useConfig();
|
||||
const controller = new AbortController();
|
||||
|
||||
async function runQuery(url: string, requestData: TFormState): Promise<TQueryResponse> {
|
||||
const { queryLocation, queryTarget, queryType, queryVrf } = requestData;
|
||||
const res = await fetchWithTimeout(
|
||||
url,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
query_location: queryLocation,
|
||||
query_target: queryTarget,
|
||||
query_type: queryType,
|
||||
query_vrf: queryVrf,
|
||||
}),
|
||||
mode: 'cors',
|
||||
},
|
||||
request_timeout * 1000,
|
||||
controller,
|
||||
);
|
||||
return await res.json();
|
||||
}
|
||||
return useQuery<TQueryResponse, Response | TQueryResponse | Error>(
|
||||
['/api/query/', query],
|
||||
runQuery,
|
||||
{ refetchInterval: false },
|
||||
);
|
||||
}
|
||||
@@ -3,8 +3,7 @@ import dayjs from 'dayjs';
|
||||
import relativeTimePlugin from 'dayjs/plugin/relativeTime';
|
||||
import utcPlugin from 'dayjs/plugin/utc';
|
||||
import { useConfig } from '~/context';
|
||||
|
||||
import { TStringTableData } from './types';
|
||||
import { isStructuredOutput } from '~/types';
|
||||
|
||||
dayjs.extend(relativeTimePlugin);
|
||||
dayjs.extend(utcPlugin);
|
||||
@@ -48,10 +47,10 @@ function formatTime(val: number): string {
|
||||
|
||||
export function useTableToString(
|
||||
target: string,
|
||||
data: TStringTableData,
|
||||
data: TQueryResponse | undefined,
|
||||
...deps: any
|
||||
): () => string {
|
||||
const { web, parsed_data_fields } = useConfig();
|
||||
const { web, parsed_data_fields, messages } = useConfig();
|
||||
|
||||
function formatRpkiState(val: number): string {
|
||||
const rpkiStates = [
|
||||
@@ -83,12 +82,13 @@ export function useTableToString(
|
||||
}
|
||||
}
|
||||
|
||||
function doFormat(target: string, data: TStringTableData): string {
|
||||
function doFormat(target: string, data: TQueryResponse | undefined): string {
|
||||
let result = messages.no_output;
|
||||
try {
|
||||
if (typeof data !== 'undefined' && isStructuredOutput(data)) {
|
||||
let tableStringParts = [`Routes For: ${target}`, `Timestamp: ${data.timestamp} UTC`];
|
||||
|
||||
data.output.routes.map(route => {
|
||||
parsed_data_fields.map(field => {
|
||||
for (const route of data.output.routes) {
|
||||
for (const field of parsed_data_fields) {
|
||||
const [header, accessor, align] = field;
|
||||
if (align !== null) {
|
||||
let value = route[accessor];
|
||||
@@ -100,9 +100,11 @@ export function useTableToString(
|
||||
tableStringParts.push(` - ${header}: ${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return tableStringParts.join('\n');
|
||||
}
|
||||
}
|
||||
result = tableStringParts.join('\n');
|
||||
}
|
||||
return result;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return `An error occurred while parsing the output: '${err.message}'`;
|
||||
|
||||
@@ -7,3 +7,18 @@ export interface TFormData {
|
||||
query_vrf: string;
|
||||
query_target: string;
|
||||
}
|
||||
|
||||
export interface TFormState {
|
||||
queryLocation: string[];
|
||||
queryType: TQueryTypes;
|
||||
queryVrf: string;
|
||||
queryTarget: string;
|
||||
}
|
||||
|
||||
export interface TStringTableData extends Omit<TQueryResponse, 'output'> {
|
||||
output: TStructuredResponse;
|
||||
}
|
||||
|
||||
export interface TQueryResponseString extends Omit<TQueryResponse, 'output'> {
|
||||
output: string;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TValidQueryTypes } from './data';
|
||||
import { TValidQueryTypes, TStringTableData, TQueryResponseString } from './data';
|
||||
|
||||
export function isQueryType(q: any): q is TValidQueryTypes {
|
||||
let result = false;
|
||||
@@ -14,3 +14,11 @@ export function isQueryType(q: any): q is TValidQueryTypes {
|
||||
export function isString(a: any): a is string {
|
||||
return typeof a === 'string';
|
||||
}
|
||||
|
||||
export function isStructuredOutput(data: any): data is TStringTableData {
|
||||
return typeof data.output !== 'string';
|
||||
}
|
||||
|
||||
export function isStringOutput(data: any): data is TQueryResponseString {
|
||||
return typeof data.output === 'string';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user