{% load humanize %} {% comment %} The subscriber panel: who is on the sequence, and the manual add/remove SPEC §12 asks for. The contact is named by id in the POST body rather than in the URL, so tests/idor.py — which walks URL kwargs — cannot reach the lookup. It is scoped in the view and covered by a direct cross-tenant test, the same arrangement apps/contacts/views.py::_selected documents for the bulk endpoints. {% endcomment %}

Subscribers

{% if can_edit %} {% comment %} A typeahead rather than a form, matching contacts/_tag_chips.html: a plain htmx GET into a results list, and each result POSTs the id it names. There is no submit button because there is nothing to submit — picking a name is the action. {% endcomment %}

Or subscribe people in bulk from the contact list.

{% endif %} {% if not enrollments %} {% comment %} Which empty, not just empty. With the filter on Active and one completed subscriber present, "Nobody here yet." is a claim about the sequence that the Completed tab immediately contradicts. Same branch flows/_list_rows.html makes between a filtered miss and a genuinely empty list. {% endcomment %} {% if enrolled_total %}

Nobody is {{ status }} right now. {{ enrolled_total }} enrolled in all.

{% else %}

Nobody here yet.

{% endif %} {% else %} {% comment %} The panel says when it has stopped short. A list that silently ends at the cap beside a subscriber count in the thousands is two numbers disagreeing with no explanation, and somebody scanning for one person would conclude they are not enrolled. {% endcomment %}

{% if truncated %} Showing the {{ subscriber_cap }} most recent of {{ subscriber_total }}. Filter or export from the contact list to see the rest. {% else %} {{ subscriber_total }} {% if status == "active" %}active{% else %}{{ status }}{% endif %}. {% endif %}

{% endif %}