Repository: netbox-community/netbox

Issue:
Clicking device in rackview opens new tab
### NetBox version

v3.3.1

### Python version

3.10

### Steps to Reproduce

1. Go to a rack view
2. Click on a device in the rack
3. New tab opens

### Expected Behavior

The device used to open in the same window.

### Observed Behavior

The device opens in a new tab.


Discussion:
This is the default behavior of svgwrite's `Hyperlink` class (although we do explicitly set `target="_blank"` in several places). Without this, the linked content will replaced the embedded SVG on the current page. For example, if I remove the link target and then click on a device within an elevation under the rack view, the device page replaces the image:

![Screenshot 2022-08-26 at 08-34-47 Rack Comms closet NetBox](https://user-images.githubusercontent.com/13487278/186904571-daa9f704-cd2e-469f-8538-3fee204c5906.png)

I believe the appropriate fix here is to change the link attribute to `target="_parent"`, which forces the link to replace the parent frame or document. (`_top` is also an option, but could break cases where the SVG image is embedded within a frame.)

This should be applied to cable trace diagrams as well.

Resolving patch:
diff --git a/netbox/dcim/svg/cables.py b/netbox/dcim/svg/cables.py
--- a/netbox/dcim/svg/cables.py
+++ b/netbox/dcim/svg/cables.py
@@ -94,7 +94,7 @@ def __init__(self, start, url, color, labels=[], **extra):
         self.add(cable)
 
         # Add link
-        link = Hyperlink(href=url, target='_blank')
+        link = Hyperlink(href=url, target='_parent')
 
         # Add text label(s)
         cursor = start[1]
@@ -281,7 +281,7 @@ def draw_wirelesslink(self, wirelesslink):
         self.cursor += PADDING * 2
 
         # Add link
-        link = Hyperlink(href=f'{self.base_url}{wirelesslink.get_absolute_url()}', target='_blank')
+        link = Hyperlink(href=f'{self.base_url}{wirelesslink.get_absolute_url()}', target='_parent')
 
         # Add text label(s)
         for i, label in enumerate(labels):
diff --git a/netbox/dcim/svg/racks.py b/netbox/dcim/svg/racks.py
--- a/netbox/dcim/svg/racks.py
+++ b/netbox/dcim/svg/racks.py
@@ -151,7 +151,7 @@ def _draw_device(self, device, coords, size, color=None, image=None):
         css_extra = ' shaded' if is_shaded else ''
 
         # Create hyperlink element
-        link = Hyperlink(href=f'{self.base_url}{device.get_absolute_url()}', target='_blank')
+        link = Hyperlink(href=f'{self.base_url}{device.get_absolute_url()}', target="_parent")
         link.set_desc(description)
 
         # Add rect element to hyperlink
@@ -235,10 +235,7 @@ def draw_margin(self):
                     self.margin_width,
                     u_height * self.unit_height
                 )
-                link = Hyperlink(
-                    href='{}{}'.format(self.base_url, reservation.get_absolute_url()),
-                    target='_blank'
-                )
+                link = Hyperlink(href=f'{self.base_url}{reservation.get_absolute_url()}', target='_parent')
                 link.set_desc(f'Reservation #{reservation.pk}: {reservation.description}')
                 link.add(
                     Rect(coords, size, class_='reservation')
@@ -268,7 +265,7 @@ def draw_background(self, face):
                 y_offset + self.unit_height / 2
             )
 
-            link = Hyperlink(href=url_string.format(unit), target='_blank')
+            link = Hyperlink(href=url_string.format(unit), target='_parent')
             link.add(Rect((x_offset, y_offset), (self.unit_width, self.unit_height), class_='slot'))
             link.add(Text('add device', insert=text_coords, class_='add-device'))
 


Test patch: