diff --git a/.env b/.env
index 4bd36483..f574d03d 100755
--- a/.env
+++ b/.env
@@ -59,9 +59,9 @@ SHUFFLE_ORBORUS_STARTUP_DELAY= # Used for setting up a startup delay for Orbor
SHUFFLE_SKIPSSL_VERIFY=true
IS_KUBERNETES=false # Used for controlling if the environment should run in kubernetes or not
-SHUFFLE_BASE_IMAGE_NAME=shuffle
-SHUFFLE_BASE_IMAGE_REGISTRY=ghcr.io
-SHUFFLE_BASE_IMAGE_TAG_SUFFIX="-1.3.1"
+#SHUFFLE_BASE_IMAGE_NAME=shuffle
+#SHUFFLE_BASE_IMAGE_REGISTRY=ghcr.io
+#SHUFFLE_BASE_IMAGE_TAG_SUFFIX="-1.3.1"
# The eth0 interface inside a container corresponds
# to the virtual Ethernet interface that connects
diff --git a/backend/app_sdk/app_base.py b/backend/app_sdk/app_base.py
index 9e90ec62..538d3afe 100755
--- a/backend/app_sdk/app_base.py
+++ b/backend/app_sdk/app_base.py
@@ -466,8 +466,8 @@ class AppBase:
"success": True,
"status": request.status_code,
"url": request.url,
- "headers": parsedheaders,
"body": jsondata,
+ "headers": parsedheaders,
"cookies":cookies,
})
except Exception as e:
diff --git a/frontend/src/components/Header.jsx b/frontend/src/components/Header.jsx
index dbf68fe2..4f1d47ef 100644
--- a/frontend/src/components/Header.jsx
+++ b/frontend/src/components/Header.jsx
@@ -615,7 +615,7 @@ const { globalUrl, setNotifications, notifications, isLoggedIn, removeCookie, ho
-
+
diff --git a/frontend/src/components/NewHeader.jsx b/frontend/src/components/NewHeader.jsx
index 558d0c72..c0cf173d 100644
--- a/frontend/src/components/NewHeader.jsx
+++ b/frontend/src/components/NewHeader.jsx
@@ -741,7 +741,7 @@ const Header = (props) => {
>
-
+
{
-
+
{
},
"fields": parsedFields,
"type": "oauth2-app",
- "reference_workflow": workflowId,
+ //"reference_workflow": workflowId,
}
if (setNewAppAuth !== undefined) {
diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx
index 68366fe4..7d9f2ac0 100755
--- a/frontend/src/components/ParsedAction.jsx
+++ b/frontend/src/components/ParsedAction.jsx
@@ -1644,13 +1644,11 @@ const ParsedAction = (props) => {
multiline={data.name.startsWith("${") && data.name.endsWith("}") ? true : multiline}
helperText={returnHelperText(data.name, data.value)}
onClick={() => {
- console.log("Clicked field: ", clickedFieldId, data.name)
/*
setExpansionModalOpen(false);
*/
if (setScrollConfig !== undefined && scrollConfig !== null && scrollConfig !== undefined && scrollConfig.selected !== clickedFieldId) {
- console.log("IN SCROLL CONFIG!")
scrollConfig.selected = clickedFieldId
setScrollConfig(scrollConfig)
@@ -3737,6 +3735,11 @@ const ParsedAction = (props) => {
break
}
}
+
+ // Check if it starts with "Get List" and method is "Get"
+ if (params.inputProps.value.startsWith("Get List")) {
+ console.log("Get List")
+ }
}
return (
diff --git a/frontend/src/components/SearchData.jsx b/frontend/src/components/SearchData.jsx
index 10d58c7a..148b5bab 100644
--- a/frontend/src/components/SearchData.jsx
+++ b/frontend/src/components/SearchData.jsx
@@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from 'react';
import theme from '../theme.jsx';
import { useNavigate, Link, useParams } from "react-router-dom";
+import { toast } from "react-toastify"
import {
Chip,
@@ -41,7 +42,7 @@ const chipStyle = {
const searchClient = algoliasearch("JNSS5CFDZZ", "db08e40265e2941b9a7d8f644b6e5240")
const SearchData = props => {
- const { serverside, userdata, setModalOpen, modalOpen } = props
+ const { serverside, globalUrl, userdata, setModalOpen, modalOpen } = props
let navigate = useNavigate();
const borderRadius = 3
const node = useRef()
@@ -326,6 +327,57 @@ const SearchData = props => {
)
}
+ const activateApp = (name, appid, type) => {
+ if (globalUrl === undefined || globalUrl === null) {
+ console.log(`Global URL not set`)
+ return
+ }
+
+ if (name === undefined || name === null) {
+ name = ""
+ }
+
+ name = name.replaceAll("_", " ")
+
+ if (userdata === undefined || userdata === null || userdata.id === undefined) {
+ toast(`You need to be logged in to activate the ${name} app. Redirecting`)
+
+ setTimeout(() => {
+ navigate(`/register?message=You need to be logged in to use the ${name} app.`)
+ }, 500)
+ return
+ }
+
+ const url = `${globalUrl}/api/v1/apps/${appid}/${type}`
+
+ fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ },
+ credentials: "include",
+ })
+ .then((response) => {
+ if (response.status !== 200) {
+ toast(`Failed to ${type} the app for your organization. Please try again or contact support@shuffler.io`)
+ }
+
+ return response.json()
+ })
+ .then((responseJson) => {
+ if (responseJson.success === false) {
+ toast(`Failed to ${type} the app for your organization. Please try again or contact support@shuffler.io for more info`)
+ } else {
+ toast(`App successfully ${type}d. Please refresh the page to use it.`)
+ }
+ })
+ .catch(error => {
+ //toast(error.toString())
+ console.log("Activate app error: ", error.toString())
+ });
+ }
+
const AppHits = ({ hits }) => {
const [mouseHoverIndex, setMouseHoverIndex] = useState(0)
@@ -431,7 +483,6 @@ const SearchData = props => {
return (
{
setSearchOpen(true)
-
setModalOpen(false)
aa('init', {
appId: searchClient.appId,
@@ -474,6 +525,29 @@ const SearchData = props => {
*/}
+ {
+ e.preventDefault()
+ e.stopPropagation()
+
+ console.log("OBJECT CHANGE: ", hit.objectID)
+
+ // This does nothing rofl
+ if (userdata.active_apps === undefined || userdata.active_apps === null) {
+ activateApp(hit.name, hit.objectID, "activate")
+ } else {
+ if (userdata.active_apps.includes(hit.objectID)) {
+ activateApp(hit.name, hit.objectID, "deactivate")
+ } else {
+ activateApp(hit.name, hit.objectID, "activate")
+ }
+ }
+ }}
+ >
+ {userdata.active_apps !== undefined && userdata.active_apps !== null && userdata.active_apps.includes(hit.objectID) ? "Deactivate" : "Activate"}
+
)
diff --git a/frontend/src/components/Searchfield.jsx b/frontend/src/components/Searchfield.jsx
index 4e292661..1652c55d 100644
--- a/frontend/src/components/Searchfield.jsx
+++ b/frontend/src/components/Searchfield.jsx
@@ -98,7 +98,7 @@ const SearchField = props => {
: null}
-
+
diff --git a/frontend/src/components/ShuffleCodeEditor.jsx b/frontend/src/components/ShuffleCodeEditor.jsx
index 0c86d0ee..15aec446 100644
--- a/frontend/src/components/ShuffleCodeEditor.jsx
+++ b/frontend/src/components/ShuffleCodeEditor.jsx
@@ -236,8 +236,6 @@ const CodeEditor = (props) => {
//var newitem = JSON.parse(base);
var newitem = validateJson(base).result
-
-
to_be_copied = "$" + base_node_name.toLowerCase().replaceAll(" ", "_");
for (let copykey in copy.namespace) {
if (copy.namespace[copykey].includes("Results for")) {
@@ -825,7 +823,7 @@ const CodeEditor = (props) => {
console.log("ERR IN INPUT: ", e)
}
- console.log("Got output for: ", fullpath, new_input, actionlist[k].example, typeof new_input)
+ //console.log("Got output for: ", fullpath, new_input, actionlist[k].example, typeof new_input)
if (typeof new_input === "object") {
new_input = JSON.stringify(new_input)
@@ -1078,114 +1076,122 @@ const CodeEditor = (props) => {
*/}
{ isFileEditor ? null :
-
{
- setAnchorEl(event.currentTarget);
- }}
- >
- Filters
-
-
-
{
- setAnchorEl2(event.currentTarget);
- }}
- >
- Math
-
-
-
{
- setAnchorEl3(event.currentTarget);
- }}
- >
- Python
-
-
+ {selectedAction.name === "execute_python" ?
+
+ Run Python Code
+
+ :
+
+ {
+ setAnchorEl(event.currentTarget);
+ }}
+ >
+ Filters
+
+
+ {
+ setAnchorEl2(event.currentTarget);
+ }}
+ >
+ Math
+
+
+ {
+ setAnchorEl3(event.currentTarget);
+ }}
+ >
+ Python
+
+
+
+ }
{
maxHeight: 35,
minWidth: 70,
}}
- variant="contained"
onClick={() => {
executeSingleAction(expOutput)
}}
diff --git a/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx
index 1bacd611..f653bd2c 100755
--- a/frontend/src/views/Admin.jsx
+++ b/frontend/src/views/Admin.jsx
@@ -140,6 +140,11 @@ const Admin = (props) => {
const classes = useStyles();
let navigate = useNavigate();
+ const [logsViewModal, setLogsViewModal] = React.useState(false);
+ const [userLogViewing, setUserLogViewing] = React.useState({});
+ const [ipSelected, setIpSelected] = React.useState("");
+ const [logsLoading, setLogsLoading] = React.useState(true);
+ const [logs, setLogs] = React.useState([]);
const [firstRequest, setFirstRequest] = React.useState(true);
const [orgRequest, setOrgRequest] = React.useState(true);
const [modalUser, setModalUser] = React.useState({});
@@ -3343,6 +3348,111 @@ If you're interested, please let me know a time that works for you, or set up a
backgroundColor: theme.palette.inputColor,
}}
/>
+
+
+ {logsViewModal ?
+ {
+ setLogsViewModal(false);
+ }}
+ PaperProps={{
+ style: {
+ backgroundColor: theme.palette.surfaceColor,
+ color: "white",
+ minWidth: "1200px",
+ minHeight: "320px",
+ },
+ }}
+ >
+
+ User Logs
+
+
+ {/* ask user for which IP they want to see logs for by iterating of user.login_info */}
+
+
+ User IP
+
+
+ {
+ setIpSelected(event.target.value);
+ await getLogs(event.target.value, userLogViewing.id);
+ }}
+ >
+ {(() => {
+ const uniqueIPs = new Set();
+
+ return userLogViewing.login_info.map((data, index) => {
+ if (data.ip.includes("127.0.0.1") || uniqueIPs.has(data.ip)) {
+ return null;
+ }
+
+ uniqueIPs.add(data.ip);
+
+ return (
+
+ {data.ip}
+
+ );
+ });
+ })()}
+
+
+ {logsLoading && ipSelected.length !== 0 ?
+
+
+ Loading logs
+
+ : null}
+
+
+ {logs.map((data, index) => (
+ // redirect user to logs
+ // using request id or trace id
+
+
+
+
+
+
+ ))}
+
+
+
+
+
+ : null}
+
+
+
{users === undefined || users === null
? null
@@ -3418,223 +3529,232 @@ If you're interested, please let me know a time that works for you, or set up a
}
}
- return (
-
-
+ var userData = data.username
+ if (userdata.support === true) {
+ userData = {
+ setLogsViewModal(true)
+ setUserLogViewing(data)
+ }}
+ >{data.username}
+ }
-
- {
- const elementName = "copy_element_shuffle";
- var copyText =
- document.getElementById(elementName);
- if (
- copyText !== null &&
- copyText !== undefined
- ) {
- const clipboard = navigator.clipboard;
- if (clipboard === undefined) {
- toast(
- "Can only copy over HTTPS (port 3443)"
- );
- return;
- }
+ return (
+
+
- navigator.clipboard.writeText(data.apikey);
- copyText.select();
- copyText.setSelectionRange(
- 0,
- 99999
- ); /* For mobile devices */
+
+ {
+ const elementName = "copy_element_shuffle";
+ var copyText =
+ document.getElementById(elementName);
+ if (
+ copyText !== null &&
+ copyText !== undefined
+ ) {
+ const clipboard = navigator.clipboard;
+ if (clipboard === undefined) {
+ toast(
+ "Can only copy over HTTPS (port 3443)"
+ );
+ return;
+ }
- /* Copy the text inside the text field */
- document.execCommand("copy");
+ navigator.clipboard.writeText(data.apikey);
+ copyText.select();
+ copyText.setSelectionRange(
+ 0,
+ 99999
+ ); /* For mobile devices */
- toast("Apikey copied to clipboard");
- }
- }}
- >
-
-
-
- )
- }
- />
+ /* Copy the text inside the text field */
+ document.execCommand("copy");
- {
- console.log("VALUE: ", e.target.value);
- setUser(data.id, "role", e.target.value);
- }}
- style={{
- backgroundColor: theme.palette.surfaceColor,
- color: "white",
- height: "50px",
+ toast("Apikey copied to clipboard");
+ }
}}
>
-
- Org Admin
-
-
- Org User
-
-
- Org Reader
-
-
- }
- style={{ minWidth: 135, maxWidth: 135, marginRight: 15 }}
- />
-
-
-
- {selectedOrganization.child_orgs !== undefined &&
- selectedOrganization.child_orgs !== null &&
- selectedOrganization.child_orgs.length > 0 ? (
-
- ) : null}
-
- {
- setSelectedUserModalOpen(true);
- setSelectedUser(data);
+
+
+
+ )
+ }
+ />
- // Find matching orgs between current org and current user's access to those orgs
- if (
- userdata.orgs !== undefined &&
- userdata.orgs !== null &&
- userdata.orgs.length > 0 &&
- selectedOrganization.child_orgs !== undefined &&
- selectedOrganization.child_orgs !== null &&
- selectedOrganization.child_orgs.length > 0
- ) {
- var active = [];
- for (var key in userdata.orgs) {
- const found =
- selectedOrganization.child_orgs.find(
- (item) => item.id === userdata.orgs[key].id
- );
- if (found !== null && found !== undefined) {
- if (
- data.orgs === undefined ||
- data.orgs === null
- ) {
- continue;
- }
+ {
+ console.log("VALUE: ", e.target.value);
+ setUser(data.id, "role", e.target.value);
+ }}
+ style={{
+ backgroundColor: theme.palette.surfaceColor,
+ color: "white",
+ height: "50px",
+ }}
+ >
+
+ Org Admin
+
+
+ Org User
+
+
+ Org Reader
+
+
+ }
+ style={{ minWidth: 135, maxWidth: 135, marginRight: 15 }}
+ />
+
+
+
+ {selectedOrganization.child_orgs !== undefined &&
+ selectedOrganization.child_orgs !== null &&
+ selectedOrganization.child_orgs.length > 0 ? (
+
+ ) : null}
+
+ {
+ setSelectedUserModalOpen(true);
+ setSelectedUser(data);
- const subfound = data.orgs.find(
- (item) => item === found.id
- );
- if (
- subfound !== null &&
- subfound !== undefined
- ) {
- active.push(subfound);
- }
- }
+ // Find matching orgs between current org and current user's access to those orgs
+ if (
+ userdata.orgs !== undefined &&
+ userdata.orgs !== null &&
+ userdata.orgs.length > 0 &&
+ selectedOrganization.child_orgs !== undefined &&
+ selectedOrganization.child_orgs !== null &&
+ selectedOrganization.child_orgs.length > 0
+ ) {
+ var active = [];
+ for (var key in userdata.orgs) {
+ const found =
+ selectedOrganization.child_orgs.find(
+ (item) => item.id === userdata.orgs[key].id
+ );
+ if (found !== null && found !== undefined) {
+ if (
+ data.orgs === undefined ||
+ data.orgs === null
+ ) {
+ continue;
}
- setMatchingOrganizations(active);
+ const subfound = data.orgs.find(
+ (item) => item === found.id
+ );
+ if (
+ subfound !== null &&
+ subfound !== undefined
+ ) {
+ active.push(subfound);
+ }
}
- }}
- >
-
-
- {/* {
- generateApikey(data)
- }}
- disabled={data.role === "admin" && data.username !== userdata.username}
- variant="outlined"
- color="primary"
- >
- New apikey
- */}
-
-
-
-
- );
- })}
+ }
+
+ setMatchingOrganizations(active);
+ }
+ }}
+ >
+
+
+ {/* {
+ generateApikey(data)
+ }}
+ disabled={data.role === "admin" && data.username !== userdata.username}
+ variant="outlined"
+ color="primary"
+ >
+ New apikey
+ */}
+
+
+
+
+ );
+ })}
) : null;
@@ -4131,6 +4251,46 @@ If you're interested, please let me know a time that works for you, or set up a
) : null;
+ const getLogs = async (ip, userId) => {
+ setLogsLoading(true);
+ console.log("logs loading: ", logsLoading);
+ fetch(`${globalUrl}/api/v1/users/${userId}/audit?user_ip=${ip}`, {
+ mode: "cors",
+ method: "GET",
+ credentials: "include",
+ crossDomain: true,
+ withCredentials: true,
+ headers: {
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ })
+ .then((response) => {
+ return response.json();
+ })
+ .then((responseJson) => {
+ console.log("ResponseJSON: ", responseJson);
+ if (responseJson.success === true) {
+ setLogs(responseJson.logs);
+ } else {
+ if (responseJson.success === false || responseJson.reason !== undefined) {
+ console.log("Reason given: ", responseJson.reason)
+ toast("Failed getting logs: " + responseJson.reason)
+ setLogs([])
+ } else {
+ toast("Failed getting logs");
+ }
+ }
+ console.log("logs loading now: ", logsLoading);
+ setLogsLoading(false);
+ })
+ .catch((error) => {
+ console.log("Error: ", error);
+ toast("Failed getting logs. Please contact: ", error);
+ console.log("logs loading now: ", logsLoading);
+ setLogsLoading(false);
+ });
+ };
+
const changeRecommendation = (recommendation, action) => {
const data = {
action: action,
diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx
index f22ee36b..2f461690 100755
--- a/frontend/src/views/AngularWorkflow.jsx
+++ b/frontend/src/views/AngularWorkflow.jsx
@@ -17,7 +17,7 @@ import { ToastContainer, toast } from "react-toastify"
import { isMobile } from "react-device-detect"
import aa from 'search-insights'
import Drift from "react-driftjs";
-import ShuffleCodeEditor from "../components/ShuffleCodeEditor.jsx";
+import { CodeHandler, Img, OuterLink, } from "../views/Docs.jsx";
import { InstantSearch, Configure, connectSearchBox, connectHits, Index } from 'react-instantsearch-dom';
import algoliasearch from 'algoliasearch/lite';
@@ -116,17 +116,12 @@ import {
AutoAwesome as AutoAwesomeIcon,
} from "@mui/icons-material";
-
import * as cytoscape from "cytoscape";
import * as edgehandles from "cytoscape-edgehandles";
-//import * as clipboard from "cytoscape-clipboard";
-//import undoRedo from "cytoscape-undo-redo";
-//import cxtmenu from "cytoscape-cxtmenu";
import CytoscapeComponent from "react-cytoscapejs";
-
import Draggable from "react-draggable";
-
import cytoscapestyle from "../defaultCytoscapeStyle.jsx";
+import ShuffleCodeEditor from "../components/ShuffleCodeEditor.jsx";
import { validateJson, GetIconInfo } from "../views/Workflows.jsx";
import { GetParsedPaths, internalIds, } from "../views/Apps.jsx";
@@ -842,48 +837,6 @@ const AngularWorkflow = (defaultprops) => {
});
};
- function OuterLink(props) {
- if (props.href.includes("http") || props.href.includes("mailto")) {
- return (
-
- {props.children}
-
- );
- }
- return (
-
- {props.children}
-
- );
- }
-
- function Img(props) {
- return ;
- }
-
- function CodeHandler(props) {
- return (
-
- {props.value}
-
- );
- }
-
function Heading(props) {
const element = React.createElement(
`h${props.level}`,
@@ -1021,8 +974,6 @@ const AngularWorkflow = (defaultprops) => {
return response.json();
})
.then((responseJson) => {
- console.log("GOT A RESPONSE??")
- // getWorkflowExecutionCount(id);
if (responseJson !== undefined && responseJson !== null && responseJson.executions !== undefined && responseJson.executions !== null) {
// - means it's opposite
@@ -1035,8 +986,6 @@ const AngularWorkflow = (defaultprops) => {
tmpView = execution_id;
}
- console.log("EXECUTION ID: ", tmpView)
-
// Compare with currently selected item
if (tmpView !== undefined && tmpView !== null && tmpView.length > 0) {
// Don't clean up if it's already open
@@ -1820,7 +1769,6 @@ const AngularWorkflow = (defaultprops) => {
}
}
- console.log("FOUNDMISSING: ", foundmissing)
if (foundmissing) {
//toast("This workflow contains a node that requires an execution argument. Please provide one.")
setExecutionRequestStarted(false)
@@ -2788,11 +2736,17 @@ const AngularWorkflow = (defaultprops) => {
if (response.status >= 500) {
toast("Something went wrong while loading the workflow. Please reload.")
} else {
- toast("You don't access to this workflow or loading failed. Redirecting to workflows in a few seconds..")
- setTimeout(() => {
- window.location.pathname = "/workflows";
- }, 2000);
+ // Check for execution_id in URL
+ // don't redirect if it exists
+ const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search;
+ var execFound = new URLSearchParams(cursearch).get("execution_id");
+ if (execFound === null) {
+ toast(`You don't access to this workflow or loading failed. Redirecting to workflows in a few seconds..`)
+ setTimeout(() => {
+ window.location.pathname = "/workflows";
+ }, 2000);
+ }
}
}
@@ -8518,8 +8472,6 @@ const AngularWorkflow = (defaultprops) => {
}
if (param.name === "headers") {
- console.log("Swap header? For now, yes. File found: ", fileid_found)
-
if (fileid_found) {
newSelectedAction.parameters[paramkey].value = ""
newSelectedAction.parameters[paramkey].autocompleted = true
@@ -8614,7 +8566,6 @@ const AngularWorkflow = (defaultprops) => {
if (workflow.actions !== undefined && workflow.actions !== null && workflow.actions.length > 0) {
const foundActionIndex = workflow.actions.findIndex(actiondata => actiondata.id === newSelectedAction.id)
- console.log("Found action on index ", foundActionIndex)
if (foundActionIndex >= 0) {
workflow.actions[foundActionIndex] = newSelectedAction
setWorkflow(workflow)
@@ -9444,14 +9395,18 @@ const AngularWorkflow = (defaultprops) => {
bottom: 10,
left: 10,
color: "rgba(255,255,255,0.6)",
+ zIndex: 10000,
}}
>
Conditions can't be used for loops [ .# ]{" "}
Learn more
@@ -15935,7 +15890,10 @@ const AngularWorkflow = (defaultprops) => {
setSelectedResult(data);
setCodeModalOpen(true);
} else {
- toast("Please wait until the workflow is loaded and try again")
+ toast("Please wait until the workflow is loaded and try again")
+ setCodeModalOpen(true)
+ setSelectedResult(data)
+
}
}}
>
@@ -16197,6 +16155,25 @@ const AngularWorkflow = (defaultprops) => {
}}
>
+
+ {
+ e.preventDefault()
+ }}
+ >
+
+
+
{
right: 170,
}}
onClick={(e) => {
- e.preventDefault();
+ e.preventDefault()
- if (workflowExecutions !== null) {
+ if (workflowExecutions !== null) {
for (let execkey in workflowExecutions) {
const execution = workflowExecutions[execkey];
- if (execution.execution_argument.includes("too large")) {
- continue
- }
+ if (execution.execution_argument.includes("too large")) {
+ continue
+ }
const result = execution.results.find((data) => data.status === "SUCCESS" && data.action.id === selectedResult.action.id)
- if (result !== undefined) {
- const oldstartnode = cy.getElementById(selectedResult.action.id);
- if (oldstartnode !== undefined && oldstartnode !== null) {
- const foundname = oldstartnode.data("label")
- if (foundname !== undefined && foundname !== null) {
- result.action.label = foundname
- }
- }
+ if (result !== undefined) {
+ const oldstartnode = cy.getElementById(selectedResult.action.id);
+ if (oldstartnode !== undefined && oldstartnode !== null) {
+ const foundname = oldstartnode.data("label")
+ if (foundname !== undefined && foundname !== null) {
+ result.action.label = foundname
+ }
+ }
- setSelectedResult(result);
- setUpdate(Math.random());
- break;
- }
+ setSelectedResult(result);
+ setUpdate(Math.random());
+ break;
+ }
}
- }
+ }
}}
>
diff --git a/frontend/src/views/AppCreator.jsx b/frontend/src/views/AppCreator.jsx
index 71625903..12e81862 100755
--- a/frontend/src/views/AppCreator.jsx
+++ b/frontend/src/views/AppCreator.jsx
@@ -264,7 +264,7 @@ export const appCategories = [
"name": "IAM",
"color": "#FFC107",
"icon": "iam",
- "action_labels": ["Reset Password", "Enable user", "Disable user", "Get Identity", "Get Asset", "Search Identity", ],
+ "action_labels": ["Reset Password", "Enable user", "Disable user", "Get Identity", "Get Asset", "Search Identity", "Get KMS Key",],
}, {
"name": "Network",
"color": "#FFC107",
@@ -1240,7 +1240,7 @@ const AppCreator = (defaultprops) => {
if (methodvalue.responses.default.content["text/plain"]["schema"]["format"] === "binary" && methodvalue.responses.default.content["text/plain"]["schema"]["type"] === "string") {
newaction.example_response = "shuffle_file_download"
- }
+ }
}
}
}
@@ -2174,6 +2174,10 @@ const AppCreator = (defaultprops) => {
queryitem.name.toLowerCase() == "ssl_verify" ||
queryitem.name.toLowerCase() == "queries" ||
queryitem.name.toLowerCase() == "headers" ||
+ queryitem.name.toLowerCase() == "list" ||
+ queryitem.name.toLowerCase() == "dict" ||
+ queryitem.name.toLowerCase() == "str" ||
+ queryitem.name.toLowerCase() == "int" ||
queryitem.name.toLowerCase() == "access_token") {
/*
@@ -3748,7 +3752,7 @@ const AppCreator = (defaultprops) => {
}}
>
-
+
New action
diff --git a/frontend/src/views/Docs.jsx b/frontend/src/views/Docs.jsx
index 37bcec0a..027aad59 100755
--- a/frontend/src/views/Docs.jsx
+++ b/frontend/src/views/Docs.jsx
@@ -3,10 +3,12 @@ import React, { useEffect, useState } from "react";
import { toast } from 'react-toastify';
import Markdown from 'react-markdown'
+import theme from '../theme.jsx';
+import ReactJson from "react-json-view";
+import { isMobile } from "react-device-detect";
import { BrowserView, MobileView } from "react-device-detect";
import { useParams, useNavigate, Link } from "react-router-dom";
-import { isMobile } from "react-device-detect";
-import theme from '../theme.jsx';
+import { validateJson, GetIconInfo } from "../views/Workflows.jsx";
import {
Grid,
@@ -30,6 +32,7 @@ import {
Edit as EditIcon,
KeyboardArrowRight as KeyboardArrowRightIcon,
ExpandMore as ExpandMoreIcon,
+ FileCopy as FileCopyIcon
} from "@mui/icons-material";
const Body = {
@@ -60,6 +63,120 @@ const innerHrefStyle = {
textDecoration: "none",
};
+
+export const CopyToClipboard = (props) => {
+ const {text, style, onCopy} = props;
+ const parsedstyle = style !== undefined ? style : {
+ position: "absolute",
+ right: 0,
+ top: -10,
+ }
+
+ return (
+
+ {
+ navigator.clipboard.writeText(text);
+ toast("Copied to clipboard")
+ }}
+ >
+
+
+
+ )
+}
+
+export const OuterLink = (props) => {
+ if (props.href.includes("http") || props.href.includes("mailto")) {
+ return (
+
+ {props.children}
+
+ );
+ }
+
+ return (
+
+ {props.children}
+
+ );
+ }
+
+
+export const Img = (props) => {
+ return ;
+}
+
+export const CodeHandler = (props) => {
+ const propvalue = props.value !== undefined && props.value !== null ? props.value : props.children !== undefined && props.children !== null && props.children.length > 0 ? props.children[0] : ""
+
+
+
+ const validate = validateJson(propvalue)
+
+ var newprop = propvalue
+ if (validate.valid === false) {
+ // Check if https://shuffler.io in the url
+ // if so, then we change it for the current url
+ if (propvalue.includes("https://shuffler.io")) {
+ newprop = propvalue.replace("https://shuffler.io", window.location.origin)
+ }
+
+ // Check if it contains Bearer APIKEY
+ // If so, replace apikey
+ //if (newprop.includes("Bearer APIKEY")) {
+ // newprop = newprop.replace("Bearer APIKEY", "Bearer API
+ //}
+ }
+
+ return (
+
+ {validate.valid === true ?
+
+ :
+
+
+ {newprop}
+
+
+
+ }
+
+ )
+}
+
const Docs = (defaultprops) => {
const { globalUrl, selectedDoc, serverside, serverMobile } = defaultprops;
@@ -121,6 +238,123 @@ const Docs = (defaultprops) => {
//height: "50vh",
};
+ const Heading = (props) => {
+ const element = React.createElement(
+ `h${props.level}`,
+ { style: { marginTop: props.level === 1 ? 20 : 50 } },
+ props.children
+ );
+ const [hover, setHover] = useState(false);
+
+ var extraInfo = "";
+ if (props.level === 1) {
+ extraInfo = (
+
+
+ {isMobile ? null : (
+
+
+
+ Edit
+
+
+
+ )}
+ {isMobile ? null : (
+
+ )}
+
+ {selectedMeta.read_time} minute
+ {selectedMeta.read_time === 1 ? "" : "s"} to read
+
+
+
+ {isMobile ||
+ selectedMeta.contributors === undefined ||
+ selectedMeta.contributors === null ? (
+ ""
+ ) : (
+
+ {selectedMeta.contributors.slice(0, 7).map((data, index) => {
+ return (
+
+
+
+
+
+ );
+ })}
+
+ )}
+
+
+ );
+ }
+
+ if (extraInfo !== "" && props.level === 1 && props.children !== undefined && props.children !== null && props.children.length > 0) {
+ if (props.children[0].toLowerCase().includes("privacy") || props.children[0].toLowerCase().includes("terms")) {
+ extraInfo = ""
+ }
+ }
+
+ return (
+ {
+ setHover(true);
+ }}
+ >
+ {props.level !== 1 ? (
+
+ ) : null}
+ {element}
+ {extraInfo}
+
+ )
+ }
+
const SideBar = {
minWidth: 300,
width: "20%",
@@ -382,190 +616,7 @@ const Docs = (defaultprops) => {
fontSize: isMobile ? "1.3rem" : "1.1rem",
};
- function OuterLink(props) {
- if (props.href.includes("http") || props.href.includes("mailto")) {
- return (
-
- {props.children}
-
- );
- }
- return (
-
- {props.children}
-
- );
- }
-
- function Img(props) {
- return ;
- }
-
- function CodeHandler(props) {
- //console.log("Codehandler PROPS: ", props)
-
- const propvalue = props.value !== undefined && props.value !== null ? props.value : props.children !== undefined && props.children !== null && props.children.length > 0 ? props.children[0] : ""
-
- return (
-
- {propvalue}
-
- );
- }
-
- const Heading = (props) => {
- const element = React.createElement(
- `h${props.level}`,
- { style: { marginTop: props.level === 1 ? 20 : 50 } },
- props.children
- );
- const [hover, setHover] = useState(false);
-
- var extraInfo = "";
- if (props.level === 1) {
- extraInfo = (
-
-
- {mobile ? null : (
-
-
-
- Edit
-
-
-
- )}
- {mobile ? null : (
-
- )}
-
- {selectedMeta.read_time} minute
- {selectedMeta.read_time === 1 ? "" : "s"} to read
-
-
-
- {mobile ||
- selectedMeta.contributors === undefined ||
- selectedMeta.contributors === null ? (
- ""
- ) : (
-
- {selectedMeta.contributors.slice(0, 7).map((data, index) => {
- return (
-
-
-
-
-
- );
- })}
-
- )}
-
-
- );
- }
-
- if (extraInfo !== "" && props.level === 1 && props.children !== undefined && props.children !== null && props.children.length > 0) {
- if (props.children[0].toLowerCase().includes("privacy") || props.children[0].toLowerCase().includes("terms")) {
- extraInfo = ""
- }
- }
-
- return (
- {
- setHover(true);
- }}
- >
- {props.level !== 1 ? (
-
- ) : null}
- {element}
- {/*hover ? {setHover(true)}} style={{cursor: "pointer", display: "inline", }} onClick={() => {
- window.location.href += "#hello"
- console.log(window.location)
- //window.history.pushState('page2', 'Title', '/page2.php');
- //window.history.replaceState('page2', 'Title', '/page2.php');
- }} />
- : ""
- */}
- {extraInfo}
-
- );
- };
- //React.createElement("p", {style: {color: "red", backgroundColor: "blue"}}, this.props.paragraph)
-
- //function unicodeToChar(text) {
- // return text.replace(/\\u[\dA-F]{4}/gi,
- // function (match) {
- // return String.fromCharCode(parseInt(match.replace(/\\u/g, ''), 16));
- // }
- // );
- //}
+
const CustomButton = (props) => {
diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx
index 7f78244a..0cff5f0f 100755
--- a/frontend/src/views/Workflows.jsx
+++ b/frontend/src/views/Workflows.jsx
@@ -484,7 +484,6 @@ export const validateJson = (showResult) => {
// This is where we start recursing
if (jsonvalid) {
// Check fields if they can be parsed too
- //console.log("In this window for the data. Should look for list in result! Does recursion.")
try {
for (const [key, value] of Object.entries(result)) {
if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
@@ -1649,6 +1648,7 @@ const Workflows = (props) => {
addFilter(e.target.innerHTML);
};
+ const hasWorkflows = workflows === undefined || workflows === null || workflows.length === 0
const NewWorkflowPaper = () => {
const [hover, setHover] = React.useState(false);
@@ -1659,17 +1659,17 @@ const Workflows = (props) => {
minWidth: paperAppStyle.width,
color: innerColor,
padding: paperAppStyle.padding,
- borderRadius: paperAppStyle.borderRadius,
display: "flex",
boxSizing: "border-box",
position: "relative",
- border: `2px solid ${innerColor}`,
+ border: hasWorkflows ? `2px solid #f85a3e` : `2px solid ${innerColor}`,
cursor: "pointer",
backgroundColor: hover ? "rgba(39,41,45,0.5)" : "rgba(39,41,45,1)",
+ borderRadius: paperAppStyle.borderRadius,
};
return (
-
+
{
}}
>
-
+
+
+ New Workflow
+
@@ -3328,8 +3331,8 @@ const Workflows = (props) => {
-
- {!isMobile && usecases !== null && usecases !== undefined && usecases.length > 0 ?
+
+ {!isMobile && !hasWorkflows && usecases !== null && usecases !== undefined && usecases.length > 0 ?
{usecases.map((usecase, index) => {
//console.log(usecase)