d262ef68af
- Fix version badge showing [object Object] or Python dict dump in
select_recipe, task_list, and task_complete templates by accessing
current_version.version_number instead of the whole object
- Fix recipe_editor.html Internal Server Error caused by Jinja2 block
scoping: {% set %} variables from block content were invisible in
block extra_js, replaced with direct recipe.* references
- Fix task_editor.html SyntaxError from Italian apostrophe in
nell'eliminazione breaking JS string literals, switched to |tojson
- Add i18n {{ _() }} wrappers to all hardcoded navbar strings (desktop
and mobile menus) so language toggle works correctly
- Add app title text "TieMeasureFlow" next to logo in navbar
- Add missing GET /api/tasks/{task_id} endpoint on server that caused
405 Method Not Allowed when starting measurements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
248 lines
11 KiB
HTML
248 lines
11 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}{{ recipe.name }} — {{ _('Task') }} — TieMeasureFlow{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8 py-8 max-w-5xl">
|
|
|
|
<!-- Breadcrumb -->
|
|
<nav class="mb-6" aria-label="Breadcrumb">
|
|
<ol class="flex items-center gap-2 text-sm text-[var(--text-secondary)]">
|
|
<li>
|
|
<a href="{{ url_for('measure.select_recipe') }}"
|
|
class="hover:text-primary transition-colors inline-flex items-center gap-1">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" 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>
|
|
{{ _('Misure') }}
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<svg class="w-4 h-4 text-[var(--text-muted)]" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
|
|
</svg>
|
|
</li>
|
|
<li class="font-medium text-[var(--text-primary)]">
|
|
{{ recipe.name }}
|
|
</li>
|
|
</ol>
|
|
</nav>
|
|
|
|
<!-- Recipe Info Card -->
|
|
<div class="tmf-card mb-8">
|
|
<div class="p-5 sm:p-6">
|
|
<div class="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4">
|
|
<!-- Left: Recipe Details -->
|
|
<div class="flex-1 min-w-0">
|
|
<div class="flex items-center gap-3 mb-3 flex-wrap">
|
|
<!-- Code Badge -->
|
|
<span class="inline-flex items-center px-3 py-1 rounded-md text-sm font-semibold
|
|
bg-primary-50 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300
|
|
border border-primary-200 dark:border-primary-800 font-mono tracking-wide">
|
|
{{ recipe.code }}
|
|
</span>
|
|
|
|
<!-- Version Badge -->
|
|
{% if recipe.current_version or recipe.version %}
|
|
<span class="badge badge-neutral">
|
|
v{{ recipe.current_version.version_number if recipe.current_version else recipe.version }}
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<h1 class="text-2xl font-bold text-[var(--text-primary)] mb-2">
|
|
{{ recipe.name }}
|
|
</h1>
|
|
|
|
{% if recipe.description %}
|
|
<p class="text-sm text-[var(--text-secondary)] leading-relaxed max-w-2xl">
|
|
{{ recipe.description }}
|
|
</p>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Right: Traceability Badges -->
|
|
<div class="flex flex-col gap-2 sm:items-end shrink-0">
|
|
{% if lot_number %}
|
|
<div class="inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm
|
|
bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800
|
|
text-amber-800 dark:text-amber-200">
|
|
<svg class="w-4 h-4 shrink-0" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"/>
|
|
</svg>
|
|
<span class="font-medium">{{ _('Lotto') }}:</span>
|
|
<span class="font-mono font-semibold">{{ lot_number }}</span>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if serial_number %}
|
|
<div class="inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm
|
|
bg-indigo-50 dark:bg-indigo-900/20 border border-indigo-200 dark:border-indigo-800
|
|
text-indigo-800 dark:text-indigo-200">
|
|
<svg class="w-4 h-4 shrink-0" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M7 20l4-16m2 16l4-16M6 9h14M4 15h14"/>
|
|
</svg>
|
|
<span class="font-medium">{{ _('Seriale') }}:</span>
|
|
<span class="font-mono font-semibold">{{ serial_number }}</span>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Task Count Header -->
|
|
<div class="flex items-center justify-between mb-5">
|
|
<h2 class="text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2">
|
|
<svg class="w-5 h-5 text-[var(--text-secondary)]" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 10h16M4 14h16M4 18h16"/>
|
|
</svg>
|
|
{{ _('Task da eseguire') }}
|
|
</h2>
|
|
<span class="badge badge-neutral">
|
|
{{ tasks|length }} task
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Task Cards -->
|
|
{% if tasks %}
|
|
<div class="space-y-4">
|
|
{% for task in tasks %}
|
|
<div class="tmf-card hover:border-primary/30 transition-all duration-200 group">
|
|
<div class="p-5 sm:p-6">
|
|
<div class="flex flex-col sm:flex-row sm:items-center gap-4">
|
|
|
|
<!-- Task Number Circle -->
|
|
<div class="flex items-center justify-center w-12 h-12 rounded-full shrink-0
|
|
bg-primary-50 dark:bg-primary-900/30 border-2 border-primary-200 dark:border-primary-700
|
|
text-primary-700 dark:text-primary-300 font-bold text-lg">
|
|
{{ loop.index }}
|
|
</div>
|
|
|
|
<!-- Task Info -->
|
|
<div class="flex-1 min-w-0">
|
|
<!-- Task Header -->
|
|
<div class="flex items-center gap-2 mb-1">
|
|
<span class="text-xs font-medium text-[var(--text-muted)] uppercase tracking-wider">
|
|
Task {{ loop.index }} {{ _('di') }} {{ tasks|length }}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Task Title -->
|
|
<h3 class="text-lg font-semibold text-[var(--text-primary)] mb-1">
|
|
{{ task.title or task.name or (_('Task') ~ ' ' ~ loop.index) }}
|
|
</h3>
|
|
|
|
<!-- Directive -->
|
|
{% if task.directive or task.description %}
|
|
<p class="text-sm text-[var(--text-secondary)] leading-relaxed mb-3 line-clamp-2">
|
|
{{ task.directive or task.description }}
|
|
</p>
|
|
{% endif %}
|
|
|
|
<!-- Meta Row -->
|
|
<div class="flex items-center gap-4 flex-wrap">
|
|
<!-- Subtask Count -->
|
|
{% if task.subtask_count is defined or task.subtasks %}
|
|
<span class="inline-flex items-center gap-1.5 text-xs text-[var(--text-secondary)]">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z"/>
|
|
</svg>
|
|
<span class="font-medium">
|
|
{% if task.subtask_count is defined %}
|
|
{{ task.subtask_count }}
|
|
{% elif task.subtasks %}
|
|
{{ task.subtasks|length }}
|
|
{% endif %}
|
|
{{ _('misurazioni') }}
|
|
</span>
|
|
</span>
|
|
{% endif %}
|
|
|
|
<!-- File Attachment -->
|
|
{% if task.file_path %}
|
|
<span class="inline-flex items-center gap-1.5 text-xs text-[var(--text-secondary)]">
|
|
{% if task.file_path.endswith('.pdf') %}
|
|
<svg class="w-4 h-4 text-red-500" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"/>
|
|
</svg>
|
|
{% else %}
|
|
<svg class="w-4 h-4 text-green-500" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/>
|
|
</svg>
|
|
{% endif %}
|
|
<span class="font-medium">{{ _('Allegato') }}</span>
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Button -->
|
|
<div class="shrink-0 sm:ml-4">
|
|
<a href="{{ url_for('measure.task_execute', task_id=task.id) }}"
|
|
class="btn btn-primary gap-2 w-full sm:w-auto justify-center
|
|
group-hover:shadow-md transition-shadow duration-200">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/>
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
</svg>
|
|
{{ _('Inizia Misure') }}
|
|
<svg class="w-4 h-4 transition-transform group-hover:translate-x-0.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
|
|
</svg>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
{% else %}
|
|
<!-- Empty State -->
|
|
<div class="text-center py-16">
|
|
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full
|
|
bg-[var(--bg-secondary)] mb-4">
|
|
<svg class="w-8 h-8 text-[var(--text-muted)]" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 10h16M4 14h16M4 18h16"/>
|
|
</svg>
|
|
</div>
|
|
<h3 class="text-lg font-semibold text-[var(--text-primary)] mb-1">
|
|
{{ _('Nessun task disponibile') }}
|
|
</h3>
|
|
<p class="text-sm text-[var(--text-secondary)] max-w-md mx-auto">
|
|
{{ _('Questa ricetta non ha ancora task definiti.') }}
|
|
</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Bottom Navigation -->
|
|
<div class="mt-8 flex items-center justify-between">
|
|
<a href="{{ url_for('measure.select_recipe') }}"
|
|
class="btn btn-secondary gap-2">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
|
|
</svg>
|
|
{{ _('Seleziona altra ricetta') }}
|
|
</a>
|
|
|
|
{% if tasks %}
|
|
<div class="text-sm text-[var(--text-secondary)]">
|
|
{{ tasks|length }} task ·
|
|
{% set total_subs = namespace(count=0) %}
|
|
{% for t in tasks %}
|
|
{% if t.subtask_count is defined %}
|
|
{% set total_subs.count = total_subs.count + t.subtask_count %}
|
|
{% elif t.subtasks %}
|
|
{% set total_subs.count = total_subs.count + t.subtasks|length %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% if total_subs.count > 0 %}
|
|
{{ total_subs.count }} {{ _('misurazioni totali') }}
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
</div>
|
|
{% endblock %}
|