Add more debug tools for stories
This commit is contained in:
parent
4d1cd05888
commit
1bff385805
8 changed files with 116 additions and 30 deletions
|
@ -15,6 +15,8 @@ import { SendStatus } from '../messages/MessageSendState';
|
|||
import { Theme } from '../util/theme';
|
||||
import { formatDateTimeLong } from '../util/timestamp';
|
||||
import { DurationInSeconds } from '../util/durations';
|
||||
import type { saveAttachment } from '../util/saveAttachment';
|
||||
import type { AttachmentType } from '../types/Attachment';
|
||||
import { ThemeType } from '../types/Util';
|
||||
import { Time } from './Time';
|
||||
import { groupBy } from '../util/mapUtil';
|
||||
|
@ -23,10 +25,12 @@ import { format as formatRelativeTime } from '../util/expirationTimer';
|
|||
export type PropsType = {
|
||||
getPreferredBadge: PreferredBadgeSelectorType;
|
||||
i18n: LocalizerType;
|
||||
isInternalUser?: boolean;
|
||||
onClose: () => unknown;
|
||||
saveAttachment: typeof saveAttachment;
|
||||
sender: StoryViewType['sender'];
|
||||
sendState?: Array<StorySendStateType>;
|
||||
size?: number;
|
||||
attachment?: AttachmentType;
|
||||
expirationTimestamp: number | undefined;
|
||||
timestamp: number;
|
||||
};
|
||||
|
@ -62,12 +66,14 @@ function getI18nKey(sendStatus: SendStatus | undefined): string {
|
|||
}
|
||||
|
||||
export function StoryDetailsModal({
|
||||
attachment,
|
||||
getPreferredBadge,
|
||||
i18n,
|
||||
isInternalUser,
|
||||
onClose,
|
||||
saveAttachment,
|
||||
sender,
|
||||
sendState,
|
||||
size,
|
||||
timestamp,
|
||||
expirationTimestamp,
|
||||
}: PropsType): JSX.Element {
|
||||
|
@ -193,6 +199,26 @@ export function StoryDetailsModal({
|
|||
? DurationInSeconds.fromMillis(expirationTimestamp - Date.now())
|
||||
: undefined;
|
||||
|
||||
const menuOptions = [
|
||||
{
|
||||
icon: 'StoryDetailsModal__copy-icon',
|
||||
label: i18n('StoryDetailsModal__copy-timestamp'),
|
||||
onClick: () => {
|
||||
window.navigator.clipboard.writeText(String(timestamp));
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
if (isInternalUser && attachment) {
|
||||
menuOptions.push({
|
||||
icon: 'StoryDetailsModal__download-icon',
|
||||
label: i18n('StoryDetailsModal__download-attachment'),
|
||||
onClick: () => {
|
||||
saveAttachment(attachment);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
modalName="StoryDetailsModal"
|
||||
|
@ -205,15 +231,7 @@ export function StoryDetailsModal({
|
|||
title={
|
||||
<ContextMenu
|
||||
i18n={i18n}
|
||||
menuOptions={[
|
||||
{
|
||||
icon: 'StoryDetailsModal__copy-icon',
|
||||
label: i18n('StoryDetailsModal__copy-timestamp'),
|
||||
onClick: () => {
|
||||
window.navigator.clipboard.writeText(String(timestamp));
|
||||
},
|
||||
},
|
||||
]}
|
||||
menuOptions={menuOptions}
|
||||
moduleClassName="StoryDetailsModal__debugger"
|
||||
popperOptions={{
|
||||
placement: 'bottom',
|
||||
|
@ -235,14 +253,14 @@ export function StoryDetailsModal({
|
|||
]}
|
||||
/>
|
||||
</div>
|
||||
{size && (
|
||||
{attachment && (
|
||||
<div>
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="StoryDetailsModal__file-size"
|
||||
components={[
|
||||
<span className="StoryDetailsModal__debugger__button__text">
|
||||
{formatFileSize(size)}
|
||||
{formatFileSize(attachment.size)}
|
||||
</span>,
|
||||
]}
|
||||
/>
|
||||
|
|
|
@ -45,6 +45,7 @@ import { getAvatarColor } from '../types/Colors';
|
|||
import { getStoryBackground } from '../util/getStoryBackground';
|
||||
import { getStoryDuration } from '../util/getStoryDuration';
|
||||
import { graphemeAwareSlice } from '../util/graphemeAwareSlice';
|
||||
import type { saveAttachment } from '../util/saveAttachment';
|
||||
import { isVideoAttachment } from '../types/Attachment';
|
||||
import { useEscapeHandling } from '../hooks/useEscapeHandling';
|
||||
import { useRetryStorySend } from '../hooks/useRetryStorySend';
|
||||
|
@ -75,6 +76,7 @@ export type PropsType = {
|
|||
hasAllStoriesUnmuted: boolean;
|
||||
hasViewReceiptSetting: boolean;
|
||||
i18n: LocalizerType;
|
||||
isInternalUser?: boolean;
|
||||
isSignalConversation?: boolean;
|
||||
isWindowActive: boolean;
|
||||
loadStoryReplies: (conversationId: string, messageId: string) => unknown;
|
||||
|
@ -98,6 +100,7 @@ export type PropsType = {
|
|||
renderEmojiPicker: (props: RenderEmojiPickerProps) => JSX.Element;
|
||||
replyState?: ReplyStateType;
|
||||
retrySend: (messageId: string) => unknown;
|
||||
saveAttachment: typeof saveAttachment;
|
||||
setHasAllStoriesUnmuted: (isUnmuted: boolean) => unknown;
|
||||
showToast: ShowToastActionCreatorType;
|
||||
skinTone?: number;
|
||||
|
@ -130,6 +133,7 @@ export function StoryViewer({
|
|||
hasAllStoriesUnmuted,
|
||||
hasViewReceiptSetting,
|
||||
i18n,
|
||||
isInternalUser,
|
||||
isSignalConversation,
|
||||
isWindowActive,
|
||||
loadStoryReplies,
|
||||
|
@ -148,6 +152,7 @@ export function StoryViewer({
|
|||
renderEmojiPicker,
|
||||
replyState,
|
||||
retrySend,
|
||||
saveAttachment,
|
||||
setHasAllStoriesUnmuted,
|
||||
showToast,
|
||||
skinTone,
|
||||
|
@ -886,12 +891,14 @@ export function StoryViewer({
|
|||
</div>
|
||||
{currentViewTarget === StoryViewTargetType.Details && (
|
||||
<StoryDetailsModal
|
||||
attachment={attachment}
|
||||
getPreferredBadge={getPreferredBadge}
|
||||
i18n={i18n}
|
||||
isInternalUser={isInternalUser}
|
||||
onClose={() => setCurrentViewTarget(null)}
|
||||
saveAttachment={saveAttachment}
|
||||
sender={story.sender}
|
||||
sendState={sendState}
|
||||
size={attachment?.size}
|
||||
timestamp={timestamp}
|
||||
expirationTimestamp={story.expirationTimestamp}
|
||||
/>
|
||||
|
@ -905,6 +912,7 @@ export function StoryViewer({
|
|||
hasViewReceiptSetting={hasViewReceiptSetting}
|
||||
hasViewsCapability={isSent}
|
||||
i18n={i18n}
|
||||
isInternalUser={isInternalUser}
|
||||
group={group}
|
||||
onClose={() => setCurrentViewTarget(null)}
|
||||
onReact={emoji => {
|
||||
|
|
|
@ -88,6 +88,7 @@ export type PropsType = {
|
|||
hasViewReceiptSetting: boolean;
|
||||
hasViewsCapability: boolean;
|
||||
i18n: LocalizerType;
|
||||
isInternalUser?: boolean;
|
||||
group: Pick<ConversationType, 'left'> | undefined;
|
||||
onClose: () => unknown;
|
||||
onReact: (emoji: string) => unknown;
|
||||
|
@ -120,6 +121,7 @@ export function StoryViewsNRepliesModal({
|
|||
hasViewReceiptSetting,
|
||||
hasViewsCapability,
|
||||
i18n,
|
||||
isInternalUser,
|
||||
group,
|
||||
onClose,
|
||||
onReact,
|
||||
|
@ -325,6 +327,7 @@ export function StoryViewsNRepliesModal({
|
|||
<ReplyOrReactionMessage
|
||||
key={reply.id}
|
||||
i18n={i18n}
|
||||
isInternalUser={isInternalUser}
|
||||
reply={reply}
|
||||
deleteGroupStoryReply={() => setDeleteReplyId(reply.id)}
|
||||
deleteGroupStoryReplyForEveryone={() =>
|
||||
|
@ -501,6 +504,7 @@ export function StoryViewsNRepliesModal({
|
|||
|
||||
type ReplyOrReactionMessageProps = {
|
||||
i18n: LocalizerType;
|
||||
isInternalUser?: boolean;
|
||||
reply: ReplyType;
|
||||
deleteGroupStoryReply: (replyId: string) => void;
|
||||
deleteGroupStoryReplyForEveryone: (replyId: string) => void;
|
||||
|
@ -513,6 +517,7 @@ type ReplyOrReactionMessageProps = {
|
|||
|
||||
function ReplyOrReactionMessage({
|
||||
i18n,
|
||||
isInternalUser,
|
||||
reply,
|
||||
deleteGroupStoryReply,
|
||||
deleteGroupStoryReplyForEveryone,
|
||||
|
@ -595,23 +600,31 @@ function ReplyOrReactionMessage({
|
|||
);
|
||||
};
|
||||
|
||||
const menuOptions = [
|
||||
{
|
||||
icon: 'module-message__context--icon module-message__context__delete-message',
|
||||
label: i18n('icu:StoryViewsNRepliesModal__delete-reply'),
|
||||
onClick: () => deleteGroupStoryReply(reply.id),
|
||||
},
|
||||
{
|
||||
icon: 'module-message__context--icon module-message__context__delete-message-for-everyone',
|
||||
label: i18n('icu:StoryViewsNRepliesModal__delete-reply-for-everyone'),
|
||||
onClick: () => deleteGroupStoryReplyForEveryone(reply.id),
|
||||
},
|
||||
];
|
||||
|
||||
if (isInternalUser) {
|
||||
menuOptions.push({
|
||||
icon: 'module-message__context--icon module-message__context__copy-timestamp',
|
||||
label: i18n('icu:StoryViewsNRepliesModal__copy-reply-timestamp'),
|
||||
onClick: () => {
|
||||
window.navigator.clipboard.writeText(String(reply.timestamp));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return reply.author.isMe && !reply.deletedForEveryone ? (
|
||||
<ContextMenu
|
||||
i18n={i18n}
|
||||
key={reply.id}
|
||||
menuOptions={[
|
||||
{
|
||||
icon: 'module-message__context--icon module-message__context__delete-message',
|
||||
label: i18n('icu:StoryViewsNRepliesModal__delete-reply'),
|
||||
onClick: () => deleteGroupStoryReply(reply.id),
|
||||
},
|
||||
{
|
||||
icon: 'module-message__context--icon module-message__context__delete-message-for-everyone',
|
||||
label: i18n('icu:StoryViewsNRepliesModal__delete-reply-for-everyone'),
|
||||
onClick: () => deleteGroupStoryReplyForEveryone(reply.id),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<ContextMenu i18n={i18n} key={reply.id} menuOptions={menuOptions}>
|
||||
{({ openMenu, menuNode }) => (
|
||||
<>
|
||||
{renderContent(openMenu)}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue