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

1from django.contrib.contenttypes.models import ContentType 

2from django.utils.translation import gettext_lazy as _ 

3 

4from netbox.ui import actions, attrs, panels 

5from utilities.data import resolve_attr_path 

6 

7 

8class CircuitCircuitTerminationPanel(panels.ObjectPanel): 

9 """ 

10 A panel showing the CircuitTermination assigned to the object. 

11 """ 

12 

13 template_name = 'circuits/panels/circuit_circuit_termination.html' 

14 title = _('Termination') 

15 termination_ancestor_max_depth = 3 

16 

17 def __init__(self, side, accessor=None, **kwargs): 

18 super().__init__(accessor=accessor, **kwargs) 

19 self.side = side 

20 

21 def _get_termination_nodes(self, termination): 

22 """ 

23 Return the termination target's ancestors, including itself, when the 

24 target is tree-like. 

25 

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 

32 

33 get_ancestors = getattr(target, 'get_ancestors', None) 

34 if not callable(get_ancestors): 

35 return None 

36 

37 nodes = list(get_ancestors(include_self=True)) 

38 

39 if self.termination_ancestor_max_depth is not None: 

40 nodes = nodes[-self.termination_ancestor_max_depth:] 

41 

42 return nodes 

43 

44 def get_context(self, context): 

45 termination = resolve_attr_path(context, f'{self.accessor}.termination_{self.side.lower()}') 

46 

47 return { 

48 **super().get_context(context), 

49 'side': self.side, 

50 'termination': termination, 

51 'termination_nodes': self._get_termination_nodes(termination), 

52 } 

53 

54 

55class CircuitGroupAssignmentsPanel(panels.ObjectsTablePanel): 

56 """ 

57 A panel showing all Circuit Groups attached to the object. 

58 """ 

59 

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 ] 

72 

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 ) 

82 

83 

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') 

104 

105 

106class CircuitGroupPanel(panels.OrganizationalObjectPanel): 

107 tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group') 

108 

109 

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') 

115 

116 

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') 

129 

130 

131class CircuitTypePanel(panels.OrganizationalObjectPanel): 

132 color = attrs.ColorAttr('color') 

133 

134 

135class ProviderPanel(panels.ObjectAttributesPanel): 

136 name = attrs.TextAttr('name') 

137 asns = attrs.RelatedObjectListAttr('asns', linkify=True, label=_('ASNs')) 

138 description = attrs.TextAttr('description') 

139 

140 

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') 

146 

147 

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') 

153 

154 

155class VirtualCircuitTypePanel(panels.OrganizationalObjectPanel): 

156 color = attrs.ColorAttr('color') 

157 

158 

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') 

168 

169 

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') 

176 

177 

178class VirtualCircuitTerminationInterfacePanel(panels.ObjectAttributesPanel): 

179 title = _('Interface') 

180 

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')