1{# Observer pill + record dot, visually semi-attached #}
  2<div class="inline-flex items-center gap-px">
  3
  4{# Record dot โ€” separate clickable circle, tight against the pill #}
  5{% if observer.is_summarizing() or observer.is_persist_once() %}
  6<button
  7    type="button"
  8    class="inline-flex items-center justify-center cursor-pointer rounded-full px-1.5 py-px bg-white/8 text-white/30 hover:text-red-400 hover:bg-white/12 transition-colors self-stretch"
  9    data-observer-record-page
 10    title="Record this page"
 11>
 12    <svg class="size-1.5" viewBox="0 0 16 16" fill="currentColor">
 13        <circle cx="8" cy="8" r="8"/>
 14    </svg>
 15</button>
 16{% endif %}
 17
 18{# Request pill โ€” observer state + request stats, clickable to open Observer panel #}
 19<button
 20    type="button"
 21    class="inline-flex items-center cursor-pointer text-xs rounded-full px-1 py-px bg-white/8 text-white/80 hover:bg-white/12 overflow-hidden divide-x divide-white/10 [&>span]:px-1.5"
 22    data-toolbar-tab="Observer"
 23>
 24    {% if observer.is_recording_session() %}
 25    <span class="inline-flex items-center">
 26        <span class="relative inline-flex size-1.5 mr-1.5 flex-shrink-0">
 27            <span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-red-400 opacity-75"></span>
 28            <span class="relative inline-flex size-1.5 rounded-full bg-red-500"></span>
 29        </span>
 30        <span class="text-[11px]">Recording</span>
 31    </span>
 32    {% elif not observer.is_enabled() %}
 33    <span class="inline-flex items-center gap-1.5">
 34        <span class="rounded-full bg-zinc-500 size-1.5 flex-shrink-0"></span>
 35        <span class="text-[11px]">Disabled</span>
 36    </span>
 37    {% endif %}
 38
 39    {% if trace_stats %}
 40    <span
 41        class="text-[11px] text-white/50
 42               data-[level=warn]:text-amber-400
 43               data-[level=danger]:text-red-400"
 44        title="SQL queries"
 45        {% if trace_stats.query_level != "ok" %}data-level="{{ trace_stats.query_level }}"{% endif %}
 46    >{{ trace_stats.query_count }}{% if trace_stats.duplicate_count %}+{{ trace_stats.duplicate_count }}{% endif %} {{ "query" if trace_stats.query_count == 1 else "queries" }}</span>
 47    {% if trace_stats.duration_display %}
 48    <span
 49        class="text-[11px] text-white/50
 50               data-[level=warn]:text-amber-400
 51               data-[level=danger]:text-red-400"
 52        title="Request duration"
 53        {% if trace_stats.duration_level != "ok" %}data-level="{{ trace_stats.duration_level }}"{% endif %}
 54    >{{ trace_stats.duration_display }}</span>
 55    {% endif %}
 56    {% endif %}
 57
 58    <span
 59        data-observer-response-size
 60        class="hidden text-[11px] text-white/50
 61               data-[level=warn]:text-amber-400
 62               data-[level=danger]:text-red-400"
 63        title="Response body size"
 64        data-observer-response-size-value
 65    ></span>
 66</button>
 67
 68{% if system_stats %}
 69{# System pill โ€” CPU and memory, non-interactive #}
 70<span class="inline-flex items-center text-xs rounded-full px-1 py-px bg-white/8 overflow-hidden divide-x divide-white/10 [&>span]:px-1.5">
 71    {% if system_stats.cpu_percent is defined %}
 72    <span class="items-baseline text-[11px] tabular-nums" title="Server process CPU usage">
 73        <span class="text-[9px] text-white/30 mr-0.5">CPU</span>
 74        <span
 75            class="text-white/50
 76                   data-[level=warn]:text-amber-400
 77                   data-[level=danger]:text-red-400"
 78            {% if system_stats.cpu_level != "ok" %}data-level="{{ system_stats.cpu_level }}"{% endif %}
 79        >{{ system_stats.cpu_percent }}%</span>
 80    </span>
 81    {% endif %}
 82    {% if system_stats.mem_display %}
 83    <span class="items-baseline text-[11px] tabular-nums" title="{{ system_stats.mem_title }}">
 84        <span class="text-[9px] text-white/30 mr-0.5">MEM</span>
 85        <span
 86            class="text-white/50
 87                   data-[level=warn]:text-amber-400
 88                   data-[level=danger]:text-red-400"
 89            {% if system_stats.mem_level != "ok" %}data-level="{{ system_stats.mem_level }}"{% endif %}
 90        >{{ system_stats.mem_display }}</span>
 91    </span>
 92    {% endif %}
 93</span>
 94{% endif %}
 95
 96</div>
 97
 98<script nonce="{{ request.csp_nonce }}">
 99(function() {
100    function formatBytes(bytes) {
101        if (bytes >= 1000000) return (bytes / 1000000).toFixed(1) + " MB";
102        if (bytes >= 1000) return Math.round(bytes / 1000) + " KB";
103        return bytes + " B";
104    }
105
106    window.addEventListener("load", function() {
107        var nav = performance.getEntriesByType("navigation")[0];
108        var el = document.querySelector("[data-observer-response-size]");
109        if (nav && nav.decodedBodySize > 0 && el) {
110            el.textContent = formatBytes(nav.decodedBodySize);
111            if (nav.decodedBodySize >= 1000000) {
112                el.dataset.level = "danger";
113            } else if (nav.decodedBodySize >= 100000) {
114                el.dataset.level = "warn";
115            }
116            el.classList.remove("hidden");
117        }
118    });
119
120    const recordBtn = document.querySelector("[data-observer-record-page]");
121
122    {% if observer.is_persist_once() %}
123    // Revert persist_once cookie back to summary, then re-enable record button
124    const revertForm = new FormData();
125    revertForm.append("observe_action", "summary");
126    if (recordBtn) recordBtn.disabled = true;
127    fetch("{{ url('observer:traces') }}", {
128        method: "POST",
129        body: revertForm,
130        credentials: "same-origin"
131    }).then(function() {
132        if (recordBtn) recordBtn.disabled = false;
133    });
134
135    window.addEventListener("load", function() {
136        if (window.plainToolbar) {
137            window.plainToolbar.showTab("Observer");
138        }
139    });
140    {% endif %}
141
142    if (recordBtn) {
143        recordBtn.addEventListener("click", function(e) {
144            e.stopPropagation();
145            recordBtn.style.color = "#f87171";
146            recordBtn.disabled = true;
147            const form = new FormData();
148            form.append("observe_action", "persist_once");
149            fetch("{{ url('observer:traces') }}", {
150                method: "POST",
151                body: form,
152                credentials: "same-origin"
153            }).then(function() {
154                window.location.reload();
155            });
156        });
157    }
158})();
159</script>