Fix groupV2 change rendering in notifications and left pane

Co-authored-by: Scott Nonnenberg <scott@signal.org>
This commit is contained in:
automated-signal 2021-12-16 10:04:08 -08:00 committed by GitHub
parent b3afc327da
commit a9bbc18fb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 34 additions and 28 deletions

View File

@ -12,6 +12,7 @@ import type { GroupV2ChangeType } from '../../groups';
import { SignalService as Proto } from '../../protobuf'; import { SignalService as Proto } from '../../protobuf';
import type { SmartContactRendererType } from '../../groupChange'; import type { SmartContactRendererType } from '../../groupChange';
import { GroupV2Change } from './GroupV2Change'; import { GroupV2Change } from './GroupV2Change';
import type { FullJSXType } from '../Intl';
const i18n = setupI18n('en', enMessages); const i18n = setupI18n('en', enMessages);
@ -25,7 +26,9 @@ const INVITEE_A = UUID.generate().toString();
const AccessControlEnum = Proto.AccessControl.AccessRequired; const AccessControlEnum = Proto.AccessControl.AccessRequired;
const RoleEnum = Proto.Member.Role; const RoleEnum = Proto.Member.Role;
const renderContact: SmartContactRendererType = (conversationId: string) => ( const renderContact: SmartContactRendererType<FullJSXType> = (
conversationId: string
) => (
<React.Fragment key={conversationId}> <React.Fragment key={conversationId}>
{`Conversation(${conversationId})`} {`Conversation(${conversationId})`}
</React.Fragment> </React.Fragment>

View File

@ -28,7 +28,7 @@ export type PropsDataType = {
export type PropsHousekeepingType = { export type PropsHousekeepingType = {
i18n: LocalizerType; i18n: LocalizerType;
renderContact: SmartContactRendererType; renderContact: SmartContactRendererType<FullJSXType>;
}; };
export type PropsType = PropsDataType & PropsHousekeepingType; export type PropsType = PropsDataType & PropsHousekeepingType;
@ -141,7 +141,7 @@ export function GroupV2Change(props: PropsType): ReactElement {
return ( return (
<> <>
{renderChange(change, { {renderChange<FullJSXType>(change, {
i18n, i18n,
ourUuid, ourUuid,
renderContact, renderContact,

View File

@ -53,6 +53,7 @@ import { ResetSessionNotification } from './ResetSessionNotification';
import type { PropsType as ProfileChangeNotificationPropsType } from './ProfileChangeNotification'; import type { PropsType as ProfileChangeNotificationPropsType } from './ProfileChangeNotification';
import { ProfileChangeNotification } from './ProfileChangeNotification'; import { ProfileChangeNotification } from './ProfileChangeNotification';
import * as log from '../../logging/log'; import * as log from '../../logging/log';
import type { FullJSXType } from '../Intl';
type CallHistoryType = { type CallHistoryType = {
type: 'callHistory'; type: 'callHistory';
@ -144,7 +145,7 @@ type PropsLocalType = {
id: string; id: string;
isSelected: boolean; isSelected: boolean;
selectMessage: (messageId: string, conversationId: string) => unknown; selectMessage: (messageId: string, conversationId: string) => unknown;
renderContact: SmartContactRendererType; renderContact: SmartContactRendererType<FullJSXType>;
renderUniversalTimerNotification: () => JSX.Element; renderUniversalTimerNotification: () => JSX.Element;
i18n: LocalizerType; i18n: LocalizerType;
interactionMode: InteractionModeType; interactionMode: InteractionModeType;

View File

@ -1,7 +1,6 @@
// Copyright 2020 Signal Messenger, LLC // Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import type { FullJSXType } from './components/Intl';
import type { LocalizerType } from './types/Util'; import type { LocalizerType } from './types/Util';
import type { ReplacementValuesType } from './types/I18N'; import type { ReplacementValuesType } from './types/I18N';
import type { UUIDStringType } from './types/UUID'; import type { UUIDStringType } from './types/UUID';
@ -11,42 +10,42 @@ import type { GroupV2ChangeDetailType, GroupV2ChangeType } from './groups';
import { SignalService as Proto } from './protobuf'; import { SignalService as Proto } from './protobuf';
import * as log from './logging/log'; import * as log from './logging/log';
export type SmartContactRendererType = (uuid: UUIDStringType) => FullJSXType; export type SmartContactRendererType<T> = (uuid: UUIDStringType) => T | string;
export type StringRendererType = ( export type StringRendererType<T> = (
id: string, id: string,
i18n: LocalizerType, i18n: LocalizerType,
components?: Array<FullJSXType> | ReplacementValuesType<FullJSXType> components?: Array<T | string> | ReplacementValuesType<T | string>
) => FullJSXType; ) => T | string;
export type RenderOptionsType = { export type RenderOptionsType<T> = {
from?: UUIDStringType; from?: UUIDStringType;
i18n: LocalizerType; i18n: LocalizerType;
ourUuid: UUIDStringType; ourUuid: UUIDStringType;
renderContact: SmartContactRendererType; renderContact: SmartContactRendererType<T>;
renderString: StringRendererType; renderString: StringRendererType<T>;
}; };
const AccessControlEnum = Proto.AccessControl.AccessRequired; const AccessControlEnum = Proto.AccessControl.AccessRequired;
const RoleEnum = Proto.Member.Role; const RoleEnum = Proto.Member.Role;
export function renderChange( export function renderChange<T>(
change: GroupV2ChangeType, change: GroupV2ChangeType,
options: RenderOptionsType options: RenderOptionsType<T>
): Array<FullJSXType> { ): Array<T | string> {
const { details, from } = change; const { details, from } = change;
return details.map((detail: GroupV2ChangeDetailType) => return details.map((detail: GroupV2ChangeDetailType) =>
renderChangeDetail(detail, { renderChangeDetail<T>(detail, {
...options, ...options,
from, from,
}) })
); );
} }
export function renderChangeDetail( export function renderChangeDetail<T>(
detail: GroupV2ChangeDetailType, detail: GroupV2ChangeDetailType,
options: RenderOptionsType options: RenderOptionsType<T>
): FullJSXType { ): T | string {
const { from, i18n, ourUuid, renderContact, renderString } = options; const { from, i18n, ourUuid, renderContact, renderString } = options;
const fromYou = Boolean(from && from === ourUuid); const fromYou = Boolean(from && from === ourUuid);

View File

@ -142,6 +142,7 @@ import {
isCustomError, isCustomError,
isQuoteAMatch, isQuoteAMatch,
} from '../messages/helpers'; } from '../messages/helpers';
import type { ReplacementValuesType } from '../types/I18N';
/* eslint-disable camelcase */ /* eslint-disable camelcase */
/* eslint-disable more/no-then */ /* eslint-disable more/no-then */
@ -447,11 +448,14 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
if (isGroupV2Change(attributes)) { if (isGroupV2Change(attributes)) {
const change = this.get('groupV2Change'); const change = this.get('groupV2Change');
strictAssert(
change,
'getNotificationData: isGroupV2Change true, but no groupV2Change!'
);
const lines = window.Signal.GroupChange.renderChange(change, { const lines = window.Signal.GroupChange.renderChange<string>(change, {
AccessControlEnum: Proto.AccessControl.AccessRequired,
i18n: window.i18n, i18n: window.i18n,
ourConversationId: window.ConversationController.getOurConversationId(), ourUuid: window.textsecure.storage.user.getCheckedUuid().toString(),
renderContact: (conversationId: string) => { renderContact: (conversationId: string) => {
const conversation = const conversation =
window.ConversationController.get(conversationId); window.ConversationController.get(conversationId);
@ -462,9 +466,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
renderString: ( renderString: (
key: string, key: string,
_i18n: unknown, _i18n: unknown,
placeholders: Array<string> components: Array<string> | ReplacementValuesType<string> | undefined
) => window.i18n(key, placeholders), ) => window.i18n(key, components),
RoleEnum: Proto.Member.Role,
}); });
return { text: lines.join(' ') }; return { text: lines.join(' ') };

6
ts/window.d.ts vendored
View File

@ -111,6 +111,8 @@ import { CI } from './CI';
import { IPCEventsType, IPCEventsValuesType } from './util/createIPCEvents'; import { IPCEventsType, IPCEventsValuesType } from './util/createIPCEvents';
import { ConversationView } from './views/conversation_view'; import { ConversationView } from './views/conversation_view';
import type { SignalContextType } from './windows/context'; import type { SignalContextType } from './windows/context';
import { GroupV2Change } from './components/conversation/GroupV2Change';
import * as GroupChange from './groupChange';
export { Long } from 'long'; export { Long } from 'long';
@ -381,9 +383,7 @@ declare global {
QualifiedAddress: typeof QualifiedAddress; QualifiedAddress: typeof QualifiedAddress;
}; };
Util: typeof Util; Util: typeof Util;
GroupChange: { GroupChange: typeof GroupChange;
renderChange: (change: unknown, things: unknown) => Array<string>;
};
Components: { Components: {
AttachmentList: typeof AttachmentList; AttachmentList: typeof AttachmentList;
ChatColorPicker: typeof ChatColorPicker; ChatColorPicker: typeof ChatColorPicker;