Coverage for circuits/ui/panels.py: 83%
98 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from django.contrib.contenttypes.models import ContentType
2from django.utils.translation import gettext_lazy as _
4from netbox.ui import actions, attrs, panels
5from utilities.data import resolve_attr_path
8class CircuitCircuitTerminationPanel(panels.ObjectPanel):
9 """
10 A panel showing the CircuitTermination assigned to the object.
11 """
13 template_name = 'circuits/panels/circuit_circuit_termination.html'
14 title = _('Termination')
15 termination_ancestor_max_depth = 3
17 def __init__(self, side, accessor=None, **kwargs):
18 super().__init__(accessor=accessor, **kwargs)
19 self.side = side
21 def _get_termination_nodes(self, termination):
22 """
23 Return the termination target's ancestors, including itself, when the
24 target is tree-like.
26 Non-tree GFK targets return None, so the template preserves the current
27 single-object rendering.
28 """
29 target = getattr(termination, 'termination', None)
30 if target is None:
31 return None
33 get_ancestors = getattr(target, 'get_ancestors', None)
34 if not callable(get_ancestors):
35 return None
37 nodes = list(get_ancestors(include_self=True))
39 if self.termination_ancestor_max_depth is not None:
40 nodes = nodes[-self.termination_ancestor_max_depth:]
42 return nodes
44 def get_context(self, context):
45 termination = resolve_attr_path(context, f'{self.accessor}.termination_{self.side.lower()}')
47 return {
48 **super().get_context(context),
49 'side': self.side,
50 'termination': termination,
51 'termination_nodes': self._get_termination_nodes(termination),
52 }
55class CircuitGroupAssignmentsPanel(panels.ObjectsTablePanel):
56 """
57 A panel showing all Circuit Groups attached to the object.
58 """
60 title = _('Group Assignments')
61 actions = [
62 actions.AddObject(
63 'circuits.CircuitGroupAssignment',
64 url_params={
65 'member_content_type': lambda ctx: ContentType.objects.get_for_model(ctx['object']).pk,
66 'member_object_id': lambda ctx: ctx['object'].pk,
67 'return_url': lambda ctx: ctx['object'].get_absolute_url(),
68 },
69 label=_('Assign Group'),
70 ),
71 ]
73 def __init__(self, **kwargs):
74 super().__init__(
75 'circuits.CircuitGroupAssignment',
76 filters={
77 'member_type_id': lambda ctx: ContentType.objects.get_for_model(ctx['object']).pk,
78 'member_id': lambda ctx: ctx['object'].pk,
79 },
80 **kwargs,
81 )
84class CircuitTerminationPanel(panels.ObjectAttributesPanel):
85 title = _('Circuit Termination')
86 circuit = attrs.RelatedObjectAttr('circuit', linkify=True)
87 provider = attrs.RelatedObjectAttr('circuit.provider', linkify=True)
88 termination = attrs.GenericForeignKeyAttr(
89 'termination', linkify=True, nested=True, max_depth=3, label=_('Termination point')
90 )
91 connection = attrs.TemplatedAttr(
92 'pk',
93 template_name='circuits/circuit_termination/attrs/connection.html',
94 label=_('Connection'),
95 )
96 speed = attrs.TemplatedAttr(
97 'port_speed',
98 template_name='circuits/circuit_termination/attrs/speed.html',
99 label=_('Speed'),
100 )
101 xconnect_id = attrs.TextAttr('xconnect_id', label=_('Cross-Connect'), style='font-monospace')
102 pp_info = attrs.TextAttr('pp_info', label=_('Patch Panel/Port'))
103 description = attrs.TextAttr('description')
106class CircuitGroupPanel(panels.OrganizationalObjectPanel):
107 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
110class CircuitGroupAssignmentPanel(panels.ObjectAttributesPanel):
111 group = attrs.RelatedObjectAttr('group', linkify=True)
112 provider = attrs.RelatedObjectAttr('member.provider', linkify=True)
113 member = attrs.GenericForeignKeyAttr('member', linkify=True)
114 priority = attrs.ChoiceAttr('priority')
117class CircuitPanel(panels.ObjectAttributesPanel):
118 provider = attrs.RelatedObjectAttr('provider', linkify=True)
119 provider_account = attrs.RelatedObjectAttr('provider_account', linkify=True)
120 cid = attrs.TextAttr('cid', label=_('Circuit ID'), style='font-monospace', copy_button=True)
121 type = attrs.RelatedObjectAttr('type', linkify=True, colored=True)
122 status = attrs.ChoiceAttr('status')
123 distance = attrs.DistanceAttr('distance')
124 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
125 install_date = attrs.DateTimeAttr('install_date', spec='date')
126 termination_date = attrs.DateTimeAttr('termination_date', spec='date')
127 commit_rate = attrs.TemplatedAttr('commit_rate', template_name='circuits/circuit/attrs/commit_rate.html')
128 description = attrs.TextAttr('description')
131class CircuitTypePanel(panels.OrganizationalObjectPanel):
132 color = attrs.ColorAttr('color')
135class ProviderPanel(panels.ObjectAttributesPanel):
136 name = attrs.TextAttr('name')
137 asns = attrs.RelatedObjectListAttr('asns', linkify=True, label=_('ASNs'))
138 description = attrs.TextAttr('description')
141class ProviderAccountPanel(panels.ObjectAttributesPanel):
142 provider = attrs.RelatedObjectAttr('provider', linkify=True)
143 account = attrs.TextAttr('account', style='font-monospace', copy_button=True)
144 name = attrs.TextAttr('name')
145 description = attrs.TextAttr('description')
148class ProviderNetworkPanel(panels.ObjectAttributesPanel):
149 provider = attrs.RelatedObjectAttr('provider', linkify=True)
150 name = attrs.TextAttr('name')
151 service_id = attrs.TextAttr('service_id', label=_('Service ID'), style='font-monospace', copy_button=True)
152 description = attrs.TextAttr('description')
155class VirtualCircuitTypePanel(panels.OrganizationalObjectPanel):
156 color = attrs.ColorAttr('color')
159class VirtualCircuitPanel(panels.ObjectAttributesPanel):
160 provider = attrs.RelatedObjectAttr('provider', linkify=True)
161 provider_network = attrs.RelatedObjectAttr('provider_network', linkify=True)
162 provider_account = attrs.RelatedObjectAttr('provider_account', linkify=True)
163 cid = attrs.TextAttr('cid', label=_('Circuit ID'), style='font-monospace', copy_button=True)
164 type = attrs.RelatedObjectAttr('type', linkify=True, colored=True)
165 status = attrs.ChoiceAttr('status')
166 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
167 description = attrs.TextAttr('description')
170class VirtualCircuitTerminationPanel(panels.ObjectAttributesPanel):
171 provider = attrs.RelatedObjectAttr('virtual_circuit.provider', linkify=True)
172 provider_network = attrs.RelatedObjectAttr('virtual_circuit.provider_network', linkify=True)
173 provider_account = attrs.RelatedObjectAttr('virtual_circuit.provider_account', linkify=True)
174 virtual_circuit = attrs.RelatedObjectAttr('virtual_circuit', linkify=True)
175 role = attrs.ChoiceAttr('role')
178class VirtualCircuitTerminationInterfacePanel(panels.ObjectAttributesPanel):
179 title = _('Interface')
181 device = attrs.RelatedObjectAttr('interface.device', linkify=True)
182 interface = attrs.RelatedObjectAttr('interface', linkify=True)
183 type = attrs.ChoiceAttr('interface.type')
184 description = attrs.TextAttr('interface.description')