Merge branch 'Shuffle:launch' into launch
This commit is contained in:
@@ -16,6 +16,7 @@ import Apps from "./views/Apps";
|
||||
import AppCreator from "./views/AppCreator";
|
||||
|
||||
import Dashboard from "./views/Dashboard.jsx";
|
||||
import DashboardView from "./views/DashboardViews.jsx";
|
||||
import AdminSetup from "./views/AdminSetup";
|
||||
import Admin from "./views/Admin";
|
||||
import Docs from "./views/Docs";
|
||||
@@ -656,6 +657,18 @@ const App = (message, props) => {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/dashboards"
|
||||
element={
|
||||
<DashboardView
|
||||
isLoaded={isLoaded}
|
||||
isLoggedIn={isLoggedIn}
|
||||
globalUrl={globalUrl}
|
||||
{...props}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// Move this to the backend to be loaded in?
|
||||
const extraApps = [{
|
||||
"name": "Cases",
|
||||
"description": "Allows use of other Case Management apps without knowing how to use them.",
|
||||
"app_version": "1.0.0",
|
||||
"app_name": "Cases",
|
||||
"type": "ACTION",
|
||||
"large_image": encodeURI('data:image/svg+xml;utf-8,<svg fill="rgb(248,90,62)" width="${svgSize}" height="${svgSize}" viewBox="0 0 ${svgSize} ${svgSize}" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M15.6408 8.39233H18.0922V10.0287H15.6408V8.39233ZM0.115234 8.39233H2.56663V10.0287H0.115234V8.39233ZM9.92083 0.21051V2.66506H8.28656V0.21051H9.92083ZM3.31839 2.25596L5.05889 4.00687L3.89856 5.16051L2.15807 3.42596L3.31839 2.25596ZM13.1485 3.99869L14.8808 2.25596L16.0493 3.42596L14.3088 5.16051L13.1485 3.99869ZM9.10369 4.30142C10.404 4.30142 11.651 4.81863 12.5705 5.73926C13.4899 6.65989 14.0065 7.90854 14.0065 9.21051C14.0065 11.0269 13.0178 12.6141 11.5551 13.4651V14.9378C11.5551 15.1548 11.469 15.3629 11.3158 15.5163C11.1625 15.6698 10.9547 15.756 10.738 15.756H7.46943C7.25271 15.756 7.04487 15.6698 6.89163 15.5163C6.73839 15.3629 6.6523 15.1548 6.6523 14.9378V13.4651C5.18963 12.6141 4.2009 11.0269 4.2009 9.21051C4.2009 7.90854 4.71744 6.65989 5.63689 5.73926C6.55635 4.81863 7.80339 4.30142 9.10369 4.30142ZM10.738 16.5741V17.3923C10.738 17.6093 10.6519 17.8174 10.4986 17.9709C10.3454 18.1243 10.1375 18.2105 9.92083 18.2105H8.28656C8.06984 18.2105 7.862 18.1243 7.70876 17.9709C7.55552 17.8174 7.46943 17.6093 7.46943 17.3923V16.5741H10.738ZM8.28656 14.1196H9.92083V12.3769C11.3345 12.0169 12.3722 10.7323 12.3722 9.21051C12.3722 8.34253 12.0279 7.5101 11.4149 6.89634C10.8019 6.28259 9.97056 5.93778 9.10369 5.93778C8.23683 5.93778 7.40546 6.28259 6.79249 6.89634C6.17953 7.5101 5.83516 8.34253 5.83516 9.21051C5.83516 10.7323 6.87292 12.0169 8.28656 12.3769V14.1196Z" /></svg>'),
|
||||
"template": true,
|
||||
"actions": [{
|
||||
"name": "Create Alert",
|
||||
"description": "Create a ticket",
|
||||
"parameters": [{
|
||||
"name": "id",
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"multiline": true,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}]
|
||||
|
||||
export default extraApps
|
||||
@@ -856,7 +856,7 @@ const Header = (props) => {
|
||||
position: "fixed",
|
||||
minHeight: 60,
|
||||
top: 0,
|
||||
//zIndex: 10000,
|
||||
zIndex: 10000,
|
||||
backgroundColor: "inherit",
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1064,6 +1064,8 @@ const ParsedAction = (props) => {
|
||||
*/
|
||||
}
|
||||
|
||||
console.log("APP: ", selectedApp)
|
||||
|
||||
// FIXME: Issue #40 - selectedActionParameters not reset
|
||||
if (
|
||||
Object.getOwnPropertyNames(selectedAction).length > 0 &&
|
||||
@@ -1090,6 +1092,114 @@ const ParsedAction = (props) => {
|
||||
<b>Parameters</b>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
{selectedAction.template === true && selectedAction.matching_actions !== undefined && selectedAction.matching_actions !== null && selectedAction.matching_actions.length > 0 ?
|
||||
<div>
|
||||
<Typography variant="body1">
|
||||
Select an app you want to use
|
||||
</Typography>
|
||||
<Autocomplete
|
||||
id="template_action_search"
|
||||
autoHighlight
|
||||
value={selectedAction}
|
||||
classes={{ inputRoot: classes.inputRoot }}
|
||||
ListboxProps={{
|
||||
style: {
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
getOptionLabel={(option) => {
|
||||
console.log("LABEL: ", option)
|
||||
if (
|
||||
option === undefined ||
|
||||
option === null ||
|
||||
option.app_name === undefined ||
|
||||
option.app_name === null
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const newname = (
|
||||
option.app_name.charAt(0).toUpperCase() + option.app_name.substring(1)
|
||||
).replaceAll("_", " ");
|
||||
return newname;
|
||||
}}
|
||||
options={selectedAction.matching_actions}
|
||||
fullWidth
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
height: 50,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
onChange={(event, newValue) => {
|
||||
console.log("SELECT: ", event, newValue)
|
||||
// Workaround with event lol
|
||||
//if (newValue !== undefined && newValue !== null) {
|
||||
// setNewSelectedAction({ target: { value: newValue.name } });
|
||||
//}
|
||||
}}
|
||||
renderOption={(data) => {
|
||||
var newActionname = data.app_name;
|
||||
if (
|
||||
data.label !== undefined &&
|
||||
data.label !== null &&
|
||||
data.label.length > 0
|
||||
) {
|
||||
newActionname = data.label;
|
||||
}
|
||||
|
||||
const iconInfo = GetIconInfo({ name: data.app_name });
|
||||
const useIcon = iconInfo.originalIcon;
|
||||
|
||||
newActionname = (
|
||||
newActionname.charAt(0).toUpperCase() +
|
||||
newActionname.substring(1)
|
||||
).replaceAll("_", " ");
|
||||
|
||||
return (
|
||||
<div style={{ display: "flex" }}>
|
||||
<span
|
||||
style={{
|
||||
marginRight: 10,
|
||||
marginTop: "auto",
|
||||
marginBottom: "auto",
|
||||
}}
|
||||
>
|
||||
{useIcon}
|
||||
</span>
|
||||
<span style={{}}>{newActionname}</span>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
renderInput={(params) => {
|
||||
if (params.inputProps !== undefined && params.inputProps !== null && params.inputProps.value !== undefined && params.inputProps.value !== null) {
|
||||
const prefixes = ["Post", "Put", "Patch"]
|
||||
for (var key in prefixes) {
|
||||
if (params.inputProps.value.startsWith(prefixes[key])) {
|
||||
params.inputProps.value = params.inputProps.value.replace(prefixes[key]+" ", "", -1)
|
||||
if (params.inputProps.value.length > 1) {
|
||||
params.inputProps.value = params.inputProps.value.charAt(0).toUpperCase()+params.inputProps.value.substring(1)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<TextField
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette.borderRadius,
|
||||
}}
|
||||
{...params}
|
||||
label="Find App to Translate"
|
||||
variant="outlined"
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
: null}
|
||||
{selectedAction.description !== undefined && selectedAction.description !== null && selectedAction.description.length > 0 && hiddenDescription === false ? (
|
||||
<div
|
||||
style={{
|
||||
@@ -1884,7 +1994,6 @@ const ParsedAction = (props) => {
|
||||
const coverColor = "#82ccc3"
|
||||
//menuPosition.left -= 50
|
||||
//menuPosition.top -= 250
|
||||
console.log(menuPosition)
|
||||
return parsedPaths.length > 0 ? (
|
||||
<NestedMenuItem
|
||||
key={innerdata.name}
|
||||
@@ -2369,7 +2478,7 @@ const ParsedAction = (props) => {
|
||||
title="See previous results for this action"
|
||||
placement="top"
|
||||
>
|
||||
<ArrowLeftIcon style={{ color: "white" }} />
|
||||
<ArrowLeftIcon style={{ color: "rgba(255,255,255,0.7)" }} />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
@@ -2389,7 +2498,7 @@ const ParsedAction = (props) => {
|
||||
title="Read app docs"
|
||||
placement="top"
|
||||
>
|
||||
<DescriptionIcon style={{ color: "white" }} />
|
||||
<DescriptionIcon style={{ color: "rgba(255,255,255,0.7)" }} />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
@@ -2413,7 +2522,7 @@ const ParsedAction = (props) => {
|
||||
title="What are actions?"
|
||||
placement="top"
|
||||
>
|
||||
<HelpOutlineIcon style={{ color: "white" }} />
|
||||
<HelpOutlineIcon style={{ color: "rgba(255,255,255,0.7)" }} />
|
||||
</Tooltip>
|
||||
</a>
|
||||
</IconButton>
|
||||
@@ -2448,7 +2557,7 @@ const ParsedAction = (props) => {
|
||||
title={selectedAction.run_magic_output === undefined || selectedAction.run_magic_output === null || selectedAction.run_magic_output === false ? "Click to enable magic parsing" : "Click to disable magic parsing"}
|
||||
placement="top"
|
||||
>
|
||||
<AutoFixHighIcon style={{ color: selectedAction.run_magic_output === undefined || selectedAction.run_magic_output === null || selectedAction.run_magic_output === false ? "white" : "#f86a3e"}} />
|
||||
<AutoFixHighIcon style={{ color: selectedAction.run_magic_output === undefined || selectedAction.run_magic_output === null || selectedAction.run_magic_output === false ? "rgba(255,255,255,0.7)" : "#f86a3e"}} />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
|
||||
@@ -2529,7 +2638,7 @@ const ParsedAction = (props) => {
|
||||
/>
|
||||
<div style={{display: "flex"}}>
|
||||
<div style={{flex: 5}}>
|
||||
<Typography>Name</Typography>
|
||||
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Name</Typography>
|
||||
<TextField
|
||||
style={theme.palette.textFieldStyle}
|
||||
InputProps={{
|
||||
@@ -2626,7 +2735,7 @@ const ParsedAction = (props) => {
|
||||
placement="top"
|
||||
>
|
||||
<span>
|
||||
<Typography>Delay</Typography>
|
||||
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Delay</Typography>
|
||||
<TextField
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
@@ -2691,7 +2800,7 @@ const ParsedAction = (props) => {
|
||||
selectedAction.authentication !== null &&
|
||||
selectedAction.authentication.length > 0 ? (
|
||||
<div style={{ marginTop: 15 }}>
|
||||
<Typography>Authentication</Typography>
|
||||
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Authentication</Typography>
|
||||
<div style={{ display: "flex" }}>
|
||||
<Select
|
||||
MenuProps={{
|
||||
@@ -2797,7 +2906,7 @@ const ParsedAction = (props) => {
|
||||
|
||||
{showEnvironment !== undefined && showEnvironment && environments.length > 1 ? (
|
||||
<div style={{ marginTop: "20px" }}>
|
||||
<Typography>Environment</Typography>
|
||||
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Environment</Typography>
|
||||
<Select
|
||||
MenuProps={{
|
||||
disableScrollLock: true,
|
||||
|
||||
@@ -451,7 +451,7 @@ const CodeEditor = (props) => {
|
||||
>
|
||||
{liquidFilters.map((item, index) => {
|
||||
return (
|
||||
<MenuItem onClick={() => {
|
||||
<MenuItem key={index} onClick={() => {
|
||||
handleClick(item)
|
||||
}}>{item.name}</MenuItem>
|
||||
)
|
||||
@@ -486,7 +486,7 @@ const CodeEditor = (props) => {
|
||||
>
|
||||
{mathFilters.map((item, index) => {
|
||||
return (
|
||||
<MenuItem onClick={() => {
|
||||
<MenuItem key={index} onClick={() => {
|
||||
handleClick(item)
|
||||
}}>{item.name}</MenuItem>
|
||||
)
|
||||
@@ -521,7 +521,7 @@ const CodeEditor = (props) => {
|
||||
>
|
||||
{pythonFilters.map((item, index) => {
|
||||
return (
|
||||
<MenuItem onClick={() => {
|
||||
<MenuItem key={index} onClick={() => {
|
||||
handleClick(item)
|
||||
}}>{item.name}</MenuItem>
|
||||
)
|
||||
|
||||
@@ -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());
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -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 }}
|
||||
|
||||
Reference in New Issue
Block a user