DevPlace CI / test (push) Failing after 2m7s
- Add `/block`, `/mute` endpoints with block/unblock and mute/unmute functionality in `routers/relations.py`, hiding blocked users' content everywhere except their own profile while muting only suppresses notifications - Introduce `devplace emoji-sync` CLI command to regenerate `static/js/emoji-shortcodes.js` from the emoji library, documented in `CLAUDE.md` and wired in `cli.py` - Create `get_blocked_uids()` database helper and apply it in `content.py` `load_detail()` to filter blocked users' posts from detail views - Implement `_uid_index()` and `_drop_index()` helpers in `database.py` for unique uid indexes across tables, with `user_relations` added to `SOFT_DELETE_TABLES` - Document new routes in `AGENTS.md` and `README.md`, including emoji shortcodes rendering behavior distinct from the emoji picker
48 lines
2.0 KiB
HTML
48 lines
2.0 KiB
HTML
{% extends "admin_base.html" %}
|
|
{% block extra_head %}
|
|
{{ super() }}
|
|
<link rel="stylesheet" href="{{ static_url('/static/css/bots.css') }}">
|
|
{% endblock %}
|
|
{% block admin_content %}
|
|
<div class="admin-toolbar">
|
|
<h2>Bot Monitor</h2>
|
|
<span class="admin-count" id="bots-count">{{ frames|length }} bots</span>
|
|
</div>
|
|
|
|
{% if not enabled %}
|
|
<p class="admin-empty">The Bots service is not enabled. Enable it on <a href="/admin/services">Services</a> to see live screenshots.</p>
|
|
{% endif %}
|
|
|
|
<div class="bots-grid" id="bots-grid" data-endpoint="/admin/bots/data" role="region" aria-label="Live bot screenshots" aria-live="polite">
|
|
{% for frame in frames %}
|
|
<figure class="bot-card {% if frame['active'] %}bot-active{% else %}bot-idle{% endif %}" data-slot="{{ frame['slot'] }}">
|
|
<span class="sr-only">{% if frame['active'] %}active{% else %}idle{% endif %}</span>
|
|
<div class="bot-shot">
|
|
{% if frame['has_image'] %}
|
|
<img src="{{ frame['frame_url'] }}" alt="Screenshot of bot {{ frame['label'] }}" loading="lazy" data-lightbox>
|
|
<span class="bot-shot-age" data-bot-age data-age-seconds="{{ frame['age_seconds'] }}"></span>
|
|
{% else %}
|
|
<div class="bot-shot-empty">no frame yet</div>
|
|
{% endif %}
|
|
</div>
|
|
<figcaption class="bot-meta">
|
|
<span class="bot-name">{{ frame['label'] }}</span>
|
|
<span class="bot-persona">{{ frame['persona'] or '-' }}</span>
|
|
<span class="bot-action">{{ frame['action'] or frame['status'] or 'idle' }}</span>
|
|
</figcaption>
|
|
</figure>
|
|
{% else %}
|
|
<p class="admin-empty" id="bots-empty">No bots running. Launch the fleet on <a href="/admin/services">Services</a>.</p>
|
|
{% endfor %}
|
|
</div>
|
|
{% endblock %}
|
|
{% block extra_js %}
|
|
<script type="module">
|
|
import { BotMonitor } from "{{ static_url('/static/js/BotMonitor.js') }}";
|
|
const grid = document.getElementById("bots-grid");
|
|
const view = new BotMonitor(grid);
|
|
view.init();
|
|
window.app.botMonitor = view;
|
|
</script>
|
|
{% endblock %}
|