(p: any): p is C & MDProps {
- return 'node' in p;
-}
-
-function clean(props: P): P {
- if (hasNode
(props)) {
- const { node, ...rest } = props;
- const r = (rest as unknown) as P;
- return r;
- }
- return props;
-}
-
-export const Checkbox: React.FC = (props: TCheckbox & MDProps) => {
- const { checked, node, ...rest } = props;
- return ;
-};
-
-export const List: React.FC = (props: TList) => {
- const { ordered, ...rest } = props;
- return (
- <>
-
-
-
-
-
-
- >
- );
-};
-
-export const ListItem: React.FC = (props: TListItem & MDProps) => {
- const { checked, node, ...rest } = props;
- return checked ? (
-
- ) : (
-
- );
-};
-
-export const Heading: React.FC = (props: THeading) => {
- const { level, ...rest } = props;
-
- const levelMap = {
- 1: { as: 'h1', size: 'lg', fontWeight: 'bold' },
- 2: { as: 'h2', size: 'lg', fontWeight: 'normal' },
- 3: { as: 'h3', size: 'lg', fontWeight: 'bold' },
- 4: { as: 'h4', size: 'md', fontWeight: 'normal' },
- 5: { as: 'h5', size: 'md', fontWeight: 'bold' },
- 6: { as: 'h6', size: 'sm', fontWeight: 'bold' },
- } as { [i: number]: HeadingProps };
-
- return >(rest)} />;
-};
-
-export const Link: React.FC = (props: LinkProps) => {
- const color = useColorValue('blue.500', 'blue.300');
- return (props)} />;
-};
-
-export const CodeBlock: React.FC = (props: TCodeBlock) => (
- {props.value}
-);
-
-export const Paragraph: React.FC = (props: TextProps) => (
- (props)}
- />
-);
-
-export const InlineCode: React.FC = (props: CodeProps) => (
- (props)} />
-);
-
-export const Divider: React.FC = (props: DividerProps) => (
- (props)} />
-);
-
-export const Table: React.FC = (props: TableProps) => (
- (props)} />
-);
-
-export const TableRow: React.FC = (props: TableRowProps) => (
- (props)} />
-);
-
-export const TableBody: React.FC = (props: TableBodyProps) => (
- (props)} />
-);
-
-export const TableHead: React.FC = (props: TableHeadProps) => (
- (props)} />
-);
-
-export const TableCell: React.FC = (props: TTableData) => {
- const { isHeader, ...rest } = props;
- return (
- <>
-
- (rest)} />
-
-
- (rest)} />
-
- >
- );
-};
-
-export const Br: React.FC = (props: BoxProps) => (
- (props)} />
-);
diff --git a/hyperglass/ui/components/markdown/index.ts b/hyperglass/ui/components/markdown/index.ts
deleted file mode 100644
index 99334b5..0000000
--- a/hyperglass/ui/components/markdown/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './markdown';
diff --git a/hyperglass/ui/components/markdown/markdown.tsx b/hyperglass/ui/components/markdown/markdown.tsx
deleted file mode 100644
index 8266d8b..0000000
--- a/hyperglass/ui/components/markdown/markdown.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import ReactMarkdown from 'react-markdown';
-import gfm from 'remark-gfm';
-import {
- Br,
- List,
- Link,
- Table,
- Heading,
- Divider,
- ListItem,
- TableRow,
- CodeBlock,
- TableCell,
- Paragraph,
- TableBody,
- TableHead,
- InlineCode,
-} from './elements';
-
-import type { ReactMarkdownProps } from 'react-markdown';
-import type { TMarkdown } from './types';
-
-const renderers = {
- break: Br,
- link: Link,
- list: List,
- table: Table,
- code: CodeBlock,
- heading: Heading,
- tableRow: TableRow,
- listItem: ListItem,
- tableHead: TableHead,
- tableBody: TableBody,
- paragraph: Paragraph,
- tableCell: TableCell,
- inlineCode: InlineCode,
- thematicBreak: Divider,
-} as ReactMarkdownProps['renderers'];
-
-export const Markdown: React.FC = (props: TMarkdown) => (
-
-);
diff --git a/hyperglass/ui/components/markdown/types.ts b/hyperglass/ui/components/markdown/types.ts
deleted file mode 100644
index b5e15aa..0000000
--- a/hyperglass/ui/components/markdown/types.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import type { BoxProps, CheckboxProps, HeadingProps, ListProps } from '@chakra-ui/react';
-
-export interface TMarkdown {
- content: string;
-}
-
-export interface TCheckbox extends CheckboxProps {
- checked: boolean;
-}
-
-export interface TListItem {
- checked: boolean;
- children?: React.ReactNode;
-}
-
-export interface TList extends ListProps {
- ordered: boolean;
- children?: React.ReactNode;
-}
-
-export interface THeading extends HeadingProps {
- level: 1 | 2 | 3 | 4 | 5 | 6;
-}
-
-export interface TCodeBlock {
- value: React.ReactNode;
-}
-
-export interface TTableData extends BoxProps {
- isHeader: boolean;
-}
diff --git a/hyperglass/ui/components/meta.tsx b/hyperglass/ui/components/meta.tsx
deleted file mode 100644
index 70ab813..0000000
--- a/hyperglass/ui/components/meta.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { useEffect, useMemo, useState } from 'react';
-import Head from 'next/head';
-import { useTheme } from '@chakra-ui/react';
-import { useConfig } from '~/context';
-import { googleFontUrl } from '~/util';
-
-export const Meta: React.FC = () => {
- const config = useConfig();
- const { fonts } = useTheme();
- const [location, setLocation] = useState('/');
-
- const {
- site_title: title = 'hyperglass',
- site_description: description = 'Network Looking Glass',
- site_keywords: keywords = [
- 'hyperglass',
- 'looking glass',
- 'lg',
- 'peer',
- 'peering',
- 'ipv4',
- 'ipv6',
- 'transit',
- 'community',
- 'communities',
- 'bgp',
- 'routing',
- 'network',
- 'isp',
- ],
- } = useConfig();
-
- const siteName = `${title} - ${description}`;
- const primaryFont = useMemo(() => googleFontUrl(fonts.body), []);
- const monoFont = useMemo(() => googleFontUrl(fonts.mono), []);
-
- useEffect(() => {
- if (typeof window !== 'undefined' && location === '/') {
- setLocation(window.location.href);
- }
- }, []);
-
- return (
-
- {title}
-
-
-
-
-
-
-
-
-
-
-
-
- );
-};
diff --git a/hyperglass/ui/components/output/cell.tsx b/hyperglass/ui/components/output/cell.tsx
deleted file mode 100644
index 0bcb6d9..0000000
--- a/hyperglass/ui/components/output/cell.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { MonoField, Active, Weight, Age, Communities, RPKIState, ASPath } from './fields';
-
-import type { TCell } from './types';
-
-export const Cell: React.FC = (props: TCell) => {
- const { data, rawData } = props;
- const cellId = data.column.id as keyof TRoute;
- const component = {
- med: ,
- age: ,
- prefix: ,
- next_hop: ,
- peer_rid: ,
- source_as: ,
- active: ,
- source_rid: ,
- local_preference: ,
- communities: ,
- as_path: ,
- rpki_state: ,
- weight: ,
- };
- return component[cellId] ?? <> >;
-};
diff --git a/hyperglass/ui/components/output/fields.tsx b/hyperglass/ui/components/output/fields.tsx
deleted file mode 100644
index f372bd9..0000000
--- a/hyperglass/ui/components/output/fields.tsx
+++ /dev/null
@@ -1,190 +0,0 @@
-import { forwardRef } from 'react';
-import { Icon, Text, Box, Tooltip, Menu, MenuButton, MenuList, Link } from '@chakra-ui/react';
-import { CgMoreO as More } from '@meronex/icons/cg';
-import { BisError as Warning } from '@meronex/icons/bi';
-import { MdCancel as NotAllowed } from '@meronex/icons/md';
-import { RiHome2Fill as End } from '@meronex/icons/ri';
-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';
-import { If } from '~/components';
-import { useConfig, useColorValue } from '~/context';
-import { useOpposingColor } from '~/hooks';
-
-import type {
- TAge,
- TActive,
- TWeight,
- TASPath,
- TMonoField,
- TRPKIState,
- TCommunities,
-} from './types';
-
-dayjs.extend(relativeTimePlugin);
-dayjs.extend(utcPlugin);
-
-export const MonoField: React.FC = (props: TMonoField) => {
- const { v, ...rest } = props;
- return (
-
- {v}
-
- );
-};
-
-export const Active: React.FC = (props: TActive) => {
- const { isActive } = props;
- const color = useColorValue(['gray.500', 'green.500'], ['whiteAlpha.300', 'blackAlpha.500']);
- return (
- <>
-
-
-
-
-
-
- >
- );
-};
-
-export const Age: React.FC = (props: TAge) => {
- const { inSeconds, ...rest } = props;
- const now = dayjs.utc();
- const then = now.subtract(inSeconds, 'second');
- return (
-
-
- {now.to(then, true)}
-
-
- );
-};
-
-export const Weight: React.FC = (props: TWeight) => {
- const { weight, winningWeight, ...rest } = props;
- const fixMeText =
- winningWeight === 'low' ? 'Lower Weight is Preferred' : 'Higher Weight is Preferred';
- return (
-
-
- {weight}
-
-
- );
-};
-
-export const ASPath: React.FC = (props: TASPath) => {
- const { path, active } = props;
- const color = useColorValue(
- // light: inactive, active
- ['blackAlpha.500', 'blackAlpha.500'],
- // dark: inactive, active
- ['whiteAlpha.600', 'blackAlpha.700'],
- );
-
- if (path.length === 0) {
- return ;
- }
-
- const paths = [] as JSX.Element[];
-
- path.map((asn, i) => {
- const asnStr = String(asn);
- i !== 0 &&
- paths.push(
- ,
- );
- paths.push(
-
- {asnStr}
- ,
- );
- });
-
- return <>{paths}>;
-};
-
-export const Communities: React.FC = (props: TCommunities) => {
- const { communities } = props;
- const { web } = useConfig();
- const bg = useColorValue('white', 'gray.900');
- const color = useOpposingColor(bg);
- return (
- <>
-
-
-
-
-
-
-
-
-
-
- >
- );
-};
-
-const _RPKIState: React.ForwardRefRenderFunction = (
- props: TRPKIState,
- ref,
-) => {
- const { state, active } = props;
- const { web } = useConfig();
- const bg = useColorValue(
- [
- ['red.400', 'green.500', 'yellow.400', 'gray.500'],
- ['red.500', 'green.500', 'yellow.600', 'gray.600'],
- ],
- [
- ['red.300', 'green.300', 'yellow.300', 'gray.300'],
- ['red.500', 'green.600', 'yellow.600', 'gray.800'],
- ],
- );
- const color = useOpposingColor(bg[+active][state]);
- const icon = [NotAllowed, Check, Warning, Question];
-
- const text = [
- web.text.rpki_invalid,
- web.text.rpki_valid,
- web.text.rpki_unknown,
- web.text.rpki_unverified,
- ];
-
- return (
-
-
-
-
-
- );
-};
-
-export const RPKIState = forwardRef(_RPKIState);
diff --git a/hyperglass/ui/components/output/index.ts b/hyperglass/ui/components/output/index.ts
deleted file mode 100644
index c22d499..0000000
--- a/hyperglass/ui/components/output/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './table';
-export * from './text';
diff --git a/hyperglass/ui/components/output/table.tsx b/hyperglass/ui/components/output/table.tsx
deleted file mode 100644
index a56a6fd..0000000
--- a/hyperglass/ui/components/output/table.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { Flex } from '@chakra-ui/react';
-import { useConfig } from '~/context';
-import { Table } from '~/components';
-import { Cell } from './cell';
-
-import type { TColumn, TParsedDataField, TCellRender } from '~/types';
-import type { TBGPTable } from './types';
-
-function makeColumns(fields: TParsedDataField[]): TColumn[] {
- return fields.map(pair => {
- const [header, accessor, align] = pair;
-
- const columnConfig = {
- align,
- accessor,
- hidden: false,
- Header: header,
- } as TColumn;
-
- if (align === null) {
- columnConfig.hidden = true;
- }
-
- return columnConfig;
- });
-}
-
-export const BGPTable: React.FC = (props: TBGPTable) => {
- const { children: data, ...rest } = props;
- const { parsed_data_fields } = useConfig();
- const columns = makeColumns(parsed_data_fields);
-
- return (
-
- | }
- />
-
- );
-};
diff --git a/hyperglass/ui/components/output/text.tsx b/hyperglass/ui/components/output/text.tsx
deleted file mode 100644
index 8fa794c..0000000
--- a/hyperglass/ui/components/output/text.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { Box } from '@chakra-ui/react';
-import { useColorValue } from '~/context';
-
-import type { TTextOutput } from './types';
-
-export const TextOutput: React.FC = (props: TTextOutput) => {
- const { children, ...rest } = props;
-
- const bg = useColorValue('blackAlpha.100', 'gray.800');
- const color = useColorValue('black', 'white');
- const selectionBg = useColorValue('black', 'white');
- const selectionColor = useColorValue('white', 'black');
-
- return (
-
- {children.split('\\n').join('\n').replace(/\n\n/g, '\n')}
-
- );
-};
diff --git a/hyperglass/ui/components/output/types.ts b/hyperglass/ui/components/output/types.ts
deleted file mode 100644
index a492625..0000000
--- a/hyperglass/ui/components/output/types.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import type { BoxProps, FlexProps, TextProps } from '@chakra-ui/react';
-import type { TCellRender } from '~/types';
-
-export interface TTextOutput extends Omit {
- children: string;
-}
-
-export interface TActive {
- isActive: boolean;
-}
-
-export interface TMonoField extends TextProps {
- v: React.ReactNode;
-}
-
-export interface TAge extends TextProps {
- inSeconds: number;
-}
-
-export interface TWeight extends TextProps {
- weight: number;
- winningWeight: 'low' | 'high';
-}
-
-export interface TASPath {
- path: number[];
- active: boolean;
-}
-
-export interface TCommunities {
- communities: string[];
-}
-
-export interface TRPKIState {
- state:
- | 0 // Invalid
- | 1 // Valid
- | 2 // Unknown
- | 3; // Unverified
- active: boolean;
-}
-
-export interface TCell {
- data: TCellRender;
- rawData: TStructuredResponse;
-}
-
-export interface TBGPTable extends Omit {
- children: TStructuredResponse;
-}
diff --git a/hyperglass/ui/components/path/button.tsx b/hyperglass/ui/components/path/button.tsx
deleted file mode 100644
index 94723b4..0000000
--- a/hyperglass/ui/components/path/button.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import dynamic from 'next/dynamic';
-import { Button, Icon, Tooltip } from '@chakra-ui/react';
-
-import type { TPathButton } from './types';
-
-const PathIcon = dynamic(() =>
- import('@meronex/icons/bi').then(i => i.BisNetworkChart),
-);
-
-export const PathButton: React.FC = (props: TPathButton) => {
- const { onOpen } = props;
- return (
-
-
-
- );
-};
diff --git a/hyperglass/ui/components/path/chart.tsx b/hyperglass/ui/components/path/chart.tsx
deleted file mode 100644
index 9f6cff4..0000000
--- a/hyperglass/ui/components/path/chart.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import { Box, Flex, SkeletonText, Badge, VStack } from '@chakra-ui/react';
-import ReactFlow from 'react-flow-renderer';
-import { Background, ReactFlowProvider } from 'react-flow-renderer';
-import { Handle, Position } from 'react-flow-renderer';
-import { useConfig, useColorValue, useColorToken } from '~/context';
-import { useASNDetail } from '~/hooks';
-import { Controls } from './controls';
-import { useElements } from './useElements';
-
-import type { TChart, TNode, TNodeData } from './types';
-
-export const Chart: React.FC = (props: TChart) => {
- const { data } = props;
- const { primary_asn, org_name } = useConfig();
-
- const dots = useColorToken('colors', 'blackAlpha.500', 'whiteAlpha.400');
-
- const elements = useElements({ asn: primary_asn, name: org_name }, data);
-
- return (
-
-
- setTimeout(() => inst.fitView(), 0)}
- >
-
-
-
-
-
- );
-};
-
-const ASNode: React.FC> = (props: TNode) => {
- const { data } = props;
- const { asn, name, hasChildren, hasParents } = data;
-
- const color = useColorValue('black', 'white');
- const bg = useColorValue('white', 'whiteAlpha.100');
-
- const { data: asnData, isError, isLoading } = useASNDetail(String(asn));
-
- return (
- <>
- {hasChildren && }
-
-
-
- {isLoading ? (
-
-
-
- ) : !isError && asnData?.data?.asn.organization?.orgName ? (
- asnData.data.asn.organization.orgName
- ) : (
- name
- )}
-
-
- {asn}
-
-
-
- {hasParents && }
- >
- );
-};
diff --git a/hyperglass/ui/components/path/controls.tsx b/hyperglass/ui/components/path/controls.tsx
deleted file mode 100644
index 4d6e13d..0000000
--- a/hyperglass/ui/components/path/controls.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import dynamic from 'next/dynamic';
-import { ButtonGroup, IconButton } from '@chakra-ui/react';
-import { useZoomPanHelper } from 'react-flow-renderer';
-
-const Plus = dynamic(() => import('@meronex/icons/fi').then(i => i.FiPlus));
-const Minus = dynamic(() => import('@meronex/icons/fi').then(i => i.FiMinus));
-const Square = dynamic(() => import('@meronex/icons/fi').then(i => i.FiSquare));
-
-export const Controls: React.FC = () => {
- const { fitView, zoomIn, zoomOut } = useZoomPanHelper();
- return (
-
- } onClick={() => zoomIn()} aria-label="Zoom In" />
- } onClick={() => zoomOut()} aria-label="Zoom Out" />
- } onClick={() => fitView()} aria-label="Fit Nodes" />
-
- );
-};
diff --git a/hyperglass/ui/components/path/index.ts b/hyperglass/ui/components/path/index.ts
deleted file mode 100644
index 44bb0aa..0000000
--- a/hyperglass/ui/components/path/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './path';
diff --git a/hyperglass/ui/components/path/path.tsx b/hyperglass/ui/components/path/path.tsx
deleted file mode 100644
index 96886e2..0000000
--- a/hyperglass/ui/components/path/path.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import {
- Modal,
- Skeleton,
- ModalBody,
- ModalHeader,
- ModalOverlay,
- ModalContent,
- useDisclosure,
- ModalCloseButton,
-} from '@chakra-ui/react';
-import { useColorValue, useBreakpointValue } from '~/context';
-import { useLGState, useLGMethods } from '~/hooks';
-import { PathButton } from './button';
-import { Chart } from './chart';
-
-import type { TPath } from './types';
-
-export const Path: React.FC = (props: TPath) => {
- const { device } = props;
- const { displayTarget } = useLGState();
- const { getResponse } = useLGMethods();
- const { isOpen, onClose, onOpen } = useDisclosure();
- const response = getResponse(device);
- const output = response?.output as TStructuredResponse;
- const bg = useColorValue('light.50', 'dark.900');
- const centered = useBreakpointValue({ base: false, lg: true }) ?? true;
- return (
- <>
-
-
-
-
- {`Path to ${displayTarget.value}`}
-
-
- {response !== null ? : }
-
-
-
- >
- );
-};
diff --git a/hyperglass/ui/components/path/types.ts b/hyperglass/ui/components/path/types.ts
deleted file mode 100644
index dd0f4ba..0000000
--- a/hyperglass/ui/components/path/types.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import type { NodeProps } from 'react-flow-renderer';
-
-export interface TChart {
- data: TStructuredResponse;
-}
-
-export interface TPath {
- device: string;
-}
-
-export interface TNode extends Omit {
- data: D;
-}
-
-export interface TNodeData {
- asn: string;
- name: string;
- hasChildren: boolean;
- hasParents?: boolean;
-}
-
-export interface BasePath {
- asn: string;
- name: string;
-}
-
-export interface TPathButton {
- onOpen(): void;
-}
diff --git a/hyperglass/ui/components/path/useElements.ts b/hyperglass/ui/components/path/useElements.ts
deleted file mode 100644
index e0916b4..0000000
--- a/hyperglass/ui/components/path/useElements.ts
+++ /dev/null
@@ -1,115 +0,0 @@
-import dagre from 'dagre';
-import { useMemo } from 'react';
-import isEqual from 'react-fast-compare';
-
-import type { FlowElement } from 'react-flow-renderer';
-import type { BasePath } from './types';
-
-const NODE_WIDTH = 200;
-const NODE_HEIGHT = 48;
-
-export function useElements(base: BasePath, data: TStructuredResponse): FlowElement[] {
- return useMemo(() => {
- return [...buildElements(base, data)];
- }, [data.routes.length]);
-}
-
-/**
- * Calculate the positions for each AS Path.
- * @see https://github.com/MrBlenny/react-flow-chart/issues/61
- */
-function* buildElements(base: BasePath, data: TStructuredResponse): Generator {
- const { routes } = data;
- // Eliminate empty AS paths & deduplicate non-empty AS paths. Length should be same as count minus empty paths.
- const asPaths = routes.filter(r => r.as_path.length !== 0).map(r => [...new Set(r.as_path)]);
-
- const totalPaths = asPaths.length - 1;
-
- const g = new dagre.graphlib.Graph();
- g.setGraph({ marginx: 20, marginy: 20 });
- g.setDefaultEdgeLabel(() => ({}));
-
- // Set the origin (i.e., the hyperglass user) at the base.
- g.setNode(base.asn, { width: NODE_WIDTH, height: NODE_HEIGHT });
-
- for (const [groupIdx, pathGroup] of asPaths.entries()) {
- // For each ROUTE's AS Path:
-
- // Find the route after this one.
- const nextGroup = groupIdx < totalPaths ? asPaths[groupIdx + 1] : [];
-
- // Connect the first hop in the AS Path to the base (for dagre).
- g.setEdge(base.asn, `${groupIdx}-${pathGroup[0]}`);
-
- // Eliminate duplicate AS Paths.
- if (!isEqual(pathGroup, nextGroup)) {
- for (const [idx, asn] of pathGroup.entries()) {
- // For each ASN in the ROUTE:
-
- const node = `${groupIdx}-${asn}`;
- const endIdx = pathGroup.length - 1;
-
- // Add the AS as a node.
- g.setNode(node, { width: NODE_WIDTH, height: NODE_HEIGHT });
-
- // Connect the first hop in the AS Path to the base (for react-flow).
- if (idx === 0) {
- yield {
- id: `e${base.asn}-${node}`,
- source: base.asn,
- target: node,
- };
- }
- // Connect every intermediate hop to each other.
- if (idx !== endIdx) {
- const next = `${groupIdx}-${pathGroup[idx + 1]}`;
- g.setEdge(node, next);
- yield {
- id: `e${node}-${next}`,
- source: node,
- target: next,
- };
- }
- }
- }
- }
-
- // Now that that nodes are added, create the layout.
- dagre.layout(g, { rankdir: 'BT', align: 'UR' });
-
- // Get the base ASN's positions.
- const x = g.node(base.asn).x - NODE_WIDTH / 2;
- const y = g.node(base.asn).y + NODE_HEIGHT * 6;
-
- yield {
- id: base.asn,
- type: 'ASNode',
- position: { x, y },
- data: { asn: base.asn, name: base.name, hasChildren: true, hasParents: false },
- };
-
- for (const [groupIdx, pathGroup] of asPaths.entries()) {
- const nextGroup = groupIdx < totalPaths ? asPaths[groupIdx + 1] : [];
- if (!isEqual(pathGroup, nextGroup)) {
- for (const [idx, asn] of pathGroup.entries()) {
- const node = `${groupIdx}-${asn}`;
- const endIdx = pathGroup.length - 1;
- const x = g.node(node).x - NODE_WIDTH / 2;
- const y = g.node(node).y - NODE_HEIGHT * (idx * 6);
-
- // Get each ASN's positions.
- yield {
- id: node,
- type: 'ASNode',
- position: { x, y },
- data: {
- asn,
- name: `AS${asn}`,
- hasChildren: idx < endIdx,
- hasParents: true,
- },
- };
- }
- }
- }
-}
diff --git a/hyperglass/ui/components/results/copyButton.tsx b/hyperglass/ui/components/results/copyButton.tsx
deleted file mode 100644
index bc031c3..0000000
--- a/hyperglass/ui/components/results/copyButton.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import dynamic from 'next/dynamic';
-import { Button, Icon, Tooltip, useClipboard } from '@chakra-ui/react';
-
-const Copy = dynamic(() => import('@meronex/icons/fi').then(i => i.FiCopy));
-const Check = dynamic(() => import('@meronex/icons/fi').then(i => i.FiCheck));
-
-import type { TCopyButton } from './types';
-
-export const CopyButton: React.FC = (props: TCopyButton) => {
- const { copyValue, ...rest } = props;
- const { onCopy, hasCopied } = useClipboard(copyValue);
- return (
-
-
-
- );
-};
diff --git a/hyperglass/ui/components/results/error.tsx b/hyperglass/ui/components/results/error.tsx
deleted file mode 100644
index a8292d3..0000000
--- a/hyperglass/ui/components/results/error.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { Text } from '@chakra-ui/react';
-
-import type { TFormattedError } from './types';
-
-type TFormatError = string | JSX.Element;
-
-function formatError(text: string, values: string[], regex: RegExp): TFormatError[] | TFormatError {
- if (!values.length) {
- return text;
- }
-
- const parts = text.split(regex);
-
- return parts.reduce((prev, current, i) => {
- if (!i) {
- return [current];
- }
-
- return prev.concat(
- values.includes(current) ? {current} : current,
- );
- }, [] as TFormatError[]);
-}
-
-export const FormattedError: React.FC = (props: TFormattedError) => {
- const { keywords, message } = props;
- const pattern = new RegExp(keywords.map(kw => `(${kw})`).join('|'), 'gi');
- const things = formatError(message, keywords, pattern);
- return (
-
- {keywords.length !== 0 ? things : message}
-
- );
-};
diff --git a/hyperglass/ui/components/results/group.tsx b/hyperglass/ui/components/results/group.tsx
deleted file mode 100644
index 564d2c1..0000000
--- a/hyperglass/ui/components/results/group.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import { useEffect } from 'react';
-import { Accordion } from '@chakra-ui/react';
-import { AnimatePresence } from 'framer-motion';
-import { AnimatedDiv } from '~/components';
-import { useDevice, useLGState } from '~/hooks';
-import { Result } from './individual';
-import { Tags } from './tags';
-
-export const Results: React.FC = () => {
- const { queryLocation, queryTarget, queryType, queryVrf } = useLGState();
-
- const getDevice = useDevice();
-
- // Scroll to the top of the page when results load - primarily for mobile.
- useEffect(() => {
- if (typeof window !== 'undefined') {
- window.scrollTo(0, 0);
- }
- }, []);
-
- return (
- <>
-
-
-
-
- {queryLocation.value &&
- queryLocation.map((loc, i) => {
- const device = getDevice(loc.value);
- return (
-
- );
- })}
-
-
-
- >
- );
-};
diff --git a/hyperglass/ui/components/results/guards.ts b/hyperglass/ui/components/results/guards.ts
deleted file mode 100644
index 5000fe8..0000000
--- a/hyperglass/ui/components/results/guards.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/* eslint @typescript-eslint/no-explicit-any: 0 */
-/* eslint @typescript-eslint/explicit-module-boundary-types: 0 */
-
-export function isStackError(error: any): error is Error {
- return typeof error !== 'undefined' && error !== null && 'message' in error;
-}
-
-export function isFetchError(error: any): error is Response {
- return typeof error !== 'undefined' && error !== null && 'statusText' in error;
-}
-
-export function isLGError(error: any): error is TQueryResponse {
- return typeof error !== 'undefined' && error !== null && 'output' in error;
-}
-
-/**
- * Returns true if the response is an LG error, false if not.
- */
-export function isLGOutputOrError(data: any): data is TQueryResponse {
- return typeof data !== 'undefined' && data !== null && data?.level !== 'success';
-}
diff --git a/hyperglass/ui/components/results/header.tsx b/hyperglass/ui/components/results/header.tsx
deleted file mode 100644
index 070dbf2..0000000
--- a/hyperglass/ui/components/results/header.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-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';
-import { useOpposingColor, useStrf } from '~/hooks';
-
-import type { TResultHeader } from './types';
-
-const runtimeText = (runtime: number, text: string): string => {
- let unit = 'seconds';
- if (runtime === 1) {
- unit = 'second';
- }
- return `${text} ${unit}`;
-};
-
-export const ResultHeader: React.FC = (props: TResultHeader) => {
- const { title, loading, isError, errorMsg, errorLevel, runtime } = props;
-
- const status = useColorValue('primary.500', 'primary.300');
- const warning = useColorValue(`${errorLevel}.500`, `${errorLevel}.300`);
- const defaultStatus = useColorValue('success.500', 'success.300');
-
- const { web } = useConfig();
- const text = useStrf(web.text.complete_time, { seconds: runtime }, [runtime]);
- const label = useMemo(() => runtimeText(runtime, text), [runtime]);
-
- const color = useOpposingColor(isError ? warning : defaultStatus);
-
- return (
-
-
-
- {loading ? (
-
- ) : (
-
- )}
-
-
-
- {title}
-
-
- );
-};
diff --git a/hyperglass/ui/components/results/index.ts b/hyperglass/ui/components/results/index.ts
deleted file mode 100644
index 8a78f59..0000000
--- a/hyperglass/ui/components/results/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './group';
diff --git a/hyperglass/ui/components/results/individual.tsx b/hyperglass/ui/components/results/individual.tsx
deleted file mode 100644
index a5d52cb..0000000
--- a/hyperglass/ui/components/results/individual.tsx
+++ /dev/null
@@ -1,258 +0,0 @@
-import { forwardRef, useEffect, useMemo } from 'react';
-import {
- Box,
- Flex,
- chakra,
- Icon,
- Alert,
- HStack,
- Tooltip,
- AccordionItem,
- AccordionPanel,
- useAccordionContext,
- AccordionButton,
-} from '@chakra-ui/react';
-import { motion } from 'framer-motion';
-import { BsLightningFill } from '@meronex/icons/bs';
-import { startCase } from 'lodash';
-import { BGPTable, Countdown, TextOutput, If, Path } from '~/components';
-import { useColorValue, useConfig, useMobile } from '~/context';
-import { useStrf, useLGQuery, useLGState, useTableToString } from '~/hooks';
-import { isStructuredOutput, isStringOutput } from '~/types';
-import { isStackError, isFetchError, isLGError, isLGOutputOrError } from './guards';
-import { RequeryButton } from './requeryButton';
-import { CopyButton } from './copyButton';
-import { FormattedError } from './error';
-import { ResultHeader } from './header';
-
-import type { TResult, TErrorLevels } from './types';
-
-const AnimatedAccordionItem = motion(AccordionItem);
-
-const AccordionHeaderWrapper = chakra('div', {
- baseStyle: {
- display: 'flex',
- justifyContent: 'space-between',
- _hover: { bg: 'blackAlpha.50' },
- _focus: { boxShadow: 'outline' },
- },
-});
-
-const _Result: React.ForwardRefRenderFunction = (props: TResult, ref) => {
- const { index, device, queryVrf, queryType, queryTarget, queryLocation } = props;
-
- const { web, cache, messages } = useConfig();
- const { index: indices, setIndex } = useAccordionContext();
-
- const isMobile = useMobile();
- const color = useColorValue('black', 'white');
- const scrollbar = useColorValue('blackAlpha.300', 'whiteAlpha.300');
- const scrollbarHover = useColorValue('blackAlpha.400', 'whiteAlpha.400');
- const scrollbarBg = useColorValue('blackAlpha.50', 'whiteAlpha.50');
-
- const { responses } = useLGState();
-
- const { data, error, isError, isLoading, refetch, isFetching, isFetchedAfterMount } = useLGQuery({
- queryLocation,
- queryTarget,
- queryType,
- queryVrf,
- });
-
- const isCached = useMemo(() => data?.cached || !isFetchedAfterMount, [
- data,
- isLoading,
- isFetching,
- ]);
-
- if (typeof data !== 'undefined') {
- responses.merge({ [device._id]: data });
- }
-
- const cacheLabel = useStrf(web.text.cache_icon, { time: data?.timestamp }, [data?.timestamp]);
-
- const errorKeywords = useMemo(() => {
- let kw = [] as string[];
- if (isLGError(data)) {
- kw = data.keywords;
- }
- return kw;
- }, [data]);
-
- // Parse the the response and/or the error to determine from where to extract the error message.
- const errorMsg = useMemo(() => {
- if (isLGError(error)) {
- return error.output as string;
- } else if (isLGOutputOrError(data)) {
- return data.output as string;
- } else if (isFetchError(error)) {
- return startCase(error.statusText);
- } else if (isStackError(error) && error.message.toLowerCase().startsWith('timeout')) {
- return messages.request_timeout;
- } else if (isStackError(error)) {
- return startCase(error.message);
- } else {
- return messages.general;
- }
- }, [isError, error, data]);
-
- isError && console.error(error);
-
- const errorLevel = useMemo(() => {
- const statusMap = {
- success: 'success',
- warning: 'warning',
- error: 'warning',
- danger: 'error',
- } as { [k in TResponseLevel]: 'success' | 'warning' | 'error' };
-
- let e: TErrorLevels = 'error';
-
- if (isLGError(error)) {
- const idx = error.level as TResponseLevel;
- e = statusMap[idx];
- }
- return e;
- }, [isError, isLoading, data]);
-
- const tableComponent = useMemo(() => {
- let result = false;
- if (typeof queryType.match(/^bgp_\w+$/) !== null && data?.format === 'application/json') {
- result = true;
- }
- return result;
- }, [queryType, data?.format]);
-
- let copyValue = data?.output as string;
-
- const formatData = useTableToString(queryTarget, data, [data?.format]);
-
- if (data?.format === 'application/json') {
- copyValue = formatData();
- }
-
- if (error) {
- copyValue = errorMsg;
- }
-
- // Signal to the group that this result is done loading.
- useEffect(() => {
- // Only set the index if it's not already set and the query is finished loading.
- if (Array.isArray(indices) && indices.length === 0 && !isLoading) {
- // Only set the index if the response has data or an error.
- if (data || isError) {
- setIndex([index]);
- }
- }
- }, [data, isError]);
-
- return (
-
- <>
-
-
-
-
-
- {isStructuredOutput(data) && data.level === 'success' && tableComponent && (
-
- )}
-
-
-
-
-
-
-
- {!isError && typeof data !== 'undefined' ? (
- <>
- {isStructuredOutput(data) && data.level === 'success' && tableComponent ? (
- {data.output}
- ) : isStringOutput(data) && data.level === 'success' && !tableComponent ? (
- {data.output}
- ) : isStringOutput(data) && data.level !== 'success' ? (
-
-
-
- ) : (
-
-
-
- )}
- >
- ) : (
-
-
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
-
- );
-};
-
-export const Result = forwardRef(_Result);
diff --git a/hyperglass/ui/components/results/requeryButton.tsx b/hyperglass/ui/components/results/requeryButton.tsx
deleted file mode 100644
index 1a691a2..0000000
--- a/hyperglass/ui/components/results/requeryButton.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { forwardRef } from 'react';
-import dynamic from 'next/dynamic';
-import { Button, Icon, Tooltip } from '@chakra-ui/react';
-
-import type { TRequeryButton } from './types';
-
-const Repeat = dynamic(() => import('@meronex/icons/fi').then(i => i.FiRepeat));
-
-const _RequeryButton: React.ForwardRefRenderFunction = (
- props: TRequeryButton,
- ref,
-) => {
- const { requery, ...rest } = props;
-
- return (
-
-
-
- );
-};
-
-export const RequeryButton = forwardRef(_RequeryButton);
diff --git a/hyperglass/ui/components/results/tags.tsx b/hyperglass/ui/components/results/tags.tsx
deleted file mode 100644
index 26de570..0000000
--- a/hyperglass/ui/components/results/tags.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-import { Box, Stack, useToken } from '@chakra-ui/react';
-import { motion, AnimatePresence } from 'framer-motion';
-import { Label } from '~/components';
-import { useConfig, useBreakpointValue } from '~/context';
-import { useLGState, useVrf } from '~/hooks';
-import { isQueryType } from '~/types';
-
-import type { Transition } from 'framer-motion';
-
-const transition = { duration: 0.3, delay: 0.5 } as Transition;
-
-export const Tags: React.FC = () => {
- const { queries, web } = useConfig();
- const { queryLocation, queryTarget, queryType, queryVrf } = useLGState();
-
- const targetBg = useToken('colors', 'teal.600');
- const queryBg = useToken('colors', 'cyan.500');
- const vrfBg = useToken('colors', 'blue.500');
-
- const animateLeft = useBreakpointValue({
- base: { opacity: 1, x: 0 },
- md: { opacity: 1, x: 0 },
- lg: { opacity: 1, x: 0 },
- xl: { opacity: 1, x: 0 },
- });
-
- const animateCenter = useBreakpointValue({
- base: { opacity: 1 },
- md: { opacity: 1 },
- lg: { opacity: 1 },
- xl: { opacity: 1 },
- });
-
- const animateRight = useBreakpointValue({
- base: { opacity: 1, x: 0 },
- md: { opacity: 1, x: 0 },
- lg: { opacity: 1, x: 0 },
- xl: { opacity: 1, x: 0 },
- });
-
- const initialLeft = useBreakpointValue({
- base: { opacity: 0, x: '-100%' },
- md: { opacity: 0, x: '-100%' },
- lg: { opacity: 0, x: '-100%' },
- xl: { opacity: 0, x: '-100%' },
- });
-
- const initialCenter = useBreakpointValue({
- base: { opacity: 0 },
- md: { opacity: 0 },
- lg: { opacity: 0 },
- xl: { opacity: 0 },
- });
-
- const initialRight = useBreakpointValue({
- base: { opacity: 0, x: '100%' },
- md: { opacity: 0, x: '100%' },
- lg: { opacity: 0, x: '100%' },
- xl: { opacity: 0, x: '100%' },
- });
-
- let queryTypeLabel = '';
- if (isQueryType(queryType.value)) {
- queryTypeLabel = queries[queryType.value].display_name;
- }
-
- const getVrf = useVrf();
- const vrf = getVrf(queryVrf.value);
-
- return (
-
-
-
- {queryLocation.value && (
- <>
-
-
-
-
-
-
-
-
-
- >
- )}
-
-
-
- );
-};
diff --git a/hyperglass/ui/components/results/types.ts b/hyperglass/ui/components/results/types.ts
deleted file mode 100644
index 10efab5..0000000
--- a/hyperglass/ui/components/results/types.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import type { State } from '@hookstate/core';
-import type { ButtonProps } from '@chakra-ui/react';
-import type { UseQueryResult } from 'react-query';
-import type { TDevice, TQueryTypes } from '~/types';
-
-export interface TResultHeader {
- title: string;
- loading: boolean;
- isError?: boolean;
- errorMsg: string;
- errorLevel: 'success' | 'warning' | 'error';
- runtime: number;
-}
-
-export interface TFormattedError {
- keywords: string[];
- message: string;
-}
-
-export interface TResult {
- index: number;
- device: TDevice;
- queryVrf: string;
- queryTarget: string;
- queryLocation: string;
- queryType: TQueryTypes;
-}
-
-export type TErrorLevels = 'success' | 'warning' | 'error';
-
-export interface TCopyButton extends ButtonProps {
- copyValue: string;
-}
-
-export interface TRequeryButton extends ButtonProps {
- requery: UseQueryResult['refetch'];
-}
-
-export type TUseResults = {
- firstOpen: number | null;
- locations: { [k: string]: { complete: boolean; open: boolean; index: number } };
-};
-
-export type TUseResultsMethods = {
- toggle(loc: string): void;
- setComplete(loc: string): void;
- getOpen(): number[];
-};
-
-export type UseResultsReturn = {
- results: State;
-} & TUseResultsMethods;
diff --git a/hyperglass/ui/components/results/useResults.ts b/hyperglass/ui/components/results/useResults.ts
deleted file mode 100644
index 63fb6cf..0000000
--- a/hyperglass/ui/components/results/useResults.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-import { useEffect } from 'react';
-import { createState, useState } from '@hookstate/core';
-
-import type { Plugin, State, PluginStateControl } from '@hookstate/core';
-import type { TUseResults, TUseResultsMethods, UseResultsReturn } from './types';
-
-const MethodsId = Symbol('UseResultsMethods');
-
-/**
- * Plugin methods.
- */
-class MethodsInstance {
- /**
- * Toggle a location's open/closed state.
- */
- public toggle(state: State, loc: string) {
- state.locations[loc].open.set(p => !p);
- }
- /**
- * Set a location's completion state.
- */
- public setComplete(state: State, loc: string) {
- state.locations[loc].merge({ complete: true });
- const thisLoc = state.locations[loc];
- if (
- state.firstOpen.value === null &&
- state.locations.keys.includes(loc) &&
- state.firstOpen.value !== thisLoc.index.value
- ) {
- state.firstOpen.set(thisLoc.index.value);
- this.toggle(state, loc);
- }
- }
- /**
- * Get the currently open panels. Passed to Chakra UI's index prop for internal state management.
- */
- public getOpen(state: State) {
- const open = state.locations.keys
- .filter(k => state.locations[k].complete.value && state.locations[k].open.value)
- .map(k => state.locations[k].index.value);
- return open;
- }
-}
-
-/**
- * hookstate plugin to provide convenience functions & tracking for the useResults hook.
- */
-function Methods(inst?: State): Plugin | TUseResultsMethods {
- if (inst) {
- const [instance] = inst.attach(MethodsId) as [
- MethodsInstance | Error,
- PluginStateControl,
- ];
-
- if (instance instanceof Error) {
- throw instance;
- }
-
- return {
- toggle: (loc: string) => instance.toggle(inst, loc),
- setComplete: (loc: string) => instance.setComplete(inst, loc),
- getOpen: () => instance.getOpen(inst),
- } as TUseResultsMethods;
- }
- return {
- id: MethodsId,
- init: () => {
- /* eslint @typescript-eslint/ban-types: 0 */
- return new MethodsInstance() as {};
- },
- } as Plugin;
-}
-const initialState = { firstOpen: null, locations: {} } as TUseResults;
-const resultsState = createState(initialState);
-
-/**
- * Track the state of each result, and whether or not each panel is open.
- */
-export function useResults(initial: TUseResults['locations']): UseResultsReturn {
- // Initialize the global state before instantiating the hook, only once.
- useEffect(() => {
- if (resultsState.firstOpen.value === null && resultsState.locations.keys.length === 0) {
- resultsState.set({ firstOpen: null, locations: initial });
- }
- }, []);
-
- const results = useState(resultsState);
- results.attach(Methods as () => Plugin);
-
- const methods = Methods(results) as TUseResultsMethods;
-
- // Reset the state on unmount.
- useEffect(() => {
- return () => {
- results.set(initialState);
- };
- }, []);
-
- return { results, ...methods };
-}
diff --git a/hyperglass/ui/components/select/index.ts b/hyperglass/ui/components/select/index.ts
deleted file mode 100644
index c739673..0000000
--- a/hyperglass/ui/components/select/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './select';
diff --git a/hyperglass/ui/components/select/select.tsx b/hyperglass/ui/components/select/select.tsx
deleted file mode 100644
index 1f73afc..0000000
--- a/hyperglass/ui/components/select/select.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-import { createContext, useContext, useMemo } from 'react';
-import ReactSelect from 'react-select';
-import { chakra, useDisclosure } from '@chakra-ui/react';
-import { useColorMode } from '~/context';
-import {
- useRSTheme,
- useMenuStyle,
- useMenuPortal,
- useOptionStyle,
- useControlStyle,
- useMenuListStyle,
- useMultiValueStyle,
- usePlaceholderStyle,
- useSingleValueStyle,
- useMultiValueLabelStyle,
- useMultiValueRemoveStyle,
- useIndicatorSeparatorStyle,
-} from './styles';
-
-import type { TSelectOption } from '~/types';
-import type { TSelectBase, TSelectContext, TReactSelectChakra } from './types';
-
-const SelectContext = createContext(Object());
-export const useSelectContext = (): TSelectContext => useContext(SelectContext);
-
-const ReactSelectChakra = chakra(ReactSelect);
-
-export const Select: React.FC = (props: TSelectBase) => {
- const { options, multi, onSelect, isError = false, ...rest } = props;
- const { isOpen, onOpen, onClose } = useDisclosure();
-
- const { colorMode } = useColorMode();
-
- const selectContext = useMemo(() => ({ colorMode, isOpen, isError }), [
- colorMode,
- isError,
- isOpen,
- ]);
-
- const defaultOnChange = (changed: TSelectOption | TSelectOption[]) => {
- if (!Array.isArray(changed)) {
- changed = [changed];
- }
- if (typeof onSelect === 'function') {
- onSelect(changed);
- }
- };
-
- const multiValue = useMultiValueStyle({ colorMode });
- const multiValueLabel = useMultiValueLabelStyle({ colorMode });
- const multiValueRemove = useMultiValueRemoveStyle({ colorMode });
- const menuPortal = useMenuPortal();
- const rsTheme = useRSTheme();
-
- return (
-
-
-
- );
-};
diff --git a/hyperglass/ui/components/select/styles.tsx b/hyperglass/ui/components/select/styles.tsx
deleted file mode 100644
index 0dfc6e1..0000000
--- a/hyperglass/ui/components/select/styles.tsx
+++ /dev/null
@@ -1,194 +0,0 @@
-import { useCallback, useMemo } from 'react';
-import { useToken } from '@chakra-ui/react';
-import { mergeWith } from '@chakra-ui/utils';
-import { useOpposingColor } from '~/hooks';
-import { useColorValue, useColorToken, useMobile } from '~/context';
-import { useSelectContext } from './select';
-
-import type {
- TMenu,
- TOption,
- TStyles,
- TControl,
- TRSTheme,
- TMultiValue,
- TRSThemeCallback,
- TRSStyleCallback,
-} from './types';
-
-export const useControlStyle = (base: TStyles, state: TControl): TStyles => {
- const { isFocused } = state;
- const { colorMode, isError } = useSelectContext();
-
- const minHeight = useToken('space', 12);
- const borderRadius = useToken('radii', 'md');
- const color = useColorToken('colors', 'black', 'whiteAlpha.800');
- const focusBorder = useColorToken('colors', 'blue.500', 'blue.300');
- const invalidBorder = useColorToken('colors', 'red.500', 'red.300');
- const borderColor = useColorToken('colors', 'gray.100', 'whiteAlpha.50');
- const borderHover = useColorToken('colors', 'gray.300', 'whiteAlpha.400');
- const backgroundColor = useColorToken('colors', 'white', 'whiteAlpha.100');
-
- const styles = {
- backgroundColor,
- borderRadius,
- color,
- minHeight,
- transition: 'all 0.2s',
- 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: isError ? invalidBorder : focusBorder },
- '&.invalid': { borderColor: invalidBorder, boxShadow: `0 0 0 1px ${invalidBorder}` },
- };
- return useMemo(() => mergeWith({}, base, styles), [colorMode, isFocused, isError]);
-};
-
-export const useMenuStyle = (base: TStyles, _: TMenu): TStyles => {
- const { colorMode, isOpen } = useSelectContext();
- const backgroundColor = useColorToken('colors', 'white', 'blackSolid.700');
- const styles = { backgroundColor };
- return useMemo(() => mergeWith({}, base, styles), [colorMode, isOpen]);
-};
-
-export const useMenuListStyle = (base: TStyles): TStyles => {
- const { colorMode, isOpen } = useSelectContext();
- const borderRadius = useToken('radii', 'md');
- const backgroundColor = useColorToken('colors', 'white', 'blackSolid.700');
- const scrollbarTrack = useColorToken('colors', 'blackAlpha.50', 'whiteAlpha.50');
- const scrollbarThumb = useColorToken('colors', 'blackAlpha.300', 'whiteAlpha.300');
- const scrollbarThumbHover = useColorToken('colors', 'blackAlpha.400', 'whiteAlpha.400');
-
- const styles = {
- borderRadius,
- backgroundColor,
- '&::-webkit-scrollbar': { width: '5px' },
- '&::-webkit-scrollbar-track': { backgroundColor: scrollbarTrack },
- '&::-webkit-scrollbar-thumb': { backgroundColor: scrollbarThumb },
- '&::-webkit-scrollbar-thumb:hover': { backgroundColor: scrollbarThumbHover },
- '-ms-overflow-style': { display: 'none' },
- };
- return useMemo(() => mergeWith({}, base, styles), [colorMode, isOpen]);
-};
-
-export const useOptionStyle = (base: TStyles, state: TOption): TStyles => {
- const { isFocused, isSelected, isDisabled } = state;
- const { colorMode, isOpen } = useSelectContext();
-
- const fontSize = useToken('fontSizes', 'lg');
- const disabled = useToken('colors', 'whiteAlpha.400');
- const active = useColorToken('colors', 'primary.600', 'primary.400');
- const focused = useColorToken('colors', 'primary.500', 'primary.300');
- const selected = useColorToken('colors', 'blackAlpha.400', 'whiteAlpha.400');
-
- const activeColor = useOpposingColor(active);
-
- const backgroundColor = useMemo(() => {
- let bg = 'transparent';
- switch (true) {
- case isDisabled:
- bg = disabled;
- break;
- case isSelected:
- bg = selected;
- break;
- case isFocused:
- bg = focused;
- break;
- }
- return bg;
- }, [isDisabled, isFocused, isSelected]);
-
- const color = useOpposingColor(backgroundColor);
-
- const styles = {
- color: backgroundColor === 'transparent' ? 'currentColor' : color,
- '&:active': { backgroundColor: active, color: activeColor },
- '&:focus': { backgroundColor: active, color: activeColor },
- backgroundColor,
- fontSize,
- };
-
- return useMemo(() => mergeWith({}, base, styles), [
- isOpen,
- colorMode,
- isFocused,
- isDisabled,
- isSelected,
- ]);
-};
-
-export const useIndicatorSeparatorStyle = (base: TStyles): TStyles => {
- const { colorMode } = useSelectContext();
- const backgroundColor = useColorToken('colors', 'whiteAlpha.700', 'gray.600');
- const styles = { backgroundColor };
- return useMemo(() => mergeWith({}, base, styles), [colorMode]);
-};
-
-export const usePlaceholderStyle = (base: TStyles): TStyles => {
- const { colorMode } = useSelectContext();
- const color = useColorToken('colors', 'gray.600', 'whiteAlpha.700');
- const fontSize = useToken('fontSizes', 'lg');
- return useMemo(() => mergeWith({}, base, { color, fontSize }), [colorMode]);
-};
-
-export const useSingleValueStyle = (): TRSStyleCallback => {
- const { colorMode } = useSelectContext();
-
- const color = useColorValue('black', 'whiteAlpha.800');
- const fontSize = useToken('fontSizes', 'lg');
-
- const styles = { color, fontSize };
- return useCallback((base: TStyles) => mergeWith({}, base, styles), [color, colorMode]);
-};
-
-export const useMultiValueStyle = (props: TMultiValue): TRSStyleCallback => {
- const { colorMode } = props;
-
- const backgroundColor = useColorToken('colors', 'primary.500', 'primary.300');
- const color = useOpposingColor(backgroundColor);
-
- const styles = { backgroundColor, color };
- return useCallback((base: TStyles) => mergeWith({}, base, styles), [backgroundColor, colorMode]);
-};
-
-export const useMultiValueLabelStyle = (props: TMultiValue): TRSStyleCallback => {
- const { colorMode } = props;
-
- const backgroundColor = useColorToken('colors', 'primary.500', 'primary.300');
- const color = useOpposingColor(backgroundColor);
-
- const styles = { color };
- return useCallback((base: TStyles) => mergeWith({}, base, styles), [colorMode]);
-};
-
-export const useMultiValueRemoveStyle = (props: TMultiValue): TRSStyleCallback => {
- const { colorMode } = props;
-
- const backgroundColor = useColorToken('colors', 'primary.500', 'primary.300');
- const color = useOpposingColor(backgroundColor);
-
- const styles = {
- color,
- '&:hover': { backgroundColor: 'inherit', color, opacity: 0.7 },
- };
- return useCallback((base: TStyles) => mergeWith({}, base, styles), [colorMode]);
-};
-
-export const useRSTheme = (): TRSThemeCallback => {
- const borderRadius = useToken('radii', 'md');
- return useCallback((t: TRSTheme): TRSTheme => ({ ...t, borderRadius }), []);
-};
-
-export const useMenuPortal = (): TRSStyleCallback => {
- const isMobile = useMobile();
- const styles = {
- zIndex: isMobile ? 1500 : 1,
- };
- return useCallback((base: TStyles) => mergeWith({}, base, styles), [isMobile]);
-};
diff --git a/hyperglass/ui/components/select/types.ts b/hyperglass/ui/components/select/types.ts
deleted file mode 100644
index d717a7a..0000000
--- a/hyperglass/ui/components/select/types.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-/* eslint @typescript-eslint/no-explicit-any: 0 */
-/* eslint @typescript-eslint/explicit-module-boundary-types: 0 */
-
-import type {
- Props as IReactSelect,
- ControlProps,
- MenuProps,
- MenuListComponentProps,
- OptionProps,
- MultiValueProps,
- IndicatorProps,
- Theme as RSTheme,
- PlaceholderProps,
- Styles as RSStyles,
-} from 'react-select';
-import type { BoxProps } from '@chakra-ui/react';
-import type { Theme, TSelectOption, TSelectOptionMulti, TSelectOptionGroup } from '~/types';
-
-export interface TSelectState {
- [k: string]: string[];
-}
-
-export type TOptions = Array;
-
-export type TReactSelectChakra = Omit &
- Omit;
-
-export interface TSelectBase extends TReactSelectChakra {
- name: string;
- multi?: boolean;
- isError?: boolean;
- options: TOptions;
- required?: boolean;
- onSelect?: (s: TSelectOption[]) => void;
- onChange?: (c: TSelectOption | TSelectOptionMulti) => void;
- colorScheme?: Theme.ColorNames;
-}
-
-export interface TSelectContext {
- colorMode: 'light' | 'dark';
- isOpen: boolean;
- isError: boolean;
-}
-
-export interface TMultiValueRemoveProps {
- children: Node;
- data: any;
- innerProps: {
- className: string;
- onTouchEnd: (e: any) => void;
- onClick: (e: any) => void;
- onMouseDown: (e: any) => void;
- };
- selectProps: any;
-}
-
-export interface TRSTheme extends Omit {
- borderRadius: string | number;
-}
-
-export type TControl = ControlProps;
-
-export type TMenu = MenuProps;
-
-export type TMenuList = MenuListComponentProps;
-
-export type TOption = OptionProps;
-
-export type TMultiValueState = MultiValueProps;
-
-export type TIndicator = IndicatorProps;
-
-export type TPlaceholder = PlaceholderProps;
-
-export type TMultiValue = Pick;
-
-export type TRSStyleCallback = (base: TStyles) => TStyles;
-
-export type TRSThemeCallback = (theme: TRSTheme) => TRSTheme;
-
-export type TStyles = RSStyles;
diff --git a/hyperglass/ui/components/submit/index.ts b/hyperglass/ui/components/submit/index.ts
deleted file mode 100644
index e9be2e3..0000000
--- a/hyperglass/ui/components/submit/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './submit';
diff --git a/hyperglass/ui/components/submit/submit.tsx b/hyperglass/ui/components/submit/submit.tsx
deleted file mode 100644
index 4e718e8..0000000
--- a/hyperglass/ui/components/submit/submit.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-import { forwardRef } from 'react';
-import {
- Modal,
- Popover,
- ModalBody,
- IconButton,
- PopoverBody,
- ModalOverlay,
- ModalContent,
- PopoverArrow,
- PopoverTrigger,
- PopoverContent,
- ModalCloseButton,
- PopoverCloseButton,
-} from '@chakra-ui/react';
-import { FiSearch } from '@meronex/icons/fi';
-import { useFormContext } from 'react-hook-form';
-import { If, ResolvedTarget } from '~/components';
-import { useMobile, useColorValue } from '~/context';
-import { useLGState, useLGMethods } from '~/hooks';
-
-import type { IconButtonProps } from '@chakra-ui/react';
-import type { TSubmitButton, TRSubmitButton } from './types';
-
-const _SubmitIcon: React.ForwardRefRenderFunction<
- HTMLButtonElement,
- Omit
-> = (props: Omit, ref) => {
- const { isLoading, ...rest } = props;
- return (
- }
- title="Submit Query"
- colorScheme="primary"
- isLoading={isLoading}
- aria-label="Submit Query"
- {...rest}
- />
- );
-};
-const SubmitIcon = forwardRef>(_SubmitIcon);
-
-/**
- * Mobile Submit Button
- */
-const MSubmitButton: React.FC = (props: TRSubmitButton) => {
- const { children, isOpen, onClose, onChange } = props;
- const bg = useColorValue('white', 'gray.900');
- return (
- <>
- {children}
-
-
-
-
-
- {isOpen && }
-
-
-
- >
- );
-};
-
-/**
- * Desktop Submit Button
- */
-const DSubmitButton: React.FC = (props: TRSubmitButton) => {
- const { children, isOpen, onClose, onChange } = props;
- const bg = useColorValue('white', 'gray.900');
- return (
-
- {children}
-
-
-
-
- {isOpen && }
-
-
-
- );
-};
-
-export const SubmitButton: React.FC = (props: TSubmitButton) => {
- const { handleChange } = props;
- const isMobile = useMobile();
- const { resolvedIsOpen, btnLoading } = useLGState();
- const { resolvedClose, resetForm } = useLGMethods();
-
- const { reset } = useFormContext();
-
- function handleClose(): void {
- reset();
- resetForm();
- resolvedClose();
- }
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
- >
- );
-};
diff --git a/hyperglass/ui/components/submit/types.ts b/hyperglass/ui/components/submit/types.ts
deleted file mode 100644
index 91ca90b..0000000
--- a/hyperglass/ui/components/submit/types.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import type { IconButtonProps } from '@chakra-ui/react';
-import type { OnChangeArgs } from '~/types';
-
-export interface TSubmitButton extends Omit {
- handleChange(e: OnChangeArgs): void;
-}
-
-export interface TRSubmitButton {
- isOpen: boolean;
- onClose(): void;
- onChange(e: OnChangeArgs): void;
- children: React.ReactNode;
-}
diff --git a/hyperglass/ui/components/table/body.tsx b/hyperglass/ui/components/table/body.tsx
deleted file mode 100644
index 2d62a4f..0000000
--- a/hyperglass/ui/components/table/body.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Box } from '@chakra-ui/react';
-
-import type { BoxProps } from '@chakra-ui/react';
-
-export const TableBody: React.FC = (props: BoxProps) => (
-
-);
diff --git a/hyperglass/ui/components/table/button.tsx b/hyperglass/ui/components/table/button.tsx
deleted file mode 100644
index a4e1553..0000000
--- a/hyperglass/ui/components/table/button.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import { IconButton } from '@chakra-ui/react';
-
-import type { TTableIconButton } from './types';
-
-export const TableIconButton: React.FC = (props: TTableIconButton) => (
-
-);
diff --git a/hyperglass/ui/components/table/cell.tsx b/hyperglass/ui/components/table/cell.tsx
deleted file mode 100644
index 618d094..0000000
--- a/hyperglass/ui/components/table/cell.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { Box } from '@chakra-ui/react';
-import { useColorValue } from '~/context';
-
-import type { TTableCell } from './types';
-
-export const TableCell: React.FC = (props: TTableCell) => {
- const { bordersVertical = [false, 0], align, ...rest } = props;
- const [doVerticalBorders, index] = bordersVertical;
- const borderLeftColor = useColorValue('blackAlpha.100', 'whiteAlpha.100');
-
- let borderProps = {};
- if (doVerticalBorders && index !== 0) {
- borderProps = { borderLeft: '1px solid', borderLeftColor };
- }
-
- return (
-
- );
-};
diff --git a/hyperglass/ui/components/table/head.tsx b/hyperglass/ui/components/table/head.tsx
deleted file mode 100644
index 37abe0f..0000000
--- a/hyperglass/ui/components/table/head.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { Box } from '@chakra-ui/react';
-import { useColorValue } from '~/context';
-
-import type { BoxProps } from '@chakra-ui/react';
-
-export const TableHead: React.FC = (props: BoxProps) => {
- const bg = useColorValue('blackAlpha.100', 'whiteAlpha.100');
- return ;
-};
diff --git a/hyperglass/ui/components/table/index.ts b/hyperglass/ui/components/table/index.ts
deleted file mode 100644
index 7285324..0000000
--- a/hyperglass/ui/components/table/index.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export * from './body';
-export * from './button';
-export * from './cell';
-export * from './head';
-export * from './main';
-export * from './main';
-export * from './pageSelect';
-export * from './row';
diff --git a/hyperglass/ui/components/table/main.tsx b/hyperglass/ui/components/table/main.tsx
deleted file mode 100644
index 41bd90a..0000000
--- a/hyperglass/ui/components/table/main.tsx
+++ /dev/null
@@ -1,208 +0,0 @@
-// This rule isn't needed because react-table does this for us, for better or worse.
-/* eslint react/jsx-key: 0 */
-
-import dynamic from 'next/dynamic';
-import { Flex, Icon, Text } from '@chakra-ui/react';
-import { usePagination, useSortBy, useTable } from 'react-table';
-import { useMobile } from '~/context';
-import { CardBody, CardFooter, CardHeader, If } from '~/components';
-import { TableMain } from './table';
-import { TableCell } from './cell';
-import { TableHead } from './head';
-import { TableRow } from './row';
-import { TableBody } from './body';
-import { TableIconButton } from './button';
-import { TableSelectShow } from './pageSelect';
-
-import type { TableOptions, PluginHook } from 'react-table';
-import type { TCellRender } from '~/types';
-import type { TTable } from './types';
-
-const ChevronRight = dynamic(() =>
- import('@meronex/icons/fa').then(i => i.FaChevronRight),
-);
-
-const ChevronLeft = dynamic(() =>
- import('@meronex/icons/fa').then(i => i.FaChevronLeft),
-);
-
-const ChevronDown = dynamic(() =>
- import('@meronex/icons/fa').then(i => i.FaChevronDown),
-);
-
-const DoubleChevronRight = dynamic(() =>
- import('@meronex/icons/fi').then(i => i.FiChevronsRight),
-);
-const DoubleChevronLeft = dynamic(() =>
- import('@meronex/icons/fi').then(i => i.FiChevronsLeft),
-);
-
-export const Table: React.FC = (props: TTable) => {
- const {
- data,
- columns,
- heading,
- Cell,
- rowHighlightBg,
- striped = false,
- rowHighlightProp,
- bordersVertical = false,
- bordersHorizontal = false,
- } = props;
-
- const isMobile = useMobile();
-
- const defaultColumn = {
- minWidth: 100,
- width: 150,
- maxWidth: 300,
- };
-
- const hiddenColumns = [] as string[];
-
- for (const col of columns) {
- if (col.hidden) {
- hiddenColumns.push(col.accessor);
- }
- }
-
- const options = {
- columns,
- defaultColumn,
- data,
- initialState: { hiddenColumns },
- } as TableOptions;
-
- const plugins = [useSortBy, usePagination] as PluginHook[];
-
- const instance = useTable(options, ...plugins);
-
- const {
- page,
- gotoPage,
- nextPage,
- pageCount,
- prepareRow,
- canNextPage,
- pageOptions,
- setPageSize,
- headerGroups,
- previousPage,
- getTableProps,
- canPreviousPage,
- state: { pageIndex, pageSize },
- } = instance;
-
- return (
-
- {heading && {heading}}
-
-
- {headerGroups.map((headerGroup, i) => (
-
- {headerGroup.headers.map(column => (
-
-
- {column.render('Header')}
-
-
-
-
-
-
-
-
-
- {''}
-
- ))}
-
- ))}
-
-
- {page.map((row, key) => {
- prepareRow(row);
- return (
-
- {row.cells.map((cell, i) => {
- const { column, row, value } = cell as TCellRender;
- return (
-
- {typeof Cell !== 'undefined' ? (
- |
- ) : (
- cell.render('Cell')
- )}
-
- );
- })}
-
- );
- })}
-
-
-
-
- gotoPage(0)}
- isDisabled={!canPreviousPage}
- icon={}
- />
- previousPage()}
- isDisabled={!canPreviousPage}
- icon={}
- />
-
-
-
- Page{' '}
-
- {pageIndex + 1} of {pageOptions.length}
- {' '}
-
- {!isMobile && (
- {
- setPageSize(Number(e.target.value));
- }}
- />
- )}
-
-
- }
- />
- }
- onClick={() => gotoPage(pageCount ? pageCount - 1 : 1)}
- />
-
-
-
- );
-};
diff --git a/hyperglass/ui/components/table/pageSelect.tsx b/hyperglass/ui/components/table/pageSelect.tsx
deleted file mode 100644
index fafa6d9..0000000
--- a/hyperglass/ui/components/table/pageSelect.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Select } from '@chakra-ui/react';
-import { SelectProps } from '@chakra-ui/react';
-
-export const TableSelectShow: React.FC = (props: SelectProps) => {
- const { value, ...rest } = props;
- return (
-
- );
-};
diff --git a/hyperglass/ui/components/table/row.tsx b/hyperglass/ui/components/table/row.tsx
deleted file mode 100644
index 47e4111..0000000
--- a/hyperglass/ui/components/table/row.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import { Box } from '@chakra-ui/react';
-import { useColorValue } from '~/context';
-import { useOpposingColor } from '~/hooks';
-
-import type { TTableRow } from './types';
-
-export const TableRow: React.FC = (props: TTableRow) => {
- const {
- index = 0,
- doStripe = false,
- highlight = false,
- highlightBg = 'primary',
- doHorizontalBorders = false,
- ...rest
- } = props;
-
- const alpha = useColorValue('100', '200');
- const alphaHover = useColorValue('200', '100');
- const bgStripe = useColorValue('blackAlpha.50', 'whiteAlpha.50');
- let hoverBg = useColorValue('blackAlpha.50', 'whiteAlpha.50');
- const rowBorder = useColorValue(
- { borderTop: '1px', borderTopColor: 'blackAlpha.100' },
- { borderTop: '1px', borderTopColor: 'whiteAlpha.100' },
- );
- let bg;
-
- if (highlight) {
- bg = `${String(highlightBg)}.${alpha}`;
- hoverBg = `${String(highlightBg)}.${alphaHover}`;
- } else if (doStripe && index % 2 !== 0) {
- bg = bgStripe;
- }
- const defaultBg = useColorValue('white', 'black');
- const color = useOpposingColor(bg ?? defaultBg);
- const borderProps = doHorizontalBorders && index !== 0 ? rowBorder : {};
-
- return (
- td': { color } }}
- fontWeight={highlight ? 'bold' : undefined}
- _hover={{
- cursor: 'pointer',
- backgroundColor: highlight ? `${String(highlightBg)}.${alphaHover}` : hoverBg,
- }}
- {...borderProps}
- {...rest}
- />
- );
-};
diff --git a/hyperglass/ui/components/table/table.tsx b/hyperglass/ui/components/table/table.tsx
deleted file mode 100644
index 9fb1c84..0000000
--- a/hyperglass/ui/components/table/table.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { Box } from '@chakra-ui/react';
-import { useColorValue } from '~/context';
-
-import type { BoxProps } from '@chakra-ui/react';
-
-export const TableMain: React.FC = (props: BoxProps) => {
- const scrollbar = useColorValue('blackAlpha.300', 'whiteAlpha.300');
- const scrollbarHover = useColorValue('blackAlpha.400', 'whiteAlpha.400');
- const scrollbarBg = useColorValue('blackAlpha.50', 'whiteAlpha.50');
- return (
-
- );
-};
diff --git a/hyperglass/ui/components/table/types.ts b/hyperglass/ui/components/table/types.ts
deleted file mode 100644
index 341d566..0000000
--- a/hyperglass/ui/components/table/types.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import type { BoxProps, IconButtonProps } from '@chakra-ui/react';
-
-import type { Theme, TColumn, TCellRender } from '~/types';
-
-export interface TTable {
- data: TRoute[];
- striped?: boolean;
- columns: TColumn[];
- heading?: React.ReactNode;
- bordersVertical?: boolean;
- bordersHorizontal?: boolean;
- Cell?: React.FC;
- rowHighlightProp?: keyof IRoute;
- rowHighlightBg?: Theme.ColorNames;
-}
-
-export interface TTableCell extends Omit {
- bordersVertical?: [boolean, number];
- align?: 'left' | 'right' | 'center';
-}
-
-export interface TTableRow extends BoxProps {
- highlightBg?: Theme.ColorNames;
- doHorizontalBorders?: boolean;
- highlight?: boolean;
- doStripe?: boolean;
- index: number;
-}
-
-export type TTableIconButton = Omit;
diff --git a/hyperglass/ui/components/util/animated.tsx b/hyperglass/ui/components/util/animated.tsx
deleted file mode 100644
index 901fe89..0000000
--- a/hyperglass/ui/components/util/animated.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-/* eslint react/display-name: off */
-import { Box, forwardRef } from '@chakra-ui/react';
-import { motion, isValidMotionProp } from 'framer-motion';
-
-import type { BoxProps } from '@chakra-ui/react';
-
-/**
- * Combined Chakra + Framer Motion component.
- * @see https://chakra-ui.com/guides/integrations/with-framer
- */
-export const AnimatedDiv = motion(
- forwardRef>((props, ref) => {
- const chakraProps = Object.fromEntries(
- Object.entries(props).filter(([key]) => !isValidMotionProp(key)),
- );
- return ;
- }),
-);
diff --git a/hyperglass/ui/components/util/if.tsx b/hyperglass/ui/components/util/if.tsx
deleted file mode 100644
index f518819..0000000
--- a/hyperglass/ui/components/util/if.tsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import type { TIf } from './types';
-
-export const If: React.FC = (props: TIf) => {
- const { c, children } = props;
- return c ? <>{children}> : null;
-};
diff --git a/hyperglass/ui/components/util/index.ts b/hyperglass/ui/components/util/index.ts
deleted file mode 100644
index d7a1522..0000000
--- a/hyperglass/ui/components/util/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './animated';
-export * from './if';
diff --git a/hyperglass/ui/components/util/types.ts b/hyperglass/ui/components/util/types.ts
deleted file mode 100644
index 106caa5..0000000
--- a/hyperglass/ui/components/util/types.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface TIf {
- c: boolean;
- children?: React.ReactNode;
-}
diff --git a/hyperglass/ui/context/HyperglassProvider.tsx b/hyperglass/ui/context/HyperglassProvider.tsx
deleted file mode 100644
index 0efc403..0000000
--- a/hyperglass/ui/context/HyperglassProvider.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import { createContext, useContext, useMemo } from 'react';
-import {
- useToken,
- ChakraProvider,
- useColorModeValue,
- useBreakpointValue,
- useTheme as useChakraTheme,
-} from '@chakra-ui/react';
-import { QueryClient, QueryClientProvider } from 'react-query';
-import { makeTheme, defaultTheme } from '~/util';
-
-import type { IConfig, Theme } from '~/types';
-import type { THyperglassProvider } from './types';
-
-const HyperglassContext = createContext(Object());
-
-const queryClient = new QueryClient();
-
-export const HyperglassProvider: React.FC = (props: THyperglassProvider) => {
- const { config, children } = props;
- const value = useMemo(() => config, []);
- const userTheme = value && makeTheme(value.web.theme, value.web.theme.default_color_mode);
- const theme = value ? userTheme : defaultTheme;
- return (
-
-
- {children}
-
-
- );
-};
-
-/**
- * Get the current configuration.
- */
-export const useConfig = (): IConfig => useContext(HyperglassContext);
-
-/**
- * Get the current theme object.
- */
-export const useTheme = (): Theme.Full => 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;
-
-/**
- * Convenience function to combine Chakra UI's useToken & useColorModeValue.
- */
-export const useColorToken = (
- token: keyof Theme.Full,
- light: L,
- dark: D,
-): L | D => useColorModeValue(useToken(token, light), useToken(token, dark));
-
-export {
- useColorMode,
- useBreakpointValue,
- useColorModeValue as useColorValue,
-} from '@chakra-ui/react';
diff --git a/hyperglass/ui/context/index.ts b/hyperglass/ui/context/index.ts
deleted file mode 100644
index 757b5cf..0000000
--- a/hyperglass/ui/context/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './HyperglassProvider';
diff --git a/hyperglass/ui/context/types.ts b/hyperglass/ui/context/types.ts
deleted file mode 100644
index 9168636..0000000
--- a/hyperglass/ui/context/types.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import type { State } from '@hookstate/core';
-import type { IConfig, TFormData } from '~/types';
-
-export interface THyperglassProvider {
- config: IConfig;
- children: React.ReactNode;
-}
-
-export interface TGlobalState {
- isSubmitting: boolean;
- formData: TFormData;
-}
-
-export interface TUseGlobalState {
- isSubmitting: State;
- formData: State;
- resetForm(): void;
-}
diff --git a/hyperglass/ui/hooks/index.ts b/hyperglass/ui/hooks/index.ts
deleted file mode 100644
index 882d53c..0000000
--- a/hyperglass/ui/hooks/index.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-export * from './useASNDetail';
-export * from './useBooleanValue';
-export * from './useDevice';
-export * from './useDNSQuery';
-export * from './useGoogleAnalytics';
-export * from './useGreeting';
-export * from './useLGQuery';
-export * from './useLGState';
-export * from './useOpposingColor';
-export * from './useStrf';
-export * from './useTableToString';
-export * from './useVrf';
diff --git a/hyperglass/ui/hooks/types.ts b/hyperglass/ui/hooks/types.ts
deleted file mode 100644
index 7fc3bc2..0000000
--- a/hyperglass/ui/hooks/types.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-import type { State } from '@hookstate/core';
-import type * as ReactGA from 'react-ga';
-import type {
- TDevice,
- Families,
- TFormQuery,
- TDeviceVrf,
- TQueryTypes,
- TSelectOption,
-} from '~/types';
-
-export type LGQueryKey = [string, TFormQuery];
-export type DNSQueryKey = [string, { target: string | null; family: 4 | 6 }];
-
-export interface TOpposingOptions {
- light?: string;
- dark?: string;
-}
-
-export type TUseGreetingReturn = {
- ack: State;
- isOpen: State;
- open(): void;
- close(): void;
- greetingReady(): boolean;
-};
-
-export type TUseDevice = (
- /**
- * Device's ID, e.g. the device.name field.
- */
- deviceId: string,
-) => TDevice;
-
-export type TUseVrf = (vrfId: string) => TDeviceVrf;
-
-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: 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: S): S | null;
- getResponse(d: string): TQueryResponse | null;
- resolvedClose(): void;
- resolvedOpen(): void;
- formReady(): boolean;
- resetForm(): void;
- stateExporter(o: O): O | null;
-};
-
-export type UseStrfArgs = { [k: string]: unknown } | string;
-
-export type TTableToStringFormatter =
- | ((v: string) => string)
- | ((v: number) => string)
- | ((v: number[]) => string)
- | ((v: string[]) => string)
- | ((v: boolean) => 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;
-};
-
-export type GAEffect = (ga: typeof ReactGA) => void;
-
-export interface GAReturn {
- ga: typeof ReactGA;
- initialize(trackingId: string | null, debug: boolean): void;
- trackPage(path: string): void;
- trackModal(path: string): void;
- trackEvent(event: ReactGA.EventArgs): void;
-}
diff --git a/hyperglass/ui/hooks/useASNDetail.ts b/hyperglass/ui/hooks/useASNDetail.ts
deleted file mode 100644
index 6504c35..0000000
--- a/hyperglass/ui/hooks/useASNDetail.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { useQuery } from 'react-query';
-
-import type { QueryFunctionContext, QueryObserverResult, QueryFunction } from 'react-query';
-import type { TASNQuery } from '~/types';
-
-const query: QueryFunction = async (ctx: QueryFunctionContext) => {
- const asn = ctx.queryKey;
- const res = await fetch('https://api.asrank.caida.org/v2/graphql', {
- mode: 'cors',
- method: 'POST',
- headers: { 'content-type': 'application/json' },
- /* eslint no-useless-escape: 0 */
- body: JSON.stringify({ query: `{ asn(asn:\"${asn}\"){ organization { orgName } } }` }),
- });
- return await res.json();
-};
-
-/**
- * Query the Caida AS Rank API to get an ASN's organization name for the AS Path component.
- * @see https://api.asrank.caida.org/v2/docs
- */
-export function useASNDetail(asn: string): QueryObserverResult {
- return useQuery({
- queryKey: asn,
- queryFn: query,
- refetchOnWindowFocus: false,
- refetchInterval: false,
- refetchOnMount: false,
- cacheTime: Infinity,
- });
-}
diff --git a/hyperglass/ui/hooks/useBooleanValue.ts b/hyperglass/ui/hooks/useBooleanValue.ts
deleted file mode 100644
index eb17e99..0000000
--- a/hyperglass/ui/hooks/useBooleanValue.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { useMemo } from 'react';
-
-/**
- * Track the state of a boolean and return values based on its state.
- */
-export function useBooleanValue(
- status: boolean,
- ifTrue: T,
- ifFalse: F,
-): T | F {
- return useMemo(() => {
- if (status) {
- return ifTrue;
- } else {
- return ifFalse;
- }
- }, [status]);
-}
diff --git a/hyperglass/ui/hooks/useDNSQuery.ts b/hyperglass/ui/hooks/useDNSQuery.ts
deleted file mode 100644
index cbf2c95..0000000
--- a/hyperglass/ui/hooks/useDNSQuery.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import { useQuery } from 'react-query';
-import { useConfig } from '~/context';
-import { fetchWithTimeout } from '~/util';
-import { useGoogleAnalytics } from './useGoogleAnalytics';
-
-import type { QueryFunction, QueryFunctionContext, QueryObserverResult } from 'react-query';
-import type { DnsOverHttps } from '~/types';
-import type { DNSQueryKey } from './types';
-
-/**
- * Perform a DNS over HTTPS query using the application/dns-json MIME type.
- */
-const query: QueryFunction = async (
- ctx: QueryFunctionContext,
-) => {
- const [url, { target, family }] = ctx.queryKey;
-
- const controller = new AbortController();
-
- let json;
- const type = family === 4 ? 'A' : family === 6 ? 'AAAA' : '';
-
- if (url !== null) {
- const res = await fetchWithTimeout(
- `${url}?name=${target}&type=${type}`,
- {
- headers: { accept: 'application/dns-json' },
- mode: 'cors',
- },
- 5000,
- controller,
- );
-
- json = await res.json();
- }
-
- return json;
-};
-
-/**
- * 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,
-): QueryObserverResult {
- const { cache, web } = useConfig();
- const { trackEvent } = useGoogleAnalytics();
-
- if (typeof target === 'string') {
- trackEvent({ category: 'DNS', action: 'Query', label: target, dimension1: `IPv${family}` });
- }
-
- return useQuery({
- queryKey: [web.dns_provider.url, { target, family }],
- queryFn: query,
- cacheTime: cache.timeout * 1000,
- });
-}
diff --git a/hyperglass/ui/hooks/useDevice.ts b/hyperglass/ui/hooks/useDevice.ts
deleted file mode 100644
index 09f48f2..0000000
--- a/hyperglass/ui/hooks/useDevice.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { useCallback, useMemo } from 'react';
-import { useConfig } from '~/context';
-
-import type { TDevice } from '~/types';
-import type { TUseDevice } from './types';
-
-/**
- * Get a device's configuration from the global configuration context based on its name.
- */
-export function useDevice(): TUseDevice {
- const { networks } = useConfig();
-
- const devices = useMemo(() => networks.map(n => n.locations).flat(), []);
-
- function getDevice(id: string): TDevice {
- return devices.filter(dev => dev._id === id)[0];
- }
-
- return useCallback(getDevice, []);
-}
diff --git a/hyperglass/ui/hooks/useGoogleAnalytics.tsx b/hyperglass/ui/hooks/useGoogleAnalytics.tsx
deleted file mode 100644
index 61659d1..0000000
--- a/hyperglass/ui/hooks/useGoogleAnalytics.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-import { useCallback } from 'react';
-import { createState, useState } from '@hookstate/core';
-import * as ReactGA from 'react-ga';
-
-import type { GAEffect, GAReturn } from './types';
-
-const enabledState = createState(false);
-
-export function useGoogleAnalytics(): GAReturn {
- const enabled = useState(enabledState);
-
- const useAnalytics = useCallback((effect: GAEffect): void => {
- if (typeof window !== 'undefined' && enabled.value) {
- if (typeof effect === 'function') {
- effect(ReactGA);
- }
- }
- }, []);
-
- const trackEvent = useCallback((e: ReactGA.EventArgs) => {
- useAnalytics(ga => {
- if (process.env.NODE_ENV === 'production') {
- ga.event(e);
- } else {
- console.log(
- `%cEvent %c${JSON.stringify(e)}`,
- 'background: green; color: black; padding: 0.5rem; font-size: 0.75rem;',
- 'background: black; color: green; padding: 0.5rem; font-size: 0.75rem; font-weight: bold;',
- );
- }
- });
- }, []);
-
- const trackPage = useCallback((path: string) => {
- useAnalytics(ga => {
- if (process.env.NODE_ENV === 'production') {
- ga.pageview(path);
- } else {
- console.log(
- `%cPage View %c${path}`,
- 'background: blue; color: white; padding: 0.5rem; font-size: 0.75rem;',
- 'background: white; color: blue; padding: 0.5rem; font-size: 0.75rem; font-weight: bold;',
- );
- }
- });
- }, []);
-
- const trackModal = useCallback((path: string) => {
- useAnalytics(ga => {
- if (process.env.NODE_ENV === 'production') {
- ga.modalview(path);
- } else {
- console.log(
- `%cModal View %c${path}`,
- 'background: red; color: white; padding: 0.5rem; font-size: 0.75rem;',
- 'background: white; color: red; padding: 0.5rem; font-size: 0.75rem; font-weight: bold;',
- );
- }
- });
- }, []);
-
- const initialize = useCallback((trackingId: string, debug: boolean) => {
- if (typeof trackingId !== 'string') {
- return;
- }
-
- enabled.set(true);
-
- const initializeOpts = { titleCase: false } as ReactGA.InitializeOptions;
-
- if (debug) {
- initializeOpts.debug = true;
- }
-
- useAnalytics(ga => {
- ga.initialize(trackingId, initializeOpts);
- });
- }, []);
-
- return { trackEvent, trackModal, trackPage, initialize, ga: ReactGA };
-}
diff --git a/hyperglass/ui/hooks/useGreeting.ts b/hyperglass/ui/hooks/useGreeting.ts
deleted file mode 100644
index ea25777..0000000
--- a/hyperglass/ui/hooks/useGreeting.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { createState, useState } from '@hookstate/core';
-import { Persistence } from '@hookstate/persistence';
-import { useConfig } from '~/context';
-
-import type { TUseGreetingReturn } from './types';
-
-const ackState = createState(false);
-const openState = createState(false);
-
-/**
- * Hook to manage the greeting, a.k.a. the popup at config path web.greeting.
- */
-export function useGreeting(): TUseGreetingReturn {
- const ack = useState(ackState);
- const isOpen = useState(openState);
- const { web } = useConfig();
-
- if (typeof window !== 'undefined') {
- ack.attach(Persistence('hyperglass-greeting'));
- }
-
- function open() {
- return isOpen.set(true);
- }
- function close() {
- return isOpen.set(false);
- }
-
- 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;
- }
- }
-
- return { ack, isOpen, greetingReady, open, close };
-}
diff --git a/hyperglass/ui/hooks/useLGQuery.ts b/hyperglass/ui/hooks/useLGQuery.ts
deleted file mode 100644
index a103d0a..0000000
--- a/hyperglass/ui/hooks/useLGQuery.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import { useEffect } from 'react';
-import { useQuery } from 'react-query';
-import { useConfig } from '~/context';
-import { useGoogleAnalytics } from './useGoogleAnalytics';
-import { fetchWithTimeout } from '~/util';
-
-import type { QueryFunction, QueryFunctionContext, QueryObserverResult } from 'react-query';
-import type { TFormQuery } from '~/types';
-import type { LGQueryKey } from './types';
-
-/**
- * Custom hook handle submission of a query to the hyperglass backend.
- */
-export function useLGQuery(query: TFormQuery): QueryObserverResult {
- const { request_timeout, cache } = useConfig();
- const controller = new AbortController();
-
- const { trackEvent } = useGoogleAnalytics();
-
- trackEvent({
- category: 'Query',
- action: 'submit',
- dimension1: query.queryLocation,
- dimension2: query.queryTarget,
- dimension3: query.queryType,
- dimension4: query.queryVrf,
- });
-
- const runQuery: QueryFunction = async (
- ctx: QueryFunctionContext,
- ): Promise => {
- const [url, data] = ctx.queryKey;
- const { queryLocation, queryTarget, queryType, queryVrf } = data;
- 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,
- );
- try {
- return await res.json();
- } catch (err) {
- throw new Error(res.statusText);
- }
- };
-
- // Cancel any still-running queries on unmount.
- useEffect(
- () => () => {
- controller.abort();
- },
- [],
- );
-
- 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).
- refetchInterval: false,
- // Don't refetch on component remount.
- refetchOnMount: false,
- });
-}
diff --git a/hyperglass/ui/hooks/useLGState.ts b/hyperglass/ui/hooks/useLGState.ts
deleted file mode 100644
index bbad925..0000000
--- a/hyperglass/ui/hooks/useLGState.ts
+++ /dev/null
@@ -1,162 +0,0 @@
-import { useCallback } from 'react';
-import { useState, createState } from '@hookstate/core';
-import isEqual from 'react-fast-compare';
-import { all } from '~/util';
-
-import type { State, PluginStateControl, Plugin } from '@hookstate/core';
-import type { TLGState, TLGStateHandlers, TMethodsExtension } from './types';
-
-const MethodsId = Symbol('Methods');
-
-/**
- * hookstate plugin to provide convenience functions for the useLGState hook.
- */
-class MethodsInstance {
- /**
- * Set the DNS resolver Popover to opened.
- */
- public resolvedOpen(state: State) {
- state.resolvedIsOpen.set(true);
- }
- /**
- * Set the DNS resolver Popover to closed.
- */
- public resolvedClose(state: State) {
- state.resolvedIsOpen.set(false);
- }
- /**
- * Find a response based on the device ID.
- */
- public getResponse(state: State, device: string): TQueryResponse | null {
- if (device in state.responses) {
- return state.responses[device].value;
- } else {
- 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): boolean {
- return (
- state.isSubmitting.value &&
- all(
- ...[
- state.queryVrf.value !== '',
- state.queryType.value !== '',
- state.queryTarget.value !== '',
- state.queryLocation.length !== 0,
- ],
- )
- );
- }
- /**
- * Reset form values affected by the form state to their default values.
- */
- public resetForm(state: State) {
- state.merge({
- queryVrf: '',
- families: [],
- queryType: '',
- responses: {},
- queryTarget: '',
- queryLocation: [],
- displayTarget: '',
- btnLoading: false,
- isSubmitting: false,
- resolvedIsOpen: false,
- availVrfs: [],
- selections: { queryLocation: [], queryType: null, queryVrf: null },
- });
- }
- public stateExporter(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;
-/**
- * Plugin Attachment.
- */
-function Methods(inst: State): TMethodsExtension;
-/**
- * Plugin Instance.
- */
-function Methods(inst?: State): Plugin | TMethodsExtension {
- if (inst) {
- const [instance] = inst.attach(MethodsId) as [
- MethodsInstance | Error,
- PluginStateControl,
- ];
-
- if (instance instanceof Error) {
- throw instance;
- }
-
- return {
- resetForm: () => instance.resetForm(inst),
- formReady: () => instance.formReady(inst),
- resolvedOpen: () => instance.resolvedOpen(inst),
- resolvedClose: () => instance.resolvedClose(inst),
- getResponse: device => instance.getResponse(inst, device),
- stateExporter: obj => instance.stateExporter(obj),
- };
- }
- return {
- id: MethodsId,
- init: () => {
- /* eslint @typescript-eslint/ban-types: 0 */
- return new MethodsInstance() as {};
- },
- };
-}
-
-const LGState = createState({
- selections: { queryLocation: [], queryType: null, queryVrf: null },
- resolvedIsOpen: false,
- isSubmitting: false,
- displayTarget: '',
- queryLocation: [],
- btnLoading: false,
- queryTarget: '',
- queryType: '',
- availVrfs: [],
- responses: {},
- queryVrf: '',
- families: [],
-});
-
-/**
- * Global state hook for state used throughout hyperglass.
- */
-export function useLGState(): State {
- return useState(LGState);
-}
-
-/**
- * Plugin for useLGState() that provides convenience methods for its state.
- */
-export function useLGMethods(): TLGStateHandlers {
- const state = useLGState();
- state.attach(Methods);
- const exporter = useCallback(Methods(state).stateExporter, [isEqual]);
- return {
- exportState(s) {
- return exporter(s);
- },
- ...Methods(state),
- };
-}
diff --git a/hyperglass/ui/hooks/useOpposingColor.ts b/hyperglass/ui/hooks/useOpposingColor.ts
deleted file mode 100644
index 4f2bf4d..0000000
--- a/hyperglass/ui/hooks/useOpposingColor.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-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): boolean {
- const theme = useTheme();
- if (typeof color === 'string' && color.match(/[a-zA-Z]+\.[a-zA-Z0-9]+/g)) {
- color = getColor(theme, color, color);
- }
- let opposingShouldBeDark = true;
- try {
- opposingShouldBeDark = isLight(color)(theme);
- } catch (err) {
- console.error(err);
- }
- 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);
-
- return useMemo(() => {
- if (isBlack) {
- return options?.dark ?? 'black';
- } else {
- return options?.light ?? 'white';
- }
- }, [color]);
-}
diff --git a/hyperglass/ui/hooks/useStrf.ts b/hyperglass/ui/hooks/useStrf.ts
deleted file mode 100644
index f790e8f..0000000
--- a/hyperglass/ui/hooks/useStrf.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { useMemo } from 'react';
-import format from 'string-format';
-
-import type { UseStrfArgs } from './types';
-
-/**
- * Format a string with variables, like Python's string.format()
- */
-export function useStrf(str: string, fmt: UseStrfArgs, ...deps: unknown[]): string {
- return useMemo(() => format(str, fmt), deps);
-}
diff --git a/hyperglass/ui/hooks/useTableToString.ts b/hyperglass/ui/hooks/useTableToString.ts
deleted file mode 100644
index 174f4fa..0000000
--- a/hyperglass/ui/hooks/useTableToString.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import { useCallback } from 'react';
-import dayjs from 'dayjs';
-import relativeTimePlugin from 'dayjs/plugin/relativeTime';
-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);
-
-function formatAsPath(path: number[]): string {
- return path.join(' → ');
-}
-
-function formatCommunities(comms: string[]): string {
- const commsStr = comms.map(c => ` - ${c}`);
- return '\n' + commsStr.join('\n');
-}
-
-function formatBool(val: boolean): string {
- let fmt = '';
- if (val === true) {
- fmt = 'yes';
- } else if (val === false) {
- fmt = 'no';
- }
- return fmt;
-}
-
-function formatTime(val: number): string {
- const now = dayjs.utc();
- const then = now.subtract(val, 'second');
- const timestamp = then.toString().replace('GMT', 'UTC');
- const relative = now.to(then, true);
- 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,
- ...deps: unknown[]
-): () => string {
- const { web, parsed_data_fields, messages } = useConfig();
-
- function formatRpkiState(val: number): string {
- const rpkiStates = [
- web.text.rpki_invalid,
- web.text.rpki_valid,
- web.text.rpki_unknown,
- web.text.rpki_unverified,
- ];
- return rpkiStates[val];
- }
-
- const tableFormatMap = {
- age: formatTime,
- active: formatBool,
- as_path: formatAsPath,
- communities: formatCommunities,
- rpki_state: formatRpkiState,
- };
-
- function isFormatted(key: string): key is keyof TTableToStringFormatted {
- return key in tableFormatMap;
- }
-
- function getFmtFunc(accessor: keyof TRoute): TTableToStringFormatter {
- if (isFormatted(accessor)) {
- return tableFormatMap[accessor];
- } else {
- return String;
- }
- }
-
- function doFormat(target: string, data: TQueryResponse | undefined): string {
- let result = messages.no_output;
- try {
- if (typeof data !== 'undefined' && isStructuredOutput(data)) {
- const tableStringParts = [`Routes For: ${target}`, `Timestamp: ${data.timestamp} UTC`];
- 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];
- const fmtFunc = getFmtFunc(accessor) as (v: typeof value) => string;
- value = fmtFunc(value);
- if (accessor === 'prefix') {
- tableStringParts.push(` - ${header}: ${value}`);
- } else {
- tableStringParts.push(` - ${header}: ${value}`);
- }
- }
- }
- }
- result = tableStringParts.join('\n');
- }
- return result;
- } catch (err) {
- console.error(err);
- return `An error occurred while parsing the output: '${err.message}'`;
- }
- }
- return useCallback(() => doFormat(target, data), deps);
-}
diff --git a/hyperglass/ui/hooks/useVrf.ts b/hyperglass/ui/hooks/useVrf.ts
deleted file mode 100644
index 662ecf2..0000000
--- a/hyperglass/ui/hooks/useVrf.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { useCallback, useMemo } from 'react';
-import { useConfig } from '~/context';
-
-import type { TDeviceVrf } from '~/types';
-import type { TUseVrf } from './types';
-
-/**
- * Get a VRF configuration from the global configuration context based on its name.
- */
-export function useVrf(): TUseVrf {
- const { networks } = useConfig();
-
- const vrfs = useMemo(() => networks.map(n => n.locations.map(l => l.vrfs).flat()).flat(), []);
-
- function getVrf(id: string): TDeviceVrf {
- const matching = vrfs.find(vrf => vrf._id === id);
- if (typeof matching === 'undefined') {
- if (id === '__hyperglass_default') {
- const anyDefault = vrfs.find(vrf => vrf.default === true);
- if (typeof anyDefault !== 'undefined') {
- return anyDefault;
- } else {
- throw new Error(`No matching VRF found for '${id}'`);
- }
- } else {
- throw new Error(`No matching VRF found for '${id}'`);
- }
- }
- return matching;
- }
-
- return useCallback(getVrf, []);
-}
diff --git a/hyperglass/ui/next-env.d.ts b/hyperglass/ui/next-env.d.ts
deleted file mode 100644
index 7b7aa2c..0000000
--- a/hyperglass/ui/next-env.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-///
-///
diff --git a/hyperglass/ui/next.config.js b/hyperglass/ui/next.config.js
deleted file mode 100644
index bd7f634..0000000
--- a/hyperglass/ui/next.config.js
+++ /dev/null
@@ -1,17 +0,0 @@
-const envVars = require('/tmp/hyperglass.env.json');
-const { configFile } = envVars;
-const config = require(String(configFile));
-
-module.exports = {
- reactStrictMode: true,
- poweredByHeader: false,
- env: {
- _NODE_ENV_: config.NODE_ENV,
- _HYPERGLASS_URL_: config._HYPERGLASS_URL_,
- _HYPERGLASS_CONFIG_: config._HYPERGLASS_CONFIG_,
- _HYPERGLASS_FAVICONS_: config._HYPERGLASS_FAVICONS_,
- },
- future: {
- webpack5: true,
- },
-};
diff --git a/hyperglass/ui/nextdev.js b/hyperglass/ui/nextdev.js
deleted file mode 100644
index 0facba9..0000000
--- a/hyperglass/ui/nextdev.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/* eslint-disable no-console */
-const express = require('express');
-const proxyMiddleware = require('http-proxy-middleware');
-const next = require('next');
-const envVars = require('/tmp/hyperglass.env.json');
-const { configFile } = envVars;
-const config = require(String(configFile));
-
-const { NODE_ENV: env, _HYPERGLASS_URL_: envUrl } = config;
-
-const devProxy = {
- '/api/query/': { target: envUrl + 'api/query/', pathRewrite: { '^/api/query/': '' } },
- '/images': { target: envUrl + 'images', pathRewrite: { '^/images': '' } },
- '/custom': { target: envUrl + 'custom', pathRewrite: { '^/custom': '' } },
-};
-
-const port = parseInt(process.env.PORT, 10) || 3000;
-const dev = env !== 'production';
-const app = next({
- dir: '.', // base directory where everything is, could move to src later
- dev,
-});
-
-const handle = app.getRequestHandler();
-
-let server;
-app
- .prepare()
- .then(() => {
- server = express();
-
- // Set up the proxy.
- if (dev && devProxy) {
- Object.keys(devProxy).forEach(function (context) {
- server.use(proxyMiddleware(context, devProxy[context]));
- });
- }
-
- // Default catch-all handler to allow Next.js to handle all other routes
- server.all('*', (req, res) => handle(req, res));
-
- server.listen(port, err => {
- if (err) {
- throw err;
- }
- console.log(`> Ready on port ${port} [${env}]`);
- });
- })
- .catch(err => {
- console.log('An error occurred, unable to start the server');
- console.log(err);
- });
diff --git a/hyperglass/ui/package.json b/hyperglass/ui/package.json
deleted file mode 100644
index a53d6a6..0000000
--- a/hyperglass/ui/package.json
+++ /dev/null
@@ -1,82 +0,0 @@
-{
- "name": "ui",
- "version": "1.0.0",
- "description": "UI for hyperglass, the modern network looking glass",
- "author": "Matt Love",
- "license": "BSD-3-Clause-Clear",
- "private": true,
- "scripts": {
- "lint": "eslint . --ext .ts --ext .tsx",
- "dev": "node nextdev",
- "start": "next start",
- "typecheck": "tsc --noEmit",
- "format": "prettier -c .",
- "clean": "rimraf --no-glob ./.next ./out",
- "check:es:export": "es-check es5 './out/**/*.js' -v",
- "check:es:build": "es-check es5 './.next/static/**/*.js' -v",
- "build": "next build && next export -o ../hyperglass/static/ui"
- },
- "browserslist": "> 0.25%, not dead",
- "dependencies": {
- "@chakra-ui/react": "^1.6.3",
- "@emotion/react": "^11.4.0",
- "@emotion/styled": "^11.3.0",
- "@hookform/devtools": "^3.1.0",
- "@hookform/resolvers": "^2.5.1",
- "@hookstate/core": "^3.0.7",
- "@hookstate/persistence": "^3.0.0",
- "@meronex/icons": "^4.0.0",
- "dagre": "^0.8.5",
- "dayjs": "^1.10.4",
- "framer-motion": "^4.1.17",
- "lodash": "^4.17.21",
- "next": "^10.2.3",
- "palette-by-numbers": "^0.1.5",
- "react": "^17.0.2",
- "react-countdown": "^2.2.1",
- "react-device-detect": "^1.15.0",
- "react-dom": "^17.0.2",
- "react-fast-compare": "^3.2.0",
- "react-flow-renderer": "^9.6.0",
- "react-ga": "^3.3.0",
- "react-hook-form": "^7.7.0",
- "react-markdown": "^5.0.3",
- "react-query": "^3.16.0",
- "react-select": "^4.3.1",
- "react-table": "^7.7.0",
- "remark-gfm": "^1.0.0",
- "string-format": "^2.0.0",
- "vest": "^3.2.3"
- },
- "devDependencies": {
- "@hookstate/devtools": "^3.0.0",
- "@types/dagre": "^0.7.44",
- "@types/node": "^14.14.41",
- "@types/react": "^17.0.3",
- "@types/react-select": "^4.0.15",
- "@types/react-table": "^7.7.1",
- "@types/string-format": "^2.0.0",
- "@typescript-eslint/eslint-plugin": "^4.11.1",
- "@typescript-eslint/parser": "^4.11.1",
- "@upstatement/eslint-config": "^0.4.3",
- "@upstatement/prettier-config": "^0.3.0",
- "babel-eslint": "^10.1.0",
- "eslint": "^6.8.0",
- "eslint-config-prettier": "^7.1.0",
- "eslint-config-react-app": "^5.2.0",
- "eslint-import-resolver-typescript": "^2.3.0",
- "eslint-plugin-import": "^2.22.1",
- "eslint-plugin-jest": "^24.1.3",
- "eslint-plugin-json": "^2.1.2",
- "eslint-plugin-jsx-a11y": "^6.2.3",
- "eslint-plugin-prettier": "^3.3.0",
- "eslint-plugin-react": "^7.22.0",
- "eslint-plugin-react-hooks": "^4.2.0",
- "express": "^4.17.1",
- "http-proxy-middleware": "0.20.0",
- "onchange": "^7.1.0",
- "prettier": "^2.2.1",
- "prettier-eslint": "^12.0.0",
- "typescript": "^4.3.2"
- }
-}
diff --git a/hyperglass/ui/pages/_app.tsx b/hyperglass/ui/pages/_app.tsx
deleted file mode 100644
index 1377a83..0000000
--- a/hyperglass/ui/pages/_app.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { useEffect } from 'react';
-import Head from 'next/head';
-import { HyperglassProvider } from '~/context';
-import { useGoogleAnalytics } from '~/hooks';
-import { IConfig } from '~/types';
-
-import type { AppProps, AppInitialProps, AppContext } from 'next/app';
-
-if (process.env.NODE_ENV === 'development') {
- require('@hookstate/devtools');
-}
-
-type TApp = { config: IConfig };
-
-type GetInitialPropsReturn = AppProps & AppInitialProps & { appProps: IP };
-
-type NextApp = React.FC> & {
- getInitialProps(c?: AppContext): Promise<{ appProps: IP }>;
-};
-
-const App: NextApp = (props: GetInitialPropsReturn) => {
- const { Component, pageProps, appProps, router } = props;
- const { config } = appProps;
- const { initialize, trackPage } = useGoogleAnalytics();
-
- initialize(config.google_analytics, config.developer_mode);
-
- useEffect(() => {
- router.events.on('routeChangeComplete', trackPage);
- }, []);
-
- return (
- <>
-
- hyperglass
-
-
-
-
-
-
-
-
-
-
-
- >
- );
-};
-
-App.getInitialProps = async function getInitialProps() {
- const config = (process.env._HYPERGLASS_CONFIG_ as unknown) as IConfig;
- return { appProps: { config } };
-};
-
-export default App;
diff --git a/hyperglass/ui/pages/_document.tsx b/hyperglass/ui/pages/_document.tsx
deleted file mode 100644
index f54a823..0000000
--- a/hyperglass/ui/pages/_document.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import Document, { Html, Head, Main, NextScript } from 'next/document';
-import type { DocumentContext, DocumentInitialProps } from 'next/document';
-
-class MyDocument extends Document {
- static async getInitialProps(ctx: DocumentContext): Promise {
- const initialProps = await Document.getInitialProps(ctx);
- return { ...initialProps };
- }
-
- render(): JSX.Element {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
-
-export default MyDocument;
diff --git a/hyperglass/ui/pages/index.tsx b/hyperglass/ui/pages/index.tsx
deleted file mode 100644
index bbe4adc..0000000
--- a/hyperglass/ui/pages/index.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import Head from 'next/head';
-import dynamic from 'next/dynamic';
-import { Meta, Loading } from '~/components';
-
-import type { GetStaticProps } from 'next';
-import type { Favicon, FaviconComponent } from '~/types';
-
-const Layout = dynamic(() => import('~/components').then(i => i.Layout), {
- loading: Loading,
-});
-
-interface TIndex {
- favicons: FaviconComponent[];
-}
-
-const Index: React.FC = (props: TIndex) => {
- const { favicons } = props;
- return (
- <>
-
- {favicons.map((icon, idx) => {
- const { rel, href, type } = icon;
- return ;
- })}
-
-
-
- >
- );
-};
-
-export const getStaticProps: GetStaticProps = async () => {
- const faviconConfig = (process.env._HYPERGLASS_FAVICONS_ as unknown) as Favicon[];
- const favicons = faviconConfig.map(icon => {
- const { image_format, dimensions, prefix } = icon;
- let { rel } = icon;
- if (rel === null) {
- rel = '';
- }
- const src = `/images/favicons/${prefix}-${dimensions[0]}x${dimensions[1]}.${image_format}`;
- return { rel, href: src, type: `image/${image_format}` };
- });
- return {
- props: { favicons },
- };
-};
-
-export default Index;
diff --git a/hyperglass/ui/public/robots.txt b/hyperglass/ui/public/robots.txt
deleted file mode 100644
index 3f49e23..0000000
--- a/hyperglass/ui/public/robots.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-User-agent: *
-Disallow: /*__*
\ No newline at end of file
diff --git a/hyperglass/ui/tsconfig.json b/hyperglass/ui/tsconfig.json
deleted file mode 100644
index 8d3a05c..0000000
--- a/hyperglass/ui/tsconfig.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES5",
- "module": "esnext",
- "downlevelIteration": true,
- "strict": true,
- "baseUrl": "." /* Base directory to resolve non-absolute module names. */,
- "paths": {
- "~/components": ["components/index"],
- "~/components/*": ["components/*"],
- "~/context": ["context/index"],
- "~/context/*": ["context/*"],
- "~/hooks": ["hooks/index"],
- "~/hooks/*": ["hooks/*"],
- "~/state": ["state/index"],
- "~/state/*": ["state/*"],
- "~/types": ["types/index"],
- "~/types/*": ["types/*"],
- "~/util": ["util/index"],
- "~/util/*": ["util/*"]
- },
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true,
- "lib": ["dom", "dom.iterable", "esnext"],
- "allowJs": true,
- "noEmit": true,
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "jsx": "preserve"
- },
- "exclude": ["node_modules", ".next"],
- "include": [
- "next-env.d.ts",
- "**/*.ts",
- "**/*.tsx",
- "types/globals.d.ts",
- "next.config.js",
- "nextdev.js"
- ]
-}
diff --git a/hyperglass/ui/types/caida.ts b/hyperglass/ui/types/caida.ts
deleted file mode 100644
index accd0a7..0000000
--- a/hyperglass/ui/types/caida.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export interface TASNQuery {
- data: {
- asn: {
- organization: {
- orgName: string;
- } | null;
- };
- };
-}
diff --git a/hyperglass/ui/types/common.ts b/hyperglass/ui/types/common.ts
deleted file mode 100644
index 5efd424..0000000
--- a/hyperglass/ui/types/common.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { State } from '@hookstate/core';
-
-export type TSelectOptionBase = {
- label: string;
- value: string;
- group?: string;
-};
-
-export type TSelectOption = TSelectOptionBase | null;
-
-export type TSelectOptionMulti = TSelectOptionBase[] | null;
-
-export type TSelectOptionState = State;
-
-export type TSelectOptionGroup = {
- label: string;
- options: TSelectOption[];
-};
-
-export type OnChangeArgs = { field: string; value: string | string[] };
-
-export type Families = [4] | [6] | [4, 6] | [];
diff --git a/hyperglass/ui/types/config.ts b/hyperglass/ui/types/config.ts
deleted file mode 100644
index 0e7d36d..0000000
--- a/hyperglass/ui/types/config.ts
+++ /dev/null
@@ -1,216 +0,0 @@
-import type { Theme } from './theme';
-
-export type TQueryFields = 'query_type' | 'query_target' | 'query_location' | 'query_vrf';
-
-type TSide = 'left' | 'right';
-
-export interface IConfigMessages {
- no_input: string;
- acl_denied: string;
- acl_not_allowed: string;
- feature_not_enabled: string;
- invalid_input: string;
- invalid_field: string;
- general: string;
- request_timeout: string;
- connection_error: string;
- authentication_error: string;
- no_response: string;
- vrf_not_associated: string;
- vrf_not_found: string;
- no_output: string;
- parsing_error: string;
-}
-
-export interface IConfigTheme {
- colors: { [k: string]: string };
- default_color_mode: 'light' | 'dark' | null;
- fonts: Theme.Fonts;
-}
-
-export interface IConfigWebText {
- title_mode: string;
- title: string;
- subtitle: string;
- query_location: string;
- query_type: string;
- query_target: string;
- 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;
- rpki_invalid: string;
- rpki_valid: string;
- rpki_unknown: string;
- rpki_unverified: string;
- no_communities: string;
-}
-
-export interface TConfigGreeting {
- enable: boolean;
- title: string;
- button: string;
- required: boolean;
-}
-
-export interface TConfigWebLogo {
- width: string;
- height: string | null;
- light_format: string;
- dark_format: string;
-}
-
-export interface TLink {
- title: string;
- url: string;
- show_icon: boolean;
- side: TSide;
- order: number;
-}
-
-export interface TMenu {
- title: string;
- content: string;
- side: TSide;
- order: number;
-}
-
-export interface IConfigWeb {
- credit: { enable: boolean };
- dns_provider: { name: string; url: string };
- links: TLink[];
- menus: TMenu[];
- greeting: TConfigGreeting;
- help_menu: { enable: boolean; title: string };
- logo: TConfigWebLogo;
- terms: { enable: boolean; title: string };
- text: IConfigWebText;
- theme: IConfigTheme;
-}
-
-export interface TQuery {
- name: string;
- enable: boolean;
- display_name: string;
-}
-
-export interface TBGPCommunity {
- community: string;
- display_name: string;
- description: string;
-}
-
-export interface IQueryBGPRoute extends TQuery {}
-export interface IQueryBGPASPath extends TQuery {}
-export interface IQueryPing extends TQuery {}
-export interface IQueryTraceroute extends TQuery {}
-export interface IQueryBGPCommunity extends TQuery {
- mode: 'input' | 'select';
- communities: TBGPCommunity[];
-}
-
-export interface TConfigQueries {
- bgp_route: IQueryBGPRoute;
- bgp_community: IQueryBGPCommunity;
- bgp_aspath: IQueryBGPASPath;
- ping: IQueryPing;
- traceroute: IQueryTraceroute;
- list: TQuery[];
-}
-
-interface TDeviceVrfBase {
- _id: string;
- display_name: string;
- default: boolean;
-}
-
-export interface TDeviceVrf extends TDeviceVrfBase {
- ipv4: boolean;
- ipv6: boolean;
-}
-
-interface TDeviceBase {
- _id: string;
- name: string;
- network: string;
-}
-
-export interface TDevice extends TDeviceBase {
- vrfs: TDeviceVrf[];
-}
-
-export interface TNetworkLocation extends TDeviceBase {
- vrfs: TDeviceVrf[];
-}
-
-export interface TNetwork {
- display_name: string;
- locations: TDevice[];
-}
-
-export type TParsedDataField = [string, keyof TRoute, 'left' | 'right' | 'center' | null];
-
-export interface TQueryContent {
- content: string;
- enable: boolean;
- params: {
- primary_asn: IConfig['primary_asn'];
- org_name: IConfig['org_name'];
- site_title: IConfig['site_title'];
- title: string;
- [k: string]: string;
- };
-}
-
-export interface IConfigContent {
- credit: string;
- greeting: string;
- vrf: {
- [k: string]: {
- bgp_route: TQueryContent;
- bgp_community: TQueryContent;
- bgp_aspath: TQueryContent;
- ping: TQueryContent;
- traceroute: TQueryContent;
- };
- };
-}
-
-export interface IConfig {
- cache: { show_text: boolean; timeout: number };
- debug: boolean;
- developer_mode: boolean;
- primary_asn: string;
- request_timeout: number;
- org_name: string;
- google_analytics: string | null;
- site_title: string;
- site_keywords: string[];
- site_description: string;
- web: IConfigWeb;
- messages: IConfigMessages;
- hyperglass_version: string;
- queries: TConfigQueries;
- devices: TDevice[];
- networks: TNetwork[];
- vrfs: TDeviceVrfBase[];
- parsed_data_fields: TParsedDataField[];
- content: IConfigContent;
-}
-
-export interface Favicon {
- rel: string | null;
- dimensions: [number, number];
- image_format: string;
- prefix: string;
-}
-
-export interface FaviconComponent {
- rel: string;
- href: string;
- type: string;
-}
diff --git a/hyperglass/ui/types/data.ts b/hyperglass/ui/types/data.ts
deleted file mode 100644
index 87adbcf..0000000
--- a/hyperglass/ui/types/data.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-export type TQueryTypes = '' | TValidQueryTypes;
-export type TValidQueryTypes = 'bgp_route' | 'bgp_community' | 'bgp_aspath' | 'ping' | 'traceroute';
-
-export interface TFormData {
- query_location: string[];
- query_type: TQueryTypes;
- query_vrf: string;
- query_target: string;
-}
-
-export interface TFormState {
- queryLocation: string[];
- queryType: TQueryTypes;
- queryVrf: string;
- queryTarget: string;
-}
-
-export interface TFormQuery extends Omit {
- queryLocation: string;
-}
-
-export interface TStringTableData extends Omit {
- output: TStructuredResponse;
-}
-
-export interface TQueryResponseString extends Omit {
- output: string;
-}
diff --git a/hyperglass/ui/types/dns-over-https.ts b/hyperglass/ui/types/dns-over-https.ts
deleted file mode 100644
index 26719af..0000000
--- a/hyperglass/ui/types/dns-over-https.ts
+++ /dev/null
@@ -1,204 +0,0 @@
-/**
- * DNS Over HTTPS Types, primarily adapted from:
- *
- * @see https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
- * @see https://developers.cloudflare.com/1.1.1.1/dns-over-https/json-format
- * @see https://developers.google.com/speed/public-dns/docs/doh/json
- */
-export namespace DnsOverHttps {
- /**
- * DNS RCODEs
- * @see https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
- */
- export enum Status {
- /**
- * No Error
- */
- NO_ERROR = 0,
- /**
- * Format Error
- */
- FORM_ERR = 1,
- /**
- * Server Failure
- */
- SERV_FAIL = 2,
- /**
- * Non-Existent Domain
- */
- NX_DOMAIN = 3,
- /**
- * Not Implemented
- */
- NOT_IMP = 4,
- /**
- * Query Refused
- */
- REFUSED = 5,
- /**
- * Name Exists when it should not
- */
- YX_DOMAIN = 6,
- /**
- * RR Set Exists when it should not
- */
- YXRR_SET = 7,
- /**
- * RR Set that should exist does not
- */
- NXRR_SET = 8,
- /**
- * Server Not Authoritative for zone
- */
- NOT_AUTH = 9,
- /**
- * Name not contained in zone
- */
- NOT_ZONE = 10,
- /**
- * DSO-TYPE Not Implemented
- */
- DSO_TYPE_NI = 11,
- /**
- * TSIG Signature Failure
- */
- BADSIG = 16,
- /**
- * Key not recognized
- */
- BADKEY = 17,
- /**
- * Signature out of time window
- */
- BADTIME = 18,
- /**
- * Bad TKEY Mode
- */
- BADMODE = 19,
- /**
- * Duplicate key name
- */
- BADNAME = 20,
- /**
- * Algorithm not supported
- */
- BADALG = 21,
- /**
- * Bad Truncation
- */
- BADTRUNC = 22,
- /**
- * Bad/missing Server Cookie
- */
- BADCOOKIE = 23,
- }
- /**
- * Resource Record (RR) Types
- * @see https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4
- */
- export enum Type {
- /**
- * IPv4 Host Address Record.
- */
- A = 1,
- /**
- * Name Server Record.
- */
- NS = 2,
- /**
- * Canonical Alias Name Record.
- */
- CNAME = 5,
- /**
- * Start of Zone Authority Record.
- */
- SOA = 6,
- /**
- * Well Know Service Description Record.
- */
- WKS = 11,
- /**
- * Domain Name Pointer Record.
- */
- PTR = 12,
- /**
- * Mail Exchange Record.
- */
- MX = 15,
- /**
- * IPv6 Host Address Record.
- */
- AAAA = 28,
- /**
- * Server Selection Record.
- */
- SRV = 33,
- /**
- * DNAME Record.
- */
- DNAME = 39,
- /**
- * DNSKEY Record.
- */
- DNSKEY = 48,
- }
- export interface Question {
- /**
- * FQDN with trailing dot.
- */
- name: string;
- /**
- * DNS RR Type.
- */
- type: Type;
- }
- export interface Answer {
- /**
- * FQDN with trailing dot.
- */
- name: string;
- /**
- * DNS RR Type.
- */
- type: Type;
- /**
- * Time to live in seconds.
- */
- TTL: number;
- /**
- * Response data.
- */
- data: string;
- }
- export interface Response {
- Status: Status;
- /**
- * Truncated bit was set.
- */
- TC: boolean;
- /**
- * Recursive Desired bit was set.
- */
- RD: boolean;
- /**
- * Recursion Available bit was set.
- */
- RA: boolean;
- /**
- * If true, it means that every record in the answer was verified with DNSSEC.
- */
- AD: boolean;
- /**
- * If true, the client asked to disable DNSSEC validation.
- */
- CD: boolean;
- /**
- * Queried Resources.
- */
- Question: Question[];
- /**
- * Response Data.
- */
- Answer: Answer[];
- }
-}
diff --git a/hyperglass/ui/types/globals.d.ts b/hyperglass/ui/types/globals.d.ts
deleted file mode 100644
index fd8d66c..0000000
--- a/hyperglass/ui/types/globals.d.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import type { MotionProps } from 'framer-motion';
-
-declare global {
- type Dict = Record;
- type ValueOf = T[keyof T];
-
- type TRPKIStates = 0 | 1 | 2 | 3;
-
- type TResponseLevel = 'success' | 'warning' | 'error' | 'danger';
-
- interface IRoute {
- prefix: string;
- active: boolean;
- age: number;
- weight: number;
- med: number;
- local_preference: number;
- as_path: number[];
- communities: string[];
- next_hop: string;
- source_as: number;
- source_rid: string;
- peer_rid: string;
- rpki_state: TRPKIStates;
- }
-
- type TRoute = {
- prefix: string;
- active: boolean;
- age: number;
- weight: number;
- med: number;
- local_preference: number;
- as_path: number[];
- communities: string[];
- next_hop: string;
- source_as: number;
- source_rid: string;
- peer_rid: string;
- rpki_state: TRPKIStates;
- };
- type TRouteField = { [k in keyof TRoute]: ValueOf };
-
- type TStructuredResponse = {
- vrf: string;
- count: number;
- routes: TRoute[];
- winning_weight: 'high' | 'low';
- };
- type TQueryResponse = {
- random: string;
- cached: boolean;
- runtime: number;
- level: TResponseLevel;
- timestamp: string;
- keywords: string[];
- output: string | TStructuredResponse;
- format: 'text/plain' | 'application/json';
- };
- type ReactRef = MutableRefObject;
-
- type Animated = Omit &
- Omit & { transition?: MotionProps['transition'] };
-
- type MeronexIcon = import('@meronex/icons').IconBaseProps;
-}
diff --git a/hyperglass/ui/types/guards.ts b/hyperglass/ui/types/guards.ts
deleted file mode 100644
index f6439b5..0000000
--- a/hyperglass/ui/types/guards.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/* eslint @typescript-eslint/explicit-module-boundary-types: off */
-/* eslint @typescript-eslint/no-explicit-any: off */
-import type { State } from '@hookstate/core';
-import type { TFormData, TValidQueryTypes, TStringTableData, TQueryResponseString } from './data';
-import type { TSelectOption } from './common';
-import type { TQueryContent } from './config';
-
-export function isQueryType(q: unknown): q is TValidQueryTypes {
- let result = false;
- if (
- typeof q === 'string' &&
- ['bgp_route', 'bgp_community', 'bgp_aspath', 'ping', 'traceroute'].includes(q)
- ) {
- result = true;
- }
- return result;
-}
-
-export function isString(a: unknown): a is string {
- return typeof a === 'string';
-}
-
-export function isStructuredOutput(data: any): data is TStringTableData {
- return typeof data !== 'undefined' && 'output' in data && typeof data.output !== 'string';
-}
-
-export function isStringOutput(data: any): data is TQueryResponseString {
- return typeof data !== 'undefined' && 'output' in data && typeof data.output === 'string';
-}
-
-export function isQueryContent(c: any): c is TQueryContent {
- return typeof c !== 'undefined' && c !== null && 'content' in c;
-}
-
-/**
- * Determine if an object is a Select option.
- */
-export function isSelectOption(a: any): a is NonNullable {
- return typeof a !== 'undefined' && a !== null && 'label' in a && 'value' in a;
-}
-
-/**
- * Determine if an object is a HookState Proxy.
- */
-export function isState(a: any): a is State> {
- let result = false;
- if (typeof a !== 'undefined' && a !== null) {
- if (
- 'get' in a &&
- typeof a.get === 'function' &&
- 'set' in a &&
- typeof a.set === 'function' &&
- 'promised' in a
- ) {
- result = true;
- }
- }
- return result;
-}
-
-/**
- * Determine if a form field name is a valid form key name.
- */
-export function isQueryField(field: string): field is keyof TFormData {
- return ['query_location', 'query_type', 'query_vrf', 'query_target'].includes(field);
-}
diff --git a/hyperglass/ui/types/index.ts b/hyperglass/ui/types/index.ts
deleted file mode 100644
index 637512e..0000000
--- a/hyperglass/ui/types/index.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export * from './caida';
-export * from './common';
-export * from './config';
-export * from './data';
-export * from './dns-over-https';
-export * from './guards';
-export * from './table';
-export * from './theme';
-export * from './util';
diff --git a/hyperglass/ui/types/react-table-config.d.ts b/hyperglass/ui/types/react-table-config.d.ts
deleted file mode 100644
index 57a0a3e..0000000
--- a/hyperglass/ui/types/react-table-config.d.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-/* eslint-disable */
-
-import type {
- TableInstance,
- UseSortByHooks,
- UseSortByState,
- UseFiltersState,
- UseGroupByHooks,
- UseGroupByState,
- UseExpandedHooks,
- UseExpandedState,
- UseSortByOptions,
- UseFiltersOptions,
- UseGroupByOptions,
- UseRowSelectHooks,
- UseRowSelectState,
- UseExpandedOptions,
- UseGroupByRowProps,
- UsePaginationState,
- UseColumnOrderState,
- UseExpandedRowProps,
- UseGroupByCellProps,
- UseRowSelectOptions,
- UsePaginationOptions,
- UseRowSelectRowProps,
- UseSortByColumnProps,
- UseFiltersColumnProps,
- UseGlobalFiltersState,
- UseGroupByColumnProps,
- UseResizeColumnsState,
- UseSortByColumnOptions,
- UseSortByInstanceProps,
- UseFiltersColumnOptions,
- UseFiltersInstanceProps,
- UseGlobalFiltersOptions,
- UseGroupByColumnOptions,
- UseGroupByInstanceProps,
- UseResizeColumnsOptions,
- UseExpandedInstanceProps,
- UseRowSelectInstanceProps,
- UsePaginationInstanceProps,
- UseColumnOrderInstanceProps,
- UseResizeColumnsColumnProps,
- UseGlobalFiltersInstanceProps,
- UseResizeColumnsColumnOptions,
-} from 'react-table';
-
-declare module 'react-table' {
- export interface UseFlexLayoutInstanceProps | |