heartwood every commit a ring
6.0 KB raw
{% extends "base.html" %}

{% block extra_css %}
<link rel="stylesheet" href="{{ vite_asset('static_src/properties/index.js', 'css') }}">
{% endblock %}

{% block breadcrumbs %}
<nav aria-label="breadcrumb">
  <ol class="breadcrumb mb-0">
    <li class="breadcrumb-item"><a href="/">Home</a></li>
    <li class="breadcrumb-item active" aria-current="page">{{ title }}</li>
  </ol>
</nav>
{% endblock %}

{% block main %}
<div class="container my-4">
  <div class="row align-items-center g-3 mb-4">
    <div class="col-md-5">
      <div class="section-label mb-1">operator</div>
      <h1 class="fw-bolder text-white mb-0" style="letter-spacing: -0.01em;">{{ title }}</h1>
      <p class="text-muted mb-0 small mt-1">Every URL you've registered, current probe state, and audit signals.</p>
    </div>
    <div class="col-md-7">
      <div class="dashboard-toolbar">
        <form method="get" class="search-form flex-grow-1">
          <input type="text" class="form-control search-input" name="q" id="id_search" placeholder="grep properties..."{% if q %} value="{{ q }}"{% endif %} />
        </form>
        <button class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePropertyAdd" aria-expanded="false" aria-controls="collapsePropertyAdd">
          + new
        </button>
      </div>
    </div>
  </div>

  <div class="collapse mb-4" id="collapsePropertyAdd">
    <div class="bg-surface border-subtle rounded border p-3">
      <div class="section-label mb-2">register property</div>
      <p class="text-muted small mb-3">Any public URL. Probe begins within 3 minutes.</p>
      <form method="POST" action="{{ url_for('properties') }}" class="dashboard-toolbar">
        <input type="url" name="url" id="id_url" class="form-control flex-grow-1" placeholder="https://example.com" required>
        <button type="submit" class="btn btn-primary">Add →</button>
      </form>
    </div>
  </div>

  <div class="section-label mb-2">registered properties</div>
  {% for property in properties %}
    <div class="property-row {% if property.current_status != 200 %}is-down{% endif %}">
      <div class="pr-main">
        <div class="pr-title">
          <span class="status-dot {% if property.current_status == 200 %}is-up{% else %}is-down{% endif %}" aria-hidden="true"></span>
          <a href="/{{ property.id }}" class="text-truncate">{{ property.name }}</a>
        </div>
        <div class="pr-url">{{ property.url }}</div>
        <div class="uptime-strip" aria-label="Recent checks">
          {% for tick in property.recent_tick_stream %}
            <span class="uptime-tick is-{{ tick }}"></span>
          {% else %}
            {% for i in range(30) %}<span class="uptime-tick is-none"></span>{% endfor %}
          {% endfor %}
        </div>
      </div>
      <div class="pr-side">
        <div class="pr-meta">
          <div class="pr-meta-cell">
            <span class="pr-meta-k">status</span>
            {% if property.current_status == 200 %}
              <span class="chip chip-ok">ok · 200</span>
            {% else %}
              <span class="chip chip-down">down · {{ property.current_status }}</span>
            {% endif %}
          </div>
          <div class="pr-meta-cell">
            <span class="pr-meta-k">uptime</span>
            {% if property.recent_uptime_pct is not none %}
              {% if property.recent_uptime_pct >= 99 %}
                <span class="chip chip-ok">{{ property.recent_uptime_pct }}%</span>
              {% elif property.recent_uptime_pct < 95 %}
                <span class="chip chip-down">{{ property.recent_uptime_pct }}%</span>
              {% else %}
                <span class="chip chip-warn">{{ property.recent_uptime_pct }}%</span>
              {% endif %}
            {% else %}
              <span class="chip chip-muted">—</span>
            {% endif %}
          </div>
          <div class="pr-meta-cell">
            <span class="pr-meta-k">sec</span>
            {% if property.has_security_issue %}
              <span class="chip chip-warn">issues</span>
            {% else %}
              <span class="chip chip-ok">ok</span>
            {% endif %}
          </div>
          <div class="pr-meta-cell">
            <span class="pr-meta-k">seo</span>
            {% set insights = property.crawler_insights | length %}
            {% if insights > 100 %}
              <span class="chip chip-down">{{ insights }}</span>
            {% elif insights > 25 %}
              <span class="chip chip-warn">{{ insights }}</span>
            {% else %}
              <span class="chip chip-ok">{{ insights }}</span>
            {% endif %}
          </div>
          <div class="pr-meta-cell">
            <span class="pr-meta-k">lh</span>
            {% if property.avg_lighthouse_score %}
              {% if property.avg_lighthouse_score >= 90 %}
                <span class="chip chip-ok">{{ property.avg_lighthouse_score }}%</span>
              {% elif property.avg_lighthouse_score >= 80 %}
                <span class="chip chip-warn">{{ property.avg_lighthouse_score }}%</span>
              {% else %}
                <span class="chip chip-down">{{ property.avg_lighthouse_score }}%</span>
              {% endif %}
            {% else %}
              <span class="chip chip-muted">—</span>
            {% endif %}
          </div>
        </div>
        <div class="pr-actions">
          {% if not property.is_protected %}
          <form method="POST" action="/properties/{{ property.id }}/delete" class="d-inline" onsubmit="return confirm('Delete {{ property.url }} and all its checks?');">
            <button type="submit" class="btn btn-sm btn-outline-danger">Delete</button>
          </form>
          {% endif %}
          <a href="/{{ property.id }}" class="btn btn-sm btn-outline-light">View →</a>
        </div>
      </div>
    </div>
  {% else %}
    <div class="text-center py-5 text-muted">
      <div class="section-label mb-3" style="justify-content:center;">no properties yet</div>
      <p class="mb-0 small">Click <strong>+ new</strong> above to register your first URL.</p>
    </div>
  {% endfor %}
</div>
{% endblock %}