diff --git a/frontend/src/components/AppFramework.jsx b/frontend/src/components/AppFramework.jsx index 54fb6869..e562a159 100644 --- a/frontend/src/components/AppFramework.jsx +++ b/frontend/src/components/AppFramework.jsx @@ -23,13 +23,16 @@ import { Dialog, Chip, Avatar, +} from "@material-ui/core"; + +import { Button -} from "@mui/material"; +} from '@material-ui/core'; import { Close as CloseIcon, Delete as DeleteIcon, -} from "@mui/icons-material"; +} from "@material-ui/icons"; import * as edgehandles from "cytoscape-edgehandles"; import * as cytoscape from "cytoscape"; @@ -1856,6 +1859,7 @@ const AppFramework = (props) => { //autounselectify={true} var usecasediff = -100 const bgColor = color === undefined || color === null || color.length === 0 ? theme.palette.surfaceColor : color + console.log("Background: ", bgColor) return (
@@ -1996,7 +2000,7 @@ const AppFramework = (props) => { {paperTitle.length > 0 ? - {paperTitle} + {paperTitle.replace("_", " ", -1)} diff --git a/frontend/src/components/Appsearch.jsx b/frontend/src/components/Appsearch.jsx index 5defd0f0..40af3e48 100644 --- a/frontend/src/components/Appsearch.jsx +++ b/frontend/src/components/Appsearch.jsx @@ -1,14 +1,14 @@ import React, { useState, useEffect } from 'react'; -import theme from '../theme.jsx'; import ReactGA from 'react-ga4'; +import { useTheme } from '@material-ui/core/styles'; import {Link} from 'react-router-dom'; import { useAlert } from "react-alert"; -import { Search as SearchIcon, CloudQueue as CloudQueueIcon, Code as CodeIcon } from '@mui/icons-material'; +import { Search as SearchIcon, CloudQueue as CloudQueueIcon, Code as CodeIcon } from '@material-ui/icons'; //import algoliasearch from 'algoliasearch/lite'; import algoliasearch from 'algoliasearch'; import { InstantSearch, connectSearchBox, connectHits } from 'react-instantsearch-dom'; -import { Grid, Paper, TextField, ButtonBase, InputAdornment, Typography, Button, Tooltip} from '@mui/material'; +import { Grid, Paper, TextField, ButtonBase, InputAdornment, Typography, Button, Tooltip} from '@material-ui/core'; import aa from 'search-insights' const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240") const Appsearch = props => { @@ -18,6 +18,7 @@ const Appsearch = props => { const alert = useAlert(); const rowHandler = maxRows === undefined || maxRows === null ? 50 : maxRows const xs = parsedXs === undefined || parsedXs === null ? 12 : parsedXs + const theme = useTheme(); //const [apps, setApps] = React.useState([]); //const [filteredApps, setFilteredApps] = React.useState([]); const [formMail, setFormMail] = React.useState(""); @@ -69,43 +70,6 @@ const Appsearch = props => { console.log(error); }); }; - const submitContact = (email, message) => { - const data = { - "firstname": "", - "lastname": "", - "title": "", - "companyname": "", - "email": email, - "phone": "", - "message": message, - } - - const errorMessage = "Something went wrong. Please contact frikky@shuffler.io directly." - - fetch(globalUrl+"/api/v1/contact", { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(data), - }) - .then(response => response.json()) - .then(response => { - if (response.success === true) { - setFormMessage(response.reason) - //alert.info("Thanks for submitting!") - } else { - setFormMessage(errorMessage) - } - - setFormMail("") - setMessage("") - }) - .catch(error => { - setFormMessage(errorMessage) - console.log(error) - }); - } // value={currentRefinement} const SearchBox = ({currentRefinement, refine, isSearchStalled} ) => { diff --git a/frontend/src/components/EditWorkflow.jsx b/frontend/src/components/EditWorkflow.jsx index 5e8b0493..f4a2b6e0 100644 --- a/frontend/src/components/EditWorkflow.jsx +++ b/frontend/src/components/EditWorkflow.jsx @@ -3,6 +3,7 @@ import theme from '../theme.jsx'; import { isMobile } from "react-device-detect" import ChipInput from "material-ui-chip-input"; import UsecaseSearch from "../components/UsecaseSearch.jsx" +import dayjs from 'dayjs'; import { Badge, @@ -37,28 +38,35 @@ import { FormControl, FormLabel, -} from "@mui/material"; +} from "@material-ui/core"; + +import { + DatePicker, + LocalizationProvider, +} from '@mui/x-date-pickers' + +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs' import { ExpandLess as ExpandLessIcon, ExpandMore as ExpandMoreIcon, Publish as PublishIcon, OpenInNew as OpenInNewIcon, -} from "@mui/icons-material"; +} from "@material-ui/icons"; const EditWorkflow = (props) => { const { globalUrl, workflow, setWorkflow, modalOpen, setModalOpen, showUpload, usecases, setNewWorkflow, appFramework, isEditing, userdata, } = props + const [_, setUpdate] = React.useState(""); // Used for rendering, don't remove const [submitLoading, setSubmitLoading] = React.useState(false); const [showMoreClicked, setShowMoreClicked] = React.useState(false); const [innerWorkflow, setInnerWorkflow] = React.useState(workflow) - const [_, setUpdate] = React.useState(""); // Used for rendering, don't remove const [newWorkflowTags, setNewWorkflowTags] = React.useState(workflow.tags !== undefined && workflow.tags !== null ? JSON.parse(JSON.stringify(workflow.tags)) : []) const [selectedUsecases, setSelectedUsecases] = React.useState(workflow.usecase_ids !== undefined && workflow.usecase_ids !== null ? JSON.parse(JSON.stringify(workflow.usecase_ids)) : []); const [foundWorkflowId, setFoundWorkflowId] = React.useState("") const [name, setName] = React.useState(workflow.name !== undefined ? workflow.name : "") const [description, setDescription] = React.useState(workflow.description !== undefined ? workflow.description : "") - + const [dueDate, setDueDate] = React.useState(workflow.due_date !== undefined && workflow.due_date !== null && workflow.due_date !== 0 ? dayjs(workflow.due_date*1000) : dayjs().subtract(1, 'day')) // Gets the generated workflow const getGeneratedWorkflow = (workflow_id) => { @@ -231,24 +239,26 @@ const EditWorkflow = (props) => { autoFocus fullWidth /> - { - setDescription(event.target.value) - }} - InputProps={{ - style: { - color: "white", - }, - }} - maxRows={4} - color="primary" - defaultValue={innerWorkflow.description} - placeholder="Description" - multiline - label="Description" - margin="dense" - fullWidth - /> +
+ { + setDescription(event.target.value) + }} + InputProps={{ + style: { + color: "white", + }, + }} + maxRows={4} + color="primary" + defaultValue={innerWorkflow.description} + placeholder="Description" + multiline + label="Description" + margin="dense" + fullWidth + /> +
{ setNewWorkflowTags(newWorkflowTags); }} onDelete={(chip, index) => { + console.log("Deleting: ", chip, index) newWorkflowTags.splice(index, 1); setNewWorkflowTags(newWorkflowTags); + setUpdate(Math.random()); }} /> {usecases !== null && usecases !== undefined && usecases.length > 0 ? @@ -328,26 +340,41 @@ const EditWorkflow = (props) => { {showMoreClicked === true ? +
+ + Status + { + console.log("Data: ", e.target.value) + + innerWorkflow.workflow_type = e.target.value + setInnerWorkflow(innerWorkflow) + }} + > + } label="Test" /> + } label="Production" /> - - Status - { - console.log("Data: ", e.target.value) - - innerWorkflow.workflow_type = e.target.value - setInnerWorkflow(innerWorkflow) + + + + - } label="Test" /> - } label="Production" /> - - - + value={dueDate} + label="Due Date" + format="YYYY-MM-DD" + onChange={(newValue) => { + setDueDate(newValue) + }} + /> + +
@@ -430,38 +457,27 @@ const EditWorkflow = (props) => { : null} - { - setShowMoreClicked(!showMoreClicked); - }} - > - {showMoreClicked ? : } - - -
- {/*newWorkflow === true ? -
- -
- : null*/} + { + setShowMoreClicked(!showMoreClicked); + }} + > + {showMoreClicked ? : } + + +
+
@@ -698,17 +703,24 @@ const { globalUrl, setNotifications, notifications, isLoggedIn, removeCookie, ho {/* */} - Apps + Apps + {/* + + +
Dashboard
+ +
+ */}
{/* */} - Docs + Docs
@@ -782,14 +794,13 @@ const { globalUrl, setNotifications, notifications, isLoggedIn, removeCookie, ho : null*/} - - {userdata === undefined || userdata.orgs === undefined || userdata.orgs === null || userdata.orgs.length <= 1 ? null : -
{ @@ -2266,7 +2443,6 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user > -
{selectedOrganization.defaults !== undefined && selectedOrganization.defaults.documentation_reference !== undefined && selectedOrganization.defaults.documentation_reference !== null && selectedOrganization.defaults.documentation_reference.includes("http") ? -
-
: null} {selectedOrganization.name.length > 0 ? ( @@ -2341,7 +2515,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user - Billing + Billing (Beta)
/> /> - - Usage - - /> - {/* - - Notifications - - /> - */} , + icon: , }; return ( - -
- -
+ + ); })} @@ -2614,6 +2772,8 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user adminTab={adminTab} globalUrl={globalUrl} checkLogin={checkLogin} + setAdminTab={setAdminTab} + setCurTab={setCurTab} /> : adminTab === 3 ? @@ -2635,6 +2796,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user globalUrl={globalUrl} handleGetOrg={handleGetOrg} selectedOrganization={selectedOrganization} + selectedOrganization={selectedOrganization} setSelectedOrganization={setSelectedOrganization} /> : null @@ -2940,7 +3102,6 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user style={{}} aria-label={"Copy APIkey"} > -
{ @@ -2977,7 +3138,6 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user style={{ color: "rgba(255,255,255,0.8)" }} /> -
) } @@ -3550,19 +3710,17 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user title="Set in EVERY workflow" placement="top" > -
- { - editAuthenticationConfig(data.id); - }} - > - - -
+ { + editAuthenticationConfig(data.id); + }} + > + + ) : ( -
{}} @@ -3579,7 +3736,6 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user color={data.defined ? "primary" : "secondary"} /> -
)} -
-
} /> @@ -3920,7 +4074,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user {showCPUAlert === false ? null : -
+
90% CPU the server(s) hosting the Shuffle App Runner (Orborus) was found. @@ -4202,7 +4356,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user - + Environments /> diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 024799fb..f88ae850 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -1,18 +1,19 @@ /* eslint-disable react/no-multi-comp */ import React, { useState, useEffect, useLayoutEffect } from "react"; import ReactDOM from "react-dom" -import theme from '../theme.jsx'; import { useInterval } from "react-powerhooks"; -//import { makeStyles, } from "@mui/styles"; +import { makeStyles, useTheme } from "@material-ui/core/styles"; import { v4 as uuidv4 } from "uuid"; import { useNavigate, Link, useParams } from "react-router-dom"; +// import { Prompt } from "react-router"; // FIXME import { useBeforeunload } from "react-beforeunload"; import ReactJson from "react-json-view"; -import { NestedMenuItem } from "mui-nested-menu" +import NestedMenuItem from "material-ui-nested-menu-item"; import ReactMarkdown from "react-markdown"; import { useAlert } from "react-alert"; +import theme from '../theme.jsx'; import { isMobile } from "react-device-detect" import aa from 'search-insights' import Drift from "react-driftjs"; @@ -50,7 +51,7 @@ import { IconButton, Menu, Input, - Collapse, + Fade, FormGroup, FormControlLabel, Typography, @@ -66,9 +67,11 @@ import { ListItemText, ListItemAvatar, Badge, - Autocomplete, +} from "@material-ui/core"; + +import { AvatarGroup, -} from "@mui/material"; +} from "@mui/material" import { Folder as FolderIcon, @@ -84,7 +87,7 @@ import { ArrowLeft as ArrowLeftIcon, Cached as CachedIcon, DirectionsRun as DirectionsRunIcon, - Code as CodeIcon, + Polymer as PolymerIcon, FormatListNumbered as FormatListNumberedIcon, PlayArrow as PlayArrowIcon, AspectRatio as AspectRatioIcon, @@ -104,25 +107,30 @@ import { VpnKey as VpnKeyIcon, AddComment as AddCommentIcon, Edit as EditIcon, - Send as SendIcon, + Send as SendIcon, + Restore as RestoreIcon, +} from "@material-ui/icons"; + +import { Preview as PreviewIcon, ContentCopy as ContentCopyIcon, Circle as CircleIcon, SquareFoot as SquareFootIcon, AutoFixHigh as AutoFixHighIcon, -} from "@mui/icons-material"; +} from '@mui/icons-material'; +import Autocomplete from "@material-ui/lab/Autocomplete"; import * as cytoscape from "cytoscape"; import * as edgehandles from "cytoscape-edgehandles"; -//import * as clipboard from "cytoscape-clipboard"; -//import undoRedo from "cytoscape-undo-redo"; -//import cxtmenu from "cytoscape-cxtmenu"; +import * as clipboard from "cytoscape-clipboard"; import CytoscapeComponent from "react-cytoscapejs"; +import undoRedo from "cytoscape-undo-redo"; import Draggable from "react-draggable"; import cytoscapestyle from "../defaultCytoscapeStyle.jsx"; +import cxtmenu from "cytoscape-cxtmenu"; import { validateJson, GetIconInfo } from "./Workflows.jsx"; import { GetParsedPaths } from "./Apps.jsx"; @@ -228,9 +236,9 @@ const inputColor = "#383B40"; // http://apps.cytoscape.org/apps/yfileslayoutalgorithms cytoscape.use(edgehandles); -//cytoscape.use(clipboard); -//cytoscape.use(undoRedo); -//cytoscape.use(cxtmenu); +cytoscape.use(clipboard); +cytoscape.use(undoRedo); +cytoscape.use(cxtmenu); // Adds specific text to items //import popper from 'cytoscape-popper'; @@ -353,6 +361,32 @@ export function removeParam(key, sourceURL) { return rtn; } +const useStyles = makeStyles({ + notchedOutline: { + borderColor: "#f85a3e !important", + }, + root: { + "& .MuiAutocomplete-listbox": { + border: "2px solid #f85a3e", + color: "white", + fontSize: 18, + "& li:nth-child(even)": { + backgroundColor: "#CCC", + }, + "& li:nth-child(odd)": { + backgroundColor: "#FFF", + }, + }, + }, + inputRoot: { + color: "white", + // This matches the specificity of the default styles at https://github.com/mui-org/material-ui/blob/v4.11.3/packages/material-ui-lab/src/Autocomplete/Autocomplete.js#L90 + "&:hover .MuiOutlinedInput-notchedOutline": { + borderColor: "#f86a3e", + }, + }, +}); + const splitter = "|~|"; const svgSize = 24; //const referenceUrl = "https://shuffler.io/functions/webhooks/" @@ -369,6 +403,8 @@ const AngularWorkflow = (defaultprops) => { props.match = {} props.match.params = params + //const theme = useTheme(); + var to_be_copied = ""; const [firstrequest, setFirstrequest] = React.useState(true); @@ -385,6 +421,7 @@ const AngularWorkflow = (defaultprops) => { const [editWorkflowDetails, setEditWorkflowDetails] = React.useState(false); const [workflow, setWorkflow] = React.useState({}); + const [originalWorkflow, setOriginalWorkflow] = React.useState({}); const [userSettings, setUserSettings] = React.useState({}); const [subworkflow, setSubworkflow] = React.useState({}); const [subworkflowStartnode, setSubworkflowStartnode] = React.useState(""); @@ -448,6 +485,8 @@ const AngularWorkflow = (defaultprops) => { const [destinationValue, setDestinationValue] = React.useState({}); const [conditionValue, setConditionValue] = React.useState({}); const [dragging, setDragging] = React.useState(false); + const [showWorkflowRevisions, setShowWorkflowRevisions] = React.useState(false); + const [selectedRevision, setSelectedRevision] = useState({}) const [dragPosition, setDragPosition] = React.useState({ x: 0, y: 0, @@ -461,6 +500,7 @@ const AngularWorkflow = (defaultprops) => { const [selectedEdgeIndex, setSelectedEdgeIndex] = React.useState({}); const [visited, setVisited] = React.useState([]); + const [allRevisions, setAllRevisions] = useState([]) const [apps, setApps] = React.useState([]); const [filteredApps, setFilteredApps] = React.useState([]); @@ -524,6 +564,7 @@ const AngularWorkflow = (defaultprops) => { const appBarSize = isCloud ? 75 : 72; const triggerEnvironments = isCloud ? ["cloud"] : ["onprem", "cloud"]; const unloadText = "Are you sure you want to leave without saving (CTRL+S)?"; + const classes = useStyles(); const [bodyWidth, bodyHeight] = useWindowSize() //console.log("Mobile: ", isMobile, bodyWidth, bodyHeight) @@ -1539,6 +1580,7 @@ const AngularWorkflow = (defaultprops) => { console.log("Save workflow error: ", error.toString()); }); + setOriginalWorkflow(useworkflow) return success; }; @@ -2076,13 +2118,13 @@ const AngularWorkflow = (defaultprops) => { var nodefound = false; var target = sourcenode.parameters.find((item) => item.name === "startnode"); - console.log("Got rightclick target: ", target) - if (target === undefined || target === null) { - target = { - "name": "startnode", - "value": responseJson.start - } - } + console.log("Got rightclick target: ", target) + if (target === undefined || target === null) { + target = { + "name": "startnode", + "value": responseJson.start + } + } console.log(sourcenode.parameters); console.log(target); @@ -2223,6 +2265,7 @@ const AngularWorkflow = (defaultprops) => { cy.on("add", "node", (e) => onNodeAdded(e)); cy.on("add", "edge", (e) => onEdgeAdded(e)); } else { + setOriginalWorkflow(responseJson); setWorkflow(responseJson); setWorkflowDone(true); @@ -2236,7 +2279,7 @@ const AngularWorkflow = (defaultprops) => { responseJson.errors !== // what responseJson.errors.length > 0 ) { - console.log("Setting configure Modal to open") + console.log("Setting configure Modal to open") setConfigureWorkflowModalOpen(true); } } @@ -3765,8 +3808,10 @@ const AngularWorkflow = (defaultprops) => { workflow.branches[branchkey].source_id === edge.source ) { console.log(edge.source); - alert.error("That branch already exists"); + + //alert.error("That branch already exists"); event.target.remove(); + found = true; break; } else if (edge.target === workflow.start) { @@ -4005,18 +4050,14 @@ const AngularWorkflow = (defaultprops) => { data: newcybranch, }; - if ( - nodedata.name !== "User Input" && - nodedata.name !== "Shuffle Workflow" - ) { - if ( - workflow.actions !== undefined && - workflow.actions !== null && - workflow.actions.length > 0 - ) { - cy.add(edgeToBeAdded); - } - } + if (edgeToBeAdded.data.source !== edgeToBeAdded.data.target && edgeToBeAdded.data.source !== undefined && edgeToBeAdded.data.target !== undefined) { + if (nodedata.name !== "User Input" && nodedata.name !== "Shuffle Workflow") { + if (workflow.actions !== undefined && workflow.actions !== null && workflow.actions.length > 0) { + console.log("Edge handle: ", edgeToBeAdded) + cy.add(edgeToBeAdded); + } + } + } setWorkflow(workflow); } @@ -4041,7 +4082,7 @@ const AngularWorkflow = (defaultprops) => { } // Check if the source is trigger and can start - console.log("Removed: ", edge.data()) + //console.log("Removed: ", edge.data()) const allNodes = cy.nodes().jsons() for (let nodekey in allNodes) { const curnode = allNodes[nodekey] @@ -4049,33 +4090,33 @@ const AngularWorkflow = (defaultprops) => { continue } - if (curnode.data.id === edge.data("source")) { - console.log("Found matching trigger source: ", curnode) - if (curnode.data.app_name !== "Shuffle Workflow" && curnode.data.app_name !== "User Input") { - // If it's started, READD the edge - if (curnode.data.status === "running") { - console.log("Edge is running - readd it: ", edge.data()) + if (curnode.data.id === edge.data("source")) { + console.log("Found matching trigger source: ", curnode) + if (curnode.data.app_name !== "Shuffle Workflow" && curnode.data.app_name !== "User Input") { + // If it's started, READD the edge + if (curnode.data.status === "running") { + console.log("Edge is running - readd it: ", edge.data()) - // Just making sure it's not running infinitely - var newdata = edge.data() - newdata.readded = true + // Just making sure it's not running infinitely + var newdata = edge.data() + newdata.readded = true - try { - cy.add({ - group: "edges", - data: newdata, - }) + try { + cy.add({ + group: "edges", + data: newdata, + }) - alert.error("You must STOP the trigger before deleting its branches") - } catch (e) { - console.log("Failed re-adding edge: ", e) - } - } + alert.error("You must STOP the trigger before deleting its branches") + } catch (e) { + console.log("Failed re-adding edge: ", e) + } + } - //status: "uninitialized", - } - } - } + //status: "uninitialized", + } + } + } workflow.branches = workflow.branches.filter( (a) => a.id !== edge.data().id @@ -5117,8 +5158,36 @@ const AngularWorkflow = (defaultprops) => { } } - const setupGraph = () => { - const actions = workflow.actions.map((action) => { + const setupGraph = (inputworkflow) => { + // Reset cytoscape nodes and branches + if (cy !== undefined && cy !== null) { + if (inputworkflow.actions !== undefined && inputworkflow.actions !== null && inputworkflow.actions.length > 0) { + cy.remove('*') + } + console.log("INPUT: ", inputworkflow) + } + + if (inputworkflow.actions === undefined || inputworkflow.actions === null) { + inputworkflow.actions = [] + } + + if (inputworkflow.branches === undefined || inputworkflow.branches === null) { + inputworkflow.branches = [] + } + + if (inputworkflow.triggers === undefined || inputworkflow.triggers === null) { + inputworkflow.triggers = [] + } + + if (inputworkflow.comments === undefined || inputworkflow.comments === null) { + inputworkflow.comments = [] + } + + if (inputworkflow.visual_branches === undefined || inputworkflow.visual_branches === null) { + inputworkflow.visual_branches = [] + } + + const actions = inputworkflow.actions.map((action) => { const node = {}; if (!action.isStartNode && action.app_name === "Shuffle Tools") { @@ -5145,9 +5214,9 @@ const AngularWorkflow = (defaultprops) => { node.data.id = action["id"]; node.data._id = action["id"]; node.data.type = "ACTION"; - node.isStartNode = action["id"] === workflow.start; + node.isStartNode = action["id"] === inputworkflow.start; - if (workflow.public === true) { + if (inputworkflow.public === true) { node.data.is_valid = true node.is_valid = true } @@ -5166,7 +5235,7 @@ const AngularWorkflow = (defaultprops) => { return node; }); - const decoratorNodes = workflow.actions.map((action) => { + const decoratorNodes = inputworkflow.actions.map((action) => { if (!action.isStartNode) { if (action.app_name === "Testing") { return null; @@ -5200,7 +5269,7 @@ const AngularWorkflow = (defaultprops) => { }); - const foundtriggers = workflow.triggers.map((trigger) => { + const foundtriggers = inputworkflow.triggers.map((trigger) => { const node = {}; node.position = trigger.position; node.data = trigger; @@ -5214,11 +5283,11 @@ const AngularWorkflow = (defaultprops) => { var comments = []; if ( - workflow.comments !== undefined && - workflow.comments !== null && - workflow.comments.length > 0 + inputworkflow.comments !== undefined && + inputworkflow.comments !== null && + inputworkflow.comments.length > 0 ) { - comments = workflow.comments.map((comment) => { + comments = inputworkflow.comments.map((comment) => { const node = {}; node.position = comment.position; node.data = comment; @@ -5230,13 +5299,12 @@ const AngularWorkflow = (defaultprops) => { }); } - // FIXME - tmp branch update var insertedNodes = [].concat(actions, foundtriggers, decoratorNodes, comments); insertedNodes = insertedNodes.filter((node) => node !== null); - var edges = workflow.branches.map((branch, index) => { + var edges = inputworkflow.branches.map((branch, index) => { const edge = {}; - var conditions = workflow.branches[index].conditions; + var conditions = inputworkflow.branches[index].conditions; if (conditions === undefined || conditions === null) { conditions = []; } @@ -5248,6 +5316,26 @@ const AngularWorkflow = (defaultprops) => { label = conditions.length + " conditions"; } + // Verify if branch.source_id and branch.destination_id exists in triggers or actions + /* + var sourceExists = false; + var destinationExists = false; + for (var i = 0; i < insertedNodes.length; i++) { + console.log("Insertednode: ", insertedNodes[i].data); + if (insertedNodes[i].data._id === branch.source_id) { + sourceExists = true; + } + if (insertedNodes[i].data._id === branch.destination_id) { + destinationExists = true; + } + } + + if (sourceExists === false || destinationExists === false) { + console.log("Couldn't find source node for branch " + branch.id); + return null; + } + */ + edge.data = { id: branch.id, _id: branch.id, @@ -5287,18 +5375,18 @@ const AngularWorkflow = (defaultprops) => { }); if ( - workflow.visual_branches !== undefined && - workflow.visual_branches !== null && - workflow.visual_branches.length > 0 + inputworkflow.visual_branches !== undefined && + inputworkflow.visual_branches !== null && + inputworkflow.visual_branches.length > 0 ) { - const visualedges = workflow.visual_branches.map((branch, index) => { + const visualedges = inputworkflow.visual_branches.map((branch, index) => { const edge = {}; - if (workflow.branches[index] === undefined) { + if (inputworkflow.branches[index] === undefined) { return {}; } - var conditions = workflow.branches[index].conditions; + var conditions = inputworkflow.branches[index].conditions; if (conditions === undefined || conditions === null) { conditions = []; } @@ -5319,7 +5407,6 @@ const AngularWorkflow = (defaultprops) => { edges = edges.concat(visualedges); } - setWorkflow(workflow); // Verifies if a branch is valid and skips others var newedges = []; @@ -5343,7 +5430,18 @@ const AngularWorkflow = (defaultprops) => { } insertedNodes = insertedNodes.concat(newedges); - setElements(insertedNodes); + + console.log("NODES: ", insertedNodes) + setWorkflow(inputworkflow); + + // Reset view for cytoscape + if (cy !== undefined && cy !== null) { + console.log("In cy add!") + cy.add(insertedNodes); + cy.fit(null, 200); + } else { + setElements(insertedNodes); + } }; const removeNode = (nodeId) => { @@ -5487,11 +5585,47 @@ const AngularWorkflow = (defaultprops) => { }) } + const getRevisionHistory = (workflow_id) => { + console.log("Loading revisions for workflow ID ", workflow_id) + + fetch(`${globalUrl}/api/v1/workflows/${workflow_id}/revisions`, { + 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!"); + } + + // Read text from stream + //return response.text(); + return response.json(); + }) + .then((responseJson) => { + console.log("Got workflow revisions: ", responseJson) + + if (responseJson.success === false) { + console.log("Error getting workflow revisions: ", responseJson) + return + } + + setAllRevisions(responseJson) + }) + .catch((error) => { + console.log("Error getting workflow revisions: ", error) + }); + } + // eslint-disable-next-line react-hooks/exhaustive-deps //useEffect(() => { if (firstrequest) { setFirstrequest(false); getWorkflow(props.match.params.key, {}); + getRevisionHistory(props.match.params.key) getApps(); fetchUsecases() @@ -5532,7 +5666,7 @@ const AngularWorkflow = (defaultprops) => { // App length necessary cus of cy initialization if (elements.length === 0 && workflow.actions !== undefined && !graphSetup && Object.getOwnPropertyNames(workflow).length > 0) { setGraphSetup(true); - setupGraph(); + setupGraph(workflow); console.log("In graph setup") // 2nd load - configures cytoscape @@ -7080,6 +7214,12 @@ const AngularWorkflow = (defaultprops) => {
{ if (allitems !== undefined && allitems !== null) { for (let itemkey in allitems) { const item = allitems[itemkey]; - if ( - item.app_name === appName && - item.label !== undefined && - item.label !== null - ) { + console.log("Appname: ", appName, "Item: ", item); + + if (item.app_name === appName && item.label !== undefined && item.label !== null) { var number = item.label.split("_"); - if ( - isNaN(number[-1]) && - parseInt(number[number.length - 1]) > highest - ) { + if (isNaN(number[-1]) && parseInt(number[number.length - 1]) > highest) { highest = number[number.length - 1]; } } @@ -7783,6 +7918,15 @@ const AngularWorkflow = (defaultprops) => { backgroundColor: inputColor, borderRadius: theme.palette.borderRadius, }} + InputProps={{ + style: { + color: "white", + minHeight: 50, + marginLeft: "5px", + maxWidth: "95%", + fontSize: "1em", + }, + }} fullWidth multiline={multiline} color="primary" @@ -9131,6 +9275,15 @@ const AngularWorkflow = (defaultprops) => { backgroundColor: inputColor, borderRadius: theme.palette.borderRadius, }} + InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + height: 50, + fontSize: "1em", + }, + }} fullWidth color="primary" placeholder={selectedTrigger.label} @@ -9145,6 +9298,13 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + height: 50, + fontSize: "1em", + }, }} required disabled @@ -9875,6 +10035,15 @@ const AngularWorkflow = (defaultprops) => { backgroundColor: inputColor, borderRadius: theme.palette.borderRadius, }} + InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + height: 50, + fontSize: "1em", + }, + }} fullWidth color="primary" placeholder={selectedTrigger.label} @@ -9891,6 +10060,14 @@ const AngularWorkflow = (defaultprops) => { Delay { freeSolo //autoSelect value={subworkflow} + classes={{ inputRoot: classes.inputRoot }} ListboxProps={{ style: { backgroundColor: theme.palette.inputColor, @@ -10119,6 +10297,7 @@ const AngularWorkflow = (defaultprops) => { id="subflow_node_search" autoHighlight value={subworkflowStartnode} + classes={{ inputRoot: classes.inputRoot }} ListboxProps={{ style: { backgroundColor: theme.palette.inputColor, @@ -10211,6 +10390,12 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + fontSize: "1em", + }, endAdornment: ( @@ -10357,6 +10542,12 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + fontSize: "1em", + }, }} multiline rows="4" @@ -10378,6 +10569,13 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + height: 50, + fontSize: "1em", + }, }} fullWidth color="primary" @@ -10425,6 +10623,13 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + height: 50, + fontSize: "1em", + }, }} fullWidth color="primary" @@ -10444,6 +10649,13 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + height: 50, + fontSize: "1em", + }, }} fullWidth color="primary" @@ -10463,6 +10675,13 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + height: 50, + fontSize: "1em", + }, }} fullWidth color="primary" @@ -10567,6 +10786,13 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + height: 50, + fontSize: "1em", + }, }} fullWidth color="primary" @@ -10579,6 +10805,7 @@ const AngularWorkflow = (defaultprops) => { id="action_search" autoHighlight value={selectedTrigger.app_association} + classes={{ inputRoot: classes.inputRoot }} ListboxProps={{ style: { backgroundColor: theme.palette.inputColor, @@ -10913,6 +11140,12 @@ const AngularWorkflow = (defaultprops) => { id="webhook_uri_header" onClick={() => { }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + fontSize: "1em", + }, }} fullWidth multiline @@ -10964,6 +11197,12 @@ const AngularWorkflow = (defaultprops) => { id="webhook_uri_header" onClick={() => { }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + fontSize: "1em", + }, }} fullWidth multiline @@ -11367,6 +11606,13 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + height: 50, + fontSize: "1em", + }, }} fullWidth color="primary" @@ -11434,6 +11680,13 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + marginTop: "3px", + fontSize: "1em", + }, }} fullWidth rows="4" @@ -11523,6 +11776,7 @@ const AngularWorkflow = (defaultprops) => { id="subflow_search" autoHighlight value={subworkflow} + classes={{ inputRoot: classes.inputRoot }} ListboxProps={{ style: { backgroundColor: theme.palette.inputColor, @@ -11641,6 +11895,13 @@ const AngularWorkflow = (defaultprops) => { marginTop: 10, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + height: 50, + fontSize: "1em", + }, }} fullWidth color="primary" @@ -11723,6 +11984,13 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + height: 50, + fontSize: "1em", + }, }} fullWidth color="primary" @@ -11820,6 +12088,13 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + height: 50, + marginLeft: "5px", + maxWidth: "95%", + fontSize: "1em", + }, }} fullWidth disabled={ @@ -11868,6 +12143,13 @@ const AngularWorkflow = (defaultprops) => { borderRadius: theme.palette.borderRadius, }} InputProps={{ + style: { + color: "white", + marginLeft: "5px", + maxWidth: "95%", + marginTop: "3px", + fontSize: "1em", + }, }} disabled={ workflow.triggers[selectedTriggerIndex].status === "running" @@ -11975,7 +12257,7 @@ const AngularWorkflow = (defaultprops) => { margin: "0px 0px 0px 0px", }} > - + Workflows @@ -12517,6 +12799,27 @@ const AngularWorkflow = (defaultprops) => { + + + + +
); @@ -12696,11 +12999,11 @@ const AngularWorkflow = (defaultprops) => { {defaultReturn} : - +
{defaultReturn}
-
+ ); //return null; @@ -14776,7 +15079,7 @@ const AngularWorkflow = (defaultprops) => {
) : ( - + { setCy(incy); }} /> - + )}
{executionModal} @@ -14835,36 +15138,16 @@ const AngularWorkflow = (defaultprops) => { setSelectedActionEnvironment={setSelectedActionEnvironment} requiresAuthentication={requiresAuthentication} /> - - + + {showWorkflowRevisions ? null : + + + + + }
); - const editWorkflowModal = - { - setEditWorkflowDetails(false) - }} - PaperProps={{ - style: { - pointerEvents: "auto", - backgroundColor: surfaceColor, - color: "white", - border: theme.palette.defaultBorder, - maxWidth: "100%", - padding: 50, - }, - }} - > - Edit workflow! - const ExecutionVariableModal = (props) => { const { variableInfo } = props @@ -16140,6 +16423,290 @@ const AngularWorkflow = (defaultprops) => { ) } + + /*else if (selectedRevision === undefined || selectedRevision === null || selectedRevision == {} && originalWorkflow !== undefined && originalWorkflow !== null && originalWorkflow !== {}) { + console.log("Setting original workflow as selected revision") + setSelectedRevision(originalWorkflow) + }*/ + + const RevisionBox = (props) => { + const { revision, } = props + + if (revision === undefined || revision === null || revision === {}) { + return null + } + + // Make unix timestamp into ISO timestamp in the format July 27th, 3:05 AM + // Format: July 27th, 3:05 AM + const translatedDate = new Date(revision.edited).toLocaleString('en-US', { month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', hour12: true }) + + var workflowStatus = revision.status !== undefined && revision.status !== null && revision.status !== "" ? revision.status : "test" + if (revision.name !== undefined && revision.name !== null && revision.name !== "") { + if (revision.name.toLowerCase().includes("test")) { + workflowStatus = "test" + } + + if (revision.name.toLowerCase().includes("dev") || revision.name.toLowerCase().includes("staging") || revision.name.toLowerCase().includes("rollback")) { + workflowStatus = "dev" + } + + if (revision.name.toLowerCase().includes("prod") || revision.name.toLowerCase().includes("main")) { + workflowStatus = "prod" + } + } + + return ( + { + if (revision.edited === selectedRevision.edited) { + console.log("Same revision! No setting.") + return + } + + // Should render if it's not the same as workflow.edited + console.log("Clicked revision: ", revision) + setLastSaved(false) + setSelectedRevision(revision) + setWorkflow(revision) + setSelectedAction({}); + setSelectedApp({}) + + // Remove all cytoscape triggers first? + if (cy !== undefined && cy !== null) { + cy.removeListener("select"); + cy.removeListener("unselect"); + + cy.removeListener("add"); + cy.removeListener("remove"); + + cy.removeListener("mouseover"); + cy.removeListener("mouseout"); + + cy.removeListener("drag"); + cy.removeListener("free"); + cy.removeListener("cxttap"); + } + + setupGraph(revision) + + // Re-adding cytoscape triggers + if (cy !== undefined && cy !== null) { + cy.on("select", "node", (e) => { + onNodeSelect(e, appAuthentication); + }); + cy.on("select", "edge", (e) => onEdgeSelect(e)); + + cy.on("unselect", (e) => onUnselect(e)); + + cy.on("add", "node", (e) => onNodeAdded(e)); + cy.on("add", "edge", (e) => onEdgeAdded(e)); + cy.on("remove", "node", (e) => onNodeRemoved(e)); + cy.on("remove", "edge", (e) => onEdgeRemoved(e)); + + cy.on("mouseover", "edge", (e) => onEdgeHover(e)); + cy.on("mouseout", "edge", (e) => onEdgeHoverOut(e)); + cy.on("mouseover", "node", (e) => onNodeHover(e)); + cy.on("mouseout", "node", (e) => onNodeHoverOut(e)); + + // Handles dragging + cy.on("drag", "node", (e) => onNodeDrag(e, selectedAction)); + cy.on("free", "node", (e) => onNodeDragStop(e, selectedAction)); + + cy.on("cxttap", "node", (e) => onCtxTap(e)); + } + + // Need to run through graph setup with this one + }}> +
+ + + {translatedDate} + + + + + +
+ {/*revision.edited === originalWorkflow.edited ? + + Current version + + : null*/} +
+ {revision.actions !== undefined && revision.actions !== null ? + + + + + {revision.actions.length} + + + + : null} + {revision.triggers !== undefined && revision.triggers !== null ? + + + + + {revision.triggers.length} + + + + : null} +
+ {revision.updated_by !== undefined && revision.updated_by !== null && revision.updated_by !== "" ? + + {revision.updated_by} + + : null} +
+ ) + } + + const drawerData = originalWorkflow !== undefined && originalWorkflow !== null && originalWorkflow !== {} ? +
+ + Version History (Beta) + + + + + {allRevisions.length > 0 ? + allRevisions.map((revision, index) => { + if (revision.edited === originalWorkflow.edited) { + return null + } + + return ( + + ) + }) + : +
+ + No other revisions found. Save your workflow with changes to create a revision. + +
+ } +
+ : null + + const workflowRevisions = !showWorkflowRevisions ? null : +
+ { + //setShowWorkflowRevisions(false) + }} + style={{ resize: "both", overflow: "auto", zIndex: 10005 }} + hideBackdrop={true} + variant="persistent" + BackdropProps={{ + style: { + //backgroundColor: "transparent", + } + }} + PaperProps={{ + style: { + resize: "both", + overflow: "auto", + minWidth: isMobile ? "100%" : 360, + maxWidth: isMobile ? "100%" : 360, + backgroundColor: theme.palette.platformColor, + color: "white", + fontSize: 18, + zIndex: 15001, + borderRight: theme.palette.defaultBorder, + paddingTop: 15, + }, + }} + > + {drawerData} + +
+
+ {/*selectedRevision.edited !== undefined && selectedRevision.edited !== null && selectedRevision.edited !== originalWorkflow.edited ? + + : null*/} +
+
+ + {selectedRevision.name} + +
+ {/* Cross icon to close it */} +
+ { + setShowWorkflowRevisions(false) + }} + style={{color: "white", height: 50, width: 50, }} + > + + +
+
+
+ + const loadedCheck = isLoaded && workflowDone ? (
@@ -16150,9 +16717,9 @@ const AngularWorkflow = (defaultprops) => { {authenticationModal} {codePopoutModal} {configureWorkflowModal} - {editWorkflowModal} - - + {/*editWorkflowModal*/} + {workflowRevisions} + {editWorkflowModalOpen === true ? { return (
+ {/* Removed due to missing react router features + + */} {loadedCheck}
); diff --git a/frontend/src/views/Welcome.jsx b/frontend/src/views/Welcome.jsx index 7cafddfd..1e209780 100644 --- a/frontend/src/views/Welcome.jsx +++ b/frontend/src/views/Welcome.jsx @@ -1,17 +1,15 @@ import React, { useState, useEffect } from 'react'; import ReactGA from 'react-ga4'; import WelcomeForm2 from "../components/WelcomeForm2.jsx"; -import { - Stepper, - Step, - StepLabel, -} from '@mui/material'; +import Stepper from "@material-ui/core/Stepper"; +import Step from "@material-ui/core/Step"; +import StepLabel from "@material-ui/core/StepLabel"; import AppFramework from "../components/AppFramework.jsx"; import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; import { Grid, Container, - Collapse, + Fade, Typography, Paper, Button, @@ -417,7 +415,7 @@ const Welcome = (props) => { App Framework - + { isLoggedIn={true} globalUrl={globalUrl} size={0.78} - color={theme.palette.platformColor} + color={theme.palette.backgroundColor} discoveryWrapper={discoveryWrapper} setDiscoveryWrapper={setDiscoveryWrapper} apps={apps} inputUsecases={usecases} setInputUsecases={setUsecases} /> - +
} : - +
{/*
@@ -537,7 +535,7 @@ const Welcome = (props) => {
-
+ } ) diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index d7f83edb..cd26d205 100755 --- a/frontend/src/views/Workflows.jsx +++ b/frontend/src/views/Workflows.jsx @@ -1,14 +1,14 @@ import React, { useEffect, useContext } from "react"; import ReactDOM from "react-dom" -import { makeStyles } from "@mui/styles"; +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 { ShepherdTour, ShepherdTourContext } from 'react-shepherd' import Priority from "../components/Priority.jsx"; import { isMobile } from "react-device-detect" @@ -41,7 +41,7 @@ import { Checkbox, LinearProgress, ListItemText, -} from "@mui/material" +} from "@material-ui/core"; import { AvatarGroup, @@ -79,7 +79,7 @@ import { RadioButtonUnchecked as RadioButtonUncheckedIcon, ArrowLeft as ArrowLeftIcon, ArrowRight as ArrowRightIcon, -} from "@mui/icons-material"; +} 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'; @@ -409,16 +409,16 @@ export const validateJson = (showResult) => { } if (typeof showResult === "object" || typeof showResult === "array") { - return { - valid: true, - result: showResult, - } + return { + valid: true, + result: showResult, + } } if (showResult[0] === "\"") { - return { - valid: false, - result: showResult, + return { + valid: false, + result: showResult, } } @@ -427,10 +427,10 @@ export const validateJson = (showResult) => { if (!showResult.includes("{") && !showResult.includes("[")) { jsonvalid = false - return { - valid: jsonvalid, - result: showResult, - }; + return { + valid: jsonvalid, + result: showResult, + }; } } catch (e) { showResult = showResult.split("'").join('"'); @@ -1182,7 +1182,7 @@ const Workflows = (props) => { setUsecases(newcategories) } else { - setUsecases(categorydata) + setUsecases(categorydata) } } @@ -1272,11 +1272,11 @@ const Workflows = (props) => { width: "100%", color: "white", backgroundColor: surfaceColor, + padding: "12px 12px 0px 15px", borderRadius: 5, display: "flex", boxSizing: "border-box", position: "relative", - padding: "12px 12px 0px 15px", }; const gridContainer = { @@ -1603,9 +1603,10 @@ const Workflows = (props) => { const innerColor = "rgba(255,255,255,0.3)"; const setupPaperStyle = { minHeight: paperAppStyle.minHeight, - maxWidth: "100%", + maxWidth: "100%", minWidth: paperAppStyle.width, color: innerColor, + padding: paperAppStyle.padding, borderRadius: paperAppStyle.borderRadius, display: "flex", boxSizing: "border-box", @@ -1613,12 +1614,10 @@ const Workflows = (props) => { border: `2px solid ${innerColor}`, cursor: "pointer", backgroundColor: hover ? "rgba(39,41,45,0.5)" : "rgba(39,41,45,1)", - - padding: paperAppStyle.padding, }; return ( - + { selectedUsecases.push(subcase.name) } - setUpdate(Math.random()); + setUpdate(Math.random()); setSelectedUsecases(selectedUsecases) }}> @@ -3067,12 +3066,153 @@ const Workflows = (props) => { ); + // 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 + // } + // ] + + // function TourButton() { + // const tour = useContext(ShepherdTourContext); + + // return ( + // + // ); + // } + 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 ; - //} + // 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} + // + //
+ //
+ //
+ //) } var workflowDelay = -150 @@ -3084,40 +3224,101 @@ const Workflows = (props) => {
- - Workflows - + + Workflows +
- {isMobile ? null : -
-
- { - addFilter(chip); - }} - onDelete={(_, index) => { - removeFilter(index); - }} - /> -
-
- } + {/* + + */} + {isMobile ? null : +
+
+ { + addFilter(chip); + }} + onDelete={(_, index) => { + removeFilter(index); + }} + /> +
+
+ }
{workflowButtons}
+ {/* +
+
+
+
+
+
{workflows.length}
+
ACTIVE WORKFLOWS
+
+
+
+
+
+
+
+
{workflows.length}
+
AVAILABE WORKFLOWS
+
+
+
+
+
+
+
+
{workflows.length}
+
NOTIFICATIONS
+
+
+
+
+ */} + + {/* + chipRenderer={({ value, isFocused, isDisabled, handleClick, handleRequestDelete }, key) => { + console.log("VALUE: ", value) + + return ( + + {value} + + ) + }} + */}
{!isMobile && usecases !== null && usecases !== undefined && usecases.length > 0 ? @@ -3125,6 +3326,7 @@ const Workflows = (props) => { {usecases.map((usecase, index) => { //console.log(usecase) const percentDone = usecase.matches.length > 0 ? parseInt(usecase.matches.length/usecase.list.length*100) : 0 + console.log("Usecase Matches: ", usecase.matches, ", Percent: ", percentDone) return ( {
- {!isMobile && actionImageList !== undefined && actionImageList !== null && actionImageList.length > 0 ? ( + {!isMobile && + actionImageList !== undefined && + actionImageList !== null && + actionImageList.length > 0 ? (
{ return returnData } - /**/ return ( - - {returnData} - + + {returnData} + ); })}
@@ -3296,11 +3500,13 @@ const Workflows = (props) => { /> : null} - {/**/}
{view === "grid" ? ( - + + + + {filteredWorkflows.map((data, index) => { // Shouldn't be a part of this list if (data.public === true) { @@ -3311,17 +3517,15 @@ const Workflows = (props) => { workflowDelay += 75 } else { return ( - - - - - + + + ) } return ( - + @@ -3728,7 +3932,7 @@ const Workflows = (props) => { setWorkflow={setEditingWorkflow} modalOpen={modalOpen} setModalOpen={setModalOpen} - usecases={usecases} + usecases={usecases} setNewWorkflow={setNewWorkflow} appFramework={appFramework} isEditing={isEditing}