{% extends 'generic/object.html' %} {% load helpers %} {% load plugins %} {% load i18n %} {% block content %}

{% trans "Design" %}

{% trans "Title" %} {{ object.title }}
{% trans "Site" %} {{ object.site|linkify }}
{% trans "Status" %} {% badge object.get_status_display bg_color=object.get_status_color %}
{% trans "Summary" %} {{ object.summary|placeholder }}
{% trans "Link" %} {% if object.link %} {{ object.link }} {% else %} {{ ''|placeholder }} {% endif %}
{% trans "Group" %} {{ object.group|linkify|placeholder }}

{% trans "Versioning & Sequencing" %}

{% trans "Version" %} v{{ object.version }}
{% trans "Based on" %} {{ object.based_on|linkify|placeholder }}
{% trans "Sequence" %} {{ object.sequence }}
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/comments.html' %} {% plugin_left_page object %}

{% trans "Dependencies" %}

{% trans "Depends on" %} {% with deps=object.depends_on.all %} {% if deps %}
    {% for dep in deps %}
  • {{ dep|linkify }}
  • {% endfor %}
{% else %} {{ ''|placeholder }} {% endif %} {% endwith %}
{% trans "Required by" %} {% with rev=object.dependents.all %} {% if rev %}
    {% for dep in rev %}
  • {{ dep|linkify }}
  • {% endfor %}
{% else %} {{ ''|placeholder }} {% endif %} {% endwith %}
{# ---------------------------------------------------------------- #} {# LINEAGE (design chains, PLAN-design-chains.md §2). Distinct from #} {# the "Dependencies" card above: that card is the depends_on / #} {# dependents M2M, an informational "must run after" edge that does #} {# NOT affect projection. This card is the based_on tree -- the #} {# layer stack a design's projection actually inherits (§2.1) -- plus #} {# the freeze / un-approve consequences of being part of one (§2.2) #} {# and the re-base warning of §9.2. #} {# ---------------------------------------------------------------- #}
{% with ancestors=object.baseline_chain children=object.children %}

{% trans "Design chain" %} {{ children|length }} {% if perms.netbox_rack_design.add_design or perms.netbox_rack_design.change_design %}
{# Derive: only meaningful from an APPROVED design -- DesignDeriveView #} {# itself refuses otherwise (§2.2) -- and only offered to a user who #} {# can create the resulting design (add_design). #} {% if object.is_frozen and perms.netbox_rack_design.add_design %} {% trans "Derive design" %} {% endif %} {# Re-base: edits THIS design's own based_on, so it only needs #} {# change_design -- shown regardless of frozen state, since a #} {# draft design re-bases just as often as an approved one. #} {% if perms.netbox_rack_design.change_design %} {% trans "Re-base" %} {% endif %}
{% endif %}

{% if not ancestors and not children %}
{% trans "This design stands alone — it has no parent and nothing is based on it." %}
{% else %}
{% trans "Parent" %} {% if object.based_on %} {{ object.based_on|linkify }} {% badge object.based_on.get_status_display bg_color=object.based_on.get_status_color %} {% else %} {{ ''|placeholder }} {% endif %}
{% trans "Ancestor stack" %} {% if ancestors %}
    {% for ancestor in ancestors %}
  1. {{ ancestor|linkify }} {% badge ancestor.get_status_display bg_color=ancestor.get_status_color %} {% if forloop.last %} {% trans "(immediate parent — the only editable relation)" %} {% endif %}
  2. {% endfor %}
{% else %} {{ ''|placeholder }} {% endif %}
{% trans "Children" %} {% if children %}
    {% for child in children %}
  • {{ child|linkify }} {% badge child.get_status_display bg_color=child.get_status_color %}
  • {% endfor %}
{% else %} {{ ''|placeholder }} {% endif %}
{% for ancestor in ancestors %} {% if ancestor.status == "implemented" %} {% endif %} {% endfor %} {% endif %} {% endwith %}
{% include 'inc/panels/tags.html' %} {% plugin_right_page object %}

{% trans "Placements" %} {% if perms.netbox_rack_design.add_designplacement %} {% endif %}

{% htmx_table 'plugins:netbox_rack_design:designplacement_list' design_id=object.pk %}

{% trans "Racks" %} {% if scoped_racks or perms.netbox_rack_design.change_design %}
{% if scoped_racks %} {% trans "View elevation" %} {% endif %} {% if perms.netbox_rack_design.change_design %} {# Targets the default (no-rack) editor route so it works even when #} {# the design has no scoped racks yet (add the first rack inside). #} {% trans "Open editor" %} {% endif %}
{% endif %}

{% for rack in scoped_racks %} {% empty %} {% endfor %}
{% trans "Rack" %} {% trans "Site" %} {% trans "Location" %} {% trans "Actions" %}
{{ rack|linkify }} {{ rack.site|linkify|placeholder }} {{ rack.location|linkify|placeholder }} {% trans "View elevation" %} {% if perms.netbox_rack_design.change_design %} {% trans "Edit layout" %} {% endif %}
{% trans "No racks in scope yet" %}
{# ------------------------------------------------------------------------ #} {# STALE placements: their real device was deleted from DCIM. A stale row is #} {# inert (projection.py filters device__isnull=False for move/remove), so it #} {# renders nowhere else -- this panel is the only place the loss is visible. #} {# ------------------------------------------------------------------------ #}

{% trans "Stale placements" %} {{ stale_placements|length }}

{% for placement in stale_placements %} {% empty %} {% endfor %}
{% trans "Deleted device" %} {% trans "Kind" %} {% trans "Target rack" %} {% trans "Proposed name" %} {% trans "Actions" %}
{{ placement.stale_device_name }} {% badge placement.get_kind_display bg_color=placement.get_kind_color %} {{ placement.target_rack|linkify|placeholder }} {{ placement.proposed_name|placeholder }} {% if perms.netbox_rack_design.change_designplacement %} {% endif %} {% if perms.netbox_rack_design.delete_designplacement %} {% endif %}
{% trans "No stale placements — every planned device still exists in DCIM." %}
{# ------------------------------------------------------------------------ #} {# PLANNED power feeds. They are written by the rack-power "copy from rack" #} {# dialog and the PDU bind dialog, and they SIZE a greenfield rack's capacity #} {# bar -- so a stray one silently inflates it. Until now they had no UI at #} {# all; this panel is where a plan shows its own supply. #} {# ------------------------------------------------------------------------ #}

{% trans "Planned power feeds" %} {{ planned_feeds|length }}

{% for row in planned_feeds %} {# A planned feed is now an object of its own, so it can be #} {# corrected or removed without hunting through the editor. #} {% empty %} {% endfor %}
{% trans "Rack" %} {% trans "Feed" %} {% trans "Supply" %} {% trans "Capacity" %} {% trans "Bound PDUs" %} {% trans "Actions" %}
{{ row.rack|linkify }} {{ row.feed|linkify }} {{ row.feed.voltage }} V · {{ row.feed.amperage }} A · {{ row.feed.get_phase_display }} · {{ row.feed.get_supply_display }} {{ row.watts }} W {% for placement in row.bound %} {{ placement.proposed_name|default:placement }}{% if not forloop.last %}, {% endif %} {% empty %} {% trans "none" %} {% endfor %} {% if perms.netbox_rack_design.change_designpowerfeed %} {% endif %} {% if perms.netbox_rack_design.delete_designpowerfeed %} {% endif %}
{% trans "No planned feeds — this design's racks are sized from their real feeds." %}

{% trans "Affected racks" %}

{% for rack in affected_racks %} {% empty %} {% endfor %}
{% trans "Rack" %} {% trans "Site" %} {% trans "Actions" %}
{{ rack|linkify }} {{ rack.site|linkify|placeholder }} {% trans "View elevation" %} {% if perms.netbox_rack_design.change_design %} {% trans "Edit layout" %} {% endif %}
{% trans "No racks affected yet" %}
{% plugin_full_width_page object %}
{% endblock content %}