Change Impact_Choices to DB
This commit is contained in:
parent
a5a31f4dcf
commit
a314816150
10 changed files with 138 additions and 68 deletions
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
|
@ -6,6 +6,7 @@ from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
Control,
|
Control,
|
||||||
|
ImpactChoice,
|
||||||
Incident,
|
Incident,
|
||||||
LikelihoodChoice,
|
LikelihoodChoice,
|
||||||
Notification,
|
Notification,
|
||||||
|
@ -239,3 +240,10 @@ class UserAdmin(BaseUserAdmin):
|
||||||
@admin.register(LikelihoodChoice)
|
@admin.register(LikelihoodChoice)
|
||||||
class LikelihoodChoiceAdmin(admin.ModelAdmin):
|
class LikelihoodChoiceAdmin(admin.ModelAdmin):
|
||||||
list_display = ("value", "name", "description")
|
list_display = ("value", "name", "description")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# ImpactChoice
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
@admin.register(ImpactChoice)
|
||||||
|
class ImpactChoiceAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("value", "name", "description")
|
|
@ -1,5 +1,6 @@
|
||||||
from .auditlog import AuditLog
|
from .auditlog import AuditLog
|
||||||
from .control import Control
|
from .control import Control
|
||||||
|
from .impact_choice import ImpactChoice
|
||||||
from .incident import Incident
|
from .incident import Incident
|
||||||
from .likelihood_choice import LikelihoodChoice
|
from .likelihood_choice import LikelihoodChoice
|
||||||
from .notification import Notification
|
from .notification import Notification
|
||||||
|
@ -11,4 +12,4 @@ from .risk import Risk
|
||||||
from .user import User
|
from .user import User
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["AuditLog", "Control", "Incident", "LikelihoodChoice", "Notification", "NotificationKind", "NotificationPreference", "NotificationRule", "ResidualRisk", "Risk", "User"]
|
__all__ = ["AuditLog", "Control", "ImpactChoice", "Incident", "LikelihoodChoice", "Notification", "NotificationKind", "NotificationPreference", "NotificationRule", "ResidualRisk", "Risk", "User"]
|
13
risks/models/impact_choice.py
Normal file
13
risks/models/impact_choice.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
class ImpactChoice(models.Model):
|
||||||
|
"""
|
||||||
|
Impact choices for Risks and Controls.
|
||||||
|
"""
|
||||||
|
name = models.CharField(_("Impact Name"), max_length=50)
|
||||||
|
description = models.TextField(_("Description"), blank=True, null=True)
|
||||||
|
value = models.IntegerField(_("Numeric Value"), unique=True, default=1)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.value} - {self.name} ({self.description})"
|
|
@ -1,5 +1,6 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from .impact_choice import ImpactChoice
|
||||||
from .likelihood_choice import LikelihoodChoice
|
from .likelihood_choice import LikelihoodChoice
|
||||||
from .risk import Risk
|
from .risk import Risk
|
||||||
|
|
||||||
|
@ -21,7 +22,12 @@ class ResidualRisk(models.Model):
|
||||||
verbose_name=_("Likelihood"),
|
verbose_name=_("Likelihood"),
|
||||||
related_name="residual_risks",
|
related_name="residual_risks",
|
||||||
)
|
)
|
||||||
impact = models.IntegerField(choices=Risk.IMPACT_CHOICES, default=1)
|
impact = models.ForeignKey(
|
||||||
|
ImpactChoice,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
verbose_name=_("Impact"),
|
||||||
|
related_name="residual_risks",
|
||||||
|
)
|
||||||
score = models.IntegerField(editable=False)
|
score = models.IntegerField(editable=False)
|
||||||
level = models.CharField(max_length=50, editable=False)
|
level = models.CharField(max_length=50, editable=False)
|
||||||
review_required = models.BooleanField(default=False)
|
review_required = models.BooleanField(default=False)
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from multiselectfield import MultiSelectField
|
from multiselectfield import MultiSelectField
|
||||||
|
from .impact_choice import ImpactChoice
|
||||||
from .likelihood_choice import LikelihoodChoice
|
from .likelihood_choice import LikelihoodChoice
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
@ -19,13 +20,6 @@ class Risk(models.Model):
|
||||||
("closed", _("Closed")),
|
("closed", _("Closed")),
|
||||||
("review_required", _("Review required")),
|
("review_required", _("Review required")),
|
||||||
]
|
]
|
||||||
IMPACT_CHOICES = [
|
|
||||||
(1, _("Very Low (< 1,000 € – minor operational impact)")),
|
|
||||||
(2, _("Low (1,000–5,000 € – local impact)")),
|
|
||||||
(3, _("High (5,000–15,000 € – team-level impact)")),
|
|
||||||
(4, _("Severe (50,000–100,000 € – regional impact)")),
|
|
||||||
(5, _("Critical (> 100,000 € – existential threat)")),
|
|
||||||
]
|
|
||||||
CIA_CHOICES = [
|
CIA_CHOICES = [
|
||||||
("1", _("Confidentiality")),
|
("1", _("Confidentiality")),
|
||||||
("2", _("Integrity")),
|
("2", _("Integrity")),
|
||||||
|
@ -59,7 +53,12 @@ class Risk(models.Model):
|
||||||
verbose_name=_("Likelihood"),
|
verbose_name=_("Likelihood"),
|
||||||
related_name="risks",
|
related_name="risks",
|
||||||
)
|
)
|
||||||
impact = models.IntegerField(choices=IMPACT_CHOICES, default=1)
|
impact = models.ForeignKey(
|
||||||
|
ImpactChoice,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
verbose_name=_("impact"),
|
||||||
|
related_name="risks",
|
||||||
|
)
|
||||||
|
|
||||||
# Calculated fields
|
# Calculated fields
|
||||||
score = models.IntegerField(editable=False)
|
score = models.IntegerField(editable=False)
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
from django import template
|
from django import template
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from ..models import Control, Incident, Risk, LikelihoodChoice
|
from ..models import Control, ImpactChoice, Incident, Risk, LikelihoodChoice
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
_RISK_STATUS_MAP = dict(Risk.STATUS_CHOICES)
|
_RISK_STATUS_MAP = dict(Risk.STATUS_CHOICES)
|
||||||
_CONTROL_STATUS_MAP = dict(Control.STATUS_CHOICES)
|
_CONTROL_STATUS_MAP = dict(Control.STATUS_CHOICES)
|
||||||
_INCIDENT_STATUS_MAP = dict(Incident.STATUS_CHOICES)
|
_INCIDENT_STATUS_MAP = dict(Incident.STATUS_CHOICES)
|
||||||
_IMPACT_LABELS = dict(Risk.IMPACT_CHOICES)
|
|
||||||
LEVEL_ID_MAP = {"Low": 1, "Medium": 2, "High": 3, "Critical": 4}
|
LEVEL_ID_MAP = {"Low": 1, "Medium": 2, "High": 3, "Critical": 4}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
# Likelihood
|
# Likelihood
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Likelihood Label
|
||||||
def get_likelihood_label(likelihood_obj):
|
def get_likelihood_label(likelihood_obj):
|
||||||
if not likelihood_obj:
|
if not likelihood_obj:
|
||||||
return ""
|
return ""
|
||||||
|
@ -22,6 +25,7 @@ def likelihood_id_label(likelihood):
|
||||||
return f"{likelihood.value} ({likelihood.name})"
|
return f"{likelihood.value} ({likelihood.name})"
|
||||||
return likelihood
|
return likelihood
|
||||||
|
|
||||||
|
# Likelihood Value
|
||||||
def get_likelihood_value(likelihood):
|
def get_likelihood_value(likelihood):
|
||||||
if isinstance(likelihood, LikelihoodChoice):
|
if isinstance(likelihood, LikelihoodChoice):
|
||||||
return likelihood.value
|
return likelihood.value
|
||||||
|
@ -31,6 +35,7 @@ def get_likelihood_value(likelihood):
|
||||||
def likelihood_value(likelihood_obj):
|
def likelihood_value(likelihood_obj):
|
||||||
return get_likelihood_value(likelihood_obj)
|
return get_likelihood_value(likelihood_obj)
|
||||||
|
|
||||||
|
# Likelihood Class
|
||||||
def get_likelihood_class(likelihood):
|
def get_likelihood_class(likelihood):
|
||||||
value = get_likelihood_value(likelihood)
|
value = get_likelihood_value(likelihood)
|
||||||
LIKELIHOOD_MAP = {
|
LIKELIHOOD_MAP = {
|
||||||
|
@ -45,6 +50,52 @@ def get_likelihood_class(likelihood):
|
||||||
def likelihood_class(likelihood):
|
def likelihood_class(likelihood):
|
||||||
return get_likelihood_class(likelihood)
|
return get_likelihood_class(likelihood)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Impact
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Impact Label
|
||||||
|
def get_impact_label(impact_obj):
|
||||||
|
if not impact_obj:
|
||||||
|
return ""
|
||||||
|
return f"{impact_obj.value} ({impact_obj.name})"
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def impact_id_label(impact):
|
||||||
|
if isinstance(impact, ImpactChoice):
|
||||||
|
return f"{impact.value} ({impact.name})"
|
||||||
|
return impact
|
||||||
|
|
||||||
|
# Impact Value
|
||||||
|
def get_impact_value(impact):
|
||||||
|
if isinstance(impact, ImpactChoice):
|
||||||
|
return impact.value
|
||||||
|
return impact
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def impact_value(impact_obj):
|
||||||
|
return get_impact_value(impact_obj)
|
||||||
|
|
||||||
|
# Impact Class
|
||||||
|
def get_impact_class(impact):
|
||||||
|
value = get_impact_value(impact)
|
||||||
|
IMPACT_MAP = {
|
||||||
|
1: "is-control-verylow",
|
||||||
|
2: "is-control-low",
|
||||||
|
3: "is-control-mid",
|
||||||
|
4: "is-control-high",
|
||||||
|
5: "is-control-veryhigh",
|
||||||
|
}
|
||||||
|
return IMPACT_MAP.get(value, "is-light")
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def impact_class(impact):
|
||||||
|
return get_impact_class(impact)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Unsorted
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def sort_url(request, field, current_sort, current_dir):
|
def sort_url(request, field, current_sort, current_dir):
|
||||||
query = request.GET.copy()
|
query = request.GET.copy()
|
||||||
|
@ -90,15 +141,6 @@ def _short(label: str) -> str:
|
||||||
return label.split(sep, 1)[0].strip()
|
return label.split(sep, 1)[0].strip()
|
||||||
return label.strip()
|
return label.strip()
|
||||||
|
|
||||||
@register.filter
|
|
||||||
def impact_id_label(val):
|
|
||||||
try:
|
|
||||||
i = int(val)
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
return ""
|
|
||||||
label = _IMPACT_LABELS.get(i, "")
|
|
||||||
short = _short(str(label)) if label else ""
|
|
||||||
return format_html("{} ({})", i, short) if label else format_html("{}", i)
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def risk_status_label(code):
|
def risk_status_label(code):
|
||||||
|
@ -139,13 +181,6 @@ LEVEL_MAP = {
|
||||||
"Critical": "is-control-veryhigh",
|
"Critical": "is-control-veryhigh",
|
||||||
}
|
}
|
||||||
|
|
||||||
@register.filter
|
|
||||||
def impact_class(val):
|
|
||||||
try:
|
|
||||||
return IMPACT_MAP.get(int(val), "is-light")
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
return "is-light"
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def level_class(level):
|
def level_class(level):
|
||||||
return LEVEL_MAP.get(str(level), "is-light")
|
return LEVEL_MAP.get(str(level), "is-light")
|
||||||
|
|
|
@ -13,7 +13,7 @@ from rest_framework import viewsets
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
|
||||||
from .forms import RiskStatusForm, ControlStatusForm, IncidentStatusForm, ResidualReviewForm
|
from .forms import RiskStatusForm, ControlStatusForm, IncidentStatusForm, ResidualReviewForm
|
||||||
from .models import AuditLog, Risk, Control, ResidualRisk, AuditLog, Incident, LikelihoodChoice, Notification
|
from .models import AuditLog, ImpactChoice, Risk, Control, ResidualRisk, AuditLog, Incident, LikelihoodChoice, Notification
|
||||||
from .serializers import (
|
from .serializers import (
|
||||||
ControlSerializer, RiskSerializer, ResidualRiskSerializer,
|
ControlSerializer, RiskSerializer, ResidualRiskSerializer,
|
||||||
UserSerializer, AuditSerializer, IncidentSerializer,
|
UserSerializer, AuditSerializer, IncidentSerializer,
|
||||||
|
@ -466,18 +466,24 @@ def update_residual_review(request, risk_id):
|
||||||
def risk_matrix(request):
|
def risk_matrix(request):
|
||||||
"""Show gross/net risk matrix."""
|
"""Show gross/net risk matrix."""
|
||||||
risks = Risk.objects.select_related("owner", "residual_risk").all()
|
risks = Risk.objects.select_related("owner", "residual_risk").all()
|
||||||
impacts = sorted(Risk.IMPACT_CHOICES, key=lambda x: x[0])
|
impacts = ImpactChoice.objects.all().order_by('value')
|
||||||
likelihoods = LikelihoodChoice.objects.all().order_by('value')
|
likelihoods = LikelihoodChoice.objects.all().order_by('value')
|
||||||
|
|
||||||
# Erstelle die Matrizen mit den Werten der LikelihoodChoice-Objekte
|
# Erstelle die Matrizen mit den Werten der LikelihoodChoice-Objekte
|
||||||
gross_matrix = {i: {likelihood.value: [] for likelihood in likelihoods} for i, _ in impacts}
|
gross_matrix = {
|
||||||
net_matrix = {i: {likelihood.value: [] for likelihood in likelihoods} for i, _ in impacts}
|
impact.value: {likelihood.value: [] for likelihood in likelihoods}
|
||||||
|
for impact in impacts
|
||||||
|
}
|
||||||
|
net_matrix = {
|
||||||
|
impact.value: {likelihood.value: [] for likelihood in likelihoods}
|
||||||
|
for impact in impacts
|
||||||
|
}
|
||||||
|
|
||||||
for r in risks:
|
for r in risks:
|
||||||
gross_matrix[r.impact][r.likelihood.value].append(r)
|
gross_matrix[r.impact.value][r.likelihood.value].append(r)
|
||||||
rr = getattr(r, "residual_risk", None)
|
rr = getattr(r, "residual_risk", None)
|
||||||
if rr:
|
if rr:
|
||||||
net_matrix[rr.impact][rr.likelihood.value].append(r)
|
net_matrix[rr.impact.value][rr.likelihood.value].append(r)
|
||||||
|
|
||||||
return render(request, "risks/risk_matrix.html", {
|
return render(request, "risks/risk_matrix.html", {
|
||||||
"impacts": impacts,
|
"impacts": impacts,
|
||||||
|
|
|
@ -107,8 +107,8 @@
|
||||||
<div class="column is-half">
|
<div class="column is-half">
|
||||||
<button class="risk-chip {{ risk.impact|impact_class }}" type="button">
|
<button class="risk-chip {{ risk.impact|impact_class }}" type="button">
|
||||||
<span class="chip-head">{% trans "Impact" %}</span>
|
<span class="chip-head">{% trans "Impact" %}</span>
|
||||||
<span class="chip-id">{{ risk.impact }}</span>
|
<span class="chip-id">{{ risk.impact.value }} - {{ risk.impact.name }}</span>
|
||||||
<span class="chip-label">{{ risk.get_impact_display }}</span>
|
<span class="chip-label">{{ risk.impact.description }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -153,8 +153,8 @@
|
||||||
<div class="column is-half">
|
<div class="column is-half">
|
||||||
<button class="risk-chip {{ risk.residual_risk.impact|impact_class }}" type="button">
|
<button class="risk-chip {{ risk.residual_risk.impact|impact_class }}" type="button">
|
||||||
<span class="chip-head">{% trans "Impact" %}</span>
|
<span class="chip-head">{% trans "Impact" %}</span>
|
||||||
<span class="chip-id">{{ risk.residual_risk.impact }}</span>
|
<span class="chip-id">{{ risk.residual_risk.impact.value }} - {{ risk.residual_risk.impact.name }}</span>
|
||||||
<span class="chip-label">{{ risk.residual_risk.get_impact_display }}</span>
|
<span class="chip-label">{{ risk.residual_risk.impact.description }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -17,16 +17,18 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th class="has-text-left">{% trans "Impact" %} * {% trans "Likelihood" %}</th>
|
<th class="has-text-left">{% trans "Impact" %} * {% trans "Likelihood" %}</th>
|
||||||
{% for likelihood in likelihoods %}
|
{% for likelihood in likelihoods %}
|
||||||
<th class="{{ likelihood.value|likelihood_class|to_bg }}">{{ likelihood.value }} ({{ likelihood.name }}) <br> {{ likelihood.description }}</th>
|
<th class="{{ likelihood.value|likelihood_class|to_bg }}">
|
||||||
|
{{ likelihood.value }} ({{ likelihood.name }}) <br> {{ likelihood.description }}
|
||||||
|
</th>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for i_val, i_label in impacts reversed %}
|
{% for impact in impacts reversed %}
|
||||||
<tr>
|
<tr>
|
||||||
<th class="has-text-left {{ i_val|impact_class|to_bg }}">{{ i_label }}</th>
|
<th class="has-text-left {{ impact.value|impact_class|to_bg }}">{{ impact.value }} - {{ impact.name }}<br>{{ impact.description }}</th>
|
||||||
{% for likelihood in likelihoods %}
|
{% for likelihood in likelihoods %}
|
||||||
{% with s=i_val|mul:likelihood.value %}
|
{% with s=impact.value|mul:likelihood.value %}
|
||||||
<td class="risk-matrix-cell {{ s|score_bg_class }}">
|
<td class="risk-matrix-cell {{ s|score_bg_class }}">
|
||||||
<div class="is-flex is-justify-content-center is-align-items-center">
|
<div class="is-flex is-justify-content-center is-align-items-center">
|
||||||
{% if s <= 4 %}
|
{% if s <= 4 %}
|
||||||
|
@ -71,18 +73,18 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th class="has-text-left">{% trans "Impact" %} / {% trans "Likelihood" %}</th>
|
<th class="has-text-left">{% trans "Impact" %} / {% trans "Likelihood" %}</th>
|
||||||
{% for likelihood in likelihoods %}
|
{% for likelihood in likelihoods %}
|
||||||
<th class="{{ likelihood.value|likelihood_class|to_bg }}">{{ likelihood.value }} ({{ likelihood.name }})</th>
|
<th class="{{ likelihood.value|likelihood_class|to_bg }}">{{ likelihood.value }} ({{ likelihood.name }}) <br> {{ likelihood.description }}</th>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for i_val, i_label in impacts reversed %}
|
{% for impact in impacts reversed %}
|
||||||
<tr>
|
<tr>
|
||||||
<th class="has-text-left {{ i_val|impact_class|to_bg }}">{{ i_label }}</th>
|
<th class="has-text-left {{ impact.value|impact_class|to_bg }}">{{ impact.value }} - {{ impact.name }}<br>{{ impact.description }}</th>
|
||||||
{% for likelihood in likelihoods %}
|
{% for likelihood in likelihoods %}
|
||||||
{% with row=gross_matrix|dict_get:i_val %}
|
{% with row=gross_matrix|dict_get:impact.value %}
|
||||||
{% with cell=row|dict_get:likelihood.value %}
|
{% with cell=row|dict_get:likelihood.value %}
|
||||||
{% with s=i_val|mul:likelihood.value %}
|
{% with s=impact.value|mul:likelihood.value %}
|
||||||
<td class="risk-matrix-cell {{ likelihood|likelihood_class }}">
|
<td class="risk-matrix-cell {{ likelihood|likelihood_class }}">
|
||||||
{% if cell %}
|
{% if cell %}
|
||||||
<ul class="risk-cell-list">
|
<ul class="risk-cell-list">
|
||||||
|
@ -112,18 +114,18 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th class="has-text-left">{% trans "Impact" %} / {% trans "Likelihood" %}</th>
|
<th class="has-text-left">{% trans "Impact" %} / {% trans "Likelihood" %}</th>
|
||||||
{% for likelihood in likelihoods %}
|
{% for likelihood in likelihoods %}
|
||||||
<th class="{{ likelihood.value|likelihood_class|to_bg }}">{{ likelihood.value }} ({{ likelihood.name }})</th>
|
<th class="{{ likelihood.value|likelihood_class|to_bg }}">{{ likelihood.value }} ({{ likelihood.name }}) <br> {{ likelihood.description }}</th>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for i_val, i_label in impacts reversed %}
|
{% for impact in impacts reversed %}
|
||||||
<tr>
|
<tr>
|
||||||
<th class="has-text-left {{ i_val|impact_class|to_bg }}">{{ i_label }}</th>
|
<th class="has-text-left {{ impact.value|impact_class|to_bg }}">{{ impact.value }} - {{ impact.name }}<br>{{ impact.description }}</th>
|
||||||
{% for likelihood in likelihoods %}
|
{% for likelihood in likelihoods %}
|
||||||
{% with row=net_matrix|dict_get:i_val %}
|
{% with row=net_matrix|dict_get:impact.value %}
|
||||||
{% with cell=row|dict_get:likelihood.value %}
|
{% with cell=row|dict_get:likelihood.value %}
|
||||||
{% with s=i_val|mul:likelihood.value %}
|
{% with s=impact.value|mul:likelihood.value %}
|
||||||
<td class="risk-matrix-cell {{ likelihood|likelihood_class }}">
|
<td class="risk-matrix-cell {{ likelihood|likelihood_class }}">
|
||||||
{% if cell %}
|
{% if cell %}
|
||||||
<ul class="risk-cell-list">
|
<ul class="risk-cell-list">
|
||||||
|
|
Loading…
Add table
Reference in a new issue