diff --git a/frontend/src/components/DetectionRuleCard.jsx b/frontend/src/components/DetectionRuleCard.jsx index 5fe2e908..f5a30f67 100644 --- a/frontend/src/components/DetectionRuleCard.jsx +++ b/frontend/src/components/DetectionRuleCard.jsx @@ -19,17 +19,19 @@ const RuleCard = ({ ruleName, description, file_id, globalUrl, folderDisabled, i const handleSwitchChange = (event) => { if (folderDisabled) { - toast("enable the directory to enable individual rules"); + toast.warn("Enable the directory to enable individual rules"); return; } + if (!isTenzirActive) { - toast("connect to the siem to enable/disable the rule"); + toast.warn("Connect to the siem first to enable/disable the rule"); return; } + const newIsEnabled = event.target.checked; toggleRule(file_id, !newIsEnabled, globalUrl, () => { setIsEnabled(newIsEnabled); - }); + }) }; const UpdateText = (text) => { @@ -73,7 +75,6 @@ const RuleCard = ({ ruleName, description, file_id, globalUrl, folderDisabled, i color: "white", }} > -

HELO

{ruleName}
openEditBar(file_id, setOpenCodeEditor, setFileData, globalUrl)}> @@ -82,7 +83,7 @@ const RuleCard = ({ ruleName, description, file_id, globalUrl, folderDisabled, i
@@ -107,7 +108,7 @@ const RuleCard = ({ ruleName, description, file_id, globalUrl, folderDisabled, i const toggleRule = (fileId, isCurrentlyEnabled, globalUrl, callback) => { const action = isCurrentlyEnabled ? "disable" : "enable"; - const url = `${globalUrl}/api/v1/files/detection/${fileId}/${action}_rule`; + const url = `${globalUrl}/api/v1/detections/${fileId}/${action}_rule`; fetch(url, { method: "PUT", diff --git a/frontend/src/components/NewHeader.jsx b/frontend/src/components/NewHeader.jsx index 9c7a45c4..3dc07460 100644 --- a/frontend/src/components/NewHeader.jsx +++ b/frontend/src/components/NewHeader.jsx @@ -456,15 +456,19 @@ const Header = (props) => { Use Cases - - { - handleClose(); - }} - > - Creator page - - + + {userdata?.public_username === undefined || userdata?.public_username === null || userdata?.public_username.length <= 0 ? null : + + { + handleClose(); + }} + > + Creator page + + + } + { userdata.app_execution_usage === undefined || userdata.app_execution_usage < 1000 ? null : ( + App Runs used: {userdata.app_execution_usage} / {userdata.app_execution_limit}. When the limit is reached, you can still use Shuffle normally, but your Workflow triggers will stop workflows from starting. Reach out to support@shuffler.io to extend this limit. Customer workflows are NOT stopped this way. + + } >
Learn more @@ -4994,9 +4994,20 @@ If you're interested, please let me know a time that works for you, or set up a })} )} - +
-

WebHooks

+

Webhooks

+ + Webhooks used in Shuffle workflows.  + + Learn more + +
)} - {/*
-

Tenzir Pipelines

+
+

Pipelines

Controls a pipeline to run things.{" "} - )}*/} + )}
) : null; diff --git a/frontend/src/views/Apps.jsx b/frontend/src/views/Apps.jsx index 8407462f..1c1ca152 100755 --- a/frontend/src/views/Apps.jsx +++ b/frontend/src/views/Apps.jsx @@ -334,6 +334,11 @@ const Apps = (props) => { }, }); + useEffect(() => { + console.log("APPVALID: ", appValidation) + redirectOpenApi() + }, [appValidation]) + const getUserProfile = (username) => { if (serverside === true || !isCloud) { setCreatorProfile({}) @@ -1535,27 +1540,34 @@ const Apps = (props) => { const makeFancy = text?.includes("Generate") + var parsedStyle = { + flex: 1, + padding: 15, + margin: 10, + paddingTop: 25, + backgroundColor: hover ? theme.palette.surfaceColor : "transparent", + cursor: hover ? "pointer" : "default", + textAlign: "center", + minHeight: 150, + maxHeight: 150, + + borderRadius: theme.palette.borderRadius, + } + + if (!makeFancy) { + parsedStyle.border = hover ? "1px solid #f85a3e" : "1px solid rgba(255,255,255,0.3)" + } else { + parsedStyle.border = "1px solid transparent" + parsedStyle.borderImage = "linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet) 1" + parsedStyle.borderRadius = 0 // This doesn't work. Try to hover with a high one, and it's weird due to borderImage + } + return ( setHover(true)} onMouseLeave={() => setHover(false)} onClick={func} - style={{ - flex: 1, - padding: 15, - margin: 10, - paddingTop: 25, - backgroundColor: hover ? theme.palette.surfaceColor : "transparent", - border: hover ? "1px solid #f85a3e" : "1px solid rgba(255,255,255,0.3)", - cursor: hover ? "pointer" : "default", - textAlign: "center", - minHeight: 150, - maxHeight: 150, - - borderRadius: theme.palette.borderRadius, - //borderImage: makeFancy ? "linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet) 1" : null, - - }} + style={parsedStyle} > {icon} @@ -2568,7 +2580,8 @@ const Apps = (props) => { } //fetch("http://localhost:8080/doc_to_openapi", { - fetch("https://doc-to-openapi-stbuwivzoq-nw.a.run.app/doc_to_openapi", { + //fetch("https://doc-to-openapi-stbuwivzoq-nw.a.run.app/doc_to_openapi", { + fetch("https://doc-to-openapi-stbuwivzoq-nw.a.run.app/api/v1/doc_to_openapi", { method: "POST", headers: { "Accept": "application/json", @@ -2588,14 +2601,14 @@ const Apps = (props) => { }) .then((responseJson) => { // Check if openapi or swagger in string of the json + var parsedtext = responseJson try { - const parsedtext = JSON.stringify(responseJson); + parsedtext = JSON.stringify(responseJson); if (parsedtext.indexOf("openapi") === -1 && parsedtext.indexOf("swagger") === -1) { - setValidation(false); - setOpenApiError("Error in generation: "+parsedtext); + setValidation(false) + setOpenApiError("Error in generation: "+parsedtext) - - return; + return } } catch (e) { setValidation(false); @@ -2604,7 +2617,7 @@ const Apps = (props) => { } console.log("Validating response!"); - validateOpenApi(responseJson); + validateOpenApi(parsedtext) }) .catch((error) => { setValidation(false); @@ -2716,8 +2729,16 @@ const Apps = (props) => { }; const redirectOpenApi = () => { + if (appValidation === undefined || appValidation === null || appValidation.length === 0) { + return + } + + toast.success("Successfully validated OpenAPI. Redirecting to app creation. Remember to save the app to be able to use it.", { + // Disable autoclose + autoClose: 10000, + }) navigate(`/apps/new?id=${appValidation}`) - }; + } const handleGithubValidation = (forceUpdate) => { getSpecificApps(openApi, forceUpdate); @@ -2977,10 +2998,12 @@ const Apps = (props) => { }} PaperProps={{ style: { - backgroundColor: surfaceColor, + backgroundColor: theme.palette.platformColor, + borderRadius: theme.palette.borderRadius, color: "white", minWidth: "800px", minHeight: "320px", + padding: 50, }, }} > @@ -3019,7 +3042,7 @@ const Apps = (props) => { validateDocumentationUrl(); }} > - Validate + Generate ), }} @@ -3034,22 +3057,6 @@ const Apps = (props) => { placeholder="API Documentation URL" fullWidth /> -

Or upload document with the content (coming soon)

- - {errorText} @@ -3068,17 +3075,6 @@ const Apps = (props) => { > Cancel - @@ -3094,10 +3090,12 @@ const Apps = (props) => { }} PaperProps={{ style: { - backgroundColor: surfaceColor, + backgroundColor: theme.palette.platformColor, + borderRadius: theme.palette.borderRadius, color: "white", minWidth: "800px", minHeight: "320px", + padding: 50, }, }} > diff --git a/frontend/src/views/DetectionExplorer.jsx b/frontend/src/views/DetectionExplorer.jsx new file mode 100644 index 00000000..8a9e99dc --- /dev/null +++ b/frontend/src/views/DetectionExplorer.jsx @@ -0,0 +1,225 @@ +import React, { useState } from "react"; +import { + Container, + Box, + TextField, + Switch, + Typography, + Button, + CircularProgress, + Paper, +} from "@mui/material"; + +import { toast } from "react-toastify"; +import theme from '../theme.jsx'; +import DetectionRuleCard from "../components/DetectionRuleCard.jsx"; + +const handleDirectoryChange = (folderDisabled, setFolderDisabled, globalUrl, isTenzirActive) => { + if (!isTenzirActive) { + toast.warn("Connect to siem first for global enable/disable to work"); + return; + } + + const action = folderDisabled ? "enable_folder" : "disable_folder"; + const url = `${globalUrl}/api/v1/detections/${action}`; + + fetch(url, { + method: "PUT", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => + response.json().then((responseJson) => { + if (responseJson["success"] === true) { + if (action === "enable_folder") setFolderDisabled(false); + else setFolderDisabled(true); + } else { + //toast(`failed to disable rule`); + } + }) + ) + .catch((error) => { + console.log(`Error in ${action} the rule: `, error); + toast(`An error occurred while ${action} the rule`); + }); +}; + +const Detection = (props) => { + const { globalUrl, ruleInfo, folderDisabled, setFolderDisabled, isTenzirActive, detectionInfo } = props; + const [searchQuery, setSearchQuery] = useState(""); + const [loading, setLoading] = useState(false); + + const handleConnectClick = () => { + if (isTenzirActive) { + return + } + + if (detectionInfo.category === undefined || detectionInfo.category === null) { + toast.warn("Detection category not found. Please try again or contact support@shuffler.io if you think this is a bug.") + return + } + + setLoading(true); + const url = `${globalUrl}/api/v1/detections/${detectionInfo?.category}/connect`; + + fetch(url, { + method: "GET", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => + response.json().then((responseJson) => { + if (responseJson["success"] === true) { + setTimeout(() => { + setLoading(false); + window.location.reload(); + }, 15000); + } else { + if (responseJson.reason !== undefined && responseJson.reason !== null) { + toast(responseJson.reason) + } else { + toast(`Failed to connect to ${detectionInfo?.category}`); + } + + if (responseJson.action !== undefined && responseJson.actio !== null && responseJson.action.length > 0) { + //if (responseJson.action === "environment_create") { + // navigate("/admin?tab=environments") + //} + } + + setLoading(false); + } + }) + ) + .catch((error) => { + setLoading(false); + console.log(`Error in connecting to ${detectionInfo?.category}: `, error); + toast(`An error occurred while connecting to ${detectionInfo?.category}`); + }); + } + + const filteredRules = ruleInfo === "default" ? [] : ruleInfo?.filter((rule) => + rule.title.toLowerCase().includes(searchQuery.toLowerCase()) || + rule.description.toLowerCase().includes(searchQuery.toLowerCase()) + ) + + return ( + + + + + {detectionInfo?.name} ({filteredRules?.length}) + + + + + + setSearchQuery(e.target.value)} + /> + {/* + { + uploadFiles(event.target.files); + }} + /> */} + + + + Global disable/enable + + + handleDirectoryChange(folderDisabled, setFolderDisabled, globalUrl, isTenzirActive) + } + /> + + + + {filteredRules?.length > 0 ? + filteredRules.map((rule, index) => { + console.log("RULE CARD: ", rule); + + return ( + + ) + }) + : null } + + + + ); +}; + +export default Detection;