Bladeren bron

Adds image attachment list view (#12487)

* adds image attachment list view #11932

* fixed typo

* Update netbox/extras/tables/tables.py

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>

* Update netbox/extras/forms/filtersets.py

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>

* changes as per review

* Disable ordering by size (not stored in database)

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
Abhimanyu Saharan 2 jaren geleden
bovenliggende
commit
42346702a1

+ 16 - 1
netbox/extras/forms/filtersets.py

@@ -11,7 +11,7 @@ from extras.utils import FeatureQuery
 from netbox.forms.base import NetBoxModelFilterSetForm
 from netbox.forms.base import NetBoxModelFilterSetForm
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
 from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
 from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
-from utilities.forms.fields import ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField, TagFilterField
+from utilities.forms.fields import ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField, TagFilterField
 from utilities.forms.widgets import APISelectMultiple, DateTimePicker
 from utilities.forms.widgets import APISelectMultiple, DateTimePicker
 from virtualization.models import Cluster, ClusterGroup, ClusterType
 from virtualization.models import Cluster, ClusterGroup, ClusterType
 from .mixins import SavedFiltersMixin
 from .mixins import SavedFiltersMixin
@@ -22,6 +22,7 @@ __all__ = (
     'CustomFieldFilterForm',
     'CustomFieldFilterForm',
     'CustomLinkFilterForm',
     'CustomLinkFilterForm',
     'ExportTemplateFilterForm',
     'ExportTemplateFilterForm',
+    'ImageAttachmentFilterForm',
     'JournalEntryFilterForm',
     'JournalEntryFilterForm',
     'LocalConfigContextFilterForm',
     'LocalConfigContextFilterForm',
     'ObjectChangeFilterForm',
     'ObjectChangeFilterForm',
@@ -137,6 +138,20 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
     )
     )
 
 
 
 
+class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm):
+    fieldsets = (
+        (None, ('q', 'filter_id')),
+        ('Attributes', ('content_type_id', 'name',)),
+    )
+    content_type_id = ContentTypeChoiceField(
+        queryset=ContentType.objects.filter(FeatureQuery('custom_fields').get_query()),
+        required=False
+    )
+    name = forms.CharField(
+        required=False
+    )
+
+
 class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
 class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
     fieldsets = (
     fieldsets = (
         (None, ('q', 'filter_id')),
         (None, ('q', 'filter_id')),

+ 23 - 0
netbox/extras/tables/tables.py

@@ -13,6 +13,7 @@ __all__ = (
     'CustomFieldTable',
     'CustomFieldTable',
     'CustomLinkTable',
     'CustomLinkTable',
     'ExportTemplateTable',
     'ExportTemplateTable',
+    'ImageAttachmentTable',
     'JournalEntryTable',
     'JournalEntryTable',
     'ObjectChangeTable',
     'ObjectChangeTable',
     'SavedFilterTable',
     'SavedFilterTable',
@@ -86,6 +87,28 @@ class ExportTemplateTable(NetBoxTable):
         )
         )
 
 
 
 
+class ImageAttachmentTable(NetBoxTable):
+    id = tables.Column(
+        linkify=False
+    )
+    content_type = columns.ContentTypeColumn()
+    parent = tables.Column(
+        linkify=True
+    )
+    size = tables.Column(
+        orderable=False,
+        verbose_name='Size (bytes)'
+    )
+
+    class Meta(NetBoxTable.Meta):
+        model = ImageAttachment
+        fields = (
+            'pk', 'content_type', 'parent', 'image', 'name', 'image_height', 'image_width', 'size', 'created',
+            'last_updated',
+        )
+        default_columns = ('content_type', 'parent', 'image', 'name', 'size', 'created')
+
+
 class SavedFilterTable(NetBoxTable):
 class SavedFilterTable(NetBoxTable):
     name = tables.Column(
     name = tables.Column(
         linkify=True
         linkify=True

+ 1 - 0
netbox/extras/urls.py

@@ -73,6 +73,7 @@ urlpatterns = [
     path('config-templates/<int:pk>/', include(get_model_urls('extras', 'configtemplate'))),
     path('config-templates/<int:pk>/', include(get_model_urls('extras', 'configtemplate'))),
 
 
     # Image attachments
     # Image attachments
+    path('image-attachments/', views.ImageAttachmentListView.as_view(), name='imageattachment_list'),
     path('image-attachments/add/', views.ImageAttachmentEditView.as_view(), name='imageattachment_add'),
     path('image-attachments/add/', views.ImageAttachmentEditView.as_view(), name='imageattachment_add'),
     path('image-attachments/<int:pk>/', include(get_model_urls('extras', 'imageattachment'))),
     path('image-attachments/<int:pk>/', include(get_model_urls('extras', 'imageattachment'))),
 
 

+ 8 - 0
netbox/extras/views.py

@@ -577,6 +577,14 @@ class ObjectChangeView(generic.ObjectView):
 # Image attachments
 # Image attachments
 #
 #
 
 
+class ImageAttachmentListView(generic.ObjectListView):
+    queryset = ImageAttachment.objects.all()
+    filterset = filtersets.ImageAttachmentFilterSet
+    filterset_form = forms.ImageAttachmentFilterForm
+    table = tables.ImageAttachmentTable
+    actions = ('export',)
+
+
 @register_model_view(ImageAttachment, 'edit')
 @register_model_view(ImageAttachment, 'edit')
 class ImageAttachmentEditView(generic.ObjectEditView):
 class ImageAttachmentEditView(generic.ObjectEditView):
     queryset = ImageAttachment.objects.all()
     queryset = ImageAttachment.objects.all()

+ 1 - 0
netbox/netbox/navigation/menu.py

@@ -292,6 +292,7 @@ CUSTOMIZATION_MENU = Menu(
                 get_model_item('extras', 'exporttemplate', _('Export Templates')),
                 get_model_item('extras', 'exporttemplate', _('Export Templates')),
                 get_model_item('extras', 'savedfilter', _('Saved Filters')),
                 get_model_item('extras', 'savedfilter', _('Saved Filters')),
                 get_model_item('extras', 'tag', 'Tags'),
                 get_model_item('extras', 'tag', 'Tags'),
+                get_model_item('extras', 'imageattachment', _('Image Attachments'), actions=()),
             ),
             ),
         ),
         ),
         MenuGroup(
         MenuGroup(

+ 3 - 38
netbox/templates/inc/panels/image_attachments.html

@@ -4,44 +4,9 @@
   <h5 class="card-header">
   <h5 class="card-header">
     Images
     Images
   </h5>
   </h5>
-  <div class="card-body">
-    {% with images=object.images.all %}
-      {% if images.exists %}
-        <table class="table table-hover">
-          <tr>
-            <th>Name</th>
-            <th>Size</th>
-            <th>Created</th>
-            <th></th>
-          </tr>
-          {% for attachment in images %}
-            <tr{% if not attachment.size %} class="table-danger"{% endif %}>
-              <td>
-                <i class="mdi mdi-file-image-outline"></i>
-                <a class="image-preview" href="{{ attachment.image.url }}" target="_blank">{{ attachment }}</a>
-              </td>
-              <td>{{ attachment.size|filesizeformat }}</td>
-              <td>{{ attachment.created|annotated_date }}</td>
-              <td class="text-end noprint">
-                {% if perms.extras.change_imageattachment %}
-                  <a href="{% url 'extras:imageattachment_edit' pk=attachment.pk %}" class="btn btn-warning btn-sm lh-1" title="Edit Image">
-                    <i class="mdi mdi-pencil" aria-hidden="true"></i>
-                  </a>
-                {% endif %}
-                {% if perms.extras.delete_imageattachment %}
-                  <a href="{% url 'extras:imageattachment_delete' pk=attachment.pk %}" class="btn btn-danger btn-sm lh-1" title="Delete Image">
-                    <i class="mdi mdi-trash-can-outline" aria-hidden="true"></i>
-                  </a>
-                {% endif %}
-              </td>
-            </tr>
-          {% endfor %}
-        </table>
-      {% else %}
-        <div class="text-muted">None</div>
-      {% endif %}
-    {% endwith %}
-  </div>
+  <div class="card-body htmx-container table-responsive"
+  hx-get="{% url 'extras:imageattachment_list' %}?content_type_id={{ object|content_type_id }}&object_id={{ object.pk }}"
+  hx-trigger="load"></div>
   {% if perms.extras.add_imageattachment %}
   {% if perms.extras.add_imageattachment %}
     <div class="card-footer text-end noprint">
     <div class="card-footer text-end noprint">
       <a href="{% url 'extras:imageattachment_add' %}?content_type={{ object|content_type_id }}&object_id={{ object.pk }}" class="btn btn-primary btn-sm">
       <a href="{% url 'extras:imageattachment_add' %}?content_type={{ object|content_type_id }}&object_id={{ object.pk }}" class="btn btn-primary btn-sm">