Skip to content

fix: dashboards never lose or duplicate accounts - #149

Merged
builtbyproxy merged 11 commits into
mainfrom
audit/stack-06-dashboard-safety
Oct 8, 2026
Merged

builtbyproxy merged 11 commits into
mainfrom
audit/stack-06-dashboard-safety

Conversation

@builtbyproxy

@builtbyproxy builtbyproxy commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

Layer 6 of the audit fix stack (releases 2.10.9). Fixes audit findings UI-1 to UI-11, UI-13, UI-21 to UI-25, UI-28 (with COR-14); the full audit is tracked privately. Stacked on #148.

Includes two commits by @WouterStulp from his fork (load/save failure reporting and the Integrations save result).

Release notes

The Jellyscribe dashboards now keep your accounts safe when something goes wrong. If your accounts or activity can't be loaded, the page says so and offers Retry instead of showing an empty list or zeros, so a save can no longer wipe your linked diaries. A failed or repeated Save never adds an account twice, and Remove now asks you to confirm in the page and only removes the account once the server has. Every save, sync, login check and review now tells you when it fails and why, rather than hanging on "Saving…" or claiming everything was up to date, and a sync whose progress can't be read stops with a clear message. A review with only a star rating now sets your Letterboxd rating instead of always failing. A review that lands on some of your accounts says which ones it missed. Review is no longer offered on rows that can't be reviewed. The rewatch date defaults to your own local date, and selecting text in a modal no longer closes it. On the admin dashboard, saving settings no longer undoes account changes your users made in the meantime, Sync all now also runs the TV sync for every user, and the overview is labelled as your own activity. Opening Jellyscribe from the sidebar while the admin settings page is still loaded now works. Thanks to Wouter Stulp, whose fixes for showing load and save failures and for reporting the Integrations save result are included.

What's broken

  • A failed load can wipe your accounts. If the user page can't load "My accounts", it shows an empty list with "Link a diary". Adding one account from there replaces every stored account. The overview shows zeros and "No activity yet" for someone with years of history.
  • Failed saves duplicate. A failed save, or a double click, leaves the account in the page's list. Pressing Save again sends it twice, and it syncs twice. On the admin page a failed save hangs on "Saving…".
  • Remove has no confirmation. It deletes on one click, and a failed delete still vanishes from the list.
  • Admin saves overwrite users' changes. The admin page saves the config it loaded when it opened. Accounts users added or changed in the meantime are silently undone.
  • Errors are swallowed. A refused sync (no account, already running) says "Everything was already up to date". A failing progress endpoint spins forever with the buttons disabled. Verify and Post review can hang on "Verifying…" or "Posting…".
  • Reviews.
    • A rating-only review always fails with "Failed to post.".
    • Post review can be pressed twice.
    • A review that lands on one of two accounts is reported as posted.
    • Rows without a film slug offer a Review that always fails.
  • The in-app page breaks with the admin page cached. Opening the in-app page while Jellyfin still has the admin settings page cached leaves it empty, because both pages use the same element ids.
  • The admin overview misleads. It looks server-wide but shows only the admin's own history, and "Sync all now" runs TV sync for the admin only.
  • Small modal issues. The rewatch date defaults to the UTC date. Selecting text in a modal and releasing outside it closes the modal and loses the draft.

Why it happens

  • Failures are hidden. Both pages catch failures and carry on with empty data (.catch(() => ({ accounts: [] })), .catch(function () {})).
  • Local state changes too early. It changes before the request, and nothing restores it on failure.
  • The admin save is stale. It posts the page's copy of the config, never the stored one.
  • Sync responses are not checked. The buttons start the progress watcher before the POST returns and never look at its status. Progress failures return early without counting.
  • The rating-only path does not exist on the server. The modal allows a rating-only review, but the endpoint requires text unless it is a rewatch.
  • Global lookups. userPage.html looks everything up with document.getElementById, so a cached admin page's elements win.
  • The admin sync calls are per-caller. The admin's TV sync calls the per-user SyncNow endpoint.

What this PR does

  • Wouter Stulp's two fork commits:
    • "show load and save failures instead of swallowing them" and "report the Integrations save result";
    • conflicts resolved onto the upstream write-only-secrets work, with his ntfy parts dropped.
  • Load failures: an error with Retry on both pages. Nothing that could save is shown until accounts have loaded.
  • Saves:
    • work on a copy, and the page changes only after success;
    • Save and Remove are disabled while in flight;
    • the server's error is shown.
  • Remove: an in-page confirm step.
  • Admin saves: re-read the stored config right before saving and apply only the edit. Accounts are matched by owner and login.
  • Sync buttons:
    • check each start and show the server's reason;
    • watch progress only when a start was accepted;
    • stop with "Progress unavailable" after repeated poll failures;
    • on the admin page, start the scheduled tasks for both services (every user).
  • POST Review: with stars only, it sets the film rating (SetFilmRatingAsync) and records it like RatingSyncHandler. Review errors come back as one short line.
  • Review modal:
    • Post and Cancel disabled while posting;
    • per-account results;
    • no Review button on Letterboxd rows without a slug;
    • local rewatch date.
  • In-app page:
    • sidebar.js opens the settings page when the admin page is cached;
    • userPage.html scopes every lookup to its own root.
  • Modals: close on the backdrop only for a press and release both on it.
  • Admin overview: labelled as the admin's own.

How it was tested

  • dotnet test -c Release --filter "FullyQualifiedName!~Integration": 1261 passed.
  • New ReviewRatingOnlyTests:
    • the rating is set and no diary entry is posted;
    • the result is recorded as Rated and as the last pushed rating;
    • a failure records nothing and leaves the Jellyfin rating alone;
    • validation, error sanitising and per-account results.
  • New DashboardTaskKeysTests: pins the admin page's task keys to the registered tasks. Mutation checks fail both test classes.
  • Stub harness (56 checks): a Playwright run on the UI reviewer's stub harness covers every case above on both pages. All pass on this branch, and 43 fail on the base.
  • Cached admin page: simulated with the reviewer's harness. Base renders an empty in-app page. With only the new scoping, it fills and leaves the admin copy alone. As shipped, it opens the settings page.
  • Throwaway Jellyfin 12.0 screenshots:
    • plugin API failures and replies were faked with Playwright request interception;
    • Letterboxd, Serializd and Seerr hosts were blocked;
    • no real service was contacted.
    • The 10.11 container kept exiting with code 132, so all shots are from 12.0.

Screenshots

Taken on throwaway Jellyfin test servers with placeholder users and data.

Before: accounts failed to load, empty list invites a new link

Before: accounts failed to load, empty list invites a new link

After: error with Retry

After: error with Retry

Before: failed save stuck on Saving and sent twice

Before: failed save stuck on Saving and sent twice

After: reason shown, sent once

After: reason shown, sent once

Before: Remove with no confirmation

Before: Remove with no confirmation

After: in-page confirm step

After: in-page confirm step

Before: overview failure shows zeros and 'No activity yet'

Before: overview failure shows zeros and 'No activity yet'

After: error with Retry

After: error with Retry

Before: rating-only review fails

Before: rating-only review fails

After: rating saved to Letterboxd

After: rating saved to Letterboxd

After: in-app route with the admin page cached falls back to a working dashboard

After: in-app route with the admin page cached falls back to a working dashboard

@builtbyproxy
builtbyproxy added this pull request to stack #150 October 7, 2026 11:50
@builtbyproxy builtbyproxy changed the title audit/stack 06 dashboard safety fix: dashboards never lose or duplicate accounts Oct 7, 2026
@builtbyproxy
builtbyproxy force-pushed the audit/stack-06-dashboard-safety branch from d1696d1 to 3877898 Compare October 8, 2026 02:15
@builtbyproxy
builtbyproxy force-pushed the audit/stack-06-dashboard-safety branch 3 times, most recently from bef89b3 to bd55cc7 Compare October 8, 2026 02:22
@builtbyproxy
builtbyproxy force-pushed the audit/stack-06-dashboard-safety branch from bd55cc7 to 85868e4 Compare October 8, 2026 02:22
@builtbyproxy
builtbyproxy force-pushed the audit/stack-06-dashboard-safety branch 3 times, most recently from 273bbb3 to faa173f Compare October 8, 2026 02:30
@builtbyproxy
builtbyproxy force-pushed the audit/stack-06-dashboard-safety branch from faa173f to 10b0bf8 Compare October 8, 2026 02:32
Base automatically changed from audit/stack-05-reliability to main October 8, 2026 02:33
@builtbyproxy
builtbyproxy force-pushed the audit/stack-06-dashboard-safety branch from 10b0bf8 to 5761160 Compare October 8, 2026 02:33
WouterStulp and others added 9 commits October 8, 2026 12:36
…hed, by scoping its lookups and opening the settings page instead
…ess, verify and review failures, and offer Review only where it works
…syncs for every user, label the overview as the admin's own, and report every failure
…eep the rating title plain, refuse a non-finite rating, and let Retry call only the loaders
…p words apart in a rating title, scope the disabled-button style, and pin the dashboard's task keys
@builtbyproxy
builtbyproxy force-pushed the audit/stack-06-dashboard-safety branch from 5761160 to 7ab2aae Compare October 8, 2026 02:36
@builtbyproxy
builtbyproxy merged commit f45fa6b into main Oct 8, 2026
4 checks passed
@builtbyproxy
builtbyproxy deleted the audit/stack-06-dashboard-safety branch October 8, 2026 03:31
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.

2 participants