Added fixes for public workflows with app visuals

This commit is contained in:
frikky
2022-01-31 12:22:37 +01:00
parent cc2610c2cb
commit a811036fb2
5 changed files with 337 additions and 88 deletions
+2 -2
View File
@@ -47,10 +47,10 @@ services:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- SHUFFLE_WORKER_VERSION=0.9.52
- SHUFFLE_WORKER_VERSION=nightly
- ORG_ID=${ORG_ID}
- ENVIRONMENT_NAME=${ENVIRONMENT_NAME}
- BASE_URL=https://frikky-shuffle-5gvr4xx62w64-5001.githubpreview.dev
- BASE_URL=https://${OUTER_HOSTNAME}:${BACKEND_PORT}
- DOCKER_API_VERSION=1.40
- SHUFFLE_BASE_IMAGE_NAME=${SHUFFLE_BASE_IMAGE_NAME}
- SHUFFLE_BASE_IMAGE_REGISTRY=${SHUFFLE_BASE_IMAGE_REGISTRY}
+4
View File
@@ -114,6 +114,10 @@ const AuthenticationOauth2 = (props) => {
setButtonClicked(true);
console.log("SCOPES: ", scopes);
client_id = client_id.trim()
client_secret = client_secret.trim()
oauth_url = oauth_url.trim()
var resources = "";
if (scopes !== undefined && (scopes !== null) & (scopes.length > 0)) {
if (offlineAccess === true && !scopes.includes("offline_access")) {
+258 -68
View File
@@ -14,6 +14,7 @@ import theme from '../theme';
import {
Zoom,
Avatar,
Popover,
TextField,
Drawer,
@@ -45,8 +46,13 @@ import {
Breadcrumbs,
CircularProgress,
Switch,
Chip,
} from "@material-ui/core";
import {
AvatarGroup,
} from "@mui/material"
import {
OpenInNew as OpenInNewIcon,
Undo as UndoIcon,
@@ -248,6 +254,9 @@ const AngularWorkflow = (defaultprops) => {
const [subworkflowStartnode, setSubworkflowStartnode] = React.useState("");
const [leftViewOpen, setLeftViewOpen] = React.useState(true);
const [leftBarSize, setLeftBarSize] = React.useState(350);
const [creatorProfile, setCreatorProfile] = React.useState({});
const [appGroup, setAppGroup] = React.useState([]);
const [triggerGroup, setTriggerGroup] = React.useState([]);
const [executionText, setExecutionText] = React.useState("");
const [executionRequestStarted, setExecutionRequestStarted] =
React.useState(false);
@@ -1346,7 +1355,7 @@ const AngularWorkflow = (defaultprops) => {
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for apps :O!");
console.log("Status not 200 for app auth :O!");
}
return response.json();
@@ -1460,6 +1469,10 @@ const AngularWorkflow = (defaultprops) => {
return response.json();
})
.then((responseJson) => {
if (responseJson.success === false) {
return
}
// FIXME - handle versions on left bar
//handleAppVersioning(responseJson)
//var tmpapps = []
@@ -1495,7 +1508,7 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
alert.error(error.toString());
alert.error("App loading error: ", error.toString());
});
};
@@ -1530,12 +1543,51 @@ const AngularWorkflow = (defaultprops) => {
responseJson.errors = [];
}
if (responseJson.actions === undefined || responseJson.actions === null) {
responseJson.actions = [];
}
if (responseJson.triggers === undefined || responseJson.triggers === null) {
responseJson.triggers = [];
}
if (responseJson.public) {
alert.info(
"This workflow is public. You will have to save it to make it your own!"
"This workflow is public. Save the workflow to "
);
console.log("RESP: ", responseJson)
if (Object.getOwnPropertyNames(creatorProfile).length === 0) {
getUserProfile("frikky")
}
//{appGroup.map((data, index) => {
//const [appGroup, setAppGroup] = React.useState([]);
var appsFound = []
for (var key in responseJson.actions) {
const parsedAction = responseJson.actions[key]
if (parsedAction.large_image === undefined || parsedAction.large_image === null || parsedAction.large_image === "") {
continue
}
if (appsFound.findIndex(data => data.app_name === parsedAction.app_name) < 0){
appsFound.push(parsedAction)
}
}
setAppGroup(appsFound)
appsFound = []
for (var key in responseJson.triggers) {
const parsedAction = responseJson.triggers[key]
if (appsFound.findIndex(data => data.app_name === parsedAction.app_name) < 0){
appsFound.push(parsedAction)
}
}
setTriggerGroup(appsFound)
}
// Appends SUBFLOWS. Does NOT run during normal grabbing of workflows.
if (sourcenode.id !== undefined) {
console.log("WORKFLOW: ", responseJson);
@@ -2107,9 +2159,11 @@ const AngularWorkflow = (defaultprops) => {
if (!lastSaved) {
return unloadText;
} else {
//document.removeEventListener("mousemove", onMouseUpdate, true);
document.removeEventListener("keydown", handleKeyDown, true);
document.removeEventListener("paste", handlePaste, true);
if (workflow.public === false) {
//document.removeEventListener("mousemove", onMouseUpdate, true);
document.removeEventListener("keydown", handleKeyDown, true);
document.removeEventListener("paste", handlePaste, true);
}
}
});
@@ -3393,7 +3447,7 @@ const AngularWorkflow = (defaultprops) => {
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for apps :O!");
console.log("Status not 200 for envs :O!");
if (isCloud) {
setEnvironments([{ Name: "Cloud", Type: "cloud" }]);
} else {
@@ -3820,7 +3874,7 @@ const AngularWorkflow = (defaultprops) => {
//var parentNode = cy.$("#" + event.target.data("id"));
//if (parentNode.data("isButton") || parentNode.data("buttonId")) return;
if (nodedata.app_name !== undefined) {
if (nodedata.app_name !== undefined && !workflow.public === true) {
const allNodes = cy.nodes().jsons();
var found = false;
@@ -9893,6 +9947,10 @@ const AngularWorkflow = (defaultprops) => {
};
const TopCytoscapeBar = (props) => {
if (workflow.public === true) {
return null
}
return (
<div style={topBarStyle}>
<div style={{ margin: "0px 10px 0px 10px" }}>
@@ -9916,10 +9974,6 @@ const AngularWorkflow = (defaultprops) => {
</h2>
</Link>
<h2 style={{ margin: 0 }}>{workflow.name}</h2>
{workflow.public ? (
<h2 style={{ margin: 0 }}>Public Workflow PREVIEW</h2>
) : null}
</Breadcrumbs>
</div>
</div>
@@ -10518,66 +10572,202 @@ const AngularWorkflow = (defaultprops) => {
// executeWorkflowWebsocket()
//}}>Execute websocket</Button>
//
const getUserProfile = (username) => {
fetch(`${globalUrl}/api/v1/users/creators/${username}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for WORKFLOW EXECUTION :O!");
}
const leftView = leftViewOpen ? (
<div
style={{
minWidth: leftBarSize,
maxWidth: leftBarSize,
borderRight: "1px solid rgb(91, 96, 100)",
}}
>
<HandleLeftView />
</div>
) : (
<div
style={{
minWidth: leftBarSize,
maxWidth: leftBarSize,
borderRight: "1px solid rgb(91, 96, 100)",
}}
>
<div
style={{ cursor: "pointer", height: 20, marginTop: 10, marginLeft: 10 }}
onClick={() => {
setLeftViewOpen(true);
setLeftBarSize(350);
}}
>
<Tooltip color="primary" title="Maximize" placement="top">
<KeyboardArrowRightIcon />
</Tooltip>
</div>
</div>
);
const executionPaperStyle = {
minWidth: "95%",
maxWidth: "95%",
marginTop: "5px",
color: "white",
marginBottom: 10,
padding: 5,
backgroundColor: surfaceColor,
cursor: "pointer",
display: "flex",
minHeight: 40,
maxHeight: 40,
};
return response.json();
})
.then((responseJson) => {
console.log("FOUND USER FOR: ", username, responseJson)
if (responseJson.success !== false) {
setCreatorProfile(responseJson)
}
})
.catch((error) => {
console.log(error);
})
}
const leftView = workflow.public === true ?
<div style={{minHeight: "80vh", height: "100%", minWidth: leftBarSize-70, maxWidth: leftBarSize-70, zIndex: 0, padding: 35, borderRight: "1px solid rgba(91,96,100,1)",}}>
<Typography variant="h6" color="textPrimary" style={{
margin: "0px 0px 0px 0px",
}}
>
{workflow.name}
</Typography>
<Typography variant="body2" color="textSecondary">
This workflow is public and <span style={{color: "#f86a3e", cursor: "pointer", }} onClick={() => {
saveWorkflow()
}}>must be saved</span> to be used in your organization.
</Typography>
{Object.getOwnPropertyNames(creatorProfile).length !== 0 && creatorProfile.github_avatar !== undefined && creatorProfile.github_avatar !== null ?
<div style={{display: "flex", marginTop: 10, }}>
<IconButton color="primary" style={{padding: 0, marginRight: 10, }} aria-controls="simple-menu" aria-haspopup="true" onClick={(event) => {
}}>
<Link to={`/creators/${creatorProfile.github_username}`} style={{textDecoration: "none", color: "#f86a3e"}}>
<Avatar style={{height: 30, width: 30,}} alt={"Workflow creator"} src={creatorProfile.github_avatar} />
</Link>
</IconButton>
<Typography variant="body1" color="textSecondary" style={{color: ""}}>
Shared by <Link to={`/creators/${creatorProfile.github_username}`} style={{textDecoration: "none", color: "#f86a3e"}}>{creatorProfile.github_username}</Link>
</Typography>
</div>
: null}
<div style={{marginTop: 15}} />
{workflow.tags !== undefined && workflow.tags !== null && workflow.tags.length > 0 ?
<div style={{display: "flex", overflow: "hidden",marginTop: 5, }}>
<Typography variant="body1" style={{marginRight: 10, }}>
Tags
</Typography>
<div style={{display: "flex"}}>
{workflow.tags.map((tag, index) => {
if (index >= 3) {
return null;
}
const parsedExecutionArgument = () => {
var showResult = executionData.execution_argument.trim();
const validate = validateJson(showResult);
return (
<Chip
key={index}
style={{backgroundColor: "#3d3f43", height: 30, marginRight: 5, paddingLeft: 5, paddingRight: 5, height: 28, cursor: "pointer", borderColor: "#3d3f43", color: "white",}}
label={tag}
variant="outlined"
color="primary"
/>
);
})}
</div>
</div>
: null }
<div style={{display: "flex", marginTop: 10, }}>
<Typography variant="body1">
Mitre Att&ck:
</Typography>
<Typography variant="body1" color="textSecondary">
TBD
</Typography>
</div>
{appGroup.length > 0 ?
<div style={{display: "flex", marginTop: 10, }}>
<Typography variant="body1">
Apps
</Typography>
<AvatarGroup max={6} style={{marginLeft: 10, }}>
{appGroup.map((data, index) => {
return (
<Link to={`/apps/${data.app_id}`}>
<Avatar alt={data.app_name} src={data.large_image} style={{width: 30, height: 30}}/>
</Link>
)
})}
</AvatarGroup>
</div>
: null}
{triggerGroup.length > 0 ?
<div style={{display: "flex", marginTop: 10, }}>
<Typography variant="body1">
Triggers
</Typography>
<AvatarGroup max={6} style={{marginLeft: 10, }}>
{triggerGroup.map((data, index) => {
return (
<Avatar alt={data.app_name} src={data.large_image} style={{width: 30, height: 30}}/>
)
})}
</AvatarGroup>
</div>
: null}
<div style={{display: "flex", marginTop: 10, }}>
<Typography variant="body1">
Related Workflows:
</Typography>
<Typography variant="body1" color="textSecondary">
TBD
</Typography>
</div>
{workflow.description !== undefined && workflow.description !== null && workflow.description.length > 0 ?
<div style={{marginTop: 5, }}>
<Typography variant="body1">
Description
</Typography>
<Typography variant="body1" color="textSecondary">
{workflow.description}
</Typography>
</div>
: null}
</div>
: leftViewOpen ? (
<div
style={{
minWidth: leftBarSize,
maxWidth: leftBarSize,
borderRight: "1px solid rgb(91, 96, 100)",
}}
>
<HandleLeftView />
</div>
) : (
<div
style={{
minWidth: leftBarSize,
maxWidth: leftBarSize,
borderRight: "1px solid rgb(91, 96, 100)",
}}
>
<div
style={{ cursor: "pointer", height: 20, marginTop: 10, marginLeft: 10 }}
onClick={() => {
setLeftViewOpen(true);
setLeftBarSize(350);
}}
>
<Tooltip color="primary" title="Maximize" placement="top">
<KeyboardArrowRightIcon />
</Tooltip>
</div>
</div>
);
if (validate.valid) {
if (typeof validate.result === "string") {
try {
validate.result = JSON.parse(validate.result);
} catch (e) {
console.log("Error: ", e);
validate.valid = false;
}
}
const executionPaperStyle = {
minWidth: "95%",
maxWidth: "95%",
marginTop: "5px",
color: "white",
marginBottom: 10,
padding: 5,
backgroundColor: surfaceColor,
cursor: "pointer",
display: "flex",
minHeight: 40,
maxHeight: 40,
};
const parsedExecutionArgument = () => {
var showResult = executionData.execution_argument.trim();
const validate = validateJson(showResult);
if (validate.valid) {
if (typeof validate.result === "string") {
try {
validate.result = JSON.parse(validate.result);
} catch (e) {
console.log("Error: ", e);
validate.valid = false;
}
}
return (
<div style={{display: "flex"}}>
+1 -1
View File
@@ -352,7 +352,7 @@ const Docs = (defaultprops) => {
}
function Img(props) {
return <img style={{ maxWidth: "100%" }} alt={props.alt} src={props.src} />;
return <img style={{ borderRadius: theme.palette.borderRadius, maxWidth: "100%", marginTop: 15, marginBottom: 15, }} alt={props.alt} src={props.src} />;
}
function CodeHandler(props) {
+72 -17
View File
@@ -33,6 +33,10 @@ import {
DialogContent,
} from "@material-ui/core";
import {
AvatarGroup,
} from "@mui/material"
import {
GridOn as GridOnIcon,
List as ListIcon,
@@ -1310,6 +1314,30 @@ const Workflows = (props) => {
);
};
const getWorkflowAppgroup = (data) => {
if (data.actions === undefined || data.actions === null) {
return []
}
var appsFound = []
for (var key in data.actions) {
const parsedAction = data.actions[key]
if (parsedAction.large_image === undefined || parsedAction.large_image === null || parsedAction.large_image === "") {
continue
}
if (parsedAction.app_name === "Shuffle Tools" || parsedAction.app_id === "bc78f35c6c6351b07a09b7aed5d29652") {
continue
}
if (appsFound.findIndex(data => data.app_name === parsedAction.app_name) < 0){
appsFound.push(parsedAction)
}
}
return appsFound
}
const WorkflowPaper = (props) => {
const { data } = props;
const [open, setOpen] = React.useState(false);
@@ -1339,6 +1367,7 @@ const Workflows = (props) => {
}
const actions = data.actions !== null ? data.actions.length : 0;
const appGroup = getWorkflowAppgroup(data)
const [triggers, subflows] = getWorkflowMeta(data);
const workflowMenuButtons = (
@@ -1561,22 +1590,48 @@ const Workflows = (props) => {
</Tooltip>
</Grid>
<Grid item style={workflowActionStyle}>
<Tooltip color="primary" title="Action amount" placement="bottom">
<span style={{ color: "#979797", display: "flex" }}>
<BubbleChartIcon
style={{ marginTop: "auto", marginBottom: "auto" }}
/>
<Typography
style={{
marginLeft: 5,
marginTop: "auto",
marginBottom: "auto",
}}
>
{actions}
</Typography>
</span>
</Tooltip>
{appGroup.length > 0 ?
<div style={{display: "flex", marginTop: 8, }}>
<AvatarGroup max={4} style={{marginLeft: 5, maxHeight: 24,}}>
{appGroup.map((data, index) => {
return (
<div
style={{
height: 24,
width: 24,
filter: "brightness(0.6)",
cursor: "pointer",
}}
onClick={() => {
addFilter(data.app_name);
}}
>
<Tooltip color="primary" title={data.app_name} placement="bottom">
<Avatar alt={data.app_name} src={data.large_image} style={{width: 24, height: 24}}/>
</Tooltip>
</div>
)
})}
</AvatarGroup>
</div>
:
<Tooltip color="primary" title="Action amount" placement="bottom">
<span style={{ color: "#979797", display: "flex" }}>
<BubbleChartIcon
style={{ marginTop: "auto", marginBottom: "auto" }}
/>
<Typography
style={{
marginLeft: 5,
marginTop: "auto",
marginBottom: "auto",
}}
>
{actions}
</Typography>
</span>
</Tooltip>
}
<Tooltip
color="primary"
title="Trigger amount"
@@ -1681,7 +1736,7 @@ const Workflows = (props) => {
marginTop: 5,
}}
>
{data.tags !== undefined
{data.tags !== undefined && data.tags !== null
? data.tags.map((tag, index) => {
if (index >= 3) {
return null;