{% extends "layout.html" %} {% block content %} {# Helper macro for building queue section sort links #} {% macro q_sort(label, col, current_sort, current_dir, prefix, align='left') %} {% set is_active = current_sort == col %} {% set next_dir = 'asc' if (is_active and current_dir == 'desc') else 'desc' %} {{ label }} {% if is_active %} {{ '▲' if current_dir == 'asc' else '▼' }} {% endif %} {% endmacro %} {# Helper macro for pagination controls #} {% macro q_pagination(pg, prefix) %} {% if pg and pg.total_items > 0 %}

Showing {{ pg.start_index }} to {{ pg.end_index }} of {{ pg.total_items }} results

{% if pg.total_pages > 1 %} {% endif %}
{% endif %} {% endmacro %}

Admin

Sync Queue

Live view of pending, running, and completed background jobs.

{{ summary.pending_count }}
Pending
{{ summary.running_count }}
Running
{{ summary.completed_count }}
Completed (24h)
{{ summary.failed_count }}
Failed (24h)
{% if solution %} {% endif %} {% if running %}

Running ({{ running_total }})

{{ q_sort('Project', 'project', rs, rd, 'r') }} {{ q_sort('Started', 'started_at', rs, rd, 'r') }} {{ q_sort('Jobs', 'jobs', rs, rd, 'r', align='right') }} {{ q_sort('Manifests', 'manifests', rs, rd, 'r', align='right') }} {% for sync in running %} {% endfor %}
Duration
{{ sync.config_name }} {{ sync.started_at.strftime('%Y-%m-%d %H:%M:%S') if sync.started_at else '-' }} {% if sync.started_at %} {% set elapsed = (now() - sync.started_at).total_seconds() | int %} {{ elapsed }}s {% else %} - {% endif %} {{ sync.jobs_retrieved_count or 0 }} {{ sync.manifests_updated_count or 0 }}
{{ q_pagination(running_pg, 'r') }}
{% endif %} {% if pending %}

Pending ({{ pending_total }})

{{ q_sort('Project', 'project', ps, pd, 'p') }} {{ q_sort('Queued', 'queued_at', ps, pd, 'p') }} {% for sync in pending %} {% endfor %}
Position
{{ sync.config_name }} {{ sync.queued_at.strftime('%Y-%m-%d %H:%M:%S') if sync.queued_at else '-' }} #{{ loop.index }}
{{ q_pagination(pending_pg, 'p') }}
{% endif %} {% if completed %}

Completed (Last 24h)

{{ q_sort('Project', 'project', cs, cd, 'c') }} {{ q_sort('Completed', 'completed_at', cs, cd, 'c') }} {{ q_sort('Jobs', 'jobs', cs, cd, 'c', align='right') }} {{ q_sort('Manifests', 'manifests', cs, cd, 'c', align='right') }} {% for sync in completed %} {% endfor %}
Duration
{{ sync.config_name }} {{ sync.completed_at.strftime('%Y-%m-%d %H:%M:%S') if sync.completed_at else '-' }} {% if sync.started_at and sync.completed_at %} {{ ((sync.completed_at - sync.started_at).total_seconds()) | round(1) }}s {% else %} - {% endif %} {{ sync.jobs_retrieved_count or 0 }} {{ sync.manifests_updated_count or 0 }}
{{ q_pagination(completed_pg, 'c') }}
{% endif %} {% if failed %}

Failed (Last 24h)

{{ q_sort('Project', 'project', fs, fd, 'f') }} {{ q_sort('Failed At', 'completed_at', fs, fd, 'f') }} {{ q_sort('Errors', 'errors', fs, fd, 'f', align='right') }} {% for sync in failed %} {% endfor %}
Last Error
{{ sync.config_name }} {{ sync.completed_at.strftime('%Y-%m-%d %H:%M:%S') if sync.completed_at else '-' }} {{ sync.errors|length if sync.errors else 0 }} {% if sync.errors and sync.errors|length > 0 %} {{ sync.errors[0].error_message[:100] }}{% if sync.errors[0].error_message|length > 100 %}...{% endif %} {% else %} - {% endif %}
{{ q_pagination(failed_pg, 'f') }}
{% endif %} {% if not pending and not running and not completed and not failed %}

No sync operations to display.

Sync operations will appear here when triggered from project configurations.

{% endif %}
{% endblock %}