Explorar el Código

Closes #9006: Enable custom fields, custom links, and tags for journal entries

jeremystretch hace 3 años
padre
commit
1d55c04c21

+ 4 - 1
docs/release-notes/version-3.2.md

@@ -146,6 +146,7 @@ Where it is desired to limit the range of available VLANs within a group, users
 * [#8572](https://github.com/netbox-community/netbox/issues/8572) - Add a `pre_run()` method for reports
 * [#8593](https://github.com/netbox-community/netbox/issues/8593) - Add a `link` field for contacts
 * [#8649](https://github.com/netbox-community/netbox/issues/8649) - Enable customization of configuration module using `NETBOX_CONFIGURATION` environment variable
+* [#9006](https://github.com/netbox-community/netbox/issues/9006) - Enable custom fields, custom links, and tags for journal entries
 
 ### Bug Fixes (From Beta2)
 
@@ -207,11 +208,13 @@ Where it is desired to limit the range of available VLANs within a group, users
     * Added `data_type` and `object_type` fields
 * extras.CustomLink
     * Added `enabled` field
+* extras.JournalEntry
+    * Added `custom_fields` and `tags` fields
 * ipam.ASN
     * Added `provider_count` field
 * ipam.VLANGroup
     * Added the `/availables-vlans/` endpoint
-    * Added the `min_vid` and `max_vid` fields
+    * Added `min_vid` and `max_vid` fields
 * tenancy.Contact
     * Added `link` field
 * virtualization.VMInterface

+ 3 - 3
netbox/extras/api/serializers.py

@@ -14,7 +14,7 @@ from extras.models import *
 from extras.utils import FeatureQuery
 from netbox.api import ChoiceField, ContentTypeField, SerializedPKRelatedField
 from netbox.api.exceptions import SerializerNotFound
-from netbox.api.serializers import BaseModelSerializer, ValidatedModelSerializer
+from netbox.api.serializers import BaseModelSerializer, NetBoxModelSerializer, ValidatedModelSerializer
 from tenancy.api.nested_serializers import NestedTenantSerializer, NestedTenantGroupSerializer
 from tenancy.models import Tenant, TenantGroup
 from users.api.nested_serializers import NestedUserSerializer
@@ -200,7 +200,7 @@ class ImageAttachmentSerializer(ValidatedModelSerializer):
 # Journal entries
 #
 
-class JournalEntrySerializer(ValidatedModelSerializer):
+class JournalEntrySerializer(NetBoxModelSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='extras-api:journalentry-detail')
     assigned_object_type = ContentTypeField(
         queryset=ContentType.objects.all()
@@ -221,7 +221,7 @@ class JournalEntrySerializer(ValidatedModelSerializer):
         model = JournalEntry
         fields = [
             'id', 'url', 'display', 'assigned_object_type', 'assigned_object_id', 'assigned_object', 'created',
-            'created_by', 'kind', 'comments',
+            'created_by', 'kind', 'comments', 'tags', 'custom_fields',
         ]
 
     def validate(self, data):

+ 2 - 6
netbox/extras/filtersets.py

@@ -4,7 +4,7 @@ from django.contrib.contenttypes.models import ContentType
 from django.db.models import Q
 
 from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup
-from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet
+from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet
 from tenancy.models import Tenant, TenantGroup
 from utilities.filters import ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter
 from virtualization.models import Cluster, ClusterGroup, ClusterType
@@ -134,11 +134,7 @@ class ImageAttachmentFilterSet(BaseFilterSet):
         return queryset.filter(name__icontains=value)
 
 
-class JournalEntryFilterSet(ChangeLoggedModelFilterSet):
-    q = django_filters.CharFilter(
-        method='search',
-        label='Search',
-    )
+class JournalEntryFilterSet(NetBoxModelFilterSet):
     created = django_filters.DateTimeFromToRangeFilter()
     assigned_object_type = ContentTypeFilter()
     created_by_id = django_filters.ModelMultipleChoiceFilter(

+ 7 - 4
netbox/extras/forms/filtersets.py

@@ -7,10 +7,12 @@ from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGrou
 from extras.choices import *
 from extras.models import *
 from extras.utils import FeatureQuery
+from netbox.forms.base import NetBoxModelFilterSetForm
 from tenancy.models import Tenant, TenantGroup
 from utilities.forms import (
-    add_blank_choice, APISelectMultiple, ContentTypeChoiceField, ContentTypeMultipleChoiceField, DateTimePicker,
-    DynamicModelMultipleChoiceField, FilterForm, MultipleChoiceField, StaticSelect, BOOLEAN_WITH_BLANK_CHOICES,
+    add_blank_choice, APISelectMultiple, BOOLEAN_WITH_BLANK_CHOICES, ContentTypeChoiceField,
+    ContentTypeMultipleChoiceField, DateTimePicker, DynamicModelMultipleChoiceField, FilterForm, MultipleChoiceField,
+    StaticSelect, TagFilterField,
 )
 from virtualization.models import Cluster, ClusterGroup, ClusterType
 
@@ -237,10 +239,10 @@ class LocalConfigContextFilterForm(forms.Form):
     )
 
 
-class JournalEntryFilterForm(FilterForm):
+class JournalEntryFilterForm(NetBoxModelFilterSetForm):
     model = JournalEntry
     fieldsets = (
-        (None, ('q',)),
+        (None, ('q', 'tag')),
         ('Creation', ('created_before', 'created_after', 'created_by_id')),
         ('Attributes', ('assigned_object_type_id', 'kind'))
     )
@@ -275,6 +277,7 @@ class JournalEntryFilterForm(FilterForm):
         required=False,
         widget=StaticSelect()
     )
+    tag = TagFilterField(model)
 
 
 class ObjectChangeFilterForm(FilterForm):

+ 4 - 4
netbox/extras/forms/models.py

@@ -5,6 +5,7 @@ from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGrou
 from extras.choices import *
 from extras.models import *
 from extras.utils import FeatureQuery
+from netbox.forms import NetBoxModelForm
 from tenancy.models import Tenant, TenantGroup
 from utilities.forms import (
     add_blank_choice, BootstrapMixin, CommentField, ContentTypeChoiceField, ContentTypeMultipleChoiceField,
@@ -219,18 +220,17 @@ class ImageAttachmentForm(BootstrapMixin, forms.ModelForm):
         ]
 
 
-class JournalEntryForm(BootstrapMixin, forms.ModelForm):
-    comments = CommentField()
-
+class JournalEntryForm(NetBoxModelForm):
     kind = forms.ChoiceField(
         choices=add_blank_choice(JournalEntryKindChoices),
         required=False,
         widget=StaticSelect()
     )
+    comments = CommentField()
 
     class Meta:
         model = JournalEntry
-        fields = ['assigned_object_type', 'assigned_object_id', 'kind', 'comments']
+        fields = ['assigned_object_type', 'assigned_object_id', 'kind', 'tags', 'comments']
         widgets = {
             'assigned_object_type': forms.HiddenInput,
             'assigned_object_id': forms.HiddenInput,

+ 2 - 1
netbox/extras/graphql/types.py

@@ -1,4 +1,5 @@
 from extras import filtersets, models
+from extras.graphql.mixins import CustomFieldsMixin, TagsMixin
 from netbox.graphql.types import BaseObjectType, ObjectType
 
 __all__ = (
@@ -54,7 +55,7 @@ class ImageAttachmentType(BaseObjectType):
         filterset_class = filtersets.ImageAttachmentFilterSet
 
 
-class JournalEntryType(ObjectType):
+class JournalEntryType(CustomFieldsMixin, TagsMixin, ObjectType):
 
     class Meta:
         model = models.JournalEntry

+ 23 - 0
netbox/extras/migrations/0073_journalentry_tags_custom_fields.py

@@ -0,0 +1,23 @@
+import django.core.serializers.json
+from django.db import migrations, models
+import taggit.managers
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('extras', '0072_created_datetimefield'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='journalentry',
+            name='custom_field_data',
+            field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
+        ),
+        migrations.AddField(
+            model_name='journalentry',
+            name='tags',
+            field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
+        ),
+    ]

+ 4 - 2
netbox/extras/models/models.py

@@ -19,7 +19,9 @@ from extras.constants import *
 from extras.conditions import ConditionSet
 from extras.utils import FeatureQuery, image_upload
 from netbox.models import ChangeLoggedModel
-from netbox.models.features import ExportTemplatesMixin, JobResultsMixin, WebhooksMixin
+from netbox.models.features import (
+    CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, JobResultsMixin, TagsMixin, WebhooksMixin,
+)
 from utilities.querysets import RestrictedQuerySet
 from utilities.utils import render_jinja2
 
@@ -419,7 +421,7 @@ class ImageAttachment(WebhooksMixin, ChangeLoggedModel):
         return objectchange
 
 
-class JournalEntry(WebhooksMixin, ChangeLoggedModel):
+class JournalEntry(CustomFieldsMixin, CustomLinksMixin, TagsMixin, WebhooksMixin, ChangeLoggedModel):
     """
     A historical remark concerning an object; collectively, these form an object's journal. The journal is used to
     preserve historical context around an object, and complements NetBox's built-in change logging. For example, you

+ 11 - 17
netbox/extras/tables/tables.py

@@ -12,7 +12,6 @@ __all__ = (
     'ExportTemplateTable',
     'JournalEntryTable',
     'ObjectChangeTable',
-    'ObjectJournalTable',
     'TaggedItemTable',
     'TagTable',
     'WebhookTable',
@@ -210,25 +209,11 @@ class ObjectChangeTable(NetBoxTable):
         )
 
 
-class ObjectJournalTable(NetBoxTable):
-    """
-    Used for displaying a set of JournalEntries within the context of a single object.
-    """
+class JournalEntryTable(NetBoxTable):
     created = tables.DateTimeColumn(
         linkify=True,
         format=settings.SHORT_DATETIME_FORMAT
     )
-    kind = columns.ChoiceFieldColumn()
-    comments = tables.TemplateColumn(
-        template_code='{{ value|markdown|truncatewords_html:50 }}'
-    )
-
-    class Meta(NetBoxTable.Meta):
-        model = JournalEntry
-        fields = ('id', 'created', 'created_by', 'kind', 'comments', 'actions')
-
-
-class JournalEntryTable(ObjectJournalTable):
     assigned_object_type = columns.ContentTypeColumn(
         verbose_name='Object type'
     )
@@ -237,13 +222,22 @@ class JournalEntryTable(ObjectJournalTable):
         orderable=False,
         verbose_name='Object'
     )
+    kind = columns.ChoiceFieldColumn()
     comments = columns.MarkdownColumn()
+    comments_short = tables.TemplateColumn(
+        accessor=tables.A('comments'),
+        template_code='{{ value|markdown|truncatewords_html:50 }}',
+        verbose_name='Comments (Short)'
+    )
+    tags = columns.TagColumn(
+        url_name='extras:journalentry_list'
+    )
 
     class Meta(NetBoxTable.Meta):
         model = JournalEntry
         fields = (
             'pk', 'id', 'created', 'created_by', 'assigned_object_type', 'assigned_object', 'kind', 'comments',
-            'actions',
+            'comments_short', 'tags', 'actions',
         )
         default_columns = (
             'pk', 'created', 'created_by', 'assigned_object_type', 'assigned_object', 'kind', 'comments'

+ 3 - 1
netbox/netbox/views/generic/feature_views.py

@@ -86,8 +86,10 @@ class ObjectJournalView(View):
             assigned_object_type=content_type,
             assigned_object_id=obj.pk
         )
-        journalentry_table = tables.ObjectJournalTable(journalentries)
+        journalentry_table = tables.JournalEntryTable(journalentries, user=request.user)
         journalentry_table.configure(request)
+        journalentry_table.columns.hide('assigned_object_type')
+        journalentry_table.columns.hide('assigned_object')
 
         if request.user.has_perm('extras.add_journalentry'):
             form = forms.JournalEntryForm(

+ 4 - 2
netbox/templates/extras/journalentry.html

@@ -9,7 +9,7 @@
 
 {% block content %}
     <div class="row mb-3">
-        <div class="col col-md-4">
+        <div class="col col-md-5">
             <div class="card">
                 <h5 class="card-header">
                     Journal Entry
@@ -35,8 +35,10 @@
                     </table>
                 </div>
             </div>
+            {% include 'inc/panels/custom_fields.html' %}
+            {% include 'inc/panels/tags.html' %}
         </div>
-        <div class="col col-md-8">
+        <div class="col col-md-7">
             {% include 'inc/panels/comments.html' %}
         </div>
     </div>

+ 1 - 5
netbox/templates/extras/object_journal.html

@@ -11,11 +11,7 @@
         <div class="field-group">
           <h4>New Journal Entry</h4>
           {% csrf_token %}
-          {% for field in form.hidden_fields %}
-            {{ field }}
-          {% endfor %}
-          {% render_field form.kind %}
-          {% render_field form.comments %}
+          {% render_form form %}
         </div>
         <div class="col col-md-12 text-end my-3">
           <a href="{{ object.get_absolute_url }}" class="btn btn-outline-danger">Cancel</a>