Fix following past 48 entries and make the e621 page size configurable
Follow lists were paginated at the API default of 48, but the SPA treats them as complete sets: the tag/pool toggles read their state from page one (so the 49th follow looked unfollowed and its spinner waited for a page that could never contain it) and the Followed page rendered only 48 cards while showing that as the count. Both follow endpoints are now unpaginated — they are per-user sets and still restricted to the caller's rows — and the three consumers take plain arrays. Post visibility: the old J621-Django online view fetched limit=320 (e621's maximum) while ours hard-coded 48, and fetchPostsByIds capped id batches at 100. The Online browser now has a 'Posts per page' setting (48/100/200/320) in its sidebar, mirrored in Account -> Browsing preferences, stored per user as e621_per_page and also used for pool loading; the id-batch cap is raised to 320. Tests: follow list shape/isolation (4) and preference validation/merge (3) added; the full backend suite is 46 green. Live-checked the array response shape and the preference bounds (200 accepted, 500 rejected).
This commit is contained in:
@@ -25,17 +25,18 @@ import { useIsMobile } from "@/lib/useMediaQuery";
|
||||
import { useE621 } from "@/store/e621";
|
||||
import { useUi } from "@/store/ui";
|
||||
|
||||
const CHUNK = 100;
|
||||
const CHUNK_FALLBACK = 100;
|
||||
|
||||
async function fetchPostsChunked(
|
||||
credentials: ReturnType<typeof effectiveCredentials>,
|
||||
ids: number[],
|
||||
chunk: number,
|
||||
signal?: AbortSignal,
|
||||
): Promise<E621Post[]> {
|
||||
const posts: E621Post[] = [];
|
||||
for (let index = 0; index < ids.length; index += CHUNK) {
|
||||
const chunk = ids.slice(index, index + CHUNK);
|
||||
posts.push(...(await fetchPostsByIds(credentials, chunk, signal)));
|
||||
for (let index = 0; index < ids.length; index += chunk) {
|
||||
const slice = ids.slice(index, index + chunk);
|
||||
posts.push(...(await fetchPostsByIds(credentials, slice, signal)));
|
||||
}
|
||||
return posts;
|
||||
}
|
||||
@@ -54,8 +55,11 @@ export default function PoolDetailPage() {
|
||||
const blacklistSet = useMemo(() => new Set(blacklist), [blacklist]);
|
||||
const isMobile = useIsMobile();
|
||||
const zoom = useUi((state) => state.zoom);
|
||||
// Pool posts load in chunks of the user's e621 page size (max 320).
|
||||
const e621PerPage = useUi((state) => state.e621PerPage);
|
||||
const chunk = Math.min(320, Math.max(24, e621PerPage || CHUNK_FALLBACK));
|
||||
|
||||
const [visibleCount, setVisibleCount] = useState(CHUNK);
|
||||
const [visibleCount, setVisibleCount] = useState(chunk);
|
||||
const [showBlacklisted, setShowBlacklisted] = useState(false);
|
||||
|
||||
const poolQuery = useQuery({
|
||||
@@ -84,6 +88,7 @@ export default function PoolDetailPage() {
|
||||
fetchPostsChunked(
|
||||
effectiveCredentials(credentials),
|
||||
postIds,
|
||||
chunk,
|
||||
signal,
|
||||
),
|
||||
enabled: postIds.length > 0,
|
||||
@@ -319,7 +324,7 @@ export default function PoolDetailPage() {
|
||||
<Button
|
||||
variant="secondary"
|
||||
disabled={postsQuery.isFetching}
|
||||
onClick={() => setVisibleCount((count) => count + CHUNK)}
|
||||
onClick={() => setVisibleCount((count) => count + chunk)}
|
||||
>
|
||||
{postsQuery.isFetching
|
||||
? "Loading…"
|
||||
|
||||
Reference in New Issue
Block a user