diff --git a/CHANGELOG.md b/CHANGELOG.md index 09dd26c07..6e240ea76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ All notable changes to Bambuddy will be documented in this file. - **P2S Shows Carbon Rod Maintenance Tasks** ([#640](https://github.com/maziggy/bambuddy/issues/640)) — The P2S was incorrectly classified as a carbon rod printer, showing "Lubricate Carbon Rods" and "Clean Carbon Rods" maintenance tasks. The P2S uses hardened steel linear shafts, not carbon fiber rods. Added a new `steel_rod` motion system category and "Lubricate Steel Rods" / "Clean Steel Rods" maintenance tasks specific to the P2S. X1/P1 series continue to show carbon rod tasks; A1/H2 series continue to show linear rail tasks. Reported by @maziggy. - **Dispatch Toast Stuck After Second Print** — The print dispatch progress toast ("Starting prints…") stayed visible forever after the second print dispatch in a session. The dedup guard (`lastDispatchSummaryRef`) that prevents duplicate completion toasts was never reset between batches, so every single-printer dispatch produced the same summary key (`"first-complete:1:0"`). The first print completed normally, but subsequent completions matched the stale ref and skipped creating the done toast — leaving the progress toast stuck in "Processing" state with no way to dismiss except a page reload. Now resets the dedup guard whenever the dispatch toast is dismissed (auto-dismiss timeout, cleanup events) and when a new batch starts. - **Archive Card Buttons Overlapping at Narrow Widths** ([#641](https://github.com/maziggy/bambuddy/issues/641)) — The "Reprint" and "Schedule" buttons at the bottom of archive cards overlapped when the browser window was narrower than the card grid expected (e.g. snapped to half-screen on a 2K monitor). The button text labels used a viewport-based `sm:` breakpoint that didn't account for actual card width. Added `overflow-hidden` to the flex buttons and `truncate` to the text spans so labels clip cleanly with ellipsis instead of bleeding into adjacent buttons. Reported by rsocko@outlook.com, confirmed by @dsmitty166. +- **Debug Logging Banner Timer Shows Negative Time** — When enabling debug logging, the banner showed a negative duration (e.g. "-60m -59s") equal to the server's UTC offset. The `enabled_at` timestamp was stored using `datetime.now()` (local time, no timezone indicator), but the frontend interpreted it as UTC. Now stores and compares all debug logging timestamps in UTC. ## [0.2.2b2] - 2026-03-06 diff --git a/backend/app/api/routes/support.py b/backend/app/api/routes/support.py index 152bc8019..2a948fb6e 100644 --- a/backend/app/api/routes/support.py +++ b/backend/app/api/routes/support.py @@ -10,7 +10,7 @@ import os import platform import re import zipfile -from datetime import datetime +from datetime import datetime, timezone from pathlib import Path from fastapi import APIRouter, HTTPException, Query @@ -62,7 +62,13 @@ async def _get_debug_setting(db: AsyncSession) -> tuple[bool, datetime | None]: enabled_at = None if enabled_at_setting and enabled_at_setting.value: try: +<<<<<<< HEAD enabled_at = datetime.fromisoformat(enabled_at_setting.value).replace(tzinfo=None) +======= + enabled_at = datetime.fromisoformat(enabled_at_setting.value) + if enabled_at.tzinfo is None: + enabled_at = enabled_at.replace(tzinfo=timezone.utc) +>>>>>>> 63208cf ( Fix debug logging banner showing negative timer duration) except ValueError: pass # Ignore malformed timestamp; enabled_at stays None @@ -80,7 +86,7 @@ async def _set_debug_setting(db: AsyncSession, enabled: bool) -> datetime | None db.add(Settings(key="debug_logging_enabled", value=str(enabled).lower())) # Update enabled_at timestamp - enabled_at = datetime.now() if enabled else None + enabled_at = datetime.now(tz=timezone.utc) if enabled else None result = await db.execute(select(Settings).where(Settings.key == "debug_logging_enabled_at")) at_setting = result.scalar_one_or_none() if at_setting: @@ -127,7 +133,7 @@ async def get_debug_logging_state( duration = None if enabled and enabled_at: - duration = int((datetime.now() - enabled_at).total_seconds()) + duration = int((datetime.now(tz=timezone.utc) - enabled_at).total_seconds()) return DebugLoggingState( enabled=enabled, @@ -149,7 +155,7 @@ async def toggle_debug_logging( duration = None if toggle.enabled and enabled_at: - duration = int((datetime.now() - enabled_at).total_seconds()) + duration = int((datetime.now(tz=timezone.utc) - enabled_at).total_seconds()) return DebugLoggingState( enabled=toggle.enabled,