trust_list.html 187 lignes · 8240 octets
{% extends "base.html" %}

{% block title %}{{ page_title }}{% endblock %}

{% block navbar %}
{% include "components/navbar.html" %}
{% endblock %}

{% block content %}
<div class="container mx-auto px-4 py-8" x-data="fediversePage" data-saved="{% if saved_flash %}true{% else %}false{% endif %}">

    {# Breadcrumb #}
    <nav class="text-sm breadcrumbs mb-6" aria-label="breadcrumb">
        <ul>
            <li><a href="/">{{ breadcrumb_home }}</a></li>
            <li><a href="/admin">{{ breadcrumb_admin }}</a></li>
            <li><a href="/admin/fediverse">{{ breadcrumb_federation }}</a></li>
            <li aria-current="page">{{ breadcrumb_self }}</li>
        </ul>
    </nav>

    {% include "components/admin_tabs.html" %}

    {# Page header #}
    <header class="mb-2">
        <h1 class="text-3xl font-bold mb-2">{{ heading }}</h1>
        <p class="text-base-content/70">{{ subtitle }}</p>
    </header>

    {# Mode indicator badge #}
    <div class="mb-6">
        <span class="badge {% if is_blocklist %}badge-warning{% else %}badge-success{% endif %} badge-lg">
            {{ mode_indicator }}
        </span>
    </div>

    {# Toast on save (Plan UI §3 P3) #}
    <div
        x-show="saved"
        x-transition
        role="status"
        aria-live="polite"
        class="alert alert-success mb-6"
    >
        <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
        <span>{{ saved_toast }}</span>
    </div>

    {# Add form #}
    <section class="card bg-base-100 shadow-xl mb-8" aria-labelledby="add-legend">
        <div class="card-body">
            <h2 id="add-legend" class="card-title text-xl mb-4">{{ add_form_legend }}</h2>
            <form method="POST" action="/admin/fediverse/trust_list/add" class="space-y-4">
                <input type="hidden" name="csrf_token" value="{{ csrf_token }}">

                <div class="form-control">
                    <label class="label" for="trust-domain">
                        <span class="label-text font-semibold">{{ domain_label }}</span>
                    </label>
                    <input
                        id="trust-domain"
                        type="text"
                        name="domain"
                        required
                        autocomplete="off"
                        class="input input-bordered w-full max-w-md"
                        placeholder="{{ domain_placeholder }}"
                    >
                </div>

                <div class="form-control">
                    <label class="label" for="trust-note">
                        <span class="label-text font-semibold">
                            {% if is_blocklist %}{{ reason_label }}{% else %}{{ note_label }}{% endif %}
                        </span>
                    </label>
                    <input
                        id="trust-note"
                        type="text"
                        name="note_or_reason"
                        autocomplete="off"
                        class="input input-bordered w-full max-w-md"
                    >
                </div>

                {% if is_blocklist %}
                <div class="form-control">
                    <label class="label" for="trust-severity">
                        <span class="label-text font-semibold">{{ severity_label }}</span>
                    </label>
                    <select
                        id="trust-severity"
                        name="severity"
                        required
                        class="select select-bordered w-full max-w-md"
                    >
                        <option value="suspend">{{ severity_suspend }}</option>
                        <option value="silence">{{ severity_silence }}</option>
                        <option value="reject_auth">{{ severity_reject_auth }}</option>
                    </select>
                </div>
                {% endif %}

                <div class="flex justify-end">
                    <button type="submit" class="btn btn-primary">{{ add_button }}</button>
                </div>
            </form>
        </div>
    </section>

    {# Table or empty state #}
    {% if has_entries %}
    <section class="card bg-base-100 shadow-xl">
        <div class="card-body">
            <div class="overflow-x-auto">
                <table class="table table-zebra">
                    <thead>
                        <tr>
                            <th>{{ table_domain }}</th>
                            <th>{{ table_note_or_reason }}</th>
                            {% if is_blocklist %}<th>{{ table_severity }}</th>{% endif %}
                            <th>{{ table_created_at }}</th>
                            <th class="text-right">{{ table_actions }}</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for entry in entries %}
                        <tr>
                            <td class="font-mono">{{ entry.domain }}</td>
                            <td>{% if entry.has_note_or_reason %}{{ entry.note_or_reason }}{% else %}—{% endif %}</td>
                            {% if is_blocklist %}<td>{{ entry.severity }}</td>{% endif %}
                            <td class="text-base-content/70">{{ entry.created_at }}</td>
                            <td class="text-right">
                                <button
                                    type="button"
                                    class="btn btn-sm btn-ghost text-error"
                                    @click="deleteTarget = '{{ entry.domain }}'"
                                    aria-haspopup="dialog"
                                >
                                    {{ delete_button }}
                                </button>
                            </td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </section>
    {% else %}
    {# Empty state (Plan UI §3 P4) #}
    <section class="card bg-base-200 shadow-inner" aria-label="empty-state">
        <div class="card-body items-center text-center py-16">
            <svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 text-base-content/30 mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /></svg>
            <h3 class="text-lg font-semibold">{{ empty_title }}</h3>
            <p class="text-base-content/70 max-w-md">{{ empty_body }}</p>
        </div>
    </section>
    {% endif %}

    {# Confirmation modal (Plan UI §3 P2). Triggered by `deleteTarget`. #}
    <dialog
        class="modal"
        :class="{ 'modal-open': deleteTarget !== null }"
        role="alertdialog"
        aria-labelledby="confirm-title"
        aria-describedby="confirm-body"
    >
        <div class="modal-box">
            <h3 id="confirm-title" class="font-bold text-lg">{{ delete_confirm_title }}</h3>
            <p id="confirm-body" class="py-4">
                {{ delete_confirm_body }}
                <span class="font-mono block mt-2" x-text="deleteTarget"></span>
            </p>
            <form method="POST" action="/admin/fediverse/trust_list/delete" class="modal-action">
                <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
                <input type="hidden" name="domain" :value="deleteTarget">
                <button type="button" class="btn btn-ghost" @click="deleteTarget = null">{{ modal_cancel }}</button>
                <button type="submit" class="btn btn-error">{{ modal_confirm }}</button>
            </form>
        </div>
        <form method="dialog" class="modal-backdrop">
            <button type="button" @click="deleteTarget = null" aria-label="close">close</button>
        </form>
    </dialog>
</div>
{% endblock %}