File indexing completed on 2026-04-28 07:24:56
0001 {% extends 'base.html' %}
0002 {% load static %}
0003 {% load swf_fmt %}
0004
0005 {% block title %}{{ label }} — {{ alarm_entry_id }} — Alarms{% endblock %}
0006
0007 {% block content %}
0008 <link rel="stylesheet" href="{% static 'css/state-colors.css' %}">
0009 <style>
0010 .bin-strip {
0011 display: flex; flex-wrap: wrap; gap: 6px 10px;
0012 padding: 10px 12px; background: #f3f3f3;
0013 border: 1px solid #ddd; border-radius: 4px;
0014 max-width: 1200px;
0015 }
0016 .hour-group {
0017 display: flex; flex-direction: column; align-items: center;
0018 gap: 3px;
0019 }
0020 .hour-group .bins { display: flex; gap: 1px; }
0021 .hour-group .hlabel {
0022 font-size: 10px; color: #555; font-family: "SF Mono", Monaco, Menlo, monospace;
0023 line-height: 1; white-space: nowrap;
0024 }
0025 .hour-group .dlabel {
0026 font-size: 10px; color: #888; font-family: "SF Mono", Monaco, Menlo, monospace;
0027 line-height: 1; white-space: nowrap;
0028 }
0029 .bin {
0030 width: 7px; height: 20px; border-radius: 1px; cursor: help;
0031 flex: 0 0 auto;
0032 }
0033 .bin.firing { background: #c0392b; }
0034 .bin.clear { background: #2e9a54; }
0035 .bin.unknown { background: #b0b0b0; }
0036 .strip-legend { font-size: 0.85em; color: #666; margin-top: 6px; }
0037 .strip-legend .swatch {
0038 display: inline-block; width: 14px; height: 12px; vertical-align: middle;
0039 border-radius: 2px; margin-right: 4px; border: 1px solid rgba(0,0,0,.08);
0040 }
0041 </style>
0042
0043 <div class="container mt-3" style="max-width: 1200px;">
0044 <p><a href="{% url 'monitor_app:alarms_dashboard' %}">← All alarms</a></p>
0045
0046 <h2 class="mb-1">{{ label }}</h2>
0047 <div class="text-muted mb-3">
0048 alarm: <code>{{ alarm_entry_id }}</code>
0049 · <a href="{% url 'monitor_app:alarm_config_edit' entry_id=alarm_entry_id %}">{{ alarm_title }}</a>
0050 · since last {{ hours }}h
0051 </div>
0052
0053 <h3 style="font-size:1em;">Alarm state, per engine tick</h3>
0054 {% if bin_groups %}
0055 <div class="bin-strip">
0056 {% for grp in bin_groups %}
0057 <div class="hour-group">
0058 <div class="bins">
0059 {% for b in grp.bins %}
0060 <div class="bin {{ b.state }}"
0061 title="{{ b.tick|fmt_dt }} — {{ b.state }}"></div>
0062 {% endfor %}
0063 </div>
0064 <div class="hlabel">{{ grp.label }}</div>
0065 {% if grp.date_change %}<div class="dlabel">{{ grp.date }}</div>{% endif %}
0066 </div>
0067 {% endfor %}
0068 </div>
0069 <div class="strip-legend">
0070 <span class="swatch" style="background:#2e9a54;"></span>clear
0071 ·
0072 <span class="swatch" style="background:#c0392b;"></span>firing
0073 ·
0074 <span class="swatch" style="background:#b0b0b0;"></span>no data / errored tick
0075 ·
0076 {{ bins|length }} tick{{ bins|length|pluralize }} ·
0077 left = oldest, right = newest ·
0078 each cell = one engine tick (5 min)
0079 </div>
0080 {% else %}
0081 <p class="text-muted">No engine ticks in the last {{ hours }}h.</p>
0082 {% endif %}
0083
0084 <h3 style="font-size:1em;" class="mt-4">Events for this entity</h3>
0085 {% if events %}
0086 {% for ev in events %}
0087 <div class="card mb-3" style="max-width:1100px;">
0088 <div class="card-header d-flex justify-content-between align-items-center">
0089 <div>
0090 <span class="{% if ev.state == 'active' %}failed_fill{% else %}paused_fill{% endif %}"
0091 style="font-size:0.75em; padding:2px 10px; border-radius:3px; font-weight:500;">{{ ev.state }}</span>
0092 <strong class="ms-2">{{ ev.subject }}</strong>
0093 </div>
0094 <div class="text-muted" style="font-size:0.85em;">
0095 fired {{ ev.fire_time|fmt_dt }}
0096 · {% if ev.clear_time %}cleared {{ ev.clear_time|fmt_dt }}{% else %}still active{% endif %}
0097 </div>
0098 </div>
0099 <div class="card-body">
0100 {% if ev.content %}
0101 <div style="margin-bottom: 1em;">
0102 <div class="text-muted" style="font-size:0.82em; text-transform:uppercase; letter-spacing:0.05em; margin-bottom:4px;">Description / email body</div>
0103 <pre style="white-space:pre-wrap; margin:0; background:#f3f3f3; padding:10px 14px; border-radius:4px;">{{ ev.content }}</pre>
0104 </div>
0105 {% endif %}
0106 {% if ev.context_data %}
0107 <div>
0108 <div class="text-muted" style="font-size:0.82em; text-transform:uppercase; letter-spacing:0.05em; margin-bottom:4px;">Context data</div>
0109 <table class="table table-sm mb-0" style="max-width:900px;">
0110 <tbody>
0111 {% for k, v in ev.context_data.items %}
0112 <tr>
0113 <th style="width:240px; font-weight:500;"><code>{{ k }}</code></th>
0114 {% if k == 'status' %}
0115 <td class="{{ v|state_class }}">{{ v }}</td>
0116 {% else %}
0117 <td>{{ v }}</td>
0118 {% endif %}
0119 </tr>
0120 {% endfor %}
0121 </tbody>
0122 </table>
0123 </div>
0124 {% endif %}
0125 </div>
0126 </div>
0127 {% endfor %}
0128 {% else %}
0129 <p class="text-muted">No events in the last {{ hours }}h.</p>
0130 {% endif %}
0131 </div>
0132 {% endblock %}