Explorar o código

Merge branch 'develop' into 3090-interface-filtering

hSaria %!s(int64=6) %!d(string=hai) anos
pai
achega
cfb8b3cf56

+ 2 - 0
docs/release-notes/version-2.6.md

@@ -2,7 +2,9 @@
 
 ## Enhancements
 
+* [#2050](https://github.com/netbox-community/netbox/issues/2050) - Preview image attachments when hovering the link
 * [#3090](https://github.com/netbox-community/netbox/issues/3090) - Add filter field for device interfaces
+* [#3187](https://github.com/netbox-community/netbox/issues/3187) - Add rack selection field to rack elevations
 
 ---
 

+ 28 - 0
netbox/dcim/forms.py

@@ -703,6 +703,34 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     )
 
 
+#
+# Rack elevations
+#
+
+class RackElevationFilterForm(RackFilterForm):
+    field_order = ['q', 'region', 'site', 'group_id', 'id', 'status', 'role', 'tenant_group', 'tenant']
+    id = ChainedModelChoiceField(
+        queryset=Rack.objects.all(),
+        label='Rack',
+        chains=(
+            ('site', 'site'),
+            ('group_id', 'group_id'),
+        ),
+        required=False,
+        widget=APISelectMultiple(
+            api_url='/api/dcim/racks/',
+            display_field='display_name',
+        )
+    )
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        # Filter the rack field based on the site and group
+        self.fields['site'].widget.add_filter_for('id', 'site')
+        self.fields['group_id'].widget.add_filter_for('id', 'group_id')
+
+
 #
 # Rack reservations
 #

+ 1 - 1
netbox/dcim/views.py

@@ -388,7 +388,7 @@ class RackElevationListView(PermissionRequiredMixin, View):
             'page': page,
             'total_count': total_count,
             'face_id': face_id,
-            'filter_form': forms.RackFilterForm(request.GET),
+            'filter_form': forms.RackElevationFilterForm(request.GET),
         })
 
 

+ 39 - 0
netbox/project-static/js/forms.js

@@ -398,4 +398,43 @@ $(document).ready(function() {
     // Account for the header height when hash-scrolling
     window.addEventListener('load', headerOffsetScroll);
     window.addEventListener('hashchange', headerOffsetScroll);
+
+    // Offset between the preview window and the window edges
+    const IMAGE_PREVIEW_OFFSET_X = 20
+    const IMAGE_PREVIEW_OFFSET_Y = 10
+
+    // Preview an image attachment when the link is hovered over
+    $('a.image-preview').on('mouseover', function(e) {
+        // Twice the offset to account for all sides of the picture
+        var maxWidth = window.innerWidth - (e.clientX + (IMAGE_PREVIEW_OFFSET_X * 2));
+        var maxHeight = window.innerHeight - (e.clientY + (IMAGE_PREVIEW_OFFSET_Y * 2));
+        var img = $('<img>').attr('id', 'image-preview-window').css({
+            display: 'none',
+            position: 'absolute',
+            maxWidth: maxWidth + 'px',
+            maxHeight: maxHeight + 'px',
+            left: e.pageX + IMAGE_PREVIEW_OFFSET_X + 'px',
+            top: e.pageY + IMAGE_PREVIEW_OFFSET_Y + 'px',
+            boxShadow: '0 0px 12px 3px rgba(0, 0, 0, 0.4)',
+        });
+
+        // Remove any existing preview windows and add the current one
+        $('#image-preview-window').remove();
+        $('body').append(img);
+
+        // Once loaded, show the preview if the image is indeed an image
+        img.on('load', function(e) {
+            if (e.target.complete && e.target.naturalWidth) {
+                $('#image-preview-window').fadeIn('fast');
+            }
+        });
+
+        // Begin loading
+        img.attr('src', e.target.href);
+    });
+
+    // Fade the image out; it will be deleted when another one is previewed
+    $('a.image-preview').on('mouseout', function() {
+        $('#image-preview-window').fadeOut('fast')
+    });
 });

+ 1 - 1
netbox/templates/inc/image_attachments.html

@@ -10,7 +10,7 @@
             <tr{% if not attachment.size %} class="danger"{% endif %}>
                 <td>
                     <i class="fa fa-image"></i>
-                    <a href="{{ attachment.image.url }}" target="_blank">{{ attachment }}</a>
+                    <a class="image-preview" href="{{ attachment.image.url }}" target="_blank">{{ attachment }}</a>
                 </td>
                 <td>{{ attachment.size|filesizeformat }}</td>
                 <td>{{ attachment.created }}</td>