Kaynağa Gözat

Closes #3456: Enable bulk editing of tag color

Jeremy Stretch 6 yıl önce
ebeveyn
işleme
8ff3d2cbf6

+ 1 - 0
CHANGELOG.md

@@ -16,6 +16,7 @@ v2.6.3 (FUTURE)
 * [#3405](https://github.com/netbox-community/netbox/issues/3405) - Fix population of power port/outlet details on device creation
 * [#3422](https://github.com/netbox-community/netbox/issues/3422) - Prevent navigation menu from overlapping page content
 * [#3430](https://github.com/netbox-community/netbox/issues/3430) - Linkify platform field on device view
+* [#3456](https://github.com/netbox-community/netbox/issues/3456) - Enable bulk editing of tag color
 
 ---
 

+ 18 - 2
netbox/extras/forms.py

@@ -8,9 +8,10 @@ from taggit.forms import TagField
 
 from dcim.models import DeviceRole, Platform, Region, Site
 from tenancy.models import Tenant, TenantGroup
+from utilities.constants import COLOR_CHOICES
 from utilities.forms import (
-    add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, CommentField,
-    ContentTypeSelect, FilterChoiceField, LaxURLField, JSONField, SlugField,
+    add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect,
+    CommentField, ContentTypeSelect, FilterChoiceField, LaxURLField, JSONField, SlugField,
 )
 from .constants import (
     CF_FILTER_DISABLED, CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_INTEGER, CF_TYPE_SELECT, CF_TYPE_URL,
@@ -219,6 +220,21 @@ class TagFilterForm(BootstrapMixin, forms.Form):
     )
 
 
+class TagBulkEditForm(BootstrapMixin, BulkEditForm):
+    pk = forms.ModelMultipleChoiceField(
+        queryset=Tag.objects.all(),
+        widget=forms.MultipleHiddenInput
+    )
+    color = forms.CharField(
+        max_length=6,
+        required=False,
+        widget=ColorSelect()
+    )
+
+    class Meta:
+        nullable_fields = []
+
+
 #
 # Config contexts
 #

+ 1 - 0
netbox/extras/urls.py

@@ -9,6 +9,7 @@ urlpatterns = [
 
     # Tags
     path(r'tags/', views.TagListView.as_view(), name='tag_list'),
+    path(r'tags/edit/', views.TagBulkEditView.as_view(), name='tag_bulk_edit'),
     path(r'tags/delete/', views.TagBulkDeleteView.as_view(), name='tag_bulk_delete'),
     path(r'tags/<slug:slug>/', views.TagView.as_view(), name='tag'),
     path(r'tags/<slug:slug>/edit/', views.TagEditView.as_view(), name='tag_edit'),

+ 21 - 12
netbox/extras/views.py

@@ -13,11 +13,7 @@ from django_tables2 import RequestConfig
 from utilities.forms import ConfirmationForm
 from utilities.paginator import EnhancedPaginator
 from utilities.views import BulkDeleteView, BulkEditView, ObjectDeleteView, ObjectEditView, ObjectListView
-from . import filters
-from .forms import (
-    ConfigContextForm, ConfigContextBulkEditForm, ConfigContextFilterForm, ImageAttachmentForm, ObjectChangeFilterForm,
-    TagFilterForm, TagForm,
-)
+from . import filters, forms
 from .models import ConfigContext, ImageAttachment, ObjectChange, ReportResult, Tag, TaggedItem
 from .reports import get_report, get_reports
 from .scripts import get_scripts, run_script
@@ -36,7 +32,7 @@ class TagListView(PermissionRequiredMixin, ObjectListView):
         'name'
     )
     filter = filters.TagFilter
-    filter_form = TagFilterForm
+    filter_form = forms.TagFilterForm
     table = TagTable
     template_name = 'extras/tag_list.html'
 
@@ -70,7 +66,7 @@ class TagView(View):
 class TagEditView(PermissionRequiredMixin, ObjectEditView):
     permission_required = 'extras.change_tag'
     model = Tag
-    model_form = TagForm
+    model_form = forms.TagForm
     default_return_url = 'extras:tag_list'
     template_name = 'extras/tag_edit.html'
 
@@ -81,6 +77,19 @@ class TagDeleteView(PermissionRequiredMixin, ObjectDeleteView):
     default_return_url = 'extras:tag_list'
 
 
+class TagBulkEditView(PermissionRequiredMixin, BulkEditView):
+    permission_required = 'extras.change_tag'
+    queryset = Tag.objects.annotate(
+        items=Count('extras_taggeditem_items', distinct=True)
+    ).order_by(
+        'name'
+    )
+    # filter = filters.ProviderFilter
+    table = TagTable
+    form = forms.TagBulkEditForm
+    default_return_url = 'circuits:provider_list'
+
+
 class TagBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
     permission_required = 'extras.delete_tag'
     queryset = Tag.objects.annotate(
@@ -100,7 +109,7 @@ class ConfigContextListView(PermissionRequiredMixin, ObjectListView):
     permission_required = 'extras.view_configcontext'
     queryset = ConfigContext.objects.all()
     filter = filters.ConfigContextFilter
-    filter_form = ConfigContextFilterForm
+    filter_form = forms.ConfigContextFilterForm
     table = ConfigContextTable
     template_name = 'extras/configcontext_list.html'
 
@@ -120,7 +129,7 @@ class ConfigContextView(PermissionRequiredMixin, View):
 class ConfigContextCreateView(PermissionRequiredMixin, ObjectEditView):
     permission_required = 'extras.add_configcontext'
     model = ConfigContext
-    model_form = ConfigContextForm
+    model_form = forms.ConfigContextForm
     default_return_url = 'extras:configcontext_list'
     template_name = 'extras/configcontext_edit.html'
 
@@ -134,7 +143,7 @@ class ConfigContextBulkEditView(PermissionRequiredMixin, BulkEditView):
     queryset = ConfigContext.objects.all()
     filter = filters.ConfigContextFilter
     table = ConfigContextTable
-    form = ConfigContextBulkEditForm
+    form = forms.ConfigContextBulkEditForm
     default_return_url = 'extras:configcontext_list'
 
 
@@ -179,7 +188,7 @@ class ObjectChangeListView(PermissionRequiredMixin, ObjectListView):
     permission_required = 'extras.view_objectchange'
     queryset = ObjectChange.objects.prefetch_related('user', 'changed_object_type')
     filter = filters.ObjectChangeFilter
-    filter_form = ObjectChangeFilterForm
+    filter_form = forms.ObjectChangeFilterForm
     table = ObjectChangeTable
     template_name = 'extras/objectchange_list.html'
 
@@ -258,7 +267,7 @@ class ObjectChangeLogView(View):
 class ImageAttachmentEditView(PermissionRequiredMixin, ObjectEditView):
     permission_required = 'extras.change_imageattachment'
     model = ImageAttachment
-    model_form = ImageAttachmentForm
+    model_form = forms.ImageAttachmentForm
 
     def alter_obj(self, imageattachment, request, args, kwargs):
         if not imageattachment.pk:

+ 1 - 1
netbox/templates/extras/tag_list.html

@@ -5,7 +5,7 @@
 <h1>{% block title %}Tags{% endblock %}</h1>
 <div class="row">
 	<div class="col-md-9">
-        {% include 'utilities/obj_table.html' with bulk_delete_url='extras:tag_bulk_delete' %}
+        {% include 'utilities/obj_table.html' with bulk_edit_url='extras:tag_bulk_edit' bulk_delete_url='extras:tag_bulk_delete' %}
     </div>
     <div class="col-md-3">
 		{% include 'inc/search_panel.html' %}