Do not populate left pane on initial link
This commit is contained in:
parent
f456bbd3db
commit
5e2d48cc2f
25 changed files with 791 additions and 277 deletions
|
@ -761,6 +761,10 @@
|
|||
"message": "Contacts",
|
||||
"description": "Shown to separate the types of search results"
|
||||
},
|
||||
"groupsHeader": {
|
||||
"message": "Groups",
|
||||
"description": "Shown to separate the types of search results"
|
||||
},
|
||||
"messagesHeader": {
|
||||
"message": "Messages",
|
||||
"description": "Shown to separate the types of search results"
|
||||
|
@ -1905,6 +1909,10 @@
|
|||
"message": "No contacts found",
|
||||
"description": "Label shown when there are no contacts to compose to"
|
||||
},
|
||||
"noConversationsFound": {
|
||||
"message": "No conversations found",
|
||||
"description": "Label shown when there are no conversations to compose to"
|
||||
},
|
||||
"chooseGroupMembers__title": {
|
||||
"message": "Choose members",
|
||||
"description": "The title for the 'choose group members' left pane screen"
|
||||
|
@ -5130,5 +5138,19 @@
|
|||
"MessageAudio--slider": {
|
||||
"message": "Playback time of audio attachment",
|
||||
"description": "Aria label for audio attachment's playback time slider"
|
||||
},
|
||||
"emptyInboxMessage": {
|
||||
"message": "Click the $composeIcon$ above and search for your contacts or groups to message.",
|
||||
"description": "Shown in the left-pane when the inbox is empty",
|
||||
"placeholders": {
|
||||
"composeIcon": {
|
||||
"content": "$1",
|
||||
"example": "compose button"
|
||||
}
|
||||
}
|
||||
},
|
||||
"composeIcon": {
|
||||
"message": "compose button",
|
||||
"description": "Shown in the left-pane when the inbox is empty. Describes the button that composes a new message."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,8 @@
|
|||
},
|
||||
render_attributes: {
|
||||
welcomeToSignal: i18n('welcomeToSignal'),
|
||||
selectAContact: i18n('selectAContact'),
|
||||
// TODO DESKTOP-1451: add back the selectAContact message
|
||||
selectAContact: '',
|
||||
},
|
||||
events: {
|
||||
click: 'onClick',
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
initialize(options = {}) {
|
||||
window.readyForUpdates();
|
||||
|
||||
this.didLink = false;
|
||||
this.selectStep(Steps.SCAN_QR_CODE);
|
||||
this.connect();
|
||||
this.on('disconnected', this.reconnect);
|
||||
|
@ -197,7 +196,7 @@
|
|||
this.selectStep(Steps.PROGRESS_BAR);
|
||||
|
||||
const finish = () => {
|
||||
this.didLink = true;
|
||||
window.Signal.Util.postLinkExperience.start();
|
||||
return resolve(name);
|
||||
};
|
||||
|
||||
|
|
|
@ -7401,6 +7401,36 @@ button.module-image__border-overlay:focus {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.module-left-pane__empty {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
padding: 0 32px;
|
||||
text-align: center;
|
||||
|
||||
&--composer_icon {
|
||||
align-items: center;
|
||||
background-color: $color-gray-05;
|
||||
border-radius: 100%;
|
||||
display: inline-flex;
|
||||
height: 28px;
|
||||
justify-content: center;
|
||||
margin-bottom: -2px;
|
||||
margin-left: 4px;
|
||||
vertical-align: bottom;
|
||||
width: 28px;
|
||||
|
||||
&--icon {
|
||||
$icon: '../images/icons/v2/compose-outline-24.svg';
|
||||
@include color-svg($icon, $color-gray-90);
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.module-left-pane__header {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
|
|
|
@ -2398,13 +2398,6 @@ export async function startApp(): Promise<void> {
|
|||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const conversation = window.ConversationController.get(detailsId)!;
|
||||
let activeAt = conversation.get('active_at');
|
||||
|
||||
// The idea is to make any new contact show up in the left pane. If
|
||||
// activeAt is null, then this contact has been purposefully hidden.
|
||||
if (activeAt !== null) {
|
||||
activeAt = activeAt || Date.now();
|
||||
}
|
||||
|
||||
if (details.profileKey) {
|
||||
const profileKey = window.Signal.Crypto.arrayBufferToBase64(
|
||||
|
@ -2424,7 +2417,6 @@ export async function startApp(): Promise<void> {
|
|||
conversation.set({
|
||||
name: details.name,
|
||||
color: details.color,
|
||||
active_at: activeAt,
|
||||
inbox_position: details.inboxPosition,
|
||||
});
|
||||
|
||||
|
@ -2480,8 +2472,7 @@ export async function startApp(): Promise<void> {
|
|||
await onVerified(verifiedEvent);
|
||||
}
|
||||
|
||||
const { appView } = window.owsDesktopApp;
|
||||
if (appView && appView.installView && appView.installView.didLink) {
|
||||
if (window.Signal.Util.postLinkExperience.isActive()) {
|
||||
window.log.info(
|
||||
'onContactReceived: Adding the message history disclaimer on link'
|
||||
);
|
||||
|
@ -2538,13 +2529,6 @@ export async function startApp(): Promise<void> {
|
|||
} as WhatIsThis;
|
||||
|
||||
if (details.active) {
|
||||
const activeAt = conversation.get('active_at');
|
||||
|
||||
// The idea is to make any new group show up in the left pane. If
|
||||
// activeAt is null, then this group has been purposefully hidden.
|
||||
if (activeAt !== null) {
|
||||
updates.active_at = activeAt || Date.now();
|
||||
}
|
||||
updates.left = false;
|
||||
} else {
|
||||
updates.left = true;
|
||||
|
@ -2575,8 +2559,7 @@ export async function startApp(): Promise<void> {
|
|||
|
||||
window.Signal.Data.updateConversation(conversation.attributes);
|
||||
|
||||
const { appView } = window.owsDesktopApp;
|
||||
if (appView && appView.installView && appView.installView.didLink) {
|
||||
if (window.Signal.Util.postLinkExperience.isActive()) {
|
||||
window.log.info(
|
||||
'onGroupReceived: Adding the message history disclaimer on link'
|
||||
);
|
||||
|
@ -2846,9 +2829,6 @@ export async function startApp(): Promise<void> {
|
|||
|
||||
// Finally create the V2 group normally
|
||||
const conversationId = window.ConversationController.ensureGroup(id, {
|
||||
// Note: We don't set active_at, because we don't want the group to show until
|
||||
// we have information about it beyond these initial details.
|
||||
// see maybeUpdateGroup().
|
||||
groupVersion: 2,
|
||||
masterKey: message.groupV2.masterKey,
|
||||
secretParams: message.groupV2.secretParams,
|
||||
|
|
|
@ -35,6 +35,25 @@ const defaultConversations: Array<ConversationListItemPropsType> = [
|
|||
},
|
||||
];
|
||||
|
||||
const defaultGroups: Array<ConversationListItemPropsType> = [
|
||||
{
|
||||
id: 'biking-group',
|
||||
isSelected: false,
|
||||
lastUpdated: Date.now(),
|
||||
markedUnread: false,
|
||||
title: 'Mtn Biking Arizona 🚵☀️⛰',
|
||||
type: 'group',
|
||||
},
|
||||
{
|
||||
id: 'dance-group',
|
||||
isSelected: false,
|
||||
lastUpdated: Date.now(),
|
||||
markedUnread: false,
|
||||
title: 'Are we dancers? 💃',
|
||||
type: 'group',
|
||||
},
|
||||
];
|
||||
|
||||
const defaultArchivedConversations: Array<ConversationListItemPropsType> = [
|
||||
{
|
||||
id: 'michelle-archive-convo',
|
||||
|
@ -352,12 +371,13 @@ story.add('Archive: archived conversations', () => (
|
|||
|
||||
// Compose stories
|
||||
|
||||
story.add('Compose: no contacts', () => (
|
||||
story.add('Compose: no contacts or groups', () => (
|
||||
<LeftPane
|
||||
{...createProps({
|
||||
modeSpecificProps: {
|
||||
mode: LeftPaneMode.Compose,
|
||||
composeContacts: [],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
},
|
||||
|
@ -365,12 +385,13 @@ story.add('Compose: no contacts', () => (
|
|||
/>
|
||||
));
|
||||
|
||||
story.add('Compose: some contacts, no search term', () => (
|
||||
story.add('Compose: some contacts, no groups, no search term', () => (
|
||||
<LeftPane
|
||||
{...createProps({
|
||||
modeSpecificProps: {
|
||||
mode: LeftPaneMode.Compose,
|
||||
composeContacts: defaultConversations,
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
},
|
||||
|
@ -378,14 +399,71 @@ story.add('Compose: some contacts, no search term', () => (
|
|||
/>
|
||||
));
|
||||
|
||||
story.add('Compose: some contacts with a search term', () => (
|
||||
story.add('Compose: some contacts, no groups, with a search term', () => (
|
||||
<LeftPane
|
||||
{...createProps({
|
||||
modeSpecificProps: {
|
||||
mode: LeftPaneMode.Compose,
|
||||
composeContacts: defaultConversations,
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
searchTerm: 'ar',
|
||||
},
|
||||
})}
|
||||
/>
|
||||
));
|
||||
|
||||
story.add('Compose: some groups, no contacts, no search term', () => (
|
||||
<LeftPane
|
||||
{...createProps({
|
||||
modeSpecificProps: {
|
||||
mode: LeftPaneMode.Compose,
|
||||
composeContacts: [],
|
||||
composeGroups: defaultGroups,
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
},
|
||||
})}
|
||||
/>
|
||||
));
|
||||
|
||||
story.add('Compose: some groups, no contacts, with search term', () => (
|
||||
<LeftPane
|
||||
{...createProps({
|
||||
modeSpecificProps: {
|
||||
mode: LeftPaneMode.Compose,
|
||||
composeContacts: [],
|
||||
composeGroups: defaultGroups,
|
||||
regionCode: 'US',
|
||||
searchTerm: 'ar',
|
||||
},
|
||||
})}
|
||||
/>
|
||||
));
|
||||
|
||||
story.add('Compose: some contacts, some groups, no search term', () => (
|
||||
<LeftPane
|
||||
{...createProps({
|
||||
modeSpecificProps: {
|
||||
mode: LeftPaneMode.Compose,
|
||||
composeContacts: defaultConversations,
|
||||
composeGroups: defaultGroups,
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
},
|
||||
})}
|
||||
/>
|
||||
));
|
||||
|
||||
story.add('Compose: some contacts, some groups, with a search term', () => (
|
||||
<LeftPane
|
||||
{...createProps({
|
||||
modeSpecificProps: {
|
||||
mode: LeftPaneMode.Compose,
|
||||
composeContacts: defaultConversations,
|
||||
composeGroups: defaultGroups,
|
||||
regionCode: 'US',
|
||||
searchTerm: 'ar',
|
||||
},
|
||||
})}
|
||||
/>
|
||||
|
|
|
@ -14,7 +14,7 @@ import { LocalizerType } from '../../../../types/Util';
|
|||
import { assert } from '../../../../util/assert';
|
||||
import { getOwn } from '../../../../util/getOwn';
|
||||
import { missingCaseError } from '../../../../util/missingCaseError';
|
||||
import { filterAndSortContacts } from '../../../../util/filterAndSortContacts';
|
||||
import { filterAndSortConversations } from '../../../../util/filterAndSortConversations';
|
||||
import { ConversationType } from '../../../../state/ducks/conversations';
|
||||
import { ModalHost } from '../../../ModalHost';
|
||||
import { ContactPills } from '../../../ContactPills';
|
||||
|
@ -72,13 +72,13 @@ export const ChooseGroupMembersModal: FunctionComponent<PropsType> = ({
|
|||
const canContinue = Boolean(selectedContacts.length);
|
||||
|
||||
const [filteredContacts, setFilteredContacts] = useState(
|
||||
filterAndSortContacts(candidateContacts, '')
|
||||
filterAndSortConversations(candidateContacts, '')
|
||||
);
|
||||
const normalizedSearchTerm = searchTerm.trim();
|
||||
useEffect(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
setFilteredContacts(
|
||||
filterAndSortContacts(candidateContacts, normalizedSearchTerm)
|
||||
filterAndSortConversations(candidateContacts, normalizedSearchTerm)
|
||||
);
|
||||
}, 200);
|
||||
return () => {
|
||||
|
|
|
@ -7,6 +7,7 @@ import { PhoneNumber } from 'google-libphonenumber';
|
|||
import { LeftPaneHelper } from './LeftPaneHelper';
|
||||
import { Row, RowType } from '../ConversationList';
|
||||
import { PropsDataType as ContactListItemPropsType } from '../conversationList/ContactListItem';
|
||||
import { PropsData as ConversationListItemPropsType } from '../conversationList/ConversationListItem';
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
import {
|
||||
instance as phoneNumberInstance,
|
||||
|
@ -18,6 +19,7 @@ import { isStorageWriteFeatureEnabled } from '../../storage/isFeatureEnabled';
|
|||
|
||||
export type LeftPaneComposePropsType = {
|
||||
composeContacts: ReadonlyArray<ContactListItemPropsType>;
|
||||
composeGroups: ReadonlyArray<ContactListItemPropsType>;
|
||||
regionCode: string;
|
||||
searchTerm: string;
|
||||
};
|
||||
|
@ -35,20 +37,24 @@ export class LeftPaneComposeHelper extends LeftPaneHelper<
|
|||
> {
|
||||
private readonly composeContacts: ReadonlyArray<ContactListItemPropsType>;
|
||||
|
||||
private readonly composeGroups: ReadonlyArray<ConversationListItemPropsType>;
|
||||
|
||||
private readonly searchTerm: string;
|
||||
|
||||
private readonly phoneNumber: undefined | PhoneNumber;
|
||||
|
||||
constructor({
|
||||
composeContacts,
|
||||
composeGroups,
|
||||
regionCode,
|
||||
searchTerm,
|
||||
}: Readonly<LeftPaneComposePropsType>) {
|
||||
super();
|
||||
|
||||
this.composeContacts = composeContacts;
|
||||
this.searchTerm = searchTerm;
|
||||
this.phoneNumber = parsePhoneNumber(searchTerm, regionCode);
|
||||
this.composeGroups = composeGroups;
|
||||
this.composeContacts = composeContacts;
|
||||
}
|
||||
|
||||
getHeaderContents({
|
||||
|
@ -103,7 +109,7 @@ export class LeftPaneComposeHelper extends LeftPaneHelper<
|
|||
|
||||
{this.getRowCount() ? null : (
|
||||
<div className="module-left-pane__compose-no-contacts">
|
||||
{i18n('noContactsFound')}
|
||||
{i18n('noConversationsFound')}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
@ -111,62 +117,89 @@ export class LeftPaneComposeHelper extends LeftPaneHelper<
|
|||
}
|
||||
|
||||
getRowCount(): number {
|
||||
let result = this.composeContacts.length;
|
||||
let result = this.composeContacts.length + this.composeGroups.length;
|
||||
if (this.hasTopButton()) {
|
||||
result += 1;
|
||||
}
|
||||
if (this.hasContactsHeader()) {
|
||||
result += 1;
|
||||
}
|
||||
if (this.hasGroupsHeader()) {
|
||||
result += 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
getRow(rowIndex: number): undefined | Row {
|
||||
if (rowIndex === 0) {
|
||||
const topButton = this.getTopButton();
|
||||
switch (topButton) {
|
||||
case TopButton.None:
|
||||
break;
|
||||
case TopButton.StartNewConversation:
|
||||
assert(
|
||||
this.phoneNumber,
|
||||
'LeftPaneComposeHelper: we should have a phone number if the top button is "Start new conversation"'
|
||||
);
|
||||
return {
|
||||
type: RowType.StartNewConversation,
|
||||
phoneNumber: phoneNumberInstance.format(
|
||||
getRow(actualRowIndex: number): undefined | Row {
|
||||
let virtualRowIndex = actualRowIndex;
|
||||
if (this.hasTopButton()) {
|
||||
if (virtualRowIndex === 0) {
|
||||
const topButton = this.getTopButton();
|
||||
switch (topButton) {
|
||||
case TopButton.None:
|
||||
break;
|
||||
case TopButton.StartNewConversation:
|
||||
assert(
|
||||
this.phoneNumber,
|
||||
PhoneNumberFormat.E164
|
||||
),
|
||||
};
|
||||
case TopButton.CreateNewGroup:
|
||||
return { type: RowType.CreateNewGroup };
|
||||
default:
|
||||
throw missingCaseError(topButton);
|
||||
'LeftPaneComposeHelper: we should have a phone number if the top button is "Start new conversation"'
|
||||
);
|
||||
return {
|
||||
type: RowType.StartNewConversation,
|
||||
phoneNumber: phoneNumberInstance.format(
|
||||
this.phoneNumber,
|
||||
PhoneNumberFormat.E164
|
||||
),
|
||||
};
|
||||
case TopButton.CreateNewGroup:
|
||||
return { type: RowType.CreateNewGroup };
|
||||
default:
|
||||
throw missingCaseError(topButton);
|
||||
}
|
||||
}
|
||||
|
||||
virtualRowIndex -= 1;
|
||||
}
|
||||
|
||||
if (rowIndex === 1 && this.hasContactsHeader()) {
|
||||
if (this.hasContactsHeader()) {
|
||||
if (virtualRowIndex === 0) {
|
||||
return {
|
||||
type: RowType.Header,
|
||||
i18nKey: 'contactsHeader',
|
||||
};
|
||||
}
|
||||
|
||||
virtualRowIndex -= 1;
|
||||
|
||||
const contact = this.composeContacts[virtualRowIndex];
|
||||
if (contact) {
|
||||
return {
|
||||
type: RowType.Contact,
|
||||
contact,
|
||||
};
|
||||
}
|
||||
|
||||
virtualRowIndex -= this.composeContacts.length;
|
||||
}
|
||||
|
||||
if (this.hasGroupsHeader()) {
|
||||
if (virtualRowIndex === 0) {
|
||||
return {
|
||||
type: RowType.Header,
|
||||
i18nKey: 'groupsHeader',
|
||||
};
|
||||
}
|
||||
|
||||
virtualRowIndex -= 1;
|
||||
|
||||
const group = this.composeGroups[virtualRowIndex];
|
||||
return {
|
||||
type: RowType.Header,
|
||||
i18nKey: 'contactsHeader',
|
||||
type: RowType.Conversation,
|
||||
conversation: group,
|
||||
};
|
||||
}
|
||||
|
||||
let contactIndex: number;
|
||||
if (this.hasTopButton()) {
|
||||
contactIndex = rowIndex - 2;
|
||||
} else {
|
||||
contactIndex = rowIndex;
|
||||
}
|
||||
|
||||
const contact = this.composeContacts[contactIndex];
|
||||
return contact
|
||||
? {
|
||||
type: RowType.Contact,
|
||||
contact,
|
||||
}
|
||||
: undefined;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// This is deliberately unimplemented because these keyboard shortcuts shouldn't work in
|
||||
|
@ -183,10 +216,17 @@ export class LeftPaneComposeHelper extends LeftPaneHelper<
|
|||
return undefined;
|
||||
}
|
||||
|
||||
shouldRecomputeRowHeights(old: Readonly<LeftPaneComposePropsType>): boolean {
|
||||
shouldRecomputeRowHeights(
|
||||
exProps: Readonly<LeftPaneComposePropsType>
|
||||
): boolean {
|
||||
const prev = new LeftPaneComposeHelper(exProps);
|
||||
const currHeaderIndices = this.getHeaderIndices();
|
||||
const prevHeaderIndices = prev.getHeaderIndices();
|
||||
|
||||
return (
|
||||
this.hasContactsHeader() !==
|
||||
new LeftPaneComposeHelper(old).hasContactsHeader()
|
||||
currHeaderIndices.top !== prevHeaderIndices.top ||
|
||||
currHeaderIndices.contact !== prevHeaderIndices.contact ||
|
||||
currHeaderIndices.group !== prevHeaderIndices.group
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -205,7 +245,39 @@ export class LeftPaneComposeHelper extends LeftPaneHelper<
|
|||
}
|
||||
|
||||
private hasContactsHeader(): boolean {
|
||||
return this.hasTopButton() && Boolean(this.composeContacts.length);
|
||||
return Boolean(this.composeContacts.length);
|
||||
}
|
||||
|
||||
private hasGroupsHeader(): boolean {
|
||||
return Boolean(this.composeGroups.length);
|
||||
}
|
||||
|
||||
private getHeaderIndices(): {
|
||||
top?: number;
|
||||
contact?: number;
|
||||
group?: number;
|
||||
} {
|
||||
let top: number | undefined;
|
||||
let contact: number | undefined;
|
||||
let group: number | undefined;
|
||||
let rowCount = 0;
|
||||
if (this.hasTopButton()) {
|
||||
top = 0;
|
||||
rowCount += 1;
|
||||
}
|
||||
if (this.composeContacts.length) {
|
||||
contact = rowCount;
|
||||
rowCount += this.composeContacts.length;
|
||||
}
|
||||
if (this.composeGroups.length) {
|
||||
group = rowCount;
|
||||
}
|
||||
|
||||
return {
|
||||
top,
|
||||
contact,
|
||||
group,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,14 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { last } from 'lodash';
|
||||
import React, { ReactChild } from 'react';
|
||||
|
||||
import { Intl } from '../Intl';
|
||||
import { LeftPaneHelper, ToFindType } from './LeftPaneHelper';
|
||||
import { getConversationInDirection } from './getConversationInDirection';
|
||||
import { Row, RowType } from '../ConversationList';
|
||||
import { PropsData as ConversationListItemPropsType } from '../conversationList/ConversationListItem';
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
|
||||
export type LeftPaneInboxPropsType = {
|
||||
conversations: ReadonlyArray<ConversationListItemPropsType>;
|
||||
|
@ -56,6 +59,33 @@ export class LeftPaneInboxHelper extends LeftPaneHelper<
|
|||
);
|
||||
}
|
||||
|
||||
getPreRowsNode({
|
||||
i18n,
|
||||
}: Readonly<{ i18n: LocalizerType }>): null | ReactChild {
|
||||
if (this.getRowCount() === 0) {
|
||||
return (
|
||||
<div className="module-left-pane__empty">
|
||||
<div>
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="emptyInboxMessage"
|
||||
components={[
|
||||
<span>
|
||||
<strong>{i18n('composeIcon')}</strong>
|
||||
<span className="module-left-pane__empty--composer_icon">
|
||||
<i className="module-left-pane__empty--composer_icon--icon" />
|
||||
</span>
|
||||
</span>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getRow(rowIndex: number): undefined | Row {
|
||||
const { conversations, archivedConversations, pinnedConversations } = this;
|
||||
|
74
ts/groups.ts
74
ts/groups.ts
|
@ -2598,7 +2598,8 @@ type MaybeUpdatePropsType = {
|
|||
};
|
||||
|
||||
export async function waitThenMaybeUpdateGroup(
|
||||
options: MaybeUpdatePropsType
|
||||
options: MaybeUpdatePropsType,
|
||||
{ viaSync = false } = {}
|
||||
): Promise<void> {
|
||||
// First wait to process all incoming messages on the websocket
|
||||
await window.waitForEmptyEventQueue();
|
||||
|
@ -2609,7 +2610,7 @@ export async function waitThenMaybeUpdateGroup(
|
|||
await conversation.queueJob(async () => {
|
||||
try {
|
||||
// And finally try to update the group
|
||||
await maybeUpdateGroup(options);
|
||||
await maybeUpdateGroup(options, { viaSync });
|
||||
} catch (error) {
|
||||
window.log.error(
|
||||
`waitThenMaybeUpdateGroup/${conversation.idForLogging()}: maybeUpdateGroup failure:`,
|
||||
|
@ -2619,14 +2620,17 @@ export async function waitThenMaybeUpdateGroup(
|
|||
});
|
||||
}
|
||||
|
||||
export async function maybeUpdateGroup({
|
||||
conversation,
|
||||
dropInitialJoinMessage,
|
||||
groupChangeBase64,
|
||||
newRevision,
|
||||
receivedAt,
|
||||
sentAt,
|
||||
}: MaybeUpdatePropsType): Promise<void> {
|
||||
export async function maybeUpdateGroup(
|
||||
{
|
||||
conversation,
|
||||
dropInitialJoinMessage,
|
||||
groupChangeBase64,
|
||||
newRevision,
|
||||
receivedAt,
|
||||
sentAt,
|
||||
}: MaybeUpdatePropsType,
|
||||
{ viaSync = false } = {}
|
||||
): Promise<void> {
|
||||
const logId = conversation.idForLogging();
|
||||
|
||||
try {
|
||||
|
@ -2641,7 +2645,10 @@ export async function maybeUpdateGroup({
|
|||
dropInitialJoinMessage,
|
||||
});
|
||||
|
||||
await updateGroup({ conversation, receivedAt, sentAt, updates });
|
||||
await updateGroup(
|
||||
{ conversation, receivedAt, sentAt, updates },
|
||||
{ viaSync }
|
||||
);
|
||||
} catch (error) {
|
||||
window.log.error(
|
||||
`maybeUpdateGroup/${logId}: Failed to update group:`,
|
||||
|
@ -2651,17 +2658,20 @@ export async function maybeUpdateGroup({
|
|||
}
|
||||
}
|
||||
|
||||
async function updateGroup({
|
||||
conversation,
|
||||
receivedAt,
|
||||
sentAt,
|
||||
updates,
|
||||
}: {
|
||||
conversation: ConversationModel;
|
||||
receivedAt?: number;
|
||||
sentAt?: number;
|
||||
updates: UpdatesResultType;
|
||||
}): Promise<void> {
|
||||
async function updateGroup(
|
||||
{
|
||||
conversation,
|
||||
receivedAt,
|
||||
sentAt,
|
||||
updates,
|
||||
}: {
|
||||
conversation: ConversationModel;
|
||||
receivedAt?: number;
|
||||
sentAt?: number;
|
||||
updates: UpdatesResultType;
|
||||
},
|
||||
{ viaSync = false } = {}
|
||||
): Promise<void> {
|
||||
const { newAttributes, groupChangeMessages, members } = updates;
|
||||
|
||||
const startingRevision = conversation.get('revision');
|
||||
|
@ -2684,15 +2694,21 @@ async function updateGroup({
|
|||
const previousId = conversation.get('groupId');
|
||||
const idChanged = previousId && previousId !== newAttributes.groupId;
|
||||
|
||||
// We force this conversation into the left pane if this is the first time we've
|
||||
// fetched data about it, and we were able to fetch its name. Nobody likes to see
|
||||
// Unknown Group in the left pane.
|
||||
let activeAt = null;
|
||||
if (viaSync) {
|
||||
activeAt = null;
|
||||
} else if ((isInitialDataFetch || justJoinedGroup) && newAttributes.name) {
|
||||
activeAt = initialSentAt;
|
||||
} else {
|
||||
activeAt = newAttributes.active_at;
|
||||
}
|
||||
|
||||
conversation.set({
|
||||
...newAttributes,
|
||||
// We force this conversation into the left pane if this is the first time we've
|
||||
// fetched data about it, and we were able to fetch its name. Nobody likes to see
|
||||
// Unknown Group in the left pane.
|
||||
active_at:
|
||||
(isInitialDataFetch || justJoinedGroup) && newAttributes.name
|
||||
? initialSentAt
|
||||
: newAttributes.active_at,
|
||||
active_at: activeAt,
|
||||
temporaryMemberCount: isInGroup
|
||||
? undefined
|
||||
: newAttributes.temporaryMemberCount,
|
||||
|
|
|
@ -1035,6 +1035,7 @@ async function sync(): Promise<ManifestRecordClass | undefined> {
|
|||
);
|
||||
}
|
||||
|
||||
window.Signal.Util.postLinkExperience.stop();
|
||||
window.log.info('storageService.sync: complete');
|
||||
return manifest;
|
||||
}
|
||||
|
|
|
@ -685,10 +685,13 @@ export async function mergeGroupV2Record(
|
|||
|
||||
// We don't await this because this could take a very long time, waiting for queues to
|
||||
// empty, etc.
|
||||
waitThenMaybeUpdateGroup({
|
||||
conversation,
|
||||
dropInitialJoinMessage,
|
||||
});
|
||||
waitThenMaybeUpdateGroup(
|
||||
{
|
||||
conversation,
|
||||
dropInitialJoinMessage,
|
||||
},
|
||||
{ viaSync: true }
|
||||
);
|
||||
}
|
||||
|
||||
return hasPendingChanges;
|
||||
|
|
|
@ -259,11 +259,11 @@ type ComposerGroupCreationState = {
|
|||
type ComposerStateType =
|
||||
| {
|
||||
step: ComposerStep.StartDirectConversation;
|
||||
contactSearchTerm: string;
|
||||
searchTerm: string;
|
||||
}
|
||||
| ({
|
||||
step: ComposerStep.ChooseGroupMembers;
|
||||
contactSearchTerm: string;
|
||||
searchTerm: string;
|
||||
cantAddContactIdForModal: undefined | string;
|
||||
} & ComposerGroupCreationState)
|
||||
| ({
|
||||
|
@ -529,7 +529,7 @@ type SetComposeGroupNameActionType = {
|
|||
};
|
||||
type SetComposeSearchTermActionType = {
|
||||
type: 'SET_COMPOSE_SEARCH_TERM';
|
||||
payload: { contactSearchTerm: string };
|
||||
payload: { searchTerm: string };
|
||||
};
|
||||
type SetRecentMediaItemsActionType = {
|
||||
type: 'SET_RECENT_MEDIA_ITEMS';
|
||||
|
@ -1012,11 +1012,11 @@ function setComposeGroupName(groupName: string): SetComposeGroupNameActionType {
|
|||
}
|
||||
|
||||
function setComposeSearchTerm(
|
||||
contactSearchTerm: string
|
||||
searchTerm: string
|
||||
): SetComposeSearchTermActionType {
|
||||
return {
|
||||
type: 'SET_COMPOSE_SEARCH_TERM',
|
||||
payload: { contactSearchTerm },
|
||||
payload: { searchTerm },
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2117,7 +2117,7 @@ export function reducer(
|
|||
showArchived: false,
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -2154,7 +2154,7 @@ export function reducer(
|
|||
showArchived: false,
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds,
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState,
|
||||
|
@ -2253,7 +2253,7 @@ export function reducer(
|
|||
...state,
|
||||
composer: {
|
||||
...composer,
|
||||
contactSearchTerm: action.payload.contactSearchTerm,
|
||||
searchTerm: action.payload.searchTerm,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import { PropsDataType as TimelinePropsType } from '../../components/conversatio
|
|||
import { TimelineItemType } from '../../components/conversation/TimelineItem';
|
||||
import { assert } from '../../util/assert';
|
||||
import { isConversationUnregistered } from '../../util/isConversationUnregistered';
|
||||
import { filterAndSortContacts } from '../../util/filterAndSortContacts';
|
||||
import { filterAndSortConversations } from '../../util/filterAndSortConversations';
|
||||
|
||||
import {
|
||||
getInteractionMode,
|
||||
|
@ -323,24 +323,33 @@ export const getMe = createSelector(
|
|||
}
|
||||
);
|
||||
|
||||
export const getComposerContactSearchTerm = createSelector(
|
||||
export const getComposerConversationSearchTerm = createSelector(
|
||||
getComposerState,
|
||||
(composer): string => {
|
||||
if (!composer) {
|
||||
assert(false, 'getComposerContactSearchTerm: composer is not open');
|
||||
assert(false, 'getComposerConversationSearchTerm: composer is not open');
|
||||
return '';
|
||||
}
|
||||
if (composer.step === ComposerStep.SetGroupMetadata) {
|
||||
assert(
|
||||
false,
|
||||
'getComposerContactSearchTerm: composer does not have a search term'
|
||||
'getComposerConversationSearchTerm: composer does not have a search term'
|
||||
);
|
||||
return '';
|
||||
}
|
||||
return composer.contactSearchTerm;
|
||||
return composer.searchTerm;
|
||||
}
|
||||
);
|
||||
|
||||
function canComposeConversation(conversation: ConversationType): boolean {
|
||||
return Boolean(
|
||||
!conversation.isMe &&
|
||||
!conversation.isBlocked &&
|
||||
!isConversationUnregistered(conversation) &&
|
||||
(isString(conversation.name) || conversation.profileSharing)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns contacts for the composer and group members, which isn't just your primary
|
||||
* system contacts. It may include false positives, which is better than missing contacts.
|
||||
|
@ -349,21 +358,26 @@ export const getComposerContactSearchTerm = createSelector(
|
|||
* current time, it's possible for this to return stale contacts that have unregistered
|
||||
* if no other conversations change. This should be a rare false positive.
|
||||
*/
|
||||
export const getContacts = createSelector(
|
||||
export const getComposableContacts = createSelector(
|
||||
getConversationLookup,
|
||||
(conversationLookup: ConversationLookupType): Array<ConversationType> =>
|
||||
Object.values(conversationLookup).filter(
|
||||
contact =>
|
||||
contact.type === 'direct' &&
|
||||
!contact.isMe &&
|
||||
!contact.isBlocked &&
|
||||
!isConversationUnregistered(contact) &&
|
||||
(isString(contact.name) || contact.profileSharing)
|
||||
conversation =>
|
||||
conversation.type === 'direct' && canComposeConversation(conversation)
|
||||
)
|
||||
);
|
||||
|
||||
const getNormalizedComposerContactSearchTerm = createSelector(
|
||||
getComposerContactSearchTerm,
|
||||
export const getComposableGroups = createSelector(
|
||||
getConversationLookup,
|
||||
(conversationLookup: ConversationLookupType): Array<ConversationType> =>
|
||||
Object.values(conversationLookup).filter(
|
||||
conversation =>
|
||||
conversation.type === 'group' && canComposeConversation(conversation)
|
||||
)
|
||||
);
|
||||
|
||||
const getNormalizedComposerConversationSearchTerm = createSelector(
|
||||
getComposerConversationSearchTerm,
|
||||
(searchTerm: string): string => searchTerm.trim()
|
||||
);
|
||||
|
||||
|
@ -372,8 +386,8 @@ const getNoteToSelfTitle = createSelector(getIntl, (i18n: LocalizerType) =>
|
|||
);
|
||||
|
||||
export const getComposeContacts = createSelector(
|
||||
getNormalizedComposerContactSearchTerm,
|
||||
getContacts,
|
||||
getNormalizedComposerConversationSearchTerm,
|
||||
getComposableContacts,
|
||||
getMe,
|
||||
getNoteToSelfTitle,
|
||||
(
|
||||
|
@ -382,7 +396,7 @@ export const getComposeContacts = createSelector(
|
|||
noteToSelf: ConversationType,
|
||||
noteToSelfTitle: string
|
||||
): Array<ConversationType> => {
|
||||
const result: Array<ConversationType> = filterAndSortContacts(
|
||||
const result: Array<ConversationType> = filterAndSortConversations(
|
||||
contacts,
|
||||
searchTerm
|
||||
);
|
||||
|
@ -393,10 +407,21 @@ export const getComposeContacts = createSelector(
|
|||
}
|
||||
);
|
||||
|
||||
export const getComposeGroups = createSelector(
|
||||
getNormalizedComposerConversationSearchTerm,
|
||||
getComposableGroups,
|
||||
(
|
||||
searchTerm: string,
|
||||
groups: Array<ConversationType>
|
||||
): Array<ConversationType> => {
|
||||
return filterAndSortConversations(groups, searchTerm);
|
||||
}
|
||||
);
|
||||
|
||||
export const getCandidateContactsForNewGroup = createSelector(
|
||||
getContacts,
|
||||
getNormalizedComposerContactSearchTerm,
|
||||
filterAndSortContacts
|
||||
getComposableContacts,
|
||||
getNormalizedComposerConversationSearchTerm,
|
||||
filterAndSortConversations
|
||||
);
|
||||
|
||||
export const getCantAddContactForModal = createSelector(
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
StateProps,
|
||||
} from '../../components/conversation/conversation-details/ConversationDetails';
|
||||
import {
|
||||
getContacts,
|
||||
getComposableContacts,
|
||||
getConversationSelector,
|
||||
} from '../selectors/conversations';
|
||||
import { getIntl } from '../selectors/user';
|
||||
|
@ -50,7 +50,7 @@ const mapStateToProps = (
|
|||
? conversation.canEditGroupInfo
|
||||
: false;
|
||||
const isAdmin = Boolean(conversation?.areWeAdmin);
|
||||
const candidateContactsToAdd = getContacts(state);
|
||||
const candidateContactsToAdd = getComposableContacts(state);
|
||||
|
||||
return {
|
||||
...props,
|
||||
|
|
|
@ -19,10 +19,11 @@ import {
|
|||
getCandidateContactsForNewGroup,
|
||||
getCantAddContactForModal,
|
||||
getComposeContacts,
|
||||
getComposeGroups,
|
||||
getComposeGroupAvatar,
|
||||
getComposeGroupName,
|
||||
getComposeSelectedContacts,
|
||||
getComposerContactSearchTerm,
|
||||
getComposerConversationSearchTerm,
|
||||
getComposerStep,
|
||||
getLeftPaneLists,
|
||||
getMaximumGroupSizeModalState,
|
||||
|
@ -96,8 +97,9 @@ const getModeSpecificProps = (
|
|||
return {
|
||||
mode: LeftPaneMode.Compose,
|
||||
composeContacts: getComposeContacts(state),
|
||||
composeGroups: getComposeGroups(state),
|
||||
regionCode: getRegionCode(state),
|
||||
searchTerm: getComposerContactSearchTerm(state),
|
||||
searchTerm: getComposerConversationSearchTerm(state),
|
||||
};
|
||||
case ComposerStep.ChooseGroupMembers:
|
||||
return {
|
||||
|
@ -109,7 +111,7 @@ const getModeSpecificProps = (
|
|||
OneTimeModalState.Showing,
|
||||
isShowingMaximumGroupSizeModal:
|
||||
getMaximumGroupSizeModalState(state) === OneTimeModalState.Showing,
|
||||
searchTerm: getComposerContactSearchTerm(state),
|
||||
searchTerm: getComposerConversationSearchTerm(state),
|
||||
selectedContacts: getComposeSelectedContacts(state),
|
||||
};
|
||||
case ComposerStep.SetGroupMetadata:
|
||||
|
|
|
@ -16,10 +16,11 @@ import {
|
|||
getCandidateContactsForNewGroup,
|
||||
getCantAddContactForModal,
|
||||
getComposeContacts,
|
||||
getComposeGroups,
|
||||
getComposeGroupAvatar,
|
||||
getComposeGroupName,
|
||||
getComposeSelectedContacts,
|
||||
getComposerContactSearchTerm,
|
||||
getComposerConversationSearchTerm,
|
||||
getComposerStep,
|
||||
getConversationSelector,
|
||||
getInvitedContactsForNewlyCreatedGroup,
|
||||
|
@ -271,7 +272,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation as const,
|
||||
contactSearchTerm: 'foo',
|
||||
searchTerm: 'foo',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -287,7 +288,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: 'foo',
|
||||
searchTerm: 'foo',
|
||||
selectedConversationIds: ['abc'],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -337,7 +338,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -398,7 +399,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -449,7 +450,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
});
|
||||
|
||||
describe('#getComposeContacts', () => {
|
||||
const getRootState = (contactSearchTerm = ''): StateType => {
|
||||
const getRootState = (searchTerm = ''): StateType => {
|
||||
const rootState = getEmptyRootState();
|
||||
return {
|
||||
...rootState,
|
||||
|
@ -463,7 +464,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
},
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
contactSearchTerm,
|
||||
searchTerm,
|
||||
},
|
||||
},
|
||||
user: {
|
||||
|
@ -474,10 +475,8 @@ describe('both/state/selectors/conversations', () => {
|
|||
};
|
||||
};
|
||||
|
||||
const getRootStateWithConverastions = (
|
||||
contactSearchTerm = ''
|
||||
): StateType => {
|
||||
const result = getRootState(contactSearchTerm);
|
||||
const getRootStateWithConversations = (searchTerm = ''): StateType => {
|
||||
const result = getRootState(searchTerm);
|
||||
Object.assign(result.conversations.conversationLookup, {
|
||||
'convo-1': {
|
||||
...getDefaultConversation('convo-1'),
|
||||
|
@ -534,7 +533,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
});
|
||||
|
||||
it('returns contacts with Note to Self at the end when there is no search term', () => {
|
||||
const state = getRootStateWithConverastions();
|
||||
const state = getRootStateWithConversations();
|
||||
const result = getComposeContacts(state);
|
||||
|
||||
const ids = result.map(contact => contact.id);
|
||||
|
@ -547,7 +546,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
});
|
||||
|
||||
it('can search for contacts', () => {
|
||||
const state = getRootStateWithConverastions('in system');
|
||||
const state = getRootStateWithConversations('in system');
|
||||
const result = getComposeContacts(state);
|
||||
|
||||
const ids = result.map(contact => contact.id);
|
||||
|
@ -556,8 +555,90 @@ describe('both/state/selectors/conversations', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('#getComposeGroups', () => {
|
||||
const getState = (searchTerm = ''): StateType => {
|
||||
const rootState = getEmptyRootState();
|
||||
return {
|
||||
...rootState,
|
||||
conversations: {
|
||||
...getEmptyState(),
|
||||
conversationLookup: {
|
||||
'our-conversation-id': {
|
||||
...getDefaultConversation('our-conversation-id'),
|
||||
isMe: true,
|
||||
},
|
||||
'convo-1': {
|
||||
...getDefaultConversation('convo-1'),
|
||||
name: 'In System Contacts',
|
||||
title: 'Should be dropped (contact)',
|
||||
},
|
||||
'convo-2': {
|
||||
...getDefaultConversation('convo-2'),
|
||||
title: 'Should be dropped (contact)',
|
||||
},
|
||||
'convo-3': {
|
||||
...getDefaultConversation('convo-3'),
|
||||
type: 'group',
|
||||
name: 'Hello World',
|
||||
title: 'Hello World',
|
||||
},
|
||||
'convo-4': {
|
||||
...getDefaultConversation('convo-4'),
|
||||
type: 'group',
|
||||
isBlocked: true,
|
||||
title: 'Should be dropped (blocked)',
|
||||
},
|
||||
'convo-5': {
|
||||
...getDefaultConversation('convo-5'),
|
||||
type: 'group',
|
||||
title: 'Unknown Group',
|
||||
},
|
||||
'convo-6': {
|
||||
...getDefaultConversation('convo-6'),
|
||||
type: 'group',
|
||||
name: 'Signal',
|
||||
title: 'Signal',
|
||||
},
|
||||
'convo-7': {
|
||||
...getDefaultConversation('convo-7'),
|
||||
profileSharing: false,
|
||||
type: 'group',
|
||||
name: 'Signal Fake',
|
||||
title: 'Signal Fake',
|
||||
},
|
||||
},
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
searchTerm,
|
||||
},
|
||||
},
|
||||
user: {
|
||||
...rootState.user,
|
||||
ourConversationId: 'our-conversation-id',
|
||||
i18n,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
it('can search for groups', () => {
|
||||
const state = getState('hello');
|
||||
const result = getComposeGroups(state);
|
||||
|
||||
const ids = result.map(group => group.id);
|
||||
assert.deepEqual(ids, ['convo-3']);
|
||||
});
|
||||
|
||||
it('does not return unknown groups when getting all groups (no search term)', () => {
|
||||
const state = getState();
|
||||
const result = getComposeGroups(state);
|
||||
|
||||
const ids = result.map(group => group.id);
|
||||
assert.deepEqual(ids, ['convo-3', 'convo-6', 'convo-7']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getCandidateContactsForNewGroup', () => {
|
||||
const getRootState = (contactSearchTerm = ''): StateType => {
|
||||
const getRootState = (searchTerm = ''): StateType => {
|
||||
const rootState = getEmptyRootState();
|
||||
return {
|
||||
...rootState,
|
||||
|
@ -603,7 +684,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
},
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers,
|
||||
contactSearchTerm,
|
||||
searchTerm,
|
||||
selectedConversationIds: ['abc'],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -648,7 +729,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -663,7 +744,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
cantAddContactIdForModal: undefined,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -687,7 +768,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
conversationLookup: { abc123: conversation },
|
||||
composer: {
|
||||
cantAddContactIdForModal: 'abc123',
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -702,16 +783,16 @@ describe('both/state/selectors/conversations', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('#getComposerContactSearchTerm', () => {
|
||||
describe('#getComposerConversationSearchTerm', () => {
|
||||
it("returns the composer's contact search term", () => {
|
||||
assert.strictEqual(
|
||||
getComposerContactSearchTerm({
|
||||
getComposerConversationSearchTerm({
|
||||
...getEmptyRootState(),
|
||||
conversations: {
|
||||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
contactSearchTerm: 'foo bar',
|
||||
searchTerm: 'foo bar',
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
@ -966,7 +1047,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
cantAddContactIdForModal: undefined,
|
||||
contactSearchTerm: 'to be cleared',
|
||||
searchTerm: 'to be cleared',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.Showing,
|
||||
|
@ -991,7 +1072,7 @@ describe('both/state/selectors/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
cantAddContactIdForModal: undefined,
|
||||
contactSearchTerm: 'to be cleared',
|
||||
searchTerm: 'to be cleared',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
import { assert } from 'chai';
|
||||
import { getDefaultConversation } from '../helpers/getDefaultConversation';
|
||||
|
||||
import { filterAndSortContacts } from '../../util/filterAndSortContacts';
|
||||
import { filterAndSortConversations } from '../../util/filterAndSortConversations';
|
||||
|
||||
describe('filterAndSortContacts', () => {
|
||||
describe('filterAndSortConversations', () => {
|
||||
const conversations = [
|
||||
getDefaultConversation({
|
||||
title: '+16505551234',
|
||||
|
@ -34,7 +34,7 @@ describe('filterAndSortContacts', () => {
|
|||
];
|
||||
|
||||
it('without a search term, sorts conversations by title (but puts no-name contacts at the bottom)', () => {
|
||||
const titles = filterAndSortContacts(conversations, '').map(
|
||||
const titles = filterAndSortConversations(conversations, '').map(
|
||||
contact => contact.title
|
||||
);
|
||||
assert.deepEqual(titles, [
|
||||
|
@ -47,14 +47,14 @@ describe('filterAndSortContacts', () => {
|
|||
});
|
||||
|
||||
it('can search for contacts by title', () => {
|
||||
const titles = filterAndSortContacts(conversations, 'belind').map(
|
||||
const titles = filterAndSortConversations(conversations, 'belind').map(
|
||||
contact => contact.title
|
||||
);
|
||||
assert.sameMembers(titles, ['Belinda Beetle', 'Belinda Zephyr']);
|
||||
});
|
||||
|
||||
it('can search for contacts by phone number (and puts no-name contacts at the bottom)', () => {
|
||||
const titles = filterAndSortContacts(conversations, '650555').map(
|
||||
const titles = filterAndSortConversations(conversations, '650555').map(
|
||||
contact => contact.title
|
||||
);
|
||||
assert.sameMembers(titles, ['Carlos Santana', '+16505551234']);
|
|
@ -467,7 +467,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
cantAddContactIdForModal: undefined,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -530,7 +530,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
cantAddContactIdForModal: 'abc123',
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -556,7 +556,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
cantAddContactIdForModal: 'abc123',
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.Showing,
|
||||
|
@ -581,7 +581,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
cantAddContactIdForModal: 'abc123',
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -601,7 +601,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
cantAddContactIdForModal: 'abc123',
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.Shown,
|
||||
|
@ -623,7 +623,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
cantAddContactIdForModal: 'abc123',
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -648,7 +648,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
cantAddContactIdForModal: 'abc123',
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -668,7 +668,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
cantAddContactIdForModal: 'abc123',
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1232,7 +1232,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
},
|
||||
};
|
||||
const action = setComposeSearchTerm('foo bar');
|
||||
|
@ -1240,7 +1240,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
contactSearchTerm: 'foo bar',
|
||||
searchTerm: 'foo bar',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1306,7 +1306,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
},
|
||||
};
|
||||
const action = showArchivedConversations();
|
||||
|
@ -1344,7 +1344,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
},
|
||||
};
|
||||
const action = showInbox();
|
||||
|
@ -1361,7 +1361,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation as const,
|
||||
contactSearchTerm: 'foo bar',
|
||||
searchTerm: 'foo bar',
|
||||
},
|
||||
};
|
||||
const action = startComposing();
|
||||
|
@ -1370,7 +1370,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
assert.isFalse(result.showArchived);
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
contactSearchTerm: 'foo bar',
|
||||
searchTerm: 'foo bar',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1379,7 +1379,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
cantAddContactIdForModal: undefined,
|
||||
contactSearchTerm: 'to be cleared',
|
||||
searchTerm: 'to be cleared',
|
||||
groupAvatar: undefined,
|
||||
groupName: '',
|
||||
maximumGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1394,7 +1394,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
assert.isFalse(result.showArchived);
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1418,7 +1418,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
assert.isFalse(result.showArchived);
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1430,7 +1430,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
assert.isFalse(result.showArchived);
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1445,7 +1445,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
assert.isFalse(result.showArchived);
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.StartDirectConversation,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1456,7 +1456,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.StartDirectConversation as const,
|
||||
contactSearchTerm: 'to be cleared',
|
||||
searchTerm: 'to be cleared',
|
||||
},
|
||||
};
|
||||
const action = showChooseGroupMembers();
|
||||
|
@ -1465,7 +1465,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
assert.isFalse(result.showArchived);
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.ChooseGroupMembers,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: [],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1480,7 +1480,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: 'foo bar',
|
||||
searchTerm: 'foo bar',
|
||||
selectedConversationIds: [],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1516,7 +1516,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
assert.isFalse(result.showArchived);
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.ChooseGroupMembers,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: [],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1534,7 +1534,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
assert.isFalse(result.showArchived);
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.ChooseGroupMembers,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: [],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1555,7 +1555,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
assert.isFalse(result.showArchived);
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.ChooseGroupMembers,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: [],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1572,7 +1572,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: 'foo bar',
|
||||
searchTerm: 'foo bar',
|
||||
selectedConversationIds: ['abc', 'def'],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1601,7 +1601,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: 'foo bar',
|
||||
searchTerm: 'foo bar',
|
||||
selectedConversationIds: ['abc', 'def'],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1681,7 +1681,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: [],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1695,7 +1695,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
|
||||
assert.deepEqual(two.composer, {
|
||||
step: ComposerStep.ChooseGroupMembers,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: ['abc', 'def'],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1710,7 +1710,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: ['abc', 'def'],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1724,7 +1724,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.ChooseGroupMembers,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: ['def'],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1742,7 +1742,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: oldSelectedConversationIds,
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1756,7 +1756,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.ChooseGroupMembers,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: [...oldSelectedConversationIds, newUuid],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.Showing,
|
||||
|
@ -1774,7 +1774,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: oldSelectedConversationIds,
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.Shown,
|
||||
|
@ -1788,7 +1788,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.ChooseGroupMembers,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: [...oldSelectedConversationIds, newUuid],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.Shown,
|
||||
|
@ -1808,7 +1808,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: [],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1831,7 +1831,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: oldSelectedConversationIds,
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.Shown,
|
||||
|
@ -1845,7 +1845,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.ChooseGroupMembers,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: [...oldSelectedConversationIds, newUuid],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.Shown,
|
||||
|
@ -1863,7 +1863,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: oldSelectedConversationIds,
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.Shown,
|
||||
|
@ -1877,7 +1877,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
|
||||
assert.deepEqual(result.composer, {
|
||||
step: ComposerStep.ChooseGroupMembers,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: [...oldSelectedConversationIds, newUuid],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.Shown,
|
||||
|
@ -1892,7 +1892,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: times(1000, () => uuid()),
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1919,7 +1919,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: [],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
@ -1945,7 +1945,7 @@ describe('both/state/ducks/conversations', () => {
|
|||
...getEmptyState(),
|
||||
composer: {
|
||||
step: ComposerStep.ChooseGroupMembers as const,
|
||||
contactSearchTerm: '',
|
||||
searchTerm: '',
|
||||
selectedConversationIds: [],
|
||||
cantAddContactIdForModal: undefined,
|
||||
recommendedGroupSizeModalState: OneTimeModalState.NeverShown,
|
||||
|
|
|
@ -11,7 +11,7 @@ import * as remoteConfig from '../../../RemoteConfig';
|
|||
import { LeftPaneComposeHelper } from '../../../components/leftPane/LeftPaneComposeHelper';
|
||||
|
||||
describe('LeftPaneComposeHelper', () => {
|
||||
const fakeContact = () => ({
|
||||
const fakeConvo = () => ({
|
||||
id: uuid(),
|
||||
title: uuid(),
|
||||
type: 'direct' as const,
|
||||
|
@ -40,6 +40,7 @@ describe('LeftPaneComposeHelper', () => {
|
|||
const showInbox = sinon.fake();
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts: [],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
});
|
||||
|
@ -53,6 +54,7 @@ describe('LeftPaneComposeHelper', () => {
|
|||
assert.strictEqual(
|
||||
new LeftPaneComposeHelper({
|
||||
composeContacts: [],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
}).getRowCount(),
|
||||
|
@ -63,7 +65,8 @@ describe('LeftPaneComposeHelper', () => {
|
|||
it('returns the number of contacts + 2 (for the "new group" button and header) if not searching', () => {
|
||||
assert.strictEqual(
|
||||
new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
}).getRowCount(),
|
||||
|
@ -71,10 +74,23 @@ describe('LeftPaneComposeHelper', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('returns the number of contacts if searching, but not for a phone number', () => {
|
||||
it('returns the number of contacts + number of groups + 3 (for the "new group" button and the headers) if not searching', () => {
|
||||
assert.strictEqual(
|
||||
new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [fakeConvo(), fakeConvo()],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
}).getRowCount(),
|
||||
7
|
||||
);
|
||||
});
|
||||
|
||||
it('returns the number of conversations + the headers, but not for a phone number', () => {
|
||||
assert.strictEqual(
|
||||
new LeftPaneComposeHelper({
|
||||
composeContacts: [],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
}).getRowCount(),
|
||||
|
@ -82,11 +98,21 @@ describe('LeftPaneComposeHelper', () => {
|
|||
);
|
||||
assert.strictEqual(
|
||||
new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
}).getRowCount(),
|
||||
2
|
||||
3
|
||||
);
|
||||
assert.strictEqual(
|
||||
new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [fakeConvo()],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
}).getRowCount(),
|
||||
5
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -94,6 +120,7 @@ describe('LeftPaneComposeHelper', () => {
|
|||
assert.strictEqual(
|
||||
new LeftPaneComposeHelper({
|
||||
composeContacts: [],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '+16505551234',
|
||||
}).getRowCount(),
|
||||
|
@ -104,7 +131,8 @@ describe('LeftPaneComposeHelper', () => {
|
|||
it('returns the number of contacts + 2 (for the "Start new conversation" button and header) if searching for a phone number', () => {
|
||||
assert.strictEqual(
|
||||
new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '+16505551234',
|
||||
}).getRowCount(),
|
||||
|
@ -117,6 +145,7 @@ describe('LeftPaneComposeHelper', () => {
|
|||
it('returns a "new group" button if not searching and there are no contacts', () => {
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts: [],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
});
|
||||
|
@ -128,9 +157,10 @@ describe('LeftPaneComposeHelper', () => {
|
|||
});
|
||||
|
||||
it('returns a "new group" button, a header, and contacts if not searching', () => {
|
||||
const composeContacts = [fakeContact(), fakeContact()];
|
||||
const composeContacts = [fakeConvo(), fakeConvo()];
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts,
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
});
|
||||
|
@ -152,6 +182,45 @@ describe('LeftPaneComposeHelper', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('returns a "new group" button, a header, contacts, groups header, and groups -- if not searching', () => {
|
||||
const composeContacts = [fakeConvo(), fakeConvo()];
|
||||
const composeGroups = [fakeConvo(), fakeConvo()];
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts,
|
||||
composeGroups,
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
});
|
||||
|
||||
assert.deepEqual(helper.getRow(0), {
|
||||
type: RowType.CreateNewGroup,
|
||||
});
|
||||
assert.deepEqual(helper.getRow(1), {
|
||||
type: RowType.Header,
|
||||
i18nKey: 'contactsHeader',
|
||||
});
|
||||
assert.deepEqual(helper.getRow(2), {
|
||||
type: RowType.Contact,
|
||||
contact: composeContacts[0],
|
||||
});
|
||||
assert.deepEqual(helper.getRow(3), {
|
||||
type: RowType.Contact,
|
||||
contact: composeContacts[1],
|
||||
});
|
||||
assert.deepEqual(helper.getRow(4), {
|
||||
type: RowType.Header,
|
||||
i18nKey: 'groupsHeader',
|
||||
});
|
||||
assert.deepEqual(helper.getRow(5), {
|
||||
type: RowType.Conversation,
|
||||
conversation: composeGroups[0],
|
||||
});
|
||||
assert.deepEqual(helper.getRow(6), {
|
||||
type: RowType.Conversation,
|
||||
conversation: composeGroups[1],
|
||||
});
|
||||
});
|
||||
|
||||
it("doesn't let you create new groups if storage service write is disabled", () => {
|
||||
remoteConfigStub
|
||||
.withArgs('desktop.storage')
|
||||
|
@ -162,6 +231,7 @@ describe('LeftPaneComposeHelper', () => {
|
|||
assert.isUndefined(
|
||||
new LeftPaneComposeHelper({
|
||||
composeContacts: [],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
}).getRow(0)
|
||||
|
@ -176,6 +246,7 @@ describe('LeftPaneComposeHelper', () => {
|
|||
assert.isUndefined(
|
||||
new LeftPaneComposeHelper({
|
||||
composeContacts: [],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
}).getRow(0)
|
||||
|
@ -185,6 +256,7 @@ describe('LeftPaneComposeHelper', () => {
|
|||
it('returns no rows if searching and there are no results', () => {
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts: [],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
});
|
||||
|
@ -194,18 +266,19 @@ describe('LeftPaneComposeHelper', () => {
|
|||
});
|
||||
|
||||
it('returns one row per contact if searching', () => {
|
||||
const composeContacts = [fakeContact(), fakeContact()];
|
||||
const composeContacts = [fakeConvo(), fakeConvo()];
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts,
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
});
|
||||
|
||||
assert.deepEqual(helper.getRow(0), {
|
||||
assert.deepEqual(helper.getRow(1), {
|
||||
type: RowType.Contact,
|
||||
contact: composeContacts[0],
|
||||
});
|
||||
assert.deepEqual(helper.getRow(1), {
|
||||
assert.deepEqual(helper.getRow(2), {
|
||||
type: RowType.Contact,
|
||||
contact: composeContacts[1],
|
||||
});
|
||||
|
@ -214,6 +287,7 @@ describe('LeftPaneComposeHelper', () => {
|
|||
it('returns a "start new conversation" row if searching for a phone number and there are no results', () => {
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts: [],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '+16505551234',
|
||||
});
|
||||
|
@ -226,9 +300,10 @@ describe('LeftPaneComposeHelper', () => {
|
|||
});
|
||||
|
||||
it('returns a "start new conversation" row, a header, and contacts if searching for a phone number', () => {
|
||||
const composeContacts = [fakeContact(), fakeContact()];
|
||||
const composeContacts = [fakeConvo(), fakeConvo()];
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts,
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '+16505551234',
|
||||
});
|
||||
|
@ -255,7 +330,8 @@ describe('LeftPaneComposeHelper', () => {
|
|||
describe('getConversationAndMessageAtIndex', () => {
|
||||
it('returns undefined because keyboard shortcuts are not supported', () => {
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
});
|
||||
|
@ -267,7 +343,8 @@ describe('LeftPaneComposeHelper', () => {
|
|||
describe('getConversationAndMessageInDirection', () => {
|
||||
it('returns undefined because keyboard shortcuts are not supported', () => {
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
});
|
||||
|
@ -285,21 +362,24 @@ describe('LeftPaneComposeHelper', () => {
|
|||
describe('shouldRecomputeRowHeights', () => {
|
||||
it('returns false if going from "no header" to "no header"', () => {
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
});
|
||||
|
||||
assert.isFalse(
|
||||
helper.shouldRecomputeRowHeights({
|
||||
composeContacts: [fakeContact()],
|
||||
composeContacts: [fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
})
|
||||
);
|
||||
assert.isFalse(
|
||||
helper.shouldRecomputeRowHeights({
|
||||
composeContacts: [fakeContact(), fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'bing bong',
|
||||
})
|
||||
|
@ -308,21 +388,24 @@ describe('LeftPaneComposeHelper', () => {
|
|||
|
||||
it('returns false if going from "has header" to "has header"', () => {
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
});
|
||||
|
||||
assert.isFalse(
|
||||
helper.shouldRecomputeRowHeights({
|
||||
composeContacts: [fakeContact()],
|
||||
composeContacts: [fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
})
|
||||
);
|
||||
assert.isFalse(
|
||||
helper.shouldRecomputeRowHeights({
|
||||
composeContacts: [fakeContact()],
|
||||
composeContacts: [fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '+16505559876',
|
||||
})
|
||||
|
@ -331,21 +414,24 @@ describe('LeftPaneComposeHelper', () => {
|
|||
|
||||
it('returns true if going from "no header" to "has header"', () => {
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
});
|
||||
|
||||
assert.isTrue(
|
||||
helper.shouldRecomputeRowHeights({
|
||||
composeContacts: [fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
})
|
||||
);
|
||||
assert.isTrue(
|
||||
helper.shouldRecomputeRowHeights({
|
||||
composeContacts: [fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '+16505551234',
|
||||
})
|
||||
|
@ -354,18 +440,72 @@ describe('LeftPaneComposeHelper', () => {
|
|||
|
||||
it('returns true if going from "has header" to "no header"', () => {
|
||||
const helper = new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: '',
|
||||
});
|
||||
|
||||
assert.isTrue(
|
||||
helper.shouldRecomputeRowHeights({
|
||||
composeContacts: [fakeContact(), fakeContact()],
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should be true if going from contact to group or vice versa', () => {
|
||||
const helperContacts = new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
});
|
||||
|
||||
assert.isTrue(
|
||||
helperContacts.shouldRecomputeRowHeights({
|
||||
composeContacts: [],
|
||||
composeGroups: [fakeConvo(), fakeConvo()],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
})
|
||||
);
|
||||
|
||||
const helperGroups = new LeftPaneComposeHelper({
|
||||
composeContacts: [],
|
||||
composeGroups: [fakeConvo(), fakeConvo()],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
});
|
||||
|
||||
assert.isTrue(
|
||||
helperGroups.shouldRecomputeRowHeights({
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'foo bar',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should be true if the headers are in different row indices as before', () => {
|
||||
const helperContacts = new LeftPaneComposeHelper({
|
||||
composeContacts: [fakeConvo(), fakeConvo()],
|
||||
composeGroups: [fakeConvo()],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'soup',
|
||||
});
|
||||
|
||||
assert.isTrue(
|
||||
helperContacts.shouldRecomputeRowHeights({
|
||||
composeContacts: [fakeConvo()],
|
||||
composeGroups: [fakeConvo(), fakeConvo()],
|
||||
regionCode: 'US',
|
||||
searchTerm: 'sandwich',
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -28,17 +28,17 @@ const FUSE_OPTIONS: FuseOptions<ConversationType> = {
|
|||
|
||||
const collator = new Intl.Collator();
|
||||
|
||||
export function filterAndSortContacts(
|
||||
contacts: ReadonlyArray<ConversationType>,
|
||||
export function filterAndSortConversations(
|
||||
conversations: ReadonlyArray<ConversationType>,
|
||||
searchTerm: string
|
||||
): Array<ConversationType> {
|
||||
if (searchTerm.length) {
|
||||
return new Fuse<ConversationType>(contacts, FUSE_OPTIONS).search(
|
||||
return new Fuse<ConversationType>(conversations, FUSE_OPTIONS).search(
|
||||
searchTerm
|
||||
);
|
||||
}
|
||||
|
||||
return contacts.concat().sort((a, b) => {
|
||||
return conversations.concat().sort((a, b) => {
|
||||
const aHasName = hasName(a);
|
||||
const bHasName = hasName(b);
|
||||
|
|
@ -34,6 +34,7 @@ import {
|
|||
} from './sessionTranslation';
|
||||
import * as zkgroup from './zkgroup';
|
||||
import { StartupQueue } from './StartupQueue';
|
||||
import { postLinkExperience } from './postLinkExperience';
|
||||
|
||||
export {
|
||||
GoogleChrome,
|
||||
|
@ -58,6 +59,7 @@ export {
|
|||
mapToSupportLocale,
|
||||
missingCaseError,
|
||||
parseRemoteClientExpiration,
|
||||
postLinkExperience,
|
||||
queueUpdateMessage,
|
||||
saveNewMessageBatcher,
|
||||
setBatchingStrategy,
|
||||
|
|
|
@ -645,7 +645,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " this.$('.call-manager-placeholder').append(this.callManagerView.el);",
|
||||
"lineNumber": 127,
|
||||
"lineNumber": 128,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
"reasonDetail": "Adding sub-view to DOM"
|
||||
|
@ -654,7 +654,7 @@
|
|||
"rule": "jQuery-append(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " this.$('.call-manager-placeholder').append(this.callManagerView.el);",
|
||||
"lineNumber": 127,
|
||||
"lineNumber": 128,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
"reasonDetail": "Adding sub-view to DOM"
|
||||
|
@ -663,7 +663,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " this.$('.left-pane-placeholder').append(this.leftPaneView.el);",
|
||||
"lineNumber": 138,
|
||||
"lineNumber": 139,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
"reasonDetail": "Adding sub-view to DOM"
|
||||
|
@ -672,7 +672,7 @@
|
|||
"rule": "jQuery-append(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " this.$('.left-pane-placeholder').append(this.leftPaneView.el);",
|
||||
"lineNumber": 138,
|
||||
"lineNumber": 139,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
"reasonDetail": "Adding sub-view to DOM"
|
||||
|
@ -681,7 +681,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " if (e && this.$(e.target).closest('.placeholder').length) {",
|
||||
"lineNumber": 191,
|
||||
"lineNumber": 192,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
"reasonDetail": "Static selector, read-only access"
|
||||
|
@ -690,15 +690,6 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " this.$('#header, .gutter').addClass('inactive');",
|
||||
"lineNumber": 195,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
"reasonDetail": "Static selector, adding or removing classes"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " this.$('.conversation-stack').removeClass('inactive');",
|
||||
"lineNumber": 196,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
|
@ -707,8 +698,8 @@
|
|||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " this.$('.conversation-stack').addClass('inactive');",
|
||||
"lineNumber": 199,
|
||||
"line": " this.$('.conversation-stack').removeClass('inactive');",
|
||||
"lineNumber": 197,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
"reasonDetail": "Static selector, adding or removing classes"
|
||||
|
@ -716,7 +707,7 @@
|
|||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " this.$('#header, .gutter').removeClass('inactive');",
|
||||
"line": " this.$('.conversation-stack').addClass('inactive');",
|
||||
"lineNumber": 200,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
|
@ -725,17 +716,26 @@
|
|||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " this.$('.conversation:first .menu').trigger('close');",
|
||||
"line": " this.$('#header, .gutter').removeClass('inactive');",
|
||||
"lineNumber": 201,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
"reasonDetail": "Static selector, adding or removing classes"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " this.$('.conversation:first .menu').trigger('close');",
|
||||
"lineNumber": 202,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
"reasonDetail": "Static selector, trigging DOM event"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " if (e && this.$(e.target).closest('.capture-audio').length > 0) {",
|
||||
"lineNumber": 223,
|
||||
"lineNumber": 224,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
"reasonDetail": "Static selector, read-only access"
|
||||
|
@ -744,7 +744,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
"line": " this.$('.conversation:first .recorder').trigger('close');",
|
||||
"lineNumber": 226,
|
||||
"lineNumber": 227,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2021-02-26T18:44:56.450Z",
|
||||
"reasonDetail": "Static selector, triggering DOM event"
|
||||
|
@ -771,7 +771,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#qr img').remove();",
|
||||
"lineNumber": 161,
|
||||
"lineNumber": 160,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -780,7 +780,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#qr canvas').remove();",
|
||||
"lineNumber": 162,
|
||||
"lineNumber": 161,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-09-11T17:24:56.124Z",
|
||||
"reasonDetail": "Static selector argument"
|
||||
|
@ -789,7 +789,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#qr .container').show();",
|
||||
"lineNumber": 163,
|
||||
"lineNumber": 162,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -798,7 +798,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#qr').removeClass('ready');",
|
||||
"lineNumber": 164,
|
||||
"lineNumber": 163,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-09-11T17:24:56.124Z",
|
||||
"reasonDetail": "Static selector argument"
|
||||
|
@ -807,7 +807,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " if ($('#qr').length === 0) {",
|
||||
"lineNumber": 167,
|
||||
"lineNumber": 166,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -816,7 +816,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#qr .container').hide();",
|
||||
"lineNumber": 173,
|
||||
"lineNumber": 172,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-03-24T19:03:04.861Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -825,7 +825,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.qr = new QRCode(this.$('#qr')[0]).makeCode(url);",
|
||||
"lineNumber": 174,
|
||||
"lineNumber": 173,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-03-24T19:03:04.861Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -834,7 +834,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#qr').removeAttr('title');",
|
||||
"lineNumber": 175,
|
||||
"lineNumber": 174,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-09-11T17:24:56.124Z",
|
||||
"reasonDetail": "Static selector argument"
|
||||
|
@ -843,7 +843,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#qr').addClass('ready');",
|
||||
"lineNumber": 176,
|
||||
"lineNumber": 175,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-03-24T19:03:04.861Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -852,7 +852,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$(DEVICE_NAME_SELECTOR).val(deviceName || window.getHostName());",
|
||||
"lineNumber": 181,
|
||||
"lineNumber": 180,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-03-24T19:03:04.861Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -861,7 +861,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$(DEVICE_NAME_SELECTOR).focus();",
|
||||
"lineNumber": 182,
|
||||
"lineNumber": 181,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-09-11T17:24:56.124Z",
|
||||
"reasonDetail": "Static selector argument"
|
||||
|
@ -870,7 +870,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#link-phone').submit();",
|
||||
"lineNumber": 186,
|
||||
"lineNumber": 185,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-03-24T19:03:04.861Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -879,7 +879,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#link-phone').submit(e => {",
|
||||
"lineNumber": 228,
|
||||
"lineNumber": 227,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-03-24T19:03:04.861Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -888,7 +888,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " let name = this.$(DEVICE_NAME_SELECTOR).val();",
|
||||
"lineNumber": 232,
|
||||
"lineNumber": 231,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-03-24T19:03:04.861Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -897,7 +897,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$(DEVICE_NAME_SELECTOR).focus();",
|
||||
"lineNumber": 235,
|
||||
"lineNumber": 234,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-03-24T19:03:04.861Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
|
32
ts/util/postLinkExperience.ts
Normal file
32
ts/util/postLinkExperience.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { onTimeout } from '../services/timers';
|
||||
|
||||
class PostLinkExperience {
|
||||
private hasNotFinishedSync: boolean;
|
||||
|
||||
constructor() {
|
||||
this.hasNotFinishedSync = false;
|
||||
}
|
||||
|
||||
start() {
|
||||
this.hasNotFinishedSync = true;
|
||||
|
||||
// timeout "post link" after 10 minutes in case the syncs don't complete
|
||||
// in time or are never called.
|
||||
onTimeout(Date.now() + 60 * 60 * 10 * 1000, () => {
|
||||
this.stop();
|
||||
});
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.hasNotFinishedSync = false;
|
||||
}
|
||||
|
||||
isActive(): boolean {
|
||||
return this.hasNotFinishedSync === true;
|
||||
}
|
||||
}
|
||||
|
||||
export const postLinkExperience = new PostLinkExperience();
|
Loading…
Reference in a new issue