Fixed merge conflicts

This commit is contained in:
frikky
2023-07-06 17:39:40 +02:00
209 changed files with 1826 additions and 68 deletions
Regular → Executable
View File
Regular → Executable
View File
View File
View File
View File
View File
Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 449 KiB

After

Width:  |  Height:  |  Size: 449 KiB

View File

Before

Width:  |  Height:  |  Size: 431 KiB

After

Width:  |  Height:  |  Size: 431 KiB

View File

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Regular → Executable
View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 143 KiB

View File

Before

Width:  |  Height:  |  Size: 440 KiB

After

Width:  |  Height:  |  Size: 440 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Regular → Executable
View File
View File
View File
View File
View File
View File
View File
View File
View File
+78 -4
View File
@@ -2,6 +2,7 @@ import React, { useRef, useState, useEffect, useLayoutEffect } from "react";
import { useParams, useNavigate, Link } from "react-router-dom";
import { useTheme } from "@material-ui/core/styles";
import theme from '../theme.jsx';
import { useAlert } from "react-alert";
import { v4 as uuidv4 } from "uuid";
import {
@@ -97,6 +98,7 @@ const AuthenticationOauth2 = (props) => {
} = props;
let navigate = useNavigate();
const alert = useAlert()
//const [update, setUpdate] = React.useState("|")
const [defaultConfigSet, setDefaultConfigSet] = React.useState(
@@ -282,6 +284,51 @@ const AuthenticationOauth2 = (props) => {
}
const handleOauth2Request = (client_id, client_secret, oauth_url, scopes, admin_consent, prompt) => {
setButtonClicked(true);
//console.log("SCOPES: ", scopes);
client_id = client_id.trim()
client_secret = client_secret.trim()
oauth_url = oauth_url.trim()
var resources = "";
if (scopes !== undefined && (scopes !== null) & (scopes.length > 0)) {
console.log("IN scope 1")
if (offlineAccess === true && !scopes.includes("offline_access")) {
console.log("IN scope 2")
if (!authenticationType.redirect_uri.includes("google")) {
console.log("Appending offline access")
scopes.push("offline_access")
}
}
resources = scopes.join(" ");
//resources = scopes.join(",");
}
const authentication_url = authenticationType.token_uri;
//console.log("AUTH: ", authenticationType)
//console.log("SCOPES2: ", resources)
const redirectUri = `${window.location.protocol}//${window.location.host}/set_authentication`;
const workflowId = workflow !== undefined ? workflow.id : "";
var state = `workflow_id%3D${workflowId}%26reference_action_id%3d${selectedAction.app_id}%26app_name%3d${selectedAction.app_name}%26app_id%3d${selectedAction.app_id}%26app_version%3d${selectedAction.app_version}%26authentication_url%3d${authentication_url}%26scope%3d${resources}%26client_id%3d${client_id}%26client_secret%3d${client_secret}`;
// This is to make sure authorization can be handled WITHOUT being logged in,
// kind of making it act like an api key
// https://shuffler.io/authorization -> 3rd party integration auth
const urlParams = new URLSearchParams(window.location.search);
const userAuth = urlParams.get("authorization");
if (userAuth !== undefined && userAuth !== null && userAuth.length > 0) {
console.log("Adding authorization from user side")
state += `%26authorization%3d${userAuth}`;
}
// write:request:jira-service-management
}
const handleOauth2Request = (client_id, client_secret, oauth_url, scopes, admin_consent, prompt) => {
setButtonClicked(true);
//console.log("SCOPES: ", scopes);
@@ -317,6 +364,35 @@ const AuthenticationOauth2 = (props) => {
console.log("ADDING OAUTH2 URL: ", state);
}
if (
authenticationType.refresh_uri !== undefined &&
authenticationType.refresh_uri !== null &&
authenticationType.refresh_uri.length > 0
) {
state += `%26refresh_uri%3d${authenticationType.refresh_uri}`;
} else {
state += `%26refresh_uri%3d${authentication_url}`;
}
// No prompt forcing
//var url = `${authenticationType.redirect_uri}?client_id=${client_id}&redirect_uri=${redirectUri}&response_type=code&prompt=login&scope=${resources}&state=${state}&access_type=offline`;
var defaultPrompt = "login"
if (prompt !== undefined && prompt !== null && prompt.length > 0) {
defaultPrompt = prompt
}
// Check for org_id
const orgId = urlParams.get("org_id");
if (orgId !== undefined && orgId !== null && orgId.length > 0) {
console.log("Adding org_id from user side")
state += `%26org_id%3d${orgId}`;
}
if (oauth_url !== undefined && oauth_url !== null && oauth_url.length > 0) {
state += `%26oauth_url%3d${oauth_url}`;
console.log("ADDING OAUTH2 URL: ", state);
}
if (
authenticationType.refresh_uri !== undefined &&
authenticationType.refresh_uri !== null &&
@@ -356,7 +432,7 @@ const AuthenticationOauth2 = (props) => {
// How can we get a callback properly realtime?
// How can we properly try-catch without breaks on error?
try {
var newwin = window.open(url, "", "width=800,height=600");
var newwin = window.open(url, "", "width=582,height=700");
//console.log(newwin)
var open = true;
@@ -447,9 +523,7 @@ const AuthenticationOauth2 = (props) => {
] = "false";
} else {
alert.info(
"Field " +
selectedApp.authentication.parameters[key].name +
" can't be empty"
"Field " + selectedApp.authentication.parameters[key].name.replace("_basic", "", -1).replace("_", " ", -1) + " can't be empty"
);
return;
}
File diff suppressed because one or more lines are too long
+4 -1
View File
@@ -1595,6 +1595,7 @@ const ParsedAction = (props) => {
maxWidth: "95%",
fontSize: "1em",
},
disableUnderline: true,
endAdornment: hideExtraTypes ? null : (
<InputAdornment position="end">
<ButtonGroup orientation={multiline ? "vertical" : "horizontal"}>
@@ -2958,6 +2959,7 @@ const ParsedAction = (props) => {
style={theme.palette.textFieldStyle}
InputProps={{
style: theme.palette.innerTextfieldStyle,
disableUnderline: true,
}}
fullWidth
color="primary"
@@ -3177,6 +3179,7 @@ const ParsedAction = (props) => {
}}
InputProps={{
style: theme.palette.innerTextfieldStyle,
disableUnderline: true,
}}
placeholder={selectedAction.execution_delay}
defaultValue={selectedAction.execution_delay}
@@ -3492,7 +3495,7 @@ const ParsedAction = (props) => {
</li>
)
}}
options={selectedApp.actions.filter((a) => a.category_label !== undefined && a.category_label !== null && a.category_label.length > 0).concat(sortByKey(selectedApp.actions, "label"))}
options={selectedApp.actions === undefined || selectedApp.actions === null ? [] : selectedApp.actions.filter((a) => a.category_label !== undefined && a.category_label !== null && a.category_label.length > 0).concat(sortByKey(selectedApp.actions, "label"))}
ListboxProps={{
style: {
backgroundColor: theme.palette.inputColor,
View File
View File
View File
+16 -7
View File
@@ -1694,20 +1694,29 @@ const CodeEditor = (props) => {
cursor: "pointer"
}}
onClick={(event) => {
// Take localcodedata through the Shuffle JSON parser just in case
// This is to make it so we don't need to handle these fixes on the
// backend by itself
var fixedcodedata = localcodedata
const valid = validateJson(localcodedata, true)
if (valid.valid) {
fixedcodedata = JSON.stringify(valid.result, null, 2)
}
// console.log(codedata)
// console.log(fieldCount)
if (isFileEditor === true){
runUpdateText(localcodedata);
setcodedata(localcodedata);
runUpdateText(fixedcodedata);
setcodedata(fixedcodedata);
setExpansionModalOpen(false)
} else {
changeActionParameterCodeMirror(event, fieldCount, fixedcodedata)
setExpansionModalOpen(false)
setcodedata(fixedcodedata)
}
else {
changeActionParameterCodeMirror(event, fieldCount, localcodedata)
setExpansionModalOpen(false)
setcodedata(localcodedata)}
}}
>
Done
Submit
</button>
</div>
</Dialog>)
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
+12 -4
View File
@@ -443,17 +443,17 @@ 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%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 I'm not sure if you're getting the most out of Shuffle.%0D%0A%0D%0AIf 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
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
Some of the things we can help with:%0D%0A
${your_apps}
- Properly authenticating and custom building apps%0D%0A
- Configuring and authenticating your apps%0D%0A
${usecases}
- Creating special usecases%0D%0A%0D%0A
- Creating special usecases and apps%0D%0A%0D%0A
Let me know if you're interested, or set up a call here: https://drift.me/${username}`
return `mailto:${admins}?subject=${subject}&body=${body}`
return `mailto:${admins}?bcc=frikky@shuffler.io&subject=${subject}&body=${body}`
}
const deleteAuthentication = (data) => {
@@ -3532,8 +3532,12 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
<div style={{ marginTop: 20, marginBottom: 20 }}>
<h2 style={{ display: "inline" }}>App Authentication</h2>
<span style={{ marginLeft: 25 }}>
<<<<<<< HEAD
Control the authentication options for individual apps. PS: Actions
performed here can be destructive!
=======
Control the authentication options for individual apps.
>>>>>>> master
</span>
&nbsp;
<a
@@ -3542,7 +3546,11 @@ Let me know if you're interested, or set up a call here: https://drift.me/${user
href="/docs/organizations#app_authentication"
style={{ textDecoration: "none", color: "#f85a3e" }}
>
<<<<<<< HEAD
Learn more about authentication
=======
Learn more about App Authentication
>>>>>>> master
</a>
</div>
<Divider
View File
+42 -21
View File
@@ -4638,7 +4638,8 @@ const AngularWorkflow = (defaultprops) => {
};
const addSuggestionButtons = (nodedata, event) => {
//console.log("In suggestion buttons: ", nodedata, ". This is not enabled yet. Backend needs further work.")
console.log("In suggestion buttons: ", nodedata, ". This is not enabled yet. Backend needs further work.")
return
// Skipping add for now. Should Re-enable
// Add a button for autocompletion based on input
@@ -4677,8 +4678,6 @@ const AngularWorkflow = (defaultprops) => {
cy.add(decoratorNode);
}
return
//setWorkflowRecommendations(responseJson.actions)
if (workflowRecommendations.length === 0) {
@@ -14561,9 +14560,7 @@ const AngularWorkflow = (defaultprops) => {
? "red"
: yellow;
const validate = !codeModalOpen
? ""
: validateJson(selectedResult.result.trim());
const validate = ! codeModalOpen? "" : validateJson(selectedResult.result.trim());
if (validate.valid && typeof validate.result === "string") {
validate.result = JSON.parse(validate.result);
@@ -14573,12 +14570,17 @@ const AngularWorkflow = (defaultprops) => {
const [open, setOpen] = React.useState(false)
const showVariable = data.value.length < 60
// Check if it's valid JSON
const checked = validateJson(data.value.trim())
return (
<div style={{ maxWidth: 600, overflowX: "hidden", }}>
{data.value.length > 60 ?
{data.value.length > 60 || checked.valid ?
<IconButton
style={{
marginBottom: 0, marginTop: 5, cursor: "pointer",
marginBottom: 0,
marginTop: 5,
cursor: "pointer",
padding: 3,
border: "1px solid rgba(255,255,255,0.3)",
borderRadius: theme.palette.borderRadius,
@@ -14593,7 +14595,16 @@ const AngularWorkflow = (defaultprops) => {
variant="body1"
style={{}}
>
<b>{data.name}</b> {showVariable ? data.value : null}
<b>{data.name}</b>
{checked.valid ?
<Chip
style={{marginLeft: 10, padding: 0, cursor: "pointer",}}
label={"JSON"}
variant="outlined"
color="secondary"
/>
: null}
{showVariable ? data.value : null}
</Typography>
</IconButton>
:
@@ -14605,15 +14616,25 @@ const AngularWorkflow = (defaultprops) => {
</Typography>
}
{open ?
<Typography
variant="body2"
style={{
whiteSpace: 'pre-line',
}}
color="textSecondary"
>
{data.value}
</Typography>
checked.valid ?
<ReactJson
src={checked.result}
theme={theme.palette.jsonTheme}
style={theme.palette.reactJsonStyle}
collapsed={data.value.length < 10000 ? false : true}
displayDataTypes={false}
name={"Parsed data for variable " + data.name}
/>
:
<Typography
variant="body2"
style={{
whiteSpace: 'pre-line',
}}
color="textSecondary"
>
{data.value}
</Typography>
: null}
</div>
)
@@ -15071,10 +15092,10 @@ const AngularWorkflow = (defaultprops) => {
>
<FormControl>
<DialogTitle id="draggable-dialog-title" style={{ cursor: "move", }}>
<span style={{ color: "white" }}>Execution Variable</span>
<span style={{ color: "white" }}>Runtime Variable</span>
</DialogTitle>
<DialogContent>
Execution Variables are TEMPORARY variables that you can only be set
Runtime Variables are TEMPORARY variables that you can only be set
and used during execution. Learn more{" "}
<a
rel="noopener noreferrer"
@@ -15095,7 +15116,7 @@ const AngularWorkflow = (defaultprops) => {
},
}}
margin="dense"
label="Name"
label="Name"
fullWidth
defaultValue={newVariableName}
/>
View File
Regular → Executable
View File
+345
View File
@@ -0,0 +1,345 @@
import React, { useState } from 'react';
import { BrowserView, MobileView } from "react-device-detect";
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import { useTheme } from '@material-ui/core/styles';
const bodyDivStyle = {
margin: "auto",
textAlign: "center",
width: "900px",
}
// Should be different if logged in :|
const Contact = (props) => {
const { globalUrl, isLoaded } = props;
const theme = useTheme();
const boxStyle = {
flex: "1",
marginLeft: "10px",
marginRight: "10px",
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
backgroundColor: theme.palette.surfaceColor,
display: "flex",
flexDirection: "column"
}
const bodyTextStyle = {
color: "#ffffff",
}
const [firstname, setFirstname] = useState("");
const [lastname, setLastname] = useState("");
const [title, setTitle] = useState("");
const [companyname, setCompanyname] = useState("");
const [email, setEmail] = useState("");
const [phone, setPhone] = useState("");
const [message, setMessage] = useState("");
const [formMessage, setFormMessage] = useState("");
const submitContact = () => {
const data = {
"firstname": firstname,
"lastname": lastname,
"title": title,
"companyname": companyname,
"email": email,
"phone": phone,
"message": message,
}
console.log(data)
fetch(globalUrl + "/api/v1/contact", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then(response => response.json())
.then(response => {
if (response.success === true) {
setFormMessage(response.message)
} else {
setFormMessage("Something went wrong. Please contact frikky@shuffler.io.")
}
console.log(response)
})
.catch(error => {
console.log(error)
});
}
// Random names for type & autoComplete. Didn't research :^)
const landingpageDataBrowser =
<div>
<div style={bodyTextStyle}>
<h3 style={{ color: "#f85a3e" }}>Contact us</h3>
<h2>Lets talk!</h2>
</div>
<div style={{ display: "flex" }}>
<Paper style={boxStyle}>
<h2>Contact Details</h2>
<div style={{ flex: "1", display: "flex", flexDirection: "row" }}>
<TextField
required
style={{ flex: "1", marginRight: "15px", backgroundColor: theme.palette.inputColor }}
InputProps={{
style: {
color: "white",
},
}}
color="primary"
fullWidth={true}
placeholder="First Name"
type="firstname"
id="standard-required"
autoComplete="firstname"
margin="normal"
variant="outlined"
onChange={e => setFirstname(e.target.value)}
/>
<TextField
style={{ flex: "1", marginLeft: "15px", backgroundColor: theme.palette.inputColor }}
InputProps={{
style: {
color: "white",
},
}}
color="primary"
fullWidth={true}
placeholder="Last Name"
type="lastname"
id="standard"
autoComplete="lastname"
margin="normal"
variant="outlined"
onChange={e => setLastname(e.target.value)}
/>
</div>
<div style={{ flex: "1", display: "flex", flexDirection: "row" }}>
<TextField
style={{ flex: "1", marginRight: "15px", backgroundColor: theme.palette.inputColor }}
InputProps={{
style: {
color: "white",
},
}}
color="primary"
fullWidth={true}
placeholder="Job Title"
type="jobtitle"
id="standard-required"
autoComplete="jobtitle"
margin="normal"
variant="outlined"
onChange={e => setTitle(e.target.value)}
/>
<TextField
style={{ flex: "1", marginLeft: "15px", backgroundColor: theme.palette.inputColor }}
InputProps={{
style: {
color: "white",
},
}}
color="primary"
fullWidth={true}
type="companyname"
placeholder="Company Name"
id="standard-required"
autoComplete="companyname"
margin="normal"
variant="outlined"
onChange={e => setCompanyname(e.target.value)}
/>
</div>
<div style={{ flex: "1", display: "flex", flexDirection: "row" }}>
<TextField
required
style={{ flex: "1", marginRight: "15px", backgroundColor: theme.palette.inputColor }}
InputProps={{
style: {
color: "white",
},
}}
color="primary"
fullWidth={true}
placeholder="Email"
type="email"
id="standard-required"
autoComplete="email"
margin="normal"
variant="outlined"
onChange={e => setEmail(e.target.value)}
/>
<TextField
style={{ flex: "1", marginLeft: "15px", backgroundColor: theme.palette.inputColor }}
InputProps={{
style: {
color: "white",
},
}}
color="primary"
fullWidth={true}
type="phone"
placeholder="Phone number"
id="standard-required"
autoComplete="phone"
margin="normal"
variant="outlined"
onChange={e => setPhone(e.target.value)}
/>
</div>
<div style={{ flex: 1 }}>
<h2>Message</h2>
</div>
<div style={{ flex: 4 }}>
<TextField
multiline
InputProps={{
style: {
color: "white",
},
}}
color="primary"
style={{ flex: "1", backgroundColor: theme.palette.inputColor }}
rows="6"
fullWidth={true}
placeholder="What can we help you with?"
id="filled-multiline-static"
margin="normal"
variant="outlined"
onChange={e => setMessage(e.target.value)}
/>
</div>
<Button
disabled={email.length <= 0 || message.length <= 0}
style={{ width: "100%", height: "60px", marginTop: "10px" }}
variant="contained"
color="primary"
onClick={submitContact}
>
Submit
</Button>
<h3>{formMessage}</h3>
</Paper>
</div>
</div>
const landingpageDataMobile =
<div style={{ paddingBottom: "50px" }}>
<div style={{ color: "white", textAlign: "center" }}>
<h3 style={{ color: "#f85a3e" }}>Contact us</h3>
<h2>Lets talk!</h2>
</div>
<div style={{ display: "flex" }}>
<Paper style={boxStyle}>
<h2>Contact Details</h2>
<div style={{ flex: "1", display: "flex", flexDirection: "row" }}>
<TextField
required
style={{ flex: "1", backgroundColor: theme.palette.inputColor }}
InputProps={{
style: {
color: "white",
},
}}
color="primary"
fullWidth={true}
placeholder="Name"
type="firstname"
id="standard-required"
autoComplete="firstname"
margin="normal"
variant="outlined"
onChange={e => setFirstname(e.target.value)}
/>
</div>
<div style={{ flex: "1", display: "flex", flexDirection: "row" }}>
<TextField
required
style={{ flex: "1", backgroundColor: theme.palette.inputColor }}
InputProps={{
style: {
color: "white",
},
}}
color="primary"
fullWidth={true}
placeholder="Email"
type="email"
id="standard-required"
autoComplete="email"
margin="normal"
variant="outlined"
onChange={e => setEmail(e.target.value)}
/>
</div>
<div style={{ flex: 1 }}>
<h2>Message</h2>
</div>
<div style={{ flex: 4 }}>
<TextField
multiline
style={{ flex: "1", backgroundColor: theme.palette.inputColor }}
InputProps={{
style: {
color: "white",
},
}}
color="primary"
rows="6"
fullWidth={true}
placeholder="What can we help you with?"
id="filled-multiline-static"
margin="normal"
variant="outlined"
onChange={e => setMessage(e.target.value)}
/>
</div>
<Button
disabled={email.length <= 0 || message.length <= 0}
style={{ width: "100%", height: "60px", marginTop: "10px" }}
variant="contained"
color="primary"
onClick={submitContact}
>
Submit
</Button>
<h3>{formMessage}</h3>
</Paper>
</div>
</div>
const loadedCheck = isLoaded ?
<div>
<BrowserView>
<div style={bodyDivStyle}>{landingpageDataBrowser}</div>
</BrowserView>
<MobileView>
{landingpageDataMobile}
</MobileView>
</div>
:
<div>
</div>
return (
<div>
{loadedCheck}
</div>
)
}
export default Contact;
Regular → Executable
View File
Regular → Executable
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
View File
View File
View File
Regular → Executable
View File
+26 -19
View File
@@ -6,10 +6,16 @@ import theme from '../theme.jsx';
const SetAuthentication = (props) => {
const { globalUrl } = props;
var headers = {
"Content-Type": "application/json",
"Accept": "application/json",
}
const [firstRequest, setFirstRequest] = useState(true);
const [finished, setFinished] = useState(false);
const [response, setResponse] = useState("");
const [failed, setFailed] = useState(false);
const [requestHeaders, setRequestHeaders] = useState(headers);
if (firstRequest) {
setFirstRequest(false);
@@ -20,6 +26,8 @@ const SetAuthentication = (props) => {
const params = Object.fromEntries(urlSearchParams.entries());
console.log("PARAMS: ", params)
//const authenticationStore = [];
var appAuthData = {
label: "",
@@ -40,7 +48,6 @@ const SetAuthentication = (props) => {
});
}
if (params.session_state !== undefined && params.session_state !== null) {
appAuthData.fields.push({
key: "session_state",
@@ -83,6 +90,14 @@ const SetAuthentication = (props) => {
continue;
}
if (query[0] === "org_id") {
headers["Org-Id"] = query[1]
}
if (query[0] === "authorization") {
headers["Authorization"] = "Bearer " + query[1]
}
if (query[0] === "workflow_id") {
appAuthData.reference_workflow = query[1];
}
@@ -136,6 +151,8 @@ const SetAuthentication = (props) => {
appAuthData.fields.push({ key: "refresh_url", value: query[1] });
}
}
setRequestHeaders(headers)
}
if (foundScope !== undefined && foundScope !== null && foundScope.length > 0) {
@@ -153,15 +170,13 @@ const SetAuthentication = (props) => {
setFailed(true)
setResponse(`${foundTab}`)
} else {
if (externalData.handleExternal) {
console.log("RUN EXTERNAL!!: ", externalData)
fetch(globalUrl + "/api/v1/triggers/github/register", {
method: "PUT",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
headers: requestHeaders,
credentials: "include",
body: JSON.stringify(externalData),
})
@@ -191,7 +206,6 @@ const SetAuthentication = (props) => {
.then((responseJson) => {
//setUserSettings(responseJson)
console.log("Resp: ", responseJson);
if (responseJson.reason !== undefined) {
setResponse(responseJson.reason);
setFinished(true);
@@ -227,23 +241,16 @@ const SetAuthentication = (props) => {
fetch(globalUrl + "/api/v1/apps/authentication", {
method: "PUT",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
headers: requestHeaders,
credentials: "include",
body: JSON.stringify(appAuthData),
})
.then((response) => {
const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search;
const tmpView = new URLSearchParams(cursearch).get("state");
if (
tmpView !== undefined &&
tmpView !== null &&
tmpView.length > 0
) {
console.log("State to find app name from: ", tmpView)
}
const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search;
const tmpView = new URLSearchParams(cursearch).get("state");
if (tmpView !== undefined && tmpView !== null && tmpView.length > 0) {
console.log("State to find app name from: ", tmpView)
}
if (response.status !== 200) {
console.log("Status not 200 for oauth2 authentication");
View File
View File
+172
View File
@@ -0,0 +1,172 @@
import React, { useState, useEffect } from "react";
import ReactGA from "react-ga4";
import {
Typography,
CircularProgress,
Button,
} from "@material-ui/core";
import theme from '../theme.jsx';
import { useAlert } from "react-alert";
import AuthenticationOauth2 from "../components/Oauth2Auth.jsx";
import AuthenticationWindow from "../components/AuthenticationWindow.jsx";
import { base64_decode, appCategories } from "../views/AppCreator.jsx";
const SetAuthentication = (props) => {
const { globalUrl, serverside } = props;
const [app, setApp] = useState({});
const [isAppLoaded, setIsAppLoaded] = useState(false);
const [loadFail, setLoadFail] = useState("");
const [appAuthentication, setAppAuthentication] = React.useState([]);
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
const alert = useAlert();
const parseIncomingOpenapiData = (data) => {
if (data.app === undefined || data.app === null) {
return
}
// Should basically always be true if openapi exists too
var parsedBaseapp = ""
try {
parsedBaseapp = base64_decode(data.app)
} catch (e) {
console.log("Failed JSON parsing: ", e)
parsedBaseapp = data
}
var parsedapp = JSON.parse(parsedBaseapp)
parsedapp.name = parsedapp.name.replaceAll("_", " ");
setApp(parsedapp);
document.title = parsedapp.name + " App Auth";
}
console.log("App: ", app)
const getApp = (appid) => {
if (serverside === true) {
return;
}
fetch(`${globalUrl}/api/v1/apps/${appid}/config`, {
method: "GET",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
if (isCloud) {
ReactGA.event({
category: "appauth",
action: `app_not_found`,
label: appid,
});
}
} else {
if (isCloud) {
ReactGA.event({
category: "appauth",
action: `app_found`,
label: appid,
});
}
}
return response.json();
})
.then((responseJson) => {
if (responseJson.success === false || responseJson.success === undefined) {
alert.error("Failed to get the app. Does it exist?")
setIsAppLoaded(true)
return;
}
parseIncomingOpenapiData(responseJson);
})
.catch((error) => {
alert.error("Error in app fetch: " + error.toString());
});
};
useEffect(() => {
// Find the ID for the app from the "app_id" query
const urlParams = new URLSearchParams(window.location.search);
const appid = urlParams.get("app_id");
if (appid === null) {
setLoadFail(
<span>
<Typography variant="h4">
Failed to load the app. Please contact your provider or support@shuffler.io if this persists
</Typography>
<Button
variant="contained"
color="primary"
onClick={() => window.location.reload()}
>
Reload Window
</Button>
</span>
)
} else {
getApp(appid);
}
}, []);
// Handle:
// 1. Check for org_id, authentication, and app keys in queries
// 2. Load the app auth info from the orgs' apps
// 3. Help them set info for the app
// Make sure to test both private and public apps
const appname = app.name !== undefined ? app.name : "";
return (
<div style={{width: 1000, margin: "auto", marginTop: 50, }}>
{loadFail !== "" ?
loadFail
:
<div>
<Typography variant="h4" style={{marginBottom: 20,}}>
Configure {appname} Authentication
</Typography>
{app.authentication === undefined || app.authentication === null || app.authentication.length === 0 ?
null
:
app.authentication.type === "oauth2" ?
<AuthenticationOauth2
selectedApp={app}
selectedAction={{
"app_name": app.name,
"app_id": app.id,
"app_version": app.version,
"large_image": app.large_image,
}}
authenticationType={app.authentication}
isCloud={true}
authButtonOnly={true}
getAppAuthentication={undefined}
/>
:
<AuthenticationWindow
globalUrl={globalUrl}
selectedApp={app}
authFieldsOnly={true}
getAppAuthentication={undefined}
appAuthentication={appAuthentication}
/>
}
</div>
}
</div>
)
};
export default SetAuthentication;
Regular → Executable
View File
Regular → Executable
+15 -1
View File
@@ -462,7 +462,21 @@ export const validateJson = (showResult) => {
try {
var newstr = showResult.replaceAll("'", '"')
//console.log("Try replacements and trimming with new value: ", newstr)
// Basic workarounds for issues with Python Dicts -> JSON
if (newstr.includes(": None")) {
newstr = newstr.replaceAll(": None", ': null')
}
if (newstr.includes("[\"{") && newstr.includes("}\"]")) {
newstr = newstr.replaceAll("[\"{", '[{')
newstr = newstr.replaceAll("}\"]", '}]')
}
if (newstr.includes("{\"[") && newstr.includes("]\"}")) {
newstr = newstr.replaceAll("{\"[", '[{')
newstr = newstr.replaceAll("]\"}", '}]')
}
result = JSON.parse(newstr)
jsonvalid = true
} catch (e) {