Added integration framework properly

This commit is contained in:
Frikky
2024-05-21 16:53:37 +02:00
parent d52b024716
commit b5ee9863e2
12 changed files with 1000 additions and 872 deletions
+79 -13
View File
@@ -187,7 +187,7 @@ const ConfigureWorkflow = (props) => {
console.log("No apps loaded: ", apps);
if (setConfigureWorkflowModalOpen !== undefined) {
setConfigureWorkflowModalOpen(false);
setConfigureWorkflowModalOpen(false)
}
return null;
@@ -198,7 +198,7 @@ const ConfigureWorkflow = (props) => {
const newactions = [];
for (let [key, keyval] in Object.entries(workflow.actions)) {
const action = workflow.actions[key];
var action = JSON.parse(JSON.stringify(workflow.actions[key]))
var newaction = {
large_image: action.large_image,
app_name: action.app_name,
@@ -220,17 +220,67 @@ const ConfigureWorkflow = (props) => {
}
if (action.app_name === "Integration Framework") {
console.log("Skipping integration framework: ", action)
var selected_app = ""
for (var paramkey in action.parameters) {
const param = action.parameters[paramkey]
if (param.name === "app_name") {
selected_app = param.value
break
}
}
for (var appauth in appAuthentication) {
if (appAuthentication[appauth].app.name.toLowerCase() === selected_app.toLowerCase()) {
newaction.auth_done = true
break
}
}
if (newaction.auth_done) {
continue
}
for (var appkey in apps) {
if (apps[appkey].name.toLowerCase() === selected_app.toLowerCase()) {
newaction.app_name = apps[appkey].name
newaction.app_version = apps[appkey].app_version
newaction.app = apps[appkey]
newaction.app_id = apps[appkey].id
newaction.must_activate = false
newaction.must_authenticate = true
newaction.steps.push({
"title": "Authenticate app",
"type": "authenticate",
"required": true,
})
action.app_id = apps[appkey].id
action.authentication_id = ""
action.authentication = {
"required": true,
}
break
}
}
if (newaction.app.id === undefined) {
console.log("Failed to find app: ", selected_app)
continue
}
newaction.update_version = "1.1.0"
}
// ID match OR name match + version match
//const app = apps.find((app) => app.id === action.app_id || (app.name === action.app_name && (app.app_version === action.app_version || (app.loop_versions !== null && app.loop_versions.includes(action.app_version)))))
//
// without version match
const newappname = action.app_name.toLowerCase().replaceAll(" ", "_")
const app = apps.find((app) => app.id === action.app_id || app.name.toLowerCase().replaceAll(" ", "_") === newappname)
var app = apps.find((app) => app.id === action.app_id || app.name.toLowerCase().replaceAll(" ", "_") === newappname)
if (app === undefined || app === null) {
@@ -246,6 +296,19 @@ const ConfigureWorkflow = (props) => {
"required": true,
})
} else {
if (action.authentication_id !== "" && app.authentication.required === true) {
var authFound = false
for (var authkey in appAuthentication) {
if (appAuthentication[authkey].id === action.authentication_id) {
authFound = true
break
}
}
if (!authFound) {
action.authentication_id = ""
}
}
if (action.authentication_id === "" && app.authentication.required === true && action.parameters !== undefined && action.parameters !== null) {
// Check if configuration is filled or not
@@ -292,9 +355,11 @@ const ConfigureWorkflow = (props) => {
//console.log(newaction.app_name,"AUTH: ", newaction.must_authenticate, " ACTIVATE: ", newaction.must_activate)
if (newaction.must_authenticate) {
var authenticationOptions = [];
var authenticationOptions = []
for (let [key,keyval] in Object.entries(appAuthentication)) {
const auth = appAuthentication[key];
const auth = appAuthentication[key]
if (auth.app.name === app.name && auth.active) {
//console.log("Found auth: ", auth)
authenticationOptions.push(auth);
@@ -403,17 +468,18 @@ const ConfigureWorkflow = (props) => {
continue;
}
requiredTriggers.push(trigger);
requiredTriggers.push(trigger)
}
}
if (requiredTriggers.length === 0 && requiredVariables.length === 0 && newactions.length === 0 && setConfigureWorkflowModalOpen !== undefined) {
setConfigureWorkflowModalOpen(false);
if (setConfigureWorkflowModalOpen !== undefined && requiredTriggers.length === 0 && requiredVariables.length === 0 && newactions.length === 0 ) {
console.log("No required triggers, variables or actions. Closing modal.")
setConfigureWorkflowModalOpen(false)
}
setRequiredTriggers(requiredTriggers);
setRequiredVariables(requiredVariables);
setRequiredActions(newactions);
setRequiredTriggers(requiredTriggers)
setRequiredVariables(requiredVariables)
setRequiredActions(newactions)
}
if (appAuthentication !== undefined && previousAuth !== undefined && appAuthentication.length !== previousAuth.length) {
+4
View File
@@ -496,6 +496,10 @@ const Header = (props) => {
localStorage.setItem("globalUrl", responseJson.region_url);
//globalUrl = responseJson.region_url
}
if (responseJson["reason"] === "SSO_REDIRECT") {
window.location.href = responseJson["url"]
return
}
setTimeout(() => {
window.location.reload();
+27 -169
View File
@@ -113,6 +113,11 @@ const OrgHeaderexpanded = (props) => {
? ""
: selectedOrganization.sso_config.sso_certificate
);
const [SSORequired, setSSORequired] = React.useState(selectedOrganization.sso_config === undefined
? false
: selectedOrganization.sso_config.SSORequired === undefined
? false
: selectedOrganization.sso_config.SSORequired);
const [notificationWorkflow, setNotificationWorkflow] = React.useState(
selectedOrganization.defaults === undefined
@@ -121,7 +126,7 @@ const OrgHeaderexpanded = (props) => {
selectedOrganization.defaults.notification_workflow.length === 0
? ""
: selectedOrganization.defaults.notification_workflow
)
);
const [documentationReference, setDocumentationReference] = React.useState(
selectedOrganization.defaults === undefined
@@ -304,171 +309,9 @@ const OrgHeaderexpanded = (props) => {
</Tooltip>
);
const getAppIDs = async (appList) => {
fetch(globalUrl + "/api/v1/apps", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
}).then((response) => {
if (response.status !== 200) {
toast("Failed getting app ids: ", response.reason);
console.log("Status not 200 for app ids :O!");
return;
}
return response.json();
}).then((responseJson) => {
if (responseJson !== undefined) {
// console.log("App ids: ", responseJson)
// console.log("App list: ", appList)
const filteredApps = responseJson.filter(app => appList.includes(app.name));
const appDetails = filteredApps.map(app => ({ name: app.name, id: app.id }));
return appDetails
// console.log("App IDs: ", appDetails)
}
}).catch((error) => {
console.log("Error getting app ids: " + error);
})
}
const generateNotificationWorkflow = async (appname,appImage,appAuthId,projectId,issuetype) => {
//currently only supports JIRA figure out a way to support more apps
var workflowName = `[GENERATED] ${appname} notification workflow`
var workflowDescription = "Generated by Shuffle for sending info/error notifications."
var data = {
"name": workflowName,
"description": workflowDescription,
}
fetch(globalUrl + "/api/v1/workflows", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(data),
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
toast("Failed setting notification workflow: ", response.reason);
console.log("Status not 200 for workflows :O!");
return;
}
return response.json();
}).then((responseJson)=>{
if (responseJson !== undefined) {
console.log("Notification workflow created successfully")
var workflow_id = responseJson.id
if (appname.toLowerCase() === "jira"){
console.log("updating workflow for JIRA")
var workflowBody = {
"name": workflowName,
"Description": workflowDescription,
"id": workflow_id,
"actions": [
{
"app_name": "Jira",
"name": "post_create_issue",
"authentication_id":appAuthId,
"large_image":appImage,
"isStartNode": true,
"label": "create_issue",
"app_version": "1.1.0",
"parameters": [
{
"name": "body",
"value": `{"fields": { "project": {"key": "${projectId}"},"summary": "$exec.title","issuetype": {"name": "${issuetype}"},"description": {"content": [{"content":[{"type":"text","text":"$exec.description"}],"type": "paragraph"}],"type": "doc","version": 1}}}`
},
{
"name": "username_basic",
"value": ""
},
{
"name": "password_basic",
"value": ""
},
{
"name": "url",
"value": ""
},
{
"name": "headers",
"value": "Content-type=application/json \nAccept=application/json"
},
{
"name": "queries",
"value": ""
},
{
"name": "ssl_verify",
"value": "False"
}
]
}
]
}
}
fetch(globalUrl + `/api/v1/workflows/${workflow_id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(workflowBody),
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
toast("Failed setting notification workflow: ", response.reason);
console.log("Status not 200 for workflows :O!");
return;
}
return response.json();
}).then((responseJson)=>{
if (responseJson !== undefined) {
handleEditOrg(
orgName,
orgDescription,
selectedOrganization.id,
selectedOrganization.image,
{
app_download_repo: appDownloadUrl,
app_download_branch: appDownloadBranch,
workflow_download_repo: workflowDownloadUrl,
workflow_download_branch: workflowDownloadBranch,
notification_workflow: workflow_id,
documentation_reference: documentationReference,
},
{
sso_entrypoint: ssoEntrypoint,
sso_certificate: ssoCertificate,
client_id: openidClientId,
client_secret: openidClientSecret,
openid_authorization: openidAuthorization,
openid_token: openidToken,
}
)
console.log("Notification workflow updated successfully")
toast("Notification workflow updated successfully")
}
})
}
}).catch((error) => {
console.log("Error setting workflows: " + error);
})
}
const toggleBetweenRequiredOrOptional = (event) => {
setSSORequired(event.target.checked);
};
return (
<div style={{ textAlign: "center" }}>
@@ -659,8 +502,23 @@ const generateNotificationWorkflow = async (appname,appImage,appAuthId,projectId
/>
</span>
</Grid>
{isCloud ? null :
<Grid item xs={12} style={{marginTop: 50 }}>
{/* {isCloud ? null : */}
<div style={{ display: 'flex', flexDirection: 'column', marginTop: 20, marginLeft: 10, width: '100%', borderBottom: '1px solid #414347' }}>
<div>
<Switch
checked={SSORequired}
onChange={toggleBetweenRequiredOrOptional}
name="onOffSwitch"
color="primary"
title="Make SAML SSO or OpenID Authentication Required or Optional for Your Organization"
/>
{SSORequired ? 'Required' : 'Optional'}
</div>
<Typography variant="body2" style={{ margin: '5px 0px 5px 10px' }}>Make SAML SSO or OpenID Authentication Required or Optional for Your Organization.</Typography>
</div>
<div>
</div>
<Grid item xs={12} style={{}}>
<Typography variant="h4" style={{ textAlign: "center", }}>OpenID connect</Typography>
<Grid container style={{ marginTop: 10, }}>
<Grid item xs={6} style={{}}>
@@ -813,7 +671,7 @@ const generateNotificationWorkflow = async (appname,appImage,appAuthId,projectId
</Grid>
</Grid>
</Grid>
}
{/* } */}
{/*isCloud ? null : */}
<Grid item xs={12} style={{ marginTop: 50, }}>
<Typography variant="h4" style={{ textAlign: "center", }}>SAML SSO (v1.1)</Typography>
+32 -5
View File
@@ -1558,6 +1558,17 @@ const ParsedAction = (props) => {
*/
}
if (selectedAction.name === "custom_action" && data.name === "body") {
for (var key in selectedActionParameters) {
const param = selectedActionParameters[key]
if (param.name === "method") {
if (param.value === "GET") {
return null
}
}
}
}
if (data.name.startsWith("${") && data.name.endsWith("}")) {
const paramcheck = selectedAction.parameters.find((param) => param.name === "body");
@@ -2678,8 +2689,6 @@ const ParsedAction = (props) => {
/*<div style={{width: 17, height: 17, borderRadius: 17 / 2, backgroundColor: itemColor, marginRight: 10, marginTop: 2, marginTop: "auto", marginBottom: "auto",}}/>*/
}
//console.log(data.configuration)
const buttonTitle = `Authenticate ${selectedApp.name.replaceAll("_", " ")}`
const hasAutocomplete = data.autocompleted === true
return (
@@ -3007,7 +3016,9 @@ const ParsedAction = (props) => {
a.category_label !== undefined && a.category_label !== null && a.category_label.length > 0).concat(sortByKey(selectedApp.actions, "label"))
).sort(sortByCategoryLabel))
var baselabel = selectedAction.label;
const selectedAppIcon = selectedAction.large_image
var baselabel = selectedAction.label
return (
<div style={appApiViewStyle} id="parsed_action_view">
@@ -3015,13 +3026,29 @@ const ParsedAction = (props) => {
<span>
<div style={{ display: "flex", minHeight: 40, marginBottom: 30 }}>
<div style={{ flex: 1 }}>
<h3 style={{ marginBottom: 5 }}>
<div style={{ display: "flex", }}
onClick={() => {
//window.open("/apps/${selectedAction.app_id}", "_blank")
}}
>
<Tooltip title={"App: "+selectedAction.app_name} placement="top">
<img src={selectedAppIcon} style={{
width: 30,
height: 30,
marginRight: 10,
borderRadius: 5,
marginTop: 13,
border: "2px solid rgba(255,255,255,0.3)",
}} />
</Tooltip>
<h3 style={{ }}>
{(
selectedAction.app_name.charAt(0).toUpperCase() +
selectedAction.app_name.substring(1)
).replaceAll("_", " ")}
</h3>
<div style={{display: "flex", marginTop: 10, }}>
</div>
<div style={{display: "flex", marginTop: 0, }}>
<IconButton
style={{
marginTop: "auto",
+58 -4
View File
@@ -24,8 +24,9 @@ const Priorities = (props) => {
const [showDismissed, setShowDismissed] = React.useState(false);
const [showRead, setShowRead] = React.useState(false);
const [appFramework, setAppFramework] = React.useState({});
const [selectedWorkflow, setSelectedWorkflow] = React.useState("");
const [selectedExecutionId, setSelectedExecutionId] = React.useState("");
const [selectedWorkflow, setSelectedWorkflow] = React.useState("NO HIGHLIGHT");
const [selectedExecutionId, setSelectedExecutionId] = React.useState("NO HIGHLIGHT");
let navigate = useNavigate();
useEffect(() => {
@@ -86,6 +87,44 @@ const Priorities = (props) => {
})
}
const clearNotifications = () => {
// Don't really care about the logout
toast("Clearing notifications")
fetch(`${globalUrl}/api/v1/notifications/clear`, {
credentials: "include",
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(function (response) {
if (response.status !== 200) {
console.log("Error in response");
}
return response.json();
})
.then(function (responseJson) {
if (responseJson.success === true) {
// Reload the UI
const newNotifications = notifications.map((notification) => {
notification.read = true
return notification
})
setNotifications(newNotifications)
setShowRead(true)
} else {
toast("Failed dismissing notifications. Please try again later.");
}
})
.catch((error) => {
console.log("error in notification dismissal: ", error);
//removeCookie("session_token", {path: "/"})
});
};
const dismissNotification = (alert_id, disabled) => {
var notificationurl = `${globalUrl}/api/v1/notifications/${alert_id}/markasread`
if (disabled === true) {
@@ -178,7 +217,7 @@ const Priorities = (props) => {
var orgId = "";
const highlighted = data.reference_url === undefined || data.reference_url === null || data.reference_url.length === 0 ? false : data.reference_url.includes(selectedExecutionId) || data.reference_url.includes(selectedWorkflow)
const highlighted = selectedExecutionId === "" && selectedWorkflow === "" ? false : data.reference_url === undefined || data.reference_url === null || data.reference_url.length === 0 ? false : data.reference_url.includes(selectedExecutionId) || data.reference_url.includes(selectedWorkflow)
if (userdata.orgs !== undefined) {
const foundOrg = userdata.orgs.find((org) => org.id === data["org_id"]);
@@ -351,12 +390,27 @@ const Priorities = (props) => {
</a>
</span>
<div/>
<div style={{display: "flex", marginTop: 10, marginBottom: 10, }}>
<Switch
checked={showRead}
onChange={() => {
setShowRead(!showRead);
}}
/>&nbsp; Show read
/><span style={{marginTop: 5, }}>&nbsp; Show read </span>
{notifications !== undefined && notifications !== null && notifications.length > 1 ? (
<Button
color="primary"
variant="outlined"
disabled={notifications.filter((data) => !data.read).length === 0}
onClick={() => {
clearNotifications()
}}
style={{marginLeft: 50, }}
>
Mark all as read
</Button>
) : null}
</div>
{notifications === null || notifications === undefined || notifications.length === 0 ? null :
<div>
{notifications.map((notification, index) => {
+1 -2
View File
@@ -23,6 +23,7 @@ import {
DialogTitle,
DialogContent,
} from '@mui/material';
import Mousetrap from 'mousetrap';
import {
@@ -31,7 +32,6 @@ import {
import { Search as SearchIcon, Close as CloseIcon, Folder as FolderIcon, Code as CodeIcon, LibraryBooks as LibraryBooksIcon } from '@mui/icons-material'
import KeyboardCommandKeyIcon from '@mui/icons-material/KeyboardCommandKey';
import algoliasearch from 'algoliasearch/lite';
import aa from 'search-insights'
import { InstantSearch, Configure, connectSearchBox, connectHits, Index } from 'react-instantsearch-dom';
//import { InstantSearch, SearchBox, Hits, connectSearchBox, connectHits, Index } from 'react-instantsearch-dom';
@@ -42,7 +42,6 @@ const chipStyle = {
backgroundColor: "#3d3f43", height: 30, marginRight: 5, paddingLeft: 5, paddingRight: 5, height: 28, cursor: "pointer", borderColor: "#3d3f43", color: "white",
}
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
const SearchField = props => {
const { serverside, userdata, isMobile, isLoaded, globalUrl, isHeader, isLoggedIn, small, rounded } = props
+2 -2
View File
@@ -48,8 +48,8 @@ const data = [
css: {
label: "data(label)",
shape: "roundrectangle",
"height": "16px",
"width": "120px",
"height": "18px",
"width": "145px",
"background-color": "#212121",
"border-color": "#81c784",
"z-index": 10000,
+2 -2
View File
@@ -34,7 +34,7 @@ const theme = createTheme(adaptV4Theme({
//jsonTheme: "tomorrow",
jsonIconStyle: "round",
jsonTheme: "summerfruit",
jsonCollapseStringsAfterLength: 75,
jsonCollapseStringsAfterLength: 100,
reactJsonStyle: {
padding: 5,
@@ -65,7 +65,7 @@ const theme = createTheme(adaptV4Theme({
defaultImage: "/images/no_image.png",
},
typography: {
fontFamily: `"Roboto", "Helvetica", "Arial", sans-serif`,
fontFamily: `"Roboto", "Helvetica", "Arial", "inter", sans-serif`,
useNextVariants: true,
h1: {
fontSize: 40,
+7 -1
View File
@@ -1430,6 +1430,8 @@ If you're interested, please let me know a time that works for you, or set up a
}
// Just use this one?
localStorage.setItem("globalUrl", "");
localStorage.setItem("getting_started_sidebar", "open");
fetch(`${globalUrl}/api/v1/orgs/${orgId}`, {
method: "GET",
@@ -1440,6 +1442,10 @@ If you're interested, please let me know a time that works for you, or set up a
})
.then((response) => {
if (response.status === 401) {
} else {
localStorage.removeItem("apps")
localStorage.removeItem("workflows")
localStorage.removeItem("userinfo")
}
return response.json();
@@ -1728,7 +1734,7 @@ If you're interested, please let me know a time that works for you, or set up a
// Horrible frontend fix for environments
const setDefaultEnvironment = (environment) => {
// FIXME - add more checks to this
toast("Setting default env to " + environment.name);
toast("Changing default env")
var newEnv = [];
for (var key in environments) {
if (environments[key].id == environment.id) {
+164 -48
View File
@@ -9,7 +9,7 @@ import { makeStyles, } from "@mui/styles";
import WorkflowTemplatePopup from "../components/WorkflowTemplatePopup.jsx"
import { v4 as uuidv4 } from "uuid";
import { useNavigate, Link, useParams } from "react-router-dom";
import { useBeforeunload } from "react-beforeunload";
import { useBeforeunload } from "react-beforeunload"
import ReactJson from "react-json-view";
import { NestedMenuItem } from 'mui-nested-menu';
import Markdown from "react-markdown";
@@ -642,22 +642,21 @@ const AngularWorkflow = (defaultprops) => {
"field_id": "",
})
// Event for making sure app is correct
useEffect(() => {
if (selectedApp === undefined || selectedApp === null && selectedApp.app_name === undefined) {
const [loadedApps, setLoadedApps] = React.useState([])
const loadAppConfig = (appId, select) => {
if (appId === undefined || appId === null || appId.length === 0) {
return
}
if (apps === undefined || apps === null || apps.length === 0) {
if (loadedApps.includes(appId)) {
return
}
// Handle the activation case, as they are NOT in the event management system yet
if (selectedApp.actions === undefined || selectedApp.actions === null || selectedApp.actions.length > 1) {
return
} else {
if (selectedApp.id !== undefined && selectedApp.id !== null && selectedApp.id.length > 0) {
const appUrl = `${globalUrl}/api/v1/apps/${selectedApp.id}/config?openapi=false`
loadedApps.push(appId)
setLoadedApps(loadedApps)
const appUrl = `${globalUrl}/api/v1/apps/${appId}/config?openapi=false`
fetch(appUrl, {
headers: {
Accept: "application/json",
@@ -668,11 +667,23 @@ const AngularWorkflow = (defaultprops) => {
return response.json()
})
.then((responseJson) => {
console.log("Loaded app config: ", responseJson)
if (responseJson.success === true && responseJson.app !== undefined && responseJson.app !== null && responseJson.app.length > 0) {
// Base64 decode into json
const foundapp = JSON.parse(atob(responseJson.app))
if (foundapp.actions !== undefined && foundapp.actions !== null && foundapp.actions.length > selectedApp.actions.length) {
console.log("Checked app: ", foundapp)
const selectedAppActions = selectedApp.actions === undefined || selectedApp.actions === null ? [] : selectedApp.actions
if (foundapp.actions !== undefined && foundapp.actions !== null && foundapp.actions.length > selectedAppActions.length) {
if (select) {
setSelectedApp(foundapp)
}
if (apps === undefined || apps === null || apps.length === 0) {
console.log("LOAD APPS!")
}
for (var i = 0; i < apps.length; i++) {
if (apps[i].id !== foundapp.id) {
@@ -693,9 +704,26 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
console.log(`Failed side-loading app ${selectedApp.name}`)
console.log(`Failed side-loading app ${appId}: ${error}`)
})
}
// Event for making sure app is correct
useEffect(() => {
if (selectedApp === undefined || selectedApp === null && selectedApp.app_name === undefined) {
return
}
if (apps === undefined || apps === null || apps.length === 0) {
return
}
// Handle the activation case, as they are NOT in the event management system yet
if (selectedApp.actions === undefined || selectedApp.actions === null || selectedApp.actions.length > 1) {
return
} else {
if (selectedApp.id !== undefined && selectedApp.id !== null && selectedApp.id.length > 0) {
loadAppConfig(selectedApp.id, true)
}
}
@@ -705,7 +733,6 @@ const AngularWorkflow = (defaultprops) => {
continue
}
console.log("Found app: ", curapp)
if (curapp.actions !== undefined && curapp.actions !== null && curapp.actions.length > selectedApp.actions.length) {
var foundActionIndex = -1
for (let actionkey in curapp.actions) {
@@ -1128,6 +1155,8 @@ const AngularWorkflow = (defaultprops) => {
"autoClose": false,
})
} else {
if (refresh === true) {
getAppAuthentication(true, true, true)
@@ -1138,6 +1167,13 @@ const AngularWorkflow = (defaultprops) => {
setAuthenticationModalOpen(false)
// Needs a refresh with the new authentication..
//toast("Successfully saved new app auth")
if (configureWorkflowModalOpen === true) {
setConfigureWorkflowModalOpen(false)
setTimeout(() => {
setConfigureWorkflowModalOpen(true)
}, 1000)
}
}
})
.catch((error) => {
@@ -1179,7 +1215,6 @@ const AngularWorkflow = (defaultprops) => {
if (tmpView !== undefined && tmpView !== null && tmpView.length > 0) {
// Don't clean up if it's already open
if (executionModalOpen === true) {
console.log("Execution modal already open, not cleaning up")
return
}
@@ -3221,8 +3256,9 @@ const AngularWorkflow = (defaultprops) => {
responseJson.errors.length > 0
) {
console.log("Setting configure Modal to open")
setConfigureWorkflowModalOpen(true);
}
setConfigureWorkflowModalOpen(true)
}
}
})
@@ -3777,8 +3813,21 @@ const AngularWorkflow = (defaultprops) => {
if (data.buttonType == "ACTIONSUGGESTION") {
const attachedToId = data.attachedTo
const parentitem = cy.getElementById(data.attachedTo).data()
const parentitemRaw = cy.getElementById(data.attachedTo)
const parentitem = parentitemRaw.data()
if (parentitem !== null && parentitem !== undefined) {
setTimeout(() => {
parentitemRaw.select()
const allNodes = cy.nodes().jsons()
for (var _key in allNodes) {
const currentNode = allNodes[_key]
if (currentNode.data.buttonType === "ACTIONSUGGESTION") {
cy.getElementById(currentNode.data.id).remove()
}
}
}, 100)
const findaction = data.label
console.log("CLICKED: ", findaction, apps.length)
@@ -4262,6 +4311,16 @@ const AngularWorkflow = (defaultprops) => {
curaction.app_id = curapp.id
if (curapp.authentication === undefined || curapp.authentication === null) {
setAuthenticationType({
type: "",
})
curapp.authentication = {
type: "",
required: false,
}
} else {
setAuthenticationType(
curapp.authentication.type === "oauth2-app" || (curapp.authentication.type === "oauth2" && curapp.authentication.redirect_uri !== undefined && curapp.authentication.redirect_uri !== null) ? {
type: curapp.authentication.type,
@@ -4276,6 +4335,7 @@ const AngularWorkflow = (defaultprops) => {
type: "",
}
)
}
const requiresAuth = curapp.authentication.required; //&& ((curapp.authentication.parameters !== undefined && curapp.authentication.parameters !== null) || (curapp.authentication.type === "oauth2" && curapp.authentication.redirect_uri !== undefined && curapp.authentication.redirect_uri !== null))
setRequiresAuthentication(requiresAuth);
@@ -5855,15 +5915,15 @@ const AngularWorkflow = (defaultprops) => {
};
const addActionSuggestions = (nodedata, event) => {
console.log("App Action suggestions disabled for now")
return
console.log("App Action suggestions being added")
if (nodedata.type !== "ACTION") {
return
}
var parentNode = cy.$("#" + event.target.data("id"));
if (parentNode.data("isButton") || parentNode.data("buttonId")) return;
var parentNode = cy.$("#" + event.target.data("id"))
if (parentNode.data("isButton") || parentNode.data("buttonId")) {
return
}
const px = parentNode.position("x") + 0;
const py = parentNode.position("y") + 100;
@@ -5887,6 +5947,8 @@ const AngularWorkflow = (defaultprops) => {
// 1. Find the app
// 2. Loop the apps' actions
// 3. Find actions based on category label IF it exists
console.log("Fidning app match for: ", parentname)
var added = 0
for (let appKey in apps) {
const curapp = apps[appKey]
@@ -5898,6 +5960,7 @@ const AngularWorkflow = (defaultprops) => {
continue
}
console.log("Found matching: ", curapp.name, parentname, curapp.actions.length)
for (let actionKey in curapp.actions) {
const curaction = curapp.actions[actionKey]
@@ -5907,6 +5970,7 @@ const AngularWorkflow = (defaultprops) => {
}
if (curaction.category_label !== undefined && curaction.category_label !== null && curaction.category_label.length > 0) {
console.log("IN NODE ADD")
cy.add({
group: "nodes",
@@ -5925,7 +5989,7 @@ const AngularWorkflow = (defaultprops) => {
})
added += 1
if (added >= 2) {
if (added >= 3) {
break
}
}
@@ -6182,7 +6246,6 @@ const AngularWorkflow = (defaultprops) => {
cytoscapeElement.style.cursor = "pointer"
}
sendStreamRequest({
"item": "node",
"type": "hover",
@@ -6268,7 +6331,8 @@ const AngularWorkflow = (defaultprops) => {
for (var _key in allNodes) {
const currentNode = allNodes[_key];
// console.log("CURRENT NODE: ", currentNode)
if ((currentNode.data.isButton || currentNode.data.isSuggestion) && currentNode.data.attachedTo !== nodedata.id) {
if ((currentNode.data.buttonType === "ACTIONSUGGESTION" || currentNode.data.isButton || currentNode.data.isSuggestion) && currentNode.data.attachedTo !== nodedata.id) {
cy.getElementById(currentNode.data.id).remove();
}
@@ -6320,6 +6384,10 @@ const AngularWorkflow = (defaultprops) => {
//"cursor": "pointer",
}
if (nodedata.buttonType === "ACTIONSUGGESTION") {
parsedStyle["font-size"] = "18px"
}
const typeIds = cy.elements('node:selected').jsons();
for (var idkey in typeIds) {
const item = typeIds[idkey]
@@ -7149,6 +7217,7 @@ const AngularWorkflow = (defaultprops) => {
cy.edgehandles({
handleNodes: (el) => {
if (el.isNode() &&
el.data("buttonType") != "ACTIONSUGGESTION" &&
!el.data("isButton") &&
!el.data("isDescriptor") &&
!el.data("isSuggestion") &&
@@ -8342,7 +8411,6 @@ const AngularWorkflow = (defaultprops) => {
newAppStyle.borderLeft = `${pixelSize} solid ${yellow}`;
}
return (
<Draggable
onDrag={(e) => {
@@ -8361,8 +8429,17 @@ const AngularWorkflow = (defaultprops) => {
<Paper
square
style={newAppStyle}
onMouseOver={() => {
setHover(true);
onMouseOver={(e) => {
e.preventDefault()
e.stopPropagation()
setHover(true)
if (app.actions !== undefined && app.actions !== null && app.actions.length === 1) {
console.log("HOVERING: ", app.id)
loadAppConfig(app.id, false)
}
}}
onMouseOut={() => {
setHover(false);
@@ -8784,6 +8861,7 @@ const AngularWorkflow = (defaultprops) => {
const CustomSearchBox = connectSearchBox(SearchBox)
const CustomAppHits = connectHits(AppHits)
var viewedApps = []
return (
<div style={appViewStyle}>
<div style={{ flex: "1" }}>
@@ -8839,6 +8917,12 @@ const AngularWorkflow = (defaultprops) => {
return null
}
if (viewedApps.includes(app.id)) {
return null
}
viewedApps.push(app.id)
var extraMessage = ""
if (index == 2) {
extraMessage = <div style={{ marginTop: 5 }} />
@@ -14217,7 +14301,8 @@ const AngularWorkflow = (defaultprops) => {
right: 0,
left: isMobile ? 20 : leftBarSize + 20,
top: isMobile ? 30 : appBarSize + 20,
};
pointerEvents: "none",
}
@@ -14235,11 +14320,16 @@ const AngularWorkflow = (defaultprops) => {
return (
<div style={topBarStyle}>
<div style={{ margin: "0px 10px 0px 10px" }}>
<div style={{
margin: "0px 10px 0px 10px",
pointerEvents: "none",
}}>
<Breadcrumbs
aria-label="breadcrumb"
separator="›"
style={{ color: "white" }}
style={{
color: "white"
}}
>
<Link
to="/workflows"
@@ -14255,7 +14345,10 @@ const AngularWorkflow = (defaultprops) => {
Workflows
</h2>
</Link>
<h2 style={{ margin: 0 }}>{workflow.name}</h2>
<h2 style={{
margin: 0,
pointerEvents: "none",
}}>{workflow.name}</h2>
</Breadcrumbs>
{isCorrectOrg ? null :
@@ -14282,7 +14375,9 @@ const AngularWorkflow = (defaultprops) => {
if (response.status !== 200) {
console.log("Error in response");
} else {
localStorage.setItem("apps", [])
localStorage.removeItem("apps")
localStorage.removeItem("workflows")
localStorage.removeItem("userinfo")
}
return response.json();
@@ -15939,7 +16034,6 @@ const AngularWorkflow = (defaultprops) => {
};
const handleReactJsonClipboard = (copy) => {
console.log("COPY: ", copy);
const elementName = "copy_element_shuffle";
var copyText = document.getElementById(elementName);
@@ -17270,10 +17364,9 @@ const AngularWorkflow = (defaultprops) => {
? "red"
: yellow;
const validate = ! codeModalOpen? "" : validateJson(selectedResult.result.trim());
const validate = !codeModalOpen ? "" : validateJson(selectedResult.result.trim())
if (validate.valid && typeof validate.result === "string") {
validate.result = JSON.parse(validate.result);
validate.result = JSON.parse(validate.result)
}
const AppResultVariable = ({ data }) => {
@@ -17381,7 +17474,6 @@ const AngularWorkflow = (defaultprops) => {
if (stringbody.length > 1000) {
return "Body looks to be big in a standard format. Consider using the 'To File' parameter to automatically make it into a file."
}
} else {
}
}
@@ -17405,10 +17497,19 @@ const AngularWorkflow = (defaultprops) => {
return "Authorization failed (403). The API user most likely doesn't have the correct permissions. Check the body of the result for more information."
}
if (result.status === 404) {
return "The URL, or content of the URL is incorrect. Check it and try again."
}
if (result.status === 400) {
return "The queries or data sent to the API is most likely wrong (400). Check the body of the result for more information."
}
if (result.status === 200 || result.status === 201 || result.status === 204) {
return "It looks like the result was successful! If it didn't work, make sure to check if the body you are sending was correct."
}
// Validate and check for newlines
if (result.success !== false) {
@@ -17425,7 +17526,7 @@ const AngularWorkflow = (defaultprops) => {
}
}
return ""
//return ""
}
@@ -17447,13 +17548,14 @@ const AngularWorkflow = (defaultprops) => {
return "Consider whether your Orborus environment can connect to a local IP or not."
}
if (stringjson.includes("connectionerror")) {
if (stringjson.includes("kms")) {
return "KMS authentication failed. Check your notifications for more details."
if (stringjson.includes("invalidurl")) {
// IF count of "http" is more than one, 1, it's prolly invalid
var additionalinfo = ""
if (stringjson.includes("http") && stringjson.match(/http/g).length > 1) {
additionalinfo = "You may be using multiple 'http' in the URL. "
}
return "Your URL is incorrect."
return "The URL is invalid. Change the URL to a valid one, and try again. "+additionalinfo
}
if (stringjson.includes("result too large to handle")) {
@@ -17469,6 +17571,15 @@ const AngularWorkflow = (defaultprops) => {
}
if (stringjson.includes("connectionerror")) {
if (stringjson.includes("kms")) {
return "KMS authentication failed. Check your notifications for more details."
}
return "The URL is incorrect, or Shuffle can't reach it. Set up a Shuffle Environment in the same VLAN, or whitelist Shuffle's IPs."
}
return ""
}
@@ -17706,7 +17817,7 @@ const AngularWorkflow = (defaultprops) => {
{currentSuggestion.length > 0 ?
<div style={{ marginBottom: 5 }}>
<b style={{color: "rgba(214,110,117)", }}>Debug Info:</b> {currentSuggestion}
<b style={{color: "rgba(214,110,117)", }}>Debug:</b> {currentSuggestion}
</div>
:
<div style={{ marginBottom: 5 }}>
@@ -18381,9 +18492,14 @@ const AngularWorkflow = (defaultprops) => {
selectedAction.authentication === undefined ||
selectedAction.authentication === null
) {
selectedAction.authentication = [authenticationOption];
selectedAction.authentication = [authenticationOption]
} else {
selectedAction.authentication.push(authenticationOption);
try {
selectedAction.authentication.push(authenticationOption)
} catch (e) {
//console.log("Error: ", e)
}
}
setSelectedAction(selectedAction);
@@ -19647,7 +19763,7 @@ const AngularWorkflow = (defaultprops) => {
}
}
const foundusecase.name === undefined || foundusecase.name === null || foundusecase.name === "" ? null :
const templatePopup = foundusecase.name === undefined || foundusecase.name === null || foundusecase.name === "" ? null :
<Slide direction="down" in={true} mountOnEnter unmountOnExit>
<div style={{position: "fixed", top: "10%", left: "37%", border: "1px solid rgba(255,255,255,0.3)", backgroundColor: theme.palette.inputColor, borderRadius: theme.palette.borderRadius, display: "flex", }}>
<WorkflowTemplatePopup
+3 -5
View File
@@ -427,7 +427,7 @@ const UsecaseListComponent = (props) => {
return (
<Grid id={fixedName} item xs={selectedItem ? 12 : 4} key={subindex} style={{minHeight: 110,}} onClick={() => {
if (fixedName === "increase authentication") {
if (fixedName === "reporting") {
getUsecase(subcase, index, subindex)
return
}
@@ -1192,8 +1192,7 @@ const Dashboard = (props) => {
navigate(curpath + newitem)
}
/*
const baseItem = document.getElementById("increase authentication")
const baseItem = document.getElementById("reporting")
if (baseItem !== undefined && baseItem !== null) {
baseItem.click()
@@ -1206,7 +1205,6 @@ const Dashboard = (props) => {
// Scroll back to top
window.scrollTo(0, 0)
}
*/
const foundQuery2 = params["selected_object"]
if (foundQuery2 !== null && foundQuery2 !== undefined) {
@@ -1231,7 +1229,7 @@ const Dashboard = (props) => {
} else {
//console.log("Couldn't find item with name ", queryName)
}
}, 1000);
}, 1000)
}
}
+1 -1
View File
@@ -1186,7 +1186,7 @@ const Workflows = (props) => {
}
}
if (newarray.length > 0 && storageWorkflows.length <= newarray.length) {
if (newarray.length > 0) {
try {
localStorage.setItem("workflows", JSON.stringify(newarray))
} catch (e) {