Added more hybrid features

This commit is contained in:
frikky
2021-03-27 18:57:26 +01:00
parent 45f20e1326
commit 7814eb1e08
10 changed files with 263 additions and 636 deletions
+74 -21
View File
@@ -191,6 +191,45 @@ const Admin = (props) => {
});
}
const handleStopOrgSync = (org_id) => {
if (org_id === undefined || org_id === null) {
alert.error("Couldn't get org "+org_id)
return
}
const data = {}
const url = globalUrl + '/api/v1/orgs/' + org_id + "/stop_sync";
fetch(url, {
mode: 'cors',
method: 'POST',
body: JSON.stringify(data),
credentials: 'include',
crossDomain: true,
withCredentials: true,
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
})
.then(response => {
if (response.status === 200) {
console.log("Cloud sync success?")
alert.success("Successfully stopped cloud sync")
} else {
console.log("Cloud sync fail?")
alert.error("Failed stopping sync. Try again, and contact support if this persists.")
}
return response.json()
})
.then((responseJson) => {
handleGetOrg(org_id)
})
.catch(error => {
alert.error("Err: " + error.toString())
})
}
const enableCloudSync = (apikey, organization, disableSync) => {
setOrgSyncResponse("")
@@ -1475,27 +1514,41 @@ const Admin = (props) => {
<Typography style={{whiteSpace: "nowrap", marginTop: 25, marginRight: 10}}>
Your Apikey
</Typography>
<TextField
color="primary"
style={{backgroundColor: theme.palette.inputColor, }}
InputProps={{
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
fullWidth={true}
disabled={true}
autoComplete="cloud apikey"
id="apikey_field"
margin="normal"
placeholder="Cloud Apikey"
variant="outlined"
defaultValue={userSettings.apikey}
/>
</div>
<div style={{display: "flex"}}>
<TextField
color="primary"
style={{backgroundColor: theme.palette.inputColor, }}
InputProps={{
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
fullWidth={true}
disabled={true}
autoComplete="cloud apikey"
id="apikey_field"
margin="normal"
placeholder="Cloud Apikey"
variant="outlined"
defaultValue={userSettings.apikey}
/>
{selectedOrganization.cloud_sync_active ?
<Button
style={{ width: 150, height: 50, marginLeft: 10, marginTop: 17, }}
variant="contained"
color="primary"
onClick={() => {
handleStopOrgSync(selectedOrganization.id)
}}
>
Stop Sync
</Button>
: null}
</div>
</div>
</div>
:
<div>
+29 -5
View File
@@ -785,6 +785,10 @@ const AngularWorkflow = (props) => {
console.log(responseJson)
alert.error("Failed to save: "+responseJson.reason)
} else {
if (responseJson.new_id !== undefined && responseJson.new_id !== null) {
window.location.pathname = "/workflows/"+responseJson.new_id
}
success = true
if (responseJson.errors !== undefined) {
//console.log(responseJson)
@@ -800,6 +804,7 @@ const AngularWorkflow = (props) => {
setWorkflow(workflow)
}
//alert.success("Successfully saved workflow")
setSavingState(1)
setTimeout(() => {
@@ -833,6 +838,11 @@ const AngularWorkflow = (props) => {
console.log("FIXME: Might have forgotten to save before executing.")
}
if (workflow.public) {
alert.info("Save it to get a new version")
}
var returncheck = monitorUpdates()
if (!returncheck) {
alert.error("No startnode set.")
@@ -1041,7 +1051,7 @@ const AngularWorkflow = (props) => {
})
.catch(error => {
setAuthLoaded(true)
alert.error("Auth loading error: ", error.toString())
alert.error("Auth loading error: "+error.toString())
})
}
@@ -1110,6 +1120,11 @@ const AngularWorkflow = (props) => {
responseJson.errors = []
}
if (responseJson.public) {
alert.info("This workflow is public. You'll have to save it to make it your own!")
setLastSaved(false)
}
setWorkflow(responseJson)
setWorkflowDone(true)
})
@@ -6256,6 +6271,14 @@ const AngularWorkflow = (props) => {
<h2 style={{margin: 0,}}>
{workflow.name}
</h2>
{workflow.public ?
<h2 style={{margin: 0,}}>
Public Workflow PREVIEW
</h2>
:
null
}
</Breadcrumbs>
</div>
</div>
@@ -6380,7 +6403,7 @@ const AngularWorkflow = (props) => {
</Menu>
<Tooltip color="secondary" title="Workflow settings" placement="top-start">
<span>
<Button color="primary" style={{height: 50, marginLeft: 10, }} variant="outlined" onClick={(event) => {
<Button disabled={workflow.public} color="primary" style={{height: 50, marginLeft: 10, }} variant="outlined" onClick={(event) => {
setShowShuffleMenu(!showShuffleMenu)
setNewAnchor(event.currentTarget)
}}>
@@ -6407,9 +6430,9 @@ const AngularWorkflow = (props) => {
</span>
</Tooltip>
:
<Tooltip color="primary" title="Test execution" placement="top">
<Tooltip color="primary" title="Test Execution" placement="top">
<span>
<Button disabled={executionRequestStarted || !workflow.isValid} style={{height: boxSize, width: boxSize}} color="primary" variant="contained" onClick={() => {
<Button disabled={workflow.public || executionRequestStarted || !workflow.isValid} style={{height: boxSize, width: boxSize}} color="primary" variant="contained" onClick={() => {
executeWorkflow(executionText, workflow.start)
}}>
<PlayArrowIcon style={{ fontSize: 60}} />
@@ -6425,6 +6448,7 @@ const AngularWorkflow = (props) => {
<TextField
id="execution_argument_input_field"
style={textFieldStyle}
disabled={workflow.public}
InputProps={{
style: innerTextfieldStyle,
}}
@@ -6461,7 +6485,7 @@ const AngularWorkflow = (props) => {
</Tooltip>
<Tooltip color="secondary" title="Show executions" placement="top-start">
<span>
<Button color="primary" style={{height: 50, marginLeft: 10, }} variant="outlined" onClick={() => {
<Button disabled={workflow.public} color="primary" style={{height: 50, marginLeft: 10, }} variant="outlined" onClick={() => {
setExecutionModalOpen(true)
getWorkflowExecution(props.match.params.key, "")
}}>
+3 -3
View File
@@ -380,7 +380,7 @@ const Apps = (props) => {
}
if (data.sharing) {
setSharingConfiguration("everyone")
setSharingConfiguration(isCloud ? "public" : "everyone")
}
}
}}>
@@ -602,7 +602,7 @@ const Apps = (props) => {
const userRoles = [
"you",
"everyone",
isCloud ? "public" : "everyone",
]
//fetch(globalUrl+"/api/v1/get_openapi/"+urlParams.get("id"),
@@ -666,7 +666,7 @@ const Apps = (props) => {
if (event.target.value === "you") {
updateAppField(selectedApp.id, "sharing", false)
} else if (event.target.value === "everyone") {
} else if (event.target.value === "everyone" || event.target.value === "public") {
updateAppField(selectedApp.id, "sharing", true)
} else {
console.log("Can't handle value for sharing: ", event.target.value)
+80 -13
View File
@@ -82,6 +82,7 @@ const Workflows = (props) => {
const [deleteModalOpen, setDeleteModalOpen] = 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 isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"
@@ -390,10 +391,7 @@ const Workflows = (props) => {
}
}
const exportWorkflow = (data) => {
console.log("export")
let exportFileDefaultName = data.name+'.json';
const sanitizeWorkflow = (data) => {
data["owner"] = ""
console.log(data)
if (data.triggers !== null && data.triggers !== undefined) {
@@ -413,16 +411,17 @@ const Workflows = (props) => {
for (var branchkey in data.branches) {
const branch = data.branches[branchkey]
if (branch.source_id === trigger.id) {
console.log("CHANGING SOURCE ID")
//console.log("CHANGING SOURCE ID")
branch.source_id = newId
}
if (branch.destination_id === trigger.id) {
console.log("CHANGING DESTINATION ID")
//console.log("CHANGING DESTINATION ID")
branch.destination_id = newId
}
}
trigger.environment = isCloud ? "cloud" : "Shuffle"
trigger.id = newId
}
}
@@ -458,6 +457,7 @@ const Workflows = (props) => {
}
}
data.actions[key].environment = isCloud ? "cloud" : "Shuffle"
data.actions[key].id = newId
}
}
@@ -482,9 +482,16 @@ const Workflows = (props) => {
// These are backwards.. True = saved before. Very confuse.
data["previously_saved"] = false
data["first_save"] = false
data.execution_org = {"id": ""}
console.log(data)
return data
}
const exportWorkflow = (data) => {
console.log("export")
let exportFileDefaultName = data.name+'.json';
data = sanitizeWorkflow(data)
let dataStr = JSON.stringify(data)
let dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr);
let linkElement = document.createElement('a');
@@ -493,6 +500,44 @@ const Workflows = (props) => {
linkElement.click();
}
const publishWorkflow = (data) => {
data = JSON.parse(JSON.stringify(data))
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", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify(data),
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for workflow publish :O!")
} else {
alert.success("Successfully published workflow")
}
return response.json()
})
.then((responseJson) => {
if (responseJson.reason !== undefined) {
alert.error("Failed publishing: ", responseJson.reason)
}
getAvailableWorkflows()
})
.catch(error => {
alert.error(error.toString())
})
}
const copyWorkflow = (data) => {
data = JSON.parse(JSON.stringify(data))
alert.success("Copying workflow "+data.name)
@@ -564,11 +609,16 @@ const Workflows = (props) => {
boxWidth = "4px"
}
var boxColor = "orange"
var boxColor = "#f85a3e"
if (data.is_valid) {
boxColor = "green"
}
//console.log(data)
if (!data.previously_saved) {
boxColor = "#f85a3e"
}
const menuClick = (event) => {
setOpen(!open)
setAnchorEl(event.currentTarget);
@@ -640,10 +690,16 @@ 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={() => {
copyWorkflow(data)
setOpen(false)
}} key={"copy"}>{"Copy"}</MenuItem>
}} key={"duplicate"}>{"Duplicate Workflow"}</MenuItem>
<MenuItem style={{backgroundColor: inputColor, color: "white"}} onClick={() => {
exportWorkflow(data)
setOpen(false)
@@ -1005,7 +1061,7 @@ const Workflows = (props) => {
if (editingWorkflow.id !== undefined) {
console.log("Building original workflow")
method = "PUT"
extraData = "/"+editingWorkflow.id
extraData = "/"+editingWorkflow.id+"?skip_save=true"
workflowdata = editingWorkflow
console.log("REMOVING OWNER")
@@ -1043,6 +1099,7 @@ const Workflows = (props) => {
} else if (!redirect) {
// Update :)
getAvailableWorkflows()
setImportLoading(false)
} else {
alert.info("Successfully changed basic info for workflow")
}
@@ -1051,12 +1108,15 @@ const Workflows = (props) => {
})
.catch(error => {
alert.error(error.toString())
setImportLoading(false)
});
}
const importFiles = (event) => {
console.log("Importing!")
setImportLoading(true)
const file = event.target.value
if (event.target.files.length > 0) {
for (var key in event.target.files) {
@@ -1077,6 +1137,7 @@ const Workflows = (props) => {
data = JSON.parse(reader.result)
} catch (e) {
alert.error("Invalid JSON: "+e)
setImportLoading(false)
return
}
@@ -1242,9 +1303,15 @@ const Workflows = (props) => {
</Tooltip>
: null}
<Tooltip color="primary" title={"Import workflows"} placement="top">
<Button color="primary" style={{}} variant="text" onClick={() => upload.click()}>
<PublishIcon />
</Button>
{importLoading ?
<Button color="primary" style={{}} variant="text" onClick={() => {}}>
<CircularProgress style={{maxHeight: 15, maxWidth: 15,}} />
</Button>
:
<Button color="primary" style={{}} variant="text" onClick={() => upload.click()}>
<PublishIcon />
</Button>
}
</Tooltip>
<input hidden type="file" multiple="multiple" ref={(ref) => upload = ref} onChange={importFiles} />
{workflows.length > 0 ?