mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 05:25:40 +09:00
fix(app): load more bookmarks as the list scrolls (#2556)
This commit is contained in:
1 parent
d91b5bec66
commit
fbf0f6adfe
16 files changed
+322
-57
No files matched your search
@@ -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> = [];
|
||||
|
||||
Reference in new issue
Block a user