diff --git a/ts/components/conversation/CallingNotification.dom.tsx b/ts/components/conversation/CallingNotification.dom.tsx index 390f21dce2..bd7e923f5d 100644 --- a/ts/components/conversation/CallingNotification.dom.tsx +++ b/ts/components/conversation/CallingNotification.dom.tsx @@ -73,6 +73,7 @@ export const CallingNotification: React.FC = React.memo( }); }} shouldShowAdditional={false} + onDebugMessage={null} onDownload={null} onEdit={null} onReplyToMessage={null} diff --git a/ts/components/conversation/MessageContextMenu.dom.tsx b/ts/components/conversation/MessageContextMenu.dom.tsx index 245cfec936..52140a7eef 100644 --- a/ts/components/conversation/MessageContextMenu.dom.tsx +++ b/ts/components/conversation/MessageContextMenu.dom.tsx @@ -4,6 +4,7 @@ import React, { useRef, type ReactNode } from 'react'; import type { LocalizerType } from '../../types/I18N.std.js'; import { AxoMenuBuilder } from '../../axo/AxoMenuBuilder.dom.js'; +import { isInternalFeaturesEnabled } from '../../util/isInternalFeaturesEnabled.dom.js'; type MessageContextMenuProps = Readonly<{ i18n: LocalizerType; @@ -11,6 +12,7 @@ type MessageContextMenuProps = Readonly<{ onOpenChange?: (open: boolean) => void; disabled?: boolean; shouldShowAdditional: boolean; + onDebugMessage: (() => void) | null; onDownload: (() => void) | null; onEdit: (() => void) | null; onReplyToMessage: (() => void) | null; @@ -34,6 +36,7 @@ export function MessageContextMenu({ onOpenChange, disabled, shouldShowAdditional, + onDebugMessage, onDownload, onEdit, onReplyToMessage, @@ -162,6 +165,17 @@ export function MessageContextMenu({ {i18n('icu:retryDeleteForEveryone')} )} + {isInternalFeaturesEnabled() && onDebugMessage && ( + <> + + + Internal + + Copy & debug message + + + + )} ); diff --git a/ts/components/conversation/Quote.dom.stories.tsx b/ts/components/conversation/Quote.dom.stories.tsx index 82799f91d0..d5fc594cb2 100644 --- a/ts/components/conversation/Quote.dom.stories.tsx +++ b/ts/components/conversation/Quote.dom.stories.tsx @@ -112,6 +112,7 @@ const defaultMessageProps: TimelineMessagesProps = { isSMS: false, isSpoilerExpanded: {}, isVoiceMessagePlayed: false, + handleDebugMessage: action('debugMessage'), toggleSelectMessage: action('toggleSelectMessage'), cancelAttachmentDownload: action('default--cancelAttachmentDownload'), kickOffAttachmentDownload: action('default--kickOffAttachmentDownload'), diff --git a/ts/components/conversation/Timeline.dom.stories.tsx b/ts/components/conversation/Timeline.dom.stories.tsx index 9e25aaf7b8..7032fd6c84 100644 --- a/ts/components/conversation/Timeline.dom.stories.tsx +++ b/ts/components/conversation/Timeline.dom.stories.tsx @@ -374,6 +374,7 @@ const renderItem = ({ containerWidthBreakpoint={containerWidthBreakpoint} conversationId="" item={items[messageId]} + handleDebugMessage={action('handleDebugMessage')} renderAudioAttachment={() =>
*AudioAttachment*
} renderContact={() =>
*ContactName*
} renderReactionPicker={() =>
} diff --git a/ts/components/conversation/TimelineItem.dom.stories.tsx b/ts/components/conversation/TimelineItem.dom.stories.tsx index c74011bbfd..698209c5fe 100644 --- a/ts/components/conversation/TimelineItem.dom.stories.tsx +++ b/ts/components/conversation/TimelineItem.dom.stories.tsx @@ -50,6 +50,7 @@ const getDefaultProps = () => ({ interactionMode: 'keyboard' as const, theme: ThemeType.light, platform: 'darwin', + handleDebugMessage: action('handleDebugMessage'), targetMessage: action('targetMessage'), toggleSelectMessage: action('toggleSelectMessage'), endPoll: action('endPoll'), diff --git a/ts/components/conversation/TimelineMessage.dom.stories.tsx b/ts/components/conversation/TimelineMessage.dom.stories.tsx index dff3ad4db2..53e2f9d94d 100644 --- a/ts/components/conversation/TimelineMessage.dom.stories.tsx +++ b/ts/components/conversation/TimelineMessage.dom.stories.tsx @@ -268,6 +268,7 @@ const createProps = (overrideProps: Partial = {}): Props => ({ expirationTimestamp: overrideProps.expirationTimestamp ?? 0, getPreferredBadge: overrideProps.getPreferredBadge || (() => undefined), giftBadge: overrideProps.giftBadge, + handleDebugMessage: action('handleDebugMessage'), i18n, platform: 'darwin', id: overrideProps.id ?? 'random-message-id', diff --git a/ts/components/conversation/TimelineMessage.dom.tsx b/ts/components/conversation/TimelineMessage.dom.tsx index 4c3a459d59..5f812252cf 100644 --- a/ts/components/conversation/TimelineMessage.dom.tsx +++ b/ts/components/conversation/TimelineMessage.dom.tsx @@ -86,6 +86,7 @@ export type PropsActions = { messageId: string, isPinningDisappearingMessage: boolean ) => void; + handleDebugMessage: () => void; } & Omit; export type Props = PropsData & @@ -125,6 +126,7 @@ export function TimelineMessage(props: Props): React.JSX.Element { copyMessageText, endPoll, expirationLength, + handleDebugMessage, onPinnedMessageRemove, pushPanelForConversation, reactToMessage, @@ -367,6 +369,7 @@ export function TimelineMessage(props: Props): React.JSX.Element { args: { messageId: id }, }) } + onDebugMessage={handleDebugMessage} > {children} @@ -383,6 +386,7 @@ export function TimelineMessage(props: Props): React.JSX.Element { canRetryDeleteForEveryone, conversationId, copyMessageText, + handleDebugMessage, handleDownload, handleReact, handleOpenPinMessageDialog, diff --git a/ts/state/smart/TimelineItem.preload.tsx b/ts/state/smart/TimelineItem.preload.tsx index e1a6804ac2..20ef986479 100644 --- a/ts/state/smart/TimelineItem.preload.tsx +++ b/ts/state/smart/TimelineItem.preload.tsx @@ -41,6 +41,8 @@ import { renderReactionPicker } from './renderReactionPicker.dom.js'; import type { MessageRequestState } from '../../components/conversation/MessageRequestActionsConfirmation.dom.js'; import { TargetedMessageSource } from '../ducks/conversationsEnums.std.js'; import type { MessageInteractivity } from '../../components/conversation/Message.dom.js'; +import { DataReader } from '../../sql/Client.preload.js'; +import { isInternalFeaturesEnabled } from '../../util/isInternalFeaturesEnabled.dom.js'; export type SmartTimelineItemProps = { containerElementRef: RefObject; @@ -195,6 +197,18 @@ export const SmartTimelineItem = memo(function SmartTimelineItem( [conversationId, toggleMessageRequestActionsConfirmation] ); + const handleDebugMessage = useCallback(async () => { + if (!isInternalFeaturesEnabled()) { + return; + } + const message = await DataReader.getMessageById(messageId); + // eslint-disable-next-line no-console + console.debug(message); + await window.navigator.clipboard.writeText( + JSON.stringify(message, null, 2) + ); + }, [messageId]); + return (