qrush 0.6.0

Lightweight Job Queue and Task Scheduler for Rust (Actix + Redis + Cron)
Documentation
{% extends "layout.html.tera" %}
{% block content %}
<h1 class="text-2xl font-semibold mb-4">{{ title | default(value="Retry Jobs") }}</h1>

<div class="card overflow-hidden">
  <table class="table">
    <thead class="bg-slate-50/60 dark:bg-slate-900/30">
      <tr>
        <th class="th">ID</th>
        <th class="th">Type</th>
        <th class="th">Status</th>
        <th class="th">Created</th>
        <th class="th">Run at</th>
        <th class="th">Failed at</th>
        <th class="th">Error</th>
        <th class="th">Actions</th>
      </tr>
    </thead>
    <tbody>
      {% for job in jobs %}
      <tr class="hover:bg-slate-50/60 dark:hover:bg-slate-900/30">
        <td class="td font-mono text-xs">{{ job.id }}</td>
        <td class="td">{{ job.job_type }}</td>
        <td class="td">
          {% set s = job.status | default(value="retry") %}
          <span class="{% if s == "success" %}chip-green{% elif s == "failed" %}chip-red{% elif s == "queued" %}chip-sky{% else %}chip-amber{% endif %}">{{ s }}</span>
        </td>
        <td class="td">{{ job.created_at | default(value="—") }}</td>
        <td class="td">{{ job.run_at | default(value="—") }}</td>
        <td class="td">{{ job.failed_at | default(value="—") }}</td>
        <td class="td max-w-[20rem] truncate" title="{{ job.error | default(value="") }}">{{ job.error | default(value="") }}</td>
        <td class="td">
          <button class="btn" onclick="jobAction('queue','{{ job.id }}')">Queue</button>
          <button class="btn-danger" onclick="jobAction('delete','{{ job.id }}')">Delete</button>
        </td>
      </tr>
      {% else %}
      <tr><td class="td" colspan="8">No retry jobs.</td></tr>
      {% endfor %}
    </tbody>
  </table>
</div>

{% if page is defined %}
  {% set prev = page.current - 1 %}
  {% set next = page.current + 1 %}
  <div class="mt-4 flex items-center justify-between text-sm">
    <div class="text-slate-500 dark:text-slate-400">Showing {{ page.start }}–{{ page.end }} of {{ page.total }}</div>
    <div class="flex gap-2">
      <a class="btn {% if not page.has_prev %}opacity-50 pointer-events-none{% endif %}" href="?page={{ prev }}&{{ page.query }}">Prev</a>
      <a class="btn {% if not page.has_next %}opacity-50 pointer-events-none{% endif %}" href="?page={{ next }}&{{ page.query }}">Next</a>
    </div>
  </div>
{% endif %}

<script>
async function jobAction(action, job_id){
  try{
    const r = await fetch('/qrush/metrics/jobs/action', {
      method: 'POST',
      headers: {'Content-Type':'application/json'},
      body: JSON.stringify({ action, job_id })
    });
    if(r.ok){ location.reload(); } else { alert('Action failed'); }
  } catch(e){ alert('Action error'); }
}
</script>
{% endblock content %}