diff --git a/CHANGELOG.md b/CHANGELOG.md index e0be1738..39a647b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Every screen is rebuilt on the component framework : one detail page anatomy, one section title, one empty-value marker, one badge and tag pill, and form footers with a neutral Cancel on the left. - Dates follow the active locale everywhere, and short numeric dates put the day first in English as in French. - The lifecycle editor shows its steps, transitions and JSON as stacked cards instead of tabs. +- The assessment result toggles read the planning / fieldwork phase from the assessment instead of comparing a status string in the template. ### Fixed @@ -26,11 +27,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Opening an assessment result's edit page directly failed with a server error, and so did the preview of a finding recorded without an audit. - Global search results for sites had no link, and the SWOT item and strategy dialogs could not be closed or cancelled. - The group permission matrix lacked its Validate column, which shifted the labels of the columns after it, and the decision and ISMS change forms never showed field errors. +- Risk criteria pages had no lifecycle stepper, so a criteria set could not be submitted or validated from the interface. +- Choosing another assessment on a new risk now reloads its likelihood and impact scales, in the dialog as on the page (it only ever worked on a fully reloaded page). +- Opening a drawer-only delete link directly (incidents, nonconformities, supplier contacts and sub-processors) rendered a bare dialog fragment instead of a confirmation page. +- The Trust Center hub and the semantic index pages showed a loose eyebrow (the hub's even read "Strategy") instead of their menu breadcrumb. ### Security - Saving a group's permission matrix silently revoked the permissions it did not display (assess, implement, close, cancel, override dates); they now have a column, and permissions outside the registry are never touched. - Tag colours are validated before reaching a style attribute, and Cancel / Back links no longer echo an unchecked Referer header. +- The risk scale endpoint no longer answers with the criteria of an assessment outside the user's scopes. + ## [0.36.1] - 2026-11-03 diff --git a/assets/templates/assets/supplier_contact_confirm_delete_modal.html b/assets/templates/assets/supplier_contact_confirm_delete_modal.html index 031e1b6e..bab30a6e 100644 --- a/assets/templates/assets/supplier_contact_confirm_delete_modal.html +++ b/assets/templates/assets/supplier_contact_confirm_delete_modal.html @@ -1,4 +1,4 @@ -{% extends "includes/confirm_delete_modal.html" %} +{% extends delete_shell|default:"includes/confirm_delete_modal.html" %} {% load i18n %} {% comment %} Drawer-served delete confirmation for a supplier contact. Posted via HTMX; diff --git a/assets/templates/assets/supplier_subprocessor_confirm_delete_modal.html b/assets/templates/assets/supplier_subprocessor_confirm_delete_modal.html index 63f39c13..b05a47a7 100644 --- a/assets/templates/assets/supplier_subprocessor_confirm_delete_modal.html +++ b/assets/templates/assets/supplier_subprocessor_confirm_delete_modal.html @@ -1,4 +1,4 @@ -{% extends "includes/confirm_delete_modal.html" %} +{% extends delete_shell|default:"includes/confirm_delete_modal.html" %} {% load i18n %} {% comment %} Drawer-served delete confirmation for a supplier sub-processor engagement. diff --git a/assets/views.py b/assets/views.py index 2cc77e31..9e2491c7 100644 --- a/assets/views.py +++ b/assets/views.py @@ -25,6 +25,7 @@ from core.mixins import ( AdvancedFilterMixin, ColumnPreferenceMixin, + ConfirmDeleteShellMixin, HtmxFormMixin, ListSummaryMixin, PredefinedFilterMixin, @@ -1007,7 +1008,7 @@ def get_success_url(self): return reverse_lazy("assets:supplier-detail", kwargs={"pk": self.object.supplier.pk}) -class SupplierContactDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView): +class SupplierContactDeleteView(LoginRequiredMixin, ConfirmDeleteShellMixin, PermissionRequiredMixin, DeleteView): model = SupplierContact template_name = "assets/supplier_contact_confirm_delete_modal.html" permission_required = "assets.supplier.update" @@ -1083,7 +1084,7 @@ def get_success_url(self): return reverse_lazy("assets:supplier-detail", kwargs={"pk": self.object.supplier.pk}) -class SupplierSubprocessorDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView): +class SupplierSubprocessorDeleteView(LoginRequiredMixin, ConfirmDeleteShellMixin, PermissionRequiredMixin, DeleteView): model = SupplierSubprocessor template_name = "assets/supplier_subprocessor_confirm_delete_modal.html" permission_required = "assets.supplier.update" diff --git a/assistant/templates/assistant/semantic_index.html b/assistant/templates/assistant/semantic_index.html index c86fc18d..fd9d4954 100644 --- a/assistant/templates/assistant/semantic_index.html +++ b/assistant/templates/assistant/semantic_index.html @@ -4,7 +4,7 @@ {% block title %}{% trans "Semantic index - Cairn" %}{% endblock %} {% block content %} -{% page_header _("Semantic index") eyebrow=_("Administration") accent="accounts" %}{% endpage_header %} +{% page_header _("Semantic index") nav="assistant:semantic-index" accent="accounts" %}{% endpage_header %} {% detail_layout %} {% slot rail %}{% if semantic.enabled and semantic.embeddings_supported %} diff --git a/compliance/constants.py b/compliance/constants.py index 95e64507..f608a9c4 100644 --- a/compliance/constants.py +++ b/compliance/constants.py @@ -127,6 +127,17 @@ class AssessmentStatus(models.TextChoices): AssessmentStatus.IN_PROGRESS, } +# Within the toggleable steps : planning decides what will be evaluated +# (not assessed <-> evaluated), fieldwork records the verdict +# (evaluated <-> compliant). See ComplianceAssessment.is_planning_phase. +ASSESSMENT_PLANNING_STATUSES = { + AssessmentStatus.DRAFT, + AssessmentStatus.PLANNED, +} +ASSESSMENT_FIELDWORK_STATUSES = { + AssessmentStatus.IN_PROGRESS, +} + # Statuses that allow full editing of findings and result details ASSESSMENT_EDITABLE_STATUSES = { AssessmentStatus.IN_PROGRESS, diff --git a/compliance/models/assessment.py b/compliance/models/assessment.py index 6f85485b..e1af1672 100644 --- a/compliance/models/assessment.py +++ b/compliance/models/assessment.py @@ -9,6 +9,8 @@ from simple_history.models import HistoricalRecords from compliance.constants import ( + ASSESSMENT_FIELDWORK_STATUSES, + ASSESSMENT_PLANNING_STATUSES, AssessmentStatus, ComplianceStatus, FINDING_SEVERITY_ORDER, @@ -137,6 +139,16 @@ def compliance_pct(self): def workflow_perm_namespace(self): return "compliance.assessment" + @property + def is_planning_phase(self): + """Planning: choosing what will be evaluated (not assessed <-> evaluated).""" + return self.status in ASSESSMENT_PLANNING_STATUSES + + @property + def is_fieldwork_phase(self): + """Fieldwork: recording verdicts (evaluated <-> compliant).""" + return self.status in ASSESSMENT_FIELDWORK_STATUSES + def transition_to(self, target, user=None, comment=None, *, enforce_permission=False, save=True): """Validate and perform a status transition. diff --git a/compliance/templates/compliance/assessment_results_table_body.html b/compliance/templates/compliance/assessment_results_table_body.html index 6d41e28c..695aa4dc 100644 --- a/compliance/templates/compliance/assessment_results_table_body.html +++ b/compliance/templates/compliance/assessment_results_table_body.html @@ -88,12 +88,12 @@ - {% elif assessment.status == 'in_progress' and entry.result and entry.result.compliance_status == 'not_assessed' %} + {% elif assessment.is_fieldwork_phase and entry.result and entry.result.compliance_status == 'not_assessed' %} {# IN_PROGRESS: NOT_ASSESSED is frozen #} - {% elif assessment.status == 'in_progress' %} + {% elif assessment.is_fieldwork_phase %} {# IN_PROGRESS: toggle EVALUATED ↔ COMPLIANT #}