ui: place offline SVG button directly beside "SVG herunterladen"
NetBox renders the native download link inside each per-face elevation card, not through a plugin buttons() extension point, so there's no server-side hook to inject a matching link next to it. The right_page() extension now emits only a script (no separate sidebar panel) that finds every a[href*="render=svg"] link, reads its face= param, and inserts a matching "SVG offline" button right after it. The button's href stays in sync with the rack-view select the same way the previous panel's links did. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
from netbox.plugins import PluginConfig, get_plugin_config
|
from netbox.plugins import PluginConfig, get_plugin_config
|
||||||
|
|
||||||
__version__ = "0.12.1"
|
__version__ = "0.12.2"
|
||||||
|
|
||||||
|
|
||||||
class NetBoxUtilitiesConfig(PluginConfig):
|
class NetBoxUtilitiesConfig(PluginConfig):
|
||||||
|
|||||||
@@ -156,6 +156,10 @@ class RackUtilitiesContent(PluginTemplateExtension):
|
|||||||
models = ["dcim.rack"]
|
models = ["dcim.rack"]
|
||||||
|
|
||||||
def right_page(self):
|
def right_page(self):
|
||||||
|
# Injects a script (no visible panel here) which places an "SVG
|
||||||
|
# offline" button right next to each native "SVG herunterladen"
|
||||||
|
# link, since NetBox renders those inside the per-face elevation
|
||||||
|
# cards rather than through a plugin buttons() extension point.
|
||||||
if not offline_svg_export_enabled():
|
if not offline_svg_export_enabled():
|
||||||
return ""
|
return ""
|
||||||
rack = self.context["object"]
|
rack = self.context["object"]
|
||||||
|
|||||||
@@ -1,37 +1,49 @@
|
|||||||
<div class="card">
|
|
||||||
<h2 class="card-header">SVG offline exportieren</h2>
|
|
||||||
<div class="card-body d-flex flex-column gap-2">
|
|
||||||
<a href="{% url 'plugins:netbox_utilities:rack_elevation_offline_svg' pk=rack.pk %}?face=front"
|
|
||||||
class="btn btn-outline-secondary netbox-utilities-offline-svg-link" data-face="front"
|
|
||||||
title="Vorderseite als linkfreie SVG-Datei herunterladen">
|
|
||||||
<i class="mdi mdi-download" aria-hidden="true"></i>
|
|
||||||
Vorderseite
|
|
||||||
</a>
|
|
||||||
<a href="{% url 'plugins:netbox_utilities:rack_elevation_offline_svg' pk=rack.pk %}?face=rear"
|
|
||||||
class="btn btn-outline-secondary netbox-utilities-offline-svg-link" data-face="rear"
|
|
||||||
title="Rückseite als linkfreie SVG-Datei herunterladen">
|
|
||||||
<i class="mdi mdi-download" aria-hidden="true"></i>
|
|
||||||
Rückseite
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
var links = document.querySelectorAll(".netbox-utilities-offline-svg-link");
|
var offlineBaseUrl = "{% url 'plugins:netbox_utilities:rack_elevation_offline_svg' pk=rack.pk %}";
|
||||||
var viewSelect = document.querySelector("select.rack-view");
|
var viewSelect = document.querySelector("select.rack-view");
|
||||||
if (!links.length || !viewSelect) {
|
|
||||||
return;
|
function currentView() {
|
||||||
|
return viewSelect ? viewSelect.value : "images-and-labels";
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncLinks() {
|
function buildHref(face) {
|
||||||
links.forEach(function (link) {
|
var url = new URL(offlineBaseUrl, window.location.origin);
|
||||||
var url = new URL(link.href, window.location.origin);
|
url.searchParams.set("face", face);
|
||||||
url.searchParams.set("view", viewSelect.value);
|
url.searchParams.set("view", currentView());
|
||||||
link.href = url.toString();
|
return url.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertOfflineButtons() {
|
||||||
|
document.querySelectorAll('a[href*="render=svg"]').forEach(function (nativeLink) {
|
||||||
|
if (nativeLink.dataset.netboxUtilitiesOfflineInserted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nativeLink.dataset.netboxUtilitiesOfflineInserted = "true";
|
||||||
|
|
||||||
|
var nativeUrl = new URL(nativeLink.href, window.location.origin);
|
||||||
|
var face = nativeUrl.searchParams.get("face") || "front";
|
||||||
|
|
||||||
|
var offlineLink = document.createElement("a");
|
||||||
|
offlineLink.className = nativeLink.className + " netbox-utilities-offline-svg-link";
|
||||||
|
offlineLink.title = "Wie \"SVG herunterladen\", aber ohne interne Links – funktioniert offline";
|
||||||
|
offlineLink.href = buildHref(face);
|
||||||
|
offlineLink.innerHTML = '<i class="mdi mdi-download" aria-hidden="true"></i> SVG offline';
|
||||||
|
|
||||||
|
nativeLink.insertAdjacentElement("afterend", offlineLink);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
viewSelect.addEventListener("change", syncLinks);
|
insertOfflineButtons();
|
||||||
syncLinks();
|
|
||||||
|
if (viewSelect) {
|
||||||
|
viewSelect.addEventListener("change", function () {
|
||||||
|
document.querySelectorAll(".netbox-utilities-offline-svg-link").forEach(function (link) {
|
||||||
|
var url = new URL(link.href, window.location.origin);
|
||||||
|
url.searchParams.set("view", currentView());
|
||||||
|
link.href = url.toString();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "netbox-utilities"
|
name = "netbox-utilities"
|
||||||
version = "0.12.1"
|
version = "0.12.2"
|
||||||
description = "Navigation, tenant utilities, connection VLANs, partial-width racks, and bulk operations for NetBox 4.6/4.7"
|
description = "Navigation, tenant utilities, connection VLANs, partial-width racks, and bulk operations for NetBox 4.6/4.7"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
|||||||
Reference in New Issue
Block a user