v0.2.2: support dragging a device between front and rear elevations
Front and rear panels already share one coordinate system (same UNIT_HEIGHT, RACK_X, ...), just placed side by side on screen, so the existing delta-based drag math is equally valid for a drop on the other panel - only needed to detect which face the pointer ended up over (elementFromPoint at drop time) and include it as `face` in the submitted move; the reorder endpoint already supported changing it. Also fixed a bug this surfaced: without pointer-events: none on the dragged block during the drag, elementFromPoint() at drop time always hit the dragged block itself (it's what's rendered under the cursor), never the panel actually underneath - cross-face drops would never have been detected. Pointer capture keeps delivering move/up events to the block regardless of its own pointer-events value, so this is safe. Added overflow: visible on the elevation SVGs so a device being dragged toward the other panel doesn't just vanish at its own SVG's edge mid-drag. Updated the German translation for the changed drag-hint string. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
from netbox.plugins import PluginConfig
|
||||
|
||||
__version__ = '0.2.1'
|
||||
__version__ = '0.2.2'
|
||||
|
||||
|
||||
class RackConceptConfig(PluginConfig):
|
||||
|
||||
Binary file not shown.
@@ -340,9 +340,6 @@ msgstr "Geräte"
|
||||
msgid "Dimensions"
|
||||
msgstr "Abmessungen"
|
||||
|
||||
msgid "Drag devices to move them"
|
||||
msgstr "Geräte zum Verschieben ziehen"
|
||||
|
||||
msgid "Draw.io (.drawio)"
|
||||
msgstr "Draw.io (.drawio)"
|
||||
|
||||
@@ -926,3 +923,8 @@ msgid "{{ counter }} planned device will be created per rack."
|
||||
msgid_plural "{{ counter }} planned devices will be created per rack."
|
||||
msgstr[0] "Pro Rack wird {{ counter }} geplantes Gerät angelegt."
|
||||
msgstr[1] "Pro Rack werden {{ counter }} geplante Geräte angelegt."
|
||||
|
||||
msgid "Drag devices to move or flip them between front and rear"
|
||||
msgstr ""
|
||||
"Geräte ziehen, um sie zu verschieben oder zwischen Front und Rückseite zu "
|
||||
"wechseln"
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
height: auto;
|
||||
user-select: none;
|
||||
touch-action: none;
|
||||
/* A device being dragged toward the other face's panel shouldn't just vanish the
|
||||
moment it crosses this SVG's own edge - let it render past the boundary while
|
||||
it's mid-drag, into whatever sits next to it (the other panel, side by side). */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.concept-elevation .unit-slot {
|
||||
|
||||
@@ -113,10 +113,18 @@
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
|
||||
/* Which .concept-elevation panel (front or rear) the pointer is currently over -
|
||||
used at drop time to tell whether a device was dragged onto the other face. */
|
||||
function panelAt(clientX, clientY) {
|
||||
const el = document.elementFromPoint(clientX, clientY);
|
||||
return el ? el.closest('.concept-elevation') : null;
|
||||
}
|
||||
|
||||
container.querySelectorAll('.concept-elevation').forEach(function (panel) {
|
||||
const svg = panel.querySelector('svg');
|
||||
const geo = geometry(svg);
|
||||
if (!geo) return;
|
||||
const sourceFace = panel.dataset.face;
|
||||
|
||||
panel.querySelectorAll('.device-block:not(.opposite)').forEach(function (block) {
|
||||
block.addEventListener('pointerdown', onPointerDown);
|
||||
@@ -139,6 +147,11 @@
|
||||
let dy = 0;
|
||||
|
||||
block.classList.add('dragging');
|
||||
// Without this, elementFromPoint() at drop time would always hit the
|
||||
// dragged block itself (it's what's rendered under the cursor), never
|
||||
// whatever panel is actually underneath it - pointer capture (below)
|
||||
// keeps move/up events coming to `block` regardless, so this is safe.
|
||||
block.style.pointerEvents = 'none';
|
||||
block.setPointerCapture(event.pointerId);
|
||||
|
||||
function onMove(moveEvent) {
|
||||
@@ -152,11 +165,12 @@
|
||||
block.setAttribute('transform', 'translate(' + dx + ' ' + snappedY + ')');
|
||||
}
|
||||
|
||||
function onUp() {
|
||||
function onUp(upEvent) {
|
||||
block.removeEventListener('pointermove', onMove);
|
||||
block.removeEventListener('pointerup', onUp);
|
||||
block.removeEventListener('pointercancel', onUp);
|
||||
block.classList.remove('dragging');
|
||||
block.style.pointerEvents = '';
|
||||
|
||||
if (!moved) {
|
||||
// Treat it as a click: follow the device link.
|
||||
@@ -166,6 +180,14 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Front and rear share one coordinate system (same UNIT_HEIGHT,
|
||||
// RACK_X, ...), just placed side by side on screen - the delta
|
||||
// computed against the source panel is equally valid whichever
|
||||
// panel the pointer ends up over, so dropping onto the other face
|
||||
// only needs to swap which face gets submitted.
|
||||
const targetPanel = panelAt(upEvent.clientX, upEvent.clientY);
|
||||
const targetFace = (targetPanel && targetPanel.dataset.face) || sourceFace;
|
||||
|
||||
const unitDelta = Math.round(dy / geo.unitHeight) * (descUnits ? 1 : -1);
|
||||
const lowest = startingUnit;
|
||||
const highest = startingUnit + rackHeight - deviceUnits;
|
||||
@@ -180,7 +202,8 @@
|
||||
);
|
||||
}
|
||||
|
||||
submit(block, newPosition, fraction > 1 ? horizontal : null);
|
||||
submit(block, newPosition, fraction > 1 ? horizontal : null,
|
||||
targetFace !== sourceFace ? targetFace : null);
|
||||
}
|
||||
|
||||
block.addEventListener('pointermove', onMove);
|
||||
@@ -190,7 +213,7 @@
|
||||
});
|
||||
});
|
||||
|
||||
function submit(block, position, horizontalPosition) {
|
||||
function submit(block, position, horizontalPosition, face) {
|
||||
const move = {
|
||||
id: parseInt(block.dataset.deviceId, 10),
|
||||
position: position
|
||||
@@ -198,6 +221,9 @@
|
||||
if (horizontalPosition !== null) {
|
||||
move.horizontal_position = horizontalPosition;
|
||||
}
|
||||
if (face) {
|
||||
move.face = face;
|
||||
}
|
||||
|
||||
setStatus('Saving…', false);
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
<option value="labels-only">{% trans "Labels only" %}</option>
|
||||
</select>
|
||||
{% if perms.netbox_rack_concept.change_conceptdevice %}
|
||||
<span class="badge text-bg-secondary">{% trans "Drag devices to move them" %}</span>
|
||||
<span class="badge text-bg-secondary">{% trans "Drag devices to move or flip them between front and rear" %}</span>
|
||||
{% endif %}
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
|
||||
Reference in New Issue
Block a user