fix(playlists): an Undo puts a row back after its old neighbour, not at a stale index
A raw index recorded at removal drifted once anything changed before the Undo. Both lists now read the list fresh and re-insert each row after the row that preceded it (lib/reinsert). A failed watched toggle in a Plex playlist also puts the row's state back: its local copy was never re-seeded.
This commit is contained in:
@@ -24,6 +24,7 @@ import { notify } from "../lib/notifications";
|
||||
import { notifyActionError } from "../lib/actionErrors";
|
||||
import { notifyYouTubeActionError } from "../lib/youtubeErrors";
|
||||
import { playlistName } from "../lib/playlistName";
|
||||
import { reinsertAt } from "../lib/reinsert";
|
||||
import { useUndoable } from "../lib/useUndoable";
|
||||
import { cycleSort, type SortState } from "../lib/columnSort";
|
||||
import { formatRuntime } from "../lib/format";
|
||||
@@ -476,9 +477,10 @@ export default function Playlists() {
|
||||
// so the guard reset the order: the removed row came back and the undo history the rebase had
|
||||
// kept went with it. (A failure resyncs below, which puts the row back where it belongs.)
|
||||
const before = qc.getQueryData<PlaylistDetail>(qk.playlist(listId));
|
||||
// Where it stood in the STORED order — what the Undo puts it back at (the server's list, so a
|
||||
// view sort on screen does not decide it).
|
||||
const at = before?.items.findIndex((v) => v.id === video.id) ?? -1;
|
||||
// The STORED order it stood in — the Undo puts it back after its neighbour there (the server's
|
||||
// list, so a view sort on screen does not decide it; `reinsertAt`, so a change in between does
|
||||
// not shift it off by the rows added or moved meanwhile).
|
||||
const storedBefore = before?.items.map((v) => v.id) ?? [];
|
||||
qc.setQueryData<PlaylistDetail>(qk.playlist(listId), (old) =>
|
||||
old ? { ...old, items: old.items.filter((v) => v.id !== video.id) } : old,
|
||||
);
|
||||
@@ -503,10 +505,23 @@ export default function Playlists() {
|
||||
action: {
|
||||
label: t("common.undo"),
|
||||
// ONE request that puts it back at its index (the server renumbers around it): an append
|
||||
// plus a whole-list reorder would land it at the end whenever the second call failed.
|
||||
// plus a whole-list reorder would land it at the end whenever the second call failed. The
|
||||
// index is worked out against the list as it is NOW, fetched fresh.
|
||||
onClick: () =>
|
||||
void api
|
||||
.addToPlaylist(listId, video.id, at < 0 ? undefined : at)
|
||||
void qc
|
||||
.fetchQuery({
|
||||
queryKey: qk.playlist(listId),
|
||||
queryFn: () => api.playlist(listId),
|
||||
staleTime: 0,
|
||||
})
|
||||
.then((now) => {
|
||||
const back = reinsertAt(
|
||||
storedBefore,
|
||||
[video.id],
|
||||
now.items.map((v) => v.id),
|
||||
);
|
||||
if (back.keys.length) return api.addToPlaylist(listId, video.id, back.positions[0]);
|
||||
})
|
||||
.catch((e: unknown) => notifyActionError(e, t("playlists.undoRemoveFailed")))
|
||||
.finally(() => {
|
||||
refreshAll(listId);
|
||||
|
||||
Reference in New Issue
Block a user