forked from p15670423/monkey
Moved report generation logic to service, and now all report data is automatic
also renamed fields to lowercase and renamed "recommendation" to "directive".
This commit is contained in:
parent
ae88764dc8
commit
6cd7af6eaa
|
@ -11,7 +11,8 @@ STATUS_UNEXECUTED = u"Unexecuted"
|
||||||
STATUS_POSITIVE = u"Positive"
|
STATUS_POSITIVE = u"Positive"
|
||||||
STATUS_INCONCLUSIVE = u"Inconclusive"
|
STATUS_INCONCLUSIVE = u"Inconclusive"
|
||||||
STATUS_CONCLUSIVE = u"Conclusive"
|
STATUS_CONCLUSIVE = u"Conclusive"
|
||||||
TEST_STATUSES = (STATUS_CONCLUSIVE, STATUS_INCONCLUSIVE, STATUS_POSITIVE, STATUS_UNEXECUTED)
|
# Don't change order!
|
||||||
|
TEST_STATUSES = [STATUS_CONCLUSIVE, STATUS_INCONCLUSIVE, STATUS_POSITIVE, STATUS_UNEXECUTED]
|
||||||
|
|
||||||
TEST_DATA_ENDPOINT_ELASTIC = u"unencrypted_data_endpoint_elastic"
|
TEST_DATA_ENDPOINT_ELASTIC = u"unencrypted_data_endpoint_elastic"
|
||||||
TEST_DATA_ENDPOINT_HTTP = u"unencrypted_data_endpoint_http"
|
TEST_DATA_ENDPOINT_HTTP = u"unencrypted_data_endpoint_http"
|
||||||
|
@ -120,6 +121,31 @@ def populate_pillars_to_tests():
|
||||||
|
|
||||||
populate_pillars_to_tests()
|
populate_pillars_to_tests()
|
||||||
|
|
||||||
|
DIRECTIVES_TO_TESTS = {}
|
||||||
|
|
||||||
|
|
||||||
|
def populate_directives_to_tests():
|
||||||
|
for single_directive in DIRECTIVES:
|
||||||
|
DIRECTIVES_TO_TESTS[single_directive] = []
|
||||||
|
for test, test_info in TESTS_MAP.items():
|
||||||
|
DIRECTIVES_TO_TESTS[test_info[DIRECTIVE_KEY]].append(test)
|
||||||
|
|
||||||
|
|
||||||
|
populate_directives_to_tests()
|
||||||
|
|
||||||
|
DIRECTIVES_TO_PILLARS = {}
|
||||||
|
|
||||||
|
|
||||||
|
def populate_directives_to_pillars():
|
||||||
|
for directive, directive_tests in DIRECTIVES_TO_TESTS.items():
|
||||||
|
directive_pillars = set()
|
||||||
|
for test in directive_tests:
|
||||||
|
for pillar in TESTS_MAP[test][PILLARS_KEY]:
|
||||||
|
directive_pillars.add(pillar)
|
||||||
|
DIRECTIVES_TO_PILLARS[directive] = directive_pillars
|
||||||
|
|
||||||
|
|
||||||
|
populate_directives_to_pillars()
|
||||||
|
|
||||||
EVENT_TYPE_ISLAND = "island"
|
EVENT_TYPE_ISLAND = "island"
|
||||||
EVENT_TYPE_MONKEY_NETWORK = "monkey_network"
|
EVENT_TYPE_MONKEY_NETWORK = "monkey_network"
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
import httplib
|
import httplib
|
||||||
import json
|
|
||||||
|
|
||||||
import flask_restful
|
import flask_restful
|
||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
|
|
||||||
from common.data.zero_trust_consts import TESTS_MAP, EXPLANATION_KEY, PILLARS_KEY, PILLARS, STATUS_CONCLUSIVE, \
|
|
||||||
STATUS_INCONCLUSIVE, STATUS_POSITIVE, STATUS_UNEXECUTED, PILLARS_TO_TESTS
|
|
||||||
from monkey_island.cc.auth import jwt_required
|
from monkey_island.cc.auth import jwt_required
|
||||||
from monkey_island.cc.models.finding import Finding
|
|
||||||
from monkey_island.cc.services.reporting.report import ReportService
|
from monkey_island.cc.services.reporting.report import ReportService
|
||||||
|
from monkey_island.cc.services.reporting.zero_trust_report import get_all_findings, get_pillars_grades, \
|
||||||
|
get_directives_status
|
||||||
|
|
||||||
ZERO_TRUST_REPORT_TYPE = "zero_trust"
|
ZERO_TRUST_REPORT_TYPE = "zero_trust"
|
||||||
GENERAL_REPORT_TYPE = "general"
|
GENERAL_REPORT_TYPE = "general"
|
||||||
|
@ -16,7 +15,7 @@ REPORT_TYPES = [GENERAL_REPORT_TYPE, ZERO_TRUST_REPORT_TYPE]
|
||||||
|
|
||||||
REPORT_DATA_PILLARS = "pillars"
|
REPORT_DATA_PILLARS = "pillars"
|
||||||
REPORT_DATA_FINDINGS = "findings"
|
REPORT_DATA_FINDINGS = "findings"
|
||||||
REPORT_DATA_RECOMMENDATION_STATUS = "recommendations"
|
REPORT_DATA_DIRECTIVES_STATUS = "directives"
|
||||||
|
|
||||||
__author__ = ["itay.mizeretz", "shay.nehmad"]
|
__author__ = ["itay.mizeretz", "shay.nehmad"]
|
||||||
|
|
||||||
|
@ -32,155 +31,7 @@ class Report(flask_restful.Resource):
|
||||||
return jsonify(get_all_findings())
|
return jsonify(get_all_findings())
|
||||||
elif report_data == REPORT_DATA_PILLARS:
|
elif report_data == REPORT_DATA_PILLARS:
|
||||||
return jsonify(get_pillars_grades())
|
return jsonify(get_pillars_grades())
|
||||||
elif report_data == REPORT_DATA_RECOMMENDATION_STATUS:
|
elif report_data == REPORT_DATA_DIRECTIVES_STATUS:
|
||||||
return jsonify(get_recommendations_status())
|
return jsonify(get_directives_status())
|
||||||
|
|
||||||
flask_restful.abort(httplib.NOT_FOUND)
|
flask_restful.abort(httplib.NOT_FOUND)
|
||||||
|
|
||||||
|
|
||||||
def get_all_findings():
|
|
||||||
all_findings = Finding.objects()
|
|
||||||
enriched_findings = [get_enriched_finding(f) for f in all_findings]
|
|
||||||
return enriched_findings
|
|
||||||
|
|
||||||
|
|
||||||
def get_events_as_dict(events):
|
|
||||||
return [json.loads(event.to_json()) for event in events]
|
|
||||||
|
|
||||||
|
|
||||||
def get_enriched_finding(finding):
|
|
||||||
test_info = TESTS_MAP[finding.test]
|
|
||||||
enriched_finding = {
|
|
||||||
# TODO add test explanation per status.
|
|
||||||
"test": test_info[EXPLANATION_KEY],
|
|
||||||
"pillars": test_info[PILLARS_KEY],
|
|
||||||
"status": finding.status,
|
|
||||||
"events": get_events_as_dict(finding.events)
|
|
||||||
}
|
|
||||||
return enriched_finding
|
|
||||||
|
|
||||||
|
|
||||||
def get_recommendations_status():
|
|
||||||
network_recomms = [
|
|
||||||
{
|
|
||||||
"Recommendation": "Do network segmentation.",
|
|
||||||
"Status": "Positive",
|
|
||||||
"Tests": [
|
|
||||||
{
|
|
||||||
"Test": "Test B for segmentation",
|
|
||||||
"Status": "Positive"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Test": "Test A for segmentation",
|
|
||||||
"Status": "Positive"
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Recommendation": "Analyze malicious network traffic.",
|
|
||||||
"Status": "Inconclusive",
|
|
||||||
"Tests": [
|
|
||||||
{
|
|
||||||
"Test": "Use exploits.",
|
|
||||||
"Status": "Inconclusive"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Test": "Bruteforce passwords.",
|
|
||||||
"Status": "Inconclusive"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Recommendation": "Data at trasnit should be...",
|
|
||||||
"Status": "Conclusive",
|
|
||||||
"Tests": [
|
|
||||||
{
|
|
||||||
"Test": "Scan HTTP.",
|
|
||||||
"Status": "Conclusive"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Test": "Scan elastic.",
|
|
||||||
"Status": "Unexecuted"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
device_recomms = [
|
|
||||||
{
|
|
||||||
"Recommendation": "Install AV software.",
|
|
||||||
"Status": "Unexecuted",
|
|
||||||
"Tests": [
|
|
||||||
{
|
|
||||||
"Test": "Search for active AV software processes",
|
|
||||||
"Status": "Unexecuted"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
data_recommns = [
|
|
||||||
{
|
|
||||||
"Recommendation": "Data at trasnit should be...",
|
|
||||||
"Status": "Conclusive",
|
|
||||||
"Tests": [
|
|
||||||
{
|
|
||||||
"Test": "Scan HTTP.",
|
|
||||||
"Status": "Conclusive"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Test": "Scan elastic.",
|
|
||||||
"Status": "Unexecuted"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
"pillar": "Networks",
|
|
||||||
"recommendationStatus": network_recomms
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pillar": "Data",
|
|
||||||
"recommendationStatus": data_recommns
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pillar": "Devices",
|
|
||||||
"recommendationStatus": device_recomms
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_pillar_grade(pillar, all_findings):
|
|
||||||
pillar_grade = {
|
|
||||||
"Pillar": pillar,
|
|
||||||
STATUS_CONCLUSIVE: 0,
|
|
||||||
STATUS_INCONCLUSIVE: 0,
|
|
||||||
STATUS_POSITIVE: 0,
|
|
||||||
STATUS_UNEXECUTED: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
tests_of_this_pillar = PILLARS_TO_TESTS[pillar]
|
|
||||||
|
|
||||||
test_unexecuted = {}
|
|
||||||
for test in tests_of_this_pillar:
|
|
||||||
test_unexecuted[test] = True
|
|
||||||
|
|
||||||
for finding in all_findings:
|
|
||||||
test_unexecuted[finding.test] = False
|
|
||||||
test_info = TESTS_MAP[finding.test]
|
|
||||||
if pillar in test_info[PILLARS_KEY]:
|
|
||||||
pillar_grade[finding.status] += 1
|
|
||||||
|
|
||||||
pillar_grade[STATUS_UNEXECUTED] = sum(1 for condition in test_unexecuted.values() if condition)
|
|
||||||
|
|
||||||
return pillar_grade
|
|
||||||
|
|
||||||
|
|
||||||
def get_pillars_grades():
|
|
||||||
pillars_grades = []
|
|
||||||
all_findings = Finding.objects()
|
|
||||||
for pillar in PILLARS:
|
|
||||||
pillars_grades.append(get_pillar_grade(pillar, all_findings))
|
|
||||||
return pillars_grades
|
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
import json
|
||||||
|
from common.data.zero_trust_consts import *
|
||||||
|
from monkey_island.cc.models.finding import Finding
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_findings():
|
||||||
|
all_findings = Finding.objects()
|
||||||
|
enriched_findings = [get_enriched_finding(f) for f in all_findings]
|
||||||
|
return enriched_findings
|
||||||
|
|
||||||
|
|
||||||
|
def get_events_as_dict(events):
|
||||||
|
return [json.loads(event.to_json()) for event in events]
|
||||||
|
|
||||||
|
|
||||||
|
def get_enriched_finding(finding):
|
||||||
|
test_info = TESTS_MAP[finding.test]
|
||||||
|
enriched_finding = {
|
||||||
|
# TODO add test explanation per status.
|
||||||
|
"test": test_info[EXPLANATION_KEY],
|
||||||
|
"pillars": test_info[PILLARS_KEY],
|
||||||
|
"status": finding.status,
|
||||||
|
"events": get_events_as_dict(finding.events)
|
||||||
|
}
|
||||||
|
return enriched_finding
|
||||||
|
|
||||||
|
|
||||||
|
def get_lcd_worst_status_for_test(all_findings_for_test):
|
||||||
|
current_status = STATUS_UNEXECUTED
|
||||||
|
for finding in all_findings_for_test:
|
||||||
|
if TEST_STATUSES.index(finding.status) < TEST_STATUSES.index(current_status):
|
||||||
|
current_status = finding.status
|
||||||
|
|
||||||
|
return current_status
|
||||||
|
|
||||||
|
|
||||||
|
def get_tests_status(directive_tests):
|
||||||
|
results = []
|
||||||
|
for test in directive_tests:
|
||||||
|
test_findings = Finding.objects(test=test)
|
||||||
|
results.append(
|
||||||
|
{
|
||||||
|
"test": test,
|
||||||
|
"status": get_lcd_worst_status_for_test(test_findings)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def get_directive_status(directive_tests):
|
||||||
|
worst_status = STATUS_UNEXECUTED
|
||||||
|
all_statuses = set()
|
||||||
|
for test in directive_tests:
|
||||||
|
all_statuses |= set(Finding.objects(test=test).distinct("status"))
|
||||||
|
|
||||||
|
for status in all_statuses:
|
||||||
|
if TEST_STATUSES.index(status) < TEST_STATUSES.index(worst_status):
|
||||||
|
worst_status = status
|
||||||
|
|
||||||
|
return worst_status
|
||||||
|
|
||||||
|
|
||||||
|
def get_directives_status():
|
||||||
|
all_directive_statuses = {}
|
||||||
|
|
||||||
|
# init with empty lists
|
||||||
|
for pillar in PILLARS:
|
||||||
|
all_directive_statuses[pillar] = []
|
||||||
|
|
||||||
|
for directive, directive_tests in DIRECTIVES_TO_TESTS.items():
|
||||||
|
for pillar in DIRECTIVES_TO_PILLARS[directive]:
|
||||||
|
all_directive_statuses[pillar].append(
|
||||||
|
{
|
||||||
|
"directive": directive,
|
||||||
|
"tests": get_tests_status(directive_tests),
|
||||||
|
"status": get_directive_status(directive_tests)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return all_directive_statuses
|
||||||
|
|
||||||
|
|
||||||
|
def get_pillar_grade(pillar, all_findings):
|
||||||
|
pillar_grade = {
|
||||||
|
"pillar": pillar,
|
||||||
|
STATUS_CONCLUSIVE: 0,
|
||||||
|
STATUS_INCONCLUSIVE: 0,
|
||||||
|
STATUS_POSITIVE: 0,
|
||||||
|
STATUS_UNEXECUTED: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
tests_of_this_pillar = PILLARS_TO_TESTS[pillar]
|
||||||
|
|
||||||
|
test_unexecuted = {}
|
||||||
|
for test in tests_of_this_pillar:
|
||||||
|
test_unexecuted[test] = True
|
||||||
|
|
||||||
|
for finding in all_findings:
|
||||||
|
test_unexecuted[finding.test] = False
|
||||||
|
test_info = TESTS_MAP[finding.test]
|
||||||
|
if pillar in test_info[PILLARS_KEY]:
|
||||||
|
pillar_grade[finding.status] += 1
|
||||||
|
|
||||||
|
pillar_grade[STATUS_UNEXECUTED] = sum(1 for condition in test_unexecuted.values() if condition)
|
||||||
|
|
||||||
|
return pillar_grade
|
||||||
|
|
||||||
|
|
||||||
|
def get_pillars_grades():
|
||||||
|
pillars_grades = []
|
||||||
|
all_findings = Finding.objects()
|
||||||
|
for pillar in PILLARS:
|
||||||
|
pillars_grades.append(get_pillar_grade(pillar, all_findings))
|
||||||
|
return pillars_grades
|
|
@ -4,7 +4,7 @@ import AuthComponent from '../AuthComponent';
|
||||||
import ReportHeader, {ReportTypes} from "../report-components/common/ReportHeader";
|
import ReportHeader, {ReportTypes} from "../report-components/common/ReportHeader";
|
||||||
import PillarGrades from "../report-components/zerotrust/PillarGrades";
|
import PillarGrades from "../report-components/zerotrust/PillarGrades";
|
||||||
import FindingsTable from "../report-components/zerotrust/FindingsTable";
|
import FindingsTable from "../report-components/zerotrust/FindingsTable";
|
||||||
import {SinglePillarRecommendationsStatus} from "../report-components/zerotrust/SinglePillarRecommendationsStatus";
|
import {SinglePillarDirectivesStatus} from "../report-components/zerotrust/SinglePillarDirectivesStatus";
|
||||||
|
|
||||||
class ZeroTrustReportPageComponent extends AuthComponent {
|
class ZeroTrustReportPageComponent extends AuthComponent {
|
||||||
|
|
||||||
|
@ -45,13 +45,13 @@ class ZeroTrustReportPageComponent extends AuthComponent {
|
||||||
<PillarGrades pillars={this.state.pillars}/>
|
<PillarGrades pillars={this.state.pillars}/>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
const recommendationsSection = <div><h2>Recommendations Status</h2>
|
const directivesSection = <div><h2>Directives status</h2>
|
||||||
{
|
{
|
||||||
this.state.recommendations.map((recommendation) =>
|
Object.keys(this.state.directives).map((pillar) =>
|
||||||
<SinglePillarRecommendationsStatus
|
<SinglePillarDirectivesStatus
|
||||||
key={recommendation.pillar}
|
key={pillar}
|
||||||
pillar={recommendation.pillar}
|
pillar={pillar}
|
||||||
recommendationStatus={recommendation.recommendationStatus}/>
|
directivesStatus={this.state.directives[pillar]}/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</div>;
|
</div>;
|
||||||
|
@ -61,7 +61,7 @@ class ZeroTrustReportPageComponent extends AuthComponent {
|
||||||
|
|
||||||
content = <div>
|
content = <div>
|
||||||
{pillarsSection}
|
{pillarsSection}
|
||||||
{recommendationsSection}
|
{directivesSection}
|
||||||
{findingSection}
|
{findingSection}
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
@ -84,8 +84,8 @@ class ZeroTrustReportPageComponent extends AuthComponent {
|
||||||
PILLARS:
|
PILLARS:
|
||||||
<pre>{JSON.stringify(this.state.pillars, undefined, 2)}</pre>
|
<pre>{JSON.stringify(this.state.pillars, undefined, 2)}</pre>
|
||||||
<br/>
|
<br/>
|
||||||
recommendations:
|
DIRECTIVES:
|
||||||
<pre>{JSON.stringify(this.state.recommendations, undefined, 2)}</pre>
|
<pre>{JSON.stringify(this.state.directives, undefined, 2)}</pre>
|
||||||
<br/>
|
<br/>
|
||||||
FINDINGS:
|
FINDINGS:
|
||||||
<pre>{JSON.stringify(this.state.findings, undefined, 2)}</pre>
|
<pre>{JSON.stringify(this.state.findings, undefined, 2)}</pre>
|
||||||
|
@ -95,7 +95,7 @@ class ZeroTrustReportPageComponent extends AuthComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
stillLoadingDataFromServer() {
|
stillLoadingDataFromServer() {
|
||||||
return typeof this.state.findings === "undefined" || typeof this.state.pillars === "undefined" || typeof this.state.recommendations === "undefined";
|
return typeof this.state.findings === "undefined" || typeof this.state.pillars === "undefined" || typeof this.state.directives === "undefined";
|
||||||
}
|
}
|
||||||
|
|
||||||
print() {
|
print() {
|
||||||
|
@ -111,11 +111,11 @@ class ZeroTrustReportPageComponent extends AuthComponent {
|
||||||
findings: res
|
findings: res
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.authFetch('/api/report/zero_trust/recommendations')
|
this.authFetch('/api/report/zero_trust/directives')
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(res => {
|
.then(res => {
|
||||||
this.setState({
|
this.setState({
|
||||||
recommendations: res
|
directives: res
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.authFetch('/api/report/zero_trust/pillars')
|
this.authFetch('/api/report/zero_trust/pillars')
|
||||||
|
|
|
@ -1,28 +1,29 @@
|
||||||
import React, {Component} from "react";
|
import React from "react";
|
||||||
import PagenatedTable from "../common/PagenatedTable";
|
import PagenatedTable from "../common/PagenatedTable";
|
||||||
import AuthComponent from "../../AuthComponent";
|
import AuthComponent from "../../AuthComponent";
|
||||||
|
|
||||||
|
const statusToIcon = {
|
||||||
|
"Positive": "fa-shield alert-success",
|
||||||
|
"Inconclusive": "fa-question alert-info",
|
||||||
|
"Conclusive": "fa-unlock-alt alert-danger",
|
||||||
|
"Unexecuted": "fa-toggle-off",
|
||||||
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
Header: 'Recommendations status',
|
Header: 'Directives status',
|
||||||
columns: [
|
columns: [
|
||||||
{ Header: 'Recommendation', accessor: 'Recommendation',
|
{ Header: 'Directive', accessor: 'directive',
|
||||||
style: {'whiteSpace': 'unset'} // This enables word wrap
|
style: {'whiteSpace': 'unset'} // This enables word wrap
|
||||||
},
|
},
|
||||||
{ Header: 'Status', id: "Status",
|
{ Header: 'Status', id: 'status',
|
||||||
accessor: x => {
|
accessor: x => {
|
||||||
const statusToIcon = {
|
return <i className={"fa " + statusToIcon[x.status] + " fa-3x"} />;
|
||||||
"Positive": "fa-shield alert-success",
|
|
||||||
"Inconclusive": "fa-question alert-info",
|
|
||||||
"Conclusive": "fa-unlock-alt alert-danger",
|
|
||||||
"Unexecuted": "fa-toggle-off",
|
|
||||||
};
|
|
||||||
return <i className={"fa " + statusToIcon[x.Status] + " fa-2x"} />;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ Header: 'Tests', id:"Tests",
|
{ Header: 'Tests', id: 'tests',
|
||||||
accessor: x => {
|
accessor: x => {
|
||||||
return <TestsStatus tests={x.Tests} />;
|
return <TestsStatus tests={x.tests} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -48,24 +49,24 @@ class TestsStatus extends AuthComponent {
|
||||||
|
|
||||||
getTestsOfStatusIfAny(statusToFilter) {
|
getTestsOfStatusIfAny(statusToFilter) {
|
||||||
const filteredTests = this.props.tests.filter((test) => {
|
const filteredTests = this.props.tests.filter((test) => {
|
||||||
return (test.Status === statusToFilter);
|
return (test.status === statusToFilter);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (filteredTests.length > 0) {
|
if (filteredTests.length > 0) {
|
||||||
const listItems = filteredTests.map((test) => {
|
const listItems = filteredTests.map((test) => {
|
||||||
return (<li key={test.Test}>{test.Test}</li>)
|
return (<li key={test.test}>{test.test}</li>)
|
||||||
});
|
});
|
||||||
return <div>{statusToFilter}<ul>{listItems}</ul></div>;
|
return <div><i className={"fa " + statusToIcon[statusToFilter]}/> {statusToFilter}<ul>{listItems}</ul></div>;
|
||||||
}
|
}
|
||||||
return <div/>;
|
return <div/>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RecommendationsStatusTable extends AuthComponent {
|
export class DirectivesStatusTable extends AuthComponent {
|
||||||
render() {
|
render() {
|
||||||
return <PagenatedTable data={this.props.recommendationStatus} columns={columns} pageSize={5}/>;
|
return <PagenatedTable data={this.props.directivesStatus} columns={columns} pageSize={5}/>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RecommendationsStatusTable;
|
export default DirectivesStatusTable;
|
|
@ -7,7 +7,7 @@ const columns = [
|
||||||
Header: 'Pillar Grading',
|
Header: 'Pillar Grading',
|
||||||
columns: [
|
columns: [
|
||||||
{ Header: 'Pillar', id: 'Pillar', accessor: x => {
|
{ Header: 'Pillar', id: 'Pillar', accessor: x => {
|
||||||
return (<PillarLabel pillar={x.Pillar} />);
|
return (<PillarLabel pillar={x.pillar} />);
|
||||||
}},
|
}},
|
||||||
{ Header: 'Conclusive', accessor: 'Conclusive'},
|
{ Header: 'Conclusive', accessor: 'Conclusive'},
|
||||||
{ Header: 'Inconclusive', accessor: 'Inconclusive'},
|
{ Header: 'Inconclusive', accessor: 'Inconclusive'},
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import AuthComponent from "../../AuthComponent";
|
||||||
|
import {PillarLabel} from "./PillarLabel";
|
||||||
|
import DirectivesStatusTable from "./DirectivesStatusTable";
|
||||||
|
import React, {Fragment} from "react";
|
||||||
|
|
||||||
|
export class SinglePillarDirectivesStatus extends AuthComponent {
|
||||||
|
directivesStatus;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.props.directivesStatus.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<h3><PillarLabel pillar={this.props.pillar}/></h3>
|
||||||
|
<DirectivesStatusTable directivesStatus={this.props.directivesStatus}/>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +0,0 @@
|
||||||
import AuthComponent from "../../AuthComponent";
|
|
||||||
import {PillarLabel} from "./PillarLabel";
|
|
||||||
import RecommendationsStatusTable from "./RecommendationsStatusTable";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
export class SinglePillarRecommendationsStatus extends AuthComponent {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h3><PillarLabel pillar={this.props.pillar}/></h3>
|
|
||||||
<RecommendationsStatusTable recommendationStatus={this.props.recommendationStatus}/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue