Keep the printer's name on statistics after it is deleted (issue #2873)

Every per-printer breakdown resolved the name against the printers that
exist now, so deleting a printer and choosing to keep its prints turned
"Ultron" into "Printer 1" in Prints by Printer, the success-rate and
time-accuracy lists, and Failures by Printer. Archives lose their printer
on that delete as well, so nothing was left to read a name from.

The runs themselves recorded the name they printed on. /archives/stats now
reports the last name each id was known by - taken from the newest run that
has one, so a later name-less row cannot blank it - and failure analysis
falls back to the same thing for ids with no printer left. The client keeps
preferring a live printer's own record, so a rename still shows up straight
away rather than after the next print.
This commit is contained in:
maziggy
2026-08-18 14:04:18 +02:00
parent cfecfa360e
commit 28781ea558
10 changed files with 221 additions and 4 deletions
+25
View File
@@ -1177,6 +1177,30 @@ async def get_archive_stats(
)
prints_by_printer = {str(k): v for k, v in printer_result.all()}
# Names for printers the client can no longer look up. The breakdowns above
# key on the id each run recorded, and deleting a printer while keeping its
# history leaves that id pointing at nothing, so a chart that used to read
# "Ultron" fell back to "Printer 1" (#2873). Every run also stored the name
# it printed on, so the last one recorded is what that id was called. The
# client still prefers a live printer's current name, which keeps a rename
# showing up straight away.
last_named_run = (
select(func.max(PrintLogEntry.id).label("entry_id"))
.where(
PrintLogEntry.printer_id.isnot(None),
PrintLogEntry.printer_name.isnot(None),
*base_conditions,
)
.group_by(PrintLogEntry.printer_id)
.subquery()
)
name_result = await db.execute(
select(PrintLogEntry.printer_id, PrintLogEntry.printer_name).join(
last_named_run, PrintLogEntry.id == last_named_run.c.entry_id
)
)
printer_names = {str(printer_id): name for printer_id, name in name_result.all()}
# Time accuracy — compare each completed run's actual duration to the
# slicer's estimate on the linked archive. Runs without a linked archive
# (NULL archive_id) or without an estimate are excluded.
@@ -1276,6 +1300,7 @@ async def get_archive_stats(
total_cost=round(total_cost, 2),
prints_by_filament_type=prints_by_filament,
prints_by_printer=prints_by_printer,
printer_names=printer_names,
average_time_accuracy=average_accuracy,
time_accuracy_by_printer=accuracy_by_printer if accuracy_by_printer else None,
total_energy_kwh=round(total_energy_kwh, 3),