Merge pull request #1024 from dhaval055/1.2.0

1.2.0
This commit is contained in:
Frikky
2023-01-26 15:50:53 +01:00
committed by GitHub
12 changed files with 3712 additions and 523 deletions
+317
View File
@@ -0,0 +1,317 @@
import React, { useState, useEffect } from "react";
import ReactGA from 'react-ga';
import { useTheme } from "@material-ui/core/styles";
import {
Paper,
Typography,
Divider,
Button,
Grid,
Card,
} from "@material-ui/core";
import { useAlert } from "react-alert";
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
const Billing = (props) => {
const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, } = props;
console.log("Billing: ", billingInfo);
const theme = useTheme();
const alert = useAlert();
const stripe = typeof window === 'undefined' || window.location === undefined ? "" : props.stripeKey === undefined ? "" : window.Stripe ? window.Stripe(props.stripeKey) : ""
console.log("Stripe: ", stripe)
const paperStyle = {
padding: 20,
height: "100%",
width: "100%",
backgroundColor: theme.palette.surfaceColor,
border: "1px solid rgba(255,255,255,0.3)",
marginRight: 10,
}
const isCloud =
window.location.host === "localhost:3002" ||
window.location.host === "shuffler.io";
billingInfo.subscription = {
"active": true,
"name": "Pay as you go",
"price": typecost_single,
"currency": "USD",
"currency_text": "$",
"interval": "app run / month",
"description": "Pay as you go",
"features": [
"Includes 10.000 app run/month for free. ",
"Pay for what you use with no minimum commitment and cancel anytime.",
],
"limit": 10000,
}
const handleStripeRedirect = () => {
//var priceItem = "price_1MRNF1DzMUgUjxHSfFTUb2Xh"
if (stripe == "") {
console.log("Stripe not loaded")
return
}
var priceItem = "price_1MROFrDzMUgUjxHShcSxgHO1"
const successUrl = `${window.location.origin}/admin?admin_tab=billing&payment=success`
const failUrl = `${window.location.origin}/admin?admin_tab=billing&payment=failure`
var checkoutObject = {
lineItems: [
{
price: priceItem,
quantity: 1
},
],
mode: "subscription",
billingAddressCollection: "auto",
successUrl: successUrl,
cancelUrl: failUrl,
clientReferenceId: props.userdata.active_org.id,
}
//submitType: "donate",
stripe.redirectToCheckout(checkoutObject)
.then(function (result) {
console.log("SUCCESS STRIPE?: ", result)
ReactGA.event({
category: "pricing",
action: "add_card_success",
label: "",
})
})
.catch(function(error) {
console.error("STRIPE ERROR: ", error)
ReactGA.event({
category: "pricing",
action: "add_card_error",
label: "",
})
});
}
const cancelSubscriptions = (subscription_id) => {
const orgId = selectedOrganization.id;
const data = {
subscription_id: subscription_id,
action: "cancel",
org_id: selectedOrganization.id,
};
const url = globalUrl + `/api/v1/orgs/${orgId}/cancel`;
fetch(url, {
mode: "cors",
method: "POST",
body: JSON.stringify(data),
credentials: "include",
crossDomain: true,
withCredentials: true,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
})
.then(function (response) {
if (response.status !== 200) {
console.log("Error in response");
}
if (handleGetOrg != undefined) {
handleGetOrg(selectedOrganization.id);
}
return response.json();
})
.then(function (responseJson) {
if (responseJson.success !== undefined && responseJson.success) {
alert.success("Successfully stopped subscription!");
} else {
alert.error("Failed stopping subscription. Please contact us.");
}
})
.catch(function (error) {
console.log("Error: ", error);
alert.error("Failed stopping subscription. Please contact us.");
});
};
const SubscriptionObject = (props) => {
const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, subscription, } = props;
console.log("Sub: ", subscription)
var top_text = "Base Access"
if (subscription.limit === undefined && subscription.level !== undefined) {
subscription.name = "Enterprise"
subscription.currency_text = "$"
subscription.price = subscription.level*180
subscription.limit = subscription.level*100000
subscription.interval = subscription.recurrence
subscription.features = [
"Includes " + subscription.limit + " app runs/month. ",
"Multi-Tenancy and Region-Selection",
"And all other features from /pricing",
]
}
if (subscription.name === "Enterprise" && subscription.active === true) {
top_text = "Current Plan"
}
return (
<Paper style={paperStyle}>
<div style={{display: "flex"}}>
<Typography variant="h6" style={{ marginTop: 10, marginBottom: 10 }}>
{top_text}
</Typography>
</div>
<Divider />
<div>
<Typography variant="body1" style={{ marginTop: 20, }}>
{subscription.name}
</Typography>
<div style={{display: "flex", }}>
<Typography variant="h6" style={{ marginTop: 10, }}>
{subscription.currency_text}{subscription.price}
</Typography>
<Typography variant="body1" color="textSecondary" style={{ marginLeft: 10, marginTop: 15, marginBottom: 10 }}>
/ {subscription.interval}
</Typography>
</div>
<Typography variant="body2" color="textSecondary" style={{ marginTop: 10, }}>
Features
</Typography>
<ul>
{subscription.features !== undefined && subscription.features !== null ?
subscription.features.map((feature, index) => {
return (
<li>
<Typography variant="body2" color="textPrimary" style={{ }}>
{feature}
</Typography>
</li>
)
})
: null}
</ul>
</div>
{/*subscription.name === "Pay as you go" && subscription.limit <= 10000 ?
<span>
<Typography variant="body2" color="textSecondary" style={{ marginTop: 20, marginBottom: 10 }}>
You are not subscribed to any plan and are using the free plan with max 10,000 apps per month. Activate billing to de-activate this limit.
</Typography>
<Button
variant="contained"
color="primary"
style={{ marginTop: 20, marginBottom: 10, }}
onClick={() => {
handleStripeRedirect()
}}
>
Activate Billing
</Button>
</span>
: null*/}
</Paper>
)
}
return (
<div>
<Typography variant="h6" style={{ marginTop: 20, marginBottom: 10 }}>
Billing
</Typography>
<Typography variant="body1" style={{ marginTop: 20, marginBottom: 10 }}>
We use Stripe to manage subscriptions and do not store any of your billing information. You can manage your subscription and billing information below.
</Typography>
<div style={{display: "flex", maxWidth: 768, minWidth: 768, }}>
{billingInfo.subscription !== undefined && billingInfo.subscription !== null ?
<SubscriptionObject
globalUrl={globalUrl}
userdata={userdata}
serverside={serverside}
billingInfo={billingInfo}
stripeKey={stripeKey}
selectedOrganization={selectedOrganization}
subscription={billingInfo.subscription}
/>
: null}
{isCloud &&
selectedOrganization.subscriptions !== undefined &&
selectedOrganization.subscriptions !== null &&
selectedOrganization.subscriptions.length > 0 ?
selectedOrganization.subscriptions
.reverse()
.map((sub, index) => {
return (
<SubscriptionObject
globalUrl={globalUrl}
userdata={userdata}
serverside={serverside}
billingInfo={billingInfo}
stripeKey={stripeKey}
selectedOrganization={selectedOrganization}
subscription={sub}
/>
)
})
: null}
{/*
<Grid item key={index} xs={12/selectedOrganization.subscriptions.length}>
<Card
elevation={6}
style={
paperStyle
}
>
<b>Quantity</b>: {sub.level}
<div />
<b>Recurrence</b>: {sub.recurrence}
<div />
{sub.active ? (
<div>
<b>Started</b>:{" "}
{new Date(sub.startdate * 1000).toISOString()}
<div />
<Button
variant="outlined"
color="secondary"
style={{ marginTop: 15 }}
onClick={() => {
cancelSubscriptions(sub.reference);
}}
>
Cancel subscription
</Button>
</div>
) : (
<div>
<b>Cancelled</b>:{" "}
{new Date(
sub.cancellationdate * 1000
).toISOString()}
<div />
<Typography color="textSecondary">
<b>Status</b>: Deactivated
</Typography>
</div>
)}
</Card>
</Grid>
*/}
</div>
</div>
)
}
export default Billing;
+13 -9
View File
@@ -129,7 +129,7 @@ const ConfigureWorkflow = (props) => {
setFirstLoad(workflow.id)
const newactions = [];
for (var key in workflow.actions) {
for (let [key, keyval] in workflow.actions.entries()) {
const action = workflow.actions[key];
var newaction = {
large_image: action.large_image,
@@ -175,7 +175,7 @@ const ConfigureWorkflow = (props) => {
) {
// Check if configuration is filled or not
var filled = true;
for (var key in action.parameters) {
for (let [key,keyval] in action.parameters.entries()) {
if (action.parameters[key].configuration) {
//console.log("Found config: ", action.parameters[key])
if (
@@ -216,7 +216,7 @@ const ConfigureWorkflow = (props) => {
if (newaction.must_authenticate) {
var authenticationOptions = [];
for (var key in appAuthentication) {
for (let [key,keyval] in appAuthentication.entries()) {
const auth = appAuthentication[key];
if (auth.app.name === app.name && auth.active) {
//console.log("Found auth: ", auth)
@@ -264,7 +264,8 @@ const ConfigureWorkflow = (props) => {
}
}
for (var key in workflow.workflow_variables) {
if (workflow.workflow_variables !== undefined && workflow.workflow_variables !== null && workflow.workflow_variables.length !== 0) {
for (let [key,keyval] in workflow.workflow_variables.entries()) {
const variable = workflow.workflow_variables[key];
if (
variable.value === undefined ||
@@ -276,8 +277,10 @@ const ConfigureWorkflow = (props) => {
requiredVariables.push(variable);
}
}
}
for (var key in workflow.triggers) {
if (workflow.triggers !== undefined && workflow.triggers !== null && workflow.triggers.length !== 0) {
for (let [key,keyval] in workflow.triggers.entries()) {
var trigger = workflow.triggers[key];
trigger.index = key;
@@ -299,7 +302,7 @@ const ConfigureWorkflow = (props) => {
}
]
for (var subkey in tmpsteps) {
for (let [subkey,subkeyval] in tmpsteps.entries()) {
newactions[foundindex].steps.push(tmpsteps[subkey])
}
@@ -326,6 +329,7 @@ const ConfigureWorkflow = (props) => {
requiredTriggers.push(trigger);
}
}
if (
requiredTriggers.length === 0 &&
@@ -342,11 +346,11 @@ const ConfigureWorkflow = (props) => {
if (appAuthentication.length !== previousAuth.length) {
var newactions = []
for (var actionkey in requiredActions) {
for (let [actionkey, actionkeyval] in requiredActions.entries()) {
var newaction = requiredActions[actionkey];
const app = newaction.app;
for (var key in appAuthentication) {
for (let [key,keyval] in appAuthentication.entries()) {
const auth = appAuthentication[key];
// Does this account for all the different ones of the same?
@@ -690,7 +694,7 @@ const ConfigureWorkflow = (props) => {
if (workflow.actions !== null) {
//console.log(workflow.actions)
alert.info("Setting action to version "+action.update_version)
for (var key in workflow.actions) {
for (let [key,keyval] in workflow.actions.entries()) {
if (workflow.actions[key].app_name === action.app_name && workflow.actions[key].app_version === action.app_version) {
workflow.actions[key].app_version = action.update_version
+102
View File
@@ -0,0 +1,102 @@
import React, {useState} from 'react';
import { useTheme } from '@material-ui/core/styles';
import {isMobile} from "react-device-detect";
import ReactGA from 'react-ga';
import {TextField, Typography, Button} from '@material-ui/core';
const Newsletter = (props) => {
const { globalUrl, } = props;
const theme = useTheme();
const [email, setEmail] = useState("");
const [msg, setMsg] = useState("");
const [buttonActive, setButtonActive] = useState(true);
const buttonStyle = {minWidth: 300, borderRadius: 30, height: 60, width: 140, margin: isMobile ? "15px auto 15px auto" : "20px 20px 20px 10px", fontSize: 18,}
const newsletterSignup = (inemail) => {
if (inemail.length < 4) {
setMsg("Invalid email")
setButtonActive(true)
return
}
setButtonActive(false)
const data = {"email": inemail}
const url = globalUrl+'/api/v1/functions/newsletter_signup'
fetch(url, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
})
.then(response =>
response.json().then(responseJson => {
setButtonActive(true)
setMsg(responseJson["reason"])
if (responseJson["success"] === false) {
} else {
setEmail("")
}
}),
)
.catch(error => {
setMsg("Something went wrong: ", error.toString())
setButtonActive(true)
});
}
return (
<div style={{margin: "auto", color: "white", textAlign: "center",}}>
<Typography variant="h4" style={{marginTop: 35,}}>
Security Automation Newsletter
</Typography>
<Typography variant="h6" style={{color: "#7d7f82", marginTop: 20, }}>
Defensive security is 99% noise. Join us to sift through it.
</Typography>
<div style={{}}>
<TextField
style={{minWidth: isMobile ? "90%" : 450, backgroundColor: theme.palette.inputColor, marginTop: 20, borderRadius: 10, }}
InputProps={{
style:{
borderRadius: 10,
height: 60,
color: "white",
},
}}
color="primary"
value={email}
onChange={(e) => {
setEmail(e.target.value)
}}
placeholder="Your email"
id="standard-required"
margin="normal"
variant="outlined"
/>
</div>
<Button
variant="contained"
color="primary"
style={buttonStyle}
disabled={!buttonActive}
onClick={() => {
newsletterSignup(email)
ReactGA.event({
category: "newsletter",
action: `signup_click`,
label: "",
})
}}
>
Sign up
</Button>
<div/>
{msg}
</div>
)
}
export default Newsletter;
@@ -0,0 +1,702 @@
import React, { useEffect } from "react";
import { makeStyles } from "@material-ui/styles";
import { useTheme } from "@material-ui/core/styles";
import { useAlert } from "react-alert";
import {
FormControl,
InputLabel,
Paper,
OutlinedInput,
Checkbox,
Card,
Tooltip,
FormControlLabel,
Typography,
Switch,
Select,
MenuItem,
Divider,
TextField,
Button,
Tabs,
Tab,
Grid,
} from "@material-ui/core";
import IconButton from "@material-ui/core/IconButton";
import ExpandLessIcon from "@material-ui/icons/ExpandLess";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import SaveIcon from "@material-ui/icons/Save";
const useStyles = makeStyles({
notchedOutline: {
borderColor: "#f85a3e !important",
},
});
const OrgHeaderexpanded = (props) => {
const {
userdata,
selectedOrganization,
setSelectedOrganization,
globalUrl,
isCloud,
adminTab,
} = props;
const theme = useTheme();
const alert = useAlert();
const classes = useStyles();
const defaultBranch = "master";
const [orgName, setOrgName] = React.useState(selectedOrganization.name);
const [orgDescription, setOrgDescription] = React.useState(
selectedOrganization.description
);
const [appDownloadUrl, setAppDownloadUrl] = React.useState(
selectedOrganization.defaults === undefined
? "https://github.com/frikky/shuffle-apps"
: selectedOrganization.defaults.app_download_repo === undefined ||
selectedOrganization.defaults.app_download_repo.length === 0
? "https://github.com/frikky/shuffle-apps"
: selectedOrganization.defaults.app_download_repo
);
const [appDownloadBranch, setAppDownloadBranch] = React.useState(
selectedOrganization.defaults === undefined
? defaultBranch
: selectedOrganization.defaults.app_download_branch === undefined ||
selectedOrganization.defaults.app_download_branch.length === 0
? defaultBranch
: selectedOrganization.defaults.app_download_branch
);
const [workflowDownloadUrl, setWorkflowDownloadUrl] = React.useState(
selectedOrganization.defaults === undefined
? "https://github.com/frikky/shuffle-apps"
: selectedOrganization.defaults.workflow_download_repo === undefined ||
selectedOrganization.defaults.workflow_download_repo.length === 0
? "https://github.com/frikky/shuffle-workflows"
: selectedOrganization.defaults.workflow_download_repo
);
const [workflowDownloadBranch, setWorkflowDownloadBranch] = React.useState(
selectedOrganization.defaults === undefined
? defaultBranch
: selectedOrganization.defaults.workflow_download_branch === undefined ||
selectedOrganization.defaults.workflow_download_branch.length === 0
? defaultBranch
: selectedOrganization.defaults.workflow_download_branch
);
const [ssoEntrypoint, setSsoEntrypoint] = React.useState(
selectedOrganization.sso_config === undefined
? ""
: selectedOrganization.sso_config.sso_entrypoint === undefined ||
selectedOrganization.sso_config.sso_entrypoint.length === 0
? ""
: selectedOrganization.sso_config.sso_entrypoint
);
const [ssoCertificate, setSsoCertificate] = React.useState(
selectedOrganization.sso_config === undefined
? ""
: selectedOrganization.sso_config.sso_certificate === undefined ||
selectedOrganization.sso_config.sso_certificate.length === 0
? ""
: selectedOrganization.sso_config.sso_certificate
);
const [notificationWorkflow, setNotificationWorkflow] = React.useState(
selectedOrganization.defaults === undefined
? ""
: selectedOrganization.defaults.notification_workflow === undefined ||
selectedOrganization.defaults.notification_workflow.length === 0
? ""
: selectedOrganization.defaults.notification_workflow
);
const [documentationReference, setDocumentationReference] = React.useState(
selectedOrganization.defaults === undefined
? ""
: selectedOrganization.defaults.documentation_reference === undefined ||
selectedOrganization.defaults.documentation_reference.length === 0
? ""
: selectedOrganization.defaults.documentation_reference
);
const [openidClientId, setOpenidClientId] = React.useState(
selectedOrganization.sso_config === undefined
? ""
: selectedOrganization.sso_config.client_id === undefined ||
selectedOrganization.sso_config.client_id.length === 0
? ""
: selectedOrganization.sso_config.client_id
);
const [openidClientSecret, setOpenidClientSecret] = React.useState(
selectedOrganization.sso_config === undefined
? ""
: selectedOrganization.sso_config.client_secret === undefined ||
selectedOrganization.sso_config.client_secret.length === 0
? ""
: selectedOrganization.sso_config.client_secret
);
const [openidAuthorization, setOpenidAuthorization] = React.useState(
selectedOrganization.sso_config === undefined
? ""
: selectedOrganization.sso_config.openid_authorization === undefined ||
selectedOrganization.sso_config.openid_authorization.length === 0
? ""
: selectedOrganization.sso_config.openid_authorization
);
const [openidToken, setOpenidToken] = React.useState(
selectedOrganization.sso_config === undefined
? ""
: selectedOrganization.sso_config.openid_token === undefined ||
selectedOrganization.sso_config.openid_token.length === 0
? ""
: selectedOrganization.sso_config.openid_token
)
const handleEditOrg = (
name,
description,
orgId,
image,
defaults,
sso_config
) => {
const data = {
name: name,
description: description,
org_id: orgId,
image: image,
defaults: defaults,
sso_config: sso_config,
};
const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
fetch(url, {
mode: "cors",
method: "POST",
body: JSON.stringify(data),
credentials: "include",
crossDomain: true,
withCredentials: true,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
})
.then((response) =>
response.json().then((responseJson) => {
if (responseJson["success"] === false) {
alert.error("Failed updating org: ", responseJson.reason);
} else {
alert.success("Successfully edited org!");
}
})
)
.catch((error) => {
alert.error("Err: " + error.toString());
});
};
const orgSaveButton = (
<Tooltip title="Save any unsaved data" placement="bottom">
<Button
style={{ width: 150, height: 55, flex: 1 }}
variant="contained"
color="primary"
disabled={
userdata === undefined ||
userdata === null ||
userdata.admin !== "true"
}
onClick={() =>
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: notificationWorkflow,
documentation_reference: documentationReference,
},
{
sso_entrypoint: ssoEntrypoint,
sso_certificate: ssoCertificate,
client_id: openidClientId,
client_secret: openidClientSecret,
openid_authorization: openidAuthorization,
openid_token: openidToken,
}
)
}
>
<SaveIcon />
</Button>
</Tooltip>
);
return (
<div style={{ textAlign: "center" }}>
<Grid container spacing={3} style={{ textAlign: "left" }}>
<Grid item xs={12} style={{}}>
<span>
<Typography>Notification Workflow ID</Typography>
<TextField
required
style={{
flex: "1",
marginTop: "5px",
marginRight: "15px",
backgroundColor: theme.palette.inputColor,
}}
fullWidth={true}
type="name"
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
placeholder="ID of the workflow to receive notifications"
value={notificationWorkflow}
onChange={(e) => {
setNotificationWorkflow(e.target.value);
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
color: "white",
},
}}
/>
</span>
</Grid>
<Grid item xs={12} style={{}}>
<span>
<Typography>Org Documentation reference</Typography>
<TextField
required
style={{
flex: "1",
marginTop: "5px",
marginRight: "15px",
backgroundColor: theme.palette.inputColor,
}}
fullWidth={true}
type="name"
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
placeholder="URL to an external reference for this implementation"
value={documentationReference}
onChange={(e) => {
setDocumentationReference(e.target.value);
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
color: "white",
},
}}
/>
</span>
</Grid>
{isCloud ? null :
<Grid item xs={12} style={{marginTop: 50 }}>
<Typography variant="h4" style={{textAlign: "center",}}>OpenID connect</Typography>
<Grid container style={{marginTop: 10, }}>
<Grid item xs={6} style={{}}>
<span>
<Typography>Client ID</Typography>
<TextField
required
style={{
flex: "1",
marginTop: "5px",
marginRight: "15px",
backgroundColor: theme.palette.inputColor,
}}
fullWidth={true}
type="name"
multiline={true}
rows={2}
disabled={
selectedOrganization.manager_orgs !== undefined &&
selectedOrganization.manager_orgs !== null &&
selectedOrganization.manager_orgs.length > 0
}
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
placeholder="The OpenID client ID from the identity provider"
value={openidClientId}
onChange={(e) => {
setOpenidClientId(e.target.value);
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
color: "white",
},
}}
/>
</span>
</Grid>
<Grid item xs={6} style={{}}>
<span>
<Typography>Client Secret (optional)</Typography>
<TextField
required
style={{
flex: "1",
marginTop: "5px",
marginRight: "15px",
backgroundColor: theme.palette.inputColor,
}}
fullWidth={true}
type="name"
multiline={true}
rows={2}
disabled={
selectedOrganization.manager_orgs !== undefined &&
selectedOrganization.manager_orgs !== null &&
selectedOrganization.manager_orgs.length > 0
}
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
placeholder="The OpenID client secret - DONT use this if dealing with implicit auth / PKCE"
value={openidClientSecret}
onChange={(e) => {
setOpenidClientSecret(e.target.value);
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
color: "white",
},
}}
/>
</span>
</Grid>
</Grid>
<Grid container style={{marginTop: 10, }}>
<Grid item xs={6} style={{}}>
<span>
<Typography>Authorization URL</Typography>
<TextField
required
style={{
flex: "1",
marginTop: "5px",
marginRight: "15px",
backgroundColor: theme.palette.inputColor,
}}
fullWidth={true}
type="name"
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
multiline={true}
rows={2}
placeholder="The OpenID authorization URL (usually ends with /authorize)"
value={openidAuthorization}
onChange={(e) => {
setOpenidAuthorization(e.target.value)
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
color: "white",
},
}}
/>
</span>
</Grid>
<Grid item xs={6} style={{}}>
<span>
<Typography>Token URL</Typography>
<TextField
required
style={{
flex: "1",
marginTop: "5px",
marginRight: "15px",
backgroundColor: theme.palette.inputColor,
}}
fullWidth={true}
type="name"
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
multiline={true}
rows={2}
placeholder="The OpenID token URL (usually ends with /token)"
value={openidToken}
onChange={(e) => {
setOpenidToken(e.target.value)
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
color: "white",
},
}}
/>
</span>
</Grid>
</Grid>
</Grid>
}
{/*isCloud ? null : */}
<Grid item xs={12} style={{marginTop: 50,}}>
<Typography variant="h4" style={{textAlign: "center",}}>SAML SSO (v1.1)</Typography>
<Grid container style={{marginTop: 20, }}>
<Grid item xs={6} style={{}}>
<span>
<Typography>SSO Entrypoint (IdP)</Typography>
<TextField
required
style={{
flex: "1",
marginTop: "5px",
marginRight: "15px",
backgroundColor: theme.palette.inputColor,
}}
fullWidth={true}
type="name"
multiline={true}
rows={2}
disabled={
selectedOrganization.manager_orgs !== undefined &&
selectedOrganization.manager_orgs !== null &&
selectedOrganization.manager_orgs.length > 0
}
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
placeholder="The entrypoint URL from your provider"
value={ssoEntrypoint}
onChange={(e) => {
setSsoEntrypoint(e.target.value);
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
color: "white",
},
}}
/>
</span>
</Grid>
<Grid item xs={6} style={{}}>
<span>
<Typography>SSO Certificate (X509)</Typography>
<TextField
required
style={{
flex: "1",
marginTop: "5px",
marginRight: "15px",
backgroundColor: theme.palette.inputColor,
}}
fullWidth={true}
type="name"
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
multiline={true}
rows={2}
placeholder="The X509 certificate to use"
value={ssoCertificate}
onChange={(e) => {
setSsoCertificate(e.target.value);
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
color: "white",
},
}}
/>
</span>
</Grid>
</Grid>
{isCloud ?
<Typography variant="body2" style={{textAlign: "left",}} color="textSecondary">
IdP URL for Shuffle: https://shuffler.io/api/v1/login_sso
</Typography>
: null}
</Grid>
{isCloud ? null : (
<Grid item xs={6} style={{}}>
<span>
<Typography>App Download URL</Typography>
<TextField
required
style={{
flex: "1",
marginTop: "5px",
marginRight: "15px",
backgroundColor: theme.palette.inputColor,
}}
fullWidth={true}
type="name"
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
placeholder="A description for the organization"
value={appDownloadUrl}
onChange={(e) => {
setAppDownloadUrl(e.target.value);
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
color: "white",
},
}}
/>
</span>
</Grid>
)}
{isCloud ? null : (
<Grid item xs={6} style={{}}>
<span>
<Typography>App Download Branch</Typography>
<TextField
required
style={{
flex: "1",
marginTop: "5px",
marginRight: "15px",
backgroundColor: theme.palette.inputColor,
}}
fullWidth={true}
type="name"
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
placeholder="A description for the organization"
value={appDownloadBranch}
onChange={(e) => {
setAppDownloadBranch(e.target.value);
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
color: "white",
},
}}
/>
</span>
</Grid>
)}
{isCloud ? null : (
<Grid item xs={6} style={{}}>
<span>
<Typography>Workflow Download URL</Typography>
<TextField
required
style={{
flex: "1",
marginTop: "5px",
marginRight: "15px",
backgroundColor: theme.palette.inputColor,
}}
fullWidth={true}
type="name"
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
placeholder="A description for the organization"
value={workflowDownloadUrl}
onChange={(e) => {
setWorkflowDownloadUrl(e.target.value);
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
color: "white",
},
}}
/>
</span>
</Grid>
)}
{isCloud ? null : (
<Grid item xs={6} style={{}}>
<span>
<Typography>Workflow Download Branch</Typography>
<TextField
required
style={{
flex: "1",
marginTop: "5px",
marginRight: "15px",
backgroundColor: theme.palette.inputColor,
}}
fullWidth={true}
type="name"
id="outlined-with-placeholder"
margin="normal"
variant="outlined"
placeholder="A description for the organization"
value={workflowDownloadBranch}
onChange={(e) => {
setWorkflowDownloadBranch(e.target.value);
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
color: "white",
},
}}
/>
</span>
</Grid>
)}
<div style={{ margin: "auto", textalign: "center", marginTop: 15, marginBottom: 15, }}>
{orgSaveButton}
</div>
{/*
<span style={{textAlign: "center"}}>
{expanded ?
<ExpandLessIcon />
:
<ExpandMoreIcon />
}
</span>
*/}
</Grid>
</div>
)
}
export default OrgHeaderexpanded;
+30 -30
View File
@@ -277,7 +277,7 @@ const ParsedAction = (props) => {
console.log("FOUNDACTION: ", foundAction);
if (foundAction !== null && foundAction !== undefined) {
var foundparams = [];
for (var paramkey in foundAction.parameters) {
for (let [paramkey,paramkeyval] in foundAction.parameters.entries()) {
const param = foundAction.parameters[paramkey];
const foundParam = selectedAction.parameters.find(
@@ -401,7 +401,7 @@ const ParsedAction = (props) => {
if (actionlist.length === 0) {
// FIXME: Have previous execution values in here
if (workflowExecutions.length > 0) {
for (var key in workflowExecutions) {
for (let [key,keyval] in workflowExecutions.entries()) {
if (
workflowExecutions[key].execution_argument === undefined ||
workflowExecutions[key].execution_argument === null ||
@@ -451,7 +451,7 @@ const ParsedAction = (props) => {
workflow.workflow_variables !== undefined &&
workflow.workflow_variables.length > 0
) {
for (var key in workflow.workflow_variables) {
for (let [key,keyval] in workflow.workflow_variables.entries()) {
const item = workflow.workflow_variables[key];
actionlist.push({
type: "workflow_variable",
@@ -470,7 +470,7 @@ const ParsedAction = (props) => {
workflow.execution_variables !== undefined &&
workflow.execution_variables.length > 0
) {
for (var key in workflow.execution_variables) {
for (let [key,keyval] in workflow.execution_variables.entries()) {
const item = workflow.execution_variables[key];
actionlist.push({
type: "execution_variable",
@@ -488,7 +488,7 @@ const ParsedAction = (props) => {
var parents = getParents(selectedAction);
if (parents.length > 1) {
for (var key in parents) {
for (let [key,keyval] in parents.entries()) {
const item = parents[key];
if (item.label === "Execution Argument") {
continue;
@@ -500,7 +500,7 @@ const ParsedAction = (props) => {
if (workflowExecutions.length > 0) {
// Look for the ID
const found = false;
for (var key in workflowExecutions) {
for (let [key,keyval] in workflowExecutions.entries()) {
if (
workflowExecutions[key].results === undefined ||
workflowExecutions[key].results === null
@@ -566,7 +566,7 @@ const ParsedAction = (props) => {
if (found !== null && found !== undefined) {
var new_occurences = []
for (var key in found) {
for (let [key,keyval] in found.entries()) {
if (found[key][0] !== "\\") {
new_occurences.push(found[key])
}
@@ -579,7 +579,7 @@ const ParsedAction = (props) => {
if (found !== null) {
try {
// When the found array is empty.
for (var i = 0; i < found.length; i++) {
for (let i = 0; i < found.length; i++) {
const variableSplit = found[i].split(".#")
if ((variableSplit.length-1) > 1) {
//console.log("Larger than 1: ", variableSplit)
@@ -589,7 +589,7 @@ const ParsedAction = (props) => {
}
var foundSlice = false
for (var j = 0; j < actionlist.length; j++) {
for (let j = 0; j < actionlist.length; j++) {
//console.log("ACTION: ", found[i], actionlist[j])
//console.log("ACTION :", found[i].split(".")[0].slice(1,).toLowerCase(), actionlist[j].autocomplete.toLowerCase())
if(found[i].split(".")[0].slice(1,).toLowerCase() == actionlist[j].autocomplete.toLowerCase()){
@@ -730,7 +730,7 @@ const ParsedAction = (props) => {
var curstring = "";
var record = false;
for (var key in selectedActionParameters[count].value) {
for (let [key,keyval] in selectedActionParameters[count].value.entries()) {
const item = selectedActionParameters[count].value[key];
if (record) {
curstring += item;
@@ -911,7 +911,7 @@ const ParsedAction = (props) => {
var curstring = ""
var record = false
for (var key in selectedActionParameters[count].value) {
for (let [key,keyval] in selectedActionParameters[count].value.entries()) {
const item = selectedActionParameters[count].value[key]
if (record) {
curstring += item
@@ -1187,7 +1187,7 @@ const ParsedAction = (props) => {
renderInput={(params) => {
if (params.inputProps !== undefined && params.inputProps !== null && params.inputProps.value !== undefined && params.inputProps.value !== null) {
const prefixes = ["Post", "Put", "Patch"]
for (var key in prefixes) {
for (let [key,keyval] in prefixes.entries()) {
if (params.inputProps.value.startsWith(prefixes[key])) {
params.inputProps.value = params.inputProps.value.replace(prefixes[key]+" ", "", -1)
if (params.inputProps.value.length > 1) {
@@ -1426,7 +1426,7 @@ const ParsedAction = (props) => {
setHideBody(!hideBody);
for (var key in selectedActionParameters) {
for (let [key,keyval] in selectedActionParameters.entries()) {
var currentItem = selectedActionParameters[key];
if (currentItem.name === "ssl_verify") {
@@ -1472,10 +1472,10 @@ const ParsedAction = (props) => {
openApiHelperText = "OpenAPI spec: fill the following fields.";
//console.log("SHOULD ADD TO selectedActionParameters!: ", found, selectedActionParameters)
var changed = false;
for (var specKey in found) {
for (let [specKey,specKeyVal] in found.entries()) {
const tmpitem = found[specKey];
var skip = false;
for (var innerkey in selectedActionParameters) {
for (let [innerkey,innerkeyval] in selectedActionParameters.entries()) {
if (selectedActionParameters[innerkey].name === tmpitem) {
skip = true;
break;
@@ -1707,7 +1707,7 @@ const ParsedAction = (props) => {
var foundnewline = false
var allValues = []
for (var key in splitdata) {
for (let [key,keyval] in splitdata.entries()) {
const line = splitdata[key]
if (line === "") {
foundnewline = true
@@ -1777,7 +1777,7 @@ const ParsedAction = (props) => {
const tmpsplit = selectedActionParameters[count].value.split("\n")
var valsplit = []
var add_empty = false
for (var key in tmpsplit) {
for (let [key,keyval] in tmpsplit.entries()) {
if (tmpsplit[key] === "") {
add_empty = true
continue
@@ -1792,7 +1792,7 @@ const ParsedAction = (props) => {
console.log("Split: ", valsplit)
var newarr = []
for (var key in valsplit) {
for (let [key,keyval] in valsplit.entries()) {
var line = valsplit[key]
if (key == index) {
@@ -1832,7 +1832,7 @@ const ParsedAction = (props) => {
var tmpsplit = selectedActionParameters[count].value.split("\n")
var valsplit = []
var add_empty = false
for (var key in tmpsplit) {
for (let [key,keyval] in tmpsplit.entries()) {
if (tmpsplit[key] === "") {
add_empty = true
continue
@@ -1847,7 +1847,7 @@ const ParsedAction = (props) => {
console.log("Split: ", valsplit)
var newarr = []
for (var key in valsplit) {
for (let [key,keyval] in valsplit.entries()) {
var line = valsplit[key]
if (key == index) {
@@ -2094,7 +2094,7 @@ const ParsedAction = (props) => {
: "$" + values[0].autocomplete;
toComplete = toComplete.toLowerCase().replaceAll(" ", "_");
for (var key in values) {
for (let [key,keyval] in values.entries()) {
if (key == 0 || values[key].autocomplete.length === 0) {
continue;
}
@@ -2205,7 +2205,7 @@ const ParsedAction = (props) => {
workflow.triggers !== null &&
workflow.triggers.length > 0
) {
for (var key in workflow.triggers) {
for (let [key,keyval] in workflow.triggers.entries()) {
const item = workflow.triggers[key];
if (cy !== undefined) {
@@ -2727,7 +2727,7 @@ const ParsedAction = (props) => {
if (workflowExecutions.length > 0) {
// Look for the ID
const found = false;
for (var key in workflowExecutions) {
for (let [key,keyval] in workflowExecutions.entries()) {
if (
workflowExecutions[key].results === undefined ||
workflowExecutions[key].results === null
@@ -2971,8 +2971,8 @@ const ParsedAction = (props) => {
//
// Should make it a function lol
if (workflow.branches !== undefined && workflow.branches !== null) {
for (var key in workflow.branches) {
for (var subkey in workflow.branches[key].conditions) {
for (let [key,keyval] in workflow.branches.entries()) {
for (let [subkey,subkeyval] in workflow.branches[key].conditions.entries()) {
const condition = workflow.branches[key].conditions[subkey]
const sourceparam = condition.source
const destinationparam = condition.destination
@@ -3080,12 +3080,12 @@ const ParsedAction = (props) => {
}
}
for (var key in workflow.actions) {
for (let [key,keyval] in workflow.actions.entries()) {
if (workflow.actions[key].id === selectedAction.id) {
continue
}
for (var subkey in workflow.actions[key].parameters) {
for (let [subkey, subkeyval] in workflow.actions[key].parameters.entries()) {
const param = workflow.actions[key].parameters[subkey];
if (!param.value.includes("$")) {
continue
@@ -3251,7 +3251,7 @@ const ParsedAction = (props) => {
selectedAction.selectedAuthentication = {};
selectedAction.authentication_id = "";
for (var key in selectedAction.parameters) {
for (let [key,keyval] in selectedAction.parameters.entries()) {
//console.log(selectedAction.parameters[key])
if (selectedAction.parameters[key].configuration) {
selectedAction.parameters[key].value = "";
@@ -3568,7 +3568,7 @@ const ParsedAction = (props) => {
if (method.length > 0 && data.description !== undefined && data.description !== null && data.description.includes("http")) {
var extraUrl = ""
const descSplit = data.description.split("\n")
for (var line in descSplit) {
for (let [line,lineval] in descSplit.entries()) {
if (descSplit[line].includes("http") && descSplit[line].includes("://")) {
const urlsplit = descSplit[line].split("/")
try {
@@ -3629,7 +3629,7 @@ const ParsedAction = (props) => {
renderInput={(params) => {
if (params.inputProps !== undefined && params.inputProps !== null && params.inputProps.value !== undefined && params.inputProps.value !== null) {
const prefixes = ["Post", "Put", "Patch"]
for (var key in prefixes) {
for (let [key,keyval] in prefixes.entries()) {
if (params.inputProps.value.startsWith(prefixes[key])) {
params.inputProps.value = params.inputProps.value.replace(prefixes[key]+" ", "", -1)
if (params.inputProps.value.length > 1) {