Fixed no-path issue with requirement of leading /

This commit is contained in:
frikky
2021-03-29 21:58:48 +02:00
parent 7814eb1e08
commit 1b428b301a
16 changed files with 419 additions and 161 deletions
+20 -1
View File
@@ -39,6 +39,23 @@ const data = [{
'border-color': '#81c784',
'background-width': '100%',
'background-height': '100%',
'border-radius': '5px',
},
},
{
selector: `node[app_name="Shuffle Tools"]`,
css: {
'width': '30px',
'height': '30px',
'font-size': '0px',
},
},
{
selector: `node[app_name="Testing"]`,
css: {
'width': '30px',
'height': '30px',
'font-size': '0px',
},
},
{
@@ -112,7 +129,7 @@ const data = [{
},
},
{
selector: 'node:selected',
selector: ':selected',
css: {
'background-color': '#77b0d0',
'border-color': '#77b0d0',
@@ -187,6 +204,8 @@ const data = [{
'border-width': '12px',
'transition-property': 'border-width',
'transition-duration': '0.25s',
'font-size': '30px',
'label': 'data(label)',
},
},
{
+107 -18
View File
@@ -92,7 +92,6 @@ const AngularWorkflow = (props) => {
const theme = useTheme();
const [bodyWidth, bodyHeight] = useWindowSize();
const appBarSize = 75
var to_be_copied = ""
const [cystyle, ] = useState(cytoscapestyle)
@@ -190,18 +189,22 @@ const AngularWorkflow = (props) => {
const [workflowExecutions, setWorkflowExecutions] = React.useState([]);
const [defaultEnvironmentIndex, setDefaultEnvironmentIndex] = React.useState(0)
// This should all be set once, not on every iteration
// Use states and don't update lol
const cloudSyncEnabled = props.userdata !== undefined && props.userdata.active_org !== null && props.userdata.active_org !== undefined ? props.userdata.active_org.cloud_sync === true : false
//const triggerEnvironments = cloudSyncEnabled ? ["cloud", "onprem"] : environments
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"
const appBarSize = isCloud ? 75 : 60
const triggerEnvironments = isCloud ? ["cloud"] : ["onprem", "cloud"]
const unloadText = 'Are you sure you want to leave without saving (CTRL+S)?'
useBeforeunload(() => {
if (!lastSaved) {
return unloadText
}
})
const [elements, setElements] = useState([])
// No point going as fast, as the nodes aren't realtime anymore, but bulk updated.
// Set it from 2500 to 6000 to reduce overall load
@@ -1121,7 +1124,7 @@ const AngularWorkflow = (props) => {
}
if (responseJson.public) {
alert.info("This workflow is public. You'll have to save it to make it your own!")
alert.info("This workflow is public. You will have to save it to make it your own!")
setLastSaved(false)
}
@@ -1215,9 +1218,36 @@ const AngularWorkflow = (props) => {
setSelectedTrigger({})
}
// Comparing locations between nodes and setting views
const onNodeDrag = (event, newAppAuth) => {
//console.log("DRAGGING: ", event.target)
//console.log("LEN2: ", event.target.edges.length)
/*
event.target.animate({
style: {
"border-width": "12px",
"border-opacity": ".7",
}
}, {
duration: animationDuration,
})
event.target.animate({
style: {
"border-width": "12px",
"border-opacity": ".7",
}
}, {
duration: animationDuration,
})
*/
}
// Nodeselectbatching:
// https://stackoverflow.com/questions/16677856/cy-onselect-callback-only-once
const onNodeSelect = (event, newAppAuth) => {
const data = event.target.data()
setLastSaved(false)
@@ -1619,6 +1649,17 @@ const AngularWorkflow = (props) => {
});
}
if (!firstrequest && graphSetup && established && props.match.params.key !== workflow.id && workflow.id !== undefined && workflow.id !== null && workflow.id.length > 0) {
//console.log(props.match.params.key, workflow.id)
//getWorkflow()
//setCy()
//getWorkflowExecution(props.match.params.key, "")
//setEstablished(false)
//setGraphSetup(false)
window.location.pathname = "/workflows/"+props.match.params.key
}
useEffect(() => {
if (firstrequest) {
setFirstrequest(false)
@@ -1642,14 +1683,14 @@ const AngularWorkflow = (props) => {
}
// App length necessary cus of cy initialization
if (elements.length === 0 && !graphSetup && Object.getOwnPropertyNames(workflow).length > 0) {
if (elements.length === 0 && workflow.actions !== undefined && !graphSetup && Object.getOwnPropertyNames(workflow).length > 0) {
setGraphSetup(true)
setupGraph()
} else if (!established && cy !== undefined && apps !== null && apps !== undefined && apps.length > 0 && Object.getOwnPropertyNames(workflow).length > 0 && authLoaded){
//This part has to load LAST, as it's kind of not async.
//This means we need everything else to happen first.
console.log("AUTH IN HERE: ", appAuthentication)
//
//console.log("IN THIS PART AGAIN")
setEstablished(true)
cy.edgehandles({
@@ -1677,6 +1718,9 @@ const AngularWorkflow = (props) => {
cy.on('mouseover', 'node', (e) => onNodeHover(e))
cy.on('mouseout', 'node', (e) => onNodeHoverOut(e))
// Handles dragging
//cy.on('drag', 'node', (e) => onNodeDrag(e))
//cy.on('mouseover', 'node', () => $(targetElement).addClass('mouseover'));
//cy.on('cxttapstart', 'node', (e) => edgeHandler.start(e.target))
@@ -1711,7 +1755,7 @@ const AngularWorkflow = (props) => {
const onNodeHover = (event) => {
event.target.animate({
style: {
"border-width": "5px",
"border-width": "7px",
"border-opacity": ".7",
}
}, {
@@ -1727,17 +1771,23 @@ const AngularWorkflow = (props) => {
// This is here to have a proper transition for lines
const onEdgeHover = (event) => {
if (event === null || event === undefined) {
return
}
const sourcecolor = cy.getElementById(event.target.data("source")).style("border-color")
const targetcolor = cy.getElementById(event.target.data("target")).style("border-color")
event.target.animate({
style: {
"line-fill": "linear-gradient",
'target-arrow-color': targetcolor,
"line-gradient-stop-colors": [sourcecolor, targetcolor],
"line-gradient-stop-positions": [0, 1],
},
duration: 0,
})
if (sourcecolor !== null && sourcecolor !== undefined && targetcolor !== null && targetcolor !== undefined) {
event.target.animate({
style: {
"line-fill": "linear-gradient",
'target-arrow-color': targetcolor,
"line-gradient-stop-colors": [sourcecolor, targetcolor],
"line-gradient-stop-positions": [0, 1],
},
duration: 0,
})
}
}
@@ -1799,6 +1849,31 @@ const AngularWorkflow = (props) => {
conditions: conditions,
hasErrors: branch.has_errors
};
// This is an attempt at prettier edges. The numbers are weird to work with.
/*
//http://manual.graphspace.org/projects/graphspace-python/en/latest/demos/edge-types.html
const sourcenode = actions.find(node => node.data._id === branch.source_id)
const destinationnode = actions.find(node => node.data._id === branch.destination_id)
if (sourcenode !== undefined && destinationnode !== undefined && branch.source_id !== branch.destination_id) {
//node.data._id = action["id"]
console.log("SOURCE: ", sourcenode.position)
console.log("DESTINATIONNODE: ", destinationnode.position)
var opposite = true
if (sourcenode.position.x > destinationnode.position.x) {
opposite = false
} else {
opposite = true
}
edge.style = {
'control-point-distance': opposite ? ["25%", "-75%"] : ["-10%", "90%"],
'control-point-weight': ['0.3', '0.7'],
}
}
*/
return edge;
})
@@ -4506,7 +4581,7 @@ const AngularWorkflow = (props) => {
: null
}
onClick={() => {
console.log("CHANGE FIELD")
//console.log("CHANGE FIELD")
}}
onBlur={(e) => {
changeActionVariable(data.action_field, e.target.value)
@@ -4803,6 +4878,7 @@ const AngularWorkflow = (props) => {
onClick={() => {
setSelectedEdge({})
var data = {
condition: conditionValue,
source: sourceValue,
@@ -4821,6 +4897,18 @@ const AngularWorkflow = (props) => {
}
}
var label = ""
if (selectedEdge.conditions.length === 1) {
label = selectedEdge.conditions.length+" condition"
} else if (selectedEdge.conditions.length > 1) {
label = selectedEdge.conditions.length+" conditions"
}
var currentedge = cy.getElementById(selectedEdge.id)
if (currentedge !== undefined && currentedge !== null) {
currentedge.data().label = label
}
setSelectedEdge(selectedEdge)
workflow.branches[selectedEdgeIndex] = selectedEdge
setWorkflow(workflow)
@@ -6494,7 +6582,7 @@ const AngularWorkflow = (props) => {
</span>
</Tooltip>
{/* <FileMenu /> */}
<WorkflowMenu />
{workflow.configuration !== null && workflow.configuration !== undefined && workflow.configuration.exit_on_error !== undefined ? <WorkflowMenu /> : null}
</div>
</div>
)
@@ -7211,6 +7299,7 @@ const AngularWorkflow = (props) => {
stylesheet={cystyle}
boxSelectionEnabled={true}
autounselectify={false}
showGrid={true}
cy={(incy) => {
// FIXME: There's something specific loading when
// you do the first hover of a node. Why is this different?
+3 -3
View File
@@ -1565,9 +1565,9 @@ const AppCreator = (props) => {
}
// Url verification
if (currentAction.url.length === 0) {
errormessage.push("URL path can't be empty.")
} else if (!currentAction.url.startsWith("/") && baseUrl.length > 0) {
//if (currentAction.url.length === 0) {
// errormessage.push("URL path can't be empty.")
if (!currentAction.url.startsWith("/") && baseUrl.length > 0 && currentAction.url.length > 0) {
errormessage.push("URL must start with /")
}
+109 -96
View File
@@ -68,11 +68,9 @@ const flexContainerStyle = {
}
const flexBoxStyle = {
width: "333px",
height: "125px",
margin: "10px",
borderRadius: "4px",
boxShadow: "0px 1px 2px rgba(0, 0, 0, 0.16), 0px 2px 4px rgba(0, 0, 0, 0.12), 0px 1px 8px rgba(0, 0, 0, 0.1)",
width: 333,
height: 125,
borderRadius: 4,
boxSizing: "border-box",
letterSpacing: "0.4px",
color: "#D6791E",
@@ -299,37 +297,37 @@ const MyView = (props) => {
}
const paperAppContainer = {
cursor: "pointer",
display: "flex",
flexWrap: 'wrap',
alignContent: "space-between",
}
const paperAppStyle = {
minHeight: "148px",
width: "333px",
margin: "10px",
minHeight: 130,
width: "100%",
color: "white",
backgroundColor: surfaceColor,
padding: "12px 12px 0px 15px",
borderRadius: 5,
padding: "10px",
cursor: "pointer",
display: "flex",
boxSizing: "border-box",
position: "relative",
}
const gridContainer = {
cursor: "pointer",
height: "auto",
color: "white",
margin: "10px",
backgroundColor: surfaceColor,
}
const workFlowActionStyle = {
const workflowActionStyle = {
flex: "1",
display: "flex",
width: "150px",
width: 150,
height: 44,
justifyContent: "space-between",
overflow: "hidden"
}
@@ -535,23 +533,28 @@ const MyView = (props) => {
});
}
const getWorkFlowMeta = (data) => {
const getWorkflowMeta = (data) => {
let triggers = 0
let schedules = 0
let webhooks = 0
let webhookImg = ""
let scheduleImg = ""
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
//webhookImg = data.triggers[key].large_image
} else if (data.triggers[key].app_name === "Schedule") {
schedules += 1
scheduleImg = data.triggers[key].large_image
//scheduleImg = data.triggers[key].large_image
} else if (data.triggers[key].app_name === "Subflow") {
subflows += 1
}
}
}
return [schedules, webhooks, webhookImg, scheduleImg];
return [triggers, schedules, webhooks, subflows]
}
// dropdown with copy etc I guess
@@ -565,9 +568,9 @@ const MyView = (props) => {
boxWidth = "4px"
}
var boxColor = "orange"
var boxColor = "#FECC00"
if (data.is_valid) {
boxColor = "green"
boxColor = "#86c142"
}
const menuClick = (event) => {
@@ -575,45 +578,57 @@ const MyView = (props) => {
setAnchorEl(event.currentTarget);
}
const actions = data.actions !== null ? data.actions.length : 0
const [schedules, webhooks] = getWorkFlowMeta(data);
var parsedName = data.name
console.log("LEN: ", parsedName.length)
if (parsedName !== undefined && parsedName !== null && parsedName.length > 25) {
parsedName = parsedName.slice(0,25)+".."
}
const actions = data.actions !== null ? data.actions.length : 0
const [triggers, schedules, webhooks, subflows] = getWorkflowMeta(data)
const imgSize = 25
return (
<Paper square style={paperAppStyle} onClick={(e) => {
}}>
<div style={{width: boxWidth, backgroundColor: boxColor,}} onClick={() => {
if (selectedWorkflow.id !== data.id) {
setSelectedWorkflow(data)
//getWorkflowExecution(data.id)
}
}}/>
<Grid container style={{margin: "0px 10px 0px 10px", flex: 1}}>
<Grid item xs={4} spacing={4} style={{padding: 10,}}>
<Paper square style={paperAppStyle} >
<div style={{position: "absolute", bottom: 1, left: 1, height: 12, width: 12, backgroundColor: boxColor, borderRadius: "0 100px 0 0",}} />
<Grid item style={{display: "flex", flexDirection: "column", width: "100%"}}>
<Grid item style={{flex: 1, display: "flex"}}>
<div onClick={() => {
if (selectedWorkflow.id !== data.id) {
setSelectedWorkflow(data)
//getWorkflowExecution(data.id)
}
}}>
<Typography variant="h6">
{data.name}
</Typography>
</div>
<Grid item style={{flex: 1, display: "flex", maxHeight: 34,}}>
<Typography variant="h6" style={{marginBottom: 0, paddingBottom: 0, maxHeight: 30,}}>
{parsedName}
</Typography>
</Grid>
<Grid item style={workFlowActionStyle}>
<Tooltip color="primary" title="Edit workflow" placement="bottom">
<BubbleChartIcon/>
<Grid item style={workflowActionStyle}>
<Tooltip color="primary" title="Action amount" placement="bottom">
<span style={{color: "#979797", display: "flex"}}>
<BubbleChartIcon style={{marginTop: "auto", marginBottom: "auto",}} />
<Typography style={{marginLeft: 5, marginTop: "auto", marginBottom: "auto",}}>
{actions}
</Typography>
</span>
</Tooltip>
<Tooltip color="primary" title="Execute workflow" placement="bottom">
<PlayArrowIcon color="secondary" disabled={!data.is_valid} onClick={() => executeWorkflow(data.id)} />
<Tooltip color="primary" title="Trigger amount" placement="bottom">
<span style={{marginLeft: 10, color: "#979797", display: "flex"}}>
<RestoreIcon style={{color: "#979797", marginTop: "auto", marginBottom: "auto",}}/>
<Typography style={{marginLeft: 5, marginTop: "auto", marginBottom: "auto",}}>
{triggers}
</Typography>
</span>
</Tooltip>
<Tooltip color="primary" title="Subflows used" placement="bottom">
<span style={{marginLeft: 10, display: "flex", color: "#979797", }}>
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" style={{color: "#979797", marginTop: "auto", marginBottom: "auto",}}>
<path d="M0 0H15V15H0V0ZM16 16H18V18H16V16ZM16 13H18V15H16V13ZM16 10H18V12H16V10ZM16 7H18V9H16V7ZM16 4H18V6H16V4ZM13 16H15V18H13V16ZM10 16H12V18H10V16ZM7 16H9V18H7V16ZM4 16H6V18H4V16Z" fill="#979797"/>
</svg>
<Typography style={{marginLeft: 5, marginTop: "auto", marginBottom: "auto",}}>
{subflows}
</Typography>
</span>
</Tooltip>
{/*
<Tooltip color="primary" title={`Actions: ${data.actions.length}`} placement="bottom">
<AppsIcon />
</Tooltip>
{webhooks > 0 ?
<Tooltip color="primary" title={`Webhooks: ${webhooks}`} placement="bottom">
<RestoreIcon />
</Tooltip>
@@ -623,8 +638,9 @@ const MyView = (props) => {
<RestoreIcon />
</Tooltip>
: null}
*/}
</Grid>
<Grid item style={{flex: "1", justifyContent: "left", overflow: "hidden"}}>
<Grid item style={{flex: "1", justifyContent: "left", overflow: "hidden", marginTop: 5,}}>
{data.tags !== undefined ?
data.tags.map((tag, index) => {
if (index >= 3) {
@@ -634,7 +650,7 @@ const MyView = (props) => {
return (
<Chip
key={index}
style={{height: 30, marginRight: 5, marginTop: 2, cursor: "pointer",}}
style={{backgroundColor: "#3d3f43", height: 30, marginRight: 5, paddingLeft: 5, paddingRight: 5, height: 28, cursor: "pointer", borderColor: "#3d3f43", color: "white",}}
label={tag}
variant="outlined"
color="primary"
@@ -644,30 +660,29 @@ const MyView = (props) => {
: null}
</Grid>
</Grid>
</Grid>
{data.actions !== undefined && data.actions !== null ?
<Grid item style={{display:"flex",flexDirection:"column",justifyContent:"space-between"}}>
<Grid item style={{display:"flex",flexDirection:"column", justifyContent:"space-between"}}>
<Grid>
<IconButton
aria-label="more"
aria-controls="long-menu"
aria-haspopup="true"
style={{color: "white"}}
onClick={menuClick}
style={{padding:"0px",color:"white"}}
>
<MoreVertIcon />
</IconButton>
<Menu
id="long-menu"
anchorEl={anchorEl}
keepMounted
open={open}
onClose={() => {
setOpen(false)
setAnchorEl(null)
}}
>
<IconButton
aria-label="more"
aria-controls="long-menu"
aria-haspopup="true"
style={{color: "white"}}
onClick={menuClick}
style={{padding:"0px",color:"white", color:"#979797"}}
>
<MoreVertIcon />
</IconButton>
<Menu
id="long-menu"
anchorEl={anchorEl}
keepMounted
open={open}
onClose={() => {
setOpen(false)
setAnchorEl(null)
}}
>
<MenuItem style={{backgroundColor: inputColor, color: "white"}} onClick={() => {
setModalOpen(true)
setEditingWorkflow(data)
@@ -685,26 +700,25 @@ const MyView = (props) => {
exportWorkflow(data)
setOpen(false)
}} key={"export"}>{"Export"}</MenuItem>
<MenuItem style={{backgroundColor: inputColor, color: "white"}} onClick={() => {
<MenuItem style={{backgroundColor: inputColor, color: "white"}} onClick={() => {
setDeleteModalOpen(true)
setSelectedWorkflowId(data.id)
setOpen(false)
}} key={"delete"}>{"Delete"}</MenuItem>
</Menu>
</Grid>
<Grid>
<Link to={"/workflows/"+data.id}>
<Tooltip title="Edit workflow" placement="bottom">
<EditIcon style={{background: "#F85A3E",
boxShadow: "0px 1px 2px rgba(0, 0, 0, 0.16), 0px 2px 4px rgba(0, 0, 0, 0.12), 0px 1px 8px rgba(0, 0, 0, 0.1)",
borderRadius: "4px", color: "black", height: "30px", "width": "30px", fontSize: "small"}} />
</Tooltip>
</Link>
</Grid>
</Menu>
</Grid>
<Grid>
<Link to={"/workflows/"+data.id}>
<Tooltip title="Edit workflow" placement="bottom">
<EditIcon style={{background: "#F85A3E", borderRadius: "4px", color: "black", height: 20, width: 20, padding: 7, fontSize: "small"}} />
</Tooltip>
</Link>
</Grid>
</Grid>
: null}
</Paper>
: null}
</Paper>
</Grid>
)
}
@@ -772,7 +786,6 @@ borderRadius: "4px", color: "black", height: "30px", "width": "30px", fontSize:
marginTop: "5px",
color: "white",
backgroundColor: surfaceColor,
cursor: "pointer",
display: "flex",
}
@@ -1294,13 +1307,12 @@ borderRadius: "4px", color: "black", height: "30px", "width": "30px", fontSize:
let workflowData = "";
if (workflows.length > 0) {
const columns = [
{ field: 'id', headerName: 'ID', width: 70, sortable: false, },
{ field: 'title', headerName: 'Title', width: 330, },
{ field: 'actions', headerName: 'Actions', width: 200, sortable: false,
disableClickEventBubbling: true,
renderCell: (params) => {
const data = params.row.record;
let [schedules, webhooks] = getWorkFlowMeta(data);
let [triggers, schedules, webhooks, subflows] = getWorkflowMeta(data);
return <Grid item>
<Link to={"/workflows/"+data.id}>
@@ -1340,10 +1352,11 @@ borderRadius: "4px", color: "black", height: "30px", "width": "30px", fontSize:
if (index >= 3) {
return null
}
return (
<Chip
key={index}
style={{height: 30, marginRight: 5, marginTop: 2, cursor: "pointer",}}
style={{backgroundColor: "#3d3f43", height: 30, marginRight: 5, paddingLeft: 5, paddingRight: 5, height: 28, cursor: "pointer", borderColor: "#3d3f43", color: "white",}}
label={tag}
variant="outlined"
color="primary"
@@ -1445,13 +1458,13 @@ borderRadius: "4px", color: "black", height: "30px", "width": "30px", fontSize:
</div>
{view === "grid" && (
<div style={paperAppContainer}>
<Grid container spacing={4} style={paperAppContainer}>
{workflows.map((data, index) => {
return (
<WorkflowPaper key={index} data={data} />
)
})}
</div>
</Grid>
)}
{view === "list" && (
+12 -12
View File
@@ -447,12 +447,12 @@ const Workflows = (props) => {
for (var branchkey in data.branches) {
const branch = data.branches[branchkey]
if (branch.source_id === data.actions[key].id) {
console.log("CHANGING SOURCE ID IN ACTION")
//console.log("CHANGING SOURCE ID IN ACTION")
branch.source_id = newId
}
if (branch.destination_id === data.actions[key].id) {
console.log("CHANGING DESTINATION ID IN ACTION")
//console.log("CHANGING DESTINATION ID IN ACTION")
branch.destination_id = newId
}
}
@@ -505,10 +505,8 @@ const Workflows = (props) => {
data = sanitizeWorkflow(data)
alert.info("Sanitizing and publishing "+data.name)
const url = isCloud ? globalUrl : "https://shuffler.io"
// This ALWAYS talks to Shuffle cloud
fetch(url+"/api/v1/workflows/"+data.id+"/publish", {
fetch(globalUrl+"/api/v1/workflows/"+data.id+"/publish", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -521,7 +519,11 @@ const Workflows = (props) => {
if (response.status !== 200) {
console.log("Status not 200 for workflow publish :O!")
} else {
alert.success("Successfully published workflow")
if (isCloud) {
alert.success("Successfully published workflow")
} else {
alert.success("Successfully published workflow to https://shuffler.io")
}
}
return response.json()
@@ -690,12 +692,10 @@ const Workflows = (props) => {
setNewWorkflowTags(JSON.parse(JSON.stringify(data.tags)))
}
}} key={"change"}>{"Change details"}</MenuItem>
{isCloud ?
<MenuItem style={{backgroundColor: inputColor, color: "white"}} onClick={() => {
console.log("Should publish", data)
publishWorkflow(data)
}} key={"publish"}>{"Publish Workflow"}</MenuItem>
: null}
<MenuItem style={{backgroundColor: inputColor, color: "white"}} onClick={() => {
console.log("Should publish", data)
publishWorkflow(data)
}} key={"publish"}>{"Publish Workflow"}</MenuItem>
<MenuItem style={{backgroundColor: inputColor, color: "white"}} onClick={() => {
copyWorkflow(data)
setOpen(false)