do not pass props not needed between message list components

This commit is contained in:
audric 2021-08-26 16:17:37 +10:00
parent ea2dbb4a69
commit 7fa50b4a73
32 changed files with 207 additions and 204 deletions

View File

@ -17,7 +17,6 @@
"postinstall": "electron-builder install-app-deps && rimraf node_modules/dtrace-provider",
"start": "cross-env NODE_APP_INSTANCE=$MULTI electron .",
"start-prod": "cross-env NODE_ENV=production NODE_APP_INSTANCE=devprod$MULTI electron .",
"start-prod2": "cross-env NODE_ENV=production NODE_APP_INSTANCE=devprod2 electron .",
"grunt": "grunt",
"grunt:dev": "yarn clean-transpile; yarn grunt dev --force",
"generate": "yarn grunt --force",
@ -118,7 +117,6 @@
"redux": "4.0.1",
"redux-logger": "3.0.6",
"redux-persist": "^6.0.0",
"redux-promise-middleware": "6.1.0",
"reselect": "4.0.0",
"rimraf": "2.6.2",
"sanitize.css": "^12.0.1",

View File

@ -199,7 +199,7 @@ const MessageItem = (props: {
if (!lastMessage && !isTyping) {
return null;
}
const text = lastMessage && lastMessage.text ? lastMessage.text : '';
const text = lastMessage?.text || '';
if (isEmpty(text)) {
return null;
@ -280,7 +280,7 @@ const ConversationListItem = (props: Props) => {
const membersAvatar = useMembersAvatars(props);
const openConvo = useCallback(
async (e: any) => {
async (e: React.MouseEvent<HTMLDivElement>) => {
// mousedown is invoked sooner than onClick, but for both right and left click
if (e.button === 0) {
await openConversationWithMessages({ conversationKey: conversationId });
@ -294,6 +294,10 @@ const ConversationListItem = (props: Props) => {
<div
role="button"
onMouseDown={openConvo}
onMouseUp={e => {
e.stopPropagation();
e.preventDefault();
}}
onContextMenu={(e: any) => {
contextMenu.show({
id: triggerId,

View File

@ -1,5 +1,6 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { useAppIsFocused } from '../hooks/useAppFocused';
import { getFocusedSettingsSection } from '../state/selectors/section';
import { SmartSessionConversation } from '../state/smart/SessionConversation';
@ -11,6 +12,9 @@ export const SessionMainPanel = () => {
const focusedSettingsSection = useSelector(getFocusedSettingsSection);
const isSettingsView = focusedSettingsSection !== undefined;
// even if it looks like this does nothing, this does update the redux store.
useAppIsFocused();
if (isSettingsView) {
return <FilteredSettingsView category={focusedSettingsSection} />;
}

View File

@ -3,7 +3,6 @@ import React, { useCallback } from 'react';
import { InView } from 'react-intersection-observer';
import { useDispatch, useSelector } from 'react-redux';
import { getMessageById } from '../../data/data';
import { useAppIsFocused } from '../../hooks/useAppFocused';
import { Constants } from '../../session';
import { getConversationController } from '../../session/conversations';
import {
@ -19,6 +18,7 @@ import {
getOldestMessageId,
getSelectedConversationKey,
} from '../../state/selectors/conversations';
import { getIsAppFocused } from '../../state/selectors/section';
type ReadableMessageProps = {
children: React.ReactNode;
@ -45,7 +45,7 @@ const debouncedTriggerLoadMore = _.debounce(
export const ReadableMessage = (props: ReadableMessageProps) => {
const { messageId, onContextMenu, className, receivedAt, isUnread } = props;
const isAppFocused = useAppIsFocused();
const isAppFocused = useSelector(getIsAppFocused);
const dispatch = useDispatch();
// onVisible={haveDoneFirstScrollProp ? onVisible : noop}

View File

@ -49,10 +49,16 @@ export class EditProfileDialog extends React.Component<{}, State> {
};
this.inputEl = React.createRef();
}
public componentDidMount() {
window.addEventListener('keyup', this.onKeyUp);
}
public componentWillUnmount() {
window.removeEventListener('keyup', this.onKeyUp);
}
public render() {
const i18n = window.i18n;

View File

@ -13,6 +13,8 @@ import { SessionWrapperModal } from '../session/SessionWrapperModal';
import { SpacerLG } from '../basic/Text';
import { useDispatch } from 'react-redux';
import { updateInviteContactModal } from '../../state/ducks/modalDialog';
// tslint:disable-next-line: no-submodule-imports
import useKey from 'react-use/lib/useKey';
type Props = {
conversationId: string;
@ -67,7 +69,6 @@ const InviteContactsDialogInner = (props: Props) => {
);
const closeDialog = () => {
window.removeEventListener('keyup', onKeyUp);
dispatch(updateInviteContactModal(null));
};
@ -87,19 +88,13 @@ const InviteContactsDialogInner = (props: Props) => {
closeDialog();
};
const onKeyUp = (event: any) => {
switch (event.key) {
case 'Enter':
onClickOK();
break;
case 'Esc':
case 'Escape':
closeDialog();
break;
default:
}
};
window.addEventListener('keyup', onKeyUp);
useKey((event: KeyboardEvent) => {
return event.key === 'Enter';
}, onClickOK);
useKey((event: KeyboardEvent) => {
return event.key === 'Esc' || event.key === 'Escape';
}, closeDialog);
const titleText = `${window.i18n('addingContacts')} ${chatName}`;
const cancelText = window.i18n('cancel');

View File

@ -48,15 +48,17 @@ export class SessionModal extends React.PureComponent<Props, State> {
this.close = this.close.bind(this);
this.onKeyUp = this.onKeyUp.bind(this);
this.node = null;
window.addEventListener('keyup', this.onKeyUp);
}
public componentDidMount() {
window.addEventListener('keyup', this.onKeyUp);
document.addEventListener('mousedown', this.handleClick, false);
}
public componentWillUnmount() {
window.removeEventListener('keyup', this.onKeyUp);
document.removeEventListener('mousedown', this.handleClick, false);
}
@ -118,7 +120,6 @@ export class SessionModal extends React.PureComponent<Props, State> {
isVisible: false,
});
window.removeEventListener('keyup', this.onKeyUp);
document.removeEventListener('mousedown', this.handleClick, false);
if (this.props.onClose) {

View File

@ -109,10 +109,16 @@ export class UpdateGroupMembersDialog extends React.Component<Props, State> {
admins,
isAdmin,
};
}
public componentDidMount() {
window.addEventListener('keyup', this.onKeyUp);
}
public componentWillUnmount() {
window.removeEventListener('keyup', this.onKeyUp);
}
public onClickOK() {
const members = this.getWouldBeMembers(this.state.contactList).map(d => d.id);
@ -243,8 +249,6 @@ export class UpdateGroupMembersDialog extends React.Component<Props, State> {
}
private closeDialog() {
window.removeEventListener('keyup', this.onKeyUp);
window.inboxStore?.dispatch(updateGroupMembersModal(null));
}

View File

@ -39,9 +39,16 @@ export class UpdateGroupNameDialog extends React.Component<Props, State> {
avatar: this.convo.getAvatarPath(),
};
this.inputEl = React.createRef();
}
public componentDidMount() {
window.addEventListener('keyup', this.onKeyUp);
}
public componentWillUnmount() {
window.removeEventListener('keyup', this.onKeyUp);
}
public onClickOK() {
if (!this.state.groupName.trim()) {
this.onShowError(window.i18n('emptyGroupNameError'));

View File

@ -173,7 +173,7 @@ const removeAllV1OpenGroups = async () => {
if (window.inboxStore) {
window.inboxStore?.dispatch(conversationRemoved(v1Convo.id));
window.inboxStore?.dispatch(
conversationChanged({ id: v1Convo.id, data: v1Convo.getProps() })
conversationChanged({ id: v1Convo.id, data: v1Convo.getConversationModelProps() })
);
}
} catch (e) {

View File

@ -49,14 +49,19 @@ export class SessionClosableOverlay extends React.Component<Props, State> {
this.onKeyUp = this.onKeyUp.bind(this);
this.onGroupNameChanged = this.onGroupNameChanged.bind(this);
window.addEventListener('keyup', this.onKeyUp);
}
public componentDidMount() {
window.addEventListener('keyup', this.onKeyUp);
if (this.inputRef.current) {
this.inputRef.current.focus();
}
}
public componentWillUnmount() {
window.removeEventListener('keyup', this.onKeyUp);
}
public getContacts() {
const { overlayMode } = this.props;

View File

@ -76,7 +76,7 @@ export class SessionInboxView extends React.Component<any, State> {
// Here we set up a full redux store with initial state for our LeftPane Root
const convoCollection = getConversationController().getConversations();
const conversations = convoCollection.map((conversation: ConversationModel) =>
conversation.getProps()
conversation.getConversationModelProps()
);
const filledConversations = conversations.map((conv: any) => {

View File

@ -166,7 +166,7 @@ class SessionCompositionBoxInner extends React.Component<Props, State> {
}
public componentDidMount() {
setTimeout(this.focusCompositionBox, 100);
setTimeout(this.focusCompositionBox, 500);
const div = this.container;
div?.addEventListener('paste', this.handlePaste);

View File

@ -1,8 +1,7 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { QuoteClickOptions } from '../../../models/messageType';
import { SortedMessageModelProps } from '../../../state/ducks/conversations';
import { getSortedMessagesOfSelectedConversation } from '../../../state/selectors/conversations';
import { getSortedMessagesTypesOfSelectedConversation } from '../../../state/selectors/conversations';
import {
DataExtractionNotificationItem,
GenericMessageItem,
@ -14,61 +13,57 @@ import {
export const SessionMessagesList = (props: {
scrollToQuoteMessage: (options: QuoteClickOptions) => Promise<void>;
}) => {
const messagesProps = useSelector(getSortedMessagesOfSelectedConversation);
const messagesProps = useSelector(getSortedMessagesTypesOfSelectedConversation);
return (
<>
{messagesProps.map((messageProps: SortedMessageModelProps) => {
const timerProps = messageProps.propsForTimerNotification;
const propsForGroupInvitation = messageProps.propsForGroupInvitation;
const propsForDataExtractionNotification = messageProps.propsForDataExtractionNotification;
const groupNotificationProps = messageProps.propsForGroupNotification;
if (groupNotificationProps) {
{messagesProps.map(messageProps => {
if (messageProps.messageType === 'group-notification') {
return (
<GroupUpdateItem
key={messageProps.propsForMessage.id}
groupNotificationProps={groupNotificationProps}
key={messageProps.props.messageId}
groupNotificationProps={messageProps.props}
/>
);
}
if (propsForGroupInvitation) {
if (messageProps.messageType === 'group-invitation') {
return (
<GroupInvitationItem
key={messageProps.propsForMessage.id}
propsForGroupInvitation={propsForGroupInvitation}
key={messageProps.props.messageId}
propsForGroupInvitation={messageProps.props}
/>
);
}
if (propsForDataExtractionNotification) {
if (messageProps.messageType === 'data-extraction') {
return (
<DataExtractionNotificationItem
key={messageProps.propsForMessage.id}
propsForDataExtractionNotification={propsForDataExtractionNotification}
key={messageProps.props.messageId}
propsForDataExtractionNotification={messageProps.props}
/>
);
}
if (timerProps) {
if (messageProps.messageType === 'timer-notification') {
return (
<TimerNotificationItem key={messageProps.propsForMessage.id} timerProps={timerProps} />
<TimerNotificationItem
key={messageProps.props.messageId}
timerProps={messageProps.props}
/>
);
}
if (!messageProps) {
return;
return null;
}
// firstMessageOfSeries tells us to render the avatar only for the first message
// in a series of messages from the same user
return (
<GenericMessageItem
key={messageProps.propsForMessage.id}
messageId={messageProps.propsForMessage.id}
messageProps={messageProps}
key={messageProps.props.messageId}
messageId={messageProps.props.messageId}
scrollToQuoteMessage={props.scrollToQuoteMessage}
/>
);

View File

@ -5,7 +5,6 @@ import {
PropsForExpirationTimer,
PropsForGroupInvitation,
PropsForGroupUpdate,
SortedMessageModelProps,
} from '../../../state/ducks/conversations';
import { getFirstUnreadMessageId } from '../../../state/selectors/conversations';
import { DataExtractionNotification } from '../../conversation/DataExtractionNotification';
@ -77,18 +76,13 @@ export const TimerNotificationItem = (props: { timerProps: PropsForExpirationTim
export const GenericMessageItem = (props: {
messageId: string;
messageProps: SortedMessageModelProps;
scrollToQuoteMessage: (options: QuoteClickOptions) => Promise<void>;
}) => {
const messageId = props.messageId;
const onQuoteClick = props.messageProps.propsForMessage.quote
? props.scrollToQuoteMessage
: undefined;
return (
<React.Fragment key={messageId}>
<Message messageId={messageId} onQuoteClick={onQuoteClick} key={messageId} />
<Message messageId={messageId} onQuoteClick={props.scrollToQuoteMessage} key={messageId} />
<UnreadIndicator messageId={messageId} />
</React.Fragment>
);

View File

@ -93,16 +93,21 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
void this.hasPassword();
this.onKeyUp = this.onKeyUp.bind(this);
window.addEventListener('keyup', this.onKeyUp);
}
public componentDidMount() {
window.addEventListener('keyup', this.onKeyUp);
const mediaSetting = window.getSettingValue('media-permissions');
this.setState({ mediaSetting });
setTimeout(() => ($('#password-lock-input') as any).focus(), 100);
}
public componentWillUnmount() {
window.removeEventListener('keyup', this.onKeyUp);
}
/* tslint:disable-next-line:max-func-body-length */
public renderSettingInCategory() {
const { category } = this.props;

View File

@ -1,31 +1,29 @@
import { remote } from 'electron';
import { useCallback, useEffect, useState } from 'react';
import { useCallback, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { isElectronWindowFocused } from '../session/utils/WindowUtils';
import { setIsAppFocused } from '../state/ducks/section';
import { getIsAppFocused } from '../state/selectors/section';
export function useAppIsFocused() {
const [isAppFocused, setIsAppFocused] = useState(false);
const dispatch = useDispatch();
const isFocused = useSelector(getIsAppFocused);
useEffect(() => {
setIsAppFocused(isElectronWindowFocused());
dispatch(setIsAppFocused(isElectronWindowFocused()));
}, []);
const onFocusCallback = useCallback(
(_event, win) => {
if (win.webContents.id === 1) {
setIsAppFocused(true);
}
},
[setIsAppFocused]
);
const onFocusCallback = useCallback((_event, win) => {
if (win.webContents.id === 1) {
dispatch(setIsAppFocused(true));
}
}, []);
const onBlurCallback = useCallback(
(_event, win) => {
if (win.webContents.id === 1) {
setIsAppFocused(false);
}
},
[setIsAppFocused]
);
const onBlurCallback = useCallback((_event, win) => {
if (win.webContents.id === 1) {
dispatch(setIsAppFocused(false));
}
}, []);
useEffect(() => {
remote.app.on('browser-window-focus', onFocusCallback);
@ -36,5 +34,5 @@ export function useAppIsFocused() {
};
});
return isAppFocused;
return isFocused;
}

View File

@ -1,6 +1,7 @@
import { useEffect, useRef, useState } from 'react';
import { getDecryptedMediaUrl } from '../session/crypto/DecryptedAttachmentsManager';
import { perfEnd, perfStart } from '../session/utils/Performance';
export const useEncryptedFileFetch = (url: string, contentType: string) => {
// tslint:disable-next-line: no-bitwise
@ -10,7 +11,11 @@ export const useEncryptedFileFetch = (url: string, contentType: string) => {
const mountedRef = useRef(true);
async function fetchUrl() {
perfStart(`getDecryptedMediaUrl${url}`);
const decryptedUrl = await getDecryptedMediaUrl(url, contentType);
perfEnd(`getDecryptedMediaUrl${url}`, 'getDecryptedMediaUrl');
if (mountedRef.current) {
setUrlToLoad(decryptedUrl);

View File

@ -223,7 +223,9 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
this.typingRefreshTimer = null;
this.typingPauseTimer = null;
this.lastReadTimestamp = 0;
window.inboxStore?.dispatch(conversationChanged({ id: this.id, data: this.getProps() }));
window.inboxStore?.dispatch(
conversationChanged({ id: this.id, data: this.getConversationModelProps() })
);
}
public idForLogging() {
@ -407,7 +409,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
return this.get('moderators');
}
public getProps(): ReduxConversationType {
public getConversationModelProps(): ReduxConversationType {
const groupAdmins = this.getGroupAdmins();
const members = this.isGroup() && !this.isPublic() ? this.get('members') : [];
const ourNumber = UserUtils.getOurPubKeyStrFromCache();
@ -804,13 +806,8 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
lastMessageStatus: lastMessageStatusModel,
lastMessageNotificationText: lastMessageModel ? lastMessageModel.getNotificationText() : null,
});
// Because we're no longer using Backbone-integrated saves, we need to manually
// clear the changed fields here so our hasChanged() check below is useful.
(this as any).changed = {};
this.set(lastMessageUpdate);
if (this.hasChanged()) {
await this.commit();
}
await this.commit();
}
public async updateExpireTimer(
@ -917,7 +914,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
conversationChanged({
id: this.id,
data: {
...this.getProps(),
...this.getConversationModelProps(),
isSelected: false,
},
})
@ -945,7 +942,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
window.inboxStore?.dispatch(
conversationActions.messageAdded({
conversationKey: this.id,
messageModelProps: model.getProps(),
messageModelProps: model.getMessageModelProps(),
})
);
const unreadCount = await this.getUnreadCount();
@ -1006,7 +1003,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
const allProps: Array<MessageModelPropsWithoutConvoProps> = [];
for (const nowRead of oldUnreadNowRead) {
allProps.push(nowRead.getProps());
allProps.push(nowRead.getMessageModelProps());
}
if (allProps.length) {

View File

@ -80,10 +80,10 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
window.contextMenuShown = false;
this.getProps();
this.getMessageModelProps();
}
public getProps(): MessageModelPropsWithoutConvoProps {
public getMessageModelProps(): MessageModelPropsWithoutConvoProps {
perfStart(`getPropsMessage-${this.id}`);
const messageProps: MessageModelPropsWithoutConvoProps = {
propsForMessage: this.getPropsForMessage(),
@ -1121,7 +1121,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
}
}
private dispatchMessageUpdate() {
updatesToDispatch.set(this.id, this.getProps());
updatesToDispatch.set(this.id, this.getMessageModelProps());
trotthledAllMessagesDispatch();
}
}

View File

@ -38,7 +38,7 @@ export async function onError(ev: any) {
window.inboxStore?.dispatch(
conversationActions.messageAdded({
conversationKey: conversation.id,
messageModelProps: message.getProps(),
messageModelProps: message.getMessageModelProps(),
})
);

View File

@ -454,7 +454,7 @@ export async function handleMessageJob(
updatesToDispatch.set(message.id, {
conversationKey: conversation.id,
messageModelProps: message.getProps(),
messageModelProps: message.getMessageModelProps(),
});
trotthledAllMessagesAddedDispatch();
if (message.get('unread')) {

View File

@ -120,7 +120,7 @@ export class ConversationController {
window.inboxStore?.dispatch(
conversationActions.conversationAdded({
id: conversation.id,
data: conversation.getProps(),
data: conversation.getConversationModelProps(),
})
);
}
@ -249,7 +249,7 @@ export class ConversationController {
window.inboxStore?.dispatch(
conversationActions.conversationChanged({
id: conversation.id,
data: conversation.getProps(),
data: conversation.getConversationModelProps(),
})
);
window.inboxStore?.dispatch(conversationActions.conversationRemoved(conversation.id));

View File

@ -1,4 +1,3 @@
import promise from 'redux-promise-middleware';
import { createLogger } from 'redux-logger';
import { configureStore } from '@reduxjs/toolkit';
import { rootReducer } from './reducer';
@ -6,7 +5,6 @@ import { persistReducer } from 'redux-persist';
// tslint:disable-next-line: no-submodule-imports match-default-export-name
import storage from 'redux-persist/lib/storage';
// @ts-ignore
const env = window.getEnvironment();

View File

@ -300,7 +300,7 @@ async function getMessages(
});
const messageProps: Array<MessageModelPropsWithoutConvoProps> = messageSet.models.map(m =>
m.getProps()
m.getMessageModelProps()
);
return messageProps;
}
@ -326,11 +326,11 @@ export const fetchMessagesForConversation = createAsyncThunk(
}): Promise<FetchedMessageResults> => {
const beforeTimestamp = Date.now();
// tslint:disable-next-line: no-console
console.time('fetchMessagesForConversation');
perfStart('fetchMessagesForConversation');
const messagesProps = await getMessages(conversationKey, count);
const afterTimestamp = Date.now();
// tslint:disable-next-line: no-console
console.timeEnd('fetchMessagesForConversation');
perfEnd('fetchMessagesForConversation', 'fetchMessagesForConversation');
const time = afterTimestamp - beforeTimestamp;
window?.log?.info(`Loading ${messagesProps.length} messages took ${time}ms to load.`);
@ -824,10 +824,16 @@ export async function openConversationWithMessages(args: {
messageId?: string;
}) {
const { conversationKey, messageId } = args;
perfStart('getFirstUnreadMessageIdInConversation');
const firstUnreadIdOnOpen = await getFirstUnreadMessageIdInConversation(conversationKey);
perfEnd('getFirstUnreadMessageIdInConversation', 'getFirstUnreadMessageIdInConversation');
// preload 30 messages
perfStart('getMessages');
const initialMessages = await getMessages(conversationKey, 30);
perfEnd('getMessages', 'getMessages');
console.warn('initialMessages', initialMessages);
window.inboxStore?.dispatch(
actions.openConversationExternal({

View File

@ -2,6 +2,7 @@ import { SessionSettingCategory } from '../../components/session/settings/Sessio
export const FOCUS_SECTION = 'FOCUS_SECTION';
export const FOCUS_SETTINGS_SECTION = 'FOCUS_SETTINGS_SECTION';
export const IS_APP_FOCUSED = 'IS_APP_FOCUSED';
export enum SectionType {
Profile,
@ -23,6 +24,11 @@ type FocusSettingsSectionActionType = {
payload: SessionSettingCategory;
};
type IsAppFocusedActionType = {
type: 'IS_APP_FOCUSED';
payload: boolean;
};
export function showLeftPaneSection(section: SectionType): FocusSectionActionType {
return {
type: FOCUS_SECTION,
@ -32,6 +38,13 @@ export function showLeftPaneSection(section: SectionType): FocusSectionActionTyp
type SectionActionTypes = FocusSectionActionType | FocusSettingsSectionActionType;
export function setIsAppFocused(focused: boolean): IsAppFocusedActionType {
return {
type: IS_APP_FOCUSED,
payload: focused,
};
}
export function showSettingsSection(
category: SessionSettingCategory
): FocusSettingsSectionActionType {
@ -46,14 +59,16 @@ export const actions = {
showSettingsSection,
};
export const initialSectionState = {
export const initialSectionState: SectionStateType = {
focusedSection: SectionType.Message,
focusedSettingsSection: undefined,
isAppFocused: false,
};
export type SectionStateType = {
focusedSection: SectionType;
focusedSettingsSection?: SessionSettingCategory;
isAppFocused: boolean;
};
export const reducer = (
@ -73,6 +88,7 @@ export const reducer = (
if (castedPayload !== SectionType.Settings) {
return {
...state,
focusedSection: castedPayload,
focusedSettingsSection: undefined,
};
@ -89,6 +105,12 @@ export const reducer = (
...state,
focusedSettingsSection: payload,
};
case IS_APP_FOCUSED:
return {
...state,
isAppFocused: payload,
};
default:
return state;
}

View File

@ -126,6 +126,58 @@ export const getSortedMessagesOfSelectedConversation = createSelector(
}
);
export type MessagePropsType =
| 'group-notification'
| 'group-invitation'
| 'data-extraction'
| 'timer-notification'
| 'regular-message';
export const getSortedMessagesTypesOfSelectedConversation = createSelector(
getMessagesOfSelectedConversation,
(
sortedMessages
): Array<{
messageType: MessagePropsType;
props: any;
}> => {
return sortedMessages.map(msg => {
if (msg.propsForDataExtractionNotification) {
return {
messageType: 'data-extraction',
props: { ...msg.propsForDataExtractionNotification, messageId: msg.propsForMessage.id },
};
}
if (msg.propsForGroupInvitation) {
return {
messageType: 'group-invitation',
props: { ...msg.propsForGroupInvitation, messageId: msg.propsForMessage.id },
};
}
if (msg.propsForGroupNotification) {
return {
messageType: 'group-notification',
props: { ...msg.propsForGroupNotification, messageId: msg.propsForMessage.id },
};
}
if (msg.propsForTimerNotification) {
return {
messageType: 'data-extraction',
props: { ...msg.propsForTimerNotification, messageId: msg.propsForMessage.id },
};
}
return {
messageType: 'regular-message',
props: { messageId: msg.propsForMessage.id },
};
});
}
);
function getConversationTitle(
conversation: ReduxConversationType,
testingi18n?: LocalizerType

View File

@ -15,3 +15,8 @@ export const getFocusedSettingsSection = createSelector(
getSection,
(state: SectionStateType): SessionSettingCategory | undefined => state.focusedSettingsSection
);
export const getIsAppFocused = createSelector(
getSection,
(state: SectionStateType): boolean => state.isAppFocused
);

View File

@ -2,7 +2,6 @@ import * as GoogleChrome from './GoogleChrome';
import { arrayBufferToObjectURL } from './arrayBufferToObjectURL';
import { isFileDangerous } from './isFileDangerous';
import { missingCaseError } from './missingCaseError';
import { migrateColor } from './migrateColor';
import { makeLookup } from './makeLookup';
import * as PasswordUtil from './passwordUtils';
import * as AttachmentUtil from './attachmentsUtil';
@ -15,7 +14,6 @@ export {
GoogleChrome,
isFileDangerous,
makeLookup,
migrateColor,
missingCaseError,
PasswordUtil,
AttachmentUtil,

View File

@ -290,15 +290,6 @@
"updated": "2018-09-19T21:59:32.770Z",
"reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-html(",
"path": "js/views/identicon_svg_view.js",
"line": " const html = this.render().$el.html();",
"lineNumber": 19,
"reasonCategory": "usageTrusted",
"updated": "2018-09-15T00:38:04.183Z",
"reasonDetail": "Getting the value, not setting it"
},
{
"rule": "jQuery-$(",
"path": "js/views/inbox_view.js",

View File

@ -1,82 +0,0 @@
// import { missingCaseError } from './missingCaseError';
type OldColor =
| 'amber'
| 'blue'
| 'blue_grey'
| 'brown'
| 'cyan'
| 'deep_orange'
| 'deep_purple'
| 'green'
| 'grey'
| 'indigo'
| 'lime'
| 'light_blue'
| 'light_green'
| 'orange'
| 'pink'
| 'purple'
| 'red'
| 'teal'
| 'yellow';
type NewColor =
| 'red'
| 'deep_orange'
| 'brown'
| 'pink'
| 'purple'
| 'indigo'
| 'blue'
| 'teal'
| 'green'
| 'light_green'
| 'blue_grey'
| 'grey';
export function migrateColor(color: OldColor): NewColor {
switch (color) {
// These colors no longer exist
case 'orange':
case 'amber':
return 'deep_orange';
case 'yellow':
return 'brown';
case 'deep_purple':
return 'purple';
case 'light_blue':
return 'blue';
case 'cyan':
return 'teal';
case 'lime':
return 'light_green';
// These can stay as they are
case 'red':
case 'deep_orange':
case 'brown':
case 'pink':
case 'purple':
case 'indigo':
case 'blue':
case 'teal':
case 'green':
case 'light_green':
case 'blue_grey':
case 'grey':
return color;
// Can uncomment this to ensure that we've covered all potential cases
// default:
// throw missingCaseError(color);
default:
return 'grey';
}
}

View File

@ -7542,11 +7542,6 @@ redux-persist@^6.0.0:
resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-6.0.0.tgz#b4d2972f9859597c130d40d4b146fecdab51b3a8"
integrity sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==
redux-promise-middleware@6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/redux-promise-middleware/-/redux-promise-middleware-6.1.0.tgz#ecdb22488cdd673c1a3f0d278d82b48d92ca5d06"
integrity sha512-C62Ku3TgMwxFh5r3h1/iD+XPdsoizyHLT74dTkqhJ8c0LCbEVl1z9fm8zKitAjI16e6w6+h3mxf6wHdonaYXfQ==
redux-thunk@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"