Added more hybrid features
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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, "")
|
||||
}}>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ?
|
||||
|
||||
Reference in New Issue
Block a user