Merge branch 'Shuffle:launch' into launch

This commit is contained in:
Dhaval Dave
2022-06-13 15:20:27 +05:30
committed by GitHub
13 changed files with 1144 additions and 73 deletions
+91 -38
View File
@@ -111,6 +111,7 @@ import ConfigureWorkflow from "../components/ConfigureWorkflow.jsx";
import AuthenticationOauth2 from "../components/Oauth2Auth.jsx";
import ParsedAction from "../components/ParsedAction.jsx";
import PaperComponent from "../components/PaperComponent.jsx"
import ExtraApps from "../components/ExtraApps.jsx"
const surfaceColor = "#27292D";
const inputColor = "#383B40";
@@ -451,7 +452,8 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
alert.error(error.toString());
//alert.error(error.toString());
console.log("Workflow error: ", error.toString())
});
};
@@ -539,7 +541,7 @@ const AngularWorkflow = (defaultprops) => {
setUserSettings(responseJson);
})
.catch((error) => {
console.log(error);
console.log("Apikey error: ", error);
});
};
@@ -574,7 +576,7 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
console.log(error);
console.log("Settings error: ", error);
});
};
@@ -608,7 +610,8 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
alert.error(error.toString());
//alert.error(error.toString());
console.log("New auth error: ", error.toString());
});
};
@@ -692,7 +695,8 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
alert.error(error.toString());
//alert.error(error.toString());
console.log("Get execution error: ", error.toString());
});
};
@@ -719,7 +723,7 @@ const AngularWorkflow = (defaultprops) => {
handleUpdateResults(responseJson, executionRequest);
})
.catch((error) => {
console.log("Error: ", error);
console.log("Execution result Error: ", error);
stop();
});
};
@@ -751,7 +755,8 @@ const AngularWorkflow = (defaultprops) => {
return response.json();
})
.catch((error) => {
alert.error(error.toString());
//alert.error(error.toString());
console.log("Abort error: ", error.toString());
});
};
@@ -1262,7 +1267,8 @@ const AngularWorkflow = (defaultprops) => {
})
.catch((error) => {
setSavingState(0);
alert.error(error.toString());
//alert.error(error.toString());
console.log("Save workflow error: ", error.toString());
});
return success;
@@ -1387,7 +1393,8 @@ const AngularWorkflow = (defaultprops) => {
start();
})
.catch((error) => {
alert.error(error.toString());
//alert.error(error.toString());
console.log("Execute workflow err: ", error.toString());
});
})
};
@@ -1501,7 +1508,8 @@ const AngularWorkflow = (defaultprops) => {
})
.catch((error) => {
setAuthLoaded(true);
alert.error("Auth loading error: " + error.toString());
//alert.error("Auth loading error: " + error.toString());
console.log("AppAuth error: " + error.toString());
});
};
@@ -1578,7 +1586,8 @@ const AngularWorkflow = (defaultprops) => {
})
.catch((error) => {
setAppsLoaded(true)
alert.error("App loading error: "+error.toString());
//alert.error("App loading error: "+error.toString());
console.log("App loading error: "+error.toString());
});
};
@@ -1607,7 +1616,7 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
console.log(error);
console.log("Get userprofile error: ", error);
})
}
@@ -1825,7 +1834,8 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
alert.error(error.toString());
//alert.error(error.toString());
console.log("Get workflows error: ", error.toString());
});
};
@@ -2500,6 +2510,32 @@ const AngularWorkflow = (defaultprops) => {
(a.loop_versions !== null &&
a.loop_versions.includes(curaction.app_version)))
);
if (curaction.template === true) {
//newapps.
const parsedname = curaction.name.replaceAll(" ", "_").toLowerCase()
console.log("FIND AN ACTION AMONG THE APPS THAT MATCHES NAME: ", parsedname)
curaction.matching_actions = []
for (var key in newapps) {
for (var subkey in newapps[key].actions) {
const tmpaction = newapps[key].actions[subkey]
if (tmpaction.name.replaceAll(" ", "_").toLowerCase() === parsedname) {
console.log("MATCH!: ", newapps[key])
curaction.matching_actions.push({
"app_name": newapps[key].name,
"app_version": newapps[key].app_version,
"app_id": newapps[key].id,
"action": tmpaction,
"large_image": newapps[key].large_image,
"app_index": key,
"action_index": subkey,
})
}
}
}
}
if (!curapp || curapp === undefined) {
console.log("APPS: ", newapps)
//alert.error(`App ${curaction.app_name}:${curaction.app_version} not found. Is it activated?`);
@@ -2709,7 +2745,8 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch(error => {
alert.error(error.toString())
//alert.error(error.toString())
console.log("Activate app error: ", error.toString())
});
}
@@ -3658,7 +3695,8 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
alert.error(error.toString());
//alert.error(error.toString());
console.log("Get environments error: ", error.toString());
});
};
@@ -4563,7 +4601,8 @@ const AngularWorkflow = (defaultprops) => {
saveWorkflow(workflow);
})
.catch((error) => {
alert.error(error.toString());
//alert.error(error.toString());
console.log("Stop schedule error: ", error.toString());
});
};
@@ -4615,7 +4654,8 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
alert.error(error.toString());
//alert.error(error.toString());
console.log("Get schedule error: ", error.toString());
});
};
@@ -4970,6 +5010,7 @@ const AngularWorkflow = (defaultprops) => {
var thisview = (
<AppView
allApps={apps}
extraApps={ExtraApps}
prioritizedApps={prioritizedApps}
filteredApps={filteredApps}
/>
@@ -5063,14 +5104,14 @@ const AngularWorkflow = (defaultprops) => {
is_valid: true,
label: "Webhook",
environment: "onprem",
description: "Simple HTTP webhook",
description: "Custom HTTP input",
long_description: "Execute a workflow with an unauthicated POST request",
},
{
name: "Schedule",
type: "TRIGGER",
status: "uninitialized",
description: "Schedule execution time",
description: "Specify time",
trigger_type: "SCHEDULE",
errors: null,
large_image:
@@ -5091,7 +5132,7 @@ const AngularWorkflow = (defaultprops) => {
is_valid: true,
label: "Subflow",
environment: "onprem",
description: "Control another workflow",
description: "Control a workflow",
long_description: "Execute another workflow from this workflow",
},
{
@@ -5112,7 +5153,7 @@ const AngularWorkflow = (defaultprops) => {
name: "Office365",
type: "TRIGGER",
status: "uninitialized",
description: "Starts upon O365 email",
description: "O365 email trigger",
trigger_type: "EMAIL",
errors: null,
is_valid: cloudSyncEnabled || isCloud ? true : false,
@@ -5126,7 +5167,7 @@ const AngularWorkflow = (defaultprops) => {
name: "Gmail",
type: "TRIGGER",
status: "uninitialized",
description: "Trigger based on Gmail",
description: "Gmail email trigger",
trigger_type: "EMAIL",
errors: null,
is_valid: cloudSyncEnabled || isCloud ? true : false,
@@ -5203,10 +5244,11 @@ const AngularWorkflow = (defaultprops) => {
display: "flex",
flexDirection: "column",
marginLeft: "20px",
overflow: "hidden",
}}
>
<Grid item style={{ flex: "1" }}>
<h3 style={{ marginBottom: "0px", marginTop: "10px" }}>
<Grid item style={{ flex: "1", overflow: "hidden",}}>
<h3 style={{ marginBottom: "0px", marginTop: "10px", overflow: "hidden" }}>
{trigger.name}
</h3>
</Grid>
@@ -5323,7 +5365,7 @@ const AngularWorkflow = (defaultprops) => {
}
// AUTHENTICATION
if (app.authentication.required) {
if (app.authentication !== undefined && app.authentication !== null && app.authentication.required === true) {
console.log("App auth is required!")
// Setup auth here :)
@@ -5448,6 +5490,7 @@ const AngularWorkflow = (defaultprops) => {
var description = ""
if (
app.actions[0].parameters !== undefined &&
app.actions[0].parameters !== null &&
app.actions[0].parameters.length > 0
) {
@@ -5455,6 +5498,8 @@ const AngularWorkflow = (defaultprops) => {
}
if (
app.actions[0].returns !== undefined &&
app.actions[0].returns !== null &&
app.actions[0].returns.example !== undefined &&
app.actions[0].returns.example !== null &&
app.actions[0].returns.example.length > 0
@@ -5510,6 +5555,7 @@ const AngularWorkflow = (defaultprops) => {
: "",
authentication_id: "",
finished: false,
template: app.template === true ? true : false,
};
// FIXME: overwrite category if the ACTION chosen has a different category
@@ -5534,10 +5580,12 @@ const AngularWorkflow = (defaultprops) => {
};
const AppView = (props) => {
const { allApps, prioritizedApps, filteredApps } = props;
const { allApps, prioritizedApps, filteredApps, extraApps } = props;
//extraApps,
const [visibleApps, setVisibleApps] = React.useState(
prioritizedApps.concat(
filteredApps.filter((innerapp) => !internalIds.includes(innerapp.id))
Array.prototype.concat.apply(
prioritizedApps,
filteredApps.filter((innerapp) => !internalIds.includes(innerapp.id)),
)
);
@@ -5827,7 +5875,7 @@ const AngularWorkflow = (defaultprops) => {
runSearch(event.target.value);
}}
/>
{visibleApps.length > 0 ? (
{visibleApps.length > extraApps.length ? (
<div style={appScrollStyle}>
{visibleApps.map((app, index) => {
if (app.invalid) {
@@ -7293,7 +7341,7 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
console.log(error.toString());
console.log("Get gmail folder error: ", error.toString());
});
};
@@ -7347,7 +7395,7 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
console.log(error.toString());
console.log("Get outlook folders error: ", error.toString());
});
};
@@ -7368,7 +7416,8 @@ const AngularWorkflow = (defaultprops) => {
setTriggerAuthentication(responseJson);
})
.catch((error) => {
console.log(error.toString());
//console.log(error.toString());
console.log("Set outlook auth error: ", error.toString());
});
};
@@ -7458,7 +7507,7 @@ const AngularWorkflow = (defaultprops) => {
setGmailFolders();
})
.catch((error) => {
console.log(error.toString());
console.log("Set gmail trigg error: ", error.toString());
});
}, 2500);
@@ -7556,7 +7605,7 @@ const AngularWorkflow = (defaultprops) => {
setOutlookFolders();
})
.catch((error) => {
console.log(error.toString());
console.log("Set outlook trigger error: ", error.toString());
});
}, 2500);
@@ -9476,7 +9525,8 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
alert.error(error.toString());
//alert.error(error.toString());
console.log("Stop mailsub error: ", error.toString());
});
};
@@ -9552,7 +9602,8 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
alert.error(error.toString());
//alert.error(error.toString());
console.log("Start mailsub error: ", error.toString());
});
};
@@ -9636,7 +9687,8 @@ const AngularWorkflow = (defaultprops) => {
}
})
.catch((error) => {
console.log(error.toString());
//console.log(error.toString());
console.log("New webhook error: ", error.toString());
});
};
@@ -9679,7 +9731,8 @@ const AngularWorkflow = (defaultprops) => {
setSelectedTrigger(trigger);
})
.catch((error) => {
alert.error(error.toString());
//alert.error(error.toString());
alert.error("Delete webhook error: ", error.toString());
});
};
+27 -11
View File
@@ -289,8 +289,8 @@ const AppCreator = (defaultprops) => {
type: "header",
example: "",
};
const [extraAuth, setExtraAuth] = useState([]);
const [extraAuth, setExtraAuth] = useState([]);
const [app, setApp] = useState({});
const [appAuthentication, setAppAuthentication] = React.useState([]);
const [selectedAction, setSelectedAction] = useState({});
@@ -1420,6 +1420,8 @@ const AppCreator = (defaultprops) => {
//console.log("SECURITYSCHEMES: ", securitySchemes)
if (securitySchemes !== undefined) {
console.log("NEWAUTH: ", securitySchemes)
var valueset = false
// FIXME: Should add Oauth2 (Microsoft) and JWT (Wazuh)
//console.log("SECURITY: ", securitySchemes)
//if (Object.entries(securitySchemes) > 1 &&
@@ -1444,18 +1446,31 @@ const AppCreator = (defaultprops) => {
setAuthenticationRequired(true);
} else if (key === "ApiKeyAuth" || key === "Token" || ((value.in === "header" || value.in === "query") && value.name !== undefined)) {
setAuthenticationOption("API key");
if (authenticationOption === "" || authenticationOption === "No authentication") {
setAuthenticationOption("API key");
}
value.in = value.in.charAt(0).toUpperCase() + value.in.slice(1);
setParameterLocation(value.in);
if (!apikeySelection.includes(value.in)) {
console.log("APIKEY SELECT: ", apikeySelection);
alert.error("Might be error in setting up API key authentication");
}
if (valueset === false) {
valueset = true
value.in = value.in.charAt(0).toUpperCase() + value.in.slice(1)
console.log("PARAM NAME: ", value.name);
setParameterName(value.name);
setAuthenticationRequired(true);
setParameterLocation(value.in);
if (!apikeySelection.includes(value.in)) {
console.log("APIKEY SELECT: ", apikeySelection);
alert.error("Might be error in setting up API key authentication");
}
console.log("PARAM NAME: ", value.name);
setParameterName(value.name);
setAuthenticationRequired(true);
} else {
newauth.push({
"name": key,
"type": value.in.toLowerCase(),
"in": value.in.toLowerCase(),
"example": "",
})
}
if (value.description !== undefined && value.description !== null && value.description.length > 0) {
// Don't want a real description - just the ones we're replacing with
@@ -2365,6 +2380,7 @@ const AppCreator = (defaultprops) => {
<span style={{ width: 50 }} />
)}
</div>
{extraAuth.map((value, index) => {
return (
<span
+833
View File
@@ -0,0 +1,833 @@
import React, { useState, useEffect } from "react";
import { useInterval } from "react-powerhooks";
import DetectionFramework from "../components/DetectionFramework.jsx";
import { makeStyles, useTheme } from "@material-ui/core/styles";
// nodejs library that concatenates classes
import classNames from "classnames";
import theme from '../theme';
import { useNavigate, Link, useParams } from "react-router-dom";
// react plugin used to create charts
//import { Line, Bar } from "react-chartjs-2";
import { useAlert } from "react-alert";
import Autocomplete from "@material-ui/lab/Autocomplete";
import Draggable from "react-draggable";
import {
Tooltip,
TextField,
IconButton,
Button,
Typography,
Grid,
Paper,
Chip,
Checkbox,
} from "@material-ui/core";
import {
Close as CloseIcon,
DoneAll as DoneAllIcon,
Description as DescriptionIcon,
PlayArrow as PlayArrowIcon,
Edit as EditIcon,
CheckBox as CheckBoxIcon,
CheckBoxOutlineBlank as CheckBoxOutlineBlankIcon,
OpenInNew as OpenInNewIcon,
} from "@material-ui/icons";
import WorkflowPaper from "../components/WorkflowPaper.jsx"
import { removeParam } from "../views/AngularWorkflow.jsx"
// core components
//import {
// chartExample1,
// chartExample2,
// chartExample3,
// chartExample4,
//} from "../charts.js";
import {
RadialBarChart,
RadialAreaChart,
RadialAxis,
StackedBarSeries,
TooltipArea,
ChartTooltip,
TooltipTemplate,
RadialAreaSeries,
RadialPointSeries,
RadialArea,
RadialLine,
TreeMap,
TreeMapSeries,
TreeMapLabel,
TreeMapRect,
Line,
LineChart,
LineSeries,
LinearYAxis,
LinearXAxis,
LinearYAxisTickSeries,
LinearXAxisTickSeries,
AreaChart,
AreaSeries,
PointSeries,
} from 'reaviz';
const useStyles = makeStyles({
notchedOutline: {
borderColor: "#f85a3e !important",
},
root: {
"& .MuiAutocomplete-listbox": {
border: "2px solid #f85a3e",
color: "white",
fontSize: 18,
"& li:nth-child(even)": {
backgroundColor: "#CCC",
},
"& li:nth-child(odd)": {
backgroundColor: "#FFF",
},
},
},
inputRoot: {
color: "white",
// This matches the specificity of the default styles at https://github.com/mui-org/material-ui/blob/v4.11.3/packages/material-ui-lab/src/Autocomplete/Autocomplete.js#L90
"&:hover .MuiOutlinedInput-notchedOutline": {
borderColor: "#f86a3e",
},
},
});
const inputdata = [
{
"key": "Threat Intel",
"value": 18,
"x": "2020-02-17T08:00:00.000Z",
"x0": "2020-02-17T08:00:00.000Z",
"x1": "2020-02-17T08:00:00.000Z",
"y": 18,
"y0": 0,
"y1": 18
},
{
"key": "Threat Intel",
"value": 3,
"x": "2020-02-21T08:00:00.000Z",
"x0": "2020-02-21T08:00:00.000Z",
"x1": "2020-02-21T08:00:00.000Z",
"y": 3,
"y0": 0,
"y1": 3
},
{
"key": "Threat Intel",
"value": 14,
"x": "2020-02-26T08:00:00.000Z",
"x0": "2020-02-26T08:00:00.000Z",
"x1": "2020-02-26T08:00:00.000Z",
"y": 14,
"y0": 0,
"y1": 14
},
{
"key": "Threat Intel",
"value": 18,
"x": "2020-02-29T08:00:00.000Z",
"x0": "2020-02-29T08:00:00.000Z",
"x1": "",
"y": 18,
"y0": 0,
"y1": 18
}
]
const LineChartWrapper = ({keys, height, width}) => {
const [hovered, setHovered] = useState("");
//console.log("Date: ", new Date("2019-11-14T08:00:00.000Z"))
console.log("Keys: ", keys)
var inputdata = keys.data
/*
const inputdata = [{
"key": "Intel",
"data": [
{ key: new Date('11/22/2019'), data: 3, metadata: {color: "orange", "name": "Intel"}},
{ key: new Date('11/24/2019'), data: 8, metadata: {color: "orange", "name": "Intel"}},
{ key: new Date('11/29/2019'), data: 2, metadata: {color: "orange", "name": "Intel"}},
]},
{
"key": "Popper",
"data": [
{ key: new Date('11/24/2019'), data: 9, },
{ key: new Date('11/29/2019'), data: 3, },
]
}
]
*/
return (
<div style={{}}>
<Typography variant="h6" style={{marginBotton: 15}}>
{keys.title}
</Typography>
<AreaChart
style={{marginTop: 15}}
height={height}
width={width}
data={inputdata}
series={
<AreaSeries
type="grouped"
symbols={
<PointSeries show={true} />
}
colorScheme={(colorInput) => {
var color = "cybertron"
if (colorInput !== undefined && colorInput.length > 0) {
color = colorInput[0].metadata !== undefined && colorInput[0].metadata.color !== undefined ? colorInput[0].metadata.color : color
}
return color
}}
tooltip={
<TooltipArea
color={"#000000"}
style={{
backgroundColor: "red",
}}
isRadial={true}
onValueEnter={(event) => {
if (hovered !== event.value.x) {
//setHovered(event.value.x)
}
}}
tooltip={
<ChartTooltip
followCursor={true}
modifiers={{
offset: '5px, 5px'
}}
content={(data, color) => {
console.log("DATA: ", data)
const name = data.metadata !== undefined && data.metadata.name !== undefined ? data.metadata.name : "No"
return (
<div style={{borderRadius: theme.palette.borderRadius, backgroundColor: theme.palette.inputColor, border: "1px solid rgba(255,255,255,0.3)", color: "white", padding: 5, cursor: "pointer",}}>
<Typography variant="body1">
{name}
</Typography>
</div>
)
/*
<TooltipTemplate
color={"#ffffff"}
value={{
x: data.x,
}}
/>
)
*/
}
}
/>
}
/>
}
/>
}
/>
</div>
)
}
const RadialChart = ({keys, setSelectedCategory}) => {
const [hovered, setHovered] = useState("");
return (
<div style={{cursor: "pointer",}} onClick={() => {
console.log("Click: ", hovered)
if (setSelectedCategory !== undefined) {
setSelectedCategory(hovered)
}
}}>
<RadialAreaChart
id="workflow_categories"
height={500}
width={500}
data={keys}
axis={<RadialAxis type="category" />}
series={
<RadialAreaSeries
interpolation="smooth"
colorScheme={(colorInput) => {
return '#f86a3e'
}}
animated={false}
id="workflow_series_id"
style={{cursor: "pointer",}}
line={
<RadialLine
color={"#000000"}
data={(data, color) => {
console.log("INFO: ", data, color)
return (
null
)
}}
/>
}
tooltip={
<TooltipArea
color={"#000000"}
style={{
backgroundColor: "red",
}}
isRadial={true}
onValueEnter={(event) => {
if (hovered !== event.value.x) {
setHovered(event.value.x)
}
}}
tooltip={
<ChartTooltip
followCursor={true}
modifiers={{
offset: '5px, 5px'
}}
content={(data, color) => {
return (
<div style={{borderRadius: theme.palette.borderRadius, backgroundColor: theme.palette.inputColor, border: "1px solid rgba(255,255,255,0.3)", color: "white", padding: 5, cursor: "pointer",}}>
<Typography variant="body1">
{data.x}
</Typography>
</div>
)
/*
<TooltipTemplate
color={"#ffffff"}
value={{
x: data.x,
}}
/>
)
*/
}
}
/>
}
/>
}
/>
}
/>
</div>
)
//axis={<RadialAxis type="category" />}
}
// This is the start of a dashboard that can be used.
// What data do we fill in here? Idk
const Dashboard = (props) => {
const { globalUrl, isLoggedIn } = 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);
const [keys, setKeys] = useState([])
const [treeKeys, setTreeKeys] = useState([])
const [selectedUsecaseCategory, setSelectedUsecaseCategory] = useState("");
const [selectedUsecases, setSelectedUsecases] = useState([]);
const [usecases, setUsecases] = useState([]);
const [workflows, setWorkflows] = useState([]);
const [frameworkData, setFrameworkData] = useState(undefined);
const [widgetData, setWidgetData] = useState(undefined);
let navigate = useNavigate();
const isCloud =
window.location.host === "localhost:3002" ||
window.location.host === "shuffler.io";
useEffect(() => {
if (selectedUsecaseCategory.length === 0) {
setSelectedUsecases(usecases)
} else {
const foundUsecase = usecases.find(data => data.name === selectedUsecaseCategory)
if (foundUsecase !== undefined && foundUsecase !== null) {
setSelectedUsecases([foundUsecase])
}
}
}, [selectedUsecaseCategory])
const checkSelectedParams = () => {
const urlSearchParams = new URLSearchParams(window.location.search)
const params = Object.fromEntries(urlSearchParams.entries())
const curpath = typeof window === "undefined" || window.location === undefined ? "" : window.location.pathname;
const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search;
const foundQuery = params["selected"]
if (foundQuery !== null && foundQuery !== undefined) {
setSelectedUsecaseCategory(foundQuery)
const newitem = removeParam("selected", cursearch);
navigate(curpath + newitem)
}
const foundQuery2 = params["selected_object"]
if (foundQuery2 !== null && foundQuery2 !== undefined) {
console.log("Got selected_object: ", foundQuery2)
const queryName = foundQuery2.toLowerCase().replaceAll("_", " ")
// Waiting a bit for it to render
setTimeout(() => {
const foundItem = document.getElementById(queryName)
if (foundItem !== undefined && foundItem !== null) {
foundItem.click()
} else {
//console.log("Couldn't find item with name ", queryName)
}
}, 100);
}
}
useEffect(() => {
if (usecases.length > 0) {
console.log(usecases)
checkSelectedParams()
}
}, [usecases])
const getWidget = (dashboard, widget) => {
fetch(`${globalUrl}/api/v1/dashboards/${dashboard}/widgets/${widget}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for framework!");
}
return response.json();
})
.then((responseJson) => {
console.log("Resp: ", responseJson)
if (responseJson.success === false) {
if (responseJson.reason !== undefined) {
//alert.error("Failed loading: " + responseJson.reason)
} else {
//alert.error("Failed to load framework for your org.")
}
} else {
var tmpdata = responseJson
for (var key in tmpdata.data) {
for (var subkey in tmpdata.data[key].data) {
tmpdata.data[key].data[subkey].key = new Date(tmpdata.data[key].data[subkey].key)
}
}
console.log("VAl: ", tmpdata)
setWidgetData(tmpdata)
}
})
.catch((error) => {
//alert.error(error.toString());
})
}
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 handleKeysetting = (categorydata) => {
var allCategories = []
var treeCategories = []
for (key in categorydata) {
const category = categorydata[key]
allCategories.push({"key": category.name, "data": category.list.length, "color": category.color})
treeCategories.push({"key": category.name, "data": 100, "color": category.color,})
for (var subkey in category.list) {
treeCategories.push({"key": category.list[subkey].name, "data": 20, "color": category.color})
}
}
setKeys(allCategories)
setTreeKeys(treeCategories)
}
const fetchUsecases = (workflows) => {
fetch(globalUrl + "/api/v1/workflows/usecases", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for usecases");
}
return response.json();
})
.then((responseJson) => {
// Matching workflows with usecases
if (responseJson.success !== false) {
if (workflows !== undefined && workflows !== null && workflows.length > 0) {
var categorydata = responseJson
var newcategories = []
for (var key in categorydata) {
var category = categorydata[key]
category.matches = []
for (var subcategorykey in category.list) {
var subcategory = category.list[subcategorykey]
subcategory.matches = []
for (var workflowkey in workflows) {
const workflow = workflows[workflowkey]
if (workflow.usecase_ids !== undefined && workflow.usecase_ids !== null) {
for (var usecasekey in workflow.usecase_ids) {
if (workflow.usecase_ids[usecasekey].toLowerCase() === subcategory.name.toLowerCase()) {
category.matches.push({
"workflow": workflow.id,
"category": subcategory.name,
})
subcategory.matches.push(workflow)
break
}
}
}
if (subcategory.matches.length > 0) {
break
}
}
}
newcategories.push(category)
}
if (newcategories !== undefined && newcategories !== null && newcategories.length > 0) {
handleKeysetting(newcategories)
setUsecases(newcategories)
setSelectedUsecases(newcategories)
} else {
handleKeysetting(responseJson)
setUsecases(responseJson)
setSelectedUsecases(responseJson)
}
} else {
handleKeysetting(responseJson)
setUsecases(responseJson)
setSelectedUsecases(responseJson)
}
}
})
.catch((error) => {
//alert.error("ERROR: " + error.toString());
console.log("ERROR: " + error.toString());
});
};
useEffect(() => {
getWidget("main", "tmp")
//fetchUsecases()
}, []);
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);
}
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());
console.log("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",
},
},
],
},
};
const dayGraph = {
data: (canvas) => {
let ctx = canvas.getContext("2d");
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
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",
];
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();
},
});
if (firstRequest) {
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 :)
// 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()
// Index = what day are we on
// 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 startdate = new Date();
startdate.setDate(-i);
startdate.setHours(0, 0, 0, 0);
var endtime = enddate.getTime() / 1000;
var starttime = startdate.getTime() / 1000;
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;
}
//break
}
}
newDayGraphLabels.push(i);
}
console.log(newDayGraphLabels);
console.log(newDayGraphData);
}
}
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;
}
if (stats[data].total === undefined) {
return null;
}
return (
<div>
{data}: {stats[data].total}
</div>
);
})}
</div>
) : null;
const data = (
<div className="content" style={{width: 1000, margin: "auto", paddingBottom: 200, textAlign: "center",}}>
<div style={{width: 500, margin: "auto"}}>
{keys.length > 0 ?
<span>
<RadialChart keys={keys} setSelectedCategory={setSelectedUsecaseCategory} />
</span>
: null}
</div>
{widgetData === undefined ? null :
<Draggable>
<Paper style={{height: 350, width: 500, padding: "15px 15px 15px 15px", }}>
<LineChartWrapper keys={widgetData} height={280} width={470} />
</Paper>
</Draggable>
}
</div>
);
const dataWrapper = (
<div style={{ maxWidth: 1366, margin: "auto" }}>{data}</div>
);
return dataWrapper;
};
export default Dashboard;
+1 -1
View File
@@ -733,7 +733,7 @@ const Settings = (props) => {
{isCloud ?
<span>
<Typography variant="body1" color="textSecondary">
By connecting your Github account, you agree to our <a href="/docs/terms_of_service" target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Terms of Service</a>, and acknowledge that your non-sensitive data will be turned into a <a target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}} href="https://shuffler.io/search?tab=creators">creator account</a>. This enables you to earn a passive income from Shuffle. This IS reversible.
By connecting your Github or Metamask account, you agree to our <a href="/docs/terms_of_service" target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}}>Terms of Service</a>, and acknowledge that your non-sensitive data will be turned into a <a target="_blank" style={{ textDecoration: "none", color: "#f86a3e"}} href="https://shuffler.io/search?tab=creators">creator account</a>. This enables you to earn a passive income from Shuffle. This IS reversible. Support: support@shuffler.io
</Typography>
<Button
style={{ height: 40, marginTop: 10 }}