From 8d6e94decbd2a3ff40ce7ad887cc46abe390ea67 Mon Sep 17 00:00:00 2001 From: "Thomas F. K. Jorna" Date: Mon, 9 Mar 2026 18:15:46 +0100 Subject: [PATCH 1/2] fix: actually sort layouts by collection order --- server/utils/layouts/layoutPubs.ts | 73 ++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/server/utils/layouts/layoutPubs.ts b/server/utils/layouts/layoutPubs.ts index 673b1514ad..6f4993e0d8 100644 --- a/server/utils/layouts/layoutPubs.ts +++ b/server/utils/layouts/layoutPubs.ts @@ -43,6 +43,7 @@ const getAllPubIdsRaw = async (communityId: string): Promise const query = sql`SELECT "Pub"."id", "Pub"."createdAt", +"Pub"."title", "Pub"."customPublishedAt", MIN("releases"."createdAt") AS "firstReleaseDate", COALESCE( @@ -86,6 +87,47 @@ const getPublishDate = (pub: PubWithMetadata): Date | null => { return pub.customPublishedAt || pub.firstReleaseDate || null; }; +const getLowestRelevantCollectionRank = ( + pub: PubWithMetadata, + collectionIdsSet: Set | null, +): string | null => { + let lowestRank: string | null = null; + + for (const collectionPub of pub.collectionPubs) { + if (collectionIdsSet && !collectionIdsSet.has(collectionPub.collectionId)) { + continue; + } + + const rank = collectionPub.rank || ''; + if (lowestRank === null || rank.localeCompare(lowestRank) < 0) { + lowestRank = rank; + } + } + + return lowestRank; +}; + +const compareCollectionRanks = ( + aRank: string | null, + bRank: string | null, + direction: PubsQueryOrdering['direction'], +): number => { + if (aRank === null && bRank === null) { + return 0; + } + + if (aRank === null) { + return direction === 'ASC' ? 1 : -1; + } + + if (bRank === null) { + return direction === 'ASC' ? -1 : 1; + } + + const rankComparison = aRank.localeCompare(bRank); + return direction === 'ASC' ? rankComparison : rankComparison * -1; +}; + const filterPubsByCollection = ( pubs: PubWithMetadata[], collectionIds: string[], @@ -117,23 +159,28 @@ const sortPubs = ( const sorted = [...pubs]; const ordering = getQueryOrdering(sort); + if (ordering.field === 'collectionRank') { + const collectionIdsSet = collectionIds.length > 0 ? new Set(collectionIds) : null; + const lowestRankByPubId = new Map( + sorted.map((pub) => [pub.id, getLowestRelevantCollectionRank(pub, collectionIdsSet)]), + ); + + sorted.sort((a, b) => + compareCollectionRanks( + lowestRankByPubId.get(a.id) ?? null, + lowestRankByPubId.get(b.id) ?? null, + ordering.direction, + ), + ); + + return sorted; + } + sorted.sort((a, b) => { let aValue: number | null = null; let bValue: number | null = null; - if (ordering.field === 'collectionRank') { - const getMinRank = (pub: PubWithMetadata) => { - const relevantRanks = pub.collectionPubs - .filter( - (cp) => - collectionIds.length === 0 || collectionIds.includes(cp.collectionId), - ) - .map((cp) => parseFloat(cp.rank)); - return relevantRanks.length > 0 ? Math.min(...relevantRanks) : Number.MAX_VALUE; - }; - aValue = getMinRank(a); - bValue = getMinRank(b); - } else if (ordering.field === 'creationDate') { + if (ordering.field === 'creationDate') { aValue = a.createdAt.getTime(); bValue = b.createdAt.getTime(); } else if (ordering.field === 'publishDate') { From 83e8e74275d33e2c4bc500b6479149b0ee5ad311 Mon Sep 17 00:00:00 2001 From: "Thomas F. K. Jorna" Date: Mon, 9 Mar 2026 18:24:47 +0100 Subject: [PATCH 2/2] fix: remove title --- server/utils/layouts/layoutPubs.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/server/utils/layouts/layoutPubs.ts b/server/utils/layouts/layoutPubs.ts index 6f4993e0d8..3f3bcf68e7 100644 --- a/server/utils/layouts/layoutPubs.ts +++ b/server/utils/layouts/layoutPubs.ts @@ -43,7 +43,6 @@ const getAllPubIdsRaw = async (communityId: string): Promise const query = sql`SELECT "Pub"."id", "Pub"."createdAt", -"Pub"."title", "Pub"."customPublishedAt", MIN("releases"."createdAt") AS "firstReleaseDate", COALESCE(