{% load i18n %} {% load static %} {% load rack_design %} {# ------------------------------------------------------------------------- #} {# Shared per-rack block: one rack rendered with BOTH its Front and Rear #} {# faces side by side, full-depth opposite-face hatch and the hover-card #} {# data-* attributes. Used by BOTH the interactive editor #} {# (design_editor.html, editable=True) and the read-only projected elevation #} {# (design_elevation.html, editable=False) so the two can never drift apart. #} {# #} {# Context: #} {# b the per-rack bundle from views._project_rack_bundle: #} {# {rack, front, rear, non_racked, widgets, rack_meta, hidden?} #} {# editable True -> editor affordances (drag grids, per-tile × remove, #} {# embedded widget JSON payload for editor.js). #} {# False -> static, read-only (locked tiles, no remove buttons, #} {# no JSON payload). View-only Front/Rear toggles + the #} {# hover card still work. #} {# #} {# Widget indices (editor only): the page builds `widgets` in the order #} {# (*front, *rear, *non_racked); each tile is stamped with its GLOBAL index #} {# via gs-id/data-widget-index so editor.js can pair JSON to DOM. #} {# ------------------------------------------------------------------------- #} {% with rack=b.rack front=b.front rear=b.rear non_racked=b.non_racked %} {% with front_len=front|length rear_len=rear|length %} {% with rid=rack.pk|stringformat:"s" %}
{# ---- Per-rack header: name + site/location + face toggles ---- #}
{{ rack.name }} {% if rack.location %}· {{ rack.location }} {% elif rack.site %}· {{ rack.site }}{% endif %}
{# Independent on/off toggles per rack: each shows/hides its OWN face. #} {# Both start active; the JS refuses to hide the last visible face. #}
{# ---- Rack faces: Front + Rear side by side (independent toggles). ---- #}
{# ---- Front face ---- #}

{% trans "Front" %}

    {% for u in rack.units %}
  • {% if u|rack_whole_unit %}{{ u|floatformat:"0" }}{% endif %}
  • {% endfor %}
{% for slot in front %}
{% if editable and not slot.opposite_face %}{% endif %} {{ slot.label }}
{% endfor %}
{# ---- Rear face ---- #}

{% trans "Rear" %}

    {% for u in rack.units %}
  • {% if u|rack_whole_unit %}{{ u|floatformat:"0" }}{% endif %}
  • {% endfor %}
{% for slot in rear %}
{% if editable and not slot.opposite_face %}{% endif %} {{ slot.label }}
{% endfor %}
{# /.nbx-rd-faces #} {# ---- Per-rack non-racked tray ---- #} {# Editor: always shown as a drop target. Read-only: shown only when there #} {# are non-racked placements (no empty drop affordance in view mode). #} {% if editable or non_racked %}

{% trans "Non-racked tray" %}

{% for slot in non_racked %} {# The tray is a LIST (spec §9.2/§9.4), not a grid with meaningful #} {# rows: every item gets its own sequential row (index * 2, since #} {# every tray tile is a fixed gs-h="2") so items never overlap and #} {# the container grows to fit -- server-render order first, session #} {# drops append after (see editor.js's tray "dropped" handler). #}
{% if editable %}{% endif %} {{ slot.label }}
{% endfor %}
{% endif %} {# Per-rack editor payload (editor only): one widget per projected slot, #} {# keyed by the rack pk so editor.js can hydrate each block independently. #} {% if editable %}{% with eid="rd-editor-data-"|add:rid %}{{ b.widgets|json_script:eid }}{% endwith %}{% endif %}
{# /.nbx-rd-rack-block #} {% endwith %}{% endwith %}{% endwith %}