241 lines
No EOL
7.5 KiB
HTML
241 lines
No EOL
7.5 KiB
HTML
{% extends "base.html" %}
|
|
{% load static i18n risk_extras %}
|
|
{% block crumbs %}
|
|
<li><a href="{% url 'risks:index' %}">{% trans "Dashboard" %}</a></li>
|
|
{% endblock %}
|
|
{% block content %}
|
|
|
|
<!-- Hero Section -->
|
|
<section class="hero is-small has-background-prosoft">
|
|
<div class="hero-body">
|
|
<div class="container">
|
|
<h2 class="subtitle is-5 has-text-white">
|
|
{% trans "Overview of Risks, Controls and Incidents" %}
|
|
</h2>
|
|
</div>
|
|
</div>
|
|
</section><!-- Hero Section End -->
|
|
|
|
<section class="section">
|
|
<div class="container">
|
|
|
|
<!-- KPI Cards -->
|
|
<div class="columns is-multiline">
|
|
|
|
<!-- Total Risks -->
|
|
<div class="column is-one-quarter">
|
|
<div class="box has-text-centered">
|
|
<p class="heading">{% trans "Total Risks" %}</p>
|
|
<p class="title is-4">{{ risks_total }}</p>
|
|
</div>
|
|
</div><!-- Total Risks End -->
|
|
|
|
<!-- Residual Risks -->
|
|
<div class="column is-one-quarter">
|
|
<div class="box has-text-centered {% if residual_review_required > 0 %}has-background-control-high{% else %}has-background-control-low{% endif %}">
|
|
<p class="heading">{% trans "Residual Risks Needing Review" %}</p>
|
|
<p class="title is-4">{{ residual_review_required }}</p>
|
|
</div>
|
|
</div><!-- Residual Risks End -->
|
|
|
|
<!-- Unread Notifications -->
|
|
<div class="column is-one-quarter">
|
|
<div class="box has-text-centered">
|
|
<p class="heading">{% trans "Unread Notifications" %}</p>
|
|
<p class="title is-4">{{ notifications_unread }}</p>
|
|
</div>
|
|
</div><!-- Unread Notifications End -->
|
|
|
|
</div><!-- KPI Cards End -->
|
|
|
|
<!-- Risks by CIA -->
|
|
<div class="box">
|
|
<h2 class="title is-5">{% trans "Risks by CIA" %}</h2>
|
|
<div class="columns is-multiline">
|
|
<div class="column">
|
|
<div class="notification is-control-verylow has-text-centered">
|
|
<strong>{% trans "Confidentiality" %}</strong><br>
|
|
{{ risks_by_cia.1|default:0 }}
|
|
</div>
|
|
</div>
|
|
<div class="column">
|
|
<div class="notification is-control-mid has-text-centered">
|
|
<strong>{% trans "Integrity" %}</strong><br>
|
|
{{ risks_by_cia.2|default:0 }}
|
|
</div>
|
|
</div>
|
|
<div class="column">
|
|
<div class="notification is-control-high has-text-centered">
|
|
<strong>{% trans "Availability" %}</strong><br>
|
|
{{ risks_by_cia.3|default:0 }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div><!-- Risks by CIA End -->
|
|
|
|
<div class="columns">
|
|
<!-- Risks by Status -->
|
|
<div class="column">
|
|
<div class="box">
|
|
<h2 class="title is-5">{% trans "Risks by Status" %}</h2>
|
|
<div class="table-container">
|
|
<table class="table is-fullwidth is-narrow is-hoverable">
|
|
<thead>
|
|
<tr>
|
|
<th>{% trans "Status" %}</th>
|
|
<th>{% trans "Count" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for row in risks_by_status %}
|
|
<tr>
|
|
<td>{{ row.status|risk_status_label }}</td>
|
|
<td>{{ row.count }}</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr><td colspan="2" class="has-text-grey has-text-centered">{% trans "No data" %}</td></tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div><!-- Risks End -->
|
|
|
|
<!-- Controls by Status -->
|
|
<div class="column">
|
|
<div class="box">
|
|
<h2 class="title is-5">{% trans "Controls by Status" %}</h2>
|
|
<div class="table-container">
|
|
<table class="table is-fullwidth is-narrow is-hoverable">
|
|
<thead>
|
|
<tr>
|
|
<th>{% trans "Status" %}</th>
|
|
<th>{% trans "Count" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for row in controls_by_status %}
|
|
<tr>
|
|
<td>{{ row.status|control_status_label }}</td>
|
|
<td>{{ row.count }}</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr><td colspan="2" class="has-text-grey has-text-centered">{% trans "No data" %}</td></tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div><!-- Controls End -->
|
|
|
|
<!-- Incidents by Status -->
|
|
<div class="column">
|
|
<div class="box">
|
|
<h2 class="title is-5">{% trans "Incidents by Status" %}</h2>
|
|
<div class="table-container">
|
|
<table class="table is-fullwidth is-narrow is-hoverable">
|
|
<thead>
|
|
<tr>
|
|
<th>{% trans "Status" %}</th>
|
|
<th>{% trans "Count" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for row in incidents_status %}
|
|
<tr>
|
|
<td>{{ row.status|incident_status_label }}</td>
|
|
<td>{{ row.count }}</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr><td colspan="2" class="has-text-grey has-text-centered">{% trans "No data" %}</td></tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div><!-- Incidents End -->
|
|
|
|
</div><!-- columns End -->
|
|
|
|
<div class="box">
|
|
<h2 class="title is-5">{% trans "Risk Trend (per Month)" %}</h2>
|
|
<canvas id="risksTrendChart"></canvas>
|
|
</div>
|
|
|
|
</div>
|
|
</section><!-- Dashboard Content End -->
|
|
|
|
<!-- ChartJS -->
|
|
<script src="{% static 'js/chart.js' %}"></script>
|
|
{{ months|json_script:"months-data" }}
|
|
{{ trend_data|json_script:"trend-data" }}
|
|
<script>
|
|
function getCssVar(name) {
|
|
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
const ctx = document.getElementById("risksTrendChart").getContext("2d");
|
|
|
|
const months = JSON.parse(document.getElementById("months-data").textContent);
|
|
const trendData = JSON.parse(document.getElementById("trend-data").textContent);
|
|
|
|
const chartColors = {
|
|
verylow: getCssVar("--c-verylow"),
|
|
low: getCssVar("--c-low"),
|
|
mid: getCssVar("--c-mid"),
|
|
high: getCssVar("--c-high"),
|
|
veryhigh: getCssVar("--c-veryhigh")
|
|
};
|
|
|
|
const datasets = [
|
|
{
|
|
label: "Low",
|
|
data: trendData["Low"],
|
|
borderColor: chartColors.low,
|
|
backgroundColor: chartColors.low + "33",
|
|
tension: 0.3
|
|
},
|
|
{
|
|
label: "Medium",
|
|
data: trendData["Medium"],
|
|
borderColor: chartColors.mid,
|
|
backgroundColor: chartColors.mid + "33",
|
|
tension: 0.3
|
|
},
|
|
{
|
|
label: "High",
|
|
data: trendData["High"],
|
|
borderColor: chartColors.high,
|
|
backgroundColor: chartColors.high + "33",
|
|
tension: 0.3
|
|
},
|
|
{
|
|
label: "Critical",
|
|
data: trendData["Critical"],
|
|
borderColor: chartColors.veryhigh,
|
|
backgroundColor: chartColors.veryhigh + "33",
|
|
tension: 0.3
|
|
}
|
|
];
|
|
|
|
new Chart(ctx, {
|
|
type: "line",
|
|
data: {
|
|
labels: months,
|
|
datasets: datasets
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
plugins: {
|
|
legend: { position: "bottom" }
|
|
},
|
|
scales: {
|
|
y: { beginAtZero: true }
|
|
}
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
{% endblock %} |