Bunch of fixes for MSSP feature buildout

This commit is contained in:
Frikky
2024-06-13 18:49:18 +02:00
parent 0455b59bd8
commit fe43b683b9
13 changed files with 2759 additions and 1372 deletions
+296 -163
View File
@@ -166,7 +166,9 @@ const Admin = (props) => {
//console.log("Selected: ", selectedOrganization)
const [appAuthenticationGroupModalOpen , setAppAuthenticationGroupModalOpen] = React.useState(false);
const [appsForAppAuthGroup, setAppsForAppAuthGroup] = React.useState([]);
const [appAuthenticationGroupId, setAppAuthenticationGroupId] = React.useState("");
const [appAuthenticationGroupName, setAppAuthenticationGroupName] = React.useState("");
const [appAuthenticationGroupEnvironment, setAppAuthenticationGroupEnvironment] = React.useState("");
const [appAuthenticationGroupDescription, setAppAuthenticationGroupDescription] = React.useState("");
const [appAuthenticationGroups, setAppAuthenticationGroups] = React.useState([]);
const [organizationFeatures, setOrganizationFeatures] = React.useState({});
@@ -431,23 +433,62 @@ const Admin = (props) => {
});
};
const createAppAuthenticationGroup = (name, description, appAuthIds) => {
const deleteAppAuthenticationGroup = (appAuthGroupId) => {
const url = `${globalUrl}/api/v1/authentication/group/${appAuthGroupId}`
fetch(url, {
method: "DELETE",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for deleting app auth group");
}
return response.json();
})
.then((responseJson) => {
if (responseJson.success === false) {
toast("Failed to delete app authentication group");
} else {
toast("App authentication group deleted")
getAppAuthenticationGroups()
}
})
.catch((error) => {
toast(error.toString())
})
}
const createAppAuthenticationGroup = (name, environment, description, appAuthIds) => {
// Makes list of ids into a full-on list of auth, but just with the ID
// The backend fills in the rest
console.log("INput auth: ", appAuthIds)
let app_auths = appAuthIds.map((appAuthId) => {
return { id: appAuthId };
})
fetch(globalUrl + "/api/v1/apps/authentication/group", {
var parsedAppGroup = {
label: name,
environment: environment,
description: description,
app_auths: app_auths
}
if (appAuthenticationGroupId !== undefined && appAuthenticationGroupId !== null && appAuthenticationGroupId !== "") {
parsedAppGroup.id = appAuthenticationGroupId
}
fetch(globalUrl + "/api/v1/authentication/group", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
body: JSON.stringify({
label: name,
description: description,
app_auths: app_auths
}),
body: JSON.stringify(parsedAppGroup),
})
.then((response) => {
if (response.status !== 200) {
@@ -457,8 +498,15 @@ const Admin = (props) => {
return response.json();
})
.then((responseJson) => {
// getAppAuthenticationGroups();
toast("App authentication group created");
if (responseJson.success === false) {
toast("Failed to create. Please try again, or contact support@shuffler.io")
} else {
// Close the modal
setAppAuthenticationGroupModalOpen(false)
toast("App authentication group created")
getAppAuthenticationGroups()
}
})
.catch((error) => {
toast(error.toString());
@@ -805,7 +853,7 @@ If you're interested, please let me know a time that works for you, or set up a
.then((responseJson) => {
setWebHooks(responseJson.webhooks || []); // Handling the case where the result is null or undefined
setAllSchedules(responseJson.schedules || []);
setPipelines(responseJson.pipelines || []);
// setPipelines(responseJson.pipelines || []);
})
.catch((error) => {
// toast(error.toString());
@@ -990,13 +1038,11 @@ If you're interested, please let me know a time that works for you, or set up a
}
const data = {
command: pipeline.command,
name: pipeline.name,
type: state,
environment: pipeline.environment,
workflow_id: pipeline.workflow_id,
trigger_id: pipeline.trigger_id,
start_node: pipeline.start_node,
};
if (state === "start") toast("starting the pipeline");
@@ -1027,7 +1073,6 @@ If you're interested, please let me know a time that works for you, or set up a
if (state === "start") toast("Successfully created pipeline");
else toast("Sucessfully stopped the pipeline");
}
setTimeout(handleGetAllTriggers, 1000);
})
.catch((error) => {
//toast(error.toString());
@@ -2093,10 +2138,10 @@ If you're interested, please let me know a time that works for you, or set up a
};
const getAppAuthenticationGroups = () => {
console.log("DEBUG: Skipping app auth group loading")
return
//console.log("DEBUG: Skipping app auth group loading")
//return
fetch(globalUrl + "/api/v1/apps/authentication/group", {
fetch(globalUrl + "/api/v1/authentication/group", {
method: "GET",
headers: {
"Content-Type": "application/json",
@@ -4941,7 +4986,7 @@ If you're interested, please let me know a time that works for you, or set up a
<ListItemText>
<Button
style={{ marginLeft: "140px" }}
style={{ marginLeft: "18%" }}
variant={
webhook.status === "running" ? "contained" : "outlined"
}
@@ -4963,10 +5008,10 @@ If you're interested, please let me know a time that works for you, or set up a
</List>
)}
<div style={{ marginTop: 20, marginBottom: 20 }}>
{/* <div style={{ marginTop: 20, marginBottom: 20 }}>
<h2 style={{ display: "inline" }}>Tenzir Pipelines</h2>
<span style={{ marginLeft: 25 }}>
Controls the Tenzir pipeline operations.{" "}
Controls a pipeline to run things.{" "}
<a
target="_blank"
rel="noopener noreferrer"
@@ -5013,7 +5058,7 @@ If you're interested, please let me know a time that works for you, or set up a
primary="Workflow"
style={{ maxWidth: 315, minWidth: 315 }}
/>
<ListItemText primary="Actions" style={{ marginLeft: '120px' }} />
<ListItemText primary="Actions" />
</ListItem>
{pipelines.map((pipeline, index) => {
var bgColor = "#27292d";
@@ -5066,7 +5111,7 @@ If you're interested, please let me know a time that works for you, or set up a
);
})}
</List>
)}
)}*/}
</div>
) : null;
@@ -5170,31 +5215,63 @@ If you're interested, please let me know a time that works for you, or set up a
const handleAppAuthGroupCheckbox = (data) => {
let appOrginal = data.app
if (appsForAppAuthGroup.includes(appOrginal.id)) {
return;
}
//let groupApp = data.app.id
var newappauth = appsForAppAuthGroup
if (appsForAppAuthGroup.includes(data.app.id)) {
newappauth = newappauth.filter((item) => item !== data.app.id)
}
setAppsForAppAuthGroup([...appsForAppAuthGroup, data.id]);
console.log("Apps for app auth group: ", appsForAppAuthGroup);
};
if (appsForAppAuthGroup.includes(data.id)) {
// Remove app from app auth group
newappauth = newappauth.filter((item) => item !== data.id)
setAppsForAppAuthGroup(newappauth)
return
}
for (var i = 0; i < authentication.length; i++) {
if (authentication[i].id === data.id) {
continue
}
if (!appsForAppAuthGroup.includes(authentication[i].id)) {
continue
}
if (authentication[i].app.id === data.app.id) {
// Remove app from app auth group
newappauth = newappauth.filter((item) => item !== authentication[i].id)
toast(`App ${data.app.name} is already in this group`)
}
}
setAppsForAppAuthGroup(newappauth.concat(data.id))
}
const authenticationView =
curTab === 2 ? (
<>
<div>
{/* (appAuthenticationGroupModalOpen : { */}
{appAuthenticationGroupModalOpen && (
<Dialog
open={appAuthenticationGroupModalOpen}
onClose={() => {
setAppAuthenticationGroupModalOpen(false);
setAppAuthenticationGroupId("")
setAppAuthenticationGroupName("")
setAppAuthenticationGroupEnvironment("")
setAppAuthenticationGroupDescription("")
setAppsForAppAuthGroup([])
}}
PaperProps={{
style: {
backgroundColor: theme.palette.surfaceColor,
color: "white",
minWidth: "1200px",
minWidth: "1000px",
minHeight: "320px",
padding: 25,
paddingLeft: 50,
},
}}
>
@@ -5202,106 +5279,130 @@ If you're interested, please let me know a time that works for you, or set up a
<span style={{ color: "white" }}>App Authentication Groups</span>
</DialogTitle>
<DialogContent>
<div>
<TextField
color="primary"
style={{ backgroundColor: theme.palette.inputColor }}
autoFocus
InputProps={{
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
fullWidth={true}
placeholder="Name"
id="namefield"
margin="normal"
variant="outlined"
onChange={(event) => {
setAppAuthenticationGroupName(event.target.value);
}}
/>
<DialogContent style={{marginLeft: 0, paddingLeft: 0, }}>
<div style={{display: "flex", position: "sticky", top: 0, zIndex: 1, backgroundColor: theme.palette.surfaceColor, borderRadius: theme.palette.borderRadius, padding: 20, marginBottom: 10, }}>
<div style={{marginRight: 50, minWidth: 250, }}>
<Typography style={{marginTop: 10, }}>
Name
</Typography>
<TextField
color="primary"
label="Name"
style={{ backgroundColor: theme.palette.inputColor }}
autoFocus
InputProps={{
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
fullWidth={true}
placeholder="Name"
id="namefield"
margin="normal"
variant="outlined"
defaultValue={appAuthenticationGroupName}
onChange={(event) => {
setAppAuthenticationGroupName(event.target.value);
}}
/>
</div>
<div style={{marginRight: 50, }}>
<Typography style={{marginTop: 10, marginBottom: 10}}>
Evironment
</Typography>
{environments !== undefined && environments !== null && environments.length > 0 ?
<Select
defaultValue={appAuthenticationGroupEnvironment === "" ? environments[0].Name : appAuthenticationGroupEnvironment}
onChange={(e) => {
setAppAuthenticationGroupEnvironment(e.target.value);
}}
>
{environments.map((env, index) => {
return (
<MenuItem key={index} value={env.Name}>
{env.Name}
</MenuItem>
)
})}
</Select>
:
<Typography>
Environments failed to load. Please try again
</Typography>
}
</div>
<div>
<TextField
color="primary"
style={{ backgroundColor: theme.palette.inputColor }}
autoFocus
InputProps={{
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
fullWidth={true}
placeholder="Description"
id="descriptionfield"
margin="normal"
variant="outlined"
onChange={(event) => {
setAppAuthenticationGroupDescription(event.target.value);
}}
/>
</div>
<div>
{/* Show a check box list of all app authentications to add to the auth group */}
<div>
{authentication.map((data, index) => (
<div key={index}>
<FormControlLabel
control={
<Tooltip
title={data.app.name}
>
<div style={{ display: 'flex', alignItems: 'center', marginBottom: '10px', marginLeft: '5px' }}>
<img
src={data.app.large_image ? data.app.large_image : '/images/no_image.png'}
alt=""
style={{ width: '50px', height: '50px', marginRight: '10px' }}
/>
<Checkbox
checked={data.checked}
onChange={(event) => {
handleAppAuthGroupCheckbox(data)
}}
name={data.label}
disabled={data.app.id in appsForAppAuthGroup}
/>
</div>
</Tooltip>
}
label={data.label}
/>
</div>
))}
</div>
</div>
<div>
<div style={{marginTop: 65, }}>
<Button
style={{}}
disabled={appAuthenticationGroupName === "" || appAuthenticationGroupEnvironment === "" || appsForAppAuthGroup.length === 0}
variant="contained"
color="primary"
onClick={() => {
createAppAuthenticationGroup(
appAuthenticationGroupName,
appAuthenticationGroupEnvironment,
appAuthenticationGroupDescription,
appsForAppAuthGroup
appsForAppAuthGroup,
);
}}
>
Create
Set Group
</Button>
</div>
</div>
<Divider style={{marginTop: 10, marginBottom: 10, }}/>
<div style={{marginLeft: 25, }}>
{/* Show a check box list of all app authentications to add to the auth group */}
<div>
{authentication.map((data, index) => {
var checked = data.checked
if (checked === undefined || checked === null) {
checked = false
}
if (appsForAppAuthGroup.includes(data.id)) {
checked = true
}
return (
<div key={index}>
<FormControlLabel
control={
<Tooltip
title={data.app.name}
placement="left"
>
<div style={{ display: 'flex', alignItems: 'center', marginBottom: '10px', marginLeft: '5px', }}>
<img
src={data.app.large_image ? data.app.large_image : '/images/no_image.png'}
alt=""
style={{ borderRadius: theme.palette.borderRadius, width: 50, height: 50, marginRight: 10 }}
/>
<Checkbox
checked={checked}
onChange={(event) => {
handleAppAuthGroupCheckbox(data)
}}
name={data.label}
disabled={data.app.id in appsForAppAuthGroup}
/>
</div>
</Tooltip>
}
label={data.label}
/>
</div>
)
})}
</div>
</div>
</DialogContent>
</Dialog>
)}
@@ -5311,7 +5412,7 @@ If you're interested, please let me know a time that works for you, or set up a
<div style={{ marginTop: 20, marginBottom: 20 }}>
<h2 style={{ display: "inline" }}>App Authentication</h2>
<span style={{ marginLeft: 25 }}>
Control the authentication options for individual apps.
Control the authentication options for individual apps. App Groups are farther down on this page.
</span>
&nbsp;
<a
@@ -5587,10 +5688,18 @@ If you're interested, please let me know a time that works for you, or set up a
</List>
</div>
{/* <div>
<Divider
style={{
marginTop: 20,
marginBottom: 20,
backgroundColor: theme.palette.inputColor,
}}
/>
<div style={{marginTop: 50, }}>
<div style={{ marginTop: 20, marginBottom: 20 }}>
<h2 style={{ display: "inline" }}>App Authentication Groups</h2>
<span style={{ marginLeft: 25 }}>
<h2 style={{ }}>App Authentication Groups</h2>
<span style={{ marginLeft: 0 }}>
Groups of authentication options for subflows.{" "}
<a
target="_blank"
@@ -5602,29 +5711,39 @@ If you're interested, please let me know a time that works for you, or set up a
</a>
</span>
<Divider
style={{
marginTop: 20,
marginBottom: 20,
backgroundColor: theme.palette.inputColor,
<br />
<Button
style={{ marginTop: 20 }}
variant="contained"
color="primary"
onClick={() => {
if (environments !== undefined && environments !== null && environments.length > 0) {
setAppAuthenticationGroupEnvironment(environments[0].Name)
}
setAppAuthenticationGroupModalOpen(true)
}}
/>
<List>
>
Add Group
</Button>
<List style={{marginTop: 25, }}>
<ListItem>
<ListItemText
primary="Label"
style={{ minWidth: 250, maxWidth: 250}}
/>
<ListItemText
primary="Environment"
style={{ minWidth: 150, maxWidth: 150 }}
/>
<ListItemText
primary="Description"
primary="App Auth"
style={{ minWidth: 250, maxWidth: 250 }}
/>
<ListItemText
primary="Apps"
style={{ minWidth: 250, maxWidth: 250 }}
/>
<ListItemText
primary="CreatedAt"
primary="Created At"
style={{ minWidth: 150, maxWidth: 150 }}
/>
<ListItemText
@@ -5638,31 +5757,49 @@ If you're interested, please let me know a time that works for you, or set up a
if (index % 2 === 0) {
bgColor = "#1f2023";
}
if (data.app_auths === undefined || data.app_auths === null) {
data.app_auths = []
}
return (
<ListItem key={index} style={{ backgroundColor: bgColor }}>
<ListItemText
primary={data.label}
style={{ minWidth: 150, maxWidth: 150 }}
style={{ minWidth: 250, maxWidth: 250, }}
/>
<ListItemText
primary={data.description}
style={{ minWidth: 250, maxWidth: 250 }}
primary={data.environment}
style={{ minWidth: 150, maxWidth: 150, }}
/>
<ListItemText
primary={
<div style={{ display: 'flex' }}>
{data.app_auths.map((appAuth, index) => (
<Tooltip
title={appAuth.app.name}
>
<img
key={index}
src={appAuth.app.large_image}
alt={appAuth.app.name}
style={{ width: '24px', height: '24px', marginRight: '5px' }}
/>
</Tooltip>
))}
{data.app_auths.map((appAuth, index) => {
if (appAuth.app.large_image === undefined || appAuth.app.large_image === null || appAuth.app.large_image === "") {
const foundImage = authentication.find((auth) => auth.app.id === appAuth.app.id)
if (foundImage !== undefined) {
appAuth.app.large_image = foundImage.app.large_image
appAuth.app.name = foundImage.app.name
}
}
const tooltip = `${appAuth.app.name.replaceAll("_", " ")} (authname: ${appAuth.label})`
return (
<Tooltip
title={tooltip}
>
<img
key={index}
src={appAuth.app.large_image}
alt={appAuth.app.name}
style={{ width: 30, height: 30, marginRight: 5 }}
/>
</Tooltip>
)
})}
</div>
}
style={{ minWidth: 250, maxWidth: 250 }}
@@ -5676,16 +5813,22 @@ If you're interested, please let me know a time that works for you, or set up a
<div style={{ display: 'flex' }}>
<IconButton
onClick={() => {
setAppAuthenticationGroupId(data.id)
setAppAuthenticationGroupName(data.label)
setAppAuthenticationGroupDescription(data.description)
setAppsForAppAuthGroup(data.app_auths.map((appAuth) => appAuth.id))
setAppAuthenticationGroupEnvironment(data.environment)
setAppAuthenticationGroupModalOpen(true)
}}
disabled={true}
>
<EditIcon />
</IconButton>
<IconButton
onClick={() => {
// deleteAppAuthenticationGroup(data);
deleteAppAuthenticationGroup(data.id)
}}
disabled={true}
>
<DeleteIcon />
</IconButton>
@@ -5700,20 +5843,10 @@ If you're interested, please let me know a time that works for you, or set up a
)}
</List>
<Button
style={{ marginLeft: 10 }}
variant="contained"
color="primary"
onClick={() => {
setAppAuthenticationGroupModalOpen(true);
}}
>
Add Group
</Button>
</div>
</div> */}
</>
</div>
</div>
) : null;
const getLogs = async (ip, userId) => {
File diff suppressed because it is too large Load Diff
+1
View File
@@ -46,6 +46,7 @@ const Body = {
height: "100%",
color: "white",
position: "relative",
paddingTop: 40,
//textAlign: "center",
};
+154 -70
View File
@@ -74,6 +74,7 @@ import {
ArrowLeft as ArrowLeftIcon,
ArrowRight as ArrowRightIcon,
QueryStats as QueryStatsIcon,
Visibility as VisibilityIcon,
} from "@mui/icons-material";
import { DataGrid, GridToolbar } from "@mui/x-data-grid";
@@ -614,6 +615,7 @@ const Workflows = (props) => {
const [videoViewOpen, setVideoViewOpen] = React.useState(false)
const [gettingStartedItems, setGettingStartedItems] = React.useState([])
const [selectedWorkflowIndexes, setSelectedWorkflowIndexes] = React.useState([])
const [highlightIds, setHighlightIds] = React.useState([])
const [apps, setApps] = React.useState([]);
@@ -1213,7 +1215,24 @@ const Workflows = (props) => {
}
setFirstLoad(false)
}, 100)
}, 250)
/*
setTimeout(() => {
var timeout = 0
for (var key in newarray) {
const wf = newarray[key]
if (wf.actions === undefined || wf.actions === null || wf.actions.length === 0) {
setTimeout(() => {
sideloadWorkflow(wf.id, false)
}, timeout)
timeout += 1000
}
}
}, 1000)
*/
} else {
if (isLoggedIn) {
@@ -1637,20 +1656,24 @@ const Workflows = (props) => {
});
};
const copyWorkflow = (data) => {
data = JSON.parse(JSON.stringify(data));
toast("Copying workflow " + data.name);
data.id = "";
data.name = data.name + "_copy";
data = deduplicateIds(data, true);
const duplicateWorkflow = (data) => {
//data = JSON.parse(JSON.stringify(data));
toast("Copying workflow '" + data.name + "'. The new workflow will load in and be highlighted.");
//data.id = "";
//data.name = data.name + "_copy";
//data = deduplicateIds(data, true);
fetch(globalUrl + "/api/v1/workflows", {
const duplicateData = {
name: data.name + "_copy",
}
fetch(`${globalUrl}/api/v1/workflows/${data.id}/duplicate`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(data),
body: JSON.stringify(duplicateData),
credentials: "include",
})
.then((response) => {
@@ -1660,7 +1683,20 @@ const Workflows = (props) => {
}
return response.json();
})
.then(() => {
.then((responseJson) => {
if (responseJson.success === false) {
if (responseJson.reason !== undefined) {
toast("Failed copying workflow: " + responseJson.reason)
} else {
toast("Failed copying workflow")
}
return
}
if (responseJson.id !== undefined) {
setHighlightIds([responseJson.id])
}
setTimeout(() => {
getAvailableWorkflows();
}, 1000);
@@ -1689,15 +1725,68 @@ const Workflows = (props) => {
})
}
const sideloadWorkflow = (id, openEdit) => {
const exportSingleWorkflow = (data, setOpen) => {
setExportModalOpen(true)
if (data.triggers !== null && data.triggers !== undefined) {
var newSubflows = [];
for (var key in data.triggers) {
const trigger = data.triggers[key];
if (
trigger.parameters !== null &&
trigger.parameters !== undefined
) {
for (var subkey in trigger.parameters) {
const param = trigger.parameters[subkey];
if (
param.name === "workflow" &&
param.value !== data.id &&
!newSubflows.includes(param.value)
) {
newSubflows.push(param.value);
}
}
}
}
var parsedworkflows = [];
for (var key in newSubflows) {
const foundWorkflow = workflows.find(
(workflow) => workflow.id === newSubflows[key]
);
if (foundWorkflow !== undefined && foundWorkflow !== null) {
parsedworkflows.push(foundWorkflow);
}
}
if (parsedworkflows.length > 0) {
console.log(
"Appending subflows during export: ",
parsedworkflows.length
);
data.subflows = parsedworkflows;
}
}
setExportData(data)
setOpen(false)
}
const sideloadWorkflow = (id, action, setOpen) => {
const storagewf = localStorage.getItem("workflows")
const storageWorkflows = JSON.parse(storagewf)
if (storageWorkflows === null || storageWorkflows === undefined || storageWorkflows.length === 0) {
} else {
for (var i = 0; i < storageWorkflows.length; i++) {
if (storageWorkflows[i].id === id) {
if (storageWorkflows[i].image !== "") {
return
if (storageWorkflows[i].image !== "" && storageWorkflows[i].image !== undefined && storageWorkflows[i].image !== null) {
if (action === undefined || action === null || action === "") {
console.log("RETURNING")
return
}
}
}
}
@@ -1718,8 +1807,16 @@ const Workflows = (props) => {
return response.json()
})
.then((responseJson) => {
if (openEdit) {
setEditing(responseJson)
if (responseJson.success !== false && responseJson.id !== undefined) {
if (action === "edit") {
setEditing(responseJson)
} else if (action === "publish") {
setPublishModalOpen(true)
setSelectedWorkflow(responseJson)
} else if (action === "export") {
exportSingleWorkflow(responseJson, setOpen)
}
}
for (var i = 0; i < storageWorkflows.length; i++) {
@@ -1730,8 +1827,9 @@ const Workflows = (props) => {
}
}
setWorkflows(storageWorkflows)
//setFilteredWorkflows(storageWorkflows)
//setWorkflows(storageWorkflows)
setFilteredWorkflows(storageWorkflows)
//setUpdate(Math.random())
})
.catch((error) => {
console.log(error.toString())
@@ -1878,7 +1976,9 @@ const Workflows = (props) => {
const appGroup = getWorkflowAppgroup(data)
const [triggers, subflows] = getWorkflowMeta(data)
const isDistributed = data.suborg_distribution !== undefined && data.suborg_distribution !== null && data.suborg_distribution.includes(userdata.active_org.id)
const hasSuborgs = data.suborg_distribution !== undefined && data.suborg_distribution !== null && data.suborg_distribution.length > 0
const isDistributed = (data.parentorg_workflow !== undefined && data.parentorg_workflow !== null && data.parentorg_workflow.length > 0) //|| (data.org_id !== userdata.active_org.id && data.org_id !== undefined && data.org_id !== null && data.org_id.length > 0)
const workflowMenuButtons = (
<Menu
id="long-menu"
@@ -1890,8 +1990,20 @@ const Workflows = (props) => {
setAnchorEl(null);
}}
>
{isDistributed ?
<MenuItem
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
onClick={() => {
navigate(`/workflows/${data.id}`)
}}
>
<VisibilityIcon style={{ marginLeft: 0, marginRight: 8 }} />
Explore Workflow
</MenuItem>
: null}
<MenuItem
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
disabled={isDistributed}
onClick={(event) => {
event.stopPropagation()
if (data.actions !== undefined && data.actions !== null && data.actions.length > 0 && data.image !== "") {
@@ -1899,7 +2011,9 @@ const Workflows = (props) => {
} else {
//toast("Need to side-load workflow to be edited properly")
sideloadWorkflow(data.id, true)
sideloadWorkflow(data.id, "edit")
toast.info("Loading full workflow for editing. Please wait...")
}
}}
key={"change"}
@@ -1909,9 +2023,11 @@ const Workflows = (props) => {
</MenuItem>
<MenuItem
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
disabled={isDistributed}
onClick={() => {
setSelectedWorkflow(data);
setPublishModalOpen(true);
sideloadWorkflow(data.id, "publish")
toast.info("Loading full workflow for publishing. Please wait...")
}}
key={"publish"}
>
@@ -1920,9 +2036,10 @@ const Workflows = (props) => {
</MenuItem>
<MenuItem
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
disabled={isDistributed}
onClick={() => {
copyWorkflow(data);
setOpen(false);
duplicateWorkflow(data)
setOpen(false)
}}
key={"duplicate"}
>
@@ -1931,52 +2048,11 @@ const Workflows = (props) => {
</MenuItem>
<MenuItem
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
disabled={isDistributed}
onClick={() => {
setExportModalOpen(true);
sideloadWorkflow(data.id, "export", setOpen)
if (data.triggers !== null && data.triggers !== undefined) {
var newSubflows = [];
for (var key in data.triggers) {
const trigger = data.triggers[key];
if (
trigger.parameters !== null &&
trigger.parameters !== undefined
) {
for (var subkey in trigger.parameters) {
const param = trigger.parameters[subkey];
if (
param.name === "workflow" &&
param.value !== data.id &&
!newSubflows.includes(param.value)
) {
newSubflows.push(param.value);
}
}
}
}
var parsedworkflows = [];
for (var key in newSubflows) {
const foundWorkflow = workflows.find(
(workflow) => workflow.id === newSubflows[key]
);
if (foundWorkflow !== undefined && foundWorkflow !== null) {
parsedworkflows.push(foundWorkflow);
}
}
if (parsedworkflows.length > 0) {
console.log(
"Appending subflows during export: ",
parsedworkflows.length
);
data.subflows = parsedworkflows;
}
}
setExportData(data);
setOpen(false);
toast.info("Loading full workflow to be exported. Please wait...")
}}
key={"export"}
>
@@ -1985,6 +2061,7 @@ const Workflows = (props) => {
</MenuItem>
<MenuItem
style={{ backgroundColor: theme.palette.inputColor, color: "white" }}
disabled={isDistributed}
onClick={() => {
setDeleteModalOpen(true);
setSelectedWorkflowId(data.id);
@@ -2076,7 +2153,7 @@ const Workflows = (props) => {
}
return (
<div style={{width: "100%", minWidth: 321, position: "relative", border: isDistributed ? "2px solid #40E0D0" : "inherit", borderRadius: theme.palette.borderRadius, }}>
<div style={{width: "100%", minWidth: 321, position: "relative", border: highlightIds.includes(data.id) ? "2px solid #f85a3e" : isDistributed || hasSuborgs ? "2px solid #40E0D0" : "inherit", borderRadius: theme.palette.borderRadius, }}>
<Paper square style={paperAppStyle}>
{selectedCategory !== "" ?
<Tooltip title={`Usecase Category: ${selectedCategory}`} placement="bottom">
@@ -2462,6 +2539,8 @@ const Workflows = (props) => {
}
const reader = new FileReader();
var workflowids = []
// Waits for the read
reader.addEventListener("load", (event) => {
var data = reader.result;
@@ -2497,7 +2576,8 @@ const Workflows = (props) => {
data.org_id = userdata.active_org.id
data.org = []
data.execution_org = {}
workflowids.push(data.id)
// Actually create it
setNewWorkflow(
@@ -2528,6 +2608,10 @@ const Workflows = (props) => {
}
setLoadWorkflowsModalOpen(false);
if (workflowids.length > 0) {
setHighlightIds(workflowids)
}
};
const getWorkflowMeta = (data) => {
@@ -3682,7 +3766,7 @@ const Workflows = (props) => {
workflowDelay += 75
} else {
return (
<Grid key={index} item xs={isMobile ? 12 : 4} style={{ padding: "12px 10px 12px 10px" }}>
<Grid key={index} item xs={isMobile ? 12 : 4} style={{ padding: "12px 10px 12px 10px", }}>
<WorkflowPaper key={index} data={data} />
</Grid>
)