mirror of
https://github.com/thatmattlove/hyperglass.git
synced 2026-01-17 08:48:05 +00:00
cleanup & code comments [skip ci]
This commit is contained in:
parent
486dd320ee
commit
4bbf5cde12
16 changed files with 197 additions and 321 deletions
|
|
@ -30,12 +30,25 @@ export const HyperglassProvider = (props: THyperglassProvider) => {
|
|||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current configuration.
|
||||
*/
|
||||
export const useConfig = (): IConfig => useContext(HyperglassContext);
|
||||
|
||||
/**
|
||||
* Get the current theme object.
|
||||
*/
|
||||
export const useTheme = (): ITheme => useChakraTheme();
|
||||
|
||||
/**
|
||||
* Determine if device is mobile or desktop based on Chakra UI theme breakpoints.
|
||||
*/
|
||||
export const useMobile = (): boolean =>
|
||||
useBreakpointValue({ base: true, md: true, lg: false, xl: false }) ?? true;
|
||||
useBreakpointValue<boolean>({ base: true, md: true, lg: false, xl: false }) ?? true;
|
||||
|
||||
/**
|
||||
* Convenience function to combine Chakra UI's useToken & useColorModeValue.
|
||||
*/
|
||||
export const useColorToken = <L extends string, D extends string>(
|
||||
token: keyof ITheme,
|
||||
light: L,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,5 @@ export * from './useGreeting';
|
|||
export * from './useLGQuery';
|
||||
export * from './useLGState';
|
||||
export * from './useOpposingColor';
|
||||
export * from './useScaledTitle';
|
||||
export * from './useStrf';
|
||||
export * from './useTableToString';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
import { State } from '@hookstate/core';
|
||||
import type { QueryFunctionContext } from 'react-query';
|
||||
import type { TFormQuery } from '~/types';
|
||||
import type {
|
||||
TDevice,
|
||||
Families,
|
||||
TFormQuery,
|
||||
TDeviceVrf,
|
||||
TQueryTypes,
|
||||
TSelectOption,
|
||||
} from '~/types';
|
||||
|
||||
export interface TOpposingOptions {
|
||||
light?: string;
|
||||
|
|
@ -34,3 +41,62 @@ export interface TUseDNSQueryFn {
|
|||
pageParam?: QueryFunctionContext['pageParam'];
|
||||
queryKey: [string | null, TUseDNSQueryParams];
|
||||
}
|
||||
|
||||
export type TUseDevice = (
|
||||
/**
|
||||
* Device's ID, e.g. the device.name field.
|
||||
*/
|
||||
deviceId: string,
|
||||
) => TDevice;
|
||||
|
||||
export interface TSelections {
|
||||
queryLocation: TSelectOption[] | [];
|
||||
queryType: TSelectOption | null;
|
||||
queryVrf: TSelectOption | null;
|
||||
}
|
||||
|
||||
export interface TMethodsExtension {
|
||||
getResponse(d: string): TQueryResponse | null;
|
||||
resolvedClose(): void;
|
||||
resolvedOpen(): void;
|
||||
formReady(): boolean;
|
||||
resetForm(): void;
|
||||
stateExporter<O extends unknown>(o: O): O | null;
|
||||
}
|
||||
|
||||
export type TLGState = {
|
||||
queryVrf: string;
|
||||
families: Families;
|
||||
queryTarget: string;
|
||||
btnLoading: boolean;
|
||||
isSubmitting: boolean;
|
||||
displayTarget: string;
|
||||
queryType: TQueryTypes;
|
||||
queryLocation: string[];
|
||||
availVrfs: TDeviceVrf[];
|
||||
resolvedIsOpen: boolean;
|
||||
selections: TSelections;
|
||||
responses: { [d: string]: TQueryResponse };
|
||||
};
|
||||
|
||||
export type TLGStateHandlers = {
|
||||
exportState<S extends unknown | null>(s: S): S | null;
|
||||
getResponse(d: string): TQueryResponse | null;
|
||||
resolvedClose(): void;
|
||||
resolvedOpen(): void;
|
||||
formReady(): boolean;
|
||||
resetForm(): void;
|
||||
stateExporter<O extends unknown>(o: O): O | null;
|
||||
};
|
||||
|
||||
export type UseStrfArgs = { [k: string]: any } | string;
|
||||
|
||||
export type TTableToStringFormatter = (v: any) => string;
|
||||
|
||||
export type TTableToStringFormatted = {
|
||||
age: (v: number) => string;
|
||||
active: (v: boolean) => string;
|
||||
as_path: (v: number[]) => string;
|
||||
communities: (v: string[]) => string;
|
||||
rpki_state: (v: number, n: TRPKIStates) => string;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ async function query(ctx: TUseASNDetailFn): Promise<TASNDetails> {
|
|||
return await res.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the bgpview.io API to get an ASN's organization name for the AS Path component.
|
||||
*/
|
||||
export function useASNDetail(asn: string) {
|
||||
return useQuery(asn, query, {
|
||||
refetchOnWindowFocus: false,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import { useMemo } from 'react';
|
||||
|
||||
/**
|
||||
* Track the state of a boolean and return values based on its state.
|
||||
*/
|
||||
export function useBooleanValue<T extends any, F extends any>(
|
||||
status: boolean,
|
||||
ifTrue: T,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import { fetchWithTimeout } from '~/util';
|
|||
import type { DnsOverHttps } from '~/types';
|
||||
import type { TUseDNSQueryFn } from './types';
|
||||
|
||||
/**
|
||||
* Perform a DNS over HTTPS query using the application/dns-json MIME type.
|
||||
*/
|
||||
async function dnsQuery(ctx: TUseDNSQueryFn): Promise<DnsOverHttps.Response | undefined> {
|
||||
const [url, { target, family }] = ctx.queryKey;
|
||||
|
||||
|
|
@ -30,7 +33,20 @@ async function dnsQuery(ctx: TUseDNSQueryFn): Promise<DnsOverHttps.Response | un
|
|||
return json;
|
||||
}
|
||||
|
||||
export function useDNSQuery(target: string | null, family: 4 | 6) {
|
||||
/**
|
||||
* Query the configured DNS over HTTPS provider for the provided target. If `family` is `4`, only
|
||||
* an A record will be queried. If `family` is `6`, only a AAAA record will be queried.
|
||||
*/
|
||||
export function useDNSQuery(
|
||||
/**
|
||||
* Hostname for DNS query.
|
||||
*/
|
||||
target: string | null,
|
||||
/**
|
||||
* Address family, e.g. IPv4 or IPv6.
|
||||
*/
|
||||
family: 4 | 6,
|
||||
) {
|
||||
const { cache, web } = useConfig();
|
||||
return useQuery([web.dns_provider.url, { target, family }], dnsQuery, {
|
||||
cacheTime: cache.timeout * 1000,
|
||||
|
|
|
|||
|
|
@ -3,13 +3,19 @@ import { useConfig } from '~/context';
|
|||
import { flatten } from '~/util';
|
||||
|
||||
import type { TDevice } from '~/types';
|
||||
import type { TUseDevice } from './types';
|
||||
|
||||
export function useDevice(): (i: string) => TDevice {
|
||||
/**
|
||||
* Get a device's configuration from the global configuration context based on its name.
|
||||
*/
|
||||
export function useDevice(): TUseDevice {
|
||||
const { networks } = useConfig();
|
||||
|
||||
const devices = useMemo(() => flatten<TDevice>(networks.map(n => n.locations)), []);
|
||||
|
||||
function getDevice(id: string): TDevice {
|
||||
return devices.filter(dev => dev.name === id)[0];
|
||||
}
|
||||
|
||||
return useCallback(getDevice, []);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ import type { TUseGreetingReturn } from './types';
|
|||
const ackState = createState<boolean>(false);
|
||||
const openState = createState<boolean>(false);
|
||||
|
||||
/**
|
||||
* Hook to manage the greeting, a.k.a. the popup at config path web.greeting.
|
||||
*/
|
||||
export function useGreeting(): TUseGreetingReturn {
|
||||
const ack = useState<boolean>(ackState);
|
||||
const isOpen = useState<boolean>(openState);
|
||||
|
|
@ -25,10 +28,13 @@ export function useGreeting(): TUseGreetingReturn {
|
|||
|
||||
function greetingReady(): boolean {
|
||||
if (ack.get()) {
|
||||
// If the acknowledgement is already set, no further evaluation is needed.
|
||||
return true;
|
||||
} else if (!web.greeting.required && !ack.get()) {
|
||||
// If the acknowledgement is not set, but is also not required, then pass.
|
||||
return true;
|
||||
} else if (web.greeting.required && !ack.get()) {
|
||||
// If the acknowledgement is not set, but is required, then fail.
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import { fetchWithTimeout } from '~/util';
|
|||
import type { TFormQuery } from '~/types';
|
||||
import type { TUseLGQueryFn } from './types';
|
||||
|
||||
/**
|
||||
* Custom hook handle submission of a query to the hyperglass backend.
|
||||
*/
|
||||
export function useLGQuery(query: TFormQuery) {
|
||||
const { request_timeout, cache } = useConfig();
|
||||
const controller = new AbortController();
|
||||
|
|
@ -34,9 +37,13 @@ export function useLGQuery(query: TFormQuery) {
|
|||
['/api/query/', query],
|
||||
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).
|
||||
refetchInterval: false,
|
||||
// Don't refetch on component remount.
|
||||
refetchOnMount: false,
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,28 +4,29 @@ import isEqual from 'react-fast-compare';
|
|||
import { all } from '~/util';
|
||||
|
||||
import type { State, PluginStateControl, Plugin } from '@hookstate/core';
|
||||
import type { Families, TDeviceVrf, TQueryTypes, TSelectOption } from '~/types';
|
||||
import type { TLGState, TLGStateHandlers, TMethodsExtension } from './types';
|
||||
|
||||
const PluginID = Symbol('Methods');
|
||||
const MethodsId = Symbol('Methods');
|
||||
|
||||
/**
|
||||
* Public API
|
||||
* hookstate plugin to provide convenience functions for the useLGState hook.
|
||||
*/
|
||||
interface MethodsExtension {
|
||||
getResponse(d: string): TQueryResponse | null;
|
||||
resolvedClose(): void;
|
||||
resolvedOpen(): void;
|
||||
formReady(): boolean;
|
||||
resetForm(): void;
|
||||
}
|
||||
|
||||
class MethodsInstance {
|
||||
/**
|
||||
* Set the DNS resolver Popover to opened.
|
||||
*/
|
||||
public resolvedOpen(state: State<TLGState>) {
|
||||
state.resolvedIsOpen.set(true);
|
||||
}
|
||||
/**
|
||||
* Set the DNS resolver Popover to closed.
|
||||
*/
|
||||
public resolvedClose(state: State<TLGState>) {
|
||||
state.resolvedIsOpen.set(false);
|
||||
}
|
||||
/**
|
||||
* Find a response based on the device ID.
|
||||
*/
|
||||
public getResponse(state: State<TLGState>, device: string): TQueryResponse | null {
|
||||
if (device in state.responses) {
|
||||
return state.responses[device].value;
|
||||
|
|
@ -33,6 +34,10 @@ class MethodsInstance {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Determine if the form is ready for submission, e.g. all fields have values and isSubmitting
|
||||
* has been set to true. This ultimately controls the UI layout.
|
||||
*/
|
||||
public formReady(state: State<TLGState>): boolean {
|
||||
return (
|
||||
state.isSubmitting.value &&
|
||||
|
|
@ -46,6 +51,9 @@ class MethodsInstance {
|
|||
)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Reset form values affected by the form state to their default values.
|
||||
*/
|
||||
public resetForm(state: State<TLGState>) {
|
||||
state.merge({
|
||||
queryVrf: '',
|
||||
|
|
@ -62,13 +70,34 @@ class MethodsInstance {
|
|||
selections: { queryLocation: [], queryType: null, queryVrf: null },
|
||||
});
|
||||
}
|
||||
public stateExporter<O extends unknown>(obj: O): O | null {
|
||||
let result = null;
|
||||
if (obj === null) {
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
result = JSON.parse(JSON.stringify(obj));
|
||||
} catch (err) {
|
||||
console.error(err.message);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin Initialization.
|
||||
*/
|
||||
function Methods(): Plugin;
|
||||
function Methods(inst: State<TLGState>): MethodsExtension;
|
||||
function Methods(inst?: State<TLGState>): Plugin | MethodsExtension {
|
||||
/**
|
||||
* Plugin Attachment.
|
||||
*/
|
||||
function Methods(inst: State<TLGState>): TMethodsExtension;
|
||||
/**
|
||||
* Plugin Instance.
|
||||
*/
|
||||
function Methods(inst?: State<TLGState>): Plugin | TMethodsExtension {
|
||||
if (inst) {
|
||||
const [instance] = inst.attach(PluginID) as [
|
||||
const [instance] = inst.attach(MethodsId) as [
|
||||
MethodsInstance | Error,
|
||||
PluginStateControl<TLGState>,
|
||||
];
|
||||
|
|
@ -83,46 +112,17 @@ function Methods(inst?: State<TLGState>): Plugin | MethodsExtension {
|
|||
resolvedOpen: () => instance.resolvedOpen(inst),
|
||||
resolvedClose: () => instance.resolvedClose(inst),
|
||||
getResponse: device => instance.getResponse(inst, device),
|
||||
stateExporter: obj => instance.stateExporter(obj),
|
||||
};
|
||||
}
|
||||
return {
|
||||
id: PluginID,
|
||||
id: MethodsId,
|
||||
init: () => {
|
||||
return new MethodsInstance() as {};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
interface TSelections {
|
||||
queryLocation: TSelectOption[] | [];
|
||||
queryType: TSelectOption | null;
|
||||
queryVrf: TSelectOption | null;
|
||||
}
|
||||
|
||||
type TLGState = {
|
||||
queryVrf: string;
|
||||
families: Families;
|
||||
queryTarget: string;
|
||||
btnLoading: boolean;
|
||||
isSubmitting: boolean;
|
||||
displayTarget: string;
|
||||
queryType: TQueryTypes;
|
||||
queryLocation: string[];
|
||||
availVrfs: TDeviceVrf[];
|
||||
resolvedIsOpen: boolean;
|
||||
selections: TSelections;
|
||||
responses: { [d: string]: TQueryResponse };
|
||||
};
|
||||
|
||||
type TLGStateHandlers = {
|
||||
exportState<S extends unknown | null>(s: S): S | null;
|
||||
getResponse(d: string): TQueryResponse | null;
|
||||
resolvedClose(): void;
|
||||
resolvedOpen(): void;
|
||||
formReady(): boolean;
|
||||
resetForm(): void;
|
||||
};
|
||||
|
||||
const LGState = createState<TLGState>({
|
||||
selections: { queryLocation: [], queryType: null, queryVrf: null },
|
||||
resolvedIsOpen: false,
|
||||
|
|
@ -138,27 +138,20 @@ const LGState = createState<TLGState>({
|
|||
families: [],
|
||||
});
|
||||
|
||||
/**
|
||||
* Global state hook for state used throughout hyperglass.
|
||||
*/
|
||||
export function useLGState(): State<TLGState> {
|
||||
return useState<TLGState>(LGState);
|
||||
}
|
||||
|
||||
function stateExporter<O extends unknown>(obj: O): O | null {
|
||||
let result = null;
|
||||
if (obj === null) {
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
result = JSON.parse(JSON.stringify(obj));
|
||||
} catch (err) {
|
||||
console.error(err.message);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin for useLGState() that provides convenience methods for its state.
|
||||
*/
|
||||
export function useLGMethods(): TLGStateHandlers {
|
||||
const state = useLGState();
|
||||
state.attach(Methods);
|
||||
const exporter = useCallback(stateExporter, [isEqual]);
|
||||
const exporter = useCallback(Methods(state).stateExporter, [isEqual]);
|
||||
return {
|
||||
exportState(s) {
|
||||
return exporter(s);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
import { useMemo, useState } from 'react';
|
||||
import { useToken } from '@chakra-ui/react';
|
||||
import { useMemo } from 'react';
|
||||
import { getColor, isLight } from '@chakra-ui/theme-tools';
|
||||
import { useTheme } from '~/context';
|
||||
|
||||
import type { TOpposingOptions } from './types';
|
||||
|
||||
/**
|
||||
* Parse the color string to determine if it's a Chakra UI theme key, and determine if the
|
||||
* opposing color should be black or white.
|
||||
*/
|
||||
export function useIsDark(color: string) {
|
||||
const theme = useTheme();
|
||||
if (typeof color === 'string' && color.match(/[a-zA-Z]+\.[a-zA-Z0-9]+/g)) {
|
||||
|
|
@ -19,6 +22,9 @@ export function useIsDark(color: string) {
|
|||
return opposingShouldBeDark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the foreground color for `color` should be white or black.
|
||||
*/
|
||||
export function useOpposingColor(color: string, options?: TOpposingOptions): string {
|
||||
const isBlack = useIsDark(color);
|
||||
|
||||
|
|
@ -30,14 +36,3 @@ export function useOpposingColor(color: string, options?: TOpposingOptions): str
|
|||
}
|
||||
}, [color]);
|
||||
}
|
||||
|
||||
export function useOpposingToken(color: string, options?: TOpposingOptions): string {
|
||||
const [opposingColor, setOpposingColor] = useState<string>('inherit');
|
||||
const isBlack = useIsDark(color);
|
||||
const dark = options?.dark ?? 'dark';
|
||||
const light = options?.light ?? 'light';
|
||||
|
||||
isBlack && opposingColor !== dark && setOpposingColor(dark);
|
||||
!isBlack && opposingColor !== light && setOpposingColor(light);
|
||||
return useMemo(() => opposingColor, [color]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
type ScaledTitleCallback = (f: string) => void;
|
||||
|
||||
function getWidthPx<R extends React.MutableRefObject<HTMLElement>>(ref: R) {
|
||||
const computedStyle = window.getComputedStyle(ref.current);
|
||||
const widthStr = computedStyle.width.replaceAll('px', '');
|
||||
const width = parseFloat(widthStr);
|
||||
return width;
|
||||
}
|
||||
|
||||
function reducePx(px: number) {
|
||||
return px * 0.9;
|
||||
}
|
||||
|
||||
function reducer(val: number, tooBig: () => boolean): number {
|
||||
let r = val;
|
||||
if (tooBig()) {
|
||||
r = reducePx(val);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* useScaledTitle(
|
||||
* f => {
|
||||
* setFontsize(f);
|
||||
* },
|
||||
* titleRef,
|
||||
* ref,
|
||||
* [showSubtitle],
|
||||
* );
|
||||
*/
|
||||
export function useScaledTitle<
|
||||
P extends React.MutableRefObject<HTMLDivElement>,
|
||||
T extends React.MutableRefObject<HTMLHeadingElement>
|
||||
>(callback: ScaledTitleCallback, parentRef: P, titleRef: T, deps: any[] = []) {
|
||||
console.log(deps);
|
||||
const [fontSize, setFontSize] = useState('');
|
||||
const calcSize = useRef(0);
|
||||
|
||||
function effect() {
|
||||
const computedSize = window.getComputedStyle(titleRef.current).getPropertyValue('font-size');
|
||||
|
||||
const fontPx = parseFloat(computedSize.replaceAll('px', ''));
|
||||
calcSize.current = fontPx;
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
calcSize.current = reducer(
|
||||
calcSize.current,
|
||||
() => getWidthPx(titleRef) >= getWidthPx(parentRef),
|
||||
);
|
||||
|
||||
setFontSize(`${calcSize.current}px`);
|
||||
|
||||
return callback(fontSize);
|
||||
}
|
||||
}
|
||||
|
||||
return useEffect(effect, [...deps, callback]);
|
||||
}
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
import { useMemo } from 'react';
|
||||
import format from 'string-format';
|
||||
|
||||
type FmtArgs = { [k: string]: any } | string;
|
||||
import type { UseStrfArgs } from './types';
|
||||
|
||||
export function useStrf(str: string, fmt: FmtArgs, ...deps: any[]): string {
|
||||
/**
|
||||
* Format a string with variables, like Python's string.format()
|
||||
*/
|
||||
export function useStrf(str: string, fmt: UseStrfArgs, ...deps: any[]): string {
|
||||
return useMemo(() => format(str, fmt), deps);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,19 +5,11 @@ import utcPlugin from 'dayjs/plugin/utc';
|
|||
import { useConfig } from '~/context';
|
||||
import { isStructuredOutput } from '~/types';
|
||||
|
||||
import type { TTableToStringFormatter, TTableToStringFormatted } from './types';
|
||||
|
||||
dayjs.extend(relativeTimePlugin);
|
||||
dayjs.extend(utcPlugin);
|
||||
|
||||
type TFormatter = (v: any) => string;
|
||||
|
||||
type TFormatted = {
|
||||
age: (v: number) => string;
|
||||
active: (v: boolean) => string;
|
||||
as_path: (v: number[]) => string;
|
||||
communities: (v: string[]) => string;
|
||||
rpki_state: (v: number, n: TRPKIStates) => string;
|
||||
};
|
||||
|
||||
function formatAsPath(path: number[]): string {
|
||||
return path.join(' → ');
|
||||
}
|
||||
|
|
@ -45,6 +37,9 @@ function formatTime(val: number): string {
|
|||
return `${relative} (${timestamp})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a function to convert table data to string, for use in the copy button component.
|
||||
*/
|
||||
export function useTableToString(
|
||||
target: string,
|
||||
data: TQueryResponse | undefined,
|
||||
|
|
@ -70,11 +65,11 @@ export function useTableToString(
|
|||
rpki_state: formatRpkiState,
|
||||
};
|
||||
|
||||
function isFormatted(key: string): key is keyof TFormatted {
|
||||
function isFormatted(key: string): key is keyof TTableToStringFormatted {
|
||||
return key in tableFormatMap;
|
||||
}
|
||||
|
||||
function getFmtFunc(accessor: keyof TRoute): TFormatter {
|
||||
function getFmtFunc(accessor: keyof TRoute): TTableToStringFormatter {
|
||||
if (isFormatted(accessor)) {
|
||||
return tableFormatMap[accessor];
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import Head from 'next/head';
|
||||
import { HyperglassProvider } from '~/context';
|
||||
import { IConfig } from '~/types';
|
||||
// import { useRouter } from "next/router";
|
||||
// import Error from "./_error";
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
require('@hookstate/devtools');
|
||||
}
|
||||
|
|
@ -21,10 +20,6 @@ const App = (props: TApp) => {
|
|||
const { Component, pageProps, appProps } = props;
|
||||
const { config } = appProps;
|
||||
|
||||
// const { asPath } = useRouter();
|
||||
// if (asPath === "/structured") {
|
||||
// return <Error msg="/structured" statusCode={404} />;
|
||||
// }
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
|
|
|
|||
|
|
@ -1,162 +0,0 @@
|
|||
import * as React from "react";
|
||||
import { Flex } from "@chakra-ui/core";
|
||||
import {BGPTable,Layout} from "app/components";
|
||||
|
||||
const response = {
|
||||
cached: false,
|
||||
format: "application/json",
|
||||
keywords: [],
|
||||
level: "success",
|
||||
output: {
|
||||
count: 5,
|
||||
routes: [
|
||||
{
|
||||
active: true,
|
||||
age: 1310798,
|
||||
as_path: [1299, 13335],
|
||||
communities: [
|
||||
"1299:35000",
|
||||
"14525:0",
|
||||
"14525:40",
|
||||
"14525:1021",
|
||||
"14525:2840",
|
||||
"14525:3001",
|
||||
"14525:4001",
|
||||
"14525:9003"
|
||||
],
|
||||
local_preference: 150,
|
||||
med: 0,
|
||||
next_hop: "62.115.189.136",
|
||||
peer_rid: "2.255.254.51",
|
||||
prefix: "1.1.1.0/24",
|
||||
rpki_state: 3,
|
||||
source_as: 13335,
|
||||
source_rid: "162.158.140.1",
|
||||
weight: 170
|
||||
},
|
||||
{
|
||||
active: false,
|
||||
age: 1310792,
|
||||
as_path: [174, 13335],
|
||||
communities: [
|
||||
"174:21001",
|
||||
"174:22013",
|
||||
"14525:0",
|
||||
"14525:20",
|
||||
"14525:1021",
|
||||
"14525:2840",
|
||||
"14525:3001",
|
||||
"14525:4001",
|
||||
"14525:9001"
|
||||
],
|
||||
local_preference: 150,
|
||||
med: 2020,
|
||||
next_hop: "100.64.0.122",
|
||||
peer_rid: "199.34.92.1",
|
||||
prefix: "1.1.1.0/24",
|
||||
rpki_state: 3,
|
||||
source_as: 13335,
|
||||
source_rid: "162.158.140.1",
|
||||
weight: 170
|
||||
},
|
||||
{
|
||||
active: false,
|
||||
age: 70883,
|
||||
as_path: [13335],
|
||||
communities: [
|
||||
"13335:10232",
|
||||
"13335:19000",
|
||||
"13335:20050",
|
||||
"13335:20500",
|
||||
"13335:20530",
|
||||
"14525:0",
|
||||
"14525:20",
|
||||
"14525:1021",
|
||||
"14525:2840",
|
||||
"14525:3002",
|
||||
"14525:4003",
|
||||
"14525:9009"
|
||||
],
|
||||
local_preference: 250,
|
||||
med: 0,
|
||||
next_hop: "100.64.0.122",
|
||||
peer_rid: "199.34.92.5",
|
||||
prefix: "1.1.1.0/24",
|
||||
rpki_state: 3,
|
||||
source_as: 13335,
|
||||
source_rid: "172.68.129.1",
|
||||
weight: 200
|
||||
},
|
||||
{
|
||||
active: false,
|
||||
age: 70862,
|
||||
as_path: [13335],
|
||||
communities: [
|
||||
"13335:10232",
|
||||
"13335:19000",
|
||||
"13335:20050",
|
||||
"13335:20500",
|
||||
"13335:20530",
|
||||
"14525:0",
|
||||
"14525:20",
|
||||
"14525:1021",
|
||||
"14525:2840",
|
||||
"14525:3002",
|
||||
"14525:4003",
|
||||
"14525:9009"
|
||||
],
|
||||
local_preference: 250,
|
||||
med: 0,
|
||||
next_hop: "100.64.0.122",
|
||||
peer_rid: "199.34.92.6",
|
||||
prefix: "1.1.1.0/24",
|
||||
rpki_state: 3,
|
||||
source_as: 13335,
|
||||
source_rid: "172.68.129.1",
|
||||
weight: 200
|
||||
},
|
||||
{
|
||||
active: false,
|
||||
age: 1124791,
|
||||
as_path: [174, 13335],
|
||||
communities: [
|
||||
"174:21001",
|
||||
"174:22003",
|
||||
"14525:0",
|
||||
"14525:40",
|
||||
"14525:1021",
|
||||
"14525:2840",
|
||||
"14525:3003",
|
||||
"14525:4004",
|
||||
"14525:9001"
|
||||
],
|
||||
local_preference: 150,
|
||||
med: 25090,
|
||||
next_hop: "100.64.0.122",
|
||||
peer_rid: "199.34.92.7",
|
||||
prefix: "1.1.1.0/24",
|
||||
rpki_state: 3,
|
||||
source_as: 13335,
|
||||
source_rid: "108.162.239.1",
|
||||
weight: 200
|
||||
}
|
||||
],
|
||||
vrf: "default",
|
||||
winning_weight: "low"
|
||||
},
|
||||
random: "60d6663342e1c1e3e1b2a6259b22023b45e0568dd7e31aeee9c453cf6e7091d5",
|
||||
runtime: 5,
|
||||
timestamp: "2020-06-06 04:38:46"
|
||||
};
|
||||
|
||||
const Structured = () => {
|
||||
return (
|
||||
<Layout>
|
||||
<Flex my={8} maxW={["100%", "100%", "75%", "75%"]} w="100%">
|
||||
<BGPTable>{response.output}</BGPTable>
|
||||
</Flex>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Structured;
|
||||
Loading…
Add table
Reference in a new issue