Remove Piwik support (#8835)
* Remove all mentions of Piwik * Kill off all consumer of the old Piwik Analytics module * Simplify ModalManager interface * i18n * Attempt to fix old e2e tests * Remove unused component * Iterate PR
This commit is contained in:
parent
7d14d15ba6
commit
3c5c2bef6d
142 changed files with 446 additions and 1412 deletions
|
@ -89,7 +89,6 @@
|
||||||
@import "./views/context_menus/_IconizedContextMenu.scss";
|
@import "./views/context_menus/_IconizedContextMenu.scss";
|
||||||
@import "./views/context_menus/_MessageContextMenu.scss";
|
@import "./views/context_menus/_MessageContextMenu.scss";
|
||||||
@import "./views/dialogs/_AddExistingToSpaceDialog.scss";
|
@import "./views/dialogs/_AddExistingToSpaceDialog.scss";
|
||||||
@import "./views/dialogs/_Analytics.scss";
|
|
||||||
@import "./views/dialogs/_AnalyticsLearnMoreDialog.scss";
|
@import "./views/dialogs/_AnalyticsLearnMoreDialog.scss";
|
||||||
@import "./views/dialogs/_BugReportDialog.scss";
|
@import "./views/dialogs/_BugReportDialog.scss";
|
||||||
@import "./views/dialogs/_BulkRedactDialog.scss";
|
@import "./views/dialogs/_BulkRedactDialog.scss";
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
2
src/@types/global.d.ts
vendored
2
src/@types/global.d.ts
vendored
|
@ -34,7 +34,6 @@ import type { Renderer } from "react-dom";
|
||||||
import RightPanelStore from "../stores/right-panel/RightPanelStore";
|
import RightPanelStore from "../stores/right-panel/RightPanelStore";
|
||||||
import WidgetStore from "../stores/WidgetStore";
|
import WidgetStore from "../stores/WidgetStore";
|
||||||
import CallHandler from "../CallHandler";
|
import CallHandler from "../CallHandler";
|
||||||
import { Analytics } from "../Analytics";
|
|
||||||
import UserActivity from "../UserActivity";
|
import UserActivity from "../UserActivity";
|
||||||
import { ModalWidgetStore } from "../stores/ModalWidgetStore";
|
import { ModalWidgetStore } from "../stores/ModalWidgetStore";
|
||||||
import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
|
import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
|
||||||
|
@ -91,7 +90,6 @@ declare global {
|
||||||
mxWidgetStore: WidgetStore;
|
mxWidgetStore: WidgetStore;
|
||||||
mxWidgetLayoutStore: WidgetLayoutStore;
|
mxWidgetLayoutStore: WidgetLayoutStore;
|
||||||
mxCallHandler: CallHandler;
|
mxCallHandler: CallHandler;
|
||||||
mxAnalytics: Analytics;
|
|
||||||
mxUserActivity: UserActivity;
|
mxUserActivity: UserActivity;
|
||||||
mxModalWidgetStore: ModalWidgetStore;
|
mxModalWidgetStore: ModalWidgetStore;
|
||||||
mxVoipUserMapper: VoipUserMapper;
|
mxVoipUserMapper: VoipUserMapper;
|
||||||
|
|
|
@ -206,7 +206,7 @@ export default class AddThreepid {
|
||||||
continueKind: "primary",
|
continueKind: "primary",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const { finished } = Modal.createTrackedDialog('Add Email', '', InteractiveAuthDialog, {
|
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||||
title: _t("Add Email Address"),
|
title: _t("Add Email Address"),
|
||||||
matrixClient: MatrixClientPeg.get(),
|
matrixClient: MatrixClientPeg.get(),
|
||||||
authData: e.data,
|
authData: e.data,
|
||||||
|
@ -319,7 +319,7 @@ export default class AddThreepid {
|
||||||
continueKind: "primary",
|
continueKind: "primary",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const { finished } = Modal.createTrackedDialog('Add MSISDN', '', InteractiveAuthDialog, {
|
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||||
title: _t("Add Phone Number"),
|
title: _t("Add Phone Number"),
|
||||||
matrixClient: MatrixClientPeg.get(),
|
matrixClient: MatrixClientPeg.get(),
|
||||||
authData: e.data,
|
authData: e.data,
|
||||||
|
|
|
@ -1,460 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
|
|
||||||
Copyright 2020 - 2022 The Matrix.org Foundation C.I.C.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
|
||||||
import { Optional } from "matrix-events-sdk";
|
|
||||||
import { randomString } from 'matrix-js-sdk/src/randomstring';
|
|
||||||
|
|
||||||
import { getCurrentLanguage, _t, _td, IVariables } from './languageHandler';
|
|
||||||
import PlatformPeg from './PlatformPeg';
|
|
||||||
import SdkConfig from './SdkConfig';
|
|
||||||
import Modal from './Modal';
|
|
||||||
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
|
|
||||||
import { SnakedObject } from "./utils/SnakedObject";
|
|
||||||
import { IConfigOptions } from "./IConfigOptions";
|
|
||||||
|
|
||||||
// Note: we keep the analytics redaction on groups in case people have old links.
|
|
||||||
const hashRegex = /#\/(groups?|room|user|settings|register|login|forgot_password|home|directory)/;
|
|
||||||
const hashVarRegex = /#\/(group|room|user)\/.*$/;
|
|
||||||
|
|
||||||
// Remove all but the first item in the hash path. Redact unexpected hashes.
|
|
||||||
function getRedactedHash(hash: string): string {
|
|
||||||
// Don't leak URLs we aren't expecting - they could contain tokens/PII
|
|
||||||
const match = hashRegex.exec(hash);
|
|
||||||
if (!match) {
|
|
||||||
logger.warn(`Unexpected hash location "${hash}"`);
|
|
||||||
return '#/<unexpected hash location>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hashVarRegex.test(hash)) {
|
|
||||||
return hash.replace(hashVarRegex, "#/$1/<redacted>");
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash.replace(hashRegex, "#/$1");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the current origin, path and hash separated with a `/`. This does
|
|
||||||
// not include query parameters.
|
|
||||||
function getRedactedUrl(): string {
|
|
||||||
const { origin, hash } = window.location;
|
|
||||||
let { pathname } = window.location;
|
|
||||||
|
|
||||||
// Redact paths which could contain unexpected PII
|
|
||||||
if (origin.startsWith('file://')) {
|
|
||||||
pathname = "/<redacted>/";
|
|
||||||
}
|
|
||||||
|
|
||||||
return origin + pathname + getRedactedHash(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IData {
|
|
||||||
/* eslint-disable camelcase */
|
|
||||||
gt_ms?: string;
|
|
||||||
e_c?: string;
|
|
||||||
e_a?: string;
|
|
||||||
e_n?: string;
|
|
||||||
e_v?: string;
|
|
||||||
ping?: string;
|
|
||||||
/* eslint-enable camelcase */
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IVariable {
|
|
||||||
id: number;
|
|
||||||
expl: string; // explanation
|
|
||||||
example: string; // example value
|
|
||||||
getTextVariables?(): IVariables; // object to pass as 2nd argument to `_t`
|
|
||||||
}
|
|
||||||
|
|
||||||
const customVariables: Record<string, IVariable> = {
|
|
||||||
// The Matomo installation at https://matomo.riot.im is currently configured
|
|
||||||
// with a limit of 10 custom variables.
|
|
||||||
'App Platform': {
|
|
||||||
id: 1,
|
|
||||||
expl: _td('The platform you\'re on'),
|
|
||||||
example: 'Electron Platform',
|
|
||||||
},
|
|
||||||
'App Version': {
|
|
||||||
id: 2,
|
|
||||||
expl: _td('The version of %(brand)s'),
|
|
||||||
getTextVariables: () => ({
|
|
||||||
brand: SdkConfig.get().brand,
|
|
||||||
}),
|
|
||||||
example: '15.0.0',
|
|
||||||
},
|
|
||||||
'User Type': {
|
|
||||||
id: 3,
|
|
||||||
expl: _td('Whether or not you\'re logged in (we don\'t record your username)'),
|
|
||||||
example: 'Logged In',
|
|
||||||
},
|
|
||||||
'Chosen Language': {
|
|
||||||
id: 4,
|
|
||||||
expl: _td('Your language of choice'),
|
|
||||||
example: 'en',
|
|
||||||
},
|
|
||||||
'Instance': {
|
|
||||||
id: 5,
|
|
||||||
expl: _td('Which officially provided instance you are using, if any'),
|
|
||||||
example: 'app',
|
|
||||||
},
|
|
||||||
'RTE: Uses Richtext Mode': {
|
|
||||||
id: 6,
|
|
||||||
expl: _td('Whether or not you\'re using the Richtext mode of the Rich Text Editor'),
|
|
||||||
example: 'off',
|
|
||||||
},
|
|
||||||
'Homeserver URL': {
|
|
||||||
id: 7,
|
|
||||||
expl: _td('Your homeserver\'s URL'),
|
|
||||||
example: 'https://matrix.org',
|
|
||||||
},
|
|
||||||
'Touch Input': {
|
|
||||||
id: 8,
|
|
||||||
expl: _td("Whether you're using %(brand)s on a device where touch is the primary input mechanism"),
|
|
||||||
getTextVariables: () => ({
|
|
||||||
brand: SdkConfig.get().brand,
|
|
||||||
}),
|
|
||||||
example: 'false',
|
|
||||||
},
|
|
||||||
'Breadcrumbs': {
|
|
||||||
id: 9,
|
|
||||||
expl: _td("Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)"),
|
|
||||||
example: 'disabled',
|
|
||||||
},
|
|
||||||
'Installed PWA': {
|
|
||||||
id: 10,
|
|
||||||
expl: _td("Whether you're using %(brand)s as an installed Progressive Web App"),
|
|
||||||
getTextVariables: () => ({
|
|
||||||
brand: SdkConfig.get().brand,
|
|
||||||
}),
|
|
||||||
example: 'false',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function whitelistRedact(whitelist: string[], str: string): string {
|
|
||||||
if (whitelist.includes(str)) return str;
|
|
||||||
return '<redacted>';
|
|
||||||
}
|
|
||||||
|
|
||||||
const UID_KEY = "mx_Riot_Analytics_uid";
|
|
||||||
const CREATION_TS_KEY = "mx_Riot_Analytics_cts";
|
|
||||||
const VISIT_COUNT_KEY = "mx_Riot_Analytics_vc";
|
|
||||||
const LAST_VISIT_TS_KEY = "mx_Riot_Analytics_lvts";
|
|
||||||
|
|
||||||
function getUid(): string {
|
|
||||||
try {
|
|
||||||
let data = localStorage?.getItem(UID_KEY);
|
|
||||||
if (!data && localStorage) {
|
|
||||||
localStorage.setItem(UID_KEY, data = randomString(16));
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
} catch (e) {
|
|
||||||
logger.error("Analytics error: ", e);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const HEARTBEAT_INTERVAL = 30 * 1000; // seconds
|
|
||||||
|
|
||||||
export class Analytics {
|
|
||||||
private baseUrl: URL = null;
|
|
||||||
private visitVariables: Record<number, [string, string]> = {}; // {[id: number]: [name: string, value: string]}
|
|
||||||
private firstPage = true;
|
|
||||||
private heartbeatIntervalID: number = null;
|
|
||||||
|
|
||||||
private readonly creationTs: string;
|
|
||||||
private readonly lastVisitTs: string;
|
|
||||||
private readonly visitCount: string;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.creationTs = localStorage && localStorage.getItem(CREATION_TS_KEY);
|
|
||||||
if (!this.creationTs && localStorage) {
|
|
||||||
localStorage.setItem(CREATION_TS_KEY, this.creationTs = String(new Date().getTime()));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.lastVisitTs = localStorage && localStorage.getItem(LAST_VISIT_TS_KEY);
|
|
||||||
this.visitCount = localStorage && localStorage.getItem(VISIT_COUNT_KEY) || "0";
|
|
||||||
this.visitCount = String(parseInt(this.visitCount, 10) + 1); // increment
|
|
||||||
if (localStorage) {
|
|
||||||
localStorage.setItem(VISIT_COUNT_KEY, this.visitCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public get disabled() {
|
|
||||||
return !this.baseUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public canEnable() {
|
|
||||||
const piwikConfig = SdkConfig.get("piwik");
|
|
||||||
let piwik: Optional<SnakedObject<Extract<IConfigOptions["piwik"], object>>>;
|
|
||||||
if (typeof piwikConfig === 'object') {
|
|
||||||
piwik = new SnakedObject(piwikConfig);
|
|
||||||
}
|
|
||||||
return navigator.doNotTrack !== "1" && piwik?.get("site_id");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable Analytics if initialized but disabled
|
|
||||||
* otherwise try and initalize, no-op if piwik config missing
|
|
||||||
*/
|
|
||||||
public async enable() {
|
|
||||||
if (!this.disabled) return;
|
|
||||||
if (!this.canEnable()) return;
|
|
||||||
const piwikConfig = SdkConfig.get("piwik");
|
|
||||||
let piwik: Optional<SnakedObject<Extract<IConfigOptions["piwik"], object>>>;
|
|
||||||
if (typeof piwikConfig === 'object') {
|
|
||||||
piwik = new SnakedObject(piwikConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.baseUrl = new URL("piwik.php", piwik.get("url"));
|
|
||||||
// set constants
|
|
||||||
this.baseUrl.searchParams.set("rec", "1"); // rec is required for tracking
|
|
||||||
this.baseUrl.searchParams.set("idsite", piwik.get("site_id")); // idsite is required for tracking
|
|
||||||
this.baseUrl.searchParams.set("apiv", "1"); // API version to use
|
|
||||||
this.baseUrl.searchParams.set("send_image", "0"); // we want a 204, not a tiny GIF
|
|
||||||
// set user parameters
|
|
||||||
this.baseUrl.searchParams.set("_id", getUid()); // uuid
|
|
||||||
this.baseUrl.searchParams.set("_idts", this.creationTs); // first ts
|
|
||||||
this.baseUrl.searchParams.set("_idvc", this.visitCount); // visit count
|
|
||||||
if (this.lastVisitTs) {
|
|
||||||
this.baseUrl.searchParams.set("_viewts", this.lastVisitTs); // last visit ts
|
|
||||||
}
|
|
||||||
|
|
||||||
const platform = PlatformPeg.get();
|
|
||||||
this.setVisitVariable('App Platform', platform.getHumanReadableName());
|
|
||||||
try {
|
|
||||||
this.setVisitVariable('App Version', await platform.getAppVersion());
|
|
||||||
} catch (e) {
|
|
||||||
this.setVisitVariable('App Version', 'unknown');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setVisitVariable('Chosen Language', getCurrentLanguage());
|
|
||||||
|
|
||||||
const hostname = window.location.hostname;
|
|
||||||
if (hostname === 'riot.im') {
|
|
||||||
this.setVisitVariable('Instance', window.location.pathname);
|
|
||||||
} else if (hostname.endsWith('.element.io')) {
|
|
||||||
this.setVisitVariable('Instance', hostname.replace('.element.io', ''));
|
|
||||||
}
|
|
||||||
|
|
||||||
let installedPWA = "unknown";
|
|
||||||
try {
|
|
||||||
// Known to work at least for desktop Chrome
|
|
||||||
installedPWA = String(window.matchMedia('(display-mode: standalone)').matches);
|
|
||||||
} catch (e) { }
|
|
||||||
this.setVisitVariable('Installed PWA', installedPWA);
|
|
||||||
|
|
||||||
let touchInput = "unknown";
|
|
||||||
try {
|
|
||||||
// MDN claims broad support across browsers
|
|
||||||
touchInput = String(window.matchMedia('(pointer: coarse)').matches);
|
|
||||||
} catch (e) { }
|
|
||||||
this.setVisitVariable('Touch Input', touchInput);
|
|
||||||
|
|
||||||
// start heartbeat
|
|
||||||
this.heartbeatIntervalID = window.setInterval(this.ping.bind(this), HEARTBEAT_INTERVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable Analytics, stop the heartbeat and clear identifiers from localStorage
|
|
||||||
*/
|
|
||||||
public disable() {
|
|
||||||
if (this.disabled) return;
|
|
||||||
this.trackEvent('Analytics', 'opt-out');
|
|
||||||
window.clearInterval(this.heartbeatIntervalID);
|
|
||||||
this.baseUrl = null;
|
|
||||||
this.visitVariables = {};
|
|
||||||
localStorage.removeItem(UID_KEY);
|
|
||||||
localStorage.removeItem(CREATION_TS_KEY);
|
|
||||||
localStorage.removeItem(VISIT_COUNT_KEY);
|
|
||||||
localStorage.removeItem(LAST_VISIT_TS_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async track(data: IData) {
|
|
||||||
if (this.disabled) return;
|
|
||||||
|
|
||||||
const now = new Date();
|
|
||||||
const params = {
|
|
||||||
...data,
|
|
||||||
url: getRedactedUrl(),
|
|
||||||
|
|
||||||
_cvar: JSON.stringify(this.visitVariables), // user custom vars
|
|
||||||
res: `${window.screen.width}x${window.screen.height}`, // resolution as WWWWxHHHH
|
|
||||||
rand: String(Math.random()).slice(2, 8), // random nonce to cache-bust
|
|
||||||
h: now.getHours(),
|
|
||||||
m: now.getMinutes(),
|
|
||||||
s: now.getSeconds(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const url = new URL(this.baseUrl.toString()); // copy
|
|
||||||
for (const key in params) {
|
|
||||||
url.searchParams.set(key, params[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await window.fetch(url.toString(), {
|
|
||||||
method: "GET",
|
|
||||||
mode: "no-cors",
|
|
||||||
cache: "no-cache",
|
|
||||||
redirect: "follow",
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
logger.error("Analytics error: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ping() {
|
|
||||||
this.track({
|
|
||||||
ping: "1",
|
|
||||||
});
|
|
||||||
localStorage.setItem(LAST_VISIT_TS_KEY, String(new Date().getTime())); // update last visit ts
|
|
||||||
}
|
|
||||||
|
|
||||||
public trackPageChange(generationTimeMs?: number) {
|
|
||||||
if (this.disabled) return;
|
|
||||||
if (this.firstPage) {
|
|
||||||
// De-duplicate first page
|
|
||||||
// router seems to hit the fn twice
|
|
||||||
this.firstPage = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof generationTimeMs !== 'number') {
|
|
||||||
logger.warn('Analytics.trackPageChange: expected generationTimeMs to be a number');
|
|
||||||
// But continue anyway because we still want to track the change
|
|
||||||
}
|
|
||||||
|
|
||||||
this.track({
|
|
||||||
gt_ms: String(generationTimeMs),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public trackEvent(category: string, action: string, name?: string, value?: string) {
|
|
||||||
if (this.disabled) return;
|
|
||||||
this.track({
|
|
||||||
e_c: category,
|
|
||||||
e_a: action,
|
|
||||||
e_n: name,
|
|
||||||
e_v: value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private setVisitVariable(key: keyof typeof customVariables, value: string) {
|
|
||||||
if (this.disabled) return;
|
|
||||||
this.visitVariables[customVariables[key].id] = [key, value];
|
|
||||||
}
|
|
||||||
|
|
||||||
public setLoggedIn(isGuest: boolean, homeserverUrl: string) {
|
|
||||||
if (this.disabled) return;
|
|
||||||
|
|
||||||
const piwikConfig = SdkConfig.get("piwik");
|
|
||||||
let piwik: Optional<SnakedObject<Extract<IConfigOptions["piwik"], object>>>;
|
|
||||||
if (typeof piwikConfig === 'object') {
|
|
||||||
piwik = new SnakedObject(piwikConfig);
|
|
||||||
}
|
|
||||||
if (!piwik) return;
|
|
||||||
|
|
||||||
const whitelistedHSUrls = piwik.get("whitelisted_hs_urls", "whitelistedHSUrls") || [];
|
|
||||||
|
|
||||||
this.setVisitVariable('User Type', isGuest ? 'Guest' : 'Logged In');
|
|
||||||
this.setVisitVariable('Homeserver URL', whitelistRedact(whitelistedHSUrls, homeserverUrl));
|
|
||||||
}
|
|
||||||
|
|
||||||
public setBreadcrumbs(state: boolean) {
|
|
||||||
if (this.disabled) return;
|
|
||||||
this.setVisitVariable('Breadcrumbs', state ? 'enabled' : 'disabled');
|
|
||||||
}
|
|
||||||
|
|
||||||
public showDetailsModal = () => {
|
|
||||||
let rows = [];
|
|
||||||
if (!this.disabled) {
|
|
||||||
rows = Object.values(this.visitVariables);
|
|
||||||
} else {
|
|
||||||
rows = Object.keys(customVariables).map(
|
|
||||||
(k) => [
|
|
||||||
k,
|
|
||||||
_t('e.g. %(exampleValue)s', { exampleValue: customVariables[k].example }),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const resolution = `${window.screen.width}x${window.screen.height}`;
|
|
||||||
const otherVariables = [
|
|
||||||
{
|
|
||||||
expl: _td('Every page you use in the app'),
|
|
||||||
value: _t(
|
|
||||||
'e.g. <CurrentPageURL>',
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
CurrentPageURL: getRedactedUrl,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{ expl: _td('Your user agent'), value: navigator.userAgent },
|
|
||||||
{ expl: _td('Your device resolution'), value: resolution },
|
|
||||||
];
|
|
||||||
|
|
||||||
const piwikConfig = SdkConfig.get("piwik");
|
|
||||||
let piwik: Optional<SnakedObject<Extract<IConfigOptions["piwik"], object>>>;
|
|
||||||
if (typeof piwikConfig === 'object') {
|
|
||||||
piwik = new SnakedObject(piwikConfig);
|
|
||||||
}
|
|
||||||
const cookiePolicyUrl = piwik?.get("policy_url");
|
|
||||||
const cookiePolicyLink = _t(
|
|
||||||
"Our complete cookie policy can be found <CookiePolicyLink>here</CookiePolicyLink>.",
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
"CookiePolicyLink": (sub) => {
|
|
||||||
return <a href={cookiePolicyUrl} target="_blank" rel="noreferrer noopener">{ sub }</a>;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
Modal.createTrackedDialog('Analytics Details', '', ErrorDialog, {
|
|
||||||
title: _t('Analytics'),
|
|
||||||
description: <div className="mx_AnalyticsModal">
|
|
||||||
{ cookiePolicyUrl && <p>{ cookiePolicyLink }</p> }
|
|
||||||
<div>{ _t('Some examples of the information being sent to us to help make %(brand)s better includes:', {
|
|
||||||
brand: SdkConfig.get().brand,
|
|
||||||
}) }</div>
|
|
||||||
<table>
|
|
||||||
{ rows.map((row) => <tr key={row[0]}>
|
|
||||||
<td className="mx_AnalyticsModal_label">{ _t(
|
|
||||||
customVariables[row[0]].expl,
|
|
||||||
customVariables[row[0]].getTextVariables ?
|
|
||||||
customVariables[row[0]].getTextVariables() :
|
|
||||||
null,
|
|
||||||
) }</td>
|
|
||||||
{ row[1] !== undefined && <td><code>{ row[1] }</code></td> }
|
|
||||||
</tr>) }
|
|
||||||
{ otherVariables.map((item, index) =>
|
|
||||||
<tr key={index}>
|
|
||||||
<td>{ _t(item.expl) }</td>
|
|
||||||
<td><code>{ item.value }</code></td>
|
|
||||||
</tr>,
|
|
||||||
) }
|
|
||||||
</table>
|
|
||||||
<div>
|
|
||||||
{ _t('Where this page includes identifiable information, such as a room, '
|
|
||||||
+ 'user ID, that data is removed before being sent to the server.') }
|
|
||||||
</div>
|
|
||||||
</div>,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!window.mxAnalytics) {
|
|
||||||
window.mxAnalytics = new Analytics();
|
|
||||||
}
|
|
||||||
export default window.mxAnalytics;
|
|
|
@ -47,7 +47,6 @@ import ErrorDialog from "./components/views/dialogs/ErrorDialog";
|
||||||
import WidgetStore from "./stores/WidgetStore";
|
import WidgetStore from "./stores/WidgetStore";
|
||||||
import { WidgetMessagingStore } from "./stores/widgets/WidgetMessagingStore";
|
import { WidgetMessagingStore } from "./stores/widgets/WidgetMessagingStore";
|
||||||
import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions";
|
import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions";
|
||||||
import Analytics from './Analytics';
|
|
||||||
import { UIFeature } from "./settings/UIFeature";
|
import { UIFeature } from "./settings/UIFeature";
|
||||||
import { Action } from './dispatcher/actions';
|
import { Action } from './dispatcher/actions';
|
||||||
import VoipUserMapper from './VoipUserMapper';
|
import VoipUserMapper from './VoipUserMapper';
|
||||||
|
@ -305,7 +304,6 @@ export default class CallHandler extends EventEmitter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Analytics.trackEvent('voip', 'receiveCall', 'type', call.type);
|
|
||||||
this.addCallForRoom(mappedRoomId, call);
|
this.addCallForRoom(mappedRoomId, call);
|
||||||
this.setCallListeners(call);
|
this.setCallListeners(call);
|
||||||
// Explicitly handle first state change
|
// Explicitly handle first state change
|
||||||
|
@ -447,7 +445,6 @@ export default class CallHandler extends EventEmitter {
|
||||||
call.on(CallEvent.Error, (err: CallError) => {
|
call.on(CallEvent.Error, (err: CallError) => {
|
||||||
if (!this.matchesCallForThisRoom(call)) return;
|
if (!this.matchesCallForThisRoom(call)) return;
|
||||||
|
|
||||||
Analytics.trackEvent('voip', 'callError', 'error', err.toString());
|
|
||||||
logger.error("Call error:", err);
|
logger.error("Call error:", err);
|
||||||
|
|
||||||
if (err.code === CallErrorCode.NoUserMedia) {
|
if (err.code === CallErrorCode.NoUserMedia) {
|
||||||
|
@ -463,7 +460,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Modal.createTrackedDialog('Call Failed', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Call Failed'),
|
title: _t('Call Failed'),
|
||||||
description: err.message,
|
description: err.message,
|
||||||
});
|
});
|
||||||
|
@ -471,8 +468,6 @@ export default class CallHandler extends EventEmitter {
|
||||||
call.on(CallEvent.Hangup, () => {
|
call.on(CallEvent.Hangup, () => {
|
||||||
if (!this.matchesCallForThisRoom(call)) return;
|
if (!this.matchesCallForThisRoom(call)) return;
|
||||||
|
|
||||||
Analytics.trackEvent('voip', 'callHangup');
|
|
||||||
|
|
||||||
this.removeCallForRoom(mappedRoomId);
|
this.removeCallForRoom(mappedRoomId);
|
||||||
});
|
});
|
||||||
call.on(CallEvent.State, (newState: CallState, oldState: CallState) => {
|
call.on(CallEvent.State, (newState: CallState, oldState: CallState) => {
|
||||||
|
@ -584,7 +579,6 @@ export default class CallHandler extends EventEmitter {
|
||||||
}
|
}
|
||||||
case CallState.Ended: {
|
case CallState.Ended: {
|
||||||
const hangupReason = call.hangupReason;
|
const hangupReason = call.hangupReason;
|
||||||
Analytics.trackEvent('voip', 'callEnded', 'hangupReason', hangupReason);
|
|
||||||
this.removeCallForRoom(mappedRoomId);
|
this.removeCallForRoom(mappedRoomId);
|
||||||
if (oldState === CallState.InviteSent && call.hangupParty === CallParty.Remote) {
|
if (oldState === CallState.InviteSent && call.hangupParty === CallParty.Remote) {
|
||||||
this.play(AudioID.Busy);
|
this.play(AudioID.Busy);
|
||||||
|
@ -603,13 +597,13 @@ export default class CallHandler extends EventEmitter {
|
||||||
description = _t("The call could not be established");
|
description = _t("The call could not be established");
|
||||||
}
|
}
|
||||||
|
|
||||||
Modal.createTrackedDialog('Call Handler', 'Call Failed', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title, description,
|
title, description,
|
||||||
});
|
});
|
||||||
} else if (
|
} else if (
|
||||||
hangupReason === CallErrorCode.AnsweredElsewhere && oldState === CallState.Connecting
|
hangupReason === CallErrorCode.AnsweredElsewhere && oldState === CallState.Connecting
|
||||||
) {
|
) {
|
||||||
Modal.createTrackedDialog('Call Handler', 'Call Failed', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Answered Elsewhere"),
|
title: _t("Answered Elsewhere"),
|
||||||
description: _t("The call was answered on another device."),
|
description: _t("The call was answered on another device."),
|
||||||
});
|
});
|
||||||
|
@ -709,7 +703,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
private showICEFallbackPrompt(): void {
|
private showICEFallbackPrompt(): void {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const code = sub => <code>{ sub }</code>;
|
const code = sub => <code>{ sub }</code>;
|
||||||
Modal.createTrackedDialog('No TURN servers', '', QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Call failed due to misconfigured server"),
|
title: _t("Call failed due to misconfigured server"),
|
||||||
description: <div>
|
description: <div>
|
||||||
<p>{ _t(
|
<p>{ _t(
|
||||||
|
@ -759,14 +753,12 @@ export default class CallHandler extends EventEmitter {
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
Modal.createTrackedDialog('Media capture failed', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title, description,
|
title, description,
|
||||||
}, null, true);
|
}, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async placeMatrixCall(roomId: string, type: CallType, transferee?: MatrixCall): Promise<void> {
|
private async placeMatrixCall(roomId: string, type: CallType, transferee?: MatrixCall): Promise<void> {
|
||||||
Analytics.trackEvent('voip', 'placeCall', 'type', type);
|
|
||||||
|
|
||||||
const mappedRoomId = (await VoipUserMapper.sharedInstance().getOrCreateVirtualRoomForRoom(roomId)) || roomId;
|
const mappedRoomId = (await VoipUserMapper.sharedInstance().getOrCreateVirtualRoomForRoom(roomId)) || roomId;
|
||||||
logger.debug("Mapped real room " + roomId + " to room ID " + mappedRoomId);
|
logger.debug("Mapped real room " + roomId + " to room ID " + mappedRoomId);
|
||||||
|
|
||||||
|
@ -789,7 +781,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
try {
|
try {
|
||||||
this.addCallForRoom(roomId, call);
|
this.addCallForRoom(roomId, call);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Modal.createTrackedDialog('Call Handler', 'Existing Call with user', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Already in call'),
|
title: _t('Already in call'),
|
||||||
description: _t("You're already in a call with this person."),
|
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 the runtime env doesn't do VoIP, whine.
|
||||||
if (!MatrixClientPeg.get().supportsVoip()) {
|
if (!MatrixClientPeg.get().supportsVoip()) {
|
||||||
Modal.createTrackedDialog('Call Handler', 'VoIP is unsupported', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Calls are unsupported'),
|
title: _t('Calls are unsupported'),
|
||||||
description: _t('You cannot place calls in this browser.'),
|
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) {
|
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'),
|
title: _t('Connectivity to the server has been lost'),
|
||||||
description: _t('You cannot place calls without a connection to the server.'),
|
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.
|
// don't allow > 2 calls to be placed.
|
||||||
if (this.getAllActiveCalls().length > 1) {
|
if (this.getAllActiveCalls().length > 1) {
|
||||||
Modal.createTrackedDialog('Call Handler', 'Existing Call', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Too Many Calls'),
|
title: _t('Too Many Calls'),
|
||||||
description: _t("You've reached the maximum number of simultaneous 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();
|
const members = room.getJoinedMembers();
|
||||||
if (members.length <= 1) {
|
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.'),
|
description: _t('You cannot place a call with yourself.'),
|
||||||
});
|
});
|
||||||
} else if (members.length === 2) {
|
} else if (members.length === 2) {
|
||||||
|
@ -901,7 +893,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
if (!this.calls.has(roomId)) return;
|
if (!this.calls.has(roomId)) return;
|
||||||
|
|
||||||
if (this.getAllActiveCalls().length > 1) {
|
if (this.getAllActiveCalls().length > 1) {
|
||||||
Modal.createTrackedDialog('Call Handler', 'Existing Call', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Too Many Calls'),
|
title: _t('Too Many Calls'),
|
||||||
description: _t("You've reached the maximum number of simultaneous calls."),
|
description: _t("You've reached the maximum number of simultaneous calls."),
|
||||||
});
|
});
|
||||||
|
@ -926,7 +918,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
public async dialNumber(number: string, transferee?: MatrixCall): Promise<void> {
|
public async dialNumber(number: string, transferee?: MatrixCall): Promise<void> {
|
||||||
const results = await this.pstnLookup(number);
|
const results = await this.pstnLookup(number);
|
||||||
if (!results || results.length === 0 || !results[0].userid) {
|
if (!results || results.length === 0 || !results[0].userid) {
|
||||||
Modal.createTrackedDialog('', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Unable to look up phone number"),
|
title: _t("Unable to look up phone number"),
|
||||||
description: _t("There was an error looking up the 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);
|
const results = await this.pstnLookup(destination);
|
||||||
if (!results || results.length === 0 || !results[0].userid) {
|
if (!results || results.length === 0 || !results[0].userid) {
|
||||||
Modal.createTrackedDialog('', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Unable to transfer call"),
|
title: _t("Unable to transfer call"),
|
||||||
description: _t("There was an error looking up the phone number"),
|
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);
|
await call.transfer(destination);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.log("Failed to transfer call", e);
|
logger.log("Failed to transfer call", e);
|
||||||
Modal.createTrackedDialog('Failed to transfer call', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Transfer Failed'),
|
title: _t('Transfer Failed'),
|
||||||
description: _t('Failed to transfer call'),
|
description: _t('Failed to transfer call'),
|
||||||
});
|
});
|
||||||
|
@ -1036,7 +1028,6 @@ export default class CallHandler extends EventEmitter {
|
||||||
private async placeJitsiCall(roomId: string, type: CallType): Promise<void> {
|
private async placeJitsiCall(roomId: string, type: CallType): Promise<void> {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
logger.info(`Place conference call in ${roomId}`);
|
logger.info(`Place conference call in ${roomId}`);
|
||||||
Analytics.trackEvent('voip', 'placeConferenceCall');
|
|
||||||
|
|
||||||
dis.dispatch({ action: 'appsDrawer', show: true });
|
dis.dispatch({ action: 'appsDrawer', show: true });
|
||||||
|
|
||||||
|
@ -1053,7 +1044,7 @@ export default class CallHandler extends EventEmitter {
|
||||||
logger.log('Jitsi widget added');
|
logger.log('Jitsi widget added');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.errcode === 'M_FORBIDDEN') {
|
if (e.errcode === 'M_FORBIDDEN') {
|
||||||
Modal.createTrackedDialog('Call Failed', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Permission Required'),
|
title: _t('Permission Required'),
|
||||||
description: _t("You do not have permission to start a conference call in this room"),
|
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 {
|
public hangupCallApp(roomId: string): void {
|
||||||
logger.info("Leaving conference call in " + roomId);
|
logger.info("Leaving conference call in " + roomId);
|
||||||
|
|
||||||
|
|
|
@ -397,7 +397,7 @@ export default class ContentMessages {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tooBigFiles.length > 0) {
|
if (tooBigFiles.length > 0) {
|
||||||
const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Failure', '', UploadFailureDialog, {
|
const { finished } = Modal.createDialog<[boolean]>(UploadFailureDialog, {
|
||||||
badFiles: tooBigFiles,
|
badFiles: tooBigFiles,
|
||||||
totalFiles: files.length,
|
totalFiles: files.length,
|
||||||
contentMessages: this,
|
contentMessages: this,
|
||||||
|
@ -413,13 +413,11 @@ export default class ContentMessages {
|
||||||
for (let i = 0; i < okFiles.length; ++i) {
|
for (let i = 0; i < okFiles.length; ++i) {
|
||||||
const file = okFiles[i];
|
const file = okFiles[i];
|
||||||
if (!uploadAll) {
|
if (!uploadAll) {
|
||||||
const { finished } = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation',
|
const { finished } = Modal.createDialog<[boolean, boolean]>(UploadConfirmDialog, {
|
||||||
'', UploadConfirmDialog, {
|
|
||||||
file,
|
file,
|
||||||
currentIndex: i,
|
currentIndex: i,
|
||||||
totalFiles: okFiles.length,
|
totalFiles: okFiles.length,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
const [shouldContinue, shouldUploadAll] = await finished;
|
const [shouldContinue, shouldUploadAll] = await finished;
|
||||||
if (!shouldContinue) break;
|
if (!shouldContinue) break;
|
||||||
if (shouldUploadAll) {
|
if (shouldUploadAll) {
|
||||||
|
@ -588,7 +586,7 @@ export default class ContentMessages {
|
||||||
{ fileName: upload.fileName },
|
{ fileName: upload.fileName },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Modal.createTrackedDialog('Upload failed', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Upload Failed'),
|
title: _t('Upload Failed'),
|
||||||
description: desc,
|
description: desc,
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,7 +18,6 @@ import { MatrixError } from "matrix-js-sdk/src/http-api";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { Error as ErrorEvent } from "@matrix-org/analytics-events/types/typescript/Error";
|
import { Error as ErrorEvent } from "@matrix-org/analytics-events/types/typescript/Error";
|
||||||
|
|
||||||
import Analytics from "./Analytics";
|
|
||||||
import { PosthogAnalytics } from './PosthogAnalytics';
|
import { PosthogAnalytics } from './PosthogAnalytics';
|
||||||
|
|
||||||
export class DecryptionFailure {
|
export class DecryptionFailure {
|
||||||
|
@ -37,7 +36,6 @@ export type ErrCodeMapFn = (errcode: string) => ErrorCode;
|
||||||
|
|
||||||
export class DecryptionFailureTracker {
|
export class DecryptionFailureTracker {
|
||||||
private static internalInstance = new DecryptionFailureTracker((total, errorCode, rawError) => {
|
private static internalInstance = new DecryptionFailureTracker((total, errorCode, rawError) => {
|
||||||
Analytics.trackEvent('E2E', 'Decryption failure', errorCode, String(total));
|
|
||||||
for (let i = 0; i < total; i++) {
|
for (let i = 0; i < total; i++) {
|
||||||
PosthogAnalytics.instance.trackEvent<ErrorEvent>({
|
PosthogAnalytics.instance.trackEvent<ErrorEvent>({
|
||||||
eventName: "Error",
|
eventName: "Error",
|
||||||
|
|
|
@ -135,18 +135,15 @@ export interface IConfigOptions {
|
||||||
servers: string[];
|
servers: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
// piwik (matomo) is deprecated in favour of posthog
|
|
||||||
piwik?: false | {
|
piwik?: false | {
|
||||||
url: string; // piwik instance
|
policy_url: string; // deprecated in favour of `privacy_policy_url` at root instead
|
||||||
site_id: string;
|
|
||||||
policy_url: string; // cookie policy
|
|
||||||
whitelisted_hs_urls: string[];
|
|
||||||
};
|
};
|
||||||
posthog?: {
|
posthog?: {
|
||||||
project_api_key: string;
|
project_api_key: string;
|
||||||
api_host: string; // hostname
|
api_host: string; // hostname
|
||||||
};
|
};
|
||||||
analytics_owner?: string; // defaults to `brand`
|
analytics_owner?: string; // defaults to `brand`
|
||||||
|
privacy_policy_url?: string; // location for cookie policy
|
||||||
|
|
||||||
// Server hosting upsell options
|
// Server hosting upsell options
|
||||||
hosting_signup_link?: string; // slightly different from `host_signup`
|
hosting_signup_link?: string; // slightly different from `host_signup`
|
||||||
|
|
|
@ -143,9 +143,7 @@ export default class IdentityAuthClient {
|
||||||
!doesAccountDataHaveIdentityServer() &&
|
!doesAccountDataHaveIdentityServer() &&
|
||||||
!(await doesIdentityServerHaveTerms(identityServerUrl))
|
!(await doesIdentityServerHaveTerms(identityServerUrl))
|
||||||
) {
|
) {
|
||||||
const { finished } = Modal.createTrackedDialog(
|
const { finished } = Modal.createDialog(QuestionDialog, {
|
||||||
'Default identity server terms warning', '',
|
|
||||||
QuestionDialog, {
|
|
||||||
title: _t("Identity server has no terms of service"),
|
title: _t("Identity server has no terms of service"),
|
||||||
description: (
|
description: (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -28,7 +28,6 @@ import { IMatrixClientCreds, MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import SecurityCustomisations from "./customisations/Security";
|
import SecurityCustomisations from "./customisations/Security";
|
||||||
import EventIndexPeg from './indexing/EventIndexPeg';
|
import EventIndexPeg from './indexing/EventIndexPeg';
|
||||||
import createMatrixClient from './utils/createMatrixClient';
|
import createMatrixClient from './utils/createMatrixClient';
|
||||||
import Analytics from './Analytics';
|
|
||||||
import Notifier from './Notifier';
|
import Notifier from './Notifier';
|
||||||
import UserActivity from './UserActivity';
|
import UserActivity from './UserActivity';
|
||||||
import Presence from './Presence';
|
import Presence from './Presence';
|
||||||
|
@ -201,7 +200,7 @@ export function attemptTokenLogin(
|
||||||
const identityServer = localStorage.getItem(SSO_ID_SERVER_URL_KEY);
|
const identityServer = localStorage.getItem(SSO_ID_SERVER_URL_KEY);
|
||||||
if (!homeserver) {
|
if (!homeserver) {
|
||||||
logger.warn("Cannot log in with token: can't determine HS URL to use");
|
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"),
|
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, " +
|
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."),
|
"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;
|
return true;
|
||||||
});
|
});
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
Modal.createTrackedDialog("SSO", "Token Rejected", ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("We couldn't log you in"),
|
title: _t("We couldn't log you in"),
|
||||||
description: err.name === "ConnectionError"
|
description: err.name === "ConnectionError"
|
||||||
? _t("Your homeserver was unreachable and was not able to log you in. Please try again. " +
|
? _t("Your homeserver was unreachable and was not able to log you in. Please try again. " +
|
||||||
|
@ -470,7 +469,7 @@ export async function restoreFromLocalStorage(opts?: { ignoreGuest?: boolean }):
|
||||||
async function handleLoadSessionFailure(e: Error): Promise<boolean> {
|
async function handleLoadSessionFailure(e: Error): Promise<boolean> {
|
||||||
logger.error("Unable to load session", e);
|
logger.error("Unable to load session", e);
|
||||||
|
|
||||||
const modal = Modal.createTrackedDialog('Session Restore Error', '', SessionRestoreErrorDialog, {
|
const modal = Modal.createDialog(SessionRestoreErrorDialog, {
|
||||||
error: e,
|
error: e,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -597,8 +596,6 @@ async function doSetLoggedIn(
|
||||||
await abortLogin();
|
await abortLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
Analytics.setLoggedIn(credentials.guest, credentials.homeserverUrl);
|
|
||||||
|
|
||||||
MatrixClientPeg.replaceUsingCreds(credentials);
|
MatrixClientPeg.replaceUsingCreds(credentials);
|
||||||
|
|
||||||
setSentryUser(credentials.userId);
|
setSentryUser(credentials.userId);
|
||||||
|
@ -640,7 +637,7 @@ async function doSetLoggedIn(
|
||||||
|
|
||||||
function showStorageEvictedDialog(): Promise<boolean> {
|
function showStorageEvictedDialog(): Promise<boolean> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
Modal.createTrackedDialog('Storage evicted', '', StorageEvictedDialog, {
|
Modal.createDialog(StorageEvictedDialog, {
|
||||||
onFinished: resolve,
|
onFinished: resolve,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -880,8 +877,6 @@ export async function onLoggedOut(): Promise<void> {
|
||||||
* @returns {Promise} promise which resolves once the stores have been cleared
|
* @returns {Promise} promise which resolves once the stores have been cleared
|
||||||
*/
|
*/
|
||||||
async function clearStorage(opts?: { deleteEverything?: boolean }): Promise<void> {
|
async function clearStorage(opts?: { deleteEverything?: boolean }): Promise<void> {
|
||||||
Analytics.disable();
|
|
||||||
|
|
||||||
if (window.localStorage) {
|
if (window.localStorage) {
|
||||||
// try to save any 3pid invites from being obliterated and registration time
|
// try to save any 3pid invites from being obliterated and registration time
|
||||||
const pendingInvites = ThreepidInviteStore.instance.getWireInvites();
|
const pendingInvites = ThreepidInviteStore.instance.getWireInvites();
|
||||||
|
|
|
@ -193,8 +193,6 @@ class MatrixClientPegClass implements IMatrixClientPeg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageManager.trackStores(this.matrixClient);
|
|
||||||
|
|
||||||
// try to initialise e2e on the new client
|
// try to initialise e2e on the new client
|
||||||
try {
|
try {
|
||||||
// check that we have a version of the js-sdk which includes initCrypto
|
// check that we have a version of the js-sdk which includes initCrypto
|
||||||
|
|
|
@ -20,7 +20,6 @@ import ReactDOM from 'react-dom';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { defer, sleep } from "matrix-js-sdk/src/utils";
|
import { defer, sleep } from "matrix-js-sdk/src/utils";
|
||||||
|
|
||||||
import Analytics from './Analytics';
|
|
||||||
import dis from './dispatcher/dispatcher';
|
import dis from './dispatcher/dispatcher';
|
||||||
import AsyncWrapper from './AsyncWrapper';
|
import AsyncWrapper from './AsyncWrapper';
|
||||||
|
|
||||||
|
@ -103,24 +102,6 @@ export class ModalManager {
|
||||||
return this.priorityModal || this.staticModal || this.modals.length > 0;
|
return this.priorityModal || this.staticModal || this.modals.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createTrackedDialog<T extends any[]>(
|
|
||||||
analyticsAction: string,
|
|
||||||
analyticsInfo: string,
|
|
||||||
...rest: Parameters<ModalManager["createDialog"]>
|
|
||||||
) {
|
|
||||||
Analytics.trackEvent('Modal', analyticsAction, analyticsInfo);
|
|
||||||
return this.createDialog<T>(...rest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public appendTrackedDialog<T extends any[]>(
|
|
||||||
analyticsAction: string,
|
|
||||||
analyticsInfo: string,
|
|
||||||
...rest: Parameters<ModalManager["appendDialog"]>
|
|
||||||
) {
|
|
||||||
Analytics.trackEvent('Modal', analyticsAction, analyticsInfo);
|
|
||||||
return this.appendDialog<T>(...rest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public createDialog<T extends any[]>(
|
public createDialog<T extends any[]>(
|
||||||
Element: React.ComponentType,
|
Element: React.ComponentType,
|
||||||
...rest: ParametersWithoutFirst<ModalManager["createDialogAsync"]>
|
...rest: ParametersWithoutFirst<ModalManager["createDialogAsync"]>
|
||||||
|
@ -135,24 +116,6 @@ export class ModalManager {
|
||||||
return this.appendDialogAsync<T>(Promise.resolve(Element), ...rest);
|
return this.appendDialogAsync<T>(Promise.resolve(Element), ...rest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public createTrackedDialogAsync<T extends any[]>(
|
|
||||||
analyticsAction: string,
|
|
||||||
analyticsInfo: string,
|
|
||||||
...rest: Parameters<ModalManager["createDialogAsync"]>
|
|
||||||
) {
|
|
||||||
Analytics.trackEvent('Modal', analyticsAction, analyticsInfo);
|
|
||||||
return this.createDialogAsync<T>(...rest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public appendTrackedDialogAsync<T extends any[]>(
|
|
||||||
analyticsAction: string,
|
|
||||||
analyticsInfo: string,
|
|
||||||
...rest: Parameters<ModalManager["appendDialogAsync"]>
|
|
||||||
) {
|
|
||||||
Analytics.trackEvent('Modal', analyticsAction, analyticsInfo);
|
|
||||||
return this.appendDialogAsync<T>(...rest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public closeCurrentModal(reason: string) {
|
public closeCurrentModal(reason: string) {
|
||||||
const modal = this.getCurrentModal();
|
const modal = this.getCurrentModal();
|
||||||
if (!modal) {
|
if (!modal) {
|
||||||
|
@ -273,7 +236,7 @@ export class ModalManager {
|
||||||
* @param {onBeforeClose} options.onBeforeClose a callback to decide whether to close the dialog
|
* @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
|
* @returns {object} Object with 'close' parameter being a function that will close the dialog
|
||||||
*/
|
*/
|
||||||
private createDialogAsync<T extends any[]>(
|
public createDialogAsync<T extends any[]>(
|
||||||
prom: Promise<React.ComponentType>,
|
prom: Promise<React.ComponentType>,
|
||||||
props?: IProps<T>,
|
props?: IProps<T>,
|
||||||
className?: string,
|
className?: string,
|
||||||
|
|
|
@ -28,7 +28,6 @@ import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import SdkConfig from './SdkConfig';
|
import SdkConfig from './SdkConfig';
|
||||||
import PlatformPeg from './PlatformPeg';
|
import PlatformPeg from './PlatformPeg';
|
||||||
import * as TextForEvent from './TextForEvent';
|
import * as TextForEvent from './TextForEvent';
|
||||||
import Analytics from './Analytics';
|
|
||||||
import * as Avatar from './Avatar';
|
import * as Avatar from './Avatar';
|
||||||
import dis from './dispatcher/dispatcher';
|
import dis from './dispatcher/dispatcher';
|
||||||
import { _t } from './languageHandler';
|
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
|
// 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.
|
// 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
|
// make sure that we persist the current setting audio_enabled setting
|
||||||
// before changing anything
|
// before changing anything
|
||||||
if (SettingsStore.isLevelSupported(SettingLevel.DEVICE)) {
|
if (SettingsStore.isLevelSupported(SettingLevel.DEVICE)) {
|
||||||
|
@ -249,7 +246,7 @@ export const Notifier = {
|
||||||
? _t('%(brand)s does not have permission to send you notifications - ' +
|
? _t('%(brand)s does not have permission to send you notifications - ' +
|
||||||
'please check your browser settings', { brand })
|
'please check your browser settings', { brand })
|
||||||
: _t('%(brand)s was not given permission to send notifications - please try again', { 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'),
|
title: _t('Unable to enable Notifications'),
|
||||||
description,
|
description,
|
||||||
});
|
});
|
||||||
|
@ -298,8 +295,6 @@ export const Notifier = {
|
||||||
setPromptHidden: function(hidden: boolean, persistent = true) {
|
setPromptHidden: function(hidden: boolean, persistent = true) {
|
||||||
this.toolbarHidden = hidden;
|
this.toolbarHidden = hidden;
|
||||||
|
|
||||||
Analytics.trackEvent('Notifier', 'Set Toolbar Hidden', String(hidden));
|
|
||||||
|
|
||||||
hideNotificationsToast();
|
hideNotificationsToast();
|
||||||
|
|
||||||
// update the info to localStorage for persistent settings
|
// update the info to localStorage for persistent settings
|
||||||
|
|
|
@ -49,7 +49,7 @@ export async function startAnyRegistrationFlow(
|
||||||
options: { go_home_on_cancel?: boolean, go_welcome_on_cancel?: boolean, screen_after?: boolean},
|
options: { go_home_on_cancel?: boolean, go_welcome_on_cancel?: boolean, screen_after?: boolean},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (options === undefined) options = {};
|
if (options === undefined) options = {};
|
||||||
const modal = Modal.createTrackedDialog('Registration required', '', QuestionDialog, {
|
const modal = Modal.createDialog(QuestionDialog, {
|
||||||
hasCancelButton: true,
|
hasCancelButton: true,
|
||||||
quitOnly: true,
|
quitOnly: true,
|
||||||
title: _t("Sign In or Create Account"),
|
title: _t("Sign In or Create Account"),
|
||||||
|
|
|
@ -61,16 +61,16 @@ export function inviteMultipleToRoom(
|
||||||
|
|
||||||
export function showStartChatInviteDialog(initialText = ""): void {
|
export function showStartChatInviteDialog(initialText = ""): void {
|
||||||
// This dialog handles the room creation internally - we don't need to worry about it.
|
// This dialog handles the room creation internally - we don't need to worry about it.
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(
|
||||||
'Start DM', '', InviteDialog, { kind: KIND_DM, initialText },
|
InviteDialog, { kind: KIND_DM, initialText },
|
||||||
/*className=*/"mx_InviteDialog_flexWrapper", /*isPriority=*/false, /*isStatic=*/true,
|
/*className=*/"mx_InviteDialog_flexWrapper", /*isPriority=*/false, /*isStatic=*/true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showRoomInviteDialog(roomId: string, initialText = ""): void {
|
export function showRoomInviteDialog(roomId: string, initialText = ""): void {
|
||||||
// This dialog handles the room creation internally - we don't need to worry about it.
|
// This dialog handles the room creation internally - we don't need to worry about it.
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(
|
||||||
"Invite Users", "", InviteDialog, {
|
InviteDialog, {
|
||||||
kind: KIND_INVITE,
|
kind: KIND_INVITE,
|
||||||
initialText,
|
initialText,
|
||||||
roomId,
|
roomId,
|
||||||
|
@ -108,7 +108,7 @@ export function inviteUsersToRoom(
|
||||||
showAnyInviteErrors(result.states, room, result.inviter);
|
showAnyInviteErrors(result.states, room, result.inviter);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
logger.error(err.stack);
|
logger.error(err.stack);
|
||||||
Modal.createTrackedDialog('Failed to invite', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Failed to invite"),
|
title: _t("Failed to invite"),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
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
|
// 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
|
// user. This usually means that no other users were attempted, making it
|
||||||
// pointless for us to list who failed exactly.
|
// 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 }),
|
title: _t("Failed to invite users to %(roomName)s", { roomName: room.name }),
|
||||||
description: inviter.getErrorText(failedUsers[0]),
|
description: inviter.getErrorText(failedUsers[0]),
|
||||||
});
|
});
|
||||||
|
@ -175,7 +175,7 @@ export function showAnyInviteErrors(
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
Modal.createTrackedDialog("Some invites could not be sent", "", ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Some invites couldn't be sent"),
|
title: _t("Some invites couldn't be sent"),
|
||||||
description,
|
description,
|
||||||
});
|
});
|
||||||
|
|
|
@ -150,7 +150,7 @@ async function getSecretStorageKey(
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputToKey = makeInputToKey(keyInfo);
|
const inputToKey = makeInputToKey(keyInfo);
|
||||||
const { finished } = Modal.createTrackedDialog("Access Secret Storage dialog", "",
|
const { finished } = Modal.createDialog(
|
||||||
AccessSecretStorageDialog,
|
AccessSecretStorageDialog,
|
||||||
/* props= */
|
/* props= */
|
||||||
{
|
{
|
||||||
|
@ -195,7 +195,7 @@ export async function getDehydrationKey(
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputToKey = makeInputToKey(keyInfo);
|
const inputToKey = makeInputToKey(keyInfo);
|
||||||
const { finished } = Modal.createTrackedDialog("Access Secret Storage dialog", "",
|
const { finished } = Modal.createDialog(
|
||||||
AccessSecretStorageDialog,
|
AccessSecretStorageDialog,
|
||||||
/* props= */
|
/* props= */
|
||||||
{
|
{
|
||||||
|
@ -298,7 +298,7 @@ export const crossSigningCallbacks: ICryptoCallbacks = {
|
||||||
export async function promptForBackupPassphrase(): Promise<Uint8Array> {
|
export async function promptForBackupPassphrase(): Promise<Uint8Array> {
|
||||||
let key: Uint8Array;
|
let key: Uint8Array;
|
||||||
|
|
||||||
const { finished } = Modal.createTrackedDialog('Restore Backup', '', RestoreKeyBackupDialog, {
|
const { finished } = Modal.createDialog(RestoreKeyBackupDialog, {
|
||||||
showSummary: false, keyCallback: k => key = k,
|
showSummary: false, keyCallback: k => key = k,
|
||||||
}, null, /* priority = */ false, /* static = */ true);
|
}, null, /* priority = */ false, /* static = */ true);
|
||||||
|
|
||||||
|
@ -336,7 +336,7 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f
|
||||||
if (!(await cli.hasSecretStorageKey()) || forceReset) {
|
if (!(await cli.hasSecretStorageKey()) || forceReset) {
|
||||||
// This dialog calls bootstrap itself after guiding the user through
|
// This dialog calls bootstrap itself after guiding the user through
|
||||||
// passphrase creation.
|
// passphrase creation.
|
||||||
const { finished } = Modal.createTrackedDialogAsync('Create Secret Storage dialog', '',
|
const { finished } = Modal.createDialogAsync(
|
||||||
import(
|
import(
|
||||||
"./async-components/views/dialogs/security/CreateSecretStorageDialog"
|
"./async-components/views/dialogs/security/CreateSecretStorageDialog"
|
||||||
) as unknown as Promise<ComponentType<{}>>,
|
) as unknown as Promise<ComponentType<{}>>,
|
||||||
|
@ -363,14 +363,11 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f
|
||||||
} else {
|
} else {
|
||||||
await cli.bootstrapCrossSigning({
|
await cli.bootstrapCrossSigning({
|
||||||
authUploadDeviceSigningKeys: async (makeRequest) => {
|
authUploadDeviceSigningKeys: async (makeRequest) => {
|
||||||
const { finished } = Modal.createTrackedDialog(
|
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||||
'Cross-signing keys dialog', '', InteractiveAuthDialog,
|
|
||||||
{
|
|
||||||
title: _t("Setting up keys"),
|
title: _t("Setting up keys"),
|
||||||
matrixClient: cli,
|
matrixClient: cli,
|
||||||
makeRequest,
|
makeRequest,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
const [confirmed] = await finished;
|
const [confirmed] = await finished;
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
throw new Error("Cross-signing key upload auth canceled");
|
throw new Error("Cross-signing key upload auth canceled");
|
||||||
|
|
|
@ -82,7 +82,7 @@ const singleMxcUpload = async (): Promise<any> => {
|
||||||
fileSelector.onchange = (ev: HTMLInputEvent) => {
|
fileSelector.onchange = (ev: HTMLInputEvent) => {
|
||||||
const file = ev.target.files[0];
|
const file = ev.target.files[0];
|
||||||
|
|
||||||
Modal.createTrackedDialog('Upload Files confirmation', '', UploadConfirmDialog, {
|
Modal.createDialog(UploadConfirmDialog, {
|
||||||
file,
|
file,
|
||||||
onFinished: (shouldContinue) => {
|
onFinished: (shouldContinue) => {
|
||||||
resolve(shouldContinue ? MatrixClientPeg.get().uploadContent(file) : null);
|
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,
|
RoomUpgradeWarningDialog, { roomId: roomId, targetVersion: args }, /*className=*/null,
|
||||||
/*isPriority=*/false, /*isStatic=*/true);
|
/*isPriority=*/false, /*isStatic=*/true);
|
||||||
|
|
||||||
|
@ -483,7 +483,7 @@ export const Commands = [
|
||||||
const ref = e => e && linkifyElement(e);
|
const ref = e => e && linkifyElement(e);
|
||||||
const body = topicToHtml(topic.text, topic.html, ref, true);
|
const body = topicToHtml(topic.text, topic.html, ref, true);
|
||||||
|
|
||||||
Modal.createTrackedDialog('Slash Commands', 'Topic', InfoDialog, {
|
Modal.createDialog(InfoDialog, {
|
||||||
title: room.name,
|
title: room.name,
|
||||||
description: <div ref={ref}>{ body }</div>,
|
description: <div ref={ref}>{ body }</div>,
|
||||||
hasCloseButton: true,
|
hasCloseButton: true,
|
||||||
|
@ -529,10 +529,7 @@ export const Commands = [
|
||||||
) {
|
) {
|
||||||
const defaultIdentityServerUrl = getDefaultIdentityServerUrl();
|
const defaultIdentityServerUrl = getDefaultIdentityServerUrl();
|
||||||
if (defaultIdentityServerUrl) {
|
if (defaultIdentityServerUrl) {
|
||||||
const { finished } = Modal.createTrackedDialog<[boolean]>(
|
const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, {
|
||||||
'Slash Commands',
|
|
||||||
'Identity server',
|
|
||||||
QuestionDialog, {
|
|
||||||
title: _t("Use an identity server"),
|
title: _t("Use an identity server"),
|
||||||
description: <p>{ _t(
|
description: <p>{ _t(
|
||||||
"Use an identity server to invite by email. " +
|
"Use an identity server to invite by email. " +
|
||||||
|
@ -543,8 +540,7 @@ export const Commands = [
|
||||||
},
|
},
|
||||||
) }</p>,
|
) }</p>,
|
||||||
button: _t("Continue"),
|
button: _t("Continue"),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
prom = finished.then(([useDefault]) => {
|
prom = finished.then(([useDefault]) => {
|
||||||
if (useDefault) {
|
if (useDefault) {
|
||||||
|
@ -810,7 +806,7 @@ export const Commands = [
|
||||||
ignoredUsers.push(userId); // de-duped internally in the js-sdk
|
ignoredUsers.push(userId); // de-duped internally in the js-sdk
|
||||||
return success(
|
return success(
|
||||||
cli.setIgnoredUsers(ignoredUsers).then(() => {
|
cli.setIgnoredUsers(ignoredUsers).then(() => {
|
||||||
Modal.createTrackedDialog('Slash Commands', 'User ignored', InfoDialog, {
|
Modal.createDialog(InfoDialog, {
|
||||||
title: _t('Ignored user'),
|
title: _t('Ignored user'),
|
||||||
description: <div>
|
description: <div>
|
||||||
<p>{ _t('You are now ignoring %(userId)s', { userId }) }</p>
|
<p>{ _t('You are now ignoring %(userId)s', { userId }) }</p>
|
||||||
|
@ -840,7 +836,7 @@ export const Commands = [
|
||||||
if (index !== -1) ignoredUsers.splice(index, 1);
|
if (index !== -1) ignoredUsers.splice(index, 1);
|
||||||
return success(
|
return success(
|
||||||
cli.setIgnoredUsers(ignoredUsers).then(() => {
|
cli.setIgnoredUsers(ignoredUsers).then(() => {
|
||||||
Modal.createTrackedDialog('Slash Commands', 'User unignored', InfoDialog, {
|
Modal.createDialog(InfoDialog, {
|
||||||
title: _t('Unignored user'),
|
title: _t('Unignored user'),
|
||||||
description: <div>
|
description: <div>
|
||||||
<p>{ _t('You are no longer ignoring %(userId)s', { userId }) }</p>
|
<p>{ _t('You are no longer ignoring %(userId)s', { userId }) }</p>
|
||||||
|
@ -1040,7 +1036,7 @@ export const Commands = [
|
||||||
await cli.setDeviceVerified(userId, deviceId, true);
|
await cli.setDeviceVerified(userId, deviceId, true);
|
||||||
|
|
||||||
// Tell the user we verified everything
|
// Tell the user we verified everything
|
||||||
Modal.createTrackedDialog('Slash Commands', 'Verified key', InfoDialog, {
|
Modal.createDialog(InfoDialog, {
|
||||||
title: _t('Verified key'),
|
title: _t('Verified key'),
|
||||||
description: <div>
|
description: <div>
|
||||||
<p>
|
<p>
|
||||||
|
@ -1098,7 +1094,7 @@ export const Commands = [
|
||||||
command: "help",
|
command: "help",
|
||||||
description: _td("Displays list of commands with usages and descriptions"),
|
description: _td("Displays list of commands with usages and descriptions"),
|
||||||
runFn: function() {
|
runFn: function() {
|
||||||
Modal.createTrackedDialog('Slash Commands', 'Help', SlashCommandHelpDialog);
|
Modal.createDialog(SlashCommandHelpDialog);
|
||||||
return success();
|
return success();
|
||||||
},
|
},
|
||||||
category: CommandCategories.advanced,
|
category: CommandCategories.advanced,
|
||||||
|
@ -1130,7 +1126,7 @@ export const Commands = [
|
||||||
args: "<description>",
|
args: "<description>",
|
||||||
runFn: function(roomId, args) {
|
runFn: function(roomId, args) {
|
||||||
return success(
|
return success(
|
||||||
Modal.createTrackedDialog('Slash Commands', 'Bug Report Dialog', BugReportDialog, {
|
Modal.createDialog(BugReportDialog, {
|
||||||
initialText: args,
|
initialText: args,
|
||||||
}).finished,
|
}).finished,
|
||||||
);
|
);
|
||||||
|
|
|
@ -190,7 +190,7 @@ export async function dialogTermsInteractionCallback(
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
logger.log("Terms that need agreement", policiesAndServicePairs);
|
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,
|
policiesAndServicePairs,
|
||||||
agreedUrls,
|
agreedUrls,
|
||||||
}, classNames("mx_TermsDialog", extraClassNames));
|
}, classNames("mx_TermsDialog", extraClassNames));
|
||||||
|
|
|
@ -91,7 +91,7 @@ export default class RoomListActions {
|
||||||
room, newTag === DefaultTagID.DM,
|
room, newTag === DefaultTagID.DM,
|
||||||
).catch((err) => {
|
).catch((err) => {
|
||||||
logger.error("Failed to set DM tag " + 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'),
|
title: _t('Failed to set direct message tag'),
|
||||||
description: ((err && err.message) ? err.message : _t('Operation failed')),
|
description: ((err && err.message) ? err.message : _t('Operation failed')),
|
||||||
});
|
});
|
||||||
|
@ -111,7 +111,7 @@ export default class RoomListActions {
|
||||||
roomId, oldTag,
|
roomId, oldTag,
|
||||||
).catch(function(err) {
|
).catch(function(err) {
|
||||||
logger.error("Failed to remove tag " + oldTag + " from room: " + 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 }),
|
title: _t('Failed to remove tag %(tagName)s from room', { tagName: oldTag }),
|
||||||
description: ((err && err.message) ? err.message : _t('Operation failed')),
|
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) {
|
const promiseToAdd = matrixClient.setRoomTag(roomId, newTag, metaData).catch(function(err) {
|
||||||
logger.error("Failed to add tag " + newTag + " to room: " + 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 }),
|
title: _t('Failed to add tag %(tagName)s to room', { tagName: newTag }),
|
||||||
description: ((err && err.message) ? err.message : _t('Operation failed')),
|
description: ((err && err.message) ? err.message : _t('Operation failed')),
|
||||||
});
|
});
|
||||||
|
|
|
@ -134,10 +134,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||||
|
|
||||||
private onDisable = async () => {
|
private onDisable = async () => {
|
||||||
const DisableEventIndexDialog = (await import("./DisableEventIndexDialog")).default;
|
const DisableEventIndexDialog = (await import("./DisableEventIndexDialog")).default;
|
||||||
Modal.createTrackedDialog("Disable message search", "Disable message search",
|
Modal.createDialog(DisableEventIndexDialog, null, null, /* priority = */ false, /* static = */ true);
|
||||||
DisableEventIndexDialog,
|
|
||||||
null, null, /* priority = */ false, /* static = */ true,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private onCrawlerSleepTimeChange = (e) => {
|
private onCrawlerSleepTimeChange = (e) => {
|
||||||
|
|
|
@ -303,9 +303,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const { finished } = Modal.createTrackedDialog(
|
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||||
'Cross-signing keys dialog', '', InteractiveAuthDialog,
|
|
||||||
{
|
|
||||||
title: _t("Setting up keys"),
|
title: _t("Setting up keys"),
|
||||||
matrixClient: MatrixClientPeg.get(),
|
matrixClient: MatrixClientPeg.get(),
|
||||||
makeRequest,
|
makeRequest,
|
||||||
|
@ -313,8 +311,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
|
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
|
||||||
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
|
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
);
|
|
||||||
const [confirmed] = await finished;
|
const [confirmed] = await finished;
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
throw new Error("Cross-signing key upload auth canceled");
|
throw new Error("Cross-signing key upload auth canceled");
|
||||||
|
@ -390,14 +387,10 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
// so let's stash it here, rather than prompting for it twice.
|
// so let's stash it here, rather than prompting for it twice.
|
||||||
const keyCallback = k => this.backupKey = k;
|
const keyCallback = k => this.backupKey = k;
|
||||||
|
|
||||||
const { finished } = Modal.createTrackedDialog(
|
const { finished } = Modal.createDialog(RestoreKeyBackupDialog, {
|
||||||
'Restore Backup', '', RestoreKeyBackupDialog,
|
|
||||||
{
|
|
||||||
showSummary: false,
|
showSummary: false,
|
||||||
keyCallback,
|
keyCallback,
|
||||||
},
|
}, null, /* priority = */ false, /* static = */ false);
|
||||||
null, /* priority = */ false, /* static = */ false,
|
|
||||||
);
|
|
||||||
|
|
||||||
await finished;
|
await finished;
|
||||||
const { backupSigStatus } = await this.fetchBackupInfo();
|
const { backupSigStatus } = await this.fetchBackupInfo();
|
||||||
|
|
|
@ -43,11 +43,9 @@ export default class NewRecoveryMethodDialog extends React.PureComponent<IProps>
|
||||||
};
|
};
|
||||||
|
|
||||||
private onSetupClick = async (): Promise<void> => {
|
private onSetupClick = async (): Promise<void> => {
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(RestoreKeyBackupDialog, {
|
||||||
'Restore Backup', '', RestoreKeyBackupDialog, {
|
|
||||||
onFinished: this.props.onFinished,
|
onFinished: this.props.onFinished,
|
||||||
}, null, /* priority = */ false, /* static = */ true,
|
}, null, /* priority = */ false, /* static = */ true);
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent<IPr
|
||||||
|
|
||||||
private onSetupClick = (): void => {
|
private onSetupClick = (): void => {
|
||||||
this.props.onFinished();
|
this.props.onFinished();
|
||||||
Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
|
Modal.createDialogAsync(
|
||||||
import("./CreateKeyBackupDialog") as unknown as Promise<ComponentType<{}>>,
|
import("./CreateKeyBackupDialog") as unknown as Promise<ComponentType<{}>>,
|
||||||
null, null, /* priority = */ false, /* static = */ true,
|
null, null, /* priority = */ false, /* static = */ true,
|
||||||
);
|
);
|
||||||
|
|
|
@ -30,24 +30,20 @@ import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
||||||
import { useEventEmitter } from "../../hooks/useEventEmitter";
|
import { useEventEmitter } from "../../hooks/useEventEmitter";
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
import MiniAvatarUploader, { AVATAR_SIZE } from "../views/elements/MiniAvatarUploader";
|
import MiniAvatarUploader, { AVATAR_SIZE } from "../views/elements/MiniAvatarUploader";
|
||||||
import Analytics from "../../Analytics";
|
|
||||||
import PosthogTrackers from "../../PosthogTrackers";
|
import PosthogTrackers from "../../PosthogTrackers";
|
||||||
import EmbeddedPage from "./EmbeddedPage";
|
import EmbeddedPage from "./EmbeddedPage";
|
||||||
|
|
||||||
const onClickSendDm = (ev: ButtonEvent) => {
|
const onClickSendDm = (ev: ButtonEvent) => {
|
||||||
Analytics.trackEvent('home_page', 'button', 'dm');
|
|
||||||
PosthogTrackers.trackInteraction("WebHomeCreateChatButton", ev);
|
PosthogTrackers.trackInteraction("WebHomeCreateChatButton", ev);
|
||||||
dis.dispatch({ action: 'view_create_chat' });
|
dis.dispatch({ action: 'view_create_chat' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClickExplore = (ev: ButtonEvent) => {
|
const onClickExplore = (ev: ButtonEvent) => {
|
||||||
Analytics.trackEvent('home_page', 'button', 'room_directory');
|
|
||||||
PosthogTrackers.trackInteraction("WebHomeExploreRoomsButton", ev);
|
PosthogTrackers.trackInteraction("WebHomeExploreRoomsButton", ev);
|
||||||
dis.fire(Action.ViewRoomDirectory);
|
dis.fire(Action.ViewRoomDirectory);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClickNewRoom = (ev: ButtonEvent) => {
|
const onClickNewRoom = (ev: ButtonEvent) => {
|
||||||
Analytics.trackEvent('home_page', 'button', 'create_room');
|
|
||||||
PosthogTrackers.trackInteraction("WebHomeCreateRoomButton", ev);
|
PosthogTrackers.trackInteraction("WebHomeCreateRoomButton", ev);
|
||||||
dis.dispatch({ action: 'view_create_room' });
|
dis.dispatch({ action: 'view_create_room' });
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,7 +39,6 @@ import 'focus-visible';
|
||||||
import 'what-input';
|
import 'what-input';
|
||||||
|
|
||||||
import PosthogTrackers from '../../PosthogTrackers';
|
import PosthogTrackers from '../../PosthogTrackers';
|
||||||
import Analytics from "../../Analytics";
|
|
||||||
import { DecryptionFailureTracker } from "../../DecryptionFailureTracker";
|
import { DecryptionFailureTracker } from "../../DecryptionFailureTracker";
|
||||||
import { IMatrixClientCreds, MatrixClientPeg } from "../../MatrixClientPeg";
|
import { IMatrixClientCreds, MatrixClientPeg } from "../../MatrixClientPeg";
|
||||||
import PlatformPeg from "../../PlatformPeg";
|
import PlatformPeg from "../../PlatformPeg";
|
||||||
|
@ -73,8 +72,7 @@ import LoggedInView from './LoggedInView';
|
||||||
import { Action } from "../../dispatcher/actions";
|
import { Action } from "../../dispatcher/actions";
|
||||||
import {
|
import {
|
||||||
hideToast as hideAnalyticsToast,
|
hideToast as hideAnalyticsToast,
|
||||||
showAnonymousAnalyticsOptInToast,
|
showToast as showAnalyticsToast,
|
||||||
showPseudonymousAnalyticsOptInToast,
|
|
||||||
} from "../../toasts/AnalyticsToast";
|
} from "../../toasts/AnalyticsToast";
|
||||||
import { showToast as showNotificationsToast } from "../../toasts/DesktopNotificationsToast";
|
import { showToast as showNotificationsToast } from "../../toasts/DesktopNotificationsToast";
|
||||||
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
|
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
|
||||||
|
@ -344,10 +342,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SettingsStore.getValue("pseudonymousAnalyticsOptIn")) {
|
|
||||||
Analytics.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
initSentry(SdkConfig.get("sentry"));
|
initSentry(SdkConfig.get("sentry"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +400,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
if (this.shouldTrackPageChange(prevState, this.state)) {
|
if (this.shouldTrackPageChange(prevState, this.state)) {
|
||||||
const durationMs = this.stopPageChangeTimer();
|
const durationMs = this.stopPageChangeTimer();
|
||||||
Analytics.trackPageChange(durationMs);
|
|
||||||
PosthogTrackers.instance.trackPageChange(this.state.view, this.state.page_type, durationMs);
|
PosthogTrackers.instance.trackPageChange(this.state.view, this.state.page_type, durationMs);
|
||||||
}
|
}
|
||||||
if (this.focusComposer) {
|
if (this.focusComposer) {
|
||||||
|
@ -625,7 +618,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
this.copyRoom(payload.room_id);
|
this.copyRoom(payload.room_id);
|
||||||
break;
|
break;
|
||||||
case 'reject_invite':
|
case 'reject_invite':
|
||||||
Modal.createTrackedDialog('Reject invitation', '', QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t('Reject invitation'),
|
title: _t('Reject invitation'),
|
||||||
description: _t('Are you sure you want to reject the invitation?'),
|
description: _t('Are you sure you want to reject the invitation?'),
|
||||||
onFinished: (confirm) => {
|
onFinished: (confirm) => {
|
||||||
|
@ -640,7 +633,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
modal.close();
|
modal.close();
|
||||||
Modal.createTrackedDialog('Failed to reject invitation', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Failed to reject invitation'),
|
title: _t('Failed to reject invitation'),
|
||||||
description: err.toString(),
|
description: err.toString(),
|
||||||
});
|
});
|
||||||
|
@ -684,7 +677,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
break;
|
break;
|
||||||
case Action.ViewUserSettings: {
|
case Action.ViewUserSettings: {
|
||||||
const tabPayload = payload as OpenToTabPayload;
|
const tabPayload = payload as OpenToTabPayload;
|
||||||
Modal.createTrackedDialog('User settings', '', UserSettingsDialog,
|
Modal.createDialog(UserSettingsDialog,
|
||||||
{ initialTabId: tabPayload.initialTabId },
|
{ initialTabId: tabPayload.initialTabId },
|
||||||
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
|
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
|
||||||
|
|
||||||
|
@ -699,7 +692,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
this.viewSomethingBehindModal();
|
this.viewSomethingBehindModal();
|
||||||
break;
|
break;
|
||||||
case Action.ViewRoomDirectory: {
|
case Action.ViewRoomDirectory: {
|
||||||
Modal.createTrackedDialog('Room directory', '', RoomDirectory, {
|
Modal.createDialog(RoomDirectory, {
|
||||||
initialText: payload.initialText,
|
initialText: payload.initialText,
|
||||||
}, 'mx_RoomDirectory_dialogWrapper', false, true);
|
}, 'mx_RoomDirectory_dialogWrapper', false, true);
|
||||||
|
|
||||||
|
@ -756,7 +749,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case Action.OpenDialPad:
|
case Action.OpenDialPad:
|
||||||
Modal.createTrackedDialog('Dial pad', '', DialPadModal, {}, "mx_Dialog_dialPadWrapper");
|
Modal.createDialog(DialPadModal, {}, "mx_Dialog_dialPadWrapper");
|
||||||
break;
|
break;
|
||||||
case Action.OnLoggedIn:
|
case Action.OnLoggedIn:
|
||||||
if (
|
if (
|
||||||
|
@ -801,19 +794,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
hideToSRUsers: false,
|
hideToSRUsers: false,
|
||||||
});
|
});
|
||||||
break;
|
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:
|
case Action.PseudonymousAnalyticsAccept:
|
||||||
hideAnalyticsToast();
|
hideAnalyticsToast();
|
||||||
SettingsStore.setValue("pseudonymousAnalyticsOptIn", null, SettingLevel.ACCOUNT, true);
|
SettingsStore.setValue("pseudonymousAnalyticsOptIn", null, SettingLevel.ACCOUNT, true);
|
||||||
|
@ -1009,7 +989,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createRoom(defaultPublic = false, defaultName?: string, type?: RoomType) {
|
private async createRoom(defaultPublic = false, defaultName?: string, type?: RoomType) {
|
||||||
const modal = Modal.createTrackedDialog('Create Room', '', CreateRoomDialog, {
|
const modal = Modal.createDialog(CreateRoomDialog, {
|
||||||
type,
|
type,
|
||||||
defaultPublic,
|
defaultPublic,
|
||||||
defaultName,
|
defaultName,
|
||||||
|
@ -1112,7 +1092,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
const warnings = this.leaveRoomWarnings(roomId);
|
const warnings = this.leaveRoomWarnings(roomId);
|
||||||
|
|
||||||
const isSpace = roomToLeave?.isSpaceRoom();
|
const isSpace = roomToLeave?.isSpaceRoom();
|
||||||
Modal.createTrackedDialog(isSpace ? "Leave space" : "Leave room", '', QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: isSpace ? _t("Leave space") : _t("Leave room"),
|
title: isSpace ? _t("Leave space") : _t("Leave room"),
|
||||||
description: (
|
description: (
|
||||||
<span>
|
<span>
|
||||||
|
@ -1156,7 +1136,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
RoomListStore.instance.manualRoomUpdate(room, RoomUpdateCause.RoomRemoved);
|
RoomListStore.instance.manualRoomUpdate(room, RoomUpdateCause.RoomRemoved);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
const errCode = err.errcode || _td("unknown error code");
|
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 }),
|
title: _t("Failed to forget room %(errCode)s", { errCode }),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
|
@ -1167,7 +1147,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
const roomLink = makeRoomPermalink(roomId);
|
const roomLink = makeRoomPermalink(roomId);
|
||||||
const success = await copyPlaintext(roomLink);
|
const success = await copyPlaintext(roomLink);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
Modal.createTrackedDialog("Unable to copy room link", "", ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Unable to copy room link"),
|
title: _t("Unable to copy room link"),
|
||||||
description: _t("Unable to copy a link to the room to the clipboard."),
|
description: _t("Unable to copy a link to the room to the clipboard."),
|
||||||
});
|
});
|
||||||
|
@ -1271,8 +1251,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
if (PosthogAnalytics.instance.isEnabled() && SettingsStore.isLevelSupported(SettingLevel.ACCOUNT)) {
|
if (PosthogAnalytics.instance.isEnabled() && SettingsStore.isLevelSupported(SettingLevel.ACCOUNT)) {
|
||||||
this.initPosthogAnalyticsToast();
|
this.initPosthogAnalyticsToast();
|
||||||
} else if (Analytics.canEnable() && SettingsStore.getValue("showCookieBar")) {
|
|
||||||
showAnonymousAnalyticsOptInToast();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SdkConfig.get("mobile_guide_toast")) {
|
if (SdkConfig.get("mobile_guide_toast")) {
|
||||||
|
@ -1282,14 +1260,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private showPosthogToast(analyticsOptIn: boolean) {
|
|
||||||
showPseudonymousAnalyticsOptInToast(analyticsOptIn);
|
|
||||||
}
|
|
||||||
|
|
||||||
private initPosthogAnalyticsToast() {
|
private initPosthogAnalyticsToast() {
|
||||||
// Show the analytics toast if necessary
|
// Show the analytics toast if necessary
|
||||||
if (SettingsStore.getValue("pseudonymousAnalyticsOptIn") === null) {
|
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
|
// Listen to changes in settings and show the toast if appropriate - this is necessary because account
|
||||||
|
@ -1298,7 +1272,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
SettingsStore.watchSetting("pseudonymousAnalyticsOptIn", null,
|
SettingsStore.watchSetting("pseudonymousAnalyticsOptIn", null,
|
||||||
(originalSettingName, changedInRoomId, atLevel, newValueAtLevel, newValue) => {
|
(originalSettingName, changedInRoomId, atLevel, newValueAtLevel, newValue) => {
|
||||||
if (newValue === null) {
|
if (newValue === null) {
|
||||||
this.showPosthogToast(SettingsStore.getValue("analyticsOptIn", null, true));
|
showAnalyticsToast();
|
||||||
} else {
|
} else {
|
||||||
// It's possible for the value to change if a cached sync loads at page load, but then network
|
// 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
|
// sync contains a new value of the flag with it set to false (e.g. another device set it since last
|
||||||
|
@ -1478,7 +1452,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Modal.createTrackedDialog('Signed out', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Signed Out'),
|
title: _t('Signed Out'),
|
||||||
description: _t('For security, this session has been signed out. Please sign in again.'),
|
description: _t('For security, this session has been signed out. Please sign in again.'),
|
||||||
});
|
});
|
||||||
|
@ -1488,7 +1462,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
cli.on(HttpApiEvent.NoConsent, function(message, consentUri) {
|
cli.on(HttpApiEvent.NoConsent, function(message, consentUri) {
|
||||||
Modal.createTrackedDialog('No Consent Dialog', '', QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t('Terms and Conditions'),
|
title: _t('Terms and Conditions'),
|
||||||
description: <div>
|
description: <div>
|
||||||
<p> { _t(
|
<p> { _t(
|
||||||
|
@ -1535,7 +1509,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
cli.on(CryptoEvent.Warning, (type) => {
|
cli.on(CryptoEvent.Warning, (type) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'CRYPTO_WARNING_OLD_VERSION_DETECTED':
|
case 'CRYPTO_WARNING_OLD_VERSION_DETECTED':
|
||||||
Modal.createTrackedDialog('Crypto migrated', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Old cryptography data detected'),
|
title: _t('Old cryptography data detected'),
|
||||||
description: _t(
|
description: _t(
|
||||||
"Data from an older version of %(brand)s has been detected. " +
|
"Data from an older version of %(brand)s has been detected. " +
|
||||||
|
@ -1569,14 +1543,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (haveNewVersion) {
|
if (haveNewVersion) {
|
||||||
Modal.createTrackedDialogAsync('New Recovery Method', 'New Recovery Method',
|
Modal.createDialogAsync(
|
||||||
import(
|
import(
|
||||||
'../../async-components/views/dialogs/security/NewRecoveryMethodDialog'
|
'../../async-components/views/dialogs/security/NewRecoveryMethodDialog'
|
||||||
) as unknown as Promise<ComponentType<{}>>,
|
) as unknown as Promise<ComponentType<{}>>,
|
||||||
{ newVersionInfo },
|
{ newVersionInfo },
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
Modal.createTrackedDialogAsync('Recovery Method Removed', 'Recovery Method Removed',
|
Modal.createDialogAsync(
|
||||||
import(
|
import(
|
||||||
'../../async-components/views/dialogs/security/RecoveryMethodRemovedDialog'
|
'../../async-components/views/dialogs/security/RecoveryMethodRemovedDialog'
|
||||||
) as unknown as Promise<ComponentType<{}>>,
|
) as unknown as Promise<ComponentType<{}>>,
|
||||||
|
@ -1585,16 +1559,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
});
|
});
|
||||||
|
|
||||||
cli.on(CryptoEvent.KeySignatureUploadFailure, (failures, source, continuation) => {
|
cli.on(CryptoEvent.KeySignatureUploadFailure, (failures, source, continuation) => {
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(
|
||||||
'Failed to upload key signatures',
|
|
||||||
'Failed to upload key signatures',
|
|
||||||
KeySignatureUploadFailedDialog,
|
KeySignatureUploadFailedDialog,
|
||||||
{ failures, source, continuation });
|
{ failures, source, continuation });
|
||||||
});
|
});
|
||||||
|
|
||||||
cli.on(CryptoEvent.VerificationRequest, request => {
|
cli.on(CryptoEvent.VerificationRequest, request => {
|
||||||
if (request.verifier) {
|
if (request.verifier) {
|
||||||
Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, {
|
Modal.createDialog(IncomingSasDialog, {
|
||||||
verifier: request.verifier,
|
verifier: request.verifier,
|
||||||
}, null, /* priority = */ false, /* static = */ true);
|
}, null, /* priority = */ false, /* static = */ true);
|
||||||
} else if (request.pending) {
|
} else if (request.pending) {
|
||||||
|
|
|
@ -27,7 +27,6 @@ import Modal from "../../Modal";
|
||||||
import { _t } from '../../languageHandler';
|
import { _t } from '../../languageHandler';
|
||||||
import SdkConfig from '../../SdkConfig';
|
import SdkConfig from '../../SdkConfig';
|
||||||
import { instanceForInstanceId, protocolNameForInstanceId, ALL_ROOMS, Protocols } from '../../utils/DirectoryUtils';
|
import { instanceForInstanceId, protocolNameForInstanceId, ALL_ROOMS, Protocols } from '../../utils/DirectoryUtils';
|
||||||
import Analytics from '../../Analytics';
|
|
||||||
import NetworkDropdown from "../views/directory/NetworkDropdown";
|
import NetworkDropdown from "../views/directory/NetworkDropdown";
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
import { IDialogProps } from "../views/dialogs/IDialogProps";
|
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_SERVER_KEY = "mx_last_room_directory_server";
|
||||||
const LAST_INSTANCE_KEY = "mx_last_room_directory_instance";
|
const LAST_INSTANCE_KEY = "mx_last_room_directory_instance";
|
||||||
|
|
||||||
function track(action: string) {
|
|
||||||
Analytics.trackEvent('RoomDirectory', action);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IProps extends IDialogProps {
|
interface IProps extends IDialogProps {
|
||||||
initialText?: string;
|
initialText?: string;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +116,6 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
// thing you see when loading the client!
|
// thing you see when loading the client!
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
track('Failed to get protocol list from homeserver');
|
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
this.setState({
|
this.setState({
|
||||||
error: _t(
|
error: _t(
|
||||||
|
@ -225,7 +219,6 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.error("Failed to get publicRooms: %s", JSON.stringify(err));
|
logger.error("Failed to get publicRooms: %s", JSON.stringify(err));
|
||||||
track('Failed to get public room list');
|
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
|
@ -255,7 +248,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
desc = _t('Remove %(name)s from the directory?', { name: name });
|
desc = _t('Remove %(name)s from the directory?', { name: name });
|
||||||
}
|
}
|
||||||
|
|
||||||
Modal.createTrackedDialog('Remove from Directory', '', QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t('Remove from Directory'),
|
title: _t('Remove from Directory'),
|
||||||
description: desc,
|
description: desc,
|
||||||
onFinished: (shouldDelete: boolean) => {
|
onFinished: (shouldDelete: boolean) => {
|
||||||
|
@ -275,7 +268,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
modal.close();
|
modal.close();
|
||||||
this.refreshRoomList();
|
this.refreshRoomList();
|
||||||
logger.error("Failed to " + step + ": " + err);
|
logger.error("Failed to " + step + ": " + err);
|
||||||
Modal.createTrackedDialog('Remove from Directory Error', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Error'),
|
title: _t('Error'),
|
||||||
description: (err && err.message)
|
description: (err && err.message)
|
||||||
? err.message
|
? err.message
|
||||||
|
@ -360,7 +353,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof GenericError) {
|
if (e instanceof GenericError) {
|
||||||
Modal.createTrackedDialog(e.message, '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: e.message,
|
title: e.message,
|
||||||
description: e.description,
|
description: e.description,
|
||||||
});
|
});
|
||||||
|
|
|
@ -104,7 +104,7 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private openSpotlight() {
|
private openSpotlight() {
|
||||||
Modal.createTrackedDialog("Spotlight", "", SpotlightDialog, {}, "mx_SpotlightDialog_wrapper", false, true);
|
Modal.createDialog(SpotlightDialog, {}, "mx_SpotlightDialog_wrapper", false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onAction = (payload: ActionPayload) => {
|
private onAction = (payload: ActionPayload) => {
|
||||||
|
|
|
@ -1397,7 +1397,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
});
|
});
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
logger.error("Search failed", error);
|
logger.error("Search failed", error);
|
||||||
Modal.createTrackedDialog('Search failed', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Search failed"),
|
title: _t("Search failed"),
|
||||||
description: ((error && error.message) ? error.message :
|
description: ((error && error.message) ? error.message :
|
||||||
_t("Server may be unavailable, overloaded, or search timed out :(")),
|
_t("Server may be unavailable, overloaded, or search timed out :(")),
|
||||||
|
@ -1522,7 +1522,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
logger.error("Failed to reject invite: %s", error);
|
logger.error("Failed to reject invite: %s", error);
|
||||||
|
|
||||||
const msg = error.message ? error.message : JSON.stringify(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"),
|
title: _t("Failed to reject invite"),
|
||||||
description: msg,
|
description: msg,
|
||||||
});
|
});
|
||||||
|
@ -1555,7 +1555,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
logger.error("Failed to reject invite: %s", error);
|
logger.error("Failed to reject invite: %s", error);
|
||||||
|
|
||||||
const msg = error.message ? error.message : JSON.stringify(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"),
|
title: _t("Failed to reject invite"),
|
||||||
description: msg,
|
description: msg,
|
||||||
});
|
});
|
||||||
|
|
|
@ -234,7 +234,7 @@ const ThreadPanel: React.FC<IProps> = ({
|
||||||
}, [timelineSet, timelinePanel]);
|
}, [timelineSet, timelinePanel]);
|
||||||
|
|
||||||
const openFeedback = SdkConfig.get().bug_report_endpoint_url ? () => {
|
const openFeedback = SdkConfig.get().bug_report_endpoint_url ? () => {
|
||||||
Modal.createTrackedDialog("Threads Feedback", "feature_thread", BetaFeedbackDialog, {
|
Modal.createDialog(BetaFeedbackDialog, {
|
||||||
featureId: "feature_thread",
|
featureId: "feature_thread",
|
||||||
});
|
});
|
||||||
} : null;
|
} : null;
|
||||||
|
|
|
@ -1353,7 +1353,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Modal.createTrackedDialog('Failed to load timeline position', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Failed to load timeline position"),
|
title: _t("Failed to load timeline position"),
|
||||||
description,
|
description,
|
||||||
onFinished,
|
onFinished,
|
||||||
|
|
|
@ -229,7 +229,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
Modal.createTrackedDialog('Feedback Dialog', '', FeedbackDialog);
|
Modal.createDialog(FeedbackDialog);
|
||||||
this.setState({ contextMenuPosition: null }); // also close the menu
|
this.setState({ contextMenuPosition: null }); // also close the menu
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
// log out without user prompt if they have no local megolm sessions
|
// log out without user prompt if they have no local megolm sessions
|
||||||
defaultDispatcher.dispatch({ action: 'logout' });
|
defaultDispatcher.dispatch({ action: 'logout' });
|
||||||
} else {
|
} else {
|
||||||
Modal.createTrackedDialog('Logout from LeftPanel', '', LogoutDialog);
|
Modal.createDialog(LogoutDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ contextMenuPosition: null }); // also close the menu
|
this.setState({ contextMenuPosition: null }); // also close the menu
|
||||||
|
|
|
@ -70,7 +70,7 @@ export default class UserView extends React.Component<IProps, IState> {
|
||||||
try {
|
try {
|
||||||
profileInfo = await cli.getProfileInfo(this.props.userId);
|
profileInfo = await cli.getProfileInfo(this.props.userId);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Modal.createTrackedDialog(_t('Could not load user profile'), '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Could not load user profile'),
|
title: _t('Could not load user profile'),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
|
|
|
@ -199,7 +199,7 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.logoutDevices) {
|
if (this.state.logoutDevices) {
|
||||||
const { finished } = Modal.createTrackedDialog<[boolean]>('Forgot Password Warning', '', QuestionDialog, {
|
const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, {
|
||||||
title: _t('Warning!'),
|
title: _t('Warning!'),
|
||||||
description:
|
description:
|
||||||
<div>
|
<div>
|
||||||
|
@ -271,7 +271,7 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public showErrorDialog(description: string, title?: string) {
|
public showErrorDialog(description: string, title?: string) {
|
||||||
Modal.createTrackedDialog('Forgot Password Error', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
});
|
});
|
||||||
|
|
|
@ -98,7 +98,7 @@ export default class SetupEncryptionBody extends React.Component<IProps, IState>
|
||||||
// We need to call onFinished now to close this dialog, and
|
// We need to call onFinished now to close this dialog, and
|
||||||
// again later to signal that the verification is complete.
|
// again later to signal that the verification is complete.
|
||||||
this.props.onFinished();
|
this.props.onFinished();
|
||||||
Modal.createTrackedDialog('New Session Verification', 'Starting dialog', VerificationRequestDialog, {
|
Modal.createDialog(VerificationRequestDialog, {
|
||||||
verificationRequestPromise: requestPromise,
|
verificationRequestPromise: requestPromise,
|
||||||
member: cli.getUser(userId),
|
member: cli.getUser(userId),
|
||||||
onFinished: async () => {
|
onFinished: async () => {
|
||||||
|
|
|
@ -101,7 +101,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private onClearAll = () => {
|
private onClearAll = () => {
|
||||||
Modal.createTrackedDialog('Clear Data', 'Soft Logout', ConfirmWipeDeviceDialog, {
|
Modal.createDialog(ConfirmWipeDeviceDialog, {
|
||||||
onFinished: (wipeData) => {
|
onFinished: (wipeData) => {
|
||||||
if (!wipeData) return;
|
if (!wipeData) return;
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||||
|
|
||||||
if (this.state.email === '') {
|
if (this.state.email === '') {
|
||||||
if (this.showEmail()) {
|
if (this.showEmail()) {
|
||||||
Modal.createTrackedDialog("Email prompt dialog", '', RegistrationEmailPromptDialog, {
|
Modal.createDialog(RegistrationEmailPromptDialog, {
|
||||||
onFinished: async (confirmed: boolean, email?: string) => {
|
onFinished: async (confirmed: boolean, email?: string) => {
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|
|
@ -91,7 +91,7 @@ const BetaCard = ({ title: titleOverride, featureId }: IProps) => {
|
||||||
if (value && feedbackLabel && feedbackSubheading && SdkConfig.get().bug_report_endpoint_url) {
|
if (value && feedbackLabel && feedbackSubheading && SdkConfig.get().bug_report_endpoint_url) {
|
||||||
feedbackButton = <AccessibleButton
|
feedbackButton = <AccessibleButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
Modal.createTrackedDialog("Beta Feedback", featureId, BetaFeedbackDialog, { featureId });
|
Modal.createDialog(BetaFeedbackDialog, { featureId });
|
||||||
}}
|
}}
|
||||||
kind="primary"
|
kind="primary"
|
||||||
>
|
>
|
||||||
|
|
|
@ -173,7 +173,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
||||||
};
|
};
|
||||||
|
|
||||||
private onViewSourceClick = (): void => {
|
private onViewSourceClick = (): void => {
|
||||||
Modal.createTrackedDialog('View Event Source', '', ViewSource, {
|
Modal.createDialog(ViewSource, {
|
||||||
mxEvent: this.props.mxEvent,
|
mxEvent: this.props.mxEvent,
|
||||||
}, 'mx_Dialog_viewsource');
|
}, 'mx_Dialog_viewsource');
|
||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
|
@ -238,7 +238,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
||||||
|
|
||||||
private onShareClick = (e: React.MouseEvent): void => {
|
private onShareClick = (e: React.MouseEvent): void => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
Modal.createTrackedDialog('share room message dialog', '', ShareDialog, {
|
Modal.createDialog(ShareDialog, {
|
||||||
target: this.props.mxEvent,
|
target: this.props.mxEvent,
|
||||||
permalinkCreator: this.props.permalinkCreator,
|
permalinkCreator: this.props.permalinkCreator,
|
||||||
});
|
});
|
||||||
|
@ -286,7 +286,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
||||||
|
|
||||||
private onEndPollClick = (): void => {
|
private onEndPollClick = (): void => {
|
||||||
const matrixClient = MatrixClientPeg.get();
|
const matrixClient = MatrixClientPeg.get();
|
||||||
Modal.createTrackedDialog('End Poll', '', EndPollDialog, {
|
Modal.createDialog(EndPollDialog, {
|
||||||
matrixClient,
|
matrixClient,
|
||||||
event: this.props.mxEvent,
|
event: this.props.mxEvent,
|
||||||
getRelationsForEvent: this.props.getRelationsForEvent,
|
getRelationsForEvent: this.props.getRelationsForEvent,
|
||||||
|
|
|
@ -296,7 +296,7 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
Modal.createTrackedDialog('Export room dialog', '', ExportDialog, { room });
|
Modal.createDialog(ExportDialog, { room });
|
||||||
onFinished();
|
onFinished();
|
||||||
}}
|
}}
|
||||||
label={_t("Export chat")}
|
label={_t("Export chat")}
|
||||||
|
|
|
@ -69,7 +69,7 @@ const WidgetContextMenu: React.FC<IProps> = ({
|
||||||
logger.error("Failed to start livestream", err);
|
logger.error("Failed to start livestream", err);
|
||||||
// XXX: won't i18n well, but looks like widget api only support 'message'?
|
// XXX: won't i18n well, but looks like widget api only support 'message'?
|
||||||
const message = err.message || _t("Unable to start audio streaming.");
|
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'),
|
title: _t('Failed to start livestream'),
|
||||||
description: message,
|
description: message,
|
||||||
});
|
});
|
||||||
|
@ -134,7 +134,7 @@ const WidgetContextMenu: React.FC<IProps> = ({
|
||||||
onDeleteClick();
|
onDeleteClick();
|
||||||
} else {
|
} else {
|
||||||
// Show delete confirmation dialog
|
// Show delete confirmation dialog
|
||||||
Modal.createTrackedDialog('Delete Widget', '', QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Delete Widget"),
|
title: _t("Delete Widget"),
|
||||||
description: _t(
|
description: _t(
|
||||||
"Deleting a widget removes it for all users in this room." +
|
"Deleting a widget removes it for all users in this room." +
|
||||||
|
|
|
@ -15,14 +15,13 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Optional } from "matrix-events-sdk";
|
|
||||||
|
|
||||||
import BaseDialog from "./BaseDialog";
|
import BaseDialog from "./BaseDialog";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import DialogButtons from "../elements/DialogButtons";
|
import DialogButtons from "../elements/DialogButtons";
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
import SdkConfig from "../../../SdkConfig";
|
import SdkConfig from "../../../SdkConfig";
|
||||||
import { SnakedObject } from "../../../utils/SnakedObject";
|
import { getPolicyUrl } from "../../../toasts/AnalyticsToast";
|
||||||
|
|
||||||
export enum ButtonClicked {
|
export enum ButtonClicked {
|
||||||
Primary,
|
Primary,
|
||||||
|
@ -98,19 +97,13 @@ const AnalyticsLearnMoreDialog: React.FC<IProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
export const showDialog = (props: Omit<IProps, "cookiePolicyUrl" | "analyticsOwner">): void => {
|
export const showDialog = (props: Omit<IProps, "cookiePolicyUrl" | "analyticsOwner">): void => {
|
||||||
const piwikConfig = SdkConfig.get("piwik");
|
const privacyPolicyUrl = getPolicyUrl();
|
||||||
let privacyPolicyUrl: Optional<string>;
|
|
||||||
if (piwikConfig && typeof piwikConfig === "object") {
|
|
||||||
privacyPolicyUrl = (new SnakedObject(piwikConfig)).get("policy_url");
|
|
||||||
}
|
|
||||||
const analyticsOwner = SdkConfig.get("analytics_owner") ?? SdkConfig.get("brand");
|
const analyticsOwner = SdkConfig.get("analytics_owner") ?? SdkConfig.get("brand");
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(AnalyticsLearnMoreDialog, {
|
||||||
"Analytics Learn More",
|
privacyPolicyUrl,
|
||||||
"",
|
analyticsOwner,
|
||||||
AnalyticsLearnMoreDialog,
|
...props,
|
||||||
{ privacyPolicyUrl, analyticsOwner, ...props },
|
}, "mx_AnalyticsLearnMoreDialog_wrapper");
|
||||||
"mx_AnalyticsLearnMoreDialog_wrapper",
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AnalyticsLearnMoreDialog;
|
export default AnalyticsLearnMoreDialog;
|
||||||
|
|
|
@ -110,8 +110,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (!this.unmounted) {
|
if (!this.unmounted) {
|
||||||
this.props.onFinished(false);
|
this.props.onFinished(false);
|
||||||
// N.B. first param is passed to piwik and so doesn't want i18n
|
Modal.createDialog(QuestionDialog, {
|
||||||
Modal.createTrackedDialog('Bug report sent', '', QuestionDialog, {
|
|
||||||
title: _t('Logs sent'),
|
title: _t('Logs sent'),
|
||||||
description: _t('Thank you!'),
|
description: _t('Thank you!'),
|
||||||
hasCancelButton: false,
|
hasCancelButton: false,
|
||||||
|
|
|
@ -53,7 +53,7 @@ export function createRedactEventDialog({
|
||||||
mxEvent: MatrixEvent;
|
mxEvent: MatrixEvent;
|
||||||
onCloseDialog?: () => void;
|
onCloseDialog?: () => void;
|
||||||
}) {
|
}) {
|
||||||
Modal.createTrackedDialog('Confirm Redact Dialog', '', ConfirmRedactDialog, {
|
Modal.createDialog(ConfirmRedactDialog, {
|
||||||
onFinished: async (proceed: boolean, reason?: string) => {
|
onFinished: async (proceed: boolean, reason?: string) => {
|
||||||
if (!proceed) return;
|
if (!proceed) return;
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ export function createRedactEventDialog({
|
||||||
// detached queue and we show the room status bar to allow retry
|
// detached queue and we show the room status bar to allow retry
|
||||||
if (typeof code !== "undefined") {
|
if (typeof code !== "undefined") {
|
||||||
// display error message stating you couldn't delete this.
|
// display error message stating you couldn't delete this.
|
||||||
Modal.createTrackedDialog('You cannot delete this message', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Error'),
|
title: _t('Error'),
|
||||||
description: _t('You cannot delete this message. (%(code)s)', { code }),
|
description: _t('You cannot delete this message. (%(code)s)', { code }),
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,7 +32,7 @@ const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
|
|
||||||
const _onLogoutClicked = () => {
|
const _onLogoutClicked = () => {
|
||||||
Modal.createTrackedDialog('Logout e2e db too new', '', QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Sign out"),
|
title: _t("Sign out"),
|
||||||
description: _t(
|
description: _t(
|
||||||
"To avoid losing your chat history, you must export your room keys " +
|
"To avoid losing your chat history, you must export your room keys " +
|
||||||
|
|
|
@ -19,7 +19,6 @@ import React from 'react';
|
||||||
import { AuthType, IAuthData } from 'matrix-js-sdk/src/interactive-auth';
|
import { AuthType, IAuthData } from 'matrix-js-sdk/src/interactive-auth';
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
import Analytics from '../../../Analytics';
|
|
||||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import InteractiveAuth, { ERROR_USER_CANCELLED, InteractiveAuthCallback } from "../../structures/InteractiveAuth";
|
import InteractiveAuth, { ERROR_USER_CANCELLED, InteractiveAuthCallback } from "../../structures/InteractiveAuth";
|
||||||
|
@ -122,7 +121,6 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
|
||||||
// this isn't done.
|
// this isn't done.
|
||||||
MatrixClientPeg.get().deactivateAccount(auth, this.state.shouldErase).then(r => {
|
MatrixClientPeg.get().deactivateAccount(auth, this.state.shouldErase).then(r => {
|
||||||
// Deactivation worked - logout & close this dialog
|
// Deactivation worked - logout & close this dialog
|
||||||
Analytics.trackEvent('Account', 'Deactivate Account');
|
|
||||||
defaultDispatcher.fire(Action.TriggerLogout);
|
defaultDispatcher.fire(Action.TriggerLogout);
|
||||||
this.props.onFinished(true);
|
this.props.onFinished(true);
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
|
|
|
@ -62,16 +62,11 @@ export default class EndPollDialog extends React.Component<IProps> {
|
||||||
this.props.event.getRoomId(), endEvent.type, endEvent.content,
|
this.props.event.getRoomId(), endEvent.type, endEvent.content,
|
||||||
).catch((e: any) => {
|
).catch((e: any) => {
|
||||||
console.error("Failed to submit poll response event:", e);
|
console.error("Failed to submit poll response event:", e);
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(ErrorDialog, {
|
||||||
'Failed to end poll',
|
|
||||||
'',
|
|
||||||
ErrorDialog,
|
|
||||||
{
|
|
||||||
title: _t("Failed to end poll"),
|
title: _t("Failed to end poll"),
|
||||||
description: _t(
|
description: _t(
|
||||||
"Sorry, the poll did not end. Please try again."),
|
"Sorry, the poll did not end. Please try again."),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.props.onFinished(endPoll);
|
this.props.onFinished(endPoll);
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Usage:
|
* Usage:
|
||||||
* Modal.createTrackedDialog('An Identifier', 'some detail', ErrorDialog, {
|
* Modal.createDialog(ErrorDialog, {
|
||||||
* title: "some text", (default: "Error")
|
* title: "some text", (default: "Error")
|
||||||
* description: "some more text",
|
* description: "some more text",
|
||||||
* button: "Button Text",
|
* button: "Button Text",
|
||||||
|
|
|
@ -47,7 +47,7 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
|
|
||||||
const onDebugLogsLinkClick = (): void => {
|
const onDebugLogsLinkClick = (): void => {
|
||||||
props.onFinished();
|
props.onFinished();
|
||||||
Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {});
|
Modal.createDialog(BugReportDialog, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
const rageshakeUrl = SdkConfig.get().bug_report_endpoint_url;
|
const rageshakeUrl = SdkConfig.get().bug_report_endpoint_url;
|
||||||
|
@ -58,7 +58,7 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
submitFeedback(rageshakeUrl, "feedback", comment, canContact);
|
submitFeedback(rageshakeUrl, "feedback", comment, canContact);
|
||||||
}
|
}
|
||||||
|
|
||||||
Modal.createTrackedDialog('Feedback sent', '', InfoDialog, {
|
Modal.createDialog(InfoDialog, {
|
||||||
title: _t('Feedback sent'),
|
title: _t('Feedback sent'),
|
||||||
description: _t('Thank you!'),
|
description: _t('Thank you!'),
|
||||||
});
|
});
|
||||||
|
|
|
@ -50,7 +50,7 @@ const GenericFeatureFeedbackDialog: React.FC<IProps> = ({
|
||||||
submitFeedback(SdkConfig.get().bug_report_endpoint_url, rageshakeLabel, comment, canContact, rageshakeData);
|
submitFeedback(SdkConfig.get().bug_report_endpoint_url, rageshakeLabel, comment, canContact, rageshakeData);
|
||||||
onFinished(true);
|
onFinished(true);
|
||||||
|
|
||||||
Modal.createTrackedDialog("Feedback Sent", rageshakeLabel, InfoDialog, {
|
Modal.createDialog(InfoDialog, {
|
||||||
title,
|
title,
|
||||||
description: _t("Feedback sent! Thanks, we appreciate it!"),
|
description: _t("Feedback sent! Thanks, we appreciate it!"),
|
||||||
button: _t("Close"),
|
button: _t("Close"),
|
||||||
|
|
|
@ -904,7 +904,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
|
||||||
if (this.unmounted) return;
|
if (this.unmounted) return;
|
||||||
|
|
||||||
if (failed.length > 0) {
|
if (failed.length > 0) {
|
||||||
Modal.createTrackedDialog('Invite Paste Fail', '', QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t('Failed to find the following users'),
|
title: _t('Failed to find the following users'),
|
||||||
description: _t(
|
description: _t(
|
||||||
"The following users might not exist or are invalid, and cannot be invited: %(csvNames)s",
|
"The following users might not exist or are invalid, and cannot be invited: %(csvNames)s",
|
||||||
|
|
|
@ -80,7 +80,7 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private onExportE2eKeysClicked = (): void => {
|
private onExportE2eKeysClicked = (): void => {
|
||||||
Modal.createTrackedDialogAsync('Export E2E Keys', '',
|
Modal.createDialogAsync(
|
||||||
import(
|
import(
|
||||||
'../../../async-components/views/dialogs/security/ExportE2eKeysDialog'
|
'../../../async-components/views/dialogs/security/ExportE2eKeysDialog'
|
||||||
) as unknown as Promise<ComponentType<{}>>,
|
) as unknown as Promise<ComponentType<{}>>,
|
||||||
|
@ -103,12 +103,9 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
|
||||||
// A key backup exists for this account, but the creating device is not
|
// 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
|
// verified, so restore the backup which will give us the keys from it and
|
||||||
// allow us to trust it (ie. upload keys to it)
|
// allow us to trust it (ie. upload keys to it)
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(RestoreKeyBackupDialog, null, null, /* priority = */ false, /* static = */ true);
|
||||||
'Restore Backup', '', RestoreKeyBackupDialog, null, null,
|
|
||||||
/* priority = */ false, /* static = */ true,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
|
Modal.createDialogAsync(
|
||||||
import(
|
import(
|
||||||
"../../../async-components/views/dialogs/security/CreateKeyBackupDialog"
|
"../../../async-components/views/dialogs/security/CreateKeyBackupDialog"
|
||||||
) as unknown as Promise<ComponentType<{}>>,
|
) as unknown as Promise<ComponentType<{}>>,
|
||||||
|
|
|
@ -56,7 +56,7 @@ export default class RoomUpgradeDialog extends React.Component<IProps, IState> {
|
||||||
upgradeRoom(this.props.room, this.targetVersion, false, false).then(() => {
|
upgradeRoom(this.props.room, this.targetVersion, false, false).then(() => {
|
||||||
this.props.onFinished(true);
|
this.props.onFinished(true);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
Modal.createTrackedDialog('Failed to upgrade room', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Failed to upgrade room"),
|
title: _t("Failed to upgrade room"),
|
||||||
description: ((err && err.message) ? err.message : _t("The room upgrade could not be completed")),
|
description: ((err && err.message) ? err.message : _t("The room upgrade could not be completed")),
|
||||||
});
|
});
|
||||||
|
|
|
@ -97,7 +97,7 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {});
|
Modal.createDialog(BugReportDialog, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -33,13 +33,13 @@ interface IProps extends IDialogProps {
|
||||||
|
|
||||||
export default class SessionRestoreErrorDialog extends React.Component<IProps> {
|
export default class SessionRestoreErrorDialog extends React.Component<IProps> {
|
||||||
private sendBugReport = (): void => {
|
private sendBugReport = (): void => {
|
||||||
Modal.createTrackedDialog('Session Restore Error', 'Send Bug Report Dialog', BugReportDialog, {
|
Modal.createDialog(BugReportDialog, {
|
||||||
error: this.props.error,
|
error: this.props.error,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private onClearStorageClick = (): void => {
|
private onClearStorageClick = (): void => {
|
||||||
Modal.createTrackedDialog('Session Restore Confirm Logout', '', QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Sign out"),
|
title: _t("Sign out"),
|
||||||
description:
|
description:
|
||||||
<div>{ _t("Sign out and remove encryption keys?") }</div>,
|
<div>{ _t("Sign out and remove encryption keys?") }</div>,
|
||||||
|
|
|
@ -64,7 +64,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
|
||||||
private onSubmit = (): void => {
|
private onSubmit = (): void => {
|
||||||
const emailAddress = this.state.emailAddress;
|
const emailAddress = this.state.emailAddress;
|
||||||
if (!Email.looksValid(emailAddress)) {
|
if (!Email.looksValid(emailAddress)) {
|
||||||
Modal.createTrackedDialog('Invalid Email Address', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Invalid Email Address"),
|
title: _t("Invalid Email Address"),
|
||||||
description: _t("This doesn't appear to be a valid email address"),
|
description: _t("This doesn't appear to be a valid email address"),
|
||||||
});
|
});
|
||||||
|
@ -72,7 +72,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
this.addThreepid = new AddThreepid();
|
this.addThreepid = new AddThreepid();
|
||||||
this.addThreepid.addEmailAddress(emailAddress).then(() => {
|
this.addThreepid.addEmailAddress(emailAddress).then(() => {
|
||||||
Modal.createTrackedDialog('Verification Pending', '', QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Verification Pending"),
|
title: _t("Verification Pending"),
|
||||||
description: _t(
|
description: _t(
|
||||||
"Please check your email and click on the link it contains. Once this " +
|
"Please check your email and click on the link it contains. Once this " +
|
||||||
|
@ -84,7 +84,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
this.setState({ emailBusy: false });
|
this.setState({ emailBusy: false });
|
||||||
logger.error("Unable to add email address " + emailAddress + " " + err);
|
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"),
|
title: _t("Unable to add email address"),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
|
@ -112,7 +112,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
|
||||||
if (err.errcode == 'M_THREEPID_AUTH_FAILED') {
|
if (err.errcode == 'M_THREEPID_AUTH_FAILED') {
|
||||||
const message = _t("Unable to verify email address.") + " " +
|
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.");
|
_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"),
|
title: _t("Verification Pending"),
|
||||||
description: message,
|
description: message,
|
||||||
button: _t('Continue'),
|
button: _t('Continue'),
|
||||||
|
@ -120,7 +120,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
logger.error("Unable to verify email address: " + err);
|
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."),
|
title: _t("Unable to verify email address."),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
|
|
|
@ -701,7 +701,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
|
||||||
};
|
};
|
||||||
|
|
||||||
const openFeedback = SdkConfig.get().bug_report_endpoint_url ? () => {
|
const openFeedback = SdkConfig.get().bug_report_endpoint_url ? () => {
|
||||||
Modal.createTrackedDialog("Spotlight Feedback", "feature_spotlight", BetaFeedbackDialog, {
|
Modal.createDialog(BetaFeedbackDialog, {
|
||||||
featureId: "feature_spotlight",
|
featureId: "feature_spotlight",
|
||||||
});
|
});
|
||||||
} : null;
|
} : null;
|
||||||
|
|
|
@ -30,7 +30,7 @@ interface IProps extends IDialogProps { }
|
||||||
export default class StorageEvictedDialog extends React.Component<IProps> {
|
export default class StorageEvictedDialog extends React.Component<IProps> {
|
||||||
private sendBugReport = (ev: React.MouseEvent): void => {
|
private sendBugReport = (ev: React.MouseEvent): void => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
Modal.createTrackedDialog('Storage evicted', 'Send Bug Report Dialog', BugReportDialog, {});
|
Modal.createDialog(BugReportDialog, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
private onSignOutClick = (): void => {
|
private onSignOutClick = (): void => {
|
||||||
|
|
|
@ -233,14 +233,11 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
await cli.bootstrapCrossSigning({
|
await cli.bootstrapCrossSigning({
|
||||||
authUploadDeviceSigningKeys: async (makeRequest) => {
|
authUploadDeviceSigningKeys: async (makeRequest) => {
|
||||||
const { finished } = Modal.createTrackedDialog(
|
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||||
'Cross-signing keys dialog', '', InteractiveAuthDialog,
|
|
||||||
{
|
|
||||||
title: _t("Setting up keys"),
|
title: _t("Setting up keys"),
|
||||||
matrixClient: cli,
|
matrixClient: cli,
|
||||||
makeRequest,
|
makeRequest,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
const [confirmed] = await finished;
|
const [confirmed] = await finished;
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
throw new Error("Cross-signing key upload auth canceled");
|
throw new Error("Cross-signing key upload auth canceled");
|
||||||
|
|
|
@ -123,9 +123,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const { finished } = Modal.createTrackedDialog(
|
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||||
'Cross-signing keys dialog', '', InteractiveAuthDialog,
|
|
||||||
{
|
|
||||||
title: _t("Setting up keys"),
|
title: _t("Setting up keys"),
|
||||||
matrixClient: MatrixClientPeg.get(),
|
matrixClient: MatrixClientPeg.get(),
|
||||||
makeRequest,
|
makeRequest,
|
||||||
|
@ -133,8 +131,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
|
||||||
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
|
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
|
||||||
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
|
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
);
|
|
||||||
const [confirmed] = await finished;
|
const [confirmed] = await finished;
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
throw new Error("Cross-signing key upload auth canceled");
|
throw new Error("Cross-signing key upload auth canceled");
|
||||||
|
|
|
@ -188,9 +188,7 @@ const NetworkDropdown = ({ onOptionChange, protocols = {}, selectedServerName, s
|
||||||
if (removableServers.has(server)) {
|
if (removableServers.has(server)) {
|
||||||
const onClick = async () => {
|
const onClick = async () => {
|
||||||
closeMenu();
|
closeMenu();
|
||||||
const { finished } = Modal.createTrackedDialog(
|
const { finished } = Modal.createDialog(QuestionDialog, {
|
||||||
"Network Dropdown", "Remove server", QuestionDialog,
|
|
||||||
{
|
|
||||||
title: _t("Are you sure?"),
|
title: _t("Are you sure?"),
|
||||||
description: _t("Are you sure you want to remove <b>%(serverName)s</b>", {
|
description: _t("Are you sure you want to remove <b>%(serverName)s</b>", {
|
||||||
serverName: server,
|
serverName: server,
|
||||||
|
@ -199,9 +197,7 @@ const NetworkDropdown = ({ onOptionChange, protocols = {}, selectedServerName, s
|
||||||
}),
|
}),
|
||||||
button: _t("Remove"),
|
button: _t("Remove"),
|
||||||
fixedWidth: false,
|
fixedWidth: false,
|
||||||
},
|
}, "mx_NetworkDropdown_dialog");
|
||||||
"mx_NetworkDropdown_dialog",
|
|
||||||
);
|
|
||||||
|
|
||||||
const [ok] = await finished;
|
const [ok] = await finished;
|
||||||
if (!ok) return;
|
if (!ok) return;
|
||||||
|
@ -242,7 +238,7 @@ const NetworkDropdown = ({ onOptionChange, protocols = {}, selectedServerName, s
|
||||||
|
|
||||||
const onClick = async () => {
|
const onClick = async () => {
|
||||||
closeMenu();
|
closeMenu();
|
||||||
const { finished } = Modal.createTrackedDialog("Network Dropdown", "Add a new server", TextInputDialog, {
|
const { finished } = Modal.createDialog(TextInputDialog, {
|
||||||
title: _t("Add a new server"),
|
title: _t("Add a new server"),
|
||||||
description: _t("Enter the name of a new server you want to explore."),
|
description: _t("Enter the name of a new server you want to explore."),
|
||||||
button: _t("Add"),
|
button: _t("Add"),
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 Vector Creations Ltd
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import AccessibleButton from './AccessibleButton';
|
|
||||||
import dis from '../../../dispatcher/dispatcher';
|
|
||||||
import Analytics from '../../../Analytics';
|
|
||||||
import Tooltip from './Tooltip';
|
|
||||||
|
|
||||||
interface IProps {
|
|
||||||
size?: string;
|
|
||||||
tooltip?: boolean;
|
|
||||||
action: string;
|
|
||||||
mouseOverAction?: string;
|
|
||||||
label: string;
|
|
||||||
iconPath?: string;
|
|
||||||
className?: string;
|
|
||||||
children?: JSX.Element;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IState {
|
|
||||||
showTooltip: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class ActionButton extends React.Component<IProps, IState> {
|
|
||||||
static defaultProps: Partial<IProps> = {
|
|
||||||
size: "25",
|
|
||||||
tooltip: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props: IProps) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
showTooltip: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private onClick = (ev: React.MouseEvent): void => {
|
|
||||||
ev.stopPropagation();
|
|
||||||
Analytics.trackEvent('Action Button', 'click', this.props.action);
|
|
||||||
dis.dispatch({ action: this.props.action });
|
|
||||||
};
|
|
||||||
|
|
||||||
private onMouseEnter = (): void => {
|
|
||||||
this.showTooltip();
|
|
||||||
if (this.props.mouseOverAction) {
|
|
||||||
dis.dispatch({ action: this.props.mouseOverAction });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private showTooltip = (): void => {
|
|
||||||
if (this.props.tooltip) this.setState({ showTooltip: true });
|
|
||||||
};
|
|
||||||
|
|
||||||
private hideTooltip = (): void => {
|
|
||||||
this.setState({ showTooltip: false });
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let tooltip;
|
|
||||||
if (this.state.showTooltip) {
|
|
||||||
tooltip = <Tooltip className="mx_RoleButton_tooltip" label={this.props.label} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const icon = this.props.iconPath ?
|
|
||||||
(<img src={this.props.iconPath} width={this.props.size} height={this.props.size} />) :
|
|
||||||
undefined;
|
|
||||||
|
|
||||||
const classNames = ["mx_RoleButton"];
|
|
||||||
if (this.props.className) {
|
|
||||||
classNames.push(this.props.className);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AccessibleButton
|
|
||||||
className={classNames.join(" ")}
|
|
||||||
onClick={this.onClick}
|
|
||||||
onMouseEnter={this.onMouseEnter}
|
|
||||||
onMouseLeave={this.hideTooltip}
|
|
||||||
onFocus={this.showTooltip}
|
|
||||||
onBlur={this.hideTooltip}
|
|
||||||
aria-label={this.props.label}
|
|
||||||
>
|
|
||||||
{ icon }
|
|
||||||
{ tooltip }
|
|
||||||
{ this.props.children }
|
|
||||||
</AccessibleButton>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -68,7 +68,7 @@ export default class ErrorBoundary extends React.PureComponent<{}, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onBugReport = (): void => {
|
private onBugReport = (): void => {
|
||||||
Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {
|
Modal.createDialog(BugReportDialog, {
|
||||||
label: 'react-soft-crash',
|
label: 'react-soft-crash',
|
||||||
error: this.state.error,
|
error: this.state.error,
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,7 +18,6 @@ import classNames from 'classnames';
|
||||||
import { EventType } from 'matrix-js-sdk/src/@types/event';
|
import { EventType } from 'matrix-js-sdk/src/@types/event';
|
||||||
import React, { useContext, useRef, useState, MouseEvent } from 'react';
|
import React, { useContext, useRef, useState, MouseEvent } from 'react';
|
||||||
|
|
||||||
import Analytics from "../../../Analytics";
|
|
||||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||||
import RoomContext from "../../../contexts/RoomContext";
|
import RoomContext from "../../../contexts/RoomContext";
|
||||||
import { useTimeout } from "../../../hooks/useTimeout";
|
import { useTimeout } from "../../../hooks/useTimeout";
|
||||||
|
@ -74,7 +73,6 @@ const MiniAvatarUploader: React.FC<IProps> = ({
|
||||||
onChange={async (ev) => {
|
onChange={async (ev) => {
|
||||||
if (!ev.target.files?.length) return;
|
if (!ev.target.files?.length) return;
|
||||||
setBusy(true);
|
setBusy(true);
|
||||||
Analytics.trackEvent("mini_avatar", "upload");
|
|
||||||
const file = ev.target.files[0];
|
const file = ev.target.files[0];
|
||||||
const uri = await cli.uploadContent(file);
|
const uri = await cli.uploadContent(file);
|
||||||
await setAvatarUrl(uri);
|
await setAvatarUrl(uri);
|
||||||
|
|
|
@ -172,11 +172,7 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
|
||||||
() => this.props.onFinished(true),
|
() => this.props.onFinished(true),
|
||||||
).catch(e => {
|
).catch(e => {
|
||||||
console.error("Failed to post poll:", e);
|
console.error("Failed to post poll:", e);
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(QuestionDialog, {
|
||||||
'Failed to post poll',
|
|
||||||
'',
|
|
||||||
QuestionDialog,
|
|
||||||
{
|
|
||||||
title: _t("Failed to post poll"),
|
title: _t("Failed to post poll"),
|
||||||
description: _t(
|
description: _t(
|
||||||
"Sorry, the poll you tried to create was not posted."),
|
"Sorry, the poll you tried to create was not posted."),
|
||||||
|
@ -189,8 +185,7 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
|
||||||
this.setState({ busy: false, canSubmit: true });
|
this.setState({ busy: false, canSubmit: true });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,12 +37,12 @@ const showPickerDialog = (
|
||||||
serverConfig: ValidatedServerConfig,
|
serverConfig: ValidatedServerConfig,
|
||||||
onFinished: (config: ValidatedServerConfig) => void,
|
onFinished: (config: ValidatedServerConfig) => void,
|
||||||
) => {
|
) => {
|
||||||
Modal.createTrackedDialog("Server Picker", "", ServerPickerDialog, { title, serverConfig, onFinished });
|
Modal.createDialog(ServerPickerDialog, { title, serverConfig, onFinished });
|
||||||
};
|
};
|
||||||
|
|
||||||
const onHelpClick = () => {
|
const onHelpClick = () => {
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
Modal.createTrackedDialog('Custom Server Dialog', '', InfoDialog, {
|
Modal.createDialog(InfoDialog, {
|
||||||
title: _t("Server Options"),
|
title: _t("Server Options"),
|
||||||
description: _t("You can use the custom server options to sign into other Matrix servers by specifying " +
|
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 " +
|
"a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on " +
|
||||||
|
|
|
@ -183,15 +183,10 @@ class LocationPicker extends React.Component<ILocationPickerProps, IState> {
|
||||||
// pin drop location without permissions is ok
|
// pin drop location without permissions is ok
|
||||||
if (isSharingOwnLocation(this.props.shareType)) {
|
if (isSharingOwnLocation(this.props.shareType)) {
|
||||||
this.props.onFinished();
|
this.props.onFinished();
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(ErrorDialog, {
|
||||||
'Could not fetch location',
|
|
||||||
'',
|
|
||||||
ErrorDialog,
|
|
||||||
{
|
|
||||||
title: _t("Could not fetch location"),
|
title: _t("Could not fetch location"),
|
||||||
description: positionFailureMessage(e.code),
|
description: positionFailureMessage(e.code),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.geolocate) {
|
if (this.geolocate) {
|
||||||
|
|
|
@ -49,7 +49,6 @@ const handleShareError = (error: Error, openMenu: () => void, shareType: Locatio
|
||||||
"We couldn't start sharing your live location" :
|
"We couldn't start sharing your live location" :
|
||||||
"We couldn't send your location";
|
"We couldn't send your location";
|
||||||
logger.error(errorMessage, error);
|
logger.error(errorMessage, error);
|
||||||
const analyticsAction = errorMessage;
|
|
||||||
const params = {
|
const params = {
|
||||||
title: _t("We couldn't send your location"),
|
title: _t("We couldn't send your location"),
|
||||||
description: _t("%(brand)s could not send your location. Please try again later.", {
|
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 = (
|
export const shareLiveLocation = (
|
||||||
|
|
|
@ -154,7 +154,7 @@ export default class DateSeparator extends React.Component<IProps, IState> {
|
||||||
// detached queue and we show the room status bar to allow retry
|
// detached queue and we show the room status bar to allow retry
|
||||||
if (typeof code !== "undefined") {
|
if (typeof code !== "undefined") {
|
||||||
// display error message stating you couldn't delete this.
|
// 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'),
|
title: _t('Error'),
|
||||||
description: _t('Unable to find event at that date. (%(code)s)', { code }),
|
description: _t('Unable to find event at that date. (%(code)s)', { code }),
|
||||||
});
|
});
|
||||||
|
|
|
@ -75,13 +75,13 @@ export default class EditHistoryMessage extends React.PureComponent<IProps, ISta
|
||||||
const event = this.props.mxEvent;
|
const event = this.props.mxEvent;
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
|
|
||||||
Modal.createTrackedDialog('Confirm Redact Dialog', 'Edit history', ConfirmAndWaitRedactDialog, {
|
Modal.createDialog(ConfirmAndWaitRedactDialog, {
|
||||||
redact: () => cli.redactEvent(event.getRoomId(), event.getId()),
|
redact: () => cli.redactEvent(event.getRoomId(), event.getId()),
|
||||||
}, 'mx_Dialog_confirmredact');
|
}, 'mx_Dialog_confirmredact');
|
||||||
};
|
};
|
||||||
|
|
||||||
private onViewSourceClick = (): void => {
|
private onViewSourceClick = (): void => {
|
||||||
Modal.createTrackedDialog('View Event Source', 'Edit history', ViewSource, {
|
Modal.createDialog(ViewSource, {
|
||||||
mxEvent: this.props.mxEvent,
|
mxEvent: this.props.mxEvent,
|
||||||
}, 'mx_Dialog_viewsource');
|
}, 'mx_Dialog_viewsource');
|
||||||
};
|
};
|
||||||
|
|
|
@ -106,9 +106,7 @@ const MBeaconBody: React.FC<IBodyProps> = React.forwardRef(({ mxEvent }, ref) =>
|
||||||
if (displayStatus !== BeaconDisplayStatus.Active) {
|
if (displayStatus !== BeaconDisplayStatus.Active) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(
|
||||||
'Beacon View',
|
|
||||||
'',
|
|
||||||
BeaconViewDialog,
|
BeaconViewDialog,
|
||||||
{
|
{
|
||||||
roomId: mxEvent.getRoomId(),
|
roomId: mxEvent.getRoomId(),
|
||||||
|
|
|
@ -172,7 +172,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.warn("Unable to decrypt attachment: ", err);
|
logger.warn("Unable to decrypt attachment: ", err);
|
||||||
Modal.createTrackedDialog('Error decrypting attachment', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Error"),
|
title: _t("Error"),
|
||||||
description: _t("Error decrypting attachment"),
|
description: _t("Error decrypting attachment"),
|
||||||
});
|
});
|
||||||
|
|
|
@ -57,9 +57,7 @@ export default class MLocationBody extends React.Component<IBodyProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private onClick = () => {
|
private onClick = () => {
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(
|
||||||
'Location View',
|
|
||||||
'',
|
|
||||||
LocationViewDialog,
|
LocationViewDialog,
|
||||||
{
|
{
|
||||||
matrixClient: this.context,
|
matrixClient: this.context,
|
||||||
|
|
|
@ -181,9 +181,7 @@ export function pollAlreadyHasVotes(mxEvent: MatrixEvent, getRelationsForEvent?:
|
||||||
|
|
||||||
export function launchPollEditor(mxEvent: MatrixEvent, getRelationsForEvent?: GetRelationsForEvent): void {
|
export function launchPollEditor(mxEvent: MatrixEvent, getRelationsForEvent?: GetRelationsForEvent): void {
|
||||||
if (pollAlreadyHasVotes(mxEvent, getRelationsForEvent)) {
|
if (pollAlreadyHasVotes(mxEvent, getRelationsForEvent)) {
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(
|
||||||
'Not allowed to edit poll',
|
|
||||||
'',
|
|
||||||
ErrorDialog,
|
ErrorDialog,
|
||||||
{
|
{
|
||||||
title: _t("Can't edit poll"),
|
title: _t("Can't edit poll"),
|
||||||
|
@ -193,9 +191,7 @@ export function launchPollEditor(mxEvent: MatrixEvent, getRelationsForEvent?: Ge
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(
|
||||||
'Polls',
|
|
||||||
'create',
|
|
||||||
PollCreateDialog,
|
PollCreateDialog,
|
||||||
{
|
{
|
||||||
room: MatrixClientPeg.get().getRoom(mxEvent.getRoomId()),
|
room: MatrixClientPeg.get().getRoom(mxEvent.getRoomId()),
|
||||||
|
@ -312,9 +308,7 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
|
||||||
).catch((e: any) => {
|
).catch((e: any) => {
|
||||||
console.error("Failed to submit poll response event:", e);
|
console.error("Failed to submit poll response event:", e);
|
||||||
|
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(
|
||||||
'Vote not registered',
|
|
||||||
'',
|
|
||||||
ErrorDialog,
|
ErrorDialog,
|
||||||
{
|
{
|
||||||
title: _t("Vote not registered"),
|
title: _t("Vote not registered"),
|
||||||
|
|
|
@ -468,7 +468,7 @@ export default class TextualBody extends React.Component<IBodyProps, IState> {
|
||||||
scalarClient.connect().then(() => {
|
scalarClient.connect().then(() => {
|
||||||
const completeUrl = scalarClient.getStarterLink(starterLink);
|
const completeUrl = scalarClient.getStarterLink(starterLink);
|
||||||
const integrationsUrl = integrationManager.uiUrl;
|
const integrationsUrl = integrationManager.uiUrl;
|
||||||
Modal.createTrackedDialog('Add an integration', '', QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Add an Integration"),
|
title: _t("Add an Integration"),
|
||||||
description:
|
description:
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -52,14 +52,14 @@ export default class TileErrorBoundary extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private onBugReport = (): void => {
|
private onBugReport = (): void => {
|
||||||
Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {
|
Modal.createDialog(BugReportDialog, {
|
||||||
label: 'react-soft-crash-tile',
|
label: 'react-soft-crash-tile',
|
||||||
error: this.state.error,
|
error: this.state.error,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private onViewSource = (): void => {
|
private onViewSource = (): void => {
|
||||||
Modal.createTrackedDialog('View Event Source', 'from crash', ViewSource, {
|
Modal.createDialog(ViewSource, {
|
||||||
mxEvent: this.props.mxEvent,
|
mxEvent: this.props.mxEvent,
|
||||||
}, 'mx_Dialog_viewsource');
|
}, 'mx_Dialog_viewsource');
|
||||||
};
|
};
|
||||||
|
|
|
@ -84,7 +84,7 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
|
||||||
const changeHandler = useCallback(() => {
|
const changeHandler = useCallback(() => {
|
||||||
// handle transitions -> cancelled for mismatches which fire a modal instead of showing a card
|
// handle transitions -> cancelled for mismatches which fire a modal instead of showing a card
|
||||||
if (request && request.cancelled && MISMATCHES.includes(request.cancellationCode)) {
|
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,
|
headerImage: require("../../../../res/img/e2e/warning.svg").default,
|
||||||
title: _t("Your messages are not secure"),
|
title: _t("Your messages are not secure"),
|
||||||
description: <div>
|
description: <div>
|
||||||
|
|
|
@ -21,7 +21,6 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import Analytics from '../../../Analytics';
|
|
||||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||||
import { ButtonEvent } from "../elements/AccessibleButton";
|
import { ButtonEvent } from "../elements/AccessibleButton";
|
||||||
|
|
||||||
|
@ -31,8 +30,6 @@ interface IProps {
|
||||||
isUnread?: boolean;
|
isUnread?: boolean;
|
||||||
// click handler
|
// click handler
|
||||||
onClick: (ev: ButtonEvent) => void;
|
onClick: (ev: ButtonEvent) => void;
|
||||||
// The parameters to track the click event
|
|
||||||
analytics: Parameters<typeof Analytics.trackEvent>;
|
|
||||||
|
|
||||||
// Button name
|
// Button name
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -42,14 +39,8 @@ interface IProps {
|
||||||
|
|
||||||
// TODO: replace this, the composer buttons and the right panel buttons with a unified representation
|
// TODO: replace this, the composer buttons and the right panel buttons with a unified representation
|
||||||
export default class HeaderButton extends React.Component<IProps> {
|
export default class HeaderButton extends React.Component<IProps> {
|
||||||
private onClick = (ev: ButtonEvent) => {
|
|
||||||
Analytics.trackEvent(...this.props.analytics);
|
|
||||||
this.props.onClick(ev);
|
|
||||||
};
|
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
const { isHighlighted, isUnread = false, onClick, name, title, ...props } = this.props;
|
||||||
const { isHighlighted, isUnread = false, onClick, analytics, name, title, ...props } = this.props;
|
|
||||||
|
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
mx_RightPanel_headerButton: true,
|
mx_RightPanel_headerButton: true,
|
||||||
|
@ -64,7 +55,7 @@ export default class HeaderButton extends React.Component<IProps> {
|
||||||
role="tab"
|
role="tab"
|
||||||
title={title}
|
title={title}
|
||||||
className={classes}
|
className={classes}
|
||||||
onClick={this.onClick}
|
onClick={onClick}
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,6 @@ const PinnedMessagesHeaderButton = ({ room, isHighlighted, onClick }: IHeaderBut
|
||||||
isHighlighted={isHighlighted}
|
isHighlighted={isHighlighted}
|
||||||
isUnread={!!unreadIndicator}
|
isUnread={!!unreadIndicator}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
analytics={["Right Panel", "Pinned Messages Button", "click"]}
|
|
||||||
>
|
>
|
||||||
{ unreadIndicator }
|
{ unreadIndicator }
|
||||||
</HeaderButton>;
|
</HeaderButton>;
|
||||||
|
@ -115,7 +114,6 @@ const TimelineCardHeaderButton = ({ room, isHighlighted, onClick }: IHeaderButto
|
||||||
title={_t("Chat")}
|
title={_t("Chat")}
|
||||||
isHighlighted={isHighlighted}
|
isHighlighted={isHighlighted}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
analytics={["Right Panel", "Timeline Panel Button", "click"]}
|
|
||||||
>
|
>
|
||||||
{ unreadIndicator }
|
{ unreadIndicator }
|
||||||
</HeaderButton>;
|
</HeaderButton>;
|
||||||
|
@ -244,7 +242,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
||||||
onClick={this.onThreadsPanelClicked}
|
onClick={this.onThreadsPanelClicked}
|
||||||
isHighlighted={this.isPhase(RoomHeaderButtons.THREAD_PHASES)}
|
isHighlighted={this.isPhase(RoomHeaderButtons.THREAD_PHASES)}
|
||||||
isUnread={this.threadNotificationState.color > 0}
|
isUnread={this.threadNotificationState.color > 0}
|
||||||
analytics={['Right Panel', 'Threads List Button', 'click']}>
|
>
|
||||||
<UnreadIndicator color={this.threadNotificationState.color} />
|
<UnreadIndicator color={this.threadNotificationState.color} />
|
||||||
</HeaderButton>
|
</HeaderButton>
|
||||||
: null,
|
: null,
|
||||||
|
@ -256,7 +254,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
||||||
title={_t('Notifications')}
|
title={_t('Notifications')}
|
||||||
isHighlighted={this.isPhase(RightPanelPhases.NotificationPanel)}
|
isHighlighted={this.isPhase(RightPanelPhases.NotificationPanel)}
|
||||||
onClick={this.onNotificationsClicked}
|
onClick={this.onNotificationsClicked}
|
||||||
analytics={['Right Panel', 'Notification List Button', 'click']} />,
|
/>,
|
||||||
);
|
);
|
||||||
rightPanelPhaseButtons.set(RightPanelPhases.RoomSummary,
|
rightPanelPhaseButtons.set(RightPanelPhases.RoomSummary,
|
||||||
<HeaderButton
|
<HeaderButton
|
||||||
|
@ -265,7 +263,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
||||||
title={_t('Room Info')}
|
title={_t('Room Info')}
|
||||||
isHighlighted={this.isPhase(ROOM_INFO_PHASES)}
|
isHighlighted={this.isPhase(ROOM_INFO_PHASES)}
|
||||||
onClick={this.onRoomSummaryClicked}
|
onClick={this.onRoomSummaryClicked}
|
||||||
analytics={['Right Panel', 'Room Summary Button', 'click']} />,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
|
|
|
@ -248,13 +248,13 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, onClose }) => {
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
|
|
||||||
const onShareRoomClick = () => {
|
const onShareRoomClick = () => {
|
||||||
Modal.createTrackedDialog('share room dialog', '', ShareDialog, {
|
Modal.createDialog(ShareDialog, {
|
||||||
target: room,
|
target: room,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onRoomExportClick = async () => {
|
const onRoomExportClick = async () => {
|
||||||
Modal.createTrackedDialog('export room dialog', '', ExportDialog, {
|
Modal.createDialog(ExportDialog, {
|
||||||
room,
|
room,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -365,7 +365,7 @@ const UserOptionsSection: React.FC<{
|
||||||
const isMe = member.userId === cli.getUserId();
|
const isMe = member.userId === cli.getUserId();
|
||||||
|
|
||||||
const onShareUserClick = () => {
|
const onShareUserClick = () => {
|
||||||
Modal.createTrackedDialog('share room member dialog', '', ShareDialog, {
|
Modal.createDialog(ShareDialog, {
|
||||||
target: member,
|
target: member,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -451,7 +451,7 @@ const UserOptionsSection: React.FC<{
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Modal.createTrackedDialog('Failed to invite', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Failed to invite'),
|
title: _t('Failed to invite'),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
|
@ -503,7 +503,7 @@ const UserOptionsSection: React.FC<{
|
||||||
};
|
};
|
||||||
|
|
||||||
const warnSelfDemote = async (isSpace: boolean) => {
|
const warnSelfDemote = async (isSpace: boolean) => {
|
||||||
const { finished } = Modal.createTrackedDialog('Demoting Self', '', QuestionDialog, {
|
const { finished } = Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Demote yourself?"),
|
title: _t("Demote yourself?"),
|
||||||
description:
|
description:
|
||||||
<div>
|
<div>
|
||||||
|
@ -590,9 +590,7 @@ const RoomKickButton = ({ room, member, startUpdating, stopUpdating }: Omit<IBas
|
||||||
if (member.membership !== "invite" && member.membership !== "join") return null;
|
if (member.membership !== "invite" && member.membership !== "join") return null;
|
||||||
|
|
||||||
const onKick = async () => {
|
const onKick = async () => {
|
||||||
const { finished } = Modal.createTrackedDialog(
|
const { finished } = Modal.createDialog(
|
||||||
'Confirm User Action Dialog',
|
|
||||||
'onKick',
|
|
||||||
room.isSpaceRoom() ? ConfirmSpaceUserActionDialog : ConfirmUserActionDialog,
|
room.isSpaceRoom() ? ConfirmSpaceUserActionDialog : ConfirmUserActionDialog,
|
||||||
{
|
{
|
||||||
member,
|
member,
|
||||||
|
@ -632,7 +630,7 @@ const RoomKickButton = ({ room, member, startUpdating, stopUpdating }: Omit<IBas
|
||||||
logger.log("Kick success");
|
logger.log("Kick success");
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
logger.error("Kick error: " + err);
|
logger.error("Kick error: " + err);
|
||||||
Modal.createTrackedDialog('Failed to kick', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Failed to remove user"),
|
title: _t("Failed to remove user"),
|
||||||
description: ((err && err.message) ? err.message : "Operation failed"),
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
});
|
});
|
||||||
|
@ -661,7 +659,7 @@ const RedactMessagesButton: React.FC<IBaseProps> = ({ member }) => {
|
||||||
const room = cli.getRoom(member.roomId);
|
const room = cli.getRoom(member.roomId);
|
||||||
if (!room) return;
|
if (!room) return;
|
||||||
|
|
||||||
Modal.createTrackedDialog("Bulk Redact Dialog", "", BulkRedactDialog, {
|
Modal.createDialog(BulkRedactDialog, {
|
||||||
matrixClient: cli,
|
matrixClient: cli,
|
||||||
room, member,
|
room, member,
|
||||||
});
|
});
|
||||||
|
@ -681,9 +679,7 @@ const BanToggleButton = ({ room, member, startUpdating, stopUpdating }: Omit<IBa
|
||||||
|
|
||||||
const isBanned = member.membership === "ban";
|
const isBanned = member.membership === "ban";
|
||||||
const onBanOrUnban = async () => {
|
const onBanOrUnban = async () => {
|
||||||
const { finished } = Modal.createTrackedDialog(
|
const { finished } = Modal.createDialog(
|
||||||
'Confirm User Action Dialog',
|
|
||||||
'onBanOrUnban',
|
|
||||||
room.isSpaceRoom() ? ConfirmSpaceUserActionDialog : ConfirmUserActionDialog,
|
room.isSpaceRoom() ? ConfirmSpaceUserActionDialog : ConfirmUserActionDialog,
|
||||||
{
|
{
|
||||||
member,
|
member,
|
||||||
|
@ -746,7 +742,7 @@ const BanToggleButton = ({ room, member, startUpdating, stopUpdating }: Omit<IBa
|
||||||
logger.log("Ban success");
|
logger.log("Ban success");
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
logger.error("Ban error: " + err);
|
logger.error("Ban error: " + err);
|
||||||
Modal.createTrackedDialog('Failed to ban user', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Error"),
|
title: _t("Error"),
|
||||||
description: _t("Failed to ban user"),
|
description: _t("Failed to ban user"),
|
||||||
});
|
});
|
||||||
|
@ -827,7 +823,7 @@ const MuteToggleButton: React.FC<IBaseRoomProps> = ({ member, room, powerLevels,
|
||||||
logger.log("Mute toggle success");
|
logger.log("Mute toggle success");
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
logger.error("Mute error: " + err);
|
logger.error("Mute error: " + err);
|
||||||
Modal.createTrackedDialog('Failed to mute user', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Error"),
|
title: _t("Error"),
|
||||||
description: _t("Failed to mute user"),
|
description: _t("Failed to mute user"),
|
||||||
});
|
});
|
||||||
|
@ -1048,7 +1044,7 @@ const PowerLevelEditor: React.FC<{
|
||||||
logger.log("Power change success");
|
logger.log("Power change success");
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
logger.error("Failed to change power level " + err);
|
logger.error("Failed to change power level " + err);
|
||||||
Modal.createTrackedDialog('Failed to change power level', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Error"),
|
title: _t("Error"),
|
||||||
description: _t("Failed to change power level"),
|
description: _t("Failed to change power level"),
|
||||||
});
|
});
|
||||||
|
@ -1065,7 +1061,7 @@ const PowerLevelEditor: React.FC<{
|
||||||
const myUserId = cli.getUserId();
|
const myUserId = cli.getUserId();
|
||||||
const myPower = powerLevelEvent.getContent().users[myUserId];
|
const myPower = powerLevelEvent.getContent().users[myUserId];
|
||||||
if (myPower && parseInt(myPower) <= powerLevel && myUserId !== target) {
|
if (myPower && parseInt(myPower) <= powerLevel && myUserId !== target) {
|
||||||
const { finished } = Modal.createTrackedDialog('Promote to PL100 Warning', '', QuestionDialog, {
|
const { finished } = Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Warning!"),
|
title: _t("Warning!"),
|
||||||
description:
|
description:
|
||||||
<div>
|
<div>
|
||||||
|
@ -1214,7 +1210,7 @@ const BasicUserInfo: React.FC<{
|
||||||
const roomPermissions = useRoomPermissions(cli, room, member as RoomMember);
|
const roomPermissions = useRoomPermissions(cli, room, member as RoomMember);
|
||||||
|
|
||||||
const onSynapseDeactivate = useCallback(async () => {
|
const onSynapseDeactivate = useCallback(async () => {
|
||||||
const { finished } = Modal.createTrackedDialog('Synapse User Deactivation', '', QuestionDialog, {
|
const { finished } = Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Deactivate user?"),
|
title: _t("Deactivate user?"),
|
||||||
description:
|
description:
|
||||||
<div>{ _t(
|
<div>{ _t(
|
||||||
|
@ -1234,7 +1230,7 @@ const BasicUserInfo: React.FC<{
|
||||||
logger.error("Failed to deactivate user");
|
logger.error("Failed to deactivate user");
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
|
|
||||||
Modal.createTrackedDialog('Failed to deactivate Synapse user', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Failed to deactivate user'),
|
title: _t('Failed to deactivate user'),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
|
|
|
@ -173,7 +173,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
|
||||||
this.context.sendStateEvent(this.props.roomId, "m.room.canonical_alias",
|
this.context.sendStateEvent(this.props.roomId, "m.room.canonical_alias",
|
||||||
eventContent, "").catch((err) => {
|
eventContent, "").catch((err) => {
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
Modal.createTrackedDialog('Error updating main address', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Error updating main address"),
|
title: _t("Error updating main address"),
|
||||||
description: _t(
|
description: _t(
|
||||||
"There was an error updating the room's main address. It may not be allowed by the server " +
|
"There was an error updating the room's main address. It may not be allowed by the server " +
|
||||||
|
@ -211,7 +211,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
// TODO: Add error handling based upon server validation
|
// TODO: Add error handling based upon server validation
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
Modal.createTrackedDialog('Error updating alternative addresses', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Error updating main address"),
|
title: _t("Error updating main address"),
|
||||||
description: _t(
|
description: _t(
|
||||||
"There was an error updating the room's alternative addresses. " +
|
"There was an error updating the room's alternative addresses. " +
|
||||||
|
@ -243,7 +243,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
Modal.createTrackedDialog('Error creating address', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Error creating address"),
|
title: _t("Error creating address"),
|
||||||
description: _t(
|
description: _t(
|
||||||
"There was an error creating that address. It may not be allowed by the server " +
|
"There was an error creating that address. It may not be allowed by the server " +
|
||||||
|
@ -275,7 +275,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
|
||||||
"error occurred.",
|
"error occurred.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Modal.createTrackedDialog('Error removing address', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Error removing address"),
|
title: _t("Error removing address"),
|
||||||
description,
|
description,
|
||||||
});
|
});
|
||||||
|
|
|
@ -315,9 +315,7 @@ class PollButton extends React.PureComponent<IPollButtonProps> {
|
||||||
MatrixClientPeg.get().getUserId(),
|
MatrixClientPeg.get().getUserId(),
|
||||||
);
|
);
|
||||||
if (!canSend) {
|
if (!canSend) {
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(
|
||||||
'Polls',
|
|
||||||
'permissions error: cannot start',
|
|
||||||
ErrorDialog,
|
ErrorDialog,
|
||||||
{
|
{
|
||||||
title: _t("Permission Required"),
|
title: _t("Permission Required"),
|
||||||
|
@ -331,9 +329,7 @@ class PollButton extends React.PureComponent<IPollButtonProps> {
|
||||||
? this.props.relation.event_id
|
? this.props.relation.event_id
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(
|
||||||
'Polls',
|
|
||||||
'create',
|
|
||||||
PollCreateDialog,
|
PollCreateDialog,
|
||||||
{
|
{
|
||||||
room: this.props.room,
|
room: this.props.room,
|
||||||
|
|
|
@ -22,7 +22,6 @@ import { BreadcrumbsStore } from "../../../stores/BreadcrumbsStore";
|
||||||
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
|
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||||
import Analytics from "../../../Analytics";
|
|
||||||
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
|
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
|
||||||
import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
|
import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
|
||||||
import Toolbar from "../../../accessibility/Toolbar";
|
import Toolbar from "../../../accessibility/Toolbar";
|
||||||
|
@ -104,7 +103,6 @@ export default class RoomBreadcrumbs extends React.PureComponent<IProps, IState>
|
||||||
};
|
};
|
||||||
|
|
||||||
private viewRoom = (room: Room, index: number, viaKeyboard = false) => {
|
private viewRoom = (room: Room, index: number, viaKeyboard = false) => {
|
||||||
Analytics.trackEvent("Breadcrumbs", "click_node", String(index));
|
|
||||||
defaultDispatcher.dispatch<ViewRoomPayload>({
|
defaultDispatcher.dispatch<ViewRoomPayload>({
|
||||||
action: Action.ViewRoom,
|
action: Action.ViewRoom,
|
||||||
room_id: room.roomId,
|
room_id: room.roomId,
|
||||||
|
|
|
@ -66,7 +66,7 @@ export default class RoomUpgradeWarningBar extends React.PureComponent<IProps, I
|
||||||
};
|
};
|
||||||
|
|
||||||
private onUpgradeClick = (): void => {
|
private onUpgradeClick = (): void => {
|
||||||
Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, { room: this.props.room });
|
Modal.createDialog(RoomUpgradeDialog, { room: this.props.room });
|
||||||
};
|
};
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
|
|
|
@ -106,7 +106,7 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState
|
||||||
// Revert echo because of error
|
// Revert echo because of error
|
||||||
this.setState({ invited: true });
|
this.setState({ invited: true });
|
||||||
|
|
||||||
Modal.createTrackedDialog('Revoke 3pid invite failed', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Failed to revoke invite"),
|
title: _t("Failed to revoke invite"),
|
||||||
description: _t(
|
description: _t(
|
||||||
"Could not revoke the invite. The server may be experiencing a temporary problem or " +
|
"Could not revoke the invite. The server may be experiencing a temporary problem or " +
|
||||||
|
|
|
@ -162,7 +162,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
||||||
|
|
||||||
// The "microphone access error" dialogs are used a lot, so let's functionify them
|
// The "microphone access error" dialogs are used a lot, so let's functionify them
|
||||||
const accessError = () => {
|
const accessError = () => {
|
||||||
Modal.createTrackedDialog('Microphone Access Error', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Unable to access your microphone"),
|
title: _t("Unable to access your microphone"),
|
||||||
description: <>
|
description: <>
|
||||||
<p>{ _t(
|
<p>{ _t(
|
||||||
|
@ -177,7 +177,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
||||||
try {
|
try {
|
||||||
const devices = await MediaDeviceHandler.getDevices();
|
const devices = await MediaDeviceHandler.getDevices();
|
||||||
if (!devices?.[MediaDeviceKindEnum.AudioInput]?.length) {
|
if (!devices?.[MediaDeviceKindEnum.AudioInput]?.length) {
|
||||||
Modal.createTrackedDialog('No Microphone Error', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("No microphone found"),
|
title: _t("No microphone found"),
|
||||||
description: <>
|
description: <>
|
||||||
<p>{ _t(
|
<p>{ _t(
|
||||||
|
|
|
@ -95,7 +95,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
if (userHasOtherDevices && !serverSupportsControlOfDevicesLogout && this.props.confirm) {
|
if (userHasOtherDevices && !serverSupportsControlOfDevicesLogout && this.props.confirm) {
|
||||||
// warn about logging out all devices
|
// warn about logging out all devices
|
||||||
const { finished } = Modal.createTrackedDialog<[boolean]>('Change Password', '', QuestionDialog, {
|
const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, {
|
||||||
title: _t("Warning!"),
|
title: _t("Warning!"),
|
||||||
description:
|
description:
|
||||||
<div>
|
<div>
|
||||||
|
@ -196,14 +196,14 @@ export default class ChangePassword extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
private optionallySetEmail(): Promise<boolean> {
|
private optionallySetEmail(): Promise<boolean> {
|
||||||
// Ask for an email otherwise the user has no way to reset their password
|
// 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?'),
|
title: _t('Do you want to set an email address?'),
|
||||||
});
|
});
|
||||||
return modal.finished.then(([confirmed]) => confirmed);
|
return modal.finished.then(([confirmed]) => confirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onExportE2eKeysClicked = (): void => {
|
private onExportE2eKeysClicked = (): void => {
|
||||||
Modal.createTrackedDialogAsync('Export E2E Keys', 'Change Password',
|
Modal.createDialogAsync(
|
||||||
import(
|
import(
|
||||||
'../../../async-components/views/dialogs/security/ExportE2eKeysDialog'
|
'../../../async-components/views/dialogs/security/ExportE2eKeysDialog'
|
||||||
) as unknown as Promise<ComponentType<{}>>,
|
) as unknown as Promise<ComponentType<{}>>,
|
||||||
|
|
|
@ -75,10 +75,7 @@ export default class CrossSigningPanel extends React.PureComponent<{}, IState> {
|
||||||
|
|
||||||
private onBootstrapClick = () => {
|
private onBootstrapClick = () => {
|
||||||
if (this.state.crossSigningPrivateKeysInStorage) {
|
if (this.state.crossSigningPrivateKeysInStorage) {
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(SetupEncryptionDialog, {}, null, /* priority = */ false, /* static = */ true);
|
||||||
"Verify session", "Verify session", SetupEncryptionDialog,
|
|
||||||
{}, null, /* priority = */ false, /* static = */ true,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Trigger the flow to set up secure backup, which is what this will do when in
|
// Trigger the flow to set up secure backup, which is what this will do when in
|
||||||
// the appropriate state.
|
// the appropriate state.
|
||||||
|
@ -130,14 +127,11 @@ export default class CrossSigningPanel extends React.PureComponent<{}, IState> {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
await cli.bootstrapCrossSigning({
|
await cli.bootstrapCrossSigning({
|
||||||
authUploadDeviceSigningKeys: async (makeRequest) => {
|
authUploadDeviceSigningKeys: async (makeRequest) => {
|
||||||
const { finished } = Modal.createTrackedDialog(
|
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||||
'Cross-signing keys dialog', '', InteractiveAuthDialog,
|
|
||||||
{
|
|
||||||
title: _t("Setting up keys"),
|
title: _t("Setting up keys"),
|
||||||
matrixClient: cli,
|
matrixClient: cli,
|
||||||
makeRequest,
|
makeRequest,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
const [confirmed] = await finished;
|
const [confirmed] = await finished;
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
throw new Error("Cross-signing key upload auth canceled");
|
throw new Error("Cross-signing key upload auth canceled");
|
||||||
|
|
|
@ -91,7 +91,7 @@ export default class CryptographyPanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private onExportE2eKeysClicked = (): void => {
|
private onExportE2eKeysClicked = (): void => {
|
||||||
Modal.createTrackedDialogAsync('Export E2E Keys', '',
|
Modal.createDialogAsync(
|
||||||
import(
|
import(
|
||||||
'../../../async-components/views/dialogs/security/ExportE2eKeysDialog'
|
'../../../async-components/views/dialogs/security/ExportE2eKeysDialog'
|
||||||
) as unknown as Promise<ComponentType<{}>>,
|
) as unknown as Promise<ComponentType<{}>>,
|
||||||
|
@ -100,7 +100,7 @@ export default class CryptographyPanel extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onImportE2eKeysClicked = (): void => {
|
private onImportE2eKeysClicked = (): void => {
|
||||||
Modal.createTrackedDialogAsync('Import E2E Keys', '',
|
Modal.createDialogAsync(
|
||||||
import(
|
import(
|
||||||
'../../../async-components/views/dialogs/security/ImportE2eKeysDialog'
|
'../../../async-components/views/dialogs/security/ImportE2eKeysDialog'
|
||||||
) as unknown as Promise<ComponentType<{}>>,
|
) as unknown as Promise<ComponentType<{}>>,
|
||||||
|
|
|
@ -215,7 +215,7 @@ export default class DevicesPanel extends React.Component<IProps, IState> {
|
||||||
continueKind: "danger",
|
continueKind: "danger",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Modal.createTrackedDialog('Delete Device Dialog', '', InteractiveAuthDialog, {
|
Modal.createDialog(InteractiveAuthDialog, {
|
||||||
title: _t("Authentication"),
|
title: _t("Authentication"),
|
||||||
matrixClient: MatrixClientPeg.get(),
|
matrixClient: MatrixClientPeg.get(),
|
||||||
authData: error.data,
|
authData: error.data,
|
||||||
|
|
|
@ -84,14 +84,14 @@ export default class DevicesPanelEntry extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onOwnDeviceSignOut = (): void => {
|
private onOwnDeviceSignOut = (): void => {
|
||||||
Modal.createTrackedDialog('Logout from device list', '', LogoutDialog,
|
Modal.createDialog(LogoutDialog,
|
||||||
/* props= */{}, /* className= */null,
|
/* props= */{}, /* className= */null,
|
||||||
/* isPriority= */false, /* isStatic= */true);
|
/* isPriority= */false, /* isStatic= */true);
|
||||||
};
|
};
|
||||||
|
|
||||||
private verify = async () => {
|
private verify = async () => {
|
||||||
if (this.props.isOwnDevice) {
|
if (this.props.isOwnDevice) {
|
||||||
Modal.createTrackedDialog("Verify session", "Verify session", SetupEncryptionDialog, {
|
Modal.createDialog(SetupEncryptionDialog, {
|
||||||
onFinished: this.props.onDeviceChange,
|
onFinished: this.props.onDeviceChange,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -101,7 +101,7 @@ export default class DevicesPanelEntry extends React.Component<IProps, IState> {
|
||||||
userId,
|
userId,
|
||||||
[this.props.device.device_id],
|
[this.props.device.device_id],
|
||||||
);
|
);
|
||||||
Modal.createTrackedDialog('New Session Verification', 'Starting dialog', VerificationRequestDialog, {
|
Modal.createDialog(VerificationRequestDialog, {
|
||||||
verificationRequestPromise,
|
verificationRequestPromise,
|
||||||
member: cli.getUser(userId),
|
member: cli.getUser(userId),
|
||||||
onFinished: async () => {
|
onFinished: async () => {
|
||||||
|
|
|
@ -108,7 +108,7 @@ export default class EventIndexPanel extends React.Component<{}, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private onManage = async () => {
|
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
|
// @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...
|
// has also been converted to TS as well, but I can't figure out why...
|
||||||
import('../../../async-components/views/dialogs/eventindex/ManageEventIndexDialog'),
|
import('../../../async-components/views/dialogs/eventindex/ManageEventIndexDialog'),
|
||||||
|
|
|
@ -75,7 +75,7 @@ const JoinRuleSettings = ({ room, promptUpgrade, aliasWarning, onError, beforeCh
|
||||||
}
|
}
|
||||||
|
|
||||||
const matrixClient = MatrixClientPeg.get();
|
const matrixClient = MatrixClientPeg.get();
|
||||||
const { finished } = Modal.createTrackedDialog('Edit restricted', '', ManageRestrictedJoinRuleDialog, {
|
const { finished } = Modal.createDialog(ManageRestrictedJoinRuleDialog, {
|
||||||
matrixClient,
|
matrixClient,
|
||||||
room,
|
room,
|
||||||
selected,
|
selected,
|
||||||
|
@ -227,7 +227,7 @@ const JoinRuleSettings = ({ room, promptUpgrade, aliasWarning, onError, beforeCh
|
||||||
</b>;
|
</b>;
|
||||||
}
|
}
|
||||||
|
|
||||||
Modal.createTrackedDialog('Restricted join rule upgrade', '', RoomUpgradeWarningDialog, {
|
Modal.createDialog(RoomUpgradeWarningDialog, {
|
||||||
roomId: room.roomId,
|
roomId: room.roomId,
|
||||||
targetVersion,
|
targetVersion,
|
||||||
description: <>
|
description: <>
|
||||||
|
|
|
@ -277,7 +277,7 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private showSaveError() {
|
private showSaveError() {
|
||||||
Modal.createTrackedDialog('Error saving notification preferences', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t('Error saving notification preferences'),
|
title: _t('Error saving notification preferences'),
|
||||||
description: _t('An error occurred whilst saving your notification preferences.'),
|
description: _t('An error occurred whilst saving your notification preferences.'),
|
||||||
});
|
});
|
||||||
|
|
|
@ -120,7 +120,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.log("Failed to save profile", 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"),
|
title: _t("Failed to save your profile"),
|
||||||
description: ((err && err.message) ? err.message : _t("The operation could not be completed")),
|
description: ((err && err.message) ? err.message : _t("The operation could not be completed")),
|
||||||
});
|
});
|
||||||
|
|
|
@ -167,7 +167,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private startNewBackup = (): void => {
|
private startNewBackup = (): void => {
|
||||||
Modal.createTrackedDialogAsync('Key Backup', 'Key Backup',
|
Modal.createDialogAsync(
|
||||||
import(
|
import(
|
||||||
'../../../async-components/views/dialogs/security/CreateKeyBackupDialog'
|
'../../../async-components/views/dialogs/security/CreateKeyBackupDialog'
|
||||||
) as unknown as Promise<ComponentType<{}>>,
|
) as unknown as Promise<ComponentType<{}>>,
|
||||||
|
@ -180,7 +180,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private deleteBackup = (): void => {
|
private deleteBackup = (): void => {
|
||||||
Modal.createTrackedDialog('Delete Backup', '', QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t('Delete Backup'),
|
title: _t('Delete Backup'),
|
||||||
description: _t(
|
description: _t(
|
||||||
"Are you sure? You will lose your encrypted messages if your " +
|
"Are you sure? You will lose your encrypted messages if your " +
|
||||||
|
@ -199,10 +199,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private restoreBackup = async (): Promise<void> => {
|
private restoreBackup = async (): Promise<void> => {
|
||||||
Modal.createTrackedDialog(
|
Modal.createDialog(RestoreKeyBackupDialog, null, null, /* priority = */ false, /* static = */ true);
|
||||||
'Restore Backup', '', RestoreKeyBackupDialog, null, null,
|
|
||||||
/* priority = */ false, /* static = */ true,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private resetSecretStorage = async (): Promise<void> => {
|
private resetSecretStorage = async (): Promise<void> => {
|
||||||
|
|
|
@ -219,7 +219,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private showNoTermsWarning(fullUrl) {
|
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"),
|
title: _t("Identity server has no terms of service"),
|
||||||
description: (
|
description: (
|
||||||
<div>
|
<div>
|
||||||
|
@ -320,7 +320,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
|
||||||
message = unboundMessage;
|
message = unboundMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { finished } = Modal.createTrackedDialog('Identity Server Bound Warning', '', QuestionDialog, {
|
const { finished } = Modal.createDialog(QuestionDialog, {
|
||||||
title,
|
title,
|
||||||
description: message,
|
description: message,
|
||||||
button,
|
button,
|
||||||
|
|
|
@ -80,7 +80,7 @@ export class ExistingEmailAddress extends React.Component<IExistingEmailAddressP
|
||||||
return this.props.onRemoved(this.props.email);
|
return this.props.onRemoved(this.props.email);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
logger.error("Unable to remove contact information: " + err);
|
logger.error("Unable to remove contact information: " + err);
|
||||||
Modal.createTrackedDialog('Remove 3pid failed', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Unable to remove contact information"),
|
title: _t("Unable to remove contact information"),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
|
@ -168,7 +168,7 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
// TODO: Inline field validation
|
// TODO: Inline field validation
|
||||||
if (!Email.looksValid(email)) {
|
if (!Email.looksValid(email)) {
|
||||||
Modal.createTrackedDialog('Invalid email address', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Invalid Email Address"),
|
title: _t("Invalid Email Address"),
|
||||||
description: _t("This doesn't appear to be a valid email address"),
|
description: _t("This doesn't appear to be a valid email address"),
|
||||||
});
|
});
|
||||||
|
@ -183,7 +183,7 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
logger.error("Unable to add email address " + email + " " + err);
|
logger.error("Unable to add email address " + email + " " + err);
|
||||||
this.setState({ verifying: false, continueDisabled: false, addTask: null });
|
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"),
|
title: _t("Unable to add email address"),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
|
@ -215,14 +215,14 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
this.setState({ continueDisabled: false });
|
this.setState({ continueDisabled: false });
|
||||||
if (err.errcode === 'M_THREEPID_AUTH_FAILED') {
|
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"),
|
title: _t("Your email address hasn't been verified yet"),
|
||||||
description: _t("Click the link in the email you received to verify " +
|
description: _t("Click the link in the email you received to verify " +
|
||||||
"and then click continue again."),
|
"and then click continue again."),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
logger.error("Unable to verify email address: ", err);
|
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."),
|
title: _t("Unable to verify email address."),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
|
|
|
@ -76,7 +76,7 @@ export class ExistingPhoneNumber extends React.Component<IExistingPhoneNumberPro
|
||||||
return this.props.onRemoved(this.props.msisdn);
|
return this.props.onRemoved(this.props.msisdn);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
logger.error("Unable to remove contact information: " + err);
|
logger.error("Unable to remove contact information: " + err);
|
||||||
Modal.createTrackedDialog('Remove 3pid failed', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Unable to remove contact information"),
|
title: _t("Unable to remove contact information"),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
|
@ -185,7 +185,7 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
logger.error("Unable to add phone number " + phoneNumber + " " + err);
|
logger.error("Unable to add phone number " + phoneNumber + " " + err);
|
||||||
this.setState({ verifying: false, continueDisabled: false, addTask: null });
|
this.setState({ verifying: false, continueDisabled: false, addTask: null });
|
||||||
Modal.createTrackedDialog('Add Phone Number Error', '', ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Error"),
|
title: _t("Error"),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
|
@ -222,7 +222,7 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
|
||||||
this.setState({ continueDisabled: false });
|
this.setState({ continueDisabled: false });
|
||||||
if (err.errcode !== 'M_THREEPID_AUTH_FAILED') {
|
if (err.errcode !== 'M_THREEPID_AUTH_FAILED') {
|
||||||
logger.error("Unable to verify phone number: " + err);
|
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."),
|
title: _t("Unable to verify phone number."),
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue