Files
alchemist/templates/partials/jobs_table.html
Brooklyn b8d9606499 Refactor: Decouple Analyzer/Planner/Executor and Fix Templates
Major architectural overhaul to split the monolithic processing logic into distinct components:

- Analyzer: Standardized MediaMetadata extraction using Ffprobe.

- Planner: New decision engine (BasicPlanner) to handle transcoding logic.

- Executor: Defined Executor trait and implemented FfmpegExecutor.

Fixes:

- Resolved Askama template syntax errors in analytics.html and jobs_table.html.

- Fixed compilation errors related to missing modules and trait bounds.

- Added sqlx migrations execution on startup.

Chore:

- Updated license to GPLv3 as requested.

- Removed legacy lchemist.db handling in favor of migrations.

- Cleaned up unused imports and legacy comments.
2026-01-08 19:07:45 -05:00

82 lines
4.1 KiB
HTML

<table class="w-full text-left border-collapse">
<thead>
<tr class="text-xs uppercase text-slate-500 border-b border-slate-800">
<th class="px-6 py-4 font-medium tracking-wider">Job / Path</th>
<th class="px-6 py-4 font-medium tracking-wider w-32">Status</th>
<th class="px-6 py-4 font-medium tracking-wider w-48">Progress</th>
<th class="px-6 py-4 font-medium tracking-wider w-24 text-right">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-800/50">
{% for job in jobs %}
<tr class="group hover:bg-slate-800/20 transition-colors duration-150">
<td class="px-6 py-4">
<div class="font-medium truncate max-w-sm text-slate-200">{{ job.input_path }}</div>
<div class="text-xs text-slate-500 truncate mt-1">
{% match job.decision_reason %}
{% when Some with (reason) %}{{ reason }}
{% when None %}
{% endmatch %}
</div>
{% if job.is_active() %}
<div class="mt-2 text-[10px] text-slate-500 font-mono">
Attempt #{{ job.attempt_count }} • Priority {{ job.priority }}
</div>
{% endif %}
</td>
<td class="px-6 py-4">
<span
class="px-2.5 py-1 rounded-full text-[10px] font-bold border uppercase tracking-tight {{ job.status_class() }}">
{{ job.status }}
</span>
</td>
<td class="px-6 py-4">
{% match job.vmaf_score %}
{% when Some with (vmaf) %}
<span class="ml-2 px-2 py-0.5 rounded bg-slate-800 text-slate-400 text-[9px] font-mono">
VMAF: {{ job.vmaf_fixed() }}
</span>
{% when None %}
{% endmatch %}
</td>
<td class="px-6 py-4">
<div class="flex gap-2">
<div class="w-full bg-slate-800 rounded-full h-1.5 overflow-hidden">
<div class="bg-indigo-500 h-1.5 rounded-full transition-all duration-500"
style="width: {{ job.progress_fixed() }}%">
</div>
</div>
<span class="text-xs font-mono text-slate-400 w-10 text-right">{{ job.progress_fixed() }}%</span>
</div>
</td>
<td class="px-6 py-4 text-right">
<div class="flex justify-end gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
{% if job.can_retry() %}
<button hx-post="/api/jobs/{{ job.id }}/restart" hx-swap="none"
class="p-1.5 hover:bg-slate-700 rounded text-slate-400 hover:text-white transition-colors"
title="Retry Job">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15">
</path>
</svg>
</button>
{% endif %}
{% if job.is_active() %}
<button hx-post="/api/jobs/{{ job.id }}/cancel" hx-swap="none"
class="p-1.5 hover:bg-rose-900/50 rounded text-slate-400 hover:text-rose-400 transition-colors"
title="Cancel Job">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>