@veecode-platform/plugin-kong-service-manager
Version:
395 lines (392 loc) • 16.1 kB
JavaScript
import React from 'react';
import { Modal, Fade, Box, Paper, Typography, Tooltip, IconButton, Grid, TextField, Divider, FormControl, InputLabel, Select, MenuItem, Card, Collapse, FormGroup, FormControlLabel, Checkbox, Button } from '@material-ui/core';
import Stack from '@mui/material/Stack';
import { useModalComponentStyles } from './styles.esm.js';
import StringInputList from '../StringInputList/StringInputList.esm.js';
import { convertToHeadersObject } from '../../../utils/helpers/convertoToHeadersObject.esm.js';
import { RedirectStatusCode } from '../../../utils/enums/KongRouteRedirectStatusCode.esm.js';
import { ProtocolDescriptions, Protocols } from '../../../utils/enums/KongRouteProtocols.esm.js';
import DynamicFields from './DynamicFields.esm.js';
import { convertToArrayOfObjects, convertToObjArray } from '../../../utils/helpers/convertToArrayOfObjects.esm.js';
import { prepareDestinations, prepareSources } from '../../../utils/helpers/preparePayload.esm.js';
import '../../../context/KongServiceManagerContext.esm.js';
import { useKongServiceManagerContext } from '../../../context/KongServiceManagerProvider.esm.js';
import '@backstage/core-components';
import '@backstage/plugin-catalog-react';
import '@material-ui/lab';
import '@material-ui/core/InputBase';
import '@material-ui/icons/Search';
import '../../shared/SearchBar/styles.esm.js';
import '../../shared/BoxComponent/styles.esm.js';
import 'react-router-dom';
import { CircleCloseIcon, DropUpIcon, DropDownIcon } from '../../shared/icons/Icons.esm.js';
import '../../shared/SelectComponent/Select.esm.js';
import '../../shared/HtmlTooltip/HtmlTooltip.esm.js';
import '../../shared/ButtonComponent/styles.esm.js';
import '../../shared/LoadingComponent/styles.esm.js';
import '../../shared/MissingAnnotation/styles.esm.js';
import '../../shared/Fields/Fields.esm.js';
import '../../shared/SkeletonComponent/styles.esm.js';
const ModalComponent = (props) => {
const [showFields, setShowFields] = React.useState(false);
const [name, setName] = React.useState("");
const [tags, setTags] = React.useState([]);
const [protocols, setProtocols] = React.useState("http,https");
const [protocolDescription, setProtocolDescription] = React.useState(
ProtocolDescriptions.HTTP_HTTPS
);
const [hosts, setHosts] = React.useState([]);
const [paths, setPaths] = React.useState([]);
const [snis, setSnis] = React.useState([]);
const [headers, setHeaders] = React.useState(
[]
);
const [sources, setSources] = React.useState(
[]
);
const [destinations, setDestinations] = React.useState([]);
const [methods, setMethods] = React.useState([]);
const [httpsRedirectStatusCode, setHttpsRedirectStatusCode] = React.useState(426);
const [regexPriority, setRegexPriority] = React.useState(0);
const [stripPath, setStripPath] = React.useState(true);
const [preserveHost, setPreserveHost] = React.useState(false);
const [requestBuffering, setRequestBuffering] = React.useState(true);
const [responseBuffering, setResponseBuffering] = React.useState(true);
const { show, handleCloseModal, route, refreshList } = props;
const {
fieldContent,
modalOnBlur,
modalContent,
modalHeader,
modalBody,
container,
titleBar,
content
} = useModalComponentStyles();
const { createRoute, editRoute, getRoute } = useKongServiceManagerContext();
const handleChange = (event, setState, transformFn) => {
if (Array.isArray(event)) {
setState(event);
} else {
const { value, checked } = event.target;
if (transformFn) {
setState(transformFn(value, checked));
} else {
setState(value);
}
}
};
const getProtocolDescription = (protocol) => {
const normalizedProtocol = protocol.replace(/,/g, "_");
return ProtocolDescriptions[normalizedProtocol.toUpperCase()] || "";
};
const isSaveDisabled = React.useMemo(() => {
return !(name !== "" && (hosts.length > 0 || paths.length > 0 || snis.length > 0 || headers.length > 0 || sources.length > 0 || destinations.length > 0));
}, [hosts, paths, snis, headers, sources, destinations, methods]);
const handleSaveRoute = async () => {
const fields = protocolDescription.split(", ");
const data = fields.reduce((acc, field) => {
switch (field.toLowerCase()) {
case "hosts":
acc.hosts = hosts.map((obj) => obj.value);
break;
case "paths":
acc.paths = paths.map((obj) => obj.value);
break;
case "snis":
acc.snis = snis.map((obj) => obj.value);
break;
case "headers":
acc.headers = convertToHeadersObject(headers);
break;
case "sources":
acc.sources = prepareSources(sources);
break;
case "destinations":
acc.destinations = prepareDestinations(destinations);
break;
case "methods":
acc.methods = methods;
break;
}
return acc;
}, {});
const config = {
name: name.replaceAll(" ", "_"),
protocols: protocols.split(","),
tags: tags.map((obj) => obj.value),
https_redirect_status_code: httpsRedirectStatusCode,
regex_priority: regexPriority,
strip_path: stripPath,
preserve_host: preserveHost,
request_buffering: requestBuffering,
response_buffering: responseBuffering,
path_handling: "v0",
...data
};
try {
if (route.id) {
await editRoute(config);
refreshList();
handleCloseModal({});
return;
}
const createResult = await createRoute(config);
if (createResult) {
refreshList();
handleCloseModal({});
}
} catch (error) {
console.error("Error saving route:", error);
}
};
const handleTextClick = () => {
setShowFields(!showFields);
};
React.useEffect(() => {
if (show && route.id) {
const fetchData = async () => {
const response = await getRoute(route.id);
setName(response?.name || "");
setTags(convertToArrayOfObjects(response?.tags));
setProtocols(response?.protocols.toString() || "");
setHosts(convertToArrayOfObjects(response?.hosts));
setPaths(convertToArrayOfObjects(response?.paths));
setSnis(convertToArrayOfObjects(response?.snis));
setHeaders(convertToObjArray(response?.headers));
setSources(convertToObjArray(response?.sources));
setDestinations(convertToObjArray(response?.destinations));
setMethods(response?.methods || []);
setHttpsRedirectStatusCode(response?.https_redirect_status_code || 0);
setRegexPriority(response?.regex_priority || 0);
setStripPath(response?.strip_path || true);
setPreserveHost(response?.preserve_host || false);
setRequestBuffering(response?.request_buffering || true);
setResponseBuffering(response?.response_buffering || true);
};
fetchData();
}
}, [show]);
return /* @__PURE__ */ React.createElement(
Modal,
{
open: show,
onClose: () => handleCloseModal({}),
"aria-labelledby": "modal-modal-job-details",
"aria-describedby": "modal-modal-jobs-details-and-steps",
className: modalOnBlur,
closeAfterTransition: true
},
/* @__PURE__ */ React.createElement(Fade, { in: show }, /* @__PURE__ */ React.createElement(Box, { className: modalContent }, /* @__PURE__ */ React.createElement("div", { className: modalBody }, /* @__PURE__ */ React.createElement(Paper, { className: container }, /* @__PURE__ */ React.createElement(Box, { className: titleBar }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, "Route"), /* @__PURE__ */ React.createElement("div", { className: modalHeader }, /* @__PURE__ */ React.createElement(Tooltip, { title: "Close" }, /* @__PURE__ */ React.createElement(IconButton, { onClick: () => handleCloseModal({}) }, /* @__PURE__ */ React.createElement(CircleCloseIcon, null))))), /* @__PURE__ */ React.createElement("div", { className: content }, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 4 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, "General Information"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, "General information will help you identify and manage this route")), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(
TextField,
{
id: "name",
label: "Name",
variant: "filled",
className: fieldContent,
value: name,
onChange: (event) => handleChange(event, setName, (value) => value)
}
)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(
StringInputList,
{
label: "Tags",
buttonText: "Add",
onItemsChange: (items) => handleChange(items, setTags),
initialItems: tags
}
)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, null), /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, "Route Configuration"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, "Route configuration determines how this route will handle incoming requests")), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(FormControl, { variant: "filled", className: fieldContent }, /* @__PURE__ */ React.createElement(InputLabel, { id: "protocols-label" }, "Protocols"), /* @__PURE__ */ React.createElement(
Select,
{
labelId: "protocols-label",
id: "protocols",
value: protocols,
label: "Protocols",
onChange: (event) => {
handleChange(event, setProtocols, (value) => {
const selectedProtocol = value;
setProtocolDescription(
getProtocolDescription(selectedProtocol)
);
return selectedProtocol;
});
}
},
Object.values(Protocols).map((protocol) => /* @__PURE__ */ React.createElement(MenuItem, { key: protocol, value: protocol }, protocol))
))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Card, { variant: "outlined" }, /* @__PURE__ */ React.createElement(Box, { sx: { p: 2 } }, /* @__PURE__ */ React.createElement(
Stack,
{
direction: "row",
justifyContent: "space-between",
alignItems: "center"
},
/* @__PURE__ */ React.createElement(Typography, { gutterBottom: true, variant: "h6", component: "div" }, protocols, " Routing Rules")
), /* @__PURE__ */ React.createElement(Typography, { color: "textSecondary", variant: "body2" }, "For ", protocols, ", at least one of ", protocolDescription, " ", "must be set.")), /* @__PURE__ */ React.createElement(Divider, null), /* @__PURE__ */ React.createElement(
DynamicFields,
{
protocolDescription,
hosts,
paths,
snis,
headers,
sources,
destinations,
methods,
handleChange,
setHosts,
setPaths,
setSnis,
setHeaders,
setSources,
setDestinations,
setMethods
}
))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Box, { sx: { p: 2 } }, /* @__PURE__ */ React.createElement(
Typography,
{
variant: "subtitle1",
onClick: handleTextClick,
style: {
cursor: "pointer",
display: "flex",
alignItems: "center"
}
},
"View Advanced Fields",
showFields ? /* @__PURE__ */ React.createElement(DropUpIcon, null) : /* @__PURE__ */ React.createElement(DropDownIcon, null)
), /* @__PURE__ */ React.createElement(Collapse, { in: showFields }, /* @__PURE__ */ React.createElement(Box, { sx: { p: 2 } }, /* @__PURE__ */ React.createElement(
FormControl,
{
variant: "filled",
className: fieldContent
},
/* @__PURE__ */ React.createElement(InputLabel, { id: "https-redirect-label" }, "HTTPS Redirect Status Code"),
/* @__PURE__ */ React.createElement(
Select,
{
labelId: "https-redirect-label",
id: "httpsRedirectStatusCode",
value: httpsRedirectStatusCode,
label: "HTTPS Redirect Status Code",
onChange: (event) => handleChange(
event,
setHttpsRedirectStatusCode,
(value) => value
)
},
Object.values(RedirectStatusCode).map(
(redirectStatusCode) => /* @__PURE__ */ React.createElement(
MenuItem,
{
key: redirectStatusCode,
value: redirectStatusCode
},
redirectStatusCode
)
)
)
)), /* @__PURE__ */ React.createElement(Box, { sx: { p: 2 } }, /* @__PURE__ */ React.createElement(
TextField,
{
id: "regexPriority",
label: "Regex Priority",
value: regexPriority,
type: "number",
onChange: (event) => handleChange(
event,
setRegexPriority,
(value) => value
),
variant: "filled",
className: fieldContent
}
)), /* @__PURE__ */ React.createElement(Box, { sx: { p: 2 } }, /* @__PURE__ */ React.createElement(FormGroup, null, /* @__PURE__ */ React.createElement(
FormControlLabel,
{
control: /* @__PURE__ */ React.createElement(
Checkbox,
{
checked: !!stripPath,
onChange: (event) => handleChange(
event,
setStripPath,
(_, checked) => checked
),
value: stripPath
}
),
label: "Strip Path"
}
), /* @__PURE__ */ React.createElement(
FormControlLabel,
{
control: /* @__PURE__ */ React.createElement(
Checkbox,
{
checked: !!preserveHost,
onChange: (event) => handleChange(
event,
setPreserveHost,
(_, checked) => checked
),
value: preserveHost
}
),
label: "Preserve Host"
}
), /* @__PURE__ */ React.createElement(
FormControlLabel,
{
control: /* @__PURE__ */ React.createElement(
Checkbox,
{
checked: !!requestBuffering,
onChange: (event) => handleChange(
event,
setRequestBuffering,
(_, checked) => checked
),
value: requestBuffering
}
),
label: "Request buffering"
}
), /* @__PURE__ */ React.createElement(
FormControlLabel,
{
control: /* @__PURE__ */ React.createElement(
Checkbox,
{
checked: !!responseBuffering,
onChange: (event) => handleChange(
event,
setResponseBuffering,
(_, checked) => checked
),
value: responseBuffering
}
),
label: "Response buffering"
}
)))))), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Stack, { spacing: 2, direction: "row-reverse" }, /* @__PURE__ */ React.createElement(
Button,
{
variant: "contained",
color: "primary",
onClick: handleSaveRoute,
disabled: isSaveDisabled
},
"Save"
), /* @__PURE__ */ React.createElement(
Button,
{
variant: "contained",
color: "secondary",
onClick: () => handleCloseModal({})
},
"Cancel"
)))))))))
);
};
export { ModalComponent };
//# sourceMappingURL=ModalComponent.esm.js.map