diff --git a/changes/812.fixed b/changes/812.fixed new file mode 100644 index 00000000..69fb1440 --- /dev/null +++ b/changes/812.fixed @@ -0,0 +1 @@ +Fixed bug in config compliance list view. diff --git a/nautobot_golden_config/models.py b/nautobot_golden_config/models.py index bbedd895..a8a8272f 100644 --- a/nautobot_golden_config/models.py +++ b/nautobot_golden_config/models.py @@ -368,6 +368,8 @@ def to_objectchange(self, action, *, related_object=None, object_data_extra=None related_object=related_object, ) + is_dynamic_group_associable_model = False + class Meta: """Set unique together fields for model.""" diff --git a/nautobot_golden_config/tables.py b/nautobot_golden_config/tables.py index 57adbaaf..981d7e64 100644 --- a/nautobot_golden_config/tables.py +++ b/nautobot_golden_config/tables.py @@ -1,7 +1,5 @@ """Django Tables2 classes for golden_config app.""" -import copy - from django.utils.html import format_html from django_tables2 import Column, LinkColumn, TemplateColumn from django_tables2.utils import A @@ -157,7 +155,7 @@ class ConfigComplianceTable(BaseTable): pk = ToggleColumn(accessor=A("device")) device = TemplateColumn( - template_code="""{{ record.device__name }} """ + template_code="""{{ record.device__name }} """ ) def __init__(self, *args, **kwargs): @@ -170,13 +168,19 @@ def __init__(self, *args, **kwargs): .values_list("rule__feature__slug", flat=True) .distinct() ) - extra_columns = [(feature, ComplianceColumn(verbose_name=feature)) for feature in features] - kwargs["extra_columns"] = extra_columns # Nautobot's BaseTable.configurable_columns() only recognizes columns in self.base_columns, # so override the class's base_columns to include our additional columns as configurable. - self.base_columns = copy.deepcopy(self.base_columns) - for feature, column in extra_columns: - self.base_columns[feature] = column + # Note: The correct way to modify django_tables2 columns at init is to use the extra_columns kwarg but Nautobot doesn't support that. + for feature in features: + self.base_columns[feature] = ComplianceColumn(verbose_name=feature) # pylint: disable=no-member + compliance_columns = [ + column_name + for column_name, column in self.base_columns.items() # pylint: disable=no-member + if isinstance(column, ComplianceColumn) + ] + removed_features = set(compliance_columns) - set(features) + for column_name in removed_features: + del self.base_columns[column_name] # pylint: disable=no-member super().__init__(*args, **kwargs) class Meta(BaseTable.Meta): diff --git a/nautobot_golden_config/tests/test_views.py b/nautobot_golden_config/tests/test_views.py index 937826b7..f52f022f 100644 --- a/nautobot_golden_config/tests/test_views.py +++ b/nautobot_golden_config/tests/test_views.py @@ -1,6 +1,7 @@ """Unit tests for nautobot_golden_config views.""" import datetime +import re from unittest import mock, skip import nautobot @@ -393,3 +394,42 @@ def test_alter_queryset(self): self.assertSequenceEqual(list(device.keys()), ["device", "device__name", *features]) for feature in features: self.assertIn(device[feature], [0, 1]) + + def test_table_columns(self): + """Test the columns of the ConfigCompliance table return the expected pivoted data.""" + response = self.client.get(reverse("plugins:nautobot_golden_config:configcompliance_list")) + expected_table_headers = ["Device", "TestFeature0", "TestFeature1", "TestFeature2", "TestFeature3"] + table_headers = re.findall(r'