fix(app): load more bookmarks as the list scrolls (#2556)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-06 21:05:57 +02:00
1 parent d91b5bec66
commit fbf0f6adfe
16 files changed
+322 -57

No files matched your search

+2 -1
View File
@@ -22705,7 +22705,8 @@
"type": "string",
"description": "Maximum number of saved messages to return (1-100, default 25)"
}
}
},
{"name": "before", "in": "query", "required": false, "schema": {"$ref": "#/components/schemas/SnowflakeType"}}
]
},
"post": {
@@ -123,9 +123,11 @@ export function UserContentController(app: HonoApp) {
'Retrieves all messages saved by the current user. Messages are saved privately for easy reference. Returns paginated list of saved messages with metadata.',
}),
async (ctx) => {
const {limit, before} = ctx.req.valid('query');
const response = await ctx.get('userContentRequestService').listSavedMessages({
userId: ctx.get('user').id,
limit: ctx.req.valid('query').limit,
limit,
before: before ? createMessageID(before) : undefined,
requestCache: ctx.get('requestCache'),
});
return ctx.json(response, 200);
@@ -46,6 +46,7 @@ interface UserMentionsReadParams {
interface SavedMessagesParams {
userId: UserID;
limit: number;
before?: MessageID;
requestCache: RequestCache;
}
@@ -108,7 +109,11 @@ export class UserContentRequestService {
}
async listSavedMessages(params: SavedMessagesParams): Promise<SavedMessageEntryListResponse> {
const entries = await this.userContentService.getSavedMessages({userId: params.userId, limit: params.limit});
const entries = await this.userContentService.getSavedMessages({
userId: params.userId,
limit: params.limit,
before: params.before,
});
const messages = entries.map((entry) => entry.message).filter((message): message is Message => message != null);
const responses = await this.userContentService.buildMessageResponsesForUser(params.userId, messages);
const responseByMessageId = new Map(responses.map((response) => [response.id, response] as const));
@@ -100,6 +100,7 @@ function createUserContentService({
}) {
const batchCalls: Array<ChannelBatchCall> = [];
const deletedSavedMessageIds: Array<string> = [];
const savedMessageListCalls: Array<{limit?: number; before?: MessageID}> = [];
const readableByChannel = new Map<string, Map<string, Message>>();
for (const entry of readable) {
const key = entry.channelId.toString();
@@ -109,7 +110,10 @@ function createUserContentService({
}
const userRepository = {
listRecentMentions: async () => entries,
listSavedMessages: async () => entries,
listSavedMessages: async (_userId: UserID, limit?: number, before?: MessageID) => {
savedMessageListCalls.push({limit, before});
return entries;
},
deleteSavedMessage: async (_userId: UserID, messageId: MessageID) => {
deletedSavedMessageIds.push(messageId.toString());
},
@@ -146,7 +150,7 @@ function createUserContentService({
{} as unknown as KVBulkMessageDeletionQueueService,
{} as unknown as LimitConfigService,
);
return {service, batchCalls, deletedSavedMessageIds};
return {service, batchCalls, deletedSavedMessageIds, savedMessageListCalls};
}
const CHANNEL_A = createChannelID(100n);
@@ -238,6 +242,15 @@ describe('getRecentMentions', () => {
});
describe('getSavedMessages', () => {
it('passes the page cursor to the repository', async () => {
const entries = [{channelId: CHANNEL_A, messageId: createMessageID(11n)}];
const {service, savedMessageListCalls} = createUserContentService({entries, readable: entries});
await service.getSavedMessages({userId: VIEWER_ID, limit: 50, before: createMessageID(20n)});
expect(savedMessageListCalls).toEqual([{limit: 50, before: createMessageID(20n)}]);
});
it('marks every entry of an unreachable channel as missing permissions without deleting it', async () => {
const entries = [
{channelId: CHANNEL_A, messageId: createMessageID(11n)},
@@ -229,8 +229,16 @@ export class UserContentService {
);
}
async getSavedMessages({userId, limit}: {userId: UserID; limit: number}): Promise<Array<SavedMessageEntry>> {
const savedMessages = await this.userRepository.listSavedMessages(userId, limit);
async getSavedMessages({
userId,
limit,
before,
}: {
userId: UserID;
limit: number;
before?: MessageID;
}): Promise<Array<SavedMessageEntry>> {
const savedMessages = await this.userRepository.listSavedMessages(userId, limit, before);
const messagesByChannel = await this.readMessagesByChannel(userId, savedMessages);
const results: Array<SavedMessageEntry> = [];
const staleMessageIds: Array<MessageID> = [];