Fixed a bunch of form deploy systems
This commit is contained in:
@@ -344,12 +344,13 @@ const AuthenticationData = (props) => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setAuthenticationModalOpen(false);
|
setAuthenticationModalOpen(false);
|
||||||
}}
|
}}
|
||||||
color="primary"
|
color="secondary"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
style={{ borderRadius: "0px" }}
|
style={{ borderRadius: "0px" }}
|
||||||
|
variant="outlined"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setAuthenticationOptions(authenticationOption);
|
setAuthenticationOptions(authenticationOption);
|
||||||
handleSubmitCheck();
|
handleSubmitCheck();
|
||||||
|
|||||||
@@ -106,7 +106,12 @@ const AuthenticationData = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
setSubmitSuccessful(true)
|
setSubmitSuccessful(true)
|
||||||
if (getAppAuthentication !== undefined) {
|
if (getAppAuthentication !== undefined) {
|
||||||
getAppAuthentication(true, false);
|
|
||||||
|
if (workflow !== undefined && workflow !== null && workflow.org_id !== undefined && workflow.org_id !== null && workflow.org_id.length > 0) {
|
||||||
|
getAppAuthentication(true, false, undefined, workflow.org_id)
|
||||||
|
} else {
|
||||||
|
getAppAuthentication(true, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setAuthenticationModalOpen !== undefined) {
|
if (setAuthenticationModalOpen !== undefined) {
|
||||||
|
|||||||
@@ -1097,7 +1097,7 @@ const Billing = (props) => {
|
|||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="outlined"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={toggleEditMode}
|
onClick={toggleEditMode}
|
||||||
style={{ textTransform: 'none' }}
|
style={{ textTransform: 'none' }}
|
||||||
@@ -1191,7 +1191,6 @@ const Billing = (props) => {
|
|||||||
height: 40,
|
height: 40,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: "white",
|
color: "white",
|
||||||
backgroundColor: "#f86743",
|
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
cursor: getProfessionalServices ? 'pointer' : 'not-allowed',
|
cursor: getProfessionalServices ? 'pointer' : 'not-allowed',
|
||||||
opacity: getProfessionalServices ? 1 : 0.6,
|
opacity: getProfessionalServices ? 1 : 0.6,
|
||||||
@@ -1202,7 +1201,7 @@ const Billing = (props) => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Get Professional Service
|
Use Professional Service Hours
|
||||||
</Button>
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -1368,7 +1367,7 @@ const Billing = (props) => {
|
|||||||
<Button
|
<Button
|
||||||
fullWidth
|
fullWidth
|
||||||
disabled={false}
|
disabled={false}
|
||||||
variant="outlined"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
style={{
|
style={{
|
||||||
marginTop: 10,
|
marginTop: 10,
|
||||||
@@ -1376,7 +1375,6 @@ const Billing = (props) => {
|
|||||||
height: 40,
|
height: 40,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: "white",
|
color: "white",
|
||||||
backgroundColor: "#f86743",
|
|
||||||
textTransform: 'none'
|
textTransform: 'none'
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -1403,8 +1401,6 @@ const Billing = (props) => {
|
|||||||
borderRadius: 25,
|
borderRadius: 25,
|
||||||
height: 40,
|
height: 40,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: "white",
|
|
||||||
backgroundColor: "#f86743",
|
|
||||||
textTransform: 'none'
|
textTransform: 'none'
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -626,13 +626,13 @@ const EditWorkflow = (props) => {
|
|||||||
|
|
||||||
|
|
||||||
<Typography variant="body1" style={{marginTop: 50, }}>
|
<Typography variant="body1" style={{marginTop: 50, }}>
|
||||||
MSSP Suborg Distribution (beta - contact support@shuffler.io for more info)
|
MSSP Suborg Distribution (<b>beta</b> - contact support@shuffler.io for more info)
|
||||||
</Typography>
|
</Typography>
|
||||||
{userdata !== undefined && userdata !== null && userdata.orgs !== undefined && userdata.orgs !== null && userdata.orgs.length > 0 ?
|
{userdata !== undefined && userdata !== null && userdata.orgs !== undefined && userdata.orgs !== null && userdata.orgs.length > 0 ?
|
||||||
userdata.orgs.filter(org => org.creator_org === userdata.active_org.id).length === 0 ?
|
userdata.orgs.filter(org => org.creator_org === userdata.active_org.id).length === 0 ?
|
||||||
userdata.active_org.creator_org === undefined || userdata.active_org.creator_org === null || userdata.active_org.creator_org === "" ?
|
userdata.active_org.creator_org === undefined || userdata.active_org.creator_org === null || userdata.active_org.creator_org === "" ?
|
||||||
<Typography variant="body2" style={{marginTop: 10, color: "rgba(255,255,255,0.7)"}}>
|
<Typography variant="body2" style={{marginTop: 10, color: "rgba(255,255,255,0.7)"}}>
|
||||||
Your organization does not have any suborgs yet, OR you may not have access to any suborgs directly.. Please <a href="/admin?tab=suborgs" style={{textDecoration: "none", color: "#f86a3e"}} target="_blank">make one</a> or get access to suborgs by admin, then try again.
|
Your organization does not have any suborgs yet OR your user may not have access to available suborgs. Please <a href="/admin?tab=suborgs" style={{textDecoration: "none", color: "#f86a3e"}} target="_blank">make one</a> or get access to suborgs by another admin, then try again.
|
||||||
</Typography>
|
</Typography>
|
||||||
:
|
:
|
||||||
<Typography variant="body2" style={{marginTop: 10, color: "rgba(255,255,255,0.7)"}}>
|
<Typography variant="body2" style={{marginTop: 10, color: "rgba(255,255,255,0.7)"}}>
|
||||||
@@ -738,9 +738,7 @@ const EditWorkflow = (props) => {
|
|||||||
Git Backup Repository
|
Git Backup Repository
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" style={{ textAlign: "left", marginTop: 5, }} color="textSecondary">
|
<Typography variant="body2" style={{ textAlign: "left", marginTop: 5, }} color="textSecondary">
|
||||||
Decide where this workflow is backed up in a Git repository. Will create logs and notifications if upload fails. <b>The repository and branch must already have been initialized</b>. Files will show up in the root folder in the format 'orgid/workflow status/workflow id.json' without images. Overrides the <a href="/admin?admin_tab=organization" style={{textDecoration: "none", color: "#f86a3e"}} target="_blank">default backup repository</a> your org has chosen. All fields must be filled in for the backup to work.
|
Decide where this workflow is backed up in a Git repository. Will create logs and notifications if upload fails. <b>The repository and branch must already have been initialized</b>. Files will show up in the root folder in the format 'orgid/workflow status/workflow id.json' without images. Overrides your <a href="/admin?admin_tab=organization" style={{textDecoration: "none", color: "#f86a3e"}} target="_blank">default backup repository</a>. <a href="/docs/configuration#environment-variables" style={{textDecoration: "none", color: "#f86a3e"}} target="_blank">Credentials are encrypted.</a> Creates <a href="/admin?admin_tab=priorities" style={{textDecoration: "none", color: "#f86a3e"}} target="_blank">notifications</a> if it fails.
|
||||||
<br />
|
|
||||||
PS: This is a beta feature, and might not work as expected. Credentials are NOT encrypted.
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Grid container style={{ marginTop: 10, }} spacing={2}>
|
<Grid container style={{ marginTop: 10, }} spacing={2}>
|
||||||
<Grid item xs={6} style={{}}>
|
<Grid item xs={6} style={{}}>
|
||||||
@@ -782,7 +780,6 @@ const EditWorkflow = (props) => {
|
|||||||
<span>
|
<span>
|
||||||
<Typography>Branch</Typography>
|
<Typography>Branch</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
required
|
|
||||||
style={{
|
style={{
|
||||||
flex: "1",
|
flex: "1",
|
||||||
marginTop: "5px",
|
marginTop: "5px",
|
||||||
@@ -795,7 +792,7 @@ const EditWorkflow = (props) => {
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
multiline={true}
|
multiline={true}
|
||||||
rows={1}
|
rows={1}
|
||||||
placeholder="The branch to use"
|
placeholder="The branch to use (default: master)"
|
||||||
defaultValue={innerWorkflow.backup_config === undefined || innerWorkflow.backup_config.upload_branch === undefined || innerWorkflow.backup_config.upload_branch === null || innerWorkflow.backup_config.upload_branch === "" ? "" : innerWorkflow.backup_config.upload_branch}
|
defaultValue={innerWorkflow.backup_config === undefined || innerWorkflow.backup_config.upload_branch === undefined || innerWorkflow.backup_config.upload_branch === null || innerWorkflow.backup_config.upload_branch === "" ? "" : innerWorkflow.backup_config.upload_branch}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
innerWorkflow.backup_config.upload_branch = e.target.value
|
innerWorkflow.backup_config.upload_branch = e.target.value
|
||||||
@@ -818,7 +815,6 @@ const EditWorkflow = (props) => {
|
|||||||
<span>
|
<span>
|
||||||
<Typography>Username</Typography>
|
<Typography>Username</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
required
|
|
||||||
style={{
|
style={{
|
||||||
flex: "1",
|
flex: "1",
|
||||||
marginTop: "5px",
|
marginTop: "5px",
|
||||||
@@ -831,7 +827,7 @@ const EditWorkflow = (props) => {
|
|||||||
id="outlined-with-placeholder"
|
id="outlined-with-placeholder"
|
||||||
margin="normal"
|
margin="normal"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
placeholder="The username to use"
|
placeholder="Username to use"
|
||||||
defaultValue={innerWorkflow.backup_config === undefined || innerWorkflow.backup_config.upload_username === undefined || innerWorkflow.backup_config.upload_username === null || innerWorkflow.backup_config.upload_username === "" ? "" : innerWorkflow.backup_config.upload_username}
|
defaultValue={innerWorkflow.backup_config === undefined || innerWorkflow.backup_config.upload_username === undefined || innerWorkflow.backup_config.upload_username === null || innerWorkflow.backup_config.upload_username === "" ? "" : innerWorkflow.backup_config.upload_username}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
innerWorkflow.backup_config.upload_username = e.target.value
|
innerWorkflow.backup_config.upload_username = e.target.value
|
||||||
@@ -864,7 +860,7 @@ const EditWorkflow = (props) => {
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
multiline={true}
|
multiline={true}
|
||||||
rows={1}
|
rows={1}
|
||||||
placeholder="The API token to use"
|
placeholder="Your API token. Required."
|
||||||
defaultValue={innerWorkflow.backup_config === undefined || innerWorkflow.backup_config.upload_token === undefined || innerWorkflow.backup_config.upload_token === null || innerWorkflow.backup_config.upload_token === "" ? "" : innerWorkflow.backup_config.upload_token}
|
defaultValue={innerWorkflow.backup_config === undefined || innerWorkflow.backup_config.upload_token === undefined || innerWorkflow.backup_config.upload_token === null || innerWorkflow.backup_config.upload_token === "" ? "" : innerWorkflow.backup_config.upload_token}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
innerWorkflow.backup_config.upload_token = e.target.value
|
innerWorkflow.backup_config.upload_token = e.target.value
|
||||||
@@ -1032,7 +1028,7 @@ const EditWorkflow = (props) => {
|
|||||||
Input Markdown
|
Input Markdown
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color="textSecondary" style={{marginBottom: 20, }}>
|
<Typography variant="body2" color="textSecondary" style={{marginBottom: 20, }}>
|
||||||
Markdown will be shown on the <a href={`/forms/${workflow.id}`} rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: "#f86a3e" }}>Form page</a>. Output for a Workflow is also shown in Markdown, and is controlled by the LAST action that runs.
|
Markdown will be shown on the <a href={`/forms/${workflow.id}`} rel="noopener noreferrer" target="_blank" style={{ textDecoration: "none", color: "#f86a3e" }}>Form page</a>. The first image added will be used in your Form Toolbox list. Output for a Workflow is shown in Markdown, and is controlled by the LAST action that runs. Supports HTML.
|
||||||
</Typography>
|
</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
multiline
|
multiline
|
||||||
@@ -1098,7 +1094,7 @@ const EditWorkflow = (props) => {
|
|||||||
<MenuItem value="none">
|
<MenuItem value="none">
|
||||||
<em>None</em>
|
<em>None</em>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{workflow.actions.map((action, actionIndex) => {
|
{workflow?.actions?.map((action, actionIndex) => {
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={actionIndex}
|
key={actionIndex}
|
||||||
@@ -1121,14 +1117,17 @@ const EditWorkflow = (props) => {
|
|||||||
|
|
||||||
<Tooltip color="primary" title={"Add more details"} placement="top">
|
<Tooltip color="primary" title={"Add more details"} placement="top">
|
||||||
<Button
|
<Button
|
||||||
style={{ margin: "auto", marginTop: 50, textAlign: "center", }}
|
style={{ margin: "auto", marginTop: 50, textAlign: "center", textTransform: "none", }}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
disabled={newWorkflow === true}
|
||||||
|
color="secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowMoreClicked(!showMoreClicked);
|
setShowMoreClicked(!showMoreClicked);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{showMoreClicked ? <ExpandLessIcon /> : <ExpandMoreIcon/>}
|
{showMoreClicked ? <ExpandLessIcon style={{marginRight: 10, }}/> : <ExpandMoreIcon style={{marginRight: 10, }}/>}
|
||||||
{showMoreClicked ? "Less Options": "More Options"}
|
{showMoreClicked ? "Less Options": "More Options"}
|
||||||
|
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ const Header = (props) => {
|
|||||||
const [anchorElAvatar, setAnchorElAvatar] = React.useState(null);
|
const [anchorElAvatar, setAnchorElAvatar] = React.useState(null);
|
||||||
const [subAnchorEl, setSubAnchorEl] = React.useState(null);
|
const [subAnchorEl, setSubAnchorEl] = React.useState(null);
|
||||||
const [upgradeHovered, setUpgradeHovered] = React.useState(false);
|
const [upgradeHovered, setUpgradeHovered] = React.useState(false);
|
||||||
const [showTopbar, setShowTopbar] = useState(false)
|
const [showTopbar, setShowTopbar] = useState(false) // Set to true to show top bar
|
||||||
const stripeKey = typeof window === 'undefined' || window.location === undefined ? "" : window.location.origin === "https://shuffler.io" ? "pk_live_51PXYYMEJjT17t98N20qEqItyt1fLQjrnn41lPeG2PjnSlZHTDNKHuisAbW00s4KAn86nGuqB9uSVU4ds8MutbnMU00DPXpZ8ZD" : "pk_test_51PXYYMEJjT17t98NbDkojZ3DRvsFUQBs35LGMx3i436BXwEBVFKB9nCvHt0Q3M4MG3dz4mHheuWvfoYvpaL3GmsG00k1Rb2ksO"
|
const stripeKey = typeof window === 'undefined' || window.location === undefined ? "" : window.location.origin === "https://shuffler.io" ? "pk_live_51PXYYMEJjT17t98N20qEqItyt1fLQjrnn41lPeG2PjnSlZHTDNKHuisAbW00s4KAn86nGuqB9uSVU4ds8MutbnMU00DPXpZ8ZD" : "pk_test_51PXYYMEJjT17t98NbDkojZ3DRvsFUQBs35LGMx3i436BXwEBVFKB9nCvHt0Q3M4MG3dz4mHheuWvfoYvpaL3GmsG00k1Rb2ksO"
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
@@ -171,14 +171,12 @@ const Header = (props) => {
|
|||||||
setTooltipOpen(true);
|
setTooltipOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const topbar_var = "topbar_closed4"
|
const topbar_var = "topbar_closed5"
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// Manually setShowTopbar(true) to show topbar by default
|
||||||
const topbar = localStorage.getItem(topbar_var)
|
const topbar = localStorage.getItem(topbar_var)
|
||||||
if (topbar === "true") {
|
if (topbar === "true") {
|
||||||
setShowTopbar(false)
|
setShowTopbar(false)
|
||||||
} else {
|
|
||||||
setShowTopbar(true)
|
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@@ -445,17 +443,6 @@ const Header = (props) => {
|
|||||||
})
|
})
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Link>
|
</Link>
|
||||||
{/*
|
|
||||||
<Link to="/getting-started" style={hrefStyle}>
|
|
||||||
<MenuItem
|
|
||||||
onClick={(event) => {
|
|
||||||
handleClose();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<AnalyticsIcon style={{marginRight: 5 }}/> Get Started
|
|
||||||
</MenuItem>
|
|
||||||
</Link>
|
|
||||||
*/}
|
|
||||||
<Link to="/usecases2" style={hrefStyle}>
|
<Link to="/usecases2" style={hrefStyle}>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
@@ -466,19 +453,8 @@ const Header = (props) => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/*userdata?.public_username === undefined || userdata?.public_username === null || userdata?.public_username.length <= 0 ? null :
|
|
||||||
<Link to={`/creators/${userdata.public_username}`} style={hrefStyle}>
|
|
||||||
<MenuItem
|
|
||||||
onClick={(event) => {
|
|
||||||
handleClose();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<EmojiObjectsIcon style={{ marginRight: 5 }} /> Creator page
|
|
||||||
</MenuItem>
|
|
||||||
</Link>
|
|
||||||
*/}
|
|
||||||
|
|
||||||
<Divider style={{ marginTop: 10, marginBottom: 10, }} />
|
<Divider style={{ marginTop: 10, marginBottom: 10, }} />
|
||||||
|
|
||||||
<Link to="/docs" style={hrefStyle}>
|
<Link to="/docs" style={hrefStyle}>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
|
|||||||
@@ -460,14 +460,14 @@ const AuthenticationOauth2 = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (
|
if (authenticationType.refresh_uri !== undefined && authenticationType.refresh_uri !== null && authenticationType.refresh_uri.length > 0) {
|
||||||
authenticationType.refresh_uri !== undefined &&
|
state += `%26refresh_uri%3d${authenticationType.refresh_uri}`
|
||||||
authenticationType.refresh_uri !== null &&
|
|
||||||
authenticationType.refresh_uri.length > 0
|
|
||||||
) {
|
|
||||||
state += `%26refresh_uri%3d${authenticationType.refresh_uri}`;
|
|
||||||
} else {
|
} else {
|
||||||
state += `%26refresh_uri%3d${authentication_url}`;
|
state += `%26refresh_uri%3d${authentication_url}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflow.org_id !== undefined && workflow.org_id !== null && workflow.org_id.length > 0) {
|
||||||
|
state += `%26org_id%3d${workflow.org_id}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Should this be =consent?
|
// FIXME: Should this be =consent?
|
||||||
@@ -524,7 +524,12 @@ const AuthenticationOauth2 = (props) => {
|
|||||||
//alert('"Secure Payment" window closed!');
|
//alert('"Secure Payment" window closed!');
|
||||||
|
|
||||||
if (getAppAuthentication !== undefined) {
|
if (getAppAuthentication !== undefined) {
|
||||||
getAppAuthentication(true, true, true, selectedAction.id)
|
// This should be orgId, not action Id as to load auth properly
|
||||||
|
if (workflow !== undefined && workflow !== null && workflow.org_id !== undefined && workflow.org_id !== null && workflow.org_id.length > 0) {
|
||||||
|
getAppAuthentication(true, true, true, workflow.org_id)
|
||||||
|
} else {
|
||||||
|
getAppAuthentication(true, true, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toast("Authentication successful!")
|
toast("Authentication successful!")
|
||||||
|
|||||||
@@ -382,44 +382,6 @@ const OrgHeaderexpanded = (props) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log("error for sso test is: ", err);
|
console.log("error for sso test is: ", err);
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const HandleTestSSO = () => {
|
|
||||||
const url = `${globalUrl}/api/v1/orgs/${selectedOrganization?.id}/change`;
|
|
||||||
const data = {
|
|
||||||
org_id: selectedOrganization?.id,
|
|
||||||
sso_test: true,
|
|
||||||
}
|
|
||||||
fetch(url, {
|
|
||||||
mode: "cors",
|
|
||||||
credentials: "include",
|
|
||||||
crossDomain: true,
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
withCredentials: true,
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json; charset=utf-8",
|
|
||||||
},
|
|
||||||
}).then((response) => {
|
|
||||||
if (response.status !== 200) {
|
|
||||||
toast.error("Failed to test sso. Please try again later or contact support@shuffler.io if issue persist.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
}).then((responjson) => {
|
|
||||||
if (responjson["reason"] === "SSO_REDIRECT") {
|
|
||||||
setTimeout(() => {
|
|
||||||
toast.info("Redirecting to SSO login page as SSO is required for this organization.")
|
|
||||||
window.location.href = responjson["url"];
|
|
||||||
return
|
|
||||||
}, 2000)
|
|
||||||
} else {
|
|
||||||
toast.error("No SSO found for this org. Please set up sso for this org.")
|
|
||||||
}
|
|
||||||
}).catch((err) => {
|
|
||||||
console.log("error for sso test is: ", err)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -207,7 +207,6 @@ const ParsedAction = (props) => {
|
|||||||
}
|
}
|
||||||
}, [expansionModalOpen])
|
}, [expansionModalOpen])
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedActionEnvironment === undefined || selectedActionEnvironment === null || Object.keys(selectedActionEnvironment).length === 0) {
|
if (selectedActionEnvironment === undefined || selectedActionEnvironment === null || Object.keys(selectedActionEnvironment).length === 0) {
|
||||||
|
|
||||||
@@ -224,20 +223,6 @@ const ParsedAction = (props) => {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
/*
|
|
||||||
useEffect(() => {
|
|
||||||
setParamValues(selectedAction.parameters.map((param) => {
|
|
||||||
return {
|
|
||||||
name: param.name,
|
|
||||||
value: param.value,
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
},[
|
|
||||||
selectedAction, selectedApp,setNewSelectedAction, workflow,
|
|
||||||
])
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedAction.parameters === null || selectedAction.parameters === undefined) {
|
if (selectedAction.parameters === null || selectedAction.parameters === undefined) {
|
||||||
return
|
return
|
||||||
@@ -1855,6 +1840,7 @@ const ParsedAction = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{selectedApp.name !== undefined &&
|
{selectedApp.name !== undefined &&
|
||||||
selectedAction.authentication !== null &&
|
selectedAction.authentication !== null &&
|
||||||
selectedAction.authentication !== undefined &&
|
selectedAction.authentication !== undefined &&
|
||||||
@@ -1937,8 +1923,8 @@ const ParsedAction = (props) => {
|
|||||||
selectedAction.parameters[key].value = ""
|
selectedAction.parameters[key].value = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setSelectedAction(selectedAction);
|
setSelectedAction(selectedAction)
|
||||||
setUpdate(Math.random());
|
setUpdate(Math.random())
|
||||||
|
|
||||||
} else if (e.target.value === "authgroups") {
|
} else if (e.target.value === "authgroups") {
|
||||||
if (authGroups !== undefined && authGroups !== null && authGroups.length === 0) {
|
if (authGroups !== undefined && authGroups !== null && authGroups.length === 0) {
|
||||||
@@ -2051,14 +2037,6 @@ const ParsedAction = (props) => {
|
|||||||
|
|
||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
{/*
|
|
||||||
|
|
||||||
<Button fullWidth style={{margin: "auto", marginTop: "10px",}} color="primary" variant="contained" onClick={() => setAuthenticationModalOpen(true)}>
|
|
||||||
AUTHENTICATE
|
|
||||||
</Button>
|
|
||||||
curaction.authentication = authenticationOptions
|
|
||||||
if (curaction.selectedAuthentication === null || curaction.selectedAuthentication === undefined || curaction.selectedAuthentication.length === "")
|
|
||||||
*/}
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
color="primary"
|
color="primary"
|
||||||
title={"Add authentication option"}
|
title={"Add authentication option"}
|
||||||
@@ -4163,20 +4141,12 @@ const ParsedAction = (props) => {
|
|||||||
/*<div style={{width: 17, height: 17, borderRadius: 17 / 2, backgroundColor: itemColor, marginRight: 10, marginTop: 2, marginTop: "auto", marginBottom: "auto",}}/>*/
|
/*<div style={{width: 17, height: 17, borderRadius: 17 / 2, backgroundColor: itemColor, marginRight: 10, marginTop: 2, marginTop: "auto", marginBottom: "auto",}}/>*/
|
||||||
}
|
}
|
||||||
|
|
||||||
const buttonTitle = `Authenticate ${selectedApp.name.replaceAll("_", " ")}`
|
const buttonTitle = `Authenticate API ${selectedApp.name.replaceAll("_", " ")}`
|
||||||
const hasAutocomplete = data?.autocompleted === true
|
const hasAutocomplete = data?.autocompleted === true
|
||||||
if (data.variant === undefined || data.variant === null) {
|
if (data.variant === undefined || data.variant === null) {
|
||||||
data.variant = "STATIC_VALUE"
|
data.variant = "STATIC_VALUE"
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if (data?.configuration === true) {
|
|
||||||
if (data?.name === "url" && authenticationType?.type === "oauth2-app") {
|
|
||||||
data.configuration = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={data.name}>
|
<div key={data.name}>
|
||||||
{/* {hideBodyButton} */}
|
{/* {hideBodyButton} */}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const chipStyle = {
|
|||||||
|
|
||||||
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
|
||||||
const SearchData = props => {
|
const SearchData = props => {
|
||||||
const { serverside, globalUrl, userdata, setModalOpen, modalOpen } = props
|
const { serverside, globalUrl, userdata, searchBarModalOpen, setSearchBarModalOpen } = props
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
const borderRadius = 3
|
const borderRadius = 3
|
||||||
const node = useRef()
|
const node = useRef()
|
||||||
@@ -56,8 +56,8 @@ const SearchData = props => {
|
|||||||
const [value, setValue] = useState("");
|
const [value, setValue] = useState("");
|
||||||
|
|
||||||
const handleLinkClick = () => {
|
const handleLinkClick = () => {
|
||||||
if (modalOpen) {
|
if (searchBarModalOpen) {
|
||||||
setModalOpen(false); // Assuming setModalOpen is defined correctly
|
setSearchBarModalOpen(false); // Assuming setModalOpen is defined correctly
|
||||||
} else {
|
} else {
|
||||||
console.log("Condition not met, staying on the same page");
|
console.log("Condition not met, staying on the same page");
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ const SearchData = props => {
|
|||||||
const trimmedValue = inputValue.trim();
|
const trimmedValue = inputValue.trim();
|
||||||
if (trimmedValue !== '') {
|
if (trimmedValue !== '') {
|
||||||
navigate(`/search?q=${trimmedValue}`, { state: trimmedValue, replace: true });
|
navigate(`/search?q=${trimmedValue}`, { state: trimmedValue, replace: true });
|
||||||
setModalOpen(false);
|
setSearchBarModalOpen(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -249,7 +249,7 @@ const SearchData = props => {
|
|||||||
<Link key={hit.objectID} to={parsedUrl} rel="noopener noreferrer" style={{ textDecoration: "none", color: "white", }} onClick={(event) => {
|
<Link key={hit.objectID} to={parsedUrl} rel="noopener noreferrer" style={{ textDecoration: "none", color: "white", }} onClick={(event) => {
|
||||||
//console.log("CLICK")
|
//console.log("CLICK")
|
||||||
setSearchOpen(true)
|
setSearchOpen(true)
|
||||||
setModalOpen(false)
|
setSearchBarModalOpen(false)
|
||||||
aa('init', {
|
aa('init', {
|
||||||
appId: searchClient.appId,
|
appId: searchClient.appId,
|
||||||
apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
|
apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
|
||||||
@@ -498,7 +498,7 @@ const SearchData = props => {
|
|||||||
return (
|
return (
|
||||||
<Link key={hit.objectID} to={parsedUrl} style={{ textDecoration: "none", color: "white", }} onClick={(event) => {
|
<Link key={hit.objectID} to={parsedUrl} style={{ textDecoration: "none", color: "white", }} onClick={(event) => {
|
||||||
setSearchOpen(true)
|
setSearchOpen(true)
|
||||||
setModalOpen(false)
|
setSearchBarModalOpen(false)
|
||||||
aa('init', {
|
aa('init', {
|
||||||
appId: searchClient.appId,
|
appId: searchClient.appId,
|
||||||
apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
|
apiKey: searchClient.transporter.queryParameters["x-algolia-api-key"]
|
||||||
@@ -702,7 +702,7 @@ const SearchData = props => {
|
|||||||
|
|
||||||
console.log("CLICK")
|
console.log("CLICK")
|
||||||
setSearchOpen(true)
|
setSearchOpen(true)
|
||||||
setModalOpen(false)
|
setSearchBarModalOpen(false)
|
||||||
}}>
|
}}>
|
||||||
<ListItem key={hit.objectID} style={innerlistitemStyle} onMouseOver={() => {
|
<ListItem key={hit.objectID} style={innerlistitemStyle} onMouseOver={() => {
|
||||||
setMouseHoverIndex(index)
|
setMouseHoverIndex(index)
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef, useContext } from 'react';
|
||||||
|
|
||||||
import theme from '../theme.jsx';
|
import theme from '../theme.jsx';
|
||||||
import { useNavigate, Link, useParams } from "react-router-dom";
|
import { useNavigate, Link, useParams } from "react-router-dom";
|
||||||
import SearchBox from "../components/SearchData.jsx";
|
import SearchBox from "../components/SearchData.jsx";
|
||||||
|
|
||||||
|
import { Context } from '../Context/contextApi.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Chip,
|
Chip,
|
||||||
IconButton,
|
IconButton,
|
||||||
@@ -45,20 +47,22 @@ const chipStyle = {
|
|||||||
const SearchField = props => {
|
const SearchField = props => {
|
||||||
const { serverside, userdata, isMobile, isLoaded, globalUrl, isHeader, isLoggedIn, small, rounded } = props
|
const { serverside, userdata, isMobile, isLoaded, globalUrl, isHeader, isLoggedIn, small, rounded } = props
|
||||||
|
|
||||||
|
const {searchBarModalOpen, setSearchBarModalOpen} = useContext(Context);
|
||||||
|
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
const borderRadius = 3
|
const borderRadius = 3
|
||||||
const node = useRef()
|
const node = useRef()
|
||||||
const [searchOpen, setSearchOpen] = useState(false)
|
const [searchOpen, setSearchOpen] = useState(false)
|
||||||
const [modalOpen, setModalOpen] = React.useState(false);
|
// const [modalOpen, setModalOpen] = React.useState(false);
|
||||||
const [oldPath, setOldPath] = useState("")
|
const [oldPath, setOldPath] = useState("")
|
||||||
const [value, setValue] = useState("");
|
const [value, setValue] = useState("");
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Mousetrap.bind(['command+k', 'ctrl+k'], () => {
|
Mousetrap.bind(['command+k', 'ctrl+k'], () => {
|
||||||
setModalOpen(true);
|
setSearchBarModalOpen(true);
|
||||||
return false; // Prevent the default action
|
return false; // Prevent the default action
|
||||||
});
|
});
|
||||||
Mousetrap.bind(['esc'], () => {
|
Mousetrap.bind(['esc'], () => {
|
||||||
setModalOpen(false);
|
setSearchBarModalOpen(false);
|
||||||
return false; // Prevent the default action
|
return false; // Prevent the default action
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -72,9 +76,9 @@ const SearchField = props => {
|
|||||||
// console.log("key:", dataValue.key),
|
// console.log("key:", dataValue.key),
|
||||||
//console.log("value:",dataValue.value),
|
//console.log("value:",dataValue.value),
|
||||||
<Dialog
|
<Dialog
|
||||||
open={modalOpen}
|
open={searchBarModalOpen}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setModalOpen(false);
|
setSearchBarModalOpen(false);
|
||||||
}}
|
}}
|
||||||
PaperProps={{
|
PaperProps={{
|
||||||
style: {
|
style: {
|
||||||
@@ -92,12 +96,12 @@ const SearchField = props => {
|
|||||||
{isHeader ? <div style={{ display: "flex"}}>
|
{isHeader ? <div style={{ display: "flex"}}>
|
||||||
<DialogTitle style={{ marginTop: 15, marginLeft: 5, color: "var(--Paragraph-text, #C8C8C8)" }} >Search for Docs, Apps, Workflows and more</DialogTitle>
|
<DialogTitle style={{ marginTop: 15, marginLeft: 5, color: "var(--Paragraph-text, #C8C8C8)" }} >Search for Docs, Apps, Workflows and more</DialogTitle>
|
||||||
<Button color="secondary" fullWidth style={{ marginLeft:180, }} onClick={() => {
|
<Button color="secondary" fullWidth style={{ marginLeft:180, }} onClick={() => {
|
||||||
setModalOpen(false);
|
setSearchBarModalOpen(false);
|
||||||
}}><CloseIcon /></Button>
|
}}><CloseIcon /></Button>
|
||||||
</div>
|
</div>
|
||||||
: null}
|
: null}
|
||||||
<DialogContent className='dialog-content' style={{}}>
|
<DialogContent className='dialog-content' style={{}}>
|
||||||
<SearchBox globalUrl={globalUrl} setModalOpen={setModalOpen} modalOpen={modalOpen} serverside={serverside} userdata={userdata} />
|
<SearchBox globalUrl={globalUrl} setSearchBarModalOpen={setSearchBarModalOpen} modalOpen={searchBarModalOpen} serverside={serverside} userdata={userdata} />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<Divider style={{overflow: "hidden"}}/>
|
<Divider style={{overflow: "hidden"}}/>
|
||||||
<span style={{display:"flex", width:"100%", height:30}}>
|
<span style={{display:"flex", width:"100%", height:30}}>
|
||||||
@@ -155,7 +159,7 @@ const SearchField = props => {
|
|||||||
color="primary"
|
color="primary"
|
||||||
placeholder="Search Apps, Workflows, Docs..."
|
placeholder="Search Apps, Workflows, Docs..."
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
setModalOpen(true)
|
setSearchBarModalOpen(true)
|
||||||
}}
|
}}
|
||||||
limit={5}
|
limit={5}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -261,8 +261,6 @@ const WorkflowValidationTimeline = (props) => {
|
|||||||
relevantactions.push(...newactions)
|
relevantactions.push(...newactions)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Relevant actions (return null if 0-1): ", relevantactions)
|
|
||||||
|
|
||||||
if (relevantactions.length <= 1) {
|
if (relevantactions.length <= 1) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ import cytoscapestyle from "../defaultCytoscapeStyle.jsx";
|
|||||||
import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.jsx";
|
import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.jsx";
|
||||||
|
|
||||||
import WorkflowValidationTimeline from "../components/WorkflowValidationTimeline.jsx"
|
import WorkflowValidationTimeline from "../components/WorkflowValidationTimeline.jsx"
|
||||||
import { validateJson, GetIconInfo } from "../views/Workflows.jsx";
|
import { validateJson, collapseField, GetIconInfo } from "../views/Workflows.jsx";
|
||||||
import { GetParsedPaths, internalIds, } from "../views/Apps.jsx";
|
import { GetParsedPaths, internalIds, } from "../views/Apps.jsx";
|
||||||
import ConfigureWorkflow from "../components/ConfigureWorkflow.jsx";
|
import ConfigureWorkflow from "../components/ConfigureWorkflow.jsx";
|
||||||
import AuthenticationOauth2 from "../components/Oauth2Auth.jsx";
|
import AuthenticationOauth2 from "../components/Oauth2Auth.jsx";
|
||||||
@@ -1242,12 +1242,18 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
};
|
};
|
||||||
|
|
||||||
const setNewAppAuth = (appAuthData, refresh) => {
|
const setNewAppAuth = (appAuthData, refresh) => {
|
||||||
|
var headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflow.org_id !== undefined && workflow.org_id !== null && workflow.org_id.length > 0) {
|
||||||
|
headers["Org-Id"] = workflow.org_id
|
||||||
|
}
|
||||||
|
|
||||||
fetch(globalUrl + "/api/v1/apps/authentication", {
|
fetch(globalUrl + "/api/v1/apps/authentication", {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: headers,
|
||||||
"Content-Type": "application/json",
|
|
||||||
Accept: "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(appAuthData),
|
body: JSON.stringify(appAuthData),
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
})
|
})
|
||||||
@@ -2522,13 +2528,11 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedAction.authentication = authenticationOptions;
|
console.log("auth options: ", authenticationOptions)
|
||||||
if (
|
|
||||||
selectedAction.selectedAuthentication === null ||
|
selectedAction.authentication = authenticationOptions
|
||||||
selectedAction.selectedAuthentication === undefined ||
|
if (selectedAction.selectedAuthentication === null || selectedAction.selectedAuthentication === undefined || selectedAction.selectedAuthentication.length === "") {
|
||||||
selectedAction.selectedAuthentication.length === ""
|
selectedAction.selectedAuthentication = {}
|
||||||
) {
|
|
||||||
selectedAction.selectedAuthentication = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appUpdates === true) {
|
if (appUpdates === true) {
|
||||||
@@ -2555,7 +2559,7 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
setAppAuthentication([]);
|
setAppAuthentication([])
|
||||||
shouldClose = true
|
shouldClose = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5274,7 +5278,10 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
authenticationOptions[latestindex].last_modified = true
|
authenticationOptions[latestindex].last_modified = true
|
||||||
}
|
}
|
||||||
|
|
||||||
curaction.authentication = authenticationOptions;
|
|
||||||
|
console.log("auth options 2: ", authenticationOptions)
|
||||||
|
|
||||||
|
curaction.authentication = authenticationOptions
|
||||||
if (
|
if (
|
||||||
curaction.selectedAuthentication === null ||
|
curaction.selectedAuthentication === null ||
|
||||||
curaction.selectedAuthentication === undefined ||
|
curaction.selectedAuthentication === undefined ||
|
||||||
@@ -5283,7 +5290,9 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
curaction.selectedAuthentication = {};
|
curaction.selectedAuthentication = {};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
curaction.authentication = [];
|
console.log("auth option 3")
|
||||||
|
|
||||||
|
curaction.authentication = []
|
||||||
curaction.authentication_id = "";
|
curaction.authentication_id = "";
|
||||||
curaction.selectedAuthentication = {};
|
curaction.selectedAuthentication = {};
|
||||||
}
|
}
|
||||||
@@ -7022,9 +7031,9 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
const px = parentNode.position("x") + 0;
|
const px = parentNode.position("x") + 0;
|
||||||
const py = parentNode.position("y") + 100;
|
const py = parentNode.position("y") + 100;
|
||||||
|
|
||||||
const parentlabel = parentNode.data("label").toLowerCase().replace(" ", "_")
|
const parentlabel = parentNode.data("label")?.toLowerCase().replace(" ", "_")
|
||||||
const parentname = parentNode.data("app_name").toLowerCase().replace(" ", "_")
|
const parentname = parentNode.data("app_name")?.toLowerCase().replace(" ", "_")
|
||||||
if (!parentlabel.startsWith(parentname)+"_") {
|
if (!parentlabel?.startsWith(parentname)+"_") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7855,6 +7864,7 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
return node
|
return node
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// What are these again? Where are they used?
|
||||||
const decoratorNodes = inputworkflow.actions.map((action) => {
|
const decoratorNodes = inputworkflow.actions.map((action) => {
|
||||||
if (!action.isStartNode) {
|
if (!action.isStartNode) {
|
||||||
if (action.app_name === "Testing") {
|
if (action.app_name === "Testing") {
|
||||||
@@ -7866,11 +7876,20 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action.id === undefined || action.id === null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.position === undefined || action.position === null || action.position.x === undefined || action.position.x === null || action.position.y === undefined || action.position.y === null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
const iconInfo = GetIconInfo(action);
|
const iconInfo = GetIconInfo(action);
|
||||||
const svg_pin = `<svg width="${svgSize}" height="${svgSize}" viewBox="0 0 ${svgSize} ${svgSize}" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="${iconInfo.icon}" fill="${iconInfo.iconColor}"></path></svg>`;
|
const svg_pin = `<svg width="${svgSize}" height="${svgSize}" viewBox="0 0 ${svgSize} ${svgSize}" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="${iconInfo.icon}" fill="${iconInfo.iconColor}"></path></svg>`;
|
||||||
const svgpin_Url = encodeURI("data:image/svg+xml;utf-8," + svg_pin);
|
const svgpin_Url = encodeURI("data:image/svg+xml;utf-8," + svg_pin);
|
||||||
|
|
||||||
const offset = action.isStartNode ? 36 : 44;
|
const offset = action.isStartNode ? 36 : 44;
|
||||||
|
|
||||||
const decoratorNode = {
|
const decoratorNode = {
|
||||||
position: {
|
position: {
|
||||||
x: action.position.x + offset,
|
x: action.position.x + offset,
|
||||||
@@ -7886,9 +7905,9 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
imageColor: iconInfo.iconBackgroundColor,
|
imageColor: iconInfo.iconBackgroundColor,
|
||||||
attachedTo: action.id,
|
attachedTo: action.id,
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
return decoratorNode;
|
return decoratorNode
|
||||||
});
|
})
|
||||||
|
|
||||||
|
|
||||||
const foundtriggers = inputworkflow.triggers.map((trigger) => {
|
const foundtriggers = inputworkflow.triggers.map((trigger) => {
|
||||||
@@ -9371,6 +9390,7 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
newAppData.authentication = [];
|
newAppData.authentication = [];
|
||||||
newAppData.authentication_id = "";
|
newAppData.authentication_id = "";
|
||||||
newAppData.selectedAuthentication = {};
|
newAppData.selectedAuthentication = {};
|
||||||
@@ -9505,11 +9525,9 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
}
|
}
|
||||||
|
|
||||||
var parsedEnvironments =
|
var parsedEnvironments =
|
||||||
environments === null || environments === []
|
environments === undefined || environments === null || environments === []
|
||||||
? "cloud"
|
? isCloud ? "cloud" : "Shuffle" : environments[defaultEnvironmentIndex] === undefined
|
||||||
: environments[defaultEnvironmentIndex] === undefined
|
? isCloud ? "cloud" : "Shuffle" : environments[defaultEnvironmentIndex].Name
|
||||||
? "cloud"
|
|
||||||
: environments[defaultEnvironmentIndex].Name
|
|
||||||
|
|
||||||
// Basic automatic auth mapping
|
// Basic automatic auth mapping
|
||||||
var authId = ""
|
var authId = ""
|
||||||
@@ -10512,6 +10530,10 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
// description
|
// description
|
||||||
// ACTION select
|
// ACTION select
|
||||||
const selectedNameChange = (appActionName) => {
|
const selectedNameChange = (appActionName) => {
|
||||||
|
if (appActionName === undefined || appActionName === null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
appActionName = appActionName.replaceAll("(", "");
|
appActionName = appActionName.replaceAll("(", "");
|
||||||
appActionName = appActionName.replaceAll(")", "");
|
appActionName = appActionName.replaceAll(")", "");
|
||||||
appActionName = appActionName.replaceAll("]", "");
|
appActionName = appActionName.replaceAll("]", "");
|
||||||
@@ -18142,7 +18164,10 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
src={validate.result}
|
src={validate.result}
|
||||||
theme={theme.palette.jsonTheme}
|
theme={theme.palette.jsonTheme}
|
||||||
style={theme.palette.reactJsonStyle}
|
style={theme.palette.reactJsonStyle}
|
||||||
collapsed={true}
|
collapsed={false}
|
||||||
|
shouldCollapse={(jsonField) => {
|
||||||
|
return collapseField(jsonField)
|
||||||
|
}}
|
||||||
iconStyle={theme.palette.jsonIconStyle}
|
iconStyle={theme.palette.jsonIconStyle}
|
||||||
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
||||||
displayArrayKey={false}
|
displayArrayKey={false}
|
||||||
@@ -18483,12 +18508,12 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
theme={theme.palette.jsonTheme}
|
theme={theme.palette.jsonTheme}
|
||||||
style={theme.palette.reactJsonStyle}
|
style={theme.palette.reactJsonStyle}
|
||||||
collapsed={parsedCollapse}
|
collapsed={parsedCollapse}
|
||||||
|
shouldCollapse={(jsonField) => {
|
||||||
|
return collapseField(jsonField)
|
||||||
|
}}
|
||||||
iconStyle={theme.palette.jsonIconStyle}
|
iconStyle={theme.palette.jsonIconStyle}
|
||||||
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
||||||
displayArrayKey={false}
|
displayArrayKey={false}
|
||||||
shouldCollapse={(field) => {
|
|
||||||
console.log("FIELD: ", field)
|
|
||||||
}}
|
|
||||||
enableClipboard={(copy) => {
|
enableClipboard={(copy) => {
|
||||||
handleReactJsonClipboard(copy);
|
handleReactJsonClipboard(copy);
|
||||||
}}
|
}}
|
||||||
@@ -19799,7 +19824,10 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
src={validate.result}
|
src={validate.result}
|
||||||
theme={theme.palette.jsonTheme}
|
theme={theme.palette.jsonTheme}
|
||||||
style={theme.palette.reactJsonStyle}
|
style={theme.palette.reactJsonStyle}
|
||||||
collapsed={true}
|
collapsed={false}
|
||||||
|
shouldCollapse={(jsonField) => {
|
||||||
|
return collapseField(jsonField)
|
||||||
|
}}
|
||||||
iconStyle={theme.palette.jsonIconStyle}
|
iconStyle={theme.palette.jsonIconStyle}
|
||||||
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
||||||
displayArrayKey={false}
|
displayArrayKey={false}
|
||||||
@@ -19959,6 +19987,9 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
theme={theme.palette.jsonTheme}
|
theme={theme.palette.jsonTheme}
|
||||||
style={theme.palette.reactJsonStyle}
|
style={theme.palette.reactJsonStyle}
|
||||||
collapsed={data.value.length < 10000 ? false : true}
|
collapsed={data.value.length < 10000 ? false : true}
|
||||||
|
shouldCollapse={(jsonField) => {
|
||||||
|
return collapseField(jsonField)
|
||||||
|
}}
|
||||||
iconStyle={theme.palette.jsonIconStyle}
|
iconStyle={theme.palette.jsonIconStyle}
|
||||||
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
||||||
displayArrayKey={false}
|
displayArrayKey={false}
|
||||||
@@ -20379,6 +20410,9 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
theme={theme.palette.jsonTheme}
|
theme={theme.palette.jsonTheme}
|
||||||
style={theme.palette.reactJsonStyle}
|
style={theme.palette.reactJsonStyle}
|
||||||
collapsed={selectedResult.result.length < 10000 ? false : true}
|
collapsed={selectedResult.result.length < 10000 ? false : true}
|
||||||
|
shouldCollapse={(jsonField) => {
|
||||||
|
return collapseField(jsonField)
|
||||||
|
}}
|
||||||
iconStyle={theme.palette.jsonIconStyle}
|
iconStyle={theme.palette.jsonIconStyle}
|
||||||
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
||||||
displayArrayKey={false}
|
displayArrayKey={false}
|
||||||
@@ -21098,13 +21132,13 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Action: ", selectedAction);
|
|
||||||
selectedAction.authentication_id = authenticationOption.id;
|
selectedAction.authentication_id = authenticationOption.id;
|
||||||
selectedAction.selectedAuthentication = authenticationOption;
|
selectedAction.selectedAuthentication = authenticationOption;
|
||||||
if (
|
|
||||||
selectedAction.authentication === undefined ||
|
console.log("auth option 4: ", authenticationOption)
|
||||||
selectedAction.authentication === null
|
|
||||||
) {
|
if (selectedAction.authentication === undefined || selectedAction.authentication === null) {
|
||||||
|
|
||||||
selectedAction.authentication = [authenticationOption]
|
selectedAction.authentication = [authenticationOption]
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -21115,7 +21149,7 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelectedAction(selectedAction);
|
setSelectedAction(selectedAction)
|
||||||
|
|
||||||
var newAuthOption = JSON.parse(JSON.stringify(authenticationOption));
|
var newAuthOption = JSON.parse(JSON.stringify(authenticationOption));
|
||||||
var newFields = [];
|
var newFields = [];
|
||||||
@@ -21128,20 +21162,17 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
newAuthOption.fields = newFields;
|
newAuthOption.fields = newFields
|
||||||
setNewAppAuth(newAuthOption);
|
setNewAppAuth(newAuthOption)
|
||||||
|
|
||||||
if (configureWorkflowModalOpen) {
|
if (configureWorkflowModalOpen) {
|
||||||
setSelectedAction({});
|
setSelectedAction({})
|
||||||
}
|
}
|
||||||
|
|
||||||
setUpdate(authenticationOption.id);
|
setUpdate(authenticationOption.id)
|
||||||
};
|
}
|
||||||
|
|
||||||
if (
|
if (authenticationOption.label === null || authenticationOption.label === undefined) {
|
||||||
authenticationOption.label === null ||
|
|
||||||
authenticationOption.label === undefined
|
|
||||||
) {
|
|
||||||
authenticationOption.label = selectedApp.name + " authentication";
|
authenticationOption.label = selectedApp.name + " authentication";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21164,7 +21195,7 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
<div />
|
<div />
|
||||||
These are required fields for authenticating with {selectedApp.name}
|
These are required fields for authenticating with {selectedApp.name}
|
||||||
<div style={{ marginTop: 15 }} />
|
<div style={{ marginTop: 15 }} />
|
||||||
<b>Name - what is this used for?</b>
|
<b>Label for you to remember</b>
|
||||||
<TextField
|
<TextField
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.palette.inputColor,
|
backgroundColor: theme.palette.inputColor,
|
||||||
@@ -21294,19 +21325,20 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
style={{ borderRadius: "0px" }}
|
style={{}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setAuthenticationModalOpen(false);
|
setAuthenticationModalOpen(false);
|
||||||
}}
|
}}
|
||||||
color="primary"
|
color="secondary"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
style={{ borderRadius: "0px" }}
|
style={{}}
|
||||||
|
variant="outlined"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setAuthenticationOptions(authenticationOption);
|
setAuthenticationOptions(authenticationOption);
|
||||||
handleSubmitCheck();
|
handleSubmitCheck()
|
||||||
}}
|
}}
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
@@ -21410,11 +21442,12 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
width: 50,
|
width: 50,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{selectedApp.reference_info === undefined ||
|
{ selectedApp.reference_info === undefined ||
|
||||||
selectedApp.reference_info === null ||
|
selectedApp.reference_info === null ||
|
||||||
selectedApp.reference_info.github_url === undefined ||
|
selectedApp.reference_info.github_url === undefined ||
|
||||||
selectedApp.reference_info.github_url === null ||
|
selectedApp.reference_info.github_url === null ||
|
||||||
selectedApp.reference_info.github_url.length === 0 ? (
|
selectedApp.reference_info.github_url.length === 0 ? (
|
||||||
|
|
||||||
<a
|
<a
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -21557,12 +21590,30 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
<span
|
<span
|
||||||
style={{ textAlign: "center" }}
|
style={{ textAlign: "center" }}
|
||||||
>
|
>
|
||||||
<Typography
|
<div style={{textAlign: "left", }}>
|
||||||
variant="body1"
|
<Markdown
|
||||||
style={{ marginLeft: 25, marginRight: 25 }}
|
components={{
|
||||||
|
img: Img,
|
||||||
|
code: CodeHandler,
|
||||||
|
h1: Heading,
|
||||||
|
h2: Heading,
|
||||||
|
h3: Heading,
|
||||||
|
h4: Heading,
|
||||||
|
h5: Heading,
|
||||||
|
h6: Heading,
|
||||||
|
a: OuterLink,
|
||||||
|
}}
|
||||||
|
id="markdown_wrapper"
|
||||||
|
escapeHtml={false}
|
||||||
|
style={{
|
||||||
|
maxWidth: "100%",
|
||||||
|
minWidth: "100%",
|
||||||
|
textAlign: "left",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{selectedApp.description}
|
{selectedApp.description}
|
||||||
</Typography>
|
</Markdown>
|
||||||
|
</div>
|
||||||
<Divider
|
<Divider
|
||||||
style={{
|
style={{
|
||||||
marginTop: 25,
|
marginTop: 25,
|
||||||
@@ -21580,7 +21631,7 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography variant="h6" style={{marginBottom: 25, }}>
|
<Typography variant="h6" style={{marginBottom: 25, }}>
|
||||||
There is no Shuffle-specific documentation for this app yet. Documentation is written custom for each app, and is a community effort. Hope to see your contribution
|
There is no Shuffle-specific documentation for this app yet outside of the general description above. Documentation is written for each api, and is a community effort. We hope to see your contribution!
|
||||||
</Typography>
|
</Typography>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
@@ -21724,6 +21775,7 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
: null}
|
: null}
|
||||||
|
|
||||||
<Markdown
|
<Markdown
|
||||||
components={{
|
components={{
|
||||||
img: Img,
|
img: Img,
|
||||||
@@ -22299,8 +22351,6 @@ const releaseToConnectLabel = "Release to Connect"
|
|||||||
|
|
||||||
const changeActionParameterCodeMirror = (event, count, data, actionlist) => {
|
const changeActionParameterCodeMirror = (event, count, data, actionlist) => {
|
||||||
// Check if event.target.value is an array. If it is, split with comma
|
// Check if event.target.value is an array. If it is, split with comma
|
||||||
console.log("1 - SELECTED ACTION: ", selectedAction)
|
|
||||||
console.log("1 - DATA: ", data)
|
|
||||||
|
|
||||||
if (data.startsWith("${") && data.endsWith("}")) {
|
if (data.startsWith("${") && data.endsWith("}")) {
|
||||||
// PARAM FIX - Gonna use the ID field, even though it's a hack
|
// PARAM FIX - Gonna use the ID field, even though it's a hack
|
||||||
|
|||||||
@@ -152,6 +152,8 @@ export const OuterLink = (props) => {
|
|||||||
|
|
||||||
|
|
||||||
export const Img = (props) => {
|
export const Img = (props) => {
|
||||||
|
// Find parent container and check width
|
||||||
|
|
||||||
var height = "auto"
|
var height = "auto"
|
||||||
var width = 750
|
var width = 750
|
||||||
if (props.height !== undefined && props.height !== null) {
|
if (props.height !== undefined && props.height !== null) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import ReactJson from "react-json-view-ssr";
|
|||||||
import { green, yellow, red, grey} from "./AngularWorkflow.jsx";
|
import { green, yellow, red, grey} from "./AngularWorkflow.jsx";
|
||||||
import { CodeHandler, Img, OuterLink, } from "../views/Docs.jsx";
|
import { CodeHandler, Img, OuterLink, } from "../views/Docs.jsx";
|
||||||
import { useNavigate, Link, useParams } from "react-router-dom";
|
import { useNavigate, Link, useParams } from "react-router-dom";
|
||||||
import { validateJson, GetIconInfo } from "./Workflows.jsx";
|
import { validateJson, collapseField, GetIconInfo } from "./Workflows.jsx";
|
||||||
import EditWorkflow from "../components/EditWorkflow.jsx"
|
import EditWorkflow from "../components/EditWorkflow.jsx"
|
||||||
import { toast } from "react-toastify"
|
import { toast } from "react-toastify"
|
||||||
import { makeStyles } from '@mui/material/styles';
|
import { makeStyles } from '@mui/material/styles';
|
||||||
@@ -15,6 +15,7 @@ import { isMobile } from "react-device-detect";
|
|||||||
import Markdown from "react-markdown";
|
import Markdown from "react-markdown";
|
||||||
import theme from '../theme.jsx';
|
import theme from '../theme.jsx';
|
||||||
import rehypeRaw from "rehype-raw";
|
import rehypeRaw from "rehype-raw";
|
||||||
|
import RecentWorkflow from "../components/RecentWorkflow.jsx";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
@@ -39,6 +40,9 @@ import {
|
|||||||
ContentCopy as ContentCopyIcon,
|
ContentCopy as ContentCopyIcon,
|
||||||
ArrowBack as ArrowBackIcon,
|
ArrowBack as ArrowBackIcon,
|
||||||
ArrowForward as ArrowForwardIcon,
|
ArrowForward as ArrowForwardIcon,
|
||||||
|
Lock as LockIcon,
|
||||||
|
LockOpen as LockOpenIcon,
|
||||||
|
OpenInNew as OpenInNewIcon,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
|
|
||||||
const hrefStyle = {
|
const hrefStyle = {
|
||||||
@@ -75,12 +79,30 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
const [editWorkflowModalOpen, setEditWorkflowModalOpen] = React.useState(false)
|
const [editWorkflowModalOpen, setEditWorkflowModalOpen] = React.useState(false)
|
||||||
const [sharingOpen, setSharingOpen] = React.useState(false)
|
const [sharingOpen, setSharingOpen] = React.useState(false)
|
||||||
const [realtimeMarkdown, setRealtimeMarkdown] = React.useState("")
|
const [realtimeMarkdown, setRealtimeMarkdown] = React.useState("")
|
||||||
|
const [forms, setForms] = React.useState([])
|
||||||
|
|
||||||
|
const IframeWrapper = (props) => {
|
||||||
|
var propsCopy = JSON.parse(JSON.stringify(props))
|
||||||
|
propsCopy.width = 400
|
||||||
|
propsCopy.height = 225
|
||||||
|
|
||||||
|
return <iframe {...propsCopy} style={{width: propsCopy.width, height: propsCopy.height, }} />
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImgWrapper = (props) => {
|
||||||
|
var propsCopy = JSON.parse(JSON.stringify(props))
|
||||||
|
if (propsCopy.width === undefined || propsCopy.width === null) {
|
||||||
|
propsCopy.width = 400
|
||||||
|
propsCopy.height = "auto"
|
||||||
|
}
|
||||||
|
|
||||||
|
return Img(propsCopy)
|
||||||
|
}
|
||||||
|
|
||||||
const boxStyle = {
|
const boxStyle = {
|
||||||
color: "white",
|
color: "white",
|
||||||
padding: "25px 50px 50px 50px",
|
padding: "25px 50px 50px 50px",
|
||||||
backgroundColor: theme.palette.surfaceColor,
|
backgroundColor: theme.palette.surfaceColor,
|
||||||
marginBottom: 150,
|
|
||||||
borderRadius: 25,
|
borderRadius: 25,
|
||||||
minHeight: 500,
|
minHeight: 500,
|
||||||
}
|
}
|
||||||
@@ -123,6 +145,39 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadForms = (orgId) => {
|
||||||
|
const url = `${globalUrl}/api/v1/orgs/${orgId}/forms`
|
||||||
|
fetch(url, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
credentials: "include",
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.log("Status not 200 for org forms");
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
if (responseJson.success === false) {
|
||||||
|
toast.error("Failed saving workflow. Please try again.")
|
||||||
|
} else {
|
||||||
|
if (responseJson?.length > 0) {
|
||||||
|
// Sort them by name
|
||||||
|
responseJson.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
setForms(responseJson)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
//toast.error("Load form error: " + error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const saveWorkflow = (workflow) => {
|
const saveWorkflow = (workflow) => {
|
||||||
const url = `${globalUrl}/api/v1/workflows/${workflow.id}`
|
const url = `${globalUrl}/api/v1/workflows/${workflow.id}`
|
||||||
fetch(url, {
|
fetch(url, {
|
||||||
@@ -198,26 +253,13 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
return defaultReturn
|
return defaultReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const validate = validateJson(executionData.result)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{marginTop: executionMargin, }}>
|
<div style={{marginTop: executionMargin, }}>
|
||||||
{/*executionData !== undefined && executionData !== null && executionData !== {} && executionData.status !== undefined && (answer === undefined || answer === null) ?
|
<Divider style={{marginTop: 20, marginBottom: 20, }}/>
|
||||||
<div style={{ marginBottom: 5, display: "flex" }}>
|
|
||||||
<Typography variant="body1">
|
|
||||||
<b>Status </b>
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="body1" color="textSecondary" style={{ marginRight: 15, }}>
|
|
||||||
{executionData.status}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
: null*/}
|
|
||||||
|
|
||||||
{/*
|
{validate.valid === false ?
|
||||||
<Typography variant="h6" style={{color: theme.palette.primaryColor}}>
|
|
||||||
Results: {executionData.results.length}/{executionData.workflow.actions.length}
|
|
||||||
</Typography>
|
|
||||||
*/}
|
|
||||||
|
|
||||||
{executionData.result !== undefined && executionData.result !== null && executionData.result.length > 0 ?
|
|
||||||
<div style={{marginTop: 20, }}>
|
<div style={{marginTop: 20, }}>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Markdown
|
<Markdown
|
||||||
@@ -235,10 +277,31 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{executionData.result}
|
{validate.result}
|
||||||
</Markdown>
|
</Markdown>
|
||||||
</div>
|
</div>
|
||||||
: null}
|
:
|
||||||
|
<ReactJson
|
||||||
|
src={validate.result}
|
||||||
|
theme={theme.palette.jsonTheme}
|
||||||
|
style={theme.palette.reactJsonStyle}
|
||||||
|
collapsed={false}
|
||||||
|
iconStyle={theme.palette.jsonIconStyle}
|
||||||
|
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
||||||
|
shouldCollapse={(jsonField) => {
|
||||||
|
return collapseField(jsonField)
|
||||||
|
}}
|
||||||
|
displayArrayKey={false}
|
||||||
|
enableClipboard={(copy) => {
|
||||||
|
//handleReactJsonClipboard(copy);
|
||||||
|
}}
|
||||||
|
displayDataTypes={false}
|
||||||
|
onSelect={(select) => {
|
||||||
|
//HandleJsonCopy(validate.result, select, "exec");
|
||||||
|
}}
|
||||||
|
name={false}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -249,8 +312,6 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("ONSUBMIT: ", event, execution_id, authorization, answer)
|
|
||||||
|
|
||||||
stop()
|
stop()
|
||||||
setMessage("")
|
setMessage("")
|
||||||
setExecutionLoading(true)
|
setExecutionLoading(true)
|
||||||
@@ -285,7 +346,7 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
var url = `${globalUrl}/api/v1/workflows/${props.match.params.key}/execute`
|
var url = `${globalUrl}/api/v1/workflows/${props.match.params.key}/run`
|
||||||
var fetchBody = {
|
var fetchBody = {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json; charset=utf-8',
|
'Content-Type': 'application/json; charset=utf-8',
|
||||||
@@ -319,8 +380,6 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IF there is an execution argument, we should use it
|
// IF there is an execution argument, we should use it
|
||||||
console.log("FULL URL: ", url)
|
|
||||||
|
|
||||||
fetch(url, fetchBody)
|
fetch(url, fetchBody)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status !== 200 && response.status !== 201) {
|
if (response.status !== 200 && response.status !== 201) {
|
||||||
@@ -346,6 +405,10 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
})
|
})
|
||||||
.then(responseJson => {
|
.then(responseJson => {
|
||||||
setExecutionLoading(false)
|
setExecutionLoading(false)
|
||||||
|
if (responseJson.execution_id !== undefined && responseJson.execution_id !== null && responseJson.execution_id.length > 0) {
|
||||||
|
navigate(`?execution_id=${responseJson.execution_id}`)
|
||||||
|
}
|
||||||
|
|
||||||
if (responseJson.success === false) {
|
if (responseJson.success === false) {
|
||||||
console.log("Failed sending execution request")
|
console.log("Failed sending execution request")
|
||||||
if (responseJson.reason !== undefined && responseJson.reason !== null) {
|
if (responseJson.reason !== undefined && responseJson.reason !== null) {
|
||||||
@@ -372,7 +435,7 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
//setExecutionInfo("Error in workflow startup: " + error)
|
//setExecutionInfo("Error in workflow startup: " + error)
|
||||||
toast.warn("Error in workflow startup: " + error)
|
toast.warn("Error submitting form. Please try again.")
|
||||||
|
|
||||||
stop()
|
stop()
|
||||||
setMessage("")
|
setMessage("")
|
||||||
@@ -383,10 +446,104 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
useEffect(() => {
|
||||||
|
if (executionRequest === undefined || executionRequest === null || executionRequest.execution_id === undefined || executionRequest.execution_id === null || executionRequest.execution_id.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (executionRequest.start === true) {
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}, [executionRequest])
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { start, stop } = useInterval({
|
||||||
|
duration: 1500,
|
||||||
|
startImmediate: true,
|
||||||
|
callback: () => {
|
||||||
|
fetchUpdates(executionRequest.execution_id, executionRequest.authorization)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleExecutionLoader = () => {
|
||||||
|
if (window === undefined || window === null) {
|
||||||
|
console.log("No window")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlParams = new URLSearchParams(window.location.search)
|
||||||
|
if (urlParams === undefined || urlParams === null) {
|
||||||
|
console.log("No search params")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const execution = urlParams.get("execution_id")
|
||||||
|
if (execution === undefined || execution === null || execution.length === 0) {
|
||||||
|
console.log("No execution")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only works if you're logged in
|
||||||
|
fetchUpdates(execution, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadInputWorkflowData = (workflow_id, inputWorkflow) => {
|
||||||
|
|
||||||
|
const url = `${globalUrl}/api/v1/workflows/${workflow_id}/run`
|
||||||
|
fetch(url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
credentials: "include",
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.log("Status not 200 for workflows :O!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
// Timeout after 5 seconds (max load time)
|
||||||
|
if (responseJson.execution_id !== undefined && responseJson.execution_id !== null && responseJson.execution_id.length > 0 && responseJson.authorization !== undefined && responseJson.authorization !== null && responseJson.authorization.length > 0) {
|
||||||
|
|
||||||
|
//for (var key in responseJson.results) {
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
setTimeout(() => {
|
||||||
|
fetchUpdates(responseJson.execution_id, responseJson.authorization, false, true)
|
||||||
|
}, i * 1000)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Replace the markdown with the result
|
||||||
|
if (realtimeMarkdown !== undefined && realtimeMarkdown !== null && realtimeMarkdown.length > 0) {
|
||||||
|
const newmarkdown = realtimeMarkdown.replace(`{{ ${workflow_id} }}`, "", -1)
|
||||||
|
setRealtimeMarkdown(newmarkdown)
|
||||||
|
} else if (inputWorkflow.input_markdown !== undefined && inputWorkflow.input_markdown !== null && inputWorkflow.input_markdown.length > 0) {
|
||||||
|
const newmarkdown = inputWorkflow.input_markdown.replace(`{{ ${workflow_id} }}`, "", -1)
|
||||||
|
setRealtimeMarkdown(newmarkdown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log("Get workflow error: ", error.toString())
|
||||||
|
|
||||||
|
if (realtimeMarkdown !== undefined && realtimeMarkdown !== null && realtimeMarkdown.length > 0) {
|
||||||
|
const newmarkdown = inputWorkflow.input_markdown.replace(`{{ ${workflow_id} }}`, "", -1)
|
||||||
|
setRealtimeMarkdown(newmarkdown)
|
||||||
|
} else if (inputWorkflow.input_markdown !== undefined && inputWorkflow.input_markdown !== null && inputWorkflow.input_markdown.length > 0) {
|
||||||
|
const newmarkdown = inputWorkflow.input_markdown.replace(`{{ ${workflow_id} }}`, "", -1)
|
||||||
|
setRealtimeMarkdown(newmarkdown)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const getWorkflow = (workflow_id, selectedNode) => {
|
const getWorkflow = (workflow_id, selectedNode) => {
|
||||||
const url = `${globalUrl}/api/v1/workflows/${workflow_id}`
|
setRealtimeMarkdown("")
|
||||||
|
|
||||||
|
const url = `${globalUrl}/api/v1/workflows/${workflow_id}`
|
||||||
fetch(url, {
|
fetch(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -404,7 +561,7 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
toast("This Form is not available to you. If you think this is an error, please contact support@shuffler.io with the URL.")
|
toast("This Form is not available to you. If you think this is an error, please contact support@shuffler.io with the URL.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.json();
|
return response.json()
|
||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
// Not sure why this is necessary.
|
// Not sure why this is necessary.
|
||||||
@@ -488,20 +645,57 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
if (responseJson.input_markdown !== undefined && responseJson.input_markdown !== null && responseJson.input_markdown.length > 0) {
|
if (responseJson.input_markdown !== undefined && responseJson.input_markdown !== null && responseJson.input_markdown.length > 0) {
|
||||||
// Look for {{ uuid }} format, and try to run that workflow with their account
|
// Look for {{ uuid }} format, and try to run that workflow with their account
|
||||||
// This is a hack, but a fun one.
|
// This is a hack, but a fun one.
|
||||||
|
var newmarkdown = responseJson.input_markdown.replace("", "")
|
||||||
|
|
||||||
const uuidRegex = /{{\s*[a-f0-9-]+\s*}}/g
|
const uuidRegex = /{{\s[a-f0-9-]+\s}}/g
|
||||||
const found = responseJson.input_markdown.match(uuidRegex)
|
const found = newmarkdown.match(uuidRegex)
|
||||||
if (found !== undefined && found !== null && found.length > 0) {
|
if (found !== undefined && found !== null && found.length > 0) {
|
||||||
|
var handled = []
|
||||||
for (var foundkey in found) {
|
for (var foundkey in found) {
|
||||||
const uuid = found[foundkey].replace("{{", "").replace("}}", "").trim()
|
const uuid = found[foundkey].replace("{{", "").replace("}}", "").trim()
|
||||||
// Run the workflow, then replace it.
|
|
||||||
// Only run if logged in
|
if (handled.includes(uuid)) {
|
||||||
console.log("Found UUID: " + uuid)
|
continue
|
||||||
responseJson.input_markdown = responseJson.input_markdown.replace(found[foundkey], "")
|
}
|
||||||
}
|
|
||||||
|
handled.push(uuid)
|
||||||
|
|
||||||
|
const storageKey = `workflowresult_${uuid}`
|
||||||
|
const value = localStorage.getItem(storageKey)
|
||||||
|
|
||||||
|
var runWorkflow = false
|
||||||
|
if (value !== undefined && value !== null && value.length > 0) {
|
||||||
|
// Check if timestamp with new Date().getTime() is more than 10 minutes ago
|
||||||
|
const parsedValue = JSON.parse(value)
|
||||||
|
if (parsedValue.timestamp !== undefined && parsedValue.timestamp !== null) {
|
||||||
|
// 1 min = 60000ms -> 5 min = 300000ms
|
||||||
|
const now = new Date().getTime()
|
||||||
|
if (now - parsedValue.timestamp > 300000) {
|
||||||
|
localStorage.removeItem(storageKey)
|
||||||
|
runWorkflow = true
|
||||||
|
} else {
|
||||||
|
newmarkdown = newmarkdown.replace(`{{ ${uuid} }}`, parsedValue.result, -1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
runWorkflow = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
runWorkflow = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runWorkflow) {
|
||||||
|
loadInputWorkflowData(uuid, responseJson)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setRealtimeMarkdown(newmarkdown)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
handleExecutionLoader()
|
||||||
|
|
||||||
handleGetOrg(responseJson.org_id)
|
handleGetOrg(responseJson.org_id)
|
||||||
setWorkflow(responseJson);
|
setWorkflow(responseJson);
|
||||||
})
|
})
|
||||||
@@ -510,13 +704,6 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const { start, stop } = useInterval({
|
|
||||||
duration: 1500,
|
|
||||||
startImmediate: true,
|
|
||||||
callback: () => {
|
|
||||||
fetchUpdates(executionRequest.execution_id, executionRequest.authorization)
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleUpdateResults = (responseJson, executionRequest) => {
|
const handleUpdateResults = (responseJson, executionRequest) => {
|
||||||
if (responseJson === undefined || responseJson === null || responseJson.success === false) {
|
if (responseJson === undefined || responseJson === null || responseJson.success === false) {
|
||||||
@@ -583,12 +770,15 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleGetOrg = (orgId, execution_id, authorization) => {
|
const handleGetOrg = (orgId, execution_id, authorization) => {
|
||||||
if (orgId.length === 0) {
|
if (orgId === undefined || orgId === null || orgId.length === 0) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just use this one?
|
// Just use this one?
|
||||||
var url = execution_id !== undefined && authorization !== undefined ? `${globalUrl}/api/v1/orgs/${orgId}?reference_execution=${execution_id}&authorization=${authorization}` : `${globalUrl}/api/v1/orgs/${orgId}`;
|
var url = execution_id !== undefined && authorization !== undefined ? `${globalUrl}/api/v1/orgs/${orgId}?reference_execution=${execution_id}&authorization=${authorization}` : `${globalUrl}/api/v1/orgs/${orgId}`;
|
||||||
|
|
||||||
|
loadForms(orgId)
|
||||||
|
|
||||||
fetch(url, {
|
fetch(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
@@ -611,6 +801,11 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
if (document != undefined && document.title != defaultTitle) {
|
if (document != undefined && document.title != defaultTitle) {
|
||||||
document.title = responseJson.name + " - " + defaultTitle
|
document.title = responseJson.name + " - " + defaultTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (responseJson.image !== undefined && responseJson.image !== null && responseJson.image.length > 0) {
|
||||||
|
} else {
|
||||||
|
responseJson.image = theme.palette.defaultImage
|
||||||
|
}
|
||||||
setSelectedOrganization(responseJson)
|
setSelectedOrganization(responseJson)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -619,22 +814,24 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchUpdates = (execution_id, authorization, getorg) => {
|
const fetchUpdates = (execution_id, authorization, getorg, replaceMarkdown) => {
|
||||||
if (execution_id === undefined || execution_id === null || execution_id === "") {
|
if (execution_id === undefined || execution_id === null || execution_id === "") {
|
||||||
|
console.log("No execution id: ", execution_id)
|
||||||
stop()
|
stop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const innerRequest = {
|
const innerRequest = {
|
||||||
"execution_id": execution_id,
|
"execution_id": execution_id,
|
||||||
"authorization": authorization
|
"authorization": authorization === undefined || authorization === null ? "" : authorization,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (executionRequest.execution_id !== innerRequest.execution_id) {
|
if (executionRequest.execution_id !== innerRequest.execution_id && replaceMarkdown !== true) {
|
||||||
setExecutionRequest(innerRequest)
|
setExecutionRequest(innerRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (execution_id === "" || authorization === "") {
|
if (execution_id === "") {
|
||||||
|
console.log("No execution id or authorization")
|
||||||
setExecutionLoading(false)
|
setExecutionLoading(false)
|
||||||
setExecutionRunning(false)
|
setExecutionRunning(false)
|
||||||
stop()
|
stop()
|
||||||
@@ -658,11 +855,38 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
return response.json();
|
return response.json();
|
||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
|
if (responseJson.success == false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replaceMarkdown === true) {
|
||||||
|
if (responseJson.result.length > 0) {
|
||||||
|
// Set local storage for the workflow id
|
||||||
|
const storageKey = `workflowresult_${responseJson.workflow.id}`
|
||||||
|
const value = {
|
||||||
|
"timestamp": new Date().getTime(),
|
||||||
|
"result": responseJson.result,
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem(storageKey, JSON.stringify(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (realtimeMarkdown !== undefined && realtimeMarkdown !== null && realtimeMarkdown.length > 0) {
|
||||||
|
const newmarkdown = realtimeMarkdown.replace(`{{ ${responseJson.workflow.id} }}`, responseJson.result, -1)
|
||||||
|
setRealtimeMarkdown(newmarkdown)
|
||||||
|
|
||||||
|
} else if (workflow.input_markdown !== undefined && workflow.input_markdown !== null && workflow.input_markdown.length > 0) {
|
||||||
|
const newmarkdown = workflow.input_markdown.replace(`{{ ${responseJson.workflow.id} }}`, responseJson.result, -1)
|
||||||
|
setRealtimeMarkdown(newmarkdown)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
if (getorg === true) {
|
if (getorg === true) {
|
||||||
handleGetOrg(responseJson.org_id, execution_id, authorization)
|
handleGetOrg(responseJson.org_id, execution_id, authorization)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUpdateResults(responseJson, executionRequest);
|
handleUpdateResults(responseJson, executionRequest);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log("Execution result Error: ", error);
|
console.log("Execution result Error: ", error);
|
||||||
@@ -741,10 +965,8 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)"
|
const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)"
|
||||||
const buttonStyle = {borderRadius: 25, height: 50, fontSize: 18, backgroundImage: handleValidateForm(executionArgument) || executionLoading ? buttonBackground : "grey", color: "white"}
|
const buttonStyle = {borderRadius: 25, height: 50, fontSize: 18, backgroundImage: handleValidateForm(executionArgument) || executionLoading ? buttonBackground : "grey", color: "white"}
|
||||||
|
|
||||||
const disabledButtons = message.length > 0 || executionData.status === "FINISHED" || executionData.status === "ABORTED"
|
//const disabledButtons = message.length > 0 || executionData.status === "FINISHED" || executionData.status === "ABORTED"
|
||||||
|
const disabledButtons = executionLoading || executionRunning
|
||||||
//{disabledButtons ? null :
|
|
||||||
|
|
||||||
|
|
||||||
const organization = selectedOrganization !== undefined && selectedOrganization !== null ? selectedOrganization.name : "Unknown"
|
const organization = selectedOrganization !== undefined && selectedOrganization !== null ? selectedOrganization.name : "Unknown"
|
||||||
const contact = selectedOrganization !== undefined && selectedOrganization !== null && selectedOrganization.org !== undefined && selectedOrganization.org !== null? selectedOrganization.org : "support@shuffler.io"
|
const contact = selectedOrganization !== undefined && selectedOrganization !== null && selectedOrganization.org !== undefined && selectedOrganization.org !== null? selectedOrganization.org : "support@shuffler.io"
|
||||||
@@ -786,12 +1008,12 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
{workflow.input_markdown !== undefined && workflow.input_markdown !== null && workflow.input_markdown.length > 0 ?
|
{workflow.input_markdown !== undefined && workflow.input_markdown !== null && workflow.input_markdown.length > 0 ?
|
||||||
<div style={{marginBottom: 20, }}>
|
<div style={{marginBottom: 20, }}>
|
||||||
<Markdown
|
<Markdown
|
||||||
components={{
|
components={{
|
||||||
img: Img,
|
iframe: IframeWrapper,
|
||||||
|
img: ImgWrapper,
|
||||||
code: CodeHandler,
|
code: CodeHandler,
|
||||||
a: OuterLink,
|
a: OuterLink,
|
||||||
}}
|
}}
|
||||||
@@ -872,10 +1094,12 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{marginBottom: 10}} key={index}>
|
<div style={{marginBottom: 10}} key={index}>
|
||||||
{question.name}
|
|
||||||
|
|
||||||
{multiChoiceOptions.length > 1 ?
|
{multiChoiceOptions.length > 1 ?
|
||||||
|
<div>
|
||||||
|
{question.name}
|
||||||
<Select
|
<Select
|
||||||
|
disabled={disabledButtons}
|
||||||
fullWidth
|
fullWidth
|
||||||
required
|
required
|
||||||
label={multiChoiceOptions[0]}
|
label={multiChoiceOptions[0]}
|
||||||
@@ -901,14 +1125,16 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|
||||||
|
|
||||||
</Select>
|
</Select>
|
||||||
|
</div>
|
||||||
:
|
:
|
||||||
<TextField
|
<TextField
|
||||||
color="primary"
|
color="primary"
|
||||||
style={{backgroundColor: theme.palette.inputColor, marginTop: 5, }}
|
style={{
|
||||||
label={question.value}
|
backgroundColor: theme.palette.inputColor,
|
||||||
|
marginTop: 5,
|
||||||
|
}}
|
||||||
|
label={question.value.charAt(0).toUpperCase() + question.value.slice(1)}
|
||||||
required
|
required
|
||||||
|
|
||||||
disabled={disabledButtons}
|
disabled={disabledButtons}
|
||||||
@@ -1021,7 +1247,12 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
disabled={!handleValidateForm(executionArgument) || executionLoading}
|
disabled={!handleValidateForm(executionArgument) || executionLoading}
|
||||||
>
|
>
|
||||||
{executionLoading ?
|
{executionLoading ?
|
||||||
<CircularProgress color="secondary" style={{color: "white",}} /> : "Submit"}
|
<CircularProgress color="secondary" style={{color: "white",}} />
|
||||||
|
:
|
||||||
|
executionData.result !== undefined && executionData.result !== null && executionData.result.length > 0 ? "Run Again"
|
||||||
|
:
|
||||||
|
"Submit"
|
||||||
|
}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -1048,15 +1279,16 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
|
|
||||||
const validate = validateJson(foundresult.result)
|
const validate = validateJson(foundresult.result)
|
||||||
validResults += 1
|
validResults += 1
|
||||||
console.log("VAlid: ", validate)
|
|
||||||
|
|
||||||
var appendedDetails = foundresult.result
|
var appendedDetails = foundresult.result
|
||||||
if (validate.valid) {
|
if (validate.valid) {
|
||||||
appendedDetails = <ReactJson
|
appendedDetails = <ReactJson
|
||||||
src={validate.result}
|
src={validate.result}
|
||||||
theme={theme.palette.jsonTheme}
|
theme={theme.palette.jsonTheme}
|
||||||
style={theme.palette.reactJsonStyle}
|
style={theme.palette.reactJsonStyle}
|
||||||
collapsed={true}
|
collapsed={false}
|
||||||
|
shouldCollapse={(jsonField) => {
|
||||||
|
return collapseField(jsonField)
|
||||||
|
}}
|
||||||
iconStyle={theme.palette.jsonIconStyle}
|
iconStyle={theme.palette.jsonIconStyle}
|
||||||
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
collapseStringsAfterLength={theme.palette.jsonCollapseStringsAfterLength}
|
||||||
displayArrayKey={false}
|
displayArrayKey={false}
|
||||||
@@ -1096,6 +1328,9 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Typography variant="body2" color="textSecondary" align="center" style={{marginTop: 10, }} >
|
||||||
|
Forms are in Beta. Form submissions data includes your Organization's unique ID while logged in, or a unique identifier for your browser otherwise. Your input will be automatically sanitized.
|
||||||
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@@ -1185,39 +1420,38 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
|
|
||||||
{isLoggedIn && userdata?.active_org?.id === workflow?.org_id ?
|
{isLoggedIn && userdata?.active_org?.id === workflow?.org_id ?
|
||||||
<div style={{position: "fixed", top: 10, right: 20, }}>
|
<div style={{position: "fixed", top: 10, right: 20, }}>
|
||||||
<Button
|
|
||||||
variant={"outlined"}
|
|
||||||
color={"secondary"}
|
|
||||||
style={{marginRight: 10, }}
|
|
||||||
onClick={() => {
|
|
||||||
navigate(`/workflows`)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ArrowBackIcon style={{marginRight: 5, }} />
|
|
||||||
Workflows
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant={"outlined"}
|
variant={"outlined"}
|
||||||
color={"secondary"}
|
color={"secondary"}
|
||||||
style={{marginRight: 10, }}
|
style={{marginRight: 10, }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
window.open(`/workflow/${workflow.id}`, "_blank")
|
window.open(`/workflows/${workflow.id}`, "_blank")
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ArrowForwardIcon style={{marginRight: 5, }} />
|
<OpenInNewIcon style={{marginRight: 5, }}/>
|
||||||
Workflow
|
Workflow
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant={"outlined"}
|
variant={workflow.sharing === "form" ? "outlined" : "contained"}
|
||||||
color={"secondary"}
|
color={"secondary"}
|
||||||
style={{marginRight: 10, }}
|
style={{marginRight: 10, }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSharingOpen(true)
|
setSharingOpen(true)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Share Form
|
{workflow.sharing === "form" ?
|
||||||
|
<LockOpenIcon style={{marginRight: 5, }} />
|
||||||
|
:
|
||||||
|
<LockIcon style={{marginRight: 5, }} />
|
||||||
|
}
|
||||||
|
|
||||||
|
{workflow.sharing === "form" ?
|
||||||
|
"Unshare"
|
||||||
|
:
|
||||||
|
"Share"
|
||||||
|
}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
@@ -1240,9 +1474,85 @@ const RunWorkflow = (defaultprops) => {
|
|||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
return (
|
// Check width
|
||||||
|
const overlap = window !== undefined && window.innerWidth !== undefined && window.innerWidth < 1300
|
||||||
|
const formSidebar = !isLoaded || overlap || !(forms !== undefined && forms !== null && forms.length > 1) ? null :
|
||||||
|
<div style={{
|
||||||
|
minWidth: 215,
|
||||||
|
maxWidth: 215,
|
||||||
|
overflowX: "hidden",
|
||||||
|
overflowY: "auto",
|
||||||
|
minHeight: 500,
|
||||||
|
maxHeight: 500,
|
||||||
|
position: "absolute",
|
||||||
|
left: 100,
|
||||||
|
top: 0,
|
||||||
|
border: "1px solid rgba(255,255,255,0.3)",
|
||||||
|
borderRadius: theme.palette.borderRadius,
|
||||||
|
|
||||||
|
padding: 25,
|
||||||
|
|
||||||
|
backgroundColor: theme.palette.inputColor,
|
||||||
|
zIndex: 1000,
|
||||||
|
}}>
|
||||||
|
{selectedOrganization !== undefined && selectedOrganization !== null ?
|
||||||
|
<div style={{display: "flex", marginBottom: 20, }}>
|
||||||
|
<img src={selectedOrganization.image} style={{width: 40, height: 40, borderRadius: theme.palette.borderRadius, }} />
|
||||||
|
<Typography variant="body1" style={{marginTop: 7, marginLeft: 10, }}>
|
||||||
|
{selectedOrganization.name}
|
||||||
|
</Typography>
|
||||||
|
<Divider style={{marginTop: 10, marginBottom: 10, }}/>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{forms !== undefined && forms !== null && forms.length > 0 ?
|
||||||
<div>
|
<div>
|
||||||
|
{forms.map((form, formIndex) => {
|
||||||
|
if (form.id === undefined || form.id === null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={formIndex} style={{marginBottom: 10, }}>
|
||||||
|
<RecentWorkflow
|
||||||
|
workflow={form}
|
||||||
|
onclickHandler={() => {
|
||||||
|
navigate(`/forms/${form.id}`)
|
||||||
|
getWorkflow(form.id, sourceNode)
|
||||||
|
}}
|
||||||
|
currentWorkflowId={workflow.id}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/*
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
fullWidth
|
||||||
|
style={{textTransform: "none", }}
|
||||||
|
onClick={() => {
|
||||||
|
navigate(`/forms/${form.id}`)
|
||||||
|
getWorkflow(form.id, sourceNode)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{form.name}
|
||||||
|
</Button>
|
||||||
|
*/}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div>
|
||||||
|
No forms loaded
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{position: "relative", }}>
|
||||||
{loadedCheck}
|
{loadedCheck}
|
||||||
|
{formSidebar}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import React, { useState } from "react";
|
|||||||
import { Typography, CircularProgress } from "@mui/material";
|
import { Typography, CircularProgress } from "@mui/material";
|
||||||
import theme from '../theme.jsx';
|
import theme from '../theme.jsx';
|
||||||
|
|
||||||
|
import { red, } from "../views/AngularWorkflow.jsx"
|
||||||
|
|
||||||
const SetAuthentication = (props) => {
|
const SetAuthentication = (props) => {
|
||||||
const { globalUrl } = props;
|
const { globalUrl } = props;
|
||||||
|
|
||||||
@@ -300,7 +302,7 @@ const SetAuthentication = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ maringTop: 50, padding: 50, border: "1px solid rgba(255,255,255,0.6)", borderRadius: theme.palette.borderRadius, width: 500, margin: "auto", itemAlign: "center", textAlign: "center",}}>
|
<div style={{ padding: 50, border: failed === true ? `1px solid ${red}` : "1px solid rgba(255,255,255,0.6)", borderRadius: theme.palette.borderRadius, width: 500, margin: "auto", marginTop: 50, itemAlign: "center", textAlign: "center",}}>
|
||||||
<Typography
|
<Typography
|
||||||
variant="h4"
|
variant="h4"
|
||||||
style={{ marginLeft: "auto", marginRight: "auto", marginTop: 50}}
|
style={{ marginLeft: "auto", marginRight: "auto", marginTop: 50}}
|
||||||
@@ -311,18 +313,22 @@ const SetAuthentication = (props) => {
|
|||||||
variant="h6"
|
variant="h6"
|
||||||
style={{ marginLeft: "auto", marginRight: "auto", marginTop: 50}}
|
style={{ marginLeft: "auto", marginRight: "auto", marginTop: 50}}
|
||||||
>
|
>
|
||||||
{!finished ? (
|
{!finished ?
|
||||||
failed ?
|
failed ?
|
||||||
null :
|
null :
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
) : (
|
:
|
||||||
|
failed ?
|
||||||
|
null
|
||||||
|
:
|
||||||
"Done - this window should close within 3 seconds."
|
"Done - this window should close within 3 seconds."
|
||||||
)}
|
}
|
||||||
<div />
|
|
||||||
{failed ? "Failed setup. Error: " : ""} {response}
|
<div style={{marginTop: 10, }} />
|
||||||
|
<b>{failed ? "Failed auth. Error: " : ""}</b> {response}
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
{failed ? "If the error persists, try to use fewer scopes. Contact our support at support@shuffler.io if you need further assistance. You may close this window." : ""}
|
{failed ? "If the error persists, try to use fewer scopes. Contact support@shuffler.io if you need further assistance, and include the current URL and a screenshot. You may now close this window." : ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -417,7 +417,37 @@ const chipStyle = {
|
|||||||
color: "white",
|
color: "white",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const collapseField = (field) => {
|
||||||
|
if (field === undefined || field === null) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field.name === "headers" || field.name === "cookies") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field.type === "array") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If more than 10 keys in object, collapse
|
||||||
|
if (field.type === "object") {
|
||||||
|
if (Object.keys(field.src).length > 7) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
export const validateJson = (showResult) => {
|
export const validateJson = (showResult) => {
|
||||||
|
if (showResult === undefined || showResult === null) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
result: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof showResult === 'string') {
|
if (typeof showResult === 'string') {
|
||||||
showResult = showResult.split(" False").join(" false")
|
showResult = showResult.split(" False").join(" false")
|
||||||
showResult = showResult.split(" True").join(" true")
|
showResult = showResult.split(" True").join(" true")
|
||||||
@@ -645,12 +675,8 @@ const Workflows = (props) => {
|
|||||||
}
|
}
|
||||||
setGettingStartedItems(activeFiltered)
|
setGettingStartedItems(activeFiltered)
|
||||||
|
|
||||||
//const doneFiltered = activeFiltered.filter((item) => item.done === true)
|
/*
|
||||||
//if (doneFiltered.length > 0) {
|
const sidebar = localStorage.getItem(sidebarKey)
|
||||||
// console.log("DONE: ", doneFiltered)
|
|
||||||
//}
|
|
||||||
|
|
||||||
const sidebar = localStorage.getItem(sidebarKey);
|
|
||||||
if (sidebar === null || sidebar === undefined) {
|
if (sidebar === null || sidebar === undefined) {
|
||||||
console.log("No sidebar defined")
|
console.log("No sidebar defined")
|
||||||
|
|
||||||
@@ -663,6 +689,7 @@ const Workflows = (props) => {
|
|||||||
setDrawerOpen(false)
|
setDrawerOpen(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -976,7 +1003,7 @@ const Workflows = (props) => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
console.log("Editing: ", editingWorkflow);
|
console.log("Editing: ", editingWorkflow);
|
||||||
if (selectedWorkflowId) {
|
if (selectedWorkflowId) {
|
||||||
deleteWorkflow(selectedWorkflowId);
|
deleteWorkflow(selectedWorkflowId)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
getAvailableWorkflows();
|
getAvailableWorkflows();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
@@ -1877,7 +1904,7 @@ const Workflows = (props) => {
|
|||||||
toast("Failed deleting workflow. Do you have access?");
|
toast("Failed deleting workflow. Do you have access?");
|
||||||
} else {
|
} else {
|
||||||
if (bulk !== true) {
|
if (bulk !== true) {
|
||||||
toast("Deleted workflow " + id);
|
toast(`Deleted workflow ${id}. Child Workflows in Suborgs were also removed.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2063,6 +2090,8 @@ const Workflows = (props) => {
|
|||||||
{"Create Form"}
|
{"Create Form"}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
|
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
|
||||||
disabled={isDistributed}
|
disabled={isDistributed}
|
||||||
@@ -2076,18 +2105,7 @@ const Workflows = (props) => {
|
|||||||
<CloudUploadIcon style={{ marginLeft: 0, marginRight: 8 }} />
|
<CloudUploadIcon style={{ marginLeft: 0, marginRight: 8 }} />
|
||||||
{"Publish Workflow"}
|
{"Publish Workflow"}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
|
||||||
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
|
|
||||||
disabled={isDistributed}
|
|
||||||
onClick={() => {
|
|
||||||
duplicateWorkflow(data)
|
|
||||||
setOpen(false)
|
|
||||||
}}
|
|
||||||
key={"duplicate"}
|
|
||||||
>
|
|
||||||
<FileCopyIcon style={{ marginLeft: 0, marginRight: 8 }} />
|
|
||||||
{"Duplicate Workflow"}
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
|
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
|
||||||
disabled={isDistributed}
|
disabled={isDistributed}
|
||||||
@@ -2101,6 +2119,22 @@ const Workflows = (props) => {
|
|||||||
<GetAppIcon style={{ marginLeft: 0, marginRight: 8 }} />
|
<GetAppIcon style={{ marginLeft: 0, marginRight: 8 }} />
|
||||||
{"Export Workflow"}
|
{"Export Workflow"}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<MenuItem
|
||||||
|
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
|
||||||
|
disabled={isDistributed}
|
||||||
|
onClick={() => {
|
||||||
|
duplicateWorkflow(data)
|
||||||
|
setOpen(false)
|
||||||
|
}}
|
||||||
|
key={"duplicate"}
|
||||||
|
>
|
||||||
|
<FileCopyIcon style={{ marginLeft: 0, marginRight: 8 }} />
|
||||||
|
{"Duplicate Workflow"}
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
|
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
|
||||||
disabled={isDistributed}
|
disabled={isDistributed}
|
||||||
@@ -4092,7 +4126,7 @@ const Workflows = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const gettingStartedDrawer =
|
const gettingStartedDrawer = true == true ? null :
|
||||||
<Drawer
|
<Drawer
|
||||||
anchor={"right"}
|
anchor={"right"}
|
||||||
open={drawerOpen}
|
open={drawerOpen}
|
||||||
@@ -4222,6 +4256,7 @@ const Workflows = (props) => {
|
|||||||
maxWidth: window.innerWidth > 1366 ? 1366 : isMobile ? "100%" : 1200,
|
maxWidth: window.innerWidth > 1366 ? 1366 : isMobile ? "100%" : 1200,
|
||||||
margin: "auto",
|
margin: "auto",
|
||||||
padding: 20,
|
padding: 20,
|
||||||
|
paddingLeft: userdata?.support ? 80 : 0
|
||||||
}}
|
}}
|
||||||
onDrop={uploadFile}
|
onDrop={uploadFile}
|
||||||
>
|
>
|
||||||
@@ -4233,8 +4268,9 @@ const Workflows = (props) => {
|
|||||||
{publishModal}
|
{publishModal}
|
||||||
{workflowDownloadModalOpen}
|
{workflowDownloadModalOpen}
|
||||||
|
|
||||||
{!drawerOpen ? <div style={{ position: "fixed", top: 64, right: -5, backgroundColor: theme.palette.inputColor, borderRadius: theme.palette.borderRadius, }}>
|
{/*!drawerOpen ?
|
||||||
<Tooltip title={`Getting started`} placement="bottom">
|
<div style={{ position: "fixed", top: 64, right: -5, backgroundColor: theme.palette.inputColor, borderRadius: theme.palette.borderRadius, }}>
|
||||||
|
<Tooltip title={`Getting Started`} placement="bottom">
|
||||||
<IconButton onClick={() => {
|
<IconButton onClick={() => {
|
||||||
setDrawerOpen(true)
|
setDrawerOpen(true)
|
||||||
localStorage.setItem(sidebarKey, "open");
|
localStorage.setItem(sidebarKey, "open");
|
||||||
@@ -4242,7 +4278,7 @@ const Workflows = (props) => {
|
|||||||
<ArrowLeftIcon />
|
<ArrowLeftIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div> : null}
|
</div> : null*/}
|
||||||
{isMobile ? null : gettingStartedDrawer}
|
{isMobile ? null : gettingStartedDrawer}
|
||||||
{videoView}
|
{videoView}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user