1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

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

This commit is contained in:
jeremystretch
2022-03-31 11:40:02 -04:00
parent 7a54658710
commit 1d55c04c21
12 changed files with 68 additions and 46 deletions

View File

@ -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

View File

@ -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):

View File

@ -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(

View File

@ -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):

View File

@ -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,

View File

@ -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

View File

@ -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'),
),
]

View File

@ -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

View File

@ -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'

View File

@ -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(

View File

@ -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>

View File

@ -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>