Modal Esc/overflow polish, artist-scoped post scroll, failing-sources Logs button #43

Merged
bvandeusen merged 3 commits from dev into main 2026-06-01 12:10:12 -04:00
Owner

Summary

Three coupled follow-up landings from the modal/posts/downloads UX session on 2026-06-01.

4c56cf1 — modal Esc fix + Provenance 2.5-card overflow

  • Esc from inside the tag input: ImageViewer's keydown handler bailed early on isTextEntry(ev.target) for every key, so the autofocused TagAutocomplete trapped Escape. Now Escape closes the modal even from text inputs, unless a nested Vuetify overlay is open (.v-overlay--active — menus, FandomPicker, suggestion 3-dot menu) in which case that overlay handles its own Esc.
  • Provenance cards scroll at ~2.5: post cards wrap into .fc-prov__cards with max-height: 270px; overflow-y: auto; — keeps the Tags section at a consistent position regardless of provenance count; the half-clipped third card hints there's more below.

fb605af — anchored posts view inherits artist_id/platform on scroll

Operator-flagged: clicking a post title from the modal's Provenance card opens /posts?post_id=N&artist_id=A scoped correctly, but the bidirectional infinite-scroll then pulled UNFILTERED global posts. Root cause: loadAround/loadOlder/loadNewer in posts.js only sent {around, cursor, direction} — never the filters. Backend supported them on every path; frontend just wasn't passing.

Fix: loadAround(postId, filters) stores the snapshot; _aroundParams(extra) mixes the filters into all three calls; PostsView.loadAroundAndAnchor passes artist_id + platform from the route query.

94e7d20 — Logs button on failing-sources rollup rows

Each row in the "X sources are failing" rollup gets a Logs text button next to RETRY. Clicking it calls downloadsStore.loadLastForSource(source.id) — two-steps via GET /api/downloads?source_id=N&limit=1 (most recent event) then the existing loadOne(id) for the full detail payload — and opens the same DownloadDetailModal the event-row clicks use. Surfaces stdout/stderr/error/files-written/duration for troubleshooting without leaving the Downloads tab.

Test plan

  • Open the view modal, focus is in tag input by default → press Esc → modal closes.
  • Open the modal, click the kind: dropdown (or open suggestion 3-dot menu) → press Esc → only the dropdown/menu closes; modal stays.
  • Open an image with many provenance entries → cards scroll inside a fixed-height container; Tags panel anchored below.
  • Click a post title in Provenance → land in /posts?post_id=N&artist_id=A; scroll up/down and confirm only that artist's posts load.
  • In Subscriptions → Downloads, the failing-sources rollup shows a Logs button on each row; clicking opens the DownloadDetailModal for the most recent event of that source.
## Summary Three coupled follow-up landings from the modal/posts/downloads UX session on 2026-06-01. ### `4c56cf1` — modal Esc fix + Provenance 2.5-card overflow - **Esc from inside the tag input**: ImageViewer's keydown handler bailed early on `isTextEntry(ev.target)` for every key, so the autofocused TagAutocomplete trapped Escape. Now Escape closes the modal even from text inputs, unless a nested Vuetify overlay is open (`.v-overlay--active` — menus, FandomPicker, suggestion 3-dot menu) in which case that overlay handles its own Esc. - **Provenance cards scroll at ~2.5**: post cards wrap into `.fc-prov__cards` with `max-height: 270px; overflow-y: auto;` — keeps the Tags section at a consistent position regardless of provenance count; the half-clipped third card hints there's more below. ### `fb605af` — anchored posts view inherits artist_id/platform on scroll Operator-flagged: clicking a post title from the modal's Provenance card opens `/posts?post_id=N&artist_id=A` scoped correctly, but the bidirectional infinite-scroll then pulled UNFILTERED global posts. Root cause: `loadAround`/`loadOlder`/`loadNewer` in `posts.js` only sent `{around, cursor, direction}` — never the filters. Backend supported them on every path; frontend just wasn't passing. Fix: `loadAround(postId, filters)` stores the snapshot; `_aroundParams(extra)` mixes the filters into all three calls; `PostsView.loadAroundAndAnchor` passes `artist_id` + `platform` from the route query. ### `94e7d20` — Logs button on failing-sources rollup rows Each row in the "X sources are failing" rollup gets a `Logs` text button next to RETRY. Clicking it calls `downloadsStore.loadLastForSource(source.id)` — two-steps via `GET /api/downloads?source_id=N&limit=1` (most recent event) then the existing `loadOne(id)` for the full detail payload — and opens the same `DownloadDetailModal` the event-row clicks use. Surfaces stdout/stderr/error/files-written/duration for troubleshooting without leaving the Downloads tab. ## Test plan - [ ] Open the view modal, focus is in tag input by default → press Esc → modal closes. - [ ] Open the modal, click the kind: dropdown (or open suggestion 3-dot menu) → press Esc → only the dropdown/menu closes; modal stays. - [ ] Open an image with many provenance entries → cards scroll inside a fixed-height container; Tags panel anchored below. - [ ] Click a post title in Provenance → land in `/posts?post_id=N&artist_id=A`; scroll up/down and confirm only that artist's posts load. - [ ] In Subscriptions → Downloads, the failing-sources rollup shows a `Logs` button on each row; clicking opens the DownloadDetailModal for the most recent event of that source.
bvandeusen added 3 commits 2026-06-01 12:10:01 -04:00
fix(modal): Esc closes from tag input; Provenance cards scroll at ~2.5
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 22s
CI / backend-lint-and-test (push) Successful in 29s
CI / intimp (push) Successful in 3m54s
CI / intapi (push) Successful in 7m32s
CI / intcore (push) Successful in 8m16s
4c56cf121f
Two operator-flagged UX gaps from 2026-06-01:

1. **Esc trapped inside the tag-entry field**
   The autofocused TagAutocomplete input made Esc-to-close unreachable
   because ImageViewer's keydown handler bailed early on
   `isTextEntry(ev.target)` for every key including Escape. Now Escape
   closes the modal from text inputs too — except when a Vuetify
   overlay is open (FandomPicker, autocomplete dropdown, suggestion
   3-dot menu), in which case that overlay's own Esc-handling fires
   instead of closing the whole modal mid-interaction. Detected via
   `.v-overlay--active`. Arrow keys still gate on isTextEntry so the
   tag input handles typing without navigating images.

2. **Provenance cards expanded the side panel unbounded**
   When an image had many ImageProvenance entries the cards stack
   pushed the Tags section below the fold. Wrapped the cards in a
   `.fc-prov__cards` container with max-height 270px (≈2.5 cards) and
   thin overflow scrollbar. Title stays anchored at top; Tags panel
   sits at a consistent position below regardless of provenance count.
fix(posts): anchored view scroll inherits artist_id/platform filters
CI / lint (push) Successful in 3s
CI / backend-lint-and-test (push) Successful in 19s
CI / frontend-build (push) Successful in 20s
CI / intimp (push) Successful in 3m38s
CI / intapi (push) Successful in 7m20s
CI / intcore (push) Successful in 7m45s
fb605af959
Operator-flagged 2026-06-01: clicking a Provenance post title from the
view modal opens the post in the posts feed scoped to that artist
(`/posts?post_id=N&artist_id=A`), but the older/newer infinite-scroll
loaded UNFILTERED global posts instead of staying in the artist's
stream. Root cause: the posts store's loadAround/loadOlder/loadNewer
sent only `{around, cursor, direction}` — never the `artist_id` /
`platform` filters. Backend `/api/posts` accepts them on every path
(post_feed_service.scroll filters via `Source.artist_id`); the
frontend just wasn't passing them.

Fix:
- `posts.js` `loadAround(postId, filters)` now takes the filter
  snapshot and stores it. `_aroundParams(extra)` mixes the active
  filters into around/cursor calls.
- `PostsView.vue` `loadAroundAndAnchor` passes `artist_id` +
  `platform` from the route query.
feat(downloads): Logs button on failing-sources rollup rows
CI / lint (push) Successful in 3s
CI / backend-lint-and-test (push) Successful in 16s
CI / frontend-build (push) Successful in 18s
CI / intimp (push) Successful in 3m41s
CI / intapi (push) Successful in 7m43s
CI / intcore (push) Successful in 8m10s
94e7d20792
Operator-asked 2026-06-01: each row in the "X sources are failing"
rollup needs a button to surface the last run's stdout/stderr/error
without leaving the Downloads tab to find the matching event row.

Wired:
- `downloadsStore.loadLastForSource(sourceId)` two-steps via
  `GET /api/downloads?source_id=N&limit=1` (most recent event) then
  the existing `loadOne(id)` for the full detail payload. Returns
  null if no events exist (toast warns).
- `FailingSourcesCard` row: new text button `Logs` with
  `mdi-text-box-search-outline`, per-row spinner via `logLoadingIds`,
  emits `view-logs` with the source record.
- `DownloadsTab.onViewFailingLogs` is the handler — same
  `DownloadDetailModal` instance the event-row clicks use.
bvandeusen merged commit 8cf8d2ca4d into main 2026-06-01 12:10:12 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/FabledCurator#43