{# Quick actions dynamic widgets — auto-refreshed via dashboard-refresh event. Rendered inside #dashboard-quick-actions wrapper in dashboard/index.html, and as the response body of /dashboard/quick-actions fragment route. This partial renders ONLY the dynamic items that should refresh after a sync / batch-score run (Sync Now button or active-sync progress; Score Unscored button or active-scoring progress). The "Add Job Manually" button and its dialog live outside this partial in dashboard/index.html because they are static UI. Required context: active_sync, active_scoring, unscored_count, scoring_available. #} {# No-provider banner (WP3): state-driven, not dismissible — disappears on the next fragment refresh once a provider is configured or nothing is unscored. w-full forces its own row inside the flex-wrap Quick Actions container (the #dashboard-quick-actions wrapper is class="contents"). #} {% if not scoring_available and unscored_count > 0 %}
{{ unscored_count }} job{{ '' if unscored_count == 1 else 's' }} ingested but not yet AI-scored — no AI provider is configured. Scoring is what moves jobs into your Apply / Consider pipeline. Set up a provider
{% endif %} {# Sync Now / sync progress bar #} {% if active_sync %} {% with session_id=active_sync.id, phase_label={"running": "Starting...", "gmail": "Syncing..."}.get(active_sync.status, "Syncing...") %} {% include "dashboard/_sync_progress.html" %} {% endwith %} {% else %}
{% endif %} {# Unified batch scoring — async with HTMX polling progress bar #} {% if active_scoring %} {% with session_id=active_scoring.id, total=active_scoring.total, scored=active_scoring.scored, skipped=active_scoring.skipped, cancelling=(active_scoring.status == 'cancelling') %} {% include "dashboard/_batch_score_progress.html" %} {% endwith %} {% elif scoring_available and unscored_count > 0 %}
{% else %}
{% endif %}