1
0
mirror of https://github.com/checktheroads/hyperglass synced 2024-05-11 05:55:08 +00:00

222 lines
8.1 KiB
JavaScript
Raw Normal View History

2020-03-22 11:43:14 -07:00
import React, { useEffect, useState } from "react";
2020-01-17 02:50:57 -07:00
import {
AccordionItem,
AccordionHeader,
AccordionPanel,
Alert,
Box,
ButtonGroup,
2020-01-20 00:37:04 -07:00
css,
2020-01-17 02:50:57 -07:00
Flex,
Text,
useTheme,
2020-04-15 10:43:34 -07:00
useColorMode,
2020-01-17 02:50:57 -07:00
} from "@chakra-ui/core";
import styled from "@emotion/styled";
import useAxios from "axios-hooks";
import strReplace from "react-string-replace";
2020-01-20 00:37:04 -07:00
import useConfig from "~/components/HyperglassProvider";
2020-01-17 02:50:57 -07:00
import CopyButton from "~/components/CopyButton";
import RequeryButton from "~/components/RequeryButton";
import ResultHeader from "~/components/ResultHeader";
2020-01-26 02:24:12 -07:00
import { startCase } from "lodash";
2020-01-17 02:50:57 -07:00
const FormattedError = ({ keywords, message }) => {
2020-04-15 10:43:34 -07:00
const patternStr = keywords.map((kw) => `(${kw})`).join("|");
2020-01-17 02:50:57 -07:00
const pattern = new RegExp(patternStr, "gi");
2020-03-23 01:10:27 -07:00
let errorFmt;
try {
2020-04-15 10:43:34 -07:00
errorFmt = strReplace(message, pattern, (match) => (
2020-03-23 01:10:27 -07:00
<Text key={match} as="strong">
{match}
</Text>
));
} catch (err) {
errorFmt = <Text as="span">{message}</Text>;
}
return <Text as="span">{keywords.length !== 0 ? errorFmt : message}</Text>;
2020-01-17 02:50:57 -07:00
};
2020-01-20 00:37:04 -07:00
const AccordionHeaderWrapper = styled(Flex)`
justify-content: space-between;
&:hover {
2020-04-15 10:43:34 -07:00
background-color: ${(props) => props.hoverBg};
2020-01-20 00:37:04 -07:00
}
&:focus {
box-shadow: "outline";
}
`;
2020-01-26 02:24:12 -07:00
const statusMap = { success: "success", warning: "warning", error: "warning", danger: "error" };
2020-01-20 00:37:04 -07:00
const Result = React.forwardRef(
2020-03-22 11:43:14 -07:00
(
{
device,
timeout,
queryLocation,
queryType,
queryVrf,
queryTarget,
index,
resultsComplete,
2020-04-15 10:43:34 -07:00
setComplete,
2020-03-22 11:43:14 -07:00
},
ref
) => {
2020-01-20 00:37:04 -07:00
const config = useConfig();
2020-01-17 02:50:57 -07:00
const theme = useTheme();
const { colorMode } = useColorMode();
const bg = { dark: theme.colors.gray[800], light: theme.colors.blackAlpha[100] };
const color = { dark: theme.colors.white, light: theme.colors.black };
const selectionBg = { dark: theme.colors.white, light: theme.colors.black };
const selectionColor = { dark: theme.colors.black, light: theme.colors.white };
const [{ data, loading, error }, refetch] = useAxios({
2020-01-21 17:30:14 -07:00
url: "/api/query/",
2020-01-17 02:50:57 -07:00
method: "post",
data: {
query_location: queryLocation,
query_type: queryType,
query_vrf: queryVrf,
2020-04-15 10:43:34 -07:00
query_target: queryTarget,
2020-01-17 02:50:57 -07:00
},
2020-04-15 10:43:34 -07:00
timeout: timeout,
useCache: false,
2020-01-17 02:50:57 -07:00
});
2020-03-22 11:43:14 -07:00
const [isOpen, setOpen] = useState(false);
const [hasOverride, setOverride] = useState(false);
const handleToggle = () => {
setOpen(!isOpen);
setOverride(true);
};
2020-04-15 10:43:34 -07:00
const cleanOutput = data && data.output.split("\\n").join("\n").replace(/\n\n/g, "\n");
2020-01-17 02:50:57 -07:00
const errorKw = (error && error.response?.data?.keywords) || [];
2020-01-26 02:24:12 -07:00
let errorMsg;
if (error && error.response?.data?.output) {
errorMsg = error.response.data.output;
} else if (error && error.message.startsWith("timeout")) {
errorMsg = config.messages.request_timeout;
2020-01-27 21:28:27 -07:00
} else if (error?.response?.statusText) {
errorMsg = startCase(error.response.statusText);
2020-01-26 02:24:12 -07:00
} else if (error && error.message) {
errorMsg = startCase(error.message);
} else {
errorMsg = config.messages.general;
}
2020-01-27 21:28:27 -07:00
error && console.dir(error);
2020-01-26 02:24:12 -07:00
const errorLevel =
(error?.response?.data?.level && statusMap[error.response?.data?.level]) ?? "error";
2020-03-22 11:43:14 -07:00
useEffect(() => {
!loading && resultsComplete === null && setComplete(index);
}, [loading, resultsComplete]);
useEffect(() => {
resultsComplete === index && !hasOverride && setOpen(true);
}, [resultsComplete, index]);
2020-01-17 02:50:57 -07:00
return (
<AccordionItem
2020-03-22 11:43:14 -07:00
isOpen={isOpen}
2020-01-17 02:50:57 -07:00
isDisabled={loading}
ref={ref}
2020-01-20 00:37:04 -07:00
css={css({
2020-01-17 02:50:57 -07:00
"&:last-of-type": { borderBottom: "none" },
2020-04-15 10:43:34 -07:00
"&:first-of-type": { borderTop: "none" },
2020-01-20 00:37:04 -07:00
})}
2020-01-17 02:50:57 -07:00
>
2020-01-20 00:37:04 -07:00
<AccordionHeaderWrapper hoverBg={theme.colors.blackAlpha[50]}>
2020-03-22 11:43:14 -07:00
<AccordionHeader
flex="1 0 auto"
py={2}
_hover={{}}
_focus={{}}
w="unset"
onClick={handleToggle}
>
2020-01-26 02:24:12 -07:00
<ResultHeader
title={device.display_name}
loading={loading}
error={error}
errorMsg={errorMsg}
errorLevel={errorLevel}
/>
2020-01-20 00:37:04 -07:00
</AccordionHeader>
<ButtonGroup px={3} py={2}>
2020-01-26 02:24:12 -07:00
<CopyButton copyValue={cleanOutput} variant="ghost" isDisabled={loading} />
<RequeryButton requery={refetch} variant="ghost" isDisabled={loading} />
2020-01-20 00:37:04 -07:00
</ButtonGroup>
</AccordionHeaderWrapper>
<AccordionPanel
pb={4}
overflowX="auto"
css={css({ WebkitOverflowScrolling: "touch" })}
>
<Flex direction="row" flexWrap="wrap">
2020-03-23 01:10:27 -07:00
<Flex direction="column" flex="1 0 auto" maxW={error ? "100%" : null}>
{data && !error && (
2020-01-20 00:37:04 -07:00
<Box
fontFamily="mono"
mt={5}
mx={2}
p={3}
border="1px"
borderColor="inherit"
rounded="md"
bg={bg[colorMode]}
color={color[colorMode]}
fontSize="sm"
whiteSpace="pre-wrap"
as="pre"
css={css({
"&::selection": {
backgroundColor: selectionBg[colorMode],
2020-04-15 10:43:34 -07:00
color: selectionColor[colorMode],
},
2020-01-20 00:37:04 -07:00
})}
>
{cleanOutput}
</Box>
)}
{error && (
2020-01-26 02:24:12 -07:00
<Alert rounded="lg" my={2} py={4} status={errorLevel}>
2020-01-20 00:37:04 -07:00
<FormattedError keywords={errorKw} message={errorMsg} />
2020-03-23 01:10:27 -07:00
{/* {errorMsg} */}
2020-01-20 00:37:04 -07:00
</Alert>
)}
</Flex>
2020-01-17 02:50:57 -07:00
</Flex>
2020-03-23 01:10:27 -07:00
{config.cache.show_text && (
<Flex direction="row" flexWrap="wrap">
<Flex
px={3}
mt={2}
justifyContent={[
"flex-start",
"flex-start",
"flex-end",
2020-04-15 10:43:34 -07:00
"flex-end",
2020-03-23 01:10:27 -07:00
]}
flex="1 0 auto"
>
<Text fontSize="xs" color="gray.500">
{config.web.text.cache}
</Text>
</Flex>
</Flex>
)}
2020-01-17 02:50:57 -07:00
</AccordionPanel>
</AccordionItem>
);
}
);
2020-01-20 00:37:04 -07:00
Result.displayName = "HyperglassQueryResult";
export default Result;