Reproduction steps
- Open a playlist from Playlists (i.e. be on the playlist detail page,
/playlist/<id>)
- On any video in that playlist, open the "..." menu → Add to playlist
- Choose Create new playlist, name it, press Create
- In the re-opened dialog, tick the new playlist and press Add
Adding to an existing playlist from the playlist detail page reproduces it too — "Create new playlist" is just the most common way to hit it.
Actual result
The playlist page is replaced by a loading spinner that never resolves. The page stays that way until you navigate away and back.
Note the add itself succeeds server-side — the video really is in the target playlist. Only the view dies, which makes it look like "nothing happened".
Expected result
The dialog closes and the playlist page stays rendered (refreshed in place).
Grayjay Version
Desktop, versionCode 17 (stable), Linux x86_64 (Flathub app.grayjay.Grayjay).
This is not Flatpak-specific — the cause is in the shared web frontend and I confirmed both lines below are present in current master.
What plugins are you seeing the problem on?
N/A — plugin-independent UI bug.
Are you using a VPN?
No
Root cause
Grayjay.Desktop.Web/src/pages/Playlist/index.tsx:65 passes an id-less refetch callback to PlaylistDetailView:
refetch={() => refetch()} // drops the playlist id
refetch(id?) (same file, ~lines 15–30) takes its else branch when called with undefined and does setPlaylist(undefined). The render gate at line 37 is:
<Show when={playlist$() && !isLoading$()} fallback={<CenteredLoader />}>
so clearing the signal renders CenteredLoader permanently.
Nothing recovers it:
- the only fetch trigger is
createEffect(async () => await refetch(params.id)) (lines 32–34), which tracks params.id — unchanged, so it never re-runs;
- the playlist detail page registers no
PlaylistsChanged websocket handler (only the playlists list page does, pages/Playlists/index.tsx:51), so the broadcast from StatePlaylists.CreateOrUpdate doesn't rescue it either.
Call path: components/PlaylistDetailView/index.tsx:73 → UIOverlay.overlayAddToPlaylist(content, () => props.refetch?.()) → on Add, onAdded invokes the id-less refetch().
The sibling remove-handler at pages/Playlist/index.tsx:61 already calls refetch(id) correctly, which suggests this is simply an oversight.
Suggested fix
--- a/Grayjay.Desktop.Web/src/pages/Playlist/index.tsx
+++ b/Grayjay.Desktop.Web/src/pages/Playlist/index.tsx
@@ -62,7 +62,7 @@ const PlaylistPage: Component = () => {
}}
onAddToQueue={(v) => video?.actions?.addToQueue(v)}
onDownload={() => {}}
- refetch={() => refetch()}
+ refetch={() => refetch(params.id)}
onDragEnd={async () => {
const playlist = playlist$();
if (playlist) {
Adjacent bug found while tracing this (same patch): Grayjay.Desktop.Web/src/overlays/OverlayDialog/index.tsx:152 calls checkedInputs.splice(index) with no delete count in the checkbox handler, so unchecking one item silently removes that item and every selection after it:
--- a/Grayjay.Desktop.Web/src/overlays/OverlayDialog/index.tsx
+++ b/Grayjay.Desktop.Web/src/overlays/OverlayDialog/index.tsx
@@ -149,7 +149,7 @@ const OverlayDialog: Component<OverlayDialogProps> = (props: OverlayDialogProps)
changed = true;
}
if (!next && index >= 0) {
- checkedInputs.splice(index);
+ checkedInputs.splice(index, 1);
changed = true;
}
output.selected = checkedInputs;
Optional hardening, not in the patch above:
- make
refetch() with no id keep the current playlist instead of clearing state, so a future id-less caller degrades gracefully;
- register a
PlaylistsChanged handler on the detail page — though note StatePlaylists.AddContentToPlaylists never fires OnPlaylistsChanged, so plain adds don't broadcast at all today.
Happy to submit this as a merge request if that's useful — I understand development happens on gitlab.futo.org and self-registration there is closed, so let me know how you'd prefer to take it. Disclosure: the change is mechanical and read-verified against master, but I have not built the frontend locally to runtime-test it.
References
Reproduction steps
/playlist/<id>)Adding to an existing playlist from the playlist detail page reproduces it too — "Create new playlist" is just the most common way to hit it.
Actual result
The playlist page is replaced by a loading spinner that never resolves. The page stays that way until you navigate away and back.
Note the add itself succeeds server-side — the video really is in the target playlist. Only the view dies, which makes it look like "nothing happened".
Expected result
The dialog closes and the playlist page stays rendered (refreshed in place).
Grayjay Version
Desktop, versionCode 17 (stable), Linux x86_64 (Flathub
app.grayjay.Grayjay).This is not Flatpak-specific — the cause is in the shared web frontend and I confirmed both lines below are present in current
master.What plugins are you seeing the problem on?
N/A — plugin-independent UI bug.
Are you using a VPN?
No
Root cause
Grayjay.Desktop.Web/src/pages/Playlist/index.tsx:65passes an id-less refetch callback toPlaylistDetailView:refetch(id?)(same file, ~lines 15–30) takes itselsebranch when called withundefinedand doessetPlaylist(undefined). The render gate at line 37 is:so clearing the signal renders
CenteredLoaderpermanently.Nothing recovers it:
createEffect(async () => await refetch(params.id))(lines 32–34), which tracksparams.id— unchanged, so it never re-runs;PlaylistsChangedwebsocket handler (only the playlists list page does,pages/Playlists/index.tsx:51), so the broadcast fromStatePlaylists.CreateOrUpdatedoesn't rescue it either.Call path:
components/PlaylistDetailView/index.tsx:73→UIOverlay.overlayAddToPlaylist(content, () => props.refetch?.())→ on Add,onAddedinvokes the id-lessrefetch().The sibling remove-handler at
pages/Playlist/index.tsx:61already callsrefetch(id)correctly, which suggests this is simply an oversight.Suggested fix
Adjacent bug found while tracing this (same patch):
Grayjay.Desktop.Web/src/overlays/OverlayDialog/index.tsx:152callscheckedInputs.splice(index)with no delete count in the checkbox handler, so unchecking one item silently removes that item and every selection after it:Optional hardening, not in the patch above:
refetch()with no id keep the current playlist instead of clearing state, so a future id-less caller degrades gracefully;PlaylistsChangedhandler on the detail page — though noteStatePlaylists.AddContentToPlaylistsnever firesOnPlaylistsChanged, so plain adds don't broadcast at all today.Happy to submit this as a merge request if that's useful — I understand development happens on gitlab.futo.org and self-registration there is closed, so let me know how you'd prefer to take it. Disclosure: the change is mechanical and read-verified against master, but I have not built the frontend locally to runtime-test it.
References