Skip to content

Fix top-genres banner overlap + polling backoff after 90%#102

Merged
vanajmoorthy merged 3 commits into
mainfrom
feat/banner-overlap-and-polling-backoff
May 5, 2026
Merged

Fix top-genres banner overlap + polling backoff after 90%#102
vanajmoorthy merged 3 commits into
mainfrom
feat/banner-overlap-and-polling-backoff

Conversation

@vanajmoorthy
Copy link
Copy Markdown
Owner

@vanajmoorthy vanajmoorthy commented May 5, 2026

Two small dashboard follow-ups from PR #98's deferred list, plus refactor from review feedback.

1. Banner no longer collides with content; row tiles align

The "Still enriching" banner is absolute top-0 inset-x-0 z-10. Tiles WITH the banner had their content overlapped (page-count number partially covered, donut chart sat under the translucent yellow); sibling tiles in the same row had no offset and looked misaligned.

Fix: every tile inside an .enrichment-row grid reserves a banner-height zone via a single CSS rule:

.enrichment-row:has(.enrichment-banner) > * { padding-top: 1.75rem; }
@media (min-width: 768px) {
    .enrichment-row:has(.enrichment-banner) .enrichment-corner-chart {
        top: 1.75rem !important;
    }
}

The enrichment_banner.html partial now actually renders nothing when enrichment.pending is false (was relying on Alpine x-show), so :has() is a true signal. Four row containers gained the .enrichment-row marker class; the corner charts in top-genres/top-authors gained .enrichment-corner-chart. Replaces ten copies of {% if enrichment.pending %}pt-7{% endif %} from earlier iterations of this PR.

2. Polling backoff once enrichment crosses 90%

enrichmentPoller polled /api/enrichment-status/ on a fixed 5s interval. The last 10% of enrichment is mostly long-tail stragglers (books in retry/backoff), so the dashboard kept hammering the server every 5s for what could be several minutes.

Fix: when percent > 90, switch to a 12s interval. The threshold is monotonic — once we've slowed down, we never speed back up — so a non-monotonic percent (rounding, denominator shifts when a new book lands mid-pass) can't thrash the timer. poll() also guards on an inFlight flag so a hung fetch can't stack up behind a fresh interval.

Test plan

  • docker-compose -f docker-compose.local.yml exec web poetry run python manage.py test → 343 passed
  • pnpm run build.enrichment-row:has(.enrichment-banner) present in built CSS
  • Manual verification (4 scenarios):
    • Desktop, enrichment pending: tiles in banner rows align; chart sits below banner; banner doesn't cover the page-count number
    • Desktop, enrichment complete (after auto-reload): no banner, no extra padding, chart back at top-2
    • Mobile, enrichment pending: cards stack vertically; banner-bearing tile clears its banner; sibling tiles get the same pt-7 (extra empty space at top, harmless on stacked layout)
    • DevTools → Network: /api/enrichment-status/ fires every ~5s while percent ≤ 90, then every ~12s after

Two small dashboard fixes from the StoryGraph PR's deferred follow-ups:

1. Top-genres donut chart no longer collides with the "Still enriching"
   banner. The banner is absolute-positioned full-width across the top of
   the card; the chart is also absolute-positioned at top-2 right-2. When
   enrichment is pending, push the chart down to top-8 so it sits below
   the banner instead of underneath it.

2. Once enrichment crosses 90%, the dashboard polls /api/enrichment-status/
   every 12s instead of every 5s. The final stretch is mostly the long
   tail of stragglers — no need to keep hammering the server.
The "Still enriching" banner is absolute-positioned, so a tile *with* a
banner had its content pushed down (heading, chart, big number) while
sibling tiles in the same row kept their content flush with the top —
visually misaligned, and on the key-stats row the banner partially
covered the page-count number.

Fix: when enrichment.pending, every tile in an affected row gets pt-7,
reserving a consistent banner-height zone. Tiles with a banner display
it in that zone; sibling tiles see only empty space, but at the same
height. Genres chart also drops to md:!top-7 to clear the banner.

Tiles touched: niche_read, mainstream_gauge, key_stats (all three),
top_genres_authors (both), fiction_nonfiction (card + skeleton),
book_extremes (card + skeleton).
Three review-pass fixes for PR #102.

1. Polling thrash: adjustInterval is now monotonic — once we've slowed to
   12s, we never speed back up. A non-monotonic percent (rounding,
   denominator shifts when a new book lands mid-pass) can no longer thrash
   the timer.

2. Concurrent fetches: poll() guards on this.inFlight so a hung fetch can't
   stack up behind a new interval. Cleared in finally regardless of error.

3. Replaced ten copies of `{% if enrichment.pending %}pt-7{% endif %}` with
   one CSS rule:

       .enrichment-row:has(.enrichment-banner) > * { padding-top: 1.75rem; }

   The banner partial now actually renders nothing when not pending (was
   relying on Alpine x-show), so :has() is a true signal. Row containers
   (key_stats, top_genres_authors, plus the two grids in dashboard.html)
   gained the .enrichment-row marker class. Corner charts in top-genres
   /top-authors are pushed down by a sibling @media rule.
@vanajmoorthy vanajmoorthy merged commit 73606dd into main May 5, 2026
1 check passed
@vanajmoorthy vanajmoorthy deleted the feat/banner-overlap-and-polling-backoff branch May 5, 2026 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant