ErrorBoundary improvements, StickerCreator logging/resiliency
This commit is contained in:
parent
0fb45f045d
commit
6dd6a64d6c
8 changed files with 67 additions and 19 deletions
|
@ -12,6 +12,7 @@ import { Button } from '../../elements/Button';
|
||||||
import { stickersDuck } from '../../store';
|
import { stickersDuck } from '../../store';
|
||||||
import { encryptAndUpload } from '../../util/preload';
|
import { encryptAndUpload } from '../../util/preload';
|
||||||
import { useI18n } from '../../util/i18n';
|
import { useI18n } from '../../util/i18n';
|
||||||
|
import * as Errors from '../../../ts/types/errors';
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
history.push('/add-meta');
|
history.push('/add-meta');
|
||||||
|
@ -42,7 +43,10 @@ export const UploadStage: React.ComponentType = () => {
|
||||||
actions.setPackMeta(packMeta);
|
actions.setPackMeta(packMeta);
|
||||||
history.push('/share');
|
history.push('/share');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
window.SignalContext.log.error('Error uploading image:', e);
|
window.SignalContext.log.error(
|
||||||
|
'Error uploading pack:',
|
||||||
|
Errors.toLogFormat(e)
|
||||||
|
);
|
||||||
actions.addToast({
|
actions.addToast({
|
||||||
key: 'StickerCreator--Toasts--errorUploading',
|
key: 'StickerCreator--Toasts--errorUploading',
|
||||||
subs: [e.message],
|
subs: [e.message],
|
||||||
|
|
|
@ -185,16 +185,25 @@ window.encryptAndUpload = async (
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
|
||||||
const coverStickerId =
|
const coverStickerId = 0;
|
||||||
uniqueStickers.length === stickers.length ? 0 : uniqueStickers.length - 1;
|
|
||||||
const coverStickerData = stickers[coverStickerId];
|
const coverStickerData = stickers[coverStickerId];
|
||||||
|
|
||||||
|
if (!coverStickerData) {
|
||||||
|
window.SignalContext.log.warn(
|
||||||
|
'encryptAndUpload: No coverStickerData with ' +
|
||||||
|
`index ${coverStickerId} and ${stickers.length} total stickers`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const coverSticker = new Proto.StickerPack.Sticker();
|
const coverSticker = new Proto.StickerPack.Sticker();
|
||||||
coverSticker.id = coverStickerId;
|
coverSticker.id = coverStickerId;
|
||||||
if (coverStickerData.emoji) {
|
|
||||||
|
if (coverStickerData?.emoji && coverSticker) {
|
||||||
coverSticker.emoji = coverStickerData.emoji;
|
coverSticker.emoji = coverStickerData.emoji;
|
||||||
} else {
|
} else {
|
||||||
coverSticker.emoji = '';
|
coverSticker.emoji = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
manifestProto.cover = coverSticker;
|
manifestProto.cover = coverSticker;
|
||||||
|
|
||||||
const encryptedManifest = await encrypt(
|
const encryptedManifest = await encrypt(
|
||||||
|
|
|
@ -10,6 +10,7 @@ import type { ExecuteMenuRoleType } from './TitleBarContainer';
|
||||||
import type { LocaleMessagesType } from '../types/I18N';
|
import type { LocaleMessagesType } from '../types/I18N';
|
||||||
import type { MenuOptionsType, MenuActionType } from '../types/menu';
|
import type { MenuOptionsType, MenuActionType } from '../types/menu';
|
||||||
import type { ToastType } from '../state/ducks/toast';
|
import type { ToastType } from '../state/ducks/toast';
|
||||||
|
import type { ViewStoryActionCreatorType } from '../state/ducks/stories';
|
||||||
import { AppViewType } from '../state/ducks/app';
|
import { AppViewType } from '../state/ducks/app';
|
||||||
import { Inbox } from './Inbox';
|
import { Inbox } from './Inbox';
|
||||||
import { SmartInstallScreen } from '../state/smart/InstallScreen';
|
import { SmartInstallScreen } from '../state/smart/InstallScreen';
|
||||||
|
@ -28,9 +29,9 @@ type PropsType = {
|
||||||
renderCallManager: () => JSX.Element;
|
renderCallManager: () => JSX.Element;
|
||||||
renderGlobalModalContainer: () => JSX.Element;
|
renderGlobalModalContainer: () => JSX.Element;
|
||||||
isShowingStoriesView: boolean;
|
isShowingStoriesView: boolean;
|
||||||
renderStories: () => JSX.Element;
|
renderStories: (closeView: () => unknown) => JSX.Element;
|
||||||
hasSelectedStoryData: boolean;
|
hasSelectedStoryData: boolean;
|
||||||
renderStoryViewer: () => JSX.Element;
|
renderStoryViewer: (closeView: () => unknown) => JSX.Element;
|
||||||
requestVerification: (
|
requestVerification: (
|
||||||
type: 'sms' | 'voice',
|
type: 'sms' | 'voice',
|
||||||
number: string,
|
number: string,
|
||||||
|
@ -48,6 +49,8 @@ type PropsType = {
|
||||||
titleBarDoubleClick: () => void;
|
titleBarDoubleClick: () => void;
|
||||||
toastType?: ToastType;
|
toastType?: ToastType;
|
||||||
hideToast: () => unknown;
|
hideToast: () => unknown;
|
||||||
|
toggleStoriesView: () => unknown;
|
||||||
|
viewStory: ViewStoryActionCreatorType;
|
||||||
} & ComponentProps<typeof Inbox>;
|
} & ComponentProps<typeof Inbox>;
|
||||||
|
|
||||||
export const App = ({
|
export const App = ({
|
||||||
|
@ -82,6 +85,8 @@ export const App = ({
|
||||||
theme,
|
theme,
|
||||||
titleBarDoubleClick,
|
titleBarDoubleClick,
|
||||||
toastType,
|
toastType,
|
||||||
|
toggleStoriesView,
|
||||||
|
viewStory,
|
||||||
}: PropsType): JSX.Element => {
|
}: PropsType): JSX.Element => {
|
||||||
let contents;
|
let contents;
|
||||||
|
|
||||||
|
@ -168,8 +173,9 @@ export const App = ({
|
||||||
<ToastManager hideToast={hideToast} i18n={i18n} toastType={toastType} />
|
<ToastManager hideToast={hideToast} i18n={i18n} toastType={toastType} />
|
||||||
{renderGlobalModalContainer()}
|
{renderGlobalModalContainer()}
|
||||||
{renderCallManager()}
|
{renderCallManager()}
|
||||||
{isShowingStoriesView && renderStories()}
|
{isShowingStoriesView && renderStories(toggleStoriesView)}
|
||||||
{hasSelectedStoryData && renderStoryViewer()}
|
{hasSelectedStoryData &&
|
||||||
|
renderStoryViewer(() => viewStory({ closeViewer: true }))}
|
||||||
{contents}
|
{contents}
|
||||||
</div>
|
</div>
|
||||||
</TitleBarContainer>
|
</TitleBarContainer>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode, ErrorInfo } from 'react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import * as Errors from '../types/errors';
|
import * as Errors from '../types/errors';
|
||||||
|
@ -10,6 +10,8 @@ import { ToastType } from '../state/ducks/toast';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
name: string;
|
||||||
|
closeView?: () => unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
|
@ -24,14 +26,23 @@ export class ErrorBoundary extends React.PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getDerivedStateFromError(error: Error): State {
|
public static getDerivedStateFromError(error: Error): State {
|
||||||
|
return { error };
|
||||||
|
}
|
||||||
|
|
||||||
|
public override componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
|
||||||
|
const { closeView, name } = this.props;
|
||||||
|
|
||||||
log.error(
|
log.error(
|
||||||
'ErrorBoundary: captured rendering error',
|
`ErrorBoundary/${name}: ` +
|
||||||
Errors.toLogFormat(error)
|
`captured rendering error ${Errors.toLogFormat(error)}` +
|
||||||
|
`\nerrorInfo: ${errorInfo.componentStack}`
|
||||||
);
|
);
|
||||||
if (window.reduxActions) {
|
if (window.reduxActions) {
|
||||||
window.reduxActions.toast.showToast(ToastType.Error);
|
window.reduxActions.toast.showToast(ToastType.Error);
|
||||||
}
|
}
|
||||||
return { error };
|
if (closeView) {
|
||||||
|
closeView();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): ReactNode {
|
public override render(): ReactNode {
|
||||||
|
|
|
@ -972,7 +972,10 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isImage(attachments) || isVideo(attachments)) {
|
if (
|
||||||
|
isImage(attachments) ||
|
||||||
|
(isVideo(attachments) && hasVideoScreenshot(attachments))
|
||||||
|
) {
|
||||||
const bottomOverlay = !isSticker && !collapseMetadata;
|
const bottomOverlay = !isSticker && !collapseMetadata;
|
||||||
// We only want users to tab into this if there's more than one
|
// We only want users to tab into this if there's more than one
|
||||||
const tabIndex = attachments.length > 1 ? 0 : -1;
|
const tabIndex = attachments.length > 1 ? 0 : -1;
|
||||||
|
|
|
@ -4633,13 +4633,17 @@ function extractDiffs({
|
||||||
Boolean(current.expireTimer) &&
|
Boolean(current.expireTimer) &&
|
||||||
old.expireTimer !== current.expireTimer)
|
old.expireTimer !== current.expireTimer)
|
||||||
) {
|
) {
|
||||||
|
const expireTimer = current.expireTimer || 0;
|
||||||
|
log.info(
|
||||||
|
`extractDiffs/${logId}: generating change notifcation for new ${expireTimer} timer`
|
||||||
|
);
|
||||||
timerNotification = {
|
timerNotification = {
|
||||||
...generateBasicMessage(),
|
...generateBasicMessage(),
|
||||||
type: 'timer-notification',
|
type: 'timer-notification',
|
||||||
sourceUuid,
|
sourceUuid,
|
||||||
flags: Proto.DataMessage.Flags.EXPIRATION_TIMER_UPDATE,
|
flags: Proto.DataMessage.Flags.EXPIRATION_TIMER_UPDATE,
|
||||||
expirationTimerUpdate: {
|
expirationTimerUpdate: {
|
||||||
expireTimer: current.expireTimer || 0,
|
expireTimer,
|
||||||
sourceUuid,
|
sourceUuid,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,6 +5,7 @@ import React from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import type { Store } from 'redux';
|
import type { Store } from 'redux';
|
||||||
|
import { ErrorBoundary } from '../../components/ErrorBoundary';
|
||||||
|
|
||||||
import type { PropsType } from '../smart/ConversationView';
|
import type { PropsType } from '../smart/ConversationView';
|
||||||
import { SmartConversationView } from '../smart/ConversationView';
|
import { SmartConversationView } from '../smart/ConversationView';
|
||||||
|
@ -14,6 +15,16 @@ export const createConversationView = (
|
||||||
props: PropsType
|
props: PropsType
|
||||||
): React.ReactElement => (
|
): React.ReactElement => (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<SmartConversationView {...props} />
|
<ErrorBoundary
|
||||||
|
name="createConversationView"
|
||||||
|
closeView={() => {
|
||||||
|
window.reduxActions.conversations.showConversation({
|
||||||
|
conversationId: undefined,
|
||||||
|
messageId: undefined,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SmartConversationView {...props} />
|
||||||
|
</ErrorBoundary>
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
|
|
|
@ -51,14 +51,14 @@ const mapStateToProps = (state: StateType) => {
|
||||||
renderGlobalModalContainer: () => <SmartGlobalModalContainer />,
|
renderGlobalModalContainer: () => <SmartGlobalModalContainer />,
|
||||||
renderLeftPane: () => <SmartLeftPane />,
|
renderLeftPane: () => <SmartLeftPane />,
|
||||||
isShowingStoriesView: shouldShowStoriesView(state),
|
isShowingStoriesView: shouldShowStoriesView(state),
|
||||||
renderStories: () => (
|
renderStories: (closeView: () => unknown) => (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary name="App/renderStories" closeView={closeView}>
|
||||||
<SmartStories />
|
<SmartStories />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
),
|
),
|
||||||
hasSelectedStoryData: hasSelectedStoryData(state),
|
hasSelectedStoryData: hasSelectedStoryData(state),
|
||||||
renderStoryViewer: () => (
|
renderStoryViewer: (closeView: () => unknown) => (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary name="App/renderStoryViewer" closeView={closeView}>
|
||||||
<SmartStoryViewer />
|
<SmartStoryViewer />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue