Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/+goldenconfig-bulk-edit.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a bulk edit view for Golden Config (Configuration Overview) records.
1 change: 1 addition & 0 deletions changes/+tags-support.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added tag support throughout the UI for all Golden Config models: tags can be added and removed in bulk edit, filtered on from every list view, and displayed as an optional table column.
29 changes: 19 additions & 10 deletions nautobot_golden_config/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import django.forms as django_forms
from django.conf import settings
from nautobot.apps import forms
from nautobot.apps.forms import NautobotBulkEditForm, NautobotFilterForm, NautobotModelForm
from nautobot.apps.forms import NautobotBulkEditForm, NautobotFilterForm, NautobotModelForm, TagsBulkEditFormMixin
from nautobot.dcim.models import Device, DeviceType, Location, Manufacturer, Platform, Rack, RackGroup
from nautobot.extras.models import DynamicGroup, GitRepository, GraphQLQuery, JobResult, Role, Status, Tag
from nautobot.tenancy.models import Tenant, TenantGroup
Expand Down Expand Up @@ -116,11 +116,13 @@ class GoldenConfigFilterForm(DeviceRelatedFilterForm):
"device_status",
"device_type",
"device",
"tags",
]
q = django_forms.CharField(required=False, label="Search")
tags = forms.TagFilterField(model)


class GoldenConfigBulkEditForm(NautobotBulkEditForm):
class GoldenConfigBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
"""BulkEdit form for GoldenConfig instances."""

pk = django_forms.ModelMultipleChoiceField(
Expand Down Expand Up @@ -154,9 +156,11 @@ class ConfigComplianceFilterForm(DeviceRelatedFilterForm):
"device_status",
"device_type",
"device",
"tags",
]

q = django_forms.CharField(required=False, label="Search")
tags = forms.TagFilterField(model)

def __init__(self, *args, **kwargs):
"""Required for status to work."""
Expand Down Expand Up @@ -206,9 +210,10 @@ class ComplianceRuleFilterForm(NautobotFilterForm):
)

feature = forms.DynamicModelMultipleChoiceField(queryset=models.ComplianceFeature.objects.all(), required=False)
tags = forms.TagFilterField(model)


class ComplianceRuleBulkEditForm(NautobotBulkEditForm):
class ComplianceRuleBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
"""BulkEdit form for ComplianceRule instances."""

pk = django_forms.ModelMultipleChoiceField(
Expand Down Expand Up @@ -250,6 +255,7 @@ class ComplianceFeatureFilterForm(NautobotFilterForm):
model = models.ComplianceFeature
q = django_forms.CharField(required=False, label="Search")
name = forms.DynamicModelChoiceField(queryset=models.ComplianceFeature.objects.all(), required=False)
tags = forms.TagFilterField(model)


class ComplianceFeatureFilterFormAlt(DeviceRelatedFilterForm): # pylint: disable=nb-sub-class-name
Expand Down Expand Up @@ -289,7 +295,7 @@ def __init__(self, *args, **kwargs):
self.order_fields(self.field_order)


class ComplianceFeatureBulkEditForm(NautobotBulkEditForm):
class ComplianceFeatureBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
"""BulkEdit form for ComplianceFeature instances."""

pk = django_forms.ModelMultipleChoiceField(
Expand Down Expand Up @@ -328,9 +334,10 @@ class ConfigRemoveFilterForm(NautobotFilterForm):
name = forms.DynamicModelChoiceField(
queryset=models.ConfigRemove.objects.all(), to_field_name="name", required=False
)
tags = forms.TagFilterField(model)


class ConfigRemoveBulkEditForm(NautobotBulkEditForm):
class ConfigRemoveBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
"""BulkEdit form for ConfigRemove instances."""

pk = django_forms.ModelMultipleChoiceField(
Expand Down Expand Up @@ -370,9 +377,10 @@ class ConfigReplaceFilterForm(NautobotFilterForm):
name = forms.DynamicModelChoiceField(
queryset=models.ConfigReplace.objects.all(), to_field_name="name", required=False
)
tags = forms.TagFilterField(model)


class ConfigReplaceBulkEditForm(NautobotBulkEditForm):
class ConfigReplaceBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
"""BulkEdit form for ConfigReplace instances."""

pk = django_forms.ModelMultipleChoiceField(
Expand Down Expand Up @@ -439,9 +447,10 @@ class GoldenConfigSettingFilterForm(NautobotFilterForm):
queryset=GitRepository.objects.filter(provided_contents__contains="nautobot_golden_config.jinjatemplate"),
required=False,
)
tags = forms.TagFilterField(model)


class GoldenConfigSettingBulkEditForm(NautobotBulkEditForm):
class GoldenConfigSettingBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
"""BulkEdit form for GoldenConfigSetting instances."""

pk = django_forms.ModelMultipleChoiceField(
Expand Down Expand Up @@ -479,9 +488,10 @@ class RemediationSettingFilterForm(NautobotFilterForm):
widget=django_forms.Select(),
label="Remediation Type",
)
tags = forms.TagFilterField(model)


class RemediationSettingBulkEditForm(NautobotBulkEditForm):
class RemediationSettingBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
"""BulkEdit form for RemediationSetting instances."""

pk = django_forms.ModelMultipleChoiceField(
Expand Down Expand Up @@ -640,7 +650,7 @@ class ConfigPlanFilterForm(DeviceRelatedFilterForm):
tags = forms.TagFilterField(model)


class ConfigPlanBulkEditForm(NautobotBulkEditForm):
class ConfigPlanBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
"""BulkEdit form for ConfigPlan instances."""

pk = django_forms.ModelMultipleChoiceField(
Expand All @@ -660,7 +670,6 @@ class Meta:
nullable_fields = [
"change_control_id",
"change_control_url",
"tags",
]


Expand Down
34 changes: 28 additions & 6 deletions nautobot_golden_config/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
MATCH_CONFIG = """{{ record.match_config|linebreaksbr }}"""


def actual_fields():
def actual_fields(include_tags=False):
"""Convienance function to conditionally toggle columns."""
active_fields = ["pk", "name"]
if ENABLE_BACKUP:
Expand All @@ -118,6 +118,8 @@ def actual_fields():
active_fields.append("intended_last_success_date")
if ENABLE_COMPLIANCE:
active_fields.append("compliance_last_success_date")
if include_tags:
active_fields.append("tags")
active_fields.append("actions")
return tuple(active_fields)

Expand Down Expand Up @@ -288,6 +290,8 @@ class GoldenConfigTable(BaseTable):
order_by="compliance_last_success_date",
)

tags = TagColumn(url_name="plugins:nautobot_golden_config:goldenconfig_list")

actions = ButtonsColumn(
buttons=("delete",),
model=models.GoldenConfig,
Expand Down Expand Up @@ -329,7 +333,8 @@ class Meta(BaseTable.Meta):
"""Meta for class GoldenConfigTable."""

model = models.GoldenConfig
fields = actual_fields()
fields = actual_fields(include_tags=True)
default_columns = actual_fields()


# ComplianceFeature
Expand All @@ -340,12 +345,13 @@ class ComplianceFeatureTable(BaseTable):

pk = ToggleColumn()
name = LinkColumn("plugins:nautobot_golden_config:compliancefeature", args=[A("pk")])
tags = TagColumn(url_name="plugins:nautobot_golden_config:compliancefeature_list")

class Meta(BaseTable.Meta):
"""Table to display Compliance Features Meta Data."""

model = models.ComplianceFeature
fields = ("pk", "name", "slug", "description")
fields = ("pk", "name", "slug", "description", "tags")
default_columns = ("pk", "name", "slug", "description")


Expand All @@ -361,6 +367,7 @@ class ComplianceRuleTable(BaseTable):
config_ordered = BooleanColumn()
custom_compliance = BooleanColumn()
config_remediation = BooleanColumn()
tags = TagColumn(url_name="plugins:nautobot_golden_config:compliancerule_list")

class Meta(BaseTable.Meta):
"""Table to display Compliance Rules Meta Data."""
Expand All @@ -376,6 +383,7 @@ class Meta(BaseTable.Meta):
"config_type",
"custom_compliance",
"config_remediation",
"tags",
)
default_columns = (
"pk",
Expand All @@ -398,12 +406,13 @@ class ConfigRemoveTable(BaseTable):

pk = ToggleColumn()
name = LinkColumn("plugins:nautobot_golden_config:configremove", args=[A("pk")])
tags = TagColumn(url_name="plugins:nautobot_golden_config:configremove_list")

class Meta(BaseTable.Meta):
"""Table to display Compliance Rules Meta Data."""

model = models.ConfigRemove
fields = ("pk", "name", "platform", "description", "regex")
fields = ("pk", "name", "platform", "description", "regex", "tags")
default_columns = ("pk", "name", "platform", "description", "regex")


Expand All @@ -415,12 +424,13 @@ class ConfigReplaceTable(BaseTable):

pk = ToggleColumn()
name = LinkColumn("plugins:nautobot_golden_config:configreplace", args=[A("pk")])
tags = TagColumn(url_name="plugins:nautobot_golden_config:configreplace_list")

class Meta(BaseTable.Meta):
"""Table to display Compliance Rules Meta Data."""

model = models.ConfigReplace
fields = ("pk", "name", "platform", "description", "regex", "replace")
fields = ("pk", "name", "platform", "description", "regex", "replace", "tags")
default_columns = ("pk", "name", "platform", "description", "regex", "replace")


Expand All @@ -442,6 +452,7 @@ class GoldenConfigSettingTable(BaseTable):
verbose_name="Backup Repository",
empty_values=(),
)
tags = TagColumn(url_name="plugins:nautobot_golden_config:goldenconfigsetting_list")

def _render_capability(self, record, column, record_attribute): # pylint: disable=unused-argument
if getattr(record, record_attribute, None):
Expand Down Expand Up @@ -472,6 +483,16 @@ class Meta(BaseTable.Meta):
"backup_repository",
"intended_repository",
"jinja_repository",
"tags",
)
default_columns = (
"pk",
"name",
"weight",
"description",
"backup_repository",
"intended_repository",
"jinja_repository",
)


Expand All @@ -480,12 +501,13 @@ class RemediationSettingTable(BaseTable):

pk = ToggleColumn()
platform = LinkColumn("plugins:nautobot_golden_config:remediationsetting", args=[A("pk")])
tags = TagColumn(url_name="plugins:nautobot_golden_config:remediationsetting_list")

class Meta(BaseTable.Meta):
"""Table to display RemediationSetting Meta Data."""

model = models.RemediationSetting
fields = ("pk", "platform", "remediation_type")
fields = ("pk", "platform", "remediation_type", "tags")
default_columns = ("pk", "platform", "remediation_type")


Expand Down
1 change: 1 addition & 0 deletions nautobot_golden_config/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class GoldenConfigUIViewSet( # pylint: disable=abstract-method
views.ObjectDetailViewMixin,
views.ObjectDestroyViewMixin,
views.ObjectBulkDestroyViewMixin,
views.ObjectBulkUpdateViewMixin,
views.ObjectListViewMixin, # TODO: Changing the order of the mixins breaks things... why?
ObjectDataComplianceViewMixin, # TODO: Import from views after nautobot release
):
Expand Down
Loading