{# table_rows.html — inline-editable row cells, row states, Tab navigation Requires: dzTable Alpine controller (editing, selected, isEditing, startEdit, toggleRow) Row height: h-9 (36px dense). No DaisyUI classes. #} {% from 'macros/status_badge.html' import render_status_badge %} {% if table and table.rows %} {% set _row_label_col = namespace(key="id") %} {% for col in table.columns %}{% if col.type not in ["ref", "badge", "bool", "currency"] and _row_label_col.key == "id" %}{% set _row_label_col.key = col.key %}{% endif %}{% endfor %} {% for item in table.rows %} {% set _row_label = item[_row_label_col.key] | default(item.id) %} {% set _row_label = _row_label | ref_display if _row_label is mapping else _row_label %} {# ── Checkbox cell ─────────────────────────────────────────────────────── #} {% if table.bulk_actions %} {% endif %} {# ── Data cells ────────────────────────────────────────────────────────── #} {% for col in table.columns %} {% if not col.hidden %} {# ── Inline editable cell ──────────────────────────────────────────── #} {% if table.inline_editable and col.key in table.inline_editable %} {# Edit mode: input rendered via inline_edit.html #} {# Display mode: double-click to enter edit #} {# ── Non-editable cell — type-specific rendering ───────────────────── #} {% else %} {% if col.type == "badge" %} {{ render_status_badge(value=item[col.key]) }} {% elif col.type == "bool" %} {{ item[col.key] | bool_icon }} {% elif col.type == "date" %} {{ item[col.key] | dateformat }} {% elif col.type == "currency" %} {{ item[col.key] | currency(col.currency_code or "GBP") }} {% elif col.type == "sensitive" %} {% set raw = item[col.key] | default("") | string %} {% if raw | length > 4 %}{{ "****" ~ raw[-4:] }}{% elif raw %}****{% else %}{% endif %} {% elif col.type == "ref" %} {{ item.get(col.key ~ "_display", "") or (item[col.key] | ref_display) }} {% elif col.type == "percentage" %} {{ item[col.key] | default("") }}% {% else %} {{ item[col.key] | default("") | truncate_text }} {% endif %} {% endif %} {% endif %} {% endfor %} {# ── Row actions — revealed on hover ──────────────────────────────────────── #}
{# View action #} {% if table.detail_url_template %} {# Edit action #} {% endif %} {# Delete action #}
{% endfor %} {% else %} {# Typed empty-state picker (#807). Pick the most specific per-case message, then fall back to the legacy `empty_message` (which was already populated with a reasonable default at compile time). Each case carries a different default + affordance: collection → "No X yet." + link to the create surface filtered → "No X match the current filters." + clear-filters link forbidden → "You can't see any X with your current role." loading → "Couldn't load X. Try again." (fetch errored) #} {% set _kind = table.empty_kind | default('collection') if table else 'collection' %} {% if _kind == 'filtered' %} {{ (table.empty_filtered if table and table.empty_filtered else "No " + (table.entity_name|default('items'))|lower + " match the current filters.") }} {% set _has_params = table and table.filter_values %} {% if _has_params and request is defined %} Clear filters {% endif %} {% elif _kind == 'loading' %} {{ "Couldn't load " + (table.entity_name|default('items'))|lower + ". Try reloading." if table else "Couldn't load items. Try reloading." }} {% elif _kind == 'forbidden' and table and table.empty_forbidden %} {{ table.empty_forbidden }} {% else %} {# 'collection' case OR any unknown kind — use per-case copy if available, otherwise the long-standing default. #} {{ (table.empty_collection if table and table.empty_collection else (table.empty_message if table and table.empty_message else "No " + (table.entity_name|default('items'))|lower + " found.")) }} {% if table and table.create_url %} Add one {% endif %} {% endif %} {% endif %}