Merge branch '1.4.0'
This commit is contained in:
@@ -291,8 +291,6 @@ const Admin = (props) => {
|
||||
//const alert = useAlert();
|
||||
const handleStatusChange = (event) => {
|
||||
const { value } = event.target;
|
||||
console.log("value: ", value)
|
||||
|
||||
setSelectedStatus(value);
|
||||
|
||||
|
||||
@@ -331,7 +329,7 @@ const Admin = (props) => {
|
||||
var your_apps = "- Connecting "
|
||||
|
||||
var subject_add = 0
|
||||
var subject = "Want to automate "
|
||||
var subject = "POC to automate "
|
||||
|
||||
if (org.security_framework !== undefined && org.security_framework !== null) {
|
||||
if (org.security_framework.cases.name !== undefined && org.security_framework.cases.name !== null && org.security_framework.cases.name !== "") {
|
||||
@@ -400,7 +398,7 @@ const Admin = (props) => {
|
||||
|
||||
|
||||
// Remove comma
|
||||
subject += "?"
|
||||
//subject += "?"
|
||||
your_apps = your_apps.substring(0, your_apps.length - 2)
|
||||
}
|
||||
|
||||
@@ -432,12 +430,25 @@ const Admin = (props) => {
|
||||
var admins = ""
|
||||
|
||||
// Loop users
|
||||
var lastLogin = 0
|
||||
for (var i = 0; i < users.length; i++) {
|
||||
if (users[i].username.includes("shuffler")) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (users[i].role === "admin") {
|
||||
admins += users[i].username + ","
|
||||
}
|
||||
|
||||
const data = users[i]
|
||||
for (var i = 0; i < data.login_info.length; i++) {
|
||||
if (data.login_info[i].timestamp > lastLogin) {
|
||||
lastLogin = data.login_info[i].timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Remove last comma
|
||||
admins = admins.substring(0, admins.length - 1)
|
||||
|
||||
@@ -452,15 +463,24 @@ const Admin = (props) => {
|
||||
// Get drift username from userdata.username before @ in email
|
||||
const username = userdata.username.substring(0, userdata.username.indexOf("@"))
|
||||
|
||||
var body = `Hey,%0D%0A%0D%0AI saw you trying to use Shuffle, and thought we may be able to help. Right now, it looks like you have ${workflow_amount} workflows made, but it still doesn't look like you are getting the most out of Shuffle. If you're interested, I'd love to set up a quick call to see if we can help you get more out of Shuffle. %0D%0A%0D%0A
|
||||
// Check if timestamp is more than 2 weeks ago and add "a while back" to the message
|
||||
const timeComparison = 1209600
|
||||
const extra_timestamp_text = lastLogin === 0 ? 0 : (Date.now()/1000 - lastLogin) > timeComparison ? " a while back" : ""
|
||||
console.log("LAST LOGIN: " + lastLogin, extra_timestamp_text)
|
||||
|
||||
// Check if cloud sync is active, and if so, add a message about it
|
||||
const cloudSyncInfo = selectedOrganization.cloud_sync === true ? "- Scale your onprem installation" : ""
|
||||
|
||||
var body = `Hey,%0D%0A%0D%0AI noticed you tried to use Shuffle${extra_timestamp_text}, and thought you may be interested in a POC. It looks like you have ${workflow_amount} workflows made, but it still doesn't look like you are getting what you wanted out of Shuffle. If you're interested, I'd love to set up a quick call to see if we can help you get more out of Shuffle. %0D%0A%0D%0A
|
||||
|
||||
Some of the things we can help with:%0D%0A
|
||||
${your_apps}
|
||||
- Configuring and authenticating your apps%0D%0A
|
||||
${usecases}
|
||||
- Creating special usecases and apps%0D%0A%0D%0A
|
||||
- Multi-Tenancy and creating special usecases%0D%0A
|
||||
${cloudSyncInfo}%0D%0A
|
||||
|
||||
Let me know if you're interested, or set up a call here: https://drift.me/${username}`
|
||||
If you're interested, please let me know a time that works for you, or set up a call here: https://drift.me/${username}`
|
||||
|
||||
return `mailto:${admins}?bcc=frikky@shuffler.io,binu@shuffler.io&subject=${subject}&body=${body}`
|
||||
}
|
||||
@@ -984,6 +1004,10 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
||||
leads.push("old customer")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.old_lead) {
|
||||
leads.push("old lead")
|
||||
}
|
||||
|
||||
if (responseJson.lead_info.tech_partner) {
|
||||
leads.push("tech partner")
|
||||
}
|
||||
@@ -2428,7 +2452,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
||||
renderValue={(selected) => selected.join(', ')}
|
||||
MenuProps={MenuProps}
|
||||
>
|
||||
{["contacted", "lead", "demo done", "pov", "customer", "open source", "student", "internal", "old customer", "creator", "tech partner"].map((name) => (
|
||||
{["contacted", "lead", "demo done", "pov", "customer", "open source", "student", "internal", "creator", "tech partner", "old customer", "old lead", ].map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
<Checkbox checked={selectedStatus.indexOf(name) > -1} />
|
||||
<ListItemText primary={name} />
|
||||
@@ -3124,7 +3148,6 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
||||
}
|
||||
|
||||
if (loginInfo > 0) {
|
||||
console.log("SETTING LAST LOGIN: " + loginInfo)
|
||||
lastLogin = new Date(loginInfo * 1000).toISOString().slice(0, 10) + " (" + data.login_info.length + ")"
|
||||
}
|
||||
}
|
||||
@@ -4382,7 +4405,7 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
|
||||
<Tab
|
||||
label=<span>
|
||||
<LockIcon style={iconStyle} />
|
||||
App Authentication
|
||||
App Auth
|
||||
</span>
|
||||
/>
|
||||
<Tab
|
||||
|
||||
@@ -108,10 +108,10 @@ import {
|
||||
Preview as PreviewIcon,
|
||||
ContentCopy as ContentCopyIcon,
|
||||
Circle as CircleIcon,
|
||||
SquareFoot as SquareFootIcon,
|
||||
AutoFixHigh as AutoFixHighIcon,
|
||||
|
||||
SquareFoot as SquareFootIcon,
|
||||
AutoFixHigh as AutoFixHighIcon,
|
||||
Polyline as PolylineIcon,
|
||||
QueryStats as QueryStatsIcon,
|
||||
} from "@mui/icons-material";
|
||||
|
||||
|
||||
@@ -591,7 +591,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log("In useeffect for loopRunning: ", loopRunning)
|
||||
//console.log("In useeffect for loopRunning: ", loopRunning)
|
||||
if (loopRunning) {
|
||||
const intervalId = setInterval(() => {
|
||||
if (!loopRunning) {
|
||||
@@ -1244,7 +1244,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
// Doesn't work because this is some async garbage
|
||||
if (executionData.execution_id === undefined || (responseJson.execution_id === executionData.execution_id && responseJson.results !== undefined && responseJson.results !== null)) {
|
||||
if (executionData.status !== responseJson.status || executionData.result !== responseJson.result || (executionData.results !== undefined && responseJson.results !== null && executionData.results.length !== responseJson.results.length)) {
|
||||
console.log("Updating data!")
|
||||
//console.log("Updating data!")
|
||||
setExecutionData(responseJson)
|
||||
} else {
|
||||
if (responseJson.status === "ABORTED" || responseJson.status === "STOPPED" || responseJson.status === "FAILURE" || responseJson.status === "WAITING") {
|
||||
@@ -1713,7 +1713,9 @@ const AngularWorkflow = (defaultprops) => {
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (!responseJson.success) {
|
||||
toast("Failed to start: " + responseJson.reason);
|
||||
//toast("Failed to start: " + responseJson.reason);
|
||||
toast(responseJson.reason);
|
||||
//toast.error(responseJson.reason);
|
||||
setExecutionRunning(false);
|
||||
setExecutionRequestStarted(false);
|
||||
stop();
|
||||
@@ -4593,7 +4595,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
}
|
||||
|
||||
console.log("NODE: ", nodedata)
|
||||
if (nodedata.decorator !== true && nodedata.attachedTo === undefined) {
|
||||
var newdata = JSON.parse(JSON.stringify(nodedata))
|
||||
newdata.large_image = ""
|
||||
@@ -14591,7 +14592,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
onClose={() => {
|
||||
setExecutionModalOpen(false)
|
||||
}}
|
||||
style={{ resize: "both", overflow: "auto", zIndex: 10005 }}
|
||||
style={{ resize: "both", overflow: "auto", }}
|
||||
hideBackdrop={false}
|
||||
variant="temporary"
|
||||
BackdropProps={{
|
||||
@@ -14607,7 +14608,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
maxWidth: isMobile ? "100%" : 420,
|
||||
color: "white",
|
||||
fontSize: 18,
|
||||
zIndex: 10005,
|
||||
borderLeft: theme.palette.defaultBorder,
|
||||
},
|
||||
}}
|
||||
@@ -14631,16 +14631,32 @@ const AngularWorkflow = (defaultprops) => {
|
||||
: null}
|
||||
{executionModalView === 0 ? (
|
||||
<div style={{ padding: isMobile ? "0px 0px 0px 10px" : 25, zIndex: 12502, }}>
|
||||
<Breadcrumbs
|
||||
aria-label="breadcrumb"
|
||||
separator="›"
|
||||
style={{ color: "white", fontSize: 16 }}
|
||||
>
|
||||
<h2 style={{ color: "rgba(255,255,255,0.5)" }}>
|
||||
<DirectionsRunIcon style={{ marginRight: 10 }} />
|
||||
All Workflow Runs
|
||||
</h2>
|
||||
</Breadcrumbs>
|
||||
<div style={{display: "flex", }}>
|
||||
<Breadcrumbs
|
||||
aria-label="breadcrumb"
|
||||
separator="›"
|
||||
style={{ color: "white", fontSize: 16 }}
|
||||
>
|
||||
<h2 style={{ color: "rgba(255,255,255,0.5)" }}>
|
||||
<DirectionsRunIcon style={{ marginRight: 10 }} />
|
||||
All Workflow Runs
|
||||
</h2>
|
||||
</Breadcrumbs>
|
||||
<Tooltip
|
||||
title={"Explore Executions further"}
|
||||
placement="left-start"
|
||||
style={{ zIndex: 10010 }}
|
||||
>
|
||||
<a href={`/workflows/debug?workflow_id=${workflow.id}`} style={{textDecoration: "none", }}>
|
||||
<Button
|
||||
color="secondary"
|
||||
style={{marginLeft: 50, maxHeight: 30, marginTop: 20, }}
|
||||
>
|
||||
<QueryStatsIcon style={{color: "white", }}/>
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Button
|
||||
style={{ borderRadius: "0px" }}
|
||||
variant="outlined"
|
||||
@@ -15367,7 +15383,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}}
|
||||
onClick={() => {
|
||||
const oldstartnode = cy.getElementById(data.action.id);
|
||||
console.log("FOUND NODe: ", oldstartnode)
|
||||
//console.log("FOUND NODe: ", oldstartnode)
|
||||
if (oldstartnode !== undefined && oldstartnode !== null) {
|
||||
const foundname = oldstartnode.data("label")
|
||||
if (foundname !== undefined && foundname !== null) {
|
||||
@@ -15375,7 +15391,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Click data: ", data)
|
||||
//console.log("Click data: ", data)
|
||||
//data.action.label = ""
|
||||
setSelectedResult(data);
|
||||
setCodeModalOpen(true);
|
||||
@@ -16476,7 +16492,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
var newAuthOption = JSON.parse(JSON.stringify(authenticationOption));
|
||||
var newFields = [];
|
||||
console.log("Fields: ", newAuthOption.fields)
|
||||
console.log("Fields: ", newAuthOption.fields)
|
||||
for (let authkey in newAuthOption.fields) {
|
||||
const value = newAuthOption.fields[authkey];
|
||||
newFields.push({
|
||||
|
||||
+223
-141
@@ -242,7 +242,7 @@ export const appCategories = [
|
||||
"name": "Eradication",
|
||||
"color": "#FFC107",
|
||||
"icon": "eradication",
|
||||
"action_labels": ["List Alerts", "Close Alert", "Get Alert", "Create detection", "Block hash", "Search Hosts", "Isolate host", "Unisolate host"],
|
||||
"action_labels": ["List Alerts", "Close Alert", "Get Alert", "Create detection", "Block hash", "Search Hosts", "Isolate host", "Unisolate host", "Trigger host scan",],
|
||||
}, {
|
||||
"name": "Cases",
|
||||
"color": "#FFC107",
|
||||
@@ -374,8 +374,8 @@ const AppCreator = (defaultprops) => {
|
||||
"API key",
|
||||
"Bearer auth",
|
||||
"Basic auth",
|
||||
"Oauth2",
|
||||
"JWT",
|
||||
"Oauth2",
|
||||
];
|
||||
const apikeySelection = ["Header", "Query"];
|
||||
|
||||
@@ -411,6 +411,7 @@ const AppCreator = (defaultprops) => {
|
||||
const [appBuilding, setAppBuilding] = useState(false);
|
||||
const [fileDownloadEnabled, setFileDownloadEnabled] = useState(false);
|
||||
const [actionAmount, setActionAmount] = useState(increaseAmount);
|
||||
const [oauth2Type, setOauth2Type] = useState("application");
|
||||
const defaultAuth = {
|
||||
name: "",
|
||||
type: "header",
|
||||
@@ -1678,7 +1679,7 @@ const AppCreator = (defaultprops) => {
|
||||
value.in.length > 0
|
||||
) {
|
||||
setParameterName(value.in);
|
||||
optionset = true
|
||||
optionset = true
|
||||
}
|
||||
|
||||
} else if (value.scheme === "bearer") {
|
||||
@@ -1709,24 +1710,24 @@ const AppCreator = (defaultprops) => {
|
||||
newauth.push({
|
||||
"name": key,
|
||||
"type": value.in.toLowerCase(),
|
||||
"in": value.in.toLowerCase(),
|
||||
"in": value.in.toLowerCase(),
|
||||
"example": "",
|
||||
})
|
||||
} else {
|
||||
newauth.push({
|
||||
"name": key,
|
||||
"type": value.in.toLowerCase(),
|
||||
"in": value.in.toLowerCase(),
|
||||
"example": "",
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
newauth.push({
|
||||
"name": key,
|
||||
"type": value.in.toLowerCase(),
|
||||
"in": value.in.toLowerCase(),
|
||||
"example": "",
|
||||
})
|
||||
}
|
||||
|
||||
if (value.description !== undefined && value.description !== null && value.description.length > 0) {
|
||||
// Don't want a real description - just the ones we're replacing with
|
||||
if ((value.description.split(" ").length - 1) <= 2) {
|
||||
setRefreshUrl(value.description)
|
||||
}
|
||||
}
|
||||
// Don't want a real description - just the ones we're replacing with
|
||||
if ((value.description.split(" ").length - 1) <= 2) {
|
||||
setRefreshUrl(value.description)
|
||||
}
|
||||
}
|
||||
|
||||
} else if (value.scheme === "basic") {
|
||||
setAuthenticationOption("Basic auth");
|
||||
@@ -1734,15 +1735,15 @@ const AppCreator = (defaultprops) => {
|
||||
optionset = true
|
||||
|
||||
} else if (value.scheme === "oauth2") {
|
||||
setAuthenticationOption("Oauth2");
|
||||
setAuthenticationRequired(true);
|
||||
optionset = true
|
||||
setAuthenticationOption("Oauth2");
|
||||
setAuthenticationRequired(true);
|
||||
optionset = true
|
||||
|
||||
} else if (value.type === "oauth2" || key === "Oauth2" || key === "Oauth2c" || (key !== undefined && key !== null && key.toLowerCase().includes("oauth2"))) {
|
||||
//toast("Can't handle Oauth2 auth yet.")
|
||||
setAuthenticationOption("Oauth2");
|
||||
setAuthenticationRequired(true);
|
||||
optionset = true
|
||||
optionset = true
|
||||
|
||||
//console.log("FLOW-1: ", value)
|
||||
const flowkey = value.flow === undefined ? "flows" : "flow";
|
||||
@@ -1754,12 +1755,11 @@ const AppCreator = (defaultprops) => {
|
||||
//console.log("FLOW2: ", value[flowkey][basekey])
|
||||
if (value[flowkey] !== undefined && value[flowkey][basekey] !== undefined
|
||||
) {
|
||||
if (
|
||||
value[flowkey][basekey].authorizationUrl !== undefined &&
|
||||
parameterName.length === 0
|
||||
) {
|
||||
setParameterName(value[flowkey][basekey].authorizationUrl);
|
||||
}
|
||||
if (value[flowkey][basekey].authorizationUrl !== undefined && parameterName.length === 0) {
|
||||
setParameterName(value[flowkey][basekey].authorizationUrl);
|
||||
// } else {
|
||||
// setOauth2Type("application")
|
||||
}
|
||||
|
||||
var tokenUrl = "";
|
||||
if (value[flowkey][basekey].tokenUrl !== undefined) {
|
||||
@@ -2846,7 +2846,6 @@ const AppCreator = (defaultprops) => {
|
||||
style={{ margin: 0, flex: "1", backgroundColor: inputColor }}
|
||||
fullWidth={true}
|
||||
placeholder="/security/user/authenticate"
|
||||
type="name"
|
||||
id="standard-required"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
@@ -2866,6 +2865,40 @@ const AppCreator = (defaultprops) => {
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="textSecondary"
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
Optional: Authentication queries
|
||||
</Typography>
|
||||
{/*
|
||||
<TextField
|
||||
style={{ margin: 0, flex: "1", backgroundColor: inputColor }}
|
||||
fullWidth={true}
|
||||
placeholder="grant_type=client_credentials&scope=connect.api.read"
|
||||
id=""
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
defaultValue={parameterName}
|
||||
helperText={
|
||||
<span style={{ color: "white", marginBottom: "2px" }}>
|
||||
Must use 'key=value&key=value' format
|
||||
</span>
|
||||
}
|
||||
onBlur={(e) => {
|
||||
//setParameterName(e.target.value)
|
||||
}}
|
||||
InputProps={{
|
||||
classes: {
|
||||
notchedOutline: classes.notchedOutline,
|
||||
},
|
||||
style: {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
*/}
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
@@ -2878,56 +2911,64 @@ const AppCreator = (defaultprops) => {
|
||||
color="textSecondary"
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
Find the Authorization URL, Token URL and scopes in question for the API. Ensure the app in question is pointed at https://shuffler.io/set_authentication
|
||||
{oauth2Type === "delegated" ?
|
||||
"Find the Authorization URL, Token URL and scopes in question for the API. Ensure your app in the service uses redirect url https://shuffler.io/set_authentication"
|
||||
:
|
||||
"Find the Token URL and scopes in question for the API"
|
||||
}
|
||||
</Typography>
|
||||
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="textSecondary"
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
Base Authorization URL for Oauth2
|
||||
</Typography>
|
||||
<TextField
|
||||
required
|
||||
style={{ margin: 0, flex: "1", backgroundColor: inputColor }}
|
||||
fullWidth={true}
|
||||
placeholder="https://.../oauth2/authorize"
|
||||
type="name"
|
||||
id="standard-required"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
value={parameterName}
|
||||
onChange={(e) => setParameterName(e.target.value)}
|
||||
{oauth2Type === "delegated" ?
|
||||
<span>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="textSecondary"
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
Base Authorization URL for Oauth2
|
||||
</Typography>
|
||||
<TextField
|
||||
required
|
||||
style={{ margin: 0, flex: "1", backgroundColor: inputColor }}
|
||||
fullWidth={true}
|
||||
placeholder="https://.../oauth2/authorize"
|
||||
type="name"
|
||||
id="standard-required"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
value={parameterName}
|
||||
onChange={(e) => setParameterName(e.target.value)}
|
||||
onBlur={(event) => {
|
||||
var tmpstring = event.target.value.trim();
|
||||
var tmpstring = event.target.value.trim();
|
||||
|
||||
if (
|
||||
tmpstring.length > 4 &&
|
||||
!tmpstring.startsWith("http") &&
|
||||
!tmpstring.startsWith("ftp")
|
||||
) {
|
||||
toast("Auth URL must start with http(s)://");
|
||||
}
|
||||
if (
|
||||
tmpstring.length > 4 &&
|
||||
!tmpstring.startsWith("http") &&
|
||||
!tmpstring.startsWith("ftp")
|
||||
) {
|
||||
toast("Auth URL must start with http(s)://");
|
||||
}
|
||||
|
||||
if (tmpstring.includes("?")) {
|
||||
var newtmp = tmpstring.split("?")
|
||||
if (tmpstring.length > 1) {
|
||||
tmpstring = newtmp[0]
|
||||
}
|
||||
}
|
||||
if (tmpstring.includes("?")) {
|
||||
var newtmp = tmpstring.split("?")
|
||||
if (tmpstring.length > 1) {
|
||||
tmpstring = newtmp[0]
|
||||
}
|
||||
}
|
||||
|
||||
setParameterName(tmpstring)
|
||||
}}
|
||||
InputProps={{
|
||||
classes: {
|
||||
notchedOutline: classes.notchedOutline,
|
||||
},
|
||||
style: {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
setParameterName(tmpstring)
|
||||
}}
|
||||
InputProps={{
|
||||
classes: {
|
||||
notchedOutline: classes.notchedOutline,
|
||||
},
|
||||
style: {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
: null}
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="textSecondary"
|
||||
@@ -2977,75 +3018,79 @@ const AppCreator = (defaultprops) => {
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="textSecondary"
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
Refresh-token URL for Oauth2 (Optional)
|
||||
</Typography>
|
||||
<TextField
|
||||
style={{ margin: 0, flex: "1", backgroundColor: inputColor }}
|
||||
fullWidth={true}
|
||||
placeholder="The URL to retrieve refresh-tokens at"
|
||||
type="name"
|
||||
id="standard-required"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
value={refreshUrl}
|
||||
onChange={(e) => setRefreshUrl(e.target.value)}
|
||||
onBlur={(event) => {
|
||||
var tmpstring = event.target.value.trim();
|
||||
{oauth2Type === "delegated" ?
|
||||
<span>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="textSecondary"
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
Refresh-token URL for Oauth2 (Optional)
|
||||
</Typography>
|
||||
<TextField
|
||||
style={{ margin: 0, flex: "1", backgroundColor: inputColor }}
|
||||
fullWidth={true}
|
||||
placeholder="The URL to retrieve refresh-tokens at"
|
||||
type="name"
|
||||
id="standard-required"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
value={refreshUrl}
|
||||
onChange={(e) => setRefreshUrl(e.target.value)}
|
||||
onBlur={(event) => {
|
||||
var tmpstring = event.target.value.trim();
|
||||
|
||||
if (
|
||||
tmpstring.length > 4 &&
|
||||
!tmpstring.startsWith("http") &&
|
||||
!tmpstring.startsWith("ftp")
|
||||
) {
|
||||
toast("Refresh URL must start with http(s)://");
|
||||
}
|
||||
if (
|
||||
tmpstring.length > 4 &&
|
||||
!tmpstring.startsWith("http") &&
|
||||
!tmpstring.startsWith("ftp")
|
||||
) {
|
||||
toast("Refresh URL must start with http(s)://");
|
||||
}
|
||||
|
||||
if (tmpstring.includes("?")) {
|
||||
var newtmp = tmpstring.split("?")
|
||||
if (tmpstring.length > 1) {
|
||||
tmpstring = newtmp[0]
|
||||
}
|
||||
}
|
||||
if (tmpstring.includes("?")) {
|
||||
var newtmp = tmpstring.split("?")
|
||||
if (tmpstring.length > 1) {
|
||||
tmpstring = newtmp[0]
|
||||
}
|
||||
}
|
||||
|
||||
setRefreshUrl(tmpstring)
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="textSecondary"
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
Scopes for Oauth2
|
||||
</Typography>
|
||||
<MuiChipsInput
|
||||
style={{border: "2px solid #f86a3e", borderRadius: theme.palette.borderRadius,}}
|
||||
setRefreshUrl(tmpstring)
|
||||
}}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
: null}
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="textSecondary"
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
Scopes for Oauth2
|
||||
</Typography>
|
||||
<MuiChipsInput
|
||||
style={{border: "2px solid #f86a3e", borderRadius: theme.palette.borderRadius,}}
|
||||
required
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
maxHeight: 50,
|
||||
},
|
||||
}}
|
||||
style={{ maxHeight: 80, overflowX: "hidden", overflowY: "auto" }}
|
||||
placeholder="Available Oauth2 Scopes"
|
||||
color="primary"
|
||||
fullWidth
|
||||
value={oauth2Scopes}
|
||||
InputProps={{
|
||||
style: {
|
||||
color: "white",
|
||||
maxHeight: 50,
|
||||
},
|
||||
}}
|
||||
style={{ maxHeight: 80, overflowX: "hidden", overflowY: "auto" }}
|
||||
placeholder="Available Oauth2 Scopes (enter to add)"
|
||||
color="primary"
|
||||
fullWidth
|
||||
value={oauth2Scopes}
|
||||
onChange={(chips) => {
|
||||
setOauth2Scopes(chips)
|
||||
setUpdate(Math.random())
|
||||
}}
|
||||
/>
|
||||
/>
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
@@ -3125,7 +3170,7 @@ const AppCreator = (defaultprops) => {
|
||||
</Select>
|
||||
</div>
|
||||
<div style={{marginLeft: 5, flex: 1,}}>
|
||||
Value prefix
|
||||
Prefix
|
||||
<TextField
|
||||
style={{ marginTop: 0, flex: "1", backgroundColor: inputColor }}
|
||||
fullWidth={true}
|
||||
@@ -3137,7 +3182,7 @@ const AppCreator = (defaultprops) => {
|
||||
value={refreshUrl}
|
||||
onChange={(e) => {
|
||||
// Just reusing this state
|
||||
setRefreshUrl(e.target.value);
|
||||
setRefreshUrl(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -3618,13 +3663,13 @@ const AppCreator = (defaultprops) => {
|
||||
<Dialog
|
||||
open={actionsModalOpen}
|
||||
fullWidth
|
||||
PaperProps={{
|
||||
PaperProps={{
|
||||
style: {
|
||||
backgroundColor: surfaceColor,
|
||||
color: "white",
|
||||
minWidth: 500,
|
||||
maxWidth: 500,
|
||||
maxHeight: 800,
|
||||
minWidth: 550,
|
||||
maxWidth: 550,
|
||||
maxHeight: 750,
|
||||
},
|
||||
}}
|
||||
onClose={() => {
|
||||
@@ -5865,6 +5910,7 @@ const AppCreator = (defaultprops) => {
|
||||
}}
|
||||
/>
|
||||
<div style={{padding: 25, border: "2px solid rgba(255,255,255,0.7)", borderRadius: theme.palette.borderRadius, }}>
|
||||
<span style={{display: "flex", }}>
|
||||
<FormControl style={{ }} variant="outlined">
|
||||
<Typography variant="h6">Authentication</Typography>
|
||||
<a
|
||||
@@ -5889,7 +5935,7 @@ const AppCreator = (defaultprops) => {
|
||||
setParameterLocation("")
|
||||
}
|
||||
|
||||
setExtraAuth([])
|
||||
setExtraAuth([])
|
||||
}
|
||||
}}
|
||||
value={authenticationOption}
|
||||
@@ -5910,6 +5956,42 @@ const AppCreator = (defaultprops) => {
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
{authenticationOption === "Oauth2" ?
|
||||
<FormControl style={{ marginLeft: 350, maxWidth: 200, }} variant="outlined">
|
||||
{/*
|
||||
<Typography variant="body2">
|
||||
- Delegated: The user will get a popup for access their personal data.
|
||||
- Application: Permissions are set by the app creator in the 3rd party platform.
|
||||
</Typography>
|
||||
*/}
|
||||
<Select
|
||||
fullWidth
|
||||
label="Oauth2 type"
|
||||
onChange={(e) => {
|
||||
setOauth2Type(e.target.value);
|
||||
}}
|
||||
value={oauth2Type}
|
||||
style={{
|
||||
backgroundColor: inputColor,
|
||||
color: "white",
|
||||
height: "50px",
|
||||
}}
|
||||
>
|
||||
{["delegated", "application"].map((data, index) => (
|
||||
<MenuItem
|
||||
key={index}
|
||||
style={{ backgroundColor: inputColor, color: "white" }}
|
||||
value={data}
|
||||
>
|
||||
{data}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
: null}
|
||||
</span>
|
||||
|
||||
|
||||
<div style={{marginTop: 15 }} />
|
||||
{basicAuth}
|
||||
{bearerAuth}
|
||||
|
||||
@@ -419,7 +419,7 @@ const Welcome = (props) => {
|
||||
</div>
|
||||
:
|
||||
<Fade in={true}>
|
||||
<div style={{maxWidth: isMobile ? null : 590, margin: "auto", marginTop: 50, }}>
|
||||
<div style={{maxWidth: isMobile ? null : 590, margin: "auto", marginTop: 50,textAlign : isMobile ? "center" : null }}>
|
||||
<Typography variant="h4" style={{color: "#F1F1F1", marginTop: 50, fontSize: 32}}>
|
||||
Help us get to know you
|
||||
</Typography>
|
||||
|
||||
@@ -68,11 +68,12 @@ import {
|
||||
CloudDownload as CloudDownloadIcon,
|
||||
ExpandLess as ExpandLessIcon,
|
||||
ExpandMore as ExpandMoreIcon,
|
||||
Done as DoneIcon,
|
||||
CheckCircle as CheckCircleIcon,
|
||||
RadioButtonUnchecked as RadioButtonUncheckedIcon,
|
||||
Done as DoneIcon,
|
||||
CheckCircle as CheckCircleIcon,
|
||||
RadioButtonUnchecked as RadioButtonUncheckedIcon,
|
||||
ArrowLeft as ArrowLeftIcon,
|
||||
ArrowRight as ArrowRightIcon,
|
||||
QueryStats as QueryStatsIcon,
|
||||
} from "@mui/icons-material";
|
||||
|
||||
import { DataGrid, GridToolbar } from "@mui/x-data-grid";
|
||||
@@ -3061,6 +3062,18 @@ const Workflows = (props) => {
|
||||
|
||||
const workflowButtons = (
|
||||
<span>
|
||||
<Tooltip color="primary" title={"Explore Workflow Runs"} placement="top">
|
||||
<Button
|
||||
disabled={workflows.length === 0}
|
||||
color="secondary"
|
||||
variant="text"
|
||||
onClick={() => {
|
||||
navigate("/workflows/debug")
|
||||
}}
|
||||
>
|
||||
<QueryStatsIcon />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
{view === "list" && (
|
||||
<Tooltip color="primary" title={"Grid View"} placement="top">
|
||||
<Button
|
||||
@@ -3423,8 +3436,8 @@ const Workflows = (props) => {
|
||||
height: isCloud ? imgSize : imgSize+4,
|
||||
width: isCloud ? imgSize : imgSize+4,
|
||||
position: "absolute",
|
||||
top: isCloud ? -1 : -2,
|
||||
left: isCloud ? -1 : -2,
|
||||
top: -2,
|
||||
left: -2,
|
||||
cursor: "pointer",
|
||||
zIndex: 99,
|
||||
border: "2px solid rgba(255,255,255,0.7)",
|
||||
@@ -3786,7 +3799,7 @@ const Workflows = (props) => {
|
||||
color: "white",
|
||||
fontSize: 18,
|
||||
borderLeft: theme.palette.defaultBorder,
|
||||
marginTop: 64,
|
||||
marginTop: 100,
|
||||
borderRadius: "5px 0px 0px 0px",
|
||||
},
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user