diff --git a/frontend/src/components/tables/M3UsTable.jsx b/frontend/src/components/tables/M3UsTable.jsx index 6e018b95..bd6a94d5 100644 --- a/frontend/src/components/tables/M3UsTable.jsx +++ b/frontend/src/components/tables/M3UsTable.jsx @@ -39,6 +39,9 @@ const M3UTable = () => { } switch (data.action) { + case 'initializing': + return buildInitializingStats(); + case 'downloading': return buildDownloadingStats(data); @@ -191,6 +194,18 @@ const M3UTable = () => { ); }; + const buildInitializingStats = () => { + return ( + + + + Initializing refresh... + + + + ); + }; + const toggleActive = async (playlist) => { await API.updatePlaylist({ ...playlist, @@ -310,8 +325,28 @@ const M3UTable = () => { }; const refreshPlaylist = async (id) => { - await API.refreshPlaylist(id); - setRefreshProgress(id, 0); + // Provide immediate visual feedback before the API call + setRefreshProgress(id, { + action: 'initializing', + progress: 0, + account: id, + type: 'm3u_refresh' + }); + + try { + await API.refreshPlaylist(id); + // No need to set again since WebSocket will update us once the task starts + } catch (error) { + // If the API call fails, show an error state + setRefreshProgress(id, { + action: 'error', + progress: 0, + account: id, + type: 'm3u_refresh', + error: 'Failed to start refresh task', + status: 'error' + }); + } }; const deletePlaylist = async (id) => { diff --git a/frontend/src/store/playlists.jsx b/frontend/src/store/playlists.jsx index e04263e7..bcdfff27 100644 --- a/frontend/src/store/playlists.jsx +++ b/frontend/src/store/playlists.jsx @@ -65,13 +65,37 @@ const usePlaylistsStore = create((set) => ({ // @TODO: remove playlist profiles here })), - setRefreshProgress: (data) => - set((state) => ({ - refreshProgress: { - ...state.refreshProgress, - [data.account]: data, - }, - })), + setRefreshProgress: (accountIdOrData, data) => + set((state) => { + // If called with two parameters, it's the direct setter + if (data !== undefined) { + return { + refreshProgress: { + ...state.refreshProgress, + [accountIdOrData]: data, + }, + }; + } + + // If called with WebSocket data, preserve 'initializing' status + // until we get a real progress update from the server + const accountId = accountIdOrData.account; + const existingProgress = state.refreshProgress[accountId]; + + // Don't replace 'initializing' status with empty/early server messages + if (existingProgress && + existingProgress.action === 'initializing' && + accountIdOrData.progress === 0) { + return state; // Keep showing 'initializing' until real progress comes + } + + return { + refreshProgress: { + ...state.refreshProgress, + [accountId]: accountIdOrData, + }, + }; + }), removeRefreshProgress: (id) => set((state) => {