Bug Fix: Channels table pagination error handling: Fixed "Invalid page" error notifications that appeared when filters reduced the result set while on a page beyond the new total. The API layer now automatically detects invalid page errors, resets pagination to page 1, and retries the request transparently. (Fixes #864)
Some checks are pending
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
Frontend Tests / test (push) Waiting to run

This commit is contained in:
SergeantPanda 2026-01-23 10:33:14 -06:00
parent 6e70753d1c
commit d4f412e352
3 changed files with 82 additions and 16 deletions

View file

@ -51,6 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Channels table pagination error handling: Fixed "Invalid page" error notifications that appeared when filters reduced the result set while on a page beyond the new total. The API layer now automatically detects invalid page errors, resets pagination to page 1, and retries the request transparently. (Fixes #864)
- Fixed long IP addresses overlapping adjacent columns in stream connection card by adding truncation with tooltips displaying the full address. (Fixes #712)
- Fixed nginx startup failure due to group name mismatch in non-container deployments - Thanks [@s0len](https://github.com/s0len) (Fixes #877)
- Updated streamlink from 8.1.0 to 8.1.2 to fix YouTube live stream playback issues and improve Pluto TV ad detection (Fixes #869)

View file

@ -198,6 +198,31 @@ export default class API {
return response;
} catch (e) {
// Handle invalid page error by resetting to page 1 and retrying
if (e.body?.detail === 'Invalid page.') {
const currentPagination = useChannelsTableStore.getState().pagination;
// Only retry if we're not already on page 1
if (currentPagination.pageIndex > 0) {
// Reset to page 1
useChannelsTableStore.getState().setPagination({
...currentPagination,
pageIndex: 0,
});
// Update params to page 1 and retry
const newParams = new URLSearchParams(params);
newParams.set('page', '1');
const response = await request(
`${host}/api/channels/channels/?${newParams.toString()}`
);
useChannelsTableStore.getState().queryChannels(response, newParams);
return response;
}
}
errorNotification('Failed to fetch channels', e);
}
}
@ -218,6 +243,39 @@ export default class API {
return response;
} catch (e) {
// Handle invalid page error by resetting to page 1 and retrying
if (e.body?.detail === 'Invalid page.') {
const currentPagination = useChannelsTableStore.getState().pagination;
// Only retry if we're not already on page 1
if (currentPagination.pageIndex > 0) {
// Reset to page 1
useChannelsTableStore.getState().setPagination({
...currentPagination,
pageIndex: 0,
});
// Update params to page 1 and retry
const newParams = new URLSearchParams(API.lastQueryParams);
newParams.set('page', '1');
API.lastQueryParams = newParams;
const [response, ids] = await Promise.all([
request(
`${host}/api/channels/channels/?${newParams.toString()}`
),
API.getAllChannelIds(newParams),
]);
useChannelsTableStore
.getState()
.queryChannels(response, newParams);
useChannelsTableStore.getState().setAllQueryIds(ids);
return response;
}
}
errorNotification('Failed to fetch channels', e);
}
}

View file

@ -421,25 +421,32 @@ const ChannelsTable = ({ onReady }) => {
}
});
const [results, ids] = await Promise.all([
await API.queryChannels(params),
await API.getAllChannelIds(params),
]);
try {
const [results, ids] = await Promise.all([
await API.queryChannels(params),
await API.getAllChannelIds(params),
]);
setIsLoading(false);
hasFetchedData.current = true;
setIsLoading(false);
hasFetchedData.current = true;
setTablePrefs((prev) => ({
...prev,
pageSize: pagination.pageSize,
}));
setAllRowIds(ids);
setTablePrefs((prev) => ({
...prev,
pageSize: pagination.pageSize,
}));
setAllRowIds(ids);
// Signal ready after first successful data fetch AND EPG data is loaded
// This prevents the EPG column from showing "Not Assigned" while EPG data is still loading
if (!hasSignaledReady.current && onReady && tvgsLoaded) {
hasSignaledReady.current = true;
onReady();
// Signal ready after first successful data fetch AND EPG data is loaded
// This prevents the EPG column from showing "Not Assigned" while EPG data is still loading
if (!hasSignaledReady.current && onReady && tvgsLoaded) {
hasSignaledReady.current = true;
onReady();
}
} catch (error) {
setIsLoading(false);
// API layer handles "Invalid page" errors by resetting and retrying
// Just re-throw to show notification for actual errors
throw error;
}
}, [
pagination,