resolved the conflicts& fixed the hive crash issue
This commit is contained in:
@@ -15,6 +15,7 @@ import HealthPage from "./components/HealthPage.jsx";
|
||||
import theme from "./theme";
|
||||
import Apps from "./views/Apps";
|
||||
import AppCreator from "./views/AppCreator";
|
||||
import DetectionDashBoard from "./views/DetectionDashboard.jsx";
|
||||
|
||||
import Welcome from "./views/Welcome.jsx";
|
||||
import Dashboard from "./views/Dashboard.jsx";
|
||||
@@ -414,6 +415,11 @@ const App = (message, props) => {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/detections/sigma"
|
||||
element={<DetectionDashBoard globalUrl={globalUrl} />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/workflows"
|
||||
|
||||
@@ -54,7 +54,6 @@ const Billing = (props) => {
|
||||
const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, clickedFromOrgTab } = props;
|
||||
//const alert = useAlert();
|
||||
let navigate = useNavigate();
|
||||
|
||||
const [selectedDealModalOpen, setSelectedDealModalOpen] = React.useState(false);
|
||||
const [dealList, setDealList] = React.useState([]);
|
||||
const [dealName, setDealName] = React.useState("");
|
||||
@@ -1055,10 +1054,10 @@ const Billing = (props) => {
|
||||
Consultation & Management
|
||||
</Typography>
|
||||
<div>
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: 10, }}>
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: userdata.support ? 5 : 10, }}>
|
||||
You currently have a total of {inputHour} hours and {inputMinutes} minutes of professional services available by our experts.
|
||||
</Typography>
|
||||
<div style={{ display: "flex", minWidth: 340, justifyContent: 'center', marginTop: userdata.support ? 0 : 10 }}>
|
||||
<div style={{ display: "flex", minWidth: 340, justifyContent: 'center', marginTop: userdata.support ? 0 : 15 }}>
|
||||
{editConsultation ?
|
||||
<>
|
||||
<TextField
|
||||
@@ -1106,7 +1105,7 @@ const Billing = (props) => {
|
||||
{editConsultation && <Button variant="contained" color="primary" style={{ marginLeft: 5, textTransform: 'none' }} onClick={handleSave}>Save</Button>}
|
||||
</div>
|
||||
: null}
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: userdata.support ? 5 : 10, }}>
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: userdata.support ? 5 : 25, }}>
|
||||
Features
|
||||
</Typography>
|
||||
<ul>
|
||||
@@ -1331,7 +1330,7 @@ const Billing = (props) => {
|
||||
Become a Shuffle Expert
|
||||
</Typography>
|
||||
<div>
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: 10, }}>
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: 25, }}>
|
||||
Public Training
|
||||
</Typography>
|
||||
<ul>
|
||||
@@ -1346,7 +1345,7 @@ const Billing = (props) => {
|
||||
</Typography>
|
||||
</li>
|
||||
</ul>
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: 10, }}>
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: 20, }}>
|
||||
Private Training
|
||||
</Typography>
|
||||
<ul>
|
||||
|
||||
@@ -3,15 +3,25 @@ import ReactGA from 'react-ga4';
|
||||
import theme from "../theme.jsx";
|
||||
import { ToastContainer, toast } from "react-toastify"
|
||||
|
||||
import {
|
||||
CheckCircle as CheckCircleIcon,
|
||||
} from "@mui/icons-material";
|
||||
|
||||
import {
|
||||
Paper,
|
||||
Typography,
|
||||
Divider,
|
||||
Button,
|
||||
Tooltip,
|
||||
Grid,
|
||||
Card,
|
||||
} from "@mui/material";
|
||||
|
||||
import {
|
||||
red,
|
||||
green,
|
||||
} from "../views/AngularWorkflow.jsx"
|
||||
|
||||
//import { useAlert
|
||||
|
||||
const Branding = (props) => {
|
||||
@@ -45,7 +55,7 @@ const Branding = (props) => {
|
||||
toast("Failed updating org: ", responseJson.reason);
|
||||
} else {
|
||||
if (joinStatus == "join") {
|
||||
setPublishingInfo("Your organization is now part of the Creator Incentive Program. You can now create and publish content to your organization's page. You can also create a creator account to manage your organization's content.")
|
||||
setPublishingInfo("Your organization is now part of the Partner Program. You can now create, publish and manage content for your organization's public page.")
|
||||
} else {
|
||||
setPublishingInfo("Your organization is no longer part of the Creator Incentive Program. You can still create a creator account to manage your organization's content.")
|
||||
}
|
||||
@@ -70,7 +80,15 @@ const Branding = (props) => {
|
||||
}
|
||||
|
||||
const isOrganizationReady = () => {
|
||||
console.log("Is organization ready?")
|
||||
|
||||
// Check if it's a suborg
|
||||
if (selectedOrganization.creator_org !== "") {
|
||||
const comment = "Child orgs can't become creators"
|
||||
if (!publishRequirements.includes(comment)) {
|
||||
setPublishRequirements([...publishRequirements, comment])
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// A simple checklist to ensure the button shows up properly
|
||||
if (selectedOrganization.name === selectedOrganization.org) {
|
||||
@@ -82,15 +100,6 @@ const Branding = (props) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if it's a suborg
|
||||
if (selectedOrganization.creator_org !== "") {
|
||||
const comment = "Child orgs can't become creators"
|
||||
if (!publishRequirements.includes(comment)) {
|
||||
setPublishRequirements([...publishRequirements, comment])
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (selectedOrganization.large_image === "" || selectedOrganization.large_image === theme.palette.defaultImage) {
|
||||
const comment = "Add a logo for your organization"
|
||||
if (!publishRequirements.includes(comment)) {
|
||||
@@ -102,6 +111,14 @@ const Branding = (props) => {
|
||||
return true
|
||||
}
|
||||
|
||||
const isPublished = selectedOrganization.creator_id === ""
|
||||
const leadinfo = selectedOrganization.lead_info === undefined || selectedOrganization.lead_info === null || selectedOrganization.lead_info === "" ? "" : JSON.stringify(selectedOrganization.lead_info)
|
||||
const isPartner = leadinfo.includes("partner")
|
||||
|
||||
console.log("LEADINFO: ", leadinfo)
|
||||
|
||||
console.log("SELECTEDORGANIZATION: ", selectedOrganization)
|
||||
|
||||
return (
|
||||
<div style={{ width: clickedFromOrgTab? 1030: "auto", padding: 27, height: "auto", backgroundColor: '#212121', borderRadius: '16px', }}>
|
||||
<h2 style={{marginTop: clickedFromOrgTab ?0:null,}}>
|
||||
@@ -111,27 +128,46 @@ const Branding = (props) => {
|
||||
You can customize your organization's branding by uploading a logo, changing the color scheme and a lot more.
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 20, marginBottom: 10 }}>
|
||||
{isPublished ? <CheckCircleIcon style={{color: red, }} /> : <CheckCircleIcon style={{color: green, }} />}
|
||||
<span style={{marginLeft: 10, color: isPublished ? red : green, }}>{isPublished ? "Not Published" : "Published"}</span>
|
||||
</Typography>
|
||||
|
||||
<a href="https://shuffler.io/partners" target="_blank" style={{ textDecoration: "none", }}>
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 20, marginBottom: 10 }}>
|
||||
{!isPartner ? <CheckCircleIcon style={{color: red, }} /> : <CheckCircleIcon style={{color: green, }} />}
|
||||
<Tooltip title="Official Partner Program (manual verification)" placement="top" arrow>
|
||||
<span style={{marginLeft: 10, color: !isPartner ? red : green, }}>{!isPartner? "Not Officially Partnered" : "Officially Partnered"}</span>
|
||||
</Tooltip>
|
||||
</Typography>
|
||||
</a>
|
||||
|
||||
<a href={`/partners/${selectedOrganization.creator_id}/edit`} target="_blank">
|
||||
<Button disabled={isPublished} variant="contained" style={{ marginTop: 20, marginBottom: 10, }} onClick={() => {
|
||||
}}>
|
||||
Modify Public Partner Details
|
||||
</Button>
|
||||
</a>
|
||||
|
||||
<Divider style={{marginTop: 50, marginBottom: 50, }} />
|
||||
<h2>
|
||||
Creator Incentive Program
|
||||
Partner Program
|
||||
</h2>
|
||||
<div style={{ display: "flex", width: 900, }}>
|
||||
<div>
|
||||
<span>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
By changing publishing settings, you agree to our <a href="/docs/terms_of_service" target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Terms of Service</a>, and acknowledge that your organization's non-sensitive data will be added as a <a target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}} href="https://shuffler.io/creators">creator account</a>. None of your existing workflows, apps, or other stored data will be published. Any admin in your organization can manage the creator configuration. Becoming a creator organization is reversible.<div/>Support: <a href="mailto:support@shuffler.io"target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>support@shuffler.io</a>
|
||||
By changing publishing settings, you agree to our <a href="/docs/terms_of_service" target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Terms of Service</a>, and acknowledge that your organization's non-sensitive data will be added as a <a target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}} href="https://shuffler.io/creators">creator account</a>. None of your existing workflows, apps, or other stored data will be published. Any admin in your organization can manage the creator configuration. Becoming a creator organization IS reversible.<div/>Support: <a href="mailto:support@shuffler.io"target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>support@shuffler.io</a>
|
||||
</Typography>
|
||||
{selectedOrganization.creator_id == "" ?
|
||||
<Typography variant="h6" color="textSecondary" style={{ marginTop: 20, marginBottom: 10, color: "grey", }}>
|
||||
|
||||
</Typography>
|
||||
:
|
||||
<Typography variant="h6" color="textSecondary" style={{ marginTop: 20, marginBottom: 10, color: "grey", }}>
|
||||
|
||||
<a href={`/creators/${selectedOrganization.creator_id}`} target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Modify your creator organization</a>
|
||||
</Typography>
|
||||
null
|
||||
}
|
||||
|
||||
|
||||
<Button
|
||||
style={{ height: 40, marginTop: 10, width: 300, }}
|
||||
variant={selectedOrganization.creator_id == "" ? "contained" : "outlined"}
|
||||
@@ -141,7 +177,7 @@ const Branding = (props) => {
|
||||
handleChangePublishing();
|
||||
}}
|
||||
>
|
||||
{selectedOrganization.creator_id == "" ? "Join" : "Leave"} Creators
|
||||
{selectedOrganization.creator_id == "" ? "Join" : "Leave"} Partner Program
|
||||
|
||||
</Button>
|
||||
<Typography variant="body1" color="textSecondary" style={{ marginTop: 20, marginBottom: 10, color: "white", }}>
|
||||
|
||||
@@ -690,7 +690,7 @@ const LicencePopup = (props) => {
|
||||
const priceItem = window.location.origin === "https://shuffler.io" ?
|
||||
shuffleVariant === 0 ? "app_executions" : "cores"
|
||||
:
|
||||
shuffleVariant === 0 ? "price_1PbO0cEJjT17t98NsfEMUlMn" : "price_1PbNnaEJjT17t98NLadq6Lhq"
|
||||
shuffleVariant === 0 ? "price_1PZPSSEJjT17t98NLJoTMYja" : "price_1PZPQuEJjT17t98N3yORUtd9"
|
||||
|
||||
const successUrl = `${window.location.origin}/admin?admin_tab=billing&payment=success`
|
||||
const failUrl = `${window.location.origin}/pricing?admin_tab=billing&payment=failure`
|
||||
|
||||
@@ -143,7 +143,7 @@ const Header = (props) => {
|
||||
const [subAnchorEl, setSubAnchorEl] = React.useState(null);
|
||||
const [upgradeHovered, setUpgradeHovered] = React.useState(false);
|
||||
const [showTopbar, setShowTopbar] = useState(false)
|
||||
const stripeKey = typeof window === 'undefined' || window.location === undefined ? "" : window.location.origin === "https://shuffler.io" ? "pk_live_XAxwE2Fp9DEbEcNYw4UKmyby00vIlIPPRp" : "pk_test_51PXYYMEJjT17t98NbDkojZ3DRvsFUQBs35LGMx3i436BXwEBVFKB9nCvHt0Q3M4MG3dz4mHheuWvfoYvpaL3GmsG00k1Rb2ksO"
|
||||
const stripeKey = typeof window === 'undefined' || window.location === undefined ? "" : window.location.origin === "https://shuffler.io" ? "pk_live_51PXYYMEJjT17t98N20qEqItyt1fLQjrnn41lPeG2PjnSlZHTDNKHuisAbW00s4KAn86nGuqB9uSVU4ds8MutbnMU00DPXpZ8ZD" : "pk_test_51PXYYMEJjT17t98NbDkojZ3DRvsFUQBs35LGMx3i436BXwEBVFKB9nCvHt0Q3M4MG3dz4mHheuWvfoYvpaL3GmsG00k1Rb2ksO"
|
||||
let navigate = useNavigate();
|
||||
const classes = useStyles();
|
||||
|
||||
@@ -171,8 +171,10 @@ const Header = (props) => {
|
||||
setTooltipOpen(true);
|
||||
};
|
||||
|
||||
const topbar_var = "topbar_closed2"
|
||||
|
||||
useEffect(() => {
|
||||
const topbar = localStorage.getItem("topbar_closed")
|
||||
const topbar = localStorage.getItem(topbar_var)
|
||||
if (topbar === "true") {
|
||||
setShowTopbar(false)
|
||||
} else {
|
||||
@@ -919,8 +921,8 @@ const Header = (props) => {
|
||||
</MenuItem>
|
||||
)}
|
||||
<div className={classes.divider} />
|
||||
<MenuItem className={classes.dropdownMenuItem} onClick={() => handleMenuItemClick('/professional-support')}>
|
||||
<Link to="/professional-support" style={hrefStyle}>
|
||||
<MenuItem className={classes.dropdownMenuItem} onClick={() => handleMenuItemClick('/professional-services')}>
|
||||
<Link to="/professional-services" style={hrefStyle}>
|
||||
Professional Services
|
||||
</Link>
|
||||
</MenuItem>
|
||||
@@ -929,9 +931,19 @@ const Header = (props) => {
|
||||
<Link to="/training" style={hrefStyle}>
|
||||
Training Courses
|
||||
</Link>
|
||||
</MenuItem>
|
||||
<Divider />
|
||||
|
||||
<MenuItem className={classes.dropdownMenuItem} onClick={() => handleMenuItemClick('/partners')}>
|
||||
<Link to="/partners" style={hrefStyle}>
|
||||
Partner Program
|
||||
</Link>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</ListItem>
|
||||
|
||||
|
||||
|
||||
{/* <ListItem style={{ textAlign: "center", marginLeft: 0, paddingRight: 0 }}>
|
||||
<Link rel="noopener noreferrer" to="/training" style={hrefStyle}>
|
||||
<Button
|
||||
@@ -1627,7 +1639,7 @@ const Header = (props) => {
|
||||
|
||||
const topbarHeight = showTopbar ? 40 : 0
|
||||
const topbar = !isCloud || !showTopbar ? null :
|
||||
curpath === "/" || curpath.includes("/docs") || curpath === "/pricing" || curpath === "/contact" || curpath === "/search" || curpath === "/usecases" || curpath === "/training" || curpath === "/professional-support" ?
|
||||
curpath === "/" || curpath.includes("/docs") || curpath === "/pricing" || curpath === "/contact" || curpath === "/search" || curpath === "/usecases" || curpath === "/training" || curpath === "/professional-services" ?
|
||||
<span style={{ zIndex: 50001, }}>
|
||||
<div style={{ position: "relative", height: topbarHeight, backgroundImage: "linear-gradient(to right, #f86a3e, #f34079)", overflow: "hidden", }}>
|
||||
<Typography variant="body1" style={{ paddingTop: 7, margin: "auto", textAlign: "center", color: "white", }}>
|
||||
@@ -1653,7 +1665,7 @@ const Header = (props) => {
|
||||
setShowTopbar(false)
|
||||
|
||||
// Set storage that it's clicked
|
||||
localStorage.setItem("topbar_closed", "true")
|
||||
localStorage.setItem(topbar_var, "true")
|
||||
}}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import React, { useState, useEffect, useLayoutEffect } from "react";
|
||||
import React, { useState, useEffect, useLayoutEffect, useMemo } from "react";
|
||||
import { toast } from 'react-toastify';
|
||||
import { makeStyles, createStyles } from "@mui/styles";
|
||||
import theme from '../theme.jsx';
|
||||
|
||||
|
||||
import { useNavigate, Link, useParams } from "react-router-dom";
|
||||
import { validateJson, GetIconInfo } from "../views/Workflows.jsx";
|
||||
import { GetParsedPaths } from "../views/Apps.jsx";
|
||||
import { sortByKey } from "../views/AngularWorkflow.jsx";
|
||||
import { NestedMenuItem } from "mui-nested-menu";
|
||||
import { parsedDatatypeImages } from "../components/AppFramework.jsx";
|
||||
import { green, yellow, red } from "../views/AngularWorkflow.jsx"
|
||||
//import { useAlert
|
||||
|
||||
import {
|
||||
@@ -175,26 +176,21 @@ const ParsedAction = (props) => {
|
||||
setAiQueryModalOpen,
|
||||
} = props;
|
||||
|
||||
let navigate = useNavigate();
|
||||
const classes = useStyles();
|
||||
|
||||
const [hideBody, setHideBody] = React.useState(true)
|
||||
const [activateHidingBodyButton, setActivateHidingBodyButton] = React.useState(false)
|
||||
const [appActionName, setAppActionName] = React.useState(selectedAction.label);
|
||||
const [appActionName, setAppActionName] = React.useState(selectedAction?.label);
|
||||
const [delay, setDelay] = React.useState(selectedAction?.execution_delay || 0);
|
||||
const [prevActionName, setPrevActionName] = React.useState(selectedAction.label);
|
||||
const [prevActionName, setPrevActionName] = React.useState(selectedAction?.label);
|
||||
const [fieldCount, setFieldCount] = React.useState(0);
|
||||
const [hiddenDescription, setHiddenDescription] = React.useState(true);
|
||||
const [hiddenParameters, setHiddenParameters] = React.useState(true);
|
||||
const [autoCompleting, setAutocompleting] = React.useState(false);
|
||||
const [selectedActionParameters, setSelectedActionParameters] = React.useState(selectedAction?.parameters || []);
|
||||
const [selectedVariableParameter, setSelectedVariableParameter] = React.useState("");
|
||||
const [paramValues, setParamValues] = React.useState(
|
||||
selectedAction?.parameters.map((param) => {
|
||||
return {
|
||||
name: param.name,
|
||||
value: param.value,
|
||||
}
|
||||
})
|
||||
);
|
||||
const [selectedVariableParameter, setSelectedVariableParameter] = React.useState("");
|
||||
const [paramUpdate, setParamUpdate] = React.useState("");
|
||||
const [actionlist, setActionlist] = React.useState([]);
|
||||
const [jsonList, setJsonList] = React.useState([]);
|
||||
const [showDropdown, setShowDropdown] = React.useState(false);
|
||||
@@ -210,6 +206,24 @@ const ParsedAction = (props) => {
|
||||
}
|
||||
}, [expansionModalOpen])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedActionEnvironment === undefined || selectedActionEnvironment === null || Object.keys(selectedActionEnvironment).length === 0) {
|
||||
|
||||
if (environments !== undefined && environments !== null && environments.length > 0) {
|
||||
if (selectedAction.environment !== undefined && selectedAction.environment !== null) {
|
||||
|
||||
const foundenv = environments.find(env => env.id === selectedAction.environment || selectedAction.environment === env.Name)
|
||||
|
||||
if (foundenv !== undefined && foundenv !== null) {
|
||||
setSelectedActionEnvironment(foundenv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
/*
|
||||
useEffect(() => {
|
||||
setParamValues(selectedAction.parameters.map((param) => {
|
||||
return {
|
||||
@@ -220,6 +234,8 @@ const ParsedAction = (props) => {
|
||||
},[
|
||||
selectedAction, selectedApp,setNewSelectedAction, workflow,
|
||||
])
|
||||
*/
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAction.parameters === null || selectedAction.parameters === undefined) {
|
||||
@@ -420,8 +436,8 @@ const ParsedAction = (props) => {
|
||||
}
|
||||
|
||||
// Only set selected action parameters if they have changed
|
||||
if (selectedAction.parameters && selectedAction.parameters.length > 0) {
|
||||
setSelectedActionParameters(selectedAction.parameters);
|
||||
if (selectedAction?.parameters && selectedAction?.parameters.length > 0) {
|
||||
setSelectedActionParameters(selectedAction?.parameters);
|
||||
}
|
||||
|
||||
// Only set selected variable parameter if it is null or undefined
|
||||
@@ -436,6 +452,7 @@ const ParsedAction = (props) => {
|
||||
|
||||
useEffect(() => {
|
||||
const newActionList = [];
|
||||
const parentActionList = [];
|
||||
|
||||
// Process workflowExecutions
|
||||
if (workflowExecutions.length > 0) {
|
||||
@@ -563,15 +580,67 @@ const ParsedAction = (props) => {
|
||||
autocomplete: parentNode.label.split(" ").join("_"),
|
||||
example: exampleData,
|
||||
});
|
||||
|
||||
parentActionList.push({
|
||||
type: "action",
|
||||
id: parentNode.id,
|
||||
name: parentNode.label,
|
||||
autocomplete: parentNode.label.split(" ").join("_"),
|
||||
example: exampleData,
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the actionlist state
|
||||
let newParameters = selectedAction?.parameters?.map((param) => {
|
||||
let paramvalue = param.value;
|
||||
let errorVars = [];
|
||||
if(paramvalue.includes("$")){
|
||||
let actions = workflow.actions?.map((action) => {
|
||||
return "$"+action.label.toLowerCase();
|
||||
})
|
||||
if(newActionList?.length > 0){
|
||||
let appParentActions = parentActionList?.map(action => "$" + action.name.toLowerCase());
|
||||
let notPresentAction = actions?.filter((action) => !appParentActions?.includes(action))
|
||||
notPresentAction?.forEach((action) => {
|
||||
action = action.replace(" ", "_");
|
||||
if(paramvalue.includes(action)){
|
||||
errorVars.push(action);
|
||||
// paramvalue = paramvalue.replace(action, "")
|
||||
// paramvalue = paramvalue.replace(/^\s*[\r\n]/gm, "");
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let message = "";
|
||||
if(errorVars.length > 0){
|
||||
if(errorVars.length === 1){
|
||||
message = errorVars[0] + " is not accessible in this action.";
|
||||
}else{
|
||||
message = errorVars.join(", ") + " are not accessible in this action.";
|
||||
}
|
||||
}
|
||||
|
||||
if (param?.configuration) {
|
||||
let regex = /(^|[^\\])\$/;
|
||||
if (regex.test(paramvalue)) {
|
||||
if(message.length > 0){
|
||||
message += "\nUse \"\\$\" instead of \"$\".";
|
||||
}else{
|
||||
message = "Use \"\\$\" instead of \"$\".";
|
||||
}
|
||||
}
|
||||
}
|
||||
return {...param, value: paramvalue, error: message}
|
||||
});
|
||||
setSelectedActionParameters(newParameters);
|
||||
setActionlist(newActionList);
|
||||
}, [workflow.execution_variables, workflow.workflow_variables, workflowExecutions, workflow, selectedAction, listCache, getParents]);
|
||||
|
||||
}, [workflow.execution_variables,paramUpdate, workflow.workflow_variables, workflowExecutions, workflow, selectedAction, listCache, getParents,setNewSelectedAction]);
|
||||
console.log("Selected Action:", selectedAction)
|
||||
useEffect(() => {
|
||||
selectedNameChange(appActionName)
|
||||
|
||||
@@ -581,15 +650,17 @@ const ParsedAction = (props) => {
|
||||
},[appActionName,delay])
|
||||
|
||||
const handleParamChange = (event, count,data) => {
|
||||
const newParams = [...paramValues];
|
||||
const newParams = [...selectedActionParameters];
|
||||
newParams.map((param) => {
|
||||
if (param.name === data.name) {
|
||||
param.value = event.target.value;
|
||||
}
|
||||
})
|
||||
setParamValues(newParams);
|
||||
setSelectedActionParameters(newParams);
|
||||
setParamUpdate(event.target.value);
|
||||
changeActionParameter(event, count, data)
|
||||
}
|
||||
|
||||
const calculateHelpertext = (input_data) => {
|
||||
var helperText = ""
|
||||
var looperText = ""
|
||||
@@ -1115,6 +1186,15 @@ const ParsedAction = (props) => {
|
||||
return helperText
|
||||
}
|
||||
|
||||
const errorHelperText = (name, value, error) => {
|
||||
return (
|
||||
<div style={{ whiteSpace: 'pre-line' }}>
|
||||
{error}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const analyzeFields = () => {
|
||||
|
||||
if (selectedAction === undefined || selectedAction === null) {
|
||||
@@ -1176,7 +1256,7 @@ const ParsedAction = (props) => {
|
||||
}
|
||||
|
||||
// FIXME: Issue #40 - selectedActionParameters not reset
|
||||
if (Object.getOwnPropertyNames(selectedAction).length > 0 && selectedActionParameters.length > 0) {
|
||||
if (Object.getOwnPropertyNames(selectedAction)?.length > 0 && selectedActionParameters?.length > 0) {
|
||||
var wrapperapp = {
|
||||
"id": "",
|
||||
"name": "noapp",
|
||||
@@ -1893,6 +1973,7 @@ const ParsedAction = (props) => {
|
||||
}}
|
||||
labelId="select-app-auth"
|
||||
value={
|
||||
selectedAction.authentication_id === "authgroups" ? "authgroups" :
|
||||
Object.getOwnPropertyNames(selectedAction.selectedAuthentication).length === 0
|
||||
? "No selection"
|
||||
: selectedAction.selectedAuthentication
|
||||
@@ -1909,18 +1990,48 @@ const ParsedAction = (props) => {
|
||||
selectedAction.authentication_id = "";
|
||||
|
||||
for (let [key,keyval] in Object.entries(selectedAction.parameters)) {
|
||||
//console.log(selectedAction.parameters[key])
|
||||
if (selectedAction.parameters[key].configuration) {
|
||||
selectedAction.parameters[key].value = "";
|
||||
|
||||
if (selectedAction.parameters[key].example !== undefined && selectedAction.parameters[key].example !== null && selectedAction.parameters[key].example !== "") {
|
||||
if (selectedAction.parameters[key].example.toLowerCase().includes("api") || selectedAction.parameters[key].example.toLowerCase().includes("key") || selectedAction.parameters[key].example.toLowerCase().includes("pass")) {
|
||||
selectedAction.parameters[key].value = ""
|
||||
} else {
|
||||
selectedAction.parameters[key].value = selectedAction.parameters[key].example
|
||||
}
|
||||
} else {
|
||||
selectedAction.parameters[key].value = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
setSelectedAction(selectedAction);
|
||||
setUpdate(Math.random());
|
||||
|
||||
} else if (e.target.value === "authgroups") {
|
||||
if (authGroups !== undefined && authGroups !== null && authGroups.length === 0) {
|
||||
toast("No auth groups created. Opening window to create one")
|
||||
|
||||
setTimeout(() => {
|
||||
window.open("/admin?tab=app_auth", "_blank")
|
||||
}, 2500)
|
||||
} else {
|
||||
selectedAction.selectedAuthentication = {};
|
||||
selectedAction.authentication_id = "authgroups"
|
||||
|
||||
for (let [key,keyval] in Object.entries(selectedAction.parameters)) {
|
||||
//console.log(selectedAction.parameters[key])
|
||||
if (selectedAction.parameters[key].configuration) {
|
||||
selectedAction.parameters[key].value = "authgroup controlled"
|
||||
}
|
||||
}
|
||||
|
||||
setSelectedAction(selectedAction)
|
||||
setUpdate(Math.random())
|
||||
}
|
||||
} else {
|
||||
selectedAction.selectedAuthentication = e.target.value;
|
||||
selectedAction.authentication_id = e.target.value.id;
|
||||
setSelectedAction(selectedAction);
|
||||
setUpdate(Math.random());
|
||||
setSelectedAction(selectedAction)
|
||||
setUpdate(Math.random())
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
@@ -1976,6 +2087,19 @@ const ParsedAction = (props) => {
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
|
||||
<Divider style={{marginTop: 10, marginBottom: 10, }}/>
|
||||
|
||||
<MenuItem
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
color: "white",
|
||||
}}
|
||||
value="authgroups"
|
||||
>
|
||||
<em>Auth Groups</em>
|
||||
</MenuItem>
|
||||
|
||||
</Select>
|
||||
|
||||
{/*
|
||||
@@ -2006,6 +2130,7 @@ const ParsedAction = (props) => {
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
|
||||
{showEnvironment !== undefined && showEnvironment && environments.length > 1 && !isIntegration ? (
|
||||
<div style={{ marginTop: "20px" }}>
|
||||
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Environment</Typography>
|
||||
@@ -2014,10 +2139,7 @@ const ParsedAction = (props) => {
|
||||
disableScrollLock: true,
|
||||
}}
|
||||
value={
|
||||
selectedActionEnvironment === undefined || selectedActionEnvironment === null ||
|
||||
selectedActionEnvironment.Name === undefined || selectedActionEnvironment.Name === null
|
||||
? isCloud ? "Cloud" : "Shuffle"
|
||||
: selectedActionEnvironment.Name
|
||||
selectedActionEnvironment === undefined || selectedActionEnvironment === null || selectedActionEnvironment.Name === undefined || selectedActionEnvironment.Name === null ? isCloud ? "Cloud" : "Shuffle" : selectedActionEnvironment.Name
|
||||
}
|
||||
SelectDisplayProps={{
|
||||
style: {
|
||||
@@ -2034,7 +2156,7 @@ const ParsedAction = (props) => {
|
||||
workflow.actions[actionkey].environment = env.Name
|
||||
}
|
||||
setWorkflow(workflow)
|
||||
toast("Set environment for ALL actions to " + env.Name)
|
||||
toast.success("Set environment for ALL actions to " + env.Name)
|
||||
}}
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
@@ -2045,9 +2167,11 @@ const ParsedAction = (props) => {
|
||||
>
|
||||
{environments.map((data, index) => {
|
||||
if (data.archived === true) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
const isRunning = data.running_ip !== ""
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
key={data.Name}
|
||||
@@ -2057,6 +2181,27 @@ const ParsedAction = (props) => {
|
||||
}}
|
||||
value={data.Name}
|
||||
>
|
||||
|
||||
{data.Name === "cloud" || data.Name === "Cloud" ? null : !isRunning ?
|
||||
<a href={`/admin?tab=environments&env=${data.Name}`} target="_blank" style={{textDecoration: "none",}}>
|
||||
<Tooltip title={"Click to configure the environment"} placement="top">
|
||||
<Chip
|
||||
style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer", backgroundColor: red, }}
|
||||
label={"Stopped"}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
window.open(`/admin?tab=environments&env=${data.Name}`, "_blank", "noopener,noreferrer")
|
||||
}}
|
||||
|
||||
|
||||
/>
|
||||
</Tooltip>
|
||||
</a>
|
||||
: null}
|
||||
|
||||
{data.default === true ?
|
||||
<Chip
|
||||
style={{marginLeft: 0, padding: 0, marginRight: 10, cursor: "pointer",}}
|
||||
@@ -2065,12 +2210,22 @@ const ParsedAction = (props) => {
|
||||
color="secondary"
|
||||
/>
|
||||
: null}
|
||||
|
||||
|
||||
{data.Name}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/*selectedActionEnvironment.running_ip === "" && selectedActionEnvironment.Name !== "Cloud" && selectedActionEnvironment.Name !== "cloud" ?
|
||||
<a href={`/admin?tab=environment&env=${selectedActionEnvironment.Name}`} target="_blank" style={{textDecoration: "none", color: "#f85a3e",}}>
|
||||
<Typography style={{}}>
|
||||
Configure the environment
|
||||
</Typography>
|
||||
</a>
|
||||
: null*/}
|
||||
</div>
|
||||
) : null}
|
||||
{workflow.execution_variables !== undefined &&
|
||||
workflow.execution_variables !== null &&
|
||||
@@ -2742,8 +2897,7 @@ const ParsedAction = (props) => {
|
||||
) : null}
|
||||
|
||||
{suggestionInfo()}
|
||||
|
||||
{selectedActionParameters.map((data, count) => {
|
||||
{selectedActionParameters?.map((data, count) => {
|
||||
if (data.variant === "") {
|
||||
data.variant = "STATIC_VALUE";
|
||||
}
|
||||
@@ -2752,10 +2906,16 @@ const ParsedAction = (props) => {
|
||||
return null
|
||||
}
|
||||
|
||||
if (data.value === "authgroup controlled") {
|
||||
return null
|
||||
}
|
||||
|
||||
// selectedAction.selectedAuthentication = e.target.value
|
||||
// selectedAction.authentication_id = e.target.value.id
|
||||
if (
|
||||
!selectedAction.auth_not_required &&
|
||||
(selectedAction.auth_not_required !== undefined && !selectedAction.auth_not_required) &&
|
||||
selectedActionParameters[count].value !== undefined &&
|
||||
selectedAction.parameters[count].value !== undefined &&
|
||||
selectedAction.selectedAuthentication !== undefined &&
|
||||
selectedAction.selectedAuthentication.fields !== undefined &&
|
||||
selectedAction.selectedAuthentication.fields[data.name] !==
|
||||
@@ -3158,6 +3318,14 @@ const ParsedAction = (props) => {
|
||||
<Typography variant="body2">
|
||||
<strong>Ex. :</strong> {data?.example.length > 0 ? data.example : "No example available"}
|
||||
</Typography>
|
||||
{
|
||||
data?.configuration === true ?
|
||||
(
|
||||
<Typography variant="body2" mt={0.5}>
|
||||
<strong>Auth: </strong>Use "\$" instead of "$"
|
||||
</Typography>
|
||||
) : null
|
||||
}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
@@ -3261,10 +3429,12 @@ const ParsedAction = (props) => {
|
||||
color="primary"
|
||||
// defaultValue={data.value}
|
||||
value={
|
||||
paramValues.find((param) => param.name === data.name) !== undefined
|
||||
? paramValues.find((param) => param.name === data.name).value
|
||||
: ""
|
||||
data?.value
|
||||
}
|
||||
error={
|
||||
data?.error?.length > 0 ? true : false
|
||||
}
|
||||
helperText={data?.error?.length > 0 ? errorHelperText(data?.name,data?.value,data?.error) : returnHelperText(data.name, data.value)}
|
||||
//options={{
|
||||
// theme: 'gruvbox-dark',
|
||||
// keyMap: 'sublime',
|
||||
@@ -3287,10 +3457,8 @@ const ParsedAction = (props) => {
|
||||
// changeActionParameter(event, count, data);
|
||||
handleParamChange(event, count, data)
|
||||
}}
|
||||
helperText={returnHelperText(data.name, data.value)}
|
||||
onFocus={(event) => {
|
||||
setUiBox(event.target.id)
|
||||
console.log(event.target.id)
|
||||
|
||||
}}
|
||||
onBlur={(event) => {
|
||||
@@ -4195,11 +4363,7 @@ const ParsedAction = (props) => {
|
||||
onClose={() => {
|
||||
setShowAutocomplete(false);
|
||||
|
||||
if (
|
||||
!selectedActionParameters[count].value[
|
||||
selectedActionParameters[count].value.length - 1
|
||||
] === "."
|
||||
) {
|
||||
if (!selectedActionParameters[count].value[selectedActionParameters[count].value.length - 1] === ".") {
|
||||
setShowDropdown(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ const SearchField = props => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: "auto", marginLeft: !isLoggedIn ? 0: "auto", marginRight: !isLoggedIn ? 0 : "auto", width: !isLoggedIn ? "auto" : 300, }}>
|
||||
<div style={{ marginTop: "auto", marginLeft: !isLoggedIn ? 0: "auto", marginRight: !isLoggedIn ? 0 : "auto", width: !isLoggedIn ? "auto" : 410, }}>
|
||||
{modalView}
|
||||
<TextField
|
||||
style={{ backgroundColor: "#212121", height: 48, borderRadius: rounded === true ? 25 : theme.palette.borderRadius, minWidth: fieldWidth, maxWidth: fieldWidth, }}
|
||||
|
||||
@@ -3755,7 +3755,7 @@ If you're interested, please let me know a time that works for you, or set up a
|
||||
<Tab label=<span>Limits & Cloud Sync</span> />
|
||||
<Tab label=<span>Priorities</span> />
|
||||
<Tab label=<span>Billing & Stats</span> />
|
||||
<Tab disabled={!isCloud} label=<span>Branding (Beta)</span> />
|
||||
<Tab disabled={!isCloud} label=<span>Partner</span> />
|
||||
</Tabs>
|
||||
|
||||
<Divider
|
||||
|
||||
@@ -74,6 +74,7 @@ import {
|
||||
import {
|
||||
Folder as FolderIcon,
|
||||
VerifiedUser as VerifiedUserIcon,
|
||||
CheckCircle as CheckCircleIcon,
|
||||
Insights as InsightsIcon,
|
||||
LibraryBooks as LibraryBooksIcon,
|
||||
OpenInNew as OpenInNewIcon,
|
||||
@@ -126,7 +127,7 @@ import {
|
||||
ArrowForward as ArrowForwardIcon,
|
||||
|
||||
} from "@mui/icons-material";
|
||||
|
||||
import SwapHorizIcon from '@mui/icons-material/SwapHoriz';
|
||||
//import * as cytoscape from "cytoscape";
|
||||
import cytoscape from "cytoscape";
|
||||
|
||||
@@ -320,7 +321,7 @@ export function SetJsonDotnotation(jsonInput, inputKey) {
|
||||
|
||||
export const green = "#86c142";
|
||||
export const yellow = "#FECC00";
|
||||
export const red = "red";
|
||||
export const red = "#ff3632";
|
||||
|
||||
export function removeParam(key, sourceURL) {
|
||||
if (sourceURL === undefined) {
|
||||
@@ -534,6 +535,8 @@ const AngularWorkflow = (defaultprops) => {
|
||||
const [listCache, setListCache] = React.useState([]);
|
||||
const [selectedOption, setSelectedOption] = React.useState("");
|
||||
const [tenzirConfigModalOpen, setTenzirConfigModalOpen] = React.useState(false);
|
||||
const [rules, setRules] = React.useState([]);
|
||||
const [sigmaFilesNames, setSigmaFileNames] = React.useState("")
|
||||
|
||||
const [distributedFromParent, setDistributedFromParent] = React.useState("")
|
||||
const [suborgWorkflows, setSuborgWorkflows] = React.useState([])
|
||||
@@ -1437,7 +1440,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
});
|
||||
};
|
||||
|
||||
const handleKafkaSubmit = (trigger) => {
|
||||
const handleCommandSubmit = (trigger) => {
|
||||
if (trigger.trigger_type !== "PIPELINE") {
|
||||
toast("Unable to save the configuration");
|
||||
return;
|
||||
@@ -1445,18 +1448,48 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
|
||||
trigger.parameters = []
|
||||
|
||||
const topic = document.getElementById('topic')?.value;
|
||||
const bootstrapServers = document.getElementById('bootstrap_servers')?.value;
|
||||
const groupId = document.getElementById('group_id')?.value;
|
||||
//const autoOffsetReset = document.getElementById('auto_offset_reset')?.value;
|
||||
const command = document.getElementById('sigma')?.value
|
||||
|
||||
if(command) {
|
||||
trigger.parameters.push({
|
||||
name: "command",
|
||||
value: command
|
||||
})
|
||||
} else {
|
||||
toast("Please enter the comamnd");
|
||||
return;
|
||||
}
|
||||
|
||||
// if (autoOffsetReset) {
|
||||
// trigger.parameters.push({
|
||||
// name: "auto_offset_reset",
|
||||
// value: autoOffsetReset
|
||||
// });
|
||||
// }
|
||||
|
||||
setTenzirConfigModalOpen(false);
|
||||
};
|
||||
|
||||
const handleSubmit = (trigger) => {
|
||||
if (trigger.trigger_type !== "PIPELINE") {
|
||||
toast("Unable to save the configuration");
|
||||
return;
|
||||
}
|
||||
if (selectedOption === "Kafka Queue") {
|
||||
trigger.parameters = []
|
||||
|
||||
const topic = document.getElementById('topic')?.value
|
||||
const bootstrapServers = document.getElementById('bootstrap_servers')?.value
|
||||
const groupId = document.getElementById('group_id')?.value
|
||||
const autoOffsetReset = document.getElementById('auto_offset_reset')?.value;
|
||||
|
||||
if(topic) {
|
||||
trigger.parameters.push({
|
||||
name: "topic",
|
||||
value: topic
|
||||
});
|
||||
})
|
||||
} else {
|
||||
toast("please enter the topic name");
|
||||
toast("Please enter the topic name");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1477,16 +1510,33 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
});
|
||||
}
|
||||
|
||||
// if (autoOffsetReset) {
|
||||
// trigger.parameters.push({
|
||||
// name: "auto_offset_reset",
|
||||
// value: autoOffsetReset
|
||||
// });
|
||||
// }
|
||||
if (autoOffsetReset) {
|
||||
trigger.parameters.push({
|
||||
name: "auto_offset_reset",
|
||||
value: autoOffsetReset
|
||||
});
|
||||
}
|
||||
|
||||
setTenzirConfigModalOpen(false);
|
||||
} else if (selectedOption === "Syslog listener") {
|
||||
trigger.parameters = []
|
||||
|
||||
const endpoint = document.getElementById('endpoint')?.value
|
||||
|
||||
if(endpoint) {
|
||||
trigger.parameters.push({
|
||||
name: "endpoint",
|
||||
value: endpoint
|
||||
})
|
||||
} else {
|
||||
toast("Please enter your endpoint");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
const handleColoring = (actionId, status, label) => {
|
||||
if (cy === undefined) {
|
||||
return
|
||||
@@ -3687,7 +3737,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
|
||||
|
||||
setSelectedEdge({})
|
||||
setSelectedActionEnvironment({})
|
||||
//setSelectedActionEnvironment({})
|
||||
setTriggerAuthentication({})
|
||||
setTriggerFolders([])
|
||||
setLocalFirstrequest(true)
|
||||
@@ -6130,6 +6180,8 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
if (curnode.data.id === edge.data("source")) {
|
||||
console.log("Found matching trigger source: ", curnode)
|
||||
if (curnode.data.app_name !== "Shuffle Workflow" && curnode.data.app_name !== "User Input") {
|
||||
|
||||
|
||||
// If it's started, READD the edge
|
||||
if (curnode.data.status === "running") {
|
||||
//console.log("Edge is running - readd it: ", edge.data())
|
||||
@@ -6144,7 +6196,8 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
data: newdata,
|
||||
})
|
||||
|
||||
toast.error("You must STOP the trigger before deleting its branches")
|
||||
//toast.error("You must STOP the trigger before deleting its branches")
|
||||
console.log("You must STOP the trigger before deleting its branches")
|
||||
} catch (e) {
|
||||
console.log("Failed re-adding edge: ", e)
|
||||
}
|
||||
@@ -8241,11 +8294,11 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
toast("Pipeline deleted!")
|
||||
return
|
||||
}
|
||||
|
||||
if (trigger.parameters){
|
||||
trigger.parameters.push({
|
||||
name: data.name,
|
||||
value: data.command,
|
||||
});
|
||||
});}
|
||||
|
||||
if (data.type === "stop") trigger.status = "stopped";
|
||||
else trigger.status = "running";
|
||||
@@ -8253,7 +8306,6 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
|
||||
setSelectedTrigger(trigger);
|
||||
setWorkflow(workflow);
|
||||
console.log("Should set the status to running and save");
|
||||
saveWorkflow(workflow);
|
||||
}
|
||||
})
|
||||
@@ -8328,6 +8380,32 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
});
|
||||
};
|
||||
|
||||
const getSigmaInfo = () => {
|
||||
const url = globalUrl + "/api/v1/files/detection/sigma_rules";
|
||||
|
||||
fetch(url, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) =>
|
||||
response.json().then((responseJson) => {
|
||||
if (responseJson["success"] === false) {
|
||||
toast("Failed to get sigma rules");
|
||||
} else {
|
||||
setRules(responseJson.sigma_info);
|
||||
|
||||
}
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
console.log("Error in getting sigma files: ", error);
|
||||
toast("An error occurred while fetching sigma rules");
|
||||
});
|
||||
};
|
||||
|
||||
const parsedHeight = isMobile ? bodyHeight - appBarSize * 4 : bodyHeight - appBarSize - 50
|
||||
const appViewStyle = {
|
||||
marginLeft: 5,
|
||||
@@ -9102,6 +9180,11 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
const startIndex = app.actions.findIndex((action) => action.category_label !== undefined && action.category_label !== null && action.category_label.length > 0)
|
||||
const actionIndex = startIndex < 0 ? 0 : startIndex
|
||||
|
||||
if (app.actions[actionIndex] === undefined || app.actions[actionIndex] === null) {
|
||||
console.log("No actions found for app: ", app)
|
||||
return
|
||||
}
|
||||
|
||||
// Make the first action the most relevant one for them based on previous use
|
||||
if (
|
||||
app.actions[actionIndex].parameters !== undefined &&
|
||||
@@ -11605,7 +11688,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
<div style={appApiViewStyle}>
|
||||
<div style={{ }}>
|
||||
<h3 style={{ marginBottom: 5, }}>
|
||||
Branch: Conditions - {selectedEdgeIndex}
|
||||
Conditions
|
||||
</h3>
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
@@ -11671,10 +11754,10 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
</Typography>
|
||||
: null}
|
||||
|
||||
<div style={{position: "absolute", bottom: 10, width: "90%", margin: "auto", }}>
|
||||
{/*
|
||||
<div style={{position: "absolute", bottom: 15, width: "90%", margin: "auto", }}>
|
||||
|
||||
<Button
|
||||
style={{ margin: "auto", marginTop: "10px" }}
|
||||
style={{ margin: "auto", marginTop: "15px" }}
|
||||
color="secondary"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
@@ -11688,33 +11771,37 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
|
||||
var branchdata = JSON.parse(JSON.stringify(foundBranch.data()))
|
||||
console.log("BEFORE: ", branchdata)
|
||||
|
||||
const newid = uuidv4()
|
||||
branchdata.source = target
|
||||
branchdata.target = source
|
||||
branchdata.id = newid
|
||||
branchdata._id = newid
|
||||
|
||||
foundBranch.remove()
|
||||
|
||||
setTimeout(() => {
|
||||
toast("Edge being added!")
|
||||
cy.add({
|
||||
group: "edges",
|
||||
source: target,
|
||||
target: source,
|
||||
data: branchdata,
|
||||
})
|
||||
}, 2500)
|
||||
|
||||
console.log("Start node", workflow.start)
|
||||
const startNode = workflow.start
|
||||
if(source === startNode){
|
||||
toast("Can't point to Start Node")
|
||||
}else{
|
||||
const newid = uuidv4()
|
||||
branchdata.source = target
|
||||
branchdata.target = source
|
||||
branchdata.id = newid
|
||||
branchdata._id = newid
|
||||
|
||||
foundBranch.remove()
|
||||
|
||||
cy.add({
|
||||
group: "edges",
|
||||
source: target,
|
||||
target: source,
|
||||
data: branchdata,
|
||||
})
|
||||
selectedEdge.id = newid
|
||||
setSelectedEdge(selectedEdge)
|
||||
toast("Branch direction changed!")
|
||||
}
|
||||
}
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<DeleteIcon style={{marginRight: 10, }}/>
|
||||
Change Direction
|
||||
<SwapHorizIcon style={{marginRight: 10 }}/>
|
||||
Flip Branch
|
||||
</Button>
|
||||
<Button
|
||||
{/*<Button
|
||||
style={{ margin: "auto", }}
|
||||
color="secondary"
|
||||
fullWidth
|
||||
@@ -11740,7 +11827,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
</Button>
|
||||
*/}
|
||||
<Button
|
||||
style={{ margin: "auto", marginTop: 50, }}
|
||||
style={{ margin: "auto", marginTop: 20, }}
|
||||
color="secondary"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
@@ -11750,7 +11837,6 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
if (foundBranch !== undefined && foundBranch !== null) {
|
||||
foundBranch.remove()
|
||||
}
|
||||
|
||||
setConditionsModalOpen(false)
|
||||
setSelectedEdge({})
|
||||
}}
|
||||
@@ -15268,6 +15354,14 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
}
|
||||
|
||||
</div>
|
||||
const defaultEnvironment = environments.find(
|
||||
(env) => env.default && env.Name.toLowerCase() !== "cloud"
|
||||
);
|
||||
|
||||
if (selectedTrigger.trigger_type === "PIPELINE" && selectedTrigger.environment === "onprem" && defaultEnvironment !== undefined) {
|
||||
selectedTrigger.environment = defaultEnvironment.Name
|
||||
setSelectedTrigger(selectedTrigger) }
|
||||
|
||||
const PipelineSidebar = Object.getOwnPropertyNames(selectedTrigger).length === 0 || workflow.triggers[selectedTriggerIndex] === undefined && selectedTrigger.trigger_type !== "SCHEDULE" ? null :
|
||||
<div style={appApiViewStyle}>
|
||||
<h3 style={{ marginBottom: "5px" }}>
|
||||
@@ -15366,14 +15460,32 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
<div
|
||||
key="syslogListener"
|
||||
onClick={() => {
|
||||
// setSelectedOption("Syslog listener")
|
||||
// setTenzirConfigModalOpen(true);
|
||||
}}
|
||||
if(selectedTrigger.status === "running"){
|
||||
//toast("please stop the trigger to edit the configuration");
|
||||
return;
|
||||
} else {
|
||||
setSelectedOption("Syslog listener");
|
||||
const url = `${globalUrl}/api/v1/pipelines/pipeline_${selectedTrigger.id}`
|
||||
const command = `from tcp://192.168.1.100:5162 read syslog | import`
|
||||
const pipelineConfig = {
|
||||
command: command,
|
||||
name: selectedTrigger.label,
|
||||
type: "create",
|
||||
environment: selectedTrigger.environment,
|
||||
workflow_id: workflow.id,
|
||||
trigger_id: selectedTrigger.id,
|
||||
start_node: "",
|
||||
url:url,
|
||||
};
|
||||
submitPipeline(selectedTrigger, selectedTriggerIndex, pipelineConfig);
|
||||
|
||||
|
||||
}}}
|
||||
style={{
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
padding: 10,
|
||||
cursor: "not-allowed",
|
||||
cursor: "pointer",
|
||||
marginTop: 5,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
@@ -15383,27 +15495,46 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
control={
|
||||
<Radio
|
||||
checked={selectedOption === "Syslog listener"}
|
||||
onChange={() => setSelectedOption("Syslog listener")}
|
||||
onChange={() => {
|
||||
if (selectedTrigger.status !== "running"){
|
||||
setSelectedOption("Syslog listener")}}
|
||||
}
|
||||
value={"Syslog listener"}
|
||||
name="option"
|
||||
disabled={true}
|
||||
/>
|
||||
}
|
||||
label="Start Syslog listener"
|
||||
label= {selectedOption === "Syslog listener" && selectedTrigger.status === "running" ? "listening at 192.168.1.100:5162" : "Start Syslog listener"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
key="sigmaRulesearch"
|
||||
onClick={() => {
|
||||
// setSelectedOption("Sigma Rulesearch")
|
||||
// setTenzirConfigModalOpen(true);
|
||||
}}
|
||||
if(selectedTrigger.status === "running"){
|
||||
// toast("please stop the trigger to edit the configuration");
|
||||
return;
|
||||
} else {
|
||||
setSelectedOption("SigmaRule");
|
||||
const url = `${globalUrl}/api/v1/pipelines/pipeline_${selectedTrigger.id}`
|
||||
const command = `export | sigma /var/lib/tenzir/sigma_rules | to ${url}`
|
||||
const pipelineConfig = {
|
||||
command: command,
|
||||
name: selectedTrigger.label,
|
||||
type: "create",
|
||||
environment: selectedTrigger.environment,
|
||||
workflow_id: workflow.id,
|
||||
trigger_id: selectedTrigger.id,
|
||||
start_node: "",
|
||||
url:url,
|
||||
};
|
||||
submitPipeline(selectedTrigger, selectedTriggerIndex, pipelineConfig);
|
||||
|
||||
}}}
|
||||
style={{
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
padding: 10,
|
||||
cursor: "not-allowed",
|
||||
cursor: "pointer",
|
||||
marginTop: 5,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
@@ -15412,11 +15543,12 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Radio
|
||||
checked={selectedOption === "Sigma Rulesearch"}
|
||||
onChange={() => setSelectedOption("Sigma Rulesearch")}
|
||||
checked={selectedOption === "SigmaRule"}
|
||||
onChange={() => {
|
||||
if (selectedTrigger.status !== "running"){
|
||||
setSelectedOption("SigmaRule")}}}
|
||||
value={"Sigma Rulesearch"}
|
||||
name="option"
|
||||
disabled={true}
|
||||
/>
|
||||
}
|
||||
label="Run Sigma Rulesearch"
|
||||
@@ -15447,7 +15579,9 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
control={
|
||||
<Radio
|
||||
checked={selectedOption === "Kafka Queue"}
|
||||
onChange={() => setSelectedOption("Kafka Queue")}
|
||||
onChange={() => {
|
||||
if (selectedTrigger.status !== "running"){
|
||||
setSelectedOption("Kafka Queue")}}}
|
||||
value={"Kafka Queue"}
|
||||
name="option"
|
||||
/>
|
||||
@@ -15463,10 +15597,12 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
disabled={selectedTrigger.status === "running"}
|
||||
onClick={() => {
|
||||
|
||||
if (selectedOption === "Kafka Queue"){
|
||||
const url = `${globalUrl}/api/v1/pipelines/pipeline_${selectedTrigger.id}`
|
||||
const topic = (selectedTrigger?.parameters?.find(param => param.name === "topic")?.value) || ''
|
||||
const bootstrapServers = (selectedTrigger?.parameters?.find(param => param.name === "bootstrap_servers")?.value) || ''
|
||||
const groupId = (selectedTrigger?.parameters?.find(param => param.name === "group_id")?.value) || ''
|
||||
// const autoOffsetReset = (selectedTrigger?.parameters?.find(param => param.name === "auto_offset_reset")?.value) || ''
|
||||
const autoOffsetReset = (selectedTrigger?.parameters?.find(param => param.name === "auto_offset_reset")?.value) || ''
|
||||
let command = "from kafka"
|
||||
|
||||
if(topic) {
|
||||
@@ -15487,15 +15623,15 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
} else {
|
||||
command = `${command},group.id=${selectedTrigger.id}`
|
||||
}
|
||||
// if(autoOffsetReset) {
|
||||
// command = `${command},auto.offset.reset=${autoOffsetReset}`
|
||||
// } else {
|
||||
// command = `${command},auto.offset.reset=earliest`
|
||||
if(autoOffsetReset) {
|
||||
command = `${command},auto.offset.reset=${autoOffsetReset}`
|
||||
} else {
|
||||
command = `${command},auto.offset.reset=earliest`
|
||||
|
||||
// }
|
||||
}
|
||||
command = `${command},auto.offset.reset=earliest`
|
||||
command = `${command},client.id=${selectedTrigger.id},enable.auto.commit=true,auto.commit.interval.ms=1`
|
||||
command = `${command} read json | to ${globalUrl}/api/v1/pipelines/pipeline_${selectedTrigger.id}`
|
||||
command = `${command} read json | to ${url}`
|
||||
|
||||
const pipelineConfig = {
|
||||
command: command,
|
||||
@@ -15505,9 +15641,11 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
workflow_id: workflow.id,
|
||||
trigger_id: selectedTrigger.id,
|
||||
start_node: "",
|
||||
url: url,
|
||||
};
|
||||
submitPipeline(selectedTrigger, selectedTriggerIndex, pipelineConfig);
|
||||
}}
|
||||
}
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
Start
|
||||
@@ -18166,6 +18304,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
}
|
||||
}
|
||||
|
||||
const envStatus = !(executionData.workflow !== undefined && executionData.workflow !== null && executionData.workflow.actions !== undefined && executionData.workflow.actions !== null && executionData.workflow.actions.length > 0) ? "loading" : "success"
|
||||
|
||||
var executionDelay = -75
|
||||
const executionModal = (
|
||||
@@ -18598,26 +18737,6 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
{executionData.status === "EXECUTING" ? (
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title="Abort workflow"
|
||||
placement="top"
|
||||
style={{ zIndex: 50000 }}
|
||||
>
|
||||
<span style={{}}>
|
||||
<Button
|
||||
color="primary"
|
||||
style={{ float: "right", marginTop: 20, marginLeft: 10 }}
|
||||
onClick={() => {
|
||||
abortExecution();
|
||||
}}
|
||||
>
|
||||
<PauseIcon style={{}} />
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
|
||||
<Tooltip
|
||||
color="primary"
|
||||
@@ -18691,18 +18810,41 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
||||
{isCloud ?
|
||||
{executionData.status === "EXECUTING" ? (
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title="Explore logs for the workflow"
|
||||
title="Abort workflow"
|
||||
placement="top"
|
||||
style={{ zIndex: 50000, }}
|
||||
style={{ zIndex: 50000 }}
|
||||
>
|
||||
<span style={{}}>
|
||||
<Button
|
||||
color="primary"
|
||||
style={{ float: "right", marginTop: 20, marginLeft: 10 }}
|
||||
disabled={userdata.region_url !== "https://shuffler.io"}
|
||||
onClick={() => {
|
||||
abortExecution();
|
||||
}}
|
||||
>
|
||||
<PauseIcon style={{}} />
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
|
||||
{isCloud ?
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title="Explore logs for the workflow (max 5 days ago)"
|
||||
placement="top"
|
||||
style={{ zIndex: 50000, }}
|
||||
>
|
||||
<span style={{}}>
|
||||
<Button
|
||||
color="secondary"
|
||||
style={{ float: "right", marginTop: 20, marginLeft: 10 }}
|
||||
|
||||
// Max 5 days in the past
|
||||
disabled={userdata.region_url !== "https://shuffler.io" || executionData.started_at < (Math.floor(Date.now() / 1000) - 432000)}
|
||||
onClick={() => {
|
||||
toast("Opening logs in a new tab")
|
||||
|
||||
@@ -18711,7 +18853,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
}, 250)
|
||||
}}
|
||||
>
|
||||
<InsightsIcon color="secondary" />
|
||||
<InsightsIcon />
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
@@ -18722,7 +18864,18 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
{executionData.workflow !== undefined && executionData.workflow !== null && executionData.workflow.actions !== undefined && executionData.workflow.actions !== null && executionData.workflow.actions.length > 0 ?
|
||||
<div style={{ display: "flex", marginLeft: 10, }}>
|
||||
<Typography variant="body1">
|
||||
<b>Env </b>
|
||||
|
||||
{/*envStatus === "success" ?
|
||||
<Tooltip title="Environment is healthy" placement="top">
|
||||
<CheckCircleIcon style={{ color: "green" }} />
|
||||
</Tooltip>
|
||||
: envStatus === "failure" ?
|
||||
<Tooltip title="Environment is unhealthy" placement="top">
|
||||
<ErrorIcon style={{ color: "red" }} />
|
||||
</Tooltip>
|
||||
: null*/}
|
||||
|
||||
<b style={{ }}>Env </b>
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body1" color="textSecondary" style={{color: "#f85a3e", cursor: "pointer", }} onClick={() => {
|
||||
@@ -19580,7 +19733,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
return "The app's Docker Image is not available in the environment yet. Re-run the app to force a re-download of the app. If the problem persists, contact support"
|
||||
}
|
||||
|
||||
if (result.status !== 200 && result.url !== undefined && result.url !== null && (result.url.includes("192.168") || result.url.includes("172.16") || result.url.includes("10.0"))) {
|
||||
if (result.status !== 200 && result.url !== undefined && result.url !== null && typeof result.url === "string" && (result.url.includes("192.168") || result.url.includes("172.16") || result.url.includes("10.0"))) {
|
||||
return "Consider whether your Orborus environment can connect to a local IP or not."
|
||||
}
|
||||
|
||||
@@ -21205,146 +21358,142 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
</Dialog>
|
||||
) : null;
|
||||
|
||||
const tenzirConfigModal = tenzirConfigModalOpen ? (
|
||||
<Dialog
|
||||
PaperComponent={PaperComponent}
|
||||
hideBackdrop={true}
|
||||
disableEnforceFocus={true}
|
||||
disableBackdropClick={true}
|
||||
style={{ pointerEvents: "none" }}
|
||||
open={tenzirConfigModalOpen}
|
||||
PaperProps={{
|
||||
style: {
|
||||
pointerEvents: "auto",
|
||||
color: "white",
|
||||
minWidth: 600,
|
||||
minHeight: 450,
|
||||
maxHeight: 450,
|
||||
padding: 15,
|
||||
overflow: "hidden",
|
||||
zIndex: 10012,
|
||||
border: theme.palette.defaultBorder,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: 2,
|
||||
padding: 0,
|
||||
minHeight: isMobile ? "90%" : 700,
|
||||
maxHeight: isMobile ? "90%" : 700,
|
||||
overflowY: "auto",
|
||||
overflowX: isMobile ? "auto" : "hidden",
|
||||
}}
|
||||
>
|
||||
<DialogTitle id="tenzir-config-modal" style={{ cursor: "move" }}>
|
||||
<div style={{ color: "white" }}>Configuration options for {selectedOption}</div>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
{selectedOption === "Kafka Queue" && (
|
||||
<>
|
||||
<b>Topic</b>
|
||||
<TextField
|
||||
id="topic"
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {},
|
||||
}}
|
||||
fullWidth
|
||||
color="primary"
|
||||
placeholder={"topic name"}
|
||||
defaultValue={(selectedTrigger?.parameters?.find(param => param.name === "topic")?.value) || ''}
|
||||
/>
|
||||
<b>bootstrap.servers</b>
|
||||
<TextField
|
||||
id="bootstrap_servers"
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {},
|
||||
}}
|
||||
fullWidth
|
||||
color="primary"
|
||||
placeholder={"broker1.example.com:9092,192.168.1.100:9092"}
|
||||
defaultValue={(selectedTrigger?.parameters?.find(param => param.name === "bootstrap_servers")?.value) || ''}
|
||||
/>
|
||||
<b>group.id</b>
|
||||
<TextField
|
||||
id="group_id"
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {},
|
||||
}}
|
||||
fullWidth
|
||||
color="primary"
|
||||
placeholder={"tenzir"}
|
||||
defaultValue={(selectedTrigger?.parameters?.find(param => param.name === "group_id")?.value) || ''}
|
||||
/>
|
||||
{/* <b>auto.offest.reset</b>
|
||||
<TextField
|
||||
id="auto_offset_reset"
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {},
|
||||
}}
|
||||
fullWidth
|
||||
color="primary"
|
||||
placeholder={"earliest"}
|
||||
defaultValue={(selectedTrigger?.parameters?.find(param => param.name === "auto_offset_reset")?.value) || ''}
|
||||
/> */}
|
||||
</>
|
||||
)}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
style={{ borderRadius: "0px" }}
|
||||
onClick={() => {
|
||||
setTenzirConfigModalOpen(false);
|
||||
const TenzirConfigModal = () => {
|
||||
if (!tenzirConfigModalOpen) return null;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
PaperComponent={PaperComponent}
|
||||
hideBackdrop={true}
|
||||
disableEnforceFocus={true}
|
||||
disableBackdropClick={true}
|
||||
style={{ pointerEvents: "none" }}
|
||||
open={tenzirConfigModalOpen}
|
||||
PaperProps={{
|
||||
style: {
|
||||
pointerEvents: "auto",
|
||||
color: "white",
|
||||
minWidth: 600,
|
||||
minHeight: 550,
|
||||
maxHeight: 550,
|
||||
padding: 15,
|
||||
overflow: "hidden",
|
||||
zIndex: 10012,
|
||||
border: theme.palette.defaultBorder,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DialogTitle id="tenzir-config-modal" style={{ cursor: "move" }}>
|
||||
<div style={{ color: "white" }}>Configuration options for Kafka</div>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
{selectedOption === "Kafka Queue" ? (
|
||||
<div>
|
||||
<b>Topic</b>
|
||||
<TextField
|
||||
id="topic"
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
style={{ borderRadius: "0px" }}
|
||||
onClick={() => {
|
||||
handleKafkaSubmit(selectedTrigger);
|
||||
InputProps={{
|
||||
style: {},
|
||||
}}
|
||||
fullWidth
|
||||
color="primary"
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</div>
|
||||
placeholder={"topic name"}
|
||||
defaultValue={
|
||||
selectedTrigger?.parameters?.find(
|
||||
(param) => param.name === "topic",
|
||||
)?.value || ""
|
||||
}
|
||||
/>
|
||||
<b>bootstrap.servers</b>
|
||||
<TextField
|
||||
id="bootstrap_servers"
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {},
|
||||
}}
|
||||
fullWidth
|
||||
color="primary"
|
||||
placeholder={"broker1.example.com:9092,192.168.1.100:9092"}
|
||||
defaultValue={
|
||||
selectedTrigger?.parameters?.find(
|
||||
(param) => param.name === "bootstrap_servers",
|
||||
)?.value || ""
|
||||
}
|
||||
/>
|
||||
<b>group.id</b>
|
||||
<TextField
|
||||
id="group_id"
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {},
|
||||
}}
|
||||
fullWidth
|
||||
color="primary"
|
||||
placeholder={"tenzir"}
|
||||
defaultValue={
|
||||
selectedTrigger?.parameters?.find(
|
||||
(param) => param.name === "group_id",
|
||||
)?.value || ""
|
||||
}
|
||||
/>
|
||||
<b>auto.offest.reset</b>
|
||||
<TextField
|
||||
id="auto_offset_reset"
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
InputProps={{
|
||||
style: {},
|
||||
}}
|
||||
fullWidth
|
||||
color="primary"
|
||||
placeholder={"earliest"}
|
||||
defaultValue={
|
||||
selectedTrigger?.parameters?.find(
|
||||
(param) => param.name === "auto_offset_reset",
|
||||
)?.value || ""
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : null}{" "}
|
||||
|
||||
<IconButton
|
||||
style={{
|
||||
zIndex: 5000,
|
||||
position: "absolute",
|
||||
top: 14,
|
||||
right: 18,
|
||||
color: "grey",
|
||||
}}
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<Button
|
||||
style={{ borderRadius: "0px" }}
|
||||
onClick={() => {
|
||||
setTenzirConfigModalOpen(false);
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Dialog>
|
||||
) : null;
|
||||
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
style={{ borderRadius: "0px" }}
|
||||
onClick={() => {
|
||||
handleSubmit(selectedTrigger);
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
const SuggestionBoxUi = () => {
|
||||
@@ -21737,7 +21886,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
</div>
|
||||
<div style={{textAlign: "center", color: "white", flex: 1, paddingTop: 20, }}>
|
||||
<Typography variant="h6">
|
||||
{selectedVersion.name}
|
||||
{selectedVersion?.name}
|
||||
</Typography>
|
||||
</div>
|
||||
{/* Cross icon to close it */}
|
||||
@@ -21923,7 +22072,7 @@ const releaseToConnectLabel = "Release to Connect"
|
||||
{codePopoutModal}
|
||||
{workflowRevisions}
|
||||
{authenticationModal}
|
||||
{tenzirConfigModal}
|
||||
{<TenzirConfigModal/>}
|
||||
{/*editWorkflowModal*/}
|
||||
{authgroupModal}
|
||||
{executionArgumentModal}
|
||||
|
||||
@@ -2586,6 +2586,8 @@ const Apps = (props) => {
|
||||
if (parsedtext.indexOf("openapi") === -1 && parsedtext.indexOf("swagger") === -1) {
|
||||
setValidation(false);
|
||||
setOpenApiError("Error in generation: "+parsedtext);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -2684,10 +2686,11 @@ const Apps = (props) => {
|
||||
body: openApidata,
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
.then((response) => {
|
||||
|
||||
setValidation(false);
|
||||
return response.json();
|
||||
})
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success) {
|
||||
setAppValidation(responseJson.id);
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Container,
|
||||
Box,
|
||||
TextField,
|
||||
Switch,
|
||||
Typography,
|
||||
Button,
|
||||
} from "@mui/material";
|
||||
import { toast } from "react-toastify";
|
||||
import RuleCard from "./RuleCard";
|
||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||
|
||||
const handleDirectoryChange = (folderDisabled, setFolderDisabled, globalUrl, isTenzirActive) => {
|
||||
|
||||
if (!isTenzirActive) {
|
||||
toast("connect to siem first for global enable/disable to work");
|
||||
return;
|
||||
}
|
||||
const action = folderDisabled ? "enable_folder" : "disable_folder";
|
||||
const url = `${globalUrl}/api/v1/files/detection/${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 = ({
|
||||
globalUrl,
|
||||
ruleInfo,
|
||||
folderDisabled,
|
||||
setFolderDisabled,
|
||||
isTenzirActive,
|
||||
}) => {
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleConnectClick = () => {
|
||||
if (!isTenzirActive) {
|
||||
setLoading(true);
|
||||
const url = `${globalUrl}/api/v1/detection/siem/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 {
|
||||
setLoading(false);
|
||||
toast("Failed to connect to SIEM");
|
||||
}
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
setLoading(false);
|
||||
console.log(`Error in connecting to SIEM: `, error);
|
||||
toast("An error occurred while connecting to SIEM");
|
||||
});
|
||||
} else {
|
||||
console.log("Already connected to SIEM");
|
||||
}
|
||||
};
|
||||
|
||||
const filteredRules = ruleInfo?.filter((rule) =>
|
||||
rule.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
rule.description.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
|
||||
return (
|
||||
<Container sx={{ mt: 4 }}>
|
||||
<Box sx={{ border: "1px solid #ccc", borderRadius: 2, p: 3 }}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" component="div">
|
||||
Sigma Detection Rules
|
||||
</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleConnectClick}
|
||||
disabled={loading} // Disable the button while loading
|
||||
style={{ backgroundColor: isTenzirActive ? "green" : "red"}}
|
||||
>
|
||||
{loading ? <CircularProgress size={24} /> : isTenzirActive ? "Connected to siem" : "Connect to siem"}
|
||||
</Button>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
label="Search rules"
|
||||
variant="outlined"
|
||||
size="small"
|
||||
sx={{ mr: 2 }}
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
/>
|
||||
{/* <Button
|
||||
color="primary"
|
||||
variant="contained"
|
||||
onClick={() => uploadRef.current.click()}
|
||||
>
|
||||
<PublishIcon /> Upload sigma file
|
||||
</Button>
|
||||
<input
|
||||
hidden
|
||||
type="file"
|
||||
multiple
|
||||
ref={uploadRef}
|
||||
onChange={(event) => {
|
||||
uploadFiles(event.target.files);
|
||||
}}
|
||||
/> */}
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Typography variant="body2" sx={{ mr: 1 }}>
|
||||
Global disable/enable
|
||||
</Typography>
|
||||
<Switch
|
||||
checked={!folderDisabled}
|
||||
onChange={() =>
|
||||
handleDirectoryChange(folderDisabled, setFolderDisabled, globalUrl, isTenzirActive)
|
||||
}
|
||||
disabled={!isTenzirActive}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
height: "500px",
|
||||
width: "100%",
|
||||
overflowY: "auto",
|
||||
border: "1px solid #ddd",
|
||||
p: 1,
|
||||
}}
|
||||
>
|
||||
{filteredRules?.length > 0 &&
|
||||
filteredRules.map((card) => (
|
||||
<RuleCard
|
||||
key={card.file_id}
|
||||
ruleName={card.title}
|
||||
description={card.description}
|
||||
file_id={card.file_id}
|
||||
globalUrl={globalUrl}
|
||||
folderDisabled={folderDisabled}
|
||||
isTenzirActive={isTenzirActive}
|
||||
{...card}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default Detection;
|
||||
@@ -0,0 +1,162 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Container, CircularProgress, Typography } from "@mui/material";
|
||||
import { toast } from "react-toastify";
|
||||
import Detection from "./Detection";
|
||||
|
||||
const DetectionDashBoard = (props) => {
|
||||
const { globalUrl } = props;
|
||||
const [ruleInfo, setRuleInfo] = useState(null);
|
||||
const [, setSelectedRule] = useState(null);
|
||||
const [, setFileData] = useState("");
|
||||
const [isTenzirActive, setIsTenzirActive] = useState(false);
|
||||
const [folderDisabled, setFolderDisabled] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [importAttempts, setImportAttempts] = useState(0);
|
||||
const maxImportAttempts = 2;
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTimeout = setTimeout(() => {
|
||||
fetchSigmaInfo();
|
||||
}, 1000); // Delay by 1 second
|
||||
|
||||
return () => clearTimeout(fetchTimeout);
|
||||
}, [globalUrl]);
|
||||
|
||||
useEffect(() => {
|
||||
if (ruleInfo && ruleInfo.length === 0 && importAttempts < maxImportAttempts) {
|
||||
importSigmaFromUrl();
|
||||
}
|
||||
}, [ruleInfo]);
|
||||
|
||||
const openEditBar = (rule) => {
|
||||
setSelectedRule(rule);
|
||||
fetchFileContent(rule.file_id);
|
||||
};
|
||||
|
||||
const handleSave = (updatedContent) => {
|
||||
toast("This will be saved");
|
||||
};
|
||||
|
||||
const fetchFileContent = (file_id) => {
|
||||
setFileData("");
|
||||
fetch(`${globalUrl}/api/v1/files/${file_id}/content`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for file :O!");
|
||||
return "";
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then((respdata) => {
|
||||
if (respdata.length === 0) {
|
||||
toast("Failed getting file. Is it deleted?");
|
||||
return;
|
||||
}
|
||||
setFileData(respdata);
|
||||
})
|
||||
.catch((error) => {
|
||||
toast(error.toString());
|
||||
});
|
||||
};
|
||||
|
||||
const fetchSigmaInfo = () => {
|
||||
const url = `${globalUrl}/api/v1/files/detection/sigma_rules`;
|
||||
setIsLoading(true);
|
||||
|
||||
fetch(url, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((responseJson) => {
|
||||
if (responseJson["success"] === false) {
|
||||
toast("Failed to get sigma rules");
|
||||
} else {
|
||||
setRuleInfo(responseJson.sigma_info || []);
|
||||
setFolderDisabled(responseJson.folder_disabled);
|
||||
setIsTenzirActive(responseJson.is_tenzir_active);
|
||||
}
|
||||
setIsLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
setIsLoading(false);
|
||||
console.log("Error in getting sigma files: ", error);
|
||||
toast("An error occurred while fetching sigma rules");
|
||||
setRuleInfo([]);
|
||||
});
|
||||
};
|
||||
|
||||
const importSigmaFromUrl = () => {
|
||||
setIsLoading(true);
|
||||
setImportAttempts((prevAttempts) => prevAttempts + 1);
|
||||
|
||||
const url = "https://github.com/satti-hari-krishna-reddy/shuffle_sigma";
|
||||
const folder = "sigma";
|
||||
|
||||
const parsedData = {
|
||||
url: url,
|
||||
path: folder,
|
||||
field_3: "main",
|
||||
};
|
||||
|
||||
toast(`Getting files from url ${url}. This may take a while if the repository is large. Please wait...`);
|
||||
fetch(`${globalUrl}/api/v1/files/download_remote_enhanced`, {
|
||||
method: "POST",
|
||||
mode: "cors",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify(parsedData),
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success) {
|
||||
toast("Successfully loaded files from " + url);
|
||||
fetchSigmaInfo(); // Fetch again after successful import
|
||||
} else {
|
||||
toast(responseJson.reason ? `Failed loading: ${responseJson.reason}` : "Failed loading");
|
||||
}
|
||||
setIsLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
toast(error.toString());
|
||||
setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
if (isLoading && (!ruleInfo || ruleInfo.length === 0)) {
|
||||
return (
|
||||
<Container style={{ display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }}>
|
||||
<div>
|
||||
<CircularProgress />
|
||||
<Typography variant="h6" style={{ marginTop: 20 }}>Downloading rules, please wait...</Typography>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Container style={{ display: "flex" }}>
|
||||
<Detection
|
||||
globalUrl={globalUrl}
|
||||
ruleInfo={ruleInfo}
|
||||
folderDisabled={folderDisabled}
|
||||
setFolderDisabled={setFolderDisabled}
|
||||
isTenzirActive={isTenzirActive}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default DetectionDashBoard;
|
||||
@@ -122,7 +122,7 @@ export const Paragrah = (props) => {
|
||||
|
||||
|
||||
return (
|
||||
<div class="sdf">
|
||||
<div>
|
||||
{element}
|
||||
</div>
|
||||
)
|
||||
@@ -457,6 +457,30 @@ const Docs = (defaultprops) => {
|
||||
minHeight: "80vh",
|
||||
};
|
||||
|
||||
const noteLabelStyle = {
|
||||
fontWeight: "bold",
|
||||
color: "#f86a3e",
|
||||
display: "block",
|
||||
marginBottom: "5px",
|
||||
};
|
||||
|
||||
const Blockquote = ({ children }) => {
|
||||
|
||||
const textContent = children.map(child =>
|
||||
child.props && child.props.children ? child.props.children.join('') : child
|
||||
).join('').trim();
|
||||
|
||||
// Maybe some more contents....
|
||||
const isNote = textContent.startsWith("[!TIP]");
|
||||
return (
|
||||
<blockquote style={isNote ? alertNote : {}}>
|
||||
{isNote && <span style={noteLabelStyle}>Tips:</span>}
|
||||
{isNote ? textContent.replace("[!TIP]", "").trim() : children}
|
||||
</blockquote>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const Heading = (props) => {
|
||||
const [hover, setHover] = useState(false);
|
||||
var id = props.children[0].toLowerCase().toString()
|
||||
@@ -840,6 +864,12 @@ const Docs = (defaultprops) => {
|
||||
fontSize: isMobile ? "1.3rem" : "1.1rem",
|
||||
};
|
||||
|
||||
const alertNote = {
|
||||
padding: "10px",
|
||||
borderLeft: "5px solid #f86a3e",
|
||||
backgroundColor: "rgb(26,26,26)",
|
||||
};
|
||||
|
||||
const CustomButton = (props) => {
|
||||
const { title, icon, link } = props
|
||||
|
||||
@@ -974,9 +1004,11 @@ const Docs = (defaultprops) => {
|
||||
h6: Heading,
|
||||
a: OuterLink,
|
||||
p: Paragrah,
|
||||
blockquote: Blockquote,
|
||||
}
|
||||
|
||||
|
||||
|
||||
// PostDataBrowser Section
|
||||
const postDataBrowser =
|
||||
list === undefined || list === null ? null : (
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import { Box, Typography, Button, TextField } from '@mui/material';
|
||||
|
||||
const EditComponent = ({ ruleName, description, content, setContent, lastEdited, editedBy, onSave }) => {
|
||||
|
||||
const handleSave = () => {
|
||||
onSave(content);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ p: 2, border: '1px solid #ccc', borderRadius: 2, height: '100%', width: '100%', marginTop:'30px'}}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Typography variant="h6">{ruleName}</Typography>
|
||||
</Box>
|
||||
<Typography variant="body2" style={{ marginTop: '2%' }}>
|
||||
{description}
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ mt: 1 }}>
|
||||
Last edited: {lastEdited}
|
||||
</Typography>
|
||||
<Typography variant="body2">
|
||||
Edited By: {editedBy}
|
||||
</Typography>
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<TextField
|
||||
multiline
|
||||
rows={12}
|
||||
value={content}
|
||||
onChange={(e) => setContent(e.target.value)}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'flex-end', mt: 2 }}>
|
||||
<Button variant="contained" color="primary" onClick={handleSave}>
|
||||
Save
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditComponent;
|
||||
@@ -0,0 +1,168 @@
|
||||
import React from "react";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
IconButton,
|
||||
Typography,
|
||||
Switch,
|
||||
} from "@mui/material";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import { toast } from "react-toastify";
|
||||
import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.jsx";
|
||||
|
||||
const RuleCard = ({ ruleName, description, file_id, globalUrl, folderDisabled, isTenzirActive, ...otherProps }) => {
|
||||
const [openCodeEditor, setOpenCodeEditor] = React.useState(false);
|
||||
const [fileData, setFileData] = React.useState("");
|
||||
const [isEnabled, setIsEnabled] = React.useState(otherProps.is_enabled);
|
||||
|
||||
const isCloud = ["localhost:3002", "shuffler.io"].includes(window.location.host);
|
||||
|
||||
const handleSwitchChange = (event) => {
|
||||
if (folderDisabled) {
|
||||
toast("enable the directory to enable individual rules");
|
||||
return;
|
||||
}
|
||||
if (!isTenzirActive) {
|
||||
toast("connect to the siem to enable/disable the rule");
|
||||
return;
|
||||
}
|
||||
const newIsEnabled = event.target.checked;
|
||||
toggleRule(file_id, !newIsEnabled, globalUrl, () => {
|
||||
setIsEnabled(newIsEnabled);
|
||||
});
|
||||
};
|
||||
|
||||
const UpdateText = (text) => {
|
||||
fetch(`${globalUrl}/api/v1/files/${file_id}/edit`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: text,
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Can't update file");
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success === true) {
|
||||
toast("Successfully updated file");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
toast("Error updating file: " + error.toString());
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Card variant="outlined" sx={{ mb: 2 }}>
|
||||
<CardContent>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 16,
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6">{ruleName}</Typography>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<IconButton onClick={() => openEditBar(file_id, setOpenCodeEditor, setFileData, globalUrl)}>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
<Switch
|
||||
checked={isEnabled && !folderDisabled}
|
||||
onChange={handleSwitchChange}
|
||||
disabled={!isTenzirActive}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Typography variant="body2" style={{ marginTop: '2%' }}>
|
||||
{description}
|
||||
</Typography>
|
||||
|
||||
<ShuffleCodeEditor
|
||||
isCloud={isCloud}
|
||||
expansionModalOpen={openCodeEditor}
|
||||
setExpansionModalOpen={setOpenCodeEditor}
|
||||
setcodedata={setFileData}
|
||||
codedata={fileData}
|
||||
isFileEditor={true}
|
||||
key={fileData} // https://reactjs.org/docs/reconciliation.html#recursing-on-children
|
||||
runUpdateText={UpdateText}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
const toggleRule = (fileId, isCurrentlyEnabled, globalUrl, callback) => {
|
||||
const action = isCurrentlyEnabled ? "disable" : "enable";
|
||||
const url = `${globalUrl}/api/v1/files/detection/${fileId}/${action}_rule`;
|
||||
|
||||
fetch(url, {
|
||||
method: "PUT",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) =>
|
||||
response.json().then((responseJson) => {
|
||||
if (responseJson["success"] === false) {
|
||||
toast(`Failed to ${action} the rule`);
|
||||
} else {
|
||||
toast(`Rule ${action}d successfully`);
|
||||
callback();
|
||||
}
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
console.log(`Error in ${action}ing the rule: `, error);
|
||||
toast(`An error occurred while ${action}ing the rule`);
|
||||
});
|
||||
};
|
||||
|
||||
const openEditBar = (file_id, setOpenCodeEditor, setFileData, globalUrl) => {
|
||||
getFileContent(file_id, setFileData, globalUrl)
|
||||
|
||||
setOpenCodeEditor(true);
|
||||
};
|
||||
|
||||
const getFileContent = (file_id, setFileData, globalUrl) => {
|
||||
setFileData("");
|
||||
fetch(globalUrl + "/api/v1/files/" + file_id + "/content", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for file :O!");
|
||||
return "";
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then((respdata) => {
|
||||
if (respdata.length === 0) {
|
||||
toast("Failed getting file. Is it deleted?");
|
||||
return;
|
||||
}
|
||||
return respdata
|
||||
})
|
||||
.then((responseData) => {
|
||||
|
||||
setFileData(responseData);
|
||||
})
|
||||
.catch((error) => {
|
||||
toast(error.toString());
|
||||
});
|
||||
};
|
||||
export default RuleCard;
|
||||
Reference in New Issue
Block a user