feat(measure): l'operatore entra nella sequenza, non in un elenco

Punto 10. Sceglere una ricetta apriva la lista completa dei task e chiedeva
all'operatore di decidere da dove cominciare prima ancora di aver fatto
qualcosa. Ora AVVIA IN SEQUENZA porta dentro il primo task; la lista resta,
un livello sotto, per quando serve vederla tutta o tornare indietro.

- nuova rotta /measure/start/<ricetta>: memorizza lotto e seriale (prima lo
  faceva la lista, che ora si salta), verifica la tracciabilità obbligatoria
  e apre il primo task
- GET /api/measurements/task-progress: quante quote ha già preso ogni task di
  misura, contate per quota e non per tentativo, delimitate dalla produzione
  aperta o, fuori produzione, dall'operatore
- la lista distingue «Incompiuto 1/3» da «Completato 3/3»: un task lasciato a
  metà non somigliava più a uno mai aperto
- «Visualizza singolo TASK» non è più riservato al Maker — dire «incompiuto»
  senza dare la strada per tornarci sarebbe una lamentela, non una funzione
- nel task «Riepilogo» diventa «Completato» e si apre solo quando il ciclo è
  chiuso: altrimenti sarebbe la scorciatoia che rende facoltative le quote
- «Fine ciclo misura» si vede da subito, spento, e dice quante quote mancano;
  prima compariva a task già finito, quando non serviva più saperlo

Il pulsante verde del footer diventa «Task successivo»: due bottoni con la
stessa parola addosso sono uno di troppo.

Test: 334 (erano 309). Il side effect dei mock del client Flask ora risponde
per endpoint invece che per turno — una lista posizionale si rompe appena una
pagina fa una domanda in più al server, che è come crescono tutte.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-07-28 21:31:42 +00:00
parent 919ee7ac79
commit 98b1c5ae85
15 changed files with 1656 additions and 659 deletions
@@ -24,6 +24,8 @@ from unittest.mock import MagicMock, patch
import pytest
from tests.conftest import api_get_router
# Match every inline <script>…</script> (i.e. without `src=`) so we don't try
# to syntax-check Alpine.js / Plotly bundles served from a CDN.
@@ -307,13 +309,20 @@ def test_task_list_inline_js_is_valid(logged_in_client, mock_measure_api):
with it, and the operator would simply never be called back.
"""
_force_italian(logged_in_client)
mock_measure_api.get.side_effect = [
{"id": 3, "code": "REC-3", "name": "Ricetta", "description": None},
[{
mock_measure_api.get.side_effect = api_get_router({
"/api/recipes/3/tasks": [{
"id": 11, "order_index": 0, "title": "Quota d'ingresso",
"task_type": "measure", "subtasks": [], "file_path": None,
}],
]
"/api/recipes/3": {
"id": 3, "code": "REC-3", "name": "Ricetta", "description": None,
"current_version": {"id": 5},
},
"/api/production-runs/current": None,
"/api/measurements/task-progress": {
"tasks": [{"task_id": 11, "quotes": 2, "measured": 1, "state": "partial"}],
},
})
resp = logged_in_client.get("/measure/tasks/3")
assert resp.status_code == 200