diff --git a/frontend/src/components/ConfigureWorkflow.jsx b/frontend/src/components/ConfigureWorkflow.jsx
index 66c48ab2..09fb5560 100644
--- a/frontend/src/components/ConfigureWorkflow.jsx
+++ b/frontend/src/components/ConfigureWorkflow.jsx
@@ -1,4 +1,5 @@
import React, { useState, useEffect } from "react";
+import { useInterval } from "react-powerhooks";
import {
InputAdornment,
@@ -15,7 +16,11 @@ import {
ListItemText,
Fade,
} from "@material-ui/core";
-import { FavoriteBorder as FavoriteBorderIcon } from "@material-ui/icons";
+import {
+ FavoriteBorder as FavoriteBorderIcon,
+ Error as ErrorIcon,
+ CheckCircleRounded as CheckCircleRoundedIcon,
+} from "@mui/icons-material";
import { FixName } from "../views/Apps.jsx";
// Handles workflow updates on first open to highlight the issues of the workflow
@@ -45,6 +50,8 @@ const ConfigureWorkflow = (props) => {
setAuthenticationType,
alert,
showTriggers,
+ workflowExecutions,
+ getWorkflowExecution,
} = props;
const [requiredActions, setRequiredActions] = React.useState([]);
const [requiredVariables, setRequiredVariables] = React.useState([]);
@@ -54,6 +61,22 @@ const ConfigureWorkflow = (props) => {
const [firstLoad, setFirstLoad] = React.useState("");
const [showFinalizeAnimation, setShowFinalizeAnimation] = React.useState(false);
+ const [checkStarted, setCheckStarted] = React.useState(false);
+
+ const { start, stop } = useInterval({
+ duration: 3000,
+ startImmediate: false,
+ callback: () => {
+ if (getWorkflowExecution !== undefined && workflowExecutions !== undefined) {
+ const paramkey = workflow.id
+ getWorkflowExecution(paramkey)
+ } else {
+ console.log("Executions or getWorkflowExecutions not defined")
+ }
+ },
+ });
+
+ // Where is this from?
if (workflow === undefined || workflow === null) {
return null;
}
@@ -118,6 +141,8 @@ const ConfigureWorkflow = (props) => {
action: action,
update_version: action.app_version,
app: {},
+ steps: [],
+ show_steps: false,
};
const app = apps.find(
@@ -126,17 +151,21 @@ const ConfigureWorkflow = (props) => {
(app.app_version === action.app_version ||
(app.loop_versions !== null &&
app.loop_versions.includes(action.app_version)))
- );
+ )
+
+ //newaction.steps = wazuhSteps
if (app === undefined || app === null) {
- //console.log("App not found: ", action.app_name);
-
const subapp = apps.find(app => app.name === action.app_name)
if (subapp !== undefined && subapp !== null) {
newaction.update_version = "1.1.0"
}
-
newaction.must_activate = true;
+ newaction.steps.push({
+ "title": "Activate app",
+ "type": "activate",
+ "required": true,
+ })
} else {
if (
action.authentication_id === "" &&
@@ -157,6 +186,12 @@ const ConfigureWorkflow = (props) => {
}
}
+ newaction.steps.push({
+ "title": "Authenticate app",
+ "type": "authenticate",
+ "required": true,
+ })
+
if (!filled) {
newaction.must_authenticate = true;
newaction.action_ids.push(action.id);
@@ -244,6 +279,38 @@ const ConfigureWorkflow = (props) => {
var trigger = workflow.triggers[key];
trigger.index = key;
+ if (trigger.trigger_type === "WEBHOOK") {
+ console.log("Found webhook: ", trigger)
+ if (trigger.app_association !== undefined && trigger.app_association.name !== null && trigger.app_association.name !== "") {
+ console.log("Actions: ", newactions)
+ const findapp = trigger.app_association.name.toLowerCase()
+ const foundindex = newactions.findIndex(action => action.app_name.toLowerCase() === findapp)
+
+ // Adding webhook to start of it
+ if (foundindex >= 0) {
+ const tmpsteps = newactions[foundindex].steps
+ newactions[foundindex].steps = [
+ {
+ "title": "Configure Webhook",
+ "type": "webhook",
+ "required": true,
+ }
+ ]
+
+ for (var subkey in tmpsteps) {
+ newactions[foundindex].steps.push(tmpsteps[subkey])
+ }
+
+ newactions[foundindex].show_steps = true
+
+ console.log("CHANGED ACTION: ", newactions[foundindex])
+ //console.log("Index: ", newactions[foundindex])
+
+ continue
+ }
+ }
+ }
+
if (trigger.status === "running") {
continue;
}
@@ -297,7 +364,7 @@ const ConfigureWorkflow = (props) => {
}
const TriggerSection = (props) => {
- const { trigger } = props;
+ const { trigger } = props
return (
@@ -527,8 +594,8 @@ const ConfigureWorkflow = (props) => {
textTransform: "none",
textAlign: "left",
justifyContent: "flex-start",
- backgroundColor: action.auth_done ? theme.palette.surfaceColor : "#ffffff",
- color: action.auth_done ? "#686a6c" : "#2f2f2f",
+ backgroundColor: action.auth_done ? theme.palette.surfaceColor : theme.palette.inputColor,
+ color: action.auth_done ? "#686a6c" : "#ffffff",
borderRadius: theme.palette.borderRadius,
minWidth: 350,
maxHeight: 50,
@@ -571,46 +638,11 @@ const ConfigureWorkflow = (props) => {
src={action.large_image}
/>
- {action.auth_done ? "Authenticated" : `Authenticate ${action.app_name}`}
+ {action.auth_done ? "Authenticated" : `Authenticate ${action.app_name.replaceAll("_", " ")}`}
: null}
- {action.must_activate ? (
-
- ) : null}
- {action.update_version !== action.app_version ? (
+ {action.update_version !== action.app_version ?
- ) : null}
+ :
+ action.must_activate ?
+
+ :
+ null
+ }
);
}
@@ -667,10 +737,245 @@ const ConfigureWorkflow = (props) => {
// Based on the color here. Default: #f86a3e
//backgroundColor: selectedUsecaseCategory === usecase.name ? usecase.color : theme.palette.surfaceColor,
+ const BoxHighlight = (props) => {
+ const {data, appname, appinfo, index, activeStep, setActiveStep, finished, } = props
+
+ const [hovered, setHovered] = useState(false)
+ const [isOpen, setIsOpen] = useState(false)
+ const [isLoading, setIsLoading] = useState(false)
+
+ // This kind of just works for new workflows..
+ // What if we try many times?
+
+ var webhook = {
+ "name": "Testhook",
+ "description": `A Webhook Trigger has been started and is ready to receive events from ${appname}. Click to copy the URL to send events to.`,
+ "url": "",
+ }
+
+ useEffect(() => {
+ if (data.type === "webhook" && !finished) {
+ if (!checkStarted) {
+ setCheckStarted(true)
+ start()
+ }
+ }
+ }, [])
+
+ // Load webhook docs from the app itself (Wazuh)
+ // Add a "sample" for what the event is supposed to look like
+ // Have a listener for when ACTUALLY is received
+ // INJECT the URL into the documentation when loading it in
+ // How can we load it in? Should we just use the app name & get docs -> parse?
+ if (data.type === "webhook" && workflow.triggers !== undefined && workflow.triggers !== null) {
+ //console.log("Find webhook in the workflow!")
+ for (var key in workflow.triggers) {
+ if (workflow.triggers[key].trigger_type !== "WEBHOOK") {
+ continue
+ }
+
+ for (var subkey in workflow.triggers[key].parameters) {
+ const param = workflow.triggers[key].parameters[subkey]
+ if (param.name === "url") {
+ webhook.url = param.value
+
+ if (isLoading === false) {
+ setIsLoading(true)
+ }
+ break
+ }
+ }
+ }
+ } else if (data.type == "authenticate") {
+ //console.log("Handle app authentication in the workflow!")
+ }
+
+ return (
+
{
+ setIsOpen(!isOpen)
+ setActiveStep(index)
+ }}
+ onMouseOver={() => {
+ setHovered(true);
+ }}
+ onMouseOut={() => {
+ setHovered(false);
+ }}
+ >
+
+
+ {data.title}
+ {finished ?
+
+ :
+
+ }
+
+
+ {activeStep === index ?
+
+ {data.type === "webhook" ?
+
{
+ event.preventDefault()
+ console.log("Clicked Webhook")
+
+ var copyText = document.getElementById("copy_element_shuffle")
+ if (copyText !== undefined && copyText !== null) {
+ console.log("NAVIGATOR: ", navigator);
+ const clipboard = navigator.clipboard;
+ if (clipboard === undefined) {
+ alert.error("Can only copy over HTTPS (port 3443)");
+ return;
+ }
+
+ navigator.clipboard.writeText(webhook.url);
+ copyText.select();
+ copyText.setSelectionRange(
+ 0,
+ 99999
+ ); /* For mobile devices */
+
+ /* Copy the text inside the text field */
+ document.execCommand("copy");
+ alert.success("Copied Webhook URL");
+ }
+ }}>
+
{webhook.description}
+ {/*
{webhook.url}*/}
+ {isLoading && finished === false ?
+
+
+
+ :
+ null
+ }
+
+ :
+
+ }
+
+ : null}
+
+
+ )
+ }
+
+ const AppWrapper = (props) => {
+ const {data, parentindex} = props
+ const [clicked, setClicked] = useState(true)
+ const [hovered, setHovered] = useState(false)
+ const [activeStep, setActiveStep] = useState(0)
+ const [firstRun, setFirstRun] = useState(true)
+ const [finishCount, setFinishCount] = useState(0)
+
+ return (
+
+
{
+ //setClicked(!clicked)
+ }}
+ onMouseOver={() => {
+ setHovered(true);
+ }}
+ onMouseOut={() => {
+ setHovered(false);
+ }}
+ >
+
+
+
+
+ Configure {data.app_name.replaceAll("_", " ")}
+
+
+ {clicked === true ?
+ data.steps.map((step, index) => {
+ var finished = false
+ if (step.type === "activate") {
+ if (data.activation_done === true) {
+ finished = true
+
+ if (index === activeStep && firstRun === true) {
+ setActiveStep(activeStep+1)
+ }
+
+ if (firstRun) {
+ setFinishCount(finishCount+1)
+ }
+ }
+ }
+
+ if (step.type === "authenticate") {
+ console.log("AUTH STEP: ", step)
+ if (data.must_authenticate === true ) {
+ finished = false
+ } else {
+ if (data.activation_done === true && data.auth_done === true) {
+ finished = true
+
+ if (firstRun) {
+ setFinishCount(finishCount+1)
+ }
+
+ if (index === activeStep && firstRun === true) {
+ setActiveStep(activeStep+1)
+ }
+ }
+ }
+ }
+
+ if (step.type === "webhook") {
+ for (var key in workflowExecutions) {
+ const exec = workflowExecutions[key]
+ if (exec.execution_argument !== undefined && exec.execution_argument !== null && exec.execution_argument.length > 0 && exec.execution_source === "webhook") {
+ //console.log("Done: ", exec)
+
+ finished = true
+ if (index === activeStep && firstRun === true) {
+ setActiveStep(activeStep+1)
+
+ }
+
+ if (firstRun) {
+ setFinishCount(finishCount+1)
+ }
+
+ // Finished + source = webhook
+
+ stop()
+ //if (isLoading === true) {
+ // setIsLoading(false)
+ //}
+
+
+ break
+ }
+ }
+ }
+
+ if (firstRun === true && index === data.steps.length-1) {
+ setFirstRun(false)
+ }
+
+ return (
+
+ )
+ })
+ : null}
+
+ )
+ }
+
const topColor = "#f86a3e, #fc3922"
return (
-
+
{workflow.name}
@@ -679,13 +984,20 @@ const ConfigureWorkflow = (props) => {
{requiredActions.length > 0 ? (
-
+
Required Actions
+
{requiredActions.map((data, index) => {
return (
-
+
+ {data.steps !== undefined && data.steps !== null && data.show_steps === true ?
+
+ :
+
+ }
+
)
})}
@@ -743,6 +1055,7 @@ const ConfigureWorkflow = (props) => {
variant={"outlined"}
style={{}}
onClick={() => {
+ stop()
setShowFinalizeAnimation(true)
setTimeout(() => {
if (itemChanged) {