Feedback was saving to DB but never loaded back on page revisit. Three-point fix: - Backend schema: add feedback list to OutputRowResponse - Backend service: eagerly load feedback relationship in preview query - Frontend mapper: map latest feedback entry to OutputRow.feedback Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
105 lines
3.1 KiB
Python
105 lines
3.1 KiB
Python
from uuid import UUID
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy.orm import selectinload
|
|
|
|
from app.models.job import LocaleInstance
|
|
from app.models.output import OutputRow
|
|
from app.models.source import SourceLine
|
|
from app.schemas.output import (
|
|
OutputPreviewResponse,
|
|
OutputRowResponse,
|
|
SourceLinePreview,
|
|
)
|
|
|
|
|
|
class OutputService:
|
|
"""Service for assembling output preview data and triggering exports."""
|
|
|
|
async def get_preview(
|
|
self,
|
|
db: AsyncSession,
|
|
job_id: UUID,
|
|
locale_code: str,
|
|
) -> OutputPreviewResponse | None:
|
|
"""Assemble output preview data for a specific locale instance."""
|
|
# Get the locale instance
|
|
result = await db.execute(
|
|
select(LocaleInstance)
|
|
.where(
|
|
LocaleInstance.job_id == job_id,
|
|
LocaleInstance.locale_code == locale_code,
|
|
)
|
|
)
|
|
instance = result.scalar_one_or_none()
|
|
if instance is None:
|
|
return None
|
|
|
|
# Get source lines
|
|
source_result = await db.execute(
|
|
select(SourceLine)
|
|
.where(SourceLine.job_id == job_id)
|
|
.order_by(SourceLine.row_order)
|
|
)
|
|
source_lines = [
|
|
SourceLinePreview.model_validate(sl)
|
|
for sl in source_result.scalars().all()
|
|
]
|
|
|
|
# Get output rows with feedback eagerly loaded
|
|
output_result = await db.execute(
|
|
select(OutputRow)
|
|
.where(OutputRow.instance_id == instance.id)
|
|
.order_by(OutputRow.row_order)
|
|
.options(selectinload(OutputRow.feedback))
|
|
)
|
|
output_rows = [
|
|
OutputRowResponse.model_validate(row)
|
|
for row in output_result.scalars().all()
|
|
]
|
|
|
|
return OutputPreviewResponse(
|
|
locale_code=locale_code,
|
|
instance_id=instance.id,
|
|
source_lines=source_lines,
|
|
output_rows=output_rows,
|
|
total_rows=len(output_rows),
|
|
)
|
|
|
|
async def get_output_rows(
|
|
self,
|
|
db: AsyncSession,
|
|
instance_id: UUID,
|
|
) -> list[OutputRow]:
|
|
"""Get all output rows for a locale instance."""
|
|
result = await db.execute(
|
|
select(OutputRow)
|
|
.where(OutputRow.instance_id == instance_id)
|
|
.order_by(OutputRow.row_order)
|
|
)
|
|
return list(result.scalars().all())
|
|
|
|
async def trigger_export(
|
|
self,
|
|
db: AsyncSession,
|
|
job_id: UUID,
|
|
locale_code: str,
|
|
) -> str | None:
|
|
"""Trigger export generation for a locale and return the file path."""
|
|
result = await db.execute(
|
|
select(LocaleInstance)
|
|
.where(
|
|
LocaleInstance.job_id == job_id,
|
|
LocaleInstance.locale_code == locale_code,
|
|
)
|
|
)
|
|
instance = result.scalar_one_or_none()
|
|
if instance is None:
|
|
return None
|
|
|
|
if instance.output_file_path:
|
|
return instance.output_file_path
|
|
|
|
# Export would be triggered here; for now return None indicating no export yet
|
|
return None
|