fix: Task back button navigates to correct recipe (not version_id)

- Add recipe_id property to RecipeTask model (via version relationship)
- Add recipe_id to TaskResponse schema
- Eager-load version in _get_task_or_404 query
- Use task.recipe_id instead of task.version_id in task_execute template URLs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Adriano
2026-02-08 10:34:23 +01:00
parent 00d6c68b2f
commit f665bffb7a
4 changed files with 15 additions and 4 deletions
+3 -3
View File
@@ -72,7 +72,7 @@
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
{# Breadcrumb line #} {# Breadcrumb line #}
<div class="flex items-center gap-2 mb-1.5 flex-wrap"> <div class="flex items-center gap-2 mb-1.5 flex-wrap">
<a href="{{ url_for('measure.task_list', recipe_id=task.version_id or task.recipe_id or 0) }}" <a href="{{ url_for('measure.task_list', recipe_id=task.recipe_id or 0) }}"
class="text-xs text-[var(--text-muted)] hover:text-primary transition-colors inline-flex items-center gap-1"> class="text-xs text-[var(--text-muted)] hover:text-primary transition-colors inline-flex items-center gap-1">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"> <svg class="w-3.5 h-3.5" 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"/> <path stroke-linecap="round" stroke-linejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
@@ -410,7 +410,7 @@
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
{# Left: Back button #} {# Left: Back button #}
<a href="{{ url_for('measure.task_list', recipe_id=task.version_id or task.recipe_id or 0) }}" <a href="{{ url_for('measure.task_list', recipe_id=task.recipe_id or 0) }}"
class="btn btn-secondary text-xs shrink-0 gap-1.5"> class="btn btn-secondary text-xs shrink-0 gap-1.5">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"> <svg class="w-3.5 h-3.5" 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"/> <path stroke-linecap="round" stroke-linejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
@@ -736,7 +736,7 @@ function taskExecute() {
// ---- Go to summary ---- // ---- Go to summary ----
goToSummary() { goToSummary() {
const recipeId = this.task.version_id || this.task.recipe_id || 0; const recipeId = this.task.recipe_id || 0;
window.location.href = '{{ url_for("measure.task_complete", recipe_id=0) }}'.replace('/0', '/' + recipeId) + window.location.href = '{{ url_for("measure.task_complete", recipe_id=0) }}'.replace('/0', '/' + recipeId) +
'?version_id=' + encodeURIComponent(this.task.version_id || ''); '?version_id=' + encodeURIComponent(this.task.version_id || '');
}, },
+7
View File
@@ -39,6 +39,13 @@ class RecipeTask(Base):
{"mysql_engine": "InnoDB", "mysql_charset": "utf8mb4"}, {"mysql_engine": "InnoDB", "mysql_charset": "utf8mb4"},
) )
@property
def recipe_id(self) -> int | None:
"""Shortcut: recipe_id via the version relationship."""
if self.version:
return self.version.recipe_id
return None
def __repr__(self) -> str: def __repr__(self) -> str:
return f"<RecipeTask #{self.order_index} '{self.title}'>" return f"<RecipeTask #{self.order_index} '{self.title}'>"
+4 -1
View File
@@ -55,7 +55,10 @@ async def _get_task_or_404(db: AsyncSession, task_id: int) -> RecipeTask:
result = await db.execute( result = await db.execute(
select(RecipeTask) select(RecipeTask)
.where(RecipeTask.id == task_id) .where(RecipeTask.id == task_id)
.options(selectinload(RecipeTask.subtasks)) .options(
selectinload(RecipeTask.subtasks),
selectinload(RecipeTask.version),
)
) )
task = result.scalar_one_or_none() task = result.scalar_one_or_none()
if task is None: if task is None:
+1
View File
@@ -73,6 +73,7 @@ class TaskResponse(BaseModel):
id: int id: int
version_id: int version_id: int
recipe_id: Optional[int] = None
order_index: int order_index: int
title: str title: str
directive: Optional[str] = None directive: Optional[str] = None