fix: preserve native reorder rack devices

This commit is contained in:
2026-08-13 09:58:34 +02:00
parent a5f8cb62c7
commit 33490d40c4
5 changed files with 37 additions and 8 deletions
+4
View File
@@ -117,6 +117,10 @@ Reorder ersetzt seine nativen Gerätekacheln erst, nachdem ein vollständiger
und zur JavaScript-Version passender Datensatz geprüft wurde. Bei einer
gemischten Installation aus altem Python-Code und neuen statischen Dateien
bleibt deshalb die native Ansicht erhalten, statt ein leeres Rack zu zeigen.
Ab Version `0.9.4` werden vorhandene Reorder-Kacheln außerdem direkt auf das
12-Spalten-Raster erweitert und nicht mehr vorsorglich neu erzeugt. Nur ein
zweites, von NetBox' Ein-Gerät-pro-HE-Darstellung unterschlagenes Gerät wird
aus den Plugin-Daten ergänzt. Das verhindert browserabhängige leere Racks.
Bereits vorhandene Geräte, die dieselbe HE und Rackseite belegen, aber noch
keine Plugin-Platzierungszeile besitzen, werden in Rack-SVG, Reorder und der
Topology-Rack-Ansicht ohne Datenbankänderung gleichmäßig nebeneinander
+1 -1
View File
@@ -1,6 +1,6 @@
from netbox.plugins import PluginConfig, get_plugin_config
__version__ = "0.9.3"
__version__ = "0.9.4"
class NetBoxUtilitiesConfig(PluginConfig):
@@ -48,6 +48,8 @@
console.warn('NetBox Utilities received no replacement devices and kept the populated native layout.');
return;
}
const devicesById = new Map(data.devices.map(device => [String(device.id), device]));
const nativeItemsByFace = {};
const setAttribute = (element, name, value) => element.setAttribute(name, String(value));
const originalFetch = window.fetch.bind(window);
@@ -73,12 +75,26 @@
Object.entries(gridElements).forEach(([face, grid]) => {
setAttribute(grid, 'gs-column', columns);
const nativeItemsById = new Map(
Array.from(grid.querySelectorAll('.grid-stack-item')).map(item => [item.getAttribute('gs-id'), item]),
);
grid.querySelectorAll('.grid-stack-item').forEach(item => {
// The native Reorder view is based on Rack.get_rack_units(), which can
// expose only one device per rack unit. Rebuild the mounted grids from
// the complete server payload; keep native non-racked devices intact.
// Keep every native widget whenever possible. Rack.get_rack_units() can
// expose only one device per unit, so missing shared widgets are added
// from the complete payload below.
if (face !== 'other') {
item.remove();
const device = devicesById.get(item.getAttribute('gs-id'));
const belongsOnFace = device && (device.face === face || device.full_depth);
if (!belongsOnFace) {
item.remove();
return;
}
setAttribute(item, 'gs-w', device.grid_width);
setAttribute(item, 'gs-h', device.grid_height);
setAttribute(item, 'gs-x', device.grid_x);
setAttribute(item, 'gs-y', device.grid_y);
item.dataset.rackWidth = String(device.width);
item.dataset.horizontalPosition = String(device.horizontal_position);
return;
}
setAttribute(item, 'gs-w', columns);
@@ -86,6 +102,7 @@
item.dataset.rackWidth = '1';
item.dataset.horizontalPosition = '1';
});
nativeItemsByFace[face] = nativeItemsById;
});
const addWidget = (device, gridFace, itemFace, rearSide = false) => {
@@ -125,9 +142,14 @@
data.devices.forEach(device => {
const face = device.face === 'rear' ? 'rear' : 'front';
addWidget(device, face, face);
if (!nativeItemsByFace[face].has(String(device.id))) {
addWidget(device, face, face);
}
if (device.full_depth) {
addWidget(device, face === 'front' ? 'rear' : 'front', 'back', true);
const oppositeFace = face === 'front' ? 'rear' : 'front';
if (!nativeItemsByFace[oppositeFace].has(String(device.id))) {
addWidget(device, oppositeFace, 'back', true);
}
}
});
@@ -291,6 +291,9 @@ class ReorderRackFrontendTest(SimpleTestCase):
self.assertIn("data.schema_version !== 3", script)
self.assertIn("data.complete !== true", script)
self.assertIn("nativeMountedItems.length", script)
self.assertIn("const nativeItemsByFace = {}", script)
self.assertIn("const device = devicesById.get", script)
self.assertIn("if (!nativeItemsByFace[face].has", script)
self.assertNotIn("partialDeviceIds", script)
self.assertNotIn("JSON.stringify", script)
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "netbox-utilities"
version = "0.9.3"
version = "0.9.4"
description = "Navigation, tenant utilities, partial-width rack devices, bulk uploads, and rack reordering for NetBox 4.6"
readme = "README.md"
requires-python = ">=3.12"