From 8be4fbbce3a8c78338f974ba008eb5663670f707 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 16 Mar 2021 15:57:23 -0400 Subject: [PATCH] Add JournalEntry list view w/filtering --- netbox/extras/filters.py | 30 ++++++++++------ netbox/extras/forms.py | 34 +++++++++++++++++++ netbox/extras/migrations/0058_journalentry.py | 1 + netbox/extras/models/models.py | 1 + netbox/extras/tables.py | 25 ++++++++++++++ netbox/extras/urls.py | 1 + netbox/extras/views.py | 8 +++++ netbox/templates/extras/object_journal.html | 1 + netbox/templates/inc/nav_menu.html | 3 ++ 9 files changed, 94 insertions(+), 10 deletions(-) diff --git a/netbox/extras/filters.py b/netbox/extras/filters.py index 7893b050f..afe3bff16 100644 --- a/netbox/extras/filters.py +++ b/netbox/extras/filters.py @@ -119,22 +119,32 @@ class ImageAttachmentFilterSet(BaseFilterSet): class JournalEntryFilterSet(BaseFilterSet): + q = django_filters.CharFilter( + method='search', + label='Search', + ) + created = django_filters.DateTimeFromToRangeFilter() assigned_object_type = ContentTypeFilter() - # created_by_id = django_filters.ModelMultipleChoiceFilter( - # queryset=User.objects.all(), - # label='User (ID)', - # ) - # created_by = django_filters.ModelMultipleChoiceFilter( - # field_name='user__username', - # queryset=User.objects.all(), - # to_field_name='username', - # label='User (name)', - # ) + created_by_id = django_filters.ModelMultipleChoiceFilter( + queryset=User.objects.all(), + label='User (ID)', + ) + created_by = django_filters.ModelMultipleChoiceFilter( + field_name='created_by__username', + queryset=User.objects.all(), + to_field_name='username', + label='User (name)', + ) class Meta: model = JournalEntry fields = ['id', 'assigned_object_type_id', 'assigned_object_id', 'created'] + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter(comments__icontains=value) + class TagFilterSet(BaseFilterSet): q = django_filters.CharFilter( diff --git a/netbox/extras/forms.py b/netbox/extras/forms.py index f6a960bd9..a126378fa 100644 --- a/netbox/extras/forms.py +++ b/netbox/extras/forms.py @@ -386,6 +386,40 @@ class JournalEntryForm(BootstrapMixin, forms.ModelForm): } +class JournalEntryFilterForm(BootstrapMixin, forms.Form): + model = JournalEntry + q = forms.CharField( + required=False, + label=_('Search') + ) + created_after = forms.DateTimeField( + required=False, + label=_('After'), + widget=DateTimePicker() + ) + created_before = forms.DateTimeField( + required=False, + label=_('Before'), + widget=DateTimePicker() + ) + created_by_id = DynamicModelMultipleChoiceField( + queryset=User.objects.all(), + required=False, + label=_('User'), + widget=APISelectMultiple( + api_url='/api/users/users/', + ) + ) + assigned_object_type_id = DynamicModelMultipleChoiceField( + queryset=ContentType.objects.all(), + required=False, + label=_('Object Type'), + widget=APISelectMultiple( + api_url='/api/extras/content-types/', + ) + ) + + # # Change logging # diff --git a/netbox/extras/migrations/0058_journalentry.py b/netbox/extras/migrations/0058_journalentry.py index a3a83cb78..014b9ad05 100644 --- a/netbox/extras/migrations/0058_journalentry.py +++ b/netbox/extras/migrations/0058_journalentry.py @@ -23,6 +23,7 @@ class Migration(migrations.Migration): ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), ], options={ + 'verbose_name_plural': 'journal entries', 'ordering': ('-created',), }, ), diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index 6970265e9..1bed166f8 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -405,6 +405,7 @@ class JournalEntry(BigIDModel): class Meta: ordering = ('-created',) + verbose_name_plural = 'journal entries' def __str__(self): return f"{self.created}" diff --git a/netbox/extras/tables.py b/netbox/extras/tables.py index ff3befc11..99a3a4d71 100644 --- a/netbox/extras/tables.py +++ b/netbox/extras/tables.py @@ -98,7 +98,32 @@ class ObjectChangeTable(BaseTable): fields = ('time', 'user_name', 'action', 'changed_object_type', 'object_repr', 'request_id') +class JournalEntryTable(BaseTable): + created = tables.DateTimeColumn( + format=settings.SHORT_DATETIME_FORMAT + ) + assigned_object_type = tables.Column( + verbose_name='Object type' + ) + assigned_object = tables.Column( + linkify=True, + orderable=False, + verbose_name='Object' + ) + actions = ButtonsColumn( + model=JournalEntry, + buttons=('edit', 'delete') + ) + + class Meta(BaseTable.Meta): + model = JournalEntry + fields = ('created', 'created_by', 'assigned_object_type', 'assigned_object', 'comments', 'actions') + + class ObjectJournalTable(BaseTable): + """ + Used for displaying a set of JournalEntries within the context of a single object. + """ created = tables.DateTimeColumn( format=settings.SHORT_DATETIME_FORMAT ) diff --git a/netbox/extras/urls.py b/netbox/extras/urls.py index 1b28eea84..6fbfd8bf1 100644 --- a/netbox/extras/urls.py +++ b/netbox/extras/urls.py @@ -32,6 +32,7 @@ urlpatterns = [ path('image-attachments//delete/', views.ImageAttachmentDeleteView.as_view(), name='imageattachment_delete'), # Journal entries + path('journal-entries/', views.JournalEntryListView.as_view(), name='journalentry_list'), path('journal-entries/add/', views.JournalEntryEditView.as_view(), name='journalentry_add'), path('journal-entries//edit/', views.JournalEntryEditView.as_view(), name='journalentry_edit'), path('journal-entries//delete/', views.JournalEntryDeleteView.as_view(), name='journalentry_delete'), diff --git a/netbox/extras/views.py b/netbox/extras/views.py index b41f09af3..b0caab4a6 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -286,6 +286,14 @@ class ImageAttachmentDeleteView(generic.ObjectDeleteView): # Journal entries # +class JournalEntryListView(generic.ObjectListView): + queryset = JournalEntry.objects.all() + filterset = filters.JournalEntryFilterSet + filterset_form = forms.JournalEntryFilterForm + table = tables.JournalEntryTable + action_buttons = ('export',) + + class JournalEntryEditView(generic.ObjectEditView): queryset = JournalEntry.objects.all() model_form = forms.JournalEntryForm diff --git a/netbox/templates/extras/object_journal.html b/netbox/templates/extras/object_journal.html index c643cc5b5..5e21b0cb2 100644 --- a/netbox/templates/extras/object_journal.html +++ b/netbox/templates/extras/object_journal.html @@ -27,4 +27,5 @@ {% endif %} {% include 'panel_table.html' %} + {% include 'inc/paginator.html' with paginator=table.paginator page=table.page %} {% endblock %} diff --git a/netbox/templates/inc/nav_menu.html b/netbox/templates/inc/nav_menu.html index 621251ffb..4fff16141 100644 --- a/netbox/templates/inc/nav_menu.html +++ b/netbox/templates/inc/nav_menu.html @@ -520,6 +520,9 @@