Onprem X Cloud sync commit. Large changes to the navbar mechanisms
This commit is contained in:
@@ -88,6 +88,8 @@ const EditWorkflow = (props) => {
|
||||
const [inputMarkdown, setInputMarkdown] = React.useState(workflow?.form_control?.input_markdown !== undefined && workflow?.form_control?.input_markdown !== null ? workflow?.form_control?.input_markdown : "")
|
||||
const [scrollDone, setScrollDone] = React.useState(false)
|
||||
const [selectedYieldActions, setSelectedYieldActions] = React.useState(workflow?.form_control?.output_yields !== undefined && workflow?.form_control?.output_yields !== null ? JSON.parse(JSON.stringify(workflow?.form_control?.output_yields)) : [])
|
||||
const [selectedCleanupActions, setSelectedCleanupActions] = React.useState(workflow?.form_control?.cleanup_actions !== undefined && workflow?.form_control?.cleanup_actions !== null ? JSON.parse(JSON.stringify(workflow?.form_control?.cleanup_actions)) : [])
|
||||
|
||||
const [formWidth, setFormWidth] = React.useState(boxWidth === undefined || boxWidth === null ? 500 : boxWidth)
|
||||
|
||||
const classes = useStyles();
|
||||
@@ -323,6 +325,7 @@ const EditWorkflow = (props) => {
|
||||
innerWorkflow.form_control.input_markdown = inputMarkdown
|
||||
innerWorkflow.form_control.output_yields = selectedYieldActions
|
||||
innerWorkflow.form_control.form_width = formWidth
|
||||
innerWorkflow.form_control.cleanup_actions = selectedCleanupActions
|
||||
|
||||
innerWorkflow.name = name
|
||||
innerWorkflow.description = description
|
||||
@@ -568,7 +571,7 @@ const EditWorkflow = (props) => {
|
||||
<Divider id="mssp_control" style={{ marginTop: 20, marginBottom: 20, }} />
|
||||
|
||||
<Typography variant="h4" style={{ marginTop: 50, }}>
|
||||
MSSP & Distribution controls
|
||||
Multi-Tenancy, Backups & Security
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginTop: 30, marginBottom: 10, }}>
|
||||
@@ -678,7 +681,7 @@ const EditWorkflow = (props) => {
|
||||
}
|
||||
|
||||
|
||||
<Typography variant="body1" style={{ marginTop: 75, }}>
|
||||
<Typography variant="h6" style={{ marginTop: 75, }}>
|
||||
Git Backup Repository
|
||||
</Typography>
|
||||
<Typography variant="body2" style={{ textAlign: "left", marginTop: 5, }} color="textSecondary">
|
||||
@@ -824,6 +827,60 @@ const EditWorkflow = (props) => {
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<div id="cleanup">
|
||||
<Typography variant="h6" style={{ marginTop: 50, }}>
|
||||
Result cleanup ({selectedCleanupActions.length === 0 ? "No cleanup yet" : selectedCleanupActions.length === 1 ? "Cleaning up 1 node" : `Cleaning up ${selectedCleanupActions.length} nodes`})
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginBottom: 20, }}>
|
||||
<b>Beta Feature</b>: When a workflow run is done, the data from the selected actions will be removed by replacing it with a default value. This is useful for cleaning up sensitive data, or data that is no longer needed. This is done after a workflow run is finished or aborted, and is not reversible. Data will remain in the workflow run result (last node value) even if the action result itself is cleaned up.
|
||||
</Typography>
|
||||
|
||||
<FormControl style={{ marginTop: 15, }}>
|
||||
<Select
|
||||
defaultValue=""
|
||||
id="result-cleanup-control"
|
||||
label="Cleaned Up nodes"
|
||||
multiple
|
||||
fullWidth
|
||||
style={{ width: 500, }}
|
||||
value={selectedCleanupActions === [] ? ["none"] : selectedCleanupActions}
|
||||
renderValue={(selected) => selected.join(', ')}
|
||||
onChange={(event) => {
|
||||
if (event.target.value.length > 0) {
|
||||
if (event.target.value.includes("none")) {
|
||||
setSelectedCleanupActions([])
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const newvalue = event?.target?.value
|
||||
if (newvalue === undefined || newvalue === null) {
|
||||
} else {
|
||||
setSelectedCleanupActions(newvalue)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<MenuItem value="none">
|
||||
<em>None</em>
|
||||
</MenuItem>
|
||||
{workflow?.actions?.map((action, actionIndex) => {
|
||||
return (
|
||||
<MenuItem
|
||||
key={actionIndex}
|
||||
value={action.id}
|
||||
>
|
||||
<Tooltip title={action.app_name} key={actionIndex}>
|
||||
<img src={action.large_image !== undefined && action.large_image !== null && action.large_image.length > 0 ? action.large_image : theme.palette.defaultImage} style={{ width: 20, height: 20, marginRight: 10, }} />
|
||||
</Tooltip>
|
||||
{action.label}
|
||||
</MenuItem>
|
||||
)
|
||||
})}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<Divider style={{ marginTop: 20, marginBottom: 20, }} />
|
||||
|
||||
|
||||
@@ -1023,11 +1080,11 @@ const EditWorkflow = (props) => {
|
||||
|
||||
<div id="output_control">
|
||||
<Typography variant="h6" style={{ marginTop: 50, }}>
|
||||
Output Control ({selectedYieldActions.length === 0 ? "No Returns" : selectedYieldActions.length === 1 ? "Returning 1 node" : `Returning ${selectedYieldActions.length} nodes`})
|
||||
Form Output Control ({selectedYieldActions.length === 0 ? "No Returns" : selectedYieldActions.length === 1 ? "Returning 1 node" : `Returning ${selectedYieldActions.length} nodes`})
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body2" color="textSecondary" style={{ marginBottom: 20, }}>
|
||||
When running this workflow, the output will be shown as a Markdown object by default, with JSON objects being rendered. By adding nodes below, they will be shown while the workflow is running as soon as they get a result. Failing/Skipped nodes are not shown. This makes it possible to track progress for more complex usecases.
|
||||
When running this workflow as a form, the output will be shown as a Markdown object by default, with JSON objects being rendered. By adding nodes below, they will be shown while the workflow is running as soon as they get a result. Failing/Skipped nodes are not shown. This makes it possible to track progress for more complex usecases.
|
||||
</Typography>
|
||||
|
||||
<FormControl style={{ marginTop: 15, }}>
|
||||
|
||||
@@ -1064,17 +1064,26 @@ const EnvironmentTab = memo((props) => {
|
||||
}}
|
||||
style={{minWidth:120, display: "table-cell",}}
|
||||
primary={
|
||||
<Tooltip title={environment.Type !== "cloud"
|
||||
? environment.running_ip === undefined ||
|
||||
environment.running_ip === null ||
|
||||
environment.running_ip.length === 0
|
||||
?
|
||||
"Not running. Click to get the start command that can be ran on your server."
|
||||
:
|
||||
<span>IP / label: {environment?.running_ip?.split(":")[0]}. May stay running up to a minute after stopping Orborus.</span>
|
||||
:
|
||||
"Cloud is automatically configured. Reachout to support@shuffler.io if you have any questions."
|
||||
} placement="top">
|
||||
<Tooltip title={
|
||||
<Typography variant="body1" style={{margin: 10, }}>
|
||||
{environment.Type !== "cloud"
|
||||
? environment.running_ip === undefined ||
|
||||
environment.running_ip === null ||
|
||||
environment.running_ip.length === 0
|
||||
?
|
||||
"Not running. Click to get the start command that can be ran on your server."
|
||||
:
|
||||
<span>IP / label: {environment?.running_ip?.split(":")[0]}. May stay running up to a minute after stopping Orborus.</span>
|
||||
:
|
||||
"Cloud is automatically configured. Reachout to support@shuffler.io if you have any questions."
|
||||
}
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
Last checkin: {environment?.checkin !== undefined && environment.checkin !== null && environment?.checkin > 0 ? new Date(environment?.checkin * 1000).toLocaleString() : "Never"}
|
||||
</Typography>
|
||||
} placement="top">
|
||||
<Typography
|
||||
style={{
|
||||
minWidth: 100,
|
||||
|
||||
@@ -1263,7 +1263,7 @@ const Files = memo((props) => {
|
||||
}
|
||||
const isDistributed = file?.suborg_distribution?.length > 0 ? true : false;
|
||||
const filenamesplit = file.filename.split(".")
|
||||
const iseditable = file.filesize < 2000000 && file.status === "active" && allowedFileTypes.includes(filenamesplit[filenamesplit.length-1])
|
||||
const iseditable = file.filesize < 2000000 && file.status === "active" && (allowedFileTypes.includes(filenamesplit[filenamesplit.length-1]) || !file?.filename.includes("."))
|
||||
return (
|
||||
<ListItem
|
||||
key={index}
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
Fade,
|
||||
Portal,
|
||||
Collapse,
|
||||
Tooltip,
|
||||
} from "@mui/material";
|
||||
import theme from "../theme.jsx";
|
||||
import RecentWorkflow from "../components/RecentWorkflow.jsx";
|
||||
@@ -524,7 +525,7 @@ useEffect(() => {
|
||||
<Divider style={{ marginBottom: 10, }} />
|
||||
|
||||
<Typography color="textSecondary" align="center" style={{ marginTop: 5, marginBottom: 5, fontSize: 18 }}>
|
||||
Version: 2.0.0-rc6
|
||||
Version: 2.0.0-rc7
|
||||
</Typography>
|
||||
</Menu>
|
||||
</span>
|
||||
@@ -812,14 +813,36 @@ useEffect(() => {
|
||||
setExpandLeftNav(false)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<a href="/" style={{ textDecoration: "none" }}>
|
||||
<img
|
||||
src={ShuffleLogo}
|
||||
alt="Shuffle Logo"
|
||||
style={{ width: 24, height: 24 }}
|
||||
/>
|
||||
</a>
|
||||
>
|
||||
<Tooltip
|
||||
title="Go to Home"
|
||||
placement="top"
|
||||
arrow
|
||||
componentsProps={{
|
||||
tooltip: {
|
||||
sx: {
|
||||
backgroundColor: "rgba(33, 33, 33, 1)",
|
||||
color: "rgba(241, 241, 241, 1)",
|
||||
fontSize: 12,
|
||||
border: "1px solid rgba(73, 73, 73, 1)",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
}
|
||||
},
|
||||
popper: {
|
||||
sx: {
|
||||
zIndex: 1000019,
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Link to="/">
|
||||
<img
|
||||
src={ShuffleLogo}
|
||||
alt="Shuffle Logo"
|
||||
style={{ width: 24, height: 24 }}
|
||||
/>
|
||||
</Link>
|
||||
</Tooltip>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
@@ -1454,7 +1477,7 @@ useEffect(() => {
|
||||
: "#C8C8C8"
|
||||
}}
|
||||
>
|
||||
Shuffle Agent
|
||||
Hybrid Locations
|
||||
</span>
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
@@ -688,7 +688,7 @@ const ParsedAction = (props) => {
|
||||
if (newActionList.find((item) => item.type === "Shuffle DB") === undefined) {
|
||||
let cacheKey = {
|
||||
type: "Shuffle DB",
|
||||
name: "Shuffle DB",
|
||||
name: "Shuffle Datastore",
|
||||
value: "$shuffle_cache",
|
||||
highlight: "shuffle_cache",
|
||||
autocomplete: "shuffle_cache",
|
||||
@@ -753,44 +753,78 @@ const ParsedAction = (props) => {
|
||||
if (parents.length > 1) {
|
||||
const labels = [];
|
||||
for (let parentNode of parents) {
|
||||
if (parentNode.label !== "Runtime Argument" && !labels.includes(parentNode.label)) {
|
||||
labels.push(parentNode.label);
|
||||
let exampleData = parentNode.example ?? "";
|
||||
if (!exampleData && workflowExecutions.length > 0) {
|
||||
for (let exec of workflowExecutions) {
|
||||
const foundResult = exec.results?.find(result => result.action.id === parentNode.id);
|
||||
if (foundResult) {
|
||||
const valid = validateJson(foundResult.result);
|
||||
if (valid.valid && valid.result.success !== false) {
|
||||
exampleData = valid.result;
|
||||
break;
|
||||
}
|
||||
if (parentNode.label === "Runtime Argument" || labels.includes(parentNode.label)) {
|
||||
continue
|
||||
}
|
||||
|
||||
labels.push(parentNode.label);
|
||||
let exampleData = parentNode.example ?? "";
|
||||
if (parentNode?.app_name === "http") {
|
||||
exampleData = ""
|
||||
}
|
||||
|
||||
if (workflowExecutions.length > 0) {
|
||||
for (let exec of workflowExecutions) {
|
||||
const foundResult = exec.results?.find(result => result?.action?.id === parentNode?.id);
|
||||
if (foundResult) {
|
||||
const valid = validateJson(foundResult.result);
|
||||
if (valid.valid && valid.result.success !== false) {
|
||||
exampleData = valid.result
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parentNode.label === undefined) {
|
||||
parentNode.label = ""
|
||||
}
|
||||
|
||||
newActionList.push({
|
||||
type: "action",
|
||||
id: parentNode.id,
|
||||
name: parentNode.label,
|
||||
autocomplete: parentNode.label.split(" ").join("_"),
|
||||
example: exampleData,
|
||||
});
|
||||
|
||||
parentActionList.push({
|
||||
type: "action",
|
||||
id: parentNode.id,
|
||||
name: parentNode.label,
|
||||
autocomplete: parentNode.label.split(" ").join("_"),
|
||||
example: exampleData,
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (exampleData === "" && apps !== undefined && apps !== null && apps?.length > 0) {
|
||||
// Check apps if it exists, then if it
|
||||
const foundApp = apps?.find(app => app?.id === parentNode?.app_id)
|
||||
if (foundApp !== undefined && foundApp !== null) {
|
||||
if (foundApp?.generated === true || foundApp?.name === "http") {
|
||||
const validationData = validateJson(`{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"example": "json",
|
||||
"values": "json"
|
||||
},
|
||||
"url": "https://example.com",
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Example-Header": "two"
|
||||
},
|
||||
"cookies": {
|
||||
"example": "session",
|
||||
"__session": "sessionid"
|
||||
},
|
||||
"success": true
|
||||
}`)
|
||||
|
||||
if (validationData.valid) {
|
||||
exampleData = validationData.result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parentNode.label === undefined) {
|
||||
parentNode.label = ""
|
||||
}
|
||||
|
||||
newActionList.push({
|
||||
type: "action",
|
||||
id: parentNode.id,
|
||||
name: parentNode.label,
|
||||
autocomplete: parentNode.label.split(" ").join("_"),
|
||||
example: exampleData,
|
||||
});
|
||||
|
||||
parentActionList.push({
|
||||
type: "action",
|
||||
id: parentNode.id,
|
||||
name: parentNode.label,
|
||||
autocomplete: parentNode.label.split(" ").join("_"),
|
||||
example: exampleData,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -840,8 +874,8 @@ const ParsedAction = (props) => {
|
||||
return { ...param, value: paramvalue, error: message }
|
||||
});
|
||||
|
||||
setSelectedActionParameters(newParameters);
|
||||
setActionlist(newActionList);
|
||||
setSelectedActionParameters(newParameters)
|
||||
setActionlist(newActionList)
|
||||
}, [workflow.execution_variables, paramUpdate, workflow.workflow_variables, workflowExecutions, workflow, selectedAction, listCache, getParents, setNewSelectedAction]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -2575,7 +2609,8 @@ const ParsedAction = (props) => {
|
||||
</div>
|
||||
*/}
|
||||
|
||||
{setNewSelectedAction !== undefined ? (
|
||||
{isAgent ? null :
|
||||
setNewSelectedAction !== undefined ? (
|
||||
<Autocomplete
|
||||
id="action_search"
|
||||
disabled={isAgent || (selectedAction?.parent_controlled === true && workflow?.parentorg_workflow?.length > 0)}
|
||||
|
||||
@@ -276,6 +276,8 @@ const CodeEditor = (props) => {
|
||||
parsedPaths = GetParsedPaths(actionlist[i].value, "");
|
||||
}
|
||||
} else {
|
||||
//console.log("EXAMPLE: ", actionlist[i])
|
||||
|
||||
// Handle regular action results
|
||||
if (typeof actionlist[i].example === "object") {
|
||||
parsedPaths = GetParsedPaths(actionlist[i].example, "");
|
||||
@@ -1228,7 +1230,7 @@ const CodeEditor = (props) => {
|
||||
}
|
||||
|
||||
const editorLoad = (editor) => {
|
||||
console.log("EDITOR: ", editor)
|
||||
//console.log("EDITOR: ", editor)
|
||||
editor.completers = [customCompleter]
|
||||
}
|
||||
|
||||
@@ -1526,7 +1528,7 @@ const CodeEditor = (props) => {
|
||||
Source Data
|
||||
</Typography>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
Drag the data you want into the text editor
|
||||
Drag the data you want into the text editor! <b>PS: Only support users can see this test-section!</b>
|
||||
</Typography>
|
||||
|
||||
{actionlist?.map((innerdata) => {
|
||||
@@ -2246,8 +2248,8 @@ const CodeEditor = (props) => {
|
||||
{selectedAction.name === "execute_python" || selectedAction.name === "execute_bash" ?
|
||||
"Code to run" :
|
||||
triggerId ?
|
||||
`Output : ${triggerName?.replaceAll("_", " ").slice(0, 1).toUpperCase() + triggerName?.replaceAll("_", " ").slice(1)}(${triggerField})` :
|
||||
`Output : ${appName?.replaceAll("_", " ").slice(0, 1).toUpperCase() + appName?.replaceAll("_", " ").slice(1)}(${fieldName})`
|
||||
`Output: ${triggerName?.replaceAll("_", " ").slice(0, 1).toUpperCase() + triggerName?.replaceAll("_", " ").slice(1)} (${triggerField})` :
|
||||
`Output: ${appName?.replaceAll("_", " ").slice(0, 1).toUpperCase() + appName?.replaceAll("_", " ").slice(1)} (${fieldName})`
|
||||
}
|
||||
</span>
|
||||
}
|
||||
@@ -2429,7 +2431,10 @@ const CodeEditor = (props) => {
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
navigate("")
|
||||
if (isFileEditor !== true) {
|
||||
navigate("")
|
||||
}
|
||||
|
||||
setExpansionModalOpen(false);
|
||||
}}
|
||||
>
|
||||
@@ -2453,7 +2458,9 @@ const CodeEditor = (props) => {
|
||||
}
|
||||
*/
|
||||
|
||||
navigate("")
|
||||
if (isFileEditor !== true) {
|
||||
navigate("")
|
||||
}
|
||||
// Take localcodedata through the Shuffle JSON parser just in case
|
||||
// This is to make it so we don't need to handle these fixes on the
|
||||
// backend by itself
|
||||
|
||||
@@ -678,7 +678,7 @@ const WorkflowTemplatePopup = (props) => {
|
||||
}
|
||||
{img2 !== undefined && img2 !== "" && dstapp !== undefined && dstapp !== "" ?
|
||||
<Tooltip title={dstapp.replaceAll(":default", "").replaceAll("_", " ").replaceAll(" API", "")} placement="top">
|
||||
<div style={{display: "flex", }}>
|
||||
<div style={{display : dstapp === "NA" ? "none" : "flex" }}>
|
||||
<TrendingFlatIcon style={{ marginTop: 7, }} />
|
||||
<div style={dstapp !== undefined && dstapp.includes(":default") ? imagestyleWrapperDefault : imagestyleWrapper}>
|
||||
<img src={img2} style={dstapp !== undefined && dstapp.includes(":default") ? imagestyleDefault : imagestyle} />
|
||||
|
||||
@@ -50,12 +50,13 @@ const WorkflowTemplatePopup = (props) => {
|
||||
setIsClicked,
|
||||
inputWorkflowId,
|
||||
inputWorkflow,
|
||||
onClose,
|
||||
} = props;
|
||||
|
||||
const [isActive, setIsActive] = useState(workflowBuilt === true || (workflowBuilt !== undefined && workflowBuilt !== null && workflowBuilt?.length > 0) || (inputWorkflow !== undefined && inputWorkflow !== null && inputWorkflow.id !== undefined && inputWorkflow.id !== null && inputWorkflow.id !== "") ? true : false)
|
||||
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const [modalOpen, setModalOpen] = useState(isModalOpenDefault === true ? true : false)
|
||||
const [modalOpen, setModalOpen] = useState(isModalOpenDefault === true);
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
const [workflowLoading, setWorkflowLoading] = useState(false)
|
||||
const [showLoginButton, setShowLoginButton] = useState(false);
|
||||
@@ -173,6 +174,12 @@ const WorkflowTemplatePopup = (props) => {
|
||||
}
|
||||
}, [configurationFinished, workflow])
|
||||
|
||||
useEffect(() => {
|
||||
if (isModalOpenDefault === true) {
|
||||
setModalOpen(true);
|
||||
}
|
||||
}, [isModalOpenDefault]);
|
||||
|
||||
const imageSize = 32
|
||||
const defaultBorder = "1px solid rgba(255,255,255,0.6)"
|
||||
const imagestyleWrapper = {
|
||||
@@ -516,6 +523,18 @@ const WorkflowTemplatePopup = (props) => {
|
||||
return false
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
setModalOpen(false);
|
||||
|
||||
if (onClose) {
|
||||
onClose();
|
||||
}
|
||||
|
||||
if (setIsClicked !== undefined) {
|
||||
setIsClicked(false);
|
||||
}
|
||||
}
|
||||
|
||||
const ModalView = () => {
|
||||
if (modalOpen === false) {
|
||||
return null
|
||||
@@ -528,13 +547,7 @@ const WorkflowTemplatePopup = (props) => {
|
||||
<Drawer
|
||||
anchor={"right"}
|
||||
open={modalOpen}
|
||||
onClose={() => {
|
||||
setModalOpen(false);
|
||||
|
||||
if (setIsClicked !== undefined) {
|
||||
setIsClicked(false)
|
||||
}
|
||||
}}
|
||||
onClose={handleClose}
|
||||
PaperProps={{
|
||||
style: {
|
||||
backgroundColor: "black",
|
||||
@@ -550,17 +563,15 @@ const WorkflowTemplatePopup = (props) => {
|
||||
style={{
|
||||
zIndex: 5000,
|
||||
position: "absolute",
|
||||
top: 14,
|
||||
right: 14,
|
||||
top: 110,
|
||||
right: 110,
|
||||
color: "white",
|
||||
}}
|
||||
onClick={() => {
|
||||
setModalOpen(false);
|
||||
}}
|
||||
onClick={handleClose}
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
<DialogContent style={{marginTop: 0, marginLeft: isHomePage ? null : isMobile ? null : 75, maxWidth: 470, }}>
|
||||
<DialogContent style={{marginTop: 0, marginLeft: isHomePage ? null : isMobile ? null : 75, maxWidth: 470, marginTop: 20 }}>
|
||||
<Typography variant="h4" style={{ fontSize: isMobile ? 20 : null}}>
|
||||
<b>Configure Workflow</b>
|
||||
</Typography>
|
||||
|
||||
Reference in New Issue
Block a user