Files
FabledSteward/steward/templates/ansible/inventory/target_detail.html
T
bvandeusenandClaude Opus 5.5 955450d33f
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 55s
CI / unit (push) Successful in 1m22s
CI / publish (push) Successful in 1m36s
fix(ui): section tabs above the breadcrumb, so the Ansible tab strip holds still (#5214)
The tabs were drawn in each page's content block, which base.html renders
after the breadcrumb, so on every nested Ansible page the strip moved down a
line. base.html now has a section_tabs block above the breadcrumb, and every
Ansible page fills it. A guard in test_breadcrumbs.py fails any page that calls
a tabs macro outside that block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 06:28:02 -04:00

76 lines
4.2 KiB
HTML

{# ansible/inventory/target_detail.html — one target (#5333): what it is (its
address, the Steward host it is linked to, its groups, the schedules aimed
at it), its form (operators), and at the foot Delete behind the confirm
dialog. #}
{% extends "base.html" %}
{% from "_macros.html" import crumbs, page_header %}
{% from "ansible/_tabs.html" import ansible_tabs %}
{% block title %}{{ target.name }} — Inventory — Steward{% endblock %}
{% block breadcrumb %}{{ crumbs([("Ansible", "/ansible/"), ("Inventory", "/ansible/inventory/"), (target.name, "")]) }}{% endblock %}
{% block section_tabs %}{{ ansible_tabs("inventory") }}{% endblock %}
{% block content %}
{% set can_edit = session.user_role in ('operator', 'admin') %}
{{ page_header(target.name) }}
<p class="page-verdict">
<span class="mono">{{ target.address }}</span>
· {% if host %}Steward host <a href="/hosts/{{ host.id }}">{{ host.name }}</a>{% else %}<span class="tone-dim">not linked to a Steward host</span>{% endif %}
· {% if target.groups %}in {% for g in target.groups|sort(attribute='name') %}<a href="/ansible/inventory/groups/{{ g.id }}">{{ g.name }}</a>{{ ", " if not loop.last }}{% endfor %}{% else %}<span class="tone-warn">in no group</span>{% endif %}
{%- if used %} · scheduled by {% for s in used %}<a href="/ansible/schedules/{{ s.id }}">{{ s.name }}</a>{{ ", " if not loop.last }}{% endfor %}{% endif %}
</p>
{% if not host %}<p class="field-hint">A target is linked from its host's page, in the Ansible section.</p>{% endif %}
{% if can_edit %}
<form method="post" action="/ansible/inventory/targets/{{ target.id }}" class="form-page">{{ csrf_field() }}
<section class="card form-section" aria-labelledby="tgt-conn">
<h2 id="tgt-conn" class="section-title">Connection</h2>
<div class="form-pair">
<div class="field">
<label class="field-label" for="tgt-name">Name</label>
<input class="input" id="tgt-name" type="text" name="name" value="{{ target.name }}" required>
<span class="field-hint">What plays call it: <code>hosts: {{ target.name }}</code>.</span>
</div>
<div class="field">
<label class="field-label" for="tgt-address">Address</label>
<input class="input mono" id="tgt-address" type="text" name="address" value="{{ target.address }}" required>
<span class="field-hint">Becomes <code>ansible_host</code>.</span>
</div>
</div>
<div class="field">
<label class="field-label" for="tgt-vars">Variables</label>
<textarea class="input mono" id="tgt-vars" name="ansible_vars" rows="6"
placeholder="ansible_user: ubuntu&#10;ansible_port: 22">{{ ansible_vars_yaml }}</textarea>
<span class="field-hint">YAML. These override its groups' variables for this target only.</span>
</div>
</section>
<section class="card form-section" aria-labelledby="tgt-groups">
<h2 id="tgt-groups" class="section-title">Groups</h2>
{% if not all_groups %}
<p class="tone-muted">No groups yet. <a href="/ansible/inventory/?add=group">Add a group</a> first.</p>
{% else %}
<div class="check-list">
{% for grp in all_groups %}
<label class="field-check">
<input type="checkbox" name="group_ids" value="{{ grp.id }}" {% if grp.id in member_group_ids %}checked{% endif %}>
<span>{{ grp.name }}</span>
</label>
{% endfor %}
</div>
{% endif %}
</section>
<button type="submit" class="btn">Save</button>
</form>
<section class="danger-zone" aria-labelledby="tgt-delete">
<h2 id="tgt-delete" class="section-title">Delete this target</h2>
<p class="field-hint">{% if used %}{{ used|length }} schedule{{ 's' if used|length != 1 }} run{{ 's' if used|length == 1 }} on it alone and would find nothing to run on.{% else %}It leaves its groups; its past runs stay in the Runs list.{% endif %}</p>
<form method="post" action="/ansible/inventory/targets/{{ target.id }}/delete"
data-confirm="Delete target {{ target.name }}? {% if used %}{{ used|length }} schedule{{ 's' if used|length != 1 }} aimed at it would find nothing to run on.{% else %}It leaves its groups; its past runs stay in the list.{% endif %}">{{ csrf_field() }}
<button class="btn btn-danger" type="submit">Delete target</button>
</form>
</section>
{% endif %}
{% endblock %}