{% extends 'generic/object.html' %} {% load static %} {% load i18n %} {% load rack_design %} {# Interactive single-rack layout editor (Stage 2, slice 2a: MOVE + REMOVE). #} {# Forks design_elevation.html but initialises GridStack WITHOUT staticGrid so #} {# slots can be dragged vertically (and between faces / into the non-racked #} {# tray). editor.js hydrates from #rd-editor-data, tracks each widget's original #} {# (u_position, face), and POSTs a diff to data-save-url. NO model changes. #} {# #} {# Widget indices: views.py builds `widgets` (and widgets_json) in the order #} {# (*front, *rear, *non_racked). Each grid-stack-item below is stamped with the #} {# matching GLOBAL index via `gs-id`/data-widget-index so editor.js can pair the #} {# JSON payload to its DOM tile: front uses forloop.counter0; rear adds the #} {# front length; the tray adds front+rear lengths. #} {% block head %} {{ block.super }} {% endblock head %} {% block content %}

{% blocktrans with rack=rack.name design=object.title %}Edit layout: {{ rack }} ({{ design }}){% endblocktrans %}

{# The editor root: carries the save URL + rack meta the JS needs. #}
{% with front_len=front|length rear_len=rear|length %} {# Legend — also acts as a per-state filter (see legend_filter.js). #}
{# ---- Front face ---- #}

{% trans "Front" %}

    {% for u in rack.units %}
  • {% if u|rack_whole_unit %}{{ u|floatformat:"0" }}{% endif %}
  • {% endfor %}
{% for slot in front %}
{{ slot.label }}
{% endfor %}
{{ rack.name }} {% if rack.tenant %}· {{ rack.tenant }}{% endif %}
{# ---- Rear face ---- #}
{# ---- Non-racked tray (drop zone) ---- #}

{% trans "Non-racked tray" %}

{% trans "Drag a device here to move it off the rack, or use the × on a tile to flag it for removal." %}

{% for slot in non_racked %}
{{ slot.label }}
{% endfor %}
{% endwith %} {# Editor payload for the JS: one widget per projected slot (see views._slot_to_widget). #} {# Use Django's json_script so the JSON is safely escaped for a {% endblock javascript %}