mirror of
https://github.com/checktheroads/hyperglass
synced 2024-05-11 05:55:08 +00:00
allow static bgp community definitions
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
"""Validate query configuration parameters."""
|
"""Validate query configuration parameters."""
|
||||||
|
|
||||||
|
# Standard Library
|
||||||
|
from typing import List
|
||||||
|
|
||||||
# Third Party
|
# Third Party
|
||||||
from pydantic import Field, StrictStr, StrictBool, constr
|
from pydantic import Field, StrictStr, StrictBool, constr
|
||||||
|
|
||||||
@@ -8,25 +11,7 @@ from hyperglass.models import HyperglassModel
|
|||||||
from hyperglass.constants import SUPPORTED_QUERY_TYPES
|
from hyperglass.constants import SUPPORTED_QUERY_TYPES
|
||||||
|
|
||||||
|
|
||||||
class HyperglassLevel3(HyperglassModel):
|
class BgpCommunityPattern(HyperglassModel):
|
||||||
"""Automatic docs sorting subclass."""
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
"""Pydantic model configuration."""
|
|
||||||
|
|
||||||
schema_extra = {"level": 3}
|
|
||||||
|
|
||||||
|
|
||||||
class HyperglassLevel4(HyperglassModel):
|
|
||||||
"""Automatic docs sorting subclass."""
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
"""Pydantic model configuration."""
|
|
||||||
|
|
||||||
schema_extra = {"level": 4}
|
|
||||||
|
|
||||||
|
|
||||||
class BgpCommunityPattern(HyperglassLevel4):
|
|
||||||
"""Validation model for bgp_community regex patterns."""
|
"""Validation model for bgp_community regex patterns."""
|
||||||
|
|
||||||
decimal: StrictStr = Field(
|
decimal: StrictStr = Field(
|
||||||
@@ -54,7 +39,7 @@ class BgpCommunityPattern(HyperglassLevel4):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BgpAsPathPattern(HyperglassLevel4):
|
class BgpAsPathPattern(HyperglassModel):
|
||||||
"""Validation model for bgp_aspath regex patterns."""
|
"""Validation model for bgp_aspath regex patterns."""
|
||||||
|
|
||||||
mode: constr(regex=r"asplain|asdot") = Field(
|
mode: constr(regex=r"asplain|asdot") = Field(
|
||||||
@@ -82,7 +67,15 @@ class BgpAsPathPattern(HyperglassLevel4):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BgpCommunity(HyperglassLevel3):
|
class Community(HyperglassModel):
|
||||||
|
"""Validation model for bgp_community communities."""
|
||||||
|
|
||||||
|
display_name: StrictStr
|
||||||
|
description: StrictStr
|
||||||
|
community: StrictStr
|
||||||
|
|
||||||
|
|
||||||
|
class BgpCommunity(HyperglassModel):
|
||||||
"""Validation model for bgp_community configuration."""
|
"""Validation model for bgp_community configuration."""
|
||||||
|
|
||||||
enable: StrictBool = Field(
|
enable: StrictBool = Field(
|
||||||
@@ -96,9 +89,11 @@ class BgpCommunity(HyperglassLevel3):
|
|||||||
description="Text displayed for the BGP Community query type in the hyperglas UI.",
|
description="Text displayed for the BGP Community query type in the hyperglas UI.",
|
||||||
)
|
)
|
||||||
pattern: BgpCommunityPattern = BgpCommunityPattern()
|
pattern: BgpCommunityPattern = BgpCommunityPattern()
|
||||||
|
mode: constr(regex=r"(input|select)") = "input"
|
||||||
|
communities: List[Community] = []
|
||||||
|
|
||||||
|
|
||||||
class BgpRoute(HyperglassLevel3):
|
class BgpRoute(HyperglassModel):
|
||||||
"""Validation model for bgp_route configuration."""
|
"""Validation model for bgp_route configuration."""
|
||||||
|
|
||||||
enable: StrictBool = Field(
|
enable: StrictBool = Field(
|
||||||
@@ -111,7 +106,7 @@ class BgpRoute(HyperglassLevel3):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BgpAsPath(HyperglassLevel3):
|
class BgpAsPath(HyperglassModel):
|
||||||
"""Validation model for bgp_aspath configuration."""
|
"""Validation model for bgp_aspath configuration."""
|
||||||
|
|
||||||
enable: StrictBool = Field(
|
enable: StrictBool = Field(
|
||||||
@@ -127,7 +122,7 @@ class BgpAsPath(HyperglassLevel3):
|
|||||||
pattern: BgpAsPathPattern = BgpAsPathPattern()
|
pattern: BgpAsPathPattern = BgpAsPathPattern()
|
||||||
|
|
||||||
|
|
||||||
class Ping(HyperglassLevel3):
|
class Ping(HyperglassModel):
|
||||||
"""Validation model for ping configuration."""
|
"""Validation model for ping configuration."""
|
||||||
|
|
||||||
enable: StrictBool = Field(
|
enable: StrictBool = Field(
|
||||||
@@ -140,7 +135,7 @@ class Ping(HyperglassLevel3):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Traceroute(HyperglassLevel3):
|
class Traceroute(HyperglassModel):
|
||||||
"""Validation model for traceroute configuration."""
|
"""Validation model for traceroute configuration."""
|
||||||
|
|
||||||
enable: StrictBool = Field(
|
enable: StrictBool = Field(
|
||||||
@@ -168,8 +163,9 @@ class Queries(HyperglassModel):
|
|||||||
query_obj = getattr(self, query)
|
query_obj = getattr(self, query)
|
||||||
_map[query] = {
|
_map[query] = {
|
||||||
"name": query,
|
"name": query,
|
||||||
"display_name": query_obj.display_name,
|
**query_obj.export_dict(
|
||||||
"enable": query_obj.enable,
|
include={"display_name", "enable", "mode", "communities"}
|
||||||
|
),
|
||||||
}
|
}
|
||||||
return _map
|
return _map
|
||||||
|
|
||||||
@@ -225,4 +221,3 @@ class Queries(HyperglassModel):
|
|||||||
"description": "Enable, disable, or configure the Traceroute query type.",
|
"description": "Enable, disable, or configure the Traceroute query type.",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
schema_extra = {"level": 2}
|
|
||||||
|
@@ -3,139 +3,151 @@ import { Text, useColorMode, useTheme } from "@chakra-ui/core";
|
|||||||
import Select from "react-select";
|
import Select from "react-select";
|
||||||
import { opposingColor } from "~/util";
|
import { opposingColor } from "~/util";
|
||||||
|
|
||||||
export default ({ placeholder = "Select...", isFullWidth, size, children, ...props }) => {
|
const ChakraSelect = React.forwardRef(
|
||||||
const theme = useTheme();
|
({ placeholder = "Select...", isFullWidth, size, children, ...props }, ref) => {
|
||||||
const { colorMode } = useColorMode();
|
const theme = useTheme();
|
||||||
const sizeMap = {
|
const { colorMode } = useColorMode();
|
||||||
lg: { height: theme.space[12] },
|
const sizeMap = {
|
||||||
md: { height: theme.space[10] },
|
lg: { height: theme.space[12] },
|
||||||
sm: { height: theme.space[8] }
|
md: { height: theme.space[10] },
|
||||||
};
|
sm: { height: theme.space[8] },
|
||||||
const colorSetPrimaryBg = { dark: theme.colors.primary[300], light: theme.colors.primary[500] };
|
};
|
||||||
const colorSetPrimaryColor = opposingColor(theme, colorSetPrimaryBg[colorMode]);
|
const colorSetPrimaryBg = {
|
||||||
const bg = { dark: theme.colors.whiteAlpha[100], light: theme.colors.white };
|
dark: theme.colors.primary[300],
|
||||||
const color = { dark: theme.colors.whiteAlpha[800], light: theme.colors.black };
|
light: theme.colors.primary[500],
|
||||||
const borderFocused = theme.colors.secondary[500];
|
};
|
||||||
const borderDisabled = theme.colors.whiteAlpha[100];
|
const colorSetPrimaryColor = opposingColor(theme, colorSetPrimaryBg[colorMode]);
|
||||||
const border = { dark: theme.colors.whiteAlpha[50], light: theme.colors.gray[100] };
|
const bg = { dark: theme.colors.whiteAlpha[100], light: theme.colors.white };
|
||||||
const borderRadius = theme.space[1];
|
const color = { dark: theme.colors.whiteAlpha[800], light: theme.colors.black };
|
||||||
const hoverColor = { dark: theme.colors.whiteAlpha[200], light: theme.colors.gray[300] };
|
const borderFocused = theme.colors.secondary[500];
|
||||||
const { height } = sizeMap[size];
|
const borderDisabled = theme.colors.whiteAlpha[100];
|
||||||
const optionBgActive = { dark: theme.colors.primary[400], light: theme.colors.primary[600] };
|
const border = { dark: theme.colors.whiteAlpha[50], light: theme.colors.gray[100] };
|
||||||
const optionBgColor = opposingColor(theme, optionBgActive[colorMode]);
|
const borderRadius = theme.space[1];
|
||||||
const optionSelectedBg = {
|
const hoverColor = { dark: theme.colors.whiteAlpha[200], light: theme.colors.gray[300] };
|
||||||
dark: theme.colors.whiteAlpha[400],
|
const { height } = sizeMap[size];
|
||||||
light: theme.colors.blackAlpha[400]
|
const optionBgActive = {
|
||||||
};
|
dark: theme.colors.primary[400],
|
||||||
const optionSelectedColor = opposingColor(theme, optionSelectedBg[colorMode]);
|
light: theme.colors.primary[600],
|
||||||
const selectedDisabled = theme.colors.whiteAlpha[400];
|
};
|
||||||
const placeholderColor = {
|
const optionBgColor = opposingColor(theme, optionBgActive[colorMode]);
|
||||||
dark: theme.colors.whiteAlpha[400],
|
const optionSelectedBg = {
|
||||||
light: theme.colors.gray[400]
|
dark: theme.colors.whiteAlpha[400],
|
||||||
};
|
light: theme.colors.blackAlpha[400],
|
||||||
const menuBg = { dark: theme.colors.black, light: theme.colors.white };
|
};
|
||||||
const menuColor = { dark: theme.colors.white, light: theme.colors.blackAlpha[800] };
|
const optionSelectedColor = opposingColor(theme, optionSelectedBg[colorMode]);
|
||||||
return (
|
const selectedDisabled = theme.colors.whiteAlpha[400];
|
||||||
<Select
|
const placeholderColor = {
|
||||||
styles={{
|
dark: theme.colors.whiteAlpha[400],
|
||||||
container: base => ({
|
light: theme.colors.gray[400],
|
||||||
...base,
|
};
|
||||||
minHeight: height,
|
const menuBg = { dark: theme.colors.black, light: theme.colors.white };
|
||||||
borderRadius: borderRadius,
|
const menuColor = { dark: theme.colors.white, light: theme.colors.blackAlpha[800] };
|
||||||
width: "100%"
|
return (
|
||||||
}),
|
<Select
|
||||||
control: (base, state) => ({
|
ref={ref}
|
||||||
...base,
|
styles={{
|
||||||
minHeight: height,
|
container: (base) => ({
|
||||||
backgroundColor: bg[colorMode],
|
...base,
|
||||||
color: color[colorMode],
|
minHeight: height,
|
||||||
borderColor: state.isDisabled
|
borderRadius: borderRadius,
|
||||||
? borderDisabled
|
width: "100%",
|
||||||
: state.isFocused
|
}),
|
||||||
? borderFocused
|
control: (base, state) => ({
|
||||||
: border[colorMode],
|
...base,
|
||||||
borderRadius: borderRadius,
|
minHeight: height,
|
||||||
"&:hover": {
|
backgroundColor: bg[colorMode],
|
||||||
borderColor: hoverColor[colorMode]
|
color: color[colorMode],
|
||||||
}
|
borderColor: state.isDisabled
|
||||||
}),
|
? borderDisabled
|
||||||
menu: base => ({
|
: state.isFocused
|
||||||
...base,
|
? borderFocused
|
||||||
backgroundColor: menuBg[colorMode],
|
: border[colorMode],
|
||||||
borderRadius: borderRadius
|
borderRadius: borderRadius,
|
||||||
}),
|
"&:hover": {
|
||||||
option: (base, state) => ({
|
borderColor: hoverColor[colorMode],
|
||||||
...base,
|
},
|
||||||
backgroundColor: state.isDisabled
|
}),
|
||||||
? selectedDisabled
|
menu: (base) => ({
|
||||||
: state.isSelected
|
...base,
|
||||||
? optionSelectedBg[colorMode]
|
backgroundColor: menuBg[colorMode],
|
||||||
: state.isFocused
|
borderRadius: borderRadius,
|
||||||
? colorSetPrimaryBg[colorMode]
|
}),
|
||||||
: "transparent",
|
option: (base, state) => ({
|
||||||
color: state.isDisabled
|
...base,
|
||||||
? selectedDisabled
|
backgroundColor: state.isDisabled
|
||||||
: state.isFocused
|
? selectedDisabled
|
||||||
? colorSetPrimaryColor
|
: state.isSelected
|
||||||
: state.isSelected
|
? optionSelectedBg[colorMode]
|
||||||
? optionSelectedColor
|
: state.isFocused
|
||||||
: menuColor[colorMode],
|
? colorSetPrimaryBg[colorMode]
|
||||||
fontSize: theme.fontSizes[size],
|
: "transparent",
|
||||||
"&:active": {
|
color: state.isDisabled
|
||||||
backgroundColor: optionBgActive[colorMode],
|
? selectedDisabled
|
||||||
color: optionBgColor
|
: state.isFocused
|
||||||
}
|
? colorSetPrimaryColor
|
||||||
}),
|
: state.isSelected
|
||||||
indicatorSeparator: base => ({
|
? optionSelectedColor
|
||||||
...base,
|
: menuColor[colorMode],
|
||||||
backgroundColor: placeholderColor[colorMode]
|
fontSize: theme.fontSizes[size],
|
||||||
}),
|
"&:active": {
|
||||||
dropdownIndicator: base => ({
|
backgroundColor: optionBgActive[colorMode],
|
||||||
...base,
|
color: optionBgColor,
|
||||||
color: placeholderColor[colorMode],
|
},
|
||||||
"&:hover": {
|
}),
|
||||||
color: color[colorMode]
|
indicatorSeparator: (base) => ({
|
||||||
}
|
...base,
|
||||||
}),
|
backgroundColor: placeholderColor[colorMode],
|
||||||
valueContainer: base => ({
|
}),
|
||||||
...base,
|
dropdownIndicator: (base) => ({
|
||||||
paddingLeft: theme.space[4],
|
...base,
|
||||||
paddingRight: theme.space[4]
|
color: placeholderColor[colorMode],
|
||||||
}),
|
"&:hover": {
|
||||||
multiValue: base => ({
|
color: color[colorMode],
|
||||||
...base,
|
},
|
||||||
backgroundColor: colorSetPrimaryBg[colorMode]
|
}),
|
||||||
}),
|
valueContainer: (base) => ({
|
||||||
multiValueLabel: base => ({
|
...base,
|
||||||
...base,
|
paddingLeft: theme.space[4],
|
||||||
color: colorSetPrimaryColor
|
paddingRight: theme.space[4],
|
||||||
}),
|
}),
|
||||||
multiValueRemove: base => ({
|
multiValue: (base) => ({
|
||||||
...base,
|
...base,
|
||||||
color: colorSetPrimaryColor,
|
backgroundColor: colorSetPrimaryBg[colorMode],
|
||||||
"&:hover": {
|
}),
|
||||||
|
multiValueLabel: (base) => ({
|
||||||
|
...base,
|
||||||
color: colorSetPrimaryColor,
|
color: colorSetPrimaryColor,
|
||||||
backgroundColor: "inherit"
|
}),
|
||||||
}
|
multiValueRemove: (base) => ({
|
||||||
}),
|
...base,
|
||||||
singleValue: base => ({
|
color: colorSetPrimaryColor,
|
||||||
...base,
|
"&:hover": {
|
||||||
color: color[colorMode],
|
color: colorSetPrimaryColor,
|
||||||
fontSize: theme.fontSizes[size]
|
backgroundColor: "inherit",
|
||||||
})
|
},
|
||||||
}}
|
}),
|
||||||
placeholder={
|
singleValue: (base) => ({
|
||||||
<Text
|
...base,
|
||||||
color={placeholderColor[colorMode]}
|
color: color[colorMode],
|
||||||
fontSize={size}
|
fontSize: theme.fontSizes[size],
|
||||||
fontFamily={theme.fonts.body}
|
}),
|
||||||
>
|
}}
|
||||||
{placeholder}
|
placeholder={
|
||||||
</Text>
|
<Text
|
||||||
}
|
color={placeholderColor[colorMode]}
|
||||||
{...props}
|
fontSize={size}
|
||||||
>
|
fontFamily={theme.fonts.body}
|
||||||
{children}
|
>
|
||||||
</Select>
|
{placeholder}
|
||||||
);
|
</Text>
|
||||||
};
|
}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
ChakraSelect.displayName = "ChakraSelect";
|
||||||
|
export default ChakraSelect;
|
||||||
|
41
hyperglass/ui/components/CommunitySelect.js
Normal file
41
hyperglass/ui/components/CommunitySelect.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { Text } from "@chakra-ui/core";
|
||||||
|
import { components } from "react-select";
|
||||||
|
import ChakraSelect from "~/components/ChakraSelect";
|
||||||
|
|
||||||
|
const CommunitySelect = ({ name, communities, onChange, register, unregister }) => {
|
||||||
|
const communitySelections = communities.map((c) => {
|
||||||
|
return { value: c.community, label: c.display_name, description: c.description };
|
||||||
|
});
|
||||||
|
const Option = ({ label, data, ...props }) => {
|
||||||
|
return (
|
||||||
|
<components.Option {...props}>
|
||||||
|
<Text>{label}</Text>
|
||||||
|
<Text fontSize="xs" as="span">
|
||||||
|
{data.description}
|
||||||
|
</Text>
|
||||||
|
</components.Option>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
register({ name });
|
||||||
|
return () => unregister(name);
|
||||||
|
}, [name, register, unregister]);
|
||||||
|
return (
|
||||||
|
<ChakraSelect
|
||||||
|
innerRef={register}
|
||||||
|
size="lg"
|
||||||
|
name={name}
|
||||||
|
onChange={(e) => {
|
||||||
|
onChange({ field: name, value: e.value || "" });
|
||||||
|
}}
|
||||||
|
options={communitySelections}
|
||||||
|
components={{ Option }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
CommunitySelect.displayName = "CommunitySelect";
|
||||||
|
|
||||||
|
export default CommunitySelect;
|
@@ -1,4 +1,5 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import * as React from "react";
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
import { Box, Flex } from "@chakra-ui/core";
|
import { Box, Flex } from "@chakra-ui/core";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import lodash from "lodash";
|
import lodash from "lodash";
|
||||||
@@ -9,6 +10,7 @@ import HelpModal from "~/components/HelpModal";
|
|||||||
import QueryLocation from "~/components/QueryLocation";
|
import QueryLocation from "~/components/QueryLocation";
|
||||||
import QueryType from "~/components/QueryType";
|
import QueryType from "~/components/QueryType";
|
||||||
import QueryTarget from "~/components/QueryTarget";
|
import QueryTarget from "~/components/QueryTarget";
|
||||||
|
import CommunitySelect from "~/components/CommunitySelect";
|
||||||
import QueryVrf from "~/components/QueryVrf";
|
import QueryVrf from "~/components/QueryVrf";
|
||||||
import ResolvedTarget from "~/components/ResolvedTarget";
|
import ResolvedTarget from "~/components/ResolvedTarget";
|
||||||
import SubmitButton from "~/components/SubmitButton";
|
import SubmitButton from "~/components/SubmitButton";
|
||||||
@@ -46,9 +48,9 @@ const FormRow = ({ children, ...props }) => (
|
|||||||
const HyperglassForm = React.forwardRef(
|
const HyperglassForm = React.forwardRef(
|
||||||
({ isSubmitting, setSubmitting, setFormData, greetingAck, setGreetingAck, ...props }, ref) => {
|
({ isSubmitting, setSubmitting, setFormData, greetingAck, setGreetingAck, ...props }, ref) => {
|
||||||
const config = useConfig();
|
const config = useConfig();
|
||||||
const { handleSubmit, register, setValue, errors } = useForm({
|
const { handleSubmit, register, unregister, setValue, errors } = useForm({
|
||||||
validationSchema: formSchema(config),
|
validationSchema: formSchema(config),
|
||||||
defaultValues: { query_vrf: "default" },
|
defaultValues: { query_vrf: "default", query_target: "" },
|
||||||
});
|
});
|
||||||
|
|
||||||
const [queryLocation, setQueryLocation] = useState([]);
|
const [queryLocation, setQueryLocation] = useState([]);
|
||||||
@@ -136,10 +138,10 @@ const HyperglassForm = React.forwardRef(
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
register({ name: "query_location" });
|
register({ name: "query_location" });
|
||||||
register({ name: "query_target" });
|
|
||||||
register({ name: "query_type" });
|
register({ name: "query_type" });
|
||||||
register({ name: "query_vrf" });
|
register({ name: "query_vrf" });
|
||||||
});
|
}, [register]);
|
||||||
|
Object.keys(errors).length >= 1 && console.error(errors);
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
maxW={["100%", "100%", "75%", "75%"]}
|
maxW={["100%", "100%", "75%", "75%"]}
|
||||||
@@ -202,19 +204,31 @@ const HyperglassForm = React.forwardRef(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<QueryTarget
|
{queryType === "bgp_community" &&
|
||||||
name="query_target"
|
config.queries.bgp_community.mode === "select" ? (
|
||||||
placeholder={config.web.text.query_target}
|
<CommunitySelect
|
||||||
register={register}
|
name="query_target"
|
||||||
resolveTarget={["ping", "traceroute", "bgp_route"].includes(
|
register={register}
|
||||||
queryType
|
unregister={unregister}
|
||||||
)}
|
onChange={handleChange}
|
||||||
value={queryTarget}
|
communities={config.queries.bgp_community.communities}
|
||||||
setFqdn={setFqdnTarget}
|
/>
|
||||||
setTarget={handleChange}
|
) : (
|
||||||
displayValue={displayTarget}
|
<QueryTarget
|
||||||
setDisplayValue={setDisplayTarget}
|
name="query_target"
|
||||||
/>
|
placeholder={config.web.text.query_target}
|
||||||
|
register={register}
|
||||||
|
unregister={unregister}
|
||||||
|
resolveTarget={["ping", "traceroute", "bgp_route"].includes(
|
||||||
|
queryType
|
||||||
|
)}
|
||||||
|
value={queryTarget}
|
||||||
|
setFqdn={setFqdnTarget}
|
||||||
|
setTarget={handleChange}
|
||||||
|
displayValue={displayTarget}
|
||||||
|
setDisplayValue={setDisplayTarget}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</FormField>
|
</FormField>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<FormRow mt={0} justifyContent="flex-end">
|
<FormRow mt={0} justifyContent="flex-end">
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import ChakraSelect from "~/components/ChakraSelect";
|
import ChakraSelect from "~/components/ChakraSelect";
|
||||||
|
|
||||||
const buildLocations = networks => {
|
const buildLocations = (networks) => {
|
||||||
const locations = [];
|
const locations = [];
|
||||||
networks.map(net => {
|
networks.map((net) => {
|
||||||
const netLocations = [];
|
const netLocations = [];
|
||||||
net.locations.map(loc => {
|
net.locations.map((loc) => {
|
||||||
netLocations.push({
|
netLocations.push({
|
||||||
label: loc.display_name,
|
label: loc.display_name,
|
||||||
value: loc.name,
|
value: loc.name,
|
||||||
group: net.display_name
|
group: net.display_name,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
locations.push({ label: net.display_name, options: netLocations });
|
locations.push({ label: net.display_name, options: netLocations });
|
||||||
@@ -19,10 +19,10 @@ const buildLocations = networks => {
|
|||||||
|
|
||||||
export default ({ locations, onChange }) => {
|
export default ({ locations, onChange }) => {
|
||||||
const options = buildLocations(locations);
|
const options = buildLocations(locations);
|
||||||
const handleChange = e => {
|
const handleChange = (e) => {
|
||||||
const selected = [];
|
const selected = [];
|
||||||
e &&
|
e &&
|
||||||
e.map(sel => {
|
e.map((sel) => {
|
||||||
selected.push(sel.value);
|
selected.push(sel.value);
|
||||||
});
|
});
|
||||||
onChange({ field: "query_location", value: selected });
|
onChange({ field: "query_location", value: selected });
|
||||||
@@ -34,6 +34,7 @@ export default ({ locations, onChange }) => {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
options={options}
|
options={options}
|
||||||
isMulti
|
isMulti
|
||||||
|
closeMenuOnSelect={false}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useEffect } from "react";
|
||||||
import styled from "@emotion/styled";
|
import styled from "@emotion/styled";
|
||||||
import { Input, useColorMode } from "@chakra-ui/core";
|
import { Input, useColorMode } from "@chakra-ui/core";
|
||||||
|
|
||||||
const StyledInput = styled(Input)`
|
const StyledInput = styled(Input)`
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: ${props => props.placeholderColor};
|
color: ${(props) => props.placeholderColor};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -18,13 +18,14 @@ const placeholderColor = { dark: "whiteAlpha.400", light: "gray.400" };
|
|||||||
const QueryTarget = ({
|
const QueryTarget = ({
|
||||||
placeholder,
|
placeholder,
|
||||||
register,
|
register,
|
||||||
|
unregister,
|
||||||
setFqdn,
|
setFqdn,
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
setTarget,
|
setTarget,
|
||||||
resolveTarget,
|
resolveTarget,
|
||||||
displayValue,
|
displayValue,
|
||||||
setDisplayValue
|
setDisplayValue,
|
||||||
}) => {
|
}) => {
|
||||||
const { colorMode } = useColorMode();
|
const { colorMode } = useColorMode();
|
||||||
|
|
||||||
@@ -35,15 +36,19 @@ const QueryTarget = ({
|
|||||||
setFqdn(false);
|
setFqdn(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleChange = e => {
|
const handleChange = (e) => {
|
||||||
setDisplayValue(e.target.value);
|
setDisplayValue(e.target.value);
|
||||||
setTarget({ field: name, value: e.target.value });
|
setTarget({ field: name, value: e.target.value });
|
||||||
};
|
};
|
||||||
const handleKeyDown = e => {
|
const handleKeyDown = (e) => {
|
||||||
if ([9, 13].includes(e.keyCode)) {
|
if ([9, 13].includes(e.keyCode)) {
|
||||||
handleBlur();
|
handleBlur();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
register({ name });
|
||||||
|
return () => unregister(name);
|
||||||
|
}, [register, unregister, name]);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<input hidden readOnly name={name} ref={register} value={value} />
|
<input hidden readOnly name={name} ref={register} value={value} />
|
||||||
|
@@ -13,7 +13,7 @@ const labelBgSuccess = { dark: "success", light: "success" };
|
|||||||
async function containingPrefix(ipAddress) {
|
async function containingPrefix(ipAddress) {
|
||||||
try {
|
try {
|
||||||
const prefixData = await axios.get("https://stat.ripe.net/data/network-info/data.json", {
|
const prefixData = await axios.get("https://stat.ripe.net/data/network-info/data.json", {
|
||||||
params: { resource: ipAddress }
|
params: { resource: ipAddress },
|
||||||
});
|
});
|
||||||
return prefixData.data?.data?.prefix;
|
return prefixData.data?.data?.prefix;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -36,32 +36,32 @@ const ResolvedTarget = React.forwardRef(
|
|||||||
params: { name: fqdnTarget, type: "A" },
|
params: { name: fqdnTarget, type: "A" },
|
||||||
headers: { accept: "application/dns-json" },
|
headers: { accept: "application/dns-json" },
|
||||||
crossdomain: true,
|
crossdomain: true,
|
||||||
timeout: 1000
|
timeout: 1000,
|
||||||
},
|
},
|
||||||
6: {
|
6: {
|
||||||
url: dnsUrl,
|
url: dnsUrl,
|
||||||
params: { name: fqdnTarget, type: "AAAA" },
|
params: { name: fqdnTarget, type: "AAAA" },
|
||||||
headers: { accept: "application/dns-json" },
|
headers: { accept: "application/dns-json" },
|
||||||
crossdomain: true,
|
crossdomain: true,
|
||||||
timeout: 1000
|
timeout: 1000,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const [{ data: data4, loading: loading4, error: error4 }] = useAxios(params[4]);
|
const [{ data: data4, loading: loading4, error: error4 }] = useAxios(params[4]);
|
||||||
|
|
||||||
const [{ data: data6, loading: loading6, error: error6 }] = useAxios(params[6]);
|
const [{ data: data6, loading: loading6, error: error6 }] = useAxios(params[6]);
|
||||||
|
|
||||||
const handleOverride = overridden => {
|
const handleOverride = (overridden) => {
|
||||||
setTarget({ field: "query_target", value: overridden });
|
setTarget({ field: "query_target", value: overridden });
|
||||||
};
|
};
|
||||||
|
|
||||||
const isSelected = value => {
|
const isSelected = (value) => {
|
||||||
return labelBgStatus[value === queryTarget];
|
return labelBgStatus[value === queryTarget];
|
||||||
};
|
};
|
||||||
|
|
||||||
const findAnswer = data => {
|
const findAnswer = (data) => {
|
||||||
return data?.Answer?.filter(
|
return data?.Answer?.filter(
|
||||||
answerData => answerData.type === data?.Question[0]?.type
|
(answerData) => answerData.type === data?.Question[0]?.type
|
||||||
)[0]?.data;
|
)[0]?.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,7 +74,6 @@ const ResolvedTarget = React.forwardRef(
|
|||||||
handleOverride(findAnswer(data4));
|
handleOverride(findAnswer(data4));
|
||||||
}
|
}
|
||||||
}, [data4, data6]);
|
}, [data4, data6]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
Reference in New Issue
Block a user