Ran prettier on the whole frontend codebase again

This commit is contained in:
Isoporhode
2021-11-14 23:50:59 +01:00
parent b5c977ae4e
commit 7e38eb96eb
62 changed files with 42481 additions and 31383 deletions
+1
View File
@@ -1,4 +1,5 @@
# Certificate:
Creating a localhost certificate:
```
+8 -6
View File
@@ -1,13 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Shuffle</title>
</head>
<body>
<div id="root"></div>
+535 -218
View File
@@ -1,9 +1,9 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect } from "react";
import { Route } from 'react-router';
import { BrowserRouter } from 'react-router-dom';
import { CookiesProvider } from 'react-cookie';
import { removeCookies, useCookies } from 'react-cookie';
import { Route } from "react-router";
import { BrowserRouter } from "react-router-dom";
import { CookiesProvider } from "react-cookie";
import { removeCookies, useCookies } from "react-cookie";
import EditSchedule from "./views/EditSchedule";
import Schedules from "./views/Schedules";
@@ -12,10 +12,10 @@ import Workflows from "./views/Workflows";
import EditWebhook from "./views/EditWebhook";
import AngularWorkflow from "./views/AngularWorkflow";
import Header from './components/Header';
import theme from './theme'
import Apps from './views/Apps';
import AppCreator from './views/AppCreator';
import Header from "./components/Header";
import theme from "./theme";
import Apps from "./views/Apps";
import AppCreator from "./views/AppCreator";
import Dashboard from "./views/Dashboard";
import AdminSetup from "./views/AdminSetup";
@@ -31,242 +31,559 @@ import SettingsPage from "./views/SettingsPage";
import MyView from "./views/MyView";
import { createMuiTheme, MuiThemeProvider } from '@material-ui/core/styles';
import { createMuiTheme, MuiThemeProvider } from "@material-ui/core/styles";
import ScrollToTop from "./components/ScrollToTop";
import AlertTemplate from "./components/AlertTemplate";
import { positions, Provider } from "react-alert";
import {isMobile} from "react-device-detect";
import { isMobile } from "react-device-detect";
import detectEthereumProvider from '@metamask/detect-provider';
import detectEthereumProvider from "@metamask/detect-provider";
// Production - backend proxy forwarding in nginx
var globalUrl = window.location.origin
var globalUrl = window.location.origin;
// CORS used for testing purposes. Should only happen with specific port and http
if ( window.location.port === "3000") {
globalUrl = "http://localhost:5001"
//globalUrl = "http://localhost:5002"
if (window.location.port === "3000") {
globalUrl = "http://localhost:5001";
//globalUrl = "http://localhost:5002"
}
const App = (message, props) => {
const [userdata, setUserData] = useState({});
const [notifications, setNotifications] = useState([])
const [cookies, setCookie, removeCookie] = useCookies([])
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [dataset, setDataset] = useState(false);
const [isLoaded, setIsLoaded] = useState(false);
const [curpath, setCurpath] = useState(typeof window === 'undefined' || window.location === undefined ? "" : window.location.pathname)
const [userdata, setUserData] = useState({});
const [notifications, setNotifications] = useState([]);
const [cookies, setCookie, removeCookie] = useCookies([]);
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [dataset, setDataset] = useState(false);
const [isLoaded, setIsLoaded] = useState(false);
const [curpath, setCurpath] = useState(
typeof window === "undefined" || window.location === undefined
? ""
: window.location.pathname
);
useEffect(() => {
if (dataset === false) {
getUserNotifications()
checkLogin()
setDataset(true)
}
})
useEffect(() => {
if (dataset === false) {
getUserNotifications();
checkLogin();
setDataset(true);
}
});
if (isLoaded && !isLoggedIn && (!window.location.pathname.startsWith("/login") && (!window.location.pathname.startsWith("/docs") && (!window.location.pathname.startsWith("/adminsetup"))))) {
window.location = "/login"
}
if (
isLoaded &&
!isLoggedIn &&
!window.location.pathname.startsWith("/login") &&
!window.location.pathname.startsWith("/docs") &&
!window.location.pathname.startsWith("/adminsetup")
) {
window.location = "/login";
}
const getUserNotifications = () => {
fetch(`${globalUrl}/api/v1/notifications`, {
credentials: "include",
headers: {
'Content-Type': 'application/json',
},
})
.then(response => response.json())
.then(responseJson => {
if (responseJson.success === true && responseJson.notifications !== null && responseJson.notifications !== undefined && responseJson.notifications.length > 0) {
//console.log("RESP: ", responseJson)
setNotifications(responseJson.notifications)
}
})
.catch(error => {
console.log("Failed getting notifications for user: ", error)
});
}
const getUserNotifications = () => {
fetch(`${globalUrl}/api/v1/notifications`, {
credentials: "include",
headers: {
"Content-Type": "application/json",
},
})
.then((response) => response.json())
.then((responseJson) => {
if (
responseJson.success === true &&
responseJson.notifications !== null &&
responseJson.notifications !== undefined &&
responseJson.notifications.length > 0
) {
//console.log("RESP: ", responseJson)
setNotifications(responseJson.notifications);
}
})
.catch((error) => {
console.log("Failed getting notifications for user: ", error);
});
};
const checkLogin = () => {
var baseurl = globalUrl
fetch(baseurl + "/api/v1/users/getinfo", {
credentials: "include",
headers: {
'Content-Type': 'application/json',
},
})
.then(response => response.json())
.then(responseJson => {
var userInfo = {}
if (responseJson.success === true) {
console.log(responseJson)
const checkLogin = () => {
var baseurl = globalUrl;
fetch(baseurl + "/api/v1/users/getinfo", {
credentials: "include",
headers: {
"Content-Type": "application/json",
},
})
.then((response) => response.json())
.then((responseJson) => {
var userInfo = {};
if (responseJson.success === true) {
console.log(responseJson);
userInfo = responseJson
setIsLoggedIn(true)
//console.log("Cookies: ", cookies)
// Updating cookie every request
for (var key in responseJson["cookies"]) {
setCookie(responseJson["cookies"][key].key, responseJson["cookies"][key].value, { path: "/" })
}
}
userInfo = responseJson;
setIsLoggedIn(true);
//console.log("Cookies: ", cookies)
// Updating cookie every request
for (var key in responseJson["cookies"]) {
setCookie(
responseJson["cookies"][key].key,
responseJson["cookies"][key].value,
{ path: "/" }
);
}
}
// Handling Ethereum update
detectEthereumProvider()
.then((provider) => {
if (provider && userInfo.eth_info !== undefined && userInfo.eth_info !== null) {
if (userInfo.eth_info.account !== undefined && userInfo.eth_info.account !== null && userInfo.eth_info.account.length === 0) {
userInfo.eth_info = {}
var method = "eth_requestAccounts"
var params = []
provider.request({
method: method,
params,
})
.then((result) => {
if (result !== undefined && result !== null && result.length > 0) {
userInfo.eth_info.account = result[0]
// Handling Ethereum update
detectEthereumProvider().then((provider) => {
if (
provider &&
userInfo.eth_info !== undefined &&
userInfo.eth_info !== null
) {
if (
userInfo.eth_info.account !== undefined &&
userInfo.eth_info.account !== null &&
userInfo.eth_info.account.length === 0
) {
userInfo.eth_info = {};
var method = "eth_requestAccounts";
var params = [];
provider
.request({
method: method,
params,
})
.then((result) => {
if (
result !== undefined &&
result !== null &&
result.length > 0
) {
userInfo.eth_info.account = result[0];
// Getting and setting balance for the current user
method = "eth_getBalance"
params = [
userInfo.eth_info.account,
"latest"
]
provider.request({
method: method,
params,
})
.then((result) => {
if (result !== undefined && result !== null && result.length > 0) {
userInfo.parsed_balance = result/1000000000000000000
} else {
alert.error("Couldn't find balance: ", result)
}
// The result varies by RPC method.
// For example, this method will return a transaction hash hexadecimal string on success.
})
.catch((error) => {
// If the request fails, the Promise will reject with an error.
alert.error("Failed getting info from ethereum API: "+error)
})
} else {
alert.error("Couldn't find any user: ", result)
}
})
.catch((error) => {
// If the request fails, the Promise will reject with an error.
alert.error("Failed getting info from ethereum API: "+error)
})
}
// Register hooks here
provider.on('message', (event) => {
alert.info("Message from MetaMask: ", event)
})
// Getting and setting balance for the current user
method = "eth_getBalance";
params = [userInfo.eth_info.account, "latest"];
provider
.request({
method: method,
params,
})
.then((result) => {
if (
result !== undefined &&
result !== null &&
result.length > 0
) {
userInfo.parsed_balance =
result / 1000000000000000000;
} else {
alert.error("Couldn't find balance: ", result);
}
// The result varies by RPC method.
// For example, this method will return a transaction hash hexadecimal string on success.
})
.catch((error) => {
// If the request fails, the Promise will reject with an error.
alert.error(
"Failed getting info from ethereum API: " + error
);
});
} else {
alert.error("Couldn't find any user: ", result);
}
})
.catch((error) => {
// If the request fails, the Promise will reject with an error.
alert.error(
"Failed getting info from ethereum API: " + error
);
});
}
provider.on('chainChanged', (chainId) => {
console.log("Changed chain to: ", chainId)
method = "eth_getBalance"
params = [
userInfo.eth_info.account,
"latest"
]
provider.request({
method: method,
params,
})
.then((result) => {
console.log("Got result: ", result)
if (result !== undefined && result !== null) {
userInfo.eth_info.balance = result
userInfo.eth_info.parsed_balance = result/1000000000000000000
console.log("INFO: ", userInfo)
setUserData(userInfo)
} else {
alert.error("Couldn't find balance: ", result)
}
})
.catch((error) => {
// If the request fails, the Promise will reject with an error.
alert.error("Failed getting info from ethereum API: "+error)
})
})
}
})
// Register hooks here
provider.on("message", (event) => {
alert.info("Message from MetaMask: ", event);
});
if (userInfo.eth_info !== undefined && userInfo.eth_info.balance !== undefined) {
//console.log(userInfo.eth_info.balance)
userInfo.eth_info.parsed_balance = userInfo.eth_info.balance/1000000000000000000
}
provider.on("chainChanged", (chainId) => {
console.log("Changed chain to: ", chainId);
//console.log("USER: ", userInfo)
setUserData(userInfo)
setIsLoaded(true)
method = "eth_getBalance";
params = [userInfo.eth_info.account, "latest"];
provider
.request({
method: method,
params,
})
.then((result) => {
console.log("Got result: ", result);
if (result !== undefined && result !== null) {
userInfo.eth_info.balance = result;
userInfo.eth_info.parsed_balance =
result / 1000000000000000000;
console.log("INFO: ", userInfo);
setUserData(userInfo);
} else {
alert.error("Couldn't find balance: ", result);
}
})
.catch((error) => {
// If the request fails, the Promise will reject with an error.
alert.error(
"Failed getting info from ethereum API: " + error
);
});
});
}
});
})
.catch(error => {
setIsLoaded(true)
});
}
if (
userInfo.eth_info !== undefined &&
userInfo.eth_info.balance !== undefined
) {
//console.log(userInfo.eth_info.balance)
userInfo.eth_info.parsed_balance =
userInfo.eth_info.balance / 1000000000000000000;
}
// Dumb for content load (per now), but good for making the site not suddenly reload parts (ajax thingies)
//console.log("USER: ", userInfo)
setUserData(userInfo);
setIsLoaded(true);
})
.catch((error) => {
setIsLoaded(true);
});
};
const options = {
timeout: 9000,
position: positions.BOTTOM_LEFT,
};
// Dumb for content load (per now), but good for making the site not suddenly reload parts (ajax thingies)
const includedData = window.location.pathname === "/home" || window.location.pathname === "/features" ?
<div>
<Route exact path="/home" render={props => <LandingPageNew isLoaded={isLoaded} {...props} />} />
</div> :
<div style={{ backgroundColor: "#1F2023", color: "rgba(255, 255, 255, 0.65)", minHeight: "100vh" }}>
<ScrollToTop getUserNotifications={getUserNotifications} setCurpath={setCurpath} />
<Header notifications={notifications} setNotifications={setNotifications} checkLogin={checkLogin} cookies={cookies} removeCookie={removeCookie} isLoaded={isLoaded} globalUrl={globalUrl} setIsLoggedIn={setIsLoggedIn} isLoggedIn={isLoggedIn} userdata={userdata} {...props} />
<div style={{height: 60}}/>
<Route exact path="/login" render={props => <LoginPage isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} checkLogin={checkLogin} {...props} />} />
<Route exact path="/admin" render={props => <Admin userdata={userdata} isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
<Route exact path="/admin/:key" render={props => <Admin isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
{userdata.id !== undefined ?
<Route exact path="/settings" render={props => <SettingsPage isLoaded={isLoaded} setUserData={setUserData} userdata={userdata} globalUrl={globalUrl} {...props} />} />
: null}
<Route exact path="/AdminSetup" render={props => <AdminSetup isLoaded={isLoaded} userdata={userdata} globalUrl={globalUrl} {...props} />} />
<Route exact path="/webhooks" render={props => <Webhooks isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
<Route exact path="/webhooks/:key" render={props => <EditWebhook isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
<Route exact path="/schedules" render={props => <Schedules globalUrl={globalUrl} {...props} />} />
<Route exact path="/dashboard" render={props => <Dashboard isLoaded={isLoaded} isLoggedIn={isLoggedIn} globalUrl={globalUrl} {...props} />} />
<Route exact path="/apps/new" render={props => <AppCreator isLoaded={isLoaded} isLoggedIn={isLoggedIn} globalUrl={globalUrl} {...props} />} />
<Route exact path="/apps" render={props => <Apps isLoaded={isLoaded} isLoggedIn={isLoggedIn} globalUrl={globalUrl} userdata={userdata} {...props} />} />
<Route exact path="/apps/edit/:appid" render={props => <AppCreator isLoaded={isLoaded} isLoggedIn={isLoggedIn} globalUrl={globalUrl} {...props} />} />
<Route exact path="/schedules/:key" render={props => <EditSchedule globalUrl={globalUrl} {...props} />} />
<Route exact path="/workflows" render={props => <Workflows cookies={cookies} removeCookie={removeCookie} isLoaded={isLoaded} isLoggedIn={isLoggedIn} globalUrl={globalUrl} cookies={cookies} userdata={userdata} {...props} />} />
<Route exact path="/workflows/:key" render={props => <AngularWorkflow userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} {...props} />} />
<Route exact path="/docs/:key" render={props => <Docs isMobile={isMobile} isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
<Route exact path="/docs" render={props => { window.location.pathname = "/docs/about" }} />
<Route exact path="/introduction" render={props => <Introduction isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
<Route exact path="/introduction/:key" render={props => <Introduction isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
<Route exact path="/set_authentication" render={props => <SetAuthentication userdata={userdata} isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
<Route exact path="/login_sso" render={props => <SetAuthenticationSSO userdata={userdata} isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
<Route exact path="/" render={props => <LoginPage isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
</div>
const options = {
timeout: 9000,
position: positions.BOTTOM_LEFT,
};
// <div style={{backgroundColor: "rgba(21, 32, 43, 1)", color: "#fffff", minHeight: "100vh"}}>
// backgroundColor: "#213243",
// This is a mess hahahah
return (
<MuiThemeProvider theme={theme}>
<CookiesProvider>
<BrowserRouter>
<Provider template={AlertTemplate} {...options}>
{includedData}
</Provider>
</BrowserRouter>
</CookiesProvider>
</MuiThemeProvider>
);
const includedData =
window.location.pathname === "/home" ||
window.location.pathname === "/features" ? (
<div>
<Route
exact
path="/home"
render={(props) => <LandingPageNew isLoaded={isLoaded} {...props} />}
/>
</div>
) : (
<div
style={{
backgroundColor: "#1F2023",
color: "rgba(255, 255, 255, 0.65)",
minHeight: "100vh",
}}
>
<ScrollToTop
getUserNotifications={getUserNotifications}
setCurpath={setCurpath}
/>
<Header
notifications={notifications}
setNotifications={setNotifications}
checkLogin={checkLogin}
cookies={cookies}
removeCookie={removeCookie}
isLoaded={isLoaded}
globalUrl={globalUrl}
setIsLoggedIn={setIsLoggedIn}
isLoggedIn={isLoggedIn}
userdata={userdata}
{...props}
/>
<div style={{ height: 60 }} />
<Route
exact
path="/login"
render={(props) => (
<LoginPage
isLoggedIn={isLoggedIn}
setIsLoggedIn={setIsLoggedIn}
register={true}
isLoaded={isLoaded}
globalUrl={globalUrl}
setCookie={setCookie}
cookies={cookies}
checkLogin={checkLogin}
{...props}
/>
)}
/>
<Route
exact
path="/admin"
render={(props) => (
<Admin
userdata={userdata}
isLoggedIn={isLoggedIn}
setIsLoggedIn={setIsLoggedIn}
register={true}
isLoaded={isLoaded}
globalUrl={globalUrl}
setCookie={setCookie}
cookies={cookies}
{...props}
/>
)}
/>
<Route
exact
path="/admin/:key"
render={(props) => (
<Admin
isLoggedIn={isLoggedIn}
setIsLoggedIn={setIsLoggedIn}
register={true}
isLoaded={isLoaded}
globalUrl={globalUrl}
setCookie={setCookie}
cookies={cookies}
{...props}
/>
)}
/>
{userdata.id !== undefined ? (
<Route
exact
path="/settings"
render={(props) => (
<SettingsPage
isLoaded={isLoaded}
setUserData={setUserData}
userdata={userdata}
globalUrl={globalUrl}
{...props}
/>
)}
/>
) : null}
<Route
exact
path="/AdminSetup"
render={(props) => (
<AdminSetup
isLoaded={isLoaded}
userdata={userdata}
globalUrl={globalUrl}
{...props}
/>
)}
/>
<Route
exact
path="/webhooks"
render={(props) => (
<Webhooks isLoaded={isLoaded} globalUrl={globalUrl} {...props} />
)}
/>
<Route
exact
path="/webhooks/:key"
render={(props) => (
<EditWebhook isLoaded={isLoaded} globalUrl={globalUrl} {...props} />
)}
/>
<Route
exact
path="/schedules"
render={(props) => <Schedules globalUrl={globalUrl} {...props} />}
/>
<Route
exact
path="/dashboard"
render={(props) => (
<Dashboard
isLoaded={isLoaded}
isLoggedIn={isLoggedIn}
globalUrl={globalUrl}
{...props}
/>
)}
/>
<Route
exact
path="/apps/new"
render={(props) => (
<AppCreator
isLoaded={isLoaded}
isLoggedIn={isLoggedIn}
globalUrl={globalUrl}
{...props}
/>
)}
/>
<Route
exact
path="/apps"
render={(props) => (
<Apps
isLoaded={isLoaded}
isLoggedIn={isLoggedIn}
globalUrl={globalUrl}
userdata={userdata}
{...props}
/>
)}
/>
<Route
exact
path="/apps/edit/:appid"
render={(props) => (
<AppCreator
isLoaded={isLoaded}
isLoggedIn={isLoggedIn}
globalUrl={globalUrl}
{...props}
/>
)}
/>
<Route
exact
path="/schedules/:key"
render={(props) => <EditSchedule globalUrl={globalUrl} {...props} />}
/>
<Route
exact
path="/workflows"
render={(props) => (
<Workflows
cookies={cookies}
removeCookie={removeCookie}
isLoaded={isLoaded}
isLoggedIn={isLoggedIn}
globalUrl={globalUrl}
cookies={cookies}
userdata={userdata}
{...props}
/>
)}
/>
<Route
exact
path="/workflows/:key"
render={(props) => (
<AngularWorkflow
userdata={userdata}
globalUrl={globalUrl}
isLoaded={isLoaded}
isLoggedIn={isLoggedIn}
{...props}
/>
)}
/>
<Route
exact
path="/docs/:key"
render={(props) => (
<Docs
isMobile={isMobile}
isLoaded={isLoaded}
globalUrl={globalUrl}
{...props}
/>
)}
/>
<Route
exact
path="/docs"
render={(props) => {
window.location.pathname = "/docs/about";
}}
/>
<Route
exact
path="/introduction"
render={(props) => (
<Introduction
isLoaded={isLoaded}
globalUrl={globalUrl}
{...props}
/>
)}
/>
<Route
exact
path="/introduction/:key"
render={(props) => (
<Introduction
isLoaded={isLoaded}
globalUrl={globalUrl}
{...props}
/>
)}
/>
<Route
exact
path="/set_authentication"
render={(props) => (
<SetAuthentication
userdata={userdata}
isLoggedIn={isLoggedIn}
setIsLoggedIn={setIsLoggedIn}
register={true}
isLoaded={isLoaded}
globalUrl={globalUrl}
setCookie={setCookie}
cookies={cookies}
{...props}
/>
)}
/>
<Route
exact
path="/login_sso"
render={(props) => (
<SetAuthenticationSSO
userdata={userdata}
isLoggedIn={isLoggedIn}
setIsLoggedIn={setIsLoggedIn}
register={true}
isLoaded={isLoaded}
globalUrl={globalUrl}
setCookie={setCookie}
cookies={cookies}
{...props}
/>
)}
/>
<Route
exact
path="/"
render={(props) => (
<LoginPage
isLoggedIn={isLoggedIn}
setIsLoggedIn={setIsLoggedIn}
register={true}
isLoaded={isLoaded}
globalUrl={globalUrl}
setCookie={setCookie}
cookies={cookies}
{...props}
/>
)}
/>
</div>
);
// <div style={{backgroundColor: "rgba(21, 32, 43, 1)", color: "#fffff", minHeight: "100vh"}}>
// backgroundColor: "#213243",
// This is a mess hahahah
return (
<MuiThemeProvider theme={theme}>
<CookiesProvider>
<BrowserRouter>
<Provider template={AlertTemplate} {...options}>
{includedData}
</Provider>
</BrowserRouter>
</CookiesProvider>
</MuiThemeProvider>
);
};
export default App;
File diff suppressed because one or more lines are too long
+5 -2
View File
@@ -1,3 +1,6 @@
const data = [{"name": "cloud", "type": "cloud"}, {"name": "onprem", "type": "onprem"}]
const data = [
{ name: "cloud", type: "cloud" },
{ name: "onprem", type: "onprem" },
];
export default data;
export default data;
+25 -26
View File
@@ -1,30 +1,29 @@
const Data = {
"src": {
"name": "Get Tickets",
"description": "Get tickets",
"outputparameters": [{
"name": "SymptomDescription",
"schema": {"type": "string"}},
{"name": "DetailedDescription",
"schema": {"type": "string"}},
{"name": "EventSource",
"schema": {"type": "string"}
}]
},
"dst": {
"name": "Create alert",
"description": "Create alert in TheHive",
"inputparameters": [{
"name": "title",
"required": true,
"schema": {"type": "string"}},
{"name": "description",
"required": true,
"schema": {"type": "string"}},
{"name": "source",
"required": true,
"schema": {"type": "string"}
}]}
src: {
name: "Get Tickets",
description: "Get tickets",
outputparameters: [
{
name: "SymptomDescription",
schema: { type: "string" },
},
{ name: "DetailedDescription", schema: { type: "string" } },
{ name: "EventSource", schema: { type: "string" } },
],
},
dst: {
name: "Create alert",
description: "Create alert in TheHive",
inputparameters: [
{
name: "title",
required: true,
schema: { type: "string" },
},
{ name: "description", required: true, schema: { type: "string" } },
{ name: "source", required: true, schema: { type: "string" } },
],
},
};
export default Data;
+12 -12
View File
@@ -1,15 +1,15 @@
const data = {
"id":"8ccf0bec1fde018771ab685d2a40bd52",
"info":{
"url":"",
"name":"testing",
"description":"wut"
},
"transforms":{},
"actions": {},
"type":"webhook",
"status":"uninitialized",
"running":false
}
id: "8ccf0bec1fde018771ab685d2a40bd52",
info: {
url: "",
name: "testing",
description: "wut",
},
transforms: {},
actions: {},
type: "webhook",
status: "uninitialized",
running: false,
};
export default data;
+168 -2
View File
@@ -1,3 +1,169 @@
const data = {"actions":[{"app_name":"hello_world","app_version":"1.0.0","errors":null,"id":"70574332-da82-cf17-c723-75fa7b8493c2","is_valid":true,"label":"hello_world","environment":"onprem","name":"hello_world","parameters":null,"position":{"x":353.7438792397648,"y":260.6717930890377},"priority":0},{"app_name":"hello_world","app_version":"1.0.0","errors":null,"id":"30522433-56ed-53c3-575d-766e282e1d3e","is_valid":true,"label":"random_number","environment":"cloud","name":"random_number","parameters":null,"position":{"x":458.30040774503794,"y":104.27580103487651},"priority":0},{"app_name":"hello_world","app_version":"1.0.0","errors":null,"id":"5b7ac5b5-9514-02b9-ebe0-998c0843b104","is_valid":false,"label":"hello_world_2","environment":"onprem","name":"hello_world","parameters":null,"position":{"x":414.7256019053981,"y":-140.46450482659628},"priority":0},{"app_name":"hello_world","app_version":"1.0.0","errors":null,"id":"7e6e7a19-4636-cebc-91c4-052a3769a18b","is_valid":true,"label":"hello_world_3","environment":"cloud","name":"hello_world","parameters":null,"position":{"x":83.59752786243806,"y":50.232317715020734},"priority":0},{"app_name":"hello_world","app_version":"1.0.0","errors":null,"id":"edbf927d-5a00-2405-28ed-47982cdf5110","is_valid":true,"label":"hello_world_4","environment":"cloud","name":"hello_world","parameters":null,"position":{"x":-147.30681300186404,"y":89.16690830150289},"priority":0},{"app_name":"hello_world","app_version":"1.0.0","errors":null,"id":"4844a855-1e2b-669d-fc72-5f398321ac5d","is_valid":false,"label":"hello_world_5","environment":"onprem","name":"hello_world","parameters":null,"position":{"x":130.24982593523967,"y":233.8325632286361},"priority":0},{"app_name":"hello_world","app_version":"1.0.0","errors":null,"id":"6d1d3f8a-1ac9-3db4-0e0f-2fe32e9d3c09","is_valid":true,"label":"hello_world_6","environment":"cloud","name":"hello_world","parameters":null,"position":{"x":83.551088005629,"y":-105.15867327274223},"priority":0},{"app_name":"hello_world","app_version":"1.0.0","errors":null,"id":"469d8c2b-52ac-e397-9a29-becccd04aed8","is_valid":true,"label":"hello_world_7","environment":"cloud","name":"hello_world","parameters":null,"position":{"x":314.4987657226086,"y":10.167183586257954},"priority":0}],"branches":[{"destination_id":"30522433-56ed-53c3-575d-766e282e1d3e","id":"4bcb9795-94e6-7d5f-2074-0d5b27784e0b","source_id":"70574332-da82-cf17-c723-75fa7b8493c2"},{"destination_id":"5b7ac5b5-9514-02b9-ebe0-998c0843b104","id":"fe0ab8e4-a535-61cd-3c09-8fd3d8e40769","source_id":"30522433-56ed-53c3-575d-766e282e1d3e"},{"destination_id":"469d8c2b-52ac-e397-9a29-becccd04aed8","id":"8b9ee9bc-b0ab-0bb6-af61-46d4594b2663","source_id":"30522433-56ed-53c3-575d-766e282e1d3e"},{"destination_id":"6d1d3f8a-1ac9-3db4-0e0f-2fe32e9d3c09","id":"c204d5ef-9cc1-d906-9988-86a624c57783","source_id":"469d8c2b-52ac-e397-9a29-becccd04aed8"},{"destination_id":"6d1d3f8a-1ac9-3db4-0e0f-2fe32e9d3c09","id":"1ffb3934-60ec-8f80-5cee-3ddc0a37fdb6","source_id":"5b7ac5b5-9514-02b9-ebe0-998c0843b104"},{"destination_id":"edbf927d-5a00-2405-28ed-47982cdf5110","id":"9c7fb048-9d0d-cb84-9ba0-be729af9b4d1","source_id":"6d1d3f8a-1ac9-3db4-0e0f-2fe32e9d3c09"},{"destination_id":"edbf927d-5a00-2405-28ed-47982cdf5110","id":"e3ab104e-fc8b-3af5-8daa-bfa57bcf9690","source_id":"7e6e7a19-4636-cebc-91c4-052a3769a18b"},{"destination_id":"7e6e7a19-4636-cebc-91c4-052a3769a18b","id":"b6626081-22dd-3af3-b899-480f60d886ca","source_id":"30522433-56ed-53c3-575d-766e282e1d3e"},{"destination_id":"4844a855-1e2b-669d-fc72-5f398321ac5d","id":"4275cf97-0447-bbda-0c80-ab20d389de1a","source_id":"edbf927d-5a00-2405-28ed-47982cdf5110"}],"conditions":[],"triggers":[],"transforms":[],"description":"asd","id":"2f299808-0f1b-4ae0-97fc-ac17483dfcf7","id":"2f299808-0f1b-4ae0-97fc-ac17483dfcf7","is_valid":true,"name":"test2","start":"70574332-da82-cf17-c723-75fa7b8493c2","owner":{"username":"","id":"","orgs":""},"execution_org":{"name":"","org":"","users":null,"id":""},"workflow_variables":null}
const data = {
actions: [
{
app_name: "hello_world",
app_version: "1.0.0",
errors: null,
id: "70574332-da82-cf17-c723-75fa7b8493c2",
is_valid: true,
label: "hello_world",
environment: "onprem",
name: "hello_world",
parameters: null,
position: { x: 353.7438792397648, y: 260.6717930890377 },
priority: 0,
},
{
app_name: "hello_world",
app_version: "1.0.0",
errors: null,
id: "30522433-56ed-53c3-575d-766e282e1d3e",
is_valid: true,
label: "random_number",
environment: "cloud",
name: "random_number",
parameters: null,
position: { x: 458.30040774503794, y: 104.27580103487651 },
priority: 0,
},
{
app_name: "hello_world",
app_version: "1.0.0",
errors: null,
id: "5b7ac5b5-9514-02b9-ebe0-998c0843b104",
is_valid: false,
label: "hello_world_2",
environment: "onprem",
name: "hello_world",
parameters: null,
position: { x: 414.7256019053981, y: -140.46450482659628 },
priority: 0,
},
{
app_name: "hello_world",
app_version: "1.0.0",
errors: null,
id: "7e6e7a19-4636-cebc-91c4-052a3769a18b",
is_valid: true,
label: "hello_world_3",
environment: "cloud",
name: "hello_world",
parameters: null,
position: { x: 83.59752786243806, y: 50.232317715020734 },
priority: 0,
},
{
app_name: "hello_world",
app_version: "1.0.0",
errors: null,
id: "edbf927d-5a00-2405-28ed-47982cdf5110",
is_valid: true,
label: "hello_world_4",
environment: "cloud",
name: "hello_world",
parameters: null,
position: { x: -147.30681300186404, y: 89.16690830150289 },
priority: 0,
},
{
app_name: "hello_world",
app_version: "1.0.0",
errors: null,
id: "4844a855-1e2b-669d-fc72-5f398321ac5d",
is_valid: false,
label: "hello_world_5",
environment: "onprem",
name: "hello_world",
parameters: null,
position: { x: 130.24982593523967, y: 233.8325632286361 },
priority: 0,
},
{
app_name: "hello_world",
app_version: "1.0.0",
errors: null,
id: "6d1d3f8a-1ac9-3db4-0e0f-2fe32e9d3c09",
is_valid: true,
label: "hello_world_6",
environment: "cloud",
name: "hello_world",
parameters: null,
position: { x: 83.551088005629, y: -105.15867327274223 },
priority: 0,
},
{
app_name: "hello_world",
app_version: "1.0.0",
errors: null,
id: "469d8c2b-52ac-e397-9a29-becccd04aed8",
is_valid: true,
label: "hello_world_7",
environment: "cloud",
name: "hello_world",
parameters: null,
position: { x: 314.4987657226086, y: 10.167183586257954 },
priority: 0,
},
],
branches: [
{
destination_id: "30522433-56ed-53c3-575d-766e282e1d3e",
id: "4bcb9795-94e6-7d5f-2074-0d5b27784e0b",
source_id: "70574332-da82-cf17-c723-75fa7b8493c2",
},
{
destination_id: "5b7ac5b5-9514-02b9-ebe0-998c0843b104",
id: "fe0ab8e4-a535-61cd-3c09-8fd3d8e40769",
source_id: "30522433-56ed-53c3-575d-766e282e1d3e",
},
{
destination_id: "469d8c2b-52ac-e397-9a29-becccd04aed8",
id: "8b9ee9bc-b0ab-0bb6-af61-46d4594b2663",
source_id: "30522433-56ed-53c3-575d-766e282e1d3e",
},
{
destination_id: "6d1d3f8a-1ac9-3db4-0e0f-2fe32e9d3c09",
id: "c204d5ef-9cc1-d906-9988-86a624c57783",
source_id: "469d8c2b-52ac-e397-9a29-becccd04aed8",
},
{
destination_id: "6d1d3f8a-1ac9-3db4-0e0f-2fe32e9d3c09",
id: "1ffb3934-60ec-8f80-5cee-3ddc0a37fdb6",
source_id: "5b7ac5b5-9514-02b9-ebe0-998c0843b104",
},
{
destination_id: "edbf927d-5a00-2405-28ed-47982cdf5110",
id: "9c7fb048-9d0d-cb84-9ba0-be729af9b4d1",
source_id: "6d1d3f8a-1ac9-3db4-0e0f-2fe32e9d3c09",
},
{
destination_id: "edbf927d-5a00-2405-28ed-47982cdf5110",
id: "e3ab104e-fc8b-3af5-8daa-bfa57bcf9690",
source_id: "7e6e7a19-4636-cebc-91c4-052a3769a18b",
},
{
destination_id: "7e6e7a19-4636-cebc-91c4-052a3769a18b",
id: "b6626081-22dd-3af3-b899-480f60d886ca",
source_id: "30522433-56ed-53c3-575d-766e282e1d3e",
},
{
destination_id: "4844a855-1e2b-669d-fc72-5f398321ac5d",
id: "4275cf97-0447-bbda-0c80-ab20d389de1a",
source_id: "edbf927d-5a00-2405-28ed-47982cdf5110",
},
],
conditions: [],
triggers: [],
transforms: [],
description: "asd",
id: "2f299808-0f1b-4ae0-97fc-ac17483dfcf7",
id: "2f299808-0f1b-4ae0-97fc-ac17483dfcf7",
is_valid: true,
name: "test2",
start: "70574332-da82-cf17-c723-75fa7b8493c2",
owner: { username: "", id: "", orgs: "" },
execution_org: { name: "", org: "", users: null, id: "" },
workflow_variables: null,
};
export default data;
export default data;
+68 -68
View File
@@ -23,7 +23,7 @@
let chart1_2_options = {
maintainAspectRatio: false,
legend: {
display: false
display: false,
},
tooltips: {
backgroundColor: "#f5f5f5",
@@ -33,7 +33,7 @@ let chart1_2_options = {
xPadding: 12,
mode: "nearest",
intersect: 0,
position: "nearest"
position: "nearest",
},
responsive: true,
scales: {
@@ -43,15 +43,15 @@ let chart1_2_options = {
gridLines: {
drawBorder: false,
color: "rgba(29,140,248,0.0)",
zeroLineColor: "transparent"
zeroLineColor: "transparent",
},
ticks: {
suggestedMin: 60,
suggestedMax: 125,
padding: 20,
fontColor: "#9a9a9a"
}
}
fontColor: "#9a9a9a",
},
},
],
xAxes: [
{
@@ -59,22 +59,22 @@ let chart1_2_options = {
gridLines: {
drawBorder: false,
color: "rgba(29,140,248,0.1)",
zeroLineColor: "transparent"
zeroLineColor: "transparent",
},
ticks: {
padding: 20,
fontColor: "#9a9a9a"
}
}
]
}
fontColor: "#9a9a9a",
},
},
],
},
};
// #########################################
// // // used inside src/views/Dashboard.js
// #########################################
let chartExample1 = {
data1: canvas => {
data1: (canvas) => {
let ctx = canvas.getContext("2d");
let gradientStroke = ctx.createLinearGradient(0, 230, 0, 50);
@@ -96,7 +96,7 @@ let chartExample1 = {
"SEP",
"OCT",
"NOV",
"DEC"
"DEC",
],
datasets: [
{
@@ -114,12 +114,12 @@ let chartExample1 = {
pointHoverRadius: 4,
pointHoverBorderWidth: 15,
pointRadius: 4,
data: [100, 70, 90, 70, 85, 60, 75, 60, 90, 80, 110, 100]
}
]
data: [100, 70, 90, 70, 85, 60, 75, 60, 90, 80, 110, 100],
},
],
};
},
data2: canvas => {
data2: (canvas) => {
let ctx = canvas.getContext("2d");
let gradientStroke = ctx.createLinearGradient(0, 230, 0, 50);
@@ -141,7 +141,7 @@ let chartExample1 = {
"SEP",
"OCT",
"NOV",
"DEC"
"DEC",
],
datasets: [
{
@@ -159,12 +159,12 @@ let chartExample1 = {
pointHoverRadius: 4,
pointHoverBorderWidth: 15,
pointRadius: 4,
data: [80, 120, 105, 110, 95, 105, 90, 100, 80, 95, 70, 120]
}
]
data: [80, 120, 105, 110, 95, 105, 90, 100, 80, 95, 70, 120],
},
],
};
},
data3: canvas => {
data3: (canvas) => {
let ctx = canvas.getContext("2d");
let gradientStroke = ctx.createLinearGradient(0, 230, 0, 50);
@@ -186,7 +186,7 @@ let chartExample1 = {
"SEP",
"OCT",
"NOV",
"DEC"
"DEC",
],
datasets: [
{
@@ -204,19 +204,19 @@ let chartExample1 = {
pointHoverRadius: 4,
pointHoverBorderWidth: 15,
pointRadius: 4,
data: [60, 80, 65, 130, 80, 105, 90, 130, 70, 115, 60, 130]
}
]
data: [60, 80, 65, 130, 80, 105, 90, 130, 70, 115, 60, 130],
},
],
};
},
options: chart1_2_options
options: chart1_2_options,
};
// #########################################
// // // used inside src/views/Dashboard.js
// #########################################
let chartExample2 = {
data: canvas => {
data: (canvas) => {
let ctx = canvas.getContext("2d");
let gradientStroke = ctx.createLinearGradient(0, 230, 0, 50);
@@ -243,19 +243,19 @@ let chartExample2 = {
pointHoverRadius: 4,
pointHoverBorderWidth: 15,
pointRadius: 4,
data: [80, 100, 70, 80, 120, 80]
}
]
data: [80, 100, 70, 80, 120, 80],
},
],
};
},
options: chart1_2_options
options: chart1_2_options,
};
// #########################################
// // // used inside src/views/Dashboard.js
// #########################################
let chartExample3 = {
data: canvas => {
data: (canvas) => {
let ctx = canvas.getContext("2d");
let gradientStroke = ctx.createLinearGradient(0, 230, 0, 50);
@@ -276,15 +276,15 @@ let chartExample3 = {
borderWidth: 2,
borderDash: [],
borderDashOffset: 0.0,
data: [53, 20, 10, 80, 100, 45]
}
]
data: [53, 20, 10, 80, 100, 45],
},
],
};
},
options: {
maintainAspectRatio: false,
legend: {
display: false
display: false,
},
tooltips: {
backgroundColor: "#f5f5f5",
@@ -294,7 +294,7 @@ let chartExample3 = {
xPadding: 12,
mode: "nearest",
intersect: 0,
position: "nearest"
position: "nearest",
},
responsive: true,
scales: {
@@ -303,38 +303,38 @@ let chartExample3 = {
gridLines: {
drawBorder: false,
color: "rgba(225,78,202,0.1)",
zeroLineColor: "transparent"
zeroLineColor: "transparent",
},
ticks: {
suggestedMin: 60,
suggestedMax: 120,
padding: 20,
fontColor: "#9e9e9e"
}
}
fontColor: "#9e9e9e",
},
},
],
xAxes: [
{
gridLines: {
drawBorder: false,
color: "rgba(225,78,202,0.1)",
zeroLineColor: "transparent"
zeroLineColor: "transparent",
},
ticks: {
padding: 20,
fontColor: "#9e9e9e"
}
}
]
}
}
fontColor: "#9e9e9e",
},
},
],
},
},
};
// #########################################
// // // used inside src/views/Dashboard.js
// #########################################
const chartExample4 = {
data: canvas => {
data: (canvas) => {
let ctx = canvas.getContext("2d");
let gradientStroke = ctx.createLinearGradient(0, 230, 0, 50);
@@ -361,15 +361,15 @@ const chartExample4 = {
pointHoverRadius: 4,
pointHoverBorderWidth: 15,
pointRadius: 4,
data: [90, 27, 60, 12, 80]
}
]
data: [90, 27, 60, 12, 80],
},
],
};
},
options: {
maintainAspectRatio: false,
legend: {
display: false
display: false,
},
tooltips: {
@@ -380,7 +380,7 @@ const chartExample4 = {
xPadding: 12,
mode: "nearest",
intersect: 0,
position: "nearest"
position: "nearest",
},
responsive: true,
scales: {
@@ -390,15 +390,15 @@ const chartExample4 = {
gridLines: {
drawBorder: false,
color: "rgba(29,140,248,0.0)",
zeroLineColor: "transparent"
zeroLineColor: "transparent",
},
ticks: {
suggestedMin: 50,
suggestedMax: 125,
padding: 20,
fontColor: "#9e9e9e"
}
}
fontColor: "#9e9e9e",
},
},
],
xAxes: [
@@ -407,21 +407,21 @@ const chartExample4 = {
gridLines: {
drawBorder: false,
color: "rgba(0,242,195,0.1)",
zeroLineColor: "transparent"
zeroLineColor: "transparent",
},
ticks: {
padding: 20,
fontColor: "#9e9e9e"
}
}
]
}
}
fontColor: "#9e9e9e",
},
},
],
},
},
};
module.exports = {
chartExample1, // in src/views/Dashboard.js
chartExample2, // in src/views/Dashboard.js
chartExample3, // in src/views/Dashboard.js
chartExample4 // in src/views/Dashboard.js
chartExample4, // in src/views/Dashboard.js
};
+13 -20
View File
@@ -1,26 +1,19 @@
import React, { useEffect} from 'react';
import React, { useEffect } from "react";
const Popup = (props) => {
const { data } = props;
const { data } = props;
const popupStyle = {
position: "fixed",
width: "300px",
height: "50px",
backgroundColor: "black",
color: "white",
}
const popupStyle = {
position: "fixed",
width: "300px",
height: "50px",
backgroundColor: "black",
color: "white",
};
const popupData =
<div>
HEY
</div>
const popupData = <div>HEY</div>;
return (
<div>
{popupData}
</div>
)
}
return <div>{popupData}</div>;
};
export default Popup
export default Popup;
+33 -31
View File
@@ -1,46 +1,48 @@
import React from 'react'
import InfoIcon from '@material-ui/icons/Info';
import CheckIcon from '@material-ui/icons/Check';
import ErrorOutlineIcon from '@material-ui/icons/ErrorOutline';
import CloseIcon from '@material-ui/icons/Close';
import Typography from '@material-ui/core/Typography';
import React from "react";
import InfoIcon from "@material-ui/icons/Info";
import CheckIcon from "@material-ui/icons/Check";
import ErrorOutlineIcon from "@material-ui/icons/ErrorOutline";
import CloseIcon from "@material-ui/icons/Close";
import Typography from "@material-ui/core/Typography";
const alertStyle = {
backgroundColor: 'rgba(0,0,0,0.9)',
color: 'white',
backgroundColor: "rgba(0,0,0,0.9)",
color: "white",
padding: 15,
textTransform: 'uppercase',
borderRadius: '3px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
boxShadow: '0px 2px 2px 2px rgba(0, 0, 0, 0.03)',
textTransform: "uppercase",
borderRadius: "3px",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
boxShadow: "0px 2px 2px 2px rgba(0, 0, 0, 0.03)",
width: 300,
boxSizing: 'border-box',
zIndex: 100001,
overflow: "hidden",
}
boxSizing: "border-box",
zIndex: 100001,
overflow: "hidden",
};
const buttonStyle = {
marginLeft: '20px',
border: 'none',
backgroundColor: 'transparent',
cursor: 'pointer',
color: '#FFFFFF'
}
marginLeft: "20px",
border: "none",
backgroundColor: "transparent",
cursor: "pointer",
color: "#FFFFFF",
};
const AlertTemplate = ({ message, options, style, close }) => {
return (
<div style={{ ...alertStyle, ...style }}>
{options.type === 'info' && <InfoIcon style={{color: "white"}} />}
{options.type === 'success' && <CheckIcon style={{color: "green", }}/>}
{options.type === 'error' && <ErrorOutlineIcon style={{color: "red"}} />}
<Typography style={{marginLeft: 15, flex: 2 }}>{message}</Typography>
{options.type === "info" && <InfoIcon style={{ color: "white" }} />}
{options.type === "success" && <CheckIcon style={{ color: "green" }} />}
{options.type === "error" && (
<ErrorOutlineIcon style={{ color: "red" }} />
)}
<Typography style={{ marginLeft: 15, flex: 2 }}>{message}</Typography>
<button onClick={close} style={buttonStyle}>
<CloseIcon />
</button>
</div>
)
}
);
};
export default AlertTemplate
export default AlertTemplate;
File diff suppressed because it is too large Load Diff
+22 -22
View File
@@ -1,19 +1,19 @@
import React, { useRef, useState } from 'react';
import { useEffect } from 'react';
import BackupIcon from '@material-ui/icons/Backup';
import React, { useRef, useState } from "react";
import { useEffect } from "react";
import BackupIcon from "@material-ui/icons/Backup";
const dragOverStyle = {
backgroundColor: 'rgba(0,0,0,0.8)',
border: '5px dashed white',
borderRadius: '8px',
width: '100%',
height: '100%',
position: 'absolute',
overflow: 'hidden',
backgroundColor: "rgba(0,0,0,0.8)",
border: "5px dashed white",
borderRadius: "8px",
width: "100%",
height: "100%",
position: "absolute",
overflow: "hidden",
zIndex: 100,
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
display: "flex",
alignItems: "center",
justifyContent: "center",
};
const Dropzone = ({ children, style, onDrop }) => {
@@ -56,21 +56,21 @@ const Dropzone = ({ children, style, onDrop }) => {
useEffect(() => {
if (!dropzoneRef.current) return;
dropzoneRef.current.addEventListener('dragover', handleDragOver);
dropzoneRef.current.addEventListener('dragenter', handleDragEnter);
dropzoneRef.current.addEventListener('dragleave', handleDragLeave);
dropzoneRef.current.addEventListener('drop', handleDrop);
dropzoneRef.current.addEventListener("dragover", handleDragOver);
dropzoneRef.current.addEventListener("dragenter", handleDragEnter);
dropzoneRef.current.addEventListener("dragleave", handleDragLeave);
dropzoneRef.current.addEventListener("drop", handleDrop);
return () => {
dropzoneRef.current.removeEventListener('dragover', handleDragOver);
dropzoneRef.current.removeEventListener('dragenter', handleDragEnter);
dropzoneRef.current.removeEventListener('dragleave', handleDragLeave);
dropzoneRef.current.removeEventListener('drop', handleDrop);
dropzoneRef.current.removeEventListener("dragover", handleDragOver);
dropzoneRef.current.removeEventListener("dragenter", handleDragEnter);
dropzoneRef.current.removeEventListener("dragleave", handleDragLeave);
dropzoneRef.current.removeEventListener("drop", handleDrop);
};
}, [dropzoneRef]);
return (
<div ref={dropzoneRef} style={{ position: 'relative', ...style }}>
<div ref={dropzoneRef} style={{ position: "relative", ...style }}>
{dragging && (
<div style={dragOverStyle}>
<BackupIcon fontSize="large" />
+37 -37
View File
@@ -1,54 +1,54 @@
import React from 'react';
import React from "react";
//import List from '@material-ui/core/List';
//import ListItem from '@material-ui/core/ListItem';
//borderTop: "1px solid #385F71"
const FooterStyle = {
right: "0",
left: "0",
bottom: "0",
height: "130px",
backgroundColor: 'rgba(15, 14, 31, 1)',
right: "0",
left: "0",
bottom: "0",
height: "130px",
backgroundColor: "rgba(15, 14, 31, 1)",
};
const FooterInfo = {
maxWidth: '1150px',
minWidth: '768px',
textAlign: 'center',
margin: 'auto',
maxWidth: "1150px",
minWidth: "768px",
textAlign: "center",
margin: "auto",
};
const hrefStyle = {
color: "#bdbdbd",
textDecoration: "none"
}
const Footer = props => {
return (
<div style={FooterStyle}>
<div style={FooterInfo}>
<Box />
</div>
</div>
);
color: "#bdbdbd",
textDecoration: "none",
};
const Box = props => {
return(
<div style={{display: "flex"}}>
<div style={{flex: "1"}}>
<a style={hrefStyle} href="/about">
<h1>About</h1>
</a>
</div>
<div style={{flex: "1"}}>
<a style={hrefStyle} href="/privacy-policy">
<h1>Privacy Policy</h1>
</a>
</div>
</div>
);
const Footer = (props) => {
return (
<div style={FooterStyle}>
<div style={FooterInfo}>
<Box />
</div>
</div>
);
};
const Box = (props) => {
return (
<div style={{ display: "flex" }}>
<div style={{ flex: "1" }}>
<a style={hrefStyle} href="/about">
<h1>About</h1>
</a>
</div>
<div style={{ flex: "1" }}>
<a style={hrefStyle} href="/privacy-policy">
<h1>Privacy Policy</h1>
</a>
</div>
</div>
);
};
export default Footer;
File diff suppressed because it is too large Load Diff
+160 -123
View File
@@ -1,139 +1,176 @@
/* eslint-disable react/no-multi-comp */
import React, {useState} from 'react';
import React, { useState } from "react";
import DialogTitle from '@material-ui/core/DialogTitle';
import Dialog from '@material-ui/core/Dialog';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import DialogTitle from "@material-ui/core/DialogTitle";
import Dialog from "@material-ui/core/Dialog";
import TextField from "@material-ui/core/TextField";
import Button from "@material-ui/core/Button";
const LoginDialog = props => {
const { classes, onClose, open, globalUrl, isLoggedIn, setIsLoggedIn, ...other } = props;
const LoginDialog = (props) => {
const {
classes,
onClose,
open,
globalUrl,
isLoggedIn,
setIsLoggedIn,
...other
} = props;
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
//const [selectedValue, setSelectedValue] = useState(false);
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
//const [selectedValue, setSelectedValue] = useState(false);
// Used to swap from login to register. True = login, false = register
const [loginCheck, setLoginCheck] = useState(true);
// Used to swap from login to register. True = login, false = register
const [loginCheck, setLoginCheck] = useState(true);
// Error messages etc
const [loginInfo, setLoginInfo] = useState("");
// Error messages etc
const [loginInfo, setLoginInfo] = useState("");
const handleValidateForm = () => {
return (username.length > 1 && password.length > 8);
}
const handleValidateForm = () => {
return username.length > 1 && password.length > 8;
};
const onSubmit = (e) => {
e.preventDefault()
const onSubmit = (e) => {
e.preventDefault();
// Just use this one?
var data = '{"username": "' + username + '", "password": "' + password + '"}';
var baseurl = globalUrl
if (loginCheck) {
var url = baseurl+'/login';
fetch(url, {
method: 'POST',
body: data,
headers: {
'Content-Type': 'application/json',
},
})
.then(response =>
response.json().then(responseJson => {
console.log(responseJson)
//console.log(e)
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"])
} else {
setLoginInfo("Successful login :)")
onClose()
setIsLoggedIn(true)
}
}),
)
.catch(error => {
setLoginInfo("Error in userdata")
});
} else {
url = baseurl+'/register';
fetch(url, {
method: 'POST',
body: data,
headers: {
'Content-Type': 'application/json',
},
})
.then(response =>
response.json().then(responseJson => {
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"])
} else {
setLoginInfo("Successful register :)")
onClose()
setIsLoggedIn(true)
}
}),
)
.catch(error => {
setLoginInfo("Error in userdata")
});
}
}
// Just use this one?
var data =
'{"username": "' + username + '", "password": "' + password + '"}';
var baseurl = globalUrl;
if (loginCheck) {
var url = baseurl + "/login";
fetch(url, {
method: "POST",
body: data,
headers: {
"Content-Type": "application/json",
},
})
.then((response) =>
response.json().then((responseJson) => {
console.log(responseJson);
//console.log(e)
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"]);
} else {
setLoginInfo("Successful login :)");
onClose();
setIsLoggedIn(true);
}
})
)
.catch((error) => {
setLoginInfo("Error in userdata");
});
} else {
url = baseurl + "/register";
fetch(url, {
method: "POST",
body: data,
headers: {
"Content-Type": "application/json",
},
})
.then((response) =>
response.json().then((responseJson) => {
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"]);
} else {
setLoginInfo("Successful register :)");
onClose();
setIsLoggedIn(true);
}
})
)
.catch((error) => {
setLoginInfo("Error in userdata");
});
}
};
const onChangeUser = (e) => {
setUsername(e.target.value)
}
const onChangeUser = (e) => {
setUsername(e.target.value);
};
const onChangePass = (e) => {
setPassword(e.target.value)
}
const onChangePass = (e) => {
setPassword(e.target.value);
};
const onClickRegister = () => {
setLoginCheck(!loginCheck)
}
const onClickRegister = () => {
setLoginCheck(!loginCheck);
};
//var loginChange = loginCheck ? (<div><p onClick={setLoginCheck(false)}>Want to register? Click here.</p></div>) : (<div><p onClick={setLoginCheck(true)}>Go back to login? Click here.</p></div>);
var formtitle = loginCheck ? <div>Login</div> : <div>Register</div>
var formButton = loginCheck ? <div>Click to Register</div> : <div>Click to Login</div>
//var loginChange = loginCheck ? (<div><p onClick={setLoginCheck(false)}>Want to register? Click here.</p></div>) : (<div><p onClick={setLoginCheck(true)}>Go back to login? Click here.</p></div>);
var formtitle = loginCheck ? <div>Login</div> : <div>Register</div>;
var formButton = loginCheck ? (
<div>Click to Register</div>
) : (
<div>Click to Login</div>
);
return (
<Dialog modal open={open} onClose={onClose} {...other}>
<DialogTitle>{formtitle}</DialogTitle>
<form onSubmit={onSubmit} style={{margin: "15px 15px 15px 15px"}}>
Username
<div>
<TextField
required
id="standard-required"
autoComplete="username"
margin="normal"
variant="outlined"
onChange={onChangeUser}
/>
</div>
Password
<div>
<TextField
id="outlined-password-input"
type="password"
autoComplete="current-password"
margin="normal"
variant="outlined"
onChange={onChangePass}
/>
</div>
<div style={{display: "flex", marginTop: "15px"}}>
<Button color="secondary" variant="contained" type="submit" style={{flex: "1", marginRight: "5px"}} disabled={!handleValidateForm()}>SUBMIT</Button>
<Button color="primary" variant="contained" type="button" style={{flex: "1"}} onClick={onClose}>Cancel</Button>
</div>
{loginInfo}
</form>
<div style={{display: "flex"}}>
<Button color="secondary" variant="contained" onClick={onClickRegister} type="button" style={{flex: "1"}}>{formButton}</Button>
</div>
</Dialog>
);
}
return (
<Dialog modal open={open} onClose={onClose} {...other}>
<DialogTitle>{formtitle}</DialogTitle>
<form onSubmit={onSubmit} style={{ margin: "15px 15px 15px 15px" }}>
Username
<div>
<TextField
required
id="standard-required"
autoComplete="username"
margin="normal"
variant="outlined"
onChange={onChangeUser}
/>
</div>
Password
<div>
<TextField
id="outlined-password-input"
type="password"
autoComplete="current-password"
margin="normal"
variant="outlined"
onChange={onChangePass}
/>
</div>
<div style={{ display: "flex", marginTop: "15px" }}>
<Button
color="secondary"
variant="contained"
type="submit"
style={{ flex: "1", marginRight: "5px" }}
disabled={!handleValidateForm()}
>
SUBMIT
</Button>
<Button
color="primary"
variant="contained"
type="button"
style={{ flex: "1" }}
onClick={onClose}
>
Cancel
</Button>
</div>
{loginInfo}
</form>
<div style={{ display: "flex" }}>
<Button
color="secondary"
variant="contained"
onClick={onClickRegister}
type="button"
style={{ flex: "1" }}
>
{formButton}
</Button>
</div>
</Dialog>
);
};
export default LoginDialog;
+70 -64
View File
@@ -1,9 +1,9 @@
import React, {useState, useRef, useImperativeHandle} from 'react'
import {makeStyles} from '@material-ui/core/styles'
import Menu, {MenuProps} from '@material-ui/core/Menu'
import MenuItem, {MenuItemProps} from '@material-ui/core/MenuItem'
import ArrowRight from '@material-ui/icons/ArrowRight'
import clsx from 'clsx'
import React, { useState, useRef, useImperativeHandle } from "react";
import { makeStyles } from "@material-ui/core/styles";
import Menu, { MenuProps } from "@material-ui/core/Menu";
import MenuItem, { MenuItemProps } from "@material-ui/core/MenuItem";
import ArrowRight from "@material-ui/icons/ArrowRight";
import clsx from "clsx";
//<MenuItemProps, 'button'>
@@ -39,15 +39,15 @@ import clsx from 'clsx'
// /**
// * @see https://material-ui.com/api/list-item/
// */
// button: true;
// button: true;
//}
const TRANSPARENT = 'rgba(0,0,0,0)'
const TRANSPARENT = "rgba(0,0,0,0)";
const useMenuItemStyles = makeStyles((theme) => ({
root: (props: any) => ({
backgroundColor: props.open ? theme.palette.action.hover : TRANSPARENT
})
}))
backgroundColor: props.open ? theme.palette.action.hover : TRANSPARENT,
}),
}));
/**
* Use as a drop-in replacement for `<MenuItem>` when you need to add cascading
@@ -55,11 +55,11 @@ const useMenuItemStyles = makeStyles((theme) => ({
*/
//const NestedMenuItem = React.forwardRef<NestedMenuItemProps>(
const NestedMenuItem = (props, ref) => {
console.log(props, ref)
//function NestedMenuItem(props, ref) {
console.log(props, ref);
//function NestedMenuItem(props, ref) {
const {
parentMenuOpen,
component = 'div',
component = "div",
label,
rightIcon = <ArrowRight />,
children,
@@ -68,94 +68,100 @@ const NestedMenuItem = (props, ref) => {
MenuProps = {},
ContainerProps: ContainerPropsProp = {},
...MenuItemProps
} = props
} = props;
const [isSubMenuOpen, setIsSubMenuOpen] = useState(false)
const [isSubMenuOpen, setIsSubMenuOpen] = useState(false);
const {ref: containerRefProp, ...ContainerProps} = ContainerPropsProp
const { ref: containerRefProp, ...ContainerProps } = ContainerPropsProp;
const menuItemRef = useRef < HTMLLIElement > null;
useImperativeHandle(ref, () => menuItemRef.current);
const containerRef = useRef < HTMLDivElement > null;
useImperativeHandle(containerRefProp, () => containerRef.current);
const menuContainerRef = useRef < HTMLDivElement > null;
const menuItemRef = useRef<HTMLLIElement>(null)
useImperativeHandle(ref, () => menuItemRef.current)
const containerRef = useRef<HTMLDivElement>(null)
useImperativeHandle(containerRefProp, () => containerRef.current)
const menuContainerRef = useRef<HTMLDivElement>(null)
console.log("PAST THIS: ", containerRefProp, menuItemRef, containerRef, menuContainerRef, ContainerProps)
console.log(
"PAST THIS: ",
containerRefProp,
menuItemRef,
containerRef,
menuContainerRef,
ContainerProps
);
const handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {
setIsSubMenuOpen(true)
setIsSubMenuOpen(true);
if (ContainerProps?.onMouseEnter) {
ContainerProps.onMouseEnter(event)
ContainerProps.onMouseEnter(event);
}
}
};
const handleMouseLeave = (event: React.MouseEvent<HTMLElement>) => {
setIsSubMenuOpen(false)
setIsSubMenuOpen(false);
if (ContainerProps?.onMouseLeave) {
ContainerProps.onMouseLeave(event)
ContainerProps.onMouseLeave(event);
}
}
};
// Check if any immediate children are active
const isSubmenuFocused = () => {
const active = containerRef.current?.ownerDocument?.activeElement
const active = containerRef.current?.ownerDocument?.activeElement;
for (const child of menuContainerRef.current?.children ?? []) {
if (child === active) {
return true
return true;
}
}
return false
}
return false;
};
const handleFocus = (event: React.FocusEvent<HTMLElement>) => {
if (event.target === containerRef.current) {
setIsSubMenuOpen(true)
setIsSubMenuOpen(true);
}
if (ContainerProps?.onFocus) {
ContainerProps.onFocus(event)
ContainerProps.onFocus(event);
}
}
};
const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.key === 'Escape') {
return
if (event.key === "Escape") {
return;
}
if (isSubmenuFocused()) {
event.stopPropagation()
event.stopPropagation();
}
const active = containerRef.current?.ownerDocument?.activeElement
const active = containerRef.current?.ownerDocument?.activeElement;
if (event.key === 'ArrowLeft' && isSubmenuFocused()) {
containerRef.current?.focus()
if (event.key === "ArrowLeft" && isSubmenuFocused()) {
containerRef.current?.focus();
}
if (
event.key === 'ArrowRight' &&
event.key === "ArrowRight" &&
event.target === containerRef.current &&
event.target === active
) {
console.log("MENU: ", menuContainerRef)
const firstChild = menuContainerRef.current.children[0]
console.log("FIRST: ", firstChild)
firstChild.focus()
console.log("MENU: ", menuContainerRef);
const firstChild = menuContainerRef.current.children[0];
console.log("FIRST: ", firstChild);
firstChild.focus();
}
}
};
const open = isSubMenuOpen && parentMenuOpen
const menuItemClasses = useMenuItemStyles({open})
const open = isSubMenuOpen && parentMenuOpen;
const menuItemClasses = useMenuItemStyles({ open });
// Root element must have a `tabIndex` attribute for keyboard navigation
let tabIndex
let tabIndex;
if (!props.disabled) {
tabIndex = tabIndexProp !== undefined ? tabIndexProp : -1
tabIndex = tabIndexProp !== undefined ? tabIndexProp : -1;
}
console.log("PAST 2! ", tabIndex)
console.log("PAST 2! ", tabIndex);
return (
<div
@@ -178,30 +184,30 @@ const NestedMenuItem = (props, ref) => {
<Menu
// Set pointer events to 'none' to prevent the invisible Popover div
// from capturing events for clicks and hovers
style={{pointerEvents: 'none'}}
style={{ pointerEvents: "none" }}
anchorEl={menuItemRef.current}
anchorOrigin={{
vertical: 'top',
horizontal: 'right'
vertical: "top",
horizontal: "right",
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left'
vertical: "top",
horizontal: "left",
}}
open={open}
autoFocus={false}
disableAutoFocus
disableEnforceFocus
onClose={() => {
setIsSubMenuOpen(false)
setIsSubMenuOpen(false);
}}
>
<div ref={menuContainerRef} style={{pointerEvents: 'auto'}}>
<div ref={menuContainerRef} style={{ pointerEvents: "auto" }}>
{children}
</div>
</Menu>
</div>
)
}
);
};
export default NestedMenuItem
export default NestedMenuItem;
+516 -351
View File
@@ -1,224 +1,332 @@
import React, {useRef, useState, useEffect, useLayoutEffect} from 'react';
import { useTheme } from '@material-ui/core/styles';
import React, { useRef, useState, useEffect, useLayoutEffect } from "react";
import { useTheme } from "@material-ui/core/styles";
import { v4 as uuidv4 } from 'uuid';
import { ListItemText, TextField, Drawer, Button, Paper, Grid, Tabs, InputAdornment, Tab, ButtonBase, Tooltip, Select, MenuItem, Divider, Dialog, Modal, DialogActions, DialogTitle, InputLabel, DialogContent, FormControl, IconButton, Menu, Input, FormGroup, FormControlLabel, Typography, Checkbox, Breadcrumbs, CircularProgress, Switch, Fade } from '@material-ui/core';
import { LockOpen as LockOpenIcon } from '@material-ui/icons';
import { v4 as uuidv4 } from "uuid";
import {
ListItemText,
TextField,
Drawer,
Button,
Paper,
Grid,
Tabs,
InputAdornment,
Tab,
ButtonBase,
Tooltip,
Select,
MenuItem,
Divider,
Dialog,
Modal,
DialogActions,
DialogTitle,
InputLabel,
DialogContent,
FormControl,
IconButton,
Menu,
Input,
FormGroup,
FormControlLabel,
Typography,
Checkbox,
Breadcrumbs,
CircularProgress,
Switch,
Fade,
} from "@material-ui/core";
import { LockOpen as LockOpenIcon } from "@material-ui/icons";
const ITEM_HEIGHT = 55
const ITEM_PADDING_TOP = 8
const ITEM_HEIGHT = 55;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
PaperProps: {
style: {
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
minWidth: 500,
minWidth: 500,
maxWidth: 500,
scrollX: "auto",
scrollX: "auto",
},
},
}
};
const AuthenticationOauth2 = (props) => {
const { saveWorkflow, selectedApp, workflow, selectedAction, authenticationType, getAppAuthentication, appAuthentication, setSelectedAction, setNewAppAuth, setAuthenticationModalOpen} = props;
const theme = useTheme();
const {
saveWorkflow,
selectedApp,
workflow,
selectedAction,
authenticationType,
getAppAuthentication,
appAuthentication,
setSelectedAction,
setNewAppAuth,
setAuthenticationModalOpen,
} = props;
const theme = useTheme();
//const [update, setUpdate] = React.useState("|")
const [defaultConfigSet, setDefaultConfigSet] = React.useState(authenticationType.client_id !== undefined && authenticationType.client_id !== null && authenticationType.client_id.length > 0 && authenticationType.client_secret !== undefined && authenticationType.client_secret !== null && authenticationType.client_secret.length > 0)
const [clientId, setClientId] = React.useState(defaultConfigSet ? authenticationType.client_id : "")
const [clientSecret, setClientSecret] = React.useState(defaultConfigSet ? authenticationType.client_secret : "")
const [oauthUrl, setOauthUrl] = React.useState("")
const [buttonClicked, setButtonClicked] = React.useState(false)
const [selectedScopes, setSelectedScopes] = React.useState([])
const allscopes = authenticationType.scope !== undefined ? authenticationType.scope: []
//const [update, setUpdate] = React.useState("|")
const [defaultConfigSet, setDefaultConfigSet] = React.useState(
authenticationType.client_id !== undefined &&
authenticationType.client_id !== null &&
authenticationType.client_id.length > 0 &&
authenticationType.client_secret !== undefined &&
authenticationType.client_secret !== null &&
authenticationType.client_secret.length > 0
);
const [clientId, setClientId] = React.useState(
defaultConfigSet ? authenticationType.client_id : ""
);
const [clientSecret, setClientSecret] = React.useState(
defaultConfigSet ? authenticationType.client_secret : ""
);
const [oauthUrl, setOauthUrl] = React.useState("");
const [buttonClicked, setButtonClicked] = React.useState(false);
const [selectedScopes, setSelectedScopes] = React.useState([]);
const allscopes =
authenticationType.scope !== undefined ? authenticationType.scope : [];
const [manuallyConfigure, setManuallyConfigure] = React.useState(defaultConfigSet ? false : true)
const [authenticationOption, setAuthenticationOptions] = React.useState({
app: JSON.parse(JSON.stringify(selectedApp)),
fields: {},
label: "",
usage: [{
workflow_id: workflow.id,
}],
id: uuidv4(),
active: true,
})
const [manuallyConfigure, setManuallyConfigure] = React.useState(
defaultConfigSet ? false : true
);
const [authenticationOption, setAuthenticationOptions] = React.useState({
app: JSON.parse(JSON.stringify(selectedApp)),
fields: {},
label: "",
usage: [
{
workflow_id: workflow.id,
},
],
id: uuidv4(),
active: true,
});
if (selectedApp.authentication === undefined) {
return null
}
if (selectedApp.authentication === undefined) {
return null;
}
const handleOauth2Request = (client_id, client_secret, oauth_url, scopes) => {
setButtonClicked(true)
console.log("SCOPES: ", scopes)
const handleOauth2Request = (client_id, client_secret, oauth_url, scopes) => {
setButtonClicked(true);
console.log("SCOPES: ", scopes);
var resources = ""
if (scopes !== undefined && scopes !== null & scopes.length > 0) {
//scopes.push("offline_access")
resources = scopes.join(",")
}
var resources = "";
if (scopes !== undefined && (scopes !== null) & (scopes.length > 0)) {
//scopes.push("offline_access")
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`
var state = `workflow_id%3D${workflow.id}%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}`
if (oauth_url !== undefined && oauth_url !== null && oauth_url.length > 0) {
state += `%26oauth_url%3d${oauth_url}`
console.log("ADDING OAUTH2 URL: ", state)
}
const authentication_url = authenticationType.token_uri;
//console.log("AUTH: ", authenticationType)
//console.log("SCOPES2: ", resources)
const redirectUri = `${window.location.protocol}//${window.location.host}/set_authentication`;
var state = `workflow_id%3D${workflow.id}%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}`;
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 && authenticationType.refresh_uri.length > 0) {
state += `%26refresh_uri%3d${authenticationType.refresh_uri}`
} else {
state += `%26refresh_uri%3d${authentication_url}`
}
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}`;
}
const url = `${authenticationType.redirect_uri}?client_id=${client_id}&redirect_uri=${redirectUri}&response_type=code&scope=${resources}&prompt=consent&state=${state}&access_type=offline`
const url = `${authenticationType.redirect_uri}?client_id=${client_id}&redirect_uri=${redirectUri}&response_type=code&scope=${resources}&prompt=consent&state=${state}&access_type=offline`;
//const url = `https://accounts.zoho.com/oauth/v2/auth?response_type=code&client_id=${client_id}&scope=AaaServer.profile.Read&redirect_uri=${redirectUri}&prompt=consent`
//console.log("Full URI: ", url)
//console.log("Redirect Uri: ", redirectUri)
// &resource=https%3A%2F%2Fgraph.microsoft.com&
// FIXME: Awful, but works for prototyping
// How can we get a callback properly realtime?
// How can we properly try-catch without breaks on error?
try {
//const url = `https://accounts.zoho.com/oauth/v2/auth?response_type=code&client_id=${client_id}&scope=AaaServer.profile.Read&redirect_uri=${redirectUri}&prompt=consent`
//console.log("Full URI: ", url)
//console.log("Redirect Uri: ", redirectUri)
// &resource=https%3A%2F%2Fgraph.microsoft.com&
var newwin = window.open(url, "", "width=800,height=600")
//console.log(newwin)
var open = true
const timer = setInterval(() => {
if (newwin.closed) {
setButtonClicked(false)
clearInterval(timer);
//alert('"Secure Payment" window closed!');
// FIXME: Awful, but works for prototyping
// 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");
//console.log(newwin)
getAppAuthentication(true, true)
}
}, 1000);
//do {
// setTimeout(() => {
// console.log(newwin)
// console.log("CLOSED", newwin.closed)
// if (newwin.closed) {
var open = true;
const timer = setInterval(() => {
if (newwin.closed) {
setButtonClicked(false);
clearInterval(timer);
//alert('"Secure Payment" window closed!');
// open = false
// }
// }, 1000)
//}
//while(open === true)
} catch (e) {
alert.error("Failed authentication - probably bad credentials. Try again")
setButtonClicked(false)
}
getAppAuthentication(true, true);
}
}, 1000);
//do {
// setTimeout(() => {
// console.log(newwin)
// console.log("CLOSED", newwin.closed)
// if (newwin.closed) {
return
//do {
//} while (
}
// open = false
// }
// }, 1000)
//}
//while(open === true)
} catch (e) {
alert.error(
"Failed authentication - probably bad credentials. Try again"
);
setButtonClicked(false);
}
return;
//do {
//} while (
};
authenticationOption.app.actions = []
authenticationOption.app.actions = [];
for (var key in selectedApp.authentication.parameters) {
if (authenticationOption.fields[selectedApp.authentication.parameters[key].name] === undefined) {
authenticationOption.fields[selectedApp.authentication.parameters[key].name] = ""
}
}
for (var key in selectedApp.authentication.parameters) {
if (
authenticationOption.fields[
selectedApp.authentication.parameters[key].name
] === undefined
) {
authenticationOption.fields[
selectedApp.authentication.parameters[key].name
] = "";
}
}
const handleSubmitCheck = () => {
console.log("NEW AUTH: ", authenticationOption)
if (authenticationOption.label.length === 0) {
authenticationOption.label = `Auth for ${selectedApp.name}`
//alert.info("Label can't be empty")
//return
}
const handleSubmitCheck = () => {
console.log("NEW AUTH: ", authenticationOption);
if (authenticationOption.label.length === 0) {
authenticationOption.label = `Auth for ${selectedApp.name}`;
//alert.info("Label can't be empty")
//return
}
// Automatically mapping fields that already exist (predefined).
// Warning if fields are NOT filled
for (var key in selectedApp.authentication.parameters) {
if (authenticationOption.fields[selectedApp.authentication.parameters[key].name].length === 0) {
if (selectedApp.authentication.parameters[key].value !== undefined && selectedApp.authentication.parameters[key].value !== null && selectedApp.authentication.parameters[key].value.length > 0) {
authenticationOption.fields[selectedApp.authentication.parameters[key].name] = selectedApp.authentication.parameters[key].value
} else {
if (selectedApp.authentication.parameters[key].schema.type === "bool") {
authenticationOption.fields[selectedApp.authentication.parameters[key].name] = "false"
} else {
alert.info("Field "+selectedApp.authentication.parameters[key].name+" can't be empty")
return
}
}
}
}
// Automatically mapping fields that already exist (predefined).
// Warning if fields are NOT filled
for (var key in selectedApp.authentication.parameters) {
if (
authenticationOption.fields[
selectedApp.authentication.parameters[key].name
].length === 0
) {
if (
selectedApp.authentication.parameters[key].value !== undefined &&
selectedApp.authentication.parameters[key].value !== null &&
selectedApp.authentication.parameters[key].value.length > 0
) {
authenticationOption.fields[
selectedApp.authentication.parameters[key].name
] = selectedApp.authentication.parameters[key].value;
} else {
if (
selectedApp.authentication.parameters[key].schema.type === "bool"
) {
authenticationOption.fields[
selectedApp.authentication.parameters[key].name
] = "false";
} else {
alert.info(
"Field " +
selectedApp.authentication.parameters[key].name +
" can't be empty"
);
return;
}
}
}
}
console.log("Action: ", selectedAction)
selectedAction.authentication_id = authenticationOption.id
selectedAction.selectedAuthentication = authenticationOption
if (selectedAction.authentication === undefined || selectedAction.authentication === null) {
selectedAction.authentication = [authenticationOption]
} else {
selectedAction.authentication.push(authenticationOption)
}
console.log("Action: ", selectedAction);
selectedAction.authentication_id = authenticationOption.id;
selectedAction.selectedAuthentication = authenticationOption;
if (
selectedAction.authentication === undefined ||
selectedAction.authentication === null
) {
selectedAction.authentication = [authenticationOption];
} else {
selectedAction.authentication.push(authenticationOption);
}
setSelectedAction(selectedAction)
setSelectedAction(selectedAction);
var newAuthOption = JSON.parse(JSON.stringify(authenticationOption))
var newFields = []
for (const key in newAuthOption.fields) {
const value = newAuthOption.fields[key]
newFields.push({
key: key,
value: value,
})
}
var newAuthOption = JSON.parse(JSON.stringify(authenticationOption));
var newFields = [];
for (const key in newAuthOption.fields) {
const value = newAuthOption.fields[key];
newFields.push({
key: key,
value: value,
});
}
console.log("FIELDS: ", newFields)
newAuthOption.fields = newFields
setNewAppAuth(newAuthOption)
//appAuthentication.push(newAuthOption)
//setAppAuthentication(appAuthentication)
//
//if (configureWorkflowModalOpen) {
// setSelectedAction({})
//}
//setUpdate(authenticationOption.id)
console.log("FIELDS: ", newFields);
newAuthOption.fields = newFields;
setNewAppAuth(newAuthOption);
//appAuthentication.push(newAuthOption)
//setAppAuthentication(appAuthentication)
//
/*
//if (configureWorkflowModalOpen) {
// setSelectedAction({})
//}
//setUpdate(authenticationOption.id)
/*
{selectedAction.authentication.map(data => (
<MenuItem key={data.id} style={{backgroundColor: inputColor, color: "white"}} value={data}>
*/
}
};
const handleScopeChange = (event) => {
const {
target: { value },
} = event;
} = event;
console.log("VALUE: ", value)
console.log("VALUE: ", value);
// On autofill we get a the stringified value.
setSelectedScopes(typeof value === 'string' ? value.split(',') : value)
setSelectedScopes(typeof value === "string" ? value.split(",") : value);
};
if (
authenticationOption.label === null ||
authenticationOption.label === undefined
) {
authenticationOption.label = selectedApp.name + " authentication";
}
if (authenticationOption.label === null || authenticationOption.label === undefined) {
authenticationOption.label = selectedApp.name+" authentication"
}
//console.log(
return (
<div>
<DialogTitle><div style={{color: "white"}}>Authentication for {selectedApp.name}</div></DialogTitle>
<DialogContent>
<span style={{}}>
<b>Oauth2 requires a client ID and secret to authenticate. This is usually made in the remote system.</b>
<a target="_blank" rel="norefferer" href="https://shuffler.io/docs/apps#authentication" style={{textDecoration: "none", color: "#f85a3e"}}> Learn more about Oauth2 with Shuffle</a><div/>
</span>
{/*<TextField
//console.log(
return (
<div>
<DialogTitle>
<div style={{ color: "white" }}>
Authentication for {selectedApp.name}
</div>
</DialogTitle>
<DialogContent>
<span style={{}}>
<b>
Oauth2 requires a client ID and secret to authenticate. This is
usually made in the remote system.
</b>
<a
target="_blank"
rel="norefferer"
href="https://shuffler.io/docs/apps#authentication"
style={{ textDecoration: "none", color: "#f85a3e" }}
>
{" "}
Learn more about Oauth2 with Shuffle
</a>
<div />
</span>
{/*<TextField
style={{backgroundColor: theme.palette.inputColor, borderRadius: theme.palette.borderRadius,}}
InputProps={{
style:{
@@ -240,186 +348,243 @@ const AuthenticationOauth2 = (props) => {
<Divider style={{marginTop: 15, marginBottom: 15, backgroundColor: "rgb(91, 96, 100)"}}/>
*/}
{!manuallyConfigure ? null :
<span>
{selectedApp.authentication.parameters.map((data, index) => {
//console.log(data, index)
if (data.name === "client_id" || data.name === "client_secret") {
return null
}
{!manuallyConfigure ? null : (
<span>
{selectedApp.authentication.parameters.map((data, index) => {
//console.log(data, index)
if (data.name === "client_id" || data.name === "client_secret") {
return null;
}
if (data.name !== "url") {
return null
}
if (data.name !== "url") {
return null;
}
if (oauthUrl.length === 0) {
setOauthUrl(data.value)
}
if (oauthUrl.length === 0) {
setOauthUrl(data.value);
}
return (
<div key={index} style={{marginTop: 10}}>
<LockOpenIcon style={{marginRight: 10}}/>
<b>{data.name}</b>
return (
<div key={index} style={{ marginTop: 10 }}>
<LockOpenIcon style={{ marginRight: 10 }} />
<b>{data.name}</b>
{data.schema !== undefined && data.schema !== null && data.schema.type === "bool" ?
<Select
SelectDisplayProps={{
style: {
marginLeft: 10,
}
}}
defaultValue={"false"}
fullWidth
onChange={(e) => {
console.log("Value: ", e.target.value)
authenticationOption.fields[data.name] = e.target.value
}}
style={{backgroundColor: theme.palette.surfaceColor, color: "white", height: 50}}
>
<MenuItem key={"false"} style={{backgroundColor: theme.palette.inputColor, color: "white"}} value={"false"}>
false
</MenuItem>
<MenuItem key={"true"} style={{backgroundColor: theme.palette.inputColor, color: "white"}} value={"true"}>
true
</MenuItem>
</Select>
:
<TextField
style={{backgroundColor: theme.palette.inputColor, borderRadius: theme.palette.borderRadius,}}
InputProps={{
style:{
color: "white",
marginLeft: "5px",
maxWidth: "95%",
height: 50,
fontSize: "1em",
},
}}
fullWidth
type={data.example !== undefined && data.example.includes("***") ? "password" : "text"}
color="primary"
defaultValue={data.value !== undefined && data.value !== null ? data.value : ""}
placeholder={data.example}
onChange={(event) => {
authenticationOption.fields[data.name] = event.target.value
console.log("Setting oauth url")
setOauthUrl(event.target.value)
//const [oauthUrl, setOauthUrl] = React.useState("")
}}
/>
}
</div>
)
})}
{allscopes.length === 0 ? null :
<Select
multiple
value={selectedScopes}
style={{backgroundColor: theme.palette.inputColor, color: "white", }}
onChange={(e) => {
handleScopeChange(e)
}}
fullWidth
input={<Input id="select-multiple-native" />}
renderValue={(selected) => selected.join(', ')}
MenuProps={MenuProps}
>
{allscopes.map((data, index) => {
return (
<MenuItem key={index} value={data}>
<Checkbox checked={selectedScopes.indexOf(data) > -1} />
<ListItemText primary={data} />
</MenuItem>
)
})}
</Select>
}
<TextField
style={{marginTop: 20, backgroundColor: theme.palette.inputColor, borderRadius: theme.palette.borderRadius,}}
InputProps={{
style:{
color: "white",
marginLeft: "5px",
maxWidth: "95%",
height: 50,
fontSize: "1em",
},
}}
fullWidth
color="primary"
placeholder={"Client ID"}
onChange={(event) => {
setClientId(event.target.value)
//authenticationOption.label = event.target.value
}}
/>
<TextField
style={{backgroundColor: theme.palette.inputColor, borderRadius: theme.palette.borderRadius,}}
InputProps={{
style:{
color: "white",
marginLeft: "5px",
maxWidth: "95%",
height: 50,
fontSize: "1em",
},
}}
fullWidth
color="primary"
placeholder={"Client Secret"}
onChange={(event) => {
setClientSecret(event.target.value)
//authenticationOption.label = event.target.value
}}
/>
</span>
}
<Button
style={{marginBottom: 40, marginTop: 20, borderRadius: theme.palette.borderRadius}}
disabled={clientSecret.length === 0 || clientId.length === 0 || buttonClicked}
variant="contained"
fullWidth
onClick={() => {
handleOauth2Request(clientId, clientSecret, oauthUrl, selectedScopes)
}}
color="primary"
>
{buttonClicked ?
<CircularProgress style={{color: "white", }} />
:
"Oauth2 request"
}
</Button>
{data.schema !== undefined &&
data.schema !== null &&
data.schema.type === "bool" ? (
<Select
SelectDisplayProps={{
style: {
marginLeft: 10,
},
}}
defaultValue={"false"}
fullWidth
onChange={(e) => {
console.log("Value: ", e.target.value);
authenticationOption.fields[data.name] = e.target.value;
}}
style={{
backgroundColor: theme.palette.surfaceColor,
color: "white",
height: 50,
}}
>
<MenuItem
key={"false"}
style={{
backgroundColor: theme.palette.inputColor,
color: "white",
}}
value={"false"}
>
false
</MenuItem>
<MenuItem
key={"true"}
style={{
backgroundColor: theme.palette.inputColor,
color: "white",
}}
value={"true"}
>
true
</MenuItem>
</Select>
) : (
<TextField
style={{
backgroundColor: theme.palette.inputColor,
borderRadius: theme.palette.borderRadius,
}}
InputProps={{
style: {
color: "white",
marginLeft: "5px",
maxWidth: "95%",
height: 50,
fontSize: "1em",
},
}}
fullWidth
type={
data.example !== undefined &&
data.example.includes("***")
? "password"
: "text"
}
color="primary"
defaultValue={
data.value !== undefined && data.value !== null
? data.value
: ""
}
placeholder={data.example}
onChange={(event) => {
authenticationOption.fields[data.name] =
event.target.value;
console.log("Setting oauth url");
setOauthUrl(event.target.value);
//const [oauthUrl, setOauthUrl] = React.useState("")
}}
/>
)}
</div>
);
})}
{allscopes.length === 0 ? null : (
<Select
multiple
value={selectedScopes}
style={{
backgroundColor: theme.palette.inputColor,
color: "white",
}}
onChange={(e) => {
handleScopeChange(e);
}}
fullWidth
input={<Input id="select-multiple-native" />}
renderValue={(selected) => selected.join(", ")}
MenuProps={MenuProps}
>
{allscopes.map((data, index) => {
return (
<MenuItem key={index} value={data}>
<Checkbox checked={selectedScopes.indexOf(data) > -1} />
<ListItemText primary={data} />
</MenuItem>
);
})}
</Select>
)}
<TextField
style={{
marginTop: 20,
backgroundColor: theme.palette.inputColor,
borderRadius: theme.palette.borderRadius,
}}
InputProps={{
style: {
color: "white",
marginLeft: "5px",
maxWidth: "95%",
height: 50,
fontSize: "1em",
},
}}
fullWidth
color="primary"
placeholder={"Client ID"}
onChange={(event) => {
setClientId(event.target.value);
//authenticationOption.label = event.target.value
}}
/>
<TextField
style={{
backgroundColor: theme.palette.inputColor,
borderRadius: theme.palette.borderRadius,
}}
InputProps={{
style: {
color: "white",
marginLeft: "5px",
maxWidth: "95%",
height: 50,
fontSize: "1em",
},
}}
fullWidth
color="primary"
placeholder={"Client Secret"}
onChange={(event) => {
setClientSecret(event.target.value);
//authenticationOption.label = event.target.value
}}
/>
</span>
)}
<Button
style={{
marginBottom: 40,
marginTop: 20,
borderRadius: theme.palette.borderRadius,
}}
disabled={
clientSecret.length === 0 || clientId.length === 0 || buttonClicked
}
variant="contained"
fullWidth
onClick={() => {
handleOauth2Request(
clientId,
clientSecret,
oauthUrl,
selectedScopes
);
}}
color="primary"
>
{buttonClicked ? (
<CircularProgress style={{ color: "white" }} />
) : (
"Oauth2 request"
)}
</Button>
{defaultConfigSet ?
<span style={{}}>
... or
<Button
style={{marginLeft: 10, borderRadius: theme.palette.borderRadius}}
disabled={clientSecret.length === 0 || clientId.length === 0}
variant="text"
onClick={() => {
setManuallyConfigure(!manuallyConfigure)
{defaultConfigSet ? (
<span style={{}}>
... or
<Button
style={{
marginLeft: 10,
borderRadius: theme.palette.borderRadius,
}}
disabled={clientSecret.length === 0 || clientId.length === 0}
variant="text"
onClick={() => {
setManuallyConfigure(!manuallyConfigure);
if (manuallyConfigure) {
setClientId(authenticationType.client_id)
setClientSecret(authenticationType.client_secret)
} else {
setClientId("")
setClientSecret("")
}
}}
color="primary"
>
{manuallyConfigure ? "Use auto-config" : "Manually configure Oauth2"}
</Button>
</span>
:
null
}
</DialogContent>
</div>
)
}
if (manuallyConfigure) {
setClientId(authenticationType.client_id);
setClientSecret(authenticationType.client_secret);
} else {
setClientId("");
setClientSecret("");
}
}}
color="primary"
>
{manuallyConfigure
? "Use auto-config"
: "Manually configure Oauth2"}
</Button>
</span>
) : null}
</DialogContent>
</div>
);
};
export default AuthenticationOauth2
export default AuthenticationOauth2;
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+111 -100
View File
@@ -1,79 +1,82 @@
import React, {useState, useEffect, useLayoutEffect} from 'react';
import * as cytoscape from 'cytoscape';
import CytoscapeComponent from 'react-cytoscapejs';
import cystyle from '../defaultCytoscapeStyle';
import React, { useState, useEffect, useLayoutEffect } from "react";
import * as cytoscape from "cytoscape";
import CytoscapeComponent from "react-cytoscapejs";
import cystyle from "../defaultCytoscapeStyle";
const surfaceColor = "#27292D"
const surfaceColor = "#27292D";
const CytoscapeWrapper = (props) => {
const { globalUrl, inworkflow } = props;
const [elements, setElements] = useState([])
const [workflow, setWorkflow] = useState(inworkflow)
const [cy, setCy] = React.useState()
const bodyWidth = 200
const bodyHeight = 150
const [elements, setElements] = useState([]);
const [workflow, setWorkflow] = useState(inworkflow);
const [cy, setCy] = React.useState();
const bodyWidth = 200;
const bodyHeight = 150;
const setupGraph = () => {
const actions = workflow.actions.map(action => {
const node = {}
node.position = action.position
node.data = action
const setupGraph = () => {
const actions = workflow.actions.map((action) => {
const node = {};
node.position = action.position;
node.data = action;
node.data._id = action["id"]
node.data.type = "ACTION"
node.isStartNode = action["id"] === workflow.start
node.data._id = action["id"];
node.data.type = "ACTION";
node.isStartNode = action["id"] === workflow.start;
var example = "";
if (
action.example !== undefined &&
action.example !== null &&
action.example.length > 0
) {
example = action.example;
}
var example = ""
if (action.example !== undefined && action.example !== null && action.example.length > 0) {
example = action.example
}
node.data.example = example;
return node;
});
node.data.example = example
return node;
})
const triggers = workflow.triggers.map((trigger) => {
const node = {};
node.position = trigger.position;
node.data = trigger;
const triggers = workflow.triggers.map(trigger => {
const node = {}
node.position = trigger.position
node.data = trigger
node.data._id = trigger["id"];
node.data.type = "TRIGGER";
node.data._id = trigger["id"]
node.data.type = "TRIGGER"
return node;
});
return node;
})
// FIXME - tmp branch update
var insertedNodes = [].concat(actions, triggers);
const edges = workflow.branches.map((branch, index) => {
//workflow.branches[index].conditions = [{
// FIXME - tmp branch update
var insertedNodes = [].concat(actions, triggers)
const edges = workflow.branches.map((branch, index) => {
//workflow.branches[index].conditions = [{
const edge = {};
var conditions = workflow.branches[index].conditions;
if (conditions === undefined || conditions === null) {
conditions = [];
}
const edge = { };
var conditions = workflow.branches[index].conditions
if (conditions === undefined || conditions === null) {
conditions = []
}
var label = "";
if (conditions.length === 1) {
label = conditions.length + " condition";
} else if (conditions.length > 1) {
label = conditions.length + " conditions";
}
var label = ""
if (conditions.length === 1) {
label = conditions.length+" condition"
} else if (conditions.length > 1) {
label = conditions.length+" conditions"
}
edge.data = {
id: branch.id,
_id: branch.id,
source: branch.source_id,
target: branch.destination_id,
label: label,
conditions: conditions,
hasErrors: branch.has_errors,
};
edge.data = {
id: branch.id,
_id: branch.id,
source: branch.source_id,
target: branch.destination_id,
label: label,
conditions: conditions,
hasErrors: branch.has_errors
};
// This is an attempt at prettier edges. The numbers are weird to work with.
/*
// This is an attempt at prettier edges. The numbers are weird to work with.
/*
//http://manual.graphspace.org/projects/graphspace-python/en/latest/demos/edge-types.html
const sourcenode = actions.find(node => node.data._id === branch.source_id)
const destinationnode = actions.find(node => node.data._id === branch.destination_id)
@@ -96,51 +99,59 @@ const CytoscapeWrapper = (props) => {
}
*/
return edge;
})
return edge;
});
setWorkflow(workflow)
setWorkflow(workflow);
// Verifies if a branch is valid and skips others
var newedges = []
for (var key in edges) {
var item = edges[key]
// Verifies if a branch is valid and skips others
var newedges = [];
for (var key in edges) {
var item = edges[key];
const sourcecheck = insertedNodes.find(data => data.data.id === item.data.source)
const destcheck = insertedNodes.find(data => data.data.id === item.data.target)
if (sourcecheck === undefined || destcheck === undefined) {
continue
}
const sourcecheck = insertedNodes.find(
(data) => data.data.id === item.data.source
);
const destcheck = insertedNodes.find(
(data) => data.data.id === item.data.target
);
if (sourcecheck === undefined || destcheck === undefined) {
continue;
}
newedges.push(item)
}
newedges.push(item);
}
insertedNodes = insertedNodes.concat(newedges)
setElements(insertedNodes)
}
insertedNodes = insertedNodes.concat(newedges);
setElements(insertedNodes);
};
if (elements.length === 0) {
setupGraph()
}
if (elements.length === 0) {
setupGraph();
}
return (
<CytoscapeComponent
elements={elements}
minZoom={0.35}
maxZoom={2.00}
style={{width: bodyWidth-15, height: bodyHeight-5, backgroundColor: surfaceColor}}
stylesheet={cystyle}
boxSelectionEnabled={true}
autounselectify={false}
showGrid={true}
cy={(incy) => {
// FIXME: There's something specific loading when
// you do the first hover of a node. Why is this different?
//console.log("CY: ", incy)
setCy(incy)
}}
/>
)
}
return (
<CytoscapeComponent
elements={elements}
minZoom={0.35}
maxZoom={2.0}
style={{
width: bodyWidth - 15,
height: bodyHeight - 5,
backgroundColor: surfaceColor,
}}
stylesheet={cystyle}
boxSelectionEnabled={true}
autounselectify={false}
showGrid={true}
cy={(incy) => {
// FIXME: There's something specific loading when
// you do the first hover of a node. Why is this different?
//console.log("CY: ", incy)
setCy(incy);
}}
/>
);
};
export default CytoscapeWrapper
export default CytoscapeWrapper;
+11 -11
View File
@@ -1,24 +1,24 @@
import { useEffect } from 'react';
import { withRouter } from 'react-router-dom';
import { useEffect } from "react";
import { withRouter } from "react-router-dom";
function ScrollToTop({getUserNotifications, setCurpath, history }) {
function ScrollToTop({ getUserNotifications, setCurpath, history }) {
useEffect(() => {
const unlisten = history.listen(() => {
window.scroll({
top: 0,
left: 0,
behavior: "smooth",
});
top: 0,
left: 0,
behavior: "smooth",
});
setCurpath(window.location.pathname)
getUserNotifications()
setCurpath(window.location.pathname);
getUserNotifications();
});
return () => {
unlisten();
}
};
}, []);
return (null);
return null;
}
// https://stackoverflow.com/questions/36904185/react-router-scroll-to-top-on-every-transition
+161 -125
View File
@@ -1,141 +1,177 @@
import React, {useState} from 'react';
import React, { useState } from "react";
import DialogTitle from '@material-ui/core/DialogTitle';
import Dialog from '@material-ui/core/Dialog';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import Divider from '@material-ui/core/Divider';
import DialogTitle from "@material-ui/core/DialogTitle";
import Dialog from "@material-ui/core/Dialog";
import TextField from "@material-ui/core/TextField";
import Button from "@material-ui/core/Button";
import Divider from "@material-ui/core/Divider";
const SettingsDialog = (props) => {
const {
classes,
onClose,
settingsOpen,
settingsData,
globalUrl,
isLoggedIn,
setIsLoggedIn,
...other
} = props;
const SettingsDialog = props => {
const { classes, onClose, settingsOpen, settingsData, globalUrl, isLoggedIn, setIsLoggedIn, ...other } = props;
const [password1, setPassword1] = useState("");
const [password2, setPassword2] = useState("");
const [password3, setPassword3] = useState("");
const handleValidateForm = () => {
var passlength = 10
if (password1 === password2 && password1.length >= passlength && password3.length >= passlength) {
return true
}
const handleValidateForm = () => {
var passlength = 10;
if (
password1 === password2 &&
password1.length >= passlength &&
password3.length >= passlength
) {
return true;
}
return false
}
return false;
};
const onChangePass1 = (e) => {
setPassword1(e.target.value)
}
const onChangePass1 = (e) => {
setPassword1(e.target.value);
};
const onChangePass2 = (e) => {
setPassword2(e.target.value)
}
const onChangePass2 = (e) => {
setPassword2(e.target.value);
};
const onChangePass3 = (e) => {
setPassword3(e.target.value)
}
const onChangePass3 = (e) => {
setPassword3(e.target.value);
};
const onSubmitPassReset = () => {
console.log("Should change password")
// Rofl, this can't possibly be typesafe
var data = '{"password1": "'+password1+'", "password2": "'+password2+'", "password3": "'+password3+'"}'
const onSubmitPassReset = () => {
console.log("Should change password");
// Rofl, this can't possibly be typesafe
var data =
'{"password1": "' +
password1 +
'", "password2": "' +
password2 +
'", "password3": "' +
password3 +
'"}';
fetch(globalUrl+"/passwordreset", {
body: data,
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
fetch(globalUrl + "/passwordreset", {
body: data,
method: "POST",
headers: {
"Content-Type": "application/json",
},
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson)
if (responseJson.status === true) {
console.log("SUCCESS")
}
})
.catch(error => {
console.log(error)
});
}
//PaperProps={{style: {minWidth: "500px"}}
return(
<Dialog open={settingsOpen} onClose={() => onClose()} {...other}>
<DialogTitle>Settings</DialogTitle>
<Divider />
<div style={{marginLeft: "15px", marginRight: "15px"}}>
<h3>
Username
</h3>
{settingsData.username}
</div>
<div style={{marginLeft: "15px", marginRight: "15px", marginBottom: "15px"}}>
<h3>
ApiKey
</h3>
<TextField
id="outlined-read-only-input"
defaultValue={settingsData.apikey}
value={settingsData.apikey}
style={{width: 320}}
InputProps={{
readOnly: true,
}}
variant="outlined"
/>
</div>
<Divider />
<form style={{margin: "15px 15px 15px 15px"}}>
<h3>
Change password
</h3>
<div>
<TextField
id="standard-password-input"
label="Current password"
type="password"
name="password"
style={{width: 320}}
placeholder="********************************"
autoComplete="current-password"
margin="normal"
variant="outlined"
onChange={onChangePass1}
/>
</div>
<div>
<TextField
label="Confirm current password"
type="password"
placeholder="********************************"
name="password"
style={{width: 320}}
autoComplete="current-password"
margin="normal"
variant="outlined"
onChange={onChangePass2}
/>
</div>
<div>
<TextField
label="New password"
type="password"
name="password"
placeholder="********************************"
style={{width: 320}}
margin="normal"
variant="outlined"
onChange={onChangePass3}
/>
</div>
<div style={{display: "flex", marginTop: "10px"}}>
<Button color="secondary" variant="contained" onClick={onSubmitPassReset} type="button" style={{flex: "1", marginRight: "5px"}} disabled={!handleValidateForm()}>SUBMIT</Button>
<Button color="primary" variant="contained" type="button" style={{flex: "1"}} onClick={onClose}>Cancel</Button>
</div>
</form>
</Dialog>
);
}
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
if (responseJson.status === true) {
console.log("SUCCESS");
}
})
.catch((error) => {
console.log(error);
});
};
//PaperProps={{style: {minWidth: "500px"}}
return (
<Dialog open={settingsOpen} onClose={() => onClose()} {...other}>
<DialogTitle>Settings</DialogTitle>
<Divider />
<div style={{ marginLeft: "15px", marginRight: "15px" }}>
<h3>Username</h3>
{settingsData.username}
</div>
<div
style={{
marginLeft: "15px",
marginRight: "15px",
marginBottom: "15px",
}}
>
<h3>ApiKey</h3>
<TextField
id="outlined-read-only-input"
defaultValue={settingsData.apikey}
value={settingsData.apikey}
style={{ width: 320 }}
InputProps={{
readOnly: true,
}}
variant="outlined"
/>
</div>
<Divider />
<form style={{ margin: "15px 15px 15px 15px" }}>
<h3>Change password</h3>
<div>
<TextField
id="standard-password-input"
label="Current password"
type="password"
name="password"
style={{ width: 320 }}
placeholder="********************************"
autoComplete="current-password"
margin="normal"
variant="outlined"
onChange={onChangePass1}
/>
</div>
<div>
<TextField
label="Confirm current password"
type="password"
placeholder="********************************"
name="password"
style={{ width: 320 }}
autoComplete="current-password"
margin="normal"
variant="outlined"
onChange={onChangePass2}
/>
</div>
<div>
<TextField
label="New password"
type="password"
name="password"
placeholder="********************************"
style={{ width: 320 }}
margin="normal"
variant="outlined"
onChange={onChangePass3}
/>
</div>
<div style={{ display: "flex", marginTop: "10px" }}>
<Button
color="secondary"
variant="contained"
onClick={onSubmitPassReset}
type="button"
style={{ flex: "1", marginRight: "5px" }}
disabled={!handleValidateForm()}
>
SUBMIT
</Button>
<Button
color="primary"
variant="contained"
type="button"
style={{ flex: "1" }}
onClick={onClose}
>
Cancel
</Button>
</div>
</form>
</Dialog>
);
};
export default SettingsDialog;
+5 -5
View File
@@ -1,8 +1,8 @@
import { createBrowserHistory } from 'history';
import { createBrowserHistory } from "history";
var localExport
if (typeof window !== 'undefined') {
localExport = createBrowserHistory({forceRefresh: true});
var localExport;
if (typeof window !== "undefined") {
localExport = createBrowserHistory({ forceRefresh: true });
}
export default localExport
export default localExport;
+19 -14
View File
@@ -1,40 +1,45 @@
/* cyrillic-ext */
@font-face {
font-family: 'Nunito Sans';
font-family: "Nunito Sans";
font-style: normal;
font-weight: 400;
src: url('./font1.woff2') format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
src: url("./font1.woff2") format("woff2");
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F,
U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Nunito Sans';
font-family: "Nunito Sans";
font-style: normal;
font-weight: 400;
src: url('./font2.woff2') format('woff2');
src: url("./font2.woff2") format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Nunito Sans';
font-family: "Nunito Sans";
font-style: normal;
font-weight: 400;
src: url('./font3.woff2') format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
src: url("./font3.woff2") format("woff2");
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1,
U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Nunito Sans';
font-family: "Nunito Sans";
font-style: normal;
font-weight: 400;
src: url('./font4.woff2') format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
src: url("./font4.woff2") format("woff2");
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Nunito Sans';
font-family: "Nunito Sans";
font-style: normal;
font-weight: 400;
src: url('./font5.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
src: url("./font5.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
U+FEFF, U+FFFD;
}
+389 -388
View File
@@ -1,389 +1,391 @@
const data = [{
selector: 'node',
css: {
'label': 'data(label)',
'text-valign': 'center',
'font-family': 'Segoe UI, Tahoma, Geneva, Verdana, sans-serif, sans-serif',
'font-weight': 'lighter',
'margin-right': '10px',
'font-size': '18px',
'width': '80px',
'height': '80px',
'color': 'white',
'padding': '10px',
'margin': '5px',
'border-width': '1px',
'text-margin-x': '10px',
'cursor': 'pointer',
"z-index": 5001,
}
},
{
selector: 'edge',
css: {
'target-arrow-shape': 'triangle',
'target-arrow-color': 'grey',
'curve-style': 'unbundled-bezier',
'label': 'data(label)',
'text-margin-y': '-15px',
'width': '5px',
"color": "white",
'cursor': 'pointer',
"line-fill": "linear-gradient",
"line-gradient-stop-positions": ["0.0", "100"],
"line-gradient-stop-colors": ["grey", "grey"],
"z-index": 5001,
},
},
{
selector: `node[type="ACTION"]`,
css: {
'shape': 'roundrectangle',
'background-color': '#213243',
'border-color': '#81c784',
'background-width': '100%',
'background-height': '100%',
'border-radius': '5px',
'z-index': 5001,
},
},
{
selector: `node[type="COMMENT"]`,
css: {
'shape': 'roundrectangle',
'background-color': 'data(backgroundcolor)',
'border-color': '#ffffff',
'color': 'data(color)',
'width': 'data(width)',
'height': 'data(height)',
'border-radius': '5px',
"background-opacity": "0.5",
'padding': '0px',
'margin': '0px',
'text-margin-x': '0px',
'z-index': 4999,
},
},
{
selector: `node[app_name="Shuffle Tools"]`,
css: {
'width': '30px',
'height': '30px',
'z-index': 5000,
'font-size': '0px',
'background-width': '75%',
'background-height': '75%',
'background-color': 'data(iconBackground)',
'background-fill': 'data(fillstyle)',
'background-gradient-direction': 'to-right',
'background-gradient-stop-colors': 'data(fillGradient)',
}
},
{
selector: `node[app_name="Testing"]`,
css: {
'width': '30px',
'height': '30px',
'z-index': 5000,
'font-size': '0px',
},
},
{
selector: `node[?small_image]`,
css: {
'background-image': 'data(small_image)',
'text-halign': 'right',
},
},
{
selector: `node[?large_image]`,
css: {
'background-image': 'data(large_image)',
'text-halign': 'right',
},
},
{
selector: `node[type="CONDITION"]`,
css: {
'shape': 'diamond',
'border-color': '##FFEB3B',
'padding': '30px'
},
},
{
selector: `node[type="eventAction"]`,
css: {
'background-color': '#edbd21',
},
},
{
selector: `node[type="TRIGGER"]`,
css: {
'shape': 'octagon',
'border-radius': '5px',
'border-color': 'orange',
'background-color': '#213243',
'background-width': '100%',
'background-height': '100%',
},
},
{
selector: `node[status="running"]`,
css: {
'border-color': '#81c784',
},
},
{
selector: `node[status="stopped"]`,
css: {
'border-color': 'orange',
},
},
{
selector: 'node[type="mq"]',
css: {
'background-color': '#edbd21',
},
},
{
selector: 'node[?isButton]',
css: {
'shape': 'ellipse',
'width': '15px',
'height': '15px',
'z-index': '5002',
'font-size': '0px',
'border': '1px solid rgba(255,255,255,0.9)',
'background-image': 'data(icon)',
'background-color': 'data(iconBackground)',
},
},
{
selector: 'node[?isDescriptor]',
css: {
'shape': 'ellipse',
'border-color': '#80deea',
'width': '5px',
'height': '5px',
'z-index': '5002',
'font-size': '10px',
'text-valign': 'center',
'text-halign': 'center',
'border': '1px solid black',
'margin-right': '0px',
'text-margin-x': '0px',
'background-color': 'data(imageColor)',
'background-image': 'data(image)',
},
},
{
selector: 'node[?isStartNode]',
css: {
'shape': 'ellipse',
'border-color': '#80deea',
'width': '80px',
'height': '80px',
'font-size': '18px',
'background-width': '100%',
'background-height': '100%',
},
},
{
selector: "node[!is_valid]",
css: {
'border-color': 'red',
'border-width': '10px',
},
},
{
selector: ':selected',
css: {
'background-color': '#77b0d0',
'border-color': '#77b0d0',
'border-width': '20px',
},
},
{
selector: '.skipped-highlight',
css: {
'background-color': 'grey',
'border-color': 'grey',
'border-width': '8px',
'transition-property': 'background-color',
'transition-duration': '0.5s',
},
},
{
selector: '.success-highlight',
css: {
'background-color': '#41dcab',
'border-color': '#41dcab',
'border-width': '5px',
'transition-property': 'background-color',
'transition-duration': '0.5s',
},
},
{
selector: '.hover-highlight',
css: {
'background-color': '#5f9265',
'border-color': '#5f9265',
'border-width': '5px',
'transition-property': 'background-color',
'transition-duration': '0.5s',
},
},
{
selector: '.failure-highlight',
css: {
'background-color': '#8e3530',
'border-color': '#8e3530',
'border-width': '5px',
'transition-property': 'background-color',
'transition-duration': '0.5s',
},
},
{
selector: '.not-executing-highlight',
css: {
'background-color': 'grey',
'border-color': 'grey',
'border-width': '5px',
'transition-property': '#ffef47',
'transition-duration': '0.25s',
},
},
{
selector: '.executing-highlight',
css: {
'background-color': '#ffef47',
'border-color': '#ffef47',
'border-width': '8px',
'transition-property': 'border-width',
'transition-duration': '0.25s',
},
},
{
selector: '.awaiting-data-highlight',
css: {
'background-color': '#f4ad42',
'border-color': '#f4ad42',
'border-width': '5px',
'transition-property': 'border-color',
'transition-duration': '0.5s',
},
},
{
selector: '.shuffle-hover-highlight',
css: {
'background-color': "#f85a3e",
'border-color': '#f85a3e',
'border-width': '12px',
'transition-property': 'border-width',
'transition-duration': '0.25s',
'label': 'data(label)',
'font-size': '18px',
'color': 'white',
},
},
{
selector: '$node > node',
css: {
'padding-top': '10px',
'padding-left': '10px',
'padding-bottom': '10px',
'padding-right': '10px',
},
},
{
selector: 'edge.executing-highlight',
css: {
'width': '5px',
'target-arrow-color': '#ffef47',
'line-color': '#ffef47',
'transition-property': 'line-color, width',
'transition-duration': '0.25s',
},
},
{
selector: `edge[?decorator]`,
css: {
'width': '1px',
'line-style': 'dashed',
"line-fill": "linear-gradient",
'target-arrow-color': '#f34079',
"line-gradient-stop-positions": ["0.0", "100"],
"line-gradient-stop-colors": ["#f86a3e", "#f34079"],
},
},
{
selector: 'edge.success-highlight',
css: {
'width': '5px',
'target-arrow-color': '#41dcab',
'line-color': '#41dcab',
'transition-property': 'line-color, width',
'transition-duration': '0.5s',
"line-fill": "linear-gradient",
"line-gradient-stop-positions": ["0.0", "100"],
"line-gradient-stop-colors": ["#41dcab", "#41dcab"],
},
},
{
selector: '.eh-handle',
style: {
'background-color': '#337ab7',
'width': '1px',
'height': '1px',
'shape': 'circle',
'border-width': '1px',
'border-color': 'black'
}
},
{
selector: '.eh-source',
style: {
'border-width': '3',
'border-color': '#337ab7'
}
},
{
selector: '.eh-target',
style: {
'border-width': '3',
'border-color': '#337ab7'
}
},
{
selector: '.eh-preview, .eh-ghost-edge',
style: {
'background-color': '#337ab7',
'line-color': '#337ab7',
'target-arrow-color': '#337ab7',
'source-arrow-color': '#337ab7'
}
},
{
selector: 'edge:selected',
css: {
'target-arrow-color': '#f85a3e',
},
},
{
selector: `edge[?source_workflow]`,
css: {
"background-opacity": "1",
'font-size': '0px',
},
},
{
selector: `node[?source_workflow]`,
css: {
"background-opacity": "0",
'font-size': '0px',
},
},
]
const data = [
{
selector: "node",
css: {
label: "data(label)",
"text-valign": "center",
"font-family":
"Segoe UI, Tahoma, Geneva, Verdana, sans-serif, sans-serif",
"font-weight": "lighter",
"margin-right": "10px",
"font-size": "18px",
width: "80px",
height: "80px",
color: "white",
padding: "10px",
margin: "5px",
"border-width": "1px",
"text-margin-x": "10px",
cursor: "pointer",
"z-index": 5001,
},
},
{
selector: "edge",
css: {
"target-arrow-shape": "triangle",
"target-arrow-color": "grey",
"curve-style": "unbundled-bezier",
label: "data(label)",
"text-margin-y": "-15px",
width: "5px",
color: "white",
cursor: "pointer",
"line-fill": "linear-gradient",
"line-gradient-stop-positions": ["0.0", "100"],
"line-gradient-stop-colors": ["grey", "grey"],
"z-index": 5001,
},
},
{
selector: `node[type="ACTION"]`,
css: {
shape: "roundrectangle",
"background-color": "#213243",
"border-color": "#81c784",
"background-width": "100%",
"background-height": "100%",
"border-radius": "5px",
"z-index": 5001,
},
},
{
selector: `node[type="COMMENT"]`,
css: {
shape: "roundrectangle",
"background-color": "data(backgroundcolor)",
"border-color": "#ffffff",
color: "data(color)",
width: "data(width)",
height: "data(height)",
"border-radius": "5px",
"background-opacity": "0.5",
padding: "0px",
margin: "0px",
"text-margin-x": "0px",
"z-index": 4999,
},
},
{
selector: `node[app_name="Shuffle Tools"]`,
css: {
width: "30px",
height: "30px",
"z-index": 5000,
"font-size": "0px",
"background-width": "75%",
"background-height": "75%",
"background-color": "data(iconBackground)",
"background-fill": "data(fillstyle)",
"background-gradient-direction": "to-right",
"background-gradient-stop-colors": "data(fillGradient)",
},
},
{
selector: `node[app_name="Testing"]`,
css: {
width: "30px",
height: "30px",
"z-index": 5000,
"font-size": "0px",
},
},
{
selector: `node[?small_image]`,
css: {
"background-image": "data(small_image)",
"text-halign": "right",
},
},
{
selector: `node[?large_image]`,
css: {
"background-image": "data(large_image)",
"text-halign": "right",
},
},
{
selector: `node[type="CONDITION"]`,
css: {
shape: "diamond",
"border-color": "##FFEB3B",
padding: "30px",
},
},
{
selector: `node[type="eventAction"]`,
css: {
"background-color": "#edbd21",
},
},
{
selector: `node[type="TRIGGER"]`,
css: {
shape: "octagon",
"border-radius": "5px",
"border-color": "orange",
"background-color": "#213243",
"background-width": "100%",
"background-height": "100%",
},
},
{
selector: `node[status="running"]`,
css: {
"border-color": "#81c784",
},
},
{
selector: `node[status="stopped"]`,
css: {
"border-color": "orange",
},
},
{
selector: 'node[type="mq"]',
css: {
"background-color": "#edbd21",
},
},
{
selector: "node[?isButton]",
css: {
shape: "ellipse",
width: "15px",
height: "15px",
"z-index": "5002",
"font-size": "0px",
border: "1px solid rgba(255,255,255,0.9)",
"background-image": "data(icon)",
"background-color": "data(iconBackground)",
},
},
{
selector: "node[?isDescriptor]",
css: {
shape: "ellipse",
"border-color": "#80deea",
width: "5px",
height: "5px",
"z-index": "5002",
"font-size": "10px",
"text-valign": "center",
"text-halign": "center",
border: "1px solid black",
"margin-right": "0px",
"text-margin-x": "0px",
"background-color": "data(imageColor)",
"background-image": "data(image)",
},
},
{
selector: "node[?isStartNode]",
css: {
shape: "ellipse",
"border-color": "#80deea",
width: "80px",
height: "80px",
"font-size": "18px",
"background-width": "100%",
"background-height": "100%",
},
},
{
selector: "node[!is_valid]",
css: {
"border-color": "red",
"border-width": "10px",
},
},
{
selector: ":selected",
css: {
"background-color": "#77b0d0",
"border-color": "#77b0d0",
"border-width": "20px",
},
},
{
selector: ".skipped-highlight",
css: {
"background-color": "grey",
"border-color": "grey",
"border-width": "8px",
"transition-property": "background-color",
"transition-duration": "0.5s",
},
},
{
selector: ".success-highlight",
css: {
"background-color": "#41dcab",
"border-color": "#41dcab",
"border-width": "5px",
"transition-property": "background-color",
"transition-duration": "0.5s",
},
},
{
selector: ".hover-highlight",
css: {
"background-color": "#5f9265",
"border-color": "#5f9265",
"border-width": "5px",
"transition-property": "background-color",
"transition-duration": "0.5s",
},
},
{
selector: ".failure-highlight",
css: {
"background-color": "#8e3530",
"border-color": "#8e3530",
"border-width": "5px",
"transition-property": "background-color",
"transition-duration": "0.5s",
},
},
{
selector: ".not-executing-highlight",
css: {
"background-color": "grey",
"border-color": "grey",
"border-width": "5px",
"transition-property": "#ffef47",
"transition-duration": "0.25s",
},
},
{
selector: ".executing-highlight",
css: {
"background-color": "#ffef47",
"border-color": "#ffef47",
"border-width": "8px",
"transition-property": "border-width",
"transition-duration": "0.25s",
},
},
{
selector: ".awaiting-data-highlight",
css: {
"background-color": "#f4ad42",
"border-color": "#f4ad42",
"border-width": "5px",
"transition-property": "border-color",
"transition-duration": "0.5s",
},
},
{
selector: ".shuffle-hover-highlight",
css: {
"background-color": "#f85a3e",
"border-color": "#f85a3e",
"border-width": "12px",
"transition-property": "border-width",
"transition-duration": "0.25s",
label: "data(label)",
"font-size": "18px",
color: "white",
},
},
{
selector: "$node > node",
css: {
"padding-top": "10px",
"padding-left": "10px",
"padding-bottom": "10px",
"padding-right": "10px",
},
},
{
selector: "edge.executing-highlight",
css: {
width: "5px",
"target-arrow-color": "#ffef47",
"line-color": "#ffef47",
"transition-property": "line-color, width",
"transition-duration": "0.25s",
},
},
{
selector: `edge[?decorator]`,
css: {
width: "1px",
"line-style": "dashed",
"line-fill": "linear-gradient",
"target-arrow-color": "#f34079",
"line-gradient-stop-positions": ["0.0", "100"],
"line-gradient-stop-colors": ["#f86a3e", "#f34079"],
},
},
{
selector: "edge.success-highlight",
css: {
width: "5px",
"target-arrow-color": "#41dcab",
"line-color": "#41dcab",
"transition-property": "line-color, width",
"transition-duration": "0.5s",
"line-fill": "linear-gradient",
"line-gradient-stop-positions": ["0.0", "100"],
"line-gradient-stop-colors": ["#41dcab", "#41dcab"],
},
},
{
selector: ".eh-handle",
style: {
"background-color": "#337ab7",
width: "1px",
height: "1px",
shape: "circle",
"border-width": "1px",
"border-color": "black",
},
},
{
selector: ".eh-source",
style: {
"border-width": "3",
"border-color": "#337ab7",
},
},
{
selector: ".eh-target",
style: {
"border-width": "3",
"border-color": "#337ab7",
},
},
{
selector: ".eh-preview, .eh-ghost-edge",
style: {
"background-color": "#337ab7",
"line-color": "#337ab7",
"target-arrow-color": "#337ab7",
"source-arrow-color": "#337ab7",
},
},
{
selector: "edge:selected",
css: {
"target-arrow-color": "#f85a3e",
},
},
{
selector: `edge[?source_workflow]`,
css: {
"background-opacity": "1",
"font-size": "0px",
},
},
{
selector: `node[?source_workflow]`,
css: {
"background-opacity": "0",
"font-size": "0px",
},
},
];
//{
// selector: 'edge[?hasErrors]',
@@ -397,5 +399,4 @@ const data = [{
// },
//},
export default data
export default data;
+2 -2
View File
@@ -1,9 +1,9 @@
@import url('./css/nunito.css');
@import url("./css/nunito.css");
body {
margin: 0;
padding: 0;
font-family: "Nunito Sans", sans-serif;
font-family: "Nunito Sans", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
+6 -9
View File
@@ -1,13 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
ReactDOM.render(
<App />
, document.getElementById('root'));
ReactDOM.render(<App />, document.getElementById("root"));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
+18 -18
View File
@@ -9,9 +9,9 @@
// This link also includes instructions on opting out of this behavior.
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
window.location.hostname === "localhost" ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
window.location.hostname === "[::1]" ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
@@ -19,7 +19,7 @@ const isLocalhost = Boolean(
);
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
if (publicUrl.origin !== window.location.origin) {
@@ -29,7 +29,7 @@ export function register(config) {
return;
}
window.addEventListener('load', () => {
window.addEventListener("load", () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
@@ -40,8 +40,8 @@ export function register(config) {
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://goo.gl/SC7cgQ'
"This web app is being served cache-first by a service " +
"worker. To learn more, visit https://goo.gl/SC7cgQ"
);
});
} else {
@@ -55,17 +55,17 @@ export function register(config) {
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
.then((registration) => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (installingWorker.state === "installed") {
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and
// the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is
// available; please refresh." message in your web app.
console.log('New content is available; please refresh.');
console.log("New content is available; please refresh.");
// Execute callback
if (config.onUpdate) {
@@ -75,7 +75,7 @@ function registerValidSW(swUrl, config) {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
console.log("Content is cached for offline use.");
// Execute callback
if (config.onSuccess) {
@@ -86,22 +86,22 @@ function registerValidSW(swUrl, config) {
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
.catch((error) => {
console.error("Error during service worker registration:", error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
.then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
if (
response.status === 404 ||
response.headers.get('content-type').indexOf('javascript') === -1
response.headers.get("content-type").indexOf("javascript") === -1
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
@@ -113,14 +113,14 @@ function checkValidServiceWorker(swUrl, config) {
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
"No internet connection found. App is running in offline mode."
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
if ("serviceWorker" in navigator) {
navigator.serviceWorker.ready.then((registration) => {
registration.unregister();
});
}
+58 -57
View File
File diff suppressed because one or more lines are too long
+62 -37
View File
@@ -1,49 +1,74 @@
import React from 'react';
import React from "react";
const hrefStyle = {
color: "#f85a3e",
textDecoration: "none"
}
color: "#f85a3e",
textDecoration: "none",
};
const About = () => {
return (
<div>
<h1>About</h1>
return (
<div>
<h1>About</h1>
<p>
Endao was started as a project in late 2018 as a free service to analyze
APK (and soon IPA) files for vulnerabilities. The project was started
after I,
<a href="https://twitter.com/frikkylikeme" style={hrefStyle}>
@frikkylikeme
</a>
, found multiple vulnerabilities in IoT devices based purely on their
apps. As I wanted to learn more about these kind of vulnerabilities, I
looked for solutions that work for my purpose, but didn't find any good,
free and easy to use service - hence this site was born.
</p>
<p>
Endao was started as a project in late 2018 as a free service to analyze APK (and soon IPA) files for vulnerabilities. The project was started after I,
<a href="https://twitter.com/frikkylikeme" style={hrefStyle}>@frikkylikeme</a>
, found multiple vulnerabilities in IoT devices based purely on their apps. As I wanted to learn more about these kind of vulnerabilities, I looked for solutions that work for my purpose, but didn't find any good, free and easy to use service - hence this site was born.
</p>
<p>
My personal goal has and will always be to make the internet safer. As
the IoT sphere grows, I want to be able to add ways of finding possible
vulnerabilities fast to this website. This will hopefully include
blogposts when I get around to it, as well as actual implementations.
The vulnerability discovery field is in no way new, but I'll try my best
to add whatever I can to it. As a disclaimer, I'm an "Ops" person, and I
had never done frontend before creating this site. This is as much of a
learning project within web development as it is in vulnerability
discovery.
</p>
<p>
My personal goal has and will always be to make the internet safer. As the IoT sphere grows, I want to be able to add ways of finding possible vulnerabilities fast to this website. This will hopefully include blogposts when I get around to it, as well as actual implementations. The vulnerability discovery field is in no way new, but I'll try my best to add whatever I can to it. As a disclaimer, I'm an "Ops" person, and I had never done frontend before creating this site. This is as much of a learning project within web development as it is in vulnerability discovery.
</p>
<p>This site currently uses the following projects</p>
<ul>
<li>
<a style={hrefStyle} href="https://superanalyzer.rocks">
SUPER Android Analyzer
</a>
</li>
<li>
<a style={hrefStyle} href="https://github.com/linkedin/qark">
Qark
</a>
</li>
<li>
<a style={hrefStyle} href="https://virustotal.com">
Virustotal
</a>{" "}
for malware checks in known APKs
</li>
<li>Some selfmade gibberish</li>
</ul>
<p>
This site currently uses the following projects
</p>
<ul>
<li><a style={hrefStyle} href="https://superanalyzer.rocks">SUPER Android Analyzer</a></li>
<li><a style={hrefStyle} href="https://github.com/linkedin/qark">Qark</a></li>
<li><a style={hrefStyle} href="https://virustotal.com">Virustotal</a> for malware checks in known APKs</li>
<li>Some selfmade gibberish</li>
</ul>
<p>Hopefully it is of use to some people :)</p>
<p>Hopefully it is of use to some people :)</p>
<h3>Thanks</h3>
<p>Thanks to Andy for the initial frontend help :)</p>
<h3>Thanks</h3>
<p>
Thanks to Andy for the initial frontend help :)
</p>
<h3>Regards</h3>
<p>
<a href="https://twitter.com/frikkylikeme" style={hrefStyle}>@frikkylikeme</a>
</p>
</div>
)
}
<h3>Regards</h3>
<p>
<a href="https://twitter.com/frikkylikeme" style={hrefStyle}>
@frikkylikeme
</a>
</p>
</div>
);
};
export default About;
+3900 -3050
View File
File diff suppressed because it is too large Load Diff
+199 -189
View File
@@ -1,223 +1,233 @@
/* eslint-disable react/no-multi-comp */
import React, {useState} from 'react';
import { makeStyles } from '@material-ui/styles';
import React, { useState } from "react";
import { makeStyles } from "@material-ui/styles";
import {CircularProgress, TextField, Button, Paper, Typography} from '@material-ui/core'
import {
CircularProgress,
TextField,
Button,
Paper,
Typography,
} from "@material-ui/core";
const bodyDivStyle = {
margin: "auto",
marginTop: "100px",
width: "500px",
}
margin: "auto",
marginTop: "100px",
width: "500px",
};
const surfaceColor = "#27292D"
const inputColor = "#383B40"
const surfaceColor = "#27292D";
const inputColor = "#383B40";
const boxStyle = {
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
backgroundColor: surfaceColor,
}
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
backgroundColor: surfaceColor,
};
const useStyles = makeStyles({
notchedOutline: {
borderColor: "#f85a3e !important"
},
notchedOutline: {
borderColor: "#f85a3e !important",
},
});
const AdminAccount = props => {
const { globalUrl, isLoaded, isLoggedIn, } = props;
const AdminAccount = (props) => {
const { globalUrl, isLoaded, isLoggedIn } = props;
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [firstRequest, setFirstRequest] = useState(true);
const [loginLoading, setLoginLoading] = useState(false);
// Used to swap from login to register. True = login, false = register
const register = true
// Used to swap from login to register. True = login, false = register
const register = true;
const classes = useStyles();
// Error messages etc
const [loginInfo, setLoginInfo] = useState("");
const classes = useStyles();
// Error messages etc
const [loginInfo, setLoginInfo] = useState("");
const handleValidateForm = () => {
return (username.length > 1 && password.length > 1);
}
const handleValidateForm = () => {
return username.length > 1 && password.length > 1;
};
if (isLoggedIn === true) {
window.location.pathname = "/workflows"
}
if (isLoggedIn === true) {
window.location.pathname = "/workflows";
}
const checkAdmin = () => {
const url = globalUrl+'/api/v1/checkusers';
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.then(response =>
response.json().then(responseJson => {
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"])
} else {
if (responseJson.reason === "redirect") {
window.location.pathname = "/login"
}
}
}),
)
.catch(error => {
setLoginInfo("Error in userdata: ", error)
})
}
const checkAdmin = () => {
const url = globalUrl + "/api/v1/checkusers";
fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((response) =>
response.json().then((responseJson) => {
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"]);
} else {
if (responseJson.reason === "redirect") {
window.location.pathname = "/login";
}
}
})
)
.catch((error) => {
setLoginInfo("Error in userdata: ", error);
});
};
if (firstRequest) {
setFirstRequest(false)
checkAdmin()
}
if (firstRequest) {
setFirstRequest(false);
checkAdmin();
}
const onSubmit = (e) => {
setLoginLoading(true)
e.preventDefault()
// FIXME - add some check here ROFL
const onSubmit = (e) => {
setLoginLoading(true);
e.preventDefault();
// FIXME - add some check here ROFL
// Just use this one?
var data = {"username": username, "password": password}
var baseurl = globalUrl
const url = baseurl+'/api/v1/register';
fetch(url, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
},
})
.then(response =>
response.json().then(responseJson => {
setLoginLoading(false)
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"])
} else {
setLoginInfo("Successful register :)")
window.location.pathname = "/login"
}
}),
)
.catch(error => {
setLoginLoading(false)
setLoginInfo("Error in userdata: ", error)
});
}
// Just use this one?
var data = { username: username, password: password };
var baseurl = globalUrl;
const url = baseurl + "/api/v1/register";
fetch(url, {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
},
})
.then((response) =>
response.json().then((responseJson) => {
setLoginLoading(false);
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"]);
} else {
setLoginInfo("Successful register :)");
window.location.pathname = "/login";
}
})
)
.catch((error) => {
setLoginLoading(false);
setLoginInfo("Error in userdata: ", error);
});
};
const onChangeUser = (e) => {
setUsername(e.target.value)
}
const onChangeUser = (e) => {
setUsername(e.target.value);
};
const onChangePass = (e) => {
setPassword(e.target.value)
}
const onChangePass = (e) => {
setPassword(e.target.value);
};
//const onClickRegister = () => {
// if (props.location.pathname === "/login") {
// window.location.pathname = "/register"
// } else {
// window.location.pathname = "/login"
// }
//const onClickRegister = () => {
// if (props.location.pathname === "/login") {
// window.location.pathname = "/register"
// } else {
// window.location.pathname = "/login"
// }
// setLoginCheck(!register)
//}
// setLoginCheck(!register)
//}
//var loginChange = register ? (<div><p onClick={setLoginCheck(false)}>Want to register? Click here.</p></div>) : (<div><p onClick={setLoginCheck(true)}>Go back to login? Click here.</p></div>);
var formtitle = register ? <div>Login</div> : <div>Register</div>
//var loginChange = register ? (<div><p onClick={setLoginCheck(false)}>Want to register? Click here.</p></div>) : (<div><p onClick={setLoginCheck(true)}>Go back to login? Click here.</p></div>);
var formtitle = register ? <div>Login</div> : <div>Register</div>;
formtitle = "Create administrator account"
const basedata =
<div style={bodyDivStyle}>
<Paper style={boxStyle}>
<form onSubmit={onSubmit} style={{color: "white", margin: "15px 15px 15px 15px"}}>
<h2>{formtitle}</h2>
Username
<div>
<TextField
color="primary"
style={{backgroundColor: inputColor}}
autoFocus
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style:{
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
fullWidth={true}
autoComplete="username"
placeholder="username@example.com"
id="emailfield"
margin="normal"
variant="outlined"
onChange={onChangeUser}
/>
</div>
Password
<div>
<TextField
color="primary"
style={{backgroundColor: inputColor,}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style:{
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
id="outlined-password-input"
fullWidth={true}
type="password"
autoComplete="current-password"
placeholder="**********"
margin="normal"
variant="outlined"
onChange={onChangePass}
/>
</div>
<div style={{display: "flex", marginTop: "15px"}}>
<Button color="primary" variant="contained" type="submit" style={{flex: "1", marginRight: "5px"}} disabled={!handleValidateForm() || loginLoading}>
{loginLoading ? <CircularProgress color="secondary" style={{color: "white",}} /> : "SUBMIT"}
</Button>
</div>
<div style={{marginTop: "10px"}}>
{loginInfo}
</div>
</form>
</Paper>
</div>
formtitle = "Create administrator account";
const loadedCheck = isLoaded ?
<div>
{basedata}
</div>
:
<div>
</div>
const basedata = (
<div style={bodyDivStyle}>
<Paper style={boxStyle}>
<form
onSubmit={onSubmit}
style={{ color: "white", margin: "15px 15px 15px 15px" }}
>
<h2>{formtitle}</h2>
Username
<div>
<TextField
color="primary"
style={{ backgroundColor: inputColor }}
autoFocus
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
fullWidth={true}
autoComplete="username"
placeholder="username@example.com"
id="emailfield"
margin="normal"
variant="outlined"
onChange={onChangeUser}
/>
</div>
Password
<div>
<TextField
color="primary"
style={{ backgroundColor: inputColor }}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
id="outlined-password-input"
fullWidth={true}
type="password"
autoComplete="current-password"
placeholder="**********"
margin="normal"
variant="outlined"
onChange={onChangePass}
/>
</div>
<div style={{ display: "flex", marginTop: "15px" }}>
<Button
color="primary"
variant="contained"
type="submit"
style={{ flex: "1", marginRight: "5px" }}
disabled={!handleValidateForm() || loginLoading}
>
{loginLoading ? (
<CircularProgress
color="secondary"
style={{ color: "white" }}
/>
) : (
"SUBMIT"
)}
</Button>
</div>
<div style={{ marginTop: "10px" }}>{loginInfo}</div>
</form>
</Paper>
</div>
);
return (
<div>
{loadedCheck}
</div>
)
}
const loadedCheck = isLoaded ? <div>{basedata}</div> : <div></div>;
return <div>{loadedCheck}</div>;
};
export default AdminAccount;
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+2082 -1537
View File
File diff suppressed because it is too large Load Diff
+344 -324
View File
@@ -1,345 +1,365 @@
import React, { useState } from 'react';
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 Paper from "@material-ui/core/Paper";
import Button from "@material-ui/core/Button";
import TextField from '@material-ui/core/TextField';
import TextField from "@material-ui/core/TextField";
import { useTheme } from '@material-ui/core/styles';
import { useTheme } from "@material-ui/core/styles";
const bodyDivStyle = {
margin: "auto",
textAlign: "center",
width: "900px",
}
margin: "auto",
textAlign: "center",
width: "900px",
};
// Should be different if logged in :|
const Contact = (props) => {
const { globalUrl, isLoaded } = props;
const theme = useTheme();
const { globalUrl, isLoaded } = props;
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 theme = useTheme();
const bodyTextStyle = {
color: "#ffffff",
}
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 [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 bodyTextStyle = {
color: "#ffffff",
};
const [formMessage, setFormMessage] = useState("");
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 submitContact = () => {
const data = {
"firstname": firstname,
"lastname": lastname,
"title": title,
"companyname": companyname,
"email": email,
"phone": phone,
"message": message,
}
console.log(data)
const [formMessage, setFormMessage] = useState("");
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)
});
}
const submitContact = () => {
const data = {
firstname: firstname,
lastname: lastname,
title: title,
companyname: companyname,
email: email,
phone: phone,
message: message,
};
console.log(data);
// 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>
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);
});
};
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>
// 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>
const loadedCheck = isLoaded ? (
<div>
<BrowserView>
<div style={bodyDivStyle}>{landingpageDataBrowser}</div>
</BrowserView>
<MobileView>{landingpageDataMobile}</MobileView>
</div>
) : (
<div></div>
);
return (
<div>
{loadedCheck}
</div>
)
}
return <div>{loadedCheck}</div>;
};
export default Contact;
+401 -398
View File
@@ -1,5 +1,5 @@
import React, {useState} from 'react';
import { useInterval } from 'react-powerhooks';
import React, { useState } from "react";
import { useInterval } from "react-powerhooks";
// nodejs library that concatenates classes
import classNames from "classnames";
// react plugin used to create charts
@@ -26,7 +26,7 @@ import {
Table,
Row,
Col,
UncontrolledTooltip
UncontrolledTooltip,
} from "reactstrap";
// core components
@@ -34,430 +34,433 @@ import {
chartExample1,
chartExample2,
chartExample3,
chartExample4
chartExample4,
} from "../charts.js";
// This is the start of a dashboard that can be used.
// This is the start of a dashboard that can be used.
// What data do we fill in here? Idk
const Dashboard = (props) => {
const { globalUrl } = props;
const alert = useAlert()
const [bigChartData, setBgChartData] = useState("data1");
const [dayAmount, setDayAmount] = useState(7);
const [firstRequest, setFirstRequest] = useState(true);
const [stats, setStats] = useState({})
const [changeme, setChangeme] = useState("")
const [statsRan, setStatsRan] = useState(false)
document.title = "Shuffle - dashboard"
var dayGraphLabels = [60, 80, 65, 130, 80, 105, 90, 130, 70, 115, 60, 130]
var dayGraphData = [60, 80, 65, 130, 80, 105, 90, 130, 70, 115, 60, 130]
const alert = useAlert();
const [bigChartData, setBgChartData] = useState("data1");
const [dayAmount, setDayAmount] = useState(7);
const [firstRequest, setFirstRequest] = useState(true);
const [stats, setStats] = useState({});
const [changeme, setChangeme] = useState("");
const [statsRan, setStatsRan] = useState(false);
const fetchdata = (stats_id) => {
fetch(globalUrl+"/api/v1/stats/"+stats_id, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
document.title = "Shuffle - dashboard";
var dayGraphLabels = [60, 80, 65, 130, 80, 105, 90, 130, 70, 115, 60, 130];
var dayGraphData = [60, 80, 65, 130, 80, 105, 90, 130, 70, 115, 60, 130];
const fetchdata = (stats_id) => {
fetch(globalUrl + "/api/v1/stats/" + stats_id, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for "+stats_id)
}
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for " + stats_id);
}
return response.json()
})
.then((responseJson) => {
stats[stats_id] = responseJson
setStats(stats)
// Used to force updates
setChangeme(stats_id)
})
.catch(error => {
alert.error("ERROR: "+error.toString())
});
}
return response.json();
})
.then((responseJson) => {
stats[stats_id] = responseJson;
setStats(stats);
// Used to force updates
setChangeme(stats_id);
})
.catch((error) => {
alert.error("ERROR: " + error.toString());
});
};
let chart1_2_options = {
maintainAspectRatio: false,
legend: {
display: false
},
tooltips: {
backgroundColor: "#f5f5f5",
titleFontColor: "#333",
bodyFontColor: "#666",
bodySpacing: 4,
xPadding: 12,
mode: "nearest",
intersect: 0,
position: "nearest"
},
responsive: true,
scales: {
yAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: "rgba(29,140,248,0.0)",
zeroLineColor: "transparent"
},
ticks: {
suggestedMin: 60,
suggestedMax: 125,
padding: 20,
fontColor: "#9a9a9a"
}
}
],
xAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: "rgba(29,140,248,0.1)",
zeroLineColor: "transparent"
},
ticks: {
padding: 20,
fontColor: "#9a9a9a"
}
}
]
}
}
let chart1_2_options = {
maintainAspectRatio: false,
legend: {
display: false,
},
tooltips: {
backgroundColor: "#f5f5f5",
titleFontColor: "#333",
bodyFontColor: "#666",
bodySpacing: 4,
xPadding: 12,
mode: "nearest",
intersect: 0,
position: "nearest",
},
responsive: true,
scales: {
yAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: "rgba(29,140,248,0.0)",
zeroLineColor: "transparent",
},
ticks: {
suggestedMin: 60,
suggestedMax: 125,
padding: 20,
fontColor: "#9a9a9a",
},
},
],
xAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: "rgba(29,140,248,0.1)",
zeroLineColor: "transparent",
},
ticks: {
padding: 20,
fontColor: "#9a9a9a",
},
},
],
},
};
const dayGraph = {
data: canvas => {
let ctx = canvas.getContext("2d");
const dayGraph = {
data: (canvas) => {
let ctx = canvas.getContext("2d");
let gradientStroke = ctx.createLinearGradient(0, 230, 0, 50);
let gradientStroke = ctx.createLinearGradient(0, 230, 0, 50);
gradientStroke.addColorStop(1, "rgba(29,140,248,0.2)");
gradientStroke.addColorStop(0.4, "rgba(29,140,248,0.0)");
gradientStroke.addColorStop(0, "rgba(29,140,248,0)"); //blue colors
gradientStroke.addColorStop(1, "rgba(29,140,248,0.2)");
gradientStroke.addColorStop(0.4, "rgba(29,140,248,0.0)");
gradientStroke.addColorStop(0, "rgba(29,140,248,0)"); //blue colors
return {
labels: dayGraphLabels,
datasets: [
{
label: "My First dataset",
fill: true,
backgroundColor: gradientStroke,
borderColor: "#1f8ef1",
borderWidth: 2,
borderDash: [],
borderDashOffset: 0.0,
pointBackgroundColor: "#1f8ef1",
pointBorderColor: "rgba(255,255,255,0)",
pointHoverBackgroundColor: "#1f8ef1",
pointBorderWidth: 20,
pointHoverRadius: 4,
pointHoverBorderWidth: 15,
pointRadius: 4,
data: dayGraphData,
}
]
}
},
options: chart1_2_options,
}
return {
labels: dayGraphLabels,
datasets: [
{
label: "My First dataset",
fill: true,
backgroundColor: gradientStroke,
borderColor: "#1f8ef1",
borderWidth: 2,
borderDash: [],
borderDashOffset: 0.0,
pointBackgroundColor: "#1f8ef1",
pointBorderColor: "rgba(255,255,255,0)",
pointHoverBackgroundColor: "#1f8ef1",
pointBorderWidth: 20,
pointHoverRadius: 4,
pointHoverBorderWidth: 15,
pointRadius: 4,
data: dayGraphData,
},
],
};
},
options: chart1_2_options,
};
// All these are currently tracked.
const variables = [
"backend_executions",
"workflow_executions",
"workflow_executions_aborted",
"workflow_executions_success",
"total_apps_created",
"total_apps_loaded",
"openapi_apps_created",
"total_apps_deleted",
"total_webhooks_ran",
"total_workflows",
"total_workflow_actions",
"total_workflow_triggers",
]
// All these are currently tracked.
const variables = [
"backend_executions",
"workflow_executions",
"workflow_executions_aborted",
"workflow_executions_success",
"total_apps_created",
"total_apps_loaded",
"openapi_apps_created",
"total_apps_deleted",
"total_webhooks_ran",
"total_workflows",
"total_workflow_actions",
"total_workflow_triggers",
];
const runUpdate = () => {
for (var key in variables) {
fetchdata(variables[key])
}
}
const runUpdate = () => {
for (var key in variables) {
fetchdata(variables[key]);
}
};
// Refresh every 60 seconds
const autoUpdate = 60000
const { start, stop } = useInterval({
duration: autoUpdate,
startImmediate: false,
callback: () => {
runUpdate()
}
})
// Refresh every 60 seconds
const autoUpdate = 60000;
const { start, stop } = useInterval({
duration: autoUpdate,
startImmediate: false,
callback: () => {
runUpdate();
},
});
if (firstRequest) {
console.log("HELO")
setFirstRequest(false)
start()
runUpdate()
} else if (!statsRan) {
// FIXME: Run this under runUpdate schedule?
// 1. Fix labels in dayGraphy.data
// 2. Add data to the daygraph
// Every time there's an update :)
if (firstRequest) {
console.log("HELO");
setFirstRequest(false);
start();
runUpdate();
} else if (!statsRan) {
// FIXME: Run this under runUpdate schedule?
// 1. Fix labels in dayGraphy.data
// 2. Add data to the daygraph
// This should probably be done in the backend.. bleh
if (stats["workflow_executions"] !== undefined && stats["workflow_executions"] !== null && stats["workflow_executions"].data !== undefined) {
setStatsRan(true)
//console.log("NEW DATA?: ", stats)
console.log('SET WORKFLOW: ', stats["workflow_executions"])
//var curday = startDate.getDate()
// Every time there's an update :)
// Index = what day are we on
// This should probably be done in the backend.. bleh
if (
stats["workflow_executions"] !== undefined &&
stats["workflow_executions"] !== null &&
stats["workflow_executions"].data !== undefined
) {
setStatsRan(true);
//console.log("NEW DATA?: ", stats)
console.log("SET WORKFLOW: ", stats["workflow_executions"]);
//var curday = startDate.getDate()
// 0 = today
var newDayGraphLabels = []
var newDayGraphData = []
for (var i = dayAmount; i > 0; i--) {
var enddate = new Date()
enddate.setDate(-i)
enddate.setHours(23,59,59,999)
// Index = what day are we on
var startdate = new Date()
startdate.setDate(-i)
startdate.setHours(0,0,0,0)
// 0 = today
var newDayGraphLabels = [];
var newDayGraphData = [];
for (var i = dayAmount; i > 0; i--) {
var enddate = new Date();
enddate.setDate(-i);
enddate.setHours(23, 59, 59, 999);
var endtime = enddate.getTime()/1000
var starttime = startdate.getTime()/1000
var startdate = new Date();
startdate.setDate(-i);
startdate.setHours(0, 0, 0, 0);
console.log("START: ", starttime, "END: ", endtime, "Data: ", stats["workflow_executions"])
for (var key in stats["workflow_executions"].data) {
const item = stats["workflow_executions"]["data"][key]
console.log("ITEM: ", item.timestamp, endtime)
console.log(endtime-starttime)
if (endtime-starttime > endtime-item.timestamp && endtime.timestamp >= 0) {
console.log("HIT? ")
}
console.log(item.timestamp-endtime)
//console.log(item.timestamp-endtime)
break
if (item.timestamp > endtime && item.timestamp < starttime) {
if (newDayGraphData[i-1] === undefined) {
newDayGraphData[i-1] = 1
} else {
newDayGraphData[i-1] += 1
}
var endtime = enddate.getTime() / 1000;
var starttime = startdate.getTime() / 1000;
//break
}
}
newDayGraphLabels.push(i)
}
console.log(
"START: ",
starttime,
"END: ",
endtime,
"Data: ",
stats["workflow_executions"]
);
for (var key in stats["workflow_executions"].data) {
const item = stats["workflow_executions"]["data"][key];
console.log("ITEM: ", item.timestamp, endtime);
console.log(endtime - starttime);
if (
endtime - starttime > endtime - item.timestamp &&
endtime.timestamp >= 0
) {
console.log("HIT? ");
}
console.log(item.timestamp - endtime);
//console.log(item.timestamp-endtime)
break;
if (item.timestamp > endtime && item.timestamp < starttime) {
if (newDayGraphData[i - 1] === undefined) {
newDayGraphData[i - 1] = 1;
} else {
newDayGraphData[i - 1] += 1;
}
console.log(newDayGraphLabels)
console.log(newDayGraphData)
}
}
//break
}
}
const newdata = Object.getOwnPropertyNames(stats).length > 0 ?
<div>
Autoupdate every {autoUpdate/1000} seconds
{variables.map(data => {
if (stats[data] === undefined || stats[data] === null) {
return null
}
newDayGraphLabels.push(i);
}
if (stats[data].total === undefined) {
return null
}
console.log(newDayGraphLabels);
console.log(newDayGraphData);
}
}
return (
<div>
{data}: {stats[data].total}
</div>
)
})}
</div>
: null
const newdata =
Object.getOwnPropertyNames(stats).length > 0 ? (
<div>
Autoupdate every {autoUpdate / 1000} seconds
{variables.map((data) => {
if (stats[data] === undefined || stats[data] === null) {
return null;
}
const data =
<div className="content">
{newdata}
<Row>
<Col xs="12">
<div className="chart-area">
<Line
data={dayGraph.data}
options={dayGraph.options}
/>
</div>
</Col>
<Col xs="12">
<Card className="card-chart">
<CardHeader>
<Row>
<Col className="text-left" sm="6">
<h5 className="card-category">Total Shipments</h5>
<CardTitle tag="h2">Workflows</CardTitle>
</Col>
<Col sm="6">
<ButtonGroup
className="btn-group-toggle float-right"
data-toggle="buttons"
>
<Button
tag="label"
className={classNames("btn-simple", {
active: bigChartData === "data1"
})}
color="info"
id="0"
size="sm"
onClick={() => setBgChartData("data1")}
>
<input
defaultChecked
className="d-none"
name="options"
type="radio"
/>
<span className="d-none d-sm-block d-md-block d-lg-block d-xl-block">
Accounts
</span>
<span className="d-block d-sm-none">
<i className="tim-icons icon-single-02" />
</span>
</Button>
<Button
color="info"
id="1"
size="sm"
tag="label"
className={classNames("btn-simple", {
active: bigChartData === "data2"
})}
onClick={() => setBgChartData("data2")}
>
<input
className="d-none"
name="options"
type="radio"
/>
<span className="d-none d-sm-block d-md-block d-lg-block d-xl-block">
Purchases
</span>
<span className="d-block d-sm-none">
<i className="tim-icons icon-gift-2" />
</span>
</Button>
<Button
color="info"
id="2"
size="sm"
tag="label"
className={classNames("btn-simple", {
active: bigChartData === "data3"
})}
onClick={() => setBgChartData("data3")}
>
<input
className="d-none"
name="options"
type="radio"
/>
<span className="d-none d-sm-block d-md-block d-lg-block d-xl-block">
Sessions
</span>
<span className="d-block d-sm-none">
<i className="tim-icons icon-tap-02" />
</span>
</Button>
</ButtonGroup>
</Col>
</Row>
</CardHeader>
<CardBody>
<div className="chart-area">
<Line
data={chartExample1[bigChartData]}
options={chartExample1.options}
/>
</div>
</CardBody>
</Card>
</Col>
</Row>
<Row>
<Col lg="4">
<Card className="card-chart">
<CardHeader>
<h5 className="card-category">Total Shipments</h5>
<CardTitle tag="h3">
<i className="tim-icons icon-bell-55 text-info" />{" "}
763,215
</CardTitle>
</CardHeader>
<CardBody>
<div className="chart-area">
<Line
data={chartExample2.data}
options={chartExample2.options}
/>
</div>
</CardBody>
</Card>
</Col>
<Col lg="4">
<Card className="card-chart">
<CardHeader>
<h5 className="card-category">Daily Sales</h5>
<CardTitle tag="h3">
<i className="tim-icons icon-delivery-fast text-primary" />{" "}
3,500
</CardTitle>
</CardHeader>
<CardBody>
<div className="chart-area">
<Bar
data={chartExample3.data}
options={chartExample3.options}
/>
</div>
</CardBody>
</Card>
</Col>
<Col lg="4">
<Card className="card-chart">
<CardHeader>
<h5 className="card-category">Completed Tasks</h5>
<CardTitle tag="h3">
<i className="tim-icons icon-send text-success" /> 12,100K
</CardTitle>
</CardHeader>
<CardBody>
<div className="chart-area">
<Line
data={chartExample4.data}
options={chartExample4.options}
/>
</div>
</CardBody>
</Card>
</Col>
</Row>
</div>
if (stats[data].total === undefined) {
return null;
}
const dataWrapper =
<div style={{maxWidth: 1366, margin: "auto"}}>
{data}
</div>
return (
<div>
{data}: {stats[data].total}
</div>
);
})}
</div>
) : null;
return dataWrapper
}
const data = (
<div className="content">
{newdata}
<Row>
<Col xs="12">
<div className="chart-area">
<Line data={dayGraph.data} options={dayGraph.options} />
</div>
</Col>
<Col xs="12">
<Card className="card-chart">
<CardHeader>
<Row>
<Col className="text-left" sm="6">
<h5 className="card-category">Total Shipments</h5>
<CardTitle tag="h2">Workflows</CardTitle>
</Col>
<Col sm="6">
<ButtonGroup
className="btn-group-toggle float-right"
data-toggle="buttons"
>
<Button
tag="label"
className={classNames("btn-simple", {
active: bigChartData === "data1",
})}
color="info"
id="0"
size="sm"
onClick={() => setBgChartData("data1")}
>
<input
defaultChecked
className="d-none"
name="options"
type="radio"
/>
<span className="d-none d-sm-block d-md-block d-lg-block d-xl-block">
Accounts
</span>
<span className="d-block d-sm-none">
<i className="tim-icons icon-single-02" />
</span>
</Button>
<Button
color="info"
id="1"
size="sm"
tag="label"
className={classNames("btn-simple", {
active: bigChartData === "data2",
})}
onClick={() => setBgChartData("data2")}
>
<input className="d-none" name="options" type="radio" />
<span className="d-none d-sm-block d-md-block d-lg-block d-xl-block">
Purchases
</span>
<span className="d-block d-sm-none">
<i className="tim-icons icon-gift-2" />
</span>
</Button>
<Button
color="info"
id="2"
size="sm"
tag="label"
className={classNames("btn-simple", {
active: bigChartData === "data3",
})}
onClick={() => setBgChartData("data3")}
>
<input className="d-none" name="options" type="radio" />
<span className="d-none d-sm-block d-md-block d-lg-block d-xl-block">
Sessions
</span>
<span className="d-block d-sm-none">
<i className="tim-icons icon-tap-02" />
</span>
</Button>
</ButtonGroup>
</Col>
</Row>
</CardHeader>
<CardBody>
<div className="chart-area">
<Line
data={chartExample1[bigChartData]}
options={chartExample1.options}
/>
</div>
</CardBody>
</Card>
</Col>
</Row>
<Row>
<Col lg="4">
<Card className="card-chart">
<CardHeader>
<h5 className="card-category">Total Shipments</h5>
<CardTitle tag="h3">
<i className="tim-icons icon-bell-55 text-info" /> 763,215
</CardTitle>
</CardHeader>
<CardBody>
<div className="chart-area">
<Line
data={chartExample2.data}
options={chartExample2.options}
/>
</div>
</CardBody>
</Card>
</Col>
<Col lg="4">
<Card className="card-chart">
<CardHeader>
<h5 className="card-category">Daily Sales</h5>
<CardTitle tag="h3">
<i className="tim-icons icon-delivery-fast text-primary" />{" "}
3,500
</CardTitle>
</CardHeader>
<CardBody>
<div className="chart-area">
<Bar
data={chartExample3.data}
options={chartExample3.options}
/>
</div>
</CardBody>
</Card>
</Col>
<Col lg="4">
<Card className="card-chart">
<CardHeader>
<h5 className="card-category">Completed Tasks</h5>
<CardTitle tag="h3">
<i className="tim-icons icon-send text-success" /> 12,100K
</CardTitle>
</CardHeader>
<CardBody>
<div className="chart-area">
<Line
data={chartExample4.data}
options={chartExample4.options}
/>
</div>
</CardBody>
</Card>
</Col>
</Row>
</div>
);
export default Dashboard
const dataWrapper = (
<div style={{ maxWidth: 1366, margin: "auto" }}>{data}</div>
);
return dataWrapper;
};
export default Dashboard;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+352 -325
View File
@@ -1,366 +1,393 @@
import React, {useState, useEffect} from 'react';
import React, { useState, useEffect } from "react";
import Button from '@material-ui/core/Button';
import Paper from '@material-ui/core/Paper';
import Divider from '@material-ui/core/Divider';
import Select from '@material-ui/core/Select';
import MenuItem from '@material-ui/core/MenuItem';
import Button from "@material-ui/core/Button";
import Paper from "@material-ui/core/Paper";
import Divider from "@material-ui/core/Divider";
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";
import WebhookImage from '../assets/img/webhook.png';
import KafkaImage from '../assets/img/kafka.png';
import WebhookImage from "../assets/img/webhook.png";
import KafkaImage from "../assets/img/kafka.png";
import EditWorkflow from "./EditWorkflow";
const EditWebhook = (props) => {
const { globalUrl, isLoaded } = props;
const { globalUrl, isLoaded } = props;
// FIXME
//const [webhookData, setWebhookData] = useState(webhooktest)
const [webhookData, setWebhookData] = useState({})
const [workflows, setWorkflows] = useState([])
const [firstrequest, setFirstrequest] = React.useState(true);
// FIXME
//const [webhookData, setWebhookData] = useState(webhooktest)
const [webhookData, setWebhookData] = useState({});
const [workflows, setWorkflows] = useState([]);
const [firstrequest, setFirstrequest] = React.useState(true);
const [selectedWorkflows, setSelectedWorkflows] = useState([])
const [selectedWorkflows, setSelectedWorkflows] = useState([]);
const getWorkflows = () => {
fetch(globalUrl+"/api/v1/workflows", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for workflows :O!")
}
return response.json()
})
.then((responseJson) => {
setWorkflows(responseJson)
const getWorkflows = () => {
fetch(globalUrl + "/api/v1/workflows", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for workflows :O!");
}
return response.json();
})
.then((responseJson) => {
setWorkflows(responseJson);
})
.catch((error) => {
console.log(error);
});
};
})
.catch(error => {
console.log(error)
});
}
const setWebhook = (inputdata) => {
console.log(inputdata);
const setWebhook = (inputdata) => {
console.log(inputdata)
fetch(globalUrl + "/api/v1/hooks/" + props.match.params.key, {
method: "PUT",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
body: JSON.stringify(inputdata),
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
})
.catch((error) => {
console.log(error);
});
};
fetch(globalUrl+"/api/v1/hooks/"+props.match.params.key, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
body: JSON.stringify(inputdata),
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson)
})
.catch(error => {
console.log(error)
});
}
const getCurrentWebhook = () => {
fetch(globalUrl + "/api/v1/hooks/" + props.match.params.key, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200!");
window.location.pathname = "webhooks";
}
return response.json();
})
.then((responseJson) => {
if (responseJson.actions === null) {
responseJson.actions = [];
}
const getCurrentWebhook = () => {
fetch(globalUrl+"/api/v1/hooks/"+props.match.params.key, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200!")
window.location.pathname = "webhooks"
}
return response.json()
})
.then((responseJson) => {
if (responseJson.actions === null) {
responseJson.actions = []
}
if (responseJson.transforms === null) {
responseJson.transforms = [];
}
if (responseJson.transforms === null) {
responseJson.transforms = []
}
setWebhookData(responseJson);
})
.catch((error) => {
console.log(error);
//window.location.pathname = "webhooks"
});
};
setWebhookData(responseJson)
})
.catch(error => {
console.log(error)
//window.location.pathname = "webhooks"
});
}
useEffect(() => {
if (firstrequest) {
setFirstrequest(false);
getCurrentWebhook();
if (workflows.length <= 0) {
getWorkflows();
}
}
useEffect(() => {
if (firstrequest) {
setFirstrequest(false)
getCurrentWebhook()
if (workflows.length <= 0) {
getWorkflows()
}
}
// After everything is loaded
if (
Object.getOwnPropertyNames(webhookData).length > 0 &&
webhookData.actions.length > 0 &&
workflows.length > 0 &&
selectedWorkflows.length === 0
) {
// Setting startup actions. making like this in case we want other actions
var tmpActionWorkflows = [];
for (var key in webhookData.actions) {
if (webhookData.actions[key].type === "workflow") {
tmpActionWorkflows.push(webhookData.actions[key]);
}
}
// After everything is loaded
if (Object.getOwnPropertyNames(webhookData).length > 0 && webhookData.actions.length > 0 && workflows.length > 0 && selectedWorkflows.length === 0) {
// Setting startup actions. making like this in case we want other actions
var tmpActionWorkflows = []
for (var key in webhookData.actions) {
if (webhookData.actions[key].type === "workflow") {
tmpActionWorkflows.push(webhookData.actions[key])
}
}
// Fix duplicates... Meh
var foundWorkflowIds = [];
var tmpWorkflows = [];
for (key in tmpActionWorkflows) {
if (foundWorkflowIds.includes(tmpActionWorkflows[key].id)) {
continue;
}
// Fix duplicates... Meh
var foundWorkflowIds = []
var tmpWorkflows = []
for (key in tmpActionWorkflows) {
if (foundWorkflowIds.includes(tmpActionWorkflows[key].id)) {
continue
}
for (var subkey in workflows) {
if (tmpActionWorkflows[key].id === workflows[subkey]["id_"]) {
console.log(tmpActionWorkflows[key].id, workflows[subkey]["id_"]);
foundWorkflowIds.push(tmpActionWorkflows[key].id);
tmpWorkflows.push(workflows[subkey]);
break;
}
}
}
for (var subkey in workflows) {
if (tmpActionWorkflows[key].id === workflows[subkey]["id_"]) {
console.log(tmpActionWorkflows[key].id, workflows[subkey]["id_"])
foundWorkflowIds.push(tmpActionWorkflows[key].id)
tmpWorkflows.push(workflows[subkey])
break
}
}
}
if (tmpWorkflows.length > 0) {
setSelectedWorkflows(tmpWorkflows);
}
}
});
if (tmpWorkflows.length > 0) {
setSelectedWorkflows(tmpWorkflows)
}
}
})
const hookPicture =
Object.getOwnPropertyNames(webhookData).length > 0 &&
webhookData.type === "webhook" ? (
<img src={WebhookImage} alt="webhook" width="100px" height="100px" />
) : (
<img src={KafkaImage} alt="MQ" width="100px" height="100px" />
);
const executeHook = (action) => {
fetch(
globalUrl + "/api/v1/hooks/" + props.match.params.key + "/" + action,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
}
)
.then((response) => response.json())
.then((responseJson) => {
setWebhookData({});
})
.catch((error) => {
console.log(error);
});
};
const hookPicture = Object.getOwnPropertyNames(webhookData).length > 0 && webhookData.type === "webhook" ?
<img
src={WebhookImage}
alt="webhook"
width="100px"
height="100px"
/>
:
<img
src={KafkaImage}
alt="MQ"
width="100px"
height="100px"
/>
const headerPaperStyle = {
display: "flex",
maxHeight: "800px",
minHeight: "800px",
margin: "10px 30px 10px 10px",
padding: "10px 5px 5px 5px",
flexDirection: "column",
};
const executeHook = (action) => {
fetch(globalUrl+"/api/v1/hooks/"+props.match.params.key+"/"+action, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
})
.then((response) => response.json())
.then((responseJson) => {
setWebhookData({})
})
.catch(error => {
console.log(error)
});
}
// FIXME - add with counter to change the correct one (not just edit)
const addNewWorkflow = (event) => {
// Verify if it already exists in the array. Returns if it exists
for (var key in selectedWorkflows) {
var item = selectedWorkflows[key];
if (item["id_"] === event.target.value["id_"]) {
return;
}
}
const headerPaperStyle = {
display: "flex",
maxHeight: "800px",
minHeight: "800px",
margin: "10px 30px 10px 10px",
padding: "10px 5px 5px 5px",
flexDirection: "column",
}
// FIXME - make this possible for all accounts
if (selectedWorkflows.length === 0) {
console.log("ADD FIRST ITEM FOR SELECTEDWORKFLOWS");
console.log(event.target.value);
// FIXME - add with counter to change the correct one (not just edit)
const addNewWorkflow = (event) => {
// Verify if it already exists in the array. Returns if it exists
for (var key in selectedWorkflows) {
var item = selectedWorkflows[key]
if (item["id_"] === event.target.value["id_"]) {
return
}
}
// Cleanup previous actions
var newActions = [];
if (webhookData.actions.length > 0) {
for (key in webhookData.actions) {
if (
webhookData.actions[key].type === "" ||
webhookData.actions[key].type === undefined
) {
continue;
}
// FIXME - make this possible for all accounts
if (selectedWorkflows.length === 0) {
console.log("ADD FIRST ITEM FOR SELECTEDWORKFLOWS")
console.log(event.target.value)
newActions.push(webhookData.actions[key]);
}
}
// Cleanup previous actions
var newActions = []
if (webhookData.actions.length > 0) {
for (key in webhookData.actions) {
if (webhookData.actions[key].type === "" || webhookData.actions[key].type === undefined) {
continue
}
// FIXME - how to stringify this better hurr
var formattedWorkflow = {
type: "workflow",
name: event.target.value.name,
id: event.target.value.id_,
field: "",
};
newActions.push(webhookData.actions[key])
}
}
// FIXME: patch this n
newActions.push(formattedWorkflow);
console.log(newActions);
// FIXME - how to stringify this better hurr
var formattedWorkflow = {
"type": "workflow",
"name": event.target.value.name,
"id": event.target.value.id_,
"field": "",
}
webhookData.actions = newActions;
setWebhook(webhookData);
}
// FIXME: patch this n
newActions.push(formattedWorkflow)
console.log(newActions)
var tmpSelectedWorkflows = [].concat(selectedWorkflows, [
event.target.value,
]);
setSelectedWorkflows(tmpSelectedWorkflows);
};
webhookData.actions = newActions
setWebhook(webhookData)
}
// FIXME
// Create a list with + button
// For each, choose the new workflow I wanna add
// Current: JUST ONE
const selectedWorkflowIds = selectedWorkflows.map((data) => {
return data["id_"];
});
const availableWorkflows = workflows.filter(
(data) => !selectedWorkflowIds.includes(data["id_"])
);
var tmpSelectedWorkflows = [].concat(selectedWorkflows, [event.target.value])
setSelectedWorkflows(tmpSelectedWorkflows)
}
const WorkflowSelect = (counter) => {
if (selectedWorkflows[counter.counter] === undefined) {
return null;
}
// FIXME
// Create a list with + button
// For each, choose the new workflow I wanna add
// Current: JUST ONE
const selectedWorkflowIds = selectedWorkflows.map(data => {return data["id_"]})
const availableWorkflows = workflows.filter(data => !selectedWorkflowIds.includes(data["id_"]))
console.log(selectedWorkflows[0]);
console.log(selectedWorkflows[0]);
console.log(selectedWorkflows[0]);
console.log(selectedWorkflows[counter.counter]);
console.log(selectedWorkflows[counter.counter].name);
return (
<div>
Workflow select:
<Select
value={selectedWorkflows[counter.counter].name}
onChange={(event) => {
addNewWorkflow(event, counter.counter);
}}
displayEmpty
name="workflow"
>
{availableWorkflows.map((data) => (
<MenuItem key={data.name} value={data} name={data.name}>
{data.name}
</MenuItem>
))}
</Select>
</div>
);
};
const WorkflowSelect = (counter) => {
if (selectedWorkflows[counter.counter] === undefined) {
return null
}
const extraWorkflow =
workflows.length > 0 && availableWorkflows.length > 0 ? (
<WorkflowSelect counter={selectedWorkflows.length} />
) : null;
console.log(selectedWorkflows[0])
console.log(selectedWorkflows[0])
console.log(selectedWorkflows[0])
console.log(selectedWorkflows[counter.counter])
console.log(selectedWorkflows[counter.counter].name)
return (
<div>
Workflow select:
<Select
value={selectedWorkflows[counter.counter].name}
onChange={(event) => {addNewWorkflow(event, counter.counter)}}
displayEmpty
name="workflow"
>
{availableWorkflows.map(data => (
<MenuItem key={data.name} value={data} name={data.name}>{data.name}</MenuItem>
))}
</Select>
</div>
)
}
const multiWorkflowSelect =
workflows.length > 0 && selectedWorkflows.length > 0 ? (
<div>
{selectedWorkflows.map((data, count) => (
<WorkflowSelect key={count} counter={count} />
))}
{extraWorkflow}
</div>
) : (
<WorkflowSelect counter={0} />
);
const extraWorkflow = workflows.length > 0 && availableWorkflows.length > 0 ?
<WorkflowSelect counter={selectedWorkflows.length}/> : null
const headerInfo =
Object.getOwnPropertyNames(webhookData).length > 0 ? (
<div>
<Paper style={headerPaperStyle}>
<div style={{ display: "flex", flex: "1" }}>
<div style={{ flex: "1" }}>{hookPicture}</div>
<div
style={{ display: "flex", flexDirection: "column", flex: "5" }}
>
<div style={{ flex: "1" }}>
<h1>Name: {webhookData.info.name}</h1>
</div>
</div>
</div>
<div style={{ flex: "4" }}>
Description: {webhookData.info.description}
<div>Id: {webhookData.id}</div>
<div>Url: {webhookData.info.url}</div>
<div>Type: {webhookData.type}</div>
<div>Status: {webhookData.status}</div>
<div>
CHOOSE ACTIONS:
{multiWorkflowSelect}
</div>
</div>
<Divider />
<div style={{ flex: "1", display: "flex", flexDirection: "row" }}>
<div style={{ flex: "1" }}>
<Button
disabled={
webhookData.running === true && webhookData.name !== ""
}
onClick={() => {
executeHook("start");
}}
style={{
left: "50%",
top: "50%",
transform: "translate(-50%, -50%)",
}}
variant="outlined"
color="primary"
>
Start {webhookData.type}
</Button>
</div>
<div style={{ flex: "1" }}>
<Button
disabled={webhookData.running === false}
onClick={() => {
executeHook("stop");
}}
style={{
left: "50%",
top: "50%",
transform: "translate(-50%, -50%)",
}}
variant="outlined"
color="primary"
>
Stop {webhookData.type}
</Button>
</div>
</div>
</Paper>
</div>
) : null;
const multiWorkflowSelect = workflows.length > 0 && selectedWorkflows.length > 0 ?
<div>
{selectedWorkflows.map((data, count) => (
<WorkflowSelect key={count} counter={count}/>
))}
{extraWorkflow}
</div>
: <WorkflowSelect counter={0}/>
// FIXME - needs refresh every time you add a new workflow
const workflowdata =
Object.getOwnPropertyNames(webhookData).length > 0 &&
selectedWorkflows.length > 0 ? (
<EditWorkflow
globalUrl={globalUrl}
inputworkflows={selectedWorkflows}
inputname={webhookData.info.name}
inputtype={webhookData.type}
/>
) : null;
const headerInfo = Object.getOwnPropertyNames(webhookData).length > 0 ?
<div>
<Paper style={headerPaperStyle}>
<div style={{display: "flex", flex: "1"}}>
<div style={{flex: "1"}}>
{hookPicture}
</div>
<div style={{display: "flex", flexDirection: "column", flex: "5"}}>
<div style={{flex: "1"}}>
<h1>Name: {webhookData.info.name}</h1>
</div>
</div>
</div>
<div style={{flex: "4"}}>
Description: {webhookData.info.description}
<div>
Id: {webhookData.id}
</div>
<div>
Url: {webhookData.info.url}
</div>
<div>
Type: {webhookData.type}
</div>
<div>
Status: {webhookData.status}
</div>
<div>
CHOOSE ACTIONS:
{multiWorkflowSelect}
</div>
</div>
<Divider />
<div style={{flex: "1", display: "flex", flexDirection: "row"}}>
<div style={{flex: "1"}}>
<Button
disabled={webhookData.running === true && webhookData.name !== ""}
onClick={() => {executeHook("start")}}
style={{left: "50%", top: "50%", transform: "translate(-50%, -50%)"}}
variant="outlined"
color="primary"
>Start {webhookData.type}</Button>
</div>
<div style={{flex: "1"}}>
<Button
disabled={webhookData.running === false}
onClick={() => {executeHook("stop")}}
style={{left: "50%", top: "50%", transform: "translate(-50%, -50%)"}}
variant="outlined"
color="primary"
>Stop {webhookData.type}</Button>
</div>
</div>
</Paper>
</div>
: null
// FIXME - needs refresh every time you add a new workflow
const workflowdata = Object.getOwnPropertyNames(webhookData).length > 0 && selectedWorkflows.length > 0 ?
<EditWorkflow globalUrl={globalUrl} inputworkflows={selectedWorkflows} inputname={webhookData.info.name} inputtype={webhookData.type} /> : null
const loadedCheck = isLoaded ? (
<div style={{ display: "flex", backgroundColor: "#f7f7f7" }}>
<div style={{ flex: 1 }}>{workflowdata}</div>
<div style={{ flex: 1 }}>{headerInfo}</div>
</div>
) : (
<div></div>
);
const loadedCheck = isLoaded ?
<div style={{display: "flex", backgroundColor: "#f7f7f7"}}>
<div style={{"flex": 1}}>
{workflowdata}
</div>
<div style={{"flex": 1}}>
{headerInfo}
</div>
</div>
:
<div>
</div>
// FIXME: Use this for testing
// <EditWorkflow globalUrl={globalUrl} inputname={"Helo?"} inputtype={"webhook"} /> : null
return (
<div>
{loadedCheck}
</div>
)
}
// FIXME: Use this for testing
// <EditWorkflow globalUrl={globalUrl} inputname={"Helo?"} inputtype={"webhook"} /> : null
return <div>{loadedCheck}</div>;
};
export default EditWebhook;
File diff suppressed because one or more lines are too long
+101 -105
View File
@@ -1,122 +1,118 @@
/* eslint-disable react/no-multi-comp */
import React, {useState} from 'react';
import React, { useState } from "react";
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import Paper from '@material-ui/core/Paper';
import TextField from "@material-ui/core/TextField";
import Button from "@material-ui/core/Button";
import Paper from "@material-ui/core/Paper";
const bodyDivStyle = {
margin: "auto",
marginTop: "100px",
width: "500px",
}
margin: "auto",
marginTop: "100px",
width: "500px",
};
const ForgotPassword = (props) => {
const { globalUrl, isLoaded, isLoggedIn, surfaceColor, inputColor } = props;
const ForgotPassword = props => {
const { globalUrl, isLoaded, isLoggedIn, surfaceColor, inputColor } = props;
const boxStyle = {
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
backgroundColor: surfaceColor,
};
const [username, setUsername] = useState("");
const [resetInfo, setResetInfo] = useState(
"You will receive an email with instructions shortly."
);
const boxStyle = {
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
backgroundColor: surfaceColor,
}
const handleValidateForm = () => {
return username.length > 3;
};
const [username, setUsername] = useState("")
const [resetInfo, setResetInfo] = useState("You will receive an email with instructions shortly.")
if (isLoggedIn === true) {
window.location.pathname = "/";
}
const handleValidateForm = () => {
return username.length > 3
}
const onSubmit = (e) => {
e.preventDefault();
// FIXME - add some check here ROFL
if (isLoggedIn === true) {
window.location.pathname = "/"
}
// Just use this one?
var data = { username: username };
var baseurl = globalUrl;
var url = baseurl + "/api/v1/passwordresetmail";
fetch(url, {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json; charset=utf-8",
},
})
.then((response) =>
response.json().then((responseJson) => {
if (responseJson["success"] === false) {
setResetInfo(responseJson["reason"]);
}
})
)
.catch((error) => {
setResetInfo("Error in userdata: " + error);
});
};
const onSubmit = (e) => {
e.preventDefault()
// FIXME - add some check here ROFL
const onChangeUser = (e) => {
setUsername(e.target.value);
};
// Just use this one?
var data = {"username": username}
var baseurl = globalUrl
var url = baseurl+'/api/v1/passwordresetmail';
fetch(url, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
})
.then(response =>
response.json().then(responseJson => {
if (responseJson["success"] === false) {
setResetInfo(responseJson["reason"])
}
}),
)
.catch(error => {
setResetInfo("Error in userdata: " + error)
});
}
const data = (
<div style={bodyDivStyle}>
<Paper style={boxStyle}>
<form onSubmit={onSubmit} style={{ margin: "15px 15px 15px 15px" }}>
<h2>Password reset</h2>
<div>
<TextField
required
fullWidth={true}
color="primary"
style={{ backgroundColor: inputColor }}
InputProps={{
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
type="username"
placeholder="Username / Email"
id="standard-required"
autoComplete="username"
margin="normal"
variant="outlined"
onChange={onChangeUser}
/>
</div>
<div style={{ display: "flex", marginTop: "15px" }}>
<Button
color="primary"
variant="contained"
type="submit"
style={{ flex: "1", marginRight: "5px" }}
disabled={!handleValidateForm()}
>
SUBMIT
</Button>
</div>
<div style={{ marginTop: "20px" }}>{resetInfo}</div>
</form>
</Paper>
</div>
);
const onChangeUser = (e) => {
setUsername(e.target.value)
}
const loadedCheck = isLoaded ? <div>{data}</div> : <div></div>;
const data =
<div style={bodyDivStyle}>
<Paper style={boxStyle}>
<form onSubmit={onSubmit} style={{margin: "15px 15px 15px 15px"}}>
<h2>Password reset</h2>
<div>
<TextField
required
fullWidth={true}
color="primary"
style={{backgroundColor: inputColor}}
InputProps={{
style:{
height: "50px",
color: "white",
fontSize: "1em",
},
}}
type="username"
placeholder="Username / Email"
id="standard-required"
autoComplete="username"
margin="normal"
variant="outlined"
onChange={onChangeUser}
/>
</div>
<div style={{display: "flex", marginTop: "15px"}}>
<Button color="primary" variant="contained" type="submit" style={{flex: "1", marginRight: "5px"}} disabled={!handleValidateForm()}>SUBMIT</Button>
</div>
<div style={{marginTop: "20px"}}>
{resetInfo}
</div>
</form>
</Paper>
</div>
const loadedCheck = isLoaded ?
<div>
{data}
</div>
:
<div>
</div>
return (
<div>
{loadedCheck}
</div>
)
}
return <div>{loadedCheck}</div>;
};
export default ForgotPassword;
+108 -106
View File
@@ -1,28 +1,28 @@
import React, {useState, useEffect} from 'react';
import React, { useState, useEffect } from "react";
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Paper from "@material-ui/core/Paper";
import Button from "@material-ui/core/Button";
import TextField from '@material-ui/core/TextField';
import TextField from "@material-ui/core/TextField";
const bodyDivStyle = {
margin: "auto",
textAlign: "center",
width: "768px",
}
margin: "auto",
textAlign: "center",
width: "768px",
};
const boxStyle = {
flex: "1",
marginLeft: "10px",
marginRight: "10px",
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
backgroundColor: "#e8eaf6",
display: "flex",
flexDirection: "column"
}
flex: "1",
marginLeft: "10px",
marginRight: "10px",
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
backgroundColor: "#e8eaf6",
display: "flex",
flexDirection: "column",
};
//const tmpdata = {
// "username": "frikky",
@@ -38,97 +38,99 @@ const boxStyle = {
// FIXME - remove tmpdata
// FIXME: Use isLoggedIn :)
const Settings = (props) => {
const { globalUrl, isLoaded, } = props;
const { globalUrl, isLoaded } = props;
const [newPassword, setNewPassword] = useState("");
const [newPassword2, setNewPassword2] = useState("");
const [passwordFormMessage, setPasswordFormMessage] = useState("");
const [newPassword, setNewPassword] = useState("");
const [newPassword2, setNewPassword2] = useState("");
const [passwordFormMessage, setPasswordFormMessage] = useState("");
const onPasswordChange = () => {
const data = {"newpassword": newPassword, "newpassword2": newPassword2, "reference": props.match.params.key}
const url = globalUrl+'/api/v1/passwordreset';
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) {
setPasswordFormMessage(responseJson["reason"])
}
}),
)
.catch(error => {
setPasswordFormMessage("Something went wrong.")
});
}
const onPasswordChange = () => {
const data = {
newpassword: newPassword,
newpassword2: newPassword2,
reference: props.match.params.key,
};
const url = globalUrl + "/api/v1/passwordreset";
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) {
setPasswordFormMessage(responseJson["reason"]);
}
})
)
.catch((error) => {
setPasswordFormMessage("Something went wrong.");
});
};
// This should "always" have data
useEffect(() => {
})
// This should "always" have data
useEffect(() => {});
// Random names for type & autoComplete. Didn't research :^)
const landingpageData =
<div style={{display: "flex", marginTop: "80px"}}>
<Paper style={boxStyle}>
<h2>Password Reset</h2>
<div style={{flex: "1", display: "flex", flexDirection: "column"}}>
<TextField
required
style={{flex: "1"}}
fullWidth={true}
placeholder="New password"
type="password"
id="standard-required"
autoComplete="password"
margin="normal"
variant="outlined"
onChange={e => setNewPassword(e.target.value)}
/>
<TextField
required
style={{flex: "1"}}
fullWidth={true}
type="password"
placeholder="Repeat new password"
id="standard-required"
margin="normal"
variant="outlined"
onChange={e => setNewPassword2(e.target.value)}
/>
</div>
<Button
disabled={(newPassword.length < 10 || newPassword2.length < 10) || newPassword !== newPassword2}
style={{width: "100%", height: "60px", marginTop: "10px"}}
variant="contained"
color="primary"
onClick={() => onPasswordChange()}
>
Submit password change
</Button>
<h3>{passwordFormMessage}</h3>
</Paper>
</div>
// Random names for type & autoComplete. Didn't research :^)
const landingpageData = (
<div style={{ display: "flex", marginTop: "80px" }}>
<Paper style={boxStyle}>
<h2>Password Reset</h2>
<div style={{ flex: "1", display: "flex", flexDirection: "column" }}>
<TextField
required
style={{ flex: "1" }}
fullWidth={true}
placeholder="New password"
type="password"
id="standard-required"
autoComplete="password"
margin="normal"
variant="outlined"
onChange={(e) => setNewPassword(e.target.value)}
/>
<TextField
required
style={{ flex: "1" }}
fullWidth={true}
type="password"
placeholder="Repeat new password"
id="standard-required"
margin="normal"
variant="outlined"
onChange={(e) => setNewPassword2(e.target.value)}
/>
</div>
<Button
disabled={
newPassword.length < 10 ||
newPassword2.length < 10 ||
newPassword !== newPassword2
}
style={{ width: "100%", height: "60px", marginTop: "10px" }}
variant="contained"
color="primary"
onClick={() => onPasswordChange()}
>
Submit password change
</Button>
<h3>{passwordFormMessage}</h3>
</Paper>
</div>
);
const loadedCheck = isLoaded ?
<div style={bodyDivStyle}>
{landingpageData}
</div>
:
<div>
</div>
const loadedCheck = isLoaded ? (
<div style={bodyDivStyle}>{landingpageData}</div>
) : (
<div></div>
);
return(
<div>
{loadedCheck}
</div>
)
}
return <div>{loadedCheck}</div>;
};
export default Settings;
+4 -6
View File
@@ -1,9 +1,7 @@
import React from 'react';
import React from "react";
const HandlePayment = () => {
return (
null
)
}
return null;
};
export default HandlePayment
export default HandlePayment;
+169 -171
View File
@@ -1,181 +1,182 @@
import React, { useEffect, useState } from 'react';
import { useTheme } from '@material-ui/core/styles';
import React, { useEffect, useState } from "react";
import { useTheme } from "@material-ui/core/styles";
import Grid from '@material-ui/core/Grid';
import Card from '@material-ui/core/Card';
import CardActionArea from '@material-ui/core/CardActionArea';
import CardContent from '@material-ui/core/CardContent';
import CardHeader from '@material-ui/core/CardHeader';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import Grid from "@material-ui/core/Grid";
import Card from "@material-ui/core/Card";
import CardActionArea from "@material-ui/core/CardActionArea";
import CardContent from "@material-ui/core/CardContent";
import CardHeader from "@material-ui/core/CardHeader";
import Typography from "@material-ui/core/Typography";
import Button from "@material-ui/core/Button";
const Workflows = (props) => {
const { globalUrl, isLoggedIn, isLoaded, } = props
const theme = useTheme();
const [curView, setCurView] = useState(0);
const [firstrequest, setFirstrequest] = useState(true)
const [selectedItems, setSelectedItems] = useState([])
const { globalUrl, isLoggedIn, isLoaded } = props;
const theme = useTheme();
const [curView, setCurView] = useState(0);
const [firstrequest, setFirstrequest] = useState(true);
const [selectedItems, setSelectedItems] = useState([]);
const viewdata1 = [
{
"title": "General",
"content": "Learn about our ticketing solutions",
"subitems": [
{
"name": "Search",
"subtitle": "Search for anything, anywhere",
},
{
"name": "Message",
"subtitle": "Read and send messages",
},
{
"name": "Parse emails",
"subtitle": "what",
},
],
},
{
"title": "Ticketing",
"subitems": [
{
"name": "Search",
"subtitle": "Search for anything, anywhere",
},
{
"name": "Message",
"subtitle": "Read and send messages",
},
{
"name": "Parse emails",
"subtitle": "what",
},
],
},
{
"title": "Threat intel",
"subitems": [
{
"name": "Search",
"subtitle": "Search for anything, anywhere",
},
{
"name": "Message",
"subtitle": "Read and send messages",
},
{
"name": "Parse emails",
"subtitle": "what",
},
],
},
]
const viewdata1 = [
{
title: "General",
content: "Learn about our ticketing solutions",
subitems: [
{
name: "Search",
subtitle: "Search for anything, anywhere",
},
{
name: "Message",
subtitle: "Read and send messages",
},
{
name: "Parse emails",
subtitle: "what",
},
],
},
{
title: "Ticketing",
subitems: [
{
name: "Search",
subtitle: "Search for anything, anywhere",
},
{
name: "Message",
subtitle: "Read and send messages",
},
{
name: "Parse emails",
subtitle: "what",
},
],
},
{
title: "Threat intel",
subitems: [
{
name: "Search",
subtitle: "Search for anything, anywhere",
},
{
name: "Message",
subtitle: "Read and send messages",
},
{
name: "Parse emails",
subtitle: "what",
},
],
},
];
if (firstrequest) {
setFirstrequest(false)
if (props.match.params.key) {
console.log("PROPS: ", props.match.params.key)
const viewitem = viewdata1.find(item => item.title.toLowerCase() === props.match.params.key.toLowerCase())
if (viewitem !== undefined && viewitem !== null) {
setCurView(1)
//setSelectedItem(viewitem)
}
}
}
if (firstrequest) {
setFirstrequest(false);
if (props.match.params.key) {
console.log("PROPS: ", props.match.params.key);
const viewitem = viewdata1.find(
(item) =>
item.title.toLowerCase() === props.match.params.key.toLowerCase()
);
if (viewitem !== undefined && viewitem !== null) {
setCurView(1);
//setSelectedItem(viewitem)
}
}
}
const cardContentStyle = {
height: "100%",
width: "100%",
padding: 40,
};
const cardContentStyle = {
height: "100%",
width: "100%",
padding: 40,
}
const outerGridView = {
width: "100%",
marginTop: 15,
};
const outerGridView = {
width: "100%",
marginTop: 15,
}
const paperStyle = {
height: 300,
color: "white",
backgroundColor: theme.palette.surfaceColor,
color: "white",
cursor: "pointer",
display: "flex",
textAlign: "center",
};
const paperStyle = {
height: 300,
color: "white",
backgroundColor: theme.palette.surfaceColor,
color: "white",
cursor: "pointer",
display: "flex",
textAlign: "center",
}
const HandleSelection = (data) => {
const [selected, setSelected] = useState(false);
const HandleSelection = (data) => {
const [selected, setSelected] = useState(false);
var baseStyle = JSON.parse(JSON.stringify(paperStyle));
if (selected) {
baseStyle.backgroundColor = "white";
baseStyle.color = "black";
}
var baseStyle = JSON.parse(JSON.stringify(paperStyle))
if (selected) {
baseStyle.backgroundColor = "white"
baseStyle.color = "black"
}
return (
<Grid
item
xs={4}
onClick={() => {
console.log(selectedItems);
if (selected) {
const index = selectedItems.findIndex(
(item) => item.title === data.title
);
if (index >= 0) {
selectedItems.splice(index, 1);
setSelectedItems(selectedItems);
}
} else {
selectedItems.push(data);
setSelectedItems(selectedItems);
}
return (
<Grid item xs={4} onClick={() => {
console.log(selectedItems)
if (selected) {
const index = selectedItems.findIndex(item => item.title === data.title)
if (index >= 0) {
selectedItems.splice(index, 1)
setSelectedItems(selectedItems)
}
} else {
selectedItems.push(data)
setSelectedItems(selectedItems)
}
setSelected(!selected);
setSelected(!selected)
//setCurView(1)
//setSelectedItem(data)
//window.location.pathname += "/"+data.title.toLowerCase()
}}>
<Card style={baseStyle}>
<CardActionArea style={cardContentStyle}>
<CardContent>
<Typography variant="h4">
{data.title}
</Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
)
}
//setCurView(1)
//setSelectedItem(data)
//window.location.pathname += "/"+data.title.toLowerCase()
}}
>
<Card style={baseStyle}>
<CardActionArea style={cardContentStyle}>
<CardContent>
<Typography variant="h4">{data.title}</Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
);
};
const view1 = curView === 0 ?
<div>
<Typography variant="h4">
What are you interested in?
</Typography>
<Grid container style={outerGridView} spacing={3}>
{viewdata1.map(data => {
return (
HandleSelection(data)
)
})}
</Grid>
{/*
const view1 =
curView === 0 ? (
<div>
<Typography variant="h4">What are you interested in?</Typography>
<Grid container style={outerGridView} spacing={3}>
{viewdata1.map((data) => {
return HandleSelection(data);
})}
</Grid>
{/*
<Button variant="contained" color="primary" style={{height: 50, width: 300, margin: "auto",}} onClick={() => {
setCurView(1)
}}>
Continue
</Button>
*/}
</div>
: null
</div>
) : null;
const view2 = curView === 1 ?
<div>
<Typography variant="h4">
Step 2.
</Typography>
{/*
const view2 =
curView === 1 ? (
<div>
<Typography variant="h4">Step 2.</Typography>
{/*
<Grid container style={outerGridView} spacing={3}>
{selectedItem.subitems === undefined ? null :
selectedItem.subitems.map(data => {
@@ -198,20 +199,17 @@ const Workflows = (props) => {
})}
</Grid>
*/}
</div>
: null
</div>
) : null;
const baseView =
<div style={{maxWidth: 1024, margin: "auto", paddingTop: 50,}}>
{view1}
{view2}
</div>
const baseView = (
<div style={{ maxWidth: 1024, margin: "auto", paddingTop: 50 }}>
{view1}
{view2}
</div>
);
return (
<div>
{baseView}
</div>
)
}
return <div>{baseView}</div>;
};
export default Workflows
export default Workflows;
+185 -159
View File
@@ -1,179 +1,205 @@
import React, {} from 'react';
import React from "react";
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Divider from '@material-ui/core/Divider';
import {BrowserView, MobileView} from "react-device-detect";
import ScheduleIcon from '@material-ui/icons/Schedule';
import Web from '@material-ui/icons/Web';
import AccountTree from '@material-ui/icons/AccountTree';
import Paper from "@material-ui/core/Paper";
import Button from "@material-ui/core/Button";
import Divider from "@material-ui/core/Divider";
import { BrowserView, MobileView } from "react-device-detect";
import ScheduleIcon from "@material-ui/icons/Schedule";
import Web from "@material-ui/icons/Web";
import AccountTree from "@material-ui/icons/AccountTree";
const bodyDivStyle = {
margin: "auto",
marginTop: "75px",
textAlign: "center",
width: "1100px",
}
margin: "auto",
marginTop: "75px",
textAlign: "center",
width: "1100px",
};
const surfaceColor = "#27292D"
const surfaceColor = "#27292D";
const boxStyle = {
flex: "1",
marginLeft: "10px",
marginRight: "10px",
height: "400px",
//backgroundColor: "#e8eaf6",
backgroundColor: surfaceColor,
textAlign: "center",
display: "flex",
flexDirection: "column",
}
flex: "1",
marginLeft: "10px",
marginRight: "10px",
height: "400px",
//backgroundColor: "#e8eaf6",
backgroundColor: surfaceColor,
textAlign: "center",
display: "flex",
flexDirection: "column",
};
const bodyTextStyle = {
color: "#ffffff",
}
color: "#ffffff",
};
const hrefStyle = {
color: "black",
textDecoration: "none",
}
color: "black",
textDecoration: "none",
};
// Should be different if logged in :|
const LandingPage = (props) => {
const { isLoaded} = props;
const { isLoaded } = props;
const textColor = "#8899A6"
const iconColor = "#1DA1F2"
const iconSize = "8em"
const GridLayout = (header, description, link, icon) => {
return (
<Paper style={boxStyle}>
<a href={link} style={hrefStyle}>
<div style={{flex: "1", color: "#FFFFFF"}}>
<h2>{header}</h2>
</div>
<Divider />
<div style={{flex: "3", marginLeft: "10px", marginRight: "10px", marginTop: "10px", color: textColor}}>
{description}
</div>
<div style={{margin: "auto"}}>
{icon}
</div>
<Divider style={{marginTop: "20px", marginBottom: "20px"}} />
<div style={{flex: "1", color: "#f85a3e"}}>
<div style={{}} >
Learn more
</div>
</div>
</a>
</Paper>
)
}
const textColor = "#8899A6";
const iconColor = "#1DA1F2";
const iconSize = "8em";
const GridLayout = (header, description, link, icon) => {
return (
<Paper style={boxStyle}>
<a href={link} style={hrefStyle}>
<div style={{ flex: "1", color: "#FFFFFF" }}>
<h2>{header}</h2>
</div>
<Divider />
<div
style={{
flex: "3",
marginLeft: "10px",
marginRight: "10px",
marginTop: "10px",
color: textColor,
}}
>
{description}
</div>
<div style={{ margin: "auto" }}>{icon}</div>
<Divider style={{ marginTop: "20px", marginBottom: "20px" }} />
<div style={{ flex: "1", color: "#f85a3e" }}>
<div style={{}}>Learn more</div>
</div>
</a>
</Paper>
);
};
const listitems = [
GridLayout("Simple integrations", "Easily use others' or create your own integration", "/docs/apps", <Web style={{fontSize: iconSize, marginTop: "20px", color: iconColor}} />),
GridLayout("Workflows", "Access the power of automation within minutes, whether its on premise or in the cloud", "/docs/workflows", <AccountTree style={{fontSize: iconSize, marginTop: "20px", color: iconColor}} />),
GridLayout("Realtime actions", "Beat the clock by leveraging our realtime triggers", "/docs/triggers", <ScheduleIcon style={{fontSize: iconSize, marginTop: "20px", color: iconColor}} />),
]
const listitems = [
GridLayout(
"Simple integrations",
"Easily use others' or create your own integration",
"/docs/apps",
<Web
style={{ fontSize: iconSize, marginTop: "20px", color: iconColor }}
/>
),
GridLayout(
"Workflows",
"Access the power of automation within minutes, whether its on premise or in the cloud",
"/docs/workflows",
<AccountTree
style={{ fontSize: iconSize, marginTop: "20px", color: iconColor }}
/>
),
GridLayout(
"Realtime actions",
"Beat the clock by leveraging our realtime triggers",
"/docs/triggers",
<ScheduleIcon
style={{ fontSize: iconSize, marginTop: "20px", color: iconColor }}
/>
),
];
// The actual landing page
// <img style={{width: "400px"}} alt={"logo"} src={Default}/>
const landingpageDataBrowser =
<div>
<div style={bodyTextStyle}>
<h1>Shuffle</h1>
<h3 style={{color: "#8899A6"}}>A general automation solution for Infosec and IT Professionals</h3>
</div>
<a href="/register" style={hrefStyle}>
<Button
style={{width: "180px", height: "50px", borderRadius: "0px"}}
variant="outlined"
color="primary"
>
Try it out
</Button>
</a>
<a href="/contact" style={hrefStyle}>
<Button
style={{width: "180px", height: "50px", borderRadius: "0px"}}
variant="contained"
color="primary"
>
Contact
</Button>
</a>
<div style={{display: "flex", marginTop: "100px"}}>
{listitems.map(item => {
return (
<div>
{item}
</div>
)
})}
</div>
</div>
// The actual landing page
// <img style={{width: "400px"}} alt={"logo"} src={Default}/>
const landingpageDataBrowser = (
<div>
<div style={bodyTextStyle}>
<h1>Shuffle</h1>
<h3 style={{ color: "#8899A6" }}>
A general automation solution for Infosec and IT Professionals
</h3>
</div>
<a href="/register" style={hrefStyle}>
<Button
style={{ width: "180px", height: "50px", borderRadius: "0px" }}
variant="outlined"
color="primary"
>
Try it out
</Button>
</a>
<a href="/contact" style={hrefStyle}>
<Button
style={{ width: "180px", height: "50px", borderRadius: "0px" }}
variant="contained"
color="primary"
>
Contact
</Button>
</a>
<div style={{ display: "flex", marginTop: "100px" }}>
{listitems.map((item) => {
return <div>{item}</div>;
})}
</div>
</div>
);
const landingpageDataMobile =
<div>
<div style={{color: "white", textAlign: "center", marginLeft: "10px", marginRight: "10px"}}>
<h1>Shuffle</h1>
<h3>A general automation solution for Infosec and IT Professionals</h3>
<a href="/contact" style={hrefStyle}>
<Button
style={{width: "220px", height: "60px", borderRadius: "0px"}}
variant="contained"
color="primary"
>
Contact
</Button>
</a>
</div>
<div style={{display: "flex", flexDirection: "column", marginTop: "100px"}}>
<div>
{listitems[0]}
</div>
<div style={{marginTop: "20px"}}>
{listitems[1]}
</div>
<div style={{marginTop: "20px", marginBottom: "30px"}}>
{listitems[2]}
</div>
<div style={{marginTop: "20px", marginBottom: "30px", textAlign: "center"}}>
<a href="/contact" style={hrefStyle}>
<Button
style={{width: "220px", height: "60px", borderRadius: "0px"}}
variant="contained"
color="primary"
>
Contact
</Button>
</a>
</div>
</div>
</div>
const landingpageDataMobile = (
<div>
<div
style={{
color: "white",
textAlign: "center",
marginLeft: "10px",
marginRight: "10px",
}}
>
<h1>Shuffle</h1>
<h3>A general automation solution for Infosec and IT Professionals</h3>
<a href="/contact" style={hrefStyle}>
<Button
style={{ width: "220px", height: "60px", borderRadius: "0px" }}
variant="contained"
color="primary"
>
Contact
</Button>
</a>
</div>
<div
style={{ display: "flex", flexDirection: "column", marginTop: "100px" }}
>
<div>{listitems[0]}</div>
<div style={{ marginTop: "20px" }}>{listitems[1]}</div>
<div style={{ marginTop: "20px", marginBottom: "30px" }}>
{listitems[2]}
</div>
<div
style={{
marginTop: "20px",
marginBottom: "30px",
textAlign: "center",
}}
>
<a href="/contact" style={hrefStyle}>
<Button
style={{ width: "220px", height: "60px", borderRadius: "0px" }}
variant="contained"
color="primary"
>
Contact
</Button>
</a>
</div>
</div>
</div>
);
// Reroute if the user is logged in
// const landingSite = isLoggedIn ? <Workflows globalUrl={globalUrl}{...props} /> : <div style={bodyDivStyle}>{landingpageData}</div>
const landingSite = <div style={bodyDivStyle}>{landingpageDataBrowser}</div>;
// Reroute if the user is logged in
// const landingSite = isLoggedIn ? <Workflows globalUrl={globalUrl}{...props} /> : <div style={bodyDivStyle}>{landingpageData}</div>
const landingSite = <div style={bodyDivStyle}>{landingpageDataBrowser}</div>
const loadedCheck = isLoaded ? (
<div>
<BrowserView>{landingSite}</BrowserView>
<MobileView>{landingpageDataMobile}</MobileView>
</div>
) : (
<div></div>
);
const loadedCheck = isLoaded ?
<div>
<BrowserView>
{landingSite}
</BrowserView>
<MobileView>
{landingpageDataMobile}
</MobileView>
</div>
:
<div>
</div>
return(
<div>
{loadedCheck}
</div>
)
}
return <div>{loadedCheck}</div>;
};
export default LandingPage;
+10 -15
View File
@@ -1,21 +1,16 @@
import React, {} from 'react';
import React from "react";
const bodyDivStyle = {
transform: "translate(-50%, -50%)",
top: "50%",
left: "50%",
position: "absolute",
width: "500px",
color: "white",
}
transform: "translate(-50%, -50%)",
top: "50%",
left: "50%",
position: "absolute",
width: "500px",
color: "white",
};
// Should be different if logged in :|
const LandingPageLoggedin = (props) => {
return(
<div style={bodyDivStyle}>
TMP landingpage when logged in
</div>
)
}
return <div style={bodyDivStyle}>TMP landingpage when logged in</div>;
};
export default LandingPageLoggedin;
+504 -324
View File
@@ -1,349 +1,529 @@
import React, {useState } from 'react';
import React, { useState } from "react";
import Paper from '@material-ui/core/Paper';
import Card from '@material-ui/core/Card';
import CardActionArea from '@material-ui/core/CardActionArea';
import CardMedia from '@material-ui/core/CardMedia';
import CardContent from '@material-ui/core/CardContent';
import CardActions from '@material-ui/core/CardActions';
import Button from '@material-ui/core/Button';
import Divider from '@material-ui/core/Divider';
import Grid from '@material-ui/core/Grid';
import {BrowserView, MobileView} from "react-device-detect";
import Paper from "@material-ui/core/Paper";
import Card from "@material-ui/core/Card";
import CardActionArea from "@material-ui/core/CardActionArea";
import CardMedia from "@material-ui/core/CardMedia";
import CardContent from "@material-ui/core/CardContent";
import CardActions from "@material-ui/core/CardActions";
import Button from "@material-ui/core/Button";
import Divider from "@material-ui/core/Divider";
import Grid from "@material-ui/core/Grid";
import { BrowserView, MobileView } from "react-device-detect";
import ScheduleIcon from '@material-ui/icons/Schedule';
import Web from '@material-ui/icons/Web';
import AccountTree from '@material-ui/icons/AccountTree';
import InfoIcon from '@material-ui/icons/Info';
import ArrowForwardIcon from '@material-ui/icons/ArrowForward';
import CreateIcon from '@material-ui/icons/Create';
import ScheduleIcon from "@material-ui/icons/Schedule";
import Web from "@material-ui/icons/Web";
import AccountTree from "@material-ui/icons/AccountTree";
import InfoIcon from "@material-ui/icons/Info";
import ArrowForwardIcon from "@material-ui/icons/ArrowForward";
import CreateIcon from "@material-ui/icons/Create";
const bodyDivStyle = {
margin: "auto",
}
margin: "auto",
};
const surfaceColor = "#27292D"
const surfaceColor = "#27292D";
const boxStyle = {
flex: "1",
marginLeft: "10px",
marginRight: "10px",
height: "400px",
//backgroundColor: "#e8eaf6",
backgroundColor: surfaceColor,
textAlign: "center",
display: "flex",
flexDirection: "column",
}
flex: "1",
marginLeft: "10px",
marginRight: "10px",
height: "400px",
//backgroundColor: "#e8eaf6",
backgroundColor: surfaceColor,
textAlign: "center",
display: "flex",
flexDirection: "column",
};
const bodyTextStyle = {
color: "#ffffff",
}
color: "#ffffff",
};
const hrefStyle = {
color: "inherit",
textDecoration: "none",
}
color: "inherit",
textDecoration: "none",
};
// Should be different if logged in :|
const LandingPage = (props) => {
const { isLoaded} = props;
const { isLoaded } = props;
const textColor = "#8899A6"
const iconColor = "#1DA1F2"
const iconSize = "8em"
const textColor = "#8899A6";
const iconColor = "#1DA1F2";
const iconSize = "8em";
const GridLayout = (header, description, link, icon) => {
return (
<Paper style={boxStyle}>
<a href={link} style={hrefStyle}>
<div style={{flex: "1", color: "#FFFFFF"}}>
<h2>{header}</h2>
</div>
<Divider />
<div style={{flex: "3", marginLeft: "10px", marginRight: "10px", marginTop: "10px", color: textColor}}>
{description}
</div>
<div style={{margin: "auto"}}>
{icon}
</div>
<Divider style={{marginTop: "20px", marginBottom: "20px"}} />
<div style={{flex: "1", color: "#f85a3e"}}>
<div style={{}} >
Learn more
</div>
</div>
</a>
</Paper>
)
}
const GridLayout = (header, description, link, icon) => {
return (
<Paper style={boxStyle}>
<a href={link} style={hrefStyle}>
<div style={{ flex: "1", color: "#FFFFFF" }}>
<h2>{header}</h2>
</div>
<Divider />
<div
style={{
flex: "3",
marginLeft: "10px",
marginRight: "10px",
marginTop: "10px",
color: textColor,
}}
>
{description}
</div>
<div style={{ margin: "auto" }}>{icon}</div>
<Divider style={{ marginTop: "20px", marginBottom: "20px" }} />
<div style={{ flex: "1", color: "#f85a3e" }}>
<div style={{}}>Learn more</div>
</div>
</a>
</Paper>
);
};
const listitems = [
GridLayout("Simple integrations", "Easily use others' or create your own integration", "/docs/features", <Web style={{fontSize: iconSize, marginTop: "20px", color: iconColor}} />),
GridLayout("Workflows", "Access the power of automation within minutes, whether its on premise or in the cloud", "/docs/features", <AccountTree style={{fontSize: iconSize, marginTop: "20px", color: iconColor}} />),
GridLayout("Realtime actions", "Beat the clock by leveraging our realtime triggers", "/docs/features", <ScheduleIcon style={{fontSize: iconSize, marginTop: "20px", color: iconColor}} />),
]
const listitems = [
GridLayout(
"Simple integrations",
"Easily use others' or create your own integration",
"/docs/features",
<Web
style={{ fontSize: iconSize, marginTop: "20px", color: iconColor }}
/>
),
GridLayout(
"Workflows",
"Access the power of automation within minutes, whether its on premise or in the cloud",
"/docs/features",
<AccountTree
style={{ fontSize: iconSize, marginTop: "20px", color: iconColor }}
/>
),
GridLayout(
"Realtime actions",
"Beat the clock by leveraging our realtime triggers",
"/docs/features",
<ScheduleIcon
style={{ fontSize: iconSize, marginTop: "20px", color: iconColor }}
/>
),
];
// The actual landing page
// <img style={{width: "400px"}} alt={"logo"} src={Default}/>
//We start by understanding your unique environment to help identify the right thing to automate.
const secondaryColor = "rgba(167,46,87,1)"
const primaryColor = "rgba(25, 35, 94, 1)"
// The actual landing page
// <img style={{width: "400px"}} alt={"logo"} src={Default}/>
//We start by understanding your unique environment to help identify the right thing to automate.
const secondaryColor = "rgba(167,46,87,1)";
const primaryColor = "rgba(25, 35, 94, 1)";
const paperStyle = {
flex: 1,
backgroundColor: "inherit",
cursor: "pointer",
}
const secondaryItemList = [
{
primaryText: "No time to waste",
secondaryText: "Bring all your applications into a single view, and make them all work together flawlessly!",
image: "/images/time.jpg",
}, {
primaryText: "Get a better overview",
secondaryText: "Don't know what's happening? We'll help you track and act on your most valuable KPI's!",
image: "/images/overview.jpg",
}, {
primaryText: "Conquer your tasks",
secondaryText: "Get access to powerful tools and pre-made workflows to help you crush your teams daily tasks!",
image: "/images/burnout.jpg",
},
]
const [image, setImage] = useState(secondaryItemList[0].image);
const paperStyle = {
flex: 1,
backgroundColor: "inherit",
cursor: "pointer",
};
const landingpageDataBrowser =
<div>
<div style={{backgroundImage: "url('/images/test.jpg')", backgroundSize: "80% 100%", backgroundRepeat: "no-repeat", minHeight: "100vh", maxHeight: 1024}}>
<div style={{textAlign: "left", paddingTop: 135, maxWidth: 700, paddingLeft: "50%", color: secondaryColor, display: "flex", fontSize: 25}}>
<div style={{flex: 1}}>
<a href="/docs/about" style={hrefStyle}>
<Grid container direction="row" alignItems="center">
<Grid item>
<InfoIcon />
</Grid>
<Grid item style={{marginLeft: 5}}>
About
</Grid>
</Grid>
</a>
</div>
<div style={{flex: 1}}>
<a href="/contact" style={hrefStyle}>
<Grid container direction="row" alignItems="center">
<Grid item>
<CreateIcon />
</Grid>
<Grid item style={{marginLeft: 5}}>
Get in touch
</Grid>
</Grid>
</a>
</div>
<div style={{flex: 1}}>
<a href="/login" style={hrefStyle}>
<Button
style={{borderRadius: 25, height: 50, minWidth: 200, backgroundColor: secondaryColor, color: "white"}} variant="contained">
Try it out <ArrowForwardIcon />
</Button>
</a>
</div>
</div>
<div style={bodyTextStyle, {textAlign: "left", paddingTop: "8%", paddingLeft: "28%", maxWidth: 430,}}>
<div style={{fontSize: 25, color:"rgba(0,0,0,0.45)"}}>
Shuffle
</div>
<div style={{fontSize: 50, color: "rgba(0,0,0,0.7)"}}>
INFORMATION <div style={{color: secondaryColor}}>OVERLOAD</div>
</div>
<div style={{fontSize: 20, color: "rgba(0, 0, 0, 0.45)", marginTop: 20,}}>
Everyone run into the same fundamental operational problems. Mailbox chaos, tickets getting out of hand and a constant feeling of being overwhelmed. The good news? <div style={{color: secondaryColor, marginTop: 10}}>Shuffle solves them.</div>
</div>
<a href="/docs/features" style={hrefStyle}>
<Button
style={{borderRadius: 25, height: 50, marginTop: 50, width: 200, backgroundColor: secondaryColor, color: "white"}}
variant="contained"
>Learn how</Button>
</a>
</div>
</div>
<div style={{minHeight: 1024, width: "100%", backgroundImage: "linear-gradient(to bottom right, #19235e, #19235e)",}}>
<div style={{minHeight: 1000, paddingTop: 150, maxWidth: 1250, margin: "auto"}}>
<div style={{color: "rgba(255,255,255,0.8", fontSize: 60, marginLeft: 25, }}>
<b>Automation is just the beginning </b>
</div>
<div style={{marginTop: 40, display: 'flex', flexDirection: "row"}}>
<div style={{flex: 8, display: "flex", flexDirection: "column", fontSize: 40, }}>
{secondaryItemList.map((data, index) => {
const color = image === data.image ? "rgba(255,255,255,1)" : "rgba(255,255,255,0.4)"
return (
<div style={{borderRadius: 15, padding: 25, maxWidth: 600, height: 150, fontSize: 40, color: color, cursor: "pointer"}} onClick={() => setImage(data.image)}>
{data.primaryText}
<div style={{fontSize: 22, marginTop: 10, }}>
{data.secondaryText}
</div>
</div>
)
})}
</div>
<div style={{flex: 1}} />
<div style={{flex: 10, height: "100%", width: "100%",}}>
<img src={image} style={{borderRadius: 15, minHeight: "100%", minWidth: "100%", maxWidth: "100%", maxHeight: "100%"}}/>
</div>
</div>
</div>
<div style={{maxWidth: 1250, paddingTop: 100, paddingBottom: 100, margin: "auto", color: "rgba(255,255,255,0.8)"}}>
<Divider style={{backgroundColor: "rgba(255,255,255,0.6)"}} />
<div style={{marginTop: 100, fontSize: 40, display: "flex", marginLeft: 100, marginRight: 100}}>
<div style={{flex: 3}}>
Learn more about the benefits of Shuffle
</div>
<div style={{flex: 1}}>
<a href="/docs/features" style={hrefStyle}>
<Button
fullWidth
style={{borderRadius: 25, minHeight: 50, minWidth: 200, backgroundColor: secondaryColor, color: "white"}} variant="contained">
See features
</Button>
</a>
</div>
</div>
</div>
</div>
<div style={{textAlign: "center", maxWidth: 1100, minHeight: 600, paddingTop: 100, margin: "auto", color: "rgba(0,0,0,1)"}}>
<div style={{fontSize: 50}}>
<b>Focus on the work that matters to you</b>
</div>
<div style={{fontSize: 20, color: "rgba(0,0,0,0.7)", maxWidth: "100%"}}>
Menial tasks, scattered content, constant copy pasting, waste of talent - <b>there's a smarter way to work.</b>
</div>
<div style={{display: "flex", marginTop: 50}}>
<Card onClick={() => {window.location.pathname = "/docs/features"}} style={{flex: 1, margin: 10, textAlign: "center"}}>
<CardActionArea>
<CardMedia
title="TEST"
image="/images/time.jpg"
/>
<CardContent>
<h3>Premade playbooks</h3>
<p>Get your automation done with minimal effort</p>
</CardContent>
</CardActionArea>
<Button size="medium" color="green">
Learn more
</Button>
</Card>
<Card onClick={() => {window.location.pathname = "/docs/features"}} style={{flex: 1, margin: 10, textAlign: "center"}}>
<CardActionArea>
<CardMedia
title="TEST"
image="/images/time.jpg"
/>
<CardContent>
<h3>Open frameworks</h3>
<p>Mitre Att&ck, OpenAPI and more!</p>
</CardContent>
</CardActionArea>
<Button size="medium" color="green">
Learn more
</Button>
</Card>
<Card onClick={() => {window.location.pathname = "/docs/features"}} style={{flex: 1, margin: 10, textAlign: "center"}}>
<CardActionArea>
<CardMedia
title="TEST"
image="/images/time.jpg"
/>
<CardContent>
<h3>Hundreds of integrations</h3>
<p>Quickly integrate your software applications</p>
</CardContent>
</CardActionArea>
<Button size="medium" color="green">
Learn more
</Button>
</Card>
<Card style={{flex: 1, margin: 10, textAlign: "center"}} onClick={() => {window.location.pathname = "/docs/features"}}>
<CardActionArea>
<CardMedia
title="TEST"
image="images/time.jpg"
/>
<CardContent>
<h3>Automated compliance</h3>
<p>Stuck with compliance needs you can't meet?</p>
</CardContent>
</CardActionArea>
<Button size="medium" color="green">
Learn more
</Button>
</Card>
</div>
</div>
</div>
const secondaryItemList = [
{
primaryText: "No time to waste",
secondaryText:
"Bring all your applications into a single view, and make them all work together flawlessly!",
image: "/images/time.jpg",
},
{
primaryText: "Get a better overview",
secondaryText:
"Don't know what's happening? We'll help you track and act on your most valuable KPI's!",
image: "/images/overview.jpg",
},
{
primaryText: "Conquer your tasks",
secondaryText:
"Get access to powerful tools and pre-made workflows to help you crush your teams daily tasks!",
image: "/images/burnout.jpg",
},
];
const [image, setImage] = useState(secondaryItemList[0].image);
const landingpageDataMobile =
<div style={{backgroundColor: "#1F2023", paddingTop: 30}}>
<div style={{color: "white", textAlign: "center", marginLeft: "10px", marginRight: "10px"}}>
<h1>Shuffle</h1>
<h3>A general automation solution for Infosec and IT Professionals</h3>
<a href="/contact" style={hrefStyle}>
<Button
style={{width: "220px", height: "60px", borderRadius: "0px"}}
variant="contained"
color="primary"
>
Contact
</Button>
</a>
</div>
<div style={{display: "flex", flexDirection: "column", marginTop: "100px"}}>
<div>
{listitems[0]}
</div>
<div style={{marginTop: "20px"}}>
{listitems[1]}
</div>
<div style={{marginTop: "20px", marginBottom: "30px"}}>
{listitems[2]}
</div>
<div style={{marginTop: "20px", marginBottom: "30px", textAlign: "center"}}>
<a href="/contact" style={hrefStyle}>
<Button
style={{width: "220px", height: "60px", borderRadius: "0px"}}
variant="contained"
color="primary"
>
Contact
</Button>
</a>
</div>
</div>
</div>
const landingpageDataBrowser = (
<div>
<div
style={{
backgroundImage: "url('/images/test.jpg')",
backgroundSize: "80% 100%",
backgroundRepeat: "no-repeat",
minHeight: "100vh",
maxHeight: 1024,
}}
>
<div
style={{
textAlign: "left",
paddingTop: 135,
maxWidth: 700,
paddingLeft: "50%",
color: secondaryColor,
display: "flex",
fontSize: 25,
}}
>
<div style={{ flex: 1 }}>
<a href="/docs/about" style={hrefStyle}>
<Grid container direction="row" alignItems="center">
<Grid item>
<InfoIcon />
</Grid>
<Grid item style={{ marginLeft: 5 }}>
About
</Grid>
</Grid>
</a>
</div>
<div style={{ flex: 1 }}>
<a href="/contact" style={hrefStyle}>
<Grid container direction="row" alignItems="center">
<Grid item>
<CreateIcon />
</Grid>
<Grid item style={{ marginLeft: 5 }}>
Get in touch
</Grid>
</Grid>
</a>
</div>
<div style={{ flex: 1 }}>
<a href="/login" style={hrefStyle}>
<Button
style={{
borderRadius: 25,
height: 50,
minWidth: 200,
backgroundColor: secondaryColor,
color: "white",
}}
variant="contained"
>
Try it out <ArrowForwardIcon />
</Button>
</a>
</div>
</div>
<div
style={
(bodyTextStyle,
{
textAlign: "left",
paddingTop: "8%",
paddingLeft: "28%",
maxWidth: 430,
})
}
>
<div style={{ fontSize: 25, color: "rgba(0,0,0,0.45)" }}>Shuffle</div>
<div style={{ fontSize: 50, color: "rgba(0,0,0,0.7)" }}>
INFORMATION <div style={{ color: secondaryColor }}>OVERLOAD</div>
</div>
<div
style={{
fontSize: 20,
color: "rgba(0, 0, 0, 0.45)",
marginTop: 20,
}}
>
Everyone run into the same fundamental operational problems. Mailbox
chaos, tickets getting out of hand and a constant feeling of being
overwhelmed. The good news?{" "}
<div style={{ color: secondaryColor, marginTop: 10 }}>
Shuffle solves them.
</div>
</div>
<a href="/docs/features" style={hrefStyle}>
<Button
style={{
borderRadius: 25,
height: 50,
marginTop: 50,
width: 200,
backgroundColor: secondaryColor,
color: "white",
}}
variant="contained"
>
Learn how
</Button>
</a>
</div>
</div>
<div
style={{
minHeight: 1024,
width: "100%",
backgroundImage: "linear-gradient(to bottom right, #19235e, #19235e)",
}}
>
<div
style={{
minHeight: 1000,
paddingTop: 150,
maxWidth: 1250,
margin: "auto",
}}
>
<div
style={{
color: "rgba(255,255,255,0.8",
fontSize: 60,
marginLeft: 25,
}}
>
<b>Automation is just the beginning </b>
</div>
<div style={{ marginTop: 40, display: "flex", flexDirection: "row" }}>
<div
style={{
flex: 8,
display: "flex",
flexDirection: "column",
fontSize: 40,
}}
>
{secondaryItemList.map((data, index) => {
const color =
image === data.image
? "rgba(255,255,255,1)"
: "rgba(255,255,255,0.4)";
return (
<div
style={{
borderRadius: 15,
padding: 25,
maxWidth: 600,
height: 150,
fontSize: 40,
color: color,
cursor: "pointer",
}}
onClick={() => setImage(data.image)}
>
{data.primaryText}
<div style={{ fontSize: 22, marginTop: 10 }}>
{data.secondaryText}
</div>
</div>
);
})}
</div>
<div style={{ flex: 1 }} />
<div style={{ flex: 10, height: "100%", width: "100%" }}>
<img
src={image}
style={{
borderRadius: 15,
minHeight: "100%",
minWidth: "100%",
maxWidth: "100%",
maxHeight: "100%",
}}
/>
</div>
</div>
</div>
<div
style={{
maxWidth: 1250,
paddingTop: 100,
paddingBottom: 100,
margin: "auto",
color: "rgba(255,255,255,0.8)",
}}
>
<Divider style={{ backgroundColor: "rgba(255,255,255,0.6)" }} />
<div
style={{
marginTop: 100,
fontSize: 40,
display: "flex",
marginLeft: 100,
marginRight: 100,
}}
>
<div style={{ flex: 3 }}>
Learn more about the benefits of Shuffle
</div>
<div style={{ flex: 1 }}>
<a href="/docs/features" style={hrefStyle}>
<Button
fullWidth
style={{
borderRadius: 25,
minHeight: 50,
minWidth: 200,
backgroundColor: secondaryColor,
color: "white",
}}
variant="contained"
>
See features
</Button>
</a>
</div>
</div>
</div>
</div>
<div
style={{
textAlign: "center",
maxWidth: 1100,
minHeight: 600,
paddingTop: 100,
margin: "auto",
color: "rgba(0,0,0,1)",
}}
>
<div style={{ fontSize: 50 }}>
<b>Focus on the work that matters to you</b>
</div>
<div
style={{ fontSize: 20, color: "rgba(0,0,0,0.7)", maxWidth: "100%" }}
>
Menial tasks, scattered content, constant copy pasting, waste of
talent - <b>there's a smarter way to work.</b>
</div>
<div style={{ display: "flex", marginTop: 50 }}>
<Card
onClick={() => {
window.location.pathname = "/docs/features";
}}
style={{ flex: 1, margin: 10, textAlign: "center" }}
>
<CardActionArea>
<CardMedia title="TEST" image="/images/time.jpg" />
<CardContent>
<h3>Premade playbooks</h3>
<p>Get your automation done with minimal effort</p>
</CardContent>
</CardActionArea>
<Button size="medium" color="green">
Learn more
</Button>
</Card>
<Card
onClick={() => {
window.location.pathname = "/docs/features";
}}
style={{ flex: 1, margin: 10, textAlign: "center" }}
>
<CardActionArea>
<CardMedia title="TEST" image="/images/time.jpg" />
<CardContent>
<h3>Open frameworks</h3>
<p>Mitre Att&ck, OpenAPI and more!</p>
</CardContent>
</CardActionArea>
<Button size="medium" color="green">
Learn more
</Button>
</Card>
<Card
onClick={() => {
window.location.pathname = "/docs/features";
}}
style={{ flex: 1, margin: 10, textAlign: "center" }}
>
<CardActionArea>
<CardMedia title="TEST" image="/images/time.jpg" />
<CardContent>
<h3>Hundreds of integrations</h3>
<p>Quickly integrate your software applications</p>
</CardContent>
</CardActionArea>
<Button size="medium" color="green">
Learn more
</Button>
</Card>
<Card
style={{ flex: 1, margin: 10, textAlign: "center" }}
onClick={() => {
window.location.pathname = "/docs/features";
}}
>
<CardActionArea>
<CardMedia title="TEST" image="images/time.jpg" />
<CardContent>
<h3>Automated compliance</h3>
<p>Stuck with compliance needs you can't meet?</p>
</CardContent>
</CardActionArea>
<Button size="medium" color="green">
Learn more
</Button>
</Card>
</div>
</div>
</div>
);
const landingpageDataMobile = (
<div style={{ backgroundColor: "#1F2023", paddingTop: 30 }}>
<div
style={{
color: "white",
textAlign: "center",
marginLeft: "10px",
marginRight: "10px",
}}
>
<h1>Shuffle</h1>
<h3>A general automation solution for Infosec and IT Professionals</h3>
<a href="/contact" style={hrefStyle}>
<Button
style={{ width: "220px", height: "60px", borderRadius: "0px" }}
variant="contained"
color="primary"
>
Contact
</Button>
</a>
</div>
<div
style={{ display: "flex", flexDirection: "column", marginTop: "100px" }}
>
<div>{listitems[0]}</div>
<div style={{ marginTop: "20px" }}>{listitems[1]}</div>
<div style={{ marginTop: "20px", marginBottom: "30px" }}>
{listitems[2]}
</div>
<div
style={{
marginTop: "20px",
marginBottom: "30px",
textAlign: "center",
}}
>
<a href="/contact" style={hrefStyle}>
<Button
style={{ width: "220px", height: "60px", borderRadius: "0px" }}
variant="contained"
color="primary"
>
Contact
</Button>
</a>
</div>
</div>
</div>
);
// Reroute if the user is logged in
// const landingSite = isLoggedIn ? <Workflows globalUrl={globalUrl}{...props} /> : <div style={bodyDivStyle}>{landingpageData}</div>
const landingSite = <div style={bodyDivStyle}>{landingpageDataBrowser}</div>
// Reroute if the user is logged in
// const landingSite = isLoggedIn ? <Workflows globalUrl={globalUrl}{...props} /> : <div style={bodyDivStyle}>{landingpageData}</div>
const landingSite = <div style={bodyDivStyle}>{landingpageDataBrowser}</div>;
const loadedCheck = isLoaded ?
<div>
<BrowserView>
{landingSite}
</BrowserView>
<MobileView>
{landingpageDataMobile}
</MobileView>
</div>
:
<div>
</div>
const loadedCheck = isLoaded ? (
<div>
<BrowserView>{landingSite}</BrowserView>
<MobileView>{landingpageDataMobile}</MobileView>
</div>
) : (
<div></div>
);
return(
<div>
{loadedCheck}
</div>
)
}
return <div>{loadedCheck}</div>;
};
export default LandingPage;
+446 -347
View File
@@ -1,391 +1,490 @@
/* eslint-disable react/no-multi-comp */
import React, { useState } from 'react';
import { makeStyles } from '@material-ui/styles';
import { useInterval } from 'react-powerhooks';
import {CircularProgress, TextField, Button, Paper, Typography} from '@material-ui/core'
import { useTheme } from '@material-ui/core/styles';
import React, { useState } from "react";
import { makeStyles } from "@material-ui/styles";
import { useInterval } from "react-powerhooks";
import {
CircularProgress,
TextField,
Button,
Paper,
Typography,
} from "@material-ui/core";
import { useTheme } from "@material-ui/core/styles";
const hrefStyle = {
color: "white",
textDecoration: "none"
}
color: "white",
textDecoration: "none",
};
const bodyDivStyle = {
margin: "auto",
marginTop: 150,
width: "500px",
}
margin: "auto",
marginTop: 150,
width: "500px",
};
const useStyles = makeStyles({
notchedOutline: {
borderColor: "#f85a3e !important"
},
notchedOutline: {
borderColor: "#f85a3e !important",
},
});
const LoginDialog = props => {
const theme = useTheme();
const LoginDialog = (props) => {
const theme = useTheme();
const { globalUrl, isLoaded, isLoggedIn, setIsLoggedIn, setCookie, register, checkLogin } = props;
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [firstRequest, setFirstRequest] = useState(true);
const {
globalUrl,
isLoaded,
isLoggedIn,
setIsLoggedIn,
setCookie,
register,
checkLogin,
} = props;
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [firstRequest, setFirstRequest] = useState(true);
const [loginLoading, setLoginLoading] = useState(false);
const [loginViewLoading, setLoginViewLoading] = useState(false);
const [ssoUrl, setSSOUrl] = useState("")
const [ssoUrl, setSSOUrl] = useState("");
const [MFAField, setMFAField] = useState(false);
const [MFAValue, setMFAValue] = useState("");
// Used to swap from login to register. True = login, false = register
// Used to swap from login to register. True = login, false = register
const classes = useStyles();
// Error messages etc
const [loginInfo, setLoginInfo] = useState("");
const classes = useStyles();
// Error messages etc
const [loginInfo, setLoginInfo] = useState("");
const handleValidateForm = () => {
return (username.length > 1 && password.length > 1);
}
const handleValidateForm = () => {
return username.length > 1 && password.length > 1;
};
if (isLoggedIn === true) {
window.location.pathname = "/workflows"
}
if (isLoggedIn === true) {
window.location.pathname = "/workflows";
}
const checkAdmin = () => {
const url = globalUrl + '/api/v1/checkusers';
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.then(response =>
response.json().then(responseJson => {
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"])
} else {
if (responseJson.sso_url !== undefined && responseJson.sso_url !== null) {
setSSOUrl(responseJson.sso_url)
}
const checkAdmin = () => {
const url = globalUrl + "/api/v1/checkusers";
fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((response) =>
response.json().then((responseJson) => {
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"]);
} else {
if (
responseJson.sso_url !== undefined &&
responseJson.sso_url !== null
) {
setSSOUrl(responseJson.sso_url);
}
if (loginViewLoading) {
setLoginViewLoading(false)
checkLogin()
stop()
if (loginViewLoading) {
setLoginViewLoading(false);
checkLogin();
stop();
if (responseJson.reason !== undefined && responseJson.reason !== null) {
setLoginInfo(responseJson.reason)
}
}
if (
responseJson.reason !== undefined &&
responseJson.reason !== null
) {
setLoginInfo(responseJson.reason);
}
}
if (responseJson.reason === "stay") {
window.location.pathname = "/adminsetup"
}
}
}),
)
.catch(error => {
if (!loginViewLoading) {
setLoginViewLoading(true)
start()
}
})
}
if (responseJson.reason === "stay") {
window.location.pathname = "/adminsetup";
}
}
})
)
.catch((error) => {
if (!loginViewLoading) {
setLoginViewLoading(true);
start();
}
});
};
const { start, stop } = useInterval({
duration: 3000,
startImmediate: false,
callback: () => {
checkAdmin()
}
})
const { start, stop } = useInterval({
duration: 3000,
startImmediate: false,
callback: () => {
checkAdmin();
},
});
if (firstRequest) {
setFirstRequest(false)
checkAdmin()
}
if (firstRequest) {
setFirstRequest(false);
checkAdmin();
}
const onSubmit = (e) => {
setLoginLoading(true)
e.preventDefault()
setLoginInfo("")
// FIXME - add some check here ROFL
const onSubmit = (e) => {
setLoginLoading(true);
e.preventDefault();
setLoginInfo("");
// FIXME - add some check here ROFL
// Just use this one?
var data = {"username": username, "password": password}
if (MFAValue !== undefined && MFAValue !== null && MFAValue.length > 0) {
data["mfa_code"] = MFAValue
}
// Just use this one?
var data = { username: username, password: password };
if (MFAValue !== undefined && MFAValue !== null && MFAValue.length > 0) {
data["mfa_code"] = MFAValue;
}
var baseurl = globalUrl
if (register) {
var url = baseurl + '/api/v1/users/login';
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 => {
setLoginLoading(false)
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"])
} else {
if (responseJson["reason"] === "MFA_REDIRECT") {
setLoginInfo("MFA required. Please the 6-digit code from your authenticator")
setMFAField(true)
return
}
var baseurl = globalUrl;
if (register) {
var url = baseurl + "/api/v1/users/login";
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) => {
setLoginLoading(false);
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"]);
} else {
if (responseJson["reason"] === "MFA_REDIRECT") {
setLoginInfo(
"MFA required. Please the 6-digit code from your authenticator"
);
setMFAField(true);
return;
}
setLoginInfo("Successful login, rerouting")
for (var key in responseJson["cookies"]) {
setCookie(responseJson["cookies"][key].key, responseJson["cookies"][key].value, { path: "/" })
}
setLoginInfo("Successful login, rerouting");
for (var key in responseJson["cookies"]) {
setCookie(
responseJson["cookies"][key].key,
responseJson["cookies"][key].value,
{ path: "/" }
);
}
setIsLoggedIn(true)
setIsLoggedIn(true);
window.location.pathname = "/workflows"
}
}),
)
.catch(error => {
setLoginLoading(false)
setLoginInfo("Error logging in: " + error)
});
} else {
url = baseurl + '/api/v1/users/register';
fetch(url, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
},
})
.then(response =>
response.json().then(responseJson => {
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"])
} else {
setLoginInfo("Successful register!")
}
}),
)
.catch(error => {
setLoginInfo("Error in from backend: ", error)
});
}
}
window.location.pathname = "/workflows";
}
})
)
.catch((error) => {
setLoginLoading(false);
setLoginInfo("Error logging in: " + error);
});
} else {
url = baseurl + "/api/v1/users/register";
fetch(url, {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
},
})
.then((response) =>
response.json().then((responseJson) => {
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"]);
} else {
setLoginInfo("Successful register!");
}
})
)
.catch((error) => {
setLoginInfo("Error in from backend: ", error);
});
}
};
const onChangeUser = (e) => {
setUsername(e.target.value)
}
const onChangeUser = (e) => {
setUsername(e.target.value);
};
const onChangePass = (e) => {
setPassword(e.target.value)
}
const onChangePass = (e) => {
setPassword(e.target.value);
};
//const onClickRegister = () => {
// if (props.location.pathname === "/login") {
// window.location.pathname = "/register"
// } else {
// window.location.pathname = "/login"
// }
//const onClickRegister = () => {
// if (props.location.pathname === "/login") {
// window.location.pathname = "/register"
// } else {
// window.location.pathname = "/login"
// }
// setLoginCheck(!register)
//}
// setLoginCheck(!register)
//}
//var loginChange = register ? (<div><p onClick={setLoginCheck(false)}>Want to register? Click here.</p></div>) : (<div><p onClick={setLoginCheck(true)}>Go back to login? Click here.</p></div>);
var formtitle = register ? <div>Login</div> : <div>Register</div>
const imgsize = 100
const basedata =
<div style={bodyDivStyle}>
<Paper style={{
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
position: "relative",
backgroundColor: theme.palette.surfaceColor,
}}>
<div style={{position: "absolute", top: -imgsize/2-10, left: 250-imgsize/2, height: imgsize, width: imgsize, }}>
<img src="images/Shuffle_logo.png" style={{height: imgsize+10, width: imgsize+10, border: "2px solid rgba(255,255,255,0.6)", borderRadius: imgsize,}}/>
</div>
{loginViewLoading ?
<div style={{textAlign: "center", marginTop: 50, }}>
<Typography variant="body2" style={{marginBottom: 20, color: "white",}}>
Waiting for the Shuffle database to become available. This may take up to a minute.
</Typography>
//var loginChange = register ? (<div><p onClick={setLoginCheck(false)}>Want to register? Click here.</p></div>) : (<div><p onClick={setLoginCheck(true)}>Go back to login? Click here.</p></div>);
var formtitle = register ? <div>Login</div> : <div>Register</div>;
const imgsize = 100;
const basedata = (
<div style={bodyDivStyle}>
<Paper
style={{
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
position: "relative",
backgroundColor: theme.palette.surfaceColor,
}}
>
<div
style={{
position: "absolute",
top: -imgsize / 2 - 10,
left: 250 - imgsize / 2,
height: imgsize,
width: imgsize,
}}
>
<img
src="images/Shuffle_logo.png"
style={{
height: imgsize + 10,
width: imgsize + 10,
border: "2px solid rgba(255,255,255,0.6)",
borderRadius: imgsize,
}}
/>
</div>
{loginViewLoading ? (
<div style={{ textAlign: "center", marginTop: 50 }}>
<Typography
variant="body2"
style={{ marginBottom: 20, color: "white" }}
>
Waiting for the Shuffle database to become available. This may
take up to a minute.
</Typography>
{loginInfo === undefined || loginInfo === null || loginInfo.length === 0 ?
null
:
<div style={{ marginTop: "10px" }}>
Response: {loginInfo}
</div>
}
<CircularProgress color="secondary" style={{color: "white",}} />
{loginInfo === undefined ||
loginInfo === null ||
loginInfo.length === 0 ? null : (
<div style={{ marginTop: "10px" }}>Response: {loginInfo}</div>
)}
<CircularProgress color="secondary" style={{ color: "white" }} />
<Paper
style={{
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
position: "relative",
backgroundColor: theme.palette.inputColor,
textAlign: "left",
marginTop: 15,
}}
>
<Typography
variant="body2"
style={{ marginBottom: 20, color: "white" }}
>
<b>
Are you sure Shuffle is{" "}
<a
rel="norefferer"
target="_blank"
href="https://github.com/frikky/Shuffle/blob/master/.github/install-guide.md"
style={{ textDecoration: "none", color: "#f86a3e" }}
>
installed correctly
</a>
?
</b>
</Typography>
<Typography
variant="body2"
style={{ marginBottom: 20, color: "white" }}
>
<b>1.</b> Make sure shuffle-database folder has correct access:{" "}
<br />
<br />
sudo chown 1000:1000 -R shuffle-database
</Typography>
<Paper style={{
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
position: "relative",
backgroundColor: theme.palette.inputColor,
textAlign: "left",
marginTop: 15,
}}>
<Typography variant="body2" style={{marginBottom: 20, color: "white",}}>
<b>Are you sure Shuffle is <a rel="norefferer" target="_blank" href="https://github.com/frikky/Shuffle/blob/master/.github/install-guide.md" style={{textDecoration: "none", color: "#f86a3e"}}>installed correctly</a>?</b>
</Typography>
<Typography variant="body2" style={{marginBottom: 20, color: "white",}}>
<b>1.</b> Make sure shuffle-database folder has correct access: <br/><br/>
sudo chown 1000:1000 -R shuffle-database
</Typography>
<Typography
variant="body2"
style={{ marginBottom: 20, color: "white" }}
>
<b>2</b>. Restart docker-compose:
<br />
<br />
sudo docker-compose restart
</Typography>
</Paper>
<Typography
variant="body2"
style={{ marginBottom: 10, color: "white", marginTop: 20 }}
>
Need help?{" "}
<a
rel="norefferer"
target="_blank"
href="https://discord.gg/B2CBzUm"
style={{ textDecoration: "none", color: "#f86a3e" }}
>
Join the Discord!
</a>
</Typography>
</div>
) : (
<form
onSubmit={onSubmit}
style={{ margin: "15px 15px 15px 15px", color: "white" }}
>
<h2>{formtitle}</h2>
Username
<div>
<TextField
color="primary"
style={{
backgroundColor: theme.palette.inputColor,
marginTop: 5,
}}
autoFocus
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
fullWidth={true}
autoComplete="username"
placeholder="username@example.com"
id="emailfield"
margin="normal"
variant="outlined"
onChange={onChangeUser}
/>
</div>
Password
<div>
<TextField
color="primary"
style={{
backgroundColor: theme.palette.inputColor,
marginTop: 5,
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
id="outlined-password-input"
fullWidth={true}
type="password"
autoComplete="current-password"
placeholder="**********"
margin="normal"
variant="outlined"
onChange={onChangePass}
/>
</div>
{MFAField === true ? (
<div style={{ marginTop: 15 }}>
5-factor code
<TextField
color="primary"
style={{
backgroundColor: theme.palette.inputColor,
marginTop: 5,
}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
id="outlined-password-input"
fullWidth={true}
type="text"
placeholder="6-digit code"
margin="normal"
variant="outlined"
onChange={(event) => {
setMFAValue(event.target.value);
}}
/>
</div>
) : null}
<div style={{ display: "flex", marginTop: "15px" }}>
<Button
color="primary"
variant="contained"
type="submit"
style={{ flex: "1" }}
disabled={!handleValidateForm() || loginLoading}
>
{loginLoading ? (
<CircularProgress
color="secondary"
style={{ color: "white" }}
/>
) : (
"SUBMIT"
)}
</Button>
</div>
<div style={{ marginTop: "10px" }}>{loginInfo}</div>
{ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length > 0 ? (
<div>
<Typography style={{ textAlign: "center" }}>Or</Typography>
<div style={{ textAlign: "center", margin: 10 }}>
<Button
fullWidth
color="secondary"
variant="outlined"
type="button"
style={{ flex: "1", marginTop: 5 }}
onClick={() => {
console.log("CLICK");
window.location = ssoUrl;
}}
>
Use SSO
</Button>
</div>
</div>
) : null}
</form>
)}
</Paper>
</div>
);
<Typography variant="body2" style={{marginBottom: 20, color: "white",}}>
<b>2</b>. Restart docker-compose:<br/><br/>
sudo docker-compose restart
</Typography>
</Paper>
<Typography variant="body2" style={{marginBottom: 10, color: "white", marginTop: 20, }}>
Need help? <a rel="norefferer" target="_blank" href="https://discord.gg/B2CBzUm" style={{textDecoration: "none", color: "#f86a3e"}}>Join the Discord!</a>
</Typography>
</div>
:
<form onSubmit={onSubmit} style={{ margin: "15px 15px 15px 15px", color: "white", }}>
<h2>{formtitle}</h2>
Username
<div>
<TextField
color="primary"
style={{ backgroundColor: theme.palette.inputColor, marginTop: 5, }}
autoFocus
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
fullWidth={true}
autoComplete="username"
placeholder="username@example.com"
id="emailfield"
margin="normal"
variant="outlined"
onChange={onChangeUser}
/>
</div>
Password
<div>
<TextField
color="primary"
style={{ backgroundColor: theme.palette.inputColor, marginTop: 5,}}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
id="outlined-password-input"
fullWidth={true}
type="password"
autoComplete="current-password"
placeholder="**********"
margin="normal"
variant="outlined"
onChange={onChangePass}
/>
</div>
{MFAField === true ?
<div style={{marginTop: 15}}>
5-factor code
<TextField
color="primary"
style={{backgroundColor: theme.palette.inputColor, marginTop: 5, }}
InputProps={{
classes: {
notchedOutline: classes.notchedOutline,
},
style:{
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
id="outlined-password-input"
fullWidth={true}
type="text"
placeholder="6-digit code"
margin="normal"
variant="outlined"
onChange={(event) => {
setMFAValue(event.target.value)
}}
/>
</div>
: null}
<div style={{ display: "flex", marginTop: "15px" }}>
<Button color="primary" variant="contained" type="submit" style={{ flex: "1", }} disabled={!handleValidateForm() || loginLoading}>
{loginLoading ? <CircularProgress color="secondary" style={{color: "white",}} /> : "SUBMIT"}
</Button>
</div>
<div style={{ marginTop: "10px" }}>
{loginInfo}
</div>
{ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length > 0 ?
<div>
<Typography style={{textAlign: "center", }}>
Or
</Typography>
<div style={{textAlign: "center", margin: 10, }}>
<Button fullWidth color="secondary" variant="outlined" type="button" style={{ flex: "1", marginTop: 5}} onClick={() => {
console.log("CLICK")
window.location = ssoUrl
}}>
Use SSO
</Button>
</div>
</div>
: null}
</form>
}
</Paper>
</div>
const loadedCheck = isLoaded ? <div>{basedata}</div> : <div></div>;
const loadedCheck = isLoaded ?
<div>
{basedata}
</div>
:
<div>
</div>
return (
<div>
{loadedCheck}
</div>
)
}
return <div>{loadedCheck}</div>;
};
export default LoginDialog;
+1978 -1515
View File
File diff suppressed because it is too large Load Diff
+4 -8
View File
@@ -1,11 +1,7 @@
import React, { } from 'react';
import React from "react";
const Oauth2 = (props) => {
return (
<div>
tmp
</div>
)
}
return <div>tmp</div>;
};
export default Oauth2;
export default Oauth2;
+47 -58
View File
@@ -1,72 +1,61 @@
import React from 'react';
import React from "react";
const Body = {
maxWidth: '1000px',
minWidth: '768px',
margin: 'auto',
display: "flex",
heigth: "100%",
color: "white",
//textAlign: "center",
maxWidth: "1000px",
minWidth: "768px",
margin: "auto",
display: "flex",
heigth: "100%",
color: "white",
//textAlign: "center",
};
const SideBar = {
maxWidth: "250px",
flex: "1",
}
maxWidth: "250px",
flex: "1",
};
const hrefStyle = {
color: "#385f71",
textDecoration: "none"
}
color: "#385f71",
textDecoration: "none",
};
const Post = (props) => {
const { currentPost, isLoaded } = props;
const { currentPost, isLoaded } = props;
const postData =
<div style={Body}>
<div style={SideBar}>
<ul style={{listStyle: "none", paddingLeft: "0"}}>
<li style={{marginTop: "10px"}}>
<a style={hrefStyle} href="/">
<h2>Home</h2>
</a>
</li>
<li style={{marginTop: "10px"}}>
<a style={hrefStyle} href="/docs">
<h2>Schedules</h2>
</a>
</li>
<li style={{marginTop: "10px"}}>
<a style={hrefStyle} href="/docs/about">
<h2>About</h2>
</a>
</li>
<li style={{marginTop: "10px"}}>
<a style={hrefStyle} href="/docs/privacy-policy">
<h2>Privacy Policy</h2>
</a>
</li>
</ul>
</div>
<div style={{flex: "1"}}>
{currentPost}
</div>
</div>
const postData = (
<div style={Body}>
<div style={SideBar}>
<ul style={{ listStyle: "none", paddingLeft: "0" }}>
<li style={{ marginTop: "10px" }}>
<a style={hrefStyle} href="/">
<h2>Home</h2>
</a>
</li>
<li style={{ marginTop: "10px" }}>
<a style={hrefStyle} href="/docs">
<h2>Schedules</h2>
</a>
</li>
<li style={{ marginTop: "10px" }}>
<a style={hrefStyle} href="/docs/about">
<h2>About</h2>
</a>
</li>
<li style={{ marginTop: "10px" }}>
<a style={hrefStyle} href="/docs/privacy-policy">
<h2>Privacy Policy</h2>
</a>
</li>
</ul>
</div>
<div style={{ flex: "1" }}>{currentPost}</div>
</div>
);
const loadedCheck = isLoaded ?
<div>
{postData}
</div>
:
<div>
</div>
const loadedCheck = isLoaded ? <div>{postData}</div> : <div></div>;
return (
<div>
{loadedCheck}
</div>
)
}
return <div>{loadedCheck}</div>;
};
export default Post;
+260 -118
View File
@@ -1,122 +1,264 @@
import React from 'react';
import React from "react";
const PrivacyPolicy = () => {
return (
<div>
<h1>Privacy Policy</h1>
<p>Effective date: 17.08.2019</p>
<p>We operate the shuffler.io website.</p>
<p>This page informs you of our policies regarding the collection, use, and disclosure of personal data when you use our service and the choices you have associated with that data.</p>
<p>We use your data to provide and improve the service. By using the service, you agree to the collection and use of information in accordance with this policy. Unless otherwise defined in this Privacy Policy, terms used in this Privacy Policy have the same meanings as in our Terms and Conditions, accessible from shuffler.io</p>
<h2>Information Collection And Use</h2>
<p>We collect several different types of information for various purposes to provide and improve our service to you.</p>
<h3>Types of Data Collected</h3>
<h4>Personal Data</h4>
<p>While using our service, we may ask you to provide us with certain personally identifiable information that can be used to contact or identify you ("Personal Data"). Personally identifiable information may include, but is not limited to:</p>
<ul>
<li>Cookies and Usage Data</li>
</ul>
<h4>Usage Data</h4>
<p>We may also collect information how the service is accessed and used ("Usage Data"). This Usage Data may include information such as your computer's Internet Protocol address (e.g. IP address), browser type, browser version, the pages of our service that you visit, the time and date of your visit, the time spent on those pages, unique device identifiers and other diagnostic data.</p>
<h4>Tracking & Cookies Data</h4>
<p>We use cookies and similar tracking technologies to track the activity on our service and hold certain information.</p>
<p>Cookies are files with small amount of data which may include an anonymous unique identifier. Cookies are sent to your browser from a website and stored on your device. Tracking technologies also used are beacons, tags, and scripts to collect and track information and to improve and analyze our service.</p>
<p>You can instruct your browser to refuse all cookies or to indicate when a cookie is being sent. However, if you do not accept cookies, you may not be able to use some portions of our service.</p>
<p>Examples of Cookies we use:</p>
<ul>
<li><strong>Session Cookies.</strong> We use Session Cookies to operate our service.</li>
<li><strong>Preference Cookies.</strong> We use Preference Cookies to remember your preferences and various settings.</li>
<li><strong>Security Cookies.</strong> We use Security Cookies for security purposes.</li>
</ul>
<h2>Use of Data</h2>
<p>Shuffler uses the collected data for various purposes:</p>
<ul>
<li>To provide and maintain the service</li>
<li>To notify you about changes to our service</li>
<li>To allow you to participate in interactive features of our service when you choose to do so</li>
<li>To provide customer care and support</li>
<li>To provide analysis or valuable information so that we can improve the service</li>
<li>To monitor the usage of the service</li>
<li>To detect, prevent and address technical issues</li>
</ul>
<h2>Transfer Of Data</h2>
<p>Your information, including Personal Data, may be transferred to — and maintained on — computers located outside of your state, province, country or other governmental jurisdiction where the data protection laws may differ than those from your jurisdiction.</p>
<p>If you are located outside Norway and choose to provide information to us, please note that we transfer the data, including Personal Data, to Norway and process it there.</p>
<p>Your consent to this Privacy Policy followed by your submission of such information represents your agreement to that transfer.</p>
<p>Shuffler will take all steps reasonably necessary to ensure that your data is treated securely and in accordance with this Privacy Policy and no transfer of your Personal Data will take place to an organization or a country unless there are adequate controls in place including the security of your data and other personal information.</p>
<h2>Disclosure Of Data</h2>
<h3>Legal Requirements</h3>
<p>Shuffler may disclose your Personal Data in the good faith belief that such action is necessary to:</p>
<ul>
<li>To comply with a legal obligation</li>
<li>To protect and defend the rights or property of Shuffler</li>
<li>To prevent or investigate possible wrongdoing in connection with the service</li>
<li>To protect the personal safety of users of the service or the public</li>
<li>To protect against legal liability</li>
</ul>
<h2>Security Of Data</h2>
<p>The security of your data is important to us, but remember that no method of transmission over the Internet, or method of electronic storage is 100% secure. While we strive to use commercially acceptable means to protect your Personal Data, we cannot guarantee its absolute security.</p>
<h2>Service Providers</h2>
<p>We may employ third party companies and individuals to facilitate our service ("service Providers"), to provide the service on our behalf, to perform service-related services or to assist us in analyzing how our service is used.</p>
<p>These third parties have access to your Personal Data only to perform these tasks on our behalf and are obligated not to disclose or use it for any other purpose.</p>
<h3>Analytics</h3>
<p>We may use third-party service Providers to monitor and analyze the use of our service.</p>
<ul>
<li>
<p><strong>Google Analytics</strong></p>
<p>Google Analytics is a web analytics service offered by Google that tracks and reports website traffic. Google uses the data collected to track and monitor the use of our service. This data is shared with other Google services. Google may use the collected data to contextualize and personalize the ads of its own advertising network.</p>
<p>You can opt-out of having made your activity on the service available to Google Analytics by installing the Google Analytics opt-out browser add-on. The add-on prevents the Google Analytics JavaScript (ga.js, analytics.js, and dc.js) from sharing information with Google Analytics about visits activity.</p> <p>For more information on the privacy practices of Google, please visit the Google Privacy & Terms web page: <a href="https://policies.google.com/privacy?hl=en">https://policies.google.com/privacy?hl=en</a></p>
</li>
</ul>
<h2>Links To Other Sites</h2>
<p>Our service may contain links to other sites that are not operated by us. If you click on a third party link, you will be directed to that third party's site. We strongly advise you to review the Privacy Policy of every site you visit.</p>
<p>We have no control over and assume no responsibility for the content, privacy policies or practices of any third party sites or services.</p>
<h2>Children's Privacy</h2>
<p>Our service does not address anyone under the age of 18 ("Children").</p>
<p>We do not knowingly collect personally identifiable information from anyone under the age of 18. If you are a parent or guardian and you are aware that your Children has provided us with Personal Data, please contact us. If we become aware that we have collected Personal Data from children without verification of parental consent, we take steps to remove that information from our servers.</p>
<h2>Changes To This Privacy Policy</h2>
<p>We may update our Privacy Policy from time to time. We will notify you of any changes by posting the new Privacy Policy on this page.</p>
<p>We will let you know via email and/or a prominent notice on our service, prior to the change becoming effective and update the "effective date" at the top of this Privacy Policy.</p>
<p>You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy Policy are effective when they are posted on this page.</p>
<h2>Contact Us</h2>
<p>If you have any questions about this Privacy Policy, please contact us:</p>
<ul>
<li>By email: fredrik_9490@hotmail.com</li>
</ul>
</div>
)
}
return (
<div>
<h1>Privacy Policy</h1>
<p>Effective date: 17.08.2019</p>
<p>We operate the shuffler.io website.</p>
<p>
This page informs you of our policies regarding the collection, use, and
disclosure of personal data when you use our service and the choices you
have associated with that data.
</p>
<p>
We use your data to provide and improve the service. By using the
service, you agree to the collection and use of information in
accordance with this policy. Unless otherwise defined in this Privacy
Policy, terms used in this Privacy Policy have the same meanings as in
our Terms and Conditions, accessible from shuffler.io
</p>
<h2>Information Collection And Use</h2>
<p>
We collect several different types of information for various purposes
to provide and improve our service to you.
</p>
<h3>Types of Data Collected</h3>
<h4>Personal Data</h4>
<p>
While using our service, we may ask you to provide us with certain
personally identifiable information that can be used to contact or
identify you ("Personal Data"). Personally identifiable information may
include, but is not limited to:
</p>
<ul>
<li>Cookies and Usage Data</li>
</ul>
<h4>Usage Data</h4>
<p>
We may also collect information how the service is accessed and used
("Usage Data"). This Usage Data may include information such as your
computer's Internet Protocol address (e.g. IP address), browser type,
browser version, the pages of our service that you visit, the time and
date of your visit, the time spent on those pages, unique device
identifiers and other diagnostic data.
</p>
<h4>Tracking & Cookies Data</h4>
<p>
We use cookies and similar tracking technologies to track the activity
on our service and hold certain information.
</p>
<p>
Cookies are files with small amount of data which may include an
anonymous unique identifier. Cookies are sent to your browser from a
website and stored on your device. Tracking technologies also used are
beacons, tags, and scripts to collect and track information and to
improve and analyze our service.
</p>
<p>
You can instruct your browser to refuse all cookies or to indicate when
a cookie is being sent. However, if you do not accept cookies, you may
not be able to use some portions of our service.
</p>
<p>Examples of Cookies we use:</p>
<ul>
<li>
<strong>Session Cookies.</strong> We use Session Cookies to operate
our service.
</li>
<li>
<strong>Preference Cookies.</strong> We use Preference Cookies to
remember your preferences and various settings.
</li>
<li>
<strong>Security Cookies.</strong> We use Security Cookies for
security purposes.
</li>
</ul>
<h2>Use of Data</h2>
<p>Shuffler uses the collected data for various purposes:</p>
<ul>
<li>To provide and maintain the service</li>
<li>To notify you about changes to our service</li>
<li>
To allow you to participate in interactive features of our service
when you choose to do so
</li>
<li>To provide customer care and support</li>
<li>
To provide analysis or valuable information so that we can improve the
service
</li>
<li>To monitor the usage of the service</li>
<li>To detect, prevent and address technical issues</li>
</ul>
<h2>Transfer Of Data</h2>
<p>
Your information, including Personal Data, may be transferred to — and
maintained on — computers located outside of your state, province,
country or other governmental jurisdiction where the data protection
laws may differ than those from your jurisdiction.
</p>
<p>
If you are located outside Norway and choose to provide information to
us, please note that we transfer the data, including Personal Data, to
Norway and process it there.
</p>
<p>
Your consent to this Privacy Policy followed by your submission of such
information represents your agreement to that transfer.
</p>
<p>
Shuffler will take all steps reasonably necessary to ensure that your
data is treated securely and in accordance with this Privacy Policy and
no transfer of your Personal Data will take place to an organization or
a country unless there are adequate controls in place including the
security of your data and other personal information.
</p>
<h2>Disclosure Of Data</h2>
<h3>Legal Requirements</h3>
<p>
Shuffler may disclose your Personal Data in the good faith belief that
such action is necessary to:
</p>
<ul>
<li>To comply with a legal obligation</li>
<li>To protect and defend the rights or property of Shuffler</li>
<li>
To prevent or investigate possible wrongdoing in connection with the
service
</li>
<li>
To protect the personal safety of users of the service or the public
</li>
<li>To protect against legal liability</li>
</ul>
<h2>Security Of Data</h2>
<p>
The security of your data is important to us, but remember that no
method of transmission over the Internet, or method of electronic
storage is 100% secure. While we strive to use commercially acceptable
means to protect your Personal Data, we cannot guarantee its absolute
security.
</p>
<h2>Service Providers</h2>
<p>
We may employ third party companies and individuals to facilitate our
service ("service Providers"), to provide the service on our behalf, to
perform service-related services or to assist us in analyzing how our
service is used.
</p>
<p>
These third parties have access to your Personal Data only to perform
these tasks on our behalf and are obligated not to disclose or use it
for any other purpose.
</p>
<h3>Analytics</h3>
<p>
We may use third-party service Providers to monitor and analyze the use
of our service.
</p>
<ul>
<li>
<p>
<strong>Google Analytics</strong>
</p>
<p>
Google Analytics is a web analytics service offered by Google that
tracks and reports website traffic. Google uses the data collected
to track and monitor the use of our service. This data is shared
with other Google services. Google may use the collected data to
contextualize and personalize the ads of its own advertising
network.
</p>
<p>
You can opt-out of having made your activity on the service
available to Google Analytics by installing the Google Analytics
opt-out browser add-on. The add-on prevents the Google Analytics
JavaScript (ga.js, analytics.js, and dc.js) from sharing information
with Google Analytics about visits activity.
</p>{" "}
<p>
For more information on the privacy practices of Google, please
visit the Google Privacy & Terms web page:{" "}
<a href="https://policies.google.com/privacy?hl=en">
https://policies.google.com/privacy?hl=en
</a>
</p>
</li>
</ul>
<h2>Links To Other Sites</h2>
<p>
Our service may contain links to other sites that are not operated by
us. If you click on a third party link, you will be directed to that
third party's site. We strongly advise you to review the Privacy Policy
of every site you visit.
</p>
<p>
We have no control over and assume no responsibility for the content,
privacy policies or practices of any third party sites or services.
</p>
<h2>Children's Privacy</h2>
<p>
Our service does not address anyone under the age of 18 ("Children").
</p>
<p>
We do not knowingly collect personally identifiable information from
anyone under the age of 18. If you are a parent or guardian and you are
aware that your Children has provided us with Personal Data, please
contact us. If we become aware that we have collected Personal Data from
children without verification of parental consent, we take steps to
remove that information from our servers.
</p>
<h2>Changes To This Privacy Policy</h2>
<p>
We may update our Privacy Policy from time to time. We will notify you
of any changes by posting the new Privacy Policy on this page.
</p>
<p>
We will let you know via email and/or a prominent notice on our service,
prior to the change becoming effective and update the "effective date"
at the top of this Privacy Policy.
</p>
<p>
You are advised to review this Privacy Policy periodically for any
changes. Changes to this Privacy Policy are effective when they are
posted on this page.
</p>
<h2>Contact Us</h2>
<p>
If you have any questions about this Privacy Policy, please contact us:
</p>
<ul>
<li>By email: fredrik_9490@hotmail.com</li>
</ul>
</div>
);
};
export default PrivacyPolicy;
+62 -68
View File
@@ -1,13 +1,12 @@
import React, {useState, useEffect} from 'react';
import React, { useState, useEffect } from "react";
import Paper from '@material-ui/core/Paper';
import Paper from "@material-ui/core/Paper";
const bodyDivStyle = {
margin: "auto",
textAlign: "center",
width: "768px",
}
margin: "auto",
textAlign: "center",
width: "768px",
};
//const tmpdata = {
// "username": "frikky",
@@ -23,71 +22,66 @@ const bodyDivStyle = {
// FIXME - remove tmpdata
// FIXME: Use isLoggedIn :)
const Settings = (props) => {
const { globalUrl, isLoaded, surfaceColor, } = props;
const { globalUrl, isLoaded, surfaceColor } = props;
const [firstRequest, setFirstRequest] = useState(true);
const boxStyle = {
flex: "1",
marginLeft: "10px",
marginRight: "10px",
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
backgroundColor: surfaceColor,
color: "white",
display: "flex",
flexDirection: "column"
}
const [firstRequest, setFirstRequest] = useState(true);
const boxStyle = {
flex: "1",
marginLeft: "10px",
marginRight: "10px",
paddingLeft: "30px",
paddingRight: "30px",
paddingBottom: "30px",
paddingTop: "30px",
backgroundColor: surfaceColor,
color: "white",
display: "flex",
flexDirection: "column",
};
const registerCall = () => {
const url = globalUrl+'/api/v1/register/'+props.match.params.key
fetch(url, {
method: 'GET',
credentials: 'include',
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
})
.then(response =>
response.json().then(responseJson => {
console.log(responseJson)
}),
)
.catch(error => {
console.log("SOMETHING WRONG")
});
}
const registerCall = () => {
const url = globalUrl + "/api/v1/register/" + props.match.params.key;
fetch(url, {
method: "GET",
credentials: "include",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
})
.then((response) =>
response.json().then((responseJson) => {
console.log(responseJson);
})
)
.catch((error) => {
console.log("SOMETHING WRONG");
});
};
// This should "always" have data
useEffect(() => {
if (firstRequest) {
setFirstRequest(false)
registerCall()
}
})
// This should "always" have data
useEffect(() => {
if (firstRequest) {
setFirstRequest(false);
registerCall();
}
});
// Random names for type & autoComplete. Didn't research :^)
const landingpageData =
<div style={{display: "flex", marginTop: "80px"}}>
<Paper style={boxStyle}>
<h2>Registration verification</h2>
<p>Thanks for verifying, redirecting you to our login!</p>
</Paper>
</div>
// Random names for type & autoComplete. Didn't research :^)
const landingpageData = (
<div style={{ display: "flex", marginTop: "80px" }}>
<Paper style={boxStyle}>
<h2>Registration verification</h2>
<p>Thanks for verifying, redirecting you to our login!</p>
</Paper>
</div>
);
const loadedCheck = isLoaded ?
<div style={bodyDivStyle}>
{landingpageData}
</div>
:
<div>
</div>
const loadedCheck = isLoaded ? (
<div style={bodyDivStyle}>{landingpageData}</div>
) : (
<div></div>
);
return(
<div>
{loadedCheck}
</div>
)
}
return <div>{loadedCheck}</div>;
};
export default Settings;
+160 -123
View File
@@ -1,139 +1,176 @@
/* eslint-disable react/no-multi-comp */
import React, {useState} from 'react';
import React, { useState } from "react";
import DialogTitle from '@material-ui/core/DialogTitle';
import Dialog from '@material-ui/core/Dialog';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import DialogTitle from "@material-ui/core/DialogTitle";
import Dialog from "@material-ui/core/Dialog";
import TextField from "@material-ui/core/TextField";
import Button from "@material-ui/core/Button";
const LoginDialog = props => {
const { classes, onClose, open, globalUrl, isLoggedIn, setIsLoggedIn, ...other } = props;
const LoginDialog = (props) => {
const {
classes,
onClose,
open,
globalUrl,
isLoggedIn,
setIsLoggedIn,
...other
} = props;
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
//const [selectedValue, setSelectedValue] = useState(false);
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
//const [selectedValue, setSelectedValue] = useState(false);
// Used to swap from login to register. True = login, false = register
const [loginCheck, setLoginCheck] = useState(true);
// Used to swap from login to register. True = login, false = register
const [loginCheck, setLoginCheck] = useState(true);
// Error messages etc
const [loginInfo, setLoginInfo] = useState("");
// Error messages etc
const [loginInfo, setLoginInfo] = useState("");
const handleValidateForm = () => {
return (username.length > 1 && password.length > 8);
}
const handleValidateForm = () => {
return username.length > 1 && password.length > 8;
};
const onSubmit = (e) => {
e.preventDefault()
const onSubmit = (e) => {
e.preventDefault();
// Just use this one?
var data = '{"username": "' + username + '", "password": "' + password + '"}';
var baseurl = globalUrl
if (loginCheck) {
var url = baseurl+'/login';
fetch(url, {
method: 'POST',
body: data,
headers: {
'Content-Type': 'application/json',
},
})
.then(response =>
response.json().then(responseJson => {
console.log(responseJson)
//console.log(e)
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"])
} else {
setLoginInfo("Successful login :)")
onClose()
setIsLoggedIn(true)
}
}),
)
.catch(error => {
setLoginInfo("Error in userdata")
});
} else {
url = baseurl+'/register';
fetch(url, {
method: 'POST',
body: data,
headers: {
'Content-Type': 'application/json',
},
})
.then(response =>
response.json().then(responseJson => {
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"])
} else {
setLoginInfo("Successful register. Please check your mail :)")
onClose()
setIsLoggedIn(true)
}
}),
)
.catch(error => {
setLoginInfo("Error in userdata")
});
}
}
// Just use this one?
var data =
'{"username": "' + username + '", "password": "' + password + '"}';
var baseurl = globalUrl;
if (loginCheck) {
var url = baseurl + "/login";
fetch(url, {
method: "POST",
body: data,
headers: {
"Content-Type": "application/json",
},
})
.then((response) =>
response.json().then((responseJson) => {
console.log(responseJson);
//console.log(e)
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"]);
} else {
setLoginInfo("Successful login :)");
onClose();
setIsLoggedIn(true);
}
})
)
.catch((error) => {
setLoginInfo("Error in userdata");
});
} else {
url = baseurl + "/register";
fetch(url, {
method: "POST",
body: data,
headers: {
"Content-Type": "application/json",
},
})
.then((response) =>
response.json().then((responseJson) => {
if (responseJson["success"] === false) {
setLoginInfo(responseJson["reason"]);
} else {
setLoginInfo("Successful register. Please check your mail :)");
onClose();
setIsLoggedIn(true);
}
})
)
.catch((error) => {
setLoginInfo("Error in userdata");
});
}
};
const onChangeUser = (e) => {
setUsername(e.target.value)
}
const onChangeUser = (e) => {
setUsername(e.target.value);
};
const onChangePass = (e) => {
setPassword(e.target.value)
}
const onChangePass = (e) => {
setPassword(e.target.value);
};
const onClickRegister = () => {
setLoginCheck(!loginCheck)
}
const onClickRegister = () => {
setLoginCheck(!loginCheck);
};
//var loginChange = loginCheck ? (<div><p onClick={setLoginCheck(false)}>Want to register? Click here.</p></div>) : (<div><p onClick={setLoginCheck(true)}>Go back to login? Click here.</p></div>);
var formtitle = loginCheck ? <div>Login</div> : <div>Register</div>
var formButton = loginCheck ? <div>Click to Register</div> : <div>Click to Login</div>
//var loginChange = loginCheck ? (<div><p onClick={setLoginCheck(false)}>Want to register? Click here.</p></div>) : (<div><p onClick={setLoginCheck(true)}>Go back to login? Click here.</p></div>);
var formtitle = loginCheck ? <div>Login</div> : <div>Register</div>;
var formButton = loginCheck ? (
<div>Click to Register</div>
) : (
<div>Click to Login</div>
);
return (
<Dialog modal open={open} onClose={onClose} {...other}>
<DialogTitle>{formtitle}</DialogTitle>
<form onSubmit={onSubmit} style={{margin: "15px 15px 15px 15px"}}>
Username
<div>
<TextField
required
id="standard-required"
autoComplete="username"
margin="normal"
variant="outlined"
onChange={onChangeUser}
/>
</div>
Password
<div>
<TextField
id="outlined-password-input"
type="password"
autoComplete="current-password"
margin="normal"
variant="outlined"
onChange={onChangePass}
/>
</div>
<div style={{display: "flex", marginTop: "15px"}}>
<Button color="secondary" variant="contained" type="submit" style={{flex: "1", marginRight: "5px"}} disabled={!handleValidateForm()}>SUBMIT</Button>
<Button color="primary" variant="contained" type="button" style={{flex: "1"}} onClick={onClose}>Cancel</Button>
</div>
{loginInfo}
</form>
<div style={{display: "flex"}}>
<Button color="secondary" variant="contained" onClick={onClickRegister} type="button" style={{flex: "1"}}>{formButton}</Button>
</div>
</Dialog>
);
}
return (
<Dialog modal open={open} onClose={onClose} {...other}>
<DialogTitle>{formtitle}</DialogTitle>
<form onSubmit={onSubmit} style={{ margin: "15px 15px 15px 15px" }}>
Username
<div>
<TextField
required
id="standard-required"
autoComplete="username"
margin="normal"
variant="outlined"
onChange={onChangeUser}
/>
</div>
Password
<div>
<TextField
id="outlined-password-input"
type="password"
autoComplete="current-password"
margin="normal"
variant="outlined"
onChange={onChangePass}
/>
</div>
<div style={{ display: "flex", marginTop: "15px" }}>
<Button
color="secondary"
variant="contained"
type="submit"
style={{ flex: "1", marginRight: "5px" }}
disabled={!handleValidateForm()}
>
SUBMIT
</Button>
<Button
color="primary"
variant="contained"
type="button"
style={{ flex: "1" }}
onClick={onClose}
>
Cancel
</Button>
</div>
{loginInfo}
</form>
<div style={{ display: "flex" }}>
<Button
color="secondary"
variant="contained"
onClick={onClickRegister}
type="button"
style={{ flex: "1" }}
>
{formButton}
</Button>
</div>
</Dialog>
);
};
export default LoginDialog;
+212 -200
View File
@@ -1,220 +1,232 @@
import React, { useEffect} from 'react';
import React, { useEffect } from "react";
import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';
import ButtonBase from '@material-ui/core/ButtonBase';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import Button from '@material-ui/core/Button';
import Paper from "@material-ui/core/Paper";
import Grid from "@material-ui/core/Grid";
import ButtonBase from "@material-ui/core/ButtonBase";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import Button from "@material-ui/core/Button";
//import Breadcrumbs from '@material-ui/core/Breadcrumbs';
const Schedules = (props) => {
const { globalUrl } = props;
const { globalUrl } = props;
//const [schedules, setSchedules] = React.useState(scheduledata);
const [schedules, setSchedules] = React.useState({});
//const [schedules, setSchedules] = React.useState(scheduledata);
const [schedules, setSchedules] = React.useState({});
const getAvailableSchedules = () => {
fetch(globalUrl+"/api/v1/schedules", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
})
.then((response) => response.json())
.then((responseJson) => {
setSchedules(responseJson)
})
.catch(error => {
console.log(error)
});
}
const getAvailableSchedules = () => {
fetch(globalUrl + "/api/v1/schedules", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
})
.then((response) => response.json())
.then((responseJson) => {
setSchedules(responseJson);
})
.catch((error) => {
console.log(error);
});
};
// FIXME - add automated redirection, as empty apps look horrible currently
const newSchedule = () => {
fetch(globalUrl+"/api/v1/schedules/new", {
method: "POST",
headers: {"content-type": "application/json"},
body: JSON.stringify(),
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson)
setSchedules({})
})
.catch(error => {
console.log(error)
});
}
// FIXME - add automated redirection, as empty apps look horrible currently
const newSchedule = () => {
fetch(globalUrl + "/api/v1/schedules/new", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(),
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
setSchedules({});
})
.catch((error) => {
console.log(error);
});
};
const deleteSchedule = (id) => {
if (id === undefined) {
return
}
const deleteSchedule = (id) => {
if (id === undefined) {
return;
}
fetch(globalUrl+"/api/v1/schedules/"+id+"/delete", {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
})
.then((response) => response.json())
.then((responseJson) => {
setSchedules({})
})
.catch(error => {
console.log(error)
});
}
fetch(globalUrl + "/api/v1/schedules/" + id + "/delete", {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
})
.then((response) => response.json())
.then((responseJson) => {
setSchedules({});
})
.catch((error) => {
console.log(error);
});
};
// FIXME - use this?
//const getNewScheduleInfo = () => {
// fetch(globalUrl+"/api/v1/schedules", {
// method: 'GET',
// headers: {
// 'Content-Type': 'application/json',
// 'Accept': 'application/json',
// },
// })
// .then((response) => response.json())
// .then((responseJson) => {
// setSchedules(responseJson)
// })
// .catch(error => {
// console.log(error)
// });
//}
// FIXME - use this?
//const getNewScheduleInfo = () => {
// fetch(globalUrl+"/api/v1/schedules", {
// method: 'GET',
// headers: {
// 'Content-Type': 'application/json',
// 'Accept': 'application/json',
// },
// })
// .then((response) => response.json())
// .then((responseJson) => {
// setSchedules(responseJson)
// })
// .catch(error => {
// console.log(error)
// });
//}
useEffect(() => {
if (Object.getOwnPropertyNames(schedules).length <= 0) {
getAvailableSchedules()
}
})
useEffect(() => {
if (Object.getOwnPropertyNames(schedules).length <= 0) {
getAvailableSchedules();
}
});
const bodyDivStyle = {
marginLeft: "20px",
marginRight: "20px",
width: "1350px",
minWidth: "1350px",
maxWidth: "1350px",
};
const bodyDivStyle = {
marginLeft: "20px",
marginRight: "20px",
width: "1350px",
minWidth: "1350px",
maxWidth: "1350px",
}
const scheduleApp = (app) => {
console.log(app);
return (
<Grid container spacing={2} style={{ margin: "10px 10px 10px 10px" }}>
<Grid item>
<ButtonBase>
<img alt="" style={{ width: "100px", height: "100px" }} />
</ButtonBase>
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={2}>
<Grid item xs>
<div>
<h2>{app.name}</h2>
</div>
<div>{app.description}</div>
</Grid>
<Grid item>{app.action}</Grid>
</Grid>
</Grid>
</Grid>
);
};
const scheduleApp = (app) => {
console.log(app)
return(
<Grid container spacing={2} style={{margin: "10px 10px 10px 10px"}}>
<Grid item>
<ButtonBase>
<img alt="" style={{width: "100px", height: "100px"}} />
</ButtonBase>
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={2}>
<Grid item xs>
<div>
<h2>{app.name}</h2>
</div>
<div>
{app.description}
</div>
</Grid>
<Grid item>
{app.action}
</Grid>
</Grid>
</Grid>
</Grid>
)
}
const splitter = (
<div
style={{
width: "1px",
backgroundColor: "grey",
margin: "5px 5px 5px 5px",
}}
/>
);
const splitter = <div style={{width: "1px", backgroundColor: "grey", margin:"5px 5px 5px 5px"}} />
const hrefStyle = {
color: "#385f71",
textDecoration: "none",
};
const hrefStyle = {
color: "#385f71",
textDecoration: "none"
}
// FIXME - add Schedule modal
const schedulePaper = (schedule) => {
return (
<div>
<Paper
style={{
maxWidth: "1000px",
display: "flex",
padding: "10px 10px 10px 10px",
}}
>
<div style={{ flex: "5" }}>
{scheduleApp(schedule.appinfo.sourceapp)}
</div>
<div style={{ flex: "1", alignItems: "center" }}>ARROW</div>
<div style={{ flex: "5" }}>
{scheduleApp(schedule.appinfo.destinationapp)}
</div>
{splitter}
<div style={{ flex: "1" }}>
<List style={{ backgroundColor: "#ffffff" }}>
<ListItem style={{ flex: "1", textAlign: "center" }}>
<a href={"/schedules/" + schedule.id} style={hrefStyle}>
<Button disabled={false} color="primary">
Edit
</Button>
</a>
</ListItem>
<ListItem style={{ flex: "1", textAlign: "center" }}>
<Button
disabled={false}
onClick={() => {
deleteSchedule(schedule.id);
}}
color="primary"
>
Delete
</Button>
</ListItem>
</List>
</div>
</Paper>
</div>
);
};
// FIXME - add Schedule modal
const schedulePaper = (schedule) => {
return(
<div>
<Paper style={{maxWidth: "1000px", display: "flex", padding: "10px 10px 10px 10px"}}>
<div style={{flex: "5"}}>
{scheduleApp(schedule.appinfo.sourceapp)}
</div>
<div style={{flex: "1", alignItems: "center"}}>
ARROW
</div>
<div style={{flex: "5"}}>
{scheduleApp(schedule.appinfo.destinationapp)}
</div>
{splitter}
<div style={{flex: "1"}}>
<List style={{backgroundColor: "#ffffff"}}>
<ListItem style={{flex: "1", textAlign: "center"}}>
<a href={"/schedules/"+schedule.id} style={hrefStyle} >
<Button
disabled={false}
color="primary"
>
Edit
</Button>
</a>
</ListItem>
<ListItem style={{flex: "1", textAlign: "center"}}>
<Button
disabled={false}
onClick={() => {deleteSchedule(schedule.id)}}
color="primary"
>Delete</Button>
</ListItem>
console.log(schedules);
console.log(schedules);
console.log(schedules.schedules);
const schedulemap =
Object.getOwnPropertyNames(schedules).length > 0 &&
schedules.schedules &&
schedules.schedules.length > 0 ? (
<div>{schedules.schedules.map((data) => schedulePaper(data))}</div>
) : (
<div style={{ marginTop: "10%", marginLeft: "50%" }}>
<Button
disabled={false}
onClick={() => {
newSchedule();
}}
variant="outlined"
color="primary"
>
CREATE NEW SCHEDULE
</Button>
</div>
);
</List>
</div>
</Paper>
</div>
)
}
const scheduleView =
Object.getOwnPropertyNames(schedules).length > 0 ? (
<div style={bodyDivStyle}>
<Button
disabled={false}
onClick={() => {
newSchedule();
}}
color="primary"
>
New
</Button>
{schedulemap}
</div>
) : null;
console.log(schedules)
console.log(schedules)
console.log(schedules.schedules)
const schedulemap = Object.getOwnPropertyNames(schedules).length > 0 && schedules.schedules && schedules.schedules.length > 0 ?
<div>
{schedules.schedules.map(data => (
schedulePaper(data)
))}
</div>
:
<div style={{marginTop: "10%", marginLeft: "50%"}} >
<Button
disabled={false}
onClick={() => {newSchedule()}}
variant="outlined"
color="primary"
>CREATE NEW SCHEDULE</Button>
</div>
// Maybe use gridview or something, idk
return <div>{scheduleView}</div>;
};
const scheduleView = Object.getOwnPropertyNames(schedules).length > 0 ?
<div style={bodyDivStyle}>
<Button
disabled={false}
onClick={() => {newSchedule()}}
color="primary"
>New</Button>
{schedulemap}
</div>
: null
// Maybe use gridview or something, idk
return (
<div>
{scheduleView}
</div>
)
}
export default Schedules
export default Schedules;
+137 -122
View File
@@ -1,155 +1,170 @@
import React, {useRef, useState, useEffect, useLayoutEffect} from 'react';
import React, { useRef, useState, useEffect, useLayoutEffect } from "react";
import { Typography, CircularProgress } from '@material-ui/core';
import { Typography, CircularProgress } from "@material-ui/core";
const SetAuthentication = (props) => {
const { globalUrl, isLoggedIn, isLoaded, userdata } = props;
const [firstRequest, setFirstRequest] = useState(true)
const [finished, setFinished] = useState(false)
const [response, setResponse] = useState("")
const [failed, setFailed] = useState(false)
const [firstRequest, setFirstRequest] = useState(true);
const [finished, setFinished] = useState(false);
const [response, setResponse] = useState("");
const [failed, setFailed] = useState(false);
if (firstRequest) {
setFirstRequest(false)
if (firstRequest) {
setFirstRequest(false);
//code
//session_state
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
//code
//session_state
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
const authenticationStore = []
var appAuthData = {
"label": "",
"app": {
"name": "",
"id": "",
"app_version": "",
},
"fields": [],
"type": "oauth2",
}
const authenticationStore = [];
var appAuthData = {
label: "",
app: {
name: "",
id: "",
app_version: "",
},
fields: [],
type: "oauth2",
};
if (window !== undefined && window !== null) {
console.log(window.location)
appAuthData.fields.push({"key": "redirect_uri", "value": window.location.origin+window.location.pathname})
}
if (window !== undefined && window !== null) {
console.log(window.location);
appAuthData.fields.push({
key: "redirect_uri",
value: window.location.origin + window.location.pathname,
});
}
if (params.code !== undefined && params.code !== null) {
appAuthData.fields.push({"key": "code", "value": params.code})
}
if (params.code !== undefined && params.code !== null) {
appAuthData.fields.push({ key: "code", value: params.code });
}
if (params.session_state !== undefined && params.session_state !== null) {
appAuthData.fields.push({"key": "session_state", "value": params.session_state})
}
if (params.session_state !== undefined && params.session_state !== null) {
appAuthData.fields.push({
key: "session_state",
value: params.session_state,
});
}
if (params.state !== undefined && params.state !== null) {
const paramsplit = params.state.split("&")
console.log(paramsplit)
for (var key in paramsplit) {
const query = paramsplit[key].split("=")
console.log(query)
if (params.state !== undefined && params.state !== null) {
const paramsplit = params.state.split("&");
console.log(paramsplit);
for (var key in paramsplit) {
const query = paramsplit[key].split("=");
console.log(query);
if (query.length !== 2) {
console.log("INVALID QUERY: ", query)
continue
}
if (query.length !== 2) {
console.log("INVALID QUERY: ", query);
continue;
}
if (query[0] === "workflow_id") {
appAuthData.reference_workflow = query[1]
}
if (query[0] === "workflow_id") {
appAuthData.reference_workflow = query[1];
}
if (query[0] === "reference_action_id") {
//appAuthData.ReferenceWorkflow = query[1]
}
if (query[0] === "reference_action_id") {
//appAuthData.ReferenceWorkflow = query[1]
}
if (query[0] === "app_name") {
appAuthData.app.name = query[1]
appAuthData.label = "Oauth2 for "+query[1]
}
if (query[0] === "app_name") {
appAuthData.app.name = query[1];
appAuthData.label = "Oauth2 for " + query[1];
}
if (query[0] === "app_id") {
appAuthData.app.id = query[1]
}
if (query[0] === "app_id") {
appAuthData.app.id = query[1];
}
if (query[0] === "app_version") {
appAuthData.app.app_version = query[1]
}
if (query[0] === "app_version") {
appAuthData.app.app_version = query[1];
}
if (query[0] === "authentication_url") {
appAuthData.fields.push({"key": "authentication_url", "value": query[1]})
}
if (query[0] === "authentication_url") {
appAuthData.fields.push({
key: "authentication_url",
value: query[1],
});
}
if (query[0] === "scope") {
appAuthData.fields.push({"key": "scope", "value": query[1]})
}
if (query[0] === "scope") {
appAuthData.fields.push({ key: "scope", value: query[1] });
}
if (query[0] === "client_id") {
appAuthData.fields.push({"key": "client_id", "value": query[1]})
}
if (query[0] === "client_id") {
appAuthData.fields.push({ key: "client_id", value: query[1] });
}
if (query[0] === "client_secret") {
appAuthData.fields.push({"key": "client_secret", "value": query[1]})
}
if (query[0] === "client_secret") {
appAuthData.fields.push({ key: "client_secret", value: query[1] });
}
if (query[0] === "oauth_url") {
appAuthData.fields.push({"key": "oauth_url", "value": query[1]})
}
if (query[0] === "oauth_url") {
appAuthData.fields.push({ key: "oauth_url", value: query[1] });
}
if (query[0] === "refresh_uri") {
appAuthData.fields.push({"key": "refresh_uri", "value": query[1]})
}
if (query[0] === "refresh_uri") {
appAuthData.fields.push({ key: "refresh_uri", value: query[1] });
}
if (query[0] === "refresh_url") {
appAuthData.fields.push({"key": "refresh_url", "value": query[1]})
}
}
}
if (query[0] === "refresh_url") {
appAuthData.fields.push({ key: "refresh_url", value: query[1] });
}
}
}
console.log(appAuthData)
console.log(appAuthData);
fetch(globalUrl+"/api/v1/apps/authentication", {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
body: JSON.stringify(appAuthData),
fetch(globalUrl + "/api/v1/apps/authentication", {
method: "PUT",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
body: JSON.stringify(appAuthData),
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for oauth2 authentication")
setFailed(true)
}
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for oauth2 authentication");
setFailed(true);
}
return response.json()
})
.then((responseJson) => {
//setUserSettings(responseJson)
console.log("Resp: ", responseJson)
setFinished(true)
setResponse(responseJson.reason)
return response.json();
})
.then((responseJson) => {
//setUserSettings(responseJson)
console.log("Resp: ", responseJson);
setFinished(true);
setResponse(responseJson.reason);
setTimeout(() => {
window.close()
}, 1000)
})
.catch(error => {
console.log(error)
});
setTimeout(() => {
window.close();
}, 1000);
})
.catch((error) => {
console.log(error);
});
}
}
return (
<div style={{width: 1000, margin: "auto", itemAlign: "center",}}>
<Typography variant="h6" style={{marginLeft: "auto", marginRight: "auto", marginTop: 200, }}>
{!finished ? <CircularProgress /> : "DONE WITH AUTH - this will close soon!!"}
<div />
{failed ? "Failed setup. Error: " : ""} {response}
</Typography>
</div>
)
}
return (
<div style={{ width: 1000, margin: "auto", itemAlign: "center" }}>
<Typography
variant="h6"
style={{ marginLeft: "auto", marginRight: "auto", marginTop: 200 }}
>
{!finished ? (
<CircularProgress />
) : (
"DONE WITH AUTH - this will close soon!!"
)}
<div />
{failed ? "Failed setup. Error: " : ""} {response}
</Typography>
</div>
);
};
export default SetAuthentication;
+128 -113
View File
@@ -1,143 +1,158 @@
import React, {useRef, useState, useEffect, useLayoutEffect} from 'react';
import React, { useRef, useState, useEffect, useLayoutEffect } from "react";
import { Typography, CircularProgress } from '@material-ui/core';
import { Typography, CircularProgress } from "@material-ui/core";
const SetAuthentication = (props) => {
const { globalUrl, isLoggedIn, isLoaded, userdata } = props;
const [firstRequest, setFirstRequest] = useState(true)
const [finished, setFinished] = useState(false)
const [response, setResponse] = useState("")
const [failed, setFailed] = useState(false)
const [firstRequest, setFirstRequest] = useState(true);
const [finished, setFinished] = useState(false);
const [response, setResponse] = useState("");
const [failed, setFailed] = useState(false);
if (firstRequest) {
setFirstRequest(false)
if (firstRequest) {
setFirstRequest(false);
//code
//session_state
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
//code
//session_state
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
const authenticationStore = []
var appAuthData = {
"label": "",
"app": {
"name": "",
"id": "",
"app_version": "",
},
"fields": [],
"type": "oauth2",
}
const authenticationStore = [];
var appAuthData = {
label: "",
app: {
name: "",
id: "",
app_version: "",
},
fields: [],
type: "oauth2",
};
if (window !== undefined && window !== null) {
console.log(window.location)
appAuthData.fields.push({"key": "redirect_uri", "value": window.location.origin+window.location.pathname})
}
if (window !== undefined && window !== null) {
console.log(window.location);
appAuthData.fields.push({
key: "redirect_uri",
value: window.location.origin + window.location.pathname,
});
}
if (params.code !== undefined && params.code !== null) {
appAuthData.fields.push({"key": "code", "value": params.code})
}
if (params.code !== undefined && params.code !== null) {
appAuthData.fields.push({ key: "code", value: params.code });
}
if (params.session_state !== undefined && params.session_state !== null) {
appAuthData.fields.push({"key": "session_state", "value": params.session_state})
}
if (params.session_state !== undefined && params.session_state !== null) {
appAuthData.fields.push({
key: "session_state",
value: params.session_state,
});
}
if (params.state !== undefined && params.state !== null) {
const paramsplit = params.state.split("&")
console.log(paramsplit)
for (var key in paramsplit) {
const query = paramsplit[key].split("=")
console.log(query)
if (params.state !== undefined && params.state !== null) {
const paramsplit = params.state.split("&");
console.log(paramsplit);
for (var key in paramsplit) {
const query = paramsplit[key].split("=");
console.log(query);
if (query.length !== 2) {
console.log("INVALID QUERY: ", query)
continue
}
if (query.length !== 2) {
console.log("INVALID QUERY: ", query);
continue;
}
if (query[0] === "workflow_id") {
appAuthData.reference_workflow = query[1]
}
if (query[0] === "workflow_id") {
appAuthData.reference_workflow = query[1];
}
if (query[0] === "reference_action_id") {
//appAuthData.ReferenceWorkflow = query[1]
}
if (query[0] === "reference_action_id") {
//appAuthData.ReferenceWorkflow = query[1]
}
if (query[0] === "app_name") {
appAuthData.app.name = query[1]
appAuthData.label = "Oauth2 for "+query[1]
}
if (query[0] === "app_name") {
appAuthData.app.name = query[1];
appAuthData.label = "Oauth2 for " + query[1];
}
if (query[0] === "app_id") {
appAuthData.app.id = query[1]
}
if (query[0] === "app_id") {
appAuthData.app.id = query[1];
}
if (query[0] === "app_version") {
appAuthData.app.app_version = query[1]
}
if (query[0] === "app_version") {
appAuthData.app.app_version = query[1];
}
if (query[0] === "authentication_url") {
appAuthData.fields.push({"key": "authentication_url", "value": query[1]})
}
if (query[0] === "authentication_url") {
appAuthData.fields.push({
key: "authentication_url",
value: query[1],
});
}
if (query[0] === "scope") {
appAuthData.fields.push({"key": "scope", "value": query[1]})
}
if (query[0] === "scope") {
appAuthData.fields.push({ key: "scope", value: query[1] });
}
if (query[0] === "client_id") {
appAuthData.fields.push({"key": "client_id", "value": query[1]})
}
if (query[0] === "client_id") {
appAuthData.fields.push({ key: "client_id", value: query[1] });
}
if (query[0] === "client_secret") {
appAuthData.fields.push({"key": "client_secret", "value": query[1]})
}
}
}
if (query[0] === "client_secret") {
appAuthData.fields.push({ key: "client_secret", value: query[1] });
}
}
}
console.log(appAuthData)
console.log(appAuthData);
fetch(globalUrl+"/api/v1/apps/authentication", {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
body: JSON.stringify(appAuthData),
fetch(globalUrl + "/api/v1/apps/authentication", {
method: "PUT",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
body: JSON.stringify(appAuthData),
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for oauth2 authentication")
setFailed(true)
}
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for oauth2 authentication");
setFailed(true);
}
return response.json()
})
.then((responseJson) => {
//setUserSettings(responseJson)
console.log("Resp: ", responseJson)
setFinished(true)
setResponse(responseJson.reason)
return response.json();
})
.then((responseJson) => {
//setUserSettings(responseJson)
console.log("Resp: ", responseJson);
setFinished(true);
setResponse(responseJson.reason);
setTimeout(() => {
window.close()
}, 1000)
})
.catch(error => {
console.log(error)
});
setTimeout(() => {
window.close();
}, 1000);
})
.catch((error) => {
console.log(error);
});
}
}
return (
<div style={{width: 1000, margin: "auto", itemAlign: "center",}}>
<Typography variant="h6" style={{marginLeft: "auto", marginRight: "auto", marginTop: 200, }}>
{!finished ? <CircularProgress /> : "DONE WITH AUTH - this will close soon!!"}
<div />
{failed ? "Failed setup. Error: " : ""} {response}
</Typography>
</div>
)
}
return (
<div style={{ width: 1000, margin: "auto", itemAlign: "center" }}>
<Typography
variant="h6"
style={{ marginLeft: "auto", marginRight: "auto", marginTop: 200 }}
>
{!finished ? (
<CircularProgress />
) : (
"DONE WITH AUTH - this will close soon!!"
)}
<div />
{failed ? "Failed setup. Error: " : ""} {response}
</Typography>
</div>
);
};
export default SetAuthentication;
File diff suppressed because it is too large Load Diff
+290 -269
View File
@@ -1,295 +1,316 @@
import React, { useEffect} from 'react';
import React, { useEffect } from "react";
import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';
import ButtonBase from '@material-ui/core/ButtonBase';
import Button from '@material-ui/core/Button';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import TextField from '@material-ui/core/TextField';
import Select from '@material-ui/core/Select';
import MenuItem from '@material-ui/core/MenuItem';
import Paper from "@material-ui/core/Paper";
import Grid from "@material-ui/core/Grid";
import ButtonBase from "@material-ui/core/ButtonBase";
import Button from "@material-ui/core/Button";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import TextField from "@material-ui/core/TextField";
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";
import Dialog from '@material-ui/core/Dialog';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import Dialog from "@material-ui/core/Dialog";
import DialogTitle from "@material-ui/core/DialogTitle";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
import WebhookImage from '../assets/img/webhook.png';
import KafkaImage from '../assets/img/kafka.png';
import WebhookImage from "../assets/img/webhook.png";
import KafkaImage from "../assets/img/kafka.png";
const Webhooks = (props) => {
const { globalUrl, isLoaded } = props;
const validtypes = ["webhook"]
const { globalUrl, isLoaded } = props;
const validtypes = ["webhook"];
//const [hooks, setSchedules] = React.useState(hookdata);
const [hooks, setHooks] = React.useState([]);
const [modalOpen, setModalOpen] = React.useState(false);
const [newHookName, setNewHookName] = React.useState("");
const [newHookDescription, setNewHookDescription] = React.useState("");
const [newHookType, setNewHookType] = React.useState("");
const [firstrequest, setFirstrequest] = React.useState(true);
const [, setModalError] = React.useState("");
//const [hooks, setSchedules] = React.useState(hookdata);
const [hooks, setHooks] = React.useState([]);
const [modalOpen, setModalOpen] = React.useState(false);
const [newHookName, setNewHookName] = React.useState("");
const [newHookDescription, setNewHookDescription] = React.useState("");
const [newHookType, setNewHookType] = React.useState("");
const [firstrequest, setFirstrequest] = React.useState(true);
const [, setModalError] = React.useState("");
useEffect(() => {
if (firstrequest) {
setFirstrequest(false)
getAvailableHooks()
}
})
useEffect(() => {
if (firstrequest) {
setFirstrequest(false);
getAvailableHooks();
}
});
const newHook = () => {
if (newHookName.length === 0) {
setModalError("Missing name in modal")
return
}
const newHook = () => {
if (newHookName.length === 0) {
setModalError("Missing name in modal");
return;
}
if (!validtypes.includes(newHookType)) {
setModalError(newHookType + " is not a valid type. Try this: "+validtypes)
}
if (!validtypes.includes(newHookType)) {
setModalError(
newHookType + " is not a valid type. Try this: " + validtypes
);
}
fetch(globalUrl+"/api/v1/hooks/new", {
method: "POST",
headers: {"content-type": "application/json"},
body: JSON.stringify({"name": newHookName, "description": newHookDescription, "type": newHookType}),
credentials: "include",
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson)
setHooks([])
})
.catch(error => {
console.log(error)
});
}
fetch(globalUrl + "/api/v1/hooks/new", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
name: newHookName,
description: newHookDescription,
type: newHookType,
}),
credentials: "include",
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
setHooks([]);
})
.catch((error) => {
console.log(error);
});
};
const getAvailableHooks = () => {
fetch(globalUrl+"/api/v1/hooks", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
})
.then((response) => response.json())
.then((responseJson) => {
setHooks(responseJson)
})
.catch(error => {
console.log(error)
// window.location.pathname = "/"
});
}
const getAvailableHooks = () => {
fetch(globalUrl + "/api/v1/hooks", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => response.json())
.then((responseJson) => {
setHooks(responseJson);
})
.catch((error) => {
console.log(error);
// window.location.pathname = "/"
});
};
const deleteHook = (id) => {
if (id === undefined) {
return
}
const deleteHook = (id) => {
if (id === undefined) {
return;
}
fetch(globalUrl+"/api/v1/hooks/"+id+"/delete", {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
})
.then((response) => response.json())
.then((responseJson) => {
setHooks([])
})
.catch(error => {
console.log(error)
});
}
fetch(globalUrl + "/api/v1/hooks/" + id + "/delete", {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => response.json())
.then((responseJson) => {
setHooks([]);
})
.catch((error) => {
console.log(error);
});
};
const bodyDivStyle = {
marginLeft: "20px",
marginRight: "20px",
width: "1350px",
minWidth: "1350px",
maxWidth: "1350px",
}
const bodyDivStyle = {
marginLeft: "20px",
marginRight: "20px",
width: "1350px",
minWidth: "1350px",
maxWidth: "1350px",
};
const hookApp = (app) => {
const hookApp = (app) => {
// Might be more options, but should be webhook or MQ
const appPicture =
app.type === "webhook" ? (
<img src={WebhookImage} alt="webhook" width="100px" height="100px" />
) : (
<img src={KafkaImage} alt="MQ" width="100px" height="100px" />
);
// Might be more options, but should be webhook or MQ
const appPicture = app.type === "webhook" ?
<img
src={WebhookImage}
alt="webhook"
width="100px"
height="100px"
/>
:
<img
src={KafkaImage}
alt="MQ"
width="100px"
height="100px"
/>
return (
<Grid container spacing={2} style={{ margin: "10px 10px 10px 10px" }}>
<Grid item style={{ marginRight: "10px" }}>
<ButtonBase>{appPicture}</ButtonBase>
</Grid>
{splitter}
<Grid item xs={12} sm container style={{ marginLeft: "10px" }}>
<Grid item xs container direction="column" spacing={2}>
<Grid item xs>
<div>
<h2>{app.info.name}</h2>
</div>
<div>Desc: {app.info.description}</div>
<div>Status: {app.status}</div>
</Grid>
<Grid item>{app.action}</Grid>
</Grid>
</Grid>
</Grid>
);
};
return(
<Grid container spacing={2} style={{margin: "10px 10px 10px 10px"}}>
<Grid item style={{marginRight: "10px"}}>
<ButtonBase>
{appPicture}
</ButtonBase>
</Grid>
{splitter}
<Grid item xs={12} sm container style={{marginLeft: "10px"}}>
<Grid item xs container direction="column" spacing={2}>
<Grid item xs>
<div>
<h2>{app.info.name}</h2>
</div>
<div>
Desc: {app.info.description}
</div>
<div>
Status: {app.status}
</div>
</Grid>
<Grid item>
{app.action}
</Grid>
</Grid>
</Grid>
</Grid>
)
}
const splitter = (
<div
style={{
width: "1px",
backgroundColor: "grey",
margin: "5px 5px 5px 5px",
}}
/>
);
const splitter = <div style={{width: "1px", backgroundColor: "grey", margin:"5px 5px 5px 5px"}} />
const hrefStyle = {
color: "#385f71",
textDecoration: "none",
};
const hrefStyle = {
color: "#385f71",
textDecoration: "none"
}
// FIXME - add Schedule modal
const hookPaper = (hook) => {
return (
<div>
<Paper
style={{
maxWidth: "500px",
display: "flex",
padding: "10px 10px 10px 10px",
marginTop: "10px",
}}
>
<div style={{ flex: "5" }}>{hookApp(hook)}</div>
{splitter}
<div style={{ flex: "1" }}>
<List style={{ backgroundColor: "#ffffff" }}>
<ListItem style={{ flex: "1", textAlign: "center" }}>
<a href={"/webhooks/" + hook.id} style={hrefStyle}>
<Button disabled={false} color="primary">
Edit
</Button>
</a>
</ListItem>
<ListItem style={{ flex: "1", textAlign: "center" }}>
<Button
disabled={false}
onClick={() => {
deleteHook(hook.id);
}}
color="primary"
>
Delete
</Button>
</ListItem>
</List>
</div>
</Paper>
</div>
);
};
// FIXME - add Schedule modal
const hookPaper = (hook) => {
return(
<div>
<Paper style={{maxWidth: "500px", display: "flex", padding: "10px 10px 10px 10px", marginTop: "10px"}}>
<div style={{flex: "5"}}>
{hookApp(hook)}
</div>
{splitter}
<div style={{flex: "1"}}>
<List style={{backgroundColor: "#ffffff"}}>
<ListItem style={{flex: "1", textAlign: "center"}}>
<a href={"/webhooks/"+hook.id} style={hrefStyle} >
<Button
disabled={false}
color="primary"
>
Edit
</Button>
</a>
</ListItem>
<ListItem style={{flex: "1", textAlign: "center"}}>
<Button
disabled={false}
onClick={() => {deleteHook(hook.id)}}
color="primary"
>Delete</Button>
</ListItem>
</List>
</div>
</Paper>
</div>
)
}
const modalView = modalOpen ? (
<Dialog
modal
open={modalOpen}
onClose={() => {
setModalOpen(false);
}}
>
<DialogTitle>Hook configuration</DialogTitle>
<DialogContent>
<TextField
onChange={(event) => {
setNewHookName(event.target.value);
}}
color="primary"
placeholder="Name"
margin="dense"
fullWidth
/>
<TextField
onChange={(event) => {
setNewHookDescription(event.target.value);
}}
color="primary"
placeholder="Description"
margin="dense"
fullWidth
/>
const modalView = modalOpen ?
<Dialog modal
open={modalOpen}
onClose={() => {setModalOpen(false)}}
>
<DialogTitle>Hook configuration</DialogTitle>
<DialogContent>
<TextField
onChange={(event) => {setNewHookName(event.target.value)}}
color="primary"
placeholder="Name"
margin="dense"
fullWidth
/>
<TextField
onChange={(event) => {setNewHookDescription(event.target.value)}}
color="primary"
placeholder="Description"
margin="dense"
fullWidth
/>
<Select
value={newHookType}
onChange={(event) => {
setNewHookType(event.target.value);
}}
fullWidth="true"
>
{validtypes.map((data) => (
<MenuItem value={data}>{data}</MenuItem>
))}
</Select>
</DialogContent>
<DialogActions>
<Button onClick={() => setModalOpen(false)} color="primary">
Cancel
</Button>
<Button
disabled={
newHookName.length === 0 || !validtypes.includes(newHookType)
}
onClick={() => {
newHook();
setModalOpen(false);
}}
color="primary"
>
Submit
</Button>
</DialogActions>
</Dialog>
) : null;
<Select
value={newHookType}
onChange={(event) => {setNewHookType(event.target.value)}}
fullWidth="true"
>
{validtypes.map(data => (
<MenuItem value={data}>
{data}
</MenuItem>
))}
</Select>
</DialogContent>
<DialogActions>
<Button onClick={() => setModalOpen(false)} color="primary">
Cancel
</Button>
<Button disabled={newHookName.length === 0 || !validtypes.includes(newHookType)} onClick={() => {newHook(); setModalOpen(false)}} color="primary">
Submit
</Button>
</DialogActions>
</Dialog>
: null
const hookmap =
hooks.length > 0 ? (
<div>{hooks.map((data) => hookPaper(data))}</div>
) : (
<div style={{ marginTop: "10%", marginLeft: "50%" }}>
<Button
disabled={false}
onClick={() => {
setModalOpen(true);
}}
variant="outlined"
color="primary"
>
CREATE NEW HOOK
</Button>
</div>
);
const hookmap = hooks.length > 0 ?
<div>
{hooks.map(data => (
hookPaper(data)
))}
</div>
:
<div style={{marginTop: "10%", marginLeft: "50%"}} >
<Button
disabled={false}
onClick={() => {setModalOpen(true)}}
variant="outlined"
color="primary"
>CREATE NEW HOOK</Button>
</div>
const hookView = (
<div style={bodyDivStyle}>
<Button
disabled={false}
onClick={() => {
setModalOpen(true);
}}
color="primary"
>
New
</Button>
{hookmap}
</div>
);
const hookView =
<div style={bodyDivStyle}>
<Button
disabled={false}
onClick={() => {setModalOpen(true)}}
color="primary"
>New</Button>
{hookmap}
</div>
const loadedCheck = isLoaded ? (
<div>
{modalView}
{hookView}
</div>
) : (
<div></div>
);
const loadedCheck = isLoaded ?
<div>
{modalView}
{hookView}
</div>
:
<div>
</div>
// Maybe use gridview or something, idk
return <div>{loadedCheck}</div>;
};
// Maybe use gridview or something, idk
return (
<div>
{loadedCheck}
</div>
)
}
export default Webhooks
export default Webhooks;
File diff suppressed because it is too large Load Diff