From ba6562a5dbe1caeeb609ad63dfbbad6467f014db Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 20 Feb 2020 13:09:43 -0500 Subject: [PATCH] Add ability to toggle the inclusion of device images when rendering a rack elevation SVG --- netbox/dcim/api/serializers.py | 7 +++++++ netbox/dcim/api/views.py | 8 +++++++- netbox/dcim/elevations.py | 19 +++++++++++-------- netbox/dcim/models/__init__.py | 9 +++++---- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index 234a9fb1c..3859ecfeb 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -186,6 +186,9 @@ class RackElevationDetailFilterSerializer(serializers.Serializer): unit_height = serializers.IntegerField( default=RACK_ELEVATION_UNIT_HEIGHT_DEFAULT ) + legend_width = serializers.IntegerField( + default=RACK_ELEVATION_LEGEND_WIDTH_DEFAULT + ) exclude = serializers.IntegerField( required=False, default=None @@ -194,6 +197,10 @@ class RackElevationDetailFilterSerializer(serializers.Serializer): required=False, default=True ) + include_images = serializers.BooleanField( + required=False, + default=True + ) # diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 8bb127f67..f8297fe46 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -220,7 +220,13 @@ class RackViewSet(CustomFieldModelViewSet): if data['render'] == 'svg': # Render and return the elevation as an SVG drawing with the correct content type - drawing = rack.get_elevation_svg(data['face'], data['unit_width'], data['unit_height']) + drawing = rack.get_elevation_svg( + face=data['face'], + unit_width=data['unit_width'], + unit_height=data['unit_height'], + legend_width=data['legend_width'], + include_images=data['include_images'] + ) return HttpResponse(drawing.tostring(), content_type='image/svg+xml') else: diff --git a/netbox/dcim/elevations.py b/netbox/dcim/elevations.py index e8b476b60..9c58134fd 100644 --- a/netbox/dcim/elevations.py +++ b/netbox/dcim/elevations.py @@ -11,9 +11,13 @@ from .choices import DeviceFaceChoices class RackElevationSVG: """ Use this class to render a rack elevation as an SVG image. + + :param rack: A NetBox Rack instance + :param include_images: If true, the SVG document will embed front/rear device face images, where available """ - def __init__(self, rack): + def __init__(self, rack, include_images=True): self.rack = rack + self.include_images = include_images @staticmethod def _add_gradient(drawing, id_, color): @@ -46,8 +50,7 @@ class RackElevationSVG: return drawing - @staticmethod - def _draw_device_front(drawing, device, start, end, text): + def _draw_device_front(self, drawing, device, start, end, text): name = str(device) if device.devicebay_count: name += ' ({}/{})'.format(device.get_children().count(), device.devicebay_count) @@ -69,14 +72,13 @@ class RackElevationSVG: link.add(drawing.text(str(name), insert=text, fill=hex_color)) # Embed front device type image if one exists - if device.device_type.front_image: + if self.include_images and device.device_type.front_image: url = device.device_type.front_image.url image = drawing.image(href=url, insert=start, size=end, class_='device-image') image.stretch() link.add(image) - @staticmethod - def _draw_device_rear(drawing, device, start, end, text): + def _draw_device_rear(self, drawing, device, start, end, text): rect = drawing.rect(start, end, class_="slot blocked") rect.set_desc('{} — {} ({}U) {} {}'.format( device.device_role, device.device_type.display_name, @@ -86,7 +88,7 @@ class RackElevationSVG: drawing.add(drawing.text(str(device), insert=text)) # Embed rear device type image if one exists - if device.device_type.front_image: + if self.include_images and device.device_type.front_image: url = device.device_type.rear_image.url image = drawing.image(href=url, insert=start, size=end, class_='device-image') image.stretch() @@ -128,11 +130,12 @@ class RackElevationSVG: return elevation - def render(self, reserved_units, face, unit_width, unit_height, legend_width): + def render(self, face, unit_width, unit_height, legend_width): """ Return an SVG document representing a rack elevation. """ drawing = self._setup_drawing(unit_width + legend_width, unit_height * self.rack.u_height) + reserved_units = self.rack.get_reserved_units() unit_cursor = 0 for ru in range(0, self.rack.u_height): diff --git a/netbox/dcim/models/__init__.py b/netbox/dcim/models/__init__.py index 25f2217b6..5848a6201 100644 --- a/netbox/dcim/models/__init__.py +++ b/netbox/dcim/models/__init__.py @@ -666,7 +666,8 @@ class Rack(ChangeLoggedModel, CustomFieldModel): face=DeviceFaceChoices.FACE_FRONT, unit_width=RACK_ELEVATION_UNIT_WIDTH_DEFAULT, unit_height=RACK_ELEVATION_UNIT_HEIGHT_DEFAULT, - legend_width=RACK_ELEVATION_LEGEND_WIDTH_DEFAULT + legend_width=RACK_ELEVATION_LEGEND_WIDTH_DEFAULT, + include_images=True ): """ Return an SVG of the rack elevation @@ -676,11 +677,11 @@ class Rack(ChangeLoggedModel, CustomFieldModel): :param unit_height: Height of each rack unit for the rendered drawing. Note this is not the total height of the elevation :param legend_width: Width of the unit legend, in pixels + :param include_images: Embed front/rear device images where available """ - elevation = RackElevationSVG(self) - reserved_units = self.get_reserved_units() + elevation = RackElevationSVG(self, include_images=include_images) - return elevation.render(reserved_units, face, unit_width, unit_height, legend_width) + return elevation.render(face, unit_width, unit_height, legend_width) def get_0u_devices(self): return self.devices.filter(position=0)