feat: Enhance job management UI and add apostrophe normalization

- Updated styles for job cards to include a paused state and improved title styling.
- Modified job card template to display job status and progress more clearly, including pause/resume functionality.
- Introduced a new script for managing chapter row states in the prepare job form, allowing for dynamic enabling/disabling of inputs.
- Created a new template for preparing jobs, featuring a summary of metadata and chapter details.
- Added a comprehensive apostrophe normalization module to handle various cases of apostrophe usage in text.
This commit is contained in:
JB
2025-10-07 05:34:53 -07:00
parent 85310ad916
commit 718a3fa1c0
9 changed files with 1426 additions and 26 deletions
+22 -8
View File
@@ -7,23 +7,37 @@
{% if active_jobs %}
<ul class="job-cards">
{% for job in active_jobs %}
<li class="job-card">
{% set progress_value = ((job.progress or 0) * 100)|round(1) %}
<li class="job-card" data-status="{{ job.status.value }}">
<div class="job-card__header">
<div>
<strong>{{ job.original_filename }}</strong>
<div class="job-card__meta">{% if job.voice_profile %}Profile: {{ job.voice_profile }}{% else %}Voice: {{ job.voice }}{% endif %} · {{ job.language }}</div>
<a class="job-card__title" href="{{ url_for('web.job_detail', job_id=job.id) }}">{{ job.original_filename }}</a>
<div class="job-card__meta">
{% if job.queue_position %}Position #{{ job.queue_position }} · {% endif %}
{% if job.voice_profile %}Profile: {{ job.voice_profile }}{% else %}Voice: {{ job.voice }}{% endif %} · {{ job.language }}
</div>
{% if job.pause_requested and job.status == JobStatus.RUNNING %}
<div class="job-card__meta job-card__meta--warning">Pause requested — waiting for a safe point…</div>
{% endif %}
</div>
<span class="badge badge--{{ job.status.value }}">{{ job.status.value|title }}</span>
</div>
<div class="job-card__progress">
<div class="progress-bar" style="--progress: {{ ((job.progress or 0) * 100)|round(1) }}%">
<div class="progress-bar" style="--progress: {{ progress_value }}%">
<div class="progress-bar__fill"></div>
</div>
<small>{{ job.processed_characters }} / {{ job.total_characters or '—' }}</small>
<small>{{ progress_value }}% · {{ job.processed_characters }} / {{ job.total_characters or '—' }}</small>
</div>
<div class="job-card__footer">
<a class="button button--ghost" href="{{ url_for('web.job_detail', job_id=job.id) }}">Inspect</a>
{% if job.status in [JobStatus.PENDING, JobStatus.RUNNING] %}
<a class="button button--ghost" href="{{ url_for('web.job_detail', job_id=job.id) }}">Details</a>
{% if job.status == JobStatus.RUNNING %}
<button type="button" class="button button--ghost" hx-post="{{ url_for('web.pause_job', job_id=job.id) }}" hx-target="#jobs-panel" hx-swap="innerHTML">Pause</button>
{% elif job.status == JobStatus.PAUSED %}
<button type="button" class="button button--ghost" hx-post="{{ url_for('web.resume_job', job_id=job.id) }}" hx-target="#jobs-panel" hx-swap="innerHTML">Resume</button>
{% elif job.status == JobStatus.PENDING %}
<button type="button" class="button button--ghost" hx-post="{{ url_for('web.pause_job', job_id=job.id) }}" hx-target="#jobs-panel" hx-swap="innerHTML">Pause</button>
{% endif %}
{% if job.status in [JobStatus.PENDING, JobStatus.RUNNING, JobStatus.PAUSED] %}
<button type="button" class="button button--ghost" hx-post="{{ url_for('web.cancel_job', job_id=job.id) }}" hx-target="#jobs-panel" hx-swap="innerHTML" hx-confirm="Cancel this conversion?">Cancel</button>
{% endif %}
</div>
@@ -48,7 +62,7 @@
<li class="job-card">
<div class="job-card__header">
<div>
<strong>{{ job.original_filename }}</strong>
<a class="job-card__title" href="{{ url_for('web.job_detail', job_id=job.id) }}">{{ job.original_filename }}</a>
<div class="job-card__meta">Finished {{ job.finished_at|datetimeformat }}</div>
</div>
<span class="badge badge--{{ job.status.value }}">{{ job.status.value|title }}</span>