From 6bbf5f95de29d2bda4ffc92b1389aa72f6ab69e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Sun, 15 Jun 2025 16:37:16 +0200 Subject: [PATCH] pl-fe: minify pleroma shoutbox messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk --- packages/pl-api/lib/features.ts | 1 - packages/pl-fe/src/actions/importer.ts | 12 +- packages/pl-fe/src/actions/shoutbox.ts | 4 +- .../chats/components/chat-list-shoutbox.tsx | 12 +- .../components/shoutbox-message-list.tsx | 144 ++++++++++-------- packages/pl-fe/src/reducers/shoutbox.ts | 17 ++- 6 files changed, 114 insertions(+), 76 deletions(-) diff --git a/packages/pl-api/lib/features.ts b/packages/pl-api/lib/features.ts index 2948e9935..fc0dd1093 100644 --- a/packages/pl-api/lib/features.ts +++ b/packages/pl-api/lib/features.ts @@ -1109,7 +1109,6 @@ const getFeatures = (instance: Instance) => { */ mastodonAdminMetrics: v.software === MASTODON && gte(v.version, '3.5.0'), - /** * Can perform moderation actions with account and reports. * @see {@link https://docs.joinmastodon.org/methods/admin/} diff --git a/packages/pl-fe/src/actions/importer.ts b/packages/pl-fe/src/actions/importer.ts index 047ac01e4..d6a22cd72 100644 --- a/packages/pl-fe/src/actions/importer.ts +++ b/packages/pl-fe/src/actions/importer.ts @@ -3,7 +3,7 @@ import { Entities } from 'pl-fe/entity-store/entities'; import { normalizeGroup } from 'pl-fe/normalizers/group'; import type { Account as BaseAccount, Group as BaseGroup, Poll as BasePoll, Relationship as BaseRelationship, Status as BaseStatus } from 'pl-api'; -import type { AppDispatch } from 'pl-fe/store'; +import type { AppDispatch, RootState } from 'pl-fe/store'; const STATUS_IMPORT = 'STATUS_IMPORT' as const; const STATUSES_IMPORT = 'STATUSES_IMPORT' as const; @@ -51,11 +51,17 @@ const importEntities = (entities: { statuses?: Array; relationships?: Array; }, options: { + // Whether to replace existing entities. Set to false when working with potentially outdated data. Currently, only implemented for accounts. + override?: boolean; withParents?: boolean; idempotencyKey?: string; } = { withParents: true, -}) => (dispatch: AppDispatch) => { +}) => (dispatch: AppDispatch, getState: () => RootState) => { + const override = options.override ?? true; + + const state: RootState = !override ? getState() : undefined as any; + const accounts: Record = {}; const groups: Record = {}; const polls: Record = {}; @@ -63,6 +69,8 @@ const importEntities = (entities: { const statuses: Record = {}; const processAccount = (account: BaseAccount, withSelf = true) => { + if (!override && state.entities[Entities.ACCOUNTS]?.store[account.id]) return; + if (withSelf) accounts[account.id] = account; if (account.moved) processAccount(account.moved); diff --git a/packages/pl-fe/src/actions/shoutbox.ts b/packages/pl-fe/src/actions/shoutbox.ts index c93e78a48..f4b5bac57 100644 --- a/packages/pl-fe/src/actions/shoutbox.ts +++ b/packages/pl-fe/src/actions/shoutbox.ts @@ -11,7 +11,7 @@ const SHOUTBOX_MESSAGES_IMPORT = 'SHOUTBOX_MESSAGES_IMPORT' as const; const SHOUTBOX_CONNECT = 'SHOUTBOX_CONNECT' as const; const importShoutboxMessages = (messages: ShoutMessage[]) => (dispatch: AppDispatch): ShoutboxAction => { - dispatch(importEntities({ accounts: messages.map((message) => message.author) })); + dispatch(importEntities({ accounts: messages.map((message) => message.author) }, { override: false })); return dispatch({ type: SHOUTBOX_MESSAGES_IMPORT, @@ -20,7 +20,7 @@ const importShoutboxMessages = (messages: ShoutMessage[]) => (dispatch: AppDispa }; const importShoutboxMessage = (message: ShoutMessage) => (dispatch: AppDispatch): ShoutboxAction => { - dispatch(importEntities({ accounts: [message.author] })); + dispatch(importEntities({ accounts: [message.author] }, { override: false })); return dispatch({ type: SHOUTBOX_MESSAGE_IMPORT, diff --git a/packages/pl-fe/src/features/chats/components/chat-list-shoutbox.tsx b/packages/pl-fe/src/features/chats/components/chat-list-shoutbox.tsx index ed7d798cc..7fd86be3e 100644 --- a/packages/pl-fe/src/features/chats/components/chat-list-shoutbox.tsx +++ b/packages/pl-fe/src/features/chats/components/chat-list-shoutbox.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; +import { useAccount } from 'pl-fe/api/hooks/accounts/use-account'; import { ParsedContent } from 'pl-fe/components/parsed-content'; import Avatar from 'pl-fe/components/ui/avatar'; import HStack from 'pl-fe/components/ui/hstack'; @@ -28,6 +29,7 @@ const ChatListShoutbox: React.FC = ({ onClick }) => }; const lastMessage = messages.at(-1); + const { account: lastMessageAuthor } = useAccount(lastMessage?.author_id); return (
= ({ onClick }) => truncate className='truncate-child pointer-events-none h-5 w-full' > - - {lastMessage.author.display_name || `@${lastMessage.author.username}`}: - {' '} - + {lastMessageAuthor && ( + + {lastMessageAuthor.display_name || `@${lastMessageAuthor.username}`}: + {' '} + + )} diff --git a/packages/pl-fe/src/features/chats/components/shoutbox-message-list.tsx b/packages/pl-fe/src/features/chats/components/shoutbox-message-list.tsx index 22a59aea8..2e6131f41 100644 --- a/packages/pl-fe/src/features/chats/components/shoutbox-message-list.tsx +++ b/packages/pl-fe/src/features/chats/components/shoutbox-message-list.tsx @@ -3,6 +3,7 @@ import React, { useState, useEffect, useRef, useMemo } from 'react'; import { Link } from 'react-router-dom'; import { Virtuoso, VirtuosoHandle } from 'react-virtuoso'; +import { useAccount } from 'pl-fe/api/hooks/accounts/use-account'; import HoverAccountWrapper from 'pl-fe/components/hover-account-wrapper'; import { ParsedContent } from 'pl-fe/components/parsed-content'; import Avatar from 'pl-fe/components/ui/avatar'; @@ -15,8 +16,81 @@ import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { ChatMessageListList, ChatMessageListScroller } from './chat-message-list'; +import type { ShoutMessage } from 'pl-fe/reducers/shoutbox'; + const START_INDEX = 10000; +interface IShoutboxMessage { + message: ShoutMessage; + isMyMessage: boolean; +} + +const ShoutboxMessage: React.FC = ({ message, isMyMessage }) => { + const { account } = useAccount(message.author_id); + + if (!account) return null; + + return ( +
+ + {!isMyMessage && ( + + + + + + )} + + + +
+ + + +
+
+ {!isMyMessage && ( + + + + )} +
+
+
+ ); +}; + /** Scrollable list of shoutbox messages. */ const ShoutboxMessageList: React.FC = () => { const node = useRef(null); @@ -70,69 +144,13 @@ const ShoutboxMessageList: React.FC = () => { {...initialScrollPositionProps} data={shoutboxMessages} followOutput='auto' - itemContent={(index, shoutboxMessage) => { - const isMyMessage = shoutboxMessage.author.id === me; - - return ( -
- - {!isMyMessage && ( - - - - - - )} - - - -
- - - -
-
- {!isMyMessage && ( - - - - )} -
-
-
- ); - }} + itemContent={(index, shoutboxMessage) => ( + + )} components={{ List: ChatMessageListList, Scroller: ChatMessageListScroller, diff --git a/packages/pl-fe/src/reducers/shoutbox.ts b/packages/pl-fe/src/reducers/shoutbox.ts index 254910785..4cb798366 100644 --- a/packages/pl-fe/src/reducers/shoutbox.ts +++ b/packages/pl-fe/src/reducers/shoutbox.ts @@ -1,6 +1,10 @@ import { SHOUTBOX_CONNECT, SHOUTBOX_MESSAGES_IMPORT, SHOUTBOX_MESSAGE_IMPORT, type ShoutboxAction } from 'pl-fe/actions/shoutbox'; -import type { PlApiClient, ShoutMessage } from 'pl-api'; +import type { PlApiClient, ShoutMessage as BaseShoutMessage } from 'pl-api'; + +interface ShoutMessage extends Omit { + author_id: string; +} interface State { socket: ReturnType<(InstanceType)['shoutbox']['connect']> | null; @@ -14,17 +18,22 @@ const initialState: State = { messages: [], }; +const minifyMessage = ({ author, ...message }: BaseShoutMessage): ShoutMessage => ({ + author_id: author.id, + ...message, +}); + const shoutboxReducer = (state = initialState, action: ShoutboxAction) => { switch (action.type) { case SHOUTBOX_CONNECT: return { ...state, socket: action.socket }; case SHOUTBOX_MESSAGES_IMPORT: - return { ...state, messages: action.messages, isLoading: false }; + return { ...state, messages: action.messages.map(minifyMessage), isLoading: false }; case SHOUTBOX_MESSAGE_IMPORT: - return { ...state, messages: [...state.messages, action.message] }; + return { ...state, messages: [...state.messages, minifyMessage(action.message)] }; default: return state; } }; -export { shoutboxReducer as default }; +export { shoutboxReducer as default, type ShoutMessage };