Remove Piwik support (#8835)

* Remove all mentions of Piwik

* Kill off all consumer of the old Piwik Analytics module

* Simplify ModalManager interface

* i18n

* Attempt to fix old e2e tests

* Remove unused component

* Iterate PR
This commit is contained in:
Michael Telatynski 2022-06-14 17:51:51 +01:00 committed by GitHub
parent 7d14d15ba6
commit 3c5c2bef6d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
142 changed files with 446 additions and 1412 deletions

View file

@ -89,7 +89,6 @@
@import "./views/context_menus/_IconizedContextMenu.scss";
@import "./views/context_menus/_MessageContextMenu.scss";
@import "./views/dialogs/_AddExistingToSpaceDialog.scss";
@import "./views/dialogs/_Analytics.scss";
@import "./views/dialogs/_AnalyticsLearnMoreDialog.scss";
@import "./views/dialogs/_BugReportDialog.scss";
@import "./views/dialogs/_BulkRedactDialog.scss";

View file

@ -1,23 +0,0 @@
/*
Copyright 2019 New Vector Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_AnalyticsModal table {
margin: 10px 0px;
.mx_AnalyticsModal_label {
width: 400px;
}
}

View file

@ -34,7 +34,6 @@ import type { Renderer } from "react-dom";
import RightPanelStore from "../stores/right-panel/RightPanelStore";
import WidgetStore from "../stores/WidgetStore";
import CallHandler from "../CallHandler";
import { Analytics } from "../Analytics";
import UserActivity from "../UserActivity";
import { ModalWidgetStore } from "../stores/ModalWidgetStore";
import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
@ -91,7 +90,6 @@ declare global {
mxWidgetStore: WidgetStore;
mxWidgetLayoutStore: WidgetLayoutStore;
mxCallHandler: CallHandler;
mxAnalytics: Analytics;
mxUserActivity: UserActivity;
mxModalWidgetStore: ModalWidgetStore;
mxVoipUserMapper: VoipUserMapper;

View file

@ -206,7 +206,7 @@ export default class AddThreepid {
continueKind: "primary",
},
};
const { finished } = Modal.createTrackedDialog('Add Email', '', InteractiveAuthDialog, {
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
title: _t("Add Email Address"),
matrixClient: MatrixClientPeg.get(),
authData: e.data,
@ -319,7 +319,7 @@ export default class AddThreepid {
continueKind: "primary",
},
};
const { finished } = Modal.createTrackedDialog('Add MSISDN', '', InteractiveAuthDialog, {
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
title: _t("Add Phone Number"),
matrixClient: MatrixClientPeg.get(),
authData: e.data,

View file

@ -1,460 +0,0 @@
/*
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2020 - 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { logger } from "matrix-js-sdk/src/logger";
import { Optional } from "matrix-events-sdk";
import { randomString } from 'matrix-js-sdk/src/randomstring';
import { getCurrentLanguage, _t, _td, IVariables } from './languageHandler';
import PlatformPeg from './PlatformPeg';
import SdkConfig from './SdkConfig';
import Modal from './Modal';
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
import { SnakedObject } from "./utils/SnakedObject";
import { IConfigOptions } from "./IConfigOptions";
// Note: we keep the analytics redaction on groups in case people have old links.
const hashRegex = /#\/(groups?|room|user|settings|register|login|forgot_password|home|directory)/;
const hashVarRegex = /#\/(group|room|user)\/.*$/;
// Remove all but the first item in the hash path. Redact unexpected hashes.
function getRedactedHash(hash: string): string {
// Don't leak URLs we aren't expecting - they could contain tokens/PII
const match = hashRegex.exec(hash);
if (!match) {
logger.warn(`Unexpected hash location "${hash}"`);
return '#/<unexpected hash location>';
}
if (hashVarRegex.test(hash)) {
return hash.replace(hashVarRegex, "#/$1/<redacted>");
}
return hash.replace(hashRegex, "#/$1");
}
// Return the current origin, path and hash separated with a `/`. This does
// not include query parameters.
function getRedactedUrl(): string {
const { origin, hash } = window.location;
let { pathname } = window.location;
// Redact paths which could contain unexpected PII
if (origin.startsWith('file://')) {
pathname = "/<redacted>/";
}
return origin + pathname + getRedactedHash(hash);
}
interface IData {
/* eslint-disable camelcase */
gt_ms?: string;
e_c?: string;
e_a?: string;
e_n?: string;
e_v?: string;
ping?: string;
/* eslint-enable camelcase */
}
interface IVariable {
id: number;
expl: string; // explanation
example: string; // example value
getTextVariables?(): IVariables; // object to pass as 2nd argument to `_t`
}
const customVariables: Record<string, IVariable> = {
// The Matomo installation at https://matomo.riot.im is currently configured
// with a limit of 10 custom variables.
'App Platform': {
id: 1,
expl: _td('The platform you\'re on'),
example: 'Electron Platform',
},
'App Version': {
id: 2,
expl: _td('The version of %(brand)s'),
getTextVariables: () => ({
brand: SdkConfig.get().brand,
}),
example: '15.0.0',
},
'User Type': {
id: 3,
expl: _td('Whether or not you\'re logged in (we don\'t record your username)'),
example: 'Logged In',
},
'Chosen Language': {
id: 4,
expl: _td('Your language of choice'),
example: 'en',
},
'Instance': {
id: 5,
expl: _td('Which officially provided instance you are using, if any'),
example: 'app',
},
'RTE: Uses Richtext Mode': {
id: 6,
expl: _td('Whether or not you\'re using the Richtext mode of the Rich Text Editor'),
example: 'off',
},
'Homeserver URL': {
id: 7,
expl: _td('Your homeserver\'s URL'),
example: 'https://matrix.org',
},
'Touch Input': {
id: 8,
expl: _td("Whether you're using %(brand)s on a device where touch is the primary input mechanism"),
getTextVariables: () => ({
brand: SdkConfig.get().brand,
}),
example: 'false',
},
'Breadcrumbs': {
id: 9,
expl: _td("Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)"),
example: 'disabled',
},
'Installed PWA': {
id: 10,
expl: _td("Whether you're using %(brand)s as an installed Progressive Web App"),
getTextVariables: () => ({
brand: SdkConfig.get().brand,
}),
example: 'false',
},
};
function whitelistRedact(whitelist: string[], str: string): string {
if (whitelist.includes(str)) return str;
return '<redacted>';
}
const UID_KEY = "mx_Riot_Analytics_uid";
const CREATION_TS_KEY = "mx_Riot_Analytics_cts";
const VISIT_COUNT_KEY = "mx_Riot_Analytics_vc";
const LAST_VISIT_TS_KEY = "mx_Riot_Analytics_lvts";
function getUid(): string {
try {
let data = localStorage?.getItem(UID_KEY);
if (!data && localStorage) {
localStorage.setItem(UID_KEY, data = randomString(16));
}
return data;
} catch (e) {
logger.error("Analytics error: ", e);
return "";
}
}
const HEARTBEAT_INTERVAL = 30 * 1000; // seconds
export class Analytics {
private baseUrl: URL = null;
private visitVariables: Record<number, [string, string]> = {}; // {[id: number]: [name: string, value: string]}
private firstPage = true;
private heartbeatIntervalID: number = null;
private readonly creationTs: string;
private readonly lastVisitTs: string;
private readonly visitCount: string;
constructor() {
this.creationTs = localStorage && localStorage.getItem(CREATION_TS_KEY);
if (!this.creationTs && localStorage) {
localStorage.setItem(CREATION_TS_KEY, this.creationTs = String(new Date().getTime()));
}
this.lastVisitTs = localStorage && localStorage.getItem(LAST_VISIT_TS_KEY);
this.visitCount = localStorage && localStorage.getItem(VISIT_COUNT_KEY) || "0";
this.visitCount = String(parseInt(this.visitCount, 10) + 1); // increment
if (localStorage) {
localStorage.setItem(VISIT_COUNT_KEY, this.visitCount);
}
}
public get disabled() {
return !this.baseUrl;
}
public canEnable() {
const piwikConfig = SdkConfig.get("piwik");
let piwik: Optional<SnakedObject<Extract<IConfigOptions["piwik"], object>>>;
if (typeof piwikConfig === 'object') {
piwik = new SnakedObject(piwikConfig);
}
return navigator.doNotTrack !== "1" && piwik?.get("site_id");
}
/**
* Enable Analytics if initialized but disabled
* otherwise try and initalize, no-op if piwik config missing
*/
public async enable() {
if (!this.disabled) return;
if (!this.canEnable()) return;
const piwikConfig = SdkConfig.get("piwik");
let piwik: Optional<SnakedObject<Extract<IConfigOptions["piwik"], object>>>;
if (typeof piwikConfig === 'object') {
piwik = new SnakedObject(piwikConfig);
}
this.baseUrl = new URL("piwik.php", piwik.get("url"));
// set constants
this.baseUrl.searchParams.set("rec", "1"); // rec is required for tracking
this.baseUrl.searchParams.set("idsite", piwik.get("site_id")); // idsite is required for tracking
this.baseUrl.searchParams.set("apiv", "1"); // API version to use
this.baseUrl.searchParams.set("send_image", "0"); // we want a 204, not a tiny GIF
// set user parameters
this.baseUrl.searchParams.set("_id", getUid()); // uuid
this.baseUrl.searchParams.set("_idts", this.creationTs); // first ts
this.baseUrl.searchParams.set("_idvc", this.visitCount); // visit count
if (this.lastVisitTs) {
this.baseUrl.searchParams.set("_viewts", this.lastVisitTs); // last visit ts
}
const platform = PlatformPeg.get();
this.setVisitVariable('App Platform', platform.getHumanReadableName());
try {
this.setVisitVariable('App Version', await platform.getAppVersion());
} catch (e) {
this.setVisitVariable('App Version', 'unknown');
}
this.setVisitVariable('Chosen Language', getCurrentLanguage());
const hostname = window.location.hostname;
if (hostname === 'riot.im') {
this.setVisitVariable('Instance', window.location.pathname);
} else if (hostname.endsWith('.element.io')) {
this.setVisitVariable('Instance', hostname.replace('.element.io', ''));
}
let installedPWA = "unknown";
try {
// Known to work at least for desktop Chrome
installedPWA = String(window.matchMedia('(display-mode: standalone)').matches);
} catch (e) { }
this.setVisitVariable('Installed PWA', installedPWA);
let touchInput = "unknown";
try {
// MDN claims broad support across browsers
touchInput = String(window.matchMedia('(pointer: coarse)').matches);
} catch (e) { }
this.setVisitVariable('Touch Input', touchInput);
// start heartbeat
this.heartbeatIntervalID = window.setInterval(this.ping.bind(this), HEARTBEAT_INTERVAL);
}
/**
* Disable Analytics, stop the heartbeat and clear identifiers from localStorage
*/
public disable() {
if (this.disabled) return;
this.trackEvent('Analytics', 'opt-out');
window.clearInterval(this.heartbeatIntervalID);
this.baseUrl = null;
this.visitVariables = {};
localStorage.removeItem(UID_KEY);
localStorage.removeItem(CREATION_TS_KEY);
localStorage.removeItem(VISIT_COUNT_KEY);
localStorage.removeItem(LAST_VISIT_TS_KEY);
}
private async track(data: IData) {
if (this.disabled) return;
const now = new Date();
const params = {
...data,
url: getRedactedUrl(),
_cvar: JSON.stringify(this.visitVariables), // user custom vars
res: `${window.screen.width}x${window.screen.height}`, // resolution as WWWWxHHHH
rand: String(Math.random()).slice(2, 8), // random nonce to cache-bust
h: now.getHours(),
m: now.getMinutes(),
s: now.getSeconds(),
};
const url = new URL(this.baseUrl.toString()); // copy
for (const key in params) {
url.searchParams.set(key, params[key]);
}
try {
await window.fetch(url.toString(), {
method: "GET",
mode: "no-cors",
cache: "no-cache",
redirect: "follow",
});
} catch (e) {
logger.error("Analytics error: ", e);
}
}
public ping() {
this.track({
ping: "1",
});
localStorage.setItem(LAST_VISIT_TS_KEY, String(new Date().getTime())); // update last visit ts
}
public trackPageChange(generationTimeMs?: number) {
if (this.disabled) return;
if (this.firstPage) {
// De-duplicate first page
// router seems to hit the fn twice
this.firstPage = false;
return;
}
if (typeof generationTimeMs !== 'number') {
logger.warn('Analytics.trackPageChange: expected generationTimeMs to be a number');
// But continue anyway because we still want to track the change
}
this.track({
gt_ms: String(generationTimeMs),
});
}
public trackEvent(category: string, action: string, name?: string, value?: string) {
if (this.disabled) return;
this.track({
e_c: category,
e_a: action,
e_n: name,
e_v: value,
});
}
private setVisitVariable(key: keyof typeof customVariables, value: string) {
if (this.disabled) return;
this.visitVariables[customVariables[key].id] = [key, value];
}
public setLoggedIn(isGuest: boolean, homeserverUrl: string) {
if (this.disabled) return;
const piwikConfig = SdkConfig.get("piwik");
let piwik: Optional<SnakedObject<Extract<IConfigOptions["piwik"], object>>>;
if (typeof piwikConfig === 'object') {
piwik = new SnakedObject(piwikConfig);
}
if (!piwik) return;
const whitelistedHSUrls = piwik.get("whitelisted_hs_urls", "whitelistedHSUrls") || [];
this.setVisitVariable('User Type', isGuest ? 'Guest' : 'Logged In');
this.setVisitVariable('Homeserver URL', whitelistRedact(whitelistedHSUrls, homeserverUrl));
}
public setBreadcrumbs(state: boolean) {
if (this.disabled) return;
this.setVisitVariable('Breadcrumbs', state ? 'enabled' : 'disabled');
}
public showDetailsModal = () => {
let rows = [];
if (!this.disabled) {
rows = Object.values(this.visitVariables);
} else {
rows = Object.keys(customVariables).map(
(k) => [
k,
_t('e.g. %(exampleValue)s', { exampleValue: customVariables[k].example }),
],
);
}
const resolution = `${window.screen.width}x${window.screen.height}`;
const otherVariables = [
{
expl: _td('Every page you use in the app'),
value: _t(
'e.g. <CurrentPageURL>',
{},
{
CurrentPageURL: getRedactedUrl,
},
),
},
{ expl: _td('Your user agent'), value: navigator.userAgent },
{ expl: _td('Your device resolution'), value: resolution },
];
const piwikConfig = SdkConfig.get("piwik");
let piwik: Optional<SnakedObject<Extract<IConfigOptions["piwik"], object>>>;
if (typeof piwikConfig === 'object') {
piwik = new SnakedObject(piwikConfig);
}
const cookiePolicyUrl = piwik?.get("policy_url");
const cookiePolicyLink = _t(
"Our complete cookie policy can be found <CookiePolicyLink>here</CookiePolicyLink>.",
{},
{
"CookiePolicyLink": (sub) => {
return <a href={cookiePolicyUrl} target="_blank" rel="noreferrer noopener">{ sub }</a>;
},
});
Modal.createTrackedDialog('Analytics Details', '', ErrorDialog, {
title: _t('Analytics'),
description: <div className="mx_AnalyticsModal">
{ cookiePolicyUrl && <p>{ cookiePolicyLink }</p> }
<div>{ _t('Some examples of the information being sent to us to help make %(brand)s better includes:', {
brand: SdkConfig.get().brand,
}) }</div>
<table>
{ rows.map((row) => <tr key={row[0]}>
<td className="mx_AnalyticsModal_label">{ _t(
customVariables[row[0]].expl,
customVariables[row[0]].getTextVariables ?
customVariables[row[0]].getTextVariables() :
null,
) }</td>
{ row[1] !== undefined && <td><code>{ row[1] }</code></td> }
</tr>) }
{ otherVariables.map((item, index) =>
<tr key={index}>
<td>{ _t(item.expl) }</td>
<td><code>{ item.value }</code></td>
</tr>,
) }
</table>
<div>
{ _t('Where this page includes identifiable information, such as a room, '
+ 'user ID, that data is removed before being sent to the server.') }
</div>
</div>,
});
};
}
if (!window.mxAnalytics) {
window.mxAnalytics = new Analytics();
}
export default window.mxAnalytics;

View file

@ -47,7 +47,6 @@ import ErrorDialog from "./components/views/dialogs/ErrorDialog";
import WidgetStore from "./stores/WidgetStore";
import { WidgetMessagingStore } from "./stores/widgets/WidgetMessagingStore";
import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions";
import Analytics from './Analytics';
import { UIFeature } from "./settings/UIFeature";
import { Action } from './dispatcher/actions';
import VoipUserMapper from './VoipUserMapper';
@ -305,7 +304,6 @@ export default class CallHandler extends EventEmitter {
return;
}
Analytics.trackEvent('voip', 'receiveCall', 'type', call.type);
this.addCallForRoom(mappedRoomId, call);
this.setCallListeners(call);
// Explicitly handle first state change
@ -447,7 +445,6 @@ export default class CallHandler extends EventEmitter {
call.on(CallEvent.Error, (err: CallError) => {
if (!this.matchesCallForThisRoom(call)) return;
Analytics.trackEvent('voip', 'callError', 'error', err.toString());
logger.error("Call error:", err);
if (err.code === CallErrorCode.NoUserMedia) {
@ -463,7 +460,7 @@ export default class CallHandler extends EventEmitter {
return;
}
Modal.createTrackedDialog('Call Failed', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Call Failed'),
description: err.message,
});
@ -471,8 +468,6 @@ export default class CallHandler extends EventEmitter {
call.on(CallEvent.Hangup, () => {
if (!this.matchesCallForThisRoom(call)) return;
Analytics.trackEvent('voip', 'callHangup');
this.removeCallForRoom(mappedRoomId);
});
call.on(CallEvent.State, (newState: CallState, oldState: CallState) => {
@ -584,7 +579,6 @@ export default class CallHandler extends EventEmitter {
}
case CallState.Ended: {
const hangupReason = call.hangupReason;
Analytics.trackEvent('voip', 'callEnded', 'hangupReason', hangupReason);
this.removeCallForRoom(mappedRoomId);
if (oldState === CallState.InviteSent && call.hangupParty === CallParty.Remote) {
this.play(AudioID.Busy);
@ -603,13 +597,13 @@ export default class CallHandler extends EventEmitter {
description = _t("The call could not be established");
}
Modal.createTrackedDialog('Call Handler', 'Call Failed', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title, description,
});
} else if (
hangupReason === CallErrorCode.AnsweredElsewhere && oldState === CallState.Connecting
) {
Modal.createTrackedDialog('Call Handler', 'Call Failed', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Answered Elsewhere"),
description: _t("The call was answered on another device."),
});
@ -709,7 +703,7 @@ export default class CallHandler extends EventEmitter {
private showICEFallbackPrompt(): void {
const cli = MatrixClientPeg.get();
const code = sub => <code>{ sub }</code>;
Modal.createTrackedDialog('No TURN servers', '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t("Call failed due to misconfigured server"),
description: <div>
<p>{ _t(
@ -759,14 +753,12 @@ export default class CallHandler extends EventEmitter {
</div>;
}
Modal.createTrackedDialog('Media capture failed', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title, description,
}, null, true);
}
private async placeMatrixCall(roomId: string, type: CallType, transferee?: MatrixCall): Promise<void> {
Analytics.trackEvent('voip', 'placeCall', 'type', type);
const mappedRoomId = (await VoipUserMapper.sharedInstance().getOrCreateVirtualRoomForRoom(roomId)) || roomId;
logger.debug("Mapped real room " + roomId + " to room ID " + mappedRoomId);
@ -789,7 +781,7 @@ export default class CallHandler extends EventEmitter {
try {
this.addCallForRoom(roomId, call);
} catch (e) {
Modal.createTrackedDialog('Call Handler', 'Existing Call with user', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Already in call'),
description: _t("You're already in a call with this person."),
});
@ -821,7 +813,7 @@ export default class CallHandler extends EventEmitter {
// if the runtime env doesn't do VoIP, whine.
if (!MatrixClientPeg.get().supportsVoip()) {
Modal.createTrackedDialog('Call Handler', 'VoIP is unsupported', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Calls are unsupported'),
description: _t('You cannot place calls in this browser.'),
});
@ -829,7 +821,7 @@ export default class CallHandler extends EventEmitter {
}
if (MatrixClientPeg.get().getSyncState() === SyncState.Error) {
Modal.createTrackedDialog('Call Handler', 'Sync error', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Connectivity to the server has been lost'),
description: _t('You cannot place calls without a connection to the server.'),
});
@ -838,7 +830,7 @@ export default class CallHandler extends EventEmitter {
// don't allow > 2 calls to be placed.
if (this.getAllActiveCalls().length > 1) {
Modal.createTrackedDialog('Call Handler', 'Existing Call', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Too Many Calls'),
description: _t("You've reached the maximum number of simultaneous calls."),
});
@ -856,7 +848,7 @@ export default class CallHandler extends EventEmitter {
const members = room.getJoinedMembers();
if (members.length <= 1) {
Modal.createTrackedDialog('Call Handler', 'Cannot place call with self', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
description: _t('You cannot place a call with yourself.'),
});
} else if (members.length === 2) {
@ -901,7 +893,7 @@ export default class CallHandler extends EventEmitter {
if (!this.calls.has(roomId)) return;
if (this.getAllActiveCalls().length > 1) {
Modal.createTrackedDialog('Call Handler', 'Existing Call', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Too Many Calls'),
description: _t("You've reached the maximum number of simultaneous calls."),
});
@ -926,7 +918,7 @@ export default class CallHandler extends EventEmitter {
public async dialNumber(number: string, transferee?: MatrixCall): Promise<void> {
const results = await this.pstnLookup(number);
if (!results || results.length === 0 || !results[0].userid) {
Modal.createTrackedDialog('', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to look up phone number"),
description: _t("There was an error looking up the phone number"),
});
@ -969,7 +961,7 @@ export default class CallHandler extends EventEmitter {
const results = await this.pstnLookup(destination);
if (!results || results.length === 0 || !results[0].userid) {
Modal.createTrackedDialog('', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to transfer call"),
description: _t("There was an error looking up the phone number"),
});
@ -998,7 +990,7 @@ export default class CallHandler extends EventEmitter {
await call.transfer(destination);
} catch (e) {
logger.log("Failed to transfer call", e);
Modal.createTrackedDialog('Failed to transfer call', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Transfer Failed'),
description: _t('Failed to transfer call'),
});
@ -1036,7 +1028,6 @@ export default class CallHandler extends EventEmitter {
private async placeJitsiCall(roomId: string, type: CallType): Promise<void> {
const client = MatrixClientPeg.get();
logger.info(`Place conference call in ${roomId}`);
Analytics.trackEvent('voip', 'placeConferenceCall');
dis.dispatch({ action: 'appsDrawer', show: true });
@ -1053,7 +1044,7 @@ export default class CallHandler extends EventEmitter {
logger.log('Jitsi widget added');
} catch (e) {
if (e.errcode === 'M_FORBIDDEN') {
Modal.createTrackedDialog('Call Failed', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Permission Required'),
description: _t("You do not have permission to start a conference call in this room"),
});
@ -1062,29 +1053,6 @@ export default class CallHandler extends EventEmitter {
}
}
public terminateCallApp(roomId: string): void {
logger.info("Terminating conference call in " + roomId);
Modal.createTrackedDialog('Confirm Jitsi Terminate', '', QuestionDialog, {
hasCancelButton: true,
title: _t("End conference"),
description: _t("This will end the conference for everyone. Continue?"),
button: _t("End conference"),
onFinished: (proceed) => {
if (!proceed) return;
// We'll just obliterate them all. There should only ever be one, but might as well
// be safe.
const roomInfo = WidgetStore.instance.getRoom(roomId);
const jitsiWidgets = roomInfo.widgets.filter(w => WidgetType.JITSI.matches(w.type));
jitsiWidgets.forEach(w => {
// setting invalid content removes it
WidgetUtils.setRoomWidget(roomId, w.id);
});
},
});
}
public hangupCallApp(roomId: string): void {
logger.info("Leaving conference call in " + roomId);

View file

@ -397,7 +397,7 @@ export default class ContentMessages {
}
if (tooBigFiles.length > 0) {
const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Failure', '', UploadFailureDialog, {
const { finished } = Modal.createDialog<[boolean]>(UploadFailureDialog, {
badFiles: tooBigFiles,
totalFiles: files.length,
contentMessages: this,
@ -413,13 +413,11 @@ export default class ContentMessages {
for (let i = 0; i < okFiles.length; ++i) {
const file = okFiles[i];
if (!uploadAll) {
const { finished } = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation',
'', UploadConfirmDialog, {
file,
currentIndex: i,
totalFiles: okFiles.length,
},
);
const { finished } = Modal.createDialog<[boolean, boolean]>(UploadConfirmDialog, {
file,
currentIndex: i,
totalFiles: okFiles.length,
});
const [shouldContinue, shouldUploadAll] = await finished;
if (!shouldContinue) break;
if (shouldUploadAll) {
@ -588,7 +586,7 @@ export default class ContentMessages {
{ fileName: upload.fileName },
);
}
Modal.createTrackedDialog('Upload failed', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Upload Failed'),
description: desc,
});

View file

@ -18,7 +18,6 @@ import { MatrixError } from "matrix-js-sdk/src/http-api";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Error as ErrorEvent } from "@matrix-org/analytics-events/types/typescript/Error";
import Analytics from "./Analytics";
import { PosthogAnalytics } from './PosthogAnalytics';
export class DecryptionFailure {
@ -37,7 +36,6 @@ export type ErrCodeMapFn = (errcode: string) => ErrorCode;
export class DecryptionFailureTracker {
private static internalInstance = new DecryptionFailureTracker((total, errorCode, rawError) => {
Analytics.trackEvent('E2E', 'Decryption failure', errorCode, String(total));
for (let i = 0; i < total; i++) {
PosthogAnalytics.instance.trackEvent<ErrorEvent>({
eventName: "Error",

View file

@ -135,18 +135,15 @@ export interface IConfigOptions {
servers: string[];
};
// piwik (matomo) is deprecated in favour of posthog
piwik?: false | {
url: string; // piwik instance
site_id: string;
policy_url: string; // cookie policy
whitelisted_hs_urls: string[];
policy_url: string; // deprecated in favour of `privacy_policy_url` at root instead
};
posthog?: {
project_api_key: string;
api_host: string; // hostname
};
analytics_owner?: string; // defaults to `brand`
privacy_policy_url?: string; // location for cookie policy
// Server hosting upsell options
hosting_signup_link?: string; // slightly different from `host_signup`

View file

@ -143,27 +143,25 @@ export default class IdentityAuthClient {
!doesAccountDataHaveIdentityServer() &&
!(await doesIdentityServerHaveTerms(identityServerUrl))
) {
const { finished } = Modal.createTrackedDialog(
'Default identity server terms warning', '',
QuestionDialog, {
title: _t("Identity server has no terms of service"),
description: (
<div>
<p>{ _t(
"This action requires accessing the default identity server " +
"<server /> to validate an email address or phone number, " +
"but the server does not have any terms of service.", {},
{
server: () => <b>{ abbreviateUrl(identityServerUrl) }</b>,
},
) }</p>
<p>{ _t(
"Only continue if you trust the owner of the server.",
) }</p>
</div>
),
button: _t("Trust"),
});
const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("Identity server has no terms of service"),
description: (
<div>
<p>{ _t(
"This action requires accessing the default identity server " +
"<server /> to validate an email address or phone number, " +
"but the server does not have any terms of service.", {},
{
server: () => <b>{ abbreviateUrl(identityServerUrl) }</b>,
},
) }</p>
<p>{ _t(
"Only continue if you trust the owner of the server.",
) }</p>
</div>
),
button: _t("Trust"),
});
const [confirmed] = await finished;
if (confirmed) {
// eslint-disable-next-line react-hooks/rules-of-hooks

View file

@ -28,7 +28,6 @@ import { IMatrixClientCreds, MatrixClientPeg } from './MatrixClientPeg';
import SecurityCustomisations from "./customisations/Security";
import EventIndexPeg from './indexing/EventIndexPeg';
import createMatrixClient from './utils/createMatrixClient';
import Analytics from './Analytics';
import Notifier from './Notifier';
import UserActivity from './UserActivity';
import Presence from './Presence';
@ -201,7 +200,7 @@ export function attemptTokenLogin(
const identityServer = localStorage.getItem(SSO_ID_SERVER_URL_KEY);
if (!homeserver) {
logger.warn("Cannot log in with token: can't determine HS URL to use");
Modal.createTrackedDialog("SSO", "Unknown HS", ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("We couldn't log you in"),
description: _t("We asked the browser to remember which homeserver you use to let you sign in, " +
"but unfortunately your browser has forgotten it. Go to the sign in page and try again."),
@ -226,7 +225,7 @@ export function attemptTokenLogin(
return true;
});
}).catch((err) => {
Modal.createTrackedDialog("SSO", "Token Rejected", ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("We couldn't log you in"),
description: err.name === "ConnectionError"
? _t("Your homeserver was unreachable and was not able to log you in. Please try again. " +
@ -470,7 +469,7 @@ export async function restoreFromLocalStorage(opts?: { ignoreGuest?: boolean }):
async function handleLoadSessionFailure(e: Error): Promise<boolean> {
logger.error("Unable to load session", e);
const modal = Modal.createTrackedDialog('Session Restore Error', '', SessionRestoreErrorDialog, {
const modal = Modal.createDialog(SessionRestoreErrorDialog, {
error: e,
});
@ -597,8 +596,6 @@ async function doSetLoggedIn(
await abortLogin();
}
Analytics.setLoggedIn(credentials.guest, credentials.homeserverUrl);
MatrixClientPeg.replaceUsingCreds(credentials);
setSentryUser(credentials.userId);
@ -640,7 +637,7 @@ async function doSetLoggedIn(
function showStorageEvictedDialog(): Promise<boolean> {
return new Promise(resolve => {
Modal.createTrackedDialog('Storage evicted', '', StorageEvictedDialog, {
Modal.createDialog(StorageEvictedDialog, {
onFinished: resolve,
});
});
@ -880,8 +877,6 @@ export async function onLoggedOut(): Promise<void> {
* @returns {Promise} promise which resolves once the stores have been cleared
*/
async function clearStorage(opts?: { deleteEverything?: boolean }): Promise<void> {
Analytics.disable();
if (window.localStorage) {
// try to save any 3pid invites from being obliterated and registration time
const pendingInvites = ThreepidInviteStore.instance.getWireInvites();

View file

@ -193,8 +193,6 @@ class MatrixClientPegClass implements IMatrixClientPeg {
}
}
StorageManager.trackStores(this.matrixClient);
// try to initialise e2e on the new client
try {
// check that we have a version of the js-sdk which includes initCrypto

View file

@ -20,7 +20,6 @@ import ReactDOM from 'react-dom';
import classNames from 'classnames';
import { defer, sleep } from "matrix-js-sdk/src/utils";
import Analytics from './Analytics';
import dis from './dispatcher/dispatcher';
import AsyncWrapper from './AsyncWrapper';
@ -103,24 +102,6 @@ export class ModalManager {
return this.priorityModal || this.staticModal || this.modals.length > 0;
}
public createTrackedDialog<T extends any[]>(
analyticsAction: string,
analyticsInfo: string,
...rest: Parameters<ModalManager["createDialog"]>
) {
Analytics.trackEvent('Modal', analyticsAction, analyticsInfo);
return this.createDialog<T>(...rest);
}
public appendTrackedDialog<T extends any[]>(
analyticsAction: string,
analyticsInfo: string,
...rest: Parameters<ModalManager["appendDialog"]>
) {
Analytics.trackEvent('Modal', analyticsAction, analyticsInfo);
return this.appendDialog<T>(...rest);
}
public createDialog<T extends any[]>(
Element: React.ComponentType,
...rest: ParametersWithoutFirst<ModalManager["createDialogAsync"]>
@ -135,24 +116,6 @@ export class ModalManager {
return this.appendDialogAsync<T>(Promise.resolve(Element), ...rest);
}
public createTrackedDialogAsync<T extends any[]>(
analyticsAction: string,
analyticsInfo: string,
...rest: Parameters<ModalManager["createDialogAsync"]>
) {
Analytics.trackEvent('Modal', analyticsAction, analyticsInfo);
return this.createDialogAsync<T>(...rest);
}
public appendTrackedDialogAsync<T extends any[]>(
analyticsAction: string,
analyticsInfo: string,
...rest: Parameters<ModalManager["appendDialogAsync"]>
) {
Analytics.trackEvent('Modal', analyticsAction, analyticsInfo);
return this.appendDialogAsync<T>(...rest);
}
public closeCurrentModal(reason: string) {
const modal = this.getCurrentModal();
if (!modal) {
@ -273,7 +236,7 @@ export class ModalManager {
* @param {onBeforeClose} options.onBeforeClose a callback to decide whether to close the dialog
* @returns {object} Object with 'close' parameter being a function that will close the dialog
*/
private createDialogAsync<T extends any[]>(
public createDialogAsync<T extends any[]>(
prom: Promise<React.ComponentType>,
props?: IProps<T>,
className?: string,

View file

@ -28,7 +28,6 @@ import { MatrixClientPeg } from './MatrixClientPeg';
import SdkConfig from './SdkConfig';
import PlatformPeg from './PlatformPeg';
import * as TextForEvent from './TextForEvent';
import Analytics from './Analytics';
import * as Avatar from './Avatar';
import dis from './dispatcher/dispatcher';
import { _t } from './languageHandler';
@ -230,8 +229,6 @@ export const Notifier = {
// calculated value. It is determined based upon whether or not the master rule is enabled
// and other flags. Setting it here would cause a circular reference.
Analytics.trackEvent('Notifier', 'Set Enabled', String(enable));
// make sure that we persist the current setting audio_enabled setting
// before changing anything
if (SettingsStore.isLevelSupported(SettingLevel.DEVICE)) {
@ -249,7 +246,7 @@ export const Notifier = {
? _t('%(brand)s does not have permission to send you notifications - ' +
'please check your browser settings', { brand })
: _t('%(brand)s was not given permission to send notifications - please try again', { brand });
Modal.createTrackedDialog('Unable to enable Notifications', result, ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Unable to enable Notifications'),
description,
});
@ -298,8 +295,6 @@ export const Notifier = {
setPromptHidden: function(hidden: boolean, persistent = true) {
this.toolbarHidden = hidden;
Analytics.trackEvent('Notifier', 'Set Toolbar Hidden', String(hidden));
hideNotificationsToast();
// update the info to localStorage for persistent settings

View file

@ -49,7 +49,7 @@ export async function startAnyRegistrationFlow(
options: { go_home_on_cancel?: boolean, go_welcome_on_cancel?: boolean, screen_after?: boolean},
): Promise<void> {
if (options === undefined) options = {};
const modal = Modal.createTrackedDialog('Registration required', '', QuestionDialog, {
const modal = Modal.createDialog(QuestionDialog, {
hasCancelButton: true,
quitOnly: true,
title: _t("Sign In or Create Account"),

View file

@ -61,16 +61,16 @@ export function inviteMultipleToRoom(
export function showStartChatInviteDialog(initialText = ""): void {
// This dialog handles the room creation internally - we don't need to worry about it.
Modal.createTrackedDialog(
'Start DM', '', InviteDialog, { kind: KIND_DM, initialText },
Modal.createDialog(
InviteDialog, { kind: KIND_DM, initialText },
/*className=*/"mx_InviteDialog_flexWrapper", /*isPriority=*/false, /*isStatic=*/true,
);
}
export function showRoomInviteDialog(roomId: string, initialText = ""): void {
// This dialog handles the room creation internally - we don't need to worry about it.
Modal.createTrackedDialog(
"Invite Users", "", InviteDialog, {
Modal.createDialog(
InviteDialog, {
kind: KIND_INVITE,
initialText,
roomId,
@ -108,7 +108,7 @@ export function inviteUsersToRoom(
showAnyInviteErrors(result.states, room, result.inviter);
}).catch((err) => {
logger.error(err.stack);
Modal.createTrackedDialog('Failed to invite', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Failed to invite"),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
@ -127,7 +127,7 @@ export function showAnyInviteErrors(
// Just get the first message because there was a fatal problem on the first
// user. This usually means that no other users were attempted, making it
// pointless for us to list who failed exactly.
Modal.createTrackedDialog('Failed to invite users to the room', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Failed to invite users to %(roomName)s", { roomName: room.name }),
description: inviter.getErrorText(failedUsers[0]),
});
@ -175,7 +175,7 @@ export function showAnyInviteErrors(
</div>
</div>;
Modal.createTrackedDialog("Some invites could not be sent", "", ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Some invites couldn't be sent"),
description,
});

View file

@ -150,7 +150,7 @@ async function getSecretStorageKey(
}
const inputToKey = makeInputToKey(keyInfo);
const { finished } = Modal.createTrackedDialog("Access Secret Storage dialog", "",
const { finished } = Modal.createDialog(
AccessSecretStorageDialog,
/* props= */
{
@ -195,7 +195,7 @@ export async function getDehydrationKey(
}
const inputToKey = makeInputToKey(keyInfo);
const { finished } = Modal.createTrackedDialog("Access Secret Storage dialog", "",
const { finished } = Modal.createDialog(
AccessSecretStorageDialog,
/* props= */
{
@ -298,7 +298,7 @@ export const crossSigningCallbacks: ICryptoCallbacks = {
export async function promptForBackupPassphrase(): Promise<Uint8Array> {
let key: Uint8Array;
const { finished } = Modal.createTrackedDialog('Restore Backup', '', RestoreKeyBackupDialog, {
const { finished } = Modal.createDialog(RestoreKeyBackupDialog, {
showSummary: false, keyCallback: k => key = k,
}, null, /* priority = */ false, /* static = */ true);
@ -336,7 +336,7 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f
if (!(await cli.hasSecretStorageKey()) || forceReset) {
// This dialog calls bootstrap itself after guiding the user through
// passphrase creation.
const { finished } = Modal.createTrackedDialogAsync('Create Secret Storage dialog', '',
const { finished } = Modal.createDialogAsync(
import(
"./async-components/views/dialogs/security/CreateSecretStorageDialog"
) as unknown as Promise<ComponentType<{}>>,
@ -363,14 +363,11 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f
} else {
await cli.bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (makeRequest) => {
const { finished } = Modal.createTrackedDialog(
'Cross-signing keys dialog', '', InteractiveAuthDialog,
{
title: _t("Setting up keys"),
matrixClient: cli,
makeRequest,
},
);
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
title: _t("Setting up keys"),
matrixClient: cli,
makeRequest,
});
const [confirmed] = await finished;
if (!confirmed) {
throw new Error("Cross-signing key upload auth canceled");

View file

@ -82,7 +82,7 @@ const singleMxcUpload = async (): Promise<any> => {
fileSelector.onchange = (ev: HTMLInputEvent) => {
const file = ev.target.files[0];
Modal.createTrackedDialog('Upload Files confirmation', '', UploadConfirmDialog, {
Modal.createDialog(UploadConfirmDialog, {
file,
onFinished: (shouldContinue) => {
resolve(shouldContinue ? MatrixClientPeg.get().uploadContent(file) : null);
@ -307,7 +307,7 @@ export const Commands = [
);
}
const { finished } = Modal.createTrackedDialog('Slash Commands', 'upgrade room confirmation',
const { finished } = Modal.createDialog(
RoomUpgradeWarningDialog, { roomId: roomId, targetVersion: args }, /*className=*/null,
/*isPriority=*/false, /*isStatic=*/true);
@ -483,7 +483,7 @@ export const Commands = [
const ref = e => e && linkifyElement(e);
const body = topicToHtml(topic.text, topic.html, ref, true);
Modal.createTrackedDialog('Slash Commands', 'Topic', InfoDialog, {
Modal.createDialog(InfoDialog, {
title: room.name,
description: <div ref={ref}>{ body }</div>,
hasCloseButton: true,
@ -529,22 +529,18 @@ export const Commands = [
) {
const defaultIdentityServerUrl = getDefaultIdentityServerUrl();
if (defaultIdentityServerUrl) {
const { finished } = Modal.createTrackedDialog<[boolean]>(
'Slash Commands',
'Identity server',
QuestionDialog, {
title: _t("Use an identity server"),
description: <p>{ _t(
"Use an identity server to invite by email. " +
"Click continue to use the default identity server " +
"(%(defaultIdentityServerName)s) or manage in Settings.",
{
defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl),
},
) }</p>,
button: _t("Continue"),
},
);
const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, {
title: _t("Use an identity server"),
description: <p>{ _t(
"Use an identity server to invite by email. " +
"Click continue to use the default identity server " +
"(%(defaultIdentityServerName)s) or manage in Settings.",
{
defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl),
},
) }</p>,
button: _t("Continue"),
});
prom = finished.then(([useDefault]) => {
if (useDefault) {
@ -810,7 +806,7 @@ export const Commands = [
ignoredUsers.push(userId); // de-duped internally in the js-sdk
return success(
cli.setIgnoredUsers(ignoredUsers).then(() => {
Modal.createTrackedDialog('Slash Commands', 'User ignored', InfoDialog, {
Modal.createDialog(InfoDialog, {
title: _t('Ignored user'),
description: <div>
<p>{ _t('You are now ignoring %(userId)s', { userId }) }</p>
@ -840,7 +836,7 @@ export const Commands = [
if (index !== -1) ignoredUsers.splice(index, 1);
return success(
cli.setIgnoredUsers(ignoredUsers).then(() => {
Modal.createTrackedDialog('Slash Commands', 'User unignored', InfoDialog, {
Modal.createDialog(InfoDialog, {
title: _t('Unignored user'),
description: <div>
<p>{ _t('You are no longer ignoring %(userId)s', { userId }) }</p>
@ -1040,7 +1036,7 @@ export const Commands = [
await cli.setDeviceVerified(userId, deviceId, true);
// Tell the user we verified everything
Modal.createTrackedDialog('Slash Commands', 'Verified key', InfoDialog, {
Modal.createDialog(InfoDialog, {
title: _t('Verified key'),
description: <div>
<p>
@ -1098,7 +1094,7 @@ export const Commands = [
command: "help",
description: _td("Displays list of commands with usages and descriptions"),
runFn: function() {
Modal.createTrackedDialog('Slash Commands', 'Help', SlashCommandHelpDialog);
Modal.createDialog(SlashCommandHelpDialog);
return success();
},
category: CommandCategories.advanced,
@ -1130,7 +1126,7 @@ export const Commands = [
args: "<description>",
runFn: function(roomId, args) {
return success(
Modal.createTrackedDialog('Slash Commands', 'Bug Report Dialog', BugReportDialog, {
Modal.createDialog(BugReportDialog, {
initialText: args,
}).finished,
);

View file

@ -190,7 +190,7 @@ export async function dialogTermsInteractionCallback(
): Promise<string[]> {
logger.log("Terms that need agreement", policiesAndServicePairs);
const { finished } = Modal.createTrackedDialog<[boolean, string[]]>('Terms of Service', '', TermsDialog, {
const { finished } = Modal.createDialog<[boolean, string[]]>(TermsDialog, {
policiesAndServicePairs,
agreedUrls,
}, classNames("mx_TermsDialog", extraClassNames));

View file

@ -91,7 +91,7 @@ export default class RoomListActions {
room, newTag === DefaultTagID.DM,
).catch((err) => {
logger.error("Failed to set DM tag " + err);
Modal.createTrackedDialog('Failed to set direct message tag', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Failed to set direct message tag'),
description: ((err && err.message) ? err.message : _t('Operation failed')),
});
@ -111,7 +111,7 @@ export default class RoomListActions {
roomId, oldTag,
).catch(function(err) {
logger.error("Failed to remove tag " + oldTag + " from room: " + err);
Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Failed to remove tag %(tagName)s from room', { tagName: oldTag }),
description: ((err && err.message) ? err.message : _t('Operation failed')),
});
@ -130,7 +130,7 @@ export default class RoomListActions {
const promiseToAdd = matrixClient.setRoomTag(roomId, newTag, metaData).catch(function(err) {
logger.error("Failed to add tag " + newTag + " to room: " + err);
Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Failed to add tag %(tagName)s to room', { tagName: newTag }),
description: ((err && err.message) ? err.message : _t('Operation failed')),
});

View file

@ -134,10 +134,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
private onDisable = async () => {
const DisableEventIndexDialog = (await import("./DisableEventIndexDialog")).default;
Modal.createTrackedDialog("Disable message search", "Disable message search",
DisableEventIndexDialog,
null, null, /* priority = */ false, /* static = */ true,
);
Modal.createDialog(DisableEventIndexDialog, null, null, /* priority = */ false, /* static = */ true);
};
private onCrawlerSleepTimeChange = (e) => {

View file

@ -303,18 +303,15 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
},
};
const { finished } = Modal.createTrackedDialog(
'Cross-signing keys dialog', '', InteractiveAuthDialog,
{
title: _t("Setting up keys"),
matrixClient: MatrixClientPeg.get(),
makeRequest,
aestheticsForStagePhases: {
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
},
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
title: _t("Setting up keys"),
matrixClient: MatrixClientPeg.get(),
makeRequest,
aestheticsForStagePhases: {
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
},
);
});
const [confirmed] = await finished;
if (!confirmed) {
throw new Error("Cross-signing key upload auth canceled");
@ -390,14 +387,10 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
// so let's stash it here, rather than prompting for it twice.
const keyCallback = k => this.backupKey = k;
const { finished } = Modal.createTrackedDialog(
'Restore Backup', '', RestoreKeyBackupDialog,
{
showSummary: false,
keyCallback,
},
null, /* priority = */ false, /* static = */ false,
);
const { finished } = Modal.createDialog(RestoreKeyBackupDialog, {
showSummary: false,
keyCallback,
}, null, /* priority = */ false, /* static = */ false);
await finished;
const { backupSigStatus } = await this.fetchBackupInfo();

View file

@ -43,11 +43,9 @@ export default class NewRecoveryMethodDialog extends React.PureComponent<IProps>
};
private onSetupClick = async (): Promise<void> => {
Modal.createTrackedDialog(
'Restore Backup', '', RestoreKeyBackupDialog, {
onFinished: this.props.onFinished,
}, null, /* priority = */ false, /* static = */ true,
);
Modal.createDialog(RestoreKeyBackupDialog, {
onFinished: this.props.onFinished,
}, null, /* priority = */ false, /* static = */ true);
};
public render(): JSX.Element {

View file

@ -35,7 +35,7 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent<IPr
private onSetupClick = (): void => {
this.props.onFinished();
Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
Modal.createDialogAsync(
import("./CreateKeyBackupDialog") as unknown as Promise<ComponentType<{}>>,
null, null, /* priority = */ false, /* static = */ true,
);

View file

@ -30,24 +30,20 @@ import { UPDATE_EVENT } from "../../stores/AsyncStore";
import { useEventEmitter } from "../../hooks/useEventEmitter";
import MatrixClientContext from "../../contexts/MatrixClientContext";
import MiniAvatarUploader, { AVATAR_SIZE } from "../views/elements/MiniAvatarUploader";
import Analytics from "../../Analytics";
import PosthogTrackers from "../../PosthogTrackers";
import EmbeddedPage from "./EmbeddedPage";
const onClickSendDm = (ev: ButtonEvent) => {
Analytics.trackEvent('home_page', 'button', 'dm');
PosthogTrackers.trackInteraction("WebHomeCreateChatButton", ev);
dis.dispatch({ action: 'view_create_chat' });
};
const onClickExplore = (ev: ButtonEvent) => {
Analytics.trackEvent('home_page', 'button', 'room_directory');
PosthogTrackers.trackInteraction("WebHomeExploreRoomsButton", ev);
dis.fire(Action.ViewRoomDirectory);
};
const onClickNewRoom = (ev: ButtonEvent) => {
Analytics.trackEvent('home_page', 'button', 'create_room');
PosthogTrackers.trackInteraction("WebHomeCreateRoomButton", ev);
dis.dispatch({ action: 'view_create_room' });
};

View file

@ -39,7 +39,6 @@ import 'focus-visible';
import 'what-input';
import PosthogTrackers from '../../PosthogTrackers';
import Analytics from "../../Analytics";
import { DecryptionFailureTracker } from "../../DecryptionFailureTracker";
import { IMatrixClientCreds, MatrixClientPeg } from "../../MatrixClientPeg";
import PlatformPeg from "../../PlatformPeg";
@ -73,8 +72,7 @@ import LoggedInView from './LoggedInView';
import { Action } from "../../dispatcher/actions";
import {
hideToast as hideAnalyticsToast,
showAnonymousAnalyticsOptInToast,
showPseudonymousAnalyticsOptInToast,
showToast as showAnalyticsToast,
} from "../../toasts/AnalyticsToast";
import { showToast as showNotificationsToast } from "../../toasts/DesktopNotificationsToast";
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
@ -344,10 +342,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
});
}
if (SettingsStore.getValue("pseudonymousAnalyticsOptIn")) {
Analytics.enable();
}
initSentry(SdkConfig.get("sentry"));
}
@ -406,7 +400,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
componentDidUpdate(prevProps, prevState) {
if (this.shouldTrackPageChange(prevState, this.state)) {
const durationMs = this.stopPageChangeTimer();
Analytics.trackPageChange(durationMs);
PosthogTrackers.instance.trackPageChange(this.state.view, this.state.page_type, durationMs);
}
if (this.focusComposer) {
@ -625,7 +618,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.copyRoom(payload.room_id);
break;
case 'reject_invite':
Modal.createTrackedDialog('Reject invitation', '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t('Reject invitation'),
description: _t('Are you sure you want to reject the invitation?'),
onFinished: (confirm) => {
@ -640,7 +633,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}
}, (err) => {
modal.close();
Modal.createTrackedDialog('Failed to reject invitation', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Failed to reject invitation'),
description: err.toString(),
});
@ -684,7 +677,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
break;
case Action.ViewUserSettings: {
const tabPayload = payload as OpenToTabPayload;
Modal.createTrackedDialog('User settings', '', UserSettingsDialog,
Modal.createDialog(UserSettingsDialog,
{ initialTabId: tabPayload.initialTabId },
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
@ -699,7 +692,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.viewSomethingBehindModal();
break;
case Action.ViewRoomDirectory: {
Modal.createTrackedDialog('Room directory', '', RoomDirectory, {
Modal.createDialog(RoomDirectory, {
initialText: payload.initialText,
}, 'mx_RoomDirectory_dialogWrapper', false, true);
@ -756,7 +749,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
});
break;
case Action.OpenDialPad:
Modal.createTrackedDialog('Dial pad', '', DialPadModal, {}, "mx_Dialog_dialPadWrapper");
Modal.createDialog(DialPadModal, {}, "mx_Dialog_dialPadWrapper");
break;
case Action.OnLoggedIn:
if (
@ -801,19 +794,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
hideToSRUsers: false,
});
break;
case Action.AnonymousAnalyticsAccept:
hideAnalyticsToast();
SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, true);
SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false);
if (Analytics.canEnable()) {
Analytics.enable();
}
break;
case Action.AnonymousAnalyticsReject:
hideAnalyticsToast();
SettingsStore.setValue("analyticsOptIn", null, SettingLevel.DEVICE, false);
SettingsStore.setValue("showCookieBar", null, SettingLevel.DEVICE, false);
break;
case Action.PseudonymousAnalyticsAccept:
hideAnalyticsToast();
SettingsStore.setValue("pseudonymousAnalyticsOptIn", null, SettingLevel.ACCOUNT, true);
@ -1009,7 +989,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}
private async createRoom(defaultPublic = false, defaultName?: string, type?: RoomType) {
const modal = Modal.createTrackedDialog('Create Room', '', CreateRoomDialog, {
const modal = Modal.createDialog(CreateRoomDialog, {
type,
defaultPublic,
defaultName,
@ -1112,7 +1092,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
const warnings = this.leaveRoomWarnings(roomId);
const isSpace = roomToLeave?.isSpaceRoom();
Modal.createTrackedDialog(isSpace ? "Leave space" : "Leave room", '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: isSpace ? _t("Leave space") : _t("Leave room"),
description: (
<span>
@ -1156,7 +1136,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
RoomListStore.instance.manualRoomUpdate(room, RoomUpdateCause.RoomRemoved);
}).catch((err) => {
const errCode = err.errcode || _td("unknown error code");
Modal.createTrackedDialog("Failed to forget room", '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Failed to forget room %(errCode)s", { errCode }),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
@ -1167,7 +1147,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
const roomLink = makeRoomPermalink(roomId);
const success = await copyPlaintext(roomLink);
if (!success) {
Modal.createTrackedDialog("Unable to copy room link", "", ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to copy room link"),
description: _t("Unable to copy a link to the room to the clipboard."),
});
@ -1271,8 +1251,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
if (PosthogAnalytics.instance.isEnabled() && SettingsStore.isLevelSupported(SettingLevel.ACCOUNT)) {
this.initPosthogAnalyticsToast();
} else if (Analytics.canEnable() && SettingsStore.getValue("showCookieBar")) {
showAnonymousAnalyticsOptInToast();
}
if (SdkConfig.get("mobile_guide_toast")) {
@ -1282,14 +1260,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}
}
private showPosthogToast(analyticsOptIn: boolean) {
showPseudonymousAnalyticsOptInToast(analyticsOptIn);
}
private initPosthogAnalyticsToast() {
// Show the analytics toast if necessary
if (SettingsStore.getValue("pseudonymousAnalyticsOptIn") === null) {
this.showPosthogToast(SettingsStore.getValue("analyticsOptIn", null, true));
showAnalyticsToast();
}
// Listen to changes in settings and show the toast if appropriate - this is necessary because account
@ -1298,7 +1272,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
SettingsStore.watchSetting("pseudonymousAnalyticsOptIn", null,
(originalSettingName, changedInRoomId, atLevel, newValueAtLevel, newValue) => {
if (newValue === null) {
this.showPosthogToast(SettingsStore.getValue("analyticsOptIn", null, true));
showAnalyticsToast();
} else {
// It's possible for the value to change if a cached sync loads at page load, but then network
// sync contains a new value of the flag with it set to false (e.g. another device set it since last
@ -1478,7 +1452,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
return;
}
Modal.createTrackedDialog('Signed out', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Signed Out'),
description: _t('For security, this session has been signed out. Please sign in again.'),
});
@ -1488,7 +1462,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
});
});
cli.on(HttpApiEvent.NoConsent, function(message, consentUri) {
Modal.createTrackedDialog('No Consent Dialog', '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t('Terms and Conditions'),
description: <div>
<p> { _t(
@ -1535,7 +1509,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
cli.on(CryptoEvent.Warning, (type) => {
switch (type) {
case 'CRYPTO_WARNING_OLD_VERSION_DETECTED':
Modal.createTrackedDialog('Crypto migrated', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Old cryptography data detected'),
description: _t(
"Data from an older version of %(brand)s has been detected. " +
@ -1569,14 +1543,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}
if (haveNewVersion) {
Modal.createTrackedDialogAsync('New Recovery Method', 'New Recovery Method',
Modal.createDialogAsync(
import(
'../../async-components/views/dialogs/security/NewRecoveryMethodDialog'
) as unknown as Promise<ComponentType<{}>>,
{ newVersionInfo },
);
} else {
Modal.createTrackedDialogAsync('Recovery Method Removed', 'Recovery Method Removed',
Modal.createDialogAsync(
import(
'../../async-components/views/dialogs/security/RecoveryMethodRemovedDialog'
) as unknown as Promise<ComponentType<{}>>,
@ -1585,16 +1559,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
});
cli.on(CryptoEvent.KeySignatureUploadFailure, (failures, source, continuation) => {
Modal.createTrackedDialog(
'Failed to upload key signatures',
'Failed to upload key signatures',
Modal.createDialog(
KeySignatureUploadFailedDialog,
{ failures, source, continuation });
});
cli.on(CryptoEvent.VerificationRequest, request => {
if (request.verifier) {
Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, {
Modal.createDialog(IncomingSasDialog, {
verifier: request.verifier,
}, null, /* priority = */ false, /* static = */ true);
} else if (request.pending) {

View file

@ -27,7 +27,6 @@ import Modal from "../../Modal";
import { _t } from '../../languageHandler';
import SdkConfig from '../../SdkConfig';
import { instanceForInstanceId, protocolNameForInstanceId, ALL_ROOMS, Protocols } from '../../utils/DirectoryUtils';
import Analytics from '../../Analytics';
import NetworkDropdown from "../views/directory/NetworkDropdown";
import SettingsStore from "../../settings/SettingsStore";
import { IDialogProps } from "../views/dialogs/IDialogProps";
@ -47,10 +46,6 @@ import { GenericError } from "../../utils/error";
const LAST_SERVER_KEY = "mx_last_room_directory_server";
const LAST_INSTANCE_KEY = "mx_last_room_directory_instance";
function track(action: string) {
Analytics.trackEvent('RoomDirectory', action);
}
interface IProps extends IDialogProps {
initialText?: string;
}
@ -121,7 +116,6 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
// thing you see when loading the client!
return;
}
track('Failed to get protocol list from homeserver');
const brand = SdkConfig.get().brand;
this.setState({
error: _t(
@ -225,7 +219,6 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
}
logger.error("Failed to get publicRooms: %s", JSON.stringify(err));
track('Failed to get public room list');
const brand = SdkConfig.get().brand;
this.setState({
loading: false,
@ -255,7 +248,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
desc = _t('Remove %(name)s from the directory?', { name: name });
}
Modal.createTrackedDialog('Remove from Directory', '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t('Remove from Directory'),
description: desc,
onFinished: (shouldDelete: boolean) => {
@ -275,7 +268,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
modal.close();
this.refreshRoomList();
logger.error("Failed to " + step + ": " + err);
Modal.createTrackedDialog('Remove from Directory Error', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Error'),
description: (err && err.message)
? err.message
@ -360,7 +353,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
});
} catch (e) {
if (e instanceof GenericError) {
Modal.createTrackedDialog(e.message, '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: e.message,
description: e.description,
});

View file

@ -104,7 +104,7 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
};
private openSpotlight() {
Modal.createTrackedDialog("Spotlight", "", SpotlightDialog, {}, "mx_SpotlightDialog_wrapper", false, true);
Modal.createDialog(SpotlightDialog, {}, "mx_SpotlightDialog_wrapper", false, true);
}
private onAction = (payload: ActionPayload) => {

View file

@ -1397,7 +1397,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
});
}, (error) => {
logger.error("Search failed", error);
Modal.createTrackedDialog('Search failed', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Search failed"),
description: ((error && error.message) ? error.message :
_t("Server may be unavailable, overloaded, or search timed out :(")),
@ -1522,7 +1522,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
logger.error("Failed to reject invite: %s", error);
const msg = error.message ? error.message : JSON.stringify(error);
Modal.createTrackedDialog('Failed to reject invite', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Failed to reject invite"),
description: msg,
});
@ -1555,7 +1555,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
logger.error("Failed to reject invite: %s", error);
const msg = error.message ? error.message : JSON.stringify(error);
Modal.createTrackedDialog('Failed to reject invite', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Failed to reject invite"),
description: msg,
});

View file

@ -234,7 +234,7 @@ const ThreadPanel: React.FC<IProps> = ({
}, [timelineSet, timelinePanel]);
const openFeedback = SdkConfig.get().bug_report_endpoint_url ? () => {
Modal.createTrackedDialog("Threads Feedback", "feature_thread", BetaFeedbackDialog, {
Modal.createDialog(BetaFeedbackDialog, {
featureId: "feature_thread",
});
} : null;

View file

@ -1353,7 +1353,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
);
}
Modal.createTrackedDialog('Failed to load timeline position', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Failed to load timeline position"),
description,
onFinished,

View file

@ -229,7 +229,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
ev.preventDefault();
ev.stopPropagation();
Modal.createTrackedDialog('Feedback Dialog', '', FeedbackDialog);
Modal.createDialog(FeedbackDialog);
this.setState({ contextMenuPosition: null }); // also close the menu
};
@ -242,7 +242,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
// log out without user prompt if they have no local megolm sessions
defaultDispatcher.dispatch({ action: 'logout' });
} else {
Modal.createTrackedDialog('Logout from LeftPanel', '', LogoutDialog);
Modal.createDialog(LogoutDialog);
}
this.setState({ contextMenuPosition: null }); // also close the menu

View file

@ -70,7 +70,7 @@ export default class UserView extends React.Component<IProps, IState> {
try {
profileInfo = await cli.getProfileInfo(this.props.userId);
} catch (err) {
Modal.createTrackedDialog(_t('Could not load user profile'), '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Could not load user profile'),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});

View file

@ -199,7 +199,7 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
}
if (this.state.logoutDevices) {
const { finished } = Modal.createTrackedDialog<[boolean]>('Forgot Password Warning', '', QuestionDialog, {
const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, {
title: _t('Warning!'),
description:
<div>
@ -271,7 +271,7 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
};
public showErrorDialog(description: string, title?: string) {
Modal.createTrackedDialog('Forgot Password Error', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title,
description,
});

View file

@ -98,7 +98,7 @@ export default class SetupEncryptionBody extends React.Component<IProps, IState>
// We need to call onFinished now to close this dialog, and
// again later to signal that the verification is complete.
this.props.onFinished();
Modal.createTrackedDialog('New Session Verification', 'Starting dialog', VerificationRequestDialog, {
Modal.createDialog(VerificationRequestDialog, {
verificationRequestPromise: requestPromise,
member: cli.getUser(userId),
onFinished: async () => {

View file

@ -101,7 +101,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
}
private onClearAll = () => {
Modal.createTrackedDialog('Clear Data', 'Soft Logout', ConfirmWipeDeviceDialog, {
Modal.createDialog(ConfirmWipeDeviceDialog, {
onFinished: (wipeData) => {
if (!wipeData) return;

View file

@ -126,7 +126,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
if (this.state.email === '') {
if (this.showEmail()) {
Modal.createTrackedDialog("Email prompt dialog", '', RegistrationEmailPromptDialog, {
Modal.createDialog(RegistrationEmailPromptDialog, {
onFinished: async (confirmed: boolean, email?: string) => {
if (confirmed) {
this.setState({

View file

@ -91,7 +91,7 @@ const BetaCard = ({ title: titleOverride, featureId }: IProps) => {
if (value && feedbackLabel && feedbackSubheading && SdkConfig.get().bug_report_endpoint_url) {
feedbackButton = <AccessibleButton
onClick={() => {
Modal.createTrackedDialog("Beta Feedback", featureId, BetaFeedbackDialog, { featureId });
Modal.createDialog(BetaFeedbackDialog, { featureId });
}}
kind="primary"
>

View file

@ -173,7 +173,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
};
private onViewSourceClick = (): void => {
Modal.createTrackedDialog('View Event Source', '', ViewSource, {
Modal.createDialog(ViewSource, {
mxEvent: this.props.mxEvent,
}, 'mx_Dialog_viewsource');
this.closeMenu();
@ -238,7 +238,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
private onShareClick = (e: React.MouseEvent): void => {
e.preventDefault();
Modal.createTrackedDialog('share room message dialog', '', ShareDialog, {
Modal.createDialog(ShareDialog, {
target: this.props.mxEvent,
permalinkCreator: this.props.permalinkCreator,
});
@ -286,7 +286,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
private onEndPollClick = (): void => {
const matrixClient = MatrixClientPeg.get();
Modal.createTrackedDialog('End Poll', '', EndPollDialog, {
Modal.createDialog(EndPollDialog, {
matrixClient,
event: this.props.mxEvent,
getRelationsForEvent: this.props.getRelationsForEvent,

View file

@ -296,7 +296,7 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
ev.preventDefault();
ev.stopPropagation();
Modal.createTrackedDialog('Export room dialog', '', ExportDialog, { room });
Modal.createDialog(ExportDialog, { room });
onFinished();
}}
label={_t("Export chat")}

View file

@ -69,7 +69,7 @@ const WidgetContextMenu: React.FC<IProps> = ({
logger.error("Failed to start livestream", err);
// XXX: won't i18n well, but looks like widget api only support 'message'?
const message = err.message || _t("Unable to start audio streaming.");
Modal.createTrackedDialog('WidgetContext Menu', 'Livestream failed', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Failed to start livestream'),
description: message,
});
@ -134,7 +134,7 @@ const WidgetContextMenu: React.FC<IProps> = ({
onDeleteClick();
} else {
// Show delete confirmation dialog
Modal.createTrackedDialog('Delete Widget', '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t("Delete Widget"),
description: _t(
"Deleting a widget removes it for all users in this room." +

View file

@ -15,14 +15,13 @@ limitations under the License.
*/
import React from "react";
import { Optional } from "matrix-events-sdk";
import BaseDialog from "./BaseDialog";
import { _t } from "../../../languageHandler";
import DialogButtons from "../elements/DialogButtons";
import Modal from "../../../Modal";
import SdkConfig from "../../../SdkConfig";
import { SnakedObject } from "../../../utils/SnakedObject";
import { getPolicyUrl } from "../../../toasts/AnalyticsToast";
export enum ButtonClicked {
Primary,
@ -98,19 +97,13 @@ const AnalyticsLearnMoreDialog: React.FC<IProps> = ({
};
export const showDialog = (props: Omit<IProps, "cookiePolicyUrl" | "analyticsOwner">): void => {
const piwikConfig = SdkConfig.get("piwik");
let privacyPolicyUrl: Optional<string>;
if (piwikConfig && typeof piwikConfig === "object") {
privacyPolicyUrl = (new SnakedObject(piwikConfig)).get("policy_url");
}
const privacyPolicyUrl = getPolicyUrl();
const analyticsOwner = SdkConfig.get("analytics_owner") ?? SdkConfig.get("brand");
Modal.createTrackedDialog(
"Analytics Learn More",
"",
AnalyticsLearnMoreDialog,
{ privacyPolicyUrl, analyticsOwner, ...props },
"mx_AnalyticsLearnMoreDialog_wrapper",
);
Modal.createDialog(AnalyticsLearnMoreDialog, {
privacyPolicyUrl,
analyticsOwner,
...props,
}, "mx_AnalyticsLearnMoreDialog_wrapper");
};
export default AnalyticsLearnMoreDialog;

View file

@ -110,8 +110,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
}).then(() => {
if (!this.unmounted) {
this.props.onFinished(false);
// N.B. first param is passed to piwik and so doesn't want i18n
Modal.createTrackedDialog('Bug report sent', '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t('Logs sent'),
description: _t('Thank you!'),
hasCancelButton: false,

View file

@ -53,7 +53,7 @@ export function createRedactEventDialog({
mxEvent: MatrixEvent;
onCloseDialog?: () => void;
}) {
Modal.createTrackedDialog('Confirm Redact Dialog', '', ConfirmRedactDialog, {
Modal.createDialog(ConfirmRedactDialog, {
onFinished: async (proceed: boolean, reason?: string) => {
if (!proceed) return;
@ -73,7 +73,7 @@ export function createRedactEventDialog({
// detached queue and we show the room status bar to allow retry
if (typeof code !== "undefined") {
// display error message stating you couldn't delete this.
Modal.createTrackedDialog('You cannot delete this message', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Error'),
description: _t('You cannot delete this message. (%(code)s)', { code }),
});

View file

@ -32,7 +32,7 @@ const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
const brand = SdkConfig.get().brand;
const _onLogoutClicked = () => {
Modal.createTrackedDialog('Logout e2e db too new', '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t("Sign out"),
description: _t(
"To avoid losing your chat history, you must export your room keys " +

View file

@ -19,7 +19,6 @@ import React from 'react';
import { AuthType, IAuthData } from 'matrix-js-sdk/src/interactive-auth';
import { logger } from "matrix-js-sdk/src/logger";
import Analytics from '../../../Analytics';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
import InteractiveAuth, { ERROR_USER_CANCELLED, InteractiveAuthCallback } from "../../structures/InteractiveAuth";
@ -122,7 +121,6 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
// this isn't done.
MatrixClientPeg.get().deactivateAccount(auth, this.state.shouldErase).then(r => {
// Deactivation worked - logout & close this dialog
Analytics.trackEvent('Account', 'Deactivate Account');
defaultDispatcher.fire(Action.TriggerLogout);
this.props.onFinished(true);
}).catch(e => {

View file

@ -62,16 +62,11 @@ export default class EndPollDialog extends React.Component<IProps> {
this.props.event.getRoomId(), endEvent.type, endEvent.content,
).catch((e: any) => {
console.error("Failed to submit poll response event:", e);
Modal.createTrackedDialog(
'Failed to end poll',
'',
ErrorDialog,
{
title: _t("Failed to end poll"),
description: _t(
"Sorry, the poll did not end. Please try again."),
},
);
Modal.createDialog(ErrorDialog, {
title: _t("Failed to end poll"),
description: _t(
"Sorry, the poll did not end. Please try again."),
});
});
}
this.props.onFinished(endPoll);

View file

@ -16,7 +16,7 @@ limitations under the License.
/*
* Usage:
* Modal.createTrackedDialog('An Identifier', 'some detail', ErrorDialog, {
* Modal.createDialog(ErrorDialog, {
* title: "some text", (default: "Error")
* description: "some more text",
* button: "Button Text",

View file

@ -47,7 +47,7 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
const onDebugLogsLinkClick = (): void => {
props.onFinished();
Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {});
Modal.createDialog(BugReportDialog, {});
};
const rageshakeUrl = SdkConfig.get().bug_report_endpoint_url;
@ -58,7 +58,7 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
submitFeedback(rageshakeUrl, "feedback", comment, canContact);
}
Modal.createTrackedDialog('Feedback sent', '', InfoDialog, {
Modal.createDialog(InfoDialog, {
title: _t('Feedback sent'),
description: _t('Thank you!'),
});

View file

@ -50,7 +50,7 @@ const GenericFeatureFeedbackDialog: React.FC<IProps> = ({
submitFeedback(SdkConfig.get().bug_report_endpoint_url, rageshakeLabel, comment, canContact, rageshakeData);
onFinished(true);
Modal.createTrackedDialog("Feedback Sent", rageshakeLabel, InfoDialog, {
Modal.createDialog(InfoDialog, {
title,
description: _t("Feedback sent! Thanks, we appreciate it!"),
button: _t("Close"),

View file

@ -904,7 +904,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
if (this.unmounted) return;
if (failed.length > 0) {
Modal.createTrackedDialog('Invite Paste Fail', '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t('Failed to find the following users'),
description: _t(
"The following users might not exist or are invalid, and cannot be invited: %(csvNames)s",

View file

@ -80,7 +80,7 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
}
private onExportE2eKeysClicked = (): void => {
Modal.createTrackedDialogAsync('Export E2E Keys', '',
Modal.createDialogAsync(
import(
'../../../async-components/views/dialogs/security/ExportE2eKeysDialog'
) as unknown as Promise<ComponentType<{}>>,
@ -103,12 +103,9 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
// A key backup exists for this account, but the creating device is not
// verified, so restore the backup which will give us the keys from it and
// allow us to trust it (ie. upload keys to it)
Modal.createTrackedDialog(
'Restore Backup', '', RestoreKeyBackupDialog, null, null,
/* priority = */ false, /* static = */ true,
);
Modal.createDialog(RestoreKeyBackupDialog, null, null, /* priority = */ false, /* static = */ true);
} else {
Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
Modal.createDialogAsync(
import(
"../../../async-components/views/dialogs/security/CreateKeyBackupDialog"
) as unknown as Promise<ComponentType<{}>>,

View file

@ -56,7 +56,7 @@ export default class RoomUpgradeDialog extends React.Component<IProps, IState> {
upgradeRoom(this.props.room, this.targetVersion, false, false).then(() => {
this.props.onFinished(true);
}).catch((err) => {
Modal.createTrackedDialog('Failed to upgrade room', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Failed to upgrade room"),
description: ((err && err.message) ? err.message : _t("The room upgrade could not be completed")),
});

View file

@ -97,7 +97,7 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
e.preventDefault();
e.stopPropagation();
Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {});
Modal.createDialog(BugReportDialog, {});
};
render() {

View file

@ -33,13 +33,13 @@ interface IProps extends IDialogProps {
export default class SessionRestoreErrorDialog extends React.Component<IProps> {
private sendBugReport = (): void => {
Modal.createTrackedDialog('Session Restore Error', 'Send Bug Report Dialog', BugReportDialog, {
Modal.createDialog(BugReportDialog, {
error: this.props.error,
});
};
private onClearStorageClick = (): void => {
Modal.createTrackedDialog('Session Restore Confirm Logout', '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t("Sign out"),
description:
<div>{ _t("Sign out and remove encryption keys?") }</div>,

View file

@ -64,7 +64,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
private onSubmit = (): void => {
const emailAddress = this.state.emailAddress;
if (!Email.looksValid(emailAddress)) {
Modal.createTrackedDialog('Invalid Email Address', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Invalid Email Address"),
description: _t("This doesn't appear to be a valid email address"),
});
@ -72,7 +72,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
}
this.addThreepid = new AddThreepid();
this.addThreepid.addEmailAddress(emailAddress).then(() => {
Modal.createTrackedDialog('Verification Pending', '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t("Verification Pending"),
description: _t(
"Please check your email and click on the link it contains. Once this " +
@ -84,7 +84,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
}, (err) => {
this.setState({ emailBusy: false });
logger.error("Unable to add email address " + emailAddress + " " + err);
Modal.createTrackedDialog('Unable to add email address', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to add email address"),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
@ -112,7 +112,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
if (err.errcode == 'M_THREEPID_AUTH_FAILED') {
const message = _t("Unable to verify email address.") + " " +
_t("Please check your email and click on the link it contains. Once this is done, click continue.");
Modal.createTrackedDialog('Verification Pending', '3pid Auth Failed', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t("Verification Pending"),
description: message,
button: _t('Continue'),
@ -120,7 +120,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
});
} else {
logger.error("Unable to verify email address: " + err);
Modal.createTrackedDialog('Unable to verify email address', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to verify email address."),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});

View file

@ -701,7 +701,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
};
const openFeedback = SdkConfig.get().bug_report_endpoint_url ? () => {
Modal.createTrackedDialog("Spotlight Feedback", "feature_spotlight", BetaFeedbackDialog, {
Modal.createDialog(BetaFeedbackDialog, {
featureId: "feature_spotlight",
});
} : null;

View file

@ -30,7 +30,7 @@ interface IProps extends IDialogProps { }
export default class StorageEvictedDialog extends React.Component<IProps> {
private sendBugReport = (ev: React.MouseEvent): void => {
ev.preventDefault();
Modal.createTrackedDialog('Storage evicted', 'Send Bug Report Dialog', BugReportDialog, {});
Modal.createDialog(BugReportDialog, {});
};
private onSignOutClick = (): void => {

View file

@ -233,14 +233,11 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
const cli = MatrixClientPeg.get();
await cli.bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (makeRequest) => {
const { finished } = Modal.createTrackedDialog(
'Cross-signing keys dialog', '', InteractiveAuthDialog,
{
title: _t("Setting up keys"),
matrixClient: cli,
makeRequest,
},
);
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
title: _t("Setting up keys"),
matrixClient: cli,
makeRequest,
});
const [confirmed] = await finished;
if (!confirmed) {
throw new Error("Cross-signing key upload auth canceled");

View file

@ -123,18 +123,15 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
},
};
const { finished } = Modal.createTrackedDialog(
'Cross-signing keys dialog', '', InteractiveAuthDialog,
{
title: _t("Setting up keys"),
matrixClient: MatrixClientPeg.get(),
makeRequest,
aestheticsForStagePhases: {
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
},
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
title: _t("Setting up keys"),
matrixClient: MatrixClientPeg.get(),
makeRequest,
aestheticsForStagePhases: {
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
},
);
});
const [confirmed] = await finished;
if (!confirmed) {
throw new Error("Cross-signing key upload auth canceled");

View file

@ -188,20 +188,16 @@ const NetworkDropdown = ({ onOptionChange, protocols = {}, selectedServerName, s
if (removableServers.has(server)) {
const onClick = async () => {
closeMenu();
const { finished } = Modal.createTrackedDialog(
"Network Dropdown", "Remove server", QuestionDialog,
{
title: _t("Are you sure?"),
description: _t("Are you sure you want to remove <b>%(serverName)s</b>", {
serverName: server,
}, {
b: serverName => <b>{ serverName }</b>,
}),
button: _t("Remove"),
fixedWidth: false,
},
"mx_NetworkDropdown_dialog",
);
const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("Are you sure?"),
description: _t("Are you sure you want to remove <b>%(serverName)s</b>", {
serverName: server,
}, {
b: serverName => <b>{ serverName }</b>,
}),
button: _t("Remove"),
fixedWidth: false,
}, "mx_NetworkDropdown_dialog");
const [ok] = await finished;
if (!ok) return;
@ -242,7 +238,7 @@ const NetworkDropdown = ({ onOptionChange, protocols = {}, selectedServerName, s
const onClick = async () => {
closeMenu();
const { finished } = Modal.createTrackedDialog("Network Dropdown", "Add a new server", TextInputDialog, {
const { finished } = Modal.createDialog(TextInputDialog, {
title: _t("Add a new server"),
description: _t("Enter the name of a new server you want to explore."),
button: _t("Add"),

View file

@ -1,105 +0,0 @@
/*
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import AccessibleButton from './AccessibleButton';
import dis from '../../../dispatcher/dispatcher';
import Analytics from '../../../Analytics';
import Tooltip from './Tooltip';
interface IProps {
size?: string;
tooltip?: boolean;
action: string;
mouseOverAction?: string;
label: string;
iconPath?: string;
className?: string;
children?: JSX.Element;
}
interface IState {
showTooltip: boolean;
}
export default class ActionButton extends React.Component<IProps, IState> {
static defaultProps: Partial<IProps> = {
size: "25",
tooltip: false,
};
constructor(props: IProps) {
super(props);
this.state = {
showTooltip: false,
};
}
private onClick = (ev: React.MouseEvent): void => {
ev.stopPropagation();
Analytics.trackEvent('Action Button', 'click', this.props.action);
dis.dispatch({ action: this.props.action });
};
private onMouseEnter = (): void => {
this.showTooltip();
if (this.props.mouseOverAction) {
dis.dispatch({ action: this.props.mouseOverAction });
}
};
private showTooltip = (): void => {
if (this.props.tooltip) this.setState({ showTooltip: true });
};
private hideTooltip = (): void => {
this.setState({ showTooltip: false });
};
render() {
let tooltip;
if (this.state.showTooltip) {
tooltip = <Tooltip className="mx_RoleButton_tooltip" label={this.props.label} />;
}
const icon = this.props.iconPath ?
(<img src={this.props.iconPath} width={this.props.size} height={this.props.size} />) :
undefined;
const classNames = ["mx_RoleButton"];
if (this.props.className) {
classNames.push(this.props.className);
}
return (
<AccessibleButton
className={classNames.join(" ")}
onClick={this.onClick}
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.hideTooltip}
onFocus={this.showTooltip}
onBlur={this.hideTooltip}
aria-label={this.props.label}
>
{ icon }
{ tooltip }
{ this.props.children }
</AccessibleButton>
);
}
}

View file

@ -68,7 +68,7 @@ export default class ErrorBoundary extends React.PureComponent<{}, IState> {
};
private onBugReport = (): void => {
Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {
Modal.createDialog(BugReportDialog, {
label: 'react-soft-crash',
error: this.state.error,
});

View file

@ -18,7 +18,6 @@ import classNames from 'classnames';
import { EventType } from 'matrix-js-sdk/src/@types/event';
import React, { useContext, useRef, useState, MouseEvent } from 'react';
import Analytics from "../../../Analytics";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import RoomContext from "../../../contexts/RoomContext";
import { useTimeout } from "../../../hooks/useTimeout";
@ -74,7 +73,6 @@ const MiniAvatarUploader: React.FC<IProps> = ({
onChange={async (ev) => {
if (!ev.target.files?.length) return;
setBusy(true);
Analytics.trackEvent("mini_avatar", "upload");
const file = ev.target.files[0];
const uri = await cli.uploadContent(file);
await setAvatarUrl(uri);

View file

@ -172,25 +172,20 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
() => this.props.onFinished(true),
).catch(e => {
console.error("Failed to post poll:", e);
Modal.createTrackedDialog(
'Failed to post poll',
'',
QuestionDialog,
{
title: _t("Failed to post poll"),
description: _t(
"Sorry, the poll you tried to create was not posted."),
button: _t('Try again'),
cancelButton: _t('Cancel'),
onFinished: (tryAgain: boolean) => {
if (!tryAgain) {
this.cancel();
} else {
this.setState({ busy: false, canSubmit: true });
}
},
Modal.createDialog(QuestionDialog, {
title: _t("Failed to post poll"),
description: _t(
"Sorry, the poll you tried to create was not posted."),
button: _t('Try again'),
cancelButton: _t('Cancel'),
onFinished: (tryAgain: boolean) => {
if (!tryAgain) {
this.cancel();
} else {
this.setState({ busy: false, canSubmit: true });
}
},
);
});
});
}

View file

@ -37,12 +37,12 @@ const showPickerDialog = (
serverConfig: ValidatedServerConfig,
onFinished: (config: ValidatedServerConfig) => void,
) => {
Modal.createTrackedDialog("Server Picker", "", ServerPickerDialog, { title, serverConfig, onFinished });
Modal.createDialog(ServerPickerDialog, { title, serverConfig, onFinished });
};
const onHelpClick = () => {
const brand = SdkConfig.get().brand;
Modal.createTrackedDialog('Custom Server Dialog', '', InfoDialog, {
Modal.createDialog(InfoDialog, {
title: _t("Server Options"),
description: _t("You can use the custom server options to sign into other Matrix servers by specifying " +
"a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on " +

View file

@ -183,15 +183,10 @@ class LocationPicker extends React.Component<ILocationPickerProps, IState> {
// pin drop location without permissions is ok
if (isSharingOwnLocation(this.props.shareType)) {
this.props.onFinished();
Modal.createTrackedDialog(
'Could not fetch location',
'',
ErrorDialog,
{
title: _t("Could not fetch location"),
description: positionFailureMessage(e.code),
},
);
Modal.createDialog(ErrorDialog, {
title: _t("Could not fetch location"),
description: positionFailureMessage(e.code),
});
}
if (this.geolocate) {

View file

@ -49,7 +49,6 @@ const handleShareError = (error: Error, openMenu: () => void, shareType: Locatio
"We couldn't start sharing your live location" :
"We couldn't send your location";
logger.error(errorMessage, error);
const analyticsAction = errorMessage;
const params = {
title: _t("We couldn't send your location"),
description: _t("%(brand)s could not send your location. Please try again later.", {
@ -63,7 +62,7 @@ const handleShareError = (error: Error, openMenu: () => void, shareType: Locatio
}
},
};
Modal.createTrackedDialog(analyticsAction, '', QuestionDialog, params);
Modal.createDialog(QuestionDialog, params);
};
export const shareLiveLocation = (

View file

@ -154,7 +154,7 @@ export default class DateSeparator extends React.Component<IProps, IState> {
// detached queue and we show the room status bar to allow retry
if (typeof code !== "undefined") {
// display error message stating you couldn't delete this.
Modal.createTrackedDialog('Unable to find event at that date', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Error'),
description: _t('Unable to find event at that date. (%(code)s)', { code }),
});

View file

@ -75,13 +75,13 @@ export default class EditHistoryMessage extends React.PureComponent<IProps, ISta
const event = this.props.mxEvent;
const cli = MatrixClientPeg.get();
Modal.createTrackedDialog('Confirm Redact Dialog', 'Edit history', ConfirmAndWaitRedactDialog, {
Modal.createDialog(ConfirmAndWaitRedactDialog, {
redact: () => cli.redactEvent(event.getRoomId(), event.getId()),
}, 'mx_Dialog_confirmredact');
};
private onViewSourceClick = (): void => {
Modal.createTrackedDialog('View Event Source', 'Edit history', ViewSource, {
Modal.createDialog(ViewSource, {
mxEvent: this.props.mxEvent,
}, 'mx_Dialog_viewsource');
};

View file

@ -106,9 +106,7 @@ const MBeaconBody: React.FC<IBodyProps> = React.forwardRef(({ mxEvent }, ref) =>
if (displayStatus !== BeaconDisplayStatus.Active) {
return;
}
Modal.createTrackedDialog(
'Beacon View',
'',
Modal.createDialog(
BeaconViewDialog,
{
roomId: mxEvent.getRoomId(),

View file

@ -172,7 +172,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
});
} catch (err) {
logger.warn("Unable to decrypt attachment: ", err);
Modal.createTrackedDialog('Error decrypting attachment', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Error"),
description: _t("Error decrypting attachment"),
});

View file

@ -57,9 +57,7 @@ export default class MLocationBody extends React.Component<IBodyProps, IState> {
}
private onClick = () => {
Modal.createTrackedDialog(
'Location View',
'',
Modal.createDialog(
LocationViewDialog,
{
matrixClient: this.context,

View file

@ -181,9 +181,7 @@ export function pollAlreadyHasVotes(mxEvent: MatrixEvent, getRelationsForEvent?:
export function launchPollEditor(mxEvent: MatrixEvent, getRelationsForEvent?: GetRelationsForEvent): void {
if (pollAlreadyHasVotes(mxEvent, getRelationsForEvent)) {
Modal.createTrackedDialog(
'Not allowed to edit poll',
'',
Modal.createDialog(
ErrorDialog,
{
title: _t("Can't edit poll"),
@ -193,9 +191,7 @@ export function launchPollEditor(mxEvent: MatrixEvent, getRelationsForEvent?: Ge
},
);
} else {
Modal.createTrackedDialog(
'Polls',
'create',
Modal.createDialog(
PollCreateDialog,
{
room: MatrixClientPeg.get().getRoom(mxEvent.getRoomId()),
@ -312,9 +308,7 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
).catch((e: any) => {
console.error("Failed to submit poll response event:", e);
Modal.createTrackedDialog(
'Vote not registered',
'',
Modal.createDialog(
ErrorDialog,
{
title: _t("Vote not registered"),

View file

@ -468,7 +468,7 @@ export default class TextualBody extends React.Component<IBodyProps, IState> {
scalarClient.connect().then(() => {
const completeUrl = scalarClient.getStarterLink(starterLink);
const integrationsUrl = integrationManager.uiUrl;
Modal.createTrackedDialog('Add an integration', '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t("Add an Integration"),
description:
<div>

View file

@ -52,14 +52,14 @@ export default class TileErrorBoundary extends React.Component<IProps, IState> {
}
private onBugReport = (): void => {
Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {
Modal.createDialog(BugReportDialog, {
label: 'react-soft-crash-tile',
error: this.state.error,
});
};
private onViewSource = (): void => {
Modal.createTrackedDialog('View Event Source', 'from crash', ViewSource, {
Modal.createDialog(ViewSource, {
mxEvent: this.props.mxEvent,
}, 'mx_Dialog_viewsource');
};

View file

@ -84,7 +84,7 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
const changeHandler = useCallback(() => {
// handle transitions -> cancelled for mismatches which fire a modal instead of showing a card
if (request && request.cancelled && MISMATCHES.includes(request.cancellationCode)) {
Modal.createTrackedDialog("Verification failed", "insecure", ErrorDialog, {
Modal.createDialog(ErrorDialog, {
headerImage: require("../../../../res/img/e2e/warning.svg").default,
title: _t("Your messages are not secure"),
description: <div>

View file

@ -21,7 +21,6 @@ limitations under the License.
import React from 'react';
import classNames from 'classnames';
import Analytics from '../../../Analytics';
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { ButtonEvent } from "../elements/AccessibleButton";
@ -31,8 +30,6 @@ interface IProps {
isUnread?: boolean;
// click handler
onClick: (ev: ButtonEvent) => void;
// The parameters to track the click event
analytics: Parameters<typeof Analytics.trackEvent>;
// Button name
name: string;
@ -42,14 +39,8 @@ interface IProps {
// TODO: replace this, the composer buttons and the right panel buttons with a unified representation
export default class HeaderButton extends React.Component<IProps> {
private onClick = (ev: ButtonEvent) => {
Analytics.trackEvent(...this.props.analytics);
this.props.onClick(ev);
};
public render() {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { isHighlighted, isUnread = false, onClick, analytics, name, title, ...props } = this.props;
const { isHighlighted, isUnread = false, onClick, name, title, ...props } = this.props;
const classes = classNames({
mx_RightPanel_headerButton: true,
@ -64,7 +55,7 @@ export default class HeaderButton extends React.Component<IProps> {
role="tab"
title={title}
className={classes}
onClick={this.onClick}
onClick={onClick}
/>;
}
}

View file

@ -95,7 +95,6 @@ const PinnedMessagesHeaderButton = ({ room, isHighlighted, onClick }: IHeaderBut
isHighlighted={isHighlighted}
isUnread={!!unreadIndicator}
onClick={onClick}
analytics={["Right Panel", "Pinned Messages Button", "click"]}
>
{ unreadIndicator }
</HeaderButton>;
@ -115,7 +114,6 @@ const TimelineCardHeaderButton = ({ room, isHighlighted, onClick }: IHeaderButto
title={_t("Chat")}
isHighlighted={isHighlighted}
onClick={onClick}
analytics={["Right Panel", "Timeline Panel Button", "click"]}
>
{ unreadIndicator }
</HeaderButton>;
@ -244,7 +242,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
onClick={this.onThreadsPanelClicked}
isHighlighted={this.isPhase(RoomHeaderButtons.THREAD_PHASES)}
isUnread={this.threadNotificationState.color > 0}
analytics={['Right Panel', 'Threads List Button', 'click']}>
>
<UnreadIndicator color={this.threadNotificationState.color} />
</HeaderButton>
: null,
@ -256,7 +254,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
title={_t('Notifications')}
isHighlighted={this.isPhase(RightPanelPhases.NotificationPanel)}
onClick={this.onNotificationsClicked}
analytics={['Right Panel', 'Notification List Button', 'click']} />,
/>,
);
rightPanelPhaseButtons.set(RightPanelPhases.RoomSummary,
<HeaderButton
@ -265,7 +263,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
title={_t('Room Info')}
isHighlighted={this.isPhase(ROOM_INFO_PHASES)}
onClick={this.onRoomSummaryClicked}
analytics={['Right Panel', 'Room Summary Button', 'click']} />,
/>,
);
return <>

View file

@ -248,13 +248,13 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, onClose }) => {
const cli = useContext(MatrixClientContext);
const onShareRoomClick = () => {
Modal.createTrackedDialog('share room dialog', '', ShareDialog, {
Modal.createDialog(ShareDialog, {
target: room,
});
};
const onRoomExportClick = async () => {
Modal.createTrackedDialog('export room dialog', '', ExportDialog, {
Modal.createDialog(ExportDialog, {
room,
});
};

View file

@ -365,7 +365,7 @@ const UserOptionsSection: React.FC<{
const isMe = member.userId === cli.getUserId();
const onShareUserClick = () => {
Modal.createTrackedDialog('share room member dialog', '', ShareDialog, {
Modal.createDialog(ShareDialog, {
target: member,
});
};
@ -451,7 +451,7 @@ const UserOptionsSection: React.FC<{
}
});
} catch (err) {
Modal.createTrackedDialog('Failed to invite', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Failed to invite'),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
@ -503,7 +503,7 @@ const UserOptionsSection: React.FC<{
};
const warnSelfDemote = async (isSpace: boolean) => {
const { finished } = Modal.createTrackedDialog('Demoting Self', '', QuestionDialog, {
const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("Demote yourself?"),
description:
<div>
@ -590,9 +590,7 @@ const RoomKickButton = ({ room, member, startUpdating, stopUpdating }: Omit<IBas
if (member.membership !== "invite" && member.membership !== "join") return null;
const onKick = async () => {
const { finished } = Modal.createTrackedDialog(
'Confirm User Action Dialog',
'onKick',
const { finished } = Modal.createDialog(
room.isSpaceRoom() ? ConfirmSpaceUserActionDialog : ConfirmUserActionDialog,
{
member,
@ -632,7 +630,7 @@ const RoomKickButton = ({ room, member, startUpdating, stopUpdating }: Omit<IBas
logger.log("Kick success");
}, function(err) {
logger.error("Kick error: " + err);
Modal.createTrackedDialog('Failed to kick', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Failed to remove user"),
description: ((err && err.message) ? err.message : "Operation failed"),
});
@ -661,7 +659,7 @@ const RedactMessagesButton: React.FC<IBaseProps> = ({ member }) => {
const room = cli.getRoom(member.roomId);
if (!room) return;
Modal.createTrackedDialog("Bulk Redact Dialog", "", BulkRedactDialog, {
Modal.createDialog(BulkRedactDialog, {
matrixClient: cli,
room, member,
});
@ -681,9 +679,7 @@ const BanToggleButton = ({ room, member, startUpdating, stopUpdating }: Omit<IBa
const isBanned = member.membership === "ban";
const onBanOrUnban = async () => {
const { finished } = Modal.createTrackedDialog(
'Confirm User Action Dialog',
'onBanOrUnban',
const { finished } = Modal.createDialog(
room.isSpaceRoom() ? ConfirmSpaceUserActionDialog : ConfirmUserActionDialog,
{
member,
@ -746,7 +742,7 @@ const BanToggleButton = ({ room, member, startUpdating, stopUpdating }: Omit<IBa
logger.log("Ban success");
}, function(err) {
logger.error("Ban error: " + err);
Modal.createTrackedDialog('Failed to ban user', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Error"),
description: _t("Failed to ban user"),
});
@ -827,7 +823,7 @@ const MuteToggleButton: React.FC<IBaseRoomProps> = ({ member, room, powerLevels,
logger.log("Mute toggle success");
}, function(err) {
logger.error("Mute error: " + err);
Modal.createTrackedDialog('Failed to mute user', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Error"),
description: _t("Failed to mute user"),
});
@ -1048,7 +1044,7 @@ const PowerLevelEditor: React.FC<{
logger.log("Power change success");
}, function(err) {
logger.error("Failed to change power level " + err);
Modal.createTrackedDialog('Failed to change power level', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Error"),
description: _t("Failed to change power level"),
});
@ -1065,7 +1061,7 @@ const PowerLevelEditor: React.FC<{
const myUserId = cli.getUserId();
const myPower = powerLevelEvent.getContent().users[myUserId];
if (myPower && parseInt(myPower) <= powerLevel && myUserId !== target) {
const { finished } = Modal.createTrackedDialog('Promote to PL100 Warning', '', QuestionDialog, {
const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("Warning!"),
description:
<div>
@ -1214,7 +1210,7 @@ const BasicUserInfo: React.FC<{
const roomPermissions = useRoomPermissions(cli, room, member as RoomMember);
const onSynapseDeactivate = useCallback(async () => {
const { finished } = Modal.createTrackedDialog('Synapse User Deactivation', '', QuestionDialog, {
const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("Deactivate user?"),
description:
<div>{ _t(
@ -1234,7 +1230,7 @@ const BasicUserInfo: React.FC<{
logger.error("Failed to deactivate user");
logger.error(err);
Modal.createTrackedDialog('Failed to deactivate Synapse user', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Failed to deactivate user'),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});

View file

@ -173,7 +173,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
this.context.sendStateEvent(this.props.roomId, "m.room.canonical_alias",
eventContent, "").catch((err) => {
logger.error(err);
Modal.createTrackedDialog('Error updating main address', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Error updating main address"),
description: _t(
"There was an error updating the room's main address. It may not be allowed by the server " +
@ -211,7 +211,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
.catch((err) => {
// TODO: Add error handling based upon server validation
logger.error(err);
Modal.createTrackedDialog('Error updating alternative addresses', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Error updating main address"),
description: _t(
"There was an error updating the room's alternative addresses. " +
@ -243,7 +243,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
}
}).catch((err) => {
logger.error(err);
Modal.createTrackedDialog('Error creating address', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Error creating address"),
description: _t(
"There was an error creating that address. It may not be allowed by the server " +
@ -275,7 +275,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
"error occurred.",
);
}
Modal.createTrackedDialog('Error removing address', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Error removing address"),
description,
});

View file

@ -315,9 +315,7 @@ class PollButton extends React.PureComponent<IPollButtonProps> {
MatrixClientPeg.get().getUserId(),
);
if (!canSend) {
Modal.createTrackedDialog(
'Polls',
'permissions error: cannot start',
Modal.createDialog(
ErrorDialog,
{
title: _t("Permission Required"),
@ -331,9 +329,7 @@ class PollButton extends React.PureComponent<IPollButtonProps> {
? this.props.relation.event_id
: null;
Modal.createTrackedDialog(
'Polls',
'create',
Modal.createDialog(
PollCreateDialog,
{
room: this.props.room,

View file

@ -22,7 +22,6 @@ import { BreadcrumbsStore } from "../../../stores/BreadcrumbsStore";
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
import { _t } from "../../../languageHandler";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import Analytics from "../../../Analytics";
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
import Toolbar from "../../../accessibility/Toolbar";
@ -104,7 +103,6 @@ export default class RoomBreadcrumbs extends React.PureComponent<IProps, IState>
};
private viewRoom = (room: Room, index: number, viaKeyboard = false) => {
Analytics.trackEvent("Breadcrumbs", "click_node", String(index));
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: room.roomId,

View file

@ -66,7 +66,7 @@ export default class RoomUpgradeWarningBar extends React.PureComponent<IProps, I
};
private onUpgradeClick = (): void => {
Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, { room: this.props.room });
Modal.createDialog(RoomUpgradeDialog, { room: this.props.room });
};
public render(): JSX.Element {

View file

@ -106,7 +106,7 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState
// Revert echo because of error
this.setState({ invited: true });
Modal.createTrackedDialog('Revoke 3pid invite failed', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Failed to revoke invite"),
description: _t(
"Could not revoke the invite. The server may be experiencing a temporary problem or " +

View file

@ -162,7 +162,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
// The "microphone access error" dialogs are used a lot, so let's functionify them
const accessError = () => {
Modal.createTrackedDialog('Microphone Access Error', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to access your microphone"),
description: <>
<p>{ _t(
@ -177,7 +177,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
try {
const devices = await MediaDeviceHandler.getDevices();
if (!devices?.[MediaDeviceKindEnum.AudioInput]?.length) {
Modal.createTrackedDialog('No Microphone Error', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("No microphone found"),
description: <>
<p>{ _t(

View file

@ -95,7 +95,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
if (userHasOtherDevices && !serverSupportsControlOfDevicesLogout && this.props.confirm) {
// warn about logging out all devices
const { finished } = Modal.createTrackedDialog<[boolean]>('Change Password', '', QuestionDialog, {
const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, {
title: _t("Warning!"),
description:
<div>
@ -196,14 +196,14 @@ export default class ChangePassword extends React.Component<IProps, IState> {
private optionallySetEmail(): Promise<boolean> {
// Ask for an email otherwise the user has no way to reset their password
const modal = Modal.createTrackedDialog('Do you want to set an email address?', '', SetEmailDialog, {
const modal = Modal.createDialog(SetEmailDialog, {
title: _t('Do you want to set an email address?'),
});
return modal.finished.then(([confirmed]) => confirmed);
}
private onExportE2eKeysClicked = (): void => {
Modal.createTrackedDialogAsync('Export E2E Keys', 'Change Password',
Modal.createDialogAsync(
import(
'../../../async-components/views/dialogs/security/ExportE2eKeysDialog'
) as unknown as Promise<ComponentType<{}>>,

View file

@ -75,10 +75,7 @@ export default class CrossSigningPanel extends React.PureComponent<{}, IState> {
private onBootstrapClick = () => {
if (this.state.crossSigningPrivateKeysInStorage) {
Modal.createTrackedDialog(
"Verify session", "Verify session", SetupEncryptionDialog,
{}, null, /* priority = */ false, /* static = */ true,
);
Modal.createDialog(SetupEncryptionDialog, {}, null, /* priority = */ false, /* static = */ true);
} else {
// Trigger the flow to set up secure backup, which is what this will do when in
// the appropriate state.
@ -130,14 +127,11 @@ export default class CrossSigningPanel extends React.PureComponent<{}, IState> {
const cli = MatrixClientPeg.get();
await cli.bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (makeRequest) => {
const { finished } = Modal.createTrackedDialog(
'Cross-signing keys dialog', '', InteractiveAuthDialog,
{
title: _t("Setting up keys"),
matrixClient: cli,
makeRequest,
},
);
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
title: _t("Setting up keys"),
matrixClient: cli,
makeRequest,
});
const [confirmed] = await finished;
if (!confirmed) {
throw new Error("Cross-signing key upload auth canceled");

View file

@ -91,7 +91,7 @@ export default class CryptographyPanel extends React.Component<IProps, IState> {
}
private onExportE2eKeysClicked = (): void => {
Modal.createTrackedDialogAsync('Export E2E Keys', '',
Modal.createDialogAsync(
import(
'../../../async-components/views/dialogs/security/ExportE2eKeysDialog'
) as unknown as Promise<ComponentType<{}>>,
@ -100,7 +100,7 @@ export default class CryptographyPanel extends React.Component<IProps, IState> {
};
private onImportE2eKeysClicked = (): void => {
Modal.createTrackedDialogAsync('Import E2E Keys', '',
Modal.createDialogAsync(
import(
'../../../async-components/views/dialogs/security/ImportE2eKeysDialog'
) as unknown as Promise<ComponentType<{}>>,

View file

@ -215,7 +215,7 @@ export default class DevicesPanel extends React.Component<IProps, IState> {
continueKind: "danger",
},
};
Modal.createTrackedDialog('Delete Device Dialog', '', InteractiveAuthDialog, {
Modal.createDialog(InteractiveAuthDialog, {
title: _t("Authentication"),
matrixClient: MatrixClientPeg.get(),
authData: error.data,

View file

@ -84,14 +84,14 @@ export default class DevicesPanelEntry extends React.Component<IProps, IState> {
};
private onOwnDeviceSignOut = (): void => {
Modal.createTrackedDialog('Logout from device list', '', LogoutDialog,
Modal.createDialog(LogoutDialog,
/* props= */{}, /* className= */null,
/* isPriority= */false, /* isStatic= */true);
};
private verify = async () => {
if (this.props.isOwnDevice) {
Modal.createTrackedDialog("Verify session", "Verify session", SetupEncryptionDialog, {
Modal.createDialog(SetupEncryptionDialog, {
onFinished: this.props.onDeviceChange,
});
} else {
@ -101,7 +101,7 @@ export default class DevicesPanelEntry extends React.Component<IProps, IState> {
userId,
[this.props.device.device_id],
);
Modal.createTrackedDialog('New Session Verification', 'Starting dialog', VerificationRequestDialog, {
Modal.createDialog(VerificationRequestDialog, {
verificationRequestPromise,
member: cli.getUser(userId),
onFinished: async () => {

View file

@ -108,7 +108,7 @@ export default class EventIndexPanel extends React.Component<{}, IState> {
}
private onManage = async () => {
Modal.createTrackedDialogAsync('Message search', 'Message search',
Modal.createDialogAsync(
// @ts-ignore: TS doesn't seem to like the type of this now that it
// has also been converted to TS as well, but I can't figure out why...
import('../../../async-components/views/dialogs/eventindex/ManageEventIndexDialog'),

View file

@ -75,7 +75,7 @@ const JoinRuleSettings = ({ room, promptUpgrade, aliasWarning, onError, beforeCh
}
const matrixClient = MatrixClientPeg.get();
const { finished } = Modal.createTrackedDialog('Edit restricted', '', ManageRestrictedJoinRuleDialog, {
const { finished } = Modal.createDialog(ManageRestrictedJoinRuleDialog, {
matrixClient,
room,
selected,
@ -227,7 +227,7 @@ const JoinRuleSettings = ({ room, promptUpgrade, aliasWarning, onError, beforeCh
</b>;
}
Modal.createTrackedDialog('Restricted join rule upgrade', '', RoomUpgradeWarningDialog, {
Modal.createDialog(RoomUpgradeWarningDialog, {
roomId: room.roomId,
targetVersion,
description: <>

View file

@ -277,7 +277,7 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
}
private showSaveError() {
Modal.createTrackedDialog('Error saving notification preferences', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t('Error saving notification preferences'),
description: _t('An error occurred whilst saving your notification preferences.'),
});

View file

@ -120,7 +120,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
}
} catch (err) {
logger.log("Failed to save profile", err);
Modal.createTrackedDialog('Failed to save profile', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Failed to save your profile"),
description: ((err && err.message) ? err.message : _t("The operation could not be completed")),
});

View file

@ -167,7 +167,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
}
private startNewBackup = (): void => {
Modal.createTrackedDialogAsync('Key Backup', 'Key Backup',
Modal.createDialogAsync(
import(
'../../../async-components/views/dialogs/security/CreateKeyBackupDialog'
) as unknown as Promise<ComponentType<{}>>,
@ -180,7 +180,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
};
private deleteBackup = (): void => {
Modal.createTrackedDialog('Delete Backup', '', QuestionDialog, {
Modal.createDialog(QuestionDialog, {
title: _t('Delete Backup'),
description: _t(
"Are you sure? You will lose your encrypted messages if your " +
@ -199,10 +199,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
};
private restoreBackup = async (): Promise<void> => {
Modal.createTrackedDialog(
'Restore Backup', '', RestoreKeyBackupDialog, null, null,
/* priority = */ false, /* static = */ true,
);
Modal.createDialog(RestoreKeyBackupDialog, null, null, /* priority = */ false, /* static = */ true);
};
private resetSecretStorage = async (): Promise<void> => {

View file

@ -219,7 +219,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
};
private showNoTermsWarning(fullUrl) {
const { finished } = Modal.createTrackedDialog('No Terms Warning', '', QuestionDialog, {
const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("Identity server has no terms of service"),
description: (
<div>
@ -320,7 +320,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
message = unboundMessage;
}
const { finished } = Modal.createTrackedDialog('Identity Server Bound Warning', '', QuestionDialog, {
const { finished } = Modal.createDialog(QuestionDialog, {
title,
description: message,
button,

View file

@ -80,7 +80,7 @@ export class ExistingEmailAddress extends React.Component<IExistingEmailAddressP
return this.props.onRemoved(this.props.email);
}).catch((err) => {
logger.error("Unable to remove contact information: " + err);
Modal.createTrackedDialog('Remove 3pid failed', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to remove contact information"),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
@ -168,7 +168,7 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
// TODO: Inline field validation
if (!Email.looksValid(email)) {
Modal.createTrackedDialog('Invalid email address', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Invalid Email Address"),
description: _t("This doesn't appear to be a valid email address"),
});
@ -183,7 +183,7 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
}).catch((err) => {
logger.error("Unable to add email address " + email + " " + err);
this.setState({ verifying: false, continueDisabled: false, addTask: null });
Modal.createTrackedDialog('Unable to add email address', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to add email address"),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
@ -215,14 +215,14 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
}).catch((err) => {
this.setState({ continueDisabled: false });
if (err.errcode === 'M_THREEPID_AUTH_FAILED') {
Modal.createTrackedDialog("Email hasn't been verified yet", "", ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Your email address hasn't been verified yet"),
description: _t("Click the link in the email you received to verify " +
"and then click continue again."),
});
} else {
logger.error("Unable to verify email address: ", err);
Modal.createTrackedDialog('Unable to verify email address', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to verify email address."),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});

View file

@ -76,7 +76,7 @@ export class ExistingPhoneNumber extends React.Component<IExistingPhoneNumberPro
return this.props.onRemoved(this.props.msisdn);
}).catch((err) => {
logger.error("Unable to remove contact information: " + err);
Modal.createTrackedDialog('Remove 3pid failed', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to remove contact information"),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
@ -185,7 +185,7 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
}).catch((err) => {
logger.error("Unable to add phone number " + phoneNumber + " " + err);
this.setState({ verifying: false, continueDisabled: false, addTask: null });
Modal.createTrackedDialog('Add Phone Number Error', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Error"),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
@ -222,7 +222,7 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
this.setState({ continueDisabled: false });
if (err.errcode !== 'M_THREEPID_AUTH_FAILED') {
logger.error("Unable to verify phone number: " + err);
Modal.createTrackedDialog('Unable to verify phone number', '', ErrorDialog, {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to verify phone number."),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});

Some files were not shown because too many files have changed in this diff Show more