forked from p34709852/monkey
Reverted changed to ZT report page and fixed rule bug in diagram + whitespace.
This commit is contained in:
parent
223adb0f33
commit
0a044e2295
|
@ -1,64 +1,17 @@
|
|||
import React from 'react';
|
||||
import {Button, Col} from 'react-bootstrap';
|
||||
import React, {Fragment} from 'react';
|
||||
import {Col, Grid, Row} from 'react-bootstrap';
|
||||
import AuthComponent from '../AuthComponent';
|
||||
import ReportHeader, {ReportTypes} from "../report-components/common/ReportHeader";
|
||||
import PillarGrades from "../report-components/zerotrust/PillarGrades";
|
||||
import PillarLabel from "../report-components/zerotrust/PillarLabel";
|
||||
import ResponsiveVennDiagram from "../report-components/zerotrust/venn-components/ResponsiveVennDiagram";
|
||||
import PillarsOverview from "../report-components/zerotrust/PillarOverview";
|
||||
import FindingsTable from "../report-components/zerotrust/FindingsTable";
|
||||
import {SinglePillarRecommendationsStatus} from "../report-components/zerotrust/SinglePillarRecommendationsStatus";
|
||||
|
||||
let mockup = [
|
||||
{
|
||||
"Conclusive": 4,
|
||||
"Inconclusive": 0,
|
||||
"Positive": 1,
|
||||
"Unexecuted": 2,
|
||||
"pillar": "Data"
|
||||
},
|
||||
{
|
||||
"Conclusive": 0,
|
||||
"Inconclusive": 5,
|
||||
"Positive": 0,
|
||||
"Unexecuted": 2,
|
||||
"pillar": "People"
|
||||
},
|
||||
{
|
||||
"Conclusive": 0,
|
||||
"Inconclusive": 0,
|
||||
"Positive": 6,
|
||||
"Unexecuted": 3,
|
||||
"pillar": "Networks"
|
||||
},
|
||||
{
|
||||
"Conclusive": 2,
|
||||
"Inconclusive": 0,
|
||||
"Positive": 1,
|
||||
"Unexecuted": 1,
|
||||
"pillar": "Devices"
|
||||
},
|
||||
{
|
||||
"Conclusive": 0,
|
||||
"Inconclusive": 0,
|
||||
"Positive": 0,
|
||||
"Unexecuted": 0,
|
||||
"pillar": "Workloads"
|
||||
},
|
||||
{
|
||||
"Conclusive": 0,
|
||||
"Inconclusive": 2,
|
||||
"Positive": 0,
|
||||
"Unexecuted": 0,
|
||||
"pillar": "Visibility & Analytics"
|
||||
},
|
||||
{
|
||||
"Conclusive": 0,
|
||||
"Inconclusive": 0,
|
||||
"Positive": 0,
|
||||
"Unexecuted": 0,
|
||||
"pillar": "Automation & Orchestration"
|
||||
}
|
||||
];
|
||||
import SinglePillarDirectivesStatus from "../report-components/zerotrust/SinglePillarDirectivesStatus";
|
||||
import MonkeysStillAliveWarning from "../report-components/common/MonkeysStillAliveWarning";
|
||||
import ReportLoader from "../report-components/common/ReportLoader";
|
||||
import MustRunMonkeyWarning from "../report-components/common/MustRunMonkeyWarning";
|
||||
import SecurityIssuesGlance from "../report-components/common/SecurityIssuesGlance";
|
||||
import StatusesToPillarsSummary from "../report-components/zerotrust/StatusesToPillarsSummary";
|
||||
import PrintReportButton from "../report-components/common/PrintReportButton";
|
||||
import {extractExecutionStatusFromServerResponse} from "../report-components/common/ExecutionStatus";
|
||||
|
||||
class ZeroTrustReportPageComponent extends AuthComponent {
|
||||
|
||||
|
@ -67,16 +20,30 @@ class ZeroTrustReportPageComponent extends AuthComponent {
|
|||
|
||||
this.state = {
|
||||
allMonkeysAreDead: false,
|
||||
runStarted: false
|
||||
runStarted: true
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
let res;
|
||||
// Todo move to componentDidMount
|
||||
this.getZeroTrustReportFromServer(res);
|
||||
componentDidMount() {
|
||||
this.updateMonkeysRunning().then(res => this.getZeroTrustReportFromServer(res));
|
||||
}
|
||||
|
||||
const content = this.generateReportContent();
|
||||
updateMonkeysRunning = () => {
|
||||
return this.authFetch('/api')
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
this.setState(extractExecutionStatusFromServerResponse(res));
|
||||
return res;
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
let content;
|
||||
if (this.state.runStarted) {
|
||||
content = this.generateReportContent();
|
||||
} else {
|
||||
content = <MustRunMonkeyWarning/>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Col xs={12} lg={10}>
|
||||
|
@ -92,63 +59,75 @@ class ZeroTrustReportPageComponent extends AuthComponent {
|
|||
let content;
|
||||
|
||||
if (this.stillLoadingDataFromServer()) {
|
||||
content = "Still empty";
|
||||
content = <ReportLoader loading={true}/>;
|
||||
} else {
|
||||
const pillarsSection = <div>
|
||||
<h2>Pillars Overview</h2>
|
||||
<PillarGrades pillars={this.state.pillars}/>
|
||||
</div>;
|
||||
|
||||
const recommendationsSection = <div><h2>Recommendations Status</h2>
|
||||
{
|
||||
this.state.recommendations.map((recommendation) =>
|
||||
<SinglePillarRecommendationsStatus
|
||||
key={recommendation.pillar}
|
||||
pillar={recommendation.pillar}
|
||||
recommendationStatus={recommendation.recommendationStatus}/>
|
||||
)
|
||||
}
|
||||
</div>;
|
||||
|
||||
const findingSection = <div><h2>Findings</h2>
|
||||
<FindingsTable findings={this.state.findings}/></div>;
|
||||
|
||||
content = <div>
|
||||
{pillarsSection}
|
||||
{recommendationsSection}
|
||||
{findingSection}
|
||||
content = <div id="MainContentSection">
|
||||
{this.generateOverviewSection()}
|
||||
{this.generateDirectivesSection()}
|
||||
{this.generateFindingsSection()}
|
||||
</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="text-center no-print" style={{marginBottom: '20px'}}>
|
||||
<Button bsSize="large" onClick={() => {
|
||||
this.print();
|
||||
}}><i className="glyphicon glyphicon-print"/> Print Report</Button>
|
||||
<Fragment>
|
||||
<div style={{marginBottom: '20px'}}>
|
||||
<PrintReportButton onClick={() => {print();}} />
|
||||
</div>
|
||||
<div className="report-page">
|
||||
<ReportHeader report_type={ReportTypes.zeroTrust}/>
|
||||
<hr/>
|
||||
{content}
|
||||
<hr/>
|
||||
<pre>{JSON.stringify(this.state.pillars, undefined, 2)}</pre>
|
||||
<br/>
|
||||
<ResponsiveVennDiagram pillarsGrades={mockup} />
|
||||
<pre>{JSON.stringify(this.state.recommendations, undefined, 2)}</pre>
|
||||
<br/>
|
||||
<pre>{JSON.stringify(this.state.findings, undefined, 2)}</pre>
|
||||
</div>
|
||||
<div style={{marginTop: '20px'}}>
|
||||
<PrintReportButton onClick={() => {print();}} />
|
||||
</div>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
stillLoadingDataFromServer() {
|
||||
return typeof this.state.findings === "undefined" || typeof this.state.pillars === "undefined" || typeof this.state.recommendations === "undefined";
|
||||
generateFindingsSection() {
|
||||
return (<div id="findings-overview">
|
||||
<h2>Findings</h2>
|
||||
<FindingsTable pillarsToStatuses={this.state.pillars.pillarsToStatuses} findings={this.state.findings}/>
|
||||
</div>);
|
||||
}
|
||||
|
||||
print() {
|
||||
alert("unimplemented");
|
||||
generateDirectivesSection() {
|
||||
return (<div id="directives-overview">
|
||||
<h2>Directives</h2>
|
||||
{
|
||||
Object.keys(this.state.directives).map((pillar) =>
|
||||
<SinglePillarDirectivesStatus
|
||||
key={pillar}
|
||||
pillar={pillar}
|
||||
directivesStatus={this.state.directives[pillar]}
|
||||
pillarsToStatuses={this.state.pillars.pillarsToStatuses}/>
|
||||
)
|
||||
}
|
||||
</div>);
|
||||
}
|
||||
|
||||
generateOverviewSection() {
|
||||
return (<div id="overview-section">
|
||||
<h2>Overview</h2>
|
||||
<Grid fluid={true}>
|
||||
<Row className="show-grid">
|
||||
<Col xs={8} sm={8} md={8} lg={8}>
|
||||
<PillarsOverview pillarsToStatuses={this.state.pillars.pillarsToStatuses}
|
||||
grades={this.state.pillars.grades}/>
|
||||
</Col>
|
||||
<Col xs={4} sm={4} md={4} lg={4}>
|
||||
<MonkeysStillAliveWarning allMonkeysAreDead={this.state.allMonkeysAreDead}/>
|
||||
<SecurityIssuesGlance issuesFound={this.anyIssuesFound()}/>
|
||||
<StatusesToPillarsSummary statusesToPillars={this.state.pillars.statusesToPillars}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Grid>
|
||||
</div>);
|
||||
}
|
||||
|
||||
stillLoadingDataFromServer() {
|
||||
return typeof this.state.findings === "undefined" || typeof this.state.pillars === "undefined" || typeof this.state.directives === "undefined";
|
||||
}
|
||||
|
||||
getZeroTrustReportFromServer() {
|
||||
|
@ -160,11 +139,11 @@ class ZeroTrustReportPageComponent extends AuthComponent {
|
|||
findings: res
|
||||
});
|
||||
});
|
||||
this.authFetch('/api/report/zero_trust/recommendations')
|
||||
this.authFetch('/api/report/zero_trust/directives')
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
this.setState({
|
||||
recommendations: res
|
||||
directives: res
|
||||
});
|
||||
});
|
||||
this.authFetch('/api/report/zero_trust/pillars')
|
||||
|
@ -175,6 +154,14 @@ class ZeroTrustReportPageComponent extends AuthComponent {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
anyIssuesFound() {
|
||||
const severe = function(finding) {
|
||||
return (finding.status === "Conclusive" || finding.status === "Inconclusive");
|
||||
};
|
||||
|
||||
return this.state.findings.some(severe);
|
||||
}
|
||||
}
|
||||
|
||||
export default ZeroTrustReportPageComponent;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, {Component} from "react";
|
||||
import PillarLabel from "./PillarLabel";
|
||||
import * as PropTypes from "prop-types";
|
||||
import ResponsiveVennDiagram from "./VennDiagram";
|
||||
import ResponsiveVennDiagram from "./venn-components/ResponsiveVennDiagram";
|
||||
|
||||
const columns = [
|
||||
{
|
||||
|
|
|
@ -7,14 +7,13 @@ import { TypographicUtilities } from './Utility.js'
|
|||
import './VennDiagram.css'
|
||||
|
||||
class VennDiagram extends React.Component{
|
||||
|
||||
constructor(props_){
|
||||
|
||||
super(props_);
|
||||
|
||||
this.state = { tooltip: { top: 0, left: 0, display: 'none', html: '' } }
|
||||
this.state = { tooltip: { top: 0, left: 0, display: 'none', html: '' } };
|
||||
|
||||
this.width = this.height = 512, this.zOrder = [];
|
||||
this.width = this.height = 512;
|
||||
this.zOrder = [];
|
||||
|
||||
this.colors = ['#777777', '#D9534F', '#F0AD4E', '#5CB85C'];
|
||||
this.prefix = 'vennDiagram';
|
||||
|
@ -24,14 +23,13 @@ class VennDiagram extends React.Component{
|
|||
|
||||
this.thirdWidth = this.width / 3;
|
||||
this.sixthWidth = this.width / 6;
|
||||
this.width2By7 = 2 * this.width / 7
|
||||
this.width2By7 = 2 * this.width / 7;
|
||||
this.width1By11 = this.width / 11;
|
||||
this.width1By28 = this.width / 28;
|
||||
|
||||
this.toggle = false;
|
||||
|
||||
this.layout = {
|
||||
|
||||
Data: { cx: 0, cy: 0, r: this.thirdWidth - this.offset * 2, offset: {x: 0, y: 0} },
|
||||
People: { cx: -this.width2By7, cy: 0, r: this.sixthWidth, offset: {x: this.width1By11, y: 0} },
|
||||
Networks: { cx: this.width2By7, cy: 0, r: this.sixthWidth, offset: {x: -this.width1By11, y: 0} },
|
||||
|
@ -39,13 +37,12 @@ class VennDiagram extends React.Component{
|
|||
Workloads : { cx: 0, cy: -this.width2By7, r: this.sixthWidth, offset: {x: 0, y: this.width1By11} },
|
||||
VisibilityAndAnalytics : { inner: this.thirdWidth - this.width1By28, outer: this.thirdWidth },
|
||||
AutomationAndOrchestration: { inner: this.thirdWidth - this.width1By28 * 2, outer: this.thirdWidth - this.width1By28 }
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
RULE #1: All scores have to be equal 0, except Unexecuted [U] which could be also a negative integer
|
||||
sum(C, I, P, U) has to be <=0
|
||||
sum(C, I, P) has to be <=0
|
||||
|
||||
RULE #2: Conclusive [C] has to be > 0,
|
||||
sum(C) > 0
|
||||
|
@ -62,31 +59,25 @@ class VennDiagram extends React.Component{
|
|||
|
||||
this.rules = [
|
||||
|
||||
{ id: 'Rule #1', f: function(d_){ return d_['Conclusive'] + d_['Inconclusive'] + d_['Positive'] + d_['Unexecuted'] <= 0; } },
|
||||
{ id: 'Rule #1', f: function(d_){ return d_['Conclusive'] + d_['Inconclusive'] + d_['Positive'] === 0; } },
|
||||
{ id: 'Rule #2', f: function(d_){ return d_['Conclusive'] > 0; } },
|
||||
{ id: 'Rule #3', f: function(d_){ return d_['Conclusive'] === 0 && d_['Inconclusive'] > 0; } },
|
||||
{ id: 'Rule #4', f: function(d_){ return d_['Positive'] + d_['Unexecuted'] >= 2 && d_['Positive'] * d_['Unexecuted'] > 0; } }
|
||||
|
||||
];
|
||||
|
||||
|
||||
this._onScroll = this._onScroll.bind(this);
|
||||
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
this.parseData();
|
||||
window.addEventListener('scroll', this._onScroll);
|
||||
|
||||
}
|
||||
|
||||
_onMouseMove(e) {
|
||||
|
||||
let self = this;
|
||||
|
||||
if(!this.toggle){
|
||||
|
||||
let hidden = 'none';
|
||||
let html = '';
|
||||
let bcolor = '#DEDEDE';
|
||||
|
@ -100,41 +91,35 @@ class VennDiagram extends React.Component{
|
|||
hidden = 'block'; e.target.setAttribute('opacity', 0.95);
|
||||
bcolor = e.target.getAttribute('fill');
|
||||
|
||||
//set highest z-index
|
||||
// Set highest z-index
|
||||
e.target.parentNode.parentNode.appendChild(e.target.parentNode);
|
||||
|
||||
}else{
|
||||
|
||||
this.divElement.style.cursor = 'default';
|
||||
|
||||
//return z indices to default
|
||||
// Return z indices to default
|
||||
Object.keys(this.layout).forEach(function(d_, i_){ document.querySelector('#' + self.prefix).appendChild(document.querySelector('#' + self.prefix + 'Node_' + i_).parentNode); })
|
||||
|
||||
}
|
||||
|
||||
this.setState({target: e, tooltip: { target: e.target, bcolor: bcolor, top: e.clientY + 8, left: e.clientX + 8, display: hidden, html: html } });
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
_onScroll(e){
|
||||
|
||||
this.divElement.style.cursor = 'default';
|
||||
this.setState({target: null, tooltip: { target: null, bcolor: 'none', top: 0, left: 0, display: 'none', html: '' } });
|
||||
|
||||
}
|
||||
|
||||
_onClick(e) {
|
||||
|
||||
if(this.state.tooltip.target === e.target) { this.toggle = true; } else { this.toggle = false; }
|
||||
this.toggle = this.state.tooltip.target === e.target;
|
||||
|
||||
//variable to external callback
|
||||
//e.target.parentNode.id)
|
||||
|
||||
}
|
||||
|
||||
parseData(){
|
||||
|
||||
let self = this;
|
||||
let data = [];
|
||||
const omit = (prop, { [prop]: _, ...rest }) => rest;
|
||||
|
@ -152,17 +137,16 @@ class VennDiagram extends React.Component{
|
|||
self.setLayoutElement(rule, key, html, d_);
|
||||
data.push(this.layout[key]);
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
this.setState({ data: data });
|
||||
this.render();
|
||||
|
||||
}
|
||||
|
||||
buildTooltipHtmlContent(object_){ return Object.keys(object_).reduce((out_, key_) => out_ + TypographicUtilities.setTitle(key_) + ': ' + object_[key_] + '\n', ''); }
|
||||
|
||||
setLayoutElement(rule_, key_, html_, d_){
|
||||
|
||||
console.log(rule_, key_, html_, d_);
|
||||
if(rule_ == null) { throw Error('The node scores are invalid'); }
|
||||
|
||||
if(key_ === 'Data'){ this.layout[key_].fontStyle = this.fontStyles[0]; }
|
||||
|
@ -172,75 +156,53 @@ class VennDiagram extends React.Component{
|
|||
this.layout[key_].label = d_.pillar + this.suffices[rule_];
|
||||
this.layout[key_].node = d_;
|
||||
this.layout[key_].tooltip = html_;
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
if(this.state.data === undefined) { return null; }
|
||||
else {
|
||||
|
||||
//equivalent to center translate (width/2, height/2)
|
||||
// equivalent to center translate (width/2, height/2)
|
||||
let viewPortParameters = (-this.width / 2) + ' ' + (-this.height / 2) + ' ' + this.width + ' ' + this.height;
|
||||
let translate = 'translate(' + this.width /2 + ',' + this.height/2 + ')';
|
||||
|
||||
let nodes = Object.values(this.layout).map((d_, i_) =>{
|
||||
|
||||
if(d_.hasOwnProperty('cx')){
|
||||
|
||||
let nodes = Object.values(this.layout).map((d_, i_) => {
|
||||
if(d_.hasOwnProperty('cx')) {
|
||||
return (
|
||||
|
||||
<CircularNode
|
||||
|
||||
prefix={this.prefix}
|
||||
key={this.prefix + 'CircularNode' + i_}
|
||||
index={i_}
|
||||
data={d_}
|
||||
|
||||
/>
|
||||
);
|
||||
|
||||
}else{
|
||||
|
||||
} else {
|
||||
d_.label = TypographicUtilities.removeBrokenBar(d_.label);
|
||||
|
||||
return (
|
||||
|
||||
<ArcNode
|
||||
|
||||
prefix={this.prefix}
|
||||
key={this.prefix + 'ArcNode' + i_}
|
||||
index={i_}
|
||||
data={d_}
|
||||
|
||||
/>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
<div ref={ (divElement) => this.divElement = divElement} onMouseMove={this._onMouseMove.bind(this)} onClick={this._onClick.bind(this)} >
|
||||
<svg id={this.prefix} viewBox={viewPortParameters} width={'100%'} height={'100%'} xmlns='http://www.w3.org/2000/svg' xmlnsXlink='http://www.w3.org/1999/xlink'>
|
||||
{nodes}
|
||||
</svg>
|
||||
<Tooltip id={this.prefix + 'Tooltip'} prefix={this.prefix} {...this.state.tooltip} />
|
||||
</div>
|
||||
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VennDiagram.propTypes = {
|
||||
|
||||
pillarsGrades: PropTypes.array
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
export default VennDiagram;
|
Loading…
Reference in New Issue