Skip to content

Commit be54797

Browse files
committed
feat: switch tooltip to popover so Trace link is clickable
Tooltip disappears before the user can click the Trace link inside it. Replace with Bootstrap Popover (container:body, placement:top, delay show:200 hide:300) which stays open when the cursor moves into it, making the Trace link reliably clickable. Both CSS grid and SVG paths updated in ports.html and deviceview.html.
1 parent a7fa915 commit be54797

2 files changed

Lines changed: 36 additions & 52 deletions

File tree

netbox_device_view/templates/netbox_device_view/deviceview.html

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -67,25 +67,15 @@
6767
{% else %}
6868
bg-danger
6969
{% endif %}"
70-
title="{{ int.name }}
71-
{% if int.connected_endpoints|length > 0 %}<hr>
72-
{% for ce in int.connected_endpoints %}
73-
{{ ce.device }} | {{ ce.name }}
74-
{% endfor %}
75-
{% elif int.link_peers|length > 0 %}<hr>
76-
{% for lp in int.link_peers %}
77-
{% if lp.device %}
78-
{{ lp.device }} | {{ lp.name }}
79-
{% elif lp.circuit %}
80-
{{ lp }}
81-
{% endif %}
82-
{% endfor %}
83-
{% endif %}
84-
<hr><a href='{{int.get_absolute_url}}trace/'>Trace</a>
85-
"
70+
data-bs-title="{{ int.name }}{% if int.connected_endpoints|length > 0 %}<hr>{% for ce in int.connected_endpoints %}{{ ce.device }} | {{ ce.name }}{% if not forloop.last %}<br>{% endif %}{% endfor %}{% elif int.link_peers|length > 0 %}<hr>{% for lp in int.link_peers %}{% if lp.device %}{{ lp.device }} | {{ lp.name }}{% elif lp.circuit %}{{ lp }}{% endif %}{% if not forloop.last %}<br>{% endif %}{% endfor %}{% endif %}"
71+
data-bs-content="<a href='{{int.get_absolute_url}}trace/'>Trace</a>"
8672
style="grid-area: {{ int.stylename }}{% if cable_colors == 'on' and int.cable.color != '' %}; background-color: #{{ int.cable.color }}{% endif %}"
87-
data-bs-toggle="tooltip"
73+
data-bs-toggle="popover"
74+
data-bs-trigger="hover focus"
75+
data-bs-placement="top"
8876
data-bs-html="true"
77+
data-bs-container="body"
78+
data-bs-delay='{"show":200,"hide":300}'
8979
data-bs-custom-class="device-view-tooltip"
9080
>
9181
{% if int.enabled and int.connected_endpoints|length > 0 or int.is_port and int.link_peers|length > 0 %}
@@ -172,21 +162,22 @@
172162
if (e.key === "Enter" || e.key === " ") { window.location.href = p.detailUrl; }
173163
});
174164

175-
var title = p.name;
165+
var popTitle = p.name;
176166
var peers = p.connectedEndpoints.length > 0 ? p.connectedEndpoints : p.linkPeers;
177-
if (peers.length > 0) { title += "<hr>" + peers.join("<br>"); }
178-
title += '<hr><a href="' + p.traceUrl + '">Trace</a>';
167+
if (peers.length > 0) { popTitle += "<hr>" + peers.join("<br>"); }
168+
var popContent = '<a href="' + p.traceUrl + '">Trace</a>';
169+
g.setAttribute("data-bs-toggle", "popover");
170+
g.setAttribute("data-bs-trigger", "hover focus");
171+
g.setAttribute("data-bs-placement", "top");
179172
g.setAttribute("data-bs-html", "true");
173+
g.setAttribute("data-bs-container", "body");
180174
g.setAttribute("data-bs-custom-class", "device-view-tooltip");
181-
g.setAttribute("title", title);
182-
175+
g.setAttribute("data-bs-title", popTitle);
176+
g.setAttribute("data-bs-content", popContent);
183177
var svgTitle = g.querySelector("title");
184178
if (svgTitle) svgTitle.textContent = p.name;
185-
186-
if (typeof Tooltip !== "undefined") {
187-
var tip = new Tooltip(g, { trigger: "manual", html: true, container: "body" });
188-
g.addEventListener("pointerenter", function () { tip.show(); });
189-
g.addEventListener("pointerleave", function () { tip.hide(); });
179+
if (typeof bootstrap !== "undefined" && bootstrap.Popover) {
180+
new bootstrap.Popover(g, { trigger: "hover focus", html: true, container: "body", delay: { show: 200, hide: 300 } });
190181
}
191182
});
192183
});

netbox_device_view/templates/netbox_device_view/ports.html

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,25 +64,15 @@ <h2 class="card-header">Deviceview {% if object.virtual_chassis %}{{ object.virt
6464
{% else %}
6565
bg-danger
6666
{% endif %}"
67-
title="{{ int.name }}
68-
{% if int.connected_endpoints|length > 0 %}<hr>
69-
{% for ce in int.connected_endpoints %}
70-
{{ ce.device }} | {{ ce.name }}
71-
{% endfor %}
72-
{% elif int.link_peers|length > 0 %}<hr>
73-
{% for lp in int.link_peers %}
74-
{% if lp.device %}
75-
{{ lp.device }} | {{ lp.name }}
76-
{% elif lp.circuit %}
77-
{{ lp }}
78-
{% endif %}
79-
{% endfor %}
80-
{% endif %}
81-
<hr><a href='{{int.get_absolute_url}}trace/'>Trace</a>
82-
"
67+
data-bs-title="{{ int.name }}{% if int.connected_endpoints|length > 0 %}<hr>{% for ce in int.connected_endpoints %}{{ ce.device }} | {{ ce.name }}{% if not forloop.last %}<br>{% endif %}{% endfor %}{% elif int.link_peers|length > 0 %}<hr>{% for lp in int.link_peers %}{% if lp.device %}{{ lp.device }} | {{ lp.name }}{% elif lp.circuit %}{{ lp }}{% endif %}{% if not forloop.last %}<br>{% endif %}{% endfor %}{% endif %}"
68+
data-bs-content="<a href='{{int.get_absolute_url}}trace/'>Trace</a>"
8369
style="grid-area: {{ int.stylename }}{% if cable_colors == 'on' and int.cable.color != '' %}; background-color: #{{ int.cable.color }}{% endif %}"
84-
data-bs-toggle="tooltip"
70+
data-bs-toggle="popover"
71+
data-bs-trigger="hover focus"
72+
data-bs-placement="top"
8573
data-bs-html="true"
74+
data-bs-container="body"
75+
data-bs-delay='{"show":200,"hide":300}'
8676
data-bs-custom-class="device-view-tooltip"
8777
>
8878
{% if int.enabled and int.connected_endpoints|length > 0 or int.is_port and int.link_peers|length > 0 %}
@@ -167,19 +157,22 @@ <h2 class="card-header">Deviceview {% if object.virtual_chassis %}{{ object.virt
167157
g.addEventListener("keydown", function (e) {
168158
if (e.key === "Enter" || e.key === " ") { window.location.href = p.detailUrl; }
169159
});
170-
var title = p.name;
160+
var popTitle = p.name;
171161
var peers = p.connectedEndpoints.length > 0 ? p.connectedEndpoints : p.linkPeers;
172-
if (peers.length > 0) { title += "<hr>" + peers.join("<br>"); }
173-
title += '<hr><a href="' + p.traceUrl + '">Trace</a>';
162+
if (peers.length > 0) { popTitle += "<hr>" + peers.join("<br>"); }
163+
var popContent = '<a href="' + p.traceUrl + '">Trace</a>';
164+
g.setAttribute("data-bs-toggle", "popover");
165+
g.setAttribute("data-bs-trigger", "hover focus");
166+
g.setAttribute("data-bs-placement", "top");
174167
g.setAttribute("data-bs-html", "true");
168+
g.setAttribute("data-bs-container", "body");
175169
g.setAttribute("data-bs-custom-class", "device-view-tooltip");
176-
g.setAttribute("title", title);
170+
g.setAttribute("data-bs-title", popTitle);
171+
g.setAttribute("data-bs-content", popContent);
177172
var svgTitle = g.querySelector("title");
178173
if (svgTitle) svgTitle.textContent = p.name;
179-
if (typeof Tooltip !== "undefined") {
180-
var tip = new Tooltip(g, { trigger: "manual", html: true, container: "body" });
181-
g.addEventListener("pointerenter", function () { tip.show(); });
182-
g.addEventListener("pointerleave", function () { tip.hide(); });
174+
if (typeof bootstrap !== "undefined" && bootstrap.Popover) {
175+
new bootstrap.Popover(g, { trigger: "hover focus", html: true, container: "body", delay: { show: 200, hide: 300 } });
183176
}
184177
});
185178
});

0 commit comments

Comments
 (0)