Explorar o código

Replace CSS-based cable trace diagrams with SVG images

jeremystretch %!s(int64=4) %!d(string=hai) anos
pai
achega
9f615cde79

+ 1 - 4
netbox/dcim/api/views.py

@@ -2,18 +2,15 @@ import socket
 from collections import OrderedDict
 from collections import OrderedDict
 
 
 from django.conf import settings
 from django.conf import settings
-from django.contrib.contenttypes.models import ContentType
-from django.db.models import F
 from django.http import HttpResponseForbidden, HttpResponse
 from django.http import HttpResponseForbidden, HttpResponse
 from django.shortcuts import get_object_or_404
 from django.shortcuts import get_object_or_404
 from drf_yasg import openapi
 from drf_yasg import openapi
 from drf_yasg.openapi import Parameter
 from drf_yasg.openapi import Parameter
 from drf_yasg.utils import swagger_auto_schema
 from drf_yasg.utils import swagger_auto_schema
 from rest_framework.decorators import action
 from rest_framework.decorators import action
-from rest_framework.mixins import ListModelMixin
 from rest_framework.response import Response
 from rest_framework.response import Response
 from rest_framework.routers import APIRootView
 from rest_framework.routers import APIRootView
-from rest_framework.viewsets import GenericViewSet, ViewSet
+from rest_framework.viewsets import ViewSet
 
 
 from circuits.models import Circuit
 from circuits.models import Circuit
 from dcim import filtersets
 from dcim import filtersets

+ 8 - 4
netbox/dcim/views.py

@@ -1,15 +1,14 @@
 import logging
 import logging
-from copy import deepcopy
 from collections import OrderedDict
 from collections import OrderedDict
 
 
 from django.contrib import messages
 from django.contrib import messages
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
-from django.core.exceptions import ObjectDoesNotExist
 from django.core.paginator import EmptyPage, PageNotAnInteger
 from django.core.paginator import EmptyPage, PageNotAnInteger
 from django.db import transaction
 from django.db import transaction
 from django.db.models import F, Prefetch
 from django.db.models import F, Prefetch
 from django.forms import ModelMultipleChoiceField, MultipleHiddenInput, modelformset_factory
 from django.forms import ModelMultipleChoiceField, MultipleHiddenInput, modelformset_factory
 from django.shortcuts import get_object_or_404, redirect, render
 from django.shortcuts import get_object_or_404, redirect, render
+from django.urls import reverse
 from django.utils.html import escape
 from django.utils.html import escape
 from django.utils.safestring import mark_safe
 from django.utils.safestring import mark_safe
 from django.views.generic import View
 from django.views.generic import View
@@ -23,7 +22,7 @@ from utilities.forms import ConfirmationForm
 from utilities.paginator import EnhancedPaginator, get_paginate_count
 from utilities.paginator import EnhancedPaginator, get_paginate_count
 from utilities.permissions import get_permission_for_model
 from utilities.permissions import get_permission_for_model
 from utilities.tables import paginate_table
 from utilities.tables import paginate_table
-from utilities.utils import csv_format, count_related
+from utilities.utils import count_related
 from utilities.views import GetReturnURLMixin, ObjectPermissionRequiredMixin
 from utilities.views import GetReturnURLMixin, ObjectPermissionRequiredMixin
 from virtualization.models import VirtualMachine
 from virtualization.models import VirtualMachine
 from . import filtersets, forms, tables
 from . import filtersets, forms, tables
@@ -2423,11 +2422,16 @@ class PathTraceView(generic.ObjectView):
         # Get the total length of the cable and whether the length is definitive (fully defined)
         # Get the total length of the cable and whether the length is definitive (fully defined)
         total_length, is_definitive = path.get_total_length() if path else (None, False)
         total_length, is_definitive = path.get_total_length() if path else (None, False)
 
 
+        # Determine the path to the SVG trace image
+        api_viewname = f"{path.origin._meta.app_label}-api:{path.origin._meta.model_name}-trace"
+        svg_url = f"{reverse(api_viewname, kwargs={'pk': path.origin.pk})}?render=svg"
+
         return {
         return {
             'path': path,
             'path': path,
             'related_paths': related_paths,
             'related_paths': related_paths,
             'total_length': total_length,
             'total_length': total_length,
-            'is_definitive': is_definitive
+            'is_definitive': is_definitive,
+            'svg_url': svg_url,
         }
         }
 
 
 
 

+ 0 - 41
netbox/project-static/netbox.scss

@@ -720,47 +720,6 @@ table tbody {
   }
   }
 }
 }
 
 
-// Cable Tracing
-.cable-trace {
-  max-width: 38rem;
-  margin: 1rem auto;
-  text-align: center;
-}
-.cable-trace .node {
-  background-color: var(--nbx-cable-node-bg);
-  border: $border-width solid var(--nbx-cable-node-border-color);
-  border-radius: $border-radius;
-  padding: 1.5rem 1rem;
-  position: relative;
-  z-index: 1;
-}
-.cable-trace .termination {
-  background-color: var(--nbx-cable-termination-bg);
-  border: $border-width solid var(--nbx-cable-termination-border-color);
-  box-shadow: $box-shadow;
-  border-radius: $border-radius;
-  margin: -1rem auto;
-  padding: 0.5rem;
-  position: relative;
-  width: 60%;
-  z-index: 2;
-}
-.cable-trace .active {
-  border: 0.25rem solid $success;
-}
-.cable-trace .cable {
-  border-left-style: solid;
-  border-left-width: 0.25rem;
-  margin: 1rem 0 1rem 50%;
-  padding: 1.5rem;
-  text-align: left;
-  width: 50%;
-}
-.cable-trace .trace-end {
-  margin-top: 2rem;
-  text-align: center;
-}
-
 pre.change-data {
 pre.change-data {
   padding-left: 0;
   padding-left: 0;
   padding-right: 0;
   padding-right: 0;

+ 38 - 77
netbox/templates/dcim/cable_trace.html

@@ -1,89 +1,50 @@
 {% extends 'base/layout.html' %}
 {% extends 'base/layout.html' %}
 {% load helpers %}
 {% load helpers %}
 
 
-{% block header %}
-    <h1>{% block title %}Cable Trace for {{ object|meta:"verbose_name"|bettertitle }} {{ object }}{% endblock %}</h1>
-{% endblock %}
+{% block title %}Cable Trace for {{ object|meta:"verbose_name"|bettertitle }} {{ object }}{% endblock %}
 
 
 {% block content %}
 {% block content %}
     <div class="row">
     <div class="row">
         <div class="col col-md-5">
         <div class="col col-md-5">
+            <object data="{{ svg_url }}" class="rack_elevation"></object>
+            <div class="text-center mt-3">
+                <a class="btn btn-outline-primary btn-sm" href="{{ svg_url }}">
+                    <i class="mdi mdi-file-download"></i> Download SVG
+                </a>
+            </div>
             <div class="cable-trace">
             <div class="cable-trace">
                 {% with traced_path=path.origin.trace %}
                 {% with traced_path=path.origin.trace %}
-                    {% for near_end, cable, far_end in traced_path %}
-
-                        {# Near end #}
-                        {% if near_end.device %}
-                            {% include 'dcim/trace/device.html' with device=near_end.device %}
-                            {% include 'dcim/trace/termination.html' with termination=near_end %}
-                        {% elif near_end.power_panel %}
-                            {% include 'dcim/trace/powerpanel.html' with powerpanel=near_end.power_panel %}
-                            {% include 'dcim/trace/termination.html' with termination=far_end%}
-                        {% elif near_end.circuit %}
-                            {% include 'dcim/trace/circuit.html' with circuit=near_end.circuit %}
-                            {% include 'dcim/trace/termination.html' with termination=near_end %}
-                        {% endif %}
-
-                        {# Cable #}
-                        {% if cable %}
-                            {% include 'dcim/trace/cable.html' %}
-                        {% elif far_end %}
-                            {% include 'dcim/trace/attachment.html' %}
-                        {% endif %}
-
-                        {# Far end #}
-                        {% if far_end.device %}
-                            {% include 'dcim/trace/termination.html' with termination=far_end %}
-                            {% if forloop.last %}
-                                {% include 'dcim/trace/device.html' with device=far_end.device %}
-                            {% endif %}
-                        {% elif far_end.power_panel %}
-                            {% include 'dcim/trace/termination.html' with termination=far_end %}
-                            {% include 'dcim/trace/powerpanel.html' with powerpanel=far_end.power_panel %}
-                        {% elif far_end.circuit %}
-                            {% include 'dcim/trace/termination.html' with termination=far_end %}
-                            {% if forloop.last %}
-                                {% include 'dcim/trace/circuit.html' with circuit=far_end.circuit %}
-                            {% endif %}
-                        {% elif far_end %}
-                            {% include 'dcim/trace/object.html' with object=far_end %}
-                        {% endif %}
-
-                        {% if forloop.last %}
-                            {% if path.is_split %}
-                                <div class="trace-end">
-                                    <h3 class="text-danger">Path split!</h3>
-                                    <p>Select a node below to continue:</p>
-                                    <ul class="text-start">
-                                        {% for next_node in path.get_split_nodes %}
-                                            {% if next_node.cable %}
-                                                <li>
-                                                    <a href="{% url 'dcim:frontport_trace' pk=next_node.pk %}">{{ next_node }}</a>
-                                                    (Cable <a href="{{ next_node.cable.get_absolute_url }}">{{ next_node.cable }}</a>)
-                                                </li>
-                                            {% else %}
-                                                <li class="text-muted">{{ next_node }}</li>
-                                            {% endif %}
-                                        {% endfor %}
-                                    </ul>
-                                </div>
-                            {% else %}
-                                <div class="trace-end">
-                                    <h3{% if far_end %} class="text-success"{% endif %}>Trace Completed</h3>
-                                    <h5>Total Segments: {{ traced_path|length }}</h5>
-                                    <h5>Total Length:
-                                        {% if total_length %}
-                                            {{ total_length|floatformat:"-2" }}{% if not is_definitive %}+{% endif %} Meters /
-                                            {{ total_length|meters_to_feet|floatformat:"-2" }} Feet
-                                        {% else %}
-                                            <span class="text-muted">N/A</span>
-                                        {% endif %}
-                                    </h5>
-                                </div>
-                            {% endif %}
-                        {% endif %}
-
-                    {% endfor %}
+                    {% if path.is_split %}
+                        <div class="trace-end">
+                            <h3 class="text-danger">Path split!</h3>
+                            <p>Select a node below to continue:</p>
+                            <ul class="text-start">
+                                {% for next_node in path.get_split_nodes %}
+                                    {% if next_node.cable %}
+                                        <li>
+                                            <a href="{% url 'dcim:frontport_trace' pk=next_node.pk %}">{{ next_node }}</a>
+                                            (Cable <a href="{{ next_node.cable.get_absolute_url }}">{{ next_node.cable }}</a>)
+                                        </li>
+                                    {% else %}
+                                        <li class="text-muted">{{ next_node }}</li>
+                                    {% endif %}
+                                {% endfor %}
+                            </ul>
+                        </div>
+                    {% else %}
+                        <div class="trace-end">
+                            <h3 class="text-success">Trace Completed</h3>
+                            <h5>Total Segments: {{ traced_path|length }}</h5>
+                            <h5>Total Length:
+                                {% if total_length %}
+                                    {{ total_length|floatformat:"-2" }}{% if not is_definitive %}+{% endif %} Meters /
+                                    {{ total_length|meters_to_feet|floatformat:"-2" }} Feet
+                                {% else %}
+                                    <span class="text-muted">N/A</span>
+                                {% endif %}
+                            </h5>
+                        </div>
+                    {% endif %}
                 {% endwith %}
                 {% endwith %}
             </div>
             </div>
         </div>
         </div>