Download templates/cpanel/tasks.html from Akoda35/PyRunner: direct link, hf CLI and curl.
- Browser
- Download file 18.2 kB
-
https://huggingface.co/spaces/Akoda35/PyRunner/resolve/main/templates/cpanel/tasks.html
- Command line
-
hf download hf://spaces/Akoda35/PyRunner/templates/cpanel/tasks.html
-
curl -L -o tasks.html https://huggingface.co/spaces/Akoda35/PyRunner/resolve/main/templates/cpanel/tasks.html
18.2 kB
| {% extends "base.html" %} | |
| {% block title %}Tasks - PyRunner{% endblock %} | |
| {% block content %} | |
| <div class="flex"> | |
| {% include "cpanel/_sidebar.html" %} | |
| <div class="flex-1 p-8"> | |
| <!-- Header --> | |
| <div class="flex items-center justify-between mb-8"> | |
| <div> | |
| <h1 class="text-2xl font-bold text-code-text">Task Queue</h1> | |
| <p class="text-code-muted">Monitor and manage Django-Q2 tasks</p> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <!-- Auto-refresh toggle --> | |
| <label class="flex items-center space-x-2 text-sm text-code-muted cursor-pointer"> | |
| <input type="checkbox" | |
| id="auto-refresh" | |
| class="w-4 h-4 text-code-accent bg-code-bg border-code-border rounded focus:ring-code-accent"> | |
| <span>Auto-refresh</span> | |
| </label> | |
| </div> | |
| </div> | |
| <!-- Statistics Cards --> | |
| <div class="grid grid-cols-4 gap-4 mb-6"> | |
| <div class="bg-code-surface border border-code-border rounded-xl p-4"> | |
| <p class="text-xs text-code-muted mb-1">Queued</p> | |
| <p class="text-2xl font-bold text-code-accent" id="stat-queued">{{ stats.queued_count }}</p> | |
| </div> | |
| <div class="bg-code-surface border border-code-border rounded-xl p-4"> | |
| <p class="text-xs text-code-muted mb-1">Running</p> | |
| <p class="text-2xl font-bold text-code-yellow" id="stat-running">{{ stats.running_count }}</p> | |
| </div> | |
| <div class="bg-code-surface border border-code-border rounded-xl p-4"> | |
| <p class="text-xs text-code-muted mb-1">Completed (24h)</p> | |
| <p class="text-2xl font-bold text-code-green" id="stat-completed">{{ stats.completed_today }}</p> | |
| </div> | |
| <div class="bg-code-surface border border-code-border rounded-xl p-4"> | |
| <p class="text-xs text-code-muted mb-1">Failed (24h)</p> | |
| <p class="text-2xl font-bold text-code-red" id="stat-failed">{{ stats.failed_today }}</p> | |
| </div> | |
| </div> | |
| <!-- Stuck Tasks Warning --> | |
| {% if stuck_tasks %} | |
| <div class="bg-code-yellow/10 border border-code-yellow/30 rounded-xl p-4 mb-6"> | |
| <div class="flex items-center justify-between"> | |
| <div class="flex items-center gap-3"> | |
| <svg class="w-6 h-6 text-code-yellow" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/> | |
| </svg> | |
| <div> | |
| <p class="text-code-yellow font-semibold">{{ stuck_tasks|length }} Stuck Task(s) Detected</p> | |
| <p class="text-sm text-code-muted">Tasks have been waiting longer than expected. Workers may not be running.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Stuck tasks list --> | |
| <div class="mt-4 space-y-2"> | |
| {% for task in stuck_tasks %} | |
| <div class="flex items-center justify-between bg-code-bg/50 rounded-lg p-3"> | |
| <div class="flex items-center gap-3"> | |
| <span class="text-code-text font-mono text-sm">{{ task.id|truncatechars:20 }}</span> | |
| <span class="text-code-muted text-sm">Stuck for {{ task.stuck_minutes }} minutes</span> | |
| {% if task.linked_run %} | |
| <a href="{% url 'cpanel:run_detail' pk=task.linked_run.pk %}" class="text-code-accent hover:underline text-sm"> | |
| {{ task.linked_run.script.name }} | |
| </a> | |
| {% endif %} | |
| </div> | |
| <button onclick="forceStopTask('{{ task.id }}')" | |
| class="px-3 py-1 bg-code-red/20 hover:bg-code-red/30 text-code-red text-sm rounded-lg transition-colors"> | |
| Force Stop | |
| </button> | |
| </div> | |
| {% endfor %} | |
| </div> | |
| </div> | |
| {% endif %} | |
| <!-- Filters --> | |
| <div class="bg-code-surface border border-code-border rounded-xl p-4 mb-6"> | |
| <form method="get" class="flex flex-wrap items-end gap-4"> | |
| <!-- Status Filter --> | |
| <div> | |
| <label class="block text-xs text-code-muted mb-1">Status</label> | |
| <select name="status" | |
| class="px-3 py-2 bg-code-bg border border-code-border rounded-lg text-code-text text-sm focus:outline-none focus:ring-2 focus:ring-code-accent/50"> | |
| <option value="">All Status</option> | |
| <option value="success" {% if status_filter == "success" %}selected{% endif %}>Success</option> | |
| <option value="failed" {% if status_filter == "failed" %}selected{% endif %}>Failed</option> | |
| </select> | |
| </div> | |
| <!-- Submit --> | |
| <button type="submit" | |
| class="px-4 py-2 bg-code-accent hover:bg-code-accent/90 text-white text-sm font-medium rounded-lg transition-colors"> | |
| Filter | |
| </button> | |
| {% if status_filter %} | |
| <a href="{% url 'cpanel:tasks' %}" | |
| class="px-4 py-2 bg-code-bg border border-code-border hover:border-code-accent text-code-text text-sm rounded-lg transition-colors"> | |
| Clear | |
| </a> | |
| {% endif %} | |
| </form> | |
| </div> | |
| <!-- Queued Tasks Section --> | |
| {% if queued_tasks %} | |
| <div class="mb-8"> | |
| <h2 class="text-lg font-semibold text-code-text mb-4">Queued Tasks ({{ queued_tasks|length }})</h2> | |
| <div class="bg-code-surface border border-code-border rounded-xl overflow-hidden"> | |
| <table class="w-full"> | |
| <thead class="bg-code-bg border-b border-code-border"> | |
| <tr> | |
| <th class="px-4 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Task ID</th> | |
| <th class="px-4 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Type</th> | |
| <th class="px-4 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Queued</th> | |
| <th class="px-4 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Linked Resource</th> | |
| <th class="px-4 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody class="divide-y divide-code-border" id="queued-tasks-body"> | |
| {% for task in queued_tasks %} | |
| <tr class="hover:bg-code-bg/50 transition-colors"> | |
| <td class="px-4 py-3 font-mono text-sm text-code-text"> | |
| {{ task.id|truncatechars:24 }} | |
| </td> | |
| <td class="px-4 py-3"> | |
| <span class="px-2 py-0.5 text-xs rounded | |
| {% if task.type == 'script_run' %}bg-code-accent/20 text-code-accent | |
| {% else %}bg-code-muted/20 text-code-muted{% endif %}"> | |
| {% if task.type == 'script_run' %}Script Run{% else %}System{% endif %} | |
| </span> | |
| </td> | |
| <td class="px-4 py-3 text-sm text-code-muted"> | |
| {{ task.queued_at|timesince }} ago | |
| </td> | |
| <td class="px-4 py-3 text-sm"> | |
| {% if task.linked_run %} | |
| <a href="{% url 'cpanel:run_detail' pk=task.linked_run.pk %}" class="text-code-accent hover:underline"> | |
| {{ task.linked_run.script.name }} | |
| </a> | |
| {% else %} | |
| <span class="text-code-muted">-</span> | |
| {% endif %} | |
| </td> | |
| <td class="px-4 py-3"> | |
| <button onclick="cancelTask('{{ task.id }}')" | |
| class="px-3 py-1 bg-code-red/20 hover:bg-code-red/30 text-code-red text-sm rounded-lg transition-colors"> | |
| Cancel | |
| </button> | |
| </td> | |
| </tr> | |
| {% endfor %} | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| {% endif %} | |
| <!-- Task History Section --> | |
| <div> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="text-lg font-semibold text-code-text">Task History</h2> | |
| <p class="text-sm text-code-muted"> | |
| Showing {{ completed_tasks|length }} of {{ total_completed }} tasks | |
| </p> | |
| </div> | |
| {% if completed_tasks %} | |
| <div class="bg-code-surface border border-code-border rounded-xl overflow-hidden"> | |
| <div class="max-h-[500px] overflow-y-auto"> | |
| <table class="w-full"> | |
| <thead class="bg-code-bg border-b border-code-border sticky top-0"> | |
| <tr> | |
| <th class="px-4 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Task Name</th> | |
| <th class="px-4 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Type</th> | |
| <th class="px-4 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Status</th> | |
| <th class="px-4 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Duration</th> | |
| <th class="px-4 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Started</th> | |
| <th class="px-4 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Linked Resource</th> | |
| </tr> | |
| </thead> | |
| <tbody class="divide-y divide-code-border"> | |
| {% for task in completed_tasks %} | |
| <tr class="hover:bg-code-bg/50 transition-colors"> | |
| <td class="px-4 py-3 font-mono text-sm text-code-text" title="{{ task.name }}"> | |
| {{ task.name|truncatechars:30 }} | |
| </td> | |
| <td class="px-4 py-3"> | |
| <span class="px-2 py-0.5 text-xs rounded | |
| {% if task.type == 'script_run' %}bg-code-accent/20 text-code-accent | |
| {% else %}bg-code-muted/20 text-code-muted{% endif %}"> | |
| {% if task.type == 'script_run' %}Script Run{% else %}System{% endif %} | |
| </span> | |
| </td> | |
| <td class="px-4 py-3"> | |
| {% if task.success %} | |
| <span class="px-2 py-0.5 text-xs rounded bg-code-green/20 text-code-green">Success</span> | |
| {% else %} | |
| <span class="px-2 py-0.5 text-xs rounded bg-code-red/20 text-code-red">Failed</span> | |
| {% endif %} | |
| </td> | |
| <td class="px-4 py-3 text-sm text-code-muted"> | |
| {{ task.duration_display }} | |
| </td> | |
| <td class="px-4 py-3 text-sm text-code-muted"> | |
| {{ task.started|date:"M d, H:i" }} | |
| </td> | |
| <td class="px-4 py-3 text-sm"> | |
| {% if task.linked_run %} | |
| <a href="{% url 'cpanel:run_detail' pk=task.linked_run.pk %}" class="text-code-accent hover:underline"> | |
| {{ task.linked_run.script.name }} | |
| </a> | |
| {% else %} | |
| <span class="text-code-muted">-</span> | |
| {% endif %} | |
| </td> | |
| </tr> | |
| {% endfor %} | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <!-- Pagination --> | |
| {% if total_pages > 1 %} | |
| <div class="flex items-center justify-center space-x-2 mt-6"> | |
| {% if page > 1 %} | |
| <a href="?page={{ page|add:'-1' }}{% if status_filter %}&status={{ status_filter }}{% endif %}" | |
| class="px-3 py-1 bg-code-bg border border-code-border rounded-lg text-code-text text-sm hover:border-code-accent transition-colors"> | |
| Previous | |
| </a> | |
| {% endif %} | |
| <span class="text-sm text-code-muted">Page {{ page }} of {{ total_pages }}</span> | |
| {% if page < total_pages %} | |
| <a href="?page={{ page|add:'1' }}{% if status_filter %}&status={{ status_filter }}{% endif %}" | |
| class="px-3 py-1 bg-code-bg border border-code-border rounded-lg text-code-text text-sm hover:border-code-accent transition-colors"> | |
| Next | |
| </a> | |
| {% endif %} | |
| </div> | |
| {% endif %} | |
| {% else %} | |
| <div class="bg-code-surface border border-code-border rounded-xl p-12 text-center"> | |
| <div class="w-16 h-16 bg-code-accent/20 rounded-full flex items-center justify-center mx-auto mb-4"> | |
| <svg class="w-8 h-8 text-code-accent" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/> | |
| </svg> | |
| </div> | |
| <h3 class="text-lg font-semibold text-code-text mb-2">No tasks found</h3> | |
| <p class="text-code-muted"> | |
| {% if status_filter %} | |
| Try adjusting your filters or <a href="{% url 'cpanel:tasks' %}" class="text-code-accent hover:underline">clear all filters</a>. | |
| {% else %} | |
| No tasks have been executed yet. | |
| {% endif %} | |
| </p> | |
| </div> | |
| {% endif %} | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| let autoRefreshInterval = null; | |
| const AUTO_REFRESH_KEY = 'pyrunner_tasks_auto_refresh'; | |
| function cancelTask(taskId) { | |
| if (!confirm('Cancel this queued task?')) return; | |
| fetch(`{% url 'cpanel:tasks' %}${taskId}/cancel/`, { | |
| method: 'POST', | |
| headers: { | |
| 'X-CSRFToken': '{{ csrf_token }}', | |
| 'Content-Type': 'application/json', | |
| }, | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| alert(data.message); | |
| window.location.reload(); | |
| } else { | |
| alert('Error: ' + data.error); | |
| } | |
| }) | |
| .catch(error => { | |
| alert('Error: ' + error.message); | |
| }); | |
| } | |
| function forceStopTask(taskId) { | |
| if (!confirm('Force stop this task? The underlying process may continue until it times out.')) return; | |
| fetch(`{% url 'cpanel:tasks' %}${taskId}/force-stop/`, { | |
| method: 'POST', | |
| headers: { | |
| 'X-CSRFToken': '{{ csrf_token }}', | |
| 'Content-Type': 'application/json', | |
| }, | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| alert(data.message); | |
| window.location.reload(); | |
| } else { | |
| alert('Error: ' + data.error); | |
| } | |
| }) | |
| .catch(error => { | |
| alert('Error: ' + error.message); | |
| }); | |
| } | |
| function startAutoRefresh() { | |
| if (!autoRefreshInterval) { | |
| autoRefreshInterval = setInterval(function() { | |
| window.location.reload(); | |
| }, 5000); | |
| } | |
| } | |
| function stopAutoRefresh() { | |
| if (autoRefreshInterval) { | |
| clearInterval(autoRefreshInterval); | |
| autoRefreshInterval = null; | |
| } | |
| } | |
| // Initialize on page load | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const checkbox = document.getElementById('auto-refresh'); | |
| const isEnabled = localStorage.getItem(AUTO_REFRESH_KEY) === 'true'; | |
| // Restore checkbox state | |
| checkbox.checked = isEnabled; | |
| // Start auto-refresh if it was enabled | |
| if (isEnabled) { | |
| startAutoRefresh(); | |
| } | |
| // Handle checkbox changes | |
| checkbox.addEventListener('change', function() { | |
| if (this.checked) { | |
| localStorage.setItem(AUTO_REFRESH_KEY, 'true'); | |
| startAutoRefresh(); | |
| } else { | |
| localStorage.setItem(AUTO_REFRESH_KEY, 'false'); | |
| stopAutoRefresh(); | |
| } | |
| }); | |
| }); | |
| </script> | |
| {% endblock %} | |