+ /*
+ console.log(userdata.eth_info)
+ if (userdata.eth_info.account.length === 0 && userdata.eth_info !== undefined && userdata.eth_info.account !== undefined && userdata.eth_info.account.length > 0) {
+ setEthInfo(userdata.eth_info)
+ } else if (userdata.eth_info.balance.length > 0 && userdata.eth_info.parsed_balance === undefined) {
+ //console.log(window.ethereum)
+ //console.log(window.ethereum.utils.formatEther(userdata.eth_info.balance))
+ const parsed_balance = parseInt(userdata.eth_info.balance, 16)/1000000000000000000
+ console.log("Parsed balance: ", parsed_balance)
+ userdata.eth_info.parsed_balance = parsed_balance
+ userdata.eth_info.parsed_balance = parsed_balance
+ setEthInfo(userdata.eth_info)
+ } else if (userdata.eth_info !== undefined && userdata.eth_info.balance !== userdata.eth_info.balance) {
+ console.log("Updating balance: ", userdata.eth_info)
+ setEthInfo(userdata.eth_info)
+ }
+ */
+
+ //Returns the value from a storage position at a given address.
+ const isCloud =
+ window.location.host === "localhost:3002" ||
+ window.location.host === "shuffler.io"
+
+ const bodyDivStyle = {
+ margin: "auto",
+ textAlign: "center",
+ width: "1100px",
+ };
+
+ const boxStyle = {
+ flex: "1",
+ color: "white",
+ position: "relative",
+ marginLeft: "10px",
+ marginRight: "10px",
+ paddingLeft: "30px",
+ paddingRight: "30px",
+ paddingBottom: "30px",
+ paddingTop: "30px",
+ backgroundColor: theme.palette.surfaceColor,
+ display: "flex",
+ flexDirection: "column",
+ };
+
+ const checkOwner = (data, userdata) => {
+ var currentOwner = false;
+ if (data.owner.address === userdata.eth_info.account) {
+ currentOwner = true;
+ } else {
+ if (
+ data.top_ownerships !== undefined &&
+ data.top_ownerships !== null &&
+ data.top_ownerships.length === 1
+ ) {
+ for (var key in data.top_ownerships) {
+ if (
+ data.top_ownerships[key].owner.address === userdata.eth_info.account
+ ) {
+ currentOwner = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return currentOwner;
+ };
+
+ const onPasswordChange = () => {
+ const data = {
+ username: userSettings.username,
+ currentpassword: currentPassword,
+ newpassword: newPassword,
+ newpassword2: newPassword2,
+ };
+ const url = globalUrl + "/api/v1/passwordchange";
+ fetch(url, {
+ mode: "cors",
+ method: "POST",
+ body: JSON.stringify(data),
+ credentials: "include",
+ crossDomain: true,
+ withCredentials: true,
+ headers: {
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ })
+ .then((response) =>
+ response.json().then((responseJson) => {
+ if (responseJson["success"] === false) {
+ setPasswordFormMessage(responseJson["reason"]);
+ } else {
+ alert.success("Changed password!");
+ setPasswordFormMessage("");
+ }
+ })
+ )
+ .catch((error) => {
+ setPasswordFormMessage("Something went wrong.");
+ });
+ };
+
+ const loadWorkflowOwnership = () => {
+ fetch(
+ globalUrl + "/api/v1/workflows/collections/untitled-collection-103712081",
+ {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ credentials: "include",
+ }
+ )
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for WORKFLOW EXECUTION :O!");
+ }
+
+ return response.json();
+ })
+ .then((responseJson) => {
+ //console.log("Values: ", responseJson)
+
+ // const [selfOwnedWorkflows, setSelfOwnedWorkflows] = React.useState([])
+ if (responseJson !== undefined && responseJson !== null) {
+ const filteredOwnerships = responseJson.filter(
+ (data) => checkOwner(data, userdata) === true
+ );
+ if (
+ filteredOwnerships !== undefined &&
+ filteredOwnerships !== null &&
+ filteredOwnerships.length > 0
+ ) {
+ setSelfOwnedWorkflows(filteredOwnerships);
+ }
+
+ var collections = [];
+ for (var key in responseJson) {
+ var collectionname = responseJson[key].collection.name;
+ if (!collections.includes(collectionname)) {
+ collections.push(collectionname);
+ }
+ }
+
+ console.log(collections);
+ setLoadedWorkflowCollections(collections);
+ setLoadedValidationWorkflows(responseJson);
+
+ setTimeout(() => {
+ window.scrollTo({
+ top: document.body.scrollHeight,
+ left: 0,
+ behavior: "smooth",
+ });
+ }, 250);
+ }
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+ };
+
+ const generateApikey = () => {
+ fetch(globalUrl + "/api/v1/generateapikey", {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ credentials: "include",
+ })
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for WORKFLOW EXECUTION :O!");
+ }
+
+ return response.json();
+ })
+ .then((responseJson) => {
+ setUserSettings(responseJson);
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+ };
+
+ const getSettings = () => {
+ fetch(globalUrl + "/api/v1/getsettings", {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ credentials: "include",
+ })
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for WORKFLOW EXECUTION :O!");
+ }
+
+
+ return response.json();
+ })
+ .then((responseJson) => {
+ setUserSettings(responseJson);
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+ };
+
+ // Gotta be a better way of doing this rofl
+ const setFields = () => {
+ if (userdata.username !== undefined) {
+ if (userdata.username.length > 0) {
+ setUsername(userdata.username);
+ }
+ //if (userdata.firstname.length > 0) {
+ // setFirstname(userdata.firstname)
+ //}
+ //if (userdata.lastname.length > 0) {
+ // setLastname(userdata.lastname)
+ //}
+ //if (userdata.title.length > 0) {
+ // setTitle(userdata.title)
+ //}
+ //if (userdata.companyname.length > 0) {
+ // setCompanyname(userdata.companyname)
+ //}
+ //if (userdata.phone.length > 0) {
+ // setPhone(userdata.phone)
+ //}
+ //if (userdata.email.length > 0) {
+ // setEmail(userdata.email)
+ //}
+ }
+ };
+
+ // const registerProviders = (userdata) => {
+ // // Register hooks here
+ // detectEthereumProvider().then((provider) => {
+ // if (provider) {
+ // if (!provider.isMetaMask) {
+ // alert.error("Only MetaMask is supported as of now.");
+ // return;
+ // }
+
+ // // Find the ethereum network
+ // // Get the users' account(s)
+ // //alert.info("Connecting to MetaMask")
+ // //console.log("Connected: ", provider.isConnected())
+
+ // if (!provider.isConnected()) {
+ // alert.error("Metamask is not connected.");
+ // return;
+ // }
+
+ // provider.on("message", (event) => {
+ // alert.info("Ethereum message: ", event);
+ // });
+
+ // provider.on("chainChanged", (chainId) => {
+ // console.log("Changed chain to: ", chainId);
+
+ // const method = "eth_getBalance";
+ // const params = [userdata.eth_info.account, "latest"];
+ // provider
+ // .request({
+ // method: method,
+ // params,
+ // })
+ // .then((result) => {
+ // console.log("Got result: ", result);
+ // if (result !== undefined && result !== null) {
+ // userdata.eth_info.balance = result;
+ // userdata.eth_info.parsed_balance = result / 1000000000000000000;
+ // console.log("INFO: ", userdata);
+ // setUserData(userdata);
+ // } else {
+ // alert.error("Couldn't find balance: ", result);
+ // }
+ // })
+ // .catch((error) => {
+ // // If the request fails, the Promise will reject with an error.
+ // alert.error("Failed getting info from ethereum API: " + error);
+ // });
+ // });
+ // }
+ // });
+ // };
+
+ // This should "always" have data
+ useEffect(() => {
+ if (firstrequest) {
+ setFirstRequest(false);
+ getSettings();
+ //registerProviders(userdata)
+ }
+
+ if (
+ Object.getOwnPropertyNames(userdata).length > 0 &&
+ username === "" &&
+ email === ""
+ ) {
+ setFields();
+ }
+ });
+
+ const ParsedWorkflowView = (props) => {
+ const { data } = props;
+
+ var innerPaperStyle = {
+ backgroundColor: theme.palette.inputColor,
+ display: "flex",
+ flexDirection: "column",
+ padding: "0px 0px 12px 0px",
+ borderRadius: theme.palette.borderRadius,
+ };
+
+ const currentOwner = checkOwner(data, userdata);
+ if (currentOwner === true) {
+ innerPaperStyle.border = "3px solid #f86a3e";
+ }
+
+ return (
+
+
+
+
+ {data.collection}
+
+ {data.name}
+
+
+ );
+ };
+
+
+ const runFlex = userdata.eth_info !== undefined && userdata.eth_info.account !== undefined &&
+ userdata.eth_info.account.length > 0 && userdata.eth_info.parsed_balance !== undefined
+
+ // Random names for type & autoComplete. Didn't research :^)
+ //var imageData = file.length > 0 ? file : fileBase64;
+ //imageData = imageData === undefined || imageData.length === 0
+ // ? theme.palette.defaultImage
+ // : imageData;
+
+ const imageData = userSettings.image === undefined || userSettings.image == null || userSettings.image.length === 0 ? theme.palette.defaultImage : userSettings.image
+ const imageInfo = (
+

{
+ if (imageData !== theme.palette.defaultImage) {
+ navigate(`/creators/${userdata.public_username}`)
+ } else {
+ navigate(`/creators`)
+ }
+ }}
+ style={{
+ cursor: "pointer",
+ maxWidth: 100,
+ maxHeight: 100,
+ minWidth: 100,
+ minHeight: 100,
+ position: "absolute",
+ top: -80,
+ left: 1020 / 2 - 25,
+ borderRadius: 50,
+ objectFit: "contain",
+ border: "2px solid rgba(255,255,255,0.7)",
+ }}
+ />
+ );
+
+ const landingpageData = (
+
+
+ {imageInfo}
+ Settings
+
+ setUsername(e.target.value)}
+ />
+
+
+ setFirstname(e.target.value)}
+ />
+ setLastname(e.target.value)}
+ />
+
+ APIKEY
+
+ What is the API key used for?
+
+
+
+
+ {/*
{
{formMessage}
*/}
- Password
-
-
setCurrentPassword(e.target.value)}
- />
+ Password
+
+ setCurrentPassword(e.target.value)}
+ />
+
+
+ setNewPassword(e.target.value)}
+ />
+ setNewPassword2(e.target.value)}
+ />
+
+
+ {passwordFormMessage}
+
+ Platform Earnings
+
+
+ {isCloud ?
+
+
+ By connecting your Github account, you agree to our Terms of Service, and acknowledge that your non-sensitive data will be turned into a creator account. This enables you to earn a passive income from Shuffle. This IS reversible. Support: support@shuffler.io
+
+
+
+ : null}
-
- setNewPassword(e.target.value)}
- />
- setNewPassword2(e.target.value)}
- />
-
-
-
{passwordFormMessage}
-
-
+
+
+ {userdata.eth_info !== undefined &&
+ userdata.eth_info.account !== undefined &&
+ userdata.eth_info.account.length > 0 &&
+ userdata.eth_info.parsed_balance !== undefined ? (
+
+
+
+
+
+
+ {/*window.ethereum.fromWei(userdata.eth_info.balance, "ether")*/}
+ {userdata.eth_info.parsed_balance.toFixed(4)} ETH
+
+
+
+ ) : null}
+
+ {userdata.eth_info !== undefined &&
+ userdata.eth_info.account !== undefined &&
+ userdata.eth_info.account.length > 0 &&
+ userdata.eth_info.parsed_balance !== undefined ? (
+
+
+ Owned Workflows
+
+ {selfOwnedWorkflows.length}
+
+
+
+ ) : null}
+
+
+ {/*userdata !== undefined &&
+ userdata.eth_info !== undefined &&
+ userdata.eth_info.account !== undefined &&
+ userdata.eth_info.account.length > 0 ? (
+
+
Network: TBD
+
+ Address: {userdata.eth_info.account}
+
+ {loadedWorkflowCollections.length > 0 ? (
+
+ Collections:
+ {loadedWorkflowCollections.map((data, index) => {
+ var collectionname = data.toLowerCase();
+ collectionname = collectionname.replaceAll("#", "");
+ collectionname = collectionname.replaceAll(" ", "-");
- const loadedCheck = isLoaded && !firstrequest ?
-
- {landingpageData}
-
- :
-
-
+ return (
+
+
+ {data}
+
+
+
+ );
+ })}
+
+ ) : null}
+
+
+ ) : (
+
+ )*/}
+
+
- return(
-
- {loadedCheck}
-
- )
-}
+ {loadedValidationWorkflows !== undefined &&
+ loadedValidationWorkflows !== null
+ ? loadedValidationWorkflows.map((data, index) => {
+ return (
+
+
+
+ );
+ })
+ : null}
+
+
+ );
+
+ /*
+ 0x1 1 Ethereum Main Network (Mainnet)
+ 0x3 3 Ropsten Test Network
+ 0x4 4 Rinkeby Test Network
+ 0x5 5 Goerli Test Network
+ 0x2a 42 Kovan Test Network
+ */
+ const setUser = (userId, field, value) => {
+ const data = { user_id: userId };
+ data[field] = value;
+
+ fetch(globalUrl + "/api/v1/users/updateuser", {
+ method: "PUT",
+ 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 WORKFLOW EXECUTION :O!");
+ }
+
+ return response.json();
+ })
+ .then((responseJson) => {
+ if (!responseJson.success && responseJson.reason !== undefined) {
+ alert.error("Failed updating user: " + responseJson.reason);
+ }
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+ };
+
+ const handleGithubConnection = () => {
+ console.log("GITHUB CONNECT WOO: ", isCloud)
+ //result = RestClient.post('https://github.com/login/oauth/access_token',
+
+ console.log("HOST: ", window.location.host);
+ console.log("Location: ", window.location);
+ const redirectUri = isCloud
+ ? window.location.host === "localhost:3002"
+ ? "http%3A%2F%2Flocalhost:3002%2Fset_authentication"
+ : "https%3A%2F%2Fshuffler.io%2Fset_authentication"
+ : window.location.protocol === "http:" ?
+ `http%3A%2F%2F${window.location.host}%2Fset_authentication`
+ :
+ `https%3A%2F%2F${window.location.host}%2Fset_authentication`
+
+ console.log("redirect: ", redirectUri)
+
+ const client_id = "3d272b1b782b100b1e61"
+ const username = userdata.id;
+ const scopes = "read:user";
+
+ const url = `https://github.com/login/oauth/authorize?access_type=offline&prompt=consent&client_id=${client_id}&redirect_uri=${redirectUri}&response_type=code&scope=${scopes}&state=username%3D${username}%26type%3Dgithub`
+
+ console.log("URL: ", url);
+
+ var newwin = window.open(url, "", "width=800,height=600");
+
+ // Check whether we got a callback somewhere
+ //var id = setInterval(function () {
+ // fetch(
+ // globalUrl + "/api/v1/triggers/gmail/" + selectedTrigger.id,
+ // {
+ // method: "GET",
+ // headers: { "content-type": "application/json" },
+ // credentials: "include",
+ // }
+ // )
+ // .then((response) => {
+ // if (response.status !== 200) {
+ // throw new Error("No trigger info :o!");
+ // }
+
+ // return response.json();
+ // })
+ // .then((responseJson) => {
+ // console.log("RESPONSE: ");
+ // setTriggerAuthentication(responseJson);
+ // clearInterval(id);
+ // newwin.close();
+ // setGmailFolders();
+ // })
+ // .catch((error) => {
+ // console.log(error.toString());
+ // });
+ //}, 2500);
+
+ //saveWorkflow(workflow);
+ }
+
+ const handleEthereumTokenCreation = async () => {
+ const provider = await detectEthereumProvider();
+ if (!provider) {
+ console.log("Please install MetaMask!");
+ alert.error(
+ "Please download the MetaMask browser extension to authenticate fully!"
+ );
+ return;
+ }
+
+ if (!provider.isMetaMask) {
+ alert.error("Only MetaMask is supported as of now.");
+ return;
+ }
+
+ if (!provider.isConnected()) {
+ alert.error("Metamask is not connected.");
+ return;
+ }
+
+ console.log("Should make a token");
+ };
+
+ const handleEthereumConnection = async () => {
+ const provider = await detectEthereumProvider();
+ if (!provider) {
+ console.log("Please install MetaMask!");
+ alert.error(
+ "Please download the MetaMask browser extension to authenticate fully!"
+ );
+ return;
+ }
+
+ if (!provider.isMetaMask) {
+ alert.error("Only MetaMask is supported as of now.");
+ return;
+ }
+
+ // Find the ethereum network
+ // Get the users' account(s)
+ //alert.info("Connecting to MetaMask")
+ //console.log("Connected: ", provider.isConnected())
+
+ if (!provider.isConnected()) {
+ alert.error("Metamask is not connected.");
+ return;
+ }
+
+ provider.on("message", (event) => {
+ alert.info("Ethereum message: ", event);
+ });
+
+ /*
+ params: [
+ {
+ from: '0xb60e8dd61c5d32be8058bb8eb970870f07233155',
+ to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
+ gas: '0x76c0', // 30400
+ gasPrice: '0x9184e72a000', // 10000000000000
+ value: '0x9184e72a', // 2441406250
+ data:
+ '0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675',
+ },
+ ]
+ */
+
+ // https://docs.metamask.io/guide/rpc-api.html
+ // Gets accounts - requires previous permissions
+ //const method = "eth_accounts"
+ //const params = []
+ //
+ // Asks for permission, and gets the accounts
+ var method = "eth_requestAccounts";
+ var params = [];
+ provider
+ .request({
+ method: method,
+ params,
+ })
+ .then((result) => {
+ if (result !== undefined && result !== null && result.length > 0) {
+ userdata.eth_info.account = result[0];
+
+ // Getting and setting balance for the current user
+ method = "eth_getBalance";
+ params = [userdata.eth_info.account, "latest"];
+ provider
+ .request({
+ method: method,
+ params,
+ })
+ .then((result) => {
+ if (
+ result !== undefined &&
+ result !== null &&
+ result.length > 0
+ ) {
+ userdata.eth_info.balance = result;
+ userdata.eth_info.parsed_balance = result / 1000000000000000000;
+ console.log(userdata.eth_info);
+ setUserData(userdata.eth_info);
+
+ // Updating
+ //if (userdata.eth_info !== userdata.userdata.eth_info) {
+ //}
+
+ setUser(userdata.id, "eth_info", userdata.eth_info);
+ userdata.userdata.eth_info = userdata.eth_info;
+ } else {
+ alert.error("Couldn't find balance: ", result);
+ }
+ // The result varies by RPC method.
+ // For example, this method will return a transaction hash hexadecimal string on success.
+ })
+ .catch((error) => {
+ // If the request fails, the Promise will reject with an error.
+ //setEthInfo(userdata.eth_info)
+ alert.error("Failed getting info from ethereum API: " + error);
+ });
+ } else {
+ alert.error("Couldn't find any user: ", result);
+ }
+ })
+ .catch((error) => {
+ // If the request fails, the Promise will reject with an error.
+ alert.error("Failed getting info from ethereum API: " + error);
+ });
+
+ // Gets the users' balance in WEI (one quintilionth ETH)
+ };
+
+ const loadedCheck =
+ isLoaded && !firstrequest ? (
+
{landingpageData}
+ ) : (
+
+ );
+
+ return
{loadedCheck}
;
+};
export default Settings;
diff --git a/frontend/src/views/Webhooks.jsx b/frontend/src/views/Webhooks.jsx
old mode 100644
new mode 100755
diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx
old mode 100644
new mode 100755
index 5805dd78..1e5e5414
--- a/frontend/src/views/Workflows.jsx
+++ b/frontend/src/views/Workflows.jsx
@@ -1,2003 +1,3282 @@
-import React, { useEffect} from 'react';
-import { useInterval } from 'react-powerhooks';
-import { makeStyles } from '@material-ui/core/styles';
-import { useTheme } from '@material-ui/core/styles';
+import React, { useEffect, useContext } from "react";
+import ReactDOM from "react-dom"
-import {Avatar, Grid, Paper, Tooltip, Divider, Button, TextField, FormControl, IconButton, Menu, MenuItem, FormControlLabel, Chip, Switch, Typography, Zoom, CircularProgress, Dialog, DialogTitle, DialogActions, DialogContent} from '@material-ui/core';
-import {GridOn as GridOnIcon, List as ListIcon, Close as CloseIcon, Compare as CompareIcon, Maximize as MaximizeIcon, Minimize as MinimizeIcon, AddCircle as AddCircleIcon, Toc as TocIcon, Send as SendIcon, Search as SearchIcon, FileCopy as FileCopyIcon, Delete as DeleteIcon, BubbleChart as BubbleChartIcon, Restore as RestoreIcon, Cached as CachedIcon, GetApp as GetAppIcon, Apps as AppsIcon, Edit as EditIcon, MoreVert as MoreVertIcon, PlayArrow as PlayArrowIcon, Add as AddIcon, Publish as PublishIcon, CloudUpload as CloudUploadIcon, CloudDownload as CloudDownloadIcon} from '@material-ui/icons';
-import NestedMenuItem from "material-ui-nested-menu-item";
-//import {Search as SearchIcon, ArrowUpward as ArrowUpwardIcon, Visibility as VisibilityIcon, Done as DoneIcon, Close as CloseIcon, Error as ErrorIcon, FindReplace as FindreplaceIcon, ArrowLeft as ArrowLeftIcon, Cached as CachedIcon, DirectionsRun as DirectionsRunIcon, Add as AddIcon, Polymer as PolymerIcon, FormatListNumbered as FormatListNumberedIcon, Create as CreateIcon, PlayArrow as PlayArrowIcon, AspectRatio as AspectRatioIcon, MoreVert as MoreVertIcon, Apps as AppsIcon, Schedule as ScheduleIcon, FavoriteBorder as FavoriteBorderIcon, Pause as PauseIcon, Delete as DeleteIcon, AddCircleOutline as AddCircleOutlineIcon, Save as SaveIcon, KeyboardArrowLeft as KeyboardArrowLeftIcon, KeyboardArrowRight as KeyboardArrowRightIcon, ArrowBack as ArrowBackIcon, Settings as SettingsIcon, LockOpen as LockOpenIcon, ExpandMore as ExpandMoreIcon, VpnKey as VpnKeyIcon} from '@material-ui/icons';
+import { makeStyles } from "@material-ui/core/styles";
+import { Navigate } from "react-router-dom";
+//import { Redirect } from "react-router-dom";
+
+
+import SecurityFramework from '../components/SecurityFramework.jsx';
+import EditWorkflow from "../components/EditWorkflow.jsx"
+import { ShepherdTour, ShepherdTourContext } from 'react-shepherd'
+import Priority from "../components/Priority.jsx";
+
+import { isMobile } from "react-device-detect"
+
+import {
+ Badge,
+ Divider,
+ Avatar,
+ Drawer,
+ Grid,
+ InputLabel,
+ Select,
+ ListSubheader,
+ Paper,
+ Tooltip,
+ Button,
+ TextField,
+ FormControl,
+ IconButton,
+ Menu,
+ MenuItem,
+ Chip,
+ Typography,
+ Zoom,
+ CircularProgress,
+ Dialog,
+ DialogTitle,
+ DialogActions,
+ DialogContent,
+ Checkbox,
+ LinearProgress,
+ ListItemText,
+} from "@material-ui/core";
+
+import {
+ AvatarGroup,
+} from "@mui/material"
+
+import {
+ GridOn as GridOnIcon,
+ List as ListIcon,
+ Close as CloseIcon,
+ Compare as CompareIcon,
+ Maximize as MaximizeIcon,
+ Minimize as MinimizeIcon,
+ AddCircle as AddCircleIcon,
+ Toc as TocIcon,
+ Send as SendIcon,
+ Search as SearchIcon,
+ FileCopy as FileCopyIcon,
+ Delete as DeleteIcon,
+ BubbleChart as BubbleChartIcon,
+ Restore as RestoreIcon,
+ Cached as CachedIcon,
+ GetApp as GetAppIcon,
+ Apps as AppsIcon,
+ Edit as EditIcon,
+ MoreVert as MoreVertIcon,
+ PlayArrow as PlayArrowIcon,
+ Add as AddIcon,
+ Publish as PublishIcon,
+ CloudUpload as CloudUploadIcon,
+ CloudDownload as CloudDownloadIcon,
+ ExpandLess as ExpandLessIcon,
+ ExpandMore as ExpandMoreIcon,
+ Done as DoneIcon,
+ CheckCircle as CheckCircleIcon,
+ RadioButtonUnchecked as RadioButtonUncheckedIcon,
+ ArrowLeft as ArrowLeftIcon,
+ ArrowRight as ArrowRightIcon,
+} from "@material-ui/icons";
+
+//import NestedMenuItem from "material-ui-nested-menu-item";
+//import {Search as SearchIcon, ArrowUpward as ArrowUpwardIcon, Visibility as VisibilityIcon, Close as CloseIcon, Error as ErrorIcon, FindReplace as FindreplaceIcon, ArrowLeft as ArrowLeftIcon, Cached as CachedIcon, DirectionsRun as DirectionsRunIcon, Add as AddIcon, Polymer as PolymerIcon, FormatListNumbered as FormatListNumberedIcon, Create as CreateIcon, PlayArrow as PlayArrowIcon, AspectRatio as AspectRatioIcon, MoreVert as MoreVertIcon, Apps as AppsIcon, Schedule as ScheduleIcon, FavoriteBorder as FavoriteBorderIcon, Pause as PauseIcon, Delete as DeleteIcon, AddCircleOutline as AddCircleOutlineIcon, Save as SaveIcon, KeyboardArrowLeft as KeyboardArrowLeftIcon, KeyboardArrowRight as KeyboardArrowRightIcon, ArrowBack as ArrowBackIcon, Settings as SettingsIcon, LockOpen as LockOpenIcon, ExpandMore as ExpandMoreIcon, VpnKey as VpnKeyIcon} from '@material-ui/icons';
//https://next.material-ui.com/components/material-icons/
-import {DataGrid, GridToolbarContainer, GridDensitySelector, GridToolbar} from '@material-ui/data-grid';
+import { DataGrid, GridToolbar } from "@mui/x-data-grid";
//import JSONPretty from 'react-json-pretty';
//import JSONPrettyMon from 'react-json-pretty/dist/monikai'
-import Dropzone from '../components/Dropzone';
+import Dropzone from "../components/Dropzone.jsx";
-import {Link} from 'react-router-dom';
+import { useNavigate, Link } from "react-router-dom";
import { useAlert } from "react-alert";
-import ChipInput from 'material-ui-chip-input'
-import { v4 as uuidv4 } from 'uuid';
-import CytoscapeWrapper from '../components/RenderCytoscape'
+import ChipInput from "material-ui-chip-input";
+import { v4 as uuidv4 } from "uuid";
+import theme from "../theme.jsx";
-//import mobileImage from '../assets/img/mobile.svg';
-//import bagImage from '../assets/img/bag.svg';
-//import bookImage from '../assets/img/book.svg';
-
-const inputColor = "#383B40"
-const surfaceColor = "#27292D"
-const svgSize = 24
-const imagesize = 22
-
-const flexContainerStyle = {
- display: "flex",
- flexDirection: "row",
- justifyContent: "left",
- alignContent: "space-between",
-}
-
-const flexBoxStyle = {
- height: 125,
- borderRadius: 4,
- boxSizing: "border-box",
- letterSpacing: "0.4px",
- color: "#D6791E",
- margin: 10,
- flex: 1,
-}
+const inputColor = "#383B40";
+const surfaceColor = "#27292D";
+const svgSize = 24;
+const imagesize = 22;
const useStyles = makeStyles((theme) => ({
- datagrid: {
- border: 0,
- '& .MuiDataGrid-columnsContainer': {
- backgroundColor: theme.palette.type === 'light' ? '#fafafa' : theme.palette.inputColor,
- },
- '& .MuiDataGrid-iconSeparator': {
- display: 'none',
- },
- '& .MuiDataGrid-colCell, .MuiDataGrid-cell': {
- borderRight: `1px solid ${
- theme.palette.type === 'light' ? 'white' : '#303030'
- }`,
- },
- '& .MuiDataGrid-columnsContainer, .MuiDataGrid-cell': {
- borderBottom: `1px solid ${
- theme.palette.type === 'light' ? '#f0f0f0' : '#303030'
- }`,
- },
- '& .MuiDataGrid-cell': {
- color:
- theme.palette.type === 'light'
- ? 'white'
- : 'rgba(255,255,255,0.65)',
- },
- '& .MuiPaginationItem-root, .MuiTablePagination-actions, .MuiTablePagination-caption': {
- borderRadius: 0,
- color: "white",
- },
- },
+ datagrid: {
+ border: 0,
+ "& .MuiDataGrid-columnsContainer": {
+ backgroundColor:
+ theme.palette.type === "light" ? "#fafafa" : theme.palette.inputColor,
+ },
+ "& .MuiDataGrid-iconSeparator": {
+ display: "none",
+ },
+ "& .MuiDataGrid-colCell, .MuiDataGrid-cell": {
+ borderRight: `1px solid ${
+ theme.palette.type === "light" ? "white" : "#303030"
+ }`,
+ },
+ "& .MuiDataGrid-columnsContainer, .MuiDataGrid-cell": {
+ borderBottom: `1px solid ${
+ theme.palette.type === "light" ? "#f0f0f0" : "#303030"
+ }`,
+ },
+ "& .MuiDataGrid-cell": {
+ color:
+ theme.palette.type === "light" ? "white" : "rgba(255,255,255,0.65)",
+ },
+ "& .MuiPaginationItem-root, .MuiTablePagination-actions, .MuiTablePagination-caption":
+ {
+ borderRadius: 0,
+ color: "white",
+ },
+ },
}));
-
-// Takes an action in Shuffle and
+// Takes an action in Shuffle and
// Returns information about the icon, the color etc to be used
// This can be used for actions of all types
export const GetIconInfo = (action) => {
- // Finds the icon based on the action. Should be verbs.
- const iconList = [
- {"key": "cache_add", "values": ["set_cache"]},
- {"key": "cache_get", "values": ["get_cache"]},
- {"key": "filter", "values": ["filter", "route", "router",]},
- {"key": "merge", "values": ["join", "merge"]},
- {"key": "search", "values": ["search", "find", "locate", "index", "analyze", "anal", "match"]},
- {"key": "list", "values": ["list", "head", "options"]},
- {"key": "download", "values": ["capture", "get", "download", "return", "hello_world", "curl", "request", "export", "preview"]},
- {"key": "add", "values": ["add"]},
- {"key": "delete", "values": ["delete", "remove", "clear", "clean",]},
- {"key": "send", "values": ["send", "dispatch", "mail", "forward", "post", "submit", "mark", "set", "release", ]},
- {"key": "repeat", "values": ["repeat", "retry", "pause", "skip", "copy", "replicat", ]},
- {"key": "execute", "values": ["execute", "run", "play", "raise",]},
- {"key": "extract", "values": ["extract", "unpack", "decompress", "open"]},
- {"key": "inflate", "values": ["inflate", "pack", "compress",]},
- {"key": "edit", "values": ["modify", "update", "create", "edit", "put", "patch", "change", "replace", "conver", "map", "format", "escape", "describe", ]},
- {"key": "compare", "values": ["compare", "convert", "to", "filter", "translate", "parse"]},
- {"key": "close", "values": ["close", "stop", "cancel", "block", ]},
- ]
+ // Finds the icon based on the action. Should be verbs.
+ const iconList = [
+ { key: "cache_add", values: ["set_cache"] },
+ { key: "cache_get", values: ["get_cache"] },
+ { key: "filter", values: ["filter"] },
+ { key: "merge", values: ["join", "merge", "route", "router"] },
+ {
+ key: "search",
+ values: ["search", "find", "locate", "index", "analyze", "anal", "match", "check cache", "check", "verify", "validate"],
+ },
+ { key: "list", values: ["list", "head", "options"] },
+ {
+ key: "download",
+ values: [
+ "capture",
+ "get",
+ "download",
+ "return",
+ "hello_world",
+ "curl",
+ "request",
+ "export",
+ "preview",
+ ],
+ },
+ { key: "add", values: ["add", "accept", ] },
+ { key: "delete", values: ["delete", "remove", "clear", "clean", "dismiss",] },
+ {
+ key: "send",
+ values: [
+ "send",
+ "dispatch",
+ "mail",
+ "forward",
+ "post",
+ "submit",
+ "mark",
+ "set",
+ "release",
+ ],
+ },
+ {
+ key: "repeat",
+ values: ["repeat", "retry", "pause", "skip", "copy", "replicat", "demo", ],
+ },
+ { key: "execute", values: ["execute", "run", "play", "raise"] },
+ { key: "extract", values: ["extract", "unpack", "decompress", "open"] },
+ { key: "inflate", values: ["inflate", "pack", "compress"] },
+ {
+ key: "edit",
+ values: [
+ "modify",
+ "update",
+ "create",
+ "edit",
+ "put",
+ "patch",
+ "change",
+ "replace",
+ "conver",
+ "map",
+ "format",
+ "escape",
+ "describe",
+ ],
+ },
+ {
+ key: "compare",
+ values: ["compare", "convert", "to", "filter", "translate", "parse"],
+ },
+ { key: "close", values: ["close", "stop", "cancel", "block"] },
+ ];
- var selectedKey = ""
- if (action.name === undefined || action.name === null) {
- } else {
- const actionname = action.name.toLowerCase()
- for (var key in iconList) {
- //console.log(iconList[key], actionname)
- const found = iconList[key].values.find(value => actionname.includes(value))
- if (found !== null && found !== undefined) {
- selectedKey = iconList[key].key
- break
- }
- }
- }
-
- // Some of these are manually parsed or created instead of material ui
- //M8 0C3.58 0 0 1.79 0 4C0 6.21 3.58 8 8 8C12.42 8 16 6.21 16 4C16 1.79 12.42 0 8 0ZM0 6V9C0 11.21 3.58 13 8 13C12.42 13 16 11.21 16 9V6C16 8.21 12.42 10 8 10C3.58 10 0 8.21 0 6ZM0 11V14C0 16.21 3.58 18 8 18C9.41 18 10.79 17.81 12 17.46V14.46C10.79 14.81 9.41 15 8 15C3.58 15 0 13.21 0 11ZM17 11V14H14V16H17V19H19V16H22V14H19V11
- //https://www.figma.com/file/uCfnMs5w6wnLx6ehPHEV74/Figma-Material-Design-System-v3_0?node-id=834%3A21
- //COLORS: https://www.pinterest.co.uk/pin/326299935499972946/
- const defaultColor = "#f76b1c"
- const defaultGradient = ["#fad961", "#f76b1c"]
- const parsedIcons = {
- "cache_add": {
- "icon": "M11 3C6.58 3 3 4.79 3 7C3 9.21 6.58 11 11 11C15.42 11 19 9.21 19 7C19 4.79 15.42 3 11 3ZM3 9V12C3 14.21 6.58 16 11 16C15.42 16 19 14.21 19 12V9C19 11.21 15.42 13 11 13C6.58 13 3 11.21 3 9ZM3 14V17C3 19.21 6.58 21 11 21C12.41 21 13.79 20.81 15 20.46V17.46C13.79 17.81 12.41 18 11 18C6.58 18 3 16.21 3 14ZM20 14V17H17V19H20V22H22V19H25V17H22V14",
- "iconColor": "white",
- "iconBackgroundColor": "#8acc3f",
- "originalIcon": "",
- "fillGradient": ["#8acc3f", "#459622"]
- },
- "cache_get": {
- "icon": "M12 2C7.58 2 4 3.79 4 6C4 8.06 7.13 9.74 11.15 9.96C12.45 8.7 14.19 8 16 8C16.8 8 17.59 8.14 18.34 8.41C19.37 7.74 20 6.91 20 6C20 3.79 16.42 2 12 2ZM4 8V11C4 12.68 6.08 14.11 9 14.71C9.06 13.7 9.32 12.72 9.77 11.82C6.44 11.34 4 9.82 4 8ZM15.93 9.94C14.75 9.95 13.53 10.4 12.46 11.46C8.21 15.71 13.71 22.5 18.75 19.17L23.29 23.71L24.71 22.29L20.17 17.75C22.66 13.97 19.47 9.93 15.93 9.94ZM15.9 12C17.47 11.95 19 13.16 19 15C19 15.7956 18.6839 16.5587 18.1213 17.1213C17.5587 17.6839 16.7956 18 16 18C13.33 18 12 14.77 13.88 12.88C14.47 12.29 15.19 12 15.9 12ZM4 13V16C4 18.05 7.09 19.72 11.06 19.95C10.17 19.07 9.54 17.95 9.22 16.74C6.18 16.17 4 14.72 4 13Z",
- "iconColor": "white",
- "iconBackgroundColor": "#8acc3f",
- "originalIcon": "",
- "fillGradient": ["#8acc3f", "#459622"]
- },
- "repeat": {
- "icon": "M19 8l-4 4h3c0 3.31-2.69 6-6 6-1.01 0-1.97-.25-2.8-.7l-1.46 1.46C8.97 19.54 10.43 20 12 20c4.42 0 8-3.58 8-8h3l-4-4zM6 12c0-3.31 2.69-6 6-6 1.01 0 1.97.25 2.8.7l1.46-1.46C15.03 4.46 13.57 4 12 4c-4.42 0-8 3.58-8 8H1l4 4 4-4H6z",
- "iconColor": "white",
- "iconBackgroundColor": defaultColor,
- "originalIcon":
,
- },
- "add": {
- "icon": "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z",
- "iconColor": "white",
- "iconBackgroundColor": defaultColor,
- "originalIcon":
,
- },
- "edit": {
- "icon": "M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34a.9959.9959 0 00-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z",
- "iconColor": "white",
- "iconBackgroundColor": defaultColor,
- "originalIcon":
,
- },
- "filter": {
- "icon": "M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39c.51-.66.04-1.61-.79-1.61H5.04c-.83 0-1.3.95-.79 1.61z",
- "iconColor": "white",
- "iconBackgroundColor": "#f5515f",
- "originalIcon": "",
- "fillGradient": ["#f5515f", "#a1051d"],
- },
- "merge": {
- "icon": "M17 20.41 18.41 19 15 15.59 13.59 17 17 20.41zM7.5 8H11v5.59L5.59 19 7 20.41l6-6V8h3.5L12 3.5 7.5 8z",
- "iconColor": "white",
- "iconBackgroundColor": "#f5515f",
- "originalIcon": "",
- "fillGradient": ["#f5515f", "#a1051d"],
- },
- "compare": {
- "icon": "M10 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h5v2h2V1h-2v2zm0 15H5l5-6v6zm9-15h-5v2h5v13l-5-6v9h5c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z",
- "iconColor": "white",
- "iconBackgroundColor": defaultColor,
- "originalIcon":
,
- },
- "extract": {
- "icon": "M3 3h18v2H3z",
- "iconColor": "white",
- "iconBackgroundColor": defaultColor,
- "originalIcon":
,
- },
- "inflate": {
- "icon": "M6 19h12v2H6z",
- "iconColor": "white",
- "iconBackgroundColor": defaultColor,
- "originalIcon":
,
- },
- "list": {
- "icon": "M3 9h14V7H3v2zm0 4h14v-2H3v2zm0 4h14v-2H3v2zm16 0h2v-2h-2v2zm0-10v2h2V7h-2zm0 6h2v-2h-2v2z",
- "iconColor": "white",
- "iconBackgroundColor": defaultColor,
- "originalIcon":
,
- },
- "execute": {
- "icon": "M8 5v14l11-7z",
- "iconColor": "white",
- "iconBackgroundColor": defaultColor,
- "originalIcon":
,
- },
- "delete": {
- "icon": "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z",
- "iconColor": "white",
- "iconBackgroundColor": "#03030e",
- "originalIcon":
,
- "fillGradient": ["#03030e", "#205d66"]
- },
- "close": {
- "icon": "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z",
- "iconColor": "white",
- "iconBackgroundColor": "#03030e",
- "originalIcon":
,
- "fillGradient": ["#03030e", "#205d66"]
- },
- "send": {
- "icon": "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z",
- "iconColor": "white",
- "iconBackgroundColor": "#0373da",
- "originalIcon":
,
- "fillGradient": ["#0bc8bf", "#0373da"]
- },
- "download": {
- "icon": "M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z",
- "iconColor": "white",
- "iconBackgroundColor": "#0373da",
- "originalIcon":
,
- "fillGradient": ["#0bc8bf", "#0373da"]
- },
- "search": {
- "icon": "M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z",
- "iconColor": "white",
- "iconBackgroundColor": "green",
- "originalIcon":
,
- }
- }
-
-
- var selectedItem = parsedIcons[selectedKey]
- if (selectedItem === undefined || selectedItem === null) {
- return {
- "icon": "",
- "iconColor": "",
- "iconBackground": "black",
- "originalIcon": "",
- }
- }
-
- if (selectedItem.fillGradient === undefined) {
- selectedItem.fillGradient = defaultGradient
- selectedItem.iconBackgroundColor = defaultColor
- }
-
- if (selectedItem.icon === "" || selectedItem.icon === undefined) {
- console.log(`MISSING PATH FOR ${selectedKey} (find in scope): `, selectedItem.originalIcon.type.type)
- }
-
- if (selectedItem.originalIcon === undefined || selectedItem.originalIcon === "" && (selectedItem.icon !== "" && selectedItem.icon !== undefined)) {
- const svg_pin =
- //const svgpin_Url = encodeURI("data:image/svg+xml;utf-8," + svg_pin)
- selectedItem.originalIcon = svg_pin
- //parsedIcons[selectedKey].originalIcon = svg_pin
- //console.log("ADDED ICON: ", svg_pin)
- }
-
- return selectedItem
-}
-
-//const activeWorkflowStyle = {backgroundColor: "#FFF5EE"}
-//const notificationStyle = {backgroundColor: "#E5F9FF"}
-//const activeWorkflowStyle = {backgroundColor: "#3d3f43"}
-const availableWorkflowStyle = {backgroundColor: "#3d3f43"}
-const notificationStyle = {backgroundColor: "#3d3f43"}
-const activeWorkflowStyle = {backgroundColor: "#3d3f43"}
-
-const fontSize_16 = {fontSize: "16px",}
-const counterStyle = {fontSize: "36px",fontWeight:"bold"}
-const blockRightStyle = {textAlign: "right",padding: "20px 20px 0px 0px",width:"100%"}
-
-const chipStyle = {
- backgroundColor: "#3d3f43", height: 30, marginRight: 5, paddingLeft: 5, paddingRight: 5, height: 28, cursor: "pointer", borderColor: "#3d3f43", color: "white",
-}
-
-const flexContentStyle = {
- display: "flex",
- flexDirection: "row"
-}
-
-const iconStyle = {
- width: "75px",
- height: "75px",
- padding: "20px"
-}
-
-export const validateJson = (showResult) => {
- //showResult = showResult.split(" None").join(" \"None\"")
- showResult = showResult.split(" False").join(" false")
- showResult = showResult.split(" True").join(" true")
-
- var jsonvalid = true
- try {
- const tmp = String(JSON.parse(showResult))
- if (!showResult.includes("{") && !showResult.includes("[")) {
- jsonvalid = false
- }
- } catch (e) {
- showResult = showResult.split("\'").join("\"")
-
- try {
- const tmp = String(JSON.parse(showResult))
- if (!showResult.includes("{") && !showResult.includes("[")) {
- jsonvalid = false
- }
- } catch (e) {
- jsonvalid = false
- }
- }
-
- const result = jsonvalid ? JSON.parse(showResult) : showResult
- //console.log("VALID: ", jsonvalid, result)
- return {
- "valid": jsonvalid,
- "result": result,
- }
-}
-
-const Workflows = (props) => {
- const { globalUrl, isLoggedIn, isLoaded, removeCookie, cookies, userdata} = props;
- document.title = "Shuffle - Workflows"
- const theme = useTheme();
- const alert = useAlert()
- const classes = useStyles(theme);
-
- const referenceUrl = globalUrl+"/api/v1/hooks/"
-
- var upload = ""
- const [file, setFile] = React.useState("");
-
- const [workflows, setWorkflows] = React.useState([]);
- const [filteredWorkflows, setFilteredWorkflows] = React.useState([]);
- const [selectedWorkflow, setSelectedWorkflow] = React.useState({});
- const [selectedExecution, setSelectedExecution] = React.useState({});
- const [workflowExecutions, setWorkflowExecutions] = React.useState([]);
- const [firstrequest, setFirstrequest] = React.useState(true)
- const [workflowDone, setWorkflowDone] = React.useState(false)
- const [, setTrackingId] = React.useState("")
- const [selectedWorkflowId, setSelectedWorkflowId] = React.useState("")
-
- const [collapseJson, setCollapseJson] = React.useState(false)
- const [field1, setField1] = React.useState("")
- const [field2, setField2] = React.useState("")
- const [downloadUrl, setDownloadUrl] = React.useState("https://github.com/frikky/shuffle-workflows")
- const [downloadBranch, setDownloadBranch] = React.useState("master")
- const [loadWorkflowsModalOpen, setLoadWorkflowsModalOpen] = React.useState(false)
- const [exportModalOpen, setExportModalOpen] = React.useState(false)
- const [exportData, setExportData] = React.useState("");
-
- const [modalOpen, setModalOpen] = React.useState(false);
- const [newWorkflowName, setNewWorkflowName] = React.useState("");
- const [newWorkflowDescription, setNewWorkflowDescription] = React.useState("");
- const [newWorkflowTags, setNewWorkflowTags] = React.useState([]);
-
- const [showExtraOptions, setShowExtraOptions] = React.useState(true);
- const [defaultReturnValue, setDefaultReturnValue] = React.useState("");
-
- const [update, setUpdate] = React.useState("test");
- const [deleteModalOpen, setDeleteModalOpen] = React.useState(false);
- const [publishModalOpen, setPublishModalOpen] = React.useState(false);
- const [editingWorkflow, setEditingWorkflow] = React.useState({})
- const [executionLoading, setExecutionLoading] = React.useState(false)
- const [importLoading, setImportLoading] = React.useState(false)
- const [isDropzone, setIsDropzone] = React.useState(false);
- const [view, setView] = React.useState("grid")
- const [filters, setFilters] = React.useState([])
- const [submitLoading, setSubmitLoading] = React.useState(false)
-
- const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"
-
- const findWorkflow = (filters) => {
- if (filters.length === 0) {
- setFilteredWorkflows(workflows)
- return
- }
-
- var newWorkflows = []
- for (var workflowKey in workflows) {
- const curWorkflow = workflows[workflowKey]
-
- var found = [false]
- if (curWorkflow.tags === undefined || curWorkflow.tags === null) {
- found = filters.map(filter => curWorkflow.name.toLowerCase().includes(filter))
- } else {
- found = filters.map(filter => {
- if (filter === undefined) {
- return false
- }
-
- if (curWorkflow.name.toLowerCase().includes(filter.toLowerCase())) {
- return true
- } else if (curWorkflow.tags.includes(filter)) {
- return true
- } else if (curWorkflow.owner === filter) {
- return true
- } else if (curWorkflow.org_id === filter) {
- return true
- } else if (curWorkflow.actions !== null && curWorkflow.actions !== undefined) {
- const newfilter = filter.toLowerCase()
- for (var key in curWorkflow.actions) {
- const action = curWorkflow.actions[key]
- if (action.app_name.toLowerCase().includes(newfilter)) {
- return true
- }
- }
- }
-
- return false
- })
- }
-
- //console.log("FOUND: ", found)
- //if (found) {
- if (found.every(v => v === true)) {
- newWorkflows.push(curWorkflow)
- continue
- }
- }
-
- if (newWorkflows.length !== workflows.length) {
- setFilteredWorkflows(newWorkflows)
- }
- }
-
- const addFilter = (data) => {
- if (data === null || data === undefined) {
- return
- }
-
- if (data.includes("<") && data.includes(">")) {
- return
- }
-
- if (filters.includes(data)) {
- return
- }
-
- filters.push(data.toLowerCase())
- setFilters(filters)
-
- findWorkflow(filters)
- }
-
- const removeFilter = (index) => {
- var newfilters = filters
-
- if (index < 0) {
- console.log("Can't handle index: ", index)
- return
- }
-
-
- //console.log("Removing filter index", index)
- newfilters.splice(index, 1)
- //console.log("FILTER LENGTH: ", filters.length)
-
- if (newfilters.length === 0) {
- newfilters = []
- setFilters(newfilters)
- } else {
- setFilters(newfilters)
- }
- //console.log("FILTERS: ", newfilters)
-
- findWorkflow(newfilters)
- }
-
- const exportVerifyModal = exportModalOpen ?
-
- : null
-
- const publishModal = publishModalOpen ?
-
- : null
-
- const deleteModal = deleteModalOpen ?
-
- : null
-
- const uploadFile = (e) => {
- const isDropzone = e.dataTransfer === undefined ? false : e.dataTransfer.files.length > 0;
- const files = isDropzone ? e.dataTransfer.files : e.target.files;
-
- const reader = new FileReader();
- alert.info("Starting upload. Please wait while we validate the workflows")
-
- try {
- reader.addEventListener('load', (e) => {
- var data = e.target.result;
- setIsDropzone(false)
- try {
- data = JSON.parse(reader.result)
- } catch (e) {
- alert.error("Invalid JSON: "+e)
- return
- }
-
- // Initialize the workflow itself
- const ret = setNewWorkflow(data.name, data.description, data.tags, data.default_return_value, {}, false)
- .then((response) => {
- if (response !== undefined) {
- // SET THE FULL THING
- data.id = response.id
-
- // Actually create it
- const ret = setNewWorkflow(data.name, data.description, data.tags, data.default_return_value, data, false)
- .then((response) => {
- if (response !== undefined) {
- alert.success(`Successfully imported ${data.name}`)
- }
- })
- }
- })
- .catch(error => {
- alert.error("Import error: "+error.toString())
- });
- })
- } catch (e) {
- console.log("Error in dropzone: ", e)
- }
-
- reader.readAsText(files[0]);
+ var selectedKey = "";
+ if (action.name === undefined || action.name === null) {
+ } else {
+ const actionname = action.name.toLowerCase();
+ for (var key in iconList) {
+ //console.log(iconList[key], actionname)
+ const found = iconList[key].values.find((value) =>
+ actionname.includes(value)
+ );
+ if (found !== null && found !== undefined) {
+ selectedKey = iconList[key].key;
+ break;
+ }
+ }
}
- useEffect(() => {
- if (isDropzone) {
- //redirectOpenApi();
- setIsDropzone(false);
+ // Some of these are manually parsed or created instead of material ui
+ //M8 0C3.58 0 0 1.79 0 4C0 6.21 3.58 8 8 8C12.42 8 16 6.21 16 4C16 1.79 12.42 0 8 0ZM0 6V9C0 11.21 3.58 13 8 13C12.42 13 16 11.21 16 9V6C16 8.21 12.42 10 8 10C3.58 10 0 8.21 0 6ZM0 11V14C0 16.21 3.58 18 8 18C9.41 18 10.79 17.81 12 17.46V14.46C10.79 14.81 9.41 15 8 15C3.58 15 0 13.21 0 11ZM17 11V14H14V16H17V19H19V16H22V14H19V11
+ //https://www.figma.com/file/uCfnMs5w6wnLx6ehPHEV74/Figma-Material-Design-System-v3_0?node-id=834%3A21
+ //COLORS: https://www.pinterest.co.uk/pin/326299935499972946/
+ const defaultColor = "#f76b1c";
+ const defaultGradient = ["#fad961", "#f76b1c"];
+ const parsedIcons = {
+ cache_add: {
+ icon: "M11 3C6.58 3 3 4.79 3 7C3 9.21 6.58 11 11 11C15.42 11 19 9.21 19 7C19 4.79 15.42 3 11 3ZM3 9V12C3 14.21 6.58 16 11 16C15.42 16 19 14.21 19 12V9C19 11.21 15.42 13 11 13C6.58 13 3 11.21 3 9ZM3 14V17C3 19.21 6.58 21 11 21C12.41 21 13.79 20.81 15 20.46V17.46C13.79 17.81 12.41 18 11 18C6.58 18 3 16.21 3 14ZM20 14V17H17V19H20V22H22V19H25V17H22V14",
+ iconColor: "white",
+ iconBackgroundColor: "#8acc3f",
+ originalIcon: "",
+ fillGradient: ["#8acc3f", "#459622"],
+ },
+ cache_get: {
+ icon: "M12 2C7.58 2 4 3.79 4 6C4 8.06 7.13 9.74 11.15 9.96C12.45 8.7 14.19 8 16 8C16.8 8 17.59 8.14 18.34 8.41C19.37 7.74 20 6.91 20 6C20 3.79 16.42 2 12 2ZM4 8V11C4 12.68 6.08 14.11 9 14.71C9.06 13.7 9.32 12.72 9.77 11.82C6.44 11.34 4 9.82 4 8ZM15.93 9.94C14.75 9.95 13.53 10.4 12.46 11.46C8.21 15.71 13.71 22.5 18.75 19.17L23.29 23.71L24.71 22.29L20.17 17.75C22.66 13.97 19.47 9.93 15.93 9.94ZM15.9 12C17.47 11.95 19 13.16 19 15C19 15.7956 18.6839 16.5587 18.1213 17.1213C17.5587 17.6839 16.7956 18 16 18C13.33 18 12 14.77 13.88 12.88C14.47 12.29 15.19 12 15.9 12ZM4 13V16C4 18.05 7.09 19.72 11.06 19.95C10.17 19.07 9.54 17.95 9.22 16.74C6.18 16.17 4 14.72 4 13Z",
+ iconColor: "white",
+ iconBackgroundColor: "#8acc3f",
+ originalIcon: "",
+ fillGradient: ["#8acc3f", "#459622"],
+ },
+ repeat: {
+ icon: "M19 8l-4 4h3c0 3.31-2.69 6-6 6-1.01 0-1.97-.25-2.8-.7l-1.46 1.46C8.97 19.54 10.43 20 12 20c4.42 0 8-3.58 8-8h3l-4-4zM6 12c0-3.31 2.69-6 6-6 1.01 0 1.97.25 2.8.7l1.46-1.46C15.03 4.46 13.57 4 12 4c-4.42 0-8 3.58-8 8H1l4 4 4-4H6z",
+ iconColor: "white",
+ iconBackgroundColor: defaultColor,
+ originalIcon:
,
+ },
+ add: {
+ icon: "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z",
+ iconColor: "white",
+ iconBackgroundColor: defaultColor,
+ originalIcon:
,
+ },
+ edit: {
+ icon: "M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34a.9959.9959 0 00-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z",
+ iconColor: "white",
+ iconBackgroundColor: defaultColor,
+ originalIcon:
,
+ },
+ filter: {
+ icon: "M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39c.51-.66.04-1.61-.79-1.61H5.04c-.83 0-1.3.95-.79 1.61z",
+ iconColor: "white",
+ iconBackgroundColor: "#f5515f",
+ originalIcon: "",
+ fillGradient: ["#f5515f", "#a1051d"],
+ },
+ merge: {
+ icon: "M17 20.41 18.41 19 15 15.59 13.59 17 17 20.41zM7.5 8H11v5.59L5.59 19 7 20.41l6-6V8h3.5L12 3.5 7.5 8z",
+ iconColor: "white",
+ iconBackgroundColor: "#f5515f",
+ originalIcon: "",
+ fillGradient: ["#f5515f", "#a1051d"],
+ },
+ compare: {
+ icon: "M10 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h5v2h2V1h-2v2zm0 15H5l5-6v6zm9-15h-5v2h5v13l-5-6v9h5c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z",
+ iconColor: "white",
+ iconBackgroundColor: defaultColor,
+ originalIcon:
,
+ },
+ extract: {
+ icon: "M3 3h18v2H3z",
+ iconColor: "white",
+ iconBackgroundColor: defaultColor,
+ originalIcon:
,
+ },
+ inflate: {
+ icon: "M6 19h12v2H6z",
+ iconColor: "white",
+ iconBackgroundColor: defaultColor,
+ originalIcon:
,
+ },
+ list: {
+ icon: "M3 9h14V7H3v2zm0 4h14v-2H3v2zm0 4h14v-2H3v2zm16 0h2v-2h-2v2zm0-10v2h2V7h-2zm0 6h2v-2h-2v2z",
+ iconColor: "white",
+ iconBackgroundColor: defaultColor,
+ originalIcon:
,
+ },
+ execute: {
+ icon: "M8 5v14l11-7z",
+ iconColor: "white",
+ iconBackgroundColor: defaultColor,
+ originalIcon:
,
+ },
+ delete: {
+ icon: "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z",
+ iconColor: "white",
+ iconBackgroundColor: "#03030e",
+ originalIcon:
,
+ fillGradient: ["#03030e", "#205d66"],
+ },
+ close: {
+ icon: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z",
+ iconColor: "white",
+ iconBackgroundColor: "#03030e",
+ originalIcon:
,
+ fillGradient: ["#03030e", "#205d66"],
+ },
+ send: {
+ icon: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z",
+ iconColor: "white",
+ iconBackgroundColor: "#0373da",
+ originalIcon:
,
+ fillGradient: ["#0bc8bf", "#0373da"],
+ },
+ download: {
+ icon: "M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z",
+ iconColor: "white",
+ iconBackgroundColor: "#0373da",
+ originalIcon:
,
+ fillGradient: ["#0bc8bf", "#0373da"],
+ },
+ search: {
+ icon: "M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z",
+ iconColor: "white",
+ iconBackgroundColor: "green",
+ originalIcon:
,
+ },
+ };
+
+ var selectedItem = parsedIcons[selectedKey];
+ if (selectedItem === undefined || selectedItem === null) {
+ return {
+ icon: "",
+ iconColor: "",
+ iconBackground: "black",
+ originalIcon: "",
+ };
+ }
+
+ if (selectedItem.fillGradient === undefined) {
+ selectedItem.fillGradient = defaultGradient;
+ selectedItem.iconBackgroundColor = defaultColor;
+ }
+
+ if (selectedItem.icon === "" || selectedItem.icon === undefined) {
+ console.log(
+ `MISSING PATH FOR ${selectedKey} (find in scope): `,
+ selectedItem.originalIcon.type.type
+ );
+ }
+
+ if (
+ (selectedItem.originalIcon === undefined ||
+ selectedItem.originalIcon === "") &&
+ selectedItem.icon !== "" &&
+ selectedItem.icon !== undefined
+ ) {
+ const svg_pin = (
+
+ );
+ selectedItem.originalIcon = svg_pin;
+ }
+
+ return selectedItem;
+};
+
+const chipStyle = {
+ backgroundColor: "#3d3f43",
+ marginRight: 5,
+ paddingLeft: 5,
+ paddingRight: 5,
+ height: 28,
+ cursor: "pointer",
+ borderColor: "#3d3f43",
+ color: "white",
+};
+
+export const validateJson = (showResult) => {
+ if (typeof showResult === 'string') {
+ showResult = showResult.split(" False").join(" false")
+ showResult = showResult.split(" True").join(" true")
+ }
+
+ if (typeof showResult === "object" || typeof showResult === "array") {
+ return {
+ valid: true,
+ result: showResult,
+ }
+ }
+
+ if (showResult[0] === "\"") {
+ return {
+ valid: false,
+ result: showResult,
}
+ }
+
+ var jsonvalid = true
+ try {
+ if (!showResult.includes("{") && !showResult.includes("[")) {
+ jsonvalid = false
+
+ return {
+ valid: jsonvalid,
+ result: showResult,
+ };
+ }
+ } catch (e) {
+ showResult = showResult.split("'").join('"');
+
+ try {
+ if (!showResult.includes("{") && !showResult.includes("[")) {
+ jsonvalid = false;
+ }
+ } catch (e) {
+
+ jsonvalid = false;
+ }
+ }
+
+ var result = showResult;
+ try {
+ result = jsonvalid ? JSON.parse(showResult, {"storeAsString": true}) : showResult;
+ } catch (e) {
+ ////console.log("Failed parsing JSON even though its valid: ", e)
+ jsonvalid = false;
+ }
+
+ if (jsonvalid === false) {
+
+ if (typeof showResult === 'string') {
+ showResult = showResult.trim()
+ }
+
+ try {
+ var newstr = showResult.replaceAll("'", '"')
+
+ // Basic workarounds for issues with Python Dicts -> JSON
+ if (newstr.includes(": None")) {
+ newstr = newstr.replaceAll(": None", ': null')
+ }
+
+ if (newstr.includes("[\"{") && newstr.includes("}\"]")) {
+ newstr = newstr.replaceAll("[\"{", '[{')
+ newstr = newstr.replaceAll("}\"]", '}]')
+ }
+
+ if (newstr.includes("{\"[") && newstr.includes("]\"}")) {
+ newstr = newstr.replaceAll("{\"[", '[{')
+ newstr = newstr.replaceAll("]\"}", '}]')
+ }
+
+ result = JSON.parse(newstr)
+ jsonvalid = true
+ } catch (e) {
+
+ //console.log("Failed parsing JSON even though its valid (2): ", e)
+ jsonvalid = false
+ }
+ }
+
+ if (jsonvalid && typeof result === "number") {
+ jsonvalid = false
+ }
+
+ // This is where we start recursing
+ if (jsonvalid) {
+ // Check fields if they can be parsed too
+ //console.log("In this window for the data. Should look for list in result! Does recursion.")
+ try {
+ for (const [key, value] of Object.entries(result)) {
+ if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
+ const inside_result = validateJson(value)
+ if (inside_result.valid) {
+ if (typeof inside_result.result === "string") {
+ const newres = JSON.parse(inside_result.result)
+ result[key] = newres
+ } else {
+ result[key] = inside_result.result
+ }
+ }
+ } else {
+
+ // Usually only reaches here if raw array > dict > value
+ if (typeof showResult !== "array") {
+ for (const [subkey, subvalue] of Object.entries(value)) {
+ if (typeof subvalue === "string" && (subvalue.startsWith("{") || subvalue.startsWith("["))) {
+ const inside_result = validateJson(subvalue)
+ if (inside_result.valid) {
+ if (typeof inside_result.result === "string") {
+ const newres = JSON.parse(inside_result.result)
+ result[key][subkey] = newres
+ } else {
+ result[key][subkey] = inside_result.result
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+ } catch (e) {
+ console.log("Failed parsing inside json subvalues: ", e)
+ }
+ }
+
+ return {
+ valid: jsonvalid,
+ result: result,
+ };
+};
+
+const Workflows = (props) => {
+ const { globalUrl, isLoggedIn, isLoaded, userdata, checkLogin } = props;
+ document.title = "Shuffle - Workflows";
+ let navigate = useNavigate();
+
+ const alert = useAlert();
+ const classes = useStyles(theme);
+ const imgSize = 60;
+
+ const referenceUrl = globalUrl + "/api/v1/hooks/";
+
+ var upload = "";
+
+ const [workflows, setWorkflows] = React.useState([]);
+ const [_, setUpdate] = React.useState(""); // Used for rendering, don't remove
+ const [selectedUsecases, setSelectedUsecases] = React.useState([]);
+ const [filteredWorkflows, setFilteredWorkflows] = React.useState([]);
+ const [selectedWorkflow, setSelectedWorkflow] = React.useState({});
+ const [workflowDone, setWorkflowDone] = React.useState(false);
+ const [selectedWorkflowId, setSelectedWorkflowId] = React.useState("");
+
+ const [field1, setField1] = React.useState("");
+ const [field2, setField2] = React.useState("");
+ const [downloadUrl, setDownloadUrl] = React.useState(
+ "https://github.com/frikky/shuffle-workflows"
+ );
+ const [downloadBranch, setDownloadBranch] = React.useState("master");
+ const [loadWorkflowsModalOpen, setLoadWorkflowsModalOpen] =
+ React.useState(false);
+ const [exportModalOpen, setExportModalOpen] = React.useState(false);
+ const [exportData, setExportData] = React.useState("");
+
+ const [modalOpen, setModalOpen] = React.useState(false);
+ const [isEditing, setIsEditing] = React.useState(true);
+ const [newWorkflowName, setNewWorkflowName] = React.useState("");
+ const [newWorkflowDescription, setNewWorkflowDescription] =
+ React.useState("");
+ const [newWorkflowTags, setNewWorkflowTags] = React.useState([]);
+
+ const [defaultReturnValue, setDefaultReturnValue] = React.useState("");
+ const [blogpost, setBlogpost] = React.useState("");
+ const [status, setStatus] = React.useState("test");
+
+ const [deleteModalOpen, setDeleteModalOpen] = React.useState(false);
+ const [publishModalOpen, setPublishModalOpen] = React.useState(false);
+ const [editingWorkflow, setEditingWorkflow] = React.useState({});
+ const [isDropzone, setIsDropzone] = React.useState(false);
+ const [view, setView] = React.useState("grid");
+ const [filters, setFilters] = React.useState([]);
+ const [submitLoading, setSubmitLoading] = React.useState(false);
+ const [actionImageList, setActionImageList] = React.useState([]);
+
+ const [firstLoad, setFirstLoad] = React.useState(true);
+ const [showMoreClicked, setShowMoreClicked] = React.useState(false);
+ const [usecases, setUsecases] = React.useState([]);
+ const [allUsecases, setAllUsecases] = React.useState({
+ "success": false,
+ });
+ const [appFramework, setAppFramework] = React.useState({});
+ const [drawerOpen, setDrawerOpen] = React.useState(false)
+ const [videoViewOpen, setVideoViewOpen] = React.useState(false)
+ const [gettingStartedItems, setGettingStartedItems] = React.useState([])
+
+ const drawerWidth = drawerOpen ? 325 : 0
+
+ const sidebarKey = "getting_started_sidebar"
+ if (isLoggedIn === true && gettingStartedItems.length === 0 && (userdata.tutorials !== undefined && userdata.tutorials !== null && userdata.tutorials.length > 0) && workflowDone === true) {
+
+ const activeFiltered = userdata.tutorials.filter((item) => item.active === true)
+ if (activeFiltered.length > 0) {
+ var newfiltered = []
+ for (var key in activeFiltered) {
+ if (activeFiltered[key].name === "Discover Usecases") {
+ if (workflows.length > 1) {
+ activeFiltered[key].done = true
+ activeFiltered[key].description = `${workflows.length} workflows created`
+ }
+ }
+
+ newfiltered.push(activeFiltered[key])
+ }
+ setGettingStartedItems(activeFiltered)
+
+ //const doneFiltered = activeFiltered.filter((item) => item.done === true)
+ //if (doneFiltered.length > 0) {
+ // console.log("DONE: ", doneFiltered)
+ //}
+
+ const sidebar = localStorage.getItem(sidebarKey);
+ if (sidebar === null || sidebar === undefined) {
+ console.log("No sidebar defined")
+
+ localStorage.setItem(sidebarKey, "open");
+ setDrawerOpen(true)
+ } else {
+ if (sidebar === "open") {
+ setDrawerOpen(true)
+ } else {
+ setDrawerOpen(false)
+ }
+ }
+ }
+
+ }
+
+ const isCloud =
+ window.location.host === "localhost:3002" ||
+ window.location.host === "shuffler.io";
+
+ const findWorkflow = (filters) => {
+ console.log("Using filters: ", filters)
+ if (filters.length === 0) {
+ setFilteredWorkflows(workflows);
+ handleKeysetting(allUsecases, workflows)
+ return;
+ }
+
+ var newWorkflows = [];
+ for (var workflowKey in workflows) {
+ const curWorkflow = workflows[workflowKey];
+
+ var found = [false];
+ if (curWorkflow.tags === undefined || curWorkflow.tags === null) {
+ found = filters.map((filter) =>
+ curWorkflow.name.toLowerCase().includes(filter)
+ );
+ }
+
+ if (found.every((v) => v !== true)) {
+ found = filters.map((filter) => {
+ if (filter === undefined || filter === null) {
+ return false;
+ }
+
+ const newfilter = filter.toLowerCase();
+
+ if (curWorkflow.name.toLowerCase().includes(filter.toLowerCase())) {
+ return true;
+ } else if (curWorkflow.tags !== undefined && curWorkflow.tags !== null && curWorkflow.tags.includes(filter)) {
+ return true;
+ } else if (curWorkflow.owner === filter) {
+ return true;
+ } else if (curWorkflow.org_id === filter) {
+ return true;
+ } else if (curWorkflow.usecase_ids !== undefined && curWorkflow.usecase_ids !== null && curWorkflow.usecase_ids.length > 0) {
+ // Check if the usecase is the right category
+ for (var key in usecases) {
+ if (usecases[key].name.toLowerCase() !== newfilter) {
+ continue
+ }
+
+ for (var subkey in usecases[key].list) {
+ if (curWorkflow.usecase_ids.includes(usecases[key].list[subkey].name)) {
+ return true
+ }
+ }
+ }
+ } else if (
+ curWorkflow.actions !== null &&
+ curWorkflow.actions !== undefined
+ ) {
+ for (var key in curWorkflow.actions) {
+ const action = curWorkflow.actions[key];
+
+ if (
+ action.app_name.toLowerCase() === newfilter ||
+ action.app_name.toLowerCase().includes(newfilter)
+ ) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ });
+ }
+
+ if (found.every((v) => v === true)) {
+ newWorkflows.push(curWorkflow);
+ continue;
+ }
+ }
+
+ console.log("Changing workflow filter, and finding new usecase mappings!")
+ if (newWorkflows.length !== workflows.length) {
+ handleKeysetting(allUsecases, newWorkflows)
+
+ setFilteredWorkflows(newWorkflows);
+ }
+ };
+
+ const addFilter = (data) => {
+ if (data === null || data === undefined) {
+ console.log("No filter data")
+ return;
+ }
+
+ if (data.includes("<") && data.includes(">")) {
+ console.log("Filter includes < or >")
+ return;
+ }
+
+ if (filters.includes(data) || filters.includes(data.toLowerCase())) {
+ console.log("Filter already has the data")
+ return;
+ }
+
+ filters.push(data.toLowerCase());
+ setFilters(filters);
+
+ findWorkflow(filters);
+ };
+
+ const removeFilter = (index) => {
+ var newfilters = filters;
+
+ if (index < 0) {
+ console.log("Can't handle index (remove): ", index);
+ return;
+ }
+
+ newfilters.splice(index, 1);
+
+ if (newfilters.length === 0) {
+ newfilters = [];
+ setFilters(newfilters);
+ } else {
+ setFilters(newfilters);
+ }
+
+ findWorkflow(newfilters);
+ };
+
+ const exportVerifyModal = exportModalOpen ? (
+
+ ) : null;
+
+ const publishModal = publishModalOpen ? (
+
+ ) : null;
+
+ const deleteModal = deleteModalOpen ? (
+
+ ) : null;
+
+ const uploadFile = (e) => {
+ const isDropzone =
+ e.dataTransfer === undefined ? false : e.dataTransfer.files.length > 0;
+ const files = isDropzone ? e.dataTransfer.files : e.target.files;
+
+ const reader = new FileReader();
+ alert.info("Starting upload. Please wait while we validate the workflows");
+
+ try {
+ reader.addEventListener("load", (e) => {
+ var data = e.target.result;
+ setIsDropzone(false);
+ try {
+ data = JSON.parse(reader.result);
+ } catch (e) {
+ alert.error("Invalid JSON: " + e);
+ return;
+ }
+
+ // Initialize the workflow itself
+ setNewWorkflow(
+ data.name,
+ data.description,
+ data.tags,
+ data.default_return_value,
+ {},
+ false,
+ [],
+ "",
+ data.status,
+ )
+ .then((response) => {
+ if (response !== undefined) {
+ // SET THE FULL THING
+ data.id = response.id;
+
+ // Actually create it
+ setNewWorkflow(
+ data.name,
+ data.description,
+ data.tags,
+ data.default_return_value,
+ data,
+ false,
+ [],
+ "",
+ data.status
+ ).then((response) => {
+ if (response !== undefined) {
+ alert.success(`Successfully imported ${data.name}`);
+ }
+ });
+ }
+ })
+ .catch((error) => {
+ alert.error("Import error: " + error.toString());
+ });
+ });
+ } catch (e) {
+ console.log("Error in dropzone: ", e);
+ }
+
+ reader.readAsText(files[0]);
+ };
+
+ useEffect(() => {
+ if (isDropzone) {
+ setIsDropzone(false);
+ }
+
}, [isDropzone]);
- const getAvailableWorkflows = () => {
- fetch(globalUrl+"/api/v1/workflows", {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- 'Accept': 'application/json',
- },
- credentials: "include",
- })
+
+ const getFramework = () => {
+ fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ credentials: "include",
+ })
.then((response) => {
if (response.status !== 200) {
- console.log("Status not 200 for workflows :O!: ", response.status)
-
- if (isCloud) {
- window.location.pathname = "/login"
- }
-
- alert.info("Failed getting workflows.")
- setWorkflowDone(true)
-
- return
+ console.log("Status not 200 for framework!");
}
- return response.json()
- })
- .then((responseJson) => {
- setSelectedExecution({})
- setWorkflowExecutions([])
- //console.log(responseJson)
- if (responseJson !== undefined) {
- setWorkflows(responseJson)
- setFilteredWorkflows(responseJson)
- setWorkflowDone(true)
+ return response.json();
+ })
+ .then((responseJson) => {
+ if (responseJson.success === false) {
+ setAppFramework({})
+ if (responseJson.reason !== undefined) {
+ //alert.error("Failed loading: " + responseJson.reason)
+ } else {
+ //alert.error("Failed to load framework for your org.")
+ }
} else {
- if (isLoggedIn) {
- alert.error("An error occurred while loading workflows")
- }
-
- return
- }
-
- if (responseJson.length > 0){
- //setSelectedWorkflow(responseJson[0])
- //getWorkflowExecution(responseJson[0].id)
- }
- })
- .catch(error => {
- alert.error(error.toString())
- });
- }
-
- useEffect(() => {
- if (workflows.length <= 0 && firstrequest) {
- const tmpView = localStorage.getItem('view');
- if (tmpView !== undefined && tmpView !== null) {
- setView(tmpView)
- }
-
- setFirstrequest(false)
- getAvailableWorkflows()
- }
- })
-
- const viewStyle = {
- color: "#ffffff",
- width: "100%",
- display: "flex",
- minWidth: 1024,
- maxWidth: 1024,
- margin: "auto",
- /*maxHeight: "90vh",*/
- }
-
- const emptyWorkflowStyle = {
- paddingTop: "200px",
- width: 1024,
- margin: "auto",
- }
-
- const boxStyle = {
- padding: "20px 20px 20px 20px",
- width: "100%",
- height: "250px",
- color: "white",
- backgroundColor: surfaceColor,
- display: "flex",
- flexDirection: "column",
- }
-
-
- const scrollStyle = {
- marginTop: "10px",
- overflow: "scroll",
- height: "90%",
- overflowX: "hidden",
- overflowY: "auto",
- }
-
- const paperAppContainer = {
- display: "flex",
- flexWrap: 'wrap',
- alignContent: "space-between",
- }
-
- const paperAppStyle = {
- minHeight: 130,
- maxHeight: 130,
- overflow: "hidden",
- width: "100%",
- color: "white",
- backgroundColor: surfaceColor,
- padding: "12px 12px 0px 15px",
- borderRadius: 5,
- display: "flex",
- boxSizing: "border-box",
- position: "relative",
- }
-
-
- const gridContainer = {
- height: "auto",
- color: "white",
- margin: "10px",
- backgroundColor: surfaceColor,
- }
-
- const workflowActionStyle = {
- display: "flex",
- width: 160,
- height: 44,
- justifyContent: "space-between",
- }
-
- const executeWorkflow = (id) => {
- alert.show("Executing workflow "+id)
- setTrackingId(id)
- fetch(globalUrl+"/api/v1/workflows/"+id+"/execute", {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- 'Accept': 'application/json',
- },
- credentials: "include",
- })
- .then((response) => {
- if (response.status !== 200) {
- console.log("Status not 200 for WORKFLOW EXECUTION :O!")
- }
-
- return response.json()
- })
- .then((responseJson) => {
- if (!responseJson.success) {
- alert.error(responseJson.reason)
+ setAppFramework(responseJson)
}
})
- .catch(error => {
- alert.error(error.toString())
- });
+ .catch((error) => {
+ console.log("err in framework: ", error.toString());
+ })
}
- function sleep (time) {
- return new Promise((resolve) => setTimeout(resolve, time));
- }
+ const getAvailableWorkflows = () => {
+ fetch(globalUrl + "/api/v1/workflows", {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ credentials: "include",
+ })
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for workflows :O!: ", response.status);
- const exportAllWorkflows = () => {
- for (var key in workflows) {
- exportWorkflow(workflows[key], false)
- }
- }
+ //if (isCloud) {
+ // navigate("/search?tab=workflows")
+ //}
- const deduplicateIds = (data) => {
- if (data.triggers !== null && data.triggers !== undefined) {
- for (var key in data.triggers) {
- const trigger = data.triggers[key]
- if (trigger.app_name === "Shuffle Workflow") {
- if (trigger.parameters.length > 2) {
- trigger.parameters[2].value = ""
+ alert.info("Failed getting workflows. Are you logged in?");
+
+ return;
+ }
+ return response.json();
+ })
+ .then((responseJson) => {
+ if (responseJson !== undefined) {
+ var newarray = []
+ for (var key in responseJson) {
+ const wf = responseJson[key]
+ if (wf.public === true) {
+ continue
+ }
+
+ newarray.push(wf)
}
- }
-
- if (trigger.status == "running") {
- trigger.status = "stopped"
- }
+
+ var setProdFilter = false
- const newId = uuidv4()
- if (trigger.trigger_type === "WEBHOOK") {
- const hookname = "webhook_"+newId
- if (trigger.parameters !== undefined && trigger.parameters !== null && trigger.parameters.length === 2) {
- trigger.parameters[0].value = referenceUrl+"webhook_"+trigger.id
- trigger.parameters[1].value = "webhook_"+trigger.id
- } else if (trigger.parameters !== undefined && trigger.parameters !== null && trigger.parameters.length === 3) {
- trigger.parameters[0].value = referenceUrl+"webhook_"+trigger.id
- trigger.parameters[1].value = "webhook_"+trigger.id
- // FIXME: Add auth here?
- } else {
- alert.info("Something is wrong with the webhook in the copy")
+ var actionnamelist = [];
+ var parsedactionlist = [];
+ for (var key in newarray) {
+ const workflow = newarray[key]
+ if (workflow.status === "production") {
+ setProdFilter = true
+ }
+
+ for (var actionkey in newarray[key].actions) {
+ const action = newarray[key].actions[actionkey];
+ //console.log("Action: ", action)
+ if (actionnamelist.includes(action.app_name)) {
+ continue;
+ }
+
+ actionnamelist.push(action.app_name);
+ parsedactionlist.push(action);
+ }
}
- }
- for (var branchkey in data.branches) {
- const branch = data.branches[branchkey]
- if (branch.source_id === trigger.id) {
- branch.source_id = newId
- }
+ //console.log(parsedactionlist)
+ setActionImageList(parsedactionlist);
- if (branch.destination_id === trigger.id) {
- branch.destination_id = newId
- }
- }
-
- trigger.environment = isCloud ? "cloud" : "Shuffle"
- trigger.id = newId
- }
- }
-
- if (data.actions !== null && data.actions !== undefined) {
- for (var key in data.actions) {
- data.actions[key].authentication_id = ""
-
- for (var subkey in data.actions[key].parameters) {
- const param = data.actions[key].parameters[subkey]
- if (param.name.includes("key") || param.name.includes("user") || param.name.includes("pass") || param.name.includes("api") || param.name.includes("auth") || param.name.includes("secret") || param.name.includes("domain") || param.name.includes("url") || param.name.includes("mail")) {
- // FIXME: This may be a vuln if api-keys are generated that start with $
- if (param.value.startsWith("$")) {
- console.log("Skipping field, as it's referencing a variable")
+
+ if (setProdFilter === true) {
+ const newWorkflows = newarray.filter(workflow => workflow.status === "production")
+ if (newWorkflows !== undefined && newWorkflows !== null) {
+ setFilteredWorkflows(newWorkflows);
} else {
- param.value = ""
- param.is_valid = false
+ setFilteredWorkflows(newarray);
+ }
+ setFilters(["status:production"]);
+ } else {
+ setFilteredWorkflows(newarray);
+ }
+
+
+ // Ensures the zooming happens only once per load
+ setTimeout(() => {
+ fetchUsecases(newarray)
+ setFirstLoad(false)
+ }, 100)
+
+ } else {
+ if (isLoggedIn) {
+ alert.error("An error occurred while loading workflows");
+ }
+
+ return;
+ }
+ })
+ .catch((error) => {
+ alert.error(error.toString());
+ });
+ };
+
+ const handleKeysetting = (categorydata, workflows) => {
+ if (workflows !== undefined && workflows !== null) {
+ var newcategories = []
+ for (var key in categorydata) {
+ var category = categorydata[key]
+ // Check if category is bool
+ if (typeof category === "boolean") {
+ continue
+ }
+
+ category.matches = []
+
+ for (var subcategorykey in category.list) {
+ var subcategory = category.list[subcategorykey]
+ subcategory.matches = []
+
+ for (var workflowkey in workflows) {
+ const workflow = workflows[workflowkey]
+
+ if (workflow.usecase_ids !== undefined && workflow.usecase_ids !== null) {
+ for (var usecasekey in workflow.usecase_ids) {
+
+ if (workflow.usecase_ids[usecasekey].toLowerCase() === subcategory.name.toLowerCase()) {
+ //console.log("Got match: ", workflow.usecase_ids[usecasekey])
+
+ category.matches.push({
+ "workflow": workflow.id,
+ "category": subcategory.name,
+ })
+ subcategory.matches.push(workflow.id)
+ break
+ }
+ }
+ }
+
+ if (subcategory.matches.length > 0) {
+ break
}
}
}
- const newId = uuidv4()
- for (var branchkey in data.branches) {
- const branch = data.branches[branchkey]
- if (branch.source_id === data.actions[key].id) {
- branch.source_id = newId
- }
+ newcategories.push(category)
+ }
- if (branch.destination_id === data.actions[key].id) {
- branch.destination_id = newId
+ setUsecases(newcategories)
+ } else {
+ setUsecases(categorydata)
+ }
+ }
+
+ const fetchUsecases = (workflows) => {
+ fetch(globalUrl + "/api/v1/workflows/usecases", {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ credentials: "include",
+ })
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for usecases");
+ }
+
+ return response.json();
+ })
+ .then((responseJson) => {
+ setWorkflows(workflows);
+ setWorkflowDone(true);
+
+ if (responseJson.success !== false) {
+ setAllUsecases(responseJson);
+ handleKeysetting(responseJson, workflows)
+ }
+ })
+ .catch((error) => {
+ //alert.error("ERROR: " + error.toString());
+ console.log("ERROR: " + error.toString());
+ setWorkflows(workflows);
+ setWorkflowDone(true);
+ });
+ };
+
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ useEffect(() => {
+ if (workflows.length <= 0) {
+ const tmpView = localStorage.getItem("view");
+ if (tmpView !== undefined && tmpView !== null) {
+ setView(tmpView);
+ }
+
+ getAvailableWorkflows();
+ getFramework()
+ }
+ }, [])
+
+ const viewStyle = {
+ color: "#ffffff",
+ width: "100%",
+ display: "flex",
+ minWidth: isMobile ? "100%" : 1024,
+ maxWidth: isMobile ? "100%" : 1024,
+ margin: drawerWidth === 0 ? "auto" : `auto ${drawerWidth+100} auto auto`,
+ paddingBottom: 200,
+ };
+
+ const emptyWorkflowStyle = {
+ paddingTop: "200px",
+ width: 1024,
+ margin: "auto",
+ };
+
+ const boxStyle = {
+ padding: "20px 20px 20px 20px",
+ width: "100%",
+ height: "250px",
+ color: "white",
+ backgroundColor: surfaceColor,
+ display: "flex",
+ flexDirection: "column",
+ };
+
+ //flexDirection: !isMobile ? "column" : "row",
+ const paperAppContainer = {
+ display: "flex",
+ flexWrap: "wrap",
+ alignContent: "space-between",
+ };
+
+ const paperAppStyle = {
+ minHeight: 130,
+ maxHeight: 130,
+ overflow: "hidden",
+ width: "100%",
+ color: "white",
+ backgroundColor: surfaceColor,
+ padding: "12px 12px 0px 15px",
+ borderRadius: 5,
+ display: "flex",
+ boxSizing: "border-box",
+ position: "relative",
+ };
+
+ const gridContainer = {
+ height: "auto",
+ color: "white",
+ margin: "10px",
+ backgroundColor: surfaceColor,
+ };
+
+ const workflowActionStyle = {
+ display: "flex",
+ width: 160,
+ height: 44,
+ justifyContent: "space-between",
+ };
+
+ const exportAllWorkflows = (allWorkflows) => {
+ for (var i = 0; i < allWorkflows.length; i++) {
+ console.log(allWorkflows[i])
+ setTimeout(() => {
+ console.log(allWorkflows[i])
+ exportWorkflow(allWorkflows[i], false)
+ }, i * 200);
+ }
+
+ alert.info(`exporting and keeping original for all ${allWorkflows.length} workflows`);
+ };
+
+ const deduplicateIds = (data, skip_sanitize) => {
+ if (data.triggers !== null && data.triggers !== undefined) {
+ for (var key in data.triggers) {
+ const trigger = data.triggers[key];
+ if (skip_sanitize !== true) {
+ if (trigger.app_name === "Shuffle Workflow") {
+ if (trigger.parameters !== null && trigger.parameters !== undefined) {
+ if (trigger.parameters.length > 2) {
+ trigger.parameters[2].value = "";
+ }
+ }
}
}
- if (data.actions[key].id === data.start) {
- data.start = newId
- }
+ if (trigger.status === "running") {
+ trigger.status = "stopped";
+ }
- //data.actions[key].environment = isCloud ? "cloud" : "Shuffle"
- data.actions[key].environment = ""
- data.actions[key].id = newId
- }
- }
+ const newId = uuidv4();
+ if (trigger.trigger_type === "WEBHOOK") {
+ if (
+ trigger.parameters !== undefined &&
+ trigger.parameters !== null &&
+ trigger.parameters.length === 2
+ ) {
+ trigger.parameters[0].value =
+ referenceUrl + "webhook_" + trigger.id;
+ trigger.parameters[1].value = "webhook_" + trigger.id;
+ } else if (
+ trigger.parameters !== undefined &&
+ trigger.parameters !== null &&
+ trigger.parameters.length === 3
+ ) {
+ trigger.parameters[0].value =
+ referenceUrl + "webhook_" + trigger.id;
+ trigger.parameters[1].value = "webhook_" + trigger.id;
+ // FIXME: Add auth here?
+ } else {
+ alert.info("Something is wrong with the webhook in the copy");
+ }
+ }
- if (data.workflow_variables !== null && data.workflow_variables !== undefined) {
- for (var key in data.workflow_variables) {
- const param = data.workflow_variables[key]
- if (param.name.includes("key") || param.name.includes("user") || param.name.includes("pass") || param.name.includes("api") || param.name.includes("auth") || param.name.includes("secret") || param.name.includes("email")) {
- param.value = ""
- param.is_valid = false
- }
- }
- }
+ for (var branchkey in data.branches) {
+ const branch = data.branches[branchkey];
+ if (branch.source_id === trigger.id) {
+ branch.source_id = newId;
+ }
- return data
- }
+ if (branch.destination_id === trigger.id) {
+ branch.destination_id = newId;
+ }
+ }
- const sanitizeWorkflow = (data) => {
- data = JSON.parse(JSON.stringify(data))
- data["owner"] = ""
- console.log("Sanitize start: ", data)
- data = deduplicateIds(data)
+ trigger.environment = isCloud ? "cloud" : "Shuffle";
+ trigger.id = newId;
+ }
+ }
- data["org"] = []
- data["org_id"] = ""
- data["execution_org"] = {}
+ if (data.actions !== null && data.actions !== undefined && skip_sanitize !== true) {
+ for (key in data.actions) {
+ data.actions[key].authentication_id = "";
- // These are backwards.. True = saved before. Very confuse.
- data["previously_saved"] = false
- data["first_save"] = false
- console.log("Sanitize end: ", data)
+ for (var subkey in data.actions[key].parameters) {
+ const param = data.actions[key].parameters[subkey];
- return data
- }
+ // Removed October 10th, 2022 as key usually isn't
+ // containing anything secret, but rather necessary configurations.
+ // param.name.includes("key") ||
+ //
+ if (
+ param.name.includes("user") ||
+ param.name.includes("pass") ||
+ param.name.includes("api") ||
+ param.name.includes("auth") ||
+ param.name.includes("secret") ||
+ param.name.includes("domain") ||
+ param.name.includes("url") ||
+ param.name.includes("mail")
+ ) {
+ // FIXME: This may be a vuln if api-keys are generated that start with $
+ if (param.value.startsWith("$")) {
+ console.log("Skipping field, as it's referencing a variable");
+ } else {
+ param.value = "";
+ param.is_valid = false;
+ }
+ }
+ }
- const exportWorkflow = (data, sanitize) => {
- data = JSON.parse(JSON.stringify(data))
- let exportFileDefaultName = data.name+'.json';
+ const newId = uuidv4();
+ for (branchkey in data.branches) {
+ const branch = data.branches[branchkey];
+ if (branch.source_id === data.actions[key].id) {
+ branch.source_id = newId;
+ }
- if (sanitize === true) {
- data = sanitizeWorkflow(data)
- }
- //return
+ if (branch.destination_id === data.actions[key].id) {
+ branch.destination_id = newId;
+ }
+ }
- // Add correct ID's for triggers
- // Add mag
+ if (data.actions[key].id === data.start) {
+ data.start = newId;
+ }
- let dataStr = JSON.stringify(data)
- let dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr);
- let linkElement = document.createElement('a');
- linkElement.setAttribute('href', dataUri);
- linkElement.setAttribute('download', exportFileDefaultName);
- linkElement.click();
- }
+ data.actions[key].environment = "";
+ data.actions[key].id = newId;
+ }
+ }
- const publishWorkflow = (data) => {
- data = JSON.parse(JSON.stringify(data))
- data = sanitizeWorkflow(data)
- alert.info("Sanitizing and publishing "+data.name)
+ if (data.workflow_variables !== null && data.workflow_variables !== undefined && skip_sanitize !== true) {
+ for (key in data.workflow_variables) {
+ const param = data.workflow_variables[key];
+ //param.name.includes("key") ||
- // This ALWAYS talks to Shuffle cloud
- fetch(globalUrl+"/api/v1/workflows/"+data.id+"/publish", {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Accept': 'application/json',
- },
- body: JSON.stringify(data),
- credentials: "include",
- })
+ if (
+ param.name.includes("user") ||
+ param.name.includes("pass") ||
+ param.name.includes("api") ||
+ param.name.includes("auth") ||
+ param.name.includes("secret") ||
+ param.name.includes("email")
+ ) {
+ param.value = "";
+ param.is_valid = false;
+ }
+ }
+ }
+
+ return data;
+ };
+
+ const sanitizeWorkflow = (data) => {
+ data = JSON.parse(JSON.stringify(data));
+ data["owner"] = "";
+ console.log("Sanitize start: ", data);
+ data = deduplicateIds(data);
+
+ data["org"] = [];
+ data["org_id"] = "";
+ data["execution_org"] = {};
+
+ // These are backwards.. True = saved before. Very confuse.
+ data["previously_saved"] = false;
+ data["first_save"] = false;
+ console.log("Sanitize end: ", data);
+
+ return data;
+ };
+
+ const exportWorkflow = (data, sanitize) => {
+ data = JSON.parse(JSON.stringify(data));
+ let exportFileDefaultName = data.name + ".json";
+
+ if (sanitize === true) {
+ data = sanitizeWorkflow(data);
+
+ if (data.subflows !== null && data.subflows !== undefined) {
+ alert.info(
+ "Not exporting with subflows when sanitizing. Please manually export them."
+ );
+ data.subflows = [];
+ }
+
+ // for (var key in data.subflows) {
+ // if (data.sublof
+ // }
+ //}
+ }
+
+ // Add correct ID's for triggers
+ // Add mag
+
+ data.status = "test"
+ let dataStr = JSON.stringify(data);
+ let dataUri =
+ "data:application/json;charset=utf-8," + encodeURIComponent(dataStr);
+ let linkElement = document.createElement("a");
+ linkElement.setAttribute("href", dataUri);
+ linkElement.setAttribute("download", exportFileDefaultName);
+ linkElement.click();
+ };
+
+ const publishWorkflow = (data) => {
+ data = JSON.parse(JSON.stringify(data));
+ data = sanitizeWorkflow(data);
+ alert.info("Sanitizing and publishing " + data.name);
+
+ // This ALWAYS talks to Shuffle cloud
+ fetch(globalUrl + "/api/v1/workflows/" + data.id + "/publish", {
+ 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 workflow publish :O!")
+ console.log("Status not 200 for workflow publish :O!");
} else {
- if (isCloud) {
- alert.success("Successfully published workflow")
+ if (isCloud) {
+ alert.success("Successfully published workflow");
} else {
- alert.success("Successfully published workflow to https://shuffler.io")
+ alert.success(
+ "Successfully published workflow to https://shuffler.io"
+ );
}
}
- return response.json()
- })
- .then((responseJson) => {
- if (responseJson.reason !== undefined) {
- alert.error("Failed publishing: ", responseJson.reason)
- }
-
- getAvailableWorkflows()
- })
- .catch(error => {
- alert.error(error.toString())
- })
- }
-
- const copyWorkflow = (data) => {
- data = JSON.parse(JSON.stringify(data))
- alert.success("Copying workflow "+data.name)
- data.id = ""
- data.name = data.name+"_copy"
- data = deduplicateIds(data)
- //console.log("COPIED DATA: ", data)
- //return
-
- fetch(globalUrl+"/api/v1/workflows", {
- 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 workflows :O!")
- return
- }
- return response.json()
- })
- .then((responseJson) => {
- setTimeout(() => {
- getAvailableWorkflows()
- }, 1000)
- })
- .catch(error => {
- alert.error(error.toString())
- })
- }
-
-
- const deleteWorkflow = (id) => {
- fetch(globalUrl+"/api/v1/workflows/"+id, {
- method: 'DELETE',
- headers: {
- 'Content-Type': 'application/json',
- 'Accept': 'application/json',
- },
- credentials: "include",
- })
- .then((response) => {
- if (response.status !== 200) {
- console.log("Status not 200 for setting workflows :O!")
- alert.error("Failed deleting workflow")
- } else {
- alert.success("Deleted workflow "+id)
- }
-
- return response.json()
+ return response.json();
})
.then((responseJson) => {
- setTimeout(() => {
- getAvailableWorkflows()
- }, 1000)
+ if (responseJson.reason !== undefined) {
+ alert.error("Failed publishing: ", responseJson.reason);
+ }
+
+ getAvailableWorkflows();
})
- .catch(error => {
- alert.error(error.toString())
+ .catch((error) => {
+ alert.error("Failed publishing: is the workflow valid? Remember to save the workflow first.")
+ console.log(error.toString());
});
+ };
+
+ const copyWorkflow = (data) => {
+ data = JSON.parse(JSON.stringify(data));
+ alert.success("Copying workflow " + data.name);
+ data.id = "";
+ data.name = data.name + "_copy";
+ data = deduplicateIds(data, true);
+
+ fetch(globalUrl + "/api/v1/workflows", {
+ 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 workflows :O!");
+ return;
+ }
+ return response.json();
+ })
+ .then(() => {
+ setTimeout(() => {
+ getAvailableWorkflows();
+ }, 1000);
+ })
+ .catch((error) => {
+ alert.error(error.toString());
+ });
+ };
+
+ const deleteWorkflow = (id) => {
+ fetch(globalUrl + "/api/v1/workflows/" + id, {
+ method: "DELETE",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ credentials: "include",
+ })
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for setting workflows :O!");
+ alert.error("Failed deleting workflow. Do you have access?");
+ } else {
+ alert.success("Deleted workflow " + id);
+ }
+
+ return response.json();
+ })
+ .then(() => {
+ setTimeout(() => {
+ getAvailableWorkflows();
+ }, 1000);
+ })
+ .catch((error) => {
+ alert.error(error.toString());
+ });
+ };
+
+ const handleChipClick = (e) => {
+ addFilter(e.target.innerHTML);
+ };
+
+ const NewWorkflowPaper = () => {
+ const [hover, setHover] = React.useState(false);
+
+ const innerColor = "rgba(255,255,255,0.3)";
+ const setupPaperStyle = {
+ minHeight: paperAppStyle.minHeight,
+ maxWidth: "100%",
+ minWidth: paperAppStyle.width,
+ color: innerColor,
+ padding: paperAppStyle.padding,
+ borderRadius: paperAppStyle.borderRadius,
+ display: "flex",
+ boxSizing: "border-box",
+ position: "relative",
+ border: `2px solid ${innerColor}`,
+ cursor: "pointer",
+ backgroundColor: hover ? "rgba(39,41,45,0.5)" : "rgba(39,41,45,1)",
+ };
+
+ return (
+
+ {
+ setModalOpen(true)
+ setIsEditing(false)
+ }}
+ onMouseOver={() => {
+ setHover(true);
+ }}
+ onMouseOut={() => {
+ setHover(false);
+ }}
+ >
+
+
+
+
+
+
+
+ );
+ };
+
+ const getWorkflowAppgroup = (data) => {
+ if (data.actions === undefined || data.actions === null) {
+ return []
+ }
+
+ var appsFound = []
+ for (var key in data.actions) {
+ const parsedAction = data.actions[key]
+ if (parsedAction.large_image === undefined || parsedAction.large_image === null || parsedAction.large_image === "") {
+ continue
+ }
+
+ if (parsedAction.app_name === "Shuffle Tools" || parsedAction.app_id === "bc78f35c6c6351b07a09b7aed5d29652") {
+ continue
+ }
+
+ if (appsFound.findIndex(data => data.app_name === parsedAction.app_name) < 0){
+ appsFound.push(parsedAction)
+ }
+ }
+
+ return appsFound
}
+ const WorkflowPaper = (props) => {
+ const { data } = props;
+ const [open, setOpen] = React.useState(false);
+ const [anchorEl, setAnchorEl] = React.useState(null);
- const handleChipClick = (e) => {
- addFilter(e.target.innerHTML)
- }
+ var boxColor = "#FECC00";
+ if (data.is_valid) {
+ boxColor = "#86c142";
+ }
+ if (!data.previously_saved) {
+ boxColor = "#f86a3e";
+ }
- const NewWorkflowPaper = (props) => {
- const [hover, setHover] = React.useState(false)
+ const menuClick = (event) => {
+ setOpen(!open);
+ setAnchorEl(event.currentTarget);
+ };
- const innerColor = "rgba(255,255,255,0.3)"
- const setupPaperStyle = {
- minHeight: paperAppStyle.minHeight,
- width: paperAppStyle.width,
- color: innerColor,
- padding: paperAppStyle.padding,
- borderRadius: paperAppStyle.borderRadius,
- display: "flex",
- boxSizing: "border-box",
- position: "relative",
- border: `2px solid ${innerColor}`,
- cursor: "pointer",
- backgroundColor: hover ? "rgba(39,41,45,0.5)" : "rgba(39,41,45,1)",
- }
+ var parsedName = data.name;
+ if (
+ parsedName !== undefined &&
+ parsedName !== null &&
+ parsedName.length > 20
+ ) {
+ parsedName = parsedName.slice(0, 21) + "..";
+ }
- return(
-
- setModalOpen(true)} onMouseOver={() => {setHover(true)}} onMouseOut={() => {setHover(false)}}>
-
-
-
-
-
-
-
- )
- }
+ const actions = data.actions !== null ? data.actions.length : 0;
+ const appGroup = getWorkflowAppgroup(data)
+ const [triggers, subflows] = getWorkflowMeta(data);
- const WorkflowPaper = (props) => {
- const { data } = props;
- const [open, setOpen] = React.useState(false);
- const [anchorEl, setAnchorEl] = React.useState(null);
+ const workflowMenuButtons = (
+
+ */}
+
+
+
+ );
+
+ var image = "";
+ var orgName = "";
+ var orgId = "";
+ if (userdata.orgs !== undefined) {
+ const foundOrg = userdata.orgs.find((org) => org.id === data["org_id"]);
+ if (foundOrg !== undefined && foundOrg !== null) {
+ //position: "absolute", bottom: 5, right: -5,
+ const imageStyle = {
+ width: imagesize,
+ height: imagesize,
+ pointerEvents: "none",
+ marginLeft:
+ data.creator_org !== undefined && data.creator_org.length > 0
+ ? 20
+ : 0,
+ borderRadius: 10,
+ border:
+ foundOrg.id === userdata.active_org.id
+ ? `3px solid ${boxColor}`
+ : null,
+ cursor: "pointer",
+ marginRight: 10,
+ };
+
+ image =
+ foundOrg.image === "" ? (
+

+ ) : (
+

{}}
+ />
+ );
+
+ orgName = foundOrg.name;
+ orgId = foundOrg.id;
+ }
+ }
+
+ var selectedCategory = ""
+ if (data.usecase_ids !== undefined && data.usecase_ids !== null && data.usecase_ids.length > 0 && usecases !== null && usecases !== undefined && usecases.length > 0) {
+ const oldcolor = boxColor.valueOf()
+
+ // Find the first usecase and use that ones' ID
+ for (var key in usecases) {
+ var category = usecases[key]
+ category.matches = []
+
+ for (var subcategorykey in category.list) {
+ var subcategory = category.list[subcategorykey]
+ subcategory.matches = []
+
+ for (var usecasekey in data.usecase_ids) {
+ if (data.usecase_ids[usecasekey].toLowerCase() === subcategory.name.toLowerCase()) {
+ boxColor = category.color
+ break
+ }
+ }
+
+ if (boxColor !== oldcolor) {
+ break
+ }
+ }
+
+ if (boxColor !== oldcolor) {
+ selectedCategory = category.name
+ break
+ }
}
}
- return (
-
-
-
-
-
-
- {
- addFilter(orgId)
- //setFilters(["Org "+orgName])
- //setFilteredWorkflows(newWorkflows)
- }}>
- {image}
+ return (
+
+
+ {selectedCategory !== "" ?
+
+ {
+ addFilter(selectedCategory)
+ }}
+ />
+
+ : null}
+
+
+
+ {
+ addFilter(orgId);
+ }}
+ >
+ {image}
+
+
+
+ {data.image !== undefined && data.image !== null && data.image.length > 0 ?
+
+ : null}
+
+ Edit {data.name}
+
+
+ } placement="bottom">
+
+
+ {parsedName}
+
+
+
+
+
+ {appGroup.length > 0 ?
+
+
+ {appGroup.map((data, index) => {
+ return (
+ {
+ addFilter(data.app_name);
+ }}
+ >
+
+
+
+
+ )
+ })}
+
-
-
-
-
- {parsedName}
-
-
-
-
-
-
-
-
-
- {actions}
-
-
-
-
-
-
-
- {triggers}
-
-
-
-
- {
- if (subflows === 0) {
- alert.info("No subflows for "+data.name)
- return
- }
-
- var newWorkflows = [data]
- for (var key in data.triggers) {
- const trigger = data.triggers[key]
- if (trigger.app_name !== "Shuffle Workflow") {
- continue
- }
-
- if (trigger.parameters !== undefined && trigger.parameters !== null && trigger.parameters.length > 0 && trigger.parameters[0].name === "workflow") {
- const newWorkflow = workflows.find(item => item.id === trigger.parameters[0].value)
- if (newWorkflow !== null && newWorkflow !== undefined) {
- newWorkflows.push(newWorkflow)
- continue
- }
- }
- }
-
- setFilters(["Subflows of "+data.name])
- setFilteredWorkflows(newWorkflows)
- }}>
-
-
- {subflows}
-
-
-
- {/*
-
-
-
-
-
-
- : null}
- {schedules > 0 ?
-
-
-
- : null}
- */}
-
-
- {data.tags !== undefined ?
- data.tags.map((tag, index) => {
- if (index >= 3) {
- return null
- }
-
-
- return (
-
+
+
- )
- })
- : null}
-
-
- {data.actions !== undefined && data.actions !== null ?
-
-
+
+ {actions}
+
+
+
+ }
+
+
+
+
+ {triggers}
+
+
+
+
+ {
+ if (subflows === 0) {
+ alert.info("No subflows for " + data.name);
+ return;
+ }
+
+ var newWorkflows = [data];
+ for (var key in data.triggers) {
+ const trigger = data.triggers[key];
+ if (trigger.app_name !== "Shuffle Workflow") {
+ continue;
+ }
+
+ if (
+ trigger.parameters !== undefined &&
+ trigger.parameters !== null &&
+ trigger.parameters.length > 0 &&
+ trigger.parameters[0].name === "workflow"
+ ) {
+ const newWorkflow = workflows.find(
+ (item) => item.id === trigger.parameters[0].value
+ );
+ if (newWorkflow !== null && newWorkflow !== undefined) {
+ newWorkflows.push(newWorkflow);
+ continue;
+ }
+ }
+ }
+
+ setFilters(["Subflows of " + data.name]);
+ setFilteredWorkflows(newWorkflows);
+ }}
+ >
+
+
+ {subflows}
+
+
+
+
+
+ {data.tags !== undefined && data.tags !== null
+ ? data.tags.map((tag, index) => {
+ if (index >= 3) {
+ return null;
+ }
+
+ return (
+
+ );
+ })
+ : null}
+
+ {data.actions !== undefined && data.actions !== null ? (
+
+ style={{ padding: "0px", color: "#979797" }}
+ >
- {workflowMenuButtons}
-
- {/*
-
-
-
-
-
-
-
- */}
-
- : null}
-
-
- )
- }
+ {workflowMenuButtons}
+
+ ) : null}
+
+
+
+ )
+ }
+ // Can create and set workflows
+ const setNewWorkflow = (
+ name,
+ description,
+ tags,
+ defaultReturnValue,
+ editingWorkflow,
+ redirect,
+ currentUsecases,
+ inputblogpost,
+ inputstatus,
+ ) => {
+ var method = "POST";
+ var extraData = "";
+ var workflowdata = {};
+ if (editingWorkflow.id !== undefined) {
+ console.log("Building original workflow");
+ method = "PUT";
+ extraData = "/" + editingWorkflow.id + "?skip_save=true";
+ workflowdata = editingWorkflow;
- const dividerColor = "rgb(225, 228, 232)"
+ console.log("REMOVING OWNER");
+ workflowdata["owner"] = "";
+ // FIXME: Loop triggers and turn them off?
+ }
- const resultPaperAppStyle = {
- minHeight: "100px",
- minWidth: "100%",
- overflow: "hidden",
- maxWidth: "100%",
- marginTop: "5px",
- color: "white",
- backgroundColor: surfaceColor,
- cursor: "pointer",
- display: "flex",
- }
+ workflowdata["name"] = name;
+ workflowdata["description"] = description;
+ if (tags !== undefined) {
+ workflowdata["tags"] = tags;
+ }
+ workflowdata["blogpost"] = inputblogpost
+ workflowdata["status"] = inputstatus
- function replaceAll(string, search, replace) {
- return string.split(search).join(replace);
- }
+ if (defaultReturnValue !== undefined) {
+ workflowdata["default_return_value"] = defaultReturnValue;
+ }
-
-
- const resultsLength = Object.getOwnPropertyNames(selectedExecution).length > 0 && selectedExecution.results !== null ? selectedExecution.results.length : 0
-
-
-
- // Can create and set workflows
- const setNewWorkflow = (name, description, tags, defaultReturnValue, editingWorkflow, redirect) => {
-
- var method = "POST"
- var extraData = ""
- var workflowdata = {}
-
- if (editingWorkflow.id !== undefined) {
- console.log("Building original workflow")
- method = "PUT"
- extraData = "/"+editingWorkflow.id+"?skip_save=true"
- workflowdata = editingWorkflow
-
- console.log("REMOVING OWNER")
- workflowdata["owner"] = ""
- // FIXME: Loop triggers and turn them off?
+ if (currentUsecases !== undefined && currentUsecases !== null) {
+ workflowdata["usecase_ids"] = currentUsecases
+ //workflows[0].category = ["detect"]
+ //workflows[0].usecase_ids = ["Correlate tickets"]
}
- workflowdata["name"] = name
- workflowdata["description"] = description
- if (tags !== undefined) {
- workflowdata["tags"] = tags
- }
-
- if (defaultReturnValue !== undefined) {
- workflowdata["default_return_value"] = defaultReturnValue
- //console.log("WORKFLOW: ", workflowdata)
- }
-
- //console.log(workflowdata)
- //return
-
- return fetch(globalUrl+"/api/v1/workflows"+extraData, {
- method: method,
- headers: {
- 'Content-Type': 'application/json',
- 'Accept': 'application/json',
- },
- body: JSON.stringify(workflowdata),
- credentials: "include",
+ const new_url = `${globalUrl}/api/v1/workflows${extraData}`
+ return fetch(new_url, {
+ method: method,
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ body: JSON.stringify(workflowdata),
+ credentials: "include",
})
- .then((response) => {
- if (response.status !== 200) {
- console.log("Status not 200 for workflows :O!")
- return
- }
- setSubmitLoading(false)
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for workflows :O!");
+ return;
+ }
+ setSubmitLoading(false);
- return response.json()
- })
- .then((responseJson) => {
- if (method === "POST" && redirect) {
- window.location.pathname = "/workflows/"+responseJson["id"]
- setModalOpen(false)
- } else if (!redirect) {
- // Update :)
- setTimeout(() => {
- getAvailableWorkflows()
- }, 1000)
- setImportLoading(false)
- setModalOpen(false)
- } else {
- alert.info("Successfully changed basic info for workflow")
- setModalOpen(false)
- }
-
- return responseJson
- })
- .catch(error => {
- alert.error(error.toString())
- setImportLoading(false)
- setModalOpen(false)
- setSubmitLoading(false)
- });
- }
-
-
- const importFiles = (event) => {
- console.log("Importing!")
-
- setImportLoading(true)
- const file = event.target.value
- if (event.target.files.length > 0) {
- for (var key in event.target.files) {
- const file = event.target.files[key]
- if (file.type !== "application/json") {
- if (file.type !== undefined) {
- alert.error("File has to contain valid json")
+ return response.json();
+ })
+ .then((responseJson) => {
+ if (responseJson.success === false) {
+ if (responseJson.reason !== undefined) {
+ alert.error("Error setting workflow: ", responseJson.reason)
+ } else {
+ alert.error("Error setting workflow.")
}
- continue
+ return
}
- const reader = new FileReader()
- // Waits for the read
- reader.addEventListener('load', (event) => {
- var data = reader.result
- try {
- data = JSON.parse(reader.result)
- } catch (e) {
- alert.error("Invalid JSON: "+e)
- setImportLoading(false)
- return
- }
+ if (redirect) {
+ //window.location.pathname = "/workflows/" + responseJson["id"];
+ navigate("/workflows/" + responseJson["id"])
+ //setModalOpen(false);
+ } else if (!redirect) {
+ // Update :)
+ setTimeout(() => {
+ getAvailableWorkflows();
+ }, 2500);
+ setSubmitLoading(false)
+ setModalOpen(false);
+ } else {
+ //alert.info("Successfully changed basic info for workflow");
+ setModalOpen(false);
+ }
- // Initialize the workflow itself
- const ret = setNewWorkflow(data.name, data.description, data.tags, data.default_return_value, {}, false)
- .then((response) => {
- if (response !== undefined) {
- // SET THE FULL THING
- data.id = response.id
- data.first_save = false
- data.previously_saved = false
- data.is_valid = false
+ return responseJson;
+ })
+ .catch((error) => {
+ alert.error(error.toString());
+ setSubmitLoading(false)
+ setModalOpen(false);
+ setSubmitLoading(false);
+ });
+ };
- // Actually create it
- const ret = setNewWorkflow(data.name, data.description, data.tags, data.default_return_value, data, false)
- .then((response) => {
- if (response !== undefined) {
- alert.success("Successfully imported "+data.name)
- }
- })
- }
- })
- .catch(error => {
- alert.error("Import error: "+error.toString())
- });
- })
+ const importFiles = (event) => {
+ console.log("Importing!");
+ setSubmitLoading(true)
- // Actually reads
- reader.readAsText(file)
- }
- }
+ if (event.target.files.length > 0) {
+ console.log("Files: !", event.target.files.length);
+ for (var key in event.target.files) {
+ const file = event.target.files[key];
+ if (file.type !== "application/json") {
+ if (file.type !== undefined) {
+ alert.error("File has to contain valid json");
+ setSubmitLoading(false)
+ }
- setLoadWorkflowsModalOpen(false)
- }
+ continue;
+ }
- const getWorkflowMeta = (data) => {
- let triggers = 0
- let schedules = 0
- let webhooks = 0
- let subflows = 0
- if (data.triggers !== undefined && data.triggers !== null && data.triggers.length > 0) {
- triggers = data.triggers.length
- for (let key in data.triggers) {
+ const reader = new FileReader();
+ // Waits for the read
+ reader.addEventListener("load", (event) => {
+ var data = reader.result;
+ try {
+ data = JSON.parse(reader.result);
+ } catch (e) {
+ alert.error("Invalid JSON: " + e);
+ setSubmitLoading(false)
+ return;
+ }
+
+ console.log("File being loaded: ", data.name);
- if (data.triggers[key].app_name === "Webhook") {
- webhooks += 1
- //webhookImg = data.triggers[key].large_image
- } else if (data.triggers[key].app_name === "Schedule") {
- schedules += 1
- //scheduleImg = data.triggers[key].large_image
- } else if (data.triggers[key].app_name === "Shuffle Workflow") {
- subflows += 1
- }
- }
- }
+ // Initialize the workflow itself
+ setNewWorkflow(
+ data.name,
+ data.description,
+ data.tags,
+ data.default_return_value,
+ {},
+ false,
+ [],
+ "",
+ data.status,
+ )
+ .then((response) => {
+ if (response !== undefined) {
+ // SET THE FULL THING
+ data.id = response.id;
+ data.first_save = false;
+ data.previously_saved = false;
+ data.is_valid = false;
- return [triggers, schedules, webhooks, subflows]
- }
+ // Actually create it
+ setNewWorkflow(
+ data.name,
+ data.description,
+ data.tags,
+ data.default_return_value,
+ data,
+ false,
+ [],
+ "",
+ data.status,
+ ).then((response) => {
+ if (response !== undefined) {
+ alert.success("Successfully imported " + data.name);
+ }
+ });
+ }
+ })
+ .catch((error) => {
+ alert.error("Import error: " + error.toString());
+ });
+ });
- const WorkflowListView = () => {
- let workflowData = "";
- if (workflows.length > 0) {
- const columns = [
- { field: 'image', headerName: 'Logo', width: 42, renderCell: (params) => {
- const data = params.row.record
+ // Actually reads
+ reader.readAsText(file);
+ }
+ }
- var boxColor = "#FECC00"
- if (data.is_valid) {
- boxColor = "#86c142"
- }
+ setLoadWorkflowsModalOpen(false);
+ };
- if (!data.previously_saved) {
- boxColor = "#f85a3e"
- }
+ const getWorkflowMeta = (data) => {
+ let triggers = 0;
+ let subflows = 0;
+ if (
+ data.triggers !== undefined &&
+ data.triggers !== null &&
+ data.triggers.length > 0
+ ) {
+ triggers = data.triggers.length;
+ for (let key in data.triggers) {
+ if (data.triggers[key].app_name === "Shuffle Workflow") {
+ subflows += 1;
+ }
+ }
+ }
- var image = ""
- var orgName = ""
- var orgId = ""
- if (userdata.orgs !== undefined) {
- const foundOrg = userdata.orgs.find(org => org.id === data["org_id"])
- if (foundOrg !== undefined && foundOrg !== null) {
- //position: "absolute", bottom: 5, right: -5,
- const imageStyle = {width: imagesize+7, height: imagesize+7, pointerEvents: "none", marginLeft: data.creator_org !== undefined && data.creator_org.length > 0 ? 20 : 0, borderRadius: 10, border: foundOrg.id === userdata.active_org.id ? `3px solid ${boxColor}` : null, cursor: "pointer", marginTop: 5, }
+ return [triggers, subflows];
+ };
- //
- image = foundOrg.image === "" ?
-
- :
-
{
- //setFilteredWorkflows(newWorkflows)
- }}/>
+ const WorkflowListView = () => {
+ let workflowData = "";
+ if (workflows.length > 0) {
+ const columns = [
+ {
+ field: "image",
+ headerName: "Logo",
+ width: 50,
+ sortable: false,
+ renderCell: (params) => {
+ const data = params.row.record;
- orgName = foundOrg.name
- orgId = foundOrg.id
- }
- }
+ var boxColor = "#FECC00";
+ if (data.is_valid) {
+ boxColor = "#86c142";
+ }
- return (
- {
- //addFilter(orgId)
- //setFilters(["Org "+orgName])
- //setFilteredWorkflows(newWorkflows)
- }}>
- {image}
-
- )
- }},
- { field: 'title', headerName: 'Title', width: 330, renderCell: (params) => {
- const data = params.row.record
+ if (!data.previously_saved) {
+ boxColor = "#f85a3e";
+ }
- return (
-
-
-
- {data.name}
-
-
-
- )
- }},
- {/* field: 'category', headerName: 'category', width: 140, renderCell: (params) => {
- const data = params.row.record
- const category = data.category === undefined ? "not defined" : data.category
- return (
-
- {category}
-
- )
- } */},
- { field: 'options', headerName: 'Options', width: 200, sortable: false,
- disableClickEventBubbling: true,
- renderCell: (params) => {
- const data = params.row.record;
- const actions = data.actions !== null ? data.actions.length : 0
- let [triggers, schedules, webhooks, subflows] = getWorkflowMeta(data);
+ var image = "";
+ if (userdata.orgs !== undefined) {
+ const foundOrg = userdata.orgs.find(
+ (org) => org.id === data["org_id"]
+ );
+ if (foundOrg !== undefined && foundOrg !== null) {
+ //position: "absolute", bottom: 5, right: -5,
+ const imageStyle = {
+ width: imagesize + 7,
+ height: imagesize + 7,
+ pointerEvents: "none",
+ marginLeft:
+ data.creator_org !== undefined &&
+ data.creator_org.length > 0
+ ? 20
+ : 0,
+ borderRadius: 10,
+ border:
+ foundOrg.id === userdata.active_org.id
+ ? `3px solid ${boxColor}`
+ : null,
+ cursor: "pointer",
+ marginTop: 5,
+ };
- return (
-
-
+ //
+ image =
+ foundOrg.image === "" ? (
+
+ ) : (
+
{
+ //setFilteredWorkflows(newWorkflows)
+ }}
+ />
+ );
+ }
+ }
+
+ return {image}
;
+ },
+ },
+ {
+ field: "title",
+ headerName: "Title",
+ width: 330,
+ renderCell: (params) => {
+ const data = params.row.record;
+
+
+ return (
+
+
+ {data.name}
+
+
+ );
+ },
+ },
+
+ {
+ field: "options",
+ headerName: "Options",
+ width: 200,
+ sortable: false,
+ disableClickEventBubbling: true,
+ renderCell: (params) => {
+ const data = params.row.record;
+ const actions = data.actions !== null ? data.actions.length : 0;
+ let [triggers, subflows] = getWorkflowMeta(data);
+ const appGroup = getWorkflowAppgroup(data)
+
+ return (
+
+
+ {appGroup.length > 0 ?
+
+
+ {appGroup.map((data, index) => {
+ return (
+ {
+ addFilter(data.app_name);
+ }}
+ >
+
+
+
+
+ )
+ })}
+
+
+ :
-
-
-
+
+
+
{actions}
-
-
-
-
- {triggers}
-
-
-
-
- {
- if (subflows === 0) {
- alert.info("No subflows for "+data.name)
- return
- }
+ }
+
+
+
+
+ {triggers}
+
+
+
+
+ {
+ if (subflows === 0) {
+ alert.info("No subflows for " + data.name);
+ return;
+ }
- var newWorkflows = [data]
- for (var key in data.triggers) {
- const trigger = data.triggers[key]
- if (trigger.app_name !== "Shuffle Workflow") {
- continue
- }
+ var newWorkflows = [data];
+ for (var key in data.triggers) {
+ const trigger = data.triggers[key];
+ if (trigger.app_name !== "Shuffle Workflow") {
+ continue;
+ }
- if (trigger.parameters !== undefined && trigger.parameters !== null && trigger.parameters.length > 0 && trigger.parameters[0].name === "workflow") {
- const newWorkflow = workflows.find(item => item.id === trigger.parameters[0].value)
- if (newWorkflow !== null && newWorkflow !== undefined) {
- newWorkflows.push(newWorkflow)
- continue
- }
- }
- }
+ if (
+ trigger.parameters !== undefined &&
+ trigger.parameters !== null &&
+ trigger.parameters.length > 0 &&
+ trigger.parameters[0].name === "workflow"
+ ) {
+ const newWorkflow = workflows.find(
+ (item) => item.id === trigger.parameters[0].value
+ );
+ if (
+ newWorkflow !== null &&
+ newWorkflow !== undefined
+ ) {
+ newWorkflows.push(newWorkflow);
+ continue;
+ }
+ }
+ }
- setFilters(["Subflows of "+data.name])
- setFilteredWorkflows(newWorkflows)
- }}>
-
-
- {subflows}
-
-
+ setFilters(["Subflows of " + data.name]);
+ setFilteredWorkflows(newWorkflows);
+ }}
+ >
+
+
+ {subflows}
+
+
+
+
+
+ );
+ },
+ },
+ {
+ field: "tags",
+ headerName: "Tags",
+ maxHeight: 15,
+ width: 300,
+ sortable: false,
+ disableClickEventBubbling: true,
+ renderCell: (params) => {
+ const data = params.row.record;
+ return (
+
+ {data.tags !== undefined
+ ? data.tags.map((tag, index) => {
+ if (index >= 3) {
+ return null;
+ }
-
-
-
- )
- }
- },
- { field: 'tags', headerName: 'Tags', maxHeight: 15, width: 300, sortable: false,
- disableClickEventBubbling: true,
- renderCell: (params) => {
- const data = params.row.record;
- return (
-
- {data.tags !== undefined ?
- data.tags.map((tag, index) => {
- if (index >= 3) {
- return null
- }
+ return (
+
+ );
+ })
+ : null}
+
+ );
+ },
+ },
+ {
+ field: "",
+ headerName: "",
+ maxHeight: 15,
+ width: 100,
+ sortable: false,
+ disableClickEventBubbling: true,
+ renderCell: (params) => {},
+ },
+ ];
+ let rows = [];
+ rows = filteredWorkflows.map((data, index) => {
+ let obj = {
+ id: index + 1,
+ title: data.name,
+ record: data,
+ };
- return (
-
- )
- })
- : null}
-
- )
- }
- },
- { field: '', headerName: '', maxHeight: 15, width: 100, sortable: false,
- disableClickEventBubbling: true,
- renderCell: (params) => {
- }
- }
- ];
- let rows = [];
- rows = workflows.map((data, index) => {
- let obj = {
- "id":index+1,
- "title":data.name,
- "record":data,
- }
+ return obj;
+ })
- return obj;
- });
- workflowData =
-
- }
- return (
-
- {workflowData}
-
- );
- }
+ workflowData = (
+
+ );
+ }
+ return {workflowData}
;
+ };
- const modalView = modalOpen ?
-
+ ) : null;
+
+ const viewSize = {
+ workflowView: 4,
+ executionsView: 3,
+ executionResults: 4,
+ };
+
+ const workflowViewStyle = {
+ flex: viewSize.workflowView,
+ marginLeft: 10,
+ marginRight: 10,
+ };
+
+ if (viewSize.workflowView === 0) {
+ workflowViewStyle.display = "none";
+ }
+
+ const workflowButtons = (
+
+ {view === "list" && (
+
+
+
+ )}
+ {view === "grid" && (
+
+
+
+ )}
+
+
+
+ (upload = ref)}
+ onChange={importFiles}
+ />
+ {workflows.length > 0 ? (
+
+
+
+ ) : null}
+ {isCloud ? null : (
+
+
+
+ )}
+
+ );
+
+ // const tourOptions = {
+ // defaultStepOptions: {
+ // classes: "shadow-md bg-purple-dark",
+ // scrollTo: true
+ // },
+ // useModalOverlay: true,
+ // tourName: workflows,
+ // exitOnEsc: true,
+ // }
+
+ // //classes: "custom-class-name-1 custom-class-name-2",
+ // const newSteps = [
+ // {
+ // id: "intro",
+ // scrollTo: true,
+ // beforeShowPromise: function() {
+ // return new Promise(function(resolve) {
+ // setTimeout(function() {
+ // window.scrollTo(0, 0);
+ // resolve();
+ // }, 500);
+ // });
+ // },
+ // buttons: [
+ // {
+ // classes: "shepherd-button-primary",
+ // style: {
+ // backgroundColor: "red",
+ // color: "white",
+ // },
+ // text: "Next",
+ // type: "next"
+ // }
+ // ],
+ // highlightClass: "highlight",
+ // showCancelLink: true,
+ // text: [
+ // "React-Shepherd is a JavaScript library for guiding users through your React app."
+ // ],
+ // when: {
+ // show: () => {
+ // console.log("show step 1");
+ // },
+ // hide: () => {
+ // console.log("hide step 1");
+ // }
+ // }
+ // },
+ // {
+ // id: "second",
+ // attachTo: {
+ // element: "second-step",
+ // on: "top"
+ // },
+ // text: [
+ // "Yuk eksplorasi hasil Tes Minat Bakat-mu dan rekomendasi Jurusan dan Karier."
+ // ],
+ // buttons: [
+ // {
+ // classes: "btn btn-info",
+ // text: "Kembali",
+ // type: "back"
+ // },
+ // {
+ // classes: "btn btn-success",
+ // text: "Saya Mengerti",
+ // type: "cancel"
+ // }
+ // ],
+ // when: {
+ // show: () => {
+ // console.log("show stepp");
+ // },
+ // hide: () => {
+ // console.log("complete step");
+ // }
+ // },
+ // showCancelLink: false,
+ // scrollTo: true,
+ // modalOverlayOpeningPadding: 4,
+ // useModalOverlay: false,
+ // canClickTarget: false
+ // }
+ // ]
- const viewSize = {
- workflowView: 4,
- executionsView: 3,
- executionResults: 4,
- }
+ // function TourButton() {
+ // const tour = useContext(ShepherdTourContext);
+
+ // return (
+ //
+ // );
+ // }
- const workflowViewStyle = {
- flex: viewSize.workflowView,
- marginLeft: "10px",
- marginRight: "10px",
- }
+ const WorkflowView = () => {
+ if (workflows.length === 0) {
+ // Not going there yet
+ //if ((userdata.tutorials !== undefined && userdata.tutorials !== null && !userdata.tutorials.includes("getting-started")) || userdata.tutorials === null) {
+ // return ;
+ //}
+ //return (
+ //
+ //
+ //
+ //
Welcome to Shuffle
+ //
+ //
+ //
+ // Shuffle is a flexible, easy to use, automation platform
+ // allowing users to integrate their services and devices freely.
+ // It's made to significantly reduce the amount of manual labor,
+ // and is focused on security applications.{" "}
+ //
+ // Click here to learn more.
+ //
+ //
+ //
+ //
+ // If you want to jump straight into it, click here to create your
+ // first workflow:
+ //
+ //
+ //
+ //
+ //
+ // ..OR
+ //
+ // {workflowButtons}
+ //
+ //
+ //
+ //
+ //)
+ }
- if (viewSize.workflowView === 0) {
- workflowViewStyle.display = "none"
- }
+ var workflowDelay = -150
+ var appDelay = -75
- const workflowButtons =
-
- {/*workflows.length > 0 ?
-
-
-
- : null*/}
- {view === "list" && (
-
-
-
- )}
- {view === "grid" && (
-
-
-
- )}
-
- {importLoading ?
-
- :
-
- }
-
- upload = ref} onChange={importFiles} />
- {workflows.length > 0 ?
-
-
-
- : null}
- {isCloud ? null :
-
-
-
- }
-
-
- const WorkflowView = () => {
- if (workflows.length === 0) {
- return (
-
-
-
-
Welcome to Shuffle
+ const foundPriority = userdata === undefined || userdata === null ? null : userdata.priorities.find(prio => prio.type === "usecase" && prio.active === true)
+ return (
+
+
+
+
+
+ Workflows
+
+
+ {/*
+
+ */}
+ {isMobile ? null :
+
+
+ {
+ addFilter(chip);
+ }}
+ onDelete={(_, index) => {
+ removeFilter(index);
+ }}
+ />
+
-
-
- Shuffle is a flexible, easy to use, automation platform allowing users to integrate their services and devices freely. It's made to significantly reduce the amount of manual labor, and is focused on security applications. Click here to learn more.
-
-
-
- If you want to jump straight into it, click here to create your first workflow:
-
-
-
-
-
- ..OR
-
- {workflowButtons}
-
-
-
-
- )
- }
-
- return (
-
-
-
-
- {/*
+ }
+
+ {workflowButtons}
+
+
+ {/*
-
+
{workflows.length}
ACTIVE WORKFLOWS
@@ -2025,7 +3304,7 @@ const Workflows = (props) => {
*/}
- {/*
+ {/*
chipRenderer={({ value, isFocused, isDisabled, handleClick, handleRequestDelete }, key) => {
console.log("VALUE: ", value)
@@ -2040,256 +3319,650 @@ const Workflows = (props) => {
)
}}
*/}
-
-
-
- {
- addFilter(chip)
- }}
- onDelete={(chip, index) => {
- removeFilter(index)
- }}
- />
-
-
- {workflowButtons}
-
-
-
- {view === "grid" ?
-
-
- {filteredWorkflows.map((data, index) => {
- return (
-
- )
- })}
-
- :
-
- }
+
+
+ {!isMobile && usecases !== null && usecases !== undefined && usecases.length > 0 ?
+
+ {usecases.map((usecase, index) => {
+ //console.log(usecase)
+ const percentDone = usecase.matches.length > 0 ? parseInt(usecase.matches.length/usecase.list.length*100) : 0
-
+ return (
+
{
+ console.log("Filters: ", filters, usecase.name.toLowerCase())
+ if (!filters.includes(usecase.name.toLowerCase())) {
+ addFilter(usecase.name)
+ } else {
+ removeFilter(filters.indexOf(usecase.name.toLowerCase()))
+ }
+
+ }}
+ >
+
+
+ {usecase.name}
+
+
+ {usecase.matches.length}/{usecase.list.length}
+
+
+
+ )
+ })}
+
+ : null}
+
+
+
+ {!isMobile &&
+ actionImageList !== undefined &&
+ actionImageList !== null &&
+ actionImageList.length > 0 ? (
+
+ {actionImageList.map((data, index) => {
+ if (
+ data.large_image === undefined ||
+ data.large_image === null ||
+ data.large_image.length === 0
+ ) {
+ return null;
+ }
+
+ if (data.app_name.toLowerCase() === "shuffle tools") {
+ data.large_image = theme.palette.defaultImage;
+ }
+
+ const returnData =
+
+ {
+ console.log("FILTER: ", data);
+ addFilter(data.app_name);
+ }}
+ >
+
+
+
+

+
+
+
+
+
+
+ if (firstLoad) {
+ appDelay += 75
+ } else {
+ //appDelay = 0
+ return returnData
+ }
+
+ return (
+
+ {returnData}
+
+ );
+ })}
+
+ ) : null}
+
+ {userdata.priorities !== undefined && userdata.priorities !== null && userdata.priorities.length > 0 && userdata.priorities[0].name.includes("CPU") ?
+
+
+
+ {userdata.priorities[0].name}
+
+
+ {userdata.priorities[0].description}
+
+
+
+
+ {/*
+
+ */}
+
+
+ : null}
+
+ {foundPriority != null && workflows.length < 6 ?
+
+ : null}
+
+
+ {view === "grid" ? (
+
+
+
+
+
+ {filteredWorkflows.map((data, index) => {
+ // Shouldn't be a part of this list
+ if (data.public === true) {
+ return null
+ }
+
+ if (firstLoad) {
+ workflowDelay += 75
+ } else {
+ return (
+
+
+
+ )
+ }
+
+ return (
+
+
+
+
+
+ )
+ })}
+
+ ) : (
+
+ )}
+
+
+ {foundPriority != null && filteredWorkflows.length > 6 ?
+
+ : null}
+
+
+ );
+ };
+
+ const importWorkflowsFromUrl = (url) => {
+ console.log("IMPORT WORKFLOWS FROM ", downloadUrl);
+
+ const parsedData = {
+ url: url,
+ field_3: downloadBranch || "master",
+ };
+
+ if (field1.length > 0) {
+ parsedData["field_1"] = field1;
+ }
+
+ if (field2.length > 0) {
+ parsedData["field_2"] = field2;
+ }
+
+ alert.success("Getting specific workflows from your URL.");
+ fetch(globalUrl + "/api/v1/workflows/download_remote", {
+ method: "POST",
+ mode: "cors",
+ headers: {
+ Accept: "application/json",
+ },
+ body: JSON.stringify(parsedData),
+ credentials: "include",
+ })
+ .then((response) => {
+ if (response.status === 200) {
+ alert.success("Successfully loaded workflows from " + downloadUrl);
+ setTimeout(() => {
+ getAvailableWorkflows();
+ }, 1000);
+ }
+
+ return response.json();
+ })
+ .then((responseJson) => {
+ if (!responseJson.success) {
+ if (responseJson.reason !== undefined) {
+ alert.error("Failed loading: " + responseJson.reason);
+ } else {
+ alert.error("Failed loading");
+ }
+ }
+ })
+ .catch((error) => {
+ alert.error(error.toString());
+ });
+ };
+
+ const handleGithubValidation = () => {
+ importWorkflowsFromUrl(downloadUrl);
+ setLoadWorkflowsModalOpen(false);
+ };
+
+ const workflowDownloadModalOpen = loadWorkflowsModalOpen ? (
+
{}}
+ PaperProps={{
+ style: {
+ backgroundColor: surfaceColor,
+ color: "white",
+ minWidth: "800px",
+ minHeight: "320px",
+ },
+ }}
+ >
+
+
+ Load workflows from github repo
+
+
+
+
+
+
+
+
+ Repository (supported: github, gitlab, bitbucket)
+ setDownloadUrl(e.target.value)}
+ placeholder="https://github.com/frikky/shuffle-apps"
+ fullWidth
+ />
+
+ Branch (default value is "master"):
+
+
+ setDownloadBranch(e.target.value)}
+ placeholder="master"
+ fullWidth
+ />
+
+
+ Authentication (optional - private repos etc):
+
+
+ setField1(e.target.value)}
+ type="username"
+ placeholder="Username / APIkey (optional)"
+ fullWidth
+ />
+ setField2(e.target.value)}
+ type="password"
+ placeholder="Password (optional)"
+ fullWidth
+ />
+
+
+
+
+
+
+
+ ) : null;
+
+
+ //const
+ //const [percentDone, setPercentDone] = React.useState(0)
+ const percentDone = gettingStartedItems.filter((item) => item.done).length / gettingStartedItems.length * 100
+
+ const GettingStartedItem = ({item, index}) => {
+ const [clicked, setClicked] = React.useState(false)
+ const doneIcon = item.done ?
:
+
+ return (
+
setClicked(true)}
+ >
+
+ {doneIcon} {index + 1}. {item.name}
+
+ {clicked ?
+
+
+ {item.description}
+
+
+
+
+
+ :
+ null
+ }
+
)
}
- const importWorkflowsFromUrl = (url) => {
- console.log("IMPORT WORKFLOWS FROM ", downloadUrl)
+ const gettingStartedDrawer =
+
+
+
+ Getting Started
+
+
+ {
+ e.preventDefault();
+ setDrawerOpen(false)
- const parsedData = {
- "url": url,
- "field_3": downloadBranch || 'master'
- }
-
- if (field1.length > 0) {
- parsedData["field_1"] = field1
- }
-
- if (field2.length > 0) {
- parsedData["field_2"] = field2
- }
-
- alert.success("Getting specific workflows from your URL.")
- var cors = "cors"
- fetch(globalUrl+"/api/v1/workflows/download_remote", {
- method: "POST",
- mode: "cors",
- headers: {
- 'Accept': 'application/json',
- },
- body: JSON.stringify(parsedData),
- credentials: "include",
- })
- .then((response) => {
- if (response.status === 200) {
- alert.success("Successfully loaded workflows from "+downloadUrl)
- setTimeout(() => {
- getAvailableWorkflows()
- }, 1000)
- }
-
- return response.json()
- })
- .then((responseJson) => {
- //console.log("DATA: ", responseJson)
- if (!responseJson.success) {
- if (responseJson.reason !== undefined) {
- alert.error("Failed loading: "+responseJson.reason)
- } else {
- alert.error("Failed loading")
- }
- }
- })
- .catch(error => {
- alert.error(error.toString())
- })
- }
-
- const handleGithubValidation = () => {
- importWorkflowsFromUrl(downloadUrl)
- setLoadWorkflowsModalOpen(false)
- }
-
- const workflowDownloadModalOpen = loadWorkflowsModalOpen ?
- {
- }}
- PaperProps={{
- style: {
- backgroundColor: surfaceColor,
- color: "white",
- minWidth: "800px",
- minHeight: "320px",
- },
- }}
- >
-
-
- Load workflows from github repo
-
-
-
-
-
-
-
-
- Repository (supported: github, gitlab, bitbucket)
- setDownloadUrl(e.target.value)}
- placeholder="https://github.com/frikky/shuffle-apps"
- fullWidth
- />
-
- Branch (default value is "master"):
-
- setDownloadBranch(e.target.value)}
- placeholder="master"
- fullWidth
- />
-
-
- Authentication (optional - private repos etc):
-
-
setField1(e.target.value)}
- type="username"
- placeholder="Username / APIkey (optional)"
- fullWidth
- />
-
+
+
+
+
+
+
+ Setup progress: {isNaN(percentDone) ? 0 : percentDone}%
+
+
+
+
+
+ Follow these steps to get you up and running!
+
+
+
{
+ setVideoViewOpen(true)
+ }}>
+ Watch 2-min introduction video
+
+
+
+ {gettingStartedItems.map((item, index) => {
+ return (
+
+ )
+ })}
+
+
+
+ const videoView =
+ {
+ setVideoViewOpen(false)
+ }}
+ PaperProps={{
+ style: {
+ backgroundColor: surfaceColor,
+ color: "white",
+ minWidth: 560,
+ minHeight: 415,
+ textAlign: "center",
+ },
+ }}
+ >
+
+ Welcome to Shuffle!
+
+
+
+ {
+ e.preventDefault();
+ setVideoViewOpen(false)
}}
- onChange={e => setField2(e.target.value)}
- type="password"
- placeholder="Password (optional)"
- fullWidth
- />
-
-
-
-
-
-
-
- : null
+ >
+
+
+
- const loadedCheck = isLoaded && isLoggedIn && workflowDone ?
-
- 1366 ? 1366 : 1200, margin: "auto", padding: 20 }} onDrop={uploadFile}>
-
-
- {modalView}
- {deleteModal}
- {exportVerifyModal}
- {publishModal}
- {workflowDownloadModalOpen}
-
- :
-
-
-
- Loading Workflows
-
-
+
+
+ const loadedCheck =
+ isLoaded && isLoggedIn && workflowDone ? (
+
+ {/*
+
+
+
+ */}
+
1366 ? 1366 : isMobile ? "100%" : 1200,
+ margin: "auto",
+ padding: 20,
+ }}
+ onDrop={uploadFile}
+ >
+
+
+ {/*modalView*/}
+ {deleteModal}
+ {exportVerifyModal}
+ {publishModal}
+ {workflowDownloadModalOpen}
- // Maybe use gridview or something, idk
- return (
-
- {loadedCheck}
-
- )
-}
+ {!drawerOpen ?
+
+ {
+ setDrawerOpen(true)
+ localStorage.setItem(sidebarKey, "open");
+ }}>
+
+
+
+
: null}
+ {isMobile ? null : gettingStartedDrawer}
+ {videoView}
-export default Workflows
+ {modalOpen === true ?
+
+ : null}
+ {/*
+
+ Need assistance? Ask our support team (it's free!).
+
+

+
*/}
+
+ ) : (
+
+
+ Loading Workflows
+
+ );
+
+ // Maybe use gridview or something, idk
+ return {loadedCheck}
;
+};
+
+export default Workflows;
diff --git a/functions/README.md b/functions/README.md
old mode 100644
new mode 100755
diff --git a/functions/extensions/cortex-responders/Shuffle/requirements.txt b/functions/extensions/cortex-responders/Shuffle/requirements.txt
old mode 100644
new mode 100755
diff --git a/functions/extensions/cortex-responders/Shuffle/shuffle.json b/functions/extensions/cortex-responders/Shuffle/shuffle.json
old mode 100644
new mode 100755
diff --git a/functions/extensions/cortex-responders/Shuffle/shuffle.py b/functions/extensions/cortex-responders/Shuffle/shuffle.py
old mode 100644
new mode 100755
diff --git a/functions/extensions/cortex-responders/Shuffle_Webhook/requirements.txt b/functions/extensions/cortex-responders/Shuffle_Webhook/requirements.txt
old mode 100644
new mode 100755
diff --git a/functions/extensions/cortex-responders/Shuffle_Webhook/shuffle_webhook.json b/functions/extensions/cortex-responders/Shuffle_Webhook/shuffle_webhook.json
old mode 100644
new mode 100755
diff --git a/functions/extensions/cortex-responders/Shuffle_Webhook/shuffle_webhook.py b/functions/extensions/cortex-responders/Shuffle_Webhook/shuffle_webhook.py
old mode 100644
new mode 100755
diff --git a/functions/extensions/elasticsearch/run.sh b/functions/extensions/elasticsearch/run.sh
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/.helmignore b/functions/extensions/k8s/shuffle/.helmignore
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/Chart.yaml b/functions/extensions/k8s/shuffle/Chart.yaml
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/templates/NOTES.txt b/functions/extensions/k8s/shuffle/templates/NOTES.txt
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/templates/_helpers.tpl b/functions/extensions/k8s/shuffle/templates/_helpers.tpl
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/templates/deployment.yaml b/functions/extensions/k8s/shuffle/templates/deployment.yaml
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/templates/hpa.yaml b/functions/extensions/k8s/shuffle/templates/hpa.yaml
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/templates/ingress.yaml b/functions/extensions/k8s/shuffle/templates/ingress.yaml
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/templates/persistent-volume.yaml b/functions/extensions/k8s/shuffle/templates/persistent-volume.yaml
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/templates/persistentvolumeclaim.yaml b/functions/extensions/k8s/shuffle/templates/persistentvolumeclaim.yaml
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/templates/service.yaml b/functions/extensions/k8s/shuffle/templates/service.yaml
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/templates/serviceaccount.yaml b/functions/extensions/k8s/shuffle/templates/serviceaccount.yaml
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/templates/tests/test-connection.yaml b/functions/extensions/k8s/shuffle/templates/tests/test-connection.yaml
old mode 100644
new mode 100755
diff --git a/functions/extensions/k8s/shuffle/values.yaml b/functions/extensions/k8s/shuffle/values.yaml
old mode 100644
new mode 100755
diff --git a/functions/extensions/misp/Dockerfile b/functions/extensions/misp/Dockerfile
old mode 100644
new mode 100755
diff --git a/functions/extensions/misp/docker-compose.yml b/functions/extensions/misp/docker-compose.yml
old mode 100644
new mode 100755
diff --git a/functions/extensions/misp/requirements.txt b/functions/extensions/misp/requirements.txt
old mode 100644
new mode 100755
diff --git a/functions/extensions/misp/sub.py b/functions/extensions/misp/sub.py
old mode 100644
new mode 100755
diff --git a/functions/extensions/scripts/disable_disk_check.sh b/functions/extensions/scripts/disable_disk_check.sh
old mode 100644
new mode 100755
diff --git a/functions/extensions/wazuh/custom-shuffle b/functions/extensions/wazuh/custom-shuffle
old mode 100644
new mode 100755
diff --git a/functions/extensions/wazuh/custom-shuffle.py b/functions/extensions/wazuh/custom-shuffle.py
old mode 100644
new mode 100755
diff --git a/functions/extensions/wazuh/ossec.conf b/functions/extensions/wazuh/ossec.conf
old mode 100644
new mode 100755
diff --git a/functions/onprem/README.md b/functions/onprem/README.md
old mode 100644
new mode 100755
diff --git a/functions/onprem/orborus/Dockerfile b/functions/onprem/orborus/Dockerfile
old mode 100644
new mode 100755
diff --git a/functions/onprem/orborus/build.sh b/functions/onprem/orborus/build.sh
old mode 100644
new mode 100755
diff --git a/functions/onprem/orborus/go.mod b/functions/onprem/orborus/go.mod
old mode 100644
new mode 100755
diff --git a/functions/onprem/orborus/go.sum b/functions/onprem/orborus/go.sum
old mode 100644
new mode 100755
diff --git a/functions/onprem/orborus/orborus.go b/functions/onprem/orborus/orborus.go
old mode 100644
new mode 100755
index eb46a708..ec72b643
--- a/functions/onprem/orborus/orborus.go
+++ b/functions/onprem/orborus/orborus.go
@@ -148,7 +148,7 @@ func deployWorker(image string, identifier string, env []string) {
NetworkMode: container.NetworkMode(fmt.Sprintf("container:%s", containerId)),
}
- if cleanupEnv == "true" {
+ if strings.ToLower(cleanupEnv) == "true" {
hostConfig.AutoRemove = true
}
diff --git a/functions/onprem/orborus/run.sh b/functions/onprem/orborus/run.sh
old mode 100644
new mode 100755
diff --git a/functions/onprem/worker/Dockerfile b/functions/onprem/worker/Dockerfile
old mode 100644
new mode 100755
diff --git a/functions/onprem/worker/build.sh b/functions/onprem/worker/build.sh
old mode 100644
new mode 100755
diff --git a/functions/onprem/worker/go.mod b/functions/onprem/worker/go.mod
old mode 100644
new mode 100755
diff --git a/functions/onprem/worker/go.sum b/functions/onprem/worker/go.sum
old mode 100644
new mode 100755
diff --git a/functions/onprem/worker/run b/functions/onprem/worker/run
old mode 100644
new mode 100755
diff --git a/functions/onprem/worker/worker.go b/functions/onprem/worker/worker.go
old mode 100644
new mode 100755
diff --git a/shuffle-apps/README.md b/shuffle-apps/README.md
old mode 100644
new mode 100755