umbral-admin 0.0.12

Auto-generated CRUD admin UI for umbral models.
Documentation
{#
  widget_data.html
  ================
  HTMX fragment returned by GET {{ admin_base }}/api/dashboard/widgets/{key}/data.
  Renders the correct widget macro based on `kind`.
#}
{% from "admin/_macros/widgets/kpi.html" import kpi_widget, sparkline_svg %}
{% from "admin/_macros/widgets/card.html" import card_widget %}
{% from "admin/_macros/widgets/bar.html" import bar_widget %}
{% from "admin/_macros/widgets/line.html" import line_widget %}
{% from "admin/_macros/widgets/donut.html" import donut_widget %}
{% from "admin/_macros/widgets/radial.html" import radial_widget %}
{% from "admin/_macros/widgets/heatmap.html" import heatmap_widget %}
{% from "admin/_macros/widgets/progress.html" import progress_widget %}
{% from "admin/_macros/widgets/feed.html" import feed_widget %}
{% from "admin/_macros/widgets/table.html" import table_widget %}
{% from "admin/_macros/widgets/filters.html" import filter_strip %}

{# The declarative filter strip renders above the widget body for EVERY kind.
   `line` is the exception: it draws its own period chips inline in its header,
   so it gets `show_chips` and we skip the strip for the period-only case it
   already handles. Any line widget that declares filters explicitly falls
   through to the generic strip and suppresses its inline chips, so there is
   never a page with two chip strips on the same widget. #}
{%- set line_handles_its_own = (kind == "line" and not has_declared_filters) -%}
{%- set show_strip = filters and not line_handles_its_own -%}
{% if show_strip or exportable %}
<div class="px-md pt-md flex items-center justify-between gap-sm flex-wrap">
  {% if show_strip %}{{ filter_strip(widget_key, filters) }}{% else %}<span></span>{% endif %}

  {# Export the rows behind the picture. The link carries the CURRENT query, so
     the CSV matches what is on screen rather than an unfiltered dump. #}
  {% if exportable %}
  <a href="{{ admin_base }}/api/dashboard/widgets/{{ widget_key }}/export.csv{% if export_query %}?{{ export_query }}{% endif %}"
     class="inline-flex items-center gap-1 text-label-sm text-on-surface-variant hover:text-on-surface
            px-2 py-1 rounded-md hover:bg-surface-container-high transition-colors"
     title="Download this widget's data as CSV"
     download>
    <i data-lucide="download" class="w-3.5 h-3.5"></i>
    <span>CSV</span>
  </a>
  {% endif %}
</div>
{% endif %}

{% if kind == "kpi" %}
  {{ kpi_widget(title, payload) }}
{% elif kind == "card" %}
  {{ card_widget(title, payload) }}
{% elif kind == "bar" %}
  {{ bar_widget(title, payload) }}
{% elif kind == "line" %}
  {{ line_widget(title, payload, widget_key, active_period, line_handles_its_own) }}
{% elif kind == "donut" %}
  {{ donut_widget(title, payload) }}
{% elif kind == "radial" %}
  {{ radial_widget(title, payload) }}
{% elif kind == "heatmap" %}
  {{ heatmap_widget(title, payload) }}
{% elif kind == "progress" %}
  {{ progress_widget(title, payload) }}
{% elif kind == "feed" %}
  {{ feed_widget(title, payload) }}
{% elif kind == "table" %}
  {{ table_widget(title, payload) }}
{% else %}
  <div class="p-md text-label-sm text-outline">Unknown widget kind: {{ kind }}</div>
{% endif %}