Merge branch 'nightly' into automation
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
/* eslint-disable react/no-multi-comp */
|
||||
import React, { useState } from "react";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import theme from '../theme.jsx';
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import {
|
||||
CircularProgress,
|
||||
@@ -20,11 +22,8 @@ const surfaceColor = "#27292D";
|
||||
const inputColor = "#383B40";
|
||||
|
||||
const boxStyle = {
|
||||
paddingLeft: "30px",
|
||||
paddingRight: "30px",
|
||||
paddingBottom: "30px",
|
||||
paddingTop: "30px",
|
||||
backgroundColor: surfaceColor,
|
||||
padding: 40,
|
||||
backgroundColor: theme.palette.backgroundColor,
|
||||
};
|
||||
|
||||
const useStyles = makeStyles({
|
||||
@@ -41,8 +40,10 @@ const AdminAccount = (props) => {
|
||||
const [firstRequest, setFirstRequest] = useState(true);
|
||||
const [loginLoading, setLoginLoading] = useState(false);
|
||||
|
||||
|
||||
// Used to swap from login to register. True = login, false = register
|
||||
const register = true;
|
||||
let navigate = useNavigate();
|
||||
|
||||
const classes = useStyles();
|
||||
// Error messages etc
|
||||
@@ -70,13 +71,16 @@ const AdminAccount = (props) => {
|
||||
setLoginInfo(responseJson["reason"]);
|
||||
} else {
|
||||
if (responseJson.reason === "redirect") {
|
||||
window.location.pathname = "/login";
|
||||
setTimeout(() => {
|
||||
window.location.pathname = "/login";
|
||||
}, 2500)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
setLoginInfo("Error in userdata: ", error);
|
||||
setLoginInfo("Error in userdata (1): ", error);
|
||||
navigate("/loginsetup")
|
||||
});
|
||||
};
|
||||
|
||||
@@ -108,13 +112,17 @@ const AdminAccount = (props) => {
|
||||
setLoginInfo(responseJson["reason"]);
|
||||
} else {
|
||||
setLoginInfo("Successful register :)");
|
||||
window.location.pathname = "/login";
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.pathname = "/login";
|
||||
}, 2500)
|
||||
}
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
setLoginLoading(false);
|
||||
setLoginInfo("Error in userdata: ", error);
|
||||
setLoginInfo("Error in userdata (2): ", error);
|
||||
setLoginLoading(false)
|
||||
navigate("/loginsetup")
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -575,11 +575,17 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}, [editWorkflowModalOpen])
|
||||
|
||||
useEffect(() => {
|
||||
if(selectedTrigger?.trigger_type === "SUBFLOW"){
|
||||
// Check if selectedTriggerIndex is a number >= 0
|
||||
if (isNaN(selectedTriggerIndex) || selectedTriggerIndex < 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (selectedTrigger?.trigger_type === "SUBFLOW" && selectedTriggerIndex !== undefined && selectedTriggerIndex !== null && workflow?.triggers[selectedTriggerIndex].parameters.length > 1) {
|
||||
setSelectedTriggerValue(workflow.triggers[selectedTriggerIndex].parameters[1].value || "")
|
||||
} else if(selectedTrigger?.trigger_type === "USERINPUT"){
|
||||
} else if (selectedTrigger?.trigger_type === "USERINPUT" && selectedTriggerIndex !== undefined && selectedTriggerIndex !== null && workflow?.triggers[selectedTriggerIndex].parameters.length > 0) {
|
||||
setSelectedTriggerValue(workflow.triggers[selectedTriggerIndex].parameters[0].value || "Do you want to continue the workflow? Start parameters: $exec")
|
||||
}
|
||||
|
||||
}, [selectedTriggerIndex, selectedTrigger, workflow])
|
||||
|
||||
useEffect(() => {
|
||||
@@ -948,11 +954,15 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (workflow.actions?.length == 1) {
|
||||
if (workflow.actions[0].app_id == "3e320a20966d33c9b7e6790b2705f0bf") {
|
||||
if (workflow?.actions?.length == 1) {
|
||||
if (workflow?.actions[0].app_id == "3e320a20966d33c9b7e6790b2705f0bf") {
|
||||
setWorkflowAsCode(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (workflow?.suborg_distribution !== undefined && workflow?.suborg_distribution !== null && workflow?.suborg_distribution.length > 0) {
|
||||
getChildWorkflows(workflow.id)
|
||||
}
|
||||
}, [workflow]);
|
||||
|
||||
// Event for making sure app is correct
|
||||
@@ -1288,56 +1298,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return
|
||||
}
|
||||
|
||||
//console.log("Failed in trigger selection: ", selectedTriggerIndex, "Trigger: ", selectedTrigger)
|
||||
|
||||
var found = null
|
||||
try {
|
||||
for (var key in workflows) {
|
||||
const curworkflow = workflows[key]
|
||||
const curtrigger = curworkflow?.triggers[selectedTriggerIndex]
|
||||
if (curtrigger === undefined || curtrigger === null) {
|
||||
console.log("Failed in trigger selection (1): ", curworkflow)
|
||||
continue
|
||||
}
|
||||
|
||||
if (curtrigger?.parameters === undefined || curtrigger?.parameters === null || curtrigger?.parameters.length === 0) {
|
||||
console.log("Failed in trigger selection (2): ", curworkflow)
|
||||
continue
|
||||
}
|
||||
|
||||
if (curtrigger?.parameters[0] === undefined || curtrigger?.parameters[0] === null || curtrigger?.parameters[0].value === undefined || curtrigger?.parameters[0].value === null) {
|
||||
console.log("Failed in trigger selection (3): ", curworkflow)
|
||||
continue
|
||||
}
|
||||
|
||||
if (curtrigger?.parameters[0].value === selectedTrigger?.parameters[0]?.value) {
|
||||
found = curworkflow
|
||||
setSubworkflow(curworkflow)
|
||||
}
|
||||
}
|
||||
|
||||
if (found !== null) {
|
||||
setSubworkflow(found)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Failed in trigger selection (4): ", e)
|
||||
//return
|
||||
}
|
||||
|
||||
if (found) {
|
||||
const startNode = found.actions?.find((action) => action.id === workflow?.triggers[selectedTriggerIndex]?.parameters[3]?.value)
|
||||
setSubworkflowStartnode(startNode)
|
||||
}
|
||||
|
||||
/*
|
||||
// Multi-tenant sometimes gives us shit :(
|
||||
if (selectedTrigger === undefined || selectedTrigger === null || selectedTrigger.id === undefined || selectedTrigger.id === null && selectedTriggerIndex >= 0) {
|
||||
if (workflow.triggers !== undefined && workflow.triggers !== null && workflow.triggers.length > selectedTriggerIndex) {
|
||||
setSelectedTrigger(workflow.triggers[selectedTriggerIndex])
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Check if the running state is correct or not according to allTriggers
|
||||
if (allTriggers !== undefined && allTriggers !== null) {
|
||||
// Find the active trigger
|
||||
@@ -1545,6 +1505,8 @@ const AngularWorkflow = (defaultprops) => {
|
||||
if (workflow.org_id !== undefined && workflow.org_id !== null && workflow.org_id.length > 0) {
|
||||
headers["Org-Id"] = workflow.org_id
|
||||
}
|
||||
|
||||
setWorkflows([])
|
||||
|
||||
fetch(globalUrl + "/api/v1/workflows?subflow=true", {
|
||||
method: "GET",
|
||||
@@ -1562,7 +1524,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
if (responseJson !== undefined) {
|
||||
|
||||
// Sets up subflow trigger with the right info
|
||||
if (trigger_index > -1) {
|
||||
if (isNaN(trigger_index) === false && trigger_index > -1) {
|
||||
|
||||
var baseSubflow = {}
|
||||
const trigger = workflow.triggers[trigger_index];
|
||||
@@ -1592,10 +1554,10 @@ const AngularWorkflow = (defaultprops) => {
|
||||
if (Object.getOwnPropertyNames(baseSubflow).length > 0) {
|
||||
const foundAction = baseSubflow.actions.find(action => action?.id === param.value)
|
||||
if (foundAction !== null && foundAction !== undefined) {
|
||||
setSubworkflowStartnode(foundAction);
|
||||
setSubworkflowStartnode(foundAction)
|
||||
}
|
||||
} else {
|
||||
setSubworkflowStartnode(param.value);
|
||||
setSubworkflowStartnode(param.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2540,18 +2502,25 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
*/
|
||||
|
||||
// FIXME: What is this?
|
||||
if (cy !== undefined && cy !== null) {
|
||||
// scale: 0.3,
|
||||
// bg: "#27292d",
|
||||
const cyImageData = cy.png({
|
||||
output: "base64uri",
|
||||
maxWidth: 480,
|
||||
maxHeight: 270,
|
||||
})
|
||||
if (cy?.png !== undefined && cy?.png !== null) {
|
||||
try {
|
||||
const cyImageData = cy.png({
|
||||
output: "base64uri",
|
||||
maxWidth: 480,
|
||||
maxHeight: 270,
|
||||
})
|
||||
|
||||
if (cyImageData !== undefined && cyImageData !== null && cyImageData.length > 0) {
|
||||
useworkflow.image = cyImageData
|
||||
}
|
||||
if (cyImageData !== undefined && cyImageData !== null && cyImageData.length > 0) {
|
||||
useworkflow.image = cyImageData
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Failed to get image data: ", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useworkflow.id === undefined || useworkflow.id === null || useworkflow.id.length === 0) {
|
||||
@@ -3948,7 +3917,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
apps.push(responseJson.actions[index]);
|
||||
}
|
||||
|
||||
console.log("Setting used subflow apps: ", apps)
|
||||
//console.log("Setting used subflow apps: ", apps)
|
||||
setUsedSubflowApps(apps);
|
||||
|
||||
return apps
|
||||
@@ -3961,6 +3930,10 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
const findWorkflowDiff = (parentWorkflow, childWorkflow) => {
|
||||
// Ensures new memory is used
|
||||
parentWorkflow = JSON.parse(JSON.stringify(parentWorkflow))
|
||||
childWorkflow = JSON.parse(JSON.stringify(childWorkflow))
|
||||
|
||||
var diff = {
|
||||
"different": false,
|
||||
"environment": false,
|
||||
@@ -3978,9 +3951,13 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return diff
|
||||
}
|
||||
|
||||
|
||||
var parentEnvironment = ""
|
||||
var childEnvironment = ""
|
||||
|
||||
if (parentWorkflow.triggers !== undefined && parentWorkflow.triggers !== null && parentWorkflow.triggers.length > 0) {
|
||||
parentWorkflow.actions = parentWorkflow.actions.concat(parentWorkflow.triggers)
|
||||
}
|
||||
|
||||
for (var parentKey in parentWorkflow.actions) {
|
||||
const parentAction = parentWorkflow.actions[parentKey]
|
||||
if (parentAction.environment !== undefined && parentAction.environment !== null && parentAction.environment !== "") {
|
||||
@@ -3992,6 +3969,19 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
var found = false
|
||||
if (childWorkflow.triggers !== undefined && childWorkflow.triggers !== null && childWorkflow.triggers.length > 0) {
|
||||
for (var triggerKey in childWorkflow.triggers) {
|
||||
if (childWorkflow.triggers[triggerKey].replacement_for_trigger !== parentAction.id) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Rewrapping the ID just in case
|
||||
childWorkflow.triggers[triggerKey].id = childWorkflow.triggers[triggerKey].replacement_for_trigger
|
||||
childWorkflow.actions.push(childWorkflow.triggers[triggerKey])
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for (var childKey in childWorkflow.actions) {
|
||||
const childAction = childWorkflow.actions[childKey]
|
||||
if (childAction.environment !== undefined && childAction.environment !== null && childAction.environment !== "") {
|
||||
@@ -4038,6 +4028,10 @@ const AngularWorkflow = (defaultprops) => {
|
||||
continue
|
||||
}
|
||||
|
||||
var parentworkflow = ""
|
||||
var parentstartnode = ""
|
||||
var childworkflow = ""
|
||||
var childstartnode = ""
|
||||
for (var parentParamIndex in parentAction.parameters) {
|
||||
const parentParam = parentAction.parameters[parentParamIndex]
|
||||
for (var childParamIndex in childAction.parameters) {
|
||||
@@ -4046,20 +4040,38 @@ const AngularWorkflow = (defaultprops) => {
|
||||
continue
|
||||
}
|
||||
|
||||
if (childParam.name === "workflow" || childParam.name === "subflow") {
|
||||
parentworkflow = parentParam.value
|
||||
childworkflow = childParam.value
|
||||
continue
|
||||
}
|
||||
|
||||
if (childParam.name == "startnode") {
|
||||
parentstartnode = parentParam.value
|
||||
childstartnode = childParam.value
|
||||
continue
|
||||
}
|
||||
|
||||
if (childParam.value !== parentParam.value) {
|
||||
actionDiff.parameters.push(childParam.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parentworkflow !== childworkflow && parentstartnode !== childstartnode) {
|
||||
actionDiff.parameters.push("subflow")
|
||||
}
|
||||
}
|
||||
|
||||
if (actionDiff.parameters.length > 0) {
|
||||
actionDiff.params = true
|
||||
}
|
||||
|
||||
/*
|
||||
if (!found) {
|
||||
actionDiff.new = true
|
||||
}
|
||||
*/
|
||||
|
||||
if (actionDiff !== undefined && actionDiff !== null && Object.keys(actionDiff).length > 1) {
|
||||
actionDiff.label = parentAction.label.replaceAll("_", " ")
|
||||
@@ -6352,11 +6364,15 @@ const AngularWorkflow = (defaultprops) => {
|
||||
if (workflow.org_id !== undefined && workflow.org_id !== null && workflow.org_id.length > 0 && originalWorkflow.org_id !== undefined && originalWorkflow.org_id !== null && originalWorkflow.org_id.length > 0 && workflow.org_id === originalWorkflow.org_id) {
|
||||
// Allows a parent workflow to control the schedule
|
||||
} else if (data.replacement_for_trigger !== undefined && data.replacement_for_trigger !== null && data.replacement_for_trigger.length > 0) {
|
||||
toast.warning("This schedule is controlled by the parent workflow. If you want additional schedule control, please add a custom schedule to this workflow.", {
|
||||
autoClose: 30000,
|
||||
})
|
||||
event.target.unselect()
|
||||
return
|
||||
|
||||
// No custom control on cloud
|
||||
if (isCloud) {
|
||||
toast.warning("This schedule is controlled by the parent workflow. If you want additional schedule control, please add a custom schedule to this workflow.", {
|
||||
autoClose: 30000,
|
||||
})
|
||||
event.target.unselect()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
} else if (data.app_name === "Webhook" && trigger_index >= 0) {
|
||||
@@ -6932,7 +6948,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
)
|
||||
if (targetnode !== -1) {
|
||||
if (workflow.triggers[targetnode].app_name === "User Input" || workflow.triggers[targetnode].app_name === "Shuffle Workflow" || workflow.triggers[targetnode].app_name === "Shuffle Subflow") {
|
||||
console.log("User Input or Shuffle Workflow")
|
||||
//console.log("User Input or Shuffle Workflow")
|
||||
} else {
|
||||
toast("Can't have triggers as target of branch")
|
||||
event.target.remove()
|
||||
@@ -9264,11 +9280,15 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
insertedNodes = insertedNodes.concat(newedges);
|
||||
setWorkflow(inputworkflow);
|
||||
setWorkflow(inputworkflow)
|
||||
|
||||
// Reset view for cytoscape
|
||||
if (cy !== undefined && cy !== null) {
|
||||
cy.add(insertedNodes)
|
||||
try {
|
||||
cy.add(insertedNodes)
|
||||
} catch (error) {
|
||||
console.log("Error adding nodes to cytoscape (6): ", error)
|
||||
}
|
||||
|
||||
try {
|
||||
cy.fit(null, 250)
|
||||
@@ -9347,12 +9367,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
}
|
||||
|
||||
//if (selectedNode.data("id") === selectedAction.id) {
|
||||
// setSelectedApp({});
|
||||
// setSelectedAction({});
|
||||
//setSelectedTrigger({});
|
||||
//setSelectedTriggerIndex({});
|
||||
//}
|
||||
const parsedSelection = cy.$(":selected");
|
||||
if (selectedNode.data().decorator === true && selectedNode.data("type") !== "COMMENT") {
|
||||
toast("This node can't be deleted.");
|
||||
@@ -9552,7 +9566,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
if (firstrequest) {
|
||||
setFirstrequest(false)
|
||||
getWorkflow(props.match.params.key, {})
|
||||
getChildWorkflows(props.match.params.key)
|
||||
getRevisionHistory(props.match.params.key)
|
||||
loadTriggers()
|
||||
getApps()
|
||||
@@ -9785,9 +9798,14 @@ const AngularWorkflow = (defaultprops) => {
|
||||
toast("Successfully stopped schedule");
|
||||
}
|
||||
|
||||
workflow.triggers[triggerindex].status = "stopped";
|
||||
trigger.status = "stopped";
|
||||
setSelectedTrigger(trigger);
|
||||
if (triggerindex !== undefined && triggerindex !== null && triggerindex >= 0) {
|
||||
workflow.triggers[triggerindex].status = "stopped";
|
||||
}
|
||||
|
||||
//trigger.status = "stopped";
|
||||
//console.log("TRIGGER: ", trigger)
|
||||
//setSelectedTrigger(trigger);
|
||||
|
||||
setWorkflow(workflow);
|
||||
saveWorkflow(workflow)
|
||||
|
||||
@@ -11446,7 +11464,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
var type = "app"
|
||||
const baseImage = <LibraryBooksIcon />
|
||||
return (
|
||||
<div style={{ position: "relative", marginTop: 15, marginLeft: 0, marginRight: 10, position: "absolute", color: "white", zIndex: 1001, backgroundColor: theme.palette.inputColor, minWidth: leftBarSize - 10, maxWidth: leftBarSize - 10, boxShadows: "none", overflowX: "hidden", }}>
|
||||
<div style={{ position: "relative", marginTop: 15, marginLeft: 0, marginRight: 10, position: "absolute", color: "white", zIndex: 1001, backgroundColor: theme.palette.inputColor, minWidth: leftBarSize+30, maxWidth: 340, boxShadows: "none", overflowX: "hidden", }}>
|
||||
<List style={{ backgroundColor: theme.palette.inputColor, }}>
|
||||
{hits.length === 0 ?
|
||||
<ListItem style={outerlistitemStyle}>
|
||||
@@ -11736,7 +11754,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}}
|
||||
>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
Click one of the relevant public apps below to Activate it for your organization.
|
||||
Click one of the public apps below to Activate it for your organization.
|
||||
</Typography>
|
||||
<InstantSearch searchClient={searchClient} indexName="appsearch" onClick={() => {
|
||||
console.log("CLICKED")
|
||||
@@ -14637,20 +14655,19 @@ const AngularWorkflow = (defaultprops) => {
|
||||
cy.add(cybranch);
|
||||
}
|
||||
|
||||
console.log("Value to be set: ", e.target.value);
|
||||
try {
|
||||
workflow.triggers[
|
||||
selectedTriggerIndex
|
||||
].parameters[3].value = e.target.value.id;
|
||||
} catch {
|
||||
workflow.triggers[selectedTriggerIndex].parameters[3] =
|
||||
{
|
||||
name: "startnode",
|
||||
value: e.target.value.id,
|
||||
};
|
||||
workflow.triggers[selectedTriggerIndex].parameters[3].value = e.target.value.id
|
||||
} catch(e) {
|
||||
console.log("Error: ", e)
|
||||
workflow.triggers[selectedTriggerIndex].parameters[3] =
|
||||
{
|
||||
name: "startnode",
|
||||
value: e.target.value.id,
|
||||
};
|
||||
}
|
||||
|
||||
setWorkflow(workflow);
|
||||
setWorkflow(workflow)
|
||||
setUpdate(Math.random())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14934,12 +14951,15 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}}
|
||||
>
|
||||
<div style={{ flex: "10" }}>
|
||||
<b>Select a workflow to execute </b>
|
||||
<b>Select a workflow to run</b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{workflow.triggers[selectedTriggerIndex].parameters[0].value
|
||||
.length === 0 ? null : workflow.triggers[selectedTriggerIndex]
|
||||
.parameters[0].value === props.match.params.key ? null : (
|
||||
.parameters[0].value === props.match.params.key ?
|
||||
null
|
||||
: (
|
||||
<div style={{ marginLeft: 5, flex: 1 }}>
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
@@ -14960,8 +14980,9 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
{workflows === undefined ||
|
||||
workflows === null ||
|
||||
workflows.length === 0 ? null : (
|
||||
|
||||
workflows.length === 0 ?
|
||||
<CircularProgress color="secondary" style={{ margin: "auto", marginTop: 10, width: 25, height: 25, }} />
|
||||
: (
|
||||
<Autocomplete
|
||||
id="subflow_search"
|
||||
autoHighlight
|
||||
@@ -15035,7 +15056,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
<Tooltip arrow placement="left" title={
|
||||
<span style={{}}>
|
||||
{data.image !== undefined && data.image !== null && data.image.length > 0 ?
|
||||
<img src={data.image} alt={data.name} style={{ backgroundColor: theme.palette.surfaceColor, maxHeight: 200, minHeigth: 200, borderRadius: theme.palette?.borderRadius, }} />
|
||||
<img src={data.image} alt={data.name} style={{ backgroundColor: theme.palette.surfaceColor, maxHeight: 200, minHeigth: 200, maxWidth: 285, borderRadius: theme.palette?.borderRadius, }} />
|
||||
: null}
|
||||
<Typography>
|
||||
Choose Subflow '{data.name}'
|
||||
@@ -15095,6 +15116,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
<b>Select the Startnode</b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Autocomplete
|
||||
id="subflow_node_search"
|
||||
autoHighlight
|
||||
@@ -18217,6 +18239,10 @@ const AngularWorkflow = (defaultprops) => {
|
||||
value={workflow.org_id}
|
||||
disabled={savingState !== 0 || suborgWorkflows?.length === 0 || allTriggers === undefined}
|
||||
onChange={(e) => {
|
||||
if (cy !== undefined && cy !== null) {
|
||||
cy.nodes().unselect()
|
||||
}
|
||||
|
||||
if (lastSaved === false && originalWorkflow.id === workflow.id) {
|
||||
setSuborgWorkflows([])
|
||||
|
||||
|
||||
@@ -2657,12 +2657,12 @@ const AppCreator = (defaultprops) => {
|
||||
if (responseJson.reason !== undefined) {
|
||||
setErrorCode(responseJson.reason);
|
||||
|
||||
if (responseJson.extra === undefined && responseJson.extra === null) {
|
||||
toast("Failed to verify: " + responseJson.reason);
|
||||
}
|
||||
toast.error("Failed to build: " + responseJson.reason, {
|
||||
autoClose: 10000
|
||||
})
|
||||
}
|
||||
} else {
|
||||
toast("Successfully uploaded openapi");
|
||||
toast.success("Successfully built openapi app! Added job to rebuild it in your hybrid runtime locations (Orborus).");
|
||||
if (window.location.pathname.includes("/new")) {
|
||||
if (responseJson.id !== undefined && responseJson.id !== null) {
|
||||
window.location = `/apps/edit/${responseJson.id}`;
|
||||
|
||||
@@ -3866,13 +3866,13 @@ const AppExplorer = (props) => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DialogTitle style={{ marginBottom: 0 }}>
|
||||
<DialogTitle style={{ marginBottom: 0, padding: 50, paddingBottom: 0, }}>
|
||||
<div style={{ textAlign: "center", color: "rgba(255,255,255,0.9)" }}>
|
||||
Are you sure you want to PUBLISH this app?
|
||||
</div>
|
||||
</DialogTitle>
|
||||
<DialogContent
|
||||
style={{ color: "rgba(255,255,255,0.65)", textAlign: "center" }}
|
||||
style={{ color: "rgba(255,255,255,0.65)", textAlign: "center", padding: 50, }}
|
||||
>
|
||||
<div>
|
||||
<Typography variant="body1" style={{ marginBottom: 20 }}>
|
||||
@@ -4120,7 +4120,7 @@ const AppExplorer = (props) => {
|
||||
</Button>
|
||||
)}
|
||||
{appType === 1 ? null :
|
||||
creatorProfile.self === true || userdata.support === true ?
|
||||
userdata?.support || userdata?.id === app?.owner || (userdata?.admin === "true" && userdata?.active_org?.id === app?.reference_org) || app?.contributors?.includes(userdata?.id) || creatorProfile?.self === true ?
|
||||
<Tooltip title="Edit App" placement="top">
|
||||
<Button
|
||||
variant="outlined"
|
||||
@@ -4167,9 +4167,9 @@ const AppExplorer = (props) => {
|
||||
Explore API
|
||||
</Button>
|
||||
</a>
|
||||
{(appdata?.owner === userdata?.id) ? (
|
||||
<Select
|
||||
value={sharingConfiguration}
|
||||
disabled={!isCloud}
|
||||
onChange={(event) => {
|
||||
if ((appdata.owner !== userdata.id) && (!userdata.support)) {
|
||||
toast("You're not the owner of this app. You can't update it.");
|
||||
@@ -4222,7 +4222,6 @@ const AppExplorer = (props) => {
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
): null }
|
||||
</div>
|
||||
) : (
|
||||
<a
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect, useContext, useCallback, memo, useMemo, useRef } from "react";
|
||||
import theme from "../theme.jsx";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import {
|
||||
TextField, Button, Typography, MenuItem, Select, Tabs, Tab, Zoom,
|
||||
@@ -590,7 +591,7 @@ const Hits = ({
|
||||
<div style={{
|
||||
flex: 1
|
||||
}}>
|
||||
{hoverEffect === index && isCloud ? (
|
||||
{hoverEffect === index ? (
|
||||
<div>
|
||||
{data.tags && (
|
||||
<Tooltip
|
||||
@@ -764,7 +765,7 @@ const SearchBox = ({ refine, searchQuery, setSearchQuery }) => {
|
||||
<TextField
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
placeholder="Search for apps"
|
||||
placeholder="Search from 2500+ public apps"
|
||||
value={localQuery}
|
||||
id="shuffle_search_field"
|
||||
inputRef={inputRef}
|
||||
@@ -2009,7 +2010,7 @@ const Apps2 = (props) => {
|
||||
}}
|
||||
/>
|
||||
<Tab
|
||||
label="Discover Apps"
|
||||
label="Discover Public Apps"
|
||||
style={{
|
||||
...tabStyle,
|
||||
marginRight: 0,
|
||||
@@ -2028,7 +2029,7 @@ const Apps2 = (props) => {
|
||||
<TextField
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
placeholder="Search for apps"
|
||||
placeholder={currTab === 1 ? "Search your apps" : "Search org apps"}
|
||||
disabled={!isLoggedIn}
|
||||
value={searchQuery}
|
||||
id="shuffle_search_field"
|
||||
|
||||
+324
-63
@@ -5,7 +5,7 @@ import theme from '../theme.jsx';
|
||||
import ReactJson from "react-json-view-ssr";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { BrowserView, MobileView } from "react-device-detect";
|
||||
import { useParams, useNavigate, Link } from "react-router-dom";
|
||||
import { useParams, useNavigate, Link, useLocation } from "react-router-dom";
|
||||
import { validateJson, GetIconInfo } from "../views/Workflows.jsx";
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import { Context } from "../context/ContextApi.jsx";
|
||||
@@ -30,7 +30,9 @@ import {
|
||||
Edit as EditIcon,
|
||||
KeyboardArrowRight as KeyboardArrowRightIcon,
|
||||
ExpandMore as ExpandMoreIcon,
|
||||
FileCopy as FileCopyIcon
|
||||
FileCopy as FileCopyIcon,
|
||||
ChevronLeft,
|
||||
ChevronRight
|
||||
} from "@mui/icons-material";
|
||||
import { fontGrid } from "@mui/material/styles/cssUtils.js";
|
||||
|
||||
@@ -51,6 +53,7 @@ const dividerColor = "rgb(225, 228, 232)";
|
||||
const hrefStyle = {
|
||||
color: "rgba(255, 255, 255, 0.8)",
|
||||
textDecoration: "none",
|
||||
marginRight: window.location.pathname.includes("/articles/") ? "0.8em" : undefined,
|
||||
};
|
||||
|
||||
|
||||
@@ -152,11 +155,33 @@ export const OuterLink = (props) => {
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const Img = (props) => {
|
||||
// Find parent container and check width
|
||||
|
||||
const isArticlePage = window.location.pathname.includes("/articles/");
|
||||
var height = "auto"
|
||||
var width = 750
|
||||
var width = isArticlePage ? 1000 : 750
|
||||
|
||||
const docsImageStyle = {
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
width: width,
|
||||
maxWidth: width,
|
||||
margin: "auto",
|
||||
marginTop: 10,
|
||||
marginBottom: 10
|
||||
}
|
||||
|
||||
const articleImageStyle = {
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
minWidth: 350,
|
||||
maxWidth: "100%",
|
||||
textAlign: "center",
|
||||
margin: "auto",
|
||||
marginTop: 20,
|
||||
marginBottom: 20,
|
||||
}
|
||||
|
||||
if (props.height !== undefined && props.height !== null) {
|
||||
height = props.height
|
||||
}
|
||||
@@ -166,11 +191,13 @@ export const Img = (props) => {
|
||||
}
|
||||
|
||||
return(
|
||||
<img
|
||||
style={{border: "1px solid rgba(255,255,255,0.3)", borderRadius: theme.palette?.borderRadius, width: width, maxWidth: width, margin: "auto", marginTop: 10, marginBottom: 10, }}
|
||||
alt={props.alt}
|
||||
src={props.src}
|
||||
/>
|
||||
<div style={{width: "100%", textAlign: "center", }}>
|
||||
<img
|
||||
style={isArticlePage ? articleImageStyle : docsImageStyle}
|
||||
alt={props.alt}
|
||||
src={props.src}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -251,8 +278,10 @@ export const CodeHandler = (props) => {
|
||||
}
|
||||
|
||||
const Docs = (defaultprops) => {
|
||||
const { globalUrl, selectedDoc, serverside, serverMobile, isLoggedIn, isLoaded } = defaultprops;
|
||||
const { globalUrl, selectedDoc, serverside, serverMobile, isLoggedIn, isLoaded, userdata } = defaultprops;
|
||||
|
||||
let navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
// Quickfix for react router 5 -> 6
|
||||
const params = useParams();
|
||||
//var props = JSON.parse(JSON.stringify(defaultprops))
|
||||
@@ -283,15 +312,31 @@ const Docs = (defaultprops) => {
|
||||
serverside === true ? "" : window.location.href
|
||||
);
|
||||
const [hashRendered, setHashRendered] = React.useState(false)
|
||||
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
const [activeSubItem, setActiveSubItem] = useState(false);
|
||||
const headingElementsRef = useRef({})
|
||||
var isArticlePage = window.location.pathname.includes("/articles/") || window.location.pathname === "/articles" ? true : false;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
//if (params["key"] === undefined) {
|
||||
// navigate("/docs/about")
|
||||
// return
|
||||
//}
|
||||
}, [])
|
||||
fetchDocList();
|
||||
setSidebarOpen(false);
|
||||
|
||||
if (props.match.params === undefined || props.match.params === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const propkey = props.match.params.key
|
||||
if (propkey === undefined || propkey === null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (location.pathname.includes("/docs/")) {
|
||||
if (propkey === "cookie_policy" || propkey === "compliance" || propkey === "privacy_policy" || propkey === "terms_of_service") {
|
||||
navigate(`/legal/${propkey}`)
|
||||
}
|
||||
}
|
||||
}, [location]);
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
@@ -460,8 +505,13 @@ const Docs = (defaultprops) => {
|
||||
}
|
||||
|
||||
const SidebarPaperStyle = {
|
||||
backgroundColor: "rgb(26,26,26)",
|
||||
backgroundColor: isArticlePage ? "transparent" : "rgb(26,26,26)",
|
||||
border: isArticlePage ? "none" : undefined,
|
||||
borderRadius: isArticlePage ? "none" : undefined,
|
||||
boxShadow: isArticlePage ? "none" : undefined,
|
||||
backgroundImage: "none",
|
||||
width: isArticlePage ? "100%" : undefined,
|
||||
height: isArticlePage ? "100%" : undefined,
|
||||
overflowX: "hidden",
|
||||
position: "relative",
|
||||
paddingLeft: 15,
|
||||
@@ -527,7 +577,7 @@ const Docs = (defaultprops) => {
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
padding: 15,
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
marginBottom: 25,
|
||||
marginBottom: isArticlePage ? 25 : 30,
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
@@ -620,7 +670,7 @@ const Docs = (defaultprops) => {
|
||||
style={{
|
||||
width: "90%",
|
||||
marginTop: 60,
|
||||
marginBottom: 20,
|
||||
marginBottom: isArticlePage ? 40 : 20,
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
}}
|
||||
/>
|
||||
@@ -630,7 +680,21 @@ const Docs = (defaultprops) => {
|
||||
marginBlock: "0.85em", alignItems: "center"
|
||||
}}>
|
||||
{element}
|
||||
<Link to={`#${id}`} style={{
|
||||
<Link to={`#${id}`}
|
||||
onClick={(e) => {
|
||||
e.preventDefault(); // Prevent default navigation
|
||||
document.getElementById(id)?.scrollIntoView({
|
||||
behavior: 'smooth'
|
||||
});
|
||||
|
||||
const url = `${window.location.origin}${window.location.pathname}#${id}`;
|
||||
navigator.clipboard.writeText(url);
|
||||
toast("Link copied to clipboard", {
|
||||
position: "bottom-center",
|
||||
autoClose: 2000,
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
textDecoration: "none", color: "white",
|
||||
paddingLeft: "0.3em", rotate: "-30deg",
|
||||
paddingTop: "0.9em", display: props.level === 1 ? "none" : "block",
|
||||
@@ -638,8 +702,7 @@ const Docs = (defaultprops) => {
|
||||
<LinkIcon />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{extraInfo}
|
||||
{isArticlePage ? (userdata?.support ? extraInfo : "") : extraInfo}
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
@@ -647,21 +710,56 @@ const Docs = (defaultprops) => {
|
||||
|
||||
const SideBar = {
|
||||
width: "17%",
|
||||
borderRight: !isArticlePage ? "1px solid rgba(255,255,255,0.3)" : undefined,
|
||||
minWidth: isArticlePage ? "250px" : "17%",
|
||||
maxWidth: isArticlePage ? "250px" : "17%",
|
||||
marginLeft: isArticlePage ? sidebarOpen ? 40 : 50 : undefined,
|
||||
position: "sticky",
|
||||
top: 50,
|
||||
paddingTop: "0.25em",
|
||||
minHeight: "95vh",
|
||||
maxHeight: "95vh",
|
||||
top: isArticlePage ? 120 : 50,
|
||||
paddingTop: isArticlePage ? "0.65em" : "0.25em",
|
||||
paddingRight: isArticlePage ? "1em" : undefined,
|
||||
minHeight: isArticlePage ? "80vh" : "95vh",
|
||||
maxHeight: isArticlePage ? "80vh" : "95vh",
|
||||
overflowX: "hidden",
|
||||
overflowY: "auto",
|
||||
zIndex: 1000,
|
||||
//borderRight: "1px solid rgba(255,255,255,0.3)",
|
||||
backgroundColor: isArticlePage ? "#212121" : undefined,
|
||||
borderRadius: isArticlePage ? theme.palette?.borderRadius : undefined,
|
||||
transition: isArticlePage ? "width 0.3s ease, min-width 0.3s ease" : undefined,
|
||||
};
|
||||
|
||||
const sideBarToggleButton = {
|
||||
position: "absolute",
|
||||
bottom: sidebarOpen ? 20 : "50%",
|
||||
right: sidebarOpen ? 30 : 21,
|
||||
zIndex: 1000,
|
||||
backgroundColor: "#212121",
|
||||
border: "1px solid rgba(255,255,255,0.3)",
|
||||
borderRadius: "50%",
|
||||
width: 40,
|
||||
height: 40,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
cursor: "pointer",
|
||||
transition: "transform 0.3s ease",
|
||||
"&:hover": {
|
||||
backgroundColor: "#2c2c2c",
|
||||
}
|
||||
};
|
||||
|
||||
const collapsedSideBar = {
|
||||
...SideBar,
|
||||
width: "40px",
|
||||
minWidth: "40px",
|
||||
maxWidth: "40px",
|
||||
overflow: "hidden",
|
||||
};
|
||||
|
||||
const IndexBar = {
|
||||
alignSelf: "flex-start",
|
||||
position: "sticky",
|
||||
top: 80,
|
||||
top: 120,
|
||||
overflowY: "auto",
|
||||
minHeight: "93vh",
|
||||
maxHeight: "93vh",
|
||||
@@ -670,8 +768,15 @@ const Docs = (defaultprops) => {
|
||||
overflow: "hidden",
|
||||
}
|
||||
|
||||
const fetchDocList = () => {
|
||||
fetch(`${globalUrl}/api/v1/docs`, {
|
||||
const fetchDocList = (resetCache = false) => {
|
||||
var url = `${globalUrl}/api/v1/docs`
|
||||
if (location.pathname.includes("/legal")) {
|
||||
url = `${globalUrl}/api/v1/docs?folder=legal&resetCache=${resetCache}`
|
||||
} else if (location.pathname.includes("/articles")) {
|
||||
url = `${globalUrl}/api/v1/docs?folder=articles&resetCache=${resetCache}`
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -691,8 +796,19 @@ const Docs = (defaultprops) => {
|
||||
.catch((error) => { });
|
||||
};
|
||||
|
||||
const fetchDocs = (docId) => {
|
||||
fetch(`${globalUrl}/api/v1/docs/${docId}`, {
|
||||
const fetchDoc = (docId) => {
|
||||
if (docId === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
var url = `${globalUrl}/api/v1/docs/${docId}`
|
||||
if (location.pathname.includes("/legal")) {
|
||||
url = `${globalUrl}/api/v1/docs/${docId}?folder=legal`
|
||||
} else if (location.pathname.includes("/articles")) {
|
||||
url = `${globalUrl}/api/v1/docs/${docId}?folder=articles`
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -706,18 +822,32 @@ const Docs = (defaultprops) => {
|
||||
}
|
||||
|
||||
if (responseJson.success && responseJson.reason !== undefined) {
|
||||
|
||||
if(isArticlePage && window.location.pathname.includes("/articles/")) {
|
||||
if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.includes("404: Not Found")) {
|
||||
setData("# Error\nThis page doesn't exist.");
|
||||
toast("This page doesn't exist. Redirecting to the latest article...", {
|
||||
position: "bottom-center",
|
||||
autoClose: 2000,
|
||||
});
|
||||
setTimeout(() => {
|
||||
navigate(`/articles/2.0_release`)
|
||||
}, 2000)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Find <img> tags and translate them into ![]() format
|
||||
const imgRegex = /<img.*?src="(.*?)"/g;
|
||||
const tocRegex = /^## Table of contents[\s\S]*?(?=^## )|^## Table of contents[\s\S]*$/gm;
|
||||
const newdata = responseJson.reason.replace(imgRegex, '').replace(tocRegex, "");
|
||||
setData(newdata);
|
||||
if (docId === undefined) {
|
||||
document.title = "Shuffle automation documentation";
|
||||
document.title = isArticlePage ? "Shuffle Articles introduction" : "Shuffle documentation";
|
||||
} else {
|
||||
document.title = "Shuffle " + docId.replace("_", " ") + " documentation";
|
||||
document.title = "Shuffle " + docId.replace("_", " ") + (isArticlePage ? " articles" : " documentation");
|
||||
}
|
||||
|
||||
if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.includes("404: Not Found")) {
|
||||
if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.includes("404: Not Found") && !isArticlePage) {
|
||||
navigate("/docs")
|
||||
return
|
||||
}
|
||||
@@ -747,6 +877,11 @@ const Docs = (defaultprops) => {
|
||||
.catch((error) => { });
|
||||
};
|
||||
|
||||
const handleResetCache = () => {
|
||||
fetchDocList(true);
|
||||
toast("Cache has been reset");
|
||||
}
|
||||
|
||||
if (firstrequest) {
|
||||
setFirstrequest(false);
|
||||
if (!serverside) {
|
||||
@@ -769,11 +904,29 @@ const Docs = (defaultprops) => {
|
||||
// return null
|
||||
//}
|
||||
//
|
||||
if (props.match.params.key === undefined) {
|
||||
|
||||
if (props.match.params.key === undefined && isArticlePage) {
|
||||
fetch(`${globalUrl}/api/v1/articles`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((responseJson) => {
|
||||
if (responseJson.success && responseJson.list && responseJson.list.length > 0) {
|
||||
// Navigate to the latest article
|
||||
if (responseJson?.list[0]?.name) {
|
||||
navigate(`/articles/${responseJson?.list[0].name}`);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error fetching articles:", error);
|
||||
});
|
||||
} else {
|
||||
console.log("DOCID: ", props.match.params.key)
|
||||
fetchDocs(props.match.params.key)
|
||||
fetchDoc(props.match.params.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -782,7 +935,7 @@ const Docs = (defaultprops) => {
|
||||
// Handles search-based changes that origin from outside this file
|
||||
if (serverside !== true && window.location.href !== baseUrl) {
|
||||
setBaseUrl(window.location.href);
|
||||
fetchDocs(props.match.params.key);
|
||||
fetchDoc(props.match.params.key);
|
||||
}
|
||||
|
||||
const markdownStyle = {
|
||||
@@ -793,7 +946,7 @@ const Docs = (defaultprops) => {
|
||||
maxWidth: "100%",
|
||||
minWidth: "100%",
|
||||
overflow: "hidden",
|
||||
fontSize: isMobile ? "1.3rem" : "1rem",
|
||||
fontSize: isMobile ? "1.3rem" : "1.1rem",
|
||||
};
|
||||
|
||||
const alertNote = {
|
||||
@@ -940,20 +1093,51 @@ const Docs = (defaultprops) => {
|
||||
}
|
||||
|
||||
|
||||
const activeHrefStyleToc2 = {
|
||||
...hrefStyleToc2,
|
||||
color: "#f86a3e",
|
||||
};
|
||||
|
||||
const activeListItemStyle = {
|
||||
backgroundColor: "rgba(248, 106, 62, 0.08)", // Slight orange tint
|
||||
marginRight: window.location.pathname.includes("/articles/") ? "0.8em" : undefined,
|
||||
borderLeft: "3px solid #f86a3e",
|
||||
paddingLeft: "13px", // Compensate for the border
|
||||
};
|
||||
|
||||
const toggleSidebar = () => {
|
||||
setSidebarOpen(!sidebarOpen);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// PostDataBrowser Section
|
||||
const postDataBrowser =
|
||||
list === undefined || list === null ? null : (
|
||||
<div style={Body}>
|
||||
<div style={SideBar}>
|
||||
<div style={!isArticlePage ? SideBar : (sidebarOpen ? SideBar : collapsedSideBar)}>
|
||||
<Paper style={SidebarPaperStyle}>
|
||||
<List style={{ listStyle: "none", paddingLeft: "0" }}>
|
||||
<List style={{
|
||||
listStyle: "none",
|
||||
paddingLeft: "0",
|
||||
display: isArticlePage ? sidebarOpen ? "block" : "none" : undefined,
|
||||
opacity: isArticlePage ? sidebarOpen ? 1 : 0 : undefined,
|
||||
transition: isArticlePage ? "opacity 0.3s ease" : undefined,
|
||||
height: isArticlePage ? "90%" : undefined,
|
||||
}}>
|
||||
{list.map((data, index) => {
|
||||
const item = data.name;
|
||||
if (item === undefined) {
|
||||
return null;
|
||||
}
|
||||
const path = "/docs/" + item;
|
||||
|
||||
var path = "/docs/" + item;
|
||||
if (location.pathname.includes("/legal")) {
|
||||
path = "/legal/" + item
|
||||
} else if (location.pathname.includes("/articles")) {
|
||||
path = "/articles/" + item
|
||||
}
|
||||
|
||||
const newname =
|
||||
item.charAt(0).toUpperCase() +
|
||||
item.substring(1).split("_").join(" ").split("-").join(" ");
|
||||
@@ -965,23 +1149,62 @@ const Docs = (defaultprops) => {
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
key={index}
|
||||
style={hrefStyle}
|
||||
style={{
|
||||
...hrefStyle,
|
||||
...(itemMatching ? activeListItemStyle : {}),
|
||||
}}
|
||||
to={path}
|
||||
>
|
||||
<ListItemText
|
||||
style={{ color: itemMatching ? "#f86a3e" : "inherit" }}
|
||||
variant="body1"
|
||||
>
|
||||
{newname}
|
||||
</ListItemText>
|
||||
style={{
|
||||
color: itemMatching ? "#f86a3e" : "inherit",
|
||||
flex: 1,
|
||||
}}
|
||||
primary={
|
||||
<Typography
|
||||
variant="body1"
|
||||
style={{
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
}}
|
||||
>
|
||||
{newname}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
<KeyboardArrowRightIcon
|
||||
style={{
|
||||
color: itemMatching ? "#f86a3e" : "inherit",
|
||||
fontSize: "1.1rem",
|
||||
marginRight: "-6px",
|
||||
}}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
{
|
||||
isArticlePage && (
|
||||
<IconButton
|
||||
onClick={toggleSidebar}
|
||||
style={sideBarToggleButton}
|
||||
>
|
||||
{sidebarOpen ? <ChevronLeft /> : <ChevronRight />}
|
||||
</IconButton>
|
||||
)
|
||||
}
|
||||
</Paper>
|
||||
</div>
|
||||
<div style={{ width: "60%", margin: "30px 0px 30px 30px", overflow: "hidden", paddingRight: 50, paddingLeft: 40 }}>
|
||||
<div style={{
|
||||
width: isArticlePage ? sidebarOpen ? "60%" : "70%" : "60%",
|
||||
margin: isArticlePage ? sidebarOpen ? "0 0px 30px 30px" : "0 0px 30px 60px" : "30px 0px 30px 30px",
|
||||
overflow: "hidden",
|
||||
paddingRight: 50,
|
||||
paddingLeft: 40,
|
||||
transition: "width 0.3s ease, margin 0.3s ease",
|
||||
}}>
|
||||
{props.match.params.key === undefined ?
|
||||
mainpageInfo
|
||||
:
|
||||
@@ -1003,12 +1226,26 @@ const Docs = (defaultprops) => {
|
||||
}
|
||||
</div>
|
||||
<div style={IndexBar}>
|
||||
{userdata?.support && isArticlePage && (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={handleResetCache}
|
||||
style={{marginBottom: "15px"}}
|
||||
>
|
||||
Reset Cache
|
||||
</Button>
|
||||
)}
|
||||
{tocLines.length > 0 ?
|
||||
(
|
||||
<h4 style={{ fontWeight: 600, margin: 0, fontSize: "16px", marginBottom: "8px" }}>Table of Content</h4>
|
||||
<h4 style={{ fontWeight: 600, margin: 0, fontSize: "16px", marginBottom: "8px" }}>Table Of Content</h4>
|
||||
|
||||
) : null}
|
||||
<nav>
|
||||
<div
|
||||
style={{
|
||||
overflowY: "auto",
|
||||
maxHeight: "90vh",
|
||||
}}>
|
||||
{tocLines.map((data, index) => {
|
||||
return (
|
||||
<div className="toc"
|
||||
@@ -1019,12 +1256,15 @@ const Docs = (defaultprops) => {
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
fontWeight: 400,
|
||||
padding: "4px 8px 4px 8px",
|
||||
padding: isArticlePage ? "4px 0" : "4px 8px 4px 8px",
|
||||
paddingLeft: isArticlePage ? "0" : "8px",
|
||||
paddingRight: isArticlePage ? "0" : "8px",
|
||||
lineHeight: "20px",
|
||||
color: activeId === data.id ? "#f86a3e" : "rgba(255,255,255,0.6)",
|
||||
color: activeId === data.id ? "#f86a3e" : "inherit",
|
||||
}}
|
||||
onClick={(e) => {
|
||||
handleCollapse(index)
|
||||
setActiveId(data.id)
|
||||
}}
|
||||
>
|
||||
{data.title}
|
||||
@@ -1041,8 +1281,12 @@ const Docs = (defaultprops) => {
|
||||
return (
|
||||
<ListItemButton
|
||||
key={i}
|
||||
style={hrefStyleToc2}
|
||||
style={activeSubItem === d.id ? activeHrefStyleToc2 : hrefStyleToc2}
|
||||
href={`#${d.id}`}
|
||||
onClick={(e) => {
|
||||
// e.preventDefault()
|
||||
setActiveSubItem(d.id)
|
||||
}}
|
||||
>
|
||||
{d.title}
|
||||
</ListItemButton>
|
||||
@@ -1055,7 +1299,7 @@ const Docs = (defaultprops) => {
|
||||
|
||||
)
|
||||
})}
|
||||
</nav>
|
||||
</div>
|
||||
</div >
|
||||
|
||||
</div >
|
||||
@@ -1083,7 +1327,7 @@ const Docs = (defaultprops) => {
|
||||
color="primary"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div style={{ color: "white" }}>More docs</div>
|
||||
<div style={{ color: "white" }}>More {isArticlePage ? "articles" : "docs"}</div>
|
||||
</Button>
|
||||
<Menu
|
||||
id="simple-menu"
|
||||
@@ -1099,7 +1343,7 @@ const Docs = (defaultprops) => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const path = "/docs/" + item;
|
||||
const path = isArticlePage ? "/articles/" + item : "/docs/" + item;
|
||||
const newname =
|
||||
item.charAt(0).toUpperCase() +
|
||||
item.substring(1).split("_").join(" ").split("-").join(" ");
|
||||
@@ -1108,7 +1352,8 @@ const Docs = (defaultprops) => {
|
||||
key={index}
|
||||
style={{ color: "white" }}
|
||||
onClick={() => {
|
||||
window.location.pathname = path;
|
||||
navigate(path)
|
||||
handleClose()
|
||||
}}
|
||||
>
|
||||
{newname}
|
||||
@@ -1140,8 +1385,22 @@ const Docs = (defaultprops) => {
|
||||
<MenuItem
|
||||
key={index}
|
||||
style={{ color: "white" }}
|
||||
component={Link}
|
||||
to={`#${data.id}`}
|
||||
onClick={() => {
|
||||
console.log(`Scrolling to: ${data.id}`);
|
||||
setTimeout(() => {
|
||||
const element = document.getElementById(data?.id);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth' });
|
||||
} else {
|
||||
console.error(`Element with id ${data.id} not found.`);
|
||||
}
|
||||
}, 100); // Delay to ensure the content is loaded
|
||||
handleCloseToc();
|
||||
}}
|
||||
>
|
||||
<a href={`#${data.id}`} style={hrefStyle}>{data.title}</a>
|
||||
{data.title}
|
||||
</MenuItem>
|
||||
)
|
||||
})}
|
||||
@@ -1178,7 +1437,7 @@ const Docs = (defaultprops) => {
|
||||
color="primary"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div style={{ color: "white" }}>More docs</div>
|
||||
<div style={{ color: "white" }}>More {isArticlePage ? "articles" : "docs"}</div>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
@@ -1198,7 +1457,7 @@ export default Docs;
|
||||
|
||||
const DocsContent = memo(({postDataBrowser, postDataMobile}) => {
|
||||
return(
|
||||
<div>
|
||||
<div style={{fontFamily: theme?.palette?.fontFamily}}>
|
||||
<BrowserView>{postDataBrowser}</BrowserView>
|
||||
<MobileView>{postDataMobile}</MobileView>
|
||||
</div>
|
||||
@@ -1210,12 +1469,14 @@ const DocsWrapper = memo(({isLoggedIn, isLoaded, children })=>{
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
marginTop: window.location.pathname.includes("/articles/") ? 50 : undefined,
|
||||
paddingBottom: 50,
|
||||
minHeight: 1000, zIndex: 1,
|
||||
maxWidth: Math.min(!(isLoggedIn && isLoaded) ? 1920 : leftSideBarOpenByClick ? windowWidth - 300 : windowWidth - 200, 1920),
|
||||
minWidth: isMobile ? null : (isLoggedIn && isLoaded) ? leftSideBarOpenByClick ? 800 : 900 : null, margin: "auto",
|
||||
position: (isLoggedIn && isLoaded) && leftSideBarOpenByClick ? "relative" : "static",
|
||||
left: (isLoggedIn && isLoaded) && leftSideBarOpenByClick ? 120 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0,
|
||||
marginLeft: windowWidth < 1920 ? leftSideBarOpenByClick && (isLoggedIn && isLoaded) ? 90 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0 : "auto", width: "100%",
|
||||
marginLeft: windowWidth < 1920 ? leftSideBarOpenByClick && (isLoggedIn && isLoaded) ? window.location.pathname.includes("/articles/") ? 0 : 90 : (isLoggedIn && isLoaded) && !leftSideBarOpenByClick ? 80 : 0 : "auto", width: "100%",
|
||||
transition: "left 0.3s ease-in-out, min-width 0.3s ease-in-out, max-width 0.3s ease-in-out, position 0.3s ease-in-out, margin 0.3s ease-in-out, margin-left 0.3s ease"
|
||||
}}>
|
||||
{children}
|
||||
|
||||
+915
-502
File diff suppressed because it is too large
Load Diff
Executable
+548
@@ -0,0 +1,548 @@
|
||||
/* eslint-disable react/no-multi-comp */
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { useInterval } from "react-powerhooks";
|
||||
import theme from '../theme.jsx';
|
||||
|
||||
import {
|
||||
CircularProgress,
|
||||
TextField,
|
||||
Button,
|
||||
Paper,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const hrefStyle = {
|
||||
color: "white",
|
||||
textDecoration: "none",
|
||||
};
|
||||
|
||||
const bodyDivStyle = {
|
||||
margin: "auto",
|
||||
marginTop: 150,
|
||||
width: "500px",
|
||||
};
|
||||
|
||||
const useStyles = makeStyles({
|
||||
notchedOutline: {
|
||||
borderColor: "#f85a3e !important",
|
||||
},
|
||||
});
|
||||
|
||||
const LoginDialog = (props) => {
|
||||
const {
|
||||
globalUrl,
|
||||
isLoaded,
|
||||
isLoggedIn,
|
||||
setIsLoggedIn,
|
||||
setCookie,
|
||||
register,
|
||||
checkLogin,
|
||||
} = props;
|
||||
|
||||
let navigate = useNavigate();
|
||||
const classes = useStyles();
|
||||
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [firstRequest, setFirstRequest] = useState(true);
|
||||
const [loginLoading, setLoginLoading] = useState(false);
|
||||
const [loginViewLoading, setLoginViewLoading] = useState(false);
|
||||
const [ssoUrl, setSSOUrl] = useState("");
|
||||
|
||||
const [MFAField, setMFAField] = useState(false);
|
||||
const [MFAValue, setMFAValue] = useState("");
|
||||
|
||||
|
||||
// Used to swap from login to register. True = login, false = register
|
||||
|
||||
useEffect(() => {
|
||||
checkAdmin()
|
||||
}, [loginViewLoading])
|
||||
|
||||
// Error messages etc
|
||||
const [loginInfo, setLoginInfo] = useState("");
|
||||
|
||||
const handleValidateForm = () => {
|
||||
return username.length > 1 && password.length > 1;
|
||||
};
|
||||
|
||||
if (isLoggedIn === true) {
|
||||
//window.location.pathname = "/workflows";
|
||||
navigate("/workflows")
|
||||
}
|
||||
|
||||
const checkAdmin = () => {
|
||||
const url = globalUrl + "/api/v1/checkusers";
|
||||
fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) =>
|
||||
response.json().then((responseJson) => {
|
||||
if (responseJson["success"] === false) {
|
||||
setLoginInfo(responseJson["reason"]);
|
||||
} else {
|
||||
|
||||
if (responseJson.sso_url !== undefined && responseJson.sso_url !== null) {
|
||||
setSSOUrl(responseJson.sso_url);
|
||||
}
|
||||
|
||||
navigate("/login")
|
||||
|
||||
if (loginViewLoading) {
|
||||
setLoginViewLoading(false);
|
||||
checkLogin();
|
||||
stop();
|
||||
|
||||
if (
|
||||
responseJson.reason !== undefined &&
|
||||
responseJson.reason !== null
|
||||
) {
|
||||
setLoginInfo(responseJson.reason);
|
||||
}
|
||||
}
|
||||
|
||||
if (responseJson.reason === "stay") {
|
||||
navigate("/adminsetup")
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
if (!loginViewLoading) {
|
||||
setLoginViewLoading(true);
|
||||
start();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const { start, stop } = useInterval({
|
||||
duration: 3000,
|
||||
startImmediate: false,
|
||||
callback: () => {
|
||||
checkAdmin();
|
||||
},
|
||||
})
|
||||
|
||||
if (firstRequest) {
|
||||
setFirstRequest(false);
|
||||
checkAdmin();
|
||||
}
|
||||
|
||||
const onSubmit = (e) => {
|
||||
setLoginLoading(true);
|
||||
e.preventDefault();
|
||||
setLoginInfo("");
|
||||
// FIXME - add some check here ROFL
|
||||
|
||||
// Just use this one?
|
||||
var data = { username: username, password: password };
|
||||
if (MFAValue !== undefined && MFAValue !== null && MFAValue.length > 0) {
|
||||
data["mfa_code"] = MFAValue;
|
||||
}
|
||||
|
||||
var baseurl = globalUrl;
|
||||
if (register) {
|
||||
var url = baseurl + "/api/v1/login";
|
||||
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) =>
|
||||
response.json().then((responseJson) => {
|
||||
setLoginLoading(false);
|
||||
if (responseJson["success"] === false) {
|
||||
setLoginInfo(responseJson["reason"]);
|
||||
} else {
|
||||
if (responseJson["reason"] === "MFA_REDIRECT") {
|
||||
setLoginInfo(
|
||||
"MFA required. Please enter the 6-digit code from your authenticator"
|
||||
);
|
||||
setMFAField(true);
|
||||
return;
|
||||
} else if (responseJson["reason"] === "MFA_SETUP") {
|
||||
window.location.href = `/login/${responseJson.url}/mfa-setup`;
|
||||
return;
|
||||
}
|
||||
|
||||
setLoginInfo("Successful login, rerouting");
|
||||
for (var key in responseJson["cookies"]) {
|
||||
setCookie(
|
||||
responseJson["cookies"][key].key,
|
||||
responseJson["cookies"][key].value,
|
||||
{ path: "/" }
|
||||
);
|
||||
}
|
||||
|
||||
if (responseJson.tutorials === undefined || responseJson.tutorials === null || !responseJson.tutorials.includes("welcome")) {
|
||||
console.log("RUN Welcome!!")
|
||||
setTimeout(() => {
|
||||
navigate("/welcome?tab=2")
|
||||
},200)
|
||||
// window.location.pathname = ""
|
||||
return
|
||||
}
|
||||
|
||||
const tmpView = new URLSearchParams(window.location.search).get("view")
|
||||
if (tmpView !== undefined && tmpView !== null) {
|
||||
//const newUrl = `/${tmpView}${decodeURIComponent(window.location.search)}`
|
||||
const newUrl = `/${tmpView}`
|
||||
window.location.pathname = newUrl
|
||||
} else {
|
||||
window.location.pathname = "/workflows"
|
||||
}
|
||||
|
||||
setIsLoggedIn(true);
|
||||
}
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
setLoginLoading(false);
|
||||
setLoginInfo("Error logging in: " + error);
|
||||
});
|
||||
} else {
|
||||
url = baseurl + "/api/v1/users/register";
|
||||
fetch(url, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) =>
|
||||
response.json().then((responseJson) => {
|
||||
if (responseJson["success"] === false) {
|
||||
setLoginInfo(responseJson["reason"]);
|
||||
} else {
|
||||
setLoginInfo("Successful register!");
|
||||
}
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
setLoginInfo("Error in from backend: ", error);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onChangeUser = (e) => {
|
||||
setUsername(e.target.value);
|
||||
};
|
||||
|
||||
const onChangePass = (e) => {
|
||||
setPassword(e.target.value);
|
||||
};
|
||||
|
||||
//const onClickRegister = () => {
|
||||
// if (props.location.pathname === "/login") {
|
||||
// window.location.pathname = "/register"
|
||||
// } else {
|
||||
// window.location.pathname = "/login"
|
||||
// }
|
||||
|
||||
// setLoginCheck(!register)
|
||||
//}
|
||||
|
||||
//var loginChange = register ? (<div><p onClick={setLoginCheck(false)}>Want to register? Click here.</p></div>) : (<div><p onClick={setLoginCheck(true)}>Go back to login? Click here.</p></div>);
|
||||
var formtitle = register ? <div>Login</div> : <div>Register</div>;
|
||||
const imgsize = 100;
|
||||
const basedata = (
|
||||
<div style={bodyDivStyle}>
|
||||
<Paper
|
||||
style={{
|
||||
paddingLeft: "30px",
|
||||
paddingRight: "30px",
|
||||
paddingBottom: "30px",
|
||||
paddingTop: "30px",
|
||||
position: "relative",
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: -imgsize / 2 - 10,
|
||||
left: 250 - imgsize / 2,
|
||||
height: imgsize,
|
||||
width: imgsize,
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="images/Shuffle_logo.png"
|
||||
style={{
|
||||
height: imgsize + 10,
|
||||
width: imgsize + 10,
|
||||
border: "2px solid rgba(255,255,255,0.6)",
|
||||
borderRadius: imgsize,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{loginViewLoading ? (
|
||||
<div style={{ textAlign: "center", marginTop: 50 }}>
|
||||
<Typography
|
||||
variant="body2"
|
||||
style={{ marginBottom: 20, color: "white" }}
|
||||
>
|
||||
Waiting for the Shuffle database to become available. This may
|
||||
take up to two minutes.
|
||||
</Typography>
|
||||
|
||||
{loginInfo === undefined ||
|
||||
loginInfo === null ||
|
||||
loginInfo.length === 0 ? null : (
|
||||
<div style={{ marginTop: "10px" }}>Database Response: {loginInfo}</div>
|
||||
)}
|
||||
<CircularProgress color="secondary" style={{ color: "white" }} />
|
||||
|
||||
<Paper
|
||||
style={{
|
||||
paddingLeft: "30px",
|
||||
paddingRight: "30px",
|
||||
paddingBottom: "30px",
|
||||
paddingTop: "30px",
|
||||
position: "relative",
|
||||
textAlign: "left",
|
||||
marginTop: 15,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
style={{ marginBottom: 20, color: "white" }}
|
||||
>
|
||||
<b>
|
||||
Are you sure Shuffle is{" "}
|
||||
<a
|
||||
rel="norefferer"
|
||||
target="_blank"
|
||||
href="https://github.com/frikky/Shuffle/blob/master/.github/install-guide.md"
|
||||
style={{ textDecoration: "none", color: "#f86a3e" }}
|
||||
>
|
||||
installed correctly
|
||||
</a>
|
||||
?
|
||||
</b>
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
style={{ marginBottom: 20, color: "white" }}
|
||||
>
|
||||
<b>1.</b> Make sure shuffle-database folder has correct access, and that you have a minimum of <b>2Gb of RAM available</b>:{" "}
|
||||
<br />
|
||||
<br />
|
||||
sudo chown -R 1000:1000 shuffle-database
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
style={{ marginBottom: 20, color: "white" }}
|
||||
>
|
||||
<b>2.</b> Disable memory swap on the host:
|
||||
<br />
|
||||
<br />
|
||||
sudo swapoff -a
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
style={{ marginBottom: 20, color: "white" }}
|
||||
>
|
||||
<b>3</b>. Restart the database:
|
||||
<br />
|
||||
<br />
|
||||
sudo docker restart shuffle-opensearch
|
||||
</Typography>
|
||||
</Paper>
|
||||
<Typography
|
||||
variant="body2"
|
||||
style={{ marginBottom: 10, color: "white", marginTop: 20 }}
|
||||
>
|
||||
Need help?{" "}
|
||||
<a
|
||||
rel="norefferer"
|
||||
target="_blank"
|
||||
href="https://discord.gg/B2CBzUm"
|
||||
style={{ textDecoration: "none", color: "#f86a3e" }}
|
||||
>
|
||||
Join the Discord!
|
||||
</a>
|
||||
</Typography>
|
||||
</div>
|
||||
) : (
|
||||
<form
|
||||
onSubmit={onSubmit}
|
||||
style={{ margin: "15px 15px 15px 15px", color: "white" }}
|
||||
>
|
||||
<h2>{formtitle}</h2>
|
||||
Username
|
||||
<div>
|
||||
<TextField
|
||||
color="primary"
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
marginTop: 5,
|
||||
}}
|
||||
autoFocus
|
||||
InputProps={{
|
||||
classes: {
|
||||
notchedOutline: classes.notchedOutline,
|
||||
},
|
||||
style: {
|
||||
height: "50px",
|
||||
color: "white",
|
||||
fontSize: "1em",
|
||||
},
|
||||
}}
|
||||
required
|
||||
fullWidth={true}
|
||||
autoComplete="username"
|
||||
placeholder="username@example.com"
|
||||
id="emailfield"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
onChange={onChangeUser}
|
||||
/>
|
||||
</div>
|
||||
Password
|
||||
<div>
|
||||
<TextField
|
||||
color="primary"
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
marginTop: 5,
|
||||
}}
|
||||
InputProps={{
|
||||
classes: {
|
||||
notchedOutline: classes.notchedOutline,
|
||||
},
|
||||
style: {
|
||||
height: "50px",
|
||||
color: "white",
|
||||
fontSize: "1em",
|
||||
},
|
||||
}}
|
||||
required
|
||||
id="outlined-password-input"
|
||||
fullWidth={true}
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
placeholder="**********"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
onChange={onChangePass}
|
||||
/>
|
||||
</div>
|
||||
{MFAField === true ? (
|
||||
<div style={{ marginTop: 15 }}>
|
||||
2-factor code
|
||||
<TextField
|
||||
color="primary"
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
marginTop: 5,
|
||||
}}
|
||||
InputProps={{
|
||||
classes: {
|
||||
notchedOutline: classes.notchedOutline,
|
||||
},
|
||||
style: {
|
||||
height: "50px",
|
||||
color: "white",
|
||||
fontSize: "1em",
|
||||
},
|
||||
}}
|
||||
required
|
||||
id="outlined-password-input"
|
||||
fullWidth={true}
|
||||
type="text"
|
||||
placeholder="6-digit code"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
onChange={(event) => {
|
||||
setMFAValue(event.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<div style={{ display: "flex", marginTop: "15px" }}>
|
||||
<Button
|
||||
color="primary"
|
||||
variant="contained"
|
||||
type="submit"
|
||||
style={{ flex: "1" }}
|
||||
disabled={!handleValidateForm() || loginLoading}
|
||||
>
|
||||
{loginLoading ? (
|
||||
<CircularProgress
|
||||
color="secondary"
|
||||
style={{ color: "white" }}
|
||||
/>
|
||||
) : (
|
||||
"SUBMIT"
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
<div style={{ marginTop: "10px" }}>{loginInfo}</div>
|
||||
{ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length > 0 ? (
|
||||
<div>
|
||||
<Typography style={{ textAlign: "center" }}>Or</Typography>
|
||||
<div style={{ textAlign: "center", margin: 10 }}>
|
||||
<Button
|
||||
fullWidth
|
||||
id="sso_button"
|
||||
color="secondary"
|
||||
variant="outlined"
|
||||
type="button"
|
||||
style={{ flex: "1", marginTop: 5 }}
|
||||
onClick={() => {
|
||||
//console.log("CLICK SSO");
|
||||
window.location.href = ssoUrl
|
||||
//navigate(ssoUrl)
|
||||
}}
|
||||
>
|
||||
Use SSO
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</form>
|
||||
)}
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
|
||||
const loadedCheck = isLoaded ? <div>{basedata}</div> : <div></div>;
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
if (ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length > 0) {
|
||||
//id="sso_button"
|
||||
const ssoBtn = document.getElementById("sso_button");
|
||||
if (ssoBtn !== undefined && ssoBtn !== null) {
|
||||
//console.log("SSO BTN: ", ssoBtn)
|
||||
const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search;
|
||||
var tmpView = new URLSearchParams(cursearch).get("autologin");
|
||||
if (tmpView !== undefined && tmpView !== null) {
|
||||
if (tmpView === "true") {
|
||||
console.log("Tmp: ", tmpView)
|
||||
ssoBtn.click()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 200);
|
||||
}, [ssoUrl])
|
||||
|
||||
return <div style={{paddingBottom: 150, }}>{loadedCheck}</div>;
|
||||
};
|
||||
|
||||
export default LoginDialog;
|
||||
@@ -1946,7 +1946,10 @@ const Workflows = (props) => {
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for setting workflows :O!");
|
||||
toast("Failed deleting workflow. Do you have access?");
|
||||
|
||||
if (bulk !== true) {
|
||||
toast(`Failed deleting workflow ${id}. Do you have access?`);
|
||||
}
|
||||
} else {
|
||||
if (bulk !== true) {
|
||||
toast(`Deleted workflow ${id}. Child Workflows in Suborgs were also removed.`)
|
||||
|
||||
@@ -1758,9 +1758,17 @@ const Workflows2 = (props) => {
|
||||
let exportFileDefaultName = data.name + ".json";
|
||||
|
||||
data["owner"] = "";
|
||||
data["updated_by"] = "";
|
||||
data["org"] = [];
|
||||
data["org_id"] = "";
|
||||
data["execution_org"] = {};
|
||||
data["created"] = 0
|
||||
data["due_date"] = 0
|
||||
data["edited"] = 0
|
||||
|
||||
data["validation"] = {};
|
||||
data["suborg_distribution"] = []
|
||||
data["parentorg_workflow"] = ""
|
||||
|
||||
// These are backwards.. True = saved before. Very confuse.
|
||||
data["previously_saved"] = false;
|
||||
@@ -2035,7 +2043,10 @@ const Workflows2 = (props) => {
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for setting workflows :O!");
|
||||
toast("Failed deleting workflow. Do you have access?");
|
||||
|
||||
if (bulk !== true) {
|
||||
toast("Failed deleting workflow. Do you have access?");
|
||||
}
|
||||
} else {
|
||||
if (bulk !== true) {
|
||||
toast(`Deleted workflow ${id}. Child Workflows in Suborgs were also removed.`)
|
||||
@@ -2813,7 +2824,7 @@ const Workflows2 = (props) => {
|
||||
|
||||
{(data.sharing !== undefined && data.sharing !== null && data.sharing === "form") || (data?.form_control?.input_markdown !== undefined && data?.form_control?.input_markdown !== null && data?.form_control?.input_markdown !== "") && type !== "public" ?
|
||||
<Tooltip title="Edit Form" placement="top">
|
||||
<div style={{ position: "absolute", top: 45, right: 8, }}>
|
||||
<div style={{ position: "absolute", top: 50, right: 8, }}>
|
||||
<IconButton
|
||||
aria-label="more"
|
||||
aria-controls="long-menu"
|
||||
@@ -2830,8 +2841,8 @@ const Workflows2 = (props) => {
|
||||
: null}
|
||||
|
||||
{(data?.validation?.validation_ran === true && data?.validation?.valid === false && data?.validation?.errors?.length > 0 ) ?
|
||||
<Tooltip title={`Explore more than ${data?.validation?.errors?.length} errors. When the last execution finishes without errors AND notifications stop occuring, this icon disappears.`} placement="top">
|
||||
<div style={{ position: "absolute", top: 45, right: 8, }}>
|
||||
<Tooltip title={`Explore more than ${data?.validation?.errors?.length} notifications. When the last execution finishes without errors AND notifications stop occuring, this icon disappears.`} placement="top">
|
||||
<div style={{ position: "absolute", top: 85, right: 8, }}>
|
||||
<IconButton
|
||||
aria-label="more"
|
||||
aria-controls="long-menu"
|
||||
@@ -2850,8 +2861,8 @@ const Workflows2 = (props) => {
|
||||
</IconButton>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
: null}
|
||||
|
||||
</Grid>
|
||||
</Paper>
|
||||
</div>
|
||||
@@ -3227,6 +3238,7 @@ const Workflows2 = (props) => {
|
||||
</span>
|
||||
</Tooltip>
|
||||
}
|
||||
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title="Amount of triggers"
|
||||
|
||||
Reference in New Issue
Block a user