Skip to content

Commit 14fd533

Browse files
committed
Add topology visualization to circuit detail view
- Extend CircuitSegmentExtension to render segment or service path topology - Integrate topology builders build_segment_topology and build_service_path_topology - Add conditional visualization card to circuit_segments_extension template - Provide fallback info message when topology data is unavailable -Fixed default ordering for SegmentCircuitMappingTable to order circuits by CID instead of name
1 parent 025b152 commit 14fd533

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

cesnet_service_path_plugin/tables/segment_circuit_mapping.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class SegmentCircuitMappingTable(NetBoxTable):
4141
order_by=("segment__location_b__name",),
4242
accessor="segment.location_b",
4343
)
44-
circuit = tables.Column(linkify=True, verbose_name="Circuit", orderable=True, order_by=("circuit__name",))
44+
circuit = tables.Column(linkify=True, verbose_name="Circuit", orderable=True, order_by=("circuit__cid",))
4545
tags = columns.TagColumn()
4646

4747
class Meta(NetBoxTable.Meta):

cesnet_service_path_plugin/template_content.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import django_tables2
2+
import json
23
from circuits.models import Provider
34
from circuits.tables import CircuitTable
45
from django.conf import settings
56
from django.utils.translation import gettext_lazy as _
67
from netbox.plugins import PluginTemplateExtension
78
from utilities.tables import register_table_column
89

9-
from cesnet_service_path_plugin.models import Segment
10+
from cesnet_service_path_plugin.models import Segment, ServicePathSegmentMapping
11+
from cesnet_service_path_plugin.utils import build_service_path_topology, build_segment_topology
12+
1013

1114
plugin_settings = settings.PLUGINS_CONFIG.get("cesnet_service_path_plugin", {})
1215

@@ -17,8 +20,38 @@ class CircuitSegmentExtension(PluginTemplateExtension):
1720
models = ["circuits.circuit"]
1821

1922
def full_width_page(self):
23+
circuit = self.context["object"]
24+
25+
# Get the first segment associated with this circuit
26+
try:
27+
segment = circuit.segment_set.first()
28+
except AttributeError:
29+
segment = None
30+
31+
# Initialize topology data
32+
topology_data = None
33+
topology_title = None
34+
35+
if segment:
36+
# Check if segment is part of any service path
37+
service_path_mapping = ServicePathSegmentMapping.objects.filter(segment=segment).first()
38+
39+
if service_path_mapping:
40+
# Build service path topology
41+
topology_title = f"Service Path Topology: {service_path_mapping.service_path.name}"
42+
topology_data = build_service_path_topology(service_path_mapping.service_path)
43+
else:
44+
# Build segment topology only
45+
topology_title = f"Segment Topology: {segment.name}"
46+
topology_data = build_segment_topology(segment)
47+
2048
return self.render(
2149
"cesnet_service_path_plugin/circuit_segments_extension.html",
50+
extra_context={
51+
"segment": segment,
52+
"topology_data": json.dumps(topology_data) if topology_data else None,
53+
"topology_title": topology_title,
54+
},
2255
)
2356

2457

cesnet_service_path_plugin/templates/cesnet_service_path_plugin/circuit_segments_extension.html

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
{% load i18n %}
2+
3+
<!-- Segments Table Card -->
24
<div class="col col-md-12">
35
<div class="card">
46
<h5 class="card-header">
@@ -13,3 +15,37 @@ <h5 class="card-header">
1315
{% htmx_table 'plugins:cesnet_service_path_plugin:segmentcircuitmapping_list' circuit_id=object.pk %}
1416
</div>
1517
</div>
18+
19+
<!-- Topology Visualization Card -->
20+
{% if topology_data %}
21+
<div class="col col-md-12 mt-3">
22+
<div class="card">
23+
<h5 class="card-header">
24+
{{ topology_title }}
25+
<div class="card-actions">
26+
<button id="fit-topology" class="btn btn-ghost-primary btn-sm" title="Fit to screen">
27+
<i class="mdi mdi-fit-to-screen" aria-hidden="true"></i>
28+
</button>
29+
<button id="reset-topology" class="btn btn-ghost-primary btn-sm" title="Reset layout">
30+
<i class="mdi mdi-refresh" aria-hidden="true"></i>
31+
</button>
32+
</div>
33+
</h5>
34+
<div class="card-body">
35+
<div id="cy-topology" style="width: 100%; height: 600px; border: 1px solid rgba(59, 130, 246, 0.08); border-radius: 20px;"></div>
36+
</div>
37+
</div>
38+
</div>
39+
40+
<!-- Include Topology Visualization -->
41+
{% include 'cesnet_service_path_plugin/inc/topology_visualization.html' %}
42+
43+
{% elif segment %}
44+
<div class="col col-md-12 mt-3">
45+
<div class="alert alert-info">
46+
<i class="mdi mdi-information-outline" aria-hidden="true"></i>
47+
This circuit is associated with segment <a href="{{ segment.get_absolute_url }}">{{ segment.name }}</a>,
48+
but topology visualization is not available. Visit the segment detail page to view its topology.
49+
</div>
50+
</div>
51+
{% endif %}

0 commit comments

Comments
 (0)