UNPKG

@veecode-platform/plugin-kong-service-manager

Version:

395 lines (392 loc) 16.1 kB
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