Introduce CircuitTerminationPanel to replace generic panel

This commit is contained in:
Jeremy Stretch
2026-04-01 17:15:05 -04:00
parent 623ab55d5b
commit faf8554d2c
5 changed files with 77 additions and 21 deletions

View File

@@ -58,6 +58,26 @@ class CircuitGroupAssignmentsPanel(panels.ObjectsTablePanel):
)
class CircuitTerminationPanel(panels.ObjectAttributesPanel):
title = _('Circuit Termination')
circuit = attrs.RelatedObjectAttr('circuit', linkify=True)
provider = attrs.RelatedObjectAttr('circuit.provider', linkify=True)
termination = attrs.GenericForeignKeyAttr('termination', linkify=True, label=_('Termination point'))
connection = attrs.TemplatedAttr(
'pk',
template_name='circuits/circuit_termination/attrs/connection.html',
label=_('Connection'),
)
speed = attrs.TemplatedAttr(
'port_speed',
template_name='circuits/circuit_termination/attrs/speed.html',
label=_('Speed'),
)
xconnect_id = attrs.TextAttr('xconnect_id', label=_('Cross-Connect'), style='font-monospace')
pp_info = attrs.TextAttr('pp_info', label=_('Patch Panel/Port'))
description = attrs.TextAttr('description')
class CircuitGroupPanel(panels.OrganizationalObjectPanel):
tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')

View File

@@ -8,7 +8,6 @@ from netbox.ui import actions, layout
from netbox.ui.panels import (
CommentsPanel,
ObjectsTablePanel,
Panel,
RelatedObjectsPanel,
)
from netbox.views import generic
@@ -508,10 +507,7 @@ class CircuitTerminationView(generic.ObjectView):
queryset = CircuitTermination.objects.all()
layout = layout.SimpleLayout(
left_panels=[
Panel(
template_name='circuits/panels/circuit_termination.html',
title=_('Circuit Termination'),
)
panels.CircuitTerminationPanel(),
],
right_panels=[
CustomFieldsPanel(),

View File

@@ -0,0 +1,48 @@
{% load helpers i18n %}
{% if object.mark_connected %}
<div>
<span class="text-success"><i class="mdi mdi-check-bold"></i></span>
<span class="text-muted">{% trans "Marked as connected" %}</span>
</div>
{% elif object.cable %}
<div>
<a class="d-block d-md-inline" href="{{ object.cable.get_absolute_url }}">{{ object.cable }}</a> {% trans "to" %}
{% for peer in object.link_peers %}
{% if peer.device %}
{{ peer.device|linkify }}<br/>
{% elif peer.circuit %}
{{ peer.circuit|linkify }}<br/>
{% endif %}
{{ peer|linkify }}{% if not forloop.last %},{% endif %}
{% endfor %}
</div>
<div class="mt-1">
<a href="{% url 'circuits:circuittermination_trace' pk=object.pk %}" class="btn btn-sm btn-primary" title="{% trans "Trace" %}">
<i class="mdi mdi-transit-connection-variant" aria-hidden="true"></i> {% trans "Trace" %}
</a>
{% if perms.dcim.change_cable %}
<a href="{% url 'dcim:cable_edit' pk=object.cable.pk %}?return_url={{ object.circuit.get_absolute_url }}" title="{% trans "Edit cable" %}" class="btn btn-sm btn-warning">
<i class="mdi mdi-ethernet-cable" aria-hidden="true"></i> {% trans "Edit" %}
</a>
{% endif %}
{% if perms.dcim.delete_cable %}
<a href="{% url 'dcim:cable_delete' pk=object.cable.pk %}?return_url={{ object.circuit.get_absolute_url }}" title="{% trans "Remove cable" %}" class="btn btn-sm btn-danger">
<i class="mdi mdi-ethernet-cable-off" aria-hidden="true"></i> {% trans "Disconnect" %}
</a>
{% endif %}
</div>
{% elif perms.dcim.add_cable %}
<div class="dropdown">
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="mdi mdi-ethernet-cable" aria-hidden="true"></span> {% trans "Connect" %}
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url 'dcim:cable_add' %}?a_terminations_type=circuits.circuittermination&a_terminations={{ object.pk }}&b_terminations_type=dcim.interface&return_url={{ object.get_absolute_url }}">{% trans "Interface" %}</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:cable_add' %}?a_terminations_type=circuits.circuittermination&a_terminations={{ object.pk }}&b_terminations_type=dcim.frontport&return_url={{ object.get_absolute_url }}">{% trans "Front Port" %}</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:cable_add' %}?a_terminations_type=circuits.circuittermination&a_terminations={{ object.pk }}&b_terminations_type=dcim.rearport&return_url={{ object.get_absolute_url }}">{% trans "Rear Port" %}</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:cable_add' %}?a_terminations_type=circuits.circuittermination&a_terminations={{ object.pk }}&b_terminations_type=circuits.circuittermination&return_url={{ object.get_absolute_url }}">{% trans "Circuit Termination" %}</a></li>
</ul>
</div>
{% else %}
{{ ''|placeholder }}
{% endif %}

View File

@@ -0,0 +1,8 @@
{% load helpers i18n %}
{% if object.upstream_speed %}
<i class="mdi mdi-arrow-down-bold" title="{% trans "Downstream" %}"></i> {{ object.port_speed|humanize_speed }}
<i class="mdi mdi-slash-forward"></i>
<i class="mdi mdi-arrow-up-bold" title="{% trans "Upstream" %}"></i> {{ object.upstream_speed|humanize_speed }}
{% else %}
{{ object.port_speed|humanize_speed }}
{% endif %}

View File

@@ -1,16 +0,0 @@
{% extends "ui/panels/_base.html" %}
{% load helpers i18n %}
{% block panel_content %}
<table class="table table-hover attr-table">
<tr>
<th scope="row">{% trans "Circuit" %}</th>
<td>{{ object.circuit|linkify|placeholder }}</td>
</tr>
<tr>
<th scope="row">{% trans "Provider" %}</th>
<td>{{ object.circuit.provider|linkify|placeholder }}</td>
</tr>
{% include 'circuits/inc/circuit_termination_fields.html' with termination=object %}
</table>
{% endblock panel_content %}