208 lines
7.8 KiB
HTML
208 lines
7.8 KiB
HTML
{% extends "base.html" %}
|
||
{% load i18n risk_extras %}
|
||
{% block crumbs %}
|
||
<li><a href="{% url 'risks:risk_matrix' %}">{% trans "Risk Matrix" %}</a></li>
|
||
{% endblock %}
|
||
{% block content %}
|
||
<div class="erp-tabs">
|
||
<a class="is-active" data-tab="matrix">{% trans "Risk Matrix" %}</a>
|
||
<a data-tab="details">{% trans "Detail View" %}</a>
|
||
</div>
|
||
|
||
<section class="section">
|
||
|
||
<!-- Main Container -->
|
||
<div class="box">
|
||
<!-- Panel: Matrix View -->
|
||
<div class="tab-panel" data-tab="matrix">
|
||
<table class="table is-bordered is-fullwidth has-text-centered risk-matrix-table">
|
||
<thead>
|
||
<tr>
|
||
<th class="has-text-left">{% trans "Impact" %} * {% trans "Likelihood" %}</th>
|
||
{% for l_val, l_label in likelihoods %}
|
||
<th class="{{ l_val|likelihood_class|to_bg }}">{{ l_label }}</th>
|
||
{% endfor %}
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for i_val, i_label in impacts reversed %}
|
||
<tr>
|
||
<th class="has-text-left {{ i_val|impact_class|to_bg }}">{{ i_label }}</th>
|
||
{% for l_val, l_label in likelihoods %}
|
||
{% with s=i_val|mul:l_val %}
|
||
<td class="risk-matrix-cell {{ s|score_bg_class }}">
|
||
<div class="is-flex is-justify-content-center is-align-items-center">
|
||
{% if s <= 4 %}
|
||
<span class="tag is-control-verylow is-light">Low ({{ s }})</span>
|
||
{% elif s <= 8 %}
|
||
<span class="tag is-control-low is-light">Medium ({{ s }})</span>
|
||
{% elif s <= 12 %}
|
||
<span class="tag is-control-mid is-light">High ({{ s }})</span>
|
||
{% else %}
|
||
<span class="tag is-control-veryhigh is-light">Critical ({{ s }})</span>
|
||
{% endif %}
|
||
</div>
|
||
</td>
|
||
{% endwith %}
|
||
{% endfor %}
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div><!-- Panel: Matrix View End -->
|
||
|
||
<!-- Panel: Details View -->
|
||
<div class="tab-panel is-hidden" data-tab="details">
|
||
|
||
<!-- Mode Toggle (Gross / Net) -->
|
||
<div class="level mb-3">
|
||
<div class="level-left">
|
||
<div class="level-item"><strong>{% trans "Show" %}:</strong></div>
|
||
<div class="level-item">
|
||
<div class="buttons has-addons">
|
||
<button type="button" class="button is-small is-info is-light details-toggle is-active" data-mode="gross">
|
||
{% trans "Gross" %}
|
||
</button>
|
||
<button type="button" class="button is-small is-info is-light details-toggle" data-mode="net">
|
||
{% trans "Net" %}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div><!-- Mode Toggle End -->
|
||
|
||
<!-- Gross Risk List -->
|
||
<div class="details-table" data-mode="gross">
|
||
<table class="table is-bordered is-fullwidth has-text-centered risk-matrix-table">
|
||
<thead>
|
||
<tr>
|
||
<th class="has-text-left">{% trans "Impact" %} / {% trans "Likelihood" %}</th>
|
||
{% for l_val, l_label in likelihoods %}
|
||
<th class="{{ l_val|likelihood_class|to_bg }}">{{ l_label }}</th>
|
||
{% endfor %}
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for i_val, i_label in impacts reversed %}
|
||
<tr>
|
||
<th class="has-text-left {{ i_val|impact_class|to_bg }}">{{ i_label }}</th>
|
||
{% for l_val, l_label in likelihoods %}
|
||
{% with row=gross_matrix|dict_get:i_val %}
|
||
{% with cell=row|dict_get:l_val %}
|
||
{% with s=i_val|mul:l_val %}
|
||
<td class="risk-matrix-cell {{ s|score_bg_class }}">
|
||
{% if cell %}
|
||
<ul class="risk-cell-list">
|
||
{% for risk in cell %}
|
||
<li style="list-style:none;">
|
||
<a href="{% url 'risks:show_risk' risk.id %}" class="tag">{{ risk.title }}</a>
|
||
</li>
|
||
{% endfor %}
|
||
</ul>
|
||
{% else %}
|
||
<span class="has-text-grey">–</span>
|
||
{% endif %}
|
||
</td>
|
||
{% endwith %}
|
||
{% endwith %}
|
||
{% endwith %}
|
||
{% endfor %}
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div><!-- Gross Risk List End -->
|
||
|
||
<!-- Net Risk List -->
|
||
<div class="details-table is-hidden" data-mode="net">
|
||
<table class="table is-bordered is-fullwidth has-text-centered risk-matrix-table">
|
||
<thead>
|
||
<tr>
|
||
<th class="has-text-left">{% trans "Impact" %} / {% trans "Likelihood" %}</th>
|
||
{% for l_val, l_label in likelihoods %}
|
||
<th class="{{ l_val|likelihood_class|to_bg }}">{{ l_label }}</th>
|
||
{% endfor %}
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for i_val, i_label in impacts reversed %}
|
||
<tr>
|
||
<th class="has-text-left {{ i_val|impact_class|to_bg }}">{{ i_label }}</th>
|
||
{% for l_val, l_label in likelihoods %}
|
||
{% with row=net_matrix|dict_get:i_val %}
|
||
{% with cell=row|dict_get:l_val %}
|
||
{% with s=i_val|mul:l_val %}
|
||
<td class="risk-matrix-cell {{ s|score_bg_class }}">
|
||
{% if cell %}
|
||
<ul class="risk-cell-list">
|
||
{% for risk in cell %}
|
||
<li style="list-style:none;">
|
||
<a href="{% url 'risks:show_risk' risk.id %}" class="tag">{{ risk.title }}</a>
|
||
</li>
|
||
{% endfor %}
|
||
</ul>
|
||
{% else %}
|
||
<span class="has-text-grey">–</span>
|
||
{% endif %}
|
||
</td>
|
||
{% endwith %}
|
||
{% endwith %}
|
||
{% endwith %}
|
||
{% endfor %}
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div><!-- Net Risk List End -->
|
||
|
||
</div><!-- Panel: Details View End -->
|
||
|
||
</div><!-- Main Container End -->
|
||
</section><!-- Section End -->
|
||
|
||
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
// Handle ERP-style tabs
|
||
const tabs = document.querySelectorAll('.erp-tabs a[data-tab]');
|
||
const panels = document.querySelectorAll('.tab-panel');
|
||
|
||
tabs.forEach(tab => {
|
||
tab.addEventListener('click', e => {
|
||
e.preventDefault();
|
||
|
||
// Deactivate all
|
||
tabs.forEach(x => x.classList.remove('is-active'));
|
||
panels.forEach(p => p.classList.add('is-hidden'));
|
||
|
||
// Activate clicked
|
||
tab.classList.add('is-active');
|
||
const target = tab.getAttribute('data-tab');
|
||
const activePanel = document.querySelector(`.tab-panel[data-tab="${target}"]`);
|
||
if (activePanel) activePanel.classList.remove('is-hidden');
|
||
});
|
||
});
|
||
|
||
// Handle Gross/Net toggle buttons in "Details" tab
|
||
const toggles = document.querySelectorAll('.details-toggle');
|
||
const tables = document.querySelectorAll('.details-table');
|
||
|
||
toggles.forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
const mode = btn.getAttribute('data-mode'); // "gross" or "net"
|
||
|
||
// Toggle active state on buttons
|
||
toggles.forEach(b => b.classList.toggle('is-active', b === btn));
|
||
|
||
// Show the right table
|
||
tables.forEach(t => {
|
||
t.classList.toggle('is-hidden', t.getAttribute('data-mode') !== mode);
|
||
});
|
||
});
|
||
});
|
||
});
|
||
</script>
|
||
|
||
|
||
{% endblock %}
|