diff --git a/res/css/_components.scss b/res/css/_components.scss index 566122a6823..29f2ec4eb6b 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -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"; diff --git a/res/css/views/dialogs/_Analytics.scss b/res/css/views/dialogs/_Analytics.scss deleted file mode 100644 index b0be14d6840..00000000000 --- a/res/css/views/dialogs/_Analytics.scss +++ /dev/null @@ -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; - } -} diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 4d87e0a2f02..bbce7ea8759 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -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; diff --git a/src/AddThreepid.ts b/src/AddThreepid.ts index 4c84294f7a6..415d6d7ad0e 100644 --- a/src/AddThreepid.ts +++ b/src/AddThreepid.ts @@ -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, diff --git a/src/Analytics.tsx b/src/Analytics.tsx deleted file mode 100644 index 0249c6ad1a2..00000000000 --- a/src/Analytics.tsx +++ /dev/null @@ -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 '#/'; - } - - if (hashVarRegex.test(hash)) { - return hash.replace(hashVarRegex, "#/$1/"); - } - - 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 = "//"; - } - - 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 = { - // 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 ''; -} - -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 = {}; // {[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>>; - 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>>; - 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>>; - 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: getRedactedUrl, - }, - ), - }, - { expl: _td('Your user agent'), value: navigator.userAgent }, - { expl: _td('Your device resolution'), value: resolution }, - ]; - - const piwikConfig = SdkConfig.get("piwik"); - let piwik: Optional>>; - if (typeof piwikConfig === 'object') { - piwik = new SnakedObject(piwikConfig); - } - const cookiePolicyUrl = piwik?.get("policy_url"); - const cookiePolicyLink = _t( - "Our complete cookie policy can be found here.", - {}, - { - "CookiePolicyLink": (sub) => { - return { sub }; - }, - }); - Modal.createTrackedDialog('Analytics Details', '', ErrorDialog, { - title: _t('Analytics'), - description:
- { cookiePolicyUrl &&

{ cookiePolicyLink }

} -
{ _t('Some examples of the information being sent to us to help make %(brand)s better includes:', { - brand: SdkConfig.get().brand, - }) }
- - { rows.map((row) => - - { row[1] !== undefined && } - ) } - { otherVariables.map((item, index) => - - - - , - ) } -
{ _t( - customVariables[row[0]].expl, - customVariables[row[0]].getTextVariables ? - customVariables[row[0]].getTextVariables() : - null, - ) }{ row[1] }
{ _t(item.expl) }{ item.value }
-
- { _t('Where this page includes identifiable information, such as a room, ' - + 'user ID, that data is removed before being sent to the server.') } -
-
, - }); - }; -} - -if (!window.mxAnalytics) { - window.mxAnalytics = new Analytics(); -} -export default window.mxAnalytics; diff --git a/src/CallHandler.tsx b/src/CallHandler.tsx index c64bedf8920..55c29c7a6f4 100644 --- a/src/CallHandler.tsx +++ b/src/CallHandler.tsx @@ -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 => { sub }; - Modal.createTrackedDialog('No TURN servers', '', QuestionDialog, { + Modal.createDialog(QuestionDialog, { title: _t("Call failed due to misconfigured server"), description:

{ _t( @@ -759,14 +753,12 @@ export default class CallHandler extends EventEmitter {

; } - Modal.createTrackedDialog('Media capture failed', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title, description, }, null, true); } private async placeMatrixCall(roomId: string, type: CallType, transferee?: MatrixCall): Promise { - 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 { 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 { 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); diff --git a/src/ContentMessages.ts b/src/ContentMessages.ts index f7b12f53e3f..ca8b68b5bbe 100644 --- a/src/ContentMessages.ts +++ b/src/ContentMessages.ts @@ -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, }); diff --git a/src/DecryptionFailureTracker.ts b/src/DecryptionFailureTracker.ts index eb1090f67d7..019f06d7755 100644 --- a/src/DecryptionFailureTracker.ts +++ b/src/DecryptionFailureTracker.ts @@ -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({ eventName: "Error", diff --git a/src/IConfigOptions.ts b/src/IConfigOptions.ts index cfaeecb75ea..09b179bc844 100644 --- a/src/IConfigOptions.ts +++ b/src/IConfigOptions.ts @@ -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` diff --git a/src/IdentityAuthClient.tsx b/src/IdentityAuthClient.tsx index 66f9ad4ddab..82baf6509c3 100644 --- a/src/IdentityAuthClient.tsx +++ b/src/IdentityAuthClient.tsx @@ -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: ( -
-

{ _t( - "This action requires accessing the default identity server " + - " to validate an email address or phone number, " + - "but the server does not have any terms of service.", {}, - { - server: () => { abbreviateUrl(identityServerUrl) }, - }, - ) }

-

{ _t( - "Only continue if you trust the owner of the server.", - ) }

-
- ), - button: _t("Trust"), - }); + const { finished } = Modal.createDialog(QuestionDialog, { + title: _t("Identity server has no terms of service"), + description: ( +
+

{ _t( + "This action requires accessing the default identity server " + + " to validate an email address or phone number, " + + "but the server does not have any terms of service.", {}, + { + server: () => { abbreviateUrl(identityServerUrl) }, + }, + ) }

+

{ _t( + "Only continue if you trust the owner of the server.", + ) }

+
+ ), + button: _t("Trust"), + }); const [confirmed] = await finished; if (confirmed) { // eslint-disable-next-line react-hooks/rules-of-hooks diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index e663a410461..4915d17e3f9 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -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 { 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 { return new Promise(resolve => { - Modal.createTrackedDialog('Storage evicted', '', StorageEvictedDialog, { + Modal.createDialog(StorageEvictedDialog, { onFinished: resolve, }); }); @@ -880,8 +877,6 @@ export async function onLoggedOut(): Promise { * @returns {Promise} promise which resolves once the stores have been cleared */ async function clearStorage(opts?: { deleteEverything?: boolean }): Promise { - Analytics.disable(); - if (window.localStorage) { // try to save any 3pid invites from being obliterated and registration time const pendingInvites = ThreepidInviteStore.instance.getWireInvites(); diff --git a/src/MatrixClientPeg.ts b/src/MatrixClientPeg.ts index e51eb789d8c..e8296afc521 100644 --- a/src/MatrixClientPeg.ts +++ b/src/MatrixClientPeg.ts @@ -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 diff --git a/src/Modal.tsx b/src/Modal.tsx index a802e36d967..af9ec22b699 100644 --- a/src/Modal.tsx +++ b/src/Modal.tsx @@ -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( - analyticsAction: string, - analyticsInfo: string, - ...rest: Parameters - ) { - Analytics.trackEvent('Modal', analyticsAction, analyticsInfo); - return this.createDialog(...rest); - } - - public appendTrackedDialog( - analyticsAction: string, - analyticsInfo: string, - ...rest: Parameters - ) { - Analytics.trackEvent('Modal', analyticsAction, analyticsInfo); - return this.appendDialog(...rest); - } - public createDialog( Element: React.ComponentType, ...rest: ParametersWithoutFirst @@ -135,24 +116,6 @@ export class ModalManager { return this.appendDialogAsync(Promise.resolve(Element), ...rest); } - public createTrackedDialogAsync( - analyticsAction: string, - analyticsInfo: string, - ...rest: Parameters - ) { - Analytics.trackEvent('Modal', analyticsAction, analyticsInfo); - return this.createDialogAsync(...rest); - } - - public appendTrackedDialogAsync( - analyticsAction: string, - analyticsInfo: string, - ...rest: Parameters - ) { - Analytics.trackEvent('Modal', analyticsAction, analyticsInfo); - return this.appendDialogAsync(...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( + public createDialogAsync( prom: Promise, props?: IProps, className?: string, diff --git a/src/Notifier.ts b/src/Notifier.ts index 60b47bfc891..88f0181ad25 100644 --- a/src/Notifier.ts +++ b/src/Notifier.ts @@ -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 diff --git a/src/Registration.tsx b/src/Registration.tsx index 87efcd6557d..7387a1d8872 100644 --- a/src/Registration.tsx +++ b/src/Registration.tsx @@ -49,7 +49,7 @@ export async function startAnyRegistrationFlow( options: { go_home_on_cancel?: boolean, go_welcome_on_cancel?: boolean, screen_after?: boolean}, ): Promise { 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"), diff --git a/src/RoomInvite.tsx b/src/RoomInvite.tsx index ff34c66274a..639840e57e2 100644 --- a/src/RoomInvite.tsx +++ b/src/RoomInvite.tsx @@ -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( ; - Modal.createTrackedDialog("Some invites could not be sent", "", ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t("Some invites couldn't be sent"), description, }); diff --git a/src/SecurityManager.ts b/src/SecurityManager.ts index 50b5f0c950a..73d3f20afc6 100644 --- a/src/SecurityManager.ts +++ b/src/SecurityManager.ts @@ -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 { 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>, @@ -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"); diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index 8bbc3acd78d..72233e6d922 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -82,7 +82,7 @@ const singleMxcUpload = async (): Promise => { 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:
{ body }
, 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:

{ _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), - }, - ) }

, - button: _t("Continue"), - }, - ); + const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, { + title: _t("Use an identity server"), + description:

{ _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), + }, + ) }

, + 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:

{ _t('You are now ignoring %(userId)s', { userId }) }

@@ -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:

{ _t('You are no longer ignoring %(userId)s', { userId }) }

@@ -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:

@@ -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: "", runFn: function(roomId, args) { return success( - Modal.createTrackedDialog('Slash Commands', 'Bug Report Dialog', BugReportDialog, { + Modal.createDialog(BugReportDialog, { initialText: args, }).finished, ); diff --git a/src/Terms.ts b/src/Terms.ts index aa94309ae35..bb7ebb59090 100644 --- a/src/Terms.ts +++ b/src/Terms.ts @@ -190,7 +190,7 @@ export async function dialogTermsInteractionCallback( ): Promise { 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)); diff --git a/src/actions/RoomListActions.ts b/src/actions/RoomListActions.ts index 696403aca82..9d614c73c0a 100644 --- a/src/actions/RoomListActions.ts +++ b/src/actions/RoomListActions.ts @@ -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')), }); diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx index c5e0fecacc5..6cc2f6526f9 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx @@ -134,10 +134,7 @@ export default class ManageEventIndexDialog extends React.Component { 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) => { diff --git a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx index 466c7dde363..769c41419b0 100644 --- a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx +++ b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx @@ -303,18 +303,15 @@ export default class CreateSecretStorageDialog extends React.PureComponent 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(); diff --git a/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.tsx b/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.tsx index ff21dba7ca6..8f7b1cd4e63 100644 --- a/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.tsx +++ b/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.tsx @@ -43,11 +43,9 @@ export default class NewRecoveryMethodDialog extends React.PureComponent }; private onSetupClick = async (): Promise => { - 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 { diff --git a/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.tsx b/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.tsx index a47e7636b38..1eb845a12aa 100644 --- a/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.tsx +++ b/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.tsx @@ -35,7 +35,7 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent { this.props.onFinished(); - Modal.createTrackedDialogAsync("Key Backup", "Key Backup", + Modal.createDialogAsync( import("./CreateKeyBackupDialog") as unknown as Promise>, null, null, /* priority = */ false, /* static = */ true, ); diff --git a/src/components/structures/HomePage.tsx b/src/components/structures/HomePage.tsx index e84d115e43d..200c28d159f 100644 --- a/src/components/structures/HomePage.tsx +++ b/src/components/structures/HomePage.tsx @@ -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' }); }; diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index c8c59cdcbac..072234b1ed0 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -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 { }); } - if (SettingsStore.getValue("pseudonymousAnalyticsOptIn")) { - Analytics.enable(); - } - initSentry(SdkConfig.get("sentry")); } @@ -406,7 +400,6 @@ export default class MatrixChat extends React.PureComponent { 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 { 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 { } }, (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 { 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 { 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 { }); 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 { 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 { } 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 { 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: ( @@ -1156,7 +1136,7 @@ export default class MatrixChat extends React.PureComponent { 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 { 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 { 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 { } } - 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 { 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 { 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 { }); }); cli.on(HttpApiEvent.NoConsent, function(message, consentUri) { - Modal.createTrackedDialog('No Consent Dialog', '', QuestionDialog, { + Modal.createDialog(QuestionDialog, { title: _t('Terms and Conditions'), description:

{ _t( @@ -1535,7 +1509,7 @@ export default class MatrixChat extends React.PureComponent { 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 { } if (haveNewVersion) { - Modal.createTrackedDialogAsync('New Recovery Method', 'New Recovery Method', + Modal.createDialogAsync( import( '../../async-components/views/dialogs/security/NewRecoveryMethodDialog' ) as unknown as Promise>, { newVersionInfo }, ); } else { - Modal.createTrackedDialogAsync('Recovery Method Removed', 'Recovery Method Removed', + Modal.createDialogAsync( import( '../../async-components/views/dialogs/security/RecoveryMethodRemovedDialog' ) as unknown as Promise>, @@ -1585,16 +1559,14 @@ export default class MatrixChat extends React.PureComponent { }); 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) { diff --git a/src/components/structures/RoomDirectory.tsx b/src/components/structures/RoomDirectory.tsx index aa8f38556a7..bd16d976ab7 100644 --- a/src/components/structures/RoomDirectory.tsx +++ b/src/components/structures/RoomDirectory.tsx @@ -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 { // 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 { } 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 { 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 { 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 { }); } catch (e) { if (e instanceof GenericError) { - Modal.createTrackedDialog(e.message, '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: e.message, description: e.description, }); diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx index 77faf0f9298..b980d1739fe 100644 --- a/src/components/structures/RoomSearch.tsx +++ b/src/components/structures/RoomSearch.tsx @@ -104,7 +104,7 @@ export default class RoomSearch extends React.PureComponent { }; private openSpotlight() { - Modal.createTrackedDialog("Spotlight", "", SpotlightDialog, {}, "mx_SpotlightDialog_wrapper", false, true); + Modal.createDialog(SpotlightDialog, {}, "mx_SpotlightDialog_wrapper", false, true); } private onAction = (payload: ActionPayload) => { diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index bb07c62b816..dbab94e8e58 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -1397,7 +1397,7 @@ export class RoomView extends React.Component { }); }, (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 { 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 { 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, }); diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx index a84013bb221..0057a74cc8c 100644 --- a/src/components/structures/ThreadPanel.tsx +++ b/src/components/structures/ThreadPanel.tsx @@ -234,7 +234,7 @@ const ThreadPanel: React.FC = ({ }, [timelineSet, timelinePanel]); const openFeedback = SdkConfig.get().bug_report_endpoint_url ? () => { - Modal.createTrackedDialog("Threads Feedback", "feature_thread", BetaFeedbackDialog, { + Modal.createDialog(BetaFeedbackDialog, { featureId: "feature_thread", }); } : null; diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index f742adad899..d6dfabe71a9 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -1353,7 +1353,7 @@ class TimelinePanel extends React.Component { ); } - Modal.createTrackedDialog('Failed to load timeline position', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t("Failed to load timeline position"), description, onFinished, diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index a9f072b21fa..6da5f86bda5 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -229,7 +229,7 @@ export default class UserMenu extends React.Component { 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 { // 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 diff --git a/src/components/structures/UserView.tsx b/src/components/structures/UserView.tsx index 9ba9d808c91..7754336b2bd 100644 --- a/src/components/structures/UserView.tsx +++ b/src/components/structures/UserView.tsx @@ -70,7 +70,7 @@ export default class UserView extends React.Component { 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")), }); diff --git a/src/components/structures/auth/ForgotPassword.tsx b/src/components/structures/auth/ForgotPassword.tsx index df39f0aa8f2..5c58903ff78 100644 --- a/src/components/structures/auth/ForgotPassword.tsx +++ b/src/components/structures/auth/ForgotPassword.tsx @@ -199,7 +199,7 @@ export default class ForgotPassword extends React.Component { } if (this.state.logoutDevices) { - const { finished } = Modal.createTrackedDialog<[boolean]>('Forgot Password Warning', '', QuestionDialog, { + const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, { title: _t('Warning!'), description:

@@ -271,7 +271,7 @@ export default class ForgotPassword extends React.Component { }; public showErrorDialog(description: string, title?: string) { - Modal.createTrackedDialog('Forgot Password Error', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title, description, }); diff --git a/src/components/structures/auth/SetupEncryptionBody.tsx b/src/components/structures/auth/SetupEncryptionBody.tsx index 5caaea0c988..647202a60f8 100644 --- a/src/components/structures/auth/SetupEncryptionBody.tsx +++ b/src/components/structures/auth/SetupEncryptionBody.tsx @@ -98,7 +98,7 @@ export default class SetupEncryptionBody extends React.Component // 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 () => { diff --git a/src/components/structures/auth/SoftLogout.tsx b/src/components/structures/auth/SoftLogout.tsx index 7a366d71225..a8a1f30c032 100644 --- a/src/components/structures/auth/SoftLogout.tsx +++ b/src/components/structures/auth/SoftLogout.tsx @@ -101,7 +101,7 @@ export default class SoftLogout extends React.Component { } private onClearAll = () => { - Modal.createTrackedDialog('Clear Data', 'Soft Logout', ConfirmWipeDeviceDialog, { + Modal.createDialog(ConfirmWipeDeviceDialog, { onFinished: (wipeData) => { if (!wipeData) return; diff --git a/src/components/views/auth/RegistrationForm.tsx b/src/components/views/auth/RegistrationForm.tsx index 83ee70a7053..e4a283c5511 100644 --- a/src/components/views/auth/RegistrationForm.tsx +++ b/src/components/views/auth/RegistrationForm.tsx @@ -126,7 +126,7 @@ export default class RegistrationForm extends React.PureComponent { if (confirmed) { this.setState({ diff --git a/src/components/views/beta/BetaCard.tsx b/src/components/views/beta/BetaCard.tsx index ac08841bf58..3db52a0b69d 100644 --- a/src/components/views/beta/BetaCard.tsx +++ b/src/components/views/beta/BetaCard.tsx @@ -91,7 +91,7 @@ const BetaCard = ({ title: titleOverride, featureId }: IProps) => { if (value && feedbackLabel && feedbackSubheading && SdkConfig.get().bug_report_endpoint_url) { feedbackButton = { - Modal.createTrackedDialog("Beta Feedback", featureId, BetaFeedbackDialog, { featureId }); + Modal.createDialog(BetaFeedbackDialog, { featureId }); }} kind="primary" > diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx index 6703c34198a..f54bee8c0ed 100644 --- a/src/components/views/context_menus/MessageContextMenu.tsx +++ b/src/components/views/context_menus/MessageContextMenu.tsx @@ -173,7 +173,7 @@ export default class MessageContextMenu extends React.Component }; 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 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 private onEndPollClick = (): void => { const matrixClient = MatrixClientPeg.get(); - Modal.createTrackedDialog('End Poll', '', EndPollDialog, { + Modal.createDialog(EndPollDialog, { matrixClient, event: this.props.mxEvent, getRelationsForEvent: this.props.getRelationsForEvent, diff --git a/src/components/views/context_menus/RoomContextMenu.tsx b/src/components/views/context_menus/RoomContextMenu.tsx index e8aa73c7790..3dfa9e4350d 100644 --- a/src/components/views/context_menus/RoomContextMenu.tsx +++ b/src/components/views/context_menus/RoomContextMenu.tsx @@ -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")} diff --git a/src/components/views/context_menus/WidgetContextMenu.tsx b/src/components/views/context_menus/WidgetContextMenu.tsx index b6a46bd2aca..550a50ce5a7 100644 --- a/src/components/views/context_menus/WidgetContextMenu.tsx +++ b/src/components/views/context_menus/WidgetContextMenu.tsx @@ -69,7 +69,7 @@ const WidgetContextMenu: React.FC = ({ 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 = ({ 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." + diff --git a/src/components/views/dialogs/AnalyticsLearnMoreDialog.tsx b/src/components/views/dialogs/AnalyticsLearnMoreDialog.tsx index a4cb0deae14..788d12932bf 100644 --- a/src/components/views/dialogs/AnalyticsLearnMoreDialog.tsx +++ b/src/components/views/dialogs/AnalyticsLearnMoreDialog.tsx @@ -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 = ({ }; export const showDialog = (props: Omit): void => { - const piwikConfig = SdkConfig.get("piwik"); - let privacyPolicyUrl: Optional; - 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; diff --git a/src/components/views/dialogs/BugReportDialog.tsx b/src/components/views/dialogs/BugReportDialog.tsx index b6ff9440471..7df389f8867 100644 --- a/src/components/views/dialogs/BugReportDialog.tsx +++ b/src/components/views/dialogs/BugReportDialog.tsx @@ -110,8 +110,7 @@ export default class BugReportDialog extends React.Component { }).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, diff --git a/src/components/views/dialogs/ConfirmRedactDialog.tsx b/src/components/views/dialogs/ConfirmRedactDialog.tsx index 9a9f3627d2f..1f704fbe73e 100644 --- a/src/components/views/dialogs/ConfirmRedactDialog.tsx +++ b/src/components/views/dialogs/ConfirmRedactDialog.tsx @@ -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 }), }); diff --git a/src/components/views/dialogs/CryptoStoreTooNewDialog.tsx b/src/components/views/dialogs/CryptoStoreTooNewDialog.tsx index e8d267414a1..5ae15d826c9 100644 --- a/src/components/views/dialogs/CryptoStoreTooNewDialog.tsx +++ b/src/components/views/dialogs/CryptoStoreTooNewDialog.tsx @@ -32,7 +32,7 @@ const CryptoStoreTooNewDialog: React.FC = (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 " + diff --git a/src/components/views/dialogs/DeactivateAccountDialog.tsx b/src/components/views/dialogs/DeactivateAccountDialog.tsx index 55251025fb7..0eb81c932be 100644 --- a/src/components/views/dialogs/DeactivateAccountDialog.tsx +++ b/src/components/views/dialogs/DeactivateAccountDialog.tsx @@ -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 { // Deactivation worked - logout & close this dialog - Analytics.trackEvent('Account', 'Deactivate Account'); defaultDispatcher.fire(Action.TriggerLogout); this.props.onFinished(true); }).catch(e => { diff --git a/src/components/views/dialogs/EndPollDialog.tsx b/src/components/views/dialogs/EndPollDialog.tsx index 743ff898857..9a4b32cf798 100644 --- a/src/components/views/dialogs/EndPollDialog.tsx +++ b/src/components/views/dialogs/EndPollDialog.tsx @@ -62,16 +62,11 @@ export default class EndPollDialog extends React.Component { 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); diff --git a/src/components/views/dialogs/ErrorDialog.tsx b/src/components/views/dialogs/ErrorDialog.tsx index 286124c6bf6..25f5691e80c 100644 --- a/src/components/views/dialogs/ErrorDialog.tsx +++ b/src/components/views/dialogs/ErrorDialog.tsx @@ -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", diff --git a/src/components/views/dialogs/FeedbackDialog.tsx b/src/components/views/dialogs/FeedbackDialog.tsx index f4bddf8e87b..373db592087 100644 --- a/src/components/views/dialogs/FeedbackDialog.tsx +++ b/src/components/views/dialogs/FeedbackDialog.tsx @@ -47,7 +47,7 @@ const FeedbackDialog: React.FC = (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 = (props: IProps) => { submitFeedback(rageshakeUrl, "feedback", comment, canContact); } - Modal.createTrackedDialog('Feedback sent', '', InfoDialog, { + Modal.createDialog(InfoDialog, { title: _t('Feedback sent'), description: _t('Thank you!'), }); diff --git a/src/components/views/dialogs/GenericFeatureFeedbackDialog.tsx b/src/components/views/dialogs/GenericFeatureFeedbackDialog.tsx index 17fab187d0a..0305962be3f 100644 --- a/src/components/views/dialogs/GenericFeatureFeedbackDialog.tsx +++ b/src/components/views/dialogs/GenericFeatureFeedbackDialog.tsx @@ -50,7 +50,7 @@ const GenericFeatureFeedbackDialog: React.FC = ({ 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"), diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index d8a6b7df7a5..118b9da9a02 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -904,7 +904,7 @@ export default class InviteDialog extends React.PureComponent 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", diff --git a/src/components/views/dialogs/LogoutDialog.tsx b/src/components/views/dialogs/LogoutDialog.tsx index 8e6550a17a3..cea5d317185 100644 --- a/src/components/views/dialogs/LogoutDialog.tsx +++ b/src/components/views/dialogs/LogoutDialog.tsx @@ -80,7 +80,7 @@ export default class LogoutDialog extends React.Component { } private onExportE2eKeysClicked = (): void => { - Modal.createTrackedDialogAsync('Export E2E Keys', '', + Modal.createDialogAsync( import( '../../../async-components/views/dialogs/security/ExportE2eKeysDialog' ) as unknown as Promise>, @@ -103,12 +103,9 @@ export default class LogoutDialog extends React.Component { // 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>, diff --git a/src/components/views/dialogs/RoomUpgradeDialog.tsx b/src/components/views/dialogs/RoomUpgradeDialog.tsx index 8ff2181d75a..d3041634a29 100644 --- a/src/components/views/dialogs/RoomUpgradeDialog.tsx +++ b/src/components/views/dialogs/RoomUpgradeDialog.tsx @@ -56,7 +56,7 @@ export default class RoomUpgradeDialog extends React.Component { 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")), }); diff --git a/src/components/views/dialogs/RoomUpgradeWarningDialog.tsx b/src/components/views/dialogs/RoomUpgradeWarningDialog.tsx index a34674ff63f..b66a180ecab 100644 --- a/src/components/views/dialogs/RoomUpgradeWarningDialog.tsx +++ b/src/components/views/dialogs/RoomUpgradeWarningDialog.tsx @@ -97,7 +97,7 @@ export default class RoomUpgradeWarningDialog extends React.Component { 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:
{ _t("Sign out and remove encryption keys?") }
, diff --git a/src/components/views/dialogs/SetEmailDialog.tsx b/src/components/views/dialogs/SetEmailDialog.tsx index 773f56db026..e8dc24b4aa2 100644 --- a/src/components/views/dialogs/SetEmailDialog.tsx +++ b/src/components/views/dialogs/SetEmailDialog.tsx @@ -64,7 +64,7 @@ export default class SetEmailDialog extends React.Component { 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 { } 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 { }, (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 { 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 { }); } 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")), }); diff --git a/src/components/views/dialogs/SpotlightDialog.tsx b/src/components/views/dialogs/SpotlightDialog.tsx index 3287a9b95a9..c94a5097caf 100644 --- a/src/components/views/dialogs/SpotlightDialog.tsx +++ b/src/components/views/dialogs/SpotlightDialog.tsx @@ -701,7 +701,7 @@ const SpotlightDialog: React.FC = ({ initialText = "", onFinished }) => }; const openFeedback = SdkConfig.get().bug_report_endpoint_url ? () => { - Modal.createTrackedDialog("Spotlight Feedback", "feature_spotlight", BetaFeedbackDialog, { + Modal.createDialog(BetaFeedbackDialog, { featureId: "feature_spotlight", }); } : null; diff --git a/src/components/views/dialogs/StorageEvictedDialog.tsx b/src/components/views/dialogs/StorageEvictedDialog.tsx index cd01fef2b8f..538fddd9a29 100644 --- a/src/components/views/dialogs/StorageEvictedDialog.tsx +++ b/src/components/views/dialogs/StorageEvictedDialog.tsx @@ -30,7 +30,7 @@ interface IProps extends IDialogProps { } export default class StorageEvictedDialog extends React.Component { private sendBugReport = (ev: React.MouseEvent): void => { ev.preventDefault(); - Modal.createTrackedDialog('Storage evicted', 'Send Bug Report Dialog', BugReportDialog, {}); + Modal.createDialog(BugReportDialog, {}); }; private onSignOutClick = (): void => { diff --git a/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx b/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx index ac7eea8e2b6..ee6d884b8cf 100644 --- a/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx +++ b/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx @@ -233,14 +233,11 @@ export default class AccessSecretStorageDialog extends React.PureComponent { - 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"); diff --git a/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx b/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx index 70bf21329fb..34f67b1407d 100644 --- a/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx +++ b/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx @@ -123,18 +123,15 @@ export default class CreateCrossSigningDialog extends React.PureComponent { closeMenu(); - const { finished } = Modal.createTrackedDialog( - "Network Dropdown", "Remove server", QuestionDialog, - { - title: _t("Are you sure?"), - description: _t("Are you sure you want to remove %(serverName)s", { - serverName: server, - }, { - b: serverName => { serverName }, - }), - 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 %(serverName)s", { + serverName: server, + }, { + b: serverName => { serverName }, + }), + 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"), diff --git a/src/components/views/elements/ActionButton.tsx b/src/components/views/elements/ActionButton.tsx deleted file mode 100644 index 9d8038f99e1..00000000000 --- a/src/components/views/elements/ActionButton.tsx +++ /dev/null @@ -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 { - static defaultProps: Partial = { - 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 = ; - } - - const icon = this.props.iconPath ? - () : - undefined; - - const classNames = ["mx_RoleButton"]; - if (this.props.className) { - classNames.push(this.props.className); - } - - return ( - - { icon } - { tooltip } - { this.props.children } - - ); - } -} diff --git a/src/components/views/elements/ErrorBoundary.tsx b/src/components/views/elements/ErrorBoundary.tsx index 4d281de12cd..e174e6ab39a 100644 --- a/src/components/views/elements/ErrorBoundary.tsx +++ b/src/components/views/elements/ErrorBoundary.tsx @@ -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, }); diff --git a/src/components/views/elements/MiniAvatarUploader.tsx b/src/components/views/elements/MiniAvatarUploader.tsx index c501c92ac9f..7e744591ec3 100644 --- a/src/components/views/elements/MiniAvatarUploader.tsx +++ b/src/components/views/elements/MiniAvatarUploader.tsx @@ -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 = ({ 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); diff --git a/src/components/views/elements/PollCreateDialog.tsx b/src/components/views/elements/PollCreateDialog.tsx index f713a779acc..b7a117d4938 100644 --- a/src/components/views/elements/PollCreateDialog.tsx +++ b/src/components/views/elements/PollCreateDialog.tsx @@ -172,25 +172,20 @@ export default class PollCreateDialog extends ScrollableBaseModal 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 }); + } }, - ); + }); }); } diff --git a/src/components/views/elements/ServerPicker.tsx b/src/components/views/elements/ServerPicker.tsx index e7b2f9ccf00..7276bd20c70 100644 --- a/src/components/views/elements/ServerPicker.tsx +++ b/src/components/views/elements/ServerPicker.tsx @@ -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 " + diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index c7fb5cd3148..ce351875ae0 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -183,15 +183,10 @@ class LocationPicker extends React.Component { // 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) { diff --git a/src/components/views/location/shareLocation.ts b/src/components/views/location/shareLocation.ts index 895f2c23c6c..5ff91939bc6 100644 --- a/src/components/views/location/shareLocation.ts +++ b/src/components/views/location/shareLocation.ts @@ -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 = ( diff --git a/src/components/views/messages/DateSeparator.tsx b/src/components/views/messages/DateSeparator.tsx index 54dde16dac2..42e7d7dbf3b 100644 --- a/src/components/views/messages/DateSeparator.tsx +++ b/src/components/views/messages/DateSeparator.tsx @@ -154,7 +154,7 @@ export default class DateSeparator extends React.Component { // 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 }), }); diff --git a/src/components/views/messages/EditHistoryMessage.tsx b/src/components/views/messages/EditHistoryMessage.tsx index 30922b62e5b..51c39be9b24 100644 --- a/src/components/views/messages/EditHistoryMessage.tsx +++ b/src/components/views/messages/EditHistoryMessage.tsx @@ -75,13 +75,13 @@ export default class EditHistoryMessage extends React.PureComponent 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'); }; diff --git a/src/components/views/messages/MBeaconBody.tsx b/src/components/views/messages/MBeaconBody.tsx index 91c54d701a4..ddb700c07a8 100644 --- a/src/components/views/messages/MBeaconBody.tsx +++ b/src/components/views/messages/MBeaconBody.tsx @@ -106,9 +106,7 @@ const MBeaconBody: React.FC = React.forwardRef(({ mxEvent }, ref) => if (displayStatus !== BeaconDisplayStatus.Active) { return; } - Modal.createTrackedDialog( - 'Beacon View', - '', + Modal.createDialog( BeaconViewDialog, { roomId: mxEvent.getRoomId(), diff --git a/src/components/views/messages/MFileBody.tsx b/src/components/views/messages/MFileBody.tsx index 1b2eaeeb501..7942f90999f 100644 --- a/src/components/views/messages/MFileBody.tsx +++ b/src/components/views/messages/MFileBody.tsx @@ -172,7 +172,7 @@ export default class MFileBody extends React.Component { }); } 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"), }); diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index f5cdf3a969c..d841133ed86 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -57,9 +57,7 @@ export default class MLocationBody extends React.Component { } private onClick = () => { - Modal.createTrackedDialog( - 'Location View', - '', + Modal.createDialog( LocationViewDialog, { matrixClient: this.context, diff --git a/src/components/views/messages/MPollBody.tsx b/src/components/views/messages/MPollBody.tsx index bea4266d2ea..7a48c7212a6 100644 --- a/src/components/views/messages/MPollBody.tsx +++ b/src/components/views/messages/MPollBody.tsx @@ -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 { ).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"), diff --git a/src/components/views/messages/TextualBody.tsx b/src/components/views/messages/TextualBody.tsx index e8239097110..89bb9adc854 100644 --- a/src/components/views/messages/TextualBody.tsx +++ b/src/components/views/messages/TextualBody.tsx @@ -468,7 +468,7 @@ export default class TextualBody extends React.Component { 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:
diff --git a/src/components/views/messages/TileErrorBoundary.tsx b/src/components/views/messages/TileErrorBoundary.tsx index c30a68bb96e..3c453f1ee82 100644 --- a/src/components/views/messages/TileErrorBoundary.tsx +++ b/src/components/views/messages/TileErrorBoundary.tsx @@ -52,14 +52,14 @@ export default class TileErrorBoundary extends React.Component { } 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'); }; diff --git a/src/components/views/right_panel/EncryptionPanel.tsx b/src/components/views/right_panel/EncryptionPanel.tsx index c2dfd7a379b..4aa3c8049b9 100644 --- a/src/components/views/right_panel/EncryptionPanel.tsx +++ b/src/components/views/right_panel/EncryptionPanel.tsx @@ -84,7 +84,7 @@ const EncryptionPanel: React.FC = (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:
diff --git a/src/components/views/right_panel/HeaderButton.tsx b/src/components/views/right_panel/HeaderButton.tsx index f422bede7ee..d78dbb867d5 100644 --- a/src/components/views/right_panel/HeaderButton.tsx +++ b/src/components/views/right_panel/HeaderButton.tsx @@ -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; // 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 { - 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 { role="tab" title={title} className={classes} - onClick={this.onClick} + onClick={onClick} />; } } diff --git a/src/components/views/right_panel/RoomHeaderButtons.tsx b/src/components/views/right_panel/RoomHeaderButtons.tsx index cb661d00a13..5a176805221 100644 --- a/src/components/views/right_panel/RoomHeaderButtons.tsx +++ b/src/components/views/right_panel/RoomHeaderButtons.tsx @@ -95,7 +95,6 @@ const PinnedMessagesHeaderButton = ({ room, isHighlighted, onClick }: IHeaderBut isHighlighted={isHighlighted} isUnread={!!unreadIndicator} onClick={onClick} - analytics={["Right Panel", "Pinned Messages Button", "click"]} > { unreadIndicator } ; @@ -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 } ; @@ -244,7 +242,7 @@ export default class RoomHeaderButtons extends HeaderButtons { onClick={this.onThreadsPanelClicked} isHighlighted={this.isPhase(RoomHeaderButtons.THREAD_PHASES)} isUnread={this.threadNotificationState.color > 0} - analytics={['Right Panel', 'Threads List Button', 'click']}> + > : null, @@ -256,7 +254,7 @@ export default class RoomHeaderButtons extends HeaderButtons { title={_t('Notifications')} isHighlighted={this.isPhase(RightPanelPhases.NotificationPanel)} onClick={this.onNotificationsClicked} - analytics={['Right Panel', 'Notification List Button', 'click']} />, + />, ); rightPanelPhaseButtons.set(RightPanelPhases.RoomSummary, { title={_t('Room Info')} isHighlighted={this.isPhase(ROOM_INFO_PHASES)} onClick={this.onRoomSummaryClicked} - analytics={['Right Panel', 'Room Summary Button', 'click']} />, + />, ); return <> diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx index fe335fab3cc..f0ff1d9d447 100644 --- a/src/components/views/right_panel/RoomSummaryCard.tsx +++ b/src/components/views/right_panel/RoomSummaryCard.tsx @@ -248,13 +248,13 @@ const RoomSummaryCard: React.FC = ({ 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, }); }; diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index abd55fc6073..04a5097649c 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -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:
@@ -590,9 +590,7 @@ const RoomKickButton = ({ room, member, startUpdating, stopUpdating }: Omit { - 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 = ({ 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 { - 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 = ({ 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:
@@ -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:
{ _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")), }); diff --git a/src/components/views/room_settings/AliasSettings.tsx b/src/components/views/room_settings/AliasSettings.tsx index 1a3e9bd417c..d1080a90666 100644 --- a/src/components/views/room_settings/AliasSettings.tsx +++ b/src/components/views/room_settings/AliasSettings.tsx @@ -173,7 +173,7 @@ export default class AliasSettings extends React.Component { 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 { .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 { } }).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 { "error occurred.", ); } - Modal.createTrackedDialog('Error removing address', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t("Error removing address"), description, }); diff --git a/src/components/views/rooms/MessageComposerButtons.tsx b/src/components/views/rooms/MessageComposerButtons.tsx index fe5c42ea261..0a7f611b71c 100644 --- a/src/components/views/rooms/MessageComposerButtons.tsx +++ b/src/components/views/rooms/MessageComposerButtons.tsx @@ -315,9 +315,7 @@ class PollButton extends React.PureComponent { 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 { ? this.props.relation.event_id : null; - Modal.createTrackedDialog( - 'Polls', - 'create', + Modal.createDialog( PollCreateDialog, { room: this.props.room, diff --git a/src/components/views/rooms/RoomBreadcrumbs.tsx b/src/components/views/rooms/RoomBreadcrumbs.tsx index af06f41bf49..0ed34e9476a 100644 --- a/src/components/views/rooms/RoomBreadcrumbs.tsx +++ b/src/components/views/rooms/RoomBreadcrumbs.tsx @@ -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 }; private viewRoom = (room: Room, index: number, viaKeyboard = false) => { - Analytics.trackEvent("Breadcrumbs", "click_node", String(index)); defaultDispatcher.dispatch({ action: Action.ViewRoom, room_id: room.roomId, diff --git a/src/components/views/rooms/RoomUpgradeWarningBar.tsx b/src/components/views/rooms/RoomUpgradeWarningBar.tsx index 47d19b8b5e3..9bf9b79d197 100644 --- a/src/components/views/rooms/RoomUpgradeWarningBar.tsx +++ b/src/components/views/rooms/RoomUpgradeWarningBar.tsx @@ -66,7 +66,7 @@ export default class RoomUpgradeWarningBar extends React.PureComponent { - Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, { room: this.props.room }); + Modal.createDialog(RoomUpgradeDialog, { room: this.props.room }); }; public render(): JSX.Element { diff --git a/src/components/views/rooms/ThirdPartyMemberInfo.tsx b/src/components/views/rooms/ThirdPartyMemberInfo.tsx index 6ff87cf52a1..57a762940af 100644 --- a/src/components/views/rooms/ThirdPartyMemberInfo.tsx +++ b/src/components/views/rooms/ThirdPartyMemberInfo.tsx @@ -106,7 +106,7 @@ export default class ThirdPartyMemberInfo extends React.Component { - Modal.createTrackedDialog('Microphone Access Error', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t("Unable to access your microphone"), description: <>

{ _t( @@ -177,7 +177,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent

{ _t( diff --git a/src/components/views/settings/ChangePassword.tsx b/src/components/views/settings/ChangePassword.tsx index 39e7ff8d1d0..f7c174da3b2 100644 --- a/src/components/views/settings/ChangePassword.tsx +++ b/src/components/views/settings/ChangePassword.tsx @@ -95,7 +95,7 @@ export default class ChangePassword extends React.Component { 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:

@@ -196,14 +196,14 @@ export default class ChangePassword extends React.Component { private optionallySetEmail(): Promise { // 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>, diff --git a/src/components/views/settings/CrossSigningPanel.tsx b/src/components/views/settings/CrossSigningPanel.tsx index 5c6e650c9fb..a70e0c8deeb 100644 --- a/src/components/views/settings/CrossSigningPanel.tsx +++ b/src/components/views/settings/CrossSigningPanel.tsx @@ -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"); diff --git a/src/components/views/settings/CryptographyPanel.tsx b/src/components/views/settings/CryptographyPanel.tsx index dd580058afb..e6bb854eb2f 100644 --- a/src/components/views/settings/CryptographyPanel.tsx +++ b/src/components/views/settings/CryptographyPanel.tsx @@ -91,7 +91,7 @@ export default class CryptographyPanel extends React.Component { } private onExportE2eKeysClicked = (): void => { - Modal.createTrackedDialogAsync('Export E2E Keys', '', + Modal.createDialogAsync( import( '../../../async-components/views/dialogs/security/ExportE2eKeysDialog' ) as unknown as Promise>, @@ -100,7 +100,7 @@ export default class CryptographyPanel extends React.Component { }; private onImportE2eKeysClicked = (): void => { - Modal.createTrackedDialogAsync('Import E2E Keys', '', + Modal.createDialogAsync( import( '../../../async-components/views/dialogs/security/ImportE2eKeysDialog' ) as unknown as Promise>, diff --git a/src/components/views/settings/DevicesPanel.tsx b/src/components/views/settings/DevicesPanel.tsx index 71f9b07e99b..5ae034d9fec 100644 --- a/src/components/views/settings/DevicesPanel.tsx +++ b/src/components/views/settings/DevicesPanel.tsx @@ -215,7 +215,7 @@ export default class DevicesPanel extends React.Component { continueKind: "danger", }, }; - Modal.createTrackedDialog('Delete Device Dialog', '', InteractiveAuthDialog, { + Modal.createDialog(InteractiveAuthDialog, { title: _t("Authentication"), matrixClient: MatrixClientPeg.get(), authData: error.data, diff --git a/src/components/views/settings/DevicesPanelEntry.tsx b/src/components/views/settings/DevicesPanelEntry.tsx index 0fbe961dce9..2e7094c7b35 100644 --- a/src/components/views/settings/DevicesPanelEntry.tsx +++ b/src/components/views/settings/DevicesPanelEntry.tsx @@ -84,14 +84,14 @@ export default class DevicesPanelEntry extends React.Component { }; 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 { userId, [this.props.device.device_id], ); - Modal.createTrackedDialog('New Session Verification', 'Starting dialog', VerificationRequestDialog, { + Modal.createDialog(VerificationRequestDialog, { verificationRequestPromise, member: cli.getUser(userId), onFinished: async () => { diff --git a/src/components/views/settings/EventIndexPanel.tsx b/src/components/views/settings/EventIndexPanel.tsx index 85fb8b79ddf..0b4d1aca529 100644 --- a/src/components/views/settings/EventIndexPanel.tsx +++ b/src/components/views/settings/EventIndexPanel.tsx @@ -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'), diff --git a/src/components/views/settings/JoinRuleSettings.tsx b/src/components/views/settings/JoinRuleSettings.tsx index 1244b344b97..08c63e69c7c 100644 --- a/src/components/views/settings/JoinRuleSettings.tsx +++ b/src/components/views/settings/JoinRuleSettings.tsx @@ -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 ; } - Modal.createTrackedDialog('Restricted join rule upgrade', '', RoomUpgradeWarningDialog, { + Modal.createDialog(RoomUpgradeWarningDialog, { roomId: room.roomId, targetVersion, description: <> diff --git a/src/components/views/settings/Notifications.tsx b/src/components/views/settings/Notifications.tsx index f758022fc46..c7a95b060ae 100644 --- a/src/components/views/settings/Notifications.tsx +++ b/src/components/views/settings/Notifications.tsx @@ -277,7 +277,7 @@ export default class Notifications extends React.PureComponent { } 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.'), }); diff --git a/src/components/views/settings/ProfileSettings.tsx b/src/components/views/settings/ProfileSettings.tsx index 94d83439995..8eddec23a85 100644 --- a/src/components/views/settings/ProfileSettings.tsx +++ b/src/components/views/settings/ProfileSettings.tsx @@ -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")), }); diff --git a/src/components/views/settings/SecureBackupPanel.tsx b/src/components/views/settings/SecureBackupPanel.tsx index da5df6c7a71..e39d1970cd9 100644 --- a/src/components/views/settings/SecureBackupPanel.tsx +++ b/src/components/views/settings/SecureBackupPanel.tsx @@ -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>, @@ -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 => { - Modal.createTrackedDialog( - 'Restore Backup', '', RestoreKeyBackupDialog, null, null, - /* priority = */ false, /* static = */ true, - ); + Modal.createDialog(RestoreKeyBackupDialog, null, null, /* priority = */ false, /* static = */ true); }; private resetSecretStorage = async (): Promise => { diff --git a/src/components/views/settings/SetIdServer.tsx b/src/components/views/settings/SetIdServer.tsx index d50ae3d3615..8e28cfad4bf 100644 --- a/src/components/views/settings/SetIdServer.tsx +++ b/src/components/views/settings/SetIdServer.tsx @@ -219,7 +219,7 @@ export default class SetIdServer extends React.Component { }; 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: (
@@ -320,7 +320,7 @@ export default class SetIdServer extends React.Component { message = unboundMessage; } - const { finished } = Modal.createTrackedDialog('Identity Server Bound Warning', '', QuestionDialog, { + const { finished } = Modal.createDialog(QuestionDialog, { title, description: message, button, diff --git a/src/components/views/settings/account/EmailAddresses.tsx b/src/components/views/settings/account/EmailAddresses.tsx index 9ee1ae742b4..422c0b2c270 100644 --- a/src/components/views/settings/account/EmailAddresses.tsx +++ b/src/components/views/settings/account/EmailAddresses.tsx @@ -80,7 +80,7 @@ export class ExistingEmailAddress extends React.Component { 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 { // 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 { }).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 { }).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")), }); diff --git a/src/components/views/settings/account/PhoneNumbers.tsx b/src/components/views/settings/account/PhoneNumbers.tsx index d2751fddbbd..2aead4fdd34 100644 --- a/src/components/views/settings/account/PhoneNumbers.tsx +++ b/src/components/views/settings/account/PhoneNumbers.tsx @@ -76,7 +76,7 @@ export class ExistingPhoneNumber extends React.Component { 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 { }).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 { 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")), }); diff --git a/src/components/views/settings/discovery/EmailAddresses.tsx b/src/components/views/settings/discovery/EmailAddresses.tsx index 8d94797ef00..d59012cb35b 100644 --- a/src/components/views/settings/discovery/EmailAddresses.tsx +++ b/src/components/views/settings/discovery/EmailAddresses.tsx @@ -104,7 +104,7 @@ export class EmailAddress extends React.Component { const room = MatrixClientPeg.get().getRoom(this.props.roomId); - Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, { room }); + Modal.createDialog(RoomUpgradeDialog, { room }); }; private onOldRoomClicked = (e) => { diff --git a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx index 85cafc37b8f..ec1c9a49fd1 100644 --- a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx @@ -81,7 +81,7 @@ export class BannedUser extends React.Component { private onUnbanClick = (e) => { MatrixClientPeg.get().unban(this.props.member.roomId, this.props.member.userId).catch((err) => { logger.error("Failed to unban: " + err); - Modal.createTrackedDialog('Failed to unban', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t('Error'), description: _t('Failed to unban'), }); @@ -180,7 +180,7 @@ export default class RolesRoomSettingsTab extends React.Component { client.sendStateEvent(this.props.roomId, EventType.RoomPowerLevels, plContent).catch(e => { logger.error(e); - Modal.createTrackedDialog('Power level requirement change failed', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t('Error changing power level requirement'), description: _t( "An error occurred changing the room's power level requirements. Ensure you have sufficient " + @@ -206,7 +206,7 @@ export default class RolesRoomSettingsTab extends React.Component { client.sendStateEvent(this.props.roomId, EventType.RoomPowerLevels, plContent).catch(e => { logger.error(e); - Modal.createTrackedDialog('Power level change failed', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t('Error changing power level'), description: _t( "An error occurred changing the user's power level. Ensure you have sufficient " + diff --git a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx index 6a72ec54412..abbd836e905 100644 --- a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx @@ -104,7 +104,7 @@ export default class SecurityRoomSettingsTab extends React.Component { if (this.context.getRoom(this.props.roomId)?.getJoinRule() === JoinRule.Public) { - const dialog = Modal.createTrackedDialog('Confirm Public Encrypted Room', '', QuestionDialog, { + const dialog = Modal.createDialog(QuestionDialog, { title: _t('Are you sure you want to add encryption to this public room?'), description:

{ _t( @@ -137,7 +137,7 @@ export default class SecurityRoomSettingsTab extends React.Component { - const modal = Modal.createTrackedDialog<[boolean, IOpts]>( - "Create Room", - "Create room after trying to make an E2EE room public", + const modal = Modal.createDialog<[boolean, IOpts]>( CreateRoomDialog, { defaultPublic, defaultEncrypted }, ); @@ -257,7 +255,7 @@ export default class SecurityRoomSettingsTab extends React.Component { - Modal.createTrackedDialog('Room not found', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t("Failed to update the join rules"), description: error.message ?? _t("Unknown failure"), }); @@ -265,7 +263,7 @@ export default class SecurityRoomSettingsTab extends React.Component => { if (this.state.encrypted && joinRule === JoinRule.Public) { - const dialog = Modal.createTrackedDialog('Confirm Public Encrypted Room', '', QuestionDialog, { + const dialog = Modal.createDialog(QuestionDialog, { title: _t("Are you sure you want to make this encrypted room public?"), description:

{ _t( diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx index 3c7bd833b73..d62c9bbaa09 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx @@ -254,7 +254,7 @@ export default class GeneralUserSettingsTab extends React.Component { - Modal.createTrackedDialog('Deactivate Account', '', DeactivateAccountDialog, { + Modal.createDialog(DeactivateAccountDialog, { onFinished: (success) => { if (success) this.props.closeSettingsFn(); }, diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx index c4e0e5d87fd..7bb06f197b7 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx @@ -87,7 +87,7 @@ export default class HelpUserSettingsTab extends React.Component }; private onBugReport = (e) => { - Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {}); + Modal.createDialog(BugReportDialog, {}); }; private onStartBotChat = (e) => { diff --git a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx index 709b3e8c56c..427f040022a 100644 --- a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx @@ -71,7 +71,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState> } catch (e) { logger.error(e); - Modal.createTrackedDialog('Failed to add Mjolnir rule', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t('Error adding ignored user/server'), description: _t('Something went wrong. Please try again or view your console for hints.'), }); @@ -92,7 +92,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState> } catch (e) { logger.error(e); - Modal.createTrackedDialog('Failed to subscribe to Mjolnir list', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t('Error subscribing to list'), description: _t('Please verify the room ID or address and try again.'), }); @@ -109,7 +109,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState> } catch (e) { logger.error(e); - Modal.createTrackedDialog('Failed to remove Mjolnir rule', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t('Error removing ignored user/server'), description: _t('Something went wrong. Please try again or view your console for hints.'), }); @@ -126,7 +126,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState> } catch (e) { logger.error(e); - Modal.createTrackedDialog('Failed to unsubscribe from Mjolnir list', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t('Error unsubscribing from list'), description: _t('Please try again or view your console for hints.'), }); @@ -149,7 +149,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState> return

    { tiles }
; }; - Modal.createTrackedDialog('View Mjolnir list rules', '', QuestionDialog, { + Modal.createDialog(QuestionDialog, { title: _t("Ban list rules - %(roomName)s", { roomName: name }), description: (
diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx index e577cd873fc..f92edb0715a 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx @@ -22,7 +22,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { _t } from "../../../../../languageHandler"; import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import AccessibleButton from "../../../elements/AccessibleButton"; -import Analytics from "../../../../../Analytics"; import dis from "../../../../../dispatcher/dispatcher"; import { SettingLevel } from "../../../../../settings/SettingLevel"; import SecureBackupPanel from "../../SecureBackupPanel"; @@ -110,10 +109,6 @@ export default class SecurityUserSettingsTab extends React.Component { - checked ? Analytics.enable() : Analytics.disable(); - }; - private onMyMembership = (room: Room, membership: string): void => { if (room.isSpaceRoom()) { return; @@ -295,16 +290,12 @@ export default class SecurityUserSettingsTab extends React.Component { - if (PosthogAnalytics.instance.isEnabled()) { - showAnalyticsLearnMoreDialog({ - primaryButton: _t("Okay"), - hasCancel: false, - }); - } else { - Analytics.showDetailsModal(); - } + showAnalyticsLearnMoreDialog({ + primaryButton: _t("Okay"), + hasCancel: false, + }); }; privacySection =
{ _t("Privacy") }
@@ -321,15 +312,11 @@ export default class SecurityUserSettingsTab extends React.Component

- { - PosthogAnalytics.instance.isEnabled() ? - : - - } + { PosthogAnalytics.instance.isEnabled() && ( + + ) }
; } diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx index 18a0b0b288c..dbd22deb4bd 100644 --- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx @@ -103,7 +103,7 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> { if (error) { logger.log("Failed to list userMedia devices", error); const brand = SdkConfig.get().brand; - Modal.createTrackedDialog('No media permissions', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t('No media permissions'), description: _t( 'You may need to manually permit %(brand)s to access your microphone/webcam', diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx index 745fdc433bc..3d0af8f6fc3 100644 --- a/src/components/views/spaces/SpaceCreateMenu.tsx +++ b/src/components/views/spaces/SpaceCreateMenu.tsx @@ -109,7 +109,7 @@ export const SpaceFeedbackPrompt = ({ onClick }: { onClick?: () => void }) => { kind="link" onClick={() => { if (onClick) onClick(); - Modal.createTrackedDialog("Spaces Feedback", "", GenericFeatureFeedbackDialog, { + Modal.createDialog(GenericFeatureFeedbackDialog, { title: _t("Spaces feedback"), subheading: _t("Thank you for trying Spaces. " + "Your feedback will help inform the next versions."), diff --git a/src/components/views/toasts/NonUrgentEchoFailureToast.tsx b/src/components/views/toasts/NonUrgentEchoFailureToast.tsx index 931cb3b3f1e..96aeac94494 100644 --- a/src/components/views/toasts/NonUrgentEchoFailureToast.tsx +++ b/src/components/views/toasts/NonUrgentEchoFailureToast.tsx @@ -23,7 +23,7 @@ import ServerOfflineDialog from "../dialogs/ServerOfflineDialog"; export default class NonUrgentEchoFailureToast extends React.PureComponent { private openDialog = () => { - Modal.createTrackedDialog('Local Echo Server Error', '', ServerOfflineDialog, {}); + Modal.createDialog(ServerOfflineDialog, {}); }; public render() { diff --git a/src/components/views/toasts/VerificationRequestToast.tsx b/src/components/views/toasts/VerificationRequestToast.tsx index 3786f5c858a..3b2e5c89a89 100644 --- a/src/components/views/toasts/VerificationRequestToast.tsx +++ b/src/components/views/toasts/VerificationRequestToast.tsx @@ -129,7 +129,7 @@ export default class VerificationRequestToast extends React.PureComponent { request.cancel(); diff --git a/src/createRoom.ts b/src/createRoom.ts index 66177d812b1..3e258d28cba 100644 --- a/src/createRoom.ts +++ b/src/createRoom.ts @@ -315,7 +315,7 @@ export default async function createRoom(opts: IOpts): Promise { // the error to the user for if/when the UI is available. description = _t("The server does not support the room version specified."); } - Modal.createTrackedDialog('Failure to create room', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t("Failure to create room"), description, }); diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 95c08075730..c400b175743 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -225,19 +225,6 @@ export enum Action { */ PseudonymousAnalyticsReject = "pseudonymous_analytics_reject", - /** - * The user accepted anonymous analytics (i.e. matomo, pre-posthog) from the toast - * (this action and its handler can be removed once posthog is rolled out) - * Payload: none - */ - AnonymousAnalyticsAccept = "anonymous_analytics_accept", - - /** - * The user rejected anonymous analytics (i.e. matomo, pre-posthog) from the toast - * Payload: none - */ - AnonymousAnalyticsReject = "anonymous_analytics_reject", - /** * Fires after crypto is setup if key backup is not enabled * Used to trigger auto rageshakes when configured diff --git a/src/editor/commands.tsx b/src/editor/commands.tsx index 88165daabaa..279dfcc1a08 100644 --- a/src/editor/commands.tsx +++ b/src/editor/commands.tsx @@ -92,7 +92,7 @@ export async function runSlashCommand( errText = _t("Server unavailable, overloaded, or something else went wrong."); } - Modal.createTrackedDialog(title, '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t(title), description: errText, }); @@ -105,7 +105,7 @@ export async function runSlashCommand( export async function shouldSendAnyway(commandText: string): Promise { // ask the user if their unknown command should be sent as a message - const { finished } = Modal.createTrackedDialog("Unknown command", "", QuestionDialog, { + const { finished } = Modal.createDialog(QuestionDialog, { title: _t("Unknown Command"), description:

diff --git a/src/group_helpers.tsx b/src/group_helpers.tsx index 0c0fe1077f6..9e5a96aa193 100644 --- a/src/group_helpers.tsx +++ b/src/group_helpers.tsx @@ -23,7 +23,7 @@ import SdkConfig, { DEFAULTS } from "./SdkConfig"; export function showGroupReplacedWithSpacesDialog(groupId: string) { const learnMoreUrl = SdkConfig.get().spaces_learn_more_url ?? DEFAULTS.spaces_learn_more_url; - Modal.createTrackedDialog("Groups are now Spaces", '', QuestionDialog, { + Modal.createDialog(QuestionDialog, { title: _t("That link is no longer supported"), description: <>

diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 829d361fb64..810d387e4af 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -13,25 +13,6 @@ "Confirm adding phone number": "Confirm adding phone number", "Click the button below to confirm adding this phone number.": "Click the button below to confirm adding this phone number.", "Add Phone Number": "Add Phone Number", - "The platform you're on": "The platform you're on", - "The version of %(brand)s": "The version of %(brand)s", - "Whether or not you're logged in (we don't record your username)": "Whether or not you're logged in (we don't record your username)", - "Your language of choice": "Your language of choice", - "Which officially provided instance you are using, if any": "Which officially provided instance you are using, if any", - "Whether or not you're using the Richtext mode of the Rich Text Editor": "Whether or not you're using the Richtext mode of the Rich Text Editor", - "Your homeserver's URL": "Your homeserver's URL", - "Whether you're using %(brand)s on a device where touch is the primary input mechanism": "Whether you're using %(brand)s on a device where touch is the primary input mechanism", - "Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)", - "Whether you're using %(brand)s as an installed Progressive Web App": "Whether you're using %(brand)s as an installed Progressive Web App", - "e.g. %(exampleValue)s": "e.g. %(exampleValue)s", - "Every page you use in the app": "Every page you use in the app", - "e.g. ": "e.g. ", - "Your user agent": "Your user agent", - "Your device resolution": "Your device resolution", - "Our complete cookie policy can be found here.": "Our complete cookie policy can be found here.", - "Analytics": "Analytics", - "Some examples of the information being sent to us to help make %(brand)s better includes:": "Some examples of the information being sent to us to help make %(brand)s better includes:", - "Where this page includes identifiable information, such as a room, user ID, that data is removed before being sent to the server.": "Where this page includes identifiable information, such as a room, user ID, that data is removed before being sent to the server.", "Error": "Error", "Unable to load! Check your network connectivity and try again.": "Unable to load! Check your network connectivity and try again.", "Dismiss": "Dismiss", @@ -69,8 +50,6 @@ "Failed to transfer call": "Failed to transfer call", "Permission Required": "Permission Required", "You do not have permission to start a conference call in this room": "You do not have permission to start a conference call in this room", - "End conference": "End conference", - "This will end the conference for everyone. Continue?": "This will end the conference for everyone. Continue?", "The file '%(fileName)s' failed to upload.": "The file '%(fileName)s' failed to upload.", "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "The file '%(fileName)s' exceeds this homeserver's size limit for uploads", "Upload Failed": "Upload Failed", @@ -780,13 +759,12 @@ "Enable": "Enable", "That's fine": "That's fine", "Stop": "Stop", - "Send anonymous usage data which helps us improve %(brand)s. This will use a cookie.": "Send anonymous usage data which helps us improve %(brand)s. This will use a cookie.", - "Help improve %(analyticsOwner)s": "Help improve %(analyticsOwner)s", "You previously consented to share anonymous usage data with us. We're updating how that works.": "You previously consented to share anonymous usage data with us. We're updating how that works.", "Learn more": "Learn more", "Share anonymous data to help us identify issues. Nothing personal. No third parties. Learn More": "Share anonymous data to help us identify issues. Nothing personal. No third parties. Learn More", "Yes": "Yes", "No": "No", + "Help improve %(analyticsOwner)s": "Help improve %(analyticsOwner)s", "You have unverified logins": "You have unverified logins", "Review to ensure your account is safe": "Review to ensure your account is safe", "Review": "Review", @@ -864,6 +842,7 @@ "Widgets": "Widgets", "Rooms": "Rooms", "Moderation": "Moderation", + "Analytics": "Analytics", "Message Previews": "Message Previews", "Themes": "Themes", "Encryption": "Encryption", diff --git a/src/integrations/IntegrationManagerInstance.ts b/src/integrations/IntegrationManagerInstance.ts index dc6a2fb9deb..46d325ee2d5 100644 --- a/src/integrations/IntegrationManagerInstance.ts +++ b/src/integrations/IntegrationManagerInstance.ts @@ -66,10 +66,7 @@ export class IntegrationManagerInstance { return IntegrationManagers.sharedInstance().showDisabledDialog(); } - const dialog = Modal.createTrackedDialog( - 'Integration Manager', '', IntegrationManager, - { loading: true }, 'mx_IntegrationManager', - ); + const dialog = Modal.createDialog(IntegrationManager, { loading: true }, 'mx_IntegrationManager'); const client = this.getScalarClient(); client.setTermsInteractionCallback((policyInfo, agreedUrls) => { @@ -101,9 +98,6 @@ export class IntegrationManagerInstance { // Close the old dialog and open a new one dialog.close(); - Modal.createTrackedDialog( - 'Integration Manager', '', IntegrationManager, - newProps, 'mx_IntegrationManager', - ); + Modal.createDialog(IntegrationManager, newProps, 'mx_IntegrationManager'); } } diff --git a/src/integrations/IntegrationManagers.ts b/src/integrations/IntegrationManagers.ts index 448b71d8ad2..b5a65c0e647 100644 --- a/src/integrations/IntegrationManagers.ts +++ b/src/integrations/IntegrationManagers.ts @@ -171,11 +171,11 @@ export class IntegrationManagers { } openNoManagerDialog(): void { - Modal.createTrackedDialog('Integrations impossible', '', IntegrationsImpossibleDialog); + Modal.createDialog(IntegrationsImpossibleDialog); } showDisabledDialog(): void { - Modal.createTrackedDialog('Integrations disabled', '', IntegrationsDisabledDialog); + Modal.createDialog(IntegrationsDisabledDialog); } async overwriteManagerOnAccount(manager: IntegrationManagerInstance) { diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 7a45447b1b0..202a5037bdd 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -711,15 +711,11 @@ export const SETTINGS: {[setting: string]: ISetting} = { supportedLevelsAreOrdered: true, default: {}, // none allowed }, + // Legacy, kept around for transitionary purposes "analyticsOptIn": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, - displayName: _td('Send analytics data'), default: false, }, - "showCookieBar": { - supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, - default: true, - }, "pseudonymousAnalyticsOptIn": { supportedLevels: [SettingLevel.ACCOUNT], displayName: _td('Send analytics data'), diff --git a/src/settings/controllers/ThreadBetaController.tsx b/src/settings/controllers/ThreadBetaController.tsx index 487d2013b17..c82610047af 100644 --- a/src/settings/controllers/ThreadBetaController.tsx +++ b/src/settings/controllers/ThreadBetaController.tsx @@ -28,7 +28,7 @@ export default class ThreadBetaController extends SettingController { public async beforeChange(level: SettingLevel, roomId: string, newValue: any): Promise { if (Thread.hasServerSideSupport || !newValue) return true; // Full support or user is disabling - const { finished } = Modal.createTrackedDialog<[boolean]>("Thread beta", "degraded mode", QuestionDialog, { + const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, { title: _t("Partial Support for Threads"), description: <>

{ _t("Your homeserver does not currently support threads, so this feature may be unreliable. " + diff --git a/src/stores/ModalWidgetStore.ts b/src/stores/ModalWidgetStore.ts index 9c38b3f3a92..d04b28a4203 100644 --- a/src/stores/ModalWidgetStore.ts +++ b/src/stores/ModalWidgetStore.ts @@ -59,7 +59,7 @@ export class ModalWidgetStore extends AsyncStoreWithClient { if (this.modalInstance) return; this.openSourceWidgetId = sourceWidget.id; this.openSourceWidgetRoomId = widgetRoomId; - this.modalInstance = Modal.createTrackedDialog('Modal Widget', '', ModalWidgetDialog, { + this.modalInstance = Modal.createDialog(ModalWidgetDialog, { widgetDefinition: { ...requestData }, widgetRoomId, sourceWidgetId: sourceWidget.id, diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index 2a72f518bfb..ea2b7e93ad2 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -448,7 +448,7 @@ export class RoomViewStore extends Store { } } - Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t("Failed to join"), description, }); diff --git a/src/stores/SetupEncryptionStore.ts b/src/stores/SetupEncryptionStore.ts index 38ba0bd9b0a..9a4b479a2ec 100644 --- a/src/stores/SetupEncryptionStore.ts +++ b/src/stores/SetupEncryptionStore.ts @@ -232,14 +232,11 @@ export class SetupEncryptionStore extends EventEmitter { 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"); diff --git a/src/stores/widgets/StopGapWidget.ts b/src/stores/widgets/StopGapWidget.ts index 8d40a89ef87..794fa17a25c 100644 --- a/src/stores/widgets/StopGapWidget.ts +++ b/src/stores/widgets/StopGapWidget.ts @@ -375,7 +375,7 @@ export class StopGapWidget extends EventEmitter { this.messaging.on(`action:${ElementWidgetActions.HangupCall}`, (ev: CustomEvent) => { if (ev.detail.data?.errorMessage) { - Modal.createTrackedDialog("Connection lost", "", ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t("Connection lost"), description: _t("You were disconnected from the call. (Error: %(message)s)", { message: ev.detail.data.errorMessage, diff --git a/src/stores/widgets/StopGapWidgetDriver.ts b/src/stores/widgets/StopGapWidgetDriver.ts index 6591a2c793f..3fcc10283eb 100644 --- a/src/stores/widgets/StopGapWidgetDriver.ts +++ b/src/stores/widgets/StopGapWidgetDriver.ts @@ -118,8 +118,7 @@ export class StopGapWidgetDriver extends WidgetDriver { let rememberApproved = false; if (missing.size > 0) { try { - const [result] = await Modal.createTrackedDialog( - 'Approve Widget Caps', '', + const [result] = await Modal.createDialog( WidgetCapabilitiesPromptDialog, { requestedCapabilities: missing, @@ -265,7 +264,7 @@ export class StopGapWidgetDriver extends WidgetDriver { observer.update({ state: OpenIDRequestState.PendingUserConfirmation }); - Modal.createTrackedDialog("OpenID widget permissions", '', WidgetOpenIDPermissionsDialog, { + Modal.createDialog(WidgetOpenIDPermissionsDialog, { widget: this.forWidget, widgetKind: this.forWidgetKind, inRoomId: this.inRoomId, diff --git a/src/toasts/AnalyticsToast.tsx b/src/toasts/AnalyticsToast.tsx index 39f1ef252f3..d056456bd9c 100644 --- a/src/toasts/AnalyticsToast.tsx +++ b/src/toasts/AnalyticsToast.tsx @@ -14,13 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { ReactNode } from "react"; +import React from "react"; import { Optional } from "matrix-events-sdk"; import { _t } from "../languageHandler"; import SdkConfig from "../SdkConfig"; import dis from "../dispatcher/dispatcher"; -import Analytics from "../Analytics"; import AccessibleButton from "../components/views/elements/AccessibleButton"; import GenericToast from "../components/views/toasts/GenericToast"; import ToastStore from "../stores/ToastStore"; @@ -31,6 +30,7 @@ import { import { Action } from "../dispatcher/actions"; import { SnakedObject } from "../utils/SnakedObject"; import { IConfigOptions } from "../IConfigOptions"; +import SettingsStore from "../settings/SettingsStore"; const onAccept = () => { dis.dispatch({ @@ -75,53 +75,26 @@ const onLearnMorePreviouslyOptedIn = () => { }); }; -const onUsageDataClicked = () => { - Analytics.showDetailsModal(); -}; - const TOAST_KEY = "analytics"; -const getAnonymousDescription = (): ReactNode => { - // get toast description for anonymous tracking (the previous scheme pre-posthog) - const brand = SdkConfig.get().brand; +export function getPolicyUrl(): Optional { + const policyUrl = SdkConfig.get("privacy_policy_url"); + if (policyUrl) return policyUrl; + + // Try get from legacy config location const piwikConfig = SdkConfig.get("piwik"); let piwik: Optional>>; if (typeof piwikConfig === 'object') { piwik = new SnakedObject(piwikConfig); } - const cookiePolicyUrl = piwik?.get("policy_url"); - return _t( - "Send anonymous usage data which helps us improve %(brand)s. " + - "This will use a cookie.", - { - brand, - }, - { - "UsageDataLink": (sub) => ( - { sub } - ), - "PolicyLink": (sub) => cookiePolicyUrl ? ( - { sub } - ) : sub, - }, - ); -}; + return piwik?.get("policy_url"); +} -const showToast = (props: Omit, "toastKey">) => { - const analyticsOwner = SdkConfig.get("analytics_owner") ?? SdkConfig.get().brand; - ToastStore.sharedInstance().addOrReplaceToast({ - key: TOAST_KEY, - title: _t("Help improve %(analyticsOwner)s", { analyticsOwner }), - props, - component: GenericToast, - className: "mx_AnalyticsToast", - priority: 10, - }); -}; +export const showToast = (): void => { + const legacyAnalyticsOptIn = SettingsStore.getValue("analyticsOptIn", null, true); -export const showPseudonymousAnalyticsOptInToast = (analyticsOptIn: boolean): void => { - let props; - if (analyticsOptIn) { + let props: Omit, "toastKey">; + if (legacyAnalyticsOptIn) { // The user previously opted into our old analytics system - let them know things have changed and ask // them to opt in again. props = { @@ -132,10 +105,10 @@ export const showPseudonymousAnalyticsOptInToast = (analyticsOptIn: boolean): vo rejectLabel: _t("Learn more"), onReject: onLearnMorePreviouslyOptedIn, }; - } else if (analyticsOptIn === null || analyticsOptIn === undefined) { + } else if (legacyAnalyticsOptIn === null || legacyAnalyticsOptIn === undefined) { // The user had no analytics setting previously set, so we just need to prompt to opt-in, rather than // explaining any change. - const learnMoreLink = (sub) => ( + const learnMoreLink = (sub: string) => ( { sub } ); props = { @@ -151,22 +124,16 @@ export const showPseudonymousAnalyticsOptInToast = (analyticsOptIn: boolean): vo // The user previously opted out of analytics, don't ask again return; } - showToast(props); -}; -export const showAnonymousAnalyticsOptInToast = (): void => { - const props = { - description: getAnonymousDescription(), - acceptLabel: _t("Yes"), - onAccept: () => dis.dispatch({ - action: Action.AnonymousAnalyticsAccept, - }), - rejectLabel: _t("No"), - onReject: () => dis.dispatch({ - action: Action.AnonymousAnalyticsReject, - }), - }; - showToast(props); + const analyticsOwner = SdkConfig.get("analytics_owner") ?? SdkConfig.get().brand; + ToastStore.sharedInstance().addOrReplaceToast({ + key: TOAST_KEY, + title: _t("Help improve %(analyticsOwner)s", { analyticsOwner }), + props, + component: GenericToast, + className: "mx_AnalyticsToast", + priority: 10, + }); }; export const hideToast = () => { diff --git a/src/toasts/SetupEncryptionToast.ts b/src/toasts/SetupEncryptionToast.ts index bdaeb5142f1..a3a90a009ff 100644 --- a/src/toasts/SetupEncryptionToast.ts +++ b/src/toasts/SetupEncryptionToast.ts @@ -85,7 +85,7 @@ export const showToast = (kind: Kind) => { const onAccept = async () => { if (kind === Kind.VERIFY_THIS_SESSION) { - Modal.createTrackedDialog("Verify session", "Verify session", SetupEncryptionDialog, + Modal.createDialog(SetupEncryptionDialog, {}, null, /* priority = */ false, /* static = */ true); } else { const modal = Modal.createDialog( diff --git a/src/toasts/UpdateToast.tsx b/src/toasts/UpdateToast.tsx index cb072705ceb..774ee364e20 100644 --- a/src/toasts/UpdateToast.tsx +++ b/src/toasts/UpdateToast.tsx @@ -49,7 +49,7 @@ export const showToast = (version: string, newVersion: string, releaseNotes?: st let acceptLabel = _t("What's new?"); if (releaseNotes) { onAccept = () => { - Modal.createTrackedDialog('Display release notes', '', QuestionDialog, { + Modal.createDialog(QuestionDialog, { title: _t("What's New"), description:

{ releaseNotes }
, button: _t("Update"), @@ -62,7 +62,7 @@ export const showToast = (version: string, newVersion: string, releaseNotes?: st }; } else if (checkVersion(version) && checkVersion(newVersion)) { onAccept = () => { - Modal.createTrackedDialog('Display Changelog', '', ChangelogDialog, { + Modal.createDialog(ChangelogDialog, { version, newVersion, onFinished: (update) => { diff --git a/src/utils/DialogOpener.ts b/src/utils/DialogOpener.ts index 8bd6c137342..0e5a3d2b11a 100644 --- a/src/utils/DialogOpener.ts +++ b/src/utils/DialogOpener.ts @@ -57,37 +57,37 @@ export class DialogOpener { private onDispatch = (payload: ActionPayload) => { switch (payload.action) { case 'open_room_settings': - Modal.createTrackedDialog('Room settings', '', RoomSettingsDialog, { + Modal.createDialog(RoomSettingsDialog, { roomId: payload.room_id || RoomViewStore.instance.getRoomId(), initialTabId: payload.initial_tab_id, }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); break; case Action.OpenForwardDialog: - Modal.createTrackedDialog('Forward Message', '', ForwardDialog, { + Modal.createDialog(ForwardDialog, { matrixClient: MatrixClientPeg.get(), event: payload.event, permalinkCreator: payload.permalinkCreator, }); break; case Action.OpenReportEventDialog: - Modal.createTrackedDialog('Report Event', '', ReportEventDialog, { + Modal.createDialog(ReportEventDialog, { mxEvent: payload.event, }, 'mx_Dialog_reportEvent'); break; case Action.OpenSpacePreferences: - Modal.createTrackedDialog("Space preferences", "", SpacePreferencesDialog, { + Modal.createDialog(SpacePreferencesDialog, { initialTabId: payload.initalTabId, space: payload.space, }, null, false, true); break; case Action.OpenSpaceSettings: - Modal.createTrackedDialog("Space Settings", "", SpaceSettingsDialog, { + Modal.createDialog(SpaceSettingsDialog, { matrixClient: payload.space.client, space: payload.space, }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); break; case Action.OpenInviteDialog: - Modal.createTrackedDialog(payload.analyticsName, '', InviteDialog, { + Modal.createDialog(InviteDialog, { kind: payload.kind, call: payload.call, roomId: payload.roomId, @@ -98,9 +98,7 @@ export class DialogOpener { break; case Action.OpenAddToExistingSpaceDialog: { const space = payload.space; - Modal.createTrackedDialog( - "Space Landing", - "Add Existing", + Modal.createDialog( AddExistingToSpaceDialog, { onCreateRoomClick: (ev: ButtonEvent) => { diff --git a/src/utils/MultiInviter.ts b/src/utils/MultiInviter.ts index cace1cb8762..3f565c079bd 100644 --- a/src/utils/MultiInviter.ts +++ b/src/utils/MultiInviter.ts @@ -316,7 +316,7 @@ export default class MultiInviter { } logger.log("Showing failed to invite dialog..."); - Modal.createTrackedDialog('Failed to invite', '', AskInviteAnywayDialog, { + Modal.createDialog(AskInviteAnywayDialog, { unknownProfileUsers: unknownProfileUsers.map(u => ({ userId: u, errorText: this.errors[u].errorText, diff --git a/src/utils/RoomUpgrade.ts b/src/utils/RoomUpgrade.ts index d881e342b18..37aa61de304 100644 --- a/src/utils/RoomUpgrade.ts +++ b/src/utils/RoomUpgrade.ts @@ -99,7 +99,7 @@ export async function upgradeRoom( if (!handleError) throw e; logger.error(e); - Modal.createTrackedDialog("Room Upgrade Error", "", ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t('Error upgrading room'), description: _t('Double check that your server supports the room version chosen and try again.'), }); diff --git a/src/utils/StorageManager.ts b/src/utils/StorageManager.ts index ed37064920c..1145bcfb15d 100644 --- a/src/utils/StorageManager.ts +++ b/src/utils/StorageManager.ts @@ -18,9 +18,6 @@ import { LocalStorageCryptoStore } from 'matrix-js-sdk/src/crypto/store/localSto import { IndexedDBStore } from "matrix-js-sdk/src/store/indexeddb"; import { IndexedDBCryptoStore } from "matrix-js-sdk/src/crypto/store/indexeddb-crypto-store"; import { logger } from "matrix-js-sdk/src/logger"; -import { MatrixClient } from 'matrix-js-sdk/src/client'; - -import Analytics from '../Analytics'; const localStorage = window.localStorage; @@ -43,10 +40,6 @@ function error(msg: string, ...args: string[]) { logger.error(`StorageManager: ${msg}`, ...args); } -function track(action: string) { - Analytics.trackEvent("StorageManager", action); -} - export function tryPersistStorage() { if (navigator.storage && navigator.storage.persist) { navigator.storage.persist().then(persistent => { @@ -81,7 +74,6 @@ export async function checkConsistency() { } else { healthy = false; error("Local storage cannot be used on this browser"); - track("Local storage disabled"); } if (indexedDB && localStorage) { @@ -92,7 +84,6 @@ export async function checkConsistency() { } else { healthy = false; error("Sync store cannot be used on this browser"); - track("Sync store disabled"); } if (indexedDB) { @@ -104,7 +95,6 @@ export async function checkConsistency() { } else { healthy = false; error("Crypto store cannot be used on this browser"); - track("Crypto store disabled"); } if (dataInLocalStorage && cryptoInited && !dataInCryptoStore) { @@ -114,15 +104,12 @@ export async function checkConsistency() { " but no data found in crypto store. " + "IndexedDB storage has likely been evicted by the browser!", ); - track("Crypto store evicted"); } if (healthy) { log("Storage consistency checks passed"); - track("Consistency checks passed"); } else { error("Storage consistency checks failed"); - track("Consistency checks failed"); } return { @@ -143,7 +130,6 @@ async function checkSyncStore() { return { exists, healthy: true }; } catch (e) { error("Sync store using IndexedDB inaccessible", e); - track("Sync store using IndexedDB inaccessible"); } log("Sync store using memory only"); return { exists, healthy: false }; @@ -159,7 +145,6 @@ async function checkCryptoStore() { return { exists, healthy: true }; } catch (e) { error("Crypto store using IndexedDB inaccessible", e); - track("Crypto store using IndexedDB inaccessible"); } try { exists = LocalStorageCryptoStore.exists(localStorage); @@ -167,18 +152,11 @@ async function checkCryptoStore() { return { exists, healthy: true }; } catch (e) { error("Crypto store using local storage inaccessible", e); - track("Crypto store using local storage inaccessible"); } log("Crypto store using memory only"); return { exists, healthy: false }; } -export function trackStores(client: MatrixClient) { - client.store?.on?.("degraded", () => { - track("Sync store using IndexedDB degraded to memory"); - }); -} - /** * Sets whether crypto has ever been successfully * initialised on this client. diff --git a/src/utils/leave-behaviour.ts b/src/utils/leave-behaviour.ts index 2d87e4d4dd0..a12cd70ebff 100644 --- a/src/utils/leave-behaviour.ts +++ b/src/utils/leave-behaviour.ts @@ -108,7 +108,7 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner = let message = _t("Unexpected server error trying to leave the room"); if (err.errcode && err.message) { if (err.errcode === 'M_CANNOT_LEAVE_SERVER_NOTICE_ROOM') { - Modal.createTrackedDialog('Error Leaving Room', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t("Can't leave Server Notices room"), description: _t( "This room is used for important messages from the Homeserver, " + @@ -121,7 +121,7 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner = } messages.push(message, React.createElement('BR')); // createElement to avoid using a tsx file in utils } - Modal.createTrackedDialog('Error Leaving Room', '', ErrorDialog, { + Modal.createDialog(ErrorDialog, { title: _t("Error leaving room"), description: messages, }); @@ -143,7 +143,7 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner = } export const leaveSpace = (space: Room) => { - Modal.createTrackedDialog("Leave Space", "", LeaveSpaceDialog, { + Modal.createDialog(LeaveSpaceDialog, { space, onFinished: async (leave: boolean, rooms: Room[]) => { if (!leave) return; diff --git a/src/utils/space.tsx b/src/utils/space.tsx index 6b341767062..9e05f0444ba 100644 --- a/src/utils/space.tsx +++ b/src/utils/space.tsx @@ -72,16 +72,11 @@ export const showAddExistingRooms = (space: Room): void => { }; export const showCreateNewRoom = async (space: Room, type?: RoomType): Promise => { - const modal = Modal.createTrackedDialog<[boolean, IOpts]>( - "Space Landing", - "Create Room", - CreateRoomDialog, - { - type, - defaultPublic: space.getJoinRule() === JoinRule.Public, - parentSpace: space, - }, - ); + const modal = Modal.createDialog<[boolean, IOpts]>(CreateRoomDialog, { + type, + defaultPublic: space.getJoinRule() === JoinRule.Public, + parentSpace: space, + }); const [shouldCreate, opts] = await modal.finished; if (shouldCreate) { await createRoom(opts); @@ -97,7 +92,7 @@ export const shouldShowSpaceInvite = (space: Room) => export const showSpaceInvite = (space: Room, initialText = ""): void => { if (space.getJoinRule() === "public") { - const modal = Modal.createTrackedDialog("Space Invite", "User Menu", InfoDialog, { + const modal = Modal.createDialog(InfoDialog, { title: _t("Invite to %(spaceName)s", { spaceName: space.name }), description: { _t("Share your public space") } @@ -114,39 +109,27 @@ export const showSpaceInvite = (space: Room, initialText = ""): void => { }; export const showAddExistingSubspace = (space: Room): void => { - Modal.createTrackedDialog( - "Space Landing", - "Create Subspace", - AddExistingSubspaceDialog, - { - space, - onCreateSubspaceClick: () => showCreateNewSubspace(space), - onFinished: (added: boolean) => { - if (added && RoomViewStore.instance.getRoomId() === space.roomId) { - defaultDispatcher.fire(Action.UpdateSpaceHierarchy); - } - }, + Modal.createDialog(AddExistingSubspaceDialog, { + space, + onCreateSubspaceClick: () => showCreateNewSubspace(space), + onFinished: (added: boolean) => { + if (added && RoomViewStore.instance.getRoomId() === space.roomId) { + defaultDispatcher.fire(Action.UpdateSpaceHierarchy); + } }, - "mx_AddExistingToSpaceDialog_wrapper", - ); + }, "mx_AddExistingToSpaceDialog_wrapper"); }; export const showCreateNewSubspace = (space: Room): void => { - Modal.createTrackedDialog( - "Space Landing", - "Create Subspace", - CreateSubspaceDialog, - { - space, - onAddExistingSpaceClick: () => showAddExistingSubspace(space), - onFinished: (added: boolean) => { - if (added && RoomViewStore.instance.getRoomId() === space.roomId) { - defaultDispatcher.fire(Action.UpdateSpaceHierarchy); - } - }, + Modal.createDialog(CreateSubspaceDialog, { + space, + onAddExistingSpaceClick: () => showAddExistingSubspace(space), + onFinished: (added: boolean) => { + if (added && RoomViewStore.instance.getRoomId() === space.roomId) { + defaultDispatcher.fire(Action.UpdateSpaceHierarchy); + } }, - "mx_CreateSubspaceDialog_wrapper", - ); + }, "mx_CreateSubspaceDialog_wrapper"); }; export const bulkSpaceBehaviour = async ( diff --git a/src/verification.ts b/src/verification.ts index 197ae051dd1..498bc632b2b 100644 --- a/src/verification.ts +++ b/src/verification.ts @@ -57,7 +57,7 @@ export async function verifyDevice(user: User, device: IDevice) { } } - Modal.createTrackedDialog("Verification warning", "unverified session", UntrustedDeviceDialog, { + Modal.createDialog(UntrustedDeviceDialog, { user, device, onFinished: async (action) => { @@ -69,13 +69,10 @@ export async function verifyDevice(user: User, device: IDevice) { ); setRightPanel({ member: user, verificationRequestPromise }); } else if (action === "legacy") { - Modal.createTrackedDialog("Legacy verify session", "legacy verify session", - ManualDeviceKeyVerificationDialog, - { - userId: user.userId, - device, - }, - ); + Modal.createDialog(ManualDeviceKeyVerificationDialog, { + userId: user.userId, + device, + }); } }, }); diff --git a/test/components/views/location/LocationShareMenu-test.tsx b/test/components/views/location/LocationShareMenu-test.tsx index 3445d49450e..c7820bc7656 100644 --- a/test/components/views/location/LocationShareMenu-test.tsx +++ b/test/components/views/location/LocationShareMenu-test.tsx @@ -66,7 +66,7 @@ jest.mock('../../../../src/stores/OwnProfileStore', () => ({ })); jest.mock('../../../../src/Modal', () => ({ - createTrackedDialog: jest.fn(), + createDialog: jest.fn(), })); describe('', () => { @@ -121,7 +121,7 @@ describe('', () => { mockClient.sendMessage.mockClear(); mockClient.unstable_createLiveBeacon.mockClear().mockResolvedValue({ event_id: '1' }); jest.spyOn(MatrixClientPeg, 'get').mockReturnValue(mockClient as unknown as MatrixClient); - mocked(Modal).createTrackedDialog.mockClear(); + mocked(Modal).createDialog.mockClear(); jest.clearAllMocks(); @@ -433,7 +433,7 @@ describe('', () => { await flushPromisesWithFakeTimers(); expect(logSpy).toHaveBeenCalledWith("We couldn't start sharing your live location", error); - expect(mocked(Modal).createTrackedDialog).toHaveBeenCalled(); + expect(mocked(Modal).createDialog).toHaveBeenCalled(); }); }); }); diff --git a/test/components/views/messages/MBeaconBody-test.tsx b/test/components/views/messages/MBeaconBody-test.tsx index b817ac29959..afcb604534c 100644 --- a/test/components/views/messages/MBeaconBody-test.tsx +++ b/test/components/views/messages/MBeaconBody-test.tsx @@ -78,7 +78,7 @@ describe('', () => { wrappingComponentProps: { value: mockClient }, }); - const modalSpy = jest.spyOn(Modal, 'createTrackedDialog').mockReturnValue(undefined); + const modalSpy = jest.spyOn(Modal, 'createDialog').mockReturnValue(undefined); beforeAll(() => { maplibregl.AttributionControl = jest.fn(); diff --git a/test/components/views/messages/MLocationBody-test.tsx b/test/components/views/messages/MLocationBody-test.tsx index ec2270f6358..5fe5a213808 100644 --- a/test/components/views/messages/MLocationBody-test.tsx +++ b/test/components/views/messages/MLocationBody-test.tsx @@ -127,7 +127,7 @@ describe("MLocationBody", () => { }); it('opens map dialog on click', () => { - const modalSpy = jest.spyOn(Modal, 'createTrackedDialog').mockReturnValue(undefined); + const modalSpy = jest.spyOn(Modal, 'createDialog').mockReturnValue(undefined); const component = getComponent(); act(() => { diff --git a/test/end-to-end-tests/element/config-template/config.json b/test/end-to-end-tests/element/config-template/config.json index b90fefc2cbe..66e1295af30 100644 --- a/test/end-to-end-tests/element/config-template/config.json +++ b/test/end-to-end-tests/element/config-template/config.json @@ -18,11 +18,9 @@ "localhost:5005" ] }, - "piwik": { - "url": "https://piwik.riot.im/", - "whitelistedHSUrls": ["http://localhost:5005"], - "whitelistedISUrls": ["https://vector.im", "https://matrix.org"], - "siteId": 1 + "posthog": { + "projectApiKey": "not-a-real-api-key", + "apiHost": "http://localhost:5005" }, "enable_presence_by_hs_url": { "https://matrix.org": false diff --git a/test/utils/MultiInviter-test.ts b/test/utils/MultiInviter-test.ts index 1d5420aa8f5..5663efe42fa 100644 --- a/test/utils/MultiInviter-test.ts +++ b/test/utils/MultiInviter-test.ts @@ -36,7 +36,7 @@ const MXID_PROFILE_STATES = { }; jest.mock('../../src/Modal', () => ({ - createTrackedDialog: jest.fn(), + createDialog: jest.fn(), })); jest.mock('../../src/settings/SettingsStore', () => ({ @@ -54,12 +54,8 @@ const mockPromptBeforeInviteUnknownUsers = (value: boolean) => { }; const mockCreateTrackedDialog = (callbackName: 'onInviteAnyways'|'onGiveUp') => { - mocked(Modal.createTrackedDialog).mockImplementation( - ( - _analyticsAction: string, - _analyticsInfo: string, - ...rest: Parameters - ): any => { + mocked(Modal.createDialog).mockImplementation( + (...rest: Parameters): any => { rest[1][callbackName](); }, );