Merge pull request #545 from Isoporhode/master

Tried some linting
This commit is contained in:
Frikky
2021-10-31 22:21:55 +01:00
committed by GitHub
13 changed files with 106 additions and 2473 deletions
+19
View File
@@ -0,0 +1,19 @@
# Security Policy
## Supported Versions
Shuffle is currently still in beta, but we aim to support older version with critical severity issues, but do advise you to stay up to date with Major versions.
| Version | Supported |
| ------- | ------------------ |
| >=0.9.0 | :white_check_mark: |
| < 0.9.0 | :x: |
## Reporting a Vulnerability
Reporting a vulnerability can either be done to (frikky@shuffler.io)[mailto:frikky@shuffler.io] or [through the contact page on our website](https://shuffler.io/contact)
Security.txt: https://shuffler.io/.well_known/security.txt
When a >medium severity vulnerability is discovered, expect it to be fixed ASAP - please nag us until it is. Security is a top priority, and we expect you to keep us accountable.
In the case it makes sense, we'll further create a security advisory, and publish a new CVE for your new glorious finding.
+1
View File
@@ -16,6 +16,7 @@ docker build . -f Dockerfile -t frikky/shuffle:app_sdk -t frikky/$NAME:$VERSION
docker push frikky/shuffle:app_sdk
docker push ghcr.io/frikky/$NAME:$VERSION
docker push ghcr.io/frikky/$NAME:nightly
docker push ghcr.io/frikky/$NAME:latest
#### BLACKARCH ###
NAME=shuffle-app_sdk_kali
+3 -3
View File
@@ -3084,7 +3084,7 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User) {
basePath, err := shuffle.BuildStructure(swagger, newmd5)
if err != nil {
log.Printf("Failed to build base structure: %s", err)
log.Printf("[WARNING] Failed to build base structure: %s", err)
resp.WriteHeader(500)
resp.Write([]byte(`{"success": false, "reason": "Failed building baseline structure"}`))
return
@@ -3103,7 +3103,7 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User) {
// Can't overwrite existing normal app
workflowApps, err := shuffle.GetPrioritizedApps(ctx, user)
if err != nil {
log.Printf("Failed getting all workflow apps from database to verify: %s", err)
log.Printf("[WARNING] Failed getting all workflow apps from database to verify: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "reason": "Failed to verify existence"}`))
return
@@ -3123,7 +3123,7 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User) {
err = shuffle.DumpApi(basePath, api)
if err != nil {
log.Printf("Failed dumping yaml: %s", err)
log.Printf("[WARNING] Failed dumping yaml: %s", err)
resp.WriteHeader(500)
resp.Write([]byte(`{"success": false, "reason": "Failed dumping yaml"}`))
return
+2 -1
View File
@@ -73,7 +73,8 @@
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"lint": "eslint 'src/**/*.{tsx,ts,js,jsx}'"
},
"eslintConfig": {
"extends": "react-app"
+1 -1
View File
@@ -2320,7 +2320,7 @@ const Admin = (props) => {
:
<Tooltip title={"Go to workflow"} style={{}} aria-label={"Download"}>
<span>
<a style={{textDecoration: "none", color: "#f85a3e"}} href={`/workflows/${file.workflow_id}`} target="_blank">
<a rel="noopener noreferrer" style={{textDecoration: "none", color: "#f85a3e"}} href={`/workflows/${file.workflow_id}`} target="_blank">
<IconButton disabled={file.workflow_id === "global"}>
<OpenInNewIcon style={{color: file.workflow_id !== "global" ? "white" : "grey",}} />
</IconButton>
+19 -19
View File
@@ -3950,7 +3950,7 @@ const AngularWorkflow = (props) => {
return (
<div style={appViewStyle}>
<div style={variableScrollStyle}>
What are <a rel="norefferer" target="_blank" href="https://shuffler.io/docs/workflows#workflow_variables" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>WORKFLOW variables?</a>
What are <a rel="noopener noreferrer" href="https://shuffler.io/docs/workflows#workflow_variables" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>WORKFLOW variables?</a>
{workflow.workflow_variables === null ?
null : workflow.workflow_variables.map((variable, index) => {
return (
@@ -4017,7 +4017,7 @@ const AngularWorkflow = (props) => {
}}>New workflow variable</Button>
</div>
<Divider style={{marginBottom: 20, marginTop: 20, height: 1, width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
What are <a rel="norefferer" target="_blank" href="https://shuffler.io/docs/workflows#execution_variables" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>EXECUTION variables?</a>
What are <a rel="noopener noreferrer" target="_blank" href="https://shuffler.io/docs/workflows#execution_variables" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>EXECUTION variables?</a>
{workflow.execution_variables === null || workflow.execution_variables === undefined ?
null : workflow.execution_variables.map(variable=> {
return (
@@ -5399,7 +5399,7 @@ const AngularWorkflow = (props) => {
}}
>
<span style={{position: "absolute", bottom: 10, left: 10, color: "rgba(255,255,255,0.6)",}}>
Conditions can't be used for loops [ .# ] <a rel="norefferer" target="_blank" href="https://shuffler.io/docs/workflows#conditions" style={{textDecoration: "none", color: "#f85a3e"}}>Learn more</a>
Conditions can't be used for loops [ .# ] <a rel="noopener noreferrer" target="_blank" href="https://shuffler.io/docs/workflows#conditions" style={{textDecoration: "none", color: "#f85a3e"}}>Learn more</a>
</span>
<FormControl>
<DialogTitle><span style={{color:"white"}}>Condition</span>
@@ -5666,7 +5666,7 @@ const AngularWorkflow = (props) => {
<div style={{display: "flex", height: "40px", marginBottom: "30px"}}>
<div style={{flex: "1"}}>
<h3 style={{marginBottom: "5px"}} >Branch: Conditions - {selectedEdgeIndex}</h3>
<a rel="norefferer" target="_blank" href="https://shuffler.io/docs/workflows#conditions" style={{textDecoration: "none", color: "#f85a3e"}}>What are conditions?</a>
<a rel="noopener noreferrer" target="_blank" href="https://shuffler.io/docs/workflows#conditions" style={{textDecoration: "none", color: "#f85a3e"}}>What are conditions?</a>
</div>
</div>
<Divider style={{marginBottom: "10px", marginTop: "10px", height: "1px", width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
@@ -6042,7 +6042,7 @@ const AngularWorkflow = (props) => {
<div style={{display: "flex", height: "40px", marginBottom: "30px"}}>
<div style={{flex: "1"}}>
<h3 style={{marginBottom: "5px"}}>{selectedTrigger.app_name}: {selectedTrigger.status}</h3>
<a rel="norefferer" target="_blank" href="https://shuffler.io/docs/triggers#email" style={{textDecoration: "none", color: "#f85a3e"}}>What are email triggers?</a>
<a rel="noopener noreferrer" target="_blank" href="https://shuffler.io/docs/triggers#email" style={{textDecoration: "none", color: "#f85a3e"}}>What are email triggers?</a>
</div>
</div>
<Divider style={{marginBottom: "10px", marginTop: "10px", height: "1px", width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
@@ -6435,7 +6435,7 @@ const AngularWorkflow = (props) => {
<div style={{display: "flex", height: "40px", marginBottom: "30px"}}>
<div style={{flex: "1"}}>
<h3 style={{marginBottom: "5px"}}>{selectedTrigger.app_name}</h3>
<a rel="norefferer" target="_blank" href="https://shuffler.io/docs/triggers#subflow" style={{textDecoration: "none", color: "#f85a3e"}}>What are subflows?</a>
<a rel="noopener noreferrer" target="_blank" href="https://shuffler.io/docs/triggers#subflow" style={{textDecoration: "none", color: "#f85a3e"}}>What are subflows?</a>
</div>
</div>
<Divider style={{marginBottom: "10px", marginTop: "10px", height: "1px", width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
@@ -6549,7 +6549,7 @@ const AngularWorkflow = (props) => {
}
{workflow.triggers[selectedTriggerIndex].parameters[0].value.length === 0 ? null :
workflow.triggers[selectedTriggerIndex].parameters[0].value === props.match.params.key ? null :
<span style={{marginTop: 5}}><a rel="norefferer" href={`/workflows/${workflow.triggers[selectedTriggerIndex].parameters[0].value}`} target="_blank" style={{textDecoration: "none", color: "#f85a3e", marginLeft: 5,}}>Explore selected workflow</a></span>
<span style={{marginTop: 5}}><a rel="noopener noreferrer" href={`/workflows/${workflow.triggers[selectedTriggerIndex].parameters[0].value}`} target="_blank" style={{textDecoration: "none", color: "#f85a3e", marginLeft: 5,}}>Explore selected workflow</a></span>
}
{subworkflow === undefined || subworkflow === null || subworkflow.id === undefined || subworkflow.actions === null || subworkflow.actions === undefined || subworkflow.actions.length === 0 ? null :
@@ -6757,7 +6757,7 @@ const AngularWorkflow = (props) => {
<div style={{display: "flex", height: "40px", marginBottom: "30px"}}>
<div style={{flex: "1"}}>
<h3 style={{marginBottom: "5px"}}>{selectedTrigger.app_name}: {selectedTrigger.status}</h3>
<a rel="norefferer" target="_blank" href="https://shuffler.io/docs/triggers#webhook" style={{textDecoration: "none", color: "#f85a3e"}}>What are webhooks?</a>
<a rel="noopener noreferrer" target="_blank" href="https://shuffler.io/docs/triggers#webhook" style={{textDecoration: "none", color: "#f85a3e"}}>What are webhooks?</a>
</div>
</div>
<Divider style={{marginBottom: "10px", marginTop: "10px", height: "1px", width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
@@ -7202,7 +7202,7 @@ const AngularWorkflow = (props) => {
<div style={{display: "flex", height: "40px", marginBottom: "30px"}}>
<div style={{flex: "1"}}>
<h3 style={{marginBottom: "5px"}}>{selectedTrigger.app_name}: {selectedTrigger.status}</h3>
<a rel="norefferer" target="_blank" href="https://shuffler.io/docs/triggers#user_input" style={{textDecoration: "none", color: "#f85a3e"}}>What is the user input trigger?</a>
<a rel="noopener noreferrer" target="_blank" href="https://shuffler.io/docs/triggers#user_input" style={{textDecoration: "none", color: "#f85a3e"}}>What is the user input trigger?</a>
</div>
</div>
<Divider style={{marginBottom: "10px", marginTop: "10px", height: "1px", width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
@@ -7380,7 +7380,7 @@ const AngularWorkflow = (props) => {
<div style={{display: "flex", height: "40px", marginBottom: "30px"}}>
<div style={{flex: "1"}}>
<h3 style={{marginBottom: "5px"}}>{selectedTrigger.app_name}: {selectedTrigger.status}</h3>
<a rel="norefferer" target="_blank" href="https://shuffler.io/docs/triggers#schedule" style={{textDecoration: "none", color: "#f85a3e"}}>What are schedules?</a>
<a rel="noopener noreferrer" target="_blank" href="https://shuffler.io/docs/triggers#schedule" style={{textDecoration: "none", color: "#f85a3e"}}>What are schedules?</a>
</div>
</div>
<Divider style={{marginBottom: "10px", marginTop: "10px", height: "1px", width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
@@ -8299,7 +8299,7 @@ const AngularWorkflow = (props) => {
</span>
:
<a rel="norefferer" href={`/workflows/${executionData.execution_source}?view=executions&execution_id=${executionData.execution_parent}`} target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>Parent Workflow</a>
<a rel="noopener noreferrer" href={`/workflows/${executionData.execution_source}?view=executions&execution_id=${executionData.execution_parent}`} target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>Parent Workflow</a>
:
executionData.execution_source
}
@@ -8476,7 +8476,7 @@ const AngularWorkflow = (props) => {
See sub-execution
</span>
:
<a rel="norefferer" href={`/workflows/${data.action.parameters[0].value}?view=executions&execution_id=${validate.result.execution_id}`} target="_blank" style={{textDecoration: "none", color: "#f85a3e"}} onClick={(event) => {
<a rel="noopener noreferrer" href={`/workflows/${data.action.parameters[0].value}?view=executions&execution_id=${validate.result.execution_id}`} target="_blank" style={{textDecoration: "none", color: "#f85a3e"}} onClick={(event) => {
}}>
<OpenInNewIcon />
</a>
@@ -8862,7 +8862,7 @@ const AngularWorkflow = (props) => {
<FormControl>
<DialogTitle><span style={{color: "white"}}>Execution Variable</span></DialogTitle>
<DialogContent>
Execution Variables are TEMPORARY variables that you can ony be set and used during execution. Learn more <a rel="norefferer" href="https://shuffler.io/docs/workflows#execution_variables" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>here</a>
Execution Variables are TEMPORARY variables that you can ony be set and used during execution. Learn more <a rel="noopener noreferrer" href="https://shuffler.io/docs/workflows#execution_variables" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>here</a>
<TextField
onBlur={(event) => setNewVariableName(event.target.value)}
color="primary"
@@ -9168,7 +9168,7 @@ const AngularWorkflow = (props) => {
<div>
<DialogTitle><div style={{color: "white"}}>Authentication for {selectedApp.name}</div></DialogTitle>
<DialogContent>
<a target="_blank" rel="norefferer" href="https://shuffler.io/docs/apps#authentication" style={{textDecoration: "none", color: "#f85a3e"}}>What is app authentication?</a><div/>
<a rel="noopener noreferrer" target="_blank" href="https://shuffler.io/docs/apps#authentication" style={{textDecoration: "none", color: "#f85a3e"}}>What is app authentication?</a><div/>
These are required fields for authenticating with {selectedApp.name}
<div style={{marginTop: 15}}/>
<b>Name - what is this used for?</b>
@@ -9354,11 +9354,11 @@ const AngularWorkflow = (props) => {
>
<div style={{zIndex: 5000, position: "absolute", top: 20, right: 54, height: 50, width: 50,}}>
{selectedApp.reference_info === undefined || selectedApp.reference_info === null || selectedApp.reference_info.github_url === undefined || selectedApp.reference_info.github_url === null || selectedApp.reference_info.github_url.length === 0 ?
<a rel="norefferer" target="_blank" href={"https://github.com/frikky/shuffle-apps"} style={{textDecoration: "none", color: "#f86a3e"}}>
<a rel="noopener noreferrer" target="_blank" href={"https://github.com/frikky/shuffle-apps"} style={{textDecoration: "none", color: "#f86a3e"}}>
<img alt={`Documentation image for ${selectedApp.name}`} src={selectedApp.large_image} style={{width: 30, height: 30, border: "2px solid rgba(255,255,255,0.6)", borderRadius: theme.palette.borderRadius, maxHeight: 30, maxWidth: 30, overflow: "hidden", fontSize: 8, }} />
</a>
:
<a rel="norefferer" target="_blank" href={selectedApp.reference_info.github_url} style={{textDecoration: "none", color: "#f86a3e"}}>
<a rel="noopener noreferrer" target="_blank" href={selectedApp.reference_info.github_url} style={{textDecoration: "none", color: "#f86a3e"}}>
<img alt={`Documentation image for ${selectedApp.name}`} src={selectedApp.large_image} style={{width: 30, height: 30, border: "2px solid rgba(255,255,255,0.6)", borderRadius: theme.palette.borderRadius, maxWidth: 30, maxHeight: 30, overflow: "hidden", fontSize: 8,}} />
</a>
}
@@ -9390,7 +9390,7 @@ const AngularWorkflow = (props) => {
There is currently no extended documentation available for this app.
</Typography>
<Typography variant="body1" style={{marginTop: 25}}>
Want help with this app? <a rel="norefferer" target="_blank" href="https://discord.gg/B2CBzUm" style={{textDecoration: "none", color: "#f86a3e"}}>Join the Discord!</a>
Want help with this app? <a rel="noopener noreferrer" target="_blank" href="https://discord.gg/B2CBzUm" style={{textDecoration: "none", color: "#f86a3e"}}>Join the Discord!</a>
</Typography>
<Typography variant="h6" style={{marginTop: 50,}}>
@@ -9399,13 +9399,13 @@ const AngularWorkflow = (props) => {
{selectedApp.reference_info === undefined || selectedApp.reference_info === null || selectedApp.reference_info.github_url === undefined || selectedApp.reference_info.github_url === null || selectedApp.reference_info.github_url.length === 0 ?
<span>
<Typography variant="body1" style={{marginTop: 25}}>
<a rel="norefferer" target="_blank" href={"https://github.com/frikky/shuffle-apps"} style={{textDecoration: "none", color: "#f86a3e"}}>Check it out on Github!</a>
<a rel="noopener noreferrer" target="_blank" href={"https://github.com/frikky/shuffle-apps"} style={{textDecoration: "none", color: "#f86a3e"}}>Check it out on Github!</a>
</Typography>
</span>
:
<span>
<Typography variant="body1" style={{marginTop: 25}}>
<a rel="norefferer" target="_blank" href={selectedApp.reference_info.github_url} style={{textDecoration: "none", color: "#f86a3e"}}>Check it out on Github!</a>
<a rel="noopener noreferrer" target="_blank" href={selectedApp.reference_info.github_url} style={{textDecoration: "none", color: "#f86a3e"}}>Check it out on Github!</a>
</Typography>
</span>
}
+7 -1
View File
@@ -426,10 +426,16 @@ const AppCreator = (props) => {
return newitem
}
const base64_decode = (str) => {
return decodeURIComponent(atob(str).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''))
}
// Sets the data up as it should be at later points
// This is the data FROM the database, not what's being saved
const parseIncomingOpenapiData = (data) => {
const parsedapp = data.openapi === undefined ? data : JSON.parse(atob(data.openapi))
const parsedapp = data.openapi === undefined ? data : JSON.parse(base64_decode(data.openapi))
data = parsedapp.body === undefined ? parsedapp : parsedapp.body
var jsonvalid = false
+6 -6
View File
@@ -695,7 +695,7 @@ const Apps = (props) => {
</Select>
: null }
{isCloud ?
<a href={"https://shuffler.io/apps/"+selectedApp.id} style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">
<a rel="noopener noreferrer" href={"https://shuffler.io/apps/"+selectedApp.id} style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">
<IconButton style={{top: -10, right: 0, position: "absolute", color: "#f85a3e"}} >
<OpenInNewIcon style={{}} />
</IconButton>
@@ -848,10 +848,10 @@ const Apps = (props) => {
<Paper square style={uploadViewPaperStyle}>
<div style={{width: "100%", margin: 25}}>
<h2>App Creator</h2>
<a href="https://shuffler.io/docs/apps" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">How it works</a>
&nbsp;- <a href="https://github.com/frikky/security-openapis" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">Security API's</a>
&nbsp;- <a href="https://github.com/APIs-guru/openapi-directory/tree/main/APIs" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">OpenAPI directory</a>
&nbsp;- <a href="https://editor.swagger.io/" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">OpenAPI Validator</a>
<a rel="noopener noreferrer" href="https://shuffler.io/docs/apps" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">How it works</a>
&nbsp;- <a rel="noopener noreferrer" href="https://github.com/frikky/security-openapis" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">Security API's</a>
&nbsp;- <a rel="noopener noreferrer" href="https://github.com/APIs-guru/openapi-directory/tree/main/APIs" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">OpenAPI directory</a>
&nbsp;- <a rel="noopener noreferrer" href="https://editor.swagger.io/" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">OpenAPI Validator</a>
<div/>
<Typography variant="body2" color="textSecondary">
Apps interact with eachother in workflows. They are created with the app creator, using OpenAPI specification or manually in python. The links above are references to OpenAPI tools and other app repositories. There's thousands of them.
@@ -1061,7 +1061,7 @@ const Apps = (props) => {
<Paper square style={uploadViewPaperStyle}>
<Typography style={{margin: 10, }}>
<span>
<a href={"https://shuffler.io/search"} style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">
<a rel="noopener noreferrer" href={"https://shuffler.io/search"} style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">
Click here
</a> to search ALL apps, not just your activated ones.
</span>
+2 -2
View File
@@ -304,7 +304,7 @@ const Docs = (props) => {
<div style={{flex: 3, display: "flex", vAlign: "center",}}>
{mobile ? null :
<Typography style={{display: "inline", marginTop: 6, }}>
<a rel="norefferer" target="_blank" href={selectedMeta.link} target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>
<a rel="noopener noreferrer" target="_blank" href={selectedMeta.link} target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>
<Button style={{}} variant="outlined">
<EditIcon /> &nbsp;&nbsp;Edit
</Button>
@@ -323,7 +323,7 @@ const Docs = (props) => {
<div style={{margin: 10, height: "100%", display: "inline",}}>
{selectedMeta.contributors.slice(0,7).map((data, index) => {
return (
<a rel="norefferer" target="_blank" href={data.url} target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>
<a rel="noopener noreferrer" target="_blank" href={data.url} target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>
<Tooltip title={data.url} placement="bottom">
<img alt={data.url} src={data.image} style={{marginTop: 5, marginRight: 10, height: 40, borderRadius: 40, }} />
</Tooltip>
+46 -235
View File
@@ -1,15 +1,15 @@
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 {Badge, 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';
//https://next.material-ui.com/components/material-icons/
import {DataGrid, GridToolbarContainer, GridDensitySelector, GridToolbar} from '@material-ui/data-grid';
import {DataGrid, GridToolbar} from '@material-ui/data-grid';
//import JSONPretty from 'react-json-pretty';
//import JSONPrettyMon from 'react-json-pretty/dist/monikai'
@@ -19,33 +19,14 @@ import {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 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 useStyles = makeStyles((theme) => ({
datagrid: {
@@ -258,42 +239,22 @@ export const GetIconInfo = (action) => {
console.log(`MISSING PATH FOR ${selectedKey} (find in scope): `, selectedItem.originalIcon.type.type)
}
if (selectedItem.originalIcon === undefined || selectedItem.originalIcon === "" && (selectedItem.icon !== "" && selectedItem.icon !== undefined)) {
if ((selectedItem.originalIcon === undefined || selectedItem.originalIcon === "") && (selectedItem.icon !== "" && selectedItem.icon !== undefined)) {
const svg_pin = <svg width={svgSize} height={svgSize} viewBox={`0 0 ${svgSize} ${svgSize}`} version="1.1" xmlns="http://www.w3.org/2000/svg"><path d={selectedItem.icon} fill={selectedItem.iconColor}></path></svg>
//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",
backgroundColor: "#3d3f43", 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\"")
@@ -302,15 +263,13 @@ export const validateJson = (showResult) => {
var jsonvalid = true
try {
const tmp = String(JSON.parse(showResult))
if (!showResult.includes("{") && !showResult.includes("[")) {
jsonvalid = false
}
} catch (e) {
showResult = showResult.split("\'").join("\"")
showResult = showResult.split("'").join("\"")
try {
const tmp = String(JSON.parse(showResult))
if (!showResult.includes("{") && !showResult.includes("[")) {
jsonvalid = false
}
@@ -328,7 +287,7 @@ export const validateJson = (showResult) => {
}
const Workflows = (props) => {
const { globalUrl, isLoggedIn, isLoaded, removeCookie, cookies, userdata} = props;
const { globalUrl, isLoggedIn, isLoaded, userdata} = props;
document.title = "Shuffle - Workflows"
const theme = useTheme();
const alert = useAlert()
@@ -338,19 +297,14 @@ const Workflows = (props) => {
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")
@@ -364,14 +318,11 @@ const Workflows = (props) => {
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")
@@ -422,8 +373,6 @@ const Workflows = (props) => {
})
}
//console.log("FOUND: ", found)
//if (found) {
if (found.every(v => v === true)) {
newWorkflows.push(curWorkflow)
continue
@@ -463,9 +412,7 @@ const Workflows = (props) => {
}
//console.log("Removing filter index", index)
newfilters.splice(index, 1)
//console.log("FILTER LENGTH: ", filters.length)
if (newfilters.length === 0) {
newfilters = []
@@ -473,7 +420,6 @@ const Workflows = (props) => {
} else {
setFilters(newfilters)
}
//console.log("FILTERS: ", newfilters)
findWorkflow(newfilters)
}
@@ -625,14 +571,14 @@ const Workflows = (props) => {
}
// Initialize the workflow itself
const ret = setNewWorkflow(data.name, data.description, data.tags, data.default_return_value, {}, false)
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)
setNewWorkflow(data.name, data.description, data.tags, data.default_return_value, data, false)
.then((response) => {
if (response !== undefined) {
alert.success(`Successfully imported ${data.name}`)
@@ -653,10 +599,10 @@ const Workflows = (props) => {
useEffect(() => {
if (isDropzone) {
//redirectOpenApi();
setIsDropzone(false);
}
}, [isDropzone]);
const getAvailableWorkflows = () => {
fetch(globalUrl+"/api/v1/workflows", {
@@ -683,9 +629,6 @@ const Workflows = (props) => {
return response.json()
})
.then((responseJson) => {
setSelectedExecution({})
setWorkflowExecutions([])
//console.log(responseJson)
if (responseJson !== undefined) {
setWorkflows(responseJson)
@@ -720,16 +663,14 @@ const Workflows = (props) => {
return
}
if (responseJson.length > 0){
//setSelectedWorkflow(responseJson[0])
//getWorkflowExecution(responseJson[0].id)
}
})
.catch(error => {
alert.error(error.toString())
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => {
if (workflows.length <= 0 && firstrequest) {
const tmpView = localStorage.getItem('view');
@@ -740,7 +681,7 @@ const Workflows = (props) => {
setFirstrequest(false)
getAvailableWorkflows()
}
})
})
const viewStyle = {
color: "#ffffff",
@@ -749,7 +690,6 @@ const Workflows = (props) => {
minWidth: 1024,
maxWidth: 1024,
margin: "auto",
/*maxHeight: "90vh",*/
}
const emptyWorkflowStyle = {
@@ -769,14 +709,6 @@ const Workflows = (props) => {
}
const scrollStyle = {
marginTop: "10px",
overflow: "scroll",
height: "90%",
overflowX: "hidden",
overflowY: "auto",
}
const paperAppContainer = {
display: "flex",
flexWrap: 'wrap',
@@ -813,38 +745,6 @@ const Workflows = (props) => {
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)
}
})
.catch(error => {
alert.error(error.toString())
});
}
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
const exportAllWorkflows = () => {
for (var key in workflows) {
exportWorkflow(workflows[key], false)
@@ -861,13 +761,12 @@ const Workflows = (props) => {
}
}
if (trigger.status == "running") {
if (trigger.status === "running") {
trigger.status = "stopped"
}
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
@@ -897,7 +796,7 @@ const Workflows = (props) => {
}
if (data.actions !== null && data.actions !== undefined) {
for (var key in data.actions) {
for (key in data.actions) {
data.actions[key].authentication_id = ""
for (var subkey in data.actions[key].parameters) {
@@ -914,7 +813,7 @@ const Workflows = (props) => {
}
const newId = uuidv4()
for (var branchkey in data.branches) {
for ( branchkey in data.branches) {
const branch = data.branches[branchkey]
if (branch.source_id === data.actions[key].id) {
branch.source_id = newId
@@ -929,14 +828,13 @@ const Workflows = (props) => {
data.start = newId
}
//data.actions[key].environment = isCloud ? "cloud" : "Shuffle"
data.actions[key].environment = ""
data.actions[key].id = newId
}
}
if (data.workflow_variables !== null && data.workflow_variables !== undefined) {
for (var key in data.workflow_variables) {
for (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 = ""
@@ -983,7 +881,6 @@ const Workflows = (props) => {
// }
//}
}
//return
// Add correct ID's for triggers
// Add mag
@@ -1042,8 +939,7 @@ const Workflows = (props) => {
data.id = ""
data.name = data.name+"_copy"
data = deduplicateIds(data)
//console.log("COPIED DATA: ", data)
//return
fetch(globalUrl+"/api/v1/workflows", {
method: 'POST',
@@ -1061,7 +957,7 @@ const Workflows = (props) => {
}
return response.json()
})
.then((responseJson) => {
.then(() => {
setTimeout(() => {
getAvailableWorkflows()
}, 1000)
@@ -1091,7 +987,7 @@ const Workflows = (props) => {
return response.json()
})
.then((responseJson) => {
.then(() => {
setTimeout(() => {
getAvailableWorkflows()
}, 1000)
@@ -1107,7 +1003,7 @@ const Workflows = (props) => {
}
const NewWorkflowPaper = (props) => {
const NewWorkflowPaper = () => {
const [hover, setHover] = React.useState(false)
const innerColor = "rgba(255,255,255,0.3)"
@@ -1143,10 +1039,7 @@ const Workflows = (props) => {
const [open, setOpen] = React.useState(false);
const [anchorEl, setAnchorEl] = React.useState(null);
var boxWidth = "2px"
if (selectedWorkflow.id === data.id) {
boxWidth = "4px"
}
var boxColor = "#FECC00"
if (data.is_valid) {
@@ -1168,8 +1061,7 @@ const Workflows = (props) => {
}
const actions = data.actions !== null ? data.actions.length : 0
const [triggers, schedules, webhooks, subflows] = getWorkflowMeta(data)
const [triggers, subflows] = getWorkflowMeta(data)
const workflowMenuButtons = <Menu
id="long-menu"
@@ -1182,7 +1074,6 @@ const Workflows = (props) => {
}}
>
<MenuItem style={{backgroundColor: inputColor, color: "white"}} onClick={() => {
//console.log("DATA:" ,data)
setModalOpen(true)
setEditingWorkflow(data)
setNewWorkflowName(data.name)
@@ -1271,14 +1162,20 @@ const Workflows = (props) => {
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", marginRight: 10, 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, }
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 }
//<Tooltip title={`Org: ${foundOrg.name}`} placement="bottom">
image = foundOrg.image === "" ?
<img alt={foundOrg.name} src={theme.palette.defaultImage} style={imageStyle} />
:
<img alt={foundOrg.name} src={foundOrg.image} style={imageStyle} onClick={() => {
//setFilteredWorkflows(newWorkflows)
}}/>
orgName = foundOrg.name
@@ -1295,8 +1192,6 @@ const Workflows = (props) => {
<Tooltip title={`Org "${orgName}"`} placement="bottom">
<div styl={{cursor: "pointer"}} onClick={() => {
addFilter(orgId)
//setFilters(["Org "+orgName])
//setFilteredWorkflows(newWorkflows)
}}>
{image}
</div>
@@ -1360,20 +1255,6 @@ const Workflows = (props) => {
</Typography>
</span>
</Tooltip>
{/*
<Tooltip color="primary" title={`Actions: ${data.actions.length}`} placement="bottom">
<AppsIcon />
</Tooltip>
<Tooltip color="primary" title={`Webhooks: ${webhooks}`} placement="bottom">
<RestoreIcon />
</Tooltip>
: null}
{schedules > 0 ?
<Tooltip color="primary" title={`Schedules: ${schedules}`} placement="bottom">
<RestoreIcon />
</Tooltip>
: null}
*/}
</Grid>
<Grid item style={{justifyContent: "left", overflow: "hidden", marginTop: 5,}}>
{data.tags !== undefined ?
@@ -1404,23 +1285,13 @@ const Workflows = (props) => {
aria-label="more"
aria-controls="long-menu"
aria-haspopup="true"
style={{color: "white"}}
onClick={menuClick}
style={{padding:"0px",color:"white", color:"#979797"}}
style={{padding:"0px", color:"#979797"}}
>
<MoreVertIcon />
</IconButton>
{workflowMenuButtons}
</Grid>
{/*
<Grid>
<Link to={"/workflows/"+data.id}>
<Tooltip title="Edit workflow" placement="bottom">
<EditIcon style={{borderRadius: "4px", color: "#F85A3E", height: 20, width: 20, padding: 7, fontSize: "small"}} />
</Tooltip>
</Link>
</Grid>
*/}
</Grid>
: null}
</Paper>
@@ -1430,29 +1301,6 @@ const Workflows = (props) => {
const dividerColor = "rgb(225, 228, 232)"
const resultPaperAppStyle = {
minHeight: "100px",
minWidth: "100%",
overflow: "hidden",
maxWidth: "100%",
marginTop: "5px",
color: "white",
backgroundColor: surfaceColor,
cursor: "pointer",
display: "flex",
}
function replaceAll(string, search, replace) {
return string.split(search).join(replace);
}
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) => {
@@ -1480,11 +1328,9 @@ const Workflows = (props) => {
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,
@@ -1535,7 +1381,6 @@ const Workflows = (props) => {
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]
@@ -1560,7 +1405,7 @@ const Workflows = (props) => {
}
// Initialize the workflow itself
const ret = setNewWorkflow(data.name, data.description, data.tags, data.default_return_value, {}, false)
setNewWorkflow(data.name, data.description, data.tags, data.default_return_value, {}, false)
.then((response) => {
if (response !== undefined) {
// SET THE FULL THING
@@ -1570,7 +1415,7 @@ const Workflows = (props) => {
data.is_valid = false
// Actually create it
const ret = setNewWorkflow(data.name, data.description, data.tags, data.default_return_value, data, false)
setNewWorkflow(data.name, data.description, data.tags, data.default_return_value, data, false)
.then((response) => {
if (response !== undefined) {
alert.success("Successfully imported "+data.name)
@@ -1593,26 +1438,17 @@ const Workflows = (props) => {
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) {
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") {
if (data.triggers[key].app_name === "Shuffle Workflow") {
subflows += 1
}
}
}
return [triggers, schedules, webhooks, subflows]
return [triggers, subflows]
}
const WorkflowListView = () => {
@@ -1632,8 +1468,6 @@ const Workflows = (props) => {
}
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) {
@@ -1648,17 +1482,11 @@ const Workflows = (props) => {
//setFilteredWorkflows(newWorkflows)
}}/>
orgName = foundOrg.name
orgId = foundOrg.id
}
}
return (
<div styl={{cursor: "pointer"}} onClick={() => {
//addFilter(orgId)
//setFilters(["Org "+orgName])
//setFilteredWorkflows(newWorkflows)
}}>
<div styl={{cursor: "pointer"}} >
{image}
</div>
)
@@ -1676,21 +1504,13 @@ const Workflows = (props) => {
</Grid>
)
}},
{/* field: 'category', headerName: 'category', width: 140, renderCell: (params) => {
const data = params.row.record
const category = data.category === undefined ? "not defined" : data.category
return (
<Typography>
{category}
</Typography>
)
} */},
{ 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);
let [triggers, subflows] = getWorkflowMeta(data);
return (
<Grid item>
@@ -1889,10 +1709,9 @@ const Workflows = (props) => {
onDelete={(chip, index) => {
newWorkflowTags.splice(index, 1)
setNewWorkflowTags(newWorkflowTags)
setUpdate("delete "+chip)
}}
/>
{showExtraOptions ?
<TextField
onBlur={(event) => setDefaultReturnValue(event.target.value)}
InputProps={{
@@ -1908,7 +1727,7 @@ const Workflows = (props) => {
margin="dense"
fullWidth
/>
: null}
</DialogContent>
<DialogActions>
<Button style={{}} onClick={() => {
@@ -1967,11 +1786,7 @@ const Workflows = (props) => {
const workflowButtons =
<span>
{/*workflows.length > 0 ?
<Tooltip color="primary" title={"Create new workflow"} placement="top">
<Button color="primary" style={{}} variant="text" onClick={() => setModalOpen(true)}><AddIcon /></Button>
</Tooltip>
: null*/}
{view === "list" && (
<Tooltip color="primary" title={"Grid View"} placement="top">
<Button color="primary" variant="text" onClick={() => {
@@ -2056,7 +1871,6 @@ const Workflows = (props) => {
<h2>Workflows</h2>
</div>
</div>
{/*
<div style={flexContainerStyle}>
<div style={{...flexBoxStyle, ...activeWorkflowStyle}}>
@@ -2107,7 +1921,7 @@ const Workflows = (props) => {
<div style={{display: "flex", margin: "0px 0px 20px 0px"}}>
<div style={{flex: 1}}>
<Typography style={{marginTop: 7, marginBottom: "auto"}}>
<a rel="norefferer" target="_blank" href="https://shuffler.io/docs/workflows" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>Learn more about Workflows</a>
<a rel="noopener noreferrer" href="https://shuffler.io/docs/workflows" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>Learn more about Workflows</a>
</Typography>
</div>
<div style={{flex: 1, float: "right",}}>
@@ -2116,7 +1930,6 @@ const Workflows = (props) => {
InputProps={{
style:{
color: "white",
//backgroundColor: inputColor,
},
}}
placeholder="Add Filter"
@@ -2126,7 +1939,7 @@ const Workflows = (props) => {
onAdd={(chip) => {
addFilter(chip)
}}
onDelete={(chip, index) => {
onDelete={(_, index) => {
removeFilter(index)
}}
/>
@@ -2202,7 +2015,6 @@ const Workflows = (props) => {
}
alert.success("Getting specific workflows from your URL.")
var cors = "cors"
fetch(globalUrl+"/api/v1/workflows/download_remote", {
method: "POST",
mode: "cors",
@@ -2223,7 +2035,6 @@ const Workflows = (props) => {
return response.json()
})
.then((responseJson) => {
//console.log("DATA: ", responseJson)
if (!responseJson.success) {
if (responseJson.reason !== undefined) {
alert.error("Failed loading: "+responseJson.reason)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff