Moves startGV2Migration to redux
This commit is contained in:
parent
452e0b7b31
commit
7ea38bb1a9
17 changed files with 171 additions and 125 deletions
|
@ -105,7 +105,7 @@ const useProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||||
),
|
),
|
||||||
title: '',
|
title: '',
|
||||||
// GroupV1 Disabled Actions
|
// GroupV1 Disabled Actions
|
||||||
onStartGroupMigration: action('onStartGroupMigration'),
|
showGV2MigrationDialog: action('showGV2MigrationDialog'),
|
||||||
// GroupV2
|
// GroupV2
|
||||||
announcementsOnly: boolean(
|
announcementsOnly: boolean(
|
||||||
'announcementsOnly',
|
'announcementsOnly',
|
||||||
|
|
|
@ -162,7 +162,7 @@ export type Props = Pick<
|
||||||
| 'clearShowPickerHint'
|
| 'clearShowPickerHint'
|
||||||
> &
|
> &
|
||||||
MessageRequestActionsProps &
|
MessageRequestActionsProps &
|
||||||
Pick<GroupV1DisabledActionsPropsType, 'onStartGroupMigration'> &
|
Pick<GroupV1DisabledActionsPropsType, 'showGV2MigrationDialog'> &
|
||||||
Pick<GroupV2PendingApprovalActionsPropsType, 'onCancelJoinRequest'> &
|
Pick<GroupV2PendingApprovalActionsPropsType, 'onCancelJoinRequest'> &
|
||||||
OwnProps;
|
OwnProps;
|
||||||
|
|
||||||
|
@ -244,7 +244,7 @@ export function CompositionArea({
|
||||||
title,
|
title,
|
||||||
// GroupV1 Disabled Actions
|
// GroupV1 Disabled Actions
|
||||||
isGroupV1AndDisabled,
|
isGroupV1AndDisabled,
|
||||||
onStartGroupMigration,
|
showGV2MigrationDialog,
|
||||||
// GroupV2
|
// GroupV2
|
||||||
announcementsOnly,
|
announcementsOnly,
|
||||||
areWeAdmin,
|
areWeAdmin,
|
||||||
|
@ -561,8 +561,9 @@ export function CompositionArea({
|
||||||
if (!left && isGroupV1AndDisabled) {
|
if (!left && isGroupV1AndDisabled) {
|
||||||
return (
|
return (
|
||||||
<GroupV1DisabledActions
|
<GroupV1DisabledActions
|
||||||
|
conversationId={conversationId}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onStartGroupMigration={onStartGroupMigration}
|
showGV2MigrationDialog={showGV2MigrationDialog}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ const contact3: ConversationType = getDefaultConversation({
|
||||||
|
|
||||||
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
areWeInvited: Boolean(overrideProps.areWeInvited),
|
areWeInvited: Boolean(overrideProps.areWeInvited),
|
||||||
|
conversationId: '123',
|
||||||
droppedMembers: overrideProps.droppedMembers || [contact3, contact1],
|
droppedMembers: overrideProps.droppedMembers || [contact3, contact1],
|
||||||
getPreferredBadge: () => undefined,
|
getPreferredBadge: () => undefined,
|
||||||
hasMigrated: Boolean(overrideProps.hasMigrated),
|
hasMigrated: Boolean(overrideProps.hasMigrated),
|
||||||
|
|
|
@ -8,39 +8,62 @@ import type { PreferredBadgeSelectorType } from '../state/selectors/badges';
|
||||||
import { GroupDialog } from './GroupDialog';
|
import { GroupDialog } from './GroupDialog';
|
||||||
import { sortByTitle } from '../util/sortByTitle';
|
import { sortByTitle } from '../util/sortByTitle';
|
||||||
|
|
||||||
type CallbackType = () => unknown;
|
|
||||||
|
|
||||||
export type DataPropsType = {
|
export type DataPropsType = {
|
||||||
|
conversationId: string;
|
||||||
readonly areWeInvited: boolean;
|
readonly areWeInvited: boolean;
|
||||||
readonly droppedMembers: Array<ConversationType>;
|
readonly droppedMembers: Array<ConversationType>;
|
||||||
readonly hasMigrated: boolean;
|
readonly hasMigrated: boolean;
|
||||||
readonly invitedMembers: Array<ConversationType>;
|
readonly invitedMembers: Array<ConversationType>;
|
||||||
readonly migrate: CallbackType;
|
|
||||||
readonly onClose: CallbackType;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type HousekeepingPropsType = {
|
|
||||||
readonly getPreferredBadge: PreferredBadgeSelectorType;
|
readonly getPreferredBadge: PreferredBadgeSelectorType;
|
||||||
readonly i18n: LocalizerType;
|
readonly i18n: LocalizerType;
|
||||||
readonly theme: ThemeType;
|
readonly theme: ThemeType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PropsType = DataPropsType & HousekeepingPropsType;
|
type ActionsPropsType =
|
||||||
|
| {
|
||||||
|
initiateMigrationToGroupV2: (conversationId: string) => unknown;
|
||||||
|
closeGV2MigrationDialog: () => unknown;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
readonly migrate: () => unknown;
|
||||||
|
readonly onClose: () => unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PropsType = DataPropsType & ActionsPropsType;
|
||||||
|
|
||||||
export const GroupV1MigrationDialog: React.FunctionComponent<PropsType> =
|
export const GroupV1MigrationDialog: React.FunctionComponent<PropsType> =
|
||||||
React.memo(function GroupV1MigrationDialogInner(props: PropsType) {
|
React.memo(function GroupV1MigrationDialogInner(props: PropsType) {
|
||||||
const {
|
const {
|
||||||
areWeInvited,
|
areWeInvited,
|
||||||
|
conversationId,
|
||||||
droppedMembers,
|
droppedMembers,
|
||||||
getPreferredBadge,
|
getPreferredBadge,
|
||||||
hasMigrated,
|
hasMigrated,
|
||||||
i18n,
|
i18n,
|
||||||
invitedMembers,
|
invitedMembers,
|
||||||
migrate,
|
|
||||||
onClose,
|
|
||||||
theme,
|
theme,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
let migrateHandler;
|
||||||
|
if ('migrate' in props) {
|
||||||
|
migrateHandler = props.migrate;
|
||||||
|
} else if ('initiateMigrationToGroupV2' in props) {
|
||||||
|
migrateHandler = () => props.initiateMigrationToGroupV2(conversationId);
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
'GroupV1MigrationDialog: No conversationId or migration function'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let closeHandler;
|
||||||
|
if ('onClose' in props) {
|
||||||
|
closeHandler = props.onClose;
|
||||||
|
} else if ('closeGV2MigrationDialog' in props) {
|
||||||
|
closeHandler = props.closeGV2MigrationDialog;
|
||||||
|
} else {
|
||||||
|
throw new Error('GroupV1MigrationDialog: No close function provided');
|
||||||
|
}
|
||||||
|
|
||||||
const title = hasMigrated
|
const title = hasMigrated
|
||||||
? i18n('GroupV1--Migration--info--title')
|
? i18n('GroupV1--Migration--info--title')
|
||||||
: i18n('GroupV1--Migration--migrate--title');
|
: i18n('GroupV1--Migration--migrate--title');
|
||||||
|
@ -60,13 +83,13 @@ export const GroupV1MigrationDialog: React.FunctionComponent<PropsType> =
|
||||||
};
|
};
|
||||||
if (hasMigrated) {
|
if (hasMigrated) {
|
||||||
primaryButtonText = i18n('Confirmation--confirm');
|
primaryButtonText = i18n('Confirmation--confirm');
|
||||||
onClickPrimaryButton = onClose;
|
onClickPrimaryButton = closeHandler;
|
||||||
} else {
|
} else {
|
||||||
primaryButtonText = i18n('GroupV1--Migration--migrate');
|
primaryButtonText = i18n('GroupV1--Migration--migrate');
|
||||||
onClickPrimaryButton = migrate;
|
onClickPrimaryButton = migrateHandler;
|
||||||
secondaryButtonProps = {
|
secondaryButtonProps = {
|
||||||
secondaryButtonText: i18n('cancel'),
|
secondaryButtonText: i18n('cancel'),
|
||||||
onClickSecondaryButton: onClose,
|
onClickSecondaryButton: closeHandler,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +97,7 @@ export const GroupV1MigrationDialog: React.FunctionComponent<PropsType> =
|
||||||
<GroupDialog
|
<GroupDialog
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClickPrimaryButton={onClickPrimaryButton}
|
onClickPrimaryButton={onClickPrimaryButton}
|
||||||
onClose={onClose}
|
onClose={closeHandler}
|
||||||
primaryButtonText={primaryButtonText}
|
primaryButtonText={primaryButtonText}
|
||||||
title={title}
|
title={title}
|
||||||
{...secondaryButtonProps}
|
{...secondaryButtonProps}
|
||||||
|
|
|
@ -12,8 +12,9 @@ import enMessages from '../../../_locales/en/messages.json';
|
||||||
const i18n = setupI18n('en', enMessages);
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
const createProps = (): GroupV1DisabledActionsPropsType => ({
|
const createProps = (): GroupV1DisabledActionsPropsType => ({
|
||||||
|
conversationId: '123',
|
||||||
i18n,
|
i18n,
|
||||||
onStartGroupMigration: action('onStartGroupMigration'),
|
showGV2MigrationDialog: action('showGV2MigrationDialog'),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -6,13 +6,15 @@ import { Intl } from '../Intl';
|
||||||
import type { LocalizerType } from '../../types/Util';
|
import type { LocalizerType } from '../../types/Util';
|
||||||
|
|
||||||
export type PropsType = {
|
export type PropsType = {
|
||||||
|
conversationId: string;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
onStartGroupMigration: () => unknown;
|
showGV2MigrationDialog: (id: string) => unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function GroupV1DisabledActions({
|
export function GroupV1DisabledActions({
|
||||||
|
conversationId,
|
||||||
i18n,
|
i18n,
|
||||||
onStartGroupMigration,
|
showGV2MigrationDialog,
|
||||||
}: PropsType): JSX.Element {
|
}: PropsType): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="module-group-v1-disabled-actions">
|
<div className="module-group-v1-disabled-actions">
|
||||||
|
@ -37,7 +39,7 @@ export function GroupV1DisabledActions({
|
||||||
<div className="module-group-v1-disabled-actions__buttons">
|
<div className="module-group-v1-disabled-actions__buttons">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onStartGroupMigration}
|
onClick={() => showGV2MigrationDialog(conversationId)}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
className="module-group-v1-disabled-actions__buttons__button"
|
className="module-group-v1-disabled-actions__buttons__button"
|
||||||
>
|
>
|
||||||
|
|
|
@ -31,6 +31,7 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
'areWeInvited',
|
'areWeInvited',
|
||||||
isBoolean(overrideProps.areWeInvited) ? overrideProps.areWeInvited : false
|
isBoolean(overrideProps.areWeInvited) ? overrideProps.areWeInvited : false
|
||||||
),
|
),
|
||||||
|
conversationId: '123',
|
||||||
droppedMembers: overrideProps.droppedMembers || [contact1],
|
droppedMembers: overrideProps.droppedMembers || [contact1],
|
||||||
getPreferredBadge: () => undefined,
|
getPreferredBadge: () => undefined,
|
||||||
i18n,
|
i18n,
|
||||||
|
|
|
@ -15,6 +15,7 @@ import * as log from '../../logging/log';
|
||||||
|
|
||||||
export type PropsDataType = {
|
export type PropsDataType = {
|
||||||
areWeInvited: boolean;
|
areWeInvited: boolean;
|
||||||
|
conversationId: string;
|
||||||
droppedMembers: Array<ConversationType>;
|
droppedMembers: Array<ConversationType>;
|
||||||
invitedMembers: Array<ConversationType>;
|
invitedMembers: Array<ConversationType>;
|
||||||
};
|
};
|
||||||
|
@ -30,6 +31,7 @@ export type PropsType = PropsDataType & PropsHousekeepingType;
|
||||||
export function GroupV1Migration(props: PropsType): React.ReactElement {
|
export function GroupV1Migration(props: PropsType): React.ReactElement {
|
||||||
const {
|
const {
|
||||||
areWeInvited,
|
areWeInvited,
|
||||||
|
conversationId,
|
||||||
droppedMembers,
|
droppedMembers,
|
||||||
getPreferredBadge,
|
getPreferredBadge,
|
||||||
i18n,
|
i18n,
|
||||||
|
@ -86,6 +88,7 @@ export function GroupV1Migration(props: PropsType): React.ReactElement {
|
||||||
{showingDialog ? (
|
{showingDialog ? (
|
||||||
<GroupV1MigrationDialog
|
<GroupV1MigrationDialog
|
||||||
areWeInvited={areWeInvited}
|
areWeInvited={areWeInvited}
|
||||||
|
conversationId={conversationId}
|
||||||
droppedMembers={droppedMembers}
|
droppedMembers={droppedMembers}
|
||||||
getPreferredBadge={getPreferredBadge}
|
getPreferredBadge={getPreferredBadge}
|
||||||
hasMigrated
|
hasMigrated
|
||||||
|
|
|
@ -28,7 +28,6 @@ import { createChatColorPicker } from './state/roots/createChatColorPicker';
|
||||||
import { createConversationDetails } from './state/roots/createConversationDetails';
|
import { createConversationDetails } from './state/roots/createConversationDetails';
|
||||||
import { createApp } from './state/roots/createApp';
|
import { createApp } from './state/roots/createApp';
|
||||||
import { createGroupLinkManagement } from './state/roots/createGroupLinkManagement';
|
import { createGroupLinkManagement } from './state/roots/createGroupLinkManagement';
|
||||||
import { createGroupV1MigrationModal } from './state/roots/createGroupV1MigrationModal';
|
|
||||||
import { createGroupV2JoinModal } from './state/roots/createGroupV2JoinModal';
|
import { createGroupV2JoinModal } from './state/roots/createGroupV2JoinModal';
|
||||||
import { createMessageDetail } from './state/roots/createMessageDetail';
|
import { createMessageDetail } from './state/roots/createMessageDetail';
|
||||||
import { createConversationNotificationsSettings } from './state/roots/createConversationNotificationsSettings';
|
import { createConversationNotificationsSettings } from './state/roots/createConversationNotificationsSettings';
|
||||||
|
@ -410,7 +409,6 @@ export const setup = (options: {
|
||||||
createChatColorPicker,
|
createChatColorPicker,
|
||||||
createConversationDetails,
|
createConversationDetails,
|
||||||
createGroupLinkManagement,
|
createGroupLinkManagement,
|
||||||
createGroupV1MigrationModal,
|
|
||||||
createGroupV2JoinModal,
|
createGroupV2JoinModal,
|
||||||
createGroupV2Permissions,
|
createGroupV2Permissions,
|
||||||
createMessageDetail,
|
createMessageDetail,
|
||||||
|
|
|
@ -107,6 +107,11 @@ import { denyPendingApprovalRequest } from '../../util/denyPendingApprovalReques
|
||||||
import { SignalService as Proto } from '../../protobuf';
|
import { SignalService as Proto } from '../../protobuf';
|
||||||
import { addReportSpamJob } from '../../jobs/helpers/addReportSpamJob';
|
import { addReportSpamJob } from '../../jobs/helpers/addReportSpamJob';
|
||||||
import { reportSpamJobQueue } from '../../jobs/reportSpamJobQueue';
|
import { reportSpamJobQueue } from '../../jobs/reportSpamJobQueue';
|
||||||
|
import {
|
||||||
|
modifyGroupV2,
|
||||||
|
buildPromotePendingAdminApprovalMemberChange,
|
||||||
|
initiateMigrationToGroupV2 as doInitiateMigrationToGroupV2,
|
||||||
|
} from '../../groups';
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
|
||||||
|
@ -876,6 +881,7 @@ export const actions = {
|
||||||
doubleCheckMissingQuoteReference,
|
doubleCheckMissingQuoteReference,
|
||||||
generateNewGroupLink,
|
generateNewGroupLink,
|
||||||
loadRecentMediaItems,
|
loadRecentMediaItems,
|
||||||
|
initiateMigrationToGroupV2,
|
||||||
messageChanged,
|
messageChanged,
|
||||||
messageDeleted,
|
messageDeleted,
|
||||||
messageExpanded,
|
messageExpanded,
|
||||||
|
@ -2142,7 +2148,7 @@ function approvePendingMembershipFromGroupV2(
|
||||||
isGroupV2(conversation.attributes) &&
|
isGroupV2(conversation.attributes) &&
|
||||||
isMemberRequestingToJoin(conversation.attributes, uuid)
|
isMemberRequestingToJoin(conversation.attributes, uuid)
|
||||||
) {
|
) {
|
||||||
await window.Signal.Groups.modifyGroupV2({
|
await modifyGroupV2({
|
||||||
conversation,
|
conversation,
|
||||||
usingCredentialsFrom: [pendingMember],
|
usingCredentialsFrom: [pendingMember],
|
||||||
createGroupChange: async () => {
|
createGroupChange: async () => {
|
||||||
|
@ -2157,12 +2163,10 @@ function approvePendingMembershipFromGroupV2(
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return window.Signal.Groups.buildPromotePendingAdminApprovalMemberChange(
|
return buildPromotePendingAdminApprovalMemberChange({
|
||||||
{
|
group: conversation.attributes,
|
||||||
group: conversation.attributes,
|
uuid,
|
||||||
uuid,
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
name: 'approvePendingMembershipFromGroupV2',
|
name: 'approvePendingMembershipFromGroupV2',
|
||||||
});
|
});
|
||||||
|
@ -2362,6 +2366,26 @@ function deleteConversation(conversationId: string): NoopActionType {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initiateMigrationToGroupV2(conversationId: string): NoopActionType {
|
||||||
|
const conversation = window.ConversationController.get(conversationId);
|
||||||
|
if (!conversation) {
|
||||||
|
throw new Error(
|
||||||
|
'deleteConversation: Expected a conversation to be found. Doing nothing'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
longRunningTaskWrapper({
|
||||||
|
idForLogging: conversation.idForLogging(),
|
||||||
|
name: 'initiateMigrationToGroupV2',
|
||||||
|
task: () => doInitiateMigrationToGroupV2(conversation),
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'NOOP',
|
||||||
|
payload: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function loadRecentMediaItems(
|
function loadRecentMediaItems(
|
||||||
conversationId: string,
|
conversationId: string,
|
||||||
limit: number
|
limit: number
|
||||||
|
|
|
@ -3,15 +3,19 @@
|
||||||
|
|
||||||
import type { ThunkAction } from 'redux-thunk';
|
import type { ThunkAction } from 'redux-thunk';
|
||||||
import type { ExplodePromiseResultType } from '../../util/explodePromise';
|
import type { ExplodePromiseResultType } from '../../util/explodePromise';
|
||||||
|
import type { GroupV2PendingMemberType } from '../../model-types.d';
|
||||||
import type { PropsForMessage } from '../selectors/message';
|
import type { PropsForMessage } from '../selectors/message';
|
||||||
|
import type { RecipientsByConversation } from './stories';
|
||||||
import type { SafetyNumberChangeSource } from '../../components/SafetyNumberChangeDialog';
|
import type { SafetyNumberChangeSource } from '../../components/SafetyNumberChangeDialog';
|
||||||
import type { StateType as RootStateType } from '../reducer';
|
import type { StateType as RootStateType } from '../reducer';
|
||||||
import type { UUIDStringType } from '../../types/UUID';
|
import type { UUIDStringType } from '../../types/UUID';
|
||||||
import * as SingleServePromise from '../../services/singleServePromise';
|
import * as SingleServePromise from '../../services/singleServePromise';
|
||||||
import { getMessageById } from '../../messages/getMessageById';
|
import { getMessageById } from '../../messages/getMessageById';
|
||||||
import { getMessagePropsSelector } from '../selectors/message';
|
import { getMessagePropsSelector } from '../selectors/message';
|
||||||
|
import { longRunningTaskWrapper } from '../../util/longRunningTaskWrapper';
|
||||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||||
import type { RecipientsByConversation } from './stories';
|
import { isGroupV1 } from '../../util/whatTypeOfConversation';
|
||||||
|
import { getGroupMigrationMembers } from '../../groups';
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
|
||||||
|
@ -24,9 +28,19 @@ export type SafetyNumberChangedBlockingDataType = Readonly<{
|
||||||
source?: SafetyNumberChangeSource;
|
source?: SafetyNumberChangeSource;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
type MigrateToGV2PropsType = {
|
||||||
|
areWeInvited: boolean;
|
||||||
|
conversationId: string;
|
||||||
|
droppedMemberIds: ReadonlyArray<string>;
|
||||||
|
hasMigrated: boolean;
|
||||||
|
invitedMemberIds: ReadonlyArray<string>;
|
||||||
|
};
|
||||||
|
|
||||||
export type GlobalModalsStateType = Readonly<{
|
export type GlobalModalsStateType = Readonly<{
|
||||||
|
addUserToAnotherGroupModalContactId?: string;
|
||||||
contactModalState?: ContactModalStateType;
|
contactModalState?: ContactModalStateType;
|
||||||
forwardMessageProps?: ForwardMessagePropsType;
|
forwardMessageProps?: ForwardMessagePropsType;
|
||||||
|
gv2MigrationProps?: MigrateToGV2PropsType;
|
||||||
isProfileEditorVisible: boolean;
|
isProfileEditorVisible: boolean;
|
||||||
isSignalConnectionsVisible: boolean;
|
isSignalConnectionsVisible: boolean;
|
||||||
isStoriesSettingsVisible: boolean;
|
isStoriesSettingsVisible: boolean;
|
||||||
|
@ -34,7 +48,6 @@ export type GlobalModalsStateType = Readonly<{
|
||||||
profileEditorHasError: boolean;
|
profileEditorHasError: boolean;
|
||||||
safetyNumberChangedBlockingData?: SafetyNumberChangedBlockingDataType;
|
safetyNumberChangedBlockingData?: SafetyNumberChangedBlockingDataType;
|
||||||
safetyNumberModalContactId?: string;
|
safetyNumberModalContactId?: string;
|
||||||
addUserToAnotherGroupModalContactId?: string;
|
|
||||||
userNotFoundModalState?: UserNotFoundModalStateType;
|
userNotFoundModalState?: UserNotFoundModalStateType;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
@ -60,6 +73,8 @@ const TOGGLE_SIGNAL_CONNECTIONS_MODAL =
|
||||||
'globalModals/TOGGLE_SIGNAL_CONNECTIONS_MODAL';
|
'globalModals/TOGGLE_SIGNAL_CONNECTIONS_MODAL';
|
||||||
export const SHOW_SEND_ANYWAY_DIALOG = 'globalModals/SHOW_SEND_ANYWAY_DIALOG';
|
export const SHOW_SEND_ANYWAY_DIALOG = 'globalModals/SHOW_SEND_ANYWAY_DIALOG';
|
||||||
const HIDE_SEND_ANYWAY_DIALOG = 'globalModals/HIDE_SEND_ANYWAY_DIALOG';
|
const HIDE_SEND_ANYWAY_DIALOG = 'globalModals/HIDE_SEND_ANYWAY_DIALOG';
|
||||||
|
const SHOW_GV2_MIGRATION_DIALOG = 'globalModals/SHOW_GV2_MIGRATION_DIALOG';
|
||||||
|
const CLOSE_GV2_MIGRATION_DIALOG = 'globalModals/CLOSE_GV2_MIGRATION_DIALOG';
|
||||||
|
|
||||||
export type ContactModalStateType = {
|
export type ContactModalStateType = {
|
||||||
contactId: string;
|
contactId: string;
|
||||||
|
@ -137,6 +152,15 @@ type HideStoriesSettingsActionType = {
|
||||||
type: typeof HIDE_STORIES_SETTINGS;
|
type: typeof HIDE_STORIES_SETTINGS;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type StartMigrationToGV2ActionType = {
|
||||||
|
type: typeof SHOW_GV2_MIGRATION_DIALOG;
|
||||||
|
payload: MigrateToGV2PropsType;
|
||||||
|
};
|
||||||
|
|
||||||
|
type CloseGV2MigrationDialogActionType = {
|
||||||
|
type: typeof CLOSE_GV2_MIGRATION_DIALOG;
|
||||||
|
};
|
||||||
|
|
||||||
export type ShowSendAnywayDialogActionType = {
|
export type ShowSendAnywayDialogActionType = {
|
||||||
type: typeof SHOW_SEND_ANYWAY_DIALOG;
|
type: typeof SHOW_SEND_ANYWAY_DIALOG;
|
||||||
payload: SafetyNumberChangedBlockingDataType & {
|
payload: SafetyNumberChangedBlockingDataType & {
|
||||||
|
@ -149,6 +173,8 @@ type HideSendAnywayDialogActiontype = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GlobalModalsActionType =
|
export type GlobalModalsActionType =
|
||||||
|
| StartMigrationToGV2ActionType
|
||||||
|
| CloseGV2MigrationDialogActionType
|
||||||
| HideContactModalActionType
|
| HideContactModalActionType
|
||||||
| ShowContactModalActionType
|
| ShowContactModalActionType
|
||||||
| HideWhatsNewModalActionType
|
| HideWhatsNewModalActionType
|
||||||
|
@ -185,6 +211,8 @@ export const actions = {
|
||||||
toggleSafetyNumberModal,
|
toggleSafetyNumberModal,
|
||||||
toggleAddUserToAnotherGroupModal,
|
toggleAddUserToAnotherGroupModal,
|
||||||
toggleSignalConnectionsModal,
|
toggleSignalConnectionsModal,
|
||||||
|
showGV2MigrationDialog,
|
||||||
|
closeGV2MigrationDialog,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGlobalModalActions = (): typeof actions =>
|
export const useGlobalModalActions = (): typeof actions =>
|
||||||
|
@ -244,6 +272,57 @@ function showStoriesSettings(): ShowStoriesSettingsActionType {
|
||||||
return { type: SHOW_STORIES_SETTINGS };
|
return { type: SHOW_STORIES_SETTINGS };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showGV2MigrationDialog(
|
||||||
|
conversationId: string
|
||||||
|
): ThunkAction<void, RootStateType, unknown, StartMigrationToGV2ActionType> {
|
||||||
|
return async dispatch => {
|
||||||
|
const conversation = window.ConversationController.get(conversationId);
|
||||||
|
if (!conversation) {
|
||||||
|
throw new Error(
|
||||||
|
'showGV2MigrationDialog: Expected a conversation to be found. Doing nothing'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const idForLogging = conversation.idForLogging();
|
||||||
|
|
||||||
|
if (!isGroupV1(conversation.attributes)) {
|
||||||
|
throw new Error(
|
||||||
|
`showGV2MigrationDialog/${idForLogging}: Cannot start, not a GroupV1 group`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this call will throw if, after generating member lists, we are no longer a
|
||||||
|
// member or are in the pending member list.
|
||||||
|
const { droppedGV2MemberIds, pendingMembersV2 } =
|
||||||
|
await longRunningTaskWrapper({
|
||||||
|
idForLogging,
|
||||||
|
name: 'getGroupMigrationMembers',
|
||||||
|
task: () => getGroupMigrationMembers(conversation),
|
||||||
|
});
|
||||||
|
|
||||||
|
const invitedMemberIds = pendingMembersV2.map(
|
||||||
|
(item: GroupV2PendingMemberType) => item.uuid
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: SHOW_GV2_MIGRATION_DIALOG,
|
||||||
|
payload: {
|
||||||
|
areWeInvited: false,
|
||||||
|
conversationId,
|
||||||
|
droppedMemberIds: droppedGV2MemberIds,
|
||||||
|
hasMigrated: false,
|
||||||
|
invitedMemberIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeGV2MigrationDialog(): CloseGV2MigrationDialogActionType {
|
||||||
|
return {
|
||||||
|
type: CLOSE_GV2_MIGRATION_DIALOG,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function toggleForwardMessageModal(
|
function toggleForwardMessageModal(
|
||||||
messageId?: string
|
messageId?: string
|
||||||
): ThunkAction<
|
): ThunkAction<
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
// Copyright 2020 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
|
||||||
|
|
||||||
import type { Store } from 'redux';
|
|
||||||
|
|
||||||
import type { PropsType } from '../smart/GroupV1MigrationDialog';
|
|
||||||
import { SmartGroupV1MigrationDialog } from '../smart/GroupV1MigrationDialog';
|
|
||||||
|
|
||||||
export const createGroupV1MigrationModal = (
|
|
||||||
store: Store,
|
|
||||||
props: PropsType
|
|
||||||
): React.ReactElement => {
|
|
||||||
return (
|
|
||||||
<Provider store={store}>
|
|
||||||
<SmartGroupV1MigrationDialog {...props} />
|
|
||||||
</Provider>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1121,6 +1121,7 @@ function getPropsForGroupV1Migration(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
areWeInvited: false,
|
areWeInvited: false,
|
||||||
|
conversationId: message.conversationId,
|
||||||
droppedMembers,
|
droppedMembers,
|
||||||
invitedMembers,
|
invitedMembers,
|
||||||
};
|
};
|
||||||
|
@ -1140,6 +1141,7 @@ function getPropsForGroupV1Migration(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
areWeInvited,
|
areWeInvited,
|
||||||
|
conversationId: message.conversationId,
|
||||||
droppedMembers,
|
droppedMembers,
|
||||||
invitedMembers,
|
invitedMembers,
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,7 +30,6 @@ export type PropsType = {
|
||||||
| 'onPickSticker'
|
| 'onPickSticker'
|
||||||
| 'onSelectMediaQuality'
|
| 'onSelectMediaQuality'
|
||||||
| 'onSendMessage'
|
| 'onSendMessage'
|
||||||
| 'onStartGroupMigration'
|
|
||||||
| 'onTextTooLong'
|
| 'onTextTooLong'
|
||||||
| 'openConversation'
|
| 'openConversation'
|
||||||
>;
|
>;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { mapDispatchToProps } from '../actions';
|
import { mapDispatchToProps } from '../actions';
|
||||||
import type { PropsType as GroupV1MigrationDialogPropsType } from '../../components/GroupV1MigrationDialog';
|
import type { DataPropsType as GroupV1MigrationDialogPropsType } from '../../components/GroupV1MigrationDialog';
|
||||||
import { GroupV1MigrationDialog } from '../../components/GroupV1MigrationDialog';
|
import { GroupV1MigrationDialog } from '../../components/GroupV1MigrationDialog';
|
||||||
import type { ConversationType } from '../ducks/conversations';
|
import type { ConversationType } from '../ducks/conversations';
|
||||||
import type { StateType } from '../reducer';
|
import type { StateType } from '../reducer';
|
||||||
|
|
|
@ -16,21 +16,14 @@ import * as Errors from '../types/errors';
|
||||||
import type { DraftBodyRangesType } from '../types/Util';
|
import type { DraftBodyRangesType } from '../types/Util';
|
||||||
import type { MIMEType } from '../types/MIME';
|
import type { MIMEType } from '../types/MIME';
|
||||||
import type { ConversationModel } from '../models/conversations';
|
import type { ConversationModel } from '../models/conversations';
|
||||||
import type {
|
import type { MessageAttributesType } from '../model-types.d';
|
||||||
GroupV2PendingMemberType,
|
|
||||||
MessageAttributesType,
|
|
||||||
} from '../model-types.d';
|
|
||||||
import type { MediaItemType, MediaItemMessageType } from '../types/MediaItem';
|
import type { MediaItemType, MediaItemMessageType } from '../types/MediaItem';
|
||||||
import { getMessageById } from '../messages/getMessageById';
|
import { getMessageById } from '../messages/getMessageById';
|
||||||
import { getContactId } from '../messages/helpers';
|
import { getContactId } from '../messages/helpers';
|
||||||
import { strictAssert } from '../util/assert';
|
import { strictAssert } from '../util/assert';
|
||||||
import { enqueueReactionForSend } from '../reactions/enqueueReactionForSend';
|
import { enqueueReactionForSend } from '../reactions/enqueueReactionForSend';
|
||||||
import type { GroupNameCollisionsWithIdsByTitle } from '../util/groupMemberNameCollisions';
|
import type { GroupNameCollisionsWithIdsByTitle } from '../util/groupMemberNameCollisions';
|
||||||
import {
|
import { isDirectConversation, isGroup } from '../util/whatTypeOfConversation';
|
||||||
isDirectConversation,
|
|
||||||
isGroup,
|
|
||||||
isGroupV1,
|
|
||||||
} from '../util/whatTypeOfConversation';
|
|
||||||
import { findAndFormatContact } from '../util/findAndFormatContact';
|
import { findAndFormatContact } from '../util/findAndFormatContact';
|
||||||
import { getPreferredBadgeSelector } from '../state/selectors/badges';
|
import { getPreferredBadgeSelector } from '../state/selectors/badges';
|
||||||
import {
|
import {
|
||||||
|
@ -195,7 +188,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
private contactModalView?: Backbone.View;
|
private contactModalView?: Backbone.View;
|
||||||
private conversationView?: Backbone.View;
|
private conversationView?: Backbone.View;
|
||||||
private lightboxView?: ReactWrapperView;
|
private lightboxView?: ReactWrapperView;
|
||||||
private migrationDialog?: Backbone.View;
|
|
||||||
private stickerPreviewModalView?: Backbone.View;
|
private stickerPreviewModalView?: Backbone.View;
|
||||||
|
|
||||||
// Panel support
|
// Panel support
|
||||||
|
@ -450,7 +442,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
onTextTooLong: () => showToast(ToastMessageBodyTooLong),
|
onTextTooLong: () => showToast(ToastMessageBodyTooLong),
|
||||||
getQuotedMessage: () => this.model.get('quotedMessageId'),
|
getQuotedMessage: () => this.model.get('quotedMessageId'),
|
||||||
clearQuotedMessage: () => this.setQuoteMessage(undefined),
|
clearQuotedMessage: () => this.setQuoteMessage(undefined),
|
||||||
onStartGroupMigration: () => this.startMigrationToGV2(),
|
|
||||||
onCancelJoinRequest: async () => {
|
onCancelJoinRequest: async () => {
|
||||||
await window.showConfirmationDialog({
|
await window.showConfirmationDialog({
|
||||||
dialogName: 'GroupV2CancelRequestToJoin',
|
dialogName: 'GroupV2CancelRequestToJoin',
|
||||||
|
@ -686,62 +677,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
this.model.loadAndScroll(messageId);
|
this.model.loadAndScroll(messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async startMigrationToGV2(): Promise<void> {
|
|
||||||
const logId = this.model.idForLogging();
|
|
||||||
|
|
||||||
if (!isGroupV1(this.model.attributes)) {
|
|
||||||
throw new Error(
|
|
||||||
`startMigrationToGV2/${logId}: Cannot start, not a GroupV1 group`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const onClose = () => {
|
|
||||||
if (this.migrationDialog) {
|
|
||||||
this.migrationDialog.remove();
|
|
||||||
this.migrationDialog = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
onClose();
|
|
||||||
|
|
||||||
const migrate = () => {
|
|
||||||
onClose();
|
|
||||||
|
|
||||||
longRunningTaskWrapper({
|
|
||||||
idForLogging: this.model.idForLogging(),
|
|
||||||
name: 'initiateMigrationToGroupV2',
|
|
||||||
task: () => window.Signal.Groups.initiateMigrationToGroupV2(this.model),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Note: this call will throw if, after generating member lists, we are no longer a
|
|
||||||
// member or are in the pending member list.
|
|
||||||
const { droppedGV2MemberIds, pendingMembersV2 } =
|
|
||||||
await longRunningTaskWrapper({
|
|
||||||
idForLogging: this.model.idForLogging(),
|
|
||||||
name: 'getGroupMigrationMembers',
|
|
||||||
task: () => window.Signal.Groups.getGroupMigrationMembers(this.model),
|
|
||||||
});
|
|
||||||
|
|
||||||
const invitedMemberIds = pendingMembersV2.map(
|
|
||||||
(item: GroupV2PendingMemberType) => item.uuid
|
|
||||||
);
|
|
||||||
|
|
||||||
this.migrationDialog = new ReactWrapperView({
|
|
||||||
className: 'group-v1-migration-wrapper',
|
|
||||||
JSX: window.Signal.State.Roots.createGroupV1MigrationModal(
|
|
||||||
window.reduxStore,
|
|
||||||
{
|
|
||||||
areWeInvited: false,
|
|
||||||
droppedMemberIds: droppedGV2MemberIds,
|
|
||||||
hasMigrated: false,
|
|
||||||
invitedMemberIds,
|
|
||||||
migrate,
|
|
||||||
onClose,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
unload(reason: string): void {
|
unload(reason: string): void {
|
||||||
log.info(
|
log.info(
|
||||||
'unloading conversation',
|
'unloading conversation',
|
||||||
|
|
2
ts/window.d.ts
vendored
2
ts/window.d.ts
vendored
|
@ -40,7 +40,6 @@ import type { createApp } from './state/roots/createApp';
|
||||||
import type { createChatColorPicker } from './state/roots/createChatColorPicker';
|
import type { createChatColorPicker } from './state/roots/createChatColorPicker';
|
||||||
import type { createConversationDetails } from './state/roots/createConversationDetails';
|
import type { createConversationDetails } from './state/roots/createConversationDetails';
|
||||||
import type { createGroupLinkManagement } from './state/roots/createGroupLinkManagement';
|
import type { createGroupLinkManagement } from './state/roots/createGroupLinkManagement';
|
||||||
import type { createGroupV1MigrationModal } from './state/roots/createGroupV1MigrationModal';
|
|
||||||
import type { createGroupV2JoinModal } from './state/roots/createGroupV2JoinModal';
|
import type { createGroupV2JoinModal } from './state/roots/createGroupV2JoinModal';
|
||||||
import type { createGroupV2Permissions } from './state/roots/createGroupV2Permissions';
|
import type { createGroupV2Permissions } from './state/roots/createGroupV2Permissions';
|
||||||
import type { createMessageDetail } from './state/roots/createMessageDetail';
|
import type { createMessageDetail } from './state/roots/createMessageDetail';
|
||||||
|
@ -172,7 +171,6 @@ export type SignalCoreType = {
|
||||||
createChatColorPicker: typeof createChatColorPicker;
|
createChatColorPicker: typeof createChatColorPicker;
|
||||||
createConversationDetails: typeof createConversationDetails;
|
createConversationDetails: typeof createConversationDetails;
|
||||||
createGroupLinkManagement: typeof createGroupLinkManagement;
|
createGroupLinkManagement: typeof createGroupLinkManagement;
|
||||||
createGroupV1MigrationModal: typeof createGroupV1MigrationModal;
|
|
||||||
createGroupV2JoinModal: typeof createGroupV2JoinModal;
|
createGroupV2JoinModal: typeof createGroupV2JoinModal;
|
||||||
createGroupV2Permissions: typeof createGroupV2Permissions;
|
createGroupV2Permissions: typeof createGroupV2Permissions;
|
||||||
createMessageDetail: typeof createMessageDetail;
|
createMessageDetail: typeof createMessageDetail;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue