{# Kanban board component (KanbanComponent in components.py; usage docs in manual/kanban.org). The baseline works without JavaScript: * Move / sort — the grip link on a card re-renders the view with ``?move=`` (the page passes it back as ``moving_id``); every eligible gap then offers a "move here" POST form to the place endpoint (fields: item_id, column_id, position, next). * Quick-add — each opted-in column ends in a one-field form posting column_id, name and next to the add endpoint. With JavaScript, static/js/kanban-dnd.js layers drag-and-drop on the same markup: it reads data-place-url / data-csrf off the root, drags .kanban-card[data-item-id] between .kanban-cards zones (keyed by data-column-id) and posts to the same place endpoint. The no-JS controls stay rendered — they remain the keyboard-accessible path. With an sse_url the root carries the construct live client's data-live-* attributes: the stream's done event reloads the view with fresh data. #} {% if live_attrs %} {# Content sink required by the live client; the watch stream's only job is the reload-triggering done event. #} {% endif %}
{% for col in column_data %} {% set column = col.column %}

{{ column.title }} {{ column.cards|length }}

{% for kind, payload in col.entries %} {% if kind == "slot" %}
{{ csrf_field }}
{% else %} {% set card = payload %} {% set is_moving = moving and card.id == moving.id %}
{# Top strip: the grip is both the no-JS move entry point and, in JS mode, the drag handle (starting a drag never fires the click). #} {% if place_url %} {% if is_moving %} {{ t.move_cancel }} {% elif not moving %} {% endif %} {% endif %} {% if card.close_action and not moving %}
{{ csrf_field }} {% for fname, fval in card.close_action.fields.items() %} {% endfor %}
{% endif %}
{% if card.url %}{{ card.title }} {% else %}{{ card.title }}{% endif %} {% for badge in card.badges %} {{ badge }} {% endfor %}
{% if card.meta %}
{% for entry in card.meta %} {% if entry is string %}{{ entry }} {% else %}{{ entry[0] }}{% endif %} {% endfor %}
{% endif %} {% if card.people %}
{% for entry in card.people %} {% if entry is string %}{{ entry }} {% else %}{{ entry[0] }}{% endif %} {% endfor %}
{% endif %} {% if card.actions and not moving %}
{% for action in card.actions %}
{{ csrf_field }} {% for fname, fval in action.fields.items() %} {% endfor %}
{% endfor %}
{% endif %}
{% endif %} {% else %}

{% endfor %}
{% if col.quick_add and not moving %}
{{ csrf_field }}
{% endif %}
{% endfor %}