import React, { forwardRef, memo, useContext, useEffect } from 'react'; import {getTheme} from "../theme.jsx"; import { toast } from "react-toastify" ; import { Divider, List, ListItem, ListItemText, Button, ButtonGroup, Tooltip, IconButton, Dialog, DialogTitle, DialogContent, DialogActions, TextField, Chip, CircularProgress, Select, MenuItem, } from '@mui/material'; import { FileCopy as FileCopyIcon, OpenInNew as OpenInNewIcon, Refresh as RefreshIcon, Delete as DeleteIcon, Check as CheckIcon, } from "@mui/icons-material" import { green, yellow, red } from '../views/AngularWorkflow.jsx' import { Box, Skeleton, Typography } from '@mui/material'; import { Context } from '../context/ContextApi.jsx'; import RunDetectionTest from '../components/RunDetectionTest.jsx'; const SchedulesTab = memo((props) => { const {globalUrl, users, } = props; const [webHooks, setWebHooks] = React.useState([]); const [allSchedules, setAllSchedules] = React.useState([]); const [pipelines, setPipelines] = React.useState([]); const [showLoader, setShowLoader] = React.useState(true); const [workflows, setWorkflows] = React.useState([]); const [pipelineModalOpen, setPipelineModalOpen] = React.useState(false); const [newPipelineValue, setNewPipelineValue] = React.useState(`export live=true | sigma "/tmp/sigma_rules" | to "SHUFFLE_WEBHOOK"`); const [ticketWebhook, setTicketWebhook] = React.useState(""); const [detectionWorkflowId, setDetectionWorkflowId] = React.useState(""); const [environments, setEnvironments] = React.useState([]); const [selectedEnvironment, setSelectedEnvironment] = React.useState(""); const { themeMode, brandColor } = useContext(Context); const theme = getTheme(themeMode, brandColor); const handleGetWorkflows = () => { const url = `${globalUrl}/api/v1/workflows`; fetch(url, { method: "GET", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", }).then((response) => { if (response.status !== 200) { console.log("Status not 200 for getting all workflows"); } return response.json(); }) .then((responseJson) => { if (responseJson.success !== false) { setWorkflows(responseJson || []); for (var i = 0; i < responseJson?.length; i++) { if (responseJson[i].background_processing === true && responseJson[i].name.toLowerCase().includes("ingest tickets") && responseJson[i].triggers !== undefined) { for (var triggerkey in responseJson[i].triggers) { if (responseJson[i].triggers[triggerkey].trigger_type === "WEBHOOK") { setDetectionWorkflowId(responseJson[i].id) setTicketWebhook(`${globalUrl}/api/v1/hooks/webhook_${responseJson[i].triggers[triggerkey].id}`) setNewPipelineValue(`export live=true | sigma /tmp/sigma_rules | to ${globalUrl}/api/v1/hooks/webhook_${responseJson[i].triggers[triggerkey].id}`) break; } } } } } }) .catch((error) => { toast(error.toString()); }) } useEffect(() => { handleGetWorkflows() if (allSchedules.length === 0 && webHooks.length === 0 && pipelines.length === 0) { handleGetAllTriggers() handleGetEnvironments() } }, []) const textColor = "#9E9E9E !important"; const changePipelineState = (pipeline, state) => { if (state.trim() === "") { toast("state is not defined"); return; } const data = { name: pipeline.name, id: pipeline.id, type: state, command: pipeline.definition, environment: pipeline.environment, }; if (state === "start") { toast("starting the pipeline") } else { toast.info("Stopping a pipeline. This may take a few minutes to propagate.") } const url = `${globalUrl}/api/v1/triggers/pipeline`; fetch(url, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(data), credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for stream results :O!"); toast("Failed to update the pipeline state"); } return response.json(); }) .then((responseJson) => { if (!responseJson.success) { toast.error("Failed to update the pipeline: " + responseJson.reason); } else { setTimeout(() => { handleGetAllTriggers() }, 5000) setTimeout(() => { handleGetAllTriggers() }, 10000) setTimeout(() => { handleGetAllTriggers() }, 20000) setTimeout(() => { handleGetAllTriggers() }, 120000) /* if (state === "start") { toast("Successfully created pipeline"); } else { toast("Sucessfully stopped the pipeline"); } */ } }) .catch((error) => { //toast(error.toString()); console.log("Get schedule error: ", error.toString()); }) } const submitPipelineWrapper = (pipelineValue, environment) => { submitPipeline(pipelineValue, environment) } const NewPipelineView = ( ) const submitPipeline = (pipeline, environment) => { var pipelineConfig = { command: pipeline, name: pipeline, type: "create", environment: "", workflow_id: "", trigger_id: "", start_node: "", } if (selectedEnvironment !== undefined && selectedEnvironment !== "") { pipelineConfig.environment = selectedEnvironment.Name } if (environment !== undefined && environment !== "") { pipelineConfig.environment = environment } const url = `${globalUrl}/api/v1/triggers/pipeline`; fetch(url, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(pipelineConfig), credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for stream results :O!"); } return response.json(); }) .then((responseJson) => { if (!responseJson.success && pipelineConfig.type !== "delete") { toast.error("Failed to set pipeline: " + responseJson.reason); } else { if (pipelineConfig.type === "create") { toast.success("Pipeline will be created. Page will autorefresh in a bit: " + responseJson.reason) setPipelineModalOpen(false) } else if (pipelineConfig.type === "stop") { toast.success("Pipeline will be stopped: " + responseJson.reason) setPipelineModalOpen(false) } else { toast.info("Unknown pipeline type: " + pipelineConfig.type) } } setTimeout(() => { handleGetAllTriggers() }, 5000) setTimeout(() => { handleGetAllTriggers() }, 10000) setTimeout(() => { handleGetAllTriggers() }, 15000) setTimeout(() => { handleGetAllTriggers() }, 20000) }) .catch((error) => { console.log("Get pipeline error: ", error.toString()); }); } const deleteSchedule = (data) => { // FIXME - add some check here ROFL console.log("INPUT: ", data); // Just use this one? const url = `${globalUrl}/api/v1/workflows/${data?.workflow_id}/schedule/${data.id}`; fetch(url, { method: "DELETE", credentials: "include", headers: { "Content-Type": "application/json", }, }) .then((response) => response.json().then((responseJson) => { if (responseJson["success"] === false) { toast("Failed stopping schedule"); } else { setTimeout(() => { handleGetAllTriggers(); }, 1500); //toast("Successfully stopped schedule!") } }) ) .catch((error) => { console.log("Error in userdata: ", error); }); }; const deleteWebhook = (trigger) => { if (trigger === undefined) { return; } fetch(globalUrl + "/api/v1/hooks/" + trigger.id + "/delete", { method: "DELETE", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for stream results :O!"); } return response.json(); }) .then((responseJson) => { if (responseJson.success) { toast("Successfully stopped webhook"); } else { if (responseJson.reason !== undefined) { toast("Failed stopping webhook: " + responseJson.reason); } } setTimeout(handleGetAllTriggers, 1000); }) .catch((error) => { toast( "Delete webhook error. Contact support or check logs if this persists.", ); }); }; const handleGetEnvironments = () => { fetch(`${globalUrl}/api/v1/environments`, { method: "GET", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for getting all triggers"); } return response.json(); }) .then((responseJson) => { setEnvironments(responseJson || []); if (responseJson?.length > 0) { var selectedEnv = "" for (var i = 0; i < responseJson?.length; i++) { const env = responseJson[i] if (env.archived) { continue } selectedEnv = env.Name if (env?.data_lake?.enabled === true) { break } } setSelectedEnvironment(selectedEnv.Name) } }) .catch((error) => { // toast(error.toString()); }); } const handleGetAllTriggers = () => { fetch(globalUrl + "/api/v1/triggers", { method: "GET", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for getting all triggers"); } return response.json(); }) .then((responseJson) => { setWebHooks(responseJson.webhooks || []); setAllSchedules(responseJson.schedules || []); setPipelines(responseJson.pipelines || []); setShowLoader(false); }) .catch((error) => { // toast(error.toString()); }); }; const startSchedule = (trigger) => { if (trigger.name.length <= 0) { toast("Error: name can't be empty"); return; } toast("Creating schedule"); const data = { name: trigger.name, frequency: trigger.frequency, execution_argument: trigger.argument, environment: trigger.environment, id: trigger.id, start: trigger.start_node, }; fetch(`${globalUrl}/api/v1/workflows/${trigger.workflow_id}/schedule`, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(data), credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for stream results :O!"); } return response.json(); }) .then((responseJson) => { if (!responseJson.success) { toast("Failed to set schedule: " + responseJson.reason); } else { toast("Successfully created schedule"); } setTimeout(handleGetAllTriggers, 1000); }) .catch((error) => { //toast(error.toString()); console.log("Get schedule error: ", error.toString()); }); } const startWebHook = (trigger) => { const hookname = trigger.info.name; if (hookname.length === 0) { toast("Missing name"); return; } if (trigger.id.length !== 36) { toast("Missing id"); return; } toast("Starting webhook"); const data = { name: hookname, type: "webhook", id: trigger.id, workflow: trigger.workflows[0], start: trigger.start, environment: trigger.environment, auth: trigger.auth, custom_response: trigger.custom_response, version: trigger.version, version_timeout: 15, }; fetch(globalUrl + "/api/v1/hooks/new", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(data), credentials: "include", }) .then((response) => response.json()) .then((responseJson) => { if (responseJson.success) { // Set the status toast("Successfully started webhook"); } else { toast("Failed starting webhook: " + responseJson.reason); } setTimeout(handleGetAllTriggers, 1000); }) .catch((error) => { //console.log(error.toString()); console.log("New webhook error: ", error.toString()); }); }; return (