Explorar o código

Fixes #9789: Fix rendering of cable traces ending at provider networks

jeremystretch %!s(int64=3) %!d(string=hai) anos
pai
achega
262a0cf397

+ 1 - 0
docs/release-notes/version-3.3.md

@@ -104,6 +104,7 @@ Custom field UI visibility has no impact on API operation.
 * [#9730](https://github.com/netbox-community/netbox/issues/9730) - Fix validation error when creating a new cable via UI form
 * [#9733](https://github.com/netbox-community/netbox/issues/9733) - Handle split paths during trace when fanning out to front ports with differing cables
 * [#9765](https://github.com/netbox-community/netbox/issues/9765) - Report correct segment count under cable trace UI view
+* [#9789](https://github.com/netbox-community/netbox/issues/9789) - Fix rendering of cable traces ending at provider networks
 * [#9794](https://github.com/netbox-community/netbox/issues/9794) - Fix link to connect a rear port to a circuit termination
 * [#9818](https://github.com/netbox-community/netbox/issues/9818) - Fix circuit side selection when connecting a cable to a circuit termination
 * [#9829](https://github.com/netbox-community/netbox/issues/9829) - Arrange custom fields by group when editing objects

+ 9 - 9
netbox/dcim/api/views.py

@@ -64,20 +64,20 @@ class PathEndpointMixin(object):
             return HttpResponse(drawing.render().tostring(), content_type='image/svg+xml')
 
         # Serialize path objects, iterating over each three-tuple in the path
-        for near_end, cable, far_end in obj.trace():
-            if near_end is not None:
-                serializer_a = get_serializer_for_model(near_end[0], prefix=NESTED_SERIALIZER_PREFIX)
-                near_end = serializer_a(near_end, many=True, context={'request': request}).data
+        for near_ends, cable, far_ends in obj.trace():
+            if near_ends:
+                serializer_a = get_serializer_for_model(near_ends[0], prefix=NESTED_SERIALIZER_PREFIX)
+                near_ends = serializer_a(near_ends, many=True, context={'request': request}).data
             else:
                 # Path is split; stop here
                 break
-            if cable is not None:
+            if cable:
                 cable = serializers.TracedCableSerializer(cable[0], context={'request': request}).data
-            if far_end is not None:
-                serializer_b = get_serializer_for_model(far_end[0], prefix=NESTED_SERIALIZER_PREFIX)
-                far_end = serializer_b(far_end, many=True, context={'request': request}).data
+            if far_ends:
+                serializer_b = get_serializer_for_model(far_ends[0], prefix=NESTED_SERIALIZER_PREFIX)
+                far_ends = serializer_b(far_ends, many=True, context={'request': request}).data
 
-            path.append((near_end, cable, far_end))
+            path.append((near_ends, cable, far_ends))
 
         return Response(path)
 

+ 7 - 4
netbox/dcim/models/device_components.py

@@ -212,10 +212,13 @@ class PathEndpoint(models.Model):
                 break
 
             path.extend(origin._path.path_objects)
-            while (len(path)) % 3:
-                # Pad to ensure we have complete three-tuples (e.g. for paths that end at a non-connected FrontPort)
-                # by inserting empty entries immediately prior to the path's destination node(s)
-                path.append([])
+
+            # If the path ends at a non-connected pass-through port, pad out the link and far-end terminations
+            if len(path) % 3 == 1:
+                path.extend(([], []))
+            # If the path ends at a site or provider network, inject a null "link" to render an attachment
+            elif len(path) % 3 == 2:
+                path.insert(-1, [])
 
             # Check for a bridged relationship to continue the trace
             destinations = origin._path.destinations

+ 4 - 2
netbox/dcim/svg/cables.py

@@ -369,14 +369,16 @@ class CableTraceSVG:
                 parent_objects = set(end.parent_object for end in far_ends)
                 self.draw_parent_objects(parent_objects)
 
+            # Render a far-end object not connected via a link (e.g. a ProviderNetwork or Site associated with
+            # a CircuitTermination)
             elif far_ends:
 
                 # Attachment
                 attachment = self.draw_attachment()
                 self.connectors.append(attachment)
 
-                # ProviderNetwork
-                self.draw_parent_objects(set(end.parent_object for end in far_ends))
+                # Object
+                self.draw_parent_objects(far_ends)
 
         # Determine drawing size
         self.drawing = svgwrite.Drawing(