From b142d72e972e39db467528ea440cb81d423fb81d Mon Sep 17 00:00:00 2001
From: RiotRobot
Date: Wed, 26 Aug 2020 11:52:28 +0100
Subject: [PATCH 01/63] Upgrade matrix-js-sdk to 8.2.0-rc.1
---
package.json | 2 +-
yarn.lock | 7 ++++---
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/package.json b/package.json
index ab71f68b08..fc24a79b48 100644
--- a/package.json
+++ b/package.json
@@ -79,7 +79,7 @@
"is-ip": "^2.0.0",
"linkifyjs": "^2.1.9",
"lodash": "^4.17.19",
- "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
+ "matrix-js-sdk": "8.2.0-rc.1",
"minimist": "^1.2.5",
"pako": "^1.0.11",
"parse5": "^5.1.1",
diff --git a/yarn.lock b/yarn.lock
index 9ee9374945..12c29e98a7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6475,9 +6475,10 @@ mathml-tag-names@^2.0.1:
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
-"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop":
- version "8.1.0"
- resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/64cdd73b93a475d10284977b69ef73138315b3be"
+matrix-js-sdk@8.2.0-rc.1:
+ version "8.2.0-rc.1"
+ resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-8.2.0-rc.1.tgz#1870ab25af7062def4b757ca5da04199df269241"
+ integrity sha512-vZTZOIoYXTFTO+NgBnP+mJMdwNwlIF8GQPeqra+esyoKcas7jVumAwektu3SXhFJPy9vnmufs7zXx4geiNNkpA==
dependencies:
"@babel/runtime" "^7.8.3"
another-json "^0.2.0"
From af76a1213d19f41ab8a41398eedec8a17de50f5e Mon Sep 17 00:00:00 2001
From: RiotRobot
Date: Wed, 26 Aug 2020 12:02:10 +0100
Subject: [PATCH 02/63] Prepare changelog for v3.3.0-rc.1
---
CHANGELOG.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 29cbb040f4..ae9027696c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,66 @@
+Changes in [3.3.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.3.0-rc.1) (2020-08-26)
+=============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.2.0...v3.3.0-rc.1)
+
+ * Upgrade to JS SDK 8.2.0-rc.1
+ * Update from Weblate
+ [\#5146](https://github.com/matrix-org/matrix-react-sdk/pull/5146)
+ * BaseAvatar avoid initial render with default avatar
+ [\#5142](https://github.com/matrix-org/matrix-react-sdk/pull/5142)
+ * Enforce Secure Backup completion when requested by HS
+ [\#5130](https://github.com/matrix-org/matrix-react-sdk/pull/5130)
+ * Communities v2 prototype: Explore rooms, global state, and default room
+ [\#5139](https://github.com/matrix-org/matrix-react-sdk/pull/5139)
+ * Add communities v2 prototyping feature flag + initial tag panel prototypes
+ [\#5133](https://github.com/matrix-org/matrix-react-sdk/pull/5133)
+ * Remove some unused components
+ [\#5134](https://github.com/matrix-org/matrix-react-sdk/pull/5134)
+ * Allow avatar image view for 1:1 rooms
+ [\#5137](https://github.com/matrix-org/matrix-react-sdk/pull/5137)
+ * Send mx_local_settings in rageshake
+ [\#5136](https://github.com/matrix-org/matrix-react-sdk/pull/5136)
+ * Run all room leaving behaviour through a single function
+ [\#5132](https://github.com/matrix-org/matrix-react-sdk/pull/5132)
+ * Add clarifying comment in media device selection
+ [\#5131](https://github.com/matrix-org/matrix-react-sdk/pull/5131)
+ * Settings v3: Feature flag changes
+ [\#5124](https://github.com/matrix-org/matrix-react-sdk/pull/5124)
+ * Clear url previews if they all get edited out of the event
+ [\#5129](https://github.com/matrix-org/matrix-react-sdk/pull/5129)
+ * Consider tab completions as modifications for editing purposes to unlock
+ sending
+ [\#5128](https://github.com/matrix-org/matrix-react-sdk/pull/5128)
+ * Use matrix-doc for SAS emoji translations
+ [\#5125](https://github.com/matrix-org/matrix-react-sdk/pull/5125)
+ * Add a rageshake function to download the logs locally
+ [\#3849](https://github.com/matrix-org/matrix-react-sdk/pull/3849)
+ * Room List filtering visual tweaks
+ [\#5123](https://github.com/matrix-org/matrix-react-sdk/pull/5123)
+ * Make reply preview not an overlay so you can see new messages
+ [\#5072](https://github.com/matrix-org/matrix-react-sdk/pull/5072)
+ * Allow room tile context menu when minimized using right click
+ [\#5113](https://github.com/matrix-org/matrix-react-sdk/pull/5113)
+ * Add null guard to group inviter for corrupted groups
+ [\#5121](https://github.com/matrix-org/matrix-react-sdk/pull/5121)
+ * Room List styling tweaks
+ [\#5118](https://github.com/matrix-org/matrix-react-sdk/pull/5118)
+ * Fix corner rounding on images not always affecting right side
+ [\#5120](https://github.com/matrix-org/matrix-react-sdk/pull/5120)
+ * Change add room action for rooms to context menu
+ [\#5108](https://github.com/matrix-org/matrix-react-sdk/pull/5108)
+ * Switch out the globe icon and colour it depending on theme
+ [\#5106](https://github.com/matrix-org/matrix-react-sdk/pull/5106)
+ * Message Action Bar watch for event send changes
+ [\#5115](https://github.com/matrix-org/matrix-react-sdk/pull/5115)
+ * Put message previews for Emoji behind Labs
+ [\#5110](https://github.com/matrix-org/matrix-react-sdk/pull/5110)
+ * Fix styling for selected community marker
+ [\#5107](https://github.com/matrix-org/matrix-react-sdk/pull/5107)
+ * Fix action bar safe area regression
+ [\#5111](https://github.com/matrix-org/matrix-react-sdk/pull/5111)
+ * Fix /op slash command
+ [\#5109](https://github.com/matrix-org/matrix-react-sdk/pull/5109)
+
Changes in [3.2.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.2.0) (2020-08-17)
===================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.2.0-rc.1...v3.2.0)
From d0358ab19640a3c369e3dd72e1be40bbc6fe2d8c Mon Sep 17 00:00:00 2001
From: RiotRobot
Date: Wed, 26 Aug 2020 12:02:11 +0100
Subject: [PATCH 03/63] v3.3.0-rc.1
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index fc24a79b48..b59c32f121 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "matrix-react-sdk",
- "version": "3.2.0",
+ "version": "3.3.0-rc.1",
"description": "SDK for matrix.org using React",
"author": "matrix.org",
"repository": {
From 2c20afc04729f157698a51471d47e4b1edd66fff Mon Sep 17 00:00:00 2001
From: resynth1943
Date: Wed, 26 Aug 2020 23:04:56 +0100
Subject: [PATCH 04/63] Fix lodash imports
Signed-off-by: resynth1943
---
src/Markdown.js | 2 +-
src/SendHistoryManager.js | 2 +-
src/autocomplete/CommunityProvider.tsx | 2 +-
src/autocomplete/RoomProvider.tsx | 3 ++-
src/components/structures/RoomSearch.tsx | 1 -
src/components/structures/SearchBox.js | 2 +-
.../views/dialogs/secretstorage/AccessSecretStorageDialog.js | 2 +-
src/components/views/elements/Field.tsx | 2 +-
src/components/views/rooms/Autocomplete.tsx | 2 +-
src/emojipicker/recent.ts | 2 +-
src/ratelimitedfunc.js | 2 +-
src/stores/CustomRoomTagStore.js | 2 +-
src/stores/OwnProfileStore.ts | 2 +-
src/stores/room-list/filters/NameFilterCondition.ts | 2 +-
src/utils/DMRoomMap.js | 2 +-
src/utils/ResizeNotifier.js | 2 +-
16 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/src/Markdown.js b/src/Markdown.js
index e57507b4de..7a573996c3 100644
--- a/src/Markdown.js
+++ b/src/Markdown.js
@@ -15,7 +15,7 @@ limitations under the License.
*/
import commonmark from 'commonmark';
-import escape from 'lodash/escape';
+import escape from "lodash/escape";
const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u'];
diff --git a/src/SendHistoryManager.js b/src/SendHistoryManager.js
index 794a58ad6f..d38227ae76 100644
--- a/src/SendHistoryManager.js
+++ b/src/SendHistoryManager.js
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import _clamp from 'lodash/clamp';
+import _clamp from "lodash/clamp";
export default class SendHistoryManager {
history: Array = [];
diff --git a/src/autocomplete/CommunityProvider.tsx b/src/autocomplete/CommunityProvider.tsx
index f34fee890e..e2baa29026 100644
--- a/src/autocomplete/CommunityProvider.tsx
+++ b/src/autocomplete/CommunityProvider.tsx
@@ -23,7 +23,7 @@ import {MatrixClientPeg} from '../MatrixClientPeg';
import QueryMatcher from './QueryMatcher';
import {PillCompletion} from './Components';
import * as sdk from '../index';
-import _sortBy from 'lodash/sortBy';
+import _sortBy from "lodash/sortBy";
import {makeGroupPermalink} from "../utils/permalinks/Permalinks";
import {ICompletion, ISelectionRange} from "./Autocompleter";
import FlairStore from "../stores/FlairStore";
diff --git a/src/autocomplete/RoomProvider.tsx b/src/autocomplete/RoomProvider.tsx
index b18b2d132c..30a322d6b1 100644
--- a/src/autocomplete/RoomProvider.tsx
+++ b/src/autocomplete/RoomProvider.tsx
@@ -27,7 +27,8 @@ import {PillCompletion} from './Components';
import * as sdk from '../index';
import {makeRoomPermalink} from "../utils/permalinks/Permalinks";
import {ICompletion, ISelectionRange} from "./Autocompleter";
-import { uniqBy, sortBy } from 'lodash';
+import uniqBy from "lodash/uniqBy";
+import sortBy from "lodash/sortBy";
const ROOM_REGEX = /\B#\S*/g;
diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx
index f6b8d42c30..fc8b7a3a12 100644
--- a/src/components/structures/RoomSearch.tsx
+++ b/src/components/structures/RoomSearch.tsx
@@ -20,7 +20,6 @@ import classNames from "classnames";
import defaultDispatcher from "../../dispatcher/dispatcher";
import { _t } from "../../languageHandler";
import { ActionPayload } from "../../dispatcher/payloads";
-import { throttle } from 'lodash';
import { Key } from "../../Keyboard";
import AccessibleButton from "../views/elements/AccessibleButton";
import { Action } from "../../dispatcher/actions";
diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js
index 7e9d290bce..ef0ee38ce6 100644
--- a/src/components/structures/SearchBox.js
+++ b/src/components/structures/SearchBox.js
@@ -20,7 +20,7 @@ import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { Key } from '../../Keyboard';
import dis from '../../dispatcher/dispatcher';
-import { throttle } from 'lodash';
+import throttle from 'lodash/throttle';
import AccessibleButton from '../../components/views/elements/AccessibleButton';
import classNames from 'classnames';
diff --git a/src/components/views/dialogs/secretstorage/AccessSecretStorageDialog.js b/src/components/views/dialogs/secretstorage/AccessSecretStorageDialog.js
index 5c01a6907f..2d556aa597 100644
--- a/src/components/views/dialogs/secretstorage/AccessSecretStorageDialog.js
+++ b/src/components/views/dialogs/secretstorage/AccessSecretStorageDialog.js
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import { debounce } from 'lodash';
+import debounce from "lodash/debounce";
import classNames from 'classnames';
import React from 'react';
import PropTypes from "prop-types";
diff --git a/src/components/views/elements/Field.tsx b/src/components/views/elements/Field.tsx
index d9fd59dc11..935d452aaa 100644
--- a/src/components/views/elements/Field.tsx
+++ b/src/components/views/elements/Field.tsx
@@ -17,7 +17,7 @@ limitations under the License.
import React, {InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes} from 'react';
import classNames from 'classnames';
import * as sdk from '../../../index';
-import { debounce } from 'lodash';
+import debounce from "lodash/debounce";
import {IFieldState, IValidationResult} from "./Validation";
// Invoke validation from user input (when typing, etc.) at most once every N ms.
diff --git a/src/components/views/rooms/Autocomplete.tsx b/src/components/views/rooms/Autocomplete.tsx
index 70f7556550..8fa623bd91 100644
--- a/src/components/views/rooms/Autocomplete.tsx
+++ b/src/components/views/rooms/Autocomplete.tsx
@@ -17,7 +17,7 @@ limitations under the License.
import React, {createRef, KeyboardEvent} from 'react';
import classNames from 'classnames';
-import flatMap from 'lodash/flatMap';
+import flatMap from "lodash/flatMap";
import {ICompletion, ISelectionRange, IProviderCompletions} from '../../../autocomplete/Autocompleter';
import {Room} from 'matrix-js-sdk/src/models/room';
diff --git a/src/emojipicker/recent.ts b/src/emojipicker/recent.ts
index d86aad660d..0f005214a3 100644
--- a/src/emojipicker/recent.ts
+++ b/src/emojipicker/recent.ts
@@ -16,7 +16,7 @@ limitations under the License.
*/
import SettingsStore from "../settings/SettingsStore";
-import {orderBy} from "lodash";
+import orderBy from "lodash/orderBy";
import { SettingLevel } from "../settings/SettingLevel";
interface ILegacyFormat {
diff --git a/src/ratelimitedfunc.js b/src/ratelimitedfunc.js
index 1f15f11d91..691671a086 100644
--- a/src/ratelimitedfunc.js
+++ b/src/ratelimitedfunc.js
@@ -26,7 +26,7 @@ limitations under the License.
* on unmount or similar to cancel any pending update.
*/
-import { throttle } from "lodash";
+import throttle from "lodash/throttle";
export default function ratelimitedfunc(fn, time) {
const throttledFn = throttle(fn, time, {
diff --git a/src/stores/CustomRoomTagStore.js b/src/stores/CustomRoomTagStore.js
index 39177181b4..ceee67c1e1 100644
--- a/src/stores/CustomRoomTagStore.js
+++ b/src/stores/CustomRoomTagStore.js
@@ -17,7 +17,7 @@ limitations under the License.
import dis from '../dispatcher/dispatcher';
import EventEmitter from 'events';
-import {throttle} from "lodash";
+import throttle from "lodash/throttle";
import SettingsStore from "../settings/SettingsStore";
import RoomListStore, {LISTS_UPDATE_EVENT} from "./room-list/RoomListStore";
import {RoomNotificationStateStore} from "./notifications/RoomNotificationStateStore";
diff --git a/src/stores/OwnProfileStore.ts b/src/stores/OwnProfileStore.ts
index 1aa761e1c4..af615b07b6 100644
--- a/src/stores/OwnProfileStore.ts
+++ b/src/stores/OwnProfileStore.ts
@@ -19,7 +19,7 @@ import { AsyncStoreWithClient } from "./AsyncStoreWithClient";
import defaultDispatcher from "../dispatcher/dispatcher";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { User } from "matrix-js-sdk/src/models/user";
-import { throttle } from "lodash";
+import throttle from "lodash/throttle";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { _t } from "../languageHandler";
diff --git a/src/stores/room-list/filters/NameFilterCondition.ts b/src/stores/room-list/filters/NameFilterCondition.ts
index 88edaecfb6..13c75f3d4d 100644
--- a/src/stores/room-list/filters/NameFilterCondition.ts
+++ b/src/stores/room-list/filters/NameFilterCondition.ts
@@ -18,7 +18,7 @@ import { Room } from "matrix-js-sdk/src/models/room";
import { FILTER_CHANGED, FilterPriority, IFilterCondition } from "./IFilterCondition";
import { EventEmitter } from "events";
import { removeHiddenChars } from "matrix-js-sdk/src/utils";
-import { throttle } from "lodash";
+import throttle from "lodash/throttle";
/**
* A filter condition for the room list which reveals rooms of a particular
diff --git a/src/utils/DMRoomMap.js b/src/utils/DMRoomMap.js
index 6ce92a0458..c6ba0d4d83 100644
--- a/src/utils/DMRoomMap.js
+++ b/src/utils/DMRoomMap.js
@@ -16,7 +16,7 @@ limitations under the License.
*/
import {MatrixClientPeg} from '../MatrixClientPeg';
-import _uniq from 'lodash/uniq';
+import _uniq from "lodash/uniq";
import {Room} from "matrix-js-sdk/src/matrix";
/**
diff --git a/src/utils/ResizeNotifier.js b/src/utils/ResizeNotifier.js
index 5467716576..c43e2c8250 100644
--- a/src/utils/ResizeNotifier.js
+++ b/src/utils/ResizeNotifier.js
@@ -23,7 +23,7 @@ limitations under the License.
* @event module:utils~ResizeNotifier#"middlePanelResizedNoisy"
*/
import { EventEmitter } from "events";
-import { throttle } from "lodash";
+import throttle from "lodash/throttle";
export default class ResizeNotifier extends EventEmitter {
constructor() {
From cc2fc911afc82915067bc6ee5790e419dd6d83dc Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Fri, 28 Aug 2020 10:03:27 -0600
Subject: [PATCH 05/63] Minor copy addition to DM dialog for communities
prototype
---
res/css/views/dialogs/_InviteDialog.scss | 7 +++++++
src/components/views/dialogs/InviteDialog.js | 10 ++++++++++
src/i18n/strings/en_EN.json | 1 +
3 files changed, 18 insertions(+)
diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss
index a77d0bfbba..a0f98d74e9 100644
--- a/res/css/views/dialogs/_InviteDialog.scss
+++ b/res/css/views/dialogs/_InviteDialog.scss
@@ -89,6 +89,13 @@ limitations under the License.
font-weight: bold;
text-transform: uppercase;
}
+
+ .mx_InviteDialog_subname {
+ margin-bottom: 10px;
+ margin-top: -10px; // HACK: Positioning with margins is bad
+ font-size: $font-12px;
+ color: $muted-fg-color;
+ }
}
.mx_InviteDialog_roomTile {
diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js
index 6cd0b22505..ba4abb31a7 100644
--- a/src/components/views/dialogs/InviteDialog.js
+++ b/src/components/views/dialogs/InviteDialog.js
@@ -37,6 +37,8 @@ import {Key} from "../../../Keyboard";
import {Action} from "../../../dispatcher/actions";
import {DefaultTagID} from "../../../stores/room-list/models";
import RoomListStore from "../../../stores/room-list/RoomListStore";
+import TagOrderStore from "../../../stores/TagOrderStore";
+import GroupStore from "../../../stores/GroupStore";
// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
/* eslint-disable camelcase */
@@ -915,6 +917,13 @@ export default class InviteDialog extends React.PureComponent {
const showMoreFn = kind === 'recents' ? this._showMoreRecents.bind(this) : this._showMoreSuggestions.bind(this);
const lastActive = (m) => kind === 'recents' ? m.lastActive : null;
let sectionName = kind === 'recents' ? _t("Recent Conversations") : _t("Suggestions");
+ let sectionSubname = null;
+
+ if (kind === 'suggestions' && TagOrderStore.getSelectedPrototypeTag()) {
+ const summary = GroupStore.getSummary(TagOrderStore.getSelectedPrototypeTag());
+ const communityName = summary?.profile?.name || TagOrderStore.getSelectedPrototypeTag();
+ sectionSubname = _t("May include members not in %(communityName)s", {communityName});
+ }
if (this.props.kind === KIND_INVITE) {
sectionName = kind === 'recents' ? _t("Recently Direct Messaged") : _t("Suggestions");
@@ -993,6 +1002,7 @@ export default class InviteDialog extends React.PureComponent {
return (
{sectionName}
+ {sectionSubname ?
{sectionSubname}
: null}
{tiles}
{showMore}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 442f07499c..2a914641f1 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -1709,6 +1709,7 @@
"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",
"Recent Conversations": "Recent Conversations",
"Suggestions": "Suggestions",
+ "May include members not in %(communityName)s": "May include members not in %(communityName)s",
"Recently Direct Messaged": "Recently Direct Messaged",
"Direct Messages": "Direct Messages",
"Start a conversation with someone using their name, username (like ) or email address.": "Start a conversation with someone using their name, username (like ) or email address.",
From 1fc55b33c1d03423395ad5d149a8796d0fe4f52b Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Fri, 28 Aug 2020 18:53:43 +0100
Subject: [PATCH 06/63] Stash lodash import optimization
---
src/Markdown.js | 2 +-
src/SendHistoryManager.js | 4 ++--
src/autocomplete/CommunityProvider.tsx | 4 ++--
src/autocomplete/EmojiProvider.tsx | 5 ++---
src/autocomplete/QueryMatcher.ts | 7 +++----
src/autocomplete/RoomProvider.tsx | 3 +--
src/autocomplete/UserProvider.tsx | 4 ++--
src/components/structures/SearchBox.js | 2 +-
.../dialogs/secretstorage/AccessSecretStorageDialog.js | 2 +-
src/components/views/elements/Field.tsx | 2 +-
src/components/views/rooms/Autocomplete.tsx | 2 +-
src/emojipicker/recent.ts | 2 +-
src/ratelimitedfunc.js | 2 +-
src/stores/CustomRoomTagStore.js | 2 +-
src/stores/OwnProfileStore.ts | 2 +-
src/stores/room-list/filters/NameFilterCondition.ts | 2 +-
src/utils/DMRoomMap.js | 4 ++--
src/utils/ResizeNotifier.js | 2 +-
18 files changed, 25 insertions(+), 28 deletions(-)
diff --git a/src/Markdown.js b/src/Markdown.js
index 7a573996c3..492450e87d 100644
--- a/src/Markdown.js
+++ b/src/Markdown.js
@@ -15,7 +15,7 @@ limitations under the License.
*/
import commonmark from 'commonmark';
-import escape from "lodash/escape";
+import {escape} from "lodash";
const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u'];
diff --git a/src/SendHistoryManager.js b/src/SendHistoryManager.js
index d38227ae76..d9955727a4 100644
--- a/src/SendHistoryManager.js
+++ b/src/SendHistoryManager.js
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import _clamp from "lodash/clamp";
+import {clamp} from "lodash";
export default class SendHistoryManager {
history: Array = [];
@@ -54,7 +54,7 @@ export default class SendHistoryManager {
}
getItem(offset: number): ?HistoryItem {
- this.currentIndex = _clamp(this.currentIndex + offset, 0, this.history.length - 1);
+ this.currentIndex = clamp(this.currentIndex + offset, 0, this.history.length - 1);
return this.history[this.currentIndex];
}
}
diff --git a/src/autocomplete/CommunityProvider.tsx b/src/autocomplete/CommunityProvider.tsx
index e2baa29026..43217cc1bb 100644
--- a/src/autocomplete/CommunityProvider.tsx
+++ b/src/autocomplete/CommunityProvider.tsx
@@ -23,7 +23,7 @@ import {MatrixClientPeg} from '../MatrixClientPeg';
import QueryMatcher from './QueryMatcher';
import {PillCompletion} from './Components';
import * as sdk from '../index';
-import _sortBy from "lodash/sortBy";
+import {sortBy} from "lodash";
import {makeGroupPermalink} from "../utils/permalinks/Permalinks";
import {ICompletion, ISelectionRange} from "./Autocompleter";
import FlairStore from "../stores/FlairStore";
@@ -81,7 +81,7 @@ export default class CommunityProvider extends AutocompleteProvider {
const matchedString = command[0];
completions = this.matcher.match(matchedString);
- completions = _sortBy(completions, [
+ completions = sortBy(completions, [
(c) => score(matchedString, c.groupId),
(c) => c.groupId.length,
]).map(({avatarUrl, groupId, name}) => ({
diff --git a/src/autocomplete/EmojiProvider.tsx b/src/autocomplete/EmojiProvider.tsx
index 147d68f5ff..1ccbc41bd6 100644
--- a/src/autocomplete/EmojiProvider.tsx
+++ b/src/autocomplete/EmojiProvider.tsx
@@ -23,8 +23,7 @@ import AutocompleteProvider from './AutocompleteProvider';
import QueryMatcher from './QueryMatcher';
import {PillCompletion} from './Components';
import {ICompletion, ISelectionRange} from './Autocompleter';
-import _uniq from 'lodash/uniq';
-import _sortBy from 'lodash/sortBy';
+import {uniq, sortBy} from 'lodash';
import SettingsStore from "../settings/SettingsStore";
import { shortcodeToUnicode } from '../HtmlUtils';
import { EMOJI, IEmoji } from '../emoji';
@@ -115,7 +114,7 @@ export default class EmojiProvider extends AutocompleteProvider {
}
// Finally, sort by original ordering
sorters.push((c) => c._orderBy);
- completions = _sortBy(_uniq(completions), sorters);
+ completions = sortBy(uniq(completions), sorters);
completions = completions.map(({shortname}) => {
const unicode = shortcodeToUnicode(shortname);
diff --git a/src/autocomplete/QueryMatcher.ts b/src/autocomplete/QueryMatcher.ts
index 9c91414556..a07ed29c7e 100644
--- a/src/autocomplete/QueryMatcher.ts
+++ b/src/autocomplete/QueryMatcher.ts
@@ -16,8 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import _at from 'lodash/at';
-import _uniq from 'lodash/uniq';
+import {at, uniq} from 'lodash';
import {removeHiddenChars} from "matrix-js-sdk/src/utils";
interface IOptions {
@@ -73,7 +72,7 @@ export default class QueryMatcher {
// type for their values. We assume that those values who's keys have
// been specified will be string. Also, we cannot infer all the
// types of the keys of the objects at compile.
- const keyValues = _at(object, this._options.keys);
+ const keyValues = at(object, this._options.keys);
if (this._options.funcs) {
for (const f of this._options.funcs) {
@@ -137,7 +136,7 @@ export default class QueryMatcher {
});
// Now map the keys to the result objects. Also remove any duplicates.
- return _uniq(matches.map((match) => match.object));
+ return uniq(matches.map((match) => match.object));
}
private processQuery(query: string): string {
diff --git a/src/autocomplete/RoomProvider.tsx b/src/autocomplete/RoomProvider.tsx
index 30a322d6b1..de16e68e01 100644
--- a/src/autocomplete/RoomProvider.tsx
+++ b/src/autocomplete/RoomProvider.tsx
@@ -27,8 +27,7 @@ import {PillCompletion} from './Components';
import * as sdk from '../index';
import {makeRoomPermalink} from "../utils/permalinks/Permalinks";
import {ICompletion, ISelectionRange} from "./Autocompleter";
-import uniqBy from "lodash/uniqBy";
-import sortBy from "lodash/sortBy";
+import {uniqBy, sortBy} from "lodash";
const ROOM_REGEX = /\B#\S*/g;
diff --git a/src/autocomplete/UserProvider.tsx b/src/autocomplete/UserProvider.tsx
index c957b5e597..d592421ef2 100644
--- a/src/autocomplete/UserProvider.tsx
+++ b/src/autocomplete/UserProvider.tsx
@@ -23,7 +23,7 @@ import AutocompleteProvider from './AutocompleteProvider';
import {PillCompletion} from './Components';
import * as sdk from '../index';
import QueryMatcher from './QueryMatcher';
-import _sortBy from 'lodash/sortBy';
+import {sortBy} from 'lodash';
import {MatrixClientPeg} from '../MatrixClientPeg';
import MatrixEvent from "matrix-js-sdk/src/models/event";
@@ -151,7 +151,7 @@ export default class UserProvider extends AutocompleteProvider {
const currentUserId = MatrixClientPeg.get().credentials.userId;
this.users = this.room.getJoinedMembers().filter(({userId}) => userId !== currentUserId);
- this.users = _sortBy(this.users, (member) => 1E20 - lastSpoken[member.userId] || 1E20);
+ this.users = sortBy(this.users, (member) => 1E20 - lastSpoken[member.userId] || 1E20);
this.matcher.setObjects(this.users);
}
diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js
index ef0ee38ce6..e4befee863 100644
--- a/src/components/structures/SearchBox.js
+++ b/src/components/structures/SearchBox.js
@@ -20,7 +20,7 @@ import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { Key } from '../../Keyboard';
import dis from '../../dispatcher/dispatcher';
-import throttle from 'lodash/throttle';
+import {throttle} from 'lodash';
import AccessibleButton from '../../components/views/elements/AccessibleButton';
import classNames from 'classnames';
diff --git a/src/components/views/dialogs/secretstorage/AccessSecretStorageDialog.js b/src/components/views/dialogs/secretstorage/AccessSecretStorageDialog.js
index 2d556aa597..85ace249a3 100644
--- a/src/components/views/dialogs/secretstorage/AccessSecretStorageDialog.js
+++ b/src/components/views/dialogs/secretstorage/AccessSecretStorageDialog.js
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import debounce from "lodash/debounce";
+import {debounce} from "lodash";
import classNames from 'classnames';
import React from 'react';
import PropTypes from "prop-types";
diff --git a/src/components/views/elements/Field.tsx b/src/components/views/elements/Field.tsx
index 935d452aaa..8c4e6aed31 100644
--- a/src/components/views/elements/Field.tsx
+++ b/src/components/views/elements/Field.tsx
@@ -17,7 +17,7 @@ limitations under the License.
import React, {InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes} from 'react';
import classNames from 'classnames';
import * as sdk from '../../../index';
-import debounce from "lodash/debounce";
+import {debounce} from "lodash";
import {IFieldState, IValidationResult} from "./Validation";
// Invoke validation from user input (when typing, etc.) at most once every N ms.
diff --git a/src/components/views/rooms/Autocomplete.tsx b/src/components/views/rooms/Autocomplete.tsx
index 8fa623bd91..15af75084a 100644
--- a/src/components/views/rooms/Autocomplete.tsx
+++ b/src/components/views/rooms/Autocomplete.tsx
@@ -17,7 +17,7 @@ limitations under the License.
import React, {createRef, KeyboardEvent} from 'react';
import classNames from 'classnames';
-import flatMap from "lodash/flatMap";
+import {flatMap} from "lodash";
import {ICompletion, ISelectionRange, IProviderCompletions} from '../../../autocomplete/Autocompleter';
import {Room} from 'matrix-js-sdk/src/models/room';
diff --git a/src/emojipicker/recent.ts b/src/emojipicker/recent.ts
index 0f005214a3..d86aad660d 100644
--- a/src/emojipicker/recent.ts
+++ b/src/emojipicker/recent.ts
@@ -16,7 +16,7 @@ limitations under the License.
*/
import SettingsStore from "../settings/SettingsStore";
-import orderBy from "lodash/orderBy";
+import {orderBy} from "lodash";
import { SettingLevel } from "../settings/SettingLevel";
interface ILegacyFormat {
diff --git a/src/ratelimitedfunc.js b/src/ratelimitedfunc.js
index 691671a086..3df3db615e 100644
--- a/src/ratelimitedfunc.js
+++ b/src/ratelimitedfunc.js
@@ -26,7 +26,7 @@ limitations under the License.
* on unmount or similar to cancel any pending update.
*/
-import throttle from "lodash/throttle";
+import {throttle} from "lodash";
export default function ratelimitedfunc(fn, time) {
const throttledFn = throttle(fn, time, {
diff --git a/src/stores/CustomRoomTagStore.js b/src/stores/CustomRoomTagStore.js
index ceee67c1e1..39177181b4 100644
--- a/src/stores/CustomRoomTagStore.js
+++ b/src/stores/CustomRoomTagStore.js
@@ -17,7 +17,7 @@ limitations under the License.
import dis from '../dispatcher/dispatcher';
import EventEmitter from 'events';
-import throttle from "lodash/throttle";
+import {throttle} from "lodash";
import SettingsStore from "../settings/SettingsStore";
import RoomListStore, {LISTS_UPDATE_EVENT} from "./room-list/RoomListStore";
import {RoomNotificationStateStore} from "./notifications/RoomNotificationStateStore";
diff --git a/src/stores/OwnProfileStore.ts b/src/stores/OwnProfileStore.ts
index af615b07b6..1aa761e1c4 100644
--- a/src/stores/OwnProfileStore.ts
+++ b/src/stores/OwnProfileStore.ts
@@ -19,7 +19,7 @@ import { AsyncStoreWithClient } from "./AsyncStoreWithClient";
import defaultDispatcher from "../dispatcher/dispatcher";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { User } from "matrix-js-sdk/src/models/user";
-import throttle from "lodash/throttle";
+import { throttle } from "lodash";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { _t } from "../languageHandler";
diff --git a/src/stores/room-list/filters/NameFilterCondition.ts b/src/stores/room-list/filters/NameFilterCondition.ts
index 13c75f3d4d..88edaecfb6 100644
--- a/src/stores/room-list/filters/NameFilterCondition.ts
+++ b/src/stores/room-list/filters/NameFilterCondition.ts
@@ -18,7 +18,7 @@ import { Room } from "matrix-js-sdk/src/models/room";
import { FILTER_CHANGED, FilterPriority, IFilterCondition } from "./IFilterCondition";
import { EventEmitter } from "events";
import { removeHiddenChars } from "matrix-js-sdk/src/utils";
-import throttle from "lodash/throttle";
+import { throttle } from "lodash";
/**
* A filter condition for the room list which reveals rooms of a particular
diff --git a/src/utils/DMRoomMap.js b/src/utils/DMRoomMap.js
index c6ba0d4d83..4e219b1611 100644
--- a/src/utils/DMRoomMap.js
+++ b/src/utils/DMRoomMap.js
@@ -16,7 +16,7 @@ limitations under the License.
*/
import {MatrixClientPeg} from '../MatrixClientPeg';
-import _uniq from "lodash/uniq";
+import {uniq} from "lodash";
import {Room} from "matrix-js-sdk/src/matrix";
/**
@@ -111,7 +111,7 @@ export default class DMRoomMap {
userToRooms[userId] = [roomId];
} else {
roomIds.push(roomId);
- userToRooms[userId] = _uniq(roomIds);
+ userToRooms[userId] = uniq(roomIds);
}
});
return true;
diff --git a/src/utils/ResizeNotifier.js b/src/utils/ResizeNotifier.js
index c43e2c8250..5467716576 100644
--- a/src/utils/ResizeNotifier.js
+++ b/src/utils/ResizeNotifier.js
@@ -23,7 +23,7 @@ limitations under the License.
* @event module:utils~ResizeNotifier#"middlePanelResizedNoisy"
*/
import { EventEmitter } from "events";
-import throttle from "lodash/throttle";
+import { throttle } from "lodash";
export default class ResizeNotifier extends EventEmitter {
constructor() {
From e58b514803d934005434ae1745fcfddb677d73d3 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Fri, 28 Aug 2020 13:22:20 -0600
Subject: [PATCH 07/63] Add clarifying text to DM dialog about what is about to
happen
---
res/css/views/dialogs/_InviteDialog.scss | 4 ++++
src/RoomInvite.js | 20 +++++++++++++++++
src/components/views/dialogs/InviteDialog.js | 23 +++++++++++++++++++-
src/i18n/strings/en_EN.json | 1 +
4 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss
index a0f98d74e9..b9063f46b9 100644
--- a/res/css/views/dialogs/_InviteDialog.scss
+++ b/res/css/views/dialogs/_InviteDialog.scss
@@ -233,3 +233,7 @@ limitations under the License.
.mx_InviteDialog_addressBar {
margin-right: 45px;
}
+
+.mx_InviteDialog_helpText .mx_AccessibleButton_kind_link {
+ padding: 0;
+}
diff --git a/src/RoomInvite.js b/src/RoomInvite.js
index 420561ea41..408b4c9c6c 100644
--- a/src/RoomInvite.js
+++ b/src/RoomInvite.js
@@ -24,6 +24,8 @@ import * as sdk from './';
import { _t } from './languageHandler';
import {KIND_DM, KIND_INVITE} from "./components/views/dialogs/InviteDialog";
import CommunityPrototypeInviteDialog from "./components/views/dialogs/CommunityPrototypeInviteDialog";
+import GroupStore from "./stores/GroupStore";
+import dis from "./dispatcher/dispatcher";
/**
* Invites multiple addresses to a room
@@ -64,6 +66,24 @@ export function showCommunityRoomInviteDialog(roomId, communityName) {
);
}
+export function showCommunityInviteDialog(communityId) {
+ const rooms = GroupStore.getGroupRooms(communityId)
+ .map(r => MatrixClientPeg.get().getRoom(r.roomId))
+ .filter(r => !!r);
+ let chat = rooms.find(r => {
+ const idState = r.currentState.getStateEvents("im.vector.general_chat", "");
+ if (!idState || idState.getContent()['groupId'] !== communityId) return false;
+ return true;
+ });
+ if (!chat) chat = rooms[0];
+ if (chat) {
+ const summary = GroupStore.getSummary(communityId);
+ showCommunityRoomInviteDialog(chat.roomId, summary?.profile?.name || communityId);
+ } else {
+ throw new Error("Failed to locate appropriate room to start an invite in");
+ }
+}
+
/**
* Checks if the given MatrixEvent is a valid 3rd party user invite.
* @param {MatrixEvent} event The event to check
diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js
index ba4abb31a7..b70f2fee10 100644
--- a/src/components/views/dialogs/InviteDialog.js
+++ b/src/components/views/dialogs/InviteDialog.js
@@ -32,7 +32,7 @@ import IdentityAuthClient from "../../../IdentityAuthClient";
import Modal from "../../../Modal";
import {humanizeTime} from "../../../utils/humanize";
import createRoom, {canEncryptToAllUsers, privateShouldBeEncrypted} from "../../../createRoom";
-import {inviteMultipleToRoom} from "../../../RoomInvite";
+import {inviteMultipleToRoom, showCommunityInviteDialog} from "../../../RoomInvite";
import {Key} from "../../../Keyboard";
import {Action} from "../../../dispatcher/actions";
import {DefaultTagID} from "../../../stores/room-list/models";
@@ -911,6 +911,11 @@ export default class InviteDialog extends React.PureComponent {
this.props.onFinished();
};
+ _onCommunityInviteClick = (e) => {
+ this.props.onFinished();
+ showCommunityInviteDialog(TagOrderStore.getSelectedPrototypeTag());
+ };
+
_renderSection(kind: "recents"|"suggestions") {
let sourceMembers = kind === 'recents' ? this.state.recents : this.state.suggestions;
let showNum = kind === 'recents' ? this.state.numRecentsShown : this.state.numSuggestionsShown;
@@ -1093,6 +1098,22 @@ export default class InviteDialog extends React.PureComponent {
return {userId} ;
}},
);
+ if (TagOrderStore.getSelectedPrototypeTag()) {
+ const communityId = TagOrderStore.getSelectedPrototypeTag();
+ const communityName = GroupStore.getSummary(communityId)?.profile?.name || communityId;
+ helpText = _t(
+ "Start a conversation with someone using their name, username (like ) or email address. " +
+ "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here .",
+ {communityName}, {
+ userId: () => {
+ return {userId} ;
+ },
+ a: (sub) => {
+ return {sub}
+ },
+ },
+ )
+ }
buttonText = _t("Go");
goButtonFn = this._startDm;
} else { // KIND_INVITE
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 2a914641f1..0d01fd47c8 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -1713,6 +1713,7 @@
"Recently Direct Messaged": "Recently Direct Messaged",
"Direct Messages": "Direct Messages",
"Start a conversation with someone using their name, username (like ) or email address.": "Start a conversation with someone using their name, username (like ) or email address.",
+ "Start a conversation with someone using their name, username (like ) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here .": "Start a conversation with someone using their name, username (like ) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here .",
"Go": "Go",
"Invite someone using their name, username (like ), email address or share this room .": "Invite someone using their name, username (like ), email address or share this room .",
"a new master key signature": "a new master key signature",
From 6f237161fd841ee181fd38bfd3b8452020494c05 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Fri, 28 Aug 2020 13:28:54 -0600
Subject: [PATCH 08/63] Appease the linter
---
src/components/views/dialogs/InviteDialog.js | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js
index b70f2fee10..934ed12ac1 100644
--- a/src/components/views/dialogs/InviteDialog.js
+++ b/src/components/views/dialogs/InviteDialog.js
@@ -1103,16 +1103,28 @@ export default class InviteDialog extends React.PureComponent {
const communityName = GroupStore.getSummary(communityId)?.profile?.name || communityId;
helpText = _t(
"Start a conversation with someone using their name, username (like ) or email address. " +
- "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here .",
+ "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click " +
+ "here .",
{communityName}, {
userId: () => {
- return {userId} ;
+ return (
+ {userId}
+ );
},
a: (sub) => {
- return {sub}
+ return (
+ {sub}
+ );
},
},
- )
+ );
}
buttonText = _t("Go");
goButtonFn = this._startDm;
From fb54b62be99ba4ae1f2c2a2bf9ffd448aeab72a2 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Fri, 28 Aug 2020 13:42:19 -0600
Subject: [PATCH 09/63] Appease the rest of the linter
---
src/RoomInvite.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/RoomInvite.js b/src/RoomInvite.js
index 408b4c9c6c..cae4501901 100644
--- a/src/RoomInvite.js
+++ b/src/RoomInvite.js
@@ -25,7 +25,6 @@ import { _t } from './languageHandler';
import {KIND_DM, KIND_INVITE} from "./components/views/dialogs/InviteDialog";
import CommunityPrototypeInviteDialog from "./components/views/dialogs/CommunityPrototypeInviteDialog";
import GroupStore from "./stores/GroupStore";
-import dis from "./dispatcher/dispatcher";
/**
* Invites multiple addresses to a room
From 90d9d7128d2ccd7767aee6a8ef4053f38174fdd4 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Fri, 28 Aug 2020 14:56:59 -0600
Subject: [PATCH 10/63] Use FlairStore's cache for group naming
Turns out GroupStore doesn't really know much.
---
src/RoomInvite.js | 4 ++--
src/components/views/dialogs/CreateRoomDialog.js | 5 ++---
src/components/views/dialogs/InviteDialog.js | 8 +++-----
src/stores/CommunityPrototypeStore.ts | 11 +++++++++++
src/stores/FlairStore.js | 16 ++++++++++++++++
5 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/src/RoomInvite.js b/src/RoomInvite.js
index cae4501901..7f2eec32f3 100644
--- a/src/RoomInvite.js
+++ b/src/RoomInvite.js
@@ -76,8 +76,8 @@ export function showCommunityInviteDialog(communityId) {
});
if (!chat) chat = rooms[0];
if (chat) {
- const summary = GroupStore.getSummary(communityId);
- showCommunityRoomInviteDialog(chat.roomId, summary?.profile?.name || communityId);
+ const name = CommunityPrototypeInviteDialog.instance.getCommunityName(communityId);
+ showCommunityRoomInviteDialog(chat.roomId, name);
} else {
throw new Error("Failed to locate appropriate room to start an invite in");
}
diff --git a/src/components/views/dialogs/CreateRoomDialog.js b/src/components/views/dialogs/CreateRoomDialog.js
index 4890626527..bdd3de07c0 100644
--- a/src/components/views/dialogs/CreateRoomDialog.js
+++ b/src/components/views/dialogs/CreateRoomDialog.js
@@ -26,7 +26,7 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg';
import {Key} from "../../../Keyboard";
import {privateShouldBeEncrypted} from "../../../createRoom";
import TagOrderStore from "../../../stores/TagOrderStore";
-import GroupStore from "../../../stores/GroupStore";
+import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
export default createReactClass({
displayName: 'CreateRoomDialog',
@@ -240,8 +240,7 @@ export default createReactClass({
let title = this.state.isPublic ? _t('Create a public room') : _t('Create a private room');
if (TagOrderStore.getSelectedPrototypeTag()) {
- const summary = GroupStore.getSummary(TagOrderStore.getSelectedPrototypeTag());
- const name = summary?.profile?.name || TagOrderStore.getSelectedPrototypeTag();
+ const name = CommunityPrototypeStore.instance.getSelectedCommunityName();
title = _t("Create a room in %(communityName)s", {communityName: name});
}
return (
diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js
index 934ed12ac1..c2fd7e5b0e 100644
--- a/src/components/views/dialogs/InviteDialog.js
+++ b/src/components/views/dialogs/InviteDialog.js
@@ -38,7 +38,7 @@ import {Action} from "../../../dispatcher/actions";
import {DefaultTagID} from "../../../stores/room-list/models";
import RoomListStore from "../../../stores/room-list/RoomListStore";
import TagOrderStore from "../../../stores/TagOrderStore";
-import GroupStore from "../../../stores/GroupStore";
+import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
/* eslint-disable camelcase */
@@ -925,8 +925,7 @@ export default class InviteDialog extends React.PureComponent {
let sectionSubname = null;
if (kind === 'suggestions' && TagOrderStore.getSelectedPrototypeTag()) {
- const summary = GroupStore.getSummary(TagOrderStore.getSelectedPrototypeTag());
- const communityName = summary?.profile?.name || TagOrderStore.getSelectedPrototypeTag();
+ const communityName = CommunityPrototypeStore.instance.getCommunityName(TagOrderStore.getSelectedPrototypeTag());
sectionSubname = _t("May include members not in %(communityName)s", {communityName});
}
@@ -1099,8 +1098,7 @@ export default class InviteDialog extends React.PureComponent {
}},
);
if (TagOrderStore.getSelectedPrototypeTag()) {
- const communityId = TagOrderStore.getSelectedPrototypeTag();
- const communityName = GroupStore.getSummary(communityId)?.profile?.name || communityId;
+ const communityName = CommunityPrototypeStore.instance.getSelectedCommunityName();
helpText = _t(
"Start a conversation with someone using their name, username (like ) or email address. " +
"This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click " +
diff --git a/src/stores/CommunityPrototypeStore.ts b/src/stores/CommunityPrototypeStore.ts
index 581f8a97c8..eec0a8aab8 100644
--- a/src/stores/CommunityPrototypeStore.ts
+++ b/src/stores/CommunityPrototypeStore.ts
@@ -22,6 +22,8 @@ import { EffectiveMembership, getEffectiveMembership } from "../utils/membership
import SettingsStore from "../settings/SettingsStore";
import * as utils from "matrix-js-sdk/src/utils";
import { UPDATE_EVENT } from "./AsyncStore";
+import FlairStore from "./FlairStore";
+import TagOrderStore from "./TagOrderStore";
interface IState {
// nothing of value - we use account data
@@ -43,6 +45,15 @@ export class CommunityPrototypeStore extends AsyncStoreWithClient {
return CommunityPrototypeStore.internalInstance;
}
+ public getSelectedCommunityName(): string {
+ return CommunityPrototypeStore.instance.getCommunityName(TagOrderStore.getSelectedPrototypeTag());
+ }
+
+ public getCommunityName(communityId: string): string {
+ const profile = FlairStore.getGroupProfileCachedFast(this.matrixClient, communityId);
+ return profile?.name || communityId;
+ }
+
protected async onAction(payload: ActionPayload): Promise {
if (!this.matrixClient || !SettingsStore.getValue("feature_communities_v2_prototypes")) {
return;
diff --git a/src/stores/FlairStore.js b/src/stores/FlairStore.js
index 94b81c1ba5..10a4d96921 100644
--- a/src/stores/FlairStore.js
+++ b/src/stores/FlairStore.js
@@ -148,6 +148,22 @@ class FlairStore extends EventEmitter {
});
}
+ /**
+ * Gets the profile for the given group if known, otherwise returns null.
+ * This triggers `getGroupProfileCached` if needed, though the result of the
+ * call will not be returned by this function.
+ * @param matrixClient The matrix client to use to fetch the profile, if needed.
+ * @param groupId The group ID to get the profile for.
+ * @returns The profile if known, otherwise null.
+ */
+ getGroupProfileCachedFast(matrixClient, groupId) {
+ if (this._groupProfiles[groupId]) {
+ return this._groupProfiles[groupId];
+ }
+ this.getGroupProfileCached(matrixClient, groupId);
+ return null;
+ }
+
async getGroupProfileCached(matrixClient, groupId) {
if (this._groupProfiles[groupId]) {
return this._groupProfiles[groupId];
From 0ffa5488647a29682fe91391126eee3d2703ba09 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Fri, 28 Aug 2020 15:37:23 -0600
Subject: [PATCH 11/63] Change the menu button to a chevron
by design request
---
res/css/structures/_UserMenu.scss | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/res/css/structures/_UserMenu.scss b/res/css/structures/_UserMenu.scss
index 78795c85a2..b4e3a08e18 100644
--- a/res/css/structures/_UserMenu.scss
+++ b/res/css/structures/_UserMenu.scss
@@ -16,7 +16,7 @@ limitations under the License.
.mx_UserMenu {
- // to make the ... button sort of aligned with the explore button below
+ // to make the menu button sort of aligned with the explore button below
padding-right: 6px;
.mx_UserMenu_headerButtons {
@@ -36,7 +36,7 @@ limitations under the License.
mask-size: contain;
mask-repeat: no-repeat;
background: $primary-fg-color;
- mask-image: url('$(res)/img/element-icons/context-menu.svg');
+ mask-image: url('$(res)/img/feather-customised/chevron-down.svg');
}
}
From 01b0acbe62c2ad2d3113df7d92957ce33b55cb9c Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Fri, 28 Aug 2020 16:14:08 -0600
Subject: [PATCH 12/63] Make the UserMenu echo the current community name
---
res/css/structures/_UserMenu.scss | 46 ++++++++++++++++++++++++++
src/components/structures/UserMenu.tsx | 35 +++++++++++++++++++-
src/i18n/strings/en_EN.json | 1 +
3 files changed, 81 insertions(+), 1 deletion(-)
diff --git a/res/css/structures/_UserMenu.scss b/res/css/structures/_UserMenu.scss
index b4e3a08e18..08fb1f49f0 100644
--- a/res/css/structures/_UserMenu.scss
+++ b/res/css/structures/_UserMenu.scss
@@ -19,6 +19,30 @@ limitations under the License.
// to make the menu button sort of aligned with the explore button below
padding-right: 6px;
+ &.mx_UserMenu_prototype {
+ // The margin & padding combination between here and the ::after is to
+ // align the border line with the tag panel.
+ margin-bottom: 6px;
+
+ padding-right: 0; // make the right edge line up with the explore button
+
+ .mx_UserMenu_headerButtons {
+ // considering we've eliminated right padding on the menu itself, we need to
+ // push the chevron in slightly (roughly lining up with the center of the
+ // plus buttons)
+ margin-right: 2px;
+ }
+
+ // we cheat opacity on the theme colour with an after selector here
+ &::after {
+ content: '';
+ border-bottom: 1px solid $roomsublist-divider-color;
+ opacity: 0.2;
+ display: block;
+ padding-top: 8px;
+ }
+ }
+
.mx_UserMenu_headerButtons {
width: 16px;
height: 16px;
@@ -56,6 +80,28 @@ limitations under the License.
}
}
+ .mx_UserMenu_doubleName {
+ flex: 1;
+ min-width: 0; // make flexbox aware that it can crush this to a tiny width
+
+ .mx_UserMenu_userName,
+ .mx_UserMenu_subUserName {
+ display: block;
+ }
+
+ .mx_UserMenu_subUserName {
+ color: $muted-fg-color;
+ font-size: $font-13px;
+ line-height: $font-18px;
+ flex: 1;
+
+ // Ellipsize any text overflow
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ }
+ }
+
.mx_UserMenu_userName {
font-weight: 600;
font-size: $font-15px;
diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx
index 30be71abcb..a1039f23b9 100644
--- a/src/components/structures/UserMenu.tsx
+++ b/src/components/structures/UserMenu.tsx
@@ -42,6 +42,9 @@ import IconizedContextMenu, {
IconizedContextMenuOption,
IconizedContextMenuOptionList
} from "../views/context_menus/IconizedContextMenu";
+import { CommunityPrototypeStore } from "../../stores/CommunityPrototypeStore";
+import * as fbEmitter from "fbemitter";
+import TagOrderStore from "../../stores/TagOrderStore";
interface IProps {
isMinimized: boolean;
@@ -58,6 +61,7 @@ export default class UserMenu extends React.Component {
private dispatcherRef: string;
private themeWatcherRef: string;
private buttonRef: React.RefObject = createRef();
+ private tagStoreRef: fbEmitter.EventSubscription;
constructor(props: IProps) {
super(props);
@@ -77,14 +81,20 @@ export default class UserMenu extends React.Component {
public componentDidMount() {
this.dispatcherRef = defaultDispatcher.register(this.onAction);
this.themeWatcherRef = SettingsStore.watchSetting("theme", null, this.onThemeChanged);
+ this.tagStoreRef = TagOrderStore.addListener(this.onTagStoreUpdate);
}
public componentWillUnmount() {
if (this.themeWatcherRef) SettingsStore.unwatchSetting(this.themeWatcherRef);
if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef);
OwnProfileStore.instance.off(UPDATE_EVENT, this.onProfileUpdate);
+ this.tagStoreRef.remove();
}
+ private onTagStoreUpdate = () => {
+ this.forceUpdate(); // we don't have anything useful in state to update
+ };
+
private isUserOnDarkTheme(): boolean {
const theme = SettingsStore.getValue("theme");
if (theme.startsWith("custom-")) {
@@ -298,12 +308,34 @@ export default class UserMenu extends React.Component {
const displayName = OwnProfileStore.instance.displayName || MatrixClientPeg.get().getUserId();
const avatarUrl = OwnProfileStore.instance.getHttpAvatarUrl(avatarSize);
+ const prototypeCommunityName = CommunityPrototypeStore.instance.getSelectedCommunityName();
+
+ let isPrototype = false;
+ let menuName = _t("User menu");
let name = {displayName} ;
let buttons = (
{/* masked image in CSS */}
);
+ if (prototypeCommunityName) {
+ name = (
+
+ {prototypeCommunityName}
+ {displayName}
+
+ );
+ menuName = _t("Community and user menu");
+ isPrototype = true;
+ } else if (SettingsStore.getValue("feature_communities_v2_prototypes")) {
+ name = (
+
+ {_t("Home")}
+ {displayName}
+
+ );
+ isPrototype = true;
+ }
if (this.props.isMinimized) {
name = null;
buttons = null;
@@ -312,6 +344,7 @@ export default class UserMenu extends React.Component {
const classes = classNames({
'mx_UserMenu': true,
'mx_UserMenu_minimized': this.props.isMinimized,
+ 'mx_UserMenu_prototype': isPrototype,
});
return (
@@ -320,7 +353,7 @@ export default class UserMenu extends React.Component {
className={classes}
onClick={this.onOpenMenuClick}
inputRef={this.buttonRef}
- label={_t("User menu")}
+ label={menuName}
isExpanded={!!this.state.contextMenuPosition}
onContextMenu={this.onContextMenu}
>
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 0d01fd47c8..3589c2ba76 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -2129,6 +2129,7 @@
"All settings": "All settings",
"Feedback": "Feedback",
"User menu": "User menu",
+ "Community and user menu": "Community and user menu",
"Could not load user profile": "Could not load user profile",
"Verify this login": "Verify this login",
"Session verified": "Session verified",
From 02095389e7b82ceeaba192e6099689d93eada97d Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Fri, 28 Aug 2020 17:03:17 -0600
Subject: [PATCH 13/63] Add structure for mixed prototype UserMenu
---
res/css/structures/_UserMenu.scss | 46 ++++++
src/components/structures/UserMenu.tsx | 197 +++++++++++++++++++------
src/i18n/strings/en_EN.json | 6 +-
3 files changed, 199 insertions(+), 50 deletions(-)
diff --git a/res/css/structures/_UserMenu.scss b/res/css/structures/_UserMenu.scss
index 08fb1f49f0..8c944935ed 100644
--- a/res/css/structures/_UserMenu.scss
+++ b/res/css/structures/_UserMenu.scss
@@ -135,6 +135,44 @@ limitations under the License.
.mx_UserMenu_contextMenu {
width: 247px;
+ // These override the styles already present on the user menu rather than try to
+ // define a new menu. They are specifically for the stacked menu when a community
+ // is being represented as a prototype.
+ &.mx_UserMenu_contextMenu_prototype {
+ padding-bottom: 16px;
+
+ .mx_UserMenu_contextMenu_header {
+ padding-bottom: 0;
+ padding-top: 16px;
+
+ &:nth-child(n + 2) {
+ padding-top: 8px;
+ }
+ }
+
+ hr {
+ width: 85%;
+ opacity: 0.2;
+ border: none;
+ border-bottom: 1px solid $roomsublist-divider-color;
+ }
+
+ &.mx_IconizedContextMenu {
+ > .mx_IconizedContextMenu_optionList {
+ margin-top: 4px;
+
+ &::before {
+ border: none;
+ }
+
+ > .mx_AccessibleButton {
+ padding-top: 2px;
+ padding-bottom: 2px;
+ }
+ }
+ }
+ }
+
&.mx_IconizedContextMenu .mx_IconizedContextMenu_optionList_red {
.mx_AccessibleButton {
padding-top: 16px;
@@ -239,4 +277,12 @@ limitations under the License.
.mx_UserMenu_iconSignOut::before {
mask-image: url('$(res)/img/element-icons/leave.svg');
}
+
+ .mx_UserMenu_iconMembers::before {
+ mask-image: url('$(res)/img/element-icons/room/members.svg');
+ }
+
+ .mx_UserMenu_iconInvite::before {
+ mask-image: url('$(res)/img/element-icons/room/invite.svg');
+ }
}
diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx
index a1039f23b9..5db5371842 100644
--- a/src/components/structures/UserMenu.tsx
+++ b/src/components/structures/UserMenu.tsx
@@ -199,9 +199,32 @@ export default class UserMenu extends React.Component {
defaultDispatcher.dispatch({action: 'view_home_page'});
};
+ private onCommunitySettingsClick = (ev: ButtonEvent) => {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ console.log("TODO@onCommunitySettingsClick");
+ };
+
+ private onCommunityMembersClick = (ev: ButtonEvent) => {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ console.log("TODO@onCommunityMembersClick");
+ };
+
+ private onCommunityInviteClick = (ev: ButtonEvent) => {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ console.log("TODO@onCommunityInviteClick");
+ };
+
private renderContextMenu = (): React.ReactNode => {
if (!this.state.contextMenuPosition) return null;
+ const prototypeCommunityName = CommunityPrototypeStore.instance.getSelectedCommunityName();
+
let hostingLink;
const signupLink = getHostingLink("user-context-menu");
if (signupLink) {
@@ -235,22 +258,135 @@ export default class UserMenu extends React.Component {
);
}
+ let primaryHeader = (
+
+
+ {OwnProfileStore.instance.displayName}
+
+
+ {MatrixClientPeg.get().getUserId()}
+
+
+ );
+ let primaryOptionList = (
+
+
+ {homeButton}
+ this.onSettingsOpen(e, USER_NOTIFICATIONS_TAB)}
+ />
+ this.onSettingsOpen(e, USER_SECURITY_TAB)}
+ />
+ this.onSettingsOpen(e, null)}
+ />
+ {/* */}
+
+
+
+
+
+
+ );
+ let secondarySection = null;
+
+ if (prototypeCommunityName) {
+ primaryHeader = (
+
+
+ {prototypeCommunityName}
+
+
+ );
+ primaryOptionList = (
+
+
+
+
+
+ );
+ secondarySection = (
+
+
+
+
+
+ {OwnProfileStore.instance.displayName}
+
+
+ {MatrixClientPeg.get().getUserId()}
+
+
+
+
+ this.onSettingsOpen(e, null)}
+ />
+
+
+
+
+
+
+ )
+ }
+
+ const classes = classNames({
+ "mx_UserMenu_contextMenu": true,
+ "mx_UserMenu_contextMenu_prototype": !!prototypeCommunityName,
+ });
+
return
-
-
- {OwnProfileStore.instance.displayName}
-
-
- {MatrixClientPeg.get().getUserId()}
-
-
+ {primaryHeader}
{
{hostingLink}
-
- {homeButton}
- this.onSettingsOpen(e, USER_NOTIFICATIONS_TAB)}
- />
- this.onSettingsOpen(e, USER_SECURITY_TAB)}
- />
- this.onSettingsOpen(e, null)}
- />
- {/* */}
-
-
-
-
-
+ {primaryOptionList}
+ {secondarySection}
;
};
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 3589c2ba76..39b6061f27 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -2121,13 +2121,13 @@
"Uploading %(filename)s and %(count)s others|other": "Uploading %(filename)s and %(count)s others",
"Uploading %(filename)s and %(count)s others|zero": "Uploading %(filename)s",
"Uploading %(filename)s and %(count)s others|one": "Uploading %(filename)s and %(count)s other",
- "Switch to light mode": "Switch to light mode",
- "Switch to dark mode": "Switch to dark mode",
- "Switch theme": "Switch theme",
"Notification settings": "Notification settings",
"Security & privacy": "Security & privacy",
"All settings": "All settings",
"Feedback": "Feedback",
+ "Switch to light mode": "Switch to light mode",
+ "Switch to dark mode": "Switch to dark mode",
+ "Switch theme": "Switch theme",
"User menu": "User menu",
"Community and user menu": "Community and user menu",
"Could not load user profile": "Could not load user profile",
From 9ba33c7f80e3c812825415923994eaf98181524f Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 29 Aug 2020 01:11:08 +0100
Subject: [PATCH 14/63] Fix eslint ts override tsx matching and delint
---
.eslintrc.js | 2 +-
src/ContentMessages.tsx | 20 ++++---
src/HtmlUtils.tsx | 11 +++-
src/Modal.tsx | 8 +--
src/SlashCommands.tsx | 14 ++---
src/accessibility/KeyboardShortcuts.tsx | 2 +-
src/accessibility/RovingTabIndex.tsx | 2 +-
src/accessibility/Toolbar.tsx | 3 +-
.../context_menu/ContextMenuTooltipButton.tsx | 2 +-
.../roving/RovingAccessibleTooltipButton.tsx | 3 +-
.../roving/RovingTabIndexWrapper.tsx | 1 -
src/autocomplete/CommandProvider.tsx | 6 ++-
src/autocomplete/CommunityProvider.tsx | 12 ++---
src/autocomplete/Components.tsx | 12 ++---
src/autocomplete/EmojiProvider.tsx | 6 ++-
src/autocomplete/RoomProvider.tsx | 4 +-
src/autocomplete/UserProvider.tsx | 15 ++++--
src/components/structures/ContextMenu.tsx | 3 +-
src/components/structures/LeftPanel.tsx | 2 +-
src/components/structures/LoggedInView.tsx | 37 +++++++------
src/components/structures/MatrixChat.tsx | 17 +++---
src/components/structures/RoomSearch.tsx | 3 +-
src/components/structures/TabbedView.tsx | 1 -
src/components/structures/UserMenu.tsx | 12 ++---
src/components/views/avatars/BaseAvatar.tsx | 4 +-
.../views/avatars/DecoratedRoomAvatar.tsx | 2 +-
src/components/views/avatars/GroupAvatar.tsx | 2 +-
src/components/views/avatars/PulsedAvatar.tsx | 2 +-
.../CommunityPrototypeInviteDialog.tsx | 52 ++++++++-----------
.../CreateCommunityPrototypeDialog.tsx | 10 +++-
src/components/views/dialogs/ShareDialog.tsx | 20 +++----
src/components/views/elements/Draggable.tsx | 4 +-
.../views/elements/EventTilePreview.tsx | 14 +++--
src/components/views/elements/Field.tsx | 6 +--
.../elements/IRCTimelineProfileResizer.tsx | 7 ++-
src/components/views/elements/InfoTooltip.tsx | 1 -
src/components/views/elements/QRCode.tsx | 2 +-
src/components/views/elements/Slider.tsx | 19 ++++---
.../views/elements/StyledCheckbox.tsx | 7 ++-
.../views/right_panel/EncryptionInfo.tsx | 6 ++-
.../views/right_panel/HeaderButtons.tsx | 16 +++---
.../views/right_panel/VerificationPanel.tsx | 23 ++++----
.../views/rooms/NotificationBadge.tsx | 1 +
src/components/views/rooms/RoomList.tsx | 32 ++++++------
src/components/views/rooms/RoomSublist.tsx | 25 +++++----
src/components/views/rooms/RoomTile.tsx | 6 +--
src/components/views/rooms/TemporaryTile.tsx | 2 -
.../views/settings/UpdateCheckButton.tsx | 2 +-
.../tabs/user/AppearanceUserSettingsTab.tsx | 4 +-
.../views/toasts/GenericExpiringToast.tsx | 10 +++-
src/components/views/toasts/GenericToast.tsx | 8 ++-
src/components/views/voip/CallView.tsx | 5 +-
src/components/views/voip/IncomingCallBox.tsx | 3 +-
src/languageHandler.tsx | 6 +--
54 files changed, 268 insertions(+), 231 deletions(-)
diff --git a/.eslintrc.js b/.eslintrc.js
index fc82e75ce2..bc2a142c2d 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -19,7 +19,7 @@ module.exports = {
},
overrides: [{
- "files": ["src/**/*.{ts, tsx}"],
+ "files": ["src/**/*.{ts,tsx}"],
"extends": ["matrix-org/ts"],
"rules": {
// We disable this while we're transitioning
diff --git a/src/ContentMessages.tsx b/src/ContentMessages.tsx
index 6f55a75d0c..eb8fff0eb1 100644
--- a/src/ContentMessages.tsx
+++ b/src/ContentMessages.tsx
@@ -70,6 +70,7 @@ interface IContent {
interface IThumbnail {
info: {
+ // eslint-disable-next-line camelcase
thumbnail_info: {
w: number;
h: number;
@@ -104,7 +105,12 @@ interface IAbortablePromise extends Promise {
* @return {Promise} A promise that resolves with an object with an info key
* and a thumbnail key.
*/
-function createThumbnail(element: ThumbnailableElement, inputWidth: number, inputHeight: number, mimeType: string): Promise {
+function createThumbnail(
+ element: ThumbnailableElement,
+ inputWidth: number,
+ inputHeight: number,
+ mimeType: string,
+): Promise {
return new Promise((resolve) => {
let targetWidth = inputWidth;
let targetHeight = inputHeight;
@@ -437,11 +443,13 @@ export default class ContentMessages {
for (let i = 0; i < okFiles.length; ++i) {
const file = okFiles[i];
if (!uploadAll) {
- const {finished} = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation', '', UploadConfirmDialog, {
- file,
- currentIndex: i,
- totalFiles: okFiles.length,
- });
+ const {finished} = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation',
+ '', UploadConfirmDialog, {
+ file,
+ currentIndex: i,
+ totalFiles: okFiles.length,
+ },
+ );
const [shouldContinue, shouldUploadAll] = await finished;
if (!shouldContinue) break;
if (shouldUploadAll) {
diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx
index 5d33645bb7..2ce9e40aa6 100644
--- a/src/HtmlUtils.tsx
+++ b/src/HtmlUtils.tsx
@@ -339,6 +339,7 @@ class HtmlHighlighter extends BaseHighlighter {
}
}
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
class TextHighlighter extends BaseHighlighter {
private key = 0;
@@ -366,6 +367,7 @@ class TextHighlighter extends BaseHighlighter {
interface IContent {
format?: string;
+ // eslint-disable-next-line camelcase
formatted_body?: string;
body: string;
}
@@ -474,8 +476,13 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts
});
return isDisplayedWithHtml ?
- :
- { strippedBody } ;
+ : { strippedBody } ;
}
/**
diff --git a/src/Modal.tsx b/src/Modal.tsx
index 82ed33b794..0a36813961 100644
--- a/src/Modal.tsx
+++ b/src/Modal.tsx
@@ -151,7 +151,7 @@ export class ModalManager {
prom: Promise,
props?: IProps,
className?: string,
- options?: IOptions
+ options?: IOptions,
) {
const modal: IModal = {
onFinished: props ? props.onFinished : null,
@@ -182,7 +182,7 @@ export class ModalManager {
private getCloseFn(
modal: IModal,
- props: IProps
+ props: IProps,
): [IHandle["close"], IHandle["finished"]] {
const deferred = defer();
return [async (...args: T) => {
@@ -264,7 +264,7 @@ export class ModalManager {
className?: string,
isPriorityModal = false,
isStaticModal = false,
- options: IOptions = {}
+ options: IOptions = {},
): IHandle {
const {modal, closeDialog, onFinishedProm} = this.buildModal(prom, props, className, options);
if (isPriorityModal) {
@@ -287,7 +287,7 @@ export class ModalManager {
private appendDialogAsync(
prom: Promise,
props?: IProps,
- className?: string
+ className?: string,
): IHandle {
const {modal, closeDialog, onFinishedProm} = this.buildModal(prom, props, className, {});
diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx
index d674634109..661ab74e6f 100644
--- a/src/SlashCommands.tsx
+++ b/src/SlashCommands.tsx
@@ -860,12 +860,12 @@ export const Commands = [
_t('WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session' +
' %(deviceId)s is "%(fprint)s" which does not match the provided key ' +
'"%(fingerprint)s". This could mean your communications are being intercepted!',
- {
- fprint,
- userId,
- deviceId,
- fingerprint,
- }));
+ {
+ fprint,
+ userId,
+ deviceId,
+ fingerprint,
+ }));
}
await cli.setDeviceVerified(userId, deviceId, true);
@@ -879,7 +879,7 @@ export const Commands = [
{
_t('The signing key you provided matches the signing key you received ' +
'from %(userId)s\'s session %(deviceId)s. Session marked as verified.',
- {userId, deviceId})
+ {userId, deviceId})
}
,
diff --git a/src/accessibility/KeyboardShortcuts.tsx b/src/accessibility/KeyboardShortcuts.tsx
index f527ab4a14..58d8124122 100644
--- a/src/accessibility/KeyboardShortcuts.tsx
+++ b/src/accessibility/KeyboardShortcuts.tsx
@@ -168,7 +168,7 @@ const shortcuts: Record = {
key: Key.U,
}],
description: _td("Upload a file"),
- }
+ },
],
[Categories.ROOM_LIST]: [
diff --git a/src/accessibility/RovingTabIndex.tsx b/src/accessibility/RovingTabIndex.tsx
index 5a650d4b6e..b1dbb56a01 100644
--- a/src/accessibility/RovingTabIndex.tsx
+++ b/src/accessibility/RovingTabIndex.tsx
@@ -190,7 +190,7 @@ export const RovingTabIndexProvider: React.FC = ({children, handleHomeEn
ev.preventDefault();
ev.stopPropagation();
} else if (onKeyDown) {
- return onKeyDown(ev, state);
+ return onKeyDown(ev, context.state);
}
}, [context.state, onKeyDown, handleHomeEnd]);
diff --git a/src/accessibility/Toolbar.tsx b/src/accessibility/Toolbar.tsx
index 0e968461a8..cc2a1769c7 100644
--- a/src/accessibility/Toolbar.tsx
+++ b/src/accessibility/Toolbar.tsx
@@ -30,6 +30,7 @@ const Toolbar: React.FC = ({children, ...props}) => {
const target = ev.target as HTMLElement;
let handled = true;
+ // HOME and END are handled by RovingTabIndexProvider
switch (ev.key) {
case Key.ARROW_UP:
case Key.ARROW_DOWN:
@@ -47,8 +48,6 @@ const Toolbar: React.FC = ({children, ...props}) => {
}
break;
- // HOME and END are handled by RovingTabIndexProvider
-
default:
handled = false;
}
diff --git a/src/accessibility/context_menu/ContextMenuTooltipButton.tsx b/src/accessibility/context_menu/ContextMenuTooltipButton.tsx
index abc5412100..49f57ca7b6 100644
--- a/src/accessibility/context_menu/ContextMenuTooltipButton.tsx
+++ b/src/accessibility/context_menu/ContextMenuTooltipButton.tsx
@@ -20,7 +20,7 @@ import React from "react";
import AccessibleTooltipButton from "../../components/views/elements/AccessibleTooltipButton";
-interface IProps extends React.ComponentProps {
+interface IProps extends React.ComponentProps {
// whether or not the context menu is currently open
isExpanded: boolean;
}
diff --git a/src/accessibility/roving/RovingAccessibleTooltipButton.tsx b/src/accessibility/roving/RovingAccessibleTooltipButton.tsx
index cc824fef22..2cb974d60e 100644
--- a/src/accessibility/roving/RovingAccessibleTooltipButton.tsx
+++ b/src/accessibility/roving/RovingAccessibleTooltipButton.tsx
@@ -20,7 +20,8 @@ import AccessibleTooltipButton from "../../components/views/elements/AccessibleT
import {useRovingTabIndex} from "../RovingTabIndex";
import {Ref} from "./types";
-interface IProps extends Omit, "onFocus" | "inputRef" | "tabIndex"> {
+type ATBProps = React.ComponentProps;
+interface IProps extends Omit {
inputRef?: Ref;
}
diff --git a/src/accessibility/roving/RovingTabIndexWrapper.tsx b/src/accessibility/roving/RovingTabIndexWrapper.tsx
index c826b74497..5211f30215 100644
--- a/src/accessibility/roving/RovingTabIndexWrapper.tsx
+++ b/src/accessibility/roving/RovingTabIndexWrapper.tsx
@@ -16,7 +16,6 @@ limitations under the License.
import React from "react";
-import AccessibleButton from "../../components/views/elements/AccessibleButton";
import {useRovingTabIndex} from "../RovingTabIndex";
import {FocusHandler, Ref} from "./types";
diff --git a/src/autocomplete/CommandProvider.tsx b/src/autocomplete/CommandProvider.tsx
index e7a6f44536..3ff8ff0469 100644
--- a/src/autocomplete/CommandProvider.tsx
+++ b/src/autocomplete/CommandProvider.tsx
@@ -89,7 +89,11 @@ export default class CommandProvider extends AutocompleteProvider {
renderCompletions(completions: React.ReactNode[]): React.ReactNode {
return (
-
+
{ completions }
);
diff --git a/src/autocomplete/CommunityProvider.tsx b/src/autocomplete/CommunityProvider.tsx
index f34fee890e..031fcd6169 100644
--- a/src/autocomplete/CommunityProvider.tsx
+++ b/src/autocomplete/CommunityProvider.tsx
@@ -91,15 +91,15 @@ export default class CommunityProvider extends AutocompleteProvider {
href: makeGroupPermalink(groupId),
component: (
-
+
),
range,
- }))
- .slice(0, 4);
+ })).slice(0, 4);
}
return completions;
}
diff --git a/src/autocomplete/Components.tsx b/src/autocomplete/Components.tsx
index 6ac2f4db14..4b0d35698d 100644
--- a/src/autocomplete/Components.tsx
+++ b/src/autocomplete/Components.tsx
@@ -34,9 +34,9 @@ export const TextualCompletion = forwardRef
((props
const {title, subtitle, description, className, ...restProps} = props;
return (
{ title }
{ subtitle }
@@ -53,9 +53,9 @@ export const PillCompletion = forwardRef
((props, ref)
const {title, subtitle, description, className, children, ...restProps} = props;
return (
{ children }
{ title }
diff --git a/src/autocomplete/EmojiProvider.tsx b/src/autocomplete/EmojiProvider.tsx
index 147d68f5ff..eaca42b0dd 100644
--- a/src/autocomplete/EmojiProvider.tsx
+++ b/src/autocomplete/EmojiProvider.tsx
@@ -139,7 +139,11 @@ export default class EmojiProvider extends AutocompleteProvider {
renderCompletions(completions: React.ReactNode[]): React.ReactNode {
return (
-
+
{ completions }
);
diff --git a/src/autocomplete/RoomProvider.tsx b/src/autocomplete/RoomProvider.tsx
index b18b2d132c..defbc8c47f 100644
--- a/src/autocomplete/RoomProvider.tsx
+++ b/src/autocomplete/RoomProvider.tsx
@@ -110,9 +110,7 @@ export default class RoomProvider extends AutocompleteProvider {
),
range,
};
- })
- .filter((completion) => !!completion.completion && completion.completion.length > 0)
- .slice(0, 4);
+ }).filter((completion) => !!completion.completion && completion.completion.length > 0).slice(0, 4);
}
return completions;
}
diff --git a/src/autocomplete/UserProvider.tsx b/src/autocomplete/UserProvider.tsx
index c957b5e597..3bde4b1d07 100644
--- a/src/autocomplete/UserProvider.tsx
+++ b/src/autocomplete/UserProvider.tsx
@@ -71,8 +71,13 @@ export default class UserProvider extends AutocompleteProvider {
}
}
- private onRoomTimeline = (ev: MatrixEvent, room: Room, toStartOfTimeline: boolean, removed: boolean,
- data: IRoomTimelineData) => {
+ private onRoomTimeline = (
+ ev: MatrixEvent,
+ room: Room,
+ toStartOfTimeline: boolean,
+ removed: boolean,
+ data: IRoomTimelineData,
+ ) => {
if (!room) return;
if (removed) return;
if (room.roomId !== this.room.roomId) return;
@@ -171,7 +176,11 @@ export default class UserProvider extends AutocompleteProvider {
renderCompletions(completions: React.ReactNode[]): React.ReactNode {
return (
-
+
{ completions }
);
diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx
index 587ae2cb6b..64e0160d83 100644
--- a/src/components/structures/ContextMenu.tsx
+++ b/src/components/structures/ContextMenu.tsx
@@ -233,8 +233,7 @@ export class ContextMenu extends React.PureComponent
{
switch (ev.key) {
case Key.TAB:
case Key.ESCAPE:
- // close on left and right arrows too for when it is a context menu on a
- case Key.ARROW_LEFT:
+ case Key.ARROW_LEFT: // close on left and right arrows too for when it is a context menu on a
case Key.ARROW_RIGHT:
this.props.onFinished();
break;
diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx
index 899dfe222d..1c2295384c 100644
--- a/src/components/structures/LeftPanel.tsx
+++ b/src/components/structures/LeftPanel.tsx
@@ -377,7 +377,7 @@ export default class LeftPanel extends React.Component {
public render(): React.ReactNode {
const tagPanel = !this.state.showTagPanel ? null : (
-
+
{SettingsStore.getValue("feature_custom_tags") ? : null}
);
diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx
index d7f2c73a0b..e427eb92cb 100644
--- a/src/components/structures/LoggedInView.tsx
+++ b/src/components/structures/LoggedInView.tsx
@@ -43,11 +43,11 @@ import PlatformPeg from "../../PlatformPeg";
import { DefaultTagID } from "../../stores/room-list/models";
import {
showToast as showSetPasswordToast,
- hideToast as hideSetPasswordToast
+ hideToast as hideSetPasswordToast,
} from "../../toasts/SetPasswordToast";
import {
showToast as showServerLimitToast,
- hideToast as hideServerLimitToast
+ hideToast as hideServerLimitToast,
} from "../../toasts/ServerLimitToast";
import { Action } from "../../dispatcher/actions";
import LeftPanel from "./LeftPanel";
@@ -79,6 +79,7 @@ interface IProps {
initialEventPixelOffset: number;
leftDisabled: boolean;
rightDisabled: boolean;
+ // eslint-disable-next-line camelcase
page_type: string;
autoJoin: boolean;
thirdPartyInvite?: object;
@@ -98,7 +99,9 @@ interface IProps {
}
interface IUsageLimit {
+ // eslint-disable-next-line camelcase
limit_type: "monthly_active_user" | string;
+ // eslint-disable-next-line camelcase
admin_contact?: string;
}
@@ -316,10 +319,10 @@ class LoggedInView extends React.Component {
}
};
- _calculateServerLimitToast(syncErrorData: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) {
- const error = syncErrorData && syncErrorData.error && syncErrorData.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED";
+ _calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) {
+ const error = syncError && syncError.error && syncError.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED";
if (error) {
- usageLimitEventContent = syncErrorData.error.data;
+ usageLimitEventContent = syncError.error.data;
}
if (usageLimitEventContent) {
@@ -620,18 +623,18 @@ class LoggedInView extends React.Component {
switch (this.props.page_type) {
case PageTypes.RoomView:
pageElement = ;
+ ref={this._roomView}
+ autoJoin={this.props.autoJoin}
+ onRegistered={this.props.onRegistered}
+ thirdPartyInvite={this.props.thirdPartyInvite}
+ oobData={this.props.roomOobData}
+ viaServers={this.props.viaServers}
+ eventPixelOffset={this.props.initialEventPixelOffset}
+ key={this.props.currentRoomId || 'roomview'}
+ disabled={this.props.middleDisabled}
+ ConferenceHandler={this.props.ConferenceHandler}
+ resizeNotifier={this.props.resizeNotifier}
+ />;
break;
case PageTypes.MyGroups:
diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx
index 9d51062b7d..176aaf95a3 100644
--- a/src/components/structures/MatrixChat.tsx
+++ b/src/components/structures/MatrixChat.tsx
@@ -69,7 +69,7 @@ import { ViewUserPayload } from "../../dispatcher/payloads/ViewUserPayload";
import { Action } from "../../dispatcher/actions";
import {
showToast as showAnalyticsToast,
- hideToast as hideAnalyticsToast
+ hideToast as hideAnalyticsToast,
} from "../../toasts/AnalyticsToast";
import {showToast as showNotificationsToast} from "../../toasts/DesktopNotificationsToast";
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
@@ -129,6 +129,7 @@ interface IScreen {
params?: object;
}
+/* eslint-disable camelcase */
interface IRoomInfo {
room_id?: string;
room_alias?: string;
@@ -140,6 +141,7 @@ interface IRoomInfo {
oob_data?: object;
via_servers?: string[];
}
+/* eslint-enable camelcase */
interface IProps { // TODO type things better
config: Record;
@@ -165,6 +167,7 @@ interface IState {
// the master view we are showing.
view: Views;
// What the LoggedInView would be showing if visible
+ // eslint-disable-next-line camelcase
page_type?: PageTypes;
// The ID of the room we're viewing. This is either populated directly
// in the case where we view a room by ID or by RoomView when it resolves
@@ -180,8 +183,11 @@ interface IState {
middleDisabled: boolean;
// the right panel's disabled state is tracked in its store.
// Parameters used in the registration dance with the IS
+ // eslint-disable-next-line camelcase
register_client_secret?: string;
+ // eslint-disable-next-line camelcase
register_session_id?: string;
+ // eslint-disable-next-line camelcase
register_id_sid?: string;
// When showing Modal dialogs we need to set aria-hidden on the root app element
// and disable it when there are no dialogs
@@ -341,6 +347,7 @@ export default class MatrixChat extends React.PureComponent {
}
// TODO: [REACT-WARNING] Replace with appropriate lifecycle stage
+ // eslint-disable-next-line camelcase
UNSAFE_componentWillUpdate(props, state) {
if (this.shouldTrackPageChange(this.state, state)) {
this.startPageChangeTimer();
@@ -610,8 +617,7 @@ export default class MatrixChat extends React.PureComponent {
const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog");
Modal.createTrackedDialog('User settings', '', UserSettingsDialog,
{initialTabId: tabPayload.initialTabId},
- /*className=*/null, /*isPriority=*/false, /*isStatic=*/true
- );
+ /*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
// View the welcome or home page if we need something to look at
this.viewSomethingBehindModal();
@@ -1080,7 +1086,7 @@ export default class MatrixChat extends React.PureComponent {
title: _t("Leave room"),
description: (
- { _t("Are you sure you want to leave the room '%(roomName)s'?", {roomName: roomToLeave.name}) }
+ { _t("Are you sure you want to leave the room '%(roomName)s'?", {roomName: roomToLeave.name}) }
{ warnings }
),
@@ -1433,7 +1439,6 @@ export default class MatrixChat extends React.PureComponent {
cli.on("crypto.warning", (type) => {
switch (type) {
case 'CRYPTO_WARNING_OLD_VERSION_DETECTED':
- const brand = SdkConfig.get().brand;
Modal.createTrackedDialog('Crypto migrated', '', ErrorDialog, {
title: _t('Old cryptography data detected'),
description: _t(
@@ -1444,7 +1449,7 @@ export default class MatrixChat extends React.PureComponent {
"in this version. This may also cause messages exchanged with this " +
"version to fail. If you experience problems, log out and back in " +
"again. To retain message history, export and re-import your keys.",
- { brand },
+ { brand: SdkConfig.get().brand },
),
});
break;
diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx
index f6b8d42c30..768bc38d23 100644
--- a/src/components/structures/RoomSearch.tsx
+++ b/src/components/structures/RoomSearch.tsx
@@ -20,7 +20,6 @@ import classNames from "classnames";
import defaultDispatcher from "../../dispatcher/dispatcher";
import { _t } from "../../languageHandler";
import { ActionPayload } from "../../dispatcher/payloads";
-import { throttle } from 'lodash';
import { Key } from "../../Keyboard";
import AccessibleButton from "../views/elements/AccessibleButton";
import { Action } from "../../dispatcher/actions";
@@ -137,7 +136,7 @@ export default class RoomSearch extends React.PureComponent {
});
let icon = (
-
+
);
let input = (
{
>
-
- {OwnProfileStore.instance.displayName}
-
+
+ {OwnProfileStore.instance.displayName}
+
- {MatrixClientPeg.get().getUserId()}
-
+ {MatrixClientPeg.get().getUserId()}
+
{
urls,
width = 40,
height = 40,
- resizeMethod = "crop", // eslint-disable-line no-unused-vars
+ resizeMethod = "crop", // eslint-disable-line @typescript-eslint/no-unused-vars
defaultToInitialLetter = true,
onClick,
inputRef,
diff --git a/src/components/views/avatars/DecoratedRoomAvatar.tsx b/src/components/views/avatars/DecoratedRoomAvatar.tsx
index e6dadf676c..d7e012467b 100644
--- a/src/components/views/avatars/DecoratedRoomAvatar.tsx
+++ b/src/components/views/avatars/DecoratedRoomAvatar.tsx
@@ -126,7 +126,7 @@ export default class DecoratedRoomAvatar extends React.PureComponent {
if (this.isUnmounted) return;
- let newIcon = this.getPresenceIcon();
+ const newIcon = this.getPresenceIcon();
if (newIcon !== this.state.icon) this.setState({icon: newIcon});
};
diff --git a/src/components/views/avatars/GroupAvatar.tsx b/src/components/views/avatars/GroupAvatar.tsx
index e55e2e6fac..51327605c0 100644
--- a/src/components/views/avatars/GroupAvatar.tsx
+++ b/src/components/views/avatars/GroupAvatar.tsx
@@ -47,7 +47,7 @@ export default class GroupAvatar extends React.Component {
render() {
// extract the props we use from props so we can pass any others through
// should consider adding this as a global rule in js-sdk?
- /*eslint no-unused-vars: ["error", { "ignoreRestSiblings": true }]*/
+ /* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */
const {groupId, groupAvatarUrl, groupName, ...otherProps} = this.props;
return (
diff --git a/src/components/views/avatars/PulsedAvatar.tsx b/src/components/views/avatars/PulsedAvatar.tsx
index 94a6c87687..b4e876b9f6 100644
--- a/src/components/views/avatars/PulsedAvatar.tsx
+++ b/src/components/views/avatars/PulsedAvatar.tsx
@@ -25,4 +25,4 @@ const PulsedAvatar: React.FC = (props) => {
;
};
-export default PulsedAvatar;
\ No newline at end of file
+export default PulsedAvatar;
diff --git a/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx b/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx
index 7a500cd053..4a454c8cbb 100644
--- a/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx
+++ b/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx
@@ -21,9 +21,6 @@ import { IDialogProps } from "./IDialogProps";
import Field from "../elements/Field";
import AccessibleButton from "../elements/AccessibleButton";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
-import InfoTooltip from "../elements/InfoTooltip";
-import dis from "../../../dispatcher/dispatcher";
-import {showCommunityRoomInviteDialog} from "../../../RoomInvite";
import { arrayFastClone } from "../../../utils/arrays";
import SdkConfig from "../../../SdkConfig";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
@@ -31,7 +28,6 @@ import InviteDialog from "./InviteDialog";
import BaseAvatar from "../avatars/BaseAvatar";
import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo";
import {inviteMultipleToRoom, showAnyInviteErrors} from "../../../RoomInvite";
-import {humanizeTime} from "../../../utils/humanize";
import StyledCheckbox from "../elements/StyledCheckbox";
import Modal from "../../../Modal";
import ErrorDialog from "./ErrorDialog";
@@ -171,44 +167,38 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent<
public render() {
const emailAddresses = [];
this.state.emailTargets.forEach((address, i) => {
- emailAddresses.push(
- this.onAddressChange(e, i)}
- label={_t("Email address")}
- placeholder={_t("Email address")}
- onBlur={() => this.onAddressBlur(i)}
- />
- );
+ emailAddresses.push( this.onAddressChange(e, i)}
+ label={_t("Email address")}
+ placeholder={_t("Email address")}
+ onBlur={() => this.onAddressBlur(i)}
+ />);
});
// Push a clean input
- emailAddresses.push(
- this.onAddressChange(e, emailAddresses.length)}
- label={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
- placeholder={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
- />
- );
+ emailAddresses.push( this.onAddressChange(e, emailAddresses.length)}
+ label={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
+ placeholder={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
+ />);
let peopleIntro = null;
- let people = [];
+ const people = [];
if (this.state.showPeople) {
const humansToPresent = this.state.people.slice(0, this.state.numPeople);
humansToPresent.forEach((person, i) => {
people.push(this.renderPerson(person, i));
});
if (humansToPresent.length < this.state.people.length) {
- people.push(
- {_t("Show more")}
- );
+ people.push({_t("Show more")} );
}
}
if (this.state.people.length > 0) {
diff --git a/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx b/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx
index 58412c23d6..dbfc208583 100644
--- a/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx
+++ b/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx
@@ -164,7 +164,10 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
);
if (this.state.error) {
helpText = (
-
+
{this.state.error}
);
@@ -205,7 +208,10 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
ref={this.avatarUploadRef} accept="image/*"
onChange={this.onAvatarChanged}
/>
-
+
{preview}
diff --git a/src/components/views/dialogs/ShareDialog.tsx b/src/components/views/dialogs/ShareDialog.tsx
index 22f83d391c..e849f7efe3 100644
--- a/src/components/views/dialogs/ShareDialog.tsx
+++ b/src/components/views/dialogs/ShareDialog.tsx
@@ -186,8 +186,8 @@ export default class ShareDialog extends React.PureComponent
{
title = _t('Share Room Message');
checkbox =
{ _t('Link to selected message') }
@@ -198,16 +198,18 @@ export default class ShareDialog extends React.PureComponent
{
const encodedUrl = encodeURIComponent(matrixToUrl);
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
- return
-
{ matrixToUrl }
diff --git a/src/components/views/elements/Draggable.tsx b/src/components/views/elements/Draggable.tsx
index 3397fd901c..a6eb8323f3 100644
--- a/src/components/views/elements/Draggable.tsx
+++ b/src/components/views/elements/Draggable.tsx
@@ -34,7 +34,6 @@ export interface ILocationState {
}
export default class Draggable extends React.Component
{
-
constructor(props: IProps) {
super(props);
@@ -77,5 +76,4 @@ export default class Draggable extends React.Component {
render() {
return
;
}
-
-}
\ No newline at end of file
+}
diff --git a/src/components/views/elements/EventTilePreview.tsx b/src/components/views/elements/EventTilePreview.tsx
index 7d8b774955..98f6850e6b 100644
--- a/src/components/views/elements/EventTilePreview.tsx
+++ b/src/components/views/elements/EventTilePreview.tsx
@@ -39,6 +39,7 @@ interface IProps {
className: string;
}
+/* eslint-disable camelcase */
interface IState {
userId: string;
displayname: string;
@@ -72,7 +73,6 @@ export default class EventTilePreview extends React.Component {
displayname: profileInfo.displayname,
avatar_url,
});
-
}
private fakeEvent({userId, displayname, avatar_url}: IState) {
@@ -114,16 +114,14 @@ export default class EventTilePreview extends React.Component {
public render() {
const event = this.fakeEvent(this.state);
- let className = classnames(
- this.props.className,
- {
- "mx_IRCLayout": this.props.useIRCLayout,
- "mx_GroupLayout": !this.props.useIRCLayout,
- }
- );
+ const className = classnames(this.props.className, {
+ "mx_IRCLayout": this.props.useIRCLayout,
+ "mx_GroupLayout": !this.props.useIRCLayout,
+ });
return
;
}
}
+/* eslint-enable camelcase */
diff --git a/src/components/views/elements/Field.tsx b/src/components/views/elements/Field.tsx
index d9fd59dc11..d2869f68c8 100644
--- a/src/components/views/elements/Field.tsx
+++ b/src/components/views/elements/Field.tsx
@@ -198,11 +198,9 @@ export default class Field extends React.PureComponent {
}
}
-
-
public render() {
- const {
- element, prefixComponent, postfixComponent, className, onValidate, children,
+ /* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */
+ const { element, prefixComponent, postfixComponent, className, onValidate, children,
tooltipContent, forceValidity, tooltipClassName, list, ...inputProps} = this.props;
// Set some defaults for the element
diff --git a/src/components/views/elements/IRCTimelineProfileResizer.tsx b/src/components/views/elements/IRCTimelineProfileResizer.tsx
index 1098d0293e..ecd63816de 100644
--- a/src/components/views/elements/IRCTimelineProfileResizer.tsx
+++ b/src/components/views/elements/IRCTimelineProfileResizer.tsx
@@ -78,7 +78,12 @@ export default class IRCTimelineProfileResizer extends React.Component = ({data, className, ...options}) => {
return () => {
cancelled = true;
};
- }, [JSON.stringify(data), options]);
+ }, [JSON.stringify(data), options]); // eslint-disable-line react-hooks/exhaustive-deps
return
{ dataUri ?
:
}
diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx
index a88c581d07..b7c8e1b533 100644
--- a/src/components/views/elements/Slider.tsx
+++ b/src/components/views/elements/Slider.tsx
@@ -45,7 +45,7 @@ export default class Slider extends React.Component
{
// non linear slider.
private offset(values: number[], value: number): number {
// the index of the first number greater than value.
- let closest = values.reduce((prev, curr) => {
+ const closest = values.reduce((prev, curr) => {
return (value > curr ? prev + 1 : prev);
}, 0);
@@ -68,17 +68,16 @@ export default class Slider extends React.Component {
const linearInterpolation = (value - closestLessValue) / (closestGreaterValue - closestLessValue);
return 100 * (closest - 1 + linearInterpolation) * intervalWidth;
-
}
render(): React.ReactNode {
- const dots = this.props.values.map(v =>
- {} : () => this.props.onSelectionChange(v)}
- key={v}
- disabled={this.props.disabled}
- />);
+ const dots = this.props.values.map(v => {} : () => this.props.onSelectionChange(v)}
+ key={v}
+ disabled={this.props.disabled}
+ />);
let selection = null;
@@ -93,7 +92,7 @@ export default class Slider extends React.Component {
return
-
{} : this.onClick.bind(this)}/>
+ {} : this.onClick.bind(this)} />
{ selection }
diff --git a/src/components/views/elements/StyledCheckbox.tsx b/src/components/views/elements/StyledCheckbox.tsx
index be983828ff..f8d2665d07 100644
--- a/src/components/views/elements/StyledCheckbox.tsx
+++ b/src/components/views/elements/StyledCheckbox.tsx
@@ -17,8 +17,6 @@ limitations under the License.
import React from "react";
import { randomString } from "matrix-js-sdk/src/randomstring";
-const CHECK_BOX_SVG = require("../../../../res/img/feather-customised/check.svg");
-
interface IProps extends React.InputHTMLAttributes
{
}
@@ -39,13 +37,14 @@ export default class StyledCheckbox extends React.PureComponent
}
public render() {
+ /* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */
const { children, className, ...otherProps } = this.props;
return
{/* Using the div to center the image */}
-
+
{ this.props.children }
@@ -53,4 +52,4 @@ export default class StyledCheckbox extends React.PureComponent
;
}
-}
\ No newline at end of file
+}
diff --git a/src/components/views/right_panel/EncryptionInfo.tsx b/src/components/views/right_panel/EncryptionInfo.tsx
index f62af65543..10d35200bd 100644
--- a/src/components/views/right_panel/EncryptionInfo.tsx
+++ b/src/components/views/right_panel/EncryptionInfo.tsx
@@ -76,14 +76,16 @@ const EncryptionInfo: React.FC = ({
description = (
{_t("Messages in this room are end-to-end encrypted.")}
-
{_t("Your messages are secured and only you and the recipient have the unique keys to unlock them.")}
+
{_t("Your messages are secured and only you and the recipient have " +
+ "the unique keys to unlock them.")}
);
} else {
description = (
{_t("Messages in this room are not end-to-end encrypted.")}
-
{_t("In encrypted rooms, your messages are secured and only you and the recipient have the unique keys to unlock them.")}
+
{_t("In encrypted rooms, your messages are secured and only you and the recipient have " +
+ "the unique keys to unlock them.")}
);
}
diff --git a/src/components/views/right_panel/HeaderButtons.tsx b/src/components/views/right_panel/HeaderButtons.tsx
index 57d3075739..bbb783ccb9 100644
--- a/src/components/views/right_panel/HeaderButtons.tsx
+++ b/src/components/views/right_panel/HeaderButtons.tsx
@@ -23,7 +23,10 @@ import dis from '../../../dispatcher/dispatcher';
import RightPanelStore from "../../../stores/RightPanelStore";
import {RightPanelPhases} from "../../../stores/RightPanelStorePhases";
import {Action} from '../../../dispatcher/actions';
-import {SetRightPanelPhasePayload, SetRightPanelPhaseRefireParams} from '../../../dispatcher/payloads/SetRightPanelPhasePayload';
+import {
+ SetRightPanelPhasePayload,
+ SetRightPanelPhaseRefireParams,
+} from '../../../dispatcher/payloads/SetRightPanelPhasePayload';
import {EventSubscription} from "fbemitter";
export enum HeaderKind {
@@ -38,7 +41,7 @@ interface IState {
interface IProps {}
-export default class HeaderButtons extends React.Component {
+export default abstract class HeaderButtons extends React.Component {
private storeToken: EventSubscription;
private dispatcherRef: string;
@@ -92,14 +95,7 @@ export default class HeaderButtons extends React.Component {
}
// XXX: Make renderButtons a prop
- public renderButtons(): JSX.Element[] {
- // Ignore - intended to be overridden by subclasses
- // Return empty fragment to satisfy the type
- return [
-
-
- ];
- }
+ public abstract renderButtons(): JSX.Element[];
public render() {
// inline style as this will be swapped around in future commits
diff --git a/src/components/views/right_panel/VerificationPanel.tsx b/src/components/views/right_panel/VerificationPanel.tsx
index 1f0703839f..f584a63209 100644
--- a/src/components/views/right_panel/VerificationPanel.tsx
+++ b/src/components/views/right_panel/VerificationPanel.tsx
@@ -30,8 +30,6 @@ import {_t} from "../../../languageHandler";
import SdkConfig from "../../../SdkConfig";
import E2EIcon from "../rooms/E2EIcon";
import {
- PHASE_UNSENT,
- PHASE_REQUESTED,
PHASE_READY,
PHASE_DONE,
PHASE_STARTED,
@@ -104,14 +102,15 @@ export default class VerificationPanel extends React.PureComponent;
}
if (showSAS) {
- sasBlockDialog =
-
-
{_t("Compare unique emoji")}
-
{_t("Compare a unique set of emoji if you don't have a camera on either device")}
-
- {_t("Start")}
-
-
;
+ sasBlockDialog =
+
{_t("Compare unique emoji")}
+
+ {_t("Compare a unique set of emoji if you don't have a camera on either device")}
+
+
+ {_t("Start")}
+
+
;
}
const or = qrBlockDialog && sasBlockDialog ?
{_t("or")}
: null;
@@ -165,8 +164,8 @@ export default class VerificationPanel extends React.PureComponent{noCommonMethodError} :
- null;
+ {noCommonMethodError}
:
+ null;
// TODO: add way to open camera to scan a QR code
return
diff --git a/src/components/views/rooms/NotificationBadge.tsx b/src/components/views/rooms/NotificationBadge.tsx
index 8253940d4e..2957b25779 100644
--- a/src/components/views/rooms/NotificationBadge.tsx
+++ b/src/components/views/rooms/NotificationBadge.tsx
@@ -92,6 +92,7 @@ export default class NotificationBadge extends React.PureComponent {
private getRoomDelta = (roomId: string, delta: number, unread = false) => {
const lists = RoomListStore.instance.orderedLists;
- let rooms: Room = [];
+ const rooms: Room = [];
TAG_ORDER.forEach(t => {
let listRooms = lists[t];
@@ -290,7 +290,7 @@ export default class RoomList extends React.PureComponent {
// TODO: Put community invites in a more sensible place (not in the room list)
// See https://github.com/vector-im/element-web/issues/14456
return MatrixClientPeg.get().getGroups().filter(g => {
- return g.myMembership === 'invite';
+ return g.myMembership === 'invite';
}).map(g => {
const avatar = (
{
: TAG_AESTHETICS[orderedTagId];
if (!aesthetics) throw new Error(`Tag ${orderedTagId} does not have aesthetics`);
- components.push(
-
- );
+ components.push( );
}
return components;
diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx
index 1e7ba3f77a..4056f2fbd4 100644
--- a/src/components/views/rooms/RoomSublist.tsx
+++ b/src/components/views/rooms/RoomSublist.tsx
@@ -517,15 +517,13 @@ export default class RoomSublist extends React.Component {
if (this.state.rooms) {
const visibleRooms = this.state.rooms.slice(0, this.numVisibleTiles);
for (const room of visibleRooms) {
- tiles.push(
-
- );
+ tiles.push( );
}
}
@@ -710,7 +708,12 @@ export default class RoomSublist extends React.Component {
// doesn't become sticky.
// The same applies to the notification badge.
return (
-
+
{
const showMoreAtMinHeight = minTiles < this.numTiles;
const minHeightPadding = RESIZE_HANDLE_HEIGHT + (showMoreAtMinHeight ? SHOW_N_BUTTON_HEIGHT : 0);
const minTilesPx = layout.tilesToPixelsWithPadding(minTiles, minHeightPadding);
- let maxTilesPx = layout.tilesToPixelsWithPadding(this.numTiles, this.padding);
+ const maxTilesPx = layout.tilesToPixelsWithPadding(this.numTiles, this.padding);
const showMoreBtnClasses = classNames({
'mx_RoomSublist_showNButton': true,
});
diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx
index a09853d762..a241a13991 100644
--- a/src/components/views/rooms/RoomTile.tsx
+++ b/src/components/views/rooms/RoomTile.tsx
@@ -31,7 +31,7 @@ import { ChevronFace, ContextMenuTooltipButton } from "../../structures/ContextM
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
import { MessagePreviewStore, ROOM_PREVIEW_CHANGED } from "../../../stores/room-list/MessagePreviewStore";
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
-import { ALL_MESSAGES, ALL_MESSAGES_LOUD, MENTIONS_ONLY, MUTE, } from "../../../RoomNotifs";
+import { ALL_MESSAGES, ALL_MESSAGES_LOUD, MENTIONS_ONLY, MUTE } from "../../../RoomNotifs";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import NotificationBadge from "./NotificationBadge";
import { Volume } from "../../../RoomNotifsTypes";
@@ -48,7 +48,7 @@ import IconizedContextMenu, {
IconizedContextMenuCheckbox,
IconizedContextMenuOption,
IconizedContextMenuOptionList,
- IconizedContextMenuRadio
+ IconizedContextMenuRadio,
} from "../context_menus/IconizedContextMenu";
import { CommunityPrototypeStore, IRoomProfile } from "../../../stores/CommunityPrototypeStore";
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
@@ -249,7 +249,7 @@ export default class RoomTile extends React.PureComponent {
removeTag,
addTag,
undefined,
- 0
+ 0,
));
} else {
console.warn(`Unexpected tag ${tagId} applied to ${this.props.room.room_id}`);
diff --git a/src/components/views/rooms/TemporaryTile.tsx b/src/components/views/rooms/TemporaryTile.tsx
index a61ff6e1da..eec3105880 100644
--- a/src/components/views/rooms/TemporaryTile.tsx
+++ b/src/components/views/rooms/TemporaryTile.tsx
@@ -19,9 +19,7 @@ import classNames from "classnames";
import {
RovingAccessibleButton,
RovingAccessibleTooltipButton,
- RovingTabIndexWrapper
} from "../../../accessibility/RovingTabIndex";
-import AccessibleButton from "../../views/elements/AccessibleButton";
import NotificationBadge from "./NotificationBadge";
import { NotificationState } from "../../../stores/notifications/NotificationState";
diff --git a/src/components/views/settings/UpdateCheckButton.tsx b/src/components/views/settings/UpdateCheckButton.tsx
index 10e0e29f31..eb1b762423 100644
--- a/src/components/views/settings/UpdateCheckButton.tsx
+++ b/src/components/views/settings/UpdateCheckButton.tsx
@@ -42,7 +42,7 @@ function getStatusText(status: UpdateCheckStatus, errorDetail?: string) {
return _t('Downloading update...');
case UpdateCheckStatus.Ready:
return _t("New version available. Update now. ", {}, {
- a: sub => {sub}
+ a: sub => {sub} ,
});
}
}
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
index c9ec4a6bc7..b4c05a2ecb 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
@@ -170,7 +170,7 @@ export default class AppearanceUserSettingsTab extends React.Component
{customThemeForm}
-
+
);
}
diff --git a/src/components/views/toasts/GenericExpiringToast.tsx b/src/components/views/toasts/GenericExpiringToast.tsx
index 83f43208c4..e63edd8e79 100644
--- a/src/components/views/toasts/GenericExpiringToast.tsx
+++ b/src/components/views/toasts/GenericExpiringToast.tsx
@@ -29,7 +29,15 @@ interface IProps extends IGenericToastProps {
const SECOND = 1000;
-const GenericExpiringToast: React.FC = ({description, acceptLabel, dismissLabel, onAccept, onDismiss, toastKey, numSeconds}) => {
+const GenericExpiringToast: React.FC = ({
+ description,
+ acceptLabel,
+ dismissLabel,
+ onAccept,
+ onDismiss,
+ toastKey,
+ numSeconds,
+}) => {
const onReject = () => {
if (onDismiss) onDismiss();
ToastStore.sharedInstance().dismissToast(toastKey);
diff --git a/src/components/views/toasts/GenericToast.tsx b/src/components/views/toasts/GenericToast.tsx
index 6cd881b9eb..a9c64f1962 100644
--- a/src/components/views/toasts/GenericToast.tsx
+++ b/src/components/views/toasts/GenericToast.tsx
@@ -31,7 +31,13 @@ interface IPropsExtended extends IProps {
onReject();
}
-const GenericToast: React.FC> = ({description, acceptLabel, rejectLabel, onAccept, onReject}) => {
+const GenericToast: React.FC> = ({
+ description,
+ acceptLabel,
+ rejectLabel,
+ onAccept,
+ onReject,
+}) => {
return
{ description }
diff --git a/src/components/views/voip/CallView.tsx b/src/components/views/voip/CallView.tsx
index 8416f56fd9..1d3a62984a 100644
--- a/src/components/views/voip/CallView.tsx
+++ b/src/components/views/voip/CallView.tsx
@@ -97,10 +97,7 @@ export default class CallView extends React.Component
{
if (this.props.room) {
const roomId = this.props.room.roomId;
call = CallHandler.getCallForRoom(roomId) ||
- (this.props.ConferenceHandler ?
- this.props.ConferenceHandler.getConferenceCallForRoom(roomId) :
- null
- );
+ (this.props.ConferenceHandler ? this.props.ConferenceHandler.getConferenceCallForRoom(roomId) : null);
if (this.call) {
this.setState({ call: call });
diff --git a/src/components/views/voip/IncomingCallBox.tsx b/src/components/views/voip/IncomingCallBox.tsx
index 00d49b20f5..b7cba7a70f 100644
--- a/src/components/views/voip/IncomingCallBox.tsx
+++ b/src/components/views/voip/IncomingCallBox.tsx
@@ -51,7 +51,7 @@ export default class IncomingCallBox extends React.Component {
private onAction = (payload: ActionPayload) => {
switch (payload.action) {
- case 'call_state':
+ case 'call_state': {
const call = CallHandler.getCall(payload.room_id);
if (call && call.call_state === 'ringing') {
this.setState({
@@ -62,6 +62,7 @@ export default class IncomingCallBox extends React.Component {
incomingCall: null,
});
}
+ }
}
};
diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx
index 59edc8766c..d9feec95b1 100644
--- a/src/languageHandler.tsx
+++ b/src/languageHandler.tsx
@@ -442,7 +442,7 @@ export function pickBestLanguage(langs: string[]): string {
}
function getLangsJson(): Promise {
- return new Promise(async (resolve, reject) => {
+ return new Promise((resolve, reject) => {
let url;
if (typeof(webpackLangJsonUrl) === 'string') { // in Jest this 'url' isn't a URL, so just fall through
url = webpackLangJsonUrl;
@@ -453,7 +453,7 @@ function getLangsJson(): Promise {
{ method: "GET", url },
(err, response, body) => {
if (err || response.status < 200 || response.status >= 300) {
- reject({err: err, response: response});
+ reject(err);
return;
}
resolve(JSON.parse(body));
@@ -488,7 +488,7 @@ function getLanguage(langPath: string): object {
{ method: "GET", url: langPath },
(err, response, body) => {
if (err || response.status < 200 || response.status >= 300) {
- reject({err: err, response: response});
+ reject(err);
return;
}
resolve(weblateToCounterpart(JSON.parse(body)));
From 35e4d89545edbf4ee7c57558dce2518f5e9c89c0 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Fri, 28 Aug 2020 20:04:19 -0600
Subject: [PATCH 15/63] Add aria labels to menu options
---
src/accessibility/context_menu/MenuItem.tsx | 3 ++-
src/components/structures/UserMenu.tsx | 2 ++
src/i18n/strings/en_EN.json | 2 ++
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/accessibility/context_menu/MenuItem.tsx b/src/accessibility/context_menu/MenuItem.tsx
index 64233e51ad..0bb169abf8 100644
--- a/src/accessibility/context_menu/MenuItem.tsx
+++ b/src/accessibility/context_menu/MenuItem.tsx
@@ -26,8 +26,9 @@ interface IProps extends React.ComponentProps {
// Semantic component for representing a role=menuitem
export const MenuItem: React.FC = ({children, label, ...props}) => {
+ const ariaLabel = props["aria-label"] || label;
return (
-
+
{ children }
);
diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx
index 5db5371842..476fe19ad7 100644
--- a/src/components/structures/UserMenu.tsx
+++ b/src/components/structures/UserMenu.tsx
@@ -322,6 +322,7 @@ export default class UserMenu extends React.Component {
{
this.onSettingsOpen(e, null)}
/>
Date: Fri, 28 Aug 2020 20:08:12 -0600
Subject: [PATCH 16/63] Wire up the invite button
---
src/RoomInvite.js | 3 ++-
src/components/structures/UserMenu.tsx | 4 +++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/RoomInvite.js b/src/RoomInvite.js
index 7f2eec32f3..ed3fe1452e 100644
--- a/src/RoomInvite.js
+++ b/src/RoomInvite.js
@@ -25,6 +25,7 @@ import { _t } from './languageHandler';
import {KIND_DM, KIND_INVITE} from "./components/views/dialogs/InviteDialog";
import CommunityPrototypeInviteDialog from "./components/views/dialogs/CommunityPrototypeInviteDialog";
import GroupStore from "./stores/GroupStore";
+import {CommunityPrototypeStore} from "./stores/CommunityPrototypeStore";
/**
* Invites multiple addresses to a room
@@ -76,7 +77,7 @@ export function showCommunityInviteDialog(communityId) {
});
if (!chat) chat = rooms[0];
if (chat) {
- const name = CommunityPrototypeInviteDialog.instance.getCommunityName(communityId);
+ const name = CommunityPrototypeStore.instance.getCommunityName(communityId);
showCommunityRoomInviteDialog(chat.roomId, name);
} else {
throw new Error("Failed to locate appropriate room to start an invite in");
diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx
index 476fe19ad7..8e62402141 100644
--- a/src/components/structures/UserMenu.tsx
+++ b/src/components/structures/UserMenu.tsx
@@ -45,6 +45,7 @@ import IconizedContextMenu, {
import { CommunityPrototypeStore } from "../../stores/CommunityPrototypeStore";
import * as fbEmitter from "fbemitter";
import TagOrderStore from "../../stores/TagOrderStore";
+import { showCommunityInviteDialog } from "../../RoomInvite";
interface IProps {
isMinimized: boolean;
@@ -217,7 +218,8 @@ export default class UserMenu extends React.Component {
ev.preventDefault();
ev.stopPropagation();
- console.log("TODO@onCommunityInviteClick");
+ showCommunityInviteDialog(TagOrderStore.getSelectedPrototypeTag());
+ this.setState({contextMenuPosition: null}); // also close the menu
};
private renderContextMenu = (): React.ReactNode => {
From 281e2ab27bcf44a230020e14b73e202afd66dd4b Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Fri, 28 Aug 2020 20:13:26 -0600
Subject: [PATCH 17/63] Null guard new function to reduce error spam
---
src/stores/FlairStore.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/stores/FlairStore.js b/src/stores/FlairStore.js
index 10a4d96921..67d9616741 100644
--- a/src/stores/FlairStore.js
+++ b/src/stores/FlairStore.js
@@ -157,6 +157,7 @@ class FlairStore extends EventEmitter {
* @returns The profile if known, otherwise null.
*/
getGroupProfileCachedFast(matrixClient, groupId) {
+ if (!matrixClient || !groupId) return null;
if (this._groupProfiles[groupId]) {
return this._groupProfiles[groupId];
}
From 672d0fe97b0c995e8807b809b9016d29a6ecf12a Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 29 Aug 2020 12:09:07 +0100
Subject: [PATCH 18/63] Remove redundant components and devDependencies
---
package.json | 4 +-
.../structures/CompatibilityPage.js | 90 ---------------
src/components/views/create_room/Presets.js | 57 ----------
src/components/views/create_room/RoomAlias.js | 106 ------------------
src/components/views/elements/UserSelector.js | 76 -------------
src/components/views/rooms/RoomNameEditor.js | 80 -------------
src/components/views/rooms/RoomTopicEditor.js | 68 -----------
7 files changed, 1 insertion(+), 480 deletions(-)
delete mode 100644 src/components/structures/CompatibilityPage.js
delete mode 100644 src/components/views/create_room/Presets.js
delete mode 100644 src/components/views/create_room/RoomAlias.js
delete mode 100644 src/components/views/elements/UserSelector.js
delete mode 100644 src/components/views/rooms/RoomNameEditor.js
delete mode 100644 src/components/views/rooms/RoomTopicEditor.js
diff --git a/package.json b/package.json
index ab71f68b08..ce559b1275 100644
--- a/package.json
+++ b/package.json
@@ -163,9 +163,7 @@
"stylelint-config-standard": "^18.3.0",
"stylelint-scss": "^3.18.0",
"typescript": "^3.9.7",
- "walk": "^2.3.14",
- "webpack": "^4.43.0",
- "webpack-cli": "^3.3.12"
+ "walk": "^2.3.14"
},
"jest": {
"testMatch": [
diff --git a/src/components/structures/CompatibilityPage.js b/src/components/structures/CompatibilityPage.js
deleted file mode 100644
index 1fa6068675..0000000000
--- a/src/components/structures/CompatibilityPage.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-Copyright 2015, 2016 OpenMarket Ltd
-Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
-Copyright 2019, 2020 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 createReactClass from 'create-react-class';
-import PropTypes from 'prop-types';
-import { _t } from '../../languageHandler';
-import SdkConfig from '../../SdkConfig';
-
-export default createReactClass({
- displayName: 'CompatibilityPage',
- propTypes: {
- onAccept: PropTypes.func,
- },
-
- getDefaultProps: function() {
- return {
- onAccept: function() {}, // NOP
- };
- },
-
- onAccept: function() {
- this.props.onAccept();
- },
-
- render: function() {
- const brand = SdkConfig.get().brand;
-
- return (
-
-
-
{_t(
- "Sorry, your browser is not able to run %(brand)s.",
- {
- brand,
- },
- {
- 'b': (sub) => {sub} ,
- })
- }
-
- { _t(
- "%(brand)s uses many advanced browser features, some of which are not available " +
- "or experimental in your current browser.",
- { brand },
- ) }
-
-
- { _t(
- 'Please install Chrome , Firefox , ' +
- 'or Safari for the best experience.',
- {},
- {
- 'chromeLink': (sub) => {sub} ,
- 'firefoxLink': (sub) => {sub} ,
- 'safariLink': (sub) => {sub} ,
- },
- )}
-
-
- { _t(
- "With your current browser, the look and feel of the application may be " +
- "completely incorrect, and some or all features may not function. " +
- "If you want to try it anyway you can continue, but you are on your own in terms " +
- "of any issues you may encounter!",
- ) }
-
-
- { _t("I understand the risks and wish to continue") }
-
-
-
- );
- },
-});
diff --git a/src/components/views/create_room/Presets.js b/src/components/views/create_room/Presets.js
deleted file mode 100644
index 0f18d11511..0000000000
--- a/src/components/views/create_room/Presets.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-Copyright 2015, 2016 OpenMarket Ltd
-Copyright 2019 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 PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
-import { _t } from '../../../languageHandler';
-
-const Presets = {
- PrivateChat: "private_chat",
- PublicChat: "public_chat",
- Custom: "custom",
-};
-
-export default createReactClass({
- displayName: 'CreateRoomPresets',
- propTypes: {
- onChange: PropTypes.func,
- preset: PropTypes.string,
- },
-
- Presets: Presets,
-
- getDefaultProps: function() {
- return {
- onChange: function() {},
- };
- },
-
- onValueChanged: function(ev) {
- this.props.onChange(ev.target.value);
- },
-
- render: function() {
- return (
-
- { _t("Private Chat") }
- { _t("Public Chat") }
- { _t("Custom") }
-
- );
- },
-});
diff --git a/src/components/views/create_room/RoomAlias.js b/src/components/views/create_room/RoomAlias.js
deleted file mode 100644
index 5bdfdde08d..0000000000
--- a/src/components/views/create_room/RoomAlias.js
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
-Copyright 2015, 2016 OpenMarket Ltd
-Copyright 2019 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 PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
-import { _t } from '../../../languageHandler';
-
-export default createReactClass({
- displayName: 'RoomAlias',
- propTypes: {
- // Specifying a homeserver will make magical things happen when you,
- // e.g. start typing in the room alias box.
- homeserver: PropTypes.string,
- alias: PropTypes.string,
- onChange: PropTypes.func,
- },
-
- getDefaultProps: function() {
- return {
- onChange: function() {},
- alias: '',
- };
- },
-
- getAliasLocalpart: function() {
- let room_alias = this.props.alias;
-
- if (room_alias && this.props.homeserver) {
- const suffix = ":" + this.props.homeserver;
- if (room_alias.startsWith("#") && room_alias.endsWith(suffix)) {
- room_alias = room_alias.slice(1, -suffix.length);
- }
- }
-
- return room_alias;
- },
-
- onValueChanged: function(ev) {
- this.props.onChange(ev.target.value);
- },
-
- onFocus: function(ev) {
- const target = ev.target;
- const curr_val = ev.target.value;
-
- if (this.props.homeserver) {
- if (curr_val == "") {
- const self = this;
- setTimeout(function() {
- target.value = "#:" + self.props.homeserver;
- target.setSelectionRange(1, 1);
- }, 0);
- } else {
- const suffix = ":" + this.props.homeserver;
- setTimeout(function() {
- target.setSelectionRange(
- curr_val.startsWith("#") ? 1 : 0,
- curr_val.endsWith(suffix) ? (target.value.length - suffix.length) : target.value.length,
- );
- }, 0);
- }
- }
- },
-
- onBlur: function(ev) {
- const curr_val = ev.target.value;
-
- if (this.props.homeserver) {
- if (curr_val == "#:" + this.props.homeserver) {
- ev.target.value = "";
- return;
- }
-
- if (curr_val != "") {
- let new_val = ev.target.value;
- const suffix = ":" + this.props.homeserver;
- if (!curr_val.startsWith("#")) new_val = "#" + new_val;
- if (!curr_val.endsWith(suffix)) new_val = new_val + suffix;
- ev.target.value = new_val;
- }
- }
- },
-
- render: function() {
- return (
-
- );
- },
-});
diff --git a/src/components/views/elements/UserSelector.js b/src/components/views/elements/UserSelector.js
deleted file mode 100644
index ffb577e090..0000000000
--- a/src/components/views/elements/UserSelector.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-Copyright 2015, 2016 OpenMarket Ltd
-Copyright 2019 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, {createRef} from 'react';
-import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
-import { _t } from '../../../languageHandler';
-
-export default createReactClass({
- displayName: 'UserSelector',
-
- propTypes: {
- onChange: PropTypes.func,
- selected_users: PropTypes.arrayOf(PropTypes.string),
- },
-
- getDefaultProps: function() {
- return {
- onChange: function() {},
- selected: [],
- };
- },
-
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
- this._user_id_input = createRef();
- },
-
- addUser: function(user_id) {
- if (this.props.selected_users.indexOf(user_id == -1)) {
- this.props.onChange(this.props.selected_users.concat([user_id]));
- }
- },
-
- removeUser: function(user_id) {
- this.props.onChange(this.props.selected_users.filter(function(e) {
- return e != user_id;
- }));
- },
-
- onAddUserId: function() {
- this.addUser(this._user_id_input.current.value);
- this._user_id_input.current.value = "";
- },
-
- render: function() {
- const self = this;
- return (
-
-
- { this.props.selected_users.map(function(user_id, i) {
- return { user_id } - X ;
- }) }
-
-
-
- { _t("Add User") }
-
-
- );
- },
-});
diff --git a/src/components/views/rooms/RoomNameEditor.js b/src/components/views/rooms/RoomNameEditor.js
deleted file mode 100644
index e0c31321c3..0000000000
--- a/src/components/views/rooms/RoomNameEditor.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-Copyright 2016 OpenMarket 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 PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
-import {MatrixClientPeg} from "../../../MatrixClientPeg";
-import * as sdk from "../../../index";
-import { _t } from '../../../languageHandler';
-
-export default createReactClass({
- displayName: 'RoomNameEditor',
-
- propTypes: {
- room: PropTypes.object.isRequired,
- },
-
- getInitialState: function() {
- return {
- name: null,
- };
- },
-
- // TODO: [REACT-WARNING] Move this to constructor
- UNSAFE_componentWillMount: function() {
- const room = this.props.room;
- const name = room.currentState.getStateEvents('m.room.name', '');
- const myId = MatrixClientPeg.get().credentials.userId;
- const defaultName = room.getDefaultRoomName(myId);
-
- this.setState({
- name: name ? name.getContent().name : '',
- });
-
- this._placeholderName = _t("Unnamed Room");
- if (defaultName && defaultName !== 'Empty room') { // default name from JS SDK, needs no translation as we don't ever show it.
- this._placeholderName += " (" + defaultName + ")";
- }
- },
-
- getRoomName: function() {
- return this.state.name;
- },
-
- _onValueChanged: function(value, shouldSubmit) {
- this.setState({
- name: value,
- });
- },
-
- render: function() {
- const EditableText = sdk.getComponent("elements.EditableText");
-
- return (
-
-
-
- );
- },
-});
diff --git a/src/components/views/rooms/RoomTopicEditor.js b/src/components/views/rooms/RoomTopicEditor.js
deleted file mode 100644
index 0adc0ff1d6..0000000000
--- a/src/components/views/rooms/RoomTopicEditor.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-Copyright 2016 OpenMarket 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 PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
-import * as sdk from '../../../index';
-import { _t } from "../../../languageHandler";
-
-export default createReactClass({
- displayName: 'RoomTopicEditor',
-
- propTypes: {
- room: PropTypes.object.isRequired,
- },
-
- getInitialState: function() {
- return {
- topic: null,
- };
- },
-
- componentDidMount: function() {
- const room = this.props.room;
- const topic = room.currentState.getStateEvents('m.room.topic', '');
- this.setState({
- topic: topic ? topic.getContent().topic : '',
- });
- },
-
- getTopic: function() {
- return this.state.topic;
- },
-
- _onValueChanged: function(value) {
- this.setState({
- topic: value,
- });
- },
-
- render: function() {
- const EditableText = sdk.getComponent("elements.EditableText");
-
- return (
-
- );
- },
-});
From 72498df28f3e20cc968cea692a9fd49ebb64973e Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 29 Aug 2020 12:14:16 +0100
Subject: [PATCH 19/63] Remove create-react-class
---
package.json | 1 -
src/AsyncWrapper.js | 36 +-
.../views/dialogs/ExportE2eKeysDialog.js | 48 ++-
.../views/dialogs/ImportE2eKeysDialog.js | 54 ++-
src/components/structures/FilePanel.js | 50 ++-
src/components/structures/GroupView.js | 261 ++++++-------
src/components/structures/InteractiveAuth.js | 81 ++--
src/components/structures/MyGroups.js | 37 +-
.../structures/NotificationPanel.js | 16 +-
src/components/structures/RoomDirectory.js | 108 +++---
src/components/structures/RoomStatusBar.js | 79 ++--
src/components/structures/RoomView.js | 360 +++++++++---------
src/components/structures/ScrollPanel.js | 149 ++++----
src/components/structures/SearchBox.js | 74 ++--
src/components/structures/TagPanel.js | 47 +--
src/components/structures/TimelinePanel.js | 243 ++++++------
src/components/structures/UploadBar.js | 26 +-
src/components/structures/ViewSource.js | 15 +-
.../structures/auth/ForgotPassword.js | 102 +++--
src/components/structures/auth/Login.js | 110 +++---
.../structures/auth/PostRegistration.js | 31 +-
.../structures/auth/Registration.js | 88 +++--
src/components/views/auth/AuthFooter.js | 11 +-
src/components/views/auth/AuthHeader.js | 15 +-
src/components/views/auth/CaptchaForm.js | 54 ++-
.../views/auth/CustomServerDialog.js | 11 +-
.../auth/InteractiveAuthEntryComponents.js | 227 +++++------
src/components/views/auth/RegistrationForm.js | 147 ++++---
.../views/context_menus/MessageContextMenu.js | 111 +++---
.../views/dialogs/AddressPickerDialog.js | 150 ++++----
.../views/dialogs/AskInviteAnywayDialog.js | 25 +-
src/components/views/dialogs/BaseDialog.js | 40 +-
.../views/dialogs/ConfirmRedactDialog.js | 11 +-
.../views/dialogs/ConfirmUserActionDialog.js | 37 +-
.../views/dialogs/CreateGroupDialog.js | 54 ++-
.../views/dialogs/CreateRoomDialog.js | 82 ++--
src/components/views/dialogs/ErrorDialog.js | 28 +-
src/components/views/dialogs/InfoDialog.js | 30 +-
.../views/dialogs/InteractiveAuthDialog.js | 45 +--
.../views/dialogs/QuestionDialog.js | 42 +-
.../views/dialogs/RoomUpgradeDialog.js | 37 +-
.../dialogs/SessionRestoreErrorDialog.js | 27 +-
.../views/dialogs/SetEmailDialog.js | 44 +--
src/components/views/dialogs/SetMxIdDialog.js | 63 ++-
.../views/dialogs/SetPasswordDialog.js | 34 +-
.../views/dialogs/TextInputDialog.js | 65 ++--
src/components/views/elements/ActionButton.js | 45 +--
.../views/elements/AddressSelector.js | 72 ++--
src/components/views/elements/AddressTile.js | 27 +-
.../views/elements/DialogButtons.js | 29 +-
src/components/views/elements/EditableText.js | 143 ++++---
.../views/elements/InlineSpinner.js | 11 +-
.../views/elements/MemberEventListSummary.js | 61 ++-
.../views/elements/PersistentApp.js | 37 +-
src/components/views/elements/Pill.js | 92 ++---
.../views/elements/PowerSelector.js | 62 ++-
src/components/views/elements/TagTile.js | 59 ++-
src/components/views/elements/TintableSvg.js | 39 +-
.../views/elements/TooltipButton.js | 27 +-
.../views/elements/TruncatedList.js | 41 +-
.../views/groups/GroupInviteTile.js | 57 ++-
.../views/groups/GroupMemberList.js | 67 ++--
.../views/groups/GroupMemberTile.js | 27 +-
.../views/groups/GroupPublicityToggle.js | 39 +-
src/components/views/groups/GroupRoomInfo.js | 63 ++-
src/components/views/groups/GroupRoomList.js | 61 ++-
src/components/views/groups/GroupRoomTile.js | 24 +-
src/components/views/groups/GroupTile.js | 47 +--
.../views/groups/GroupUserSettings.js | 27 +-
src/components/views/messages/MFileBody.js | 64 ++--
src/components/views/messages/MVideoBody.js | 49 ++-
src/components/views/messages/MessageEvent.js | 30 +-
.../views/messages/RoomAvatarEvent.js | 19 +-
src/components/views/messages/RoomCreate.js | 19 +-
.../views/messages/SenderProfile.js | 38 +-
src/components/views/messages/TextualBody.js | 112 +++---
src/components/views/messages/TextualEvent.js | 15 +-
.../views/room_settings/UrlPreviewSettings.js | 19 +-
src/components/views/rooms/AppsDrawer.js | 65 ++--
src/components/views/rooms/AuxPanel.js | 57 +--
src/components/views/rooms/EntityTile.js | 49 +--
src/components/views/rooms/EventTile.js | 126 +++---
src/components/views/rooms/ForwardMessage.js | 27 +-
.../views/rooms/LinkPreviewWidget.js | 42 +-
src/components/views/rooms/MemberList.js | 147 ++++---
src/components/views/rooms/MemberTile.js | 73 ++--
src/components/views/rooms/PinnedEventTile.js | 30 +-
.../views/rooms/PinnedEventsPanel.js | 46 +--
src/components/views/rooms/PresenceLabel.js | 33 +-
.../views/rooms/ReadReceiptMarker.js | 55 ++-
src/components/views/rooms/RoomDetailList.js | 21 +-
src/components/views/rooms/RoomDetailRow.js | 52 +--
src/components/views/rooms/RoomHeader.js | 74 ++--
src/components/views/rooms/RoomPreviewBar.js | 85 ++---
.../views/rooms/RoomUpgradeWarningBar.js | 27 +-
src/components/views/rooms/SearchBar.js | 46 +--
.../views/rooms/SearchResultTile.js | 15 +-
.../views/rooms/SimpleRoomHeader.js | 15 +-
.../views/rooms/TopUnreadMessagesBar.js | 15 +-
src/components/views/rooms/WhoIsTypingTile.js | 85 ++---
src/components/views/settings/ChangeAvatar.js | 82 ++--
.../views/settings/ChangeDisplayName.js | 19 +-
.../views/settings/ChangePassword.js | 121 +++---
.../views/settings/Notifications.js | 149 ++++----
src/components/views/voip/VideoFeed.js | 30 +-
src/components/views/voip/VideoView.js | 50 ++-
.../structures/MessagePanel-test.js | 20 +-
test/components/stub-component.js | 20 +-
108 files changed, 3059 insertions(+), 3545 deletions(-)
diff --git a/package.json b/package.json
index ce559b1275..00f6dc8a96 100644
--- a/package.json
+++ b/package.json
@@ -61,7 +61,6 @@
"classnames": "^2.2.6",
"commonmark": "^0.29.1",
"counterpart": "^0.18.6",
- "create-react-class": "^15.6.3",
"diff-dom": "^4.1.6",
"diff-match-patch": "^1.0.5",
"emojibase-data": "^5.0.1",
diff --git a/src/AsyncWrapper.js b/src/AsyncWrapper.js
index 94de5df214..359828b312 100644
--- a/src/AsyncWrapper.js
+++ b/src/AsyncWrapper.js
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import createReactClass from 'create-react-class';
+import React from "react";
import * as sdk from './index';
import PropTypes from 'prop-types';
import { _t } from './languageHandler';
@@ -24,21 +24,19 @@ import { _t } from './languageHandler';
* Wrap an asynchronous loader function with a react component which shows a
* spinner until the real component loads.
*/
-export default createReactClass({
- propTypes: {
+export default class AsyncWrapper extends React.Component {
+ static propTypes = {
/** A promise which resolves with the real component
*/
prom: PropTypes.object.isRequired,
- },
+ };
- getInitialState: function() {
- return {
- component: null,
- error: null,
- };
- },
+ state = {
+ component: null,
+ error: null,
+ };
- componentDidMount: function() {
+ componentDidMount() {
this._unmounted = false;
// XXX: temporary logging to try to diagnose
// https://github.com/vector-im/element-web/issues/3148
@@ -56,17 +54,17 @@ export default createReactClass({
console.warn('AsyncWrapper promise failed', e);
this.setState({error: e});
});
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
this._unmounted = true;
- },
+ }
- _onWrapperCancelClick: function() {
+ _onWrapperCancelClick = () => {
this.props.onFinished(false);
- },
+ };
- render: function() {
+ render() {
if (this.state.component) {
const Component = this.state.component;
return ;
@@ -87,6 +85,6 @@ export default createReactClass({
const Spinner = sdk.getComponent("elements.Spinner");
return ;
}
- },
-});
+ }
+}
diff --git a/src/async-components/views/dialogs/ExportE2eKeysDialog.js b/src/async-components/views/dialogs/ExportE2eKeysDialog.js
index a92578a547..406ffd8749 100644
--- a/src/async-components/views/dialogs/ExportE2eKeysDialog.js
+++ b/src/async-components/views/dialogs/ExportE2eKeysDialog.js
@@ -17,7 +17,6 @@ limitations under the License.
import FileSaver from 'file-saver';
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
import { MatrixClient } from 'matrix-js-sdk';
@@ -27,34 +26,31 @@ import * as sdk from '../../../index';
const PHASE_EDIT = 1;
const PHASE_EXPORTING = 2;
-export default createReactClass({
- displayName: 'ExportE2eKeysDialog',
-
- propTypes: {
+export default class ExportE2eKeysDialog extends React.Component {
+ static propTypes = {
matrixClient: PropTypes.instanceOf(MatrixClient).isRequired,
onFinished: PropTypes.func.isRequired,
- },
+ };
- getInitialState: function() {
- return {
- phase: PHASE_EDIT,
- errStr: null,
- };
- },
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this._unmounted = false;
this._passphrase1 = createRef();
this._passphrase2 = createRef();
- },
- componentWillUnmount: function() {
+ this.state = {
+ phase: PHASE_EDIT,
+ errStr: null,
+ };
+ }
+
+ componentWillUnmount() {
this._unmounted = true;
- },
+ }
- _onPassphraseFormSubmit: function(ev) {
+ _onPassphraseFormSubmit = (ev) => {
ev.preventDefault();
const passphrase = this._passphrase1.current.value;
@@ -69,9 +65,9 @@ export default createReactClass({
this._startExport(passphrase);
return false;
- },
+ };
- _startExport: function(passphrase) {
+ _startExport(passphrase) {
// extra Promise.resolve() to turn synchronous exceptions into
// asynchronous ones.
Promise.resolve().then(() => {
@@ -102,15 +98,15 @@ export default createReactClass({
errStr: null,
phase: PHASE_EXPORTING,
});
- },
+ }
- _onCancelClick: function(ev) {
+ _onCancelClick = (ev) => {
ev.preventDefault();
this.props.onFinished(false);
return false;
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const disableForm = (this.state.phase === PHASE_EXPORTING);
@@ -184,5 +180,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/async-components/views/dialogs/ImportE2eKeysDialog.js b/src/async-components/views/dialogs/ImportE2eKeysDialog.js
index 6b9d2c7e45..c2d17f681d 100644
--- a/src/async-components/views/dialogs/ImportE2eKeysDialog.js
+++ b/src/async-components/views/dialogs/ImportE2eKeysDialog.js
@@ -16,7 +16,6 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import { MatrixClient } from 'matrix-js-sdk';
import * as MegolmExportEncryption from '../../../utils/MegolmExportEncryption';
@@ -38,48 +37,45 @@ function readFileAsArrayBuffer(file) {
const PHASE_EDIT = 1;
const PHASE_IMPORTING = 2;
-export default createReactClass({
- displayName: 'ImportE2eKeysDialog',
-
- propTypes: {
+export default class ImportE2eKeysDialog extends React.Component {
+ static propTypes = {
matrixClient: PropTypes.instanceOf(MatrixClient).isRequired,
onFinished: PropTypes.func.isRequired,
- },
+ };
- getInitialState: function() {
- return {
- enableSubmit: false,
- phase: PHASE_EDIT,
- errStr: null,
- };
- },
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this._unmounted = false;
this._file = createRef();
this._passphrase = createRef();
- },
- componentWillUnmount: function() {
+ this.state = {
+ enableSubmit: false,
+ phase: PHASE_EDIT,
+ errStr: null,
+ };
+ }
+
+ componentWillUnmount() {
this._unmounted = true;
- },
+ }
- _onFormChange: function(ev) {
+ _onFormChange = (ev) => {
const files = this._file.current.files || [];
this.setState({
enableSubmit: (this._passphrase.current.value !== "" && files.length > 0),
});
- },
+ };
- _onFormSubmit: function(ev) {
+ _onFormSubmit = (ev) => {
ev.preventDefault();
this._startImport(this._file.current.files[0], this._passphrase.current.value);
return false;
- },
+ };
- _startImport: function(file, passphrase) {
+ _startImport(file, passphrase) {
this.setState({
errStr: null,
phase: PHASE_IMPORTING,
@@ -105,15 +101,15 @@ export default createReactClass({
phase: PHASE_EDIT,
});
});
- },
+ }
- _onCancelClick: function(ev) {
+ _onCancelClick = (ev) => {
ev.preventDefault();
this.props.onFinished(false);
return false;
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const disableForm = (this.state.phase !== PHASE_EDIT);
@@ -188,5 +184,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/structures/FilePanel.js b/src/components/structures/FilePanel.js
index d873dd4094..5a2d858c9d 100644
--- a/src/components/structures/FilePanel.js
+++ b/src/components/structures/FilePanel.js
@@ -16,7 +16,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import {Filter} from 'matrix-js-sdk';
@@ -28,23 +27,20 @@ import { _t } from '../../languageHandler';
/*
* Component which shows the filtered file using a TimelinePanel
*/
-const FilePanel = createReactClass({
- displayName: 'FilePanel',
+class FilePanel extends React.Component {
+ static propTypes = {
+ roomId: PropTypes.string.isRequired,
+ };
+
// This is used to track if a decrypted event was a live event and should be
// added to the timeline.
- decryptingEvents: new Set(),
+ decryptingEvents = new Set();
- propTypes: {
- roomId: PropTypes.string.isRequired,
- },
+ state = {
+ timelineSet: null,
+ };
- getInitialState: function() {
- return {
- timelineSet: null,
- };
- },
-
- onRoomTimeline(ev, room, toStartOfTimeline, removed, data) {
+ onRoomTimeline = (ev, room, toStartOfTimeline, removed, data) => {
if (room.roomId !== this.props.roomId) return;
if (toStartOfTimeline || !data || !data.liveEvent || ev.isRedacted()) return;
@@ -53,9 +49,9 @@ const FilePanel = createReactClass({
} else {
this.addEncryptedLiveEvent(ev);
}
- },
+ };
- onEventDecrypted(ev, err) {
+ onEventDecrypted = (ev, err) => {
if (ev.getRoomId() !== this.props.roomId) return;
const eventId = ev.getId();
@@ -63,7 +59,7 @@ const FilePanel = createReactClass({
if (err) return;
this.addEncryptedLiveEvent(ev);
- },
+ };
addEncryptedLiveEvent(ev, toStartOfTimeline) {
if (!this.state.timelineSet) return;
@@ -77,7 +73,7 @@ const FilePanel = createReactClass({
if (!this.state.timelineSet.eventIdToTimeline(ev.getId())) {
this.state.timelineSet.addEventToTimeline(ev, timeline, false);
}
- },
+ }
async componentDidMount() {
const client = MatrixClientPeg.get();
@@ -98,7 +94,7 @@ const FilePanel = createReactClass({
client.on('Room.timeline', this.onRoomTimeline);
client.on('Event.decrypted', this.onEventDecrypted);
}
- },
+ }
componentWillUnmount() {
const client = MatrixClientPeg.get();
@@ -110,7 +106,7 @@ const FilePanel = createReactClass({
client.removeListener('Room.timeline', this.onRoomTimeline);
client.removeListener('Event.decrypted', this.onEventDecrypted);
}
- },
+ }
async fetchFileEventsServer(room) {
const client = MatrixClientPeg.get();
@@ -134,9 +130,9 @@ const FilePanel = createReactClass({
const timelineSet = room.getOrCreateFilteredTimelineSet(filter);
return timelineSet;
- },
+ }
- onPaginationRequest(timelineWindow, direction, limit) {
+ onPaginationRequest = (timelineWindow, direction, limit) => {
const client = MatrixClientPeg.get();
const eventIndex = EventIndexPeg.get();
const roomId = this.props.roomId;
@@ -152,7 +148,7 @@ const FilePanel = createReactClass({
} else {
return timelineWindow.paginate(direction, limit);
}
- },
+ };
async updateTimelineSet(roomId: string) {
const client = MatrixClientPeg.get();
@@ -188,9 +184,9 @@ const FilePanel = createReactClass({
} else {
console.error("Failed to add filtered timelineSet for FilePanel as no room!");
}
- },
+ }
- render: function() {
+ render() {
if (MatrixClientPeg.get().isGuest()) {
return
@@ -239,7 +235,7 @@ const FilePanel = createReactClass({
);
}
- },
-});
+ }
+}
export default FilePanel;
diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js
index 2e2fa25169..83f70eb72a 100644
--- a/src/components/structures/GroupView.js
+++ b/src/components/structures/GroupView.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import {MatrixClientPeg} from '../../MatrixClientPeg';
import * as sdk from '../../index';
@@ -70,10 +69,8 @@ const UserSummaryType = PropTypes.shape({
}).isRequired,
});
-const CategoryRoomList = createReactClass({
- displayName: 'CategoryRoomList',
-
- props: {
+class CategoryRoomList extends React.Component {
+ static propTypes = {
rooms: PropTypes.arrayOf(RoomSummaryType).isRequired,
category: PropTypes.shape({
profile: PropTypes.shape({
@@ -84,9 +81,9 @@ const CategoryRoomList = createReactClass({
// Whether the list should be editable
editing: PropTypes.bool.isRequired,
- },
+ };
- onAddRoomsToSummaryClicked: function(ev) {
+ onAddRoomsToSummaryClicked = (ev) => {
ev.preventDefault();
const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog");
Modal.createTrackedDialog('Add Rooms to Group Summary', '', AddressPickerDialog, {
@@ -122,9 +119,9 @@ const CategoryRoomList = createReactClass({
});
},
}, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
- },
+ };
- render: function() {
+ render() {
const TintableSvg = sdk.getComponent("elements.TintableSvg");
const addButton = this.props.editing ?
(
;
- },
-});
+ }
+}
-const FeaturedRoom = createReactClass({
- displayName: 'FeaturedRoom',
-
- props: {
+class FeaturedRoom extends React.Component {
+ static propTypes = {
summaryInfo: RoomSummaryType.isRequired,
editing: PropTypes.bool.isRequired,
groupId: PropTypes.string.isRequired,
- },
+ };
- onClick: function(e) {
+ onClick = (e) => {
e.preventDefault();
e.stopPropagation();
@@ -176,9 +171,9 @@ const FeaturedRoom = createReactClass({
room_alias: this.props.summaryInfo.profile.canonical_alias,
room_id: this.props.summaryInfo.room_id,
});
- },
+ };
- onDeleteClicked: function(e) {
+ onDeleteClicked = (e) => {
e.preventDefault();
e.stopPropagation();
GroupStore.removeRoomFromGroupSummary(
@@ -201,9 +196,9 @@ const FeaturedRoom = createReactClass({
description: _t("The room '%(roomName)s' could not be removed from the summary.", {roomName}),
});
});
- },
+ };
- render: function() {
+ render() {
const RoomAvatar = sdk.getComponent("avatars.RoomAvatar");
const roomName = this.props.summaryInfo.profile.name ||
@@ -243,13 +238,11 @@ const FeaturedRoom = createReactClass({
{ roomNameNode }
{ deleteButton }
;
- },
-});
+ }
+}
-const RoleUserList = createReactClass({
- displayName: 'RoleUserList',
-
- props: {
+class RoleUserList extends React.Component {
+ static propTypes = {
users: PropTypes.arrayOf(UserSummaryType).isRequired,
role: PropTypes.shape({
profile: PropTypes.shape({
@@ -260,9 +253,9 @@ const RoleUserList = createReactClass({
// Whether the list should be editable
editing: PropTypes.bool.isRequired,
- },
+ };
- onAddUsersClicked: function(ev) {
+ onAddUsersClicked = (ev) => {
ev.preventDefault();
const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog");
Modal.createTrackedDialog('Add Users to Group Summary', '', AddressPickerDialog, {
@@ -298,9 +291,9 @@ const RoleUserList = createReactClass({
});
},
}, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
- },
+ };
- render: function() {
+ render() {
const TintableSvg = sdk.getComponent("elements.TintableSvg");
const addButton = this.props.editing ?
(
@@ -325,19 +318,17 @@ const RoleUserList = createReactClass({
{ userNodes }
{ addButton }
;
- },
-});
+ }
+}
-const FeaturedUser = createReactClass({
- displayName: 'FeaturedUser',
-
- props: {
+class FeaturedUser extends React.Component {
+ static propTypes = {
summaryInfo: UserSummaryType.isRequired,
editing: PropTypes.bool.isRequired,
groupId: PropTypes.string.isRequired,
- },
+ };
- onClick: function(e) {
+ onClick = (e) => {
e.preventDefault();
e.stopPropagation();
@@ -345,9 +336,9 @@ const FeaturedUser = createReactClass({
action: 'view_start_chat_or_reuse',
user_id: this.props.summaryInfo.user_id,
});
- },
+ };
- onDeleteClicked: function(e) {
+ onDeleteClicked = (e) => {
e.preventDefault();
e.stopPropagation();
GroupStore.removeUserFromGroupSummary(
@@ -368,9 +359,9 @@ const FeaturedUser = createReactClass({
description: _t("The user '%(displayName)s' could not be removed from the summary.", {displayName}),
});
});
- },
+ };
- render: function() {
+ render() {
const BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
const name = this.props.summaryInfo.displayname || this.props.summaryInfo.user_id;
@@ -394,41 +385,37 @@ const FeaturedUser = createReactClass({
{ userNameNode }
{ deleteButton }
;
- },
-});
+ }
+}
const GROUP_JOINPOLICY_OPEN = "open";
const GROUP_JOINPOLICY_INVITE = "invite";
-export default createReactClass({
- displayName: 'GroupView',
-
- propTypes: {
+export default class GroupView extends React.Component {
+ static propTypes = {
groupId: PropTypes.string.isRequired,
// Whether this is the first time the group admin is viewing the group
groupIsNew: PropTypes.bool,
- },
+ };
- getInitialState: function() {
- return {
- summary: null,
- isGroupPublicised: null,
- isUserPrivileged: null,
- groupRooms: null,
- groupRoomsLoading: null,
- error: null,
- editing: false,
- saving: false,
- uploadingAvatar: false,
- avatarChanged: false,
- membershipBusy: false,
- publicityBusy: false,
- inviterProfile: null,
- showRightPanel: RightPanelStore.getSharedInstance().isOpenForGroup,
- };
- },
+ state = {
+ summary: null,
+ isGroupPublicised: null,
+ isUserPrivileged: null,
+ groupRooms: null,
+ groupRoomsLoading: null,
+ error: null,
+ editing: false,
+ saving: false,
+ uploadingAvatar: false,
+ avatarChanged: false,
+ membershipBusy: false,
+ publicityBusy: false,
+ inviterProfile: null,
+ showRightPanel: RightPanelStore.getSharedInstance().isOpenForGroup,
+ };
- componentDidMount: function() {
+ componentDidMount() {
this._unmounted = false;
this._matrixClient = MatrixClientPeg.get();
this._matrixClient.on("Group.myMembership", this._onGroupMyMembership);
@@ -437,9 +424,9 @@ export default createReactClass({
this._dispatcherRef = dis.register(this._onAction);
this._rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this._onRightPanelStoreUpdate);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
this._unmounted = true;
this._matrixClient.removeListener("Group.myMembership", this._onGroupMyMembership);
dis.unregister(this._dispatcherRef);
@@ -448,10 +435,11 @@ export default createReactClass({
if (this._rightPanelStoreToken) {
this._rightPanelStoreToken.remove();
}
- },
+ }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
- UNSAFE_componentWillReceiveProps: function(newProps) {
+ // eslint-disable-next-line camelcase
+ UNSAFE_componentWillReceiveProps(newProps) {
if (this.props.groupId !== newProps.groupId) {
this.setState({
summary: null,
@@ -460,24 +448,24 @@ export default createReactClass({
this._initGroupStore(newProps.groupId);
});
}
- },
+ }
- _onRightPanelStoreUpdate: function() {
+ _onRightPanelStoreUpdate = () => {
this.setState({
showRightPanel: RightPanelStore.getSharedInstance().isOpenForGroup,
});
- },
+ };
- _onGroupMyMembership: function(group) {
+ _onGroupMyMembership = (group) => {
if (this._unmounted || group.groupId !== this.props.groupId) return;
if (group.myMembership === 'leave') {
// Leave settings - the user might have clicked the "Leave" button
this._closeSettings();
}
this.setState({membershipBusy: false});
- },
+ };
- _initGroupStore: function(groupId, firstInit) {
+ _initGroupStore(groupId, firstInit) {
const group = this._matrixClient.getGroup(groupId);
if (group && group.inviter && group.inviter.userId) {
this._fetchInviterProfile(group.inviter.userId);
@@ -506,9 +494,9 @@ export default createReactClass({
});
}
});
- },
+ }
- onGroupStoreUpdated(firstInit) {
+ onGroupStoreUpdated = (firstInit) => {
if (this._unmounted) return;
const summary = GroupStore.getSummary(this.props.groupId);
if (summary.profile) {
@@ -533,7 +521,7 @@ export default createReactClass({
if (this.props.groupIsNew && firstInit) {
this._onEditClick();
}
- },
+ };
_fetchInviterProfile(userId) {
this.setState({
@@ -555,9 +543,9 @@ export default createReactClass({
inviterProfileBusy: false,
});
});
- },
+ }
- _onEditClick: function() {
+ _onEditClick = () => {
this.setState({
editing: true,
profileForm: Object.assign({}, this.state.summary.profile),
@@ -568,20 +556,20 @@ export default createReactClass({
GROUP_JOINPOLICY_INVITE,
},
});
- },
+ };
- _onShareClick: function() {
+ _onShareClick = () => {
const ShareDialog = sdk.getComponent("dialogs.ShareDialog");
Modal.createTrackedDialog('share community dialog', '', ShareDialog, {
target: this._matrixClient.getGroup(this.props.groupId) || new Group(this.props.groupId),
});
- },
+ };
- _onCancelClick: function() {
+ _onCancelClick = () => {
this._closeSettings();
- },
+ };
- _onAction(payload) {
+ _onAction = (payload) => {
switch (payload.action) {
// NOTE: close_settings is an app-wide dispatch; as it is dispatched from MatrixChat
case 'close_settings':
@@ -593,34 +581,34 @@ export default createReactClass({
default:
break;
}
- },
+ };
- _closeSettings() {
+ _closeSettings = () => {
dis.dispatch({action: 'close_settings'});
- },
+ };
- _onNameChange: function(value) {
+ _onNameChange = (value) => {
const newProfileForm = Object.assign(this.state.profileForm, { name: value });
this.setState({
profileForm: newProfileForm,
});
- },
+ };
- _onShortDescChange: function(value) {
+ _onShortDescChange = (value) => {
const newProfileForm = Object.assign(this.state.profileForm, { short_description: value });
this.setState({
profileForm: newProfileForm,
});
- },
+ };
- _onLongDescChange: function(e) {
+ _onLongDescChange = (e) => {
const newProfileForm = Object.assign(this.state.profileForm, { long_description: e.target.value });
this.setState({
profileForm: newProfileForm,
});
- },
+ };
- _onAvatarSelected: function(ev) {
+ _onAvatarSelected = ev => {
const file = ev.target.files[0];
if (!file) return;
@@ -644,15 +632,15 @@ export default createReactClass({
description: _t('Failed to upload image'),
});
});
- },
+ };
- _onJoinableChange: function(ev) {
+ _onJoinableChange = ev => {
this.setState({
joinableForm: { policyType: ev.target.value },
});
- },
+ };
- _onSaveClick: function() {
+ _onSaveClick = () => {
this.setState({saving: true});
const savePromise = this.state.isUserPrivileged ? this._saveGroup() : Promise.resolve();
savePromise.then((result) => {
@@ -683,16 +671,16 @@ export default createReactClass({
avatarChanged: false,
});
});
- },
+ };
- _saveGroup: async function() {
+ async _saveGroup() {
await this._matrixClient.setGroupProfile(this.props.groupId, this.state.profileForm);
await this._matrixClient.setGroupJoinPolicy(this.props.groupId, {
type: this.state.joinableForm.policyType,
});
- },
+ }
- _onAcceptInviteClick: async function() {
+ _onAcceptInviteClick = async () => {
this.setState({membershipBusy: true});
// Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the
@@ -709,9 +697,9 @@ export default createReactClass({
description: _t("Unable to accept invite"),
});
});
- },
+ };
- _onRejectInviteClick: async function() {
+ _onRejectInviteClick = async () => {
this.setState({membershipBusy: true});
// Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the
@@ -728,9 +716,9 @@ export default createReactClass({
description: _t("Unable to reject invite"),
});
});
- },
+ };
- _onJoinClick: async function() {
+ _onJoinClick = async () => {
if (this._matrixClient.isGuest()) {
dis.dispatch({action: 'require_registration', screen_after: {screen: `group/${this.props.groupId}`}});
return;
@@ -752,9 +740,9 @@ export default createReactClass({
description: _t("Unable to join community"),
});
});
- },
+ };
- _leaveGroupWarnings: function() {
+ _leaveGroupWarnings() {
const warnings = [];
if (this.state.isUserPrivileged) {
@@ -768,10 +756,9 @@ export default createReactClass({
}
return warnings;
- },
+ }
-
- _onLeaveClick: function() {
+ _onLeaveClick = () => {
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
const warnings = this._leaveGroupWarnings();
@@ -806,13 +793,13 @@ export default createReactClass({
});
},
});
- },
+ };
- _onAddRoomsClick: function() {
+ _onAddRoomsClick = () => {
showGroupAddRoomDialog(this.props.groupId);
- },
+ };
- _getGroupSection: function() {
+ _getGroupSection() {
const groupSettingsSectionClasses = classnames({
"mx_GroupView_group": this.state.editing,
"mx_GroupView_group_disabled": this.state.editing && !this.state.isUserPrivileged,
@@ -856,9 +843,9 @@ export default createReactClass({
{ this._getLongDescriptionNode() }
{ this._getRoomsNode() }
;
- },
+ }
- _getRoomsNode: function() {
+ _getRoomsNode() {
const RoomDetailList = sdk.getComponent('rooms.RoomDetailList');
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
const TintableSvg = sdk.getComponent('elements.TintableSvg');
@@ -902,9 +889,9 @@ export default createReactClass({
className={roomDetailListClassName} />
}
;
- },
+ }
- _getFeaturedRoomsNode: function() {
+ _getFeaturedRoomsNode() {
const summary = this.state.summary;
const defaultCategoryRooms = [];
@@ -943,9 +930,9 @@ export default createReactClass({
{ defaultCategoryNode }
{ categoryRoomNodes }
;
- },
+ }
- _getFeaturedUsersNode: function() {
+ _getFeaturedUsersNode() {
const summary = this.state.summary;
const noRoleUsers = [];
@@ -984,9 +971,9 @@ export default createReactClass({
{ noRoleNode }
{ roleUserNodes }
;
- },
+ }
- _getMembershipSection: function() {
+ _getMembershipSection() {
const Spinner = sdk.getComponent("elements.Spinner");
const BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
@@ -1100,9 +1087,9 @@ export default createReactClass({
;
- },
+ }
- _getJoinableNode: function() {
+ _getJoinableNode() {
const InlineSpinner = sdk.getComponent('elements.InlineSpinner');
return this.state.editing ?
@@ -1136,9 +1123,9 @@ export default createReactClass({
: null;
- },
+ }
- _getLongDescriptionNode: function() {
+ _getLongDescriptionNode() {
const summary = this.state.summary;
let description = null;
if (summary.profile && summary.profile.long_description) {
@@ -1175,9 +1162,9 @@ export default createReactClass({
{ description }
;
- },
+ }
- render: function() {
+ render() {
const GroupAvatar = sdk.getComponent("avatars.GroupAvatar");
const Spinner = sdk.getComponent("elements.Spinner");
@@ -1366,5 +1353,5 @@ export default createReactClass({
console.error("Invalid state for GroupView");
return
;
}
- },
-});
+ }
+}
diff --git a/src/components/structures/InteractiveAuth.js b/src/components/structures/InteractiveAuth.js
index fa7860ccef..4c186bce30 100644
--- a/src/components/structures/InteractiveAuth.js
+++ b/src/components/structures/InteractiveAuth.js
@@ -17,7 +17,6 @@ limitations under the License.
import {InteractiveAuth} from "matrix-js-sdk";
import React, {createRef} from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import getEntryComponentForLoginType from '../views/auth/InteractiveAuthEntryComponents';
@@ -26,10 +25,8 @@ import * as sdk from '../../index';
export const ERROR_USER_CANCELLED = new Error("User cancelled auth session");
-export default createReactClass({
- displayName: 'InteractiveAuth',
-
- propTypes: {
+export default class InteractiveAuthComponent extends React.Component {
+ static propTypes = {
// matrix client to use for UI auth requests
matrixClient: PropTypes.object.isRequired,
@@ -86,20 +83,19 @@ export default createReactClass({
// continueText and continueKind are passed straight through to the AuthEntryComponent.
continueText: PropTypes.string,
continueKind: PropTypes.string,
- },
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this.state = {
authStage: null,
busy: false,
errorText: null,
stageErrorText: null,
submitButtonEnabled: false,
};
- },
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this._unmounted = false;
this._authLogic = new InteractiveAuth({
authData: this.props.authData,
@@ -141,17 +137,17 @@ export default createReactClass({
}
this._stageComponent = createRef();
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
this._unmounted = true;
if (this._intervalId !== null) {
clearInterval(this._intervalId);
}
- },
+ }
- _requestEmailToken: async function(...args) {
+ _requestEmailToken = async (...args) => {
this.setState({
busy: true,
});
@@ -162,15 +158,15 @@ export default createReactClass({
busy: false,
});
}
- },
+ };
- tryContinue: function() {
+ tryContinue = () => {
if (this._stageComponent.current && this._stageComponent.current.tryContinue) {
this._stageComponent.current.tryContinue();
}
- },
+ };
- _authStateUpdated: function(stageType, stageState) {
+ _authStateUpdated = (stageType, stageState) => {
const oldStage = this.state.authStage;
this.setState({
busy: false,
@@ -180,16 +176,16 @@ export default createReactClass({
}, () => {
if (oldStage != stageType) this._setFocus();
});
- },
+ };
- _requestCallback: function(auth) {
+ _requestCallback = (auth) => {
// This wrapper just exists because the js-sdk passes a second
// 'busy' param for backwards compat. This throws the tests off
// so discard it here.
return this.props.makeRequest(auth);
- },
+ };
- _onBusyChanged: function(busy) {
+ _onBusyChanged = (busy) => {
// if we've started doing stuff, reset the error messages
if (busy) {
this.setState({
@@ -204,29 +200,29 @@ export default createReactClass({
// there's a new screen to show the user. This is implemented by setting
// `busy: false` in `_authStateUpdated`.
// See also https://github.com/vector-im/element-web/issues/12546
- },
+ };
- _setFocus: function() {
+ _setFocus() {
if (this._stageComponent.current && this._stageComponent.current.focus) {
this._stageComponent.current.focus();
}
- },
+ }
- _submitAuthDict: function(authData) {
+ _submitAuthDict = authData => {
this._authLogic.submitAuthDict(authData);
- },
+ };
- _onPhaseChange: function(newPhase) {
+ _onPhaseChange = newPhase => {
if (this.props.onStagePhaseChange) {
this.props.onStagePhaseChange(this.state.authStage, newPhase || 0);
}
- },
+ };
- _onStageCancel: function() {
+ _onStageCancel = () => {
this.props.onAuthFinished(false, ERROR_USER_CANCELLED);
- },
+ };
- _renderCurrentStage: function() {
+ _renderCurrentStage() {
const stage = this.state.authStage;
if (!stage) {
if (this.state.busy) {
@@ -260,16 +256,17 @@ export default createReactClass({
onCancel={this._onStageCancel}
/>
);
- },
+ }
- _onAuthStageFailed: function(e) {
+ _onAuthStageFailed = e => {
this.props.onAuthFinished(false, e);
- },
- _setEmailSid: function(sid) {
- this._authLogic.setEmailSid(sid);
- },
+ };
- render: function() {
+ _setEmailSid = sid => {
+ this._authLogic.setEmailSid(sid);
+ };
+
+ render() {
let error = null;
if (this.state.errorText) {
error = (
@@ -287,5 +284,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js
index 7043c7f38a..e0551eecdb 100644
--- a/src/components/structures/MyGroups.js
+++ b/src/components/structures/MyGroups.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import * as sdk from '../../index';
import { _t } from '../../languageHandler';
import SdkConfig from '../../SdkConfig';
@@ -26,29 +25,23 @@ import AccessibleButton from '../views/elements/AccessibleButton';
import MatrixClientContext from "../../contexts/MatrixClientContext";
import AutoHideScrollbar from "./AutoHideScrollbar";
-export default createReactClass({
- displayName: 'MyGroups',
+export default class MyGroups extends React.Component {
+ static contextType = MatrixClientContext;
- getInitialState: function() {
- return {
- groups: null,
- error: null,
- };
- },
+ state = {
+ groups: null,
+ error: null,
+ };
- statics: {
- contextType: MatrixClientContext,
- },
-
- componentDidMount: function() {
+ componentDidMount() {
this._fetch();
- },
+ }
- _onCreateGroupClick: function() {
+ _onCreateGroupClick = () => {
dis.dispatch({action: 'view_create_group'});
- },
+ };
- _fetch: function() {
+ _fetch() {
this.context.getJoinedGroups().then((result) => {
this.setState({groups: result.groups, error: null});
}, (err) => {
@@ -59,9 +52,9 @@ export default createReactClass({
}
this.setState({groups: null, error: err});
});
- },
+ }
- render: function() {
+ render() {
const brand = SdkConfig.get().brand;
const Loader = sdk.getComponent("elements.Spinner");
const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
@@ -149,5 +142,5 @@ export default createReactClass({
{ content }
;
- },
-});
+ }
+}
diff --git a/src/components/structures/NotificationPanel.js b/src/components/structures/NotificationPanel.js
index c1f78cffda..6ae7f91142 100644
--- a/src/components/structures/NotificationPanel.js
+++ b/src/components/structures/NotificationPanel.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import { _t } from '../../languageHandler';
import {MatrixClientPeg} from "../../MatrixClientPeg";
import * as sdk from "../../index";
@@ -25,13 +24,8 @@ import * as sdk from "../../index";
/*
* Component which shows the global notification list using a TimelinePanel
*/
-const NotificationPanel = createReactClass({
- displayName: 'NotificationPanel',
-
- propTypes: {
- },
-
- render: function() {
+class NotificationPanel extends React.Component {
+ render() {
// wrap a TimelinePanel with the jump-to-event bits turned off.
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
const Loader = sdk.getComponent("elements.Spinner");
@@ -45,7 +39,7 @@ const NotificationPanel = createReactClass({
if (timelineSet) {
return (
-
);
}
- },
-});
+ }
+}
export default NotificationPanel;
diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js
index 11d3508ee5..16ab8edbed 100644
--- a/src/components/structures/RoomDirectory.js
+++ b/src/components/structures/RoomDirectory.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import {MatrixClientPeg} from "../../MatrixClientPeg";
import * as sdk from "../../index";
import dis from "../../dispatcher/dispatcher";
@@ -42,16 +41,16 @@ function track(action) {
Analytics.trackEvent('RoomDirectory', action);
}
-export default createReactClass({
- displayName: 'RoomDirectory',
-
- propTypes: {
+export default class RoomDirectory extends React.Component {
+ static propTypes = {
onFinished: PropTypes.func.isRequired,
- },
+ };
+
+ constructor(props) {
+ super(props);
- getInitialState: function() {
const selectedCommunityId = TagOrderStore.getSelectedTags()[0];
- return {
+ this.state = {
publicRooms: [],
loading: true,
protocolsLoading: true,
@@ -64,10 +63,7 @@ export default createReactClass({
: null,
communityName: null,
};
- },
- // TODO: [REACT-WARNING] Move this to constructor
- UNSAFE_componentWillMount: function() {
this._unmounted = false;
this.nextBatch = null;
this.filterTimeout = null;
@@ -115,16 +111,16 @@ export default createReactClass({
}
this.refreshRoomList();
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
if (this.filterTimeout) {
clearTimeout(this.filterTimeout);
}
this._unmounted = true;
- },
+ }
- refreshRoomList: function() {
+ refreshRoomList = () => {
if (this.state.selectedCommunityId) {
this.setState({
publicRooms: GroupStore.getGroupRooms(this.state.selectedCommunityId).map(r => {
@@ -158,9 +154,9 @@ export default createReactClass({
loading: true,
});
this.getMoreRooms();
- },
+ };
- getMoreRooms: function() {
+ getMoreRooms() {
if (this.state.selectedCommunityId) return Promise.resolve(); // no more rooms
if (!MatrixClientPeg.get()) return Promise.resolve();
@@ -233,7 +229,7 @@ export default createReactClass({
),
});
});
- },
+ }
/**
* A limited interface for removing rooms from the directory.
@@ -242,7 +238,7 @@ export default createReactClass({
* HS admins to do this through the RoomSettings interface, but
* this needs SPEC-417.
*/
- removeFromDirectory: function(room) {
+ removeFromDirectory(room) {
const alias = get_display_alias_for_room(room);
const name = room.name || alias || _t('Unnamed room');
@@ -284,18 +280,18 @@ export default createReactClass({
});
},
});
- },
+ }
- onRoomClicked: function(room, ev) {
+ onRoomClicked = (room, ev) => {
if (ev.shiftKey && !this.state.selectedCommunityId) {
ev.preventDefault();
this.removeFromDirectory(room);
} else {
this.showRoom(room);
}
- },
+ };
- onOptionChange: function(server, instanceId) {
+ onOptionChange = (server, instanceId) => {
// clear next batch so we don't try to load more rooms
this.nextBatch = null;
this.setState({
@@ -313,15 +309,15 @@ export default createReactClass({
// find the five gitter ones, at which point we do not want
// to render all those rooms when switching back to 'all networks'.
// Easiest to just blow away the state & re-fetch.
- },
+ };
- onFillRequest: function(backwards) {
+ onFillRequest = (backwards) => {
if (backwards || !this.nextBatch) return Promise.resolve(false);
return this.getMoreRooms();
- },
+ };
- onFilterChange: function(alias) {
+ onFilterChange = (alias) => {
this.setState({
filterString: alias || null,
});
@@ -337,9 +333,9 @@ export default createReactClass({
this.filterTimeout = null;
this.refreshRoomList();
}, 700);
- },
+ };
- onFilterClear: function() {
+ onFilterClear = () => {
// update immediately
this.setState({
filterString: null,
@@ -348,9 +344,9 @@ export default createReactClass({
if (this.filterTimeout) {
clearTimeout(this.filterTimeout);
}
- },
+ };
- onJoinFromSearchClick: function(alias) {
+ onJoinFromSearchClick = (alias) => {
// If we don't have a particular instance id selected, just show that rooms alias
if (!this.state.instanceId || this.state.instanceId === ALL_ROOMS) {
// If the user specified an alias without a domain, add on whichever server is selected
@@ -391,9 +387,9 @@ export default createReactClass({
});
});
}
- },
+ };
- onPreviewClick: function(ev, room) {
+ onPreviewClick = (ev, room) => {
this.props.onFinished();
dis.dispatch({
action: 'view_room',
@@ -401,9 +397,9 @@ export default createReactClass({
should_peek: true,
});
ev.stopPropagation();
- },
+ };
- onViewClick: function(ev, room) {
+ onViewClick = (ev, room) => {
this.props.onFinished();
dis.dispatch({
action: 'view_room',
@@ -411,26 +407,26 @@ export default createReactClass({
should_peek: false,
});
ev.stopPropagation();
- },
+ };
- onJoinClick: function(ev, room) {
+ onJoinClick = (ev, room) => {
this.showRoom(room, null, true);
ev.stopPropagation();
- },
+ };
- onCreateRoomClick: function(room) {
+ onCreateRoomClick = room => {
this.props.onFinished();
dis.dispatch({
action: 'view_create_room',
public: true,
});
- },
+ };
- showRoomAlias: function(alias, autoJoin=false) {
+ showRoomAlias(alias, autoJoin=false) {
this.showRoom(null, alias, autoJoin);
- },
+ }
- showRoom: function(room, room_alias, autoJoin=false) {
+ showRoom(room, room_alias, autoJoin=false) {
this.props.onFinished();
const payload = {
action: 'view_room',
@@ -474,7 +470,7 @@ export default createReactClass({
payload.room_id = room.room_id;
}
dis.dispatch(payload);
- },
+ }
getRow(room) {
const client = MatrixClientPeg.get();
@@ -540,22 +536,22 @@ export default createReactClass({
{joinOrViewButton}
);
- },
+ }
- collectScrollPanel: function(element) {
+ collectScrollPanel = (element) => {
this.scrollPanel = element;
- },
+ };
- _stringLooksLikeId: function(s, field_type) {
+ _stringLooksLikeId(s, field_type) {
let pat = /^#[^\s]+:[^\s]/;
if (field_type && field_type.regexp) {
pat = new RegExp(field_type.regexp);
}
return pat.test(s);
- },
+ }
- _getFieldsForThirdPartyLocation: function(userInput, protocol, instance) {
+ _getFieldsForThirdPartyLocation(userInput, protocol, instance) {
// make an object with the fields specified by that protocol. We
// require that the values of all but the last field come from the
// instance. The last is the user input.
@@ -569,20 +565,20 @@ export default createReactClass({
}
fields[requiredFields[requiredFields.length - 1]] = userInput;
return fields;
- },
+ }
/**
* called by the parent component when PageUp/Down/etc is pressed.
*
* We pass it down to the scroll panel.
*/
- handleScrollKey: function(ev) {
+ handleScrollKey = ev => {
if (this.scrollPanel) {
this.scrollPanel.handleScrollKey(ev);
}
- },
+ };
- render: function() {
+ render() {
const Loader = sdk.getComponent("elements.Spinner");
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
@@ -712,8 +708,8 @@ export default createReactClass({
);
- },
-});
+ }
+}
// Similar to matrix-react-sdk's MatrixTools.getDisplayAliasForRoom
// but works with the objects we get from the public room list
diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js
index 3171dbccbe..cdaa0bb7f9 100644
--- a/src/components/structures/RoomStatusBar.js
+++ b/src/components/structures/RoomStatusBar.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import Matrix from 'matrix-js-sdk';
import { _t, _td } from '../../languageHandler';
@@ -39,10 +38,8 @@ function getUnsentMessages(room) {
});
}
-export default createReactClass({
- displayName: 'RoomStatusBar',
-
- propTypes: {
+export default class RoomStatusBar extends React.Component {
+ static propTypes = {
// the room this statusbar is representing.
room: PropTypes.object.isRequired,
// This is true when the user is alone in the room, but has also sent a message.
@@ -86,37 +83,35 @@ export default createReactClass({
// callback for when the status bar is displaying something and should
// be visible
onVisible: PropTypes.func,
- },
+ };
- getInitialState: function() {
- return {
- syncState: MatrixClientPeg.get().getSyncState(),
- syncStateData: MatrixClientPeg.get().getSyncStateData(),
- unsentMessages: getUnsentMessages(this.props.room),
- };
- },
+ state = {
+ syncState: MatrixClientPeg.get().getSyncState(),
+ syncStateData: MatrixClientPeg.get().getSyncStateData(),
+ unsentMessages: getUnsentMessages(this.props.room),
+ };
- componentDidMount: function() {
+ componentDidMount() {
MatrixClientPeg.get().on("sync", this.onSyncStateChange);
MatrixClientPeg.get().on("Room.localEchoUpdated", this._onRoomLocalEchoUpdated);
this._checkSize();
- },
+ }
- componentDidUpdate: function() {
+ componentDidUpdate() {
this._checkSize();
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
// we may have entirely lost our client as we're logging out before clicking login on the guest bar...
const client = MatrixClientPeg.get();
if (client) {
client.removeListener("sync", this.onSyncStateChange);
client.removeListener("Room.localEchoUpdated", this._onRoomLocalEchoUpdated);
}
- },
+ }
- onSyncStateChange: function(state, prevState, data) {
+ onSyncStateChange = (state, prevState, data) => {
if (state === "SYNCING" && prevState === "SYNCING") {
return;
}
@@ -124,39 +119,39 @@ export default createReactClass({
syncState: state,
syncStateData: data,
});
- },
+ };
- _onResendAllClick: function() {
+ _onResendAllClick = () => {
Resend.resendUnsentEvents(this.props.room);
dis.fire(Action.FocusComposer);
- },
+ };
- _onCancelAllClick: function() {
+ _onCancelAllClick = () => {
Resend.cancelUnsentEvents(this.props.room);
dis.fire(Action.FocusComposer);
- },
+ };
- _onRoomLocalEchoUpdated: function(event, room, oldEventId, oldStatus) {
+ _onRoomLocalEchoUpdated = (event, room, oldEventId, oldStatus) => {
if (room.roomId !== this.props.room.roomId) return;
this.setState({
unsentMessages: getUnsentMessages(this.props.room),
});
- },
+ };
// Check whether current size is greater than 0, if yes call props.onVisible
- _checkSize: function() {
+ _checkSize() {
if (this._getSize()) {
if (this.props.onVisible) this.props.onVisible();
} else {
if (this.props.onHidden) this.props.onHidden();
}
- },
+ }
// We don't need the actual height - just whether it is likely to have
// changed - so we use '0' to indicate normal size, and other values to
// indicate other sizes.
- _getSize: function() {
+ _getSize() {
if (this._shouldShowConnectionError() ||
this.props.hasActiveCall ||
this.props.sentMessageAndIsAlone
@@ -166,10 +161,10 @@ export default createReactClass({
return STATUS_BAR_EXPANDED_LARGE;
}
return STATUS_BAR_HIDDEN;
- },
+ }
// return suitable content for the image on the left of the status bar.
- _getIndicator: function() {
+ _getIndicator() {
if (this.props.hasActiveCall) {
const TintableSvg = sdk.getComponent("elements.TintableSvg");
return (
@@ -182,9 +177,9 @@ export default createReactClass({
}
return null;
- },
+ }
- _shouldShowConnectionError: function() {
+ _shouldShowConnectionError() {
// no conn bar trumps the "some not sent" msg since you can't resend without
// a connection!
// There's one situation in which we don't show this 'no connection' bar, and that's
@@ -195,9 +190,9 @@ export default createReactClass({
this.state.syncStateData.error.errcode === 'M_RESOURCE_LIMIT_EXCEEDED',
);
return this.state.syncState === "ERROR" && !errorIsMauError;
- },
+ }
- _getUnsentMessageContent: function() {
+ _getUnsentMessageContent() {
const unsentMessages = this.state.unsentMessages;
if (!unsentMessages.length) return null;
@@ -272,10 +267,10 @@ export default createReactClass({
;
- },
+ }
// return suitable content for the main (text) part of the status bar.
- _getContent: function() {
+ _getContent() {
if (this._shouldShowConnectionError()) {
return (
@@ -323,9 +318,9 @@ export default createReactClass({
}
return null;
- },
+ }
- render: function() {
+ render() {
const content = this._getContent();
const indicator = this._getIndicator();
@@ -339,5 +334,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index a79e5b0aa8..157f7266fa 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -24,7 +24,6 @@ limitations under the License.
import shouldHideEvent from '../../shouldHideEvent';
import React, {createRef} from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { _t } from '../../languageHandler';
@@ -68,9 +67,8 @@ if (DEBUG) {
debuglog = console.log.bind(console);
}
-export default createReactClass({
- displayName: 'RoomView',
- propTypes: {
+export default class RoomView extends React.Component {
+ static propTypes = {
ConferenceHandler: PropTypes.any,
// Called with the credentials of a registered user (if they were a ROU that
@@ -97,15 +95,15 @@ export default createReactClass({
// Servers the RoomView can use to try and assist joins
viaServers: PropTypes.arrayOf(PropTypes.string),
- },
+ };
- statics: {
- contextType: MatrixClientContext,
- },
+ static contextType = MatrixClientContext;
+
+ constructor(props) {
+ super(props);
- getInitialState: function() {
const llMembers = this.context.hasLazyLoadMembersEnabled();
- return {
+ this.state = {
room: null,
roomId: null,
roomLoading: true,
@@ -171,10 +169,7 @@ export default createReactClass({
matrixClientIsReady: this.context && this.context.isInitialSyncComplete(),
};
- },
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this.dispatcherRef = dis.register(this.onAction);
this.context.on("Room", this.onRoom);
this.context.on("Room.timeline", this.onRoomTimeline);
@@ -201,15 +196,15 @@ export default createReactClass({
this._searchResultsPanel = createRef();
this._layoutWatcherRef = SettingsStore.watchSetting("useIRCLayout", null, this.onLayoutChange);
- },
+ }
- _onReadReceiptsChange: function() {
+ _onReadReceiptsChange = () => {
this.setState({
showReadReceipts: SettingsStore.getValue("showReadReceipts", this.state.roomId),
});
- },
+ };
- _onRoomViewStoreUpdate: function(initial) {
+ _onRoomViewStoreUpdate = initial => {
if (this.unmounted) {
return;
}
@@ -303,7 +298,7 @@ export default createReactClass({
if (initial) {
this._setupRoom(newState.room, newState.roomId, newState.joining, newState.shouldPeek);
}
- },
+ };
_getRoomId() {
// According to `_onRoomViewStoreUpdate`, `state.roomId` can be null
@@ -312,9 +307,9 @@ export default createReactClass({
// the bare room ID. (We may want to update `state.roomId` after
// resolving aliases, so we could always trust it.)
return this.state.room ? this.state.room.roomId : this.state.roomId;
- },
+ }
- _getPermalinkCreatorForRoom: function(room) {
+ _getPermalinkCreatorForRoom(room) {
if (!this._permalinkCreators) this._permalinkCreators = {};
if (this._permalinkCreators[room.roomId]) return this._permalinkCreators[room.roomId];
@@ -327,22 +322,22 @@ export default createReactClass({
this._permalinkCreators[room.roomId].load();
}
return this._permalinkCreators[room.roomId];
- },
+ }
- _stopAllPermalinkCreators: function() {
+ _stopAllPermalinkCreators() {
if (!this._permalinkCreators) return;
for (const roomId of Object.keys(this._permalinkCreators)) {
this._permalinkCreators[roomId].stop();
}
- },
+ }
- _onWidgetEchoStoreUpdate: function() {
+ _onWidgetEchoStoreUpdate = () => {
this.setState({
showApps: this._shouldShowApps(this.state.room),
});
- },
+ };
- _setupRoom: function(room, roomId, joining, shouldPeek) {
+ _setupRoom(room, roomId, joining, shouldPeek) {
// if this is an unknown room then we're in one of three states:
// - This is a room we can peek into (search engine) (we can /peek)
// - This is a room we can publicly join or were invited to. (we can /join)
@@ -404,9 +399,9 @@ export default createReactClass({
this.setState({isPeeking: false});
}
}
- },
+ }
- _shouldShowApps: function(room) {
+ _shouldShowApps(room) {
if (!BROWSER_SUPPORTS_SANDBOX) return false;
// Check if user has previously chosen to hide the app drawer for this
@@ -417,9 +412,9 @@ export default createReactClass({
// This is confusing, but it means to say that we default to the tray being
// hidden unless the user clicked to open it.
return hideWidgetDrawer === "false";
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
const call = this._getCallForRoom();
const callState = call ? call.call_state : "ended";
this.setState({
@@ -435,14 +430,14 @@ export default createReactClass({
this.onResize();
document.addEventListener("keydown", this.onNativeKeyDown);
- },
+ }
- shouldComponentUpdate: function(nextProps, nextState) {
+ shouldComponentUpdate(nextProps, nextState) {
return (!ObjectUtils.shallowEqual(this.props, nextProps) ||
!ObjectUtils.shallowEqual(this.state, nextState));
- },
+ }
- componentDidUpdate: function() {
+ componentDidUpdate() {
if (this._roomView.current) {
const roomView = this._roomView.current;
if (!roomView.ondrop) {
@@ -464,9 +459,9 @@ export default createReactClass({
atEndOfLiveTimeline: this._messagePanel.isAtEndOfLiveTimeline(),
});
}
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
// set a boolean to say we've been unmounted, which any pending
// promises can use to throw away their results.
//
@@ -543,21 +538,21 @@ export default createReactClass({
// Tinter.tint(); // reset colourscheme
SettingsStore.unwatchSetting(this._layoutWatcherRef);
- },
+ }
- onLayoutChange: function() {
+ onLayoutChange = () => {
this.setState({
useIRCLayout: SettingsStore.getValue("useIRCLayout"),
});
- },
+ };
- _onRightPanelStoreUpdate: function() {
+ _onRightPanelStoreUpdate = () => {
this.setState({
showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
});
- },
+ };
- onPageUnload(event) {
+ onPageUnload = event => {
if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) {
return event.returnValue =
_t("You seem to be uploading files, are you sure you want to quit?");
@@ -565,10 +560,10 @@ export default createReactClass({
return event.returnValue =
_t("You seem to be in a call, are you sure you want to quit?");
}
- },
+ };
// we register global shortcuts here, they *must not conflict* with local shortcuts elsewhere or both will fire
- onNativeKeyDown: function(ev) {
+ onNativeKeyDown = ev => {
let handled = false;
const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev);
@@ -592,9 +587,9 @@ export default createReactClass({
ev.stopPropagation();
ev.preventDefault();
}
- },
+ };
- onReactKeyDown: function(ev) {
+ onReactKeyDown = ev => {
let handled = false;
switch (ev.key) {
@@ -613,7 +608,7 @@ export default createReactClass({
break;
case Key.U.toUpperCase():
if (isOnlyCtrlOrCmdIgnoreShiftKeyEvent(ev) && ev.shiftKey) {
- dis.dispatch({ action: "upload_file" })
+ dis.dispatch({ action: "upload_file" });
handled = true;
}
break;
@@ -623,9 +618,9 @@ export default createReactClass({
ev.stopPropagation();
ev.preventDefault();
}
- },
+ };
- onAction: function(payload) {
+ onAction = payload => {
switch (payload.action) {
case 'message_send_failed':
case 'message_sent':
@@ -709,9 +704,9 @@ export default createReactClass({
}
break;
}
- },
+ };
- onRoomTimeline: function(ev, room, toStartOfTimeline, removed, data) {
+ onRoomTimeline = (ev, room, toStartOfTimeline, removed, data) => {
if (this.unmounted) return;
// ignore events for other rooms
@@ -747,51 +742,51 @@ export default createReactClass({
});
}
}
- },
+ };
- onRoomName: function(room) {
+ onRoomName = room => {
if (this.state.room && room.roomId == this.state.room.roomId) {
this.forceUpdate();
}
- },
+ };
- onRoomRecoveryReminderDontAskAgain: function() {
+ onRoomRecoveryReminderDontAskAgain = () => {
// Called when the option to not ask again is set:
// force an update to hide the recovery reminder
this.forceUpdate();
- },
+ };
- onKeyBackupStatus() {
+ onKeyBackupStatus = () => {
// Key backup status changes affect whether the in-room recovery
// reminder is displayed.
this.forceUpdate();
- },
+ };
- canResetTimeline: function() {
+ canResetTimeline = () => {
if (!this._messagePanel) {
return true;
}
return this._messagePanel.canResetTimeline();
- },
+ };
// called when state.room is first initialised (either at initial load,
// after a successful peek, or after we join the room).
- _onRoomLoaded: function(room) {
+ _onRoomLoaded = room => {
this._calculatePeekRules(room);
this._updatePreviewUrlVisibility(room);
this._loadMembersIfJoined(room);
this._calculateRecommendedVersion(room);
this._updateE2EStatus(room);
this._updatePermissions(room);
- },
+ };
- _calculateRecommendedVersion: async function(room) {
+ async _calculateRecommendedVersion(room) {
this.setState({
upgradeRecommendation: await room.getRecommendedVersion(),
});
- },
+ }
- _loadMembersIfJoined: async function(room) {
+ async _loadMembersIfJoined(room) {
// lazy load members if enabled
if (this.context.hasLazyLoadMembersEnabled()) {
if (room && room.getMyMembership() === 'join') {
@@ -808,9 +803,9 @@ export default createReactClass({
}
}
}
- },
+ }
- _calculatePeekRules: function(room) {
+ _calculatePeekRules(room) {
const guestAccessEvent = room.currentState.getStateEvents("m.room.guest_access", "");
if (guestAccessEvent && guestAccessEvent.getContent().guest_access === "can_join") {
this.setState({
@@ -824,17 +819,17 @@ export default createReactClass({
canPeek: true,
});
}
- },
+ }
- _updatePreviewUrlVisibility: function({roomId}) {
+ _updatePreviewUrlVisibility({roomId}) {
// URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit
const key = this.context.isRoomEncrypted(roomId) ? 'urlPreviewsEnabled_e2ee' : 'urlPreviewsEnabled';
this.setState({
showUrlPreview: SettingsStore.getValue(key, roomId),
});
- },
+ }
- onRoom: function(room) {
+ onRoom = room => {
if (!room || room.roomId !== this.state.roomId) {
return;
}
@@ -843,32 +838,32 @@ export default createReactClass({
}, () => {
this._onRoomLoaded(room);
});
- },
+ };
- onDeviceVerificationChanged: function(userId, device) {
+ onDeviceVerificationChanged = (userId, device) => {
const room = this.state.room;
if (!room.currentState.getMember(userId)) {
return;
}
this._updateE2EStatus(room);
- },
+ };
- onUserVerificationChanged: function(userId, _trustStatus) {
+ onUserVerificationChanged = (userId, _trustStatus) => {
const room = this.state.room;
if (!room || !room.currentState.getMember(userId)) {
return;
}
this._updateE2EStatus(room);
- },
+ };
- onCrossSigningKeysChanged: function() {
+ onCrossSigningKeysChanged = () => {
const room = this.state.room;
if (room) {
this._updateE2EStatus(room);
}
- },
+ };
- _updateE2EStatus: async function(room) {
+ async _updateE2EStatus(room) {
if (!this.context.isRoomEncrypted(room.roomId)) {
return;
}
@@ -886,26 +881,26 @@ export default createReactClass({
this.setState({
e2eStatus: await shieldStatusForRoom(this.context, room),
});
- },
+ }
- updateTint: function() {
+ updateTint() {
const room = this.state.room;
if (!room) return;
console.log("Tinter.tint from updateTint");
const colorScheme = SettingsStore.getValue("roomColor", room.roomId);
Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color);
- },
+ }
- onAccountData: function(event) {
+ onAccountData = event => {
const type = event.getType();
if ((type === "org.matrix.preview_urls" || type === "im.vector.web.settings") && this.state.room) {
// non-e2ee url previews are stored in legacy event type `org.matrix.room.preview_urls`
this._updatePreviewUrlVisibility(this.state.room);
}
- },
+ };
- onRoomAccountData: function(event, room) {
+ onRoomAccountData = (event, room) => {
if (room.roomId == this.state.roomId) {
const type = event.getType();
if (type === "org.matrix.room.color_scheme") {
@@ -918,18 +913,18 @@ export default createReactClass({
this._updatePreviewUrlVisibility(room);
}
}
- },
+ };
- onRoomStateEvents: function(ev, state) {
+ onRoomStateEvents = (ev, state) => {
// ignore if we don't have a room yet
if (!this.state.room || this.state.room.roomId !== state.roomId) {
return;
}
this._updatePermissions(this.state.room);
- },
+ };
- onRoomStateMember: function(ev, state, member) {
+ onRoomStateMember = (ev, state, member) => {
// ignore if we don't have a room yet
if (!this.state.room) {
return;
@@ -941,17 +936,17 @@ export default createReactClass({
}
this._updateRoomMembers(member);
- },
+ };
- onMyMembership: function(room, membership, oldMembership) {
+ onMyMembership = (room, membership, oldMembership) => {
if (room.roomId === this.state.roomId) {
this.forceUpdate();
this._loadMembersIfJoined(room);
this._updatePermissions(room);
}
- },
+ };
- _updatePermissions: function(room) {
+ _updatePermissions(room) {
if (room) {
const me = this.context.getUserId();
const canReact = room.getMyMembership() === "join" && room.currentState.maySendEvent("m.reaction", me);
@@ -959,11 +954,11 @@ export default createReactClass({
this.setState({canReact, canReply});
}
- },
+ }
// rate limited because a power level change will emit an event for every
// member in the room.
- _updateRoomMembers: rate_limited_func(function(dueToMember) {
+ _updateRoomMembers = rate_limited_func((dueToMember) => {
// a member state changed in this room
// refresh the conf call notification state
this._updateConfCallNotification();
@@ -978,9 +973,9 @@ export default createReactClass({
this._checkIfAlone(this.state.room, memberCountInfluence);
this._updateE2EStatus(this.state.room);
- }, 500),
+ }, 500);
- _checkIfAlone: function(room, countInfluence) {
+ _checkIfAlone(room, countInfluence) {
let warnedAboutLonelyRoom = false;
if (localStorage) {
warnedAboutLonelyRoom = localStorage.getItem('mx_user_alone_warned_' + this.state.room.roomId);
@@ -993,9 +988,9 @@ export default createReactClass({
let joinedOrInvitedMemberCount = room.getJoinedMemberCount() + room.getInvitedMemberCount();
if (countInfluence) joinedOrInvitedMemberCount += countInfluence;
this.setState({isAlone: joinedOrInvitedMemberCount === 1});
- },
+ }
- _updateConfCallNotification: function() {
+ _updateConfCallNotification() {
const room = this.state.room;
if (!room || !this.props.ConferenceHandler) {
return;
@@ -1017,7 +1012,7 @@ export default createReactClass({
confMember.membership === "join"
),
});
- },
+ }
_updateDMState() {
const room = this.state.room;
@@ -1028,9 +1023,9 @@ export default createReactClass({
if (dmInviter) {
Rooms.setDMRoom(room.roomId, dmInviter);
}
- },
+ }
- onSearchResultsFillRequest: function(backwards) {
+ onSearchResultsFillRequest = backwards => {
if (!backwards) {
return Promise.resolve(false);
}
@@ -1043,25 +1038,25 @@ export default createReactClass({
debuglog("no more search results");
return Promise.resolve(false);
}
- },
+ };
- onInviteButtonClick: function() {
+ onInviteButtonClick = () => {
// call AddressPickerDialog
dis.dispatch({
action: 'view_invite',
roomId: this.state.room.roomId,
});
this.setState({isAlone: false}); // there's a good chance they'll invite someone
- },
+ };
- onStopAloneWarningClick: function() {
+ onStopAloneWarningClick = () => {
if (localStorage) {
localStorage.setItem('mx_user_alone_warned_' + this.state.room.roomId, true);
}
this.setState({isAlone: false});
- },
+ };
- onJoinButtonClicked: function(ev) {
+ onJoinButtonClicked = ev => {
// If the user is a ROU, allow them to transition to a PWLU
if (this.context && this.context.isGuest()) {
// Join this room once the user has registered and logged in
@@ -1120,10 +1115,9 @@ export default createReactClass({
return Promise.resolve();
});
}
+ };
- },
-
- onMessageListScroll: function(ev) {
+ onMessageListScroll = ev => {
if (this._messagePanel.isAtEndOfLiveTimeline()) {
this.setState({
numUnreadMessages: 0,
@@ -1135,9 +1129,9 @@ export default createReactClass({
});
}
this._updateTopUnreadMessagesBar();
- },
+ };
- onDragOver: function(ev) {
+ onDragOver = ev => {
ev.stopPropagation();
ev.preventDefault();
@@ -1154,9 +1148,9 @@ export default createReactClass({
ev.dataTransfer.dropEffect = 'copy';
}
}
- },
+ };
- onDrop: function(ev) {
+ onDrop = ev => {
ev.stopPropagation();
ev.preventDefault();
ContentMessages.sharedInstance().sendContentListToRoom(
@@ -1164,15 +1158,15 @@ export default createReactClass({
);
this.setState({ draggingFile: false });
dis.fire(Action.FocusComposer);
- },
+ };
- onDragLeaveOrEnd: function(ev) {
+ onDragLeaveOrEnd = ev => {
ev.stopPropagation();
ev.preventDefault();
this.setState({ draggingFile: false });
- },
+ };
- injectSticker: function(url, info, text) {
+ injectSticker(url, info, text) {
if (this.context.isGuest()) {
dis.dispatch({action: 'require_registration'});
return;
@@ -1185,9 +1179,9 @@ export default createReactClass({
return;
}
});
- },
+ }
- onSearch: function(term, scope) {
+ onSearch = (term, scope) => {
this.setState({
searchTerm: term,
searchScope: scope,
@@ -1213,9 +1207,9 @@ export default createReactClass({
debuglog("sending search request");
const searchPromise = eventSearch(term, roomId);
this._handleSearchResult(searchPromise);
- },
+ };
- _handleSearchResult: function(searchPromise) {
+ _handleSearchResult(searchPromise) {
const self = this;
// keep a record of the current search id, so that if the search terms
@@ -1266,9 +1260,9 @@ export default createReactClass({
searchInProgress: false,
});
});
- },
+ }
- getSearchResultTiles: function() {
+ getSearchResultTiles() {
const SearchResultTile = sdk.getComponent('rooms.SearchResultTile');
const Spinner = sdk.getComponent("elements.Spinner");
@@ -1348,20 +1342,20 @@ export default createReactClass({
onHeightChanged={onHeightChanged} />);
}
return ret;
- },
+ }
- onPinnedClick: function() {
+ onPinnedClick = () => {
const nowShowingPinned = !this.state.showingPinned;
const roomId = this.state.room.roomId;
this.setState({showingPinned: nowShowingPinned, searching: false});
SettingsStore.setValue("PinnedEvents.isOpen", roomId, SettingLevel.ROOM_DEVICE, nowShowingPinned);
- },
+ };
- onSettingsClick: function() {
+ onSettingsClick = () => {
dis.dispatch({ action: 'open_room_settings' });
- },
+ };
- onCancelClick: function() {
+ onCancelClick = () => {
console.log("updateTint from onCancelClick");
this.updateTint();
if (this.state.forwardingEvent) {
@@ -1371,23 +1365,23 @@ export default createReactClass({
});
}
dis.fire(Action.FocusComposer);
- },
+ };
- onLeaveClick: function() {
+ onLeaveClick = () => {
dis.dispatch({
action: 'leave_room',
room_id: this.state.room.roomId,
});
- },
+ };
- onForgetClick: function() {
+ onForgetClick = () => {
dis.dispatch({
action: 'forget_room',
room_id: this.state.room.roomId,
});
- },
+ };
- onRejectButtonClicked: function(ev) {
+ onRejectButtonClicked = ev => {
const self = this;
this.setState({
rejecting: true,
@@ -1412,9 +1406,9 @@ export default createReactClass({
rejectError: error,
});
});
- },
+ };
- onRejectAndIgnoreClick: async function() {
+ onRejectAndIgnoreClick = async () => {
this.setState({
rejecting: true,
});
@@ -1446,49 +1440,49 @@ export default createReactClass({
rejectError: error,
});
}
- },
+ };
- onRejectThreepidInviteButtonClicked: function(ev) {
+ onRejectThreepidInviteButtonClicked = ev => {
// We can reject 3pid invites in the same way that we accept them,
// using /leave rather than /join. In the short term though, we
// just ignore them.
// https://github.com/vector-im/vector-web/issues/1134
dis.fire(Action.ViewRoomDirectory);
- },
+ };
- onSearchClick: function() {
+ onSearchClick = () => {
this.setState({
searching: !this.state.searching,
showingPinned: false,
});
- },
+ };
- onCancelSearchClick: function() {
+ onCancelSearchClick = () => {
this.setState({
searching: false,
searchResults: null,
});
- },
+ };
// jump down to the bottom of this room, where new events are arriving
- jumpToLiveTimeline: function() {
+ jumpToLiveTimeline = () => {
this._messagePanel.jumpToLiveTimeline();
dis.fire(Action.FocusComposer);
- },
+ };
// jump up to wherever our read marker is
- jumpToReadMarker: function() {
+ jumpToReadMarker = () => {
this._messagePanel.jumpToReadMarker();
- },
+ };
// update the read marker to match the read-receipt
- forgetReadMarker: function(ev) {
+ forgetReadMarker = ev => {
ev.stopPropagation();
this._messagePanel.forgetReadMarker();
- },
+ };
// decide whether or not the top 'unread messages' bar should be shown
- _updateTopUnreadMessagesBar: function() {
+ _updateTopUnreadMessagesBar = () => {
if (!this._messagePanel) {
return;
}
@@ -1497,12 +1491,12 @@ export default createReactClass({
if (this.state.showTopUnreadMessagesBar != showBar) {
this.setState({showTopUnreadMessagesBar: showBar});
}
- },
+ };
// get the current scroll position of the room, so that it can be
// restored when we switch back to it.
//
- _getScrollState: function() {
+ _getScrollState() {
const messagePanel = this._messagePanel;
if (!messagePanel) return null;
@@ -1537,9 +1531,9 @@ export default createReactClass({
focussedEvent: scrollState.trackedScrollToken,
pixelOffset: scrollState.pixelOffset,
};
- },
+ }
- onResize: function() {
+ onResize = () => {
// It seems flexbox doesn't give us a way to constrain the auxPanel height to have
// a minimum of the height of the video element, whilst also capping it from pushing out the page
// so we have to do it via JS instead. In this implementation we cap the height by putting
@@ -1557,16 +1551,16 @@ export default createReactClass({
if (auxPanelMaxHeight < 50) auxPanelMaxHeight = 50;
this.setState({auxPanelMaxHeight: auxPanelMaxHeight});
- },
+ };
- onFullscreenClick: function() {
+ onFullscreenClick = () => {
dis.dispatch({
action: 'video_fullscreen',
fullscreen: true,
}, true);
- },
+ };
- onMuteAudioClick: function() {
+ onMuteAudioClick = () => {
const call = this._getCallForRoom();
if (!call) {
return;
@@ -1574,9 +1568,9 @@ export default createReactClass({
const newState = !call.isMicrophoneMuted();
call.setMicrophoneMuted(newState);
this.forceUpdate(); // TODO: just update the voip buttons
- },
+ };
- onMuteVideoClick: function() {
+ onMuteVideoClick = () => {
const call = this._getCallForRoom();
if (!call) {
return;
@@ -1584,29 +1578,29 @@ export default createReactClass({
const newState = !call.isLocalVideoMuted();
call.setLocalVideoMuted(newState);
this.forceUpdate(); // TODO: just update the voip buttons
- },
+ };
- onStatusBarVisible: function() {
+ onStatusBarVisible = () => {
if (this.unmounted) return;
this.setState({
statusBarVisible: true,
});
- },
+ };
- onStatusBarHidden: function() {
+ onStatusBarHidden = () => {
// This is currently not desired as it is annoying if it keeps expanding and collapsing
if (this.unmounted) return;
this.setState({
statusBarVisible: false,
});
- },
+ };
/**
* called by the parent component when PageUp/Down/etc is pressed.
*
* We pass it down to the scroll panel.
*/
- handleScrollKey: function(ev) {
+ handleScrollKey = ev => {
let panel;
if (this._searchResultsPanel.current) {
panel = this._searchResultsPanel.current;
@@ -1617,48 +1611,48 @@ export default createReactClass({
if (panel) {
panel.handleScrollKey(ev);
}
- },
+ };
/**
* get any current call for this room
*/
- _getCallForRoom: function() {
+ _getCallForRoom() {
if (!this.state.room) {
return null;
}
return CallHandler.getCallForRoom(this.state.room.roomId);
- },
+ }
// this has to be a proper method rather than an unnamed function,
// otherwise react calls it with null on each update.
- _gatherTimelinePanelRef: function(r) {
+ _gatherTimelinePanelRef = r => {
this._messagePanel = r;
if (r) {
console.log("updateTint from RoomView._gatherTimelinePanelRef");
this.updateTint();
}
- },
+ };
- _getOldRoom: function() {
+ _getOldRoom() {
const createEvent = this.state.room.currentState.getStateEvents("m.room.create", "");
if (!createEvent || !createEvent.getContent()['predecessor']) return null;
return this.context.getRoom(createEvent.getContent()['predecessor']['room_id']);
- },
+ }
- _getHiddenHighlightCount: function() {
+ _getHiddenHighlightCount() {
const oldRoom = this._getOldRoom();
if (!oldRoom) return 0;
return oldRoom.getUnreadNotificationCount('highlight');
- },
+ }
- _onHiddenHighlightsClick: function() {
+ _onHiddenHighlightsClick = () => {
const oldRoom = this._getOldRoom();
if (!oldRoom) return;
dis.dispatch({action: "view_room", room_id: oldRoom.roomId});
- },
+ };
- render: function() {
+ render() {
const RoomHeader = sdk.getComponent('rooms.RoomHeader');
const ForwardMessage = sdk.getComponent("rooms.ForwardMessage");
const AuxPanel = sdk.getComponent("rooms.AuxPanel");
@@ -2118,5 +2112,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js
index 51113f4f56..ef21b5d787 100644
--- a/src/components/structures/ScrollPanel.js
+++ b/src/components/structures/ScrollPanel.js
@@ -15,7 +15,6 @@ limitations under the License.
*/
import React, {createRef} from "react";
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { Key } from '../../Keyboard';
import Timer from '../../utils/Timer';
@@ -84,10 +83,8 @@ if (DEBUG_SCROLL) {
* offset as normal.
*/
-export default createReactClass({
- displayName: 'ScrollPanel',
-
- propTypes: {
+export default class ScrollPanel extends React.Component {
+ static propTypes = {
/* stickyBottom: if set to true, then once the user hits the bottom of
* the list, any new children added to the list will cause the list to
* scroll down to show the new element, rather than preserving the
@@ -149,20 +146,19 @@ export default createReactClass({
* of the wrapper
*/
fixedChildren: PropTypes.node,
- },
+ };
- getDefaultProps: function() {
- return {
- stickyBottom: true,
- startAtBottom: true,
- onFillRequest: function(backwards) { return Promise.resolve(false); },
- onUnfillRequest: function(backwards, scrollToken) {},
- onScroll: function() {},
- };
- },
+ static defaultProps = {
+ stickyBottom: true,
+ startAtBottom: true,
+ onFillRequest: function(backwards) { return Promise.resolve(false); },
+ onUnfillRequest: function(backwards, scrollToken) {},
+ onScroll: function() {},
+ };
+
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this._pendingFillRequests = {b: null, f: null};
if (this.props.resizeNotifier) {
@@ -172,13 +168,13 @@ export default createReactClass({
this.resetScrollState();
this._itemlist = createRef();
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
this.checkScroll();
- },
+ }
- componentDidUpdate: function() {
+ componentDidUpdate() {
// after adding event tiles, we may need to tweak the scroll (either to
// keep at the bottom of the timeline, or to maintain the view after
// adding events to the top).
@@ -186,9 +182,9 @@ export default createReactClass({
// This will also re-check the fill state, in case the paginate was inadequate
this.checkScroll();
this.updatePreventShrinking();
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
// set a boolean to say we've been unmounted, which any pending
// promises can use to throw away their results.
//
@@ -198,41 +194,41 @@ export default createReactClass({
if (this.props.resizeNotifier) {
this.props.resizeNotifier.removeListener("middlePanelResized", this.onResize);
}
- },
+ }
- onScroll: function(ev) {
+ onScroll = ev => {
debuglog("onScroll", this._getScrollNode().scrollTop);
this._scrollTimeout.restart();
this._saveScrollState();
this.updatePreventShrinking();
this.props.onScroll(ev);
this.checkFillState();
- },
+ };
- onResize: function() {
+ onResize = () => {
this.checkScroll();
// update preventShrinkingState if present
if (this.preventShrinkingState) {
this.preventShrinking();
}
- },
+ };
// after an update to the contents of the panel, check that the scroll is
// where it ought to be, and set off pagination requests if necessary.
- checkScroll: function() {
+ checkScroll = () => {
if (this.unmounted) {
return;
}
this._restoreSavedScrollState();
this.checkFillState();
- },
+ };
// return true if the content is fully scrolled down right now; else false.
//
// note that this is independent of the 'stuckAtBottom' state - it is simply
// about whether the content is scrolled down right now, irrespective of
// whether it will stay that way when the children update.
- isAtBottom: function() {
+ isAtBottom = () => {
const sn = this._getScrollNode();
// fractional values (both too big and too small)
// for scrollTop happen on certain browsers/platforms
@@ -240,7 +236,7 @@ export default createReactClass({
// so check difference <= 1;
return Math.abs(sn.scrollHeight - (sn.scrollTop + sn.clientHeight)) <= 1;
- },
+ };
// returns the vertical height in the given direction that can be removed from
// the content box (which has a height of scrollHeight, see checkFillState) without
@@ -273,7 +269,7 @@ export default createReactClass({
// |#########| - |
// |#########| |
// `---------' -
- _getExcessHeight: function(backwards) {
+ _getExcessHeight(backwards) {
const sn = this._getScrollNode();
const contentHeight = this._getMessagesHeight();
const listHeight = this._getListHeight();
@@ -285,10 +281,10 @@ export default createReactClass({
} else {
return contentHeight - (unclippedScrollTop + 2*sn.clientHeight) - UNPAGINATION_PADDING;
}
- },
+ }
// check the scroll state and send out backfill requests if necessary.
- checkFillState: async function(depth=0) {
+ checkFillState = async (depth=0) => {
if (this.unmounted) {
return;
}
@@ -368,10 +364,10 @@ export default createReactClass({
this._fillRequestWhileRunning = false;
this.checkFillState();
}
- },
+ };
// check if unfilling is possible and send an unfill request if necessary
- _checkUnfillState: function(backwards) {
+ _checkUnfillState(backwards) {
let excessHeight = this._getExcessHeight(backwards);
if (excessHeight <= 0) {
return;
@@ -417,10 +413,10 @@ export default createReactClass({
this.props.onUnfillRequest(backwards, markerScrollToken);
}, UNFILL_REQUEST_DEBOUNCE_MS);
}
- },
+ }
// check if there is already a pending fill request. If not, set one off.
- _maybeFill: function(depth, backwards) {
+ _maybeFill(depth, backwards) {
const dir = backwards ? 'b' : 'f';
if (this._pendingFillRequests[dir]) {
debuglog("Already a "+dir+" fill in progress - not starting another");
@@ -456,7 +452,7 @@ export default createReactClass({
return this.checkFillState(depth + 1);
}
});
- },
+ }
/* get the current scroll state. This returns an object with the following
* properties:
@@ -472,9 +468,7 @@ export default createReactClass({
* the number of pixels the bottom of the tracked child is above the
* bottom of the scroll panel.
*/
- getScrollState: function() {
- return this.scrollState;
- },
+ getScrollState = () => this.scrollState;
/* reset the saved scroll state.
*
@@ -488,7 +482,7 @@ export default createReactClass({
* no use if no children exist yet, or if you are about to replace the
* child list.)
*/
- resetScrollState: function() {
+ resetScrollState = () => {
this.scrollState = {
stuckAtBottom: this.props.startAtBottom,
};
@@ -496,20 +490,20 @@ export default createReactClass({
this._pages = 0;
this._scrollTimeout = new Timer(100);
this._heightUpdateInProgress = false;
- },
+ };
/**
* jump to the top of the content.
*/
- scrollToTop: function() {
+ scrollToTop = () => {
this._getScrollNode().scrollTop = 0;
this._saveScrollState();
- },
+ };
/**
* jump to the bottom of the content.
*/
- scrollToBottom: function() {
+ scrollToBottom = () => {
// the easiest way to make sure that the scroll state is correctly
// saved is to do the scroll, then save the updated state. (Calculating
// it ourselves is hard, and we can't rely on an onScroll callback
@@ -517,25 +511,25 @@ export default createReactClass({
const sn = this._getScrollNode();
sn.scrollTop = sn.scrollHeight;
this._saveScrollState();
- },
+ };
/**
* Page up/down.
*
* @param {number} mult: -1 to page up, +1 to page down
*/
- scrollRelative: function(mult) {
+ scrollRelative = mult => {
const scrollNode = this._getScrollNode();
const delta = mult * scrollNode.clientHeight * 0.5;
scrollNode.scrollBy(0, delta);
this._saveScrollState();
- },
+ };
/**
* Scroll up/down in response to a scroll key
* @param {object} ev the keyboard event
*/
- handleScrollKey: function(ev) {
+ handleScrollKey = ev => {
switch (ev.key) {
case Key.PAGE_UP:
if (!ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
@@ -561,7 +555,7 @@ export default createReactClass({
}
break;
}
- },
+ };
/* Scroll the panel to bring the DOM node with the scroll token
* `scrollToken` into view.
@@ -574,7 +568,7 @@ export default createReactClass({
* node (specifically, the bottom of it) will be positioned. If omitted, it
* defaults to 0.
*/
- scrollToToken: function(scrollToken, pixelOffset, offsetBase) {
+ scrollToToken = (scrollToken, pixelOffset, offsetBase) => {
pixelOffset = pixelOffset || 0;
offsetBase = offsetBase || 0;
@@ -596,9 +590,9 @@ export default createReactClass({
scrollNode.scrollTop = (trackedNode.offsetTop - (scrollNode.clientHeight * offsetBase)) + pixelOffset;
this._saveScrollState();
}
- },
+ };
- _saveScrollState: function() {
+ _saveScrollState() {
if (this.props.stickyBottom && this.isAtBottom()) {
this.scrollState = { stuckAtBottom: true };
debuglog("saved stuckAtBottom state");
@@ -641,9 +635,9 @@ export default createReactClass({
bottomOffset: bottomOffset,
pixelOffset: bottomOffset - viewportBottom, //needed for restoring the scroll position when coming back to the room
};
- },
+ }
- _restoreSavedScrollState: async function() {
+ async _restoreSavedScrollState() {
const scrollState = this.scrollState;
if (scrollState.stuckAtBottom) {
@@ -676,7 +670,8 @@ export default createReactClass({
} else {
debuglog("not updating height because request already in progress");
}
- },
+ }
+
// need a better name that also indicates this will change scrollTop? Rebalance height? Reveal content?
async _updateHeight() {
// wait until user has stopped scrolling
@@ -731,7 +726,7 @@ export default createReactClass({
debuglog("updateHeight to", {newHeight, topDiff});
}
}
- },
+ }
_getTrackedNode() {
const scrollState = this.scrollState;
@@ -764,11 +759,11 @@ export default createReactClass({
}
return scrollState.trackedNode;
- },
+ }
_getListHeight() {
return this._bottomGrowth + (this._pages * PAGE_SIZE);
- },
+ }
_getMessagesHeight() {
const itemlist = this._itemlist.current;
@@ -777,17 +772,17 @@ export default createReactClass({
const firstNodeTop = itemlist.firstElementChild ? itemlist.firstElementChild.offsetTop : 0;
// 18 is itemlist padding
return lastNodeBottom - firstNodeTop + (18 * 2);
- },
+ }
_topFromBottom(node) {
// current capped height - distance from top = distance from bottom of container to top of tracked element
return this._itemlist.current.clientHeight - node.offsetTop;
- },
+ }
/* get the DOM node which has the scrollTop property we care about for our
* message panel.
*/
- _getScrollNode: function() {
+ _getScrollNode() {
if (this.unmounted) {
// this shouldn't happen, but when it does, turn the NPE into
// something more meaningful.
@@ -801,18 +796,18 @@ export default createReactClass({
}
return this._divScroll;
- },
+ }
- _collectScroll: function(divScroll) {
+ _collectScroll = divScroll => {
this._divScroll = divScroll;
- },
+ };
/**
Mark the bottom offset of the last tile so we can balance it out when
anything below it changes, by calling updatePreventShrinking, to keep
the same minimum bottom offset, effectively preventing the timeline to shrink.
*/
- preventShrinking: function() {
+ preventShrinking = () => {
const messageList = this._itemlist.current;
const tiles = messageList && messageList.children;
if (!messageList) {
@@ -836,16 +831,16 @@ export default createReactClass({
offsetNode: lastTileNode,
};
debuglog("prevent shrinking, last tile ", offsetFromBottom, "px from bottom");
- },
+ };
/** Clear shrinking prevention. Used internally, and when the timeline is reloaded. */
- clearPreventShrinking: function() {
+ clearPreventShrinking = () => {
const messageList = this._itemlist.current;
const balanceElement = messageList && messageList.parentElement;
if (balanceElement) balanceElement.style.paddingBottom = null;
this.preventShrinkingState = null;
debuglog("prevent shrinking cleared");
- },
+ };
/**
update the container padding to balance
@@ -855,7 +850,7 @@ export default createReactClass({
from the bottom of the marked tile grows larger than
what it was when marking.
*/
- updatePreventShrinking: function() {
+ updatePreventShrinking = () => {
if (this.preventShrinkingState) {
const sn = this._getScrollNode();
const scrollState = this.scrollState;
@@ -885,9 +880,9 @@ export default createReactClass({
this.clearPreventShrinking();
}
}
- },
+ };
- render: function() {
+ render() {
// TODO: the classnames on the div and ol could do with being updated to
// reflect the fact that we don't necessarily contain a list of messages.
// it's not obvious why we have a separate div and ol anyway.
@@ -905,5 +900,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js
index 7e9d290bce..ed118466c6 100644
--- a/src/components/structures/SearchBox.js
+++ b/src/components/structures/SearchBox.js
@@ -16,7 +16,6 @@ limitations under the License.
*/
import React, {createRef} from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { Key } from '../../Keyboard';
import dis from '../../dispatcher/dispatcher';
@@ -24,10 +23,8 @@ import { throttle } from 'lodash';
import AccessibleButton from '../../components/views/elements/AccessibleButton';
import classNames from 'classnames';
-export default createReactClass({
- displayName: 'SearchBox',
-
- propTypes: {
+export default class SearchBox extends React.Component {
+ static propTypes = {
onSearch: PropTypes.func,
onCleared: PropTypes.func,
onKeyDown: PropTypes.func,
@@ -38,35 +35,32 @@ export default createReactClass({
// on room search focus action (it would be nicer to take
// this functionality out, but not obvious how that would work)
enableRoomSearchFocus: PropTypes.bool,
- },
+ };
- getDefaultProps: function() {
- return {
- enableRoomSearchFocus: false,
- };
- },
+ static defaultProps = {
+ enableRoomSearchFocus: false,
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this._search = createRef();
+
+ this.state = {
searchTerm: "",
blurred: true,
};
- },
+ }
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
- this._search = createRef();
- },
-
- componentDidMount: function() {
+ componentDidMount() {
this.dispatcherRef = dis.register(this.onAction);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
dis.unregister(this.dispatcherRef);
- },
+ }
- onAction: function(payload) {
+ onAction = payload => {
if (!this.props.enableRoomSearchFocus) return;
switch (payload.action) {
@@ -81,51 +75,51 @@ export default createReactClass({
}
break;
}
- },
+ };
- onChange: function() {
+ onChange = () => {
if (!this._search.current) return;
this.setState({ searchTerm: this._search.current.value });
this.onSearch();
- },
+ };
- onSearch: throttle(function() {
+ onSearch = throttle(() => {
this.props.onSearch(this._search.current.value);
- }, 200, {trailing: true, leading: true}),
+ }, 200, {trailing: true, leading: true});
- _onKeyDown: function(ev) {
+ _onKeyDown = ev => {
switch (ev.key) {
case Key.ESCAPE:
this._clearSearch("keyboard");
break;
}
if (this.props.onKeyDown) this.props.onKeyDown(ev);
- },
+ };
- _onFocus: function(ev) {
+ _onFocus = ev => {
this.setState({blurred: false});
ev.target.select();
if (this.props.onFocus) {
this.props.onFocus(ev);
}
- },
+ };
- _onBlur: function(ev) {
+ _onBlur = ev => {
this.setState({blurred: true});
if (this.props.onBlur) {
this.props.onBlur(ev);
}
- },
+ };
- _clearSearch: function(source) {
+ _clearSearch(source) {
this._search.current.value = "";
this.onChange();
if (this.props.onCleared) {
this.props.onCleared(source);
}
- },
+ }
- render: function() {
+ render() {
// check for collapsed here and
// not at parent so we keep
// searchTerm in our state
@@ -166,5 +160,5 @@ export default createReactClass({
{ clearButton }
);
- },
-});
+ }
+}
diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js
index a714b126ec..135b2a1c5c 100644
--- a/src/components/structures/TagPanel.js
+++ b/src/components/structures/TagPanel.js
@@ -16,7 +16,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import TagOrderStore from '../../stores/TagOrderStore';
import GroupActions from '../../actions/GroupActions';
@@ -32,21 +31,15 @@ import AutoHideScrollbar from "./AutoHideScrollbar";
import SettingsStore from "../../settings/SettingsStore";
import UserTagTile from "../views/elements/UserTagTile";
-const TagPanel = createReactClass({
- displayName: 'TagPanel',
+class TagPanel extends React.Component {
+ static contextType = MatrixClientContext;
- statics: {
- contextType: MatrixClientContext,
- },
+ state = {
+ orderedTags: [],
+ selectedTags: [],
+ };
- getInitialState() {
- return {
- orderedTags: [],
- selectedTags: [],
- };
- },
-
- componentDidMount: function() {
+ componentDidMount() {
this.unmounted = false;
this.context.on("Group.myMembership", this._onGroupMyMembership);
this.context.on("sync", this._onClientSync);
@@ -62,7 +55,7 @@ const TagPanel = createReactClass({
});
// This could be done by anything with a matrix client
dis.dispatch(GroupActions.fetchJoinedGroups(this.context));
- },
+ }
componentWillUnmount() {
this.unmounted = true;
@@ -71,14 +64,14 @@ const TagPanel = createReactClass({
if (this._tagOrderStoreToken) {
this._tagOrderStoreToken.remove();
}
- },
+ }
- _onGroupMyMembership() {
+ _onGroupMyMembership = () => {
if (this.unmounted) return;
dis.dispatch(GroupActions.fetchJoinedGroups(this.context));
- },
+ };
- _onClientSync(syncState, prevState) {
+ _onClientSync = (syncState, prevState) => {
// Consider the client reconnected if there is no error with syncing.
// This means the state could be RECONNECTING, SYNCING, PREPARED or CATCHUP.
const reconnected = syncState !== "ERROR" && prevState !== syncState;
@@ -86,18 +79,18 @@ const TagPanel = createReactClass({
// Load joined groups
dis.dispatch(GroupActions.fetchJoinedGroups(this.context));
}
- },
+ };
- onMouseDown(e) {
+ onMouseDown = e => {
// only dispatch if its not a no-op
if (this.state.selectedTags.length > 0) {
dis.dispatch({action: 'deselect_tags'});
}
- },
+ };
- onClearFilterClick(ev) {
+ onClearFilterClick = ev => {
dis.dispatch({action: 'deselect_tags'});
- },
+ };
renderGlobalIcon() {
if (!SettingsStore.getValue("feature_communities_v2_prototypes")) return null;
@@ -108,7 +101,7 @@ const TagPanel = createReactClass({
);
- },
+ }
render() {
const DNDTagTile = sdk.getComponent('elements.DNDTagTile');
@@ -173,6 +166,6 @@ const TagPanel = createReactClass({
;
- },
-});
+ }
+}
export default TagPanel;
diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js
index 2313b60ab1..d9cec2e054 100644
--- a/src/components/structures/TimelinePanel.js
+++ b/src/components/structures/TimelinePanel.js
@@ -19,7 +19,6 @@ limitations under the License.
import SettingsStore from "../../settings/SettingsStore";
import React, {createRef} from 'react';
-import createReactClass from 'create-react-class';
import ReactDOM from "react-dom";
import PropTypes from 'prop-types';
import {EventTimeline} from "matrix-js-sdk";
@@ -54,10 +53,8 @@ if (DEBUG) {
*
* Also responsible for handling and sending read receipts.
*/
-const TimelinePanel = createReactClass({
- displayName: 'TimelinePanel',
-
- propTypes: {
+class TimelinePanel extends React.Component {
+ static propTypes = {
// The js-sdk EventTimelineSet object for the timeline sequence we are
// representing. This may or may not have a room, depending on what it's
// a timeline representing. If it has a room, we maintain RRs etc for
@@ -115,23 +112,35 @@ const TimelinePanel = createReactClass({
// whether to use the irc layout
useIRCLayout: PropTypes.bool,
- },
+ }
- statics: {
- // a map from room id to read marker event timestamp
- roomReadMarkerTsMap: {},
- },
+ // a map from room id to read marker event timestamp
+ static roomReadMarkerTsMap = {};
- getDefaultProps: function() {
- return {
- // By default, disable the timelineCap in favour of unpaginating based on
- // event tile heights. (See _unpaginateEvents)
- timelineCap: Number.MAX_VALUE,
- className: 'mx_RoomView_messagePanel',
- };
- },
+ static defaultProps = {
+ // By default, disable the timelineCap in favour of unpaginating based on
+ // event tile heights. (See _unpaginateEvents)
+ timelineCap: Number.MAX_VALUE,
+ className: 'mx_RoomView_messagePanel',
+ };
+
+ constructor(props) {
+ super(props);
+
+ debuglog("TimelinePanel: mounting");
+
+ this.lastRRSentEventId = undefined;
+ this.lastRMSentEventId = undefined;
+
+ this._messagePanel = createRef();
+
+ if (this.props.manageReadReceipts) {
+ this.updateReadReceiptOnUserActivity();
+ }
+ if (this.props.manageReadMarkers) {
+ this.updateReadMarkerOnUserActivity();
+ }
- getInitialState: function() {
// XXX: we could track RM per TimelineSet rather than per Room.
// but for now we just do it per room for simplicity.
let initialReadMarker = null;
@@ -144,7 +153,7 @@ const TimelinePanel = createReactClass({
}
}
- return {
+ this.state = {
events: [],
liveEvents: [],
timelineLoading: true, // track whether our room timeline is loading
@@ -203,24 +212,6 @@ const TimelinePanel = createReactClass({
// how long to show the RM for when it's scrolled off-screen
readMarkerOutOfViewThresholdMs: SettingsStore.getValue("readMarkerOutOfViewThresholdMs"),
};
- },
-
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
- debuglog("TimelinePanel: mounting");
-
- this.lastRRSentEventId = undefined;
- this.lastRMSentEventId = undefined;
-
- this._messagePanel = createRef();
-
- if (this.props.manageReadReceipts) {
- this.updateReadReceiptOnUserActivity();
- }
- if (this.props.manageReadMarkers) {
- this.updateReadMarkerOnUserActivity();
- }
-
this.dispatcherRef = dis.register(this.onAction);
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
@@ -236,10 +227,10 @@ const TimelinePanel = createReactClass({
MatrixClientPeg.get().on("sync", this.onSync);
this._initTimeline(this.props);
- },
+ }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
- UNSAFE_componentWillReceiveProps: function(newProps) {
+ UNSAFE_componentWillReceiveProps(newProps) {
if (newProps.timelineSet !== this.props.timelineSet) {
// throw new Error("changing timelineSet on a TimelinePanel is not supported");
@@ -260,9 +251,9 @@ const TimelinePanel = createReactClass({
" (was " + this.props.eventId + ")");
return this._initTimeline(newProps);
}
- },
+ }
- shouldComponentUpdate: function(nextProps, nextState) {
+ shouldComponentUpdate(nextProps, nextState) {
if (!ObjectUtils.shallowEqual(this.props, nextProps)) {
if (DEBUG) {
console.group("Timeline.shouldComponentUpdate: props change");
@@ -284,9 +275,9 @@ const TimelinePanel = createReactClass({
}
return false;
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
// set a boolean to say we've been unmounted, which any pending
// promises can use to throw away their results.
//
@@ -316,9 +307,9 @@ const TimelinePanel = createReactClass({
client.removeListener("Event.replaced", this.onEventReplaced);
client.removeListener("sync", this.onSync);
}
- },
+ }
- onMessageListUnfillRequest: function(backwards, scrollToken) {
+ onMessageListUnfillRequest = (backwards, scrollToken) => {
// If backwards, unpaginate from the back (i.e. the start of the timeline)
const dir = backwards ? EventTimeline.BACKWARDS : EventTimeline.FORWARDS;
debuglog("TimelinePanel: unpaginating events in direction", dir);
@@ -349,18 +340,18 @@ const TimelinePanel = createReactClass({
firstVisibleEventIndex,
});
}
- },
+ };
- onPaginationRequest(timelineWindow, direction, size) {
+ onPaginationRequest = (timelineWindow, direction, size) => {
if (this.props.onPaginationRequest) {
return this.props.onPaginationRequest(timelineWindow, direction, size);
} else {
return timelineWindow.paginate(direction, size);
}
- },
+ };
// set off a pagination request.
- onMessageListFillRequest: function(backwards) {
+ onMessageListFillRequest = backwards => {
if (!this._shouldPaginate()) return Promise.resolve(false);
const dir = backwards ? EventTimeline.BACKWARDS : EventTimeline.FORWARDS;
@@ -425,9 +416,9 @@ const TimelinePanel = createReactClass({
});
});
});
- },
+ };
- onMessageListScroll: function(e) {
+ onMessageListScroll = e => {
if (this.props.onScroll) {
this.props.onScroll(e);
}
@@ -447,9 +438,9 @@ const TimelinePanel = createReactClass({
// NO-OP when timeout already has set to the given value
this._readMarkerActivityTimer.changeTimeout(timeout);
}
- },
+ };
- onAction: function(payload) {
+ onAction = payload => {
if (payload.action === 'ignore_state_changed') {
this.forceUpdate();
}
@@ -463,9 +454,9 @@ const TimelinePanel = createReactClass({
}
});
}
- },
+ };
- onRoomTimeline: function(ev, room, toStartOfTimeline, removed, data) {
+ onRoomTimeline = (ev, room, toStartOfTimeline, removed, data) => {
// ignore events for other timeline sets
if (data.timeline.getTimelineSet() !== this.props.timelineSet) return;
@@ -537,21 +528,19 @@ const TimelinePanel = createReactClass({
}
});
});
- },
+ };
- onRoomTimelineReset: function(room, timelineSet) {
+ onRoomTimelineReset = (room, timelineSet) => {
if (timelineSet !== this.props.timelineSet) return;
if (this._messagePanel.current && this._messagePanel.current.isAtBottom()) {
this._loadTimeline();
}
- },
+ };
- canResetTimeline: function() {
- return this._messagePanel.current && this._messagePanel.current.isAtBottom();
- },
+ canResetTimeline = () => this._messagePanel.current && this._messagePanel.current.isAtBottom();
- onRoomRedaction: function(ev, room) {
+ onRoomRedaction = (ev, room) => {
if (this.unmounted) return;
// ignore events for other rooms
@@ -560,9 +549,9 @@ const TimelinePanel = createReactClass({
// we could skip an update if the event isn't in our timeline,
// but that's probably an early optimisation.
this.forceUpdate();
- },
+ };
- onEventReplaced: function(replacedEvent, room) {
+ onEventReplaced = (replacedEvent, room) => {
if (this.unmounted) return;
// ignore events for other rooms
@@ -571,27 +560,27 @@ const TimelinePanel = createReactClass({
// we could skip an update if the event isn't in our timeline,
// but that's probably an early optimisation.
this.forceUpdate();
- },
+ };
- onRoomReceipt: function(ev, room) {
+ onRoomReceipt = (ev, room) => {
if (this.unmounted) return;
// ignore events for other rooms
if (room !== this.props.timelineSet.room) return;
this.forceUpdate();
- },
+ };
- onLocalEchoUpdated: function(ev, room, oldEventId) {
+ onLocalEchoUpdated = (ev, room, oldEventId) => {
if (this.unmounted) return;
// ignore events for other rooms
if (room !== this.props.timelineSet.room) return;
this._reloadEvents();
- },
+ };
- onAccountData: function(ev, room) {
+ onAccountData = (ev, room) => {
if (this.unmounted) return;
// ignore events for other rooms
@@ -605,9 +594,9 @@ const TimelinePanel = createReactClass({
this.setState({
readMarkerEventId: ev.getContent().event_id,
}, this.props.onReadMarkerUpdated);
- },
+ };
- onEventDecrypted: function(ev) {
+ onEventDecrypted = ev => {
// Can be null for the notification timeline, etc.
if (!this.props.timelineSet.room) return;
@@ -620,19 +609,19 @@ const TimelinePanel = createReactClass({
if (ev.getRoomId() === this.props.timelineSet.room.roomId) {
this.forceUpdate();
}
- },
+ };
- onSync: function(state, prevState, data) {
+ onSync = (state, prevState, data) => {
this.setState({clientSyncState: state});
- },
+ };
_readMarkerTimeout(readMarkerPosition) {
return readMarkerPosition === 0 ?
this.state.readMarkerInViewThresholdMs :
this.state.readMarkerOutOfViewThresholdMs;
- },
+ }
- updateReadMarkerOnUserActivity: async function() {
+ async updateReadMarkerOnUserActivity() {
const initialTimeout = this._readMarkerTimeout(this.getReadMarkerPosition());
this._readMarkerActivityTimer = new Timer(initialTimeout);
@@ -644,9 +633,9 @@ const TimelinePanel = createReactClass({
// outside of try/catch to not swallow errors
this.updateReadMarker();
}
- },
+ }
- updateReadReceiptOnUserActivity: async function() {
+ async updateReadReceiptOnUserActivity() {
this._readReceiptActivityTimer = new Timer(READ_RECEIPT_INTERVAL_MS);
while (this._readReceiptActivityTimer) { //unset on unmount
UserActivity.sharedInstance().timeWhileActiveNow(this._readReceiptActivityTimer);
@@ -656,9 +645,9 @@ const TimelinePanel = createReactClass({
// outside of try/catch to not swallow errors
this.sendReadReceipt();
}
- },
+ }
- sendReadReceipt: function() {
+ sendReadReceipt = () => {
if (SettingsStore.getValue("lowBandwidth")) return;
if (!this._messagePanel.current) return;
@@ -766,11 +755,11 @@ const TimelinePanel = createReactClass({
});
}
}
- },
+ };
// if the read marker is on the screen, we can now assume we've caught up to the end
// of the screen, so move the marker down to the bottom of the screen.
- updateReadMarker: function() {
+ updateReadMarker = () => {
if (!this.props.manageReadMarkers) return;
if (this.getReadMarkerPosition() === 1) {
// the read marker is at an event below the viewport,
@@ -801,11 +790,11 @@ const TimelinePanel = createReactClass({
// Send the updated read marker (along with read receipt) to the server
this.sendReadReceipt();
- },
+ };
// advance the read marker past any events we sent ourselves.
- _advanceReadMarkerPastMyEvents: function() {
+ _advanceReadMarkerPastMyEvents() {
if (!this.props.manageReadMarkers) return;
// we call `_timelineWindow.getEvents()` rather than using
@@ -837,11 +826,11 @@ const TimelinePanel = createReactClass({
const ev = events[i];
this._setReadMarker(ev.getId(), ev.getTs());
- },
+ }
/* jump down to the bottom of this room, where new events are arriving
*/
- jumpToLiveTimeline: function() {
+ jumpToLiveTimeline = () => {
// if we can't forward-paginate the existing timeline, then there
// is no point reloading it - just jump straight to the bottom.
//
@@ -854,12 +843,12 @@ const TimelinePanel = createReactClass({
this._messagePanel.current.scrollToBottom();
}
}
- },
+ };
/* scroll to show the read-up-to marker. We put it 1/3 of the way down
* the container.
*/
- jumpToReadMarker: function() {
+ jumpToReadMarker = () => {
if (!this.props.manageReadMarkers) return;
if (!this._messagePanel.current) return;
if (!this.state.readMarkerEventId) return;
@@ -883,11 +872,11 @@ const TimelinePanel = createReactClass({
// As with jumpToLiveTimeline, we want to reload the timeline around the
// read-marker.
this._loadTimeline(this.state.readMarkerEventId, 0, 1/3);
- },
+ };
/* update the read-up-to marker to match the read receipt
*/
- forgetReadMarker: function() {
+ forgetReadMarker = () => {
if (!this.props.manageReadMarkers) return;
const rmId = this._getCurrentReadReceipt();
@@ -903,17 +892,17 @@ const TimelinePanel = createReactClass({
}
this._setReadMarker(rmId, rmTs);
- },
+ };
/* return true if the content is fully scrolled down and we are
* at the end of the live timeline.
*/
- isAtEndOfLiveTimeline: function() {
+ isAtEndOfLiveTimeline = () => {
return this._messagePanel.current
&& this._messagePanel.current.isAtBottom()
&& this._timelineWindow
&& !this._timelineWindow.canPaginate(EventTimeline.FORWARDS);
- },
+ }
/* get the current scroll state. See ScrollPanel.getScrollState for
@@ -921,10 +910,10 @@ const TimelinePanel = createReactClass({
*
* returns null if we are not mounted.
*/
- getScrollState: function() {
+ getScrollState = () => {
if (!this._messagePanel.current) { return null; }
return this._messagePanel.current.getScrollState();
- },
+ };
// returns one of:
//
@@ -932,7 +921,7 @@ const TimelinePanel = createReactClass({
// -1: read marker is above the window
// 0: read marker is visible
// +1: read marker is below the window
- getReadMarkerPosition: function() {
+ getReadMarkerPosition = () => {
if (!this.props.manageReadMarkers) return null;
if (!this._messagePanel.current) return null;
@@ -953,9 +942,9 @@ const TimelinePanel = createReactClass({
}
return null;
- },
+ };
- canJumpToReadMarker: function() {
+ canJumpToReadMarker = () => {
// 1. Do not show jump bar if neither the RM nor the RR are set.
// 3. We want to show the bar if the read-marker is off the top of the screen.
// 4. Also, if pos === null, the event might not be paginated - show the unread bar
@@ -963,14 +952,14 @@ const TimelinePanel = createReactClass({
const ret = this.state.readMarkerEventId !== null && // 1.
(pos < 0 || pos === null); // 3., 4.
return ret;
- },
+ };
/*
* called by the parent component when PageUp/Down/etc is pressed.
*
* We pass it down to the scroll panel.
*/
- handleScrollKey: function(ev) {
+ handleScrollKey = ev => {
if (!this._messagePanel.current) { return; }
// jump to the live timeline on ctrl-end, rather than the end of the
@@ -980,9 +969,9 @@ const TimelinePanel = createReactClass({
} else {
this._messagePanel.current.handleScrollKey(ev);
}
- },
+ };
- _initTimeline: function(props) {
+ _initTimeline(props) {
const initialEvent = props.eventId;
const pixelOffset = props.eventPixelOffset;
@@ -994,7 +983,7 @@ const TimelinePanel = createReactClass({
}
return this._loadTimeline(initialEvent, pixelOffset, offsetBase);
- },
+ }
/**
* (re)-load the event timeline, and initialise the scroll state, centered
@@ -1012,7 +1001,7 @@ const TimelinePanel = createReactClass({
*
* returns a promise which will resolve when the load completes.
*/
- _loadTimeline: function(eventId, pixelOffset, offsetBase) {
+ _loadTimeline(eventId, pixelOffset, offsetBase) {
this._timelineWindow = new Matrix.TimelineWindow(
MatrixClientPeg.get(), this.props.timelineSet,
{windowLimit: this.props.timelineCap});
@@ -1122,21 +1111,21 @@ const TimelinePanel = createReactClass({
});
prom.then(onLoaded, onError);
}
- },
+ }
// handle the completion of a timeline load or localEchoUpdate, by
// reloading the events from the timelinewindow and pending event list into
// the state.
- _reloadEvents: function() {
+ _reloadEvents() {
// we might have switched rooms since the load started - just bin
// the results if so.
if (this.unmounted) return;
this.setState(this._getEvents());
- },
+ }
// get the list of events from the timeline window and the pending event list
- _getEvents: function() {
+ _getEvents() {
const events = this._timelineWindow.getEvents();
const firstVisibleEventIndex = this._checkForPreJoinUISI(events);
@@ -1154,7 +1143,7 @@ const TimelinePanel = createReactClass({
liveEvents,
firstVisibleEventIndex,
};
- },
+ }
/**
* Check for undecryptable messages that were sent while the user was not in
@@ -1166,7 +1155,7 @@ const TimelinePanel = createReactClass({
* undecryptable event that was sent while the user was not in the room. If no
* such events were found, then it returns 0.
*/
- _checkForPreJoinUISI: function(events) {
+ _checkForPreJoinUISI(events) {
const room = this.props.timelineSet.room;
if (events.length === 0 || !room ||
@@ -1228,18 +1217,18 @@ const TimelinePanel = createReactClass({
}
}
return 0;
- },
+ }
- _indexForEventId: function(evId) {
+ _indexForEventId(evId) {
for (let i = 0; i < this.state.events.length; ++i) {
if (evId == this.state.events[i].getId()) {
return i;
}
}
return null;
- },
+ }
- _getLastDisplayedEventIndex: function(opts) {
+ _getLastDisplayedEventIndex(opts) {
opts = opts || {};
const ignoreOwn = opts.ignoreOwn || false;
const allowPartial = opts.allowPartial || false;
@@ -1313,7 +1302,7 @@ const TimelinePanel = createReactClass({
}
return null;
- },
+ }
/**
* Get the id of the event corresponding to our user's latest read-receipt.
@@ -1324,7 +1313,7 @@ const TimelinePanel = createReactClass({
* SDK.
* @return {String} the event ID
*/
- _getCurrentReadReceipt: function(ignoreSynthesized) {
+ _getCurrentReadReceipt(ignoreSynthesized) {
const client = MatrixClientPeg.get();
// the client can be null on logout
if (client == null) {
@@ -1333,9 +1322,9 @@ const TimelinePanel = createReactClass({
const myUserId = client.credentials.userId;
return this.props.timelineSet.room.getEventReadUpTo(myUserId, ignoreSynthesized);
- },
+ }
- _setReadMarker: function(eventId, eventTs, inhibitSetState) {
+ _setReadMarker(eventId, eventTs, inhibitSetState) {
const roomId = this.props.timelineSet.room.roomId;
// don't update the state (and cause a re-render) if there is
@@ -1358,9 +1347,9 @@ const TimelinePanel = createReactClass({
this.setState({
readMarkerEventId: eventId,
}, this.props.onReadMarkerUpdated);
- },
+ }
- _shouldPaginate: function() {
+ _shouldPaginate() {
// don't try to paginate while events in the timeline are
// still being decrypted. We don't render events while they're
// being decrypted, so they don't take up space in the timeline.
@@ -1369,13 +1358,13 @@ const TimelinePanel = createReactClass({
return !this.state.events.some((e) => {
return e.isBeingDecrypted();
});
- },
+ }
getRelationsForEvent(...args) {
return this.props.timelineSet.getRelationsForEvent(...args);
- },
+ }
- render: function() {
+ render() {
const MessagePanel = sdk.getComponent("structures.MessagePanel");
const Loader = sdk.getComponent("elements.Spinner");
@@ -1456,7 +1445,7 @@ const TimelinePanel = createReactClass({
useIRCLayout={this.props.useIRCLayout}
/>
);
- },
-});
+ }
+}
export default TimelinePanel;
diff --git a/src/components/structures/UploadBar.js b/src/components/structures/UploadBar.js
index 421d1d79a7..0865764c5a 100644
--- a/src/components/structures/UploadBar.js
+++ b/src/components/structures/UploadBar.js
@@ -16,30 +16,28 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import ContentMessages from '../../ContentMessages';
import dis from "../../dispatcher/dispatcher";
import filesize from "filesize";
import { _t } from '../../languageHandler';
-export default createReactClass({
- displayName: 'UploadBar',
- propTypes: {
+export default class UploadBar extends React.Component {
+ static propTypes = {
room: PropTypes.object,
- },
+ };
- componentDidMount: function() {
+ componentDidMount() {
this.dispatcherRef = dis.register(this.onAction);
this.mounted = true;
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
this.mounted = false;
dis.unregister(this.dispatcherRef);
- },
+ }
- onAction: function(payload) {
+ onAction = payload => {
switch (payload.action) {
case 'upload_progress':
case 'upload_finished':
@@ -48,9 +46,9 @@ export default createReactClass({
if (this.mounted) this.forceUpdate();
break;
}
- },
+ };
- render: function() {
+ render() {
const uploads = ContentMessages.sharedInstance().getCurrentUploads();
// for testing UI... - also fix up the ContentMessages.getCurrentUploads().length
@@ -105,5 +103,5 @@ export default createReactClass({
{ uploadText }
);
- },
-});
+ }
+}
diff --git a/src/components/structures/ViewSource.js b/src/components/structures/ViewSource.js
index 326ba2c22f..0b969784e5 100644
--- a/src/components/structures/ViewSource.js
+++ b/src/components/structures/ViewSource.js
@@ -17,24 +17,21 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import SyntaxHighlight from '../views/elements/SyntaxHighlight';
import {_t} from "../../languageHandler";
import * as sdk from "../../index";
-export default createReactClass({
- displayName: 'ViewSource',
-
- propTypes: {
+export default class ViewSource extends React.Component {
+ static propTypes = {
content: PropTypes.object.isRequired,
onFinished: PropTypes.func.isRequired,
roomId: PropTypes.string.isRequired,
eventId: PropTypes.string.isRequired,
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
return (
@@ -49,5 +46,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/structures/auth/ForgotPassword.js b/src/components/structures/auth/ForgotPassword.js
index 9877c53106..3fa2713a35 100644
--- a/src/components/structures/auth/ForgotPassword.js
+++ b/src/components/structures/auth/ForgotPassword.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
@@ -40,50 +39,47 @@ const PHASE_EMAIL_SENT = 3;
// User has clicked the link in email and completed reset
const PHASE_DONE = 4;
-export default createReactClass({
- displayName: 'ForgotPassword',
-
- propTypes: {
+export default class ForgotPassword extends React.Component {
+ static propTypes = {
serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired,
onServerConfigChange: PropTypes.func.isRequired,
onLoginClick: PropTypes.func,
onComplete: PropTypes.func.isRequired,
- },
+ };
- getInitialState: function() {
- return {
- phase: PHASE_FORGOT,
- email: "",
- password: "",
- password2: "",
- errorText: null,
+ state = {
+ phase: PHASE_FORGOT,
+ email: "",
+ password: "",
+ password2: "",
+ errorText: null,
- // We perform liveliness checks later, but for now suppress the errors.
- // We also track the server dead errors independently of the regular errors so
- // that we can render it differently, and override any other error the user may
- // be seeing.
- serverIsAlive: true,
- serverErrorIsFatal: false,
- serverDeadError: "",
- serverRequiresIdServer: null,
- };
- },
+ // We perform liveliness checks later, but for now suppress the errors.
+ // We also track the server dead errors independently of the regular errors so
+ // that we can render it differently, and override any other error the user may
+ // be seeing.
+ serverIsAlive: true,
+ serverErrorIsFatal: false,
+ serverDeadError: "",
+ serverRequiresIdServer: null,
+ };
- componentDidMount: function() {
+ componentDidMount() {
this.reset = null;
this._checkServerLiveliness(this.props.serverConfig);
- },
+ }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
- UNSAFE_componentWillReceiveProps: function(newProps) {
+ // eslint-disable-next-line camelcase
+ UNSAFE_componentWillReceiveProps(newProps) {
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
// Do a liveliness check on the new URLs
this._checkServerLiveliness(newProps.serverConfig);
- },
+ }
- _checkServerLiveliness: async function(serverConfig) {
+ async _checkServerLiveliness(serverConfig) {
try {
await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(
serverConfig.hsUrl,
@@ -100,9 +96,9 @@ export default createReactClass({
} catch (e) {
this.setState(AutoDiscoveryUtils.authComponentStateForError(e, "forgot_password"));
}
- },
+ }
- submitPasswordReset: function(email, password) {
+ submitPasswordReset(email, password) {
this.setState({
phase: PHASE_SENDING_EMAIL,
});
@@ -117,9 +113,9 @@ export default createReactClass({
phase: PHASE_FORGOT,
});
});
- },
+ }
- onVerify: async function(ev) {
+ onVerify = async ev => {
ev.preventDefault();
if (!this.reset) {
console.error("onVerify called before submitPasswordReset!");
@@ -131,9 +127,9 @@ export default createReactClass({
} catch (err) {
this.showErrorDialog(err.message);
}
- },
+ };
- onSubmitForm: async function(ev) {
+ onSubmitForm = async ev => {
ev.preventDefault();
// refresh the server errors, just in case the server came back online
@@ -166,41 +162,41 @@ export default createReactClass({
},
});
}
- },
+ };
- onInputChanged: function(stateKey, ev) {
+ onInputChanged = (stateKey, ev) => {
this.setState({
[stateKey]: ev.target.value,
});
- },
+ };
- async onServerDetailsNextPhaseClick() {
+ onServerDetailsNextPhaseClick = async () => {
this.setState({
phase: PHASE_FORGOT,
});
- },
+ };
- onEditServerDetailsClick(ev) {
+ onEditServerDetailsClick = ev => {
ev.preventDefault();
ev.stopPropagation();
this.setState({
phase: PHASE_SERVER_DETAILS,
});
- },
+ };
- onLoginClick: function(ev) {
+ onLoginClick = ev => {
ev.preventDefault();
ev.stopPropagation();
this.props.onLoginClick();
- },
+ };
- showErrorDialog: function(body, title) {
+ showErrorDialog(body, title) {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createTrackedDialog('Forgot Password Error', '', ErrorDialog, {
title: title,
description: body,
});
- },
+ }
renderServerDetails() {
const ServerConfig = sdk.getComponent("auth.ServerConfig");
@@ -218,7 +214,7 @@ export default createReactClass({
submitText={_t("Next")}
submitClass="mx_Login_submit"
/>;
- },
+ }
renderForgot() {
const Field = sdk.getComponent('elements.Field');
@@ -335,12 +331,12 @@ export default createReactClass({
{_t('Sign in instead')}
;
- },
+ }
renderSendingEmail() {
const Spinner = sdk.getComponent("elements.Spinner");
return ;
- },
+ }
renderEmailSent() {
return
@@ -350,7 +346,7 @@ export default createReactClass({
;
- },
+ }
renderDone() {
return
@@ -363,9 +359,9 @@ export default createReactClass({
;
- },
+ }
- render: function() {
+ render() {
const AuthHeader = sdk.getComponent("auth.AuthHeader");
const AuthBody = sdk.getComponent("auth.AuthBody");
@@ -397,5 +393,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js
index 3bc363f863..e56a9ea5e9 100644
--- a/src/components/structures/auth/Login.js
+++ b/src/components/structures/auth/Login.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import {_t, _td} from '../../../languageHandler';
import * as sdk from '../../../index';
@@ -56,10 +55,8 @@ _td("General failure");
/**
* A wire component which glues together login UI components and Login logic
*/
-export default createReactClass({
- displayName: 'Login',
-
- propTypes: {
+export default class Login extends React.Component {
+ static propTypes = {
// Called when the user has logged in. Params:
// - The object returned by the login API
// - The user's password, if applicable, (may be cached in memory for a
@@ -85,10 +82,14 @@ export default createReactClass({
serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired,
isSyncing: PropTypes.bool,
- },
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this._unmounted = false;
+
+ this.state = {
busy: false,
busyLoggingIn: null,
errorText: null,
@@ -113,11 +114,6 @@ export default createReactClass({
serverErrorIsFatal: false,
serverDeadError: "",
};
- },
-
- // TODO: [REACT-WARNING] Move this to constructor
- UNSAFE_componentWillMount: function() {
- this._unmounted = false;
// map from login step type to a function which will render a control
// letting you do that login type
@@ -130,11 +126,11 @@ export default createReactClass({
};
this._initLoginLogic();
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
this._unmounted = true;
- },
+ }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
UNSAFE_componentWillReceiveProps(newProps) {
@@ -143,20 +139,18 @@ export default createReactClass({
// Ensure that we end up actually logging in to the right place
this._initLoginLogic(newProps.serverConfig.hsUrl, newProps.serverConfig.isUrl);
- },
+ }
- onPasswordLoginError: function(errorText) {
+ onPasswordLoginError = errorText => {
this.setState({
errorText,
loginIncorrect: Boolean(errorText),
});
- },
+ };
- isBusy: function() {
- return this.state.busy || this.props.busy;
- },
+ isBusy = () => this.state.busy || this.props.busy;
- onPasswordLogin: async function(username, phoneCountry, phoneNumber, password) {
+ onPasswordLogin = async (username, phoneCountry, phoneNumber, password) => {
if (!this.state.serverIsAlive) {
this.setState({busy: true});
// Do a quick liveliness check on the URLs
@@ -263,13 +257,13 @@ export default createReactClass({
loginIncorrect: error.httpStatus === 401 || error.httpStatus === 403,
});
});
- },
+ };
- onUsernameChanged: function(username) {
+ onUsernameChanged = username => {
this.setState({ username: username });
- },
+ };
- onUsernameBlur: async function(username) {
+ onUsernameBlur = async username => {
const doWellknownLookup = username[0] === "@";
this.setState({
username: username,
@@ -314,19 +308,19 @@ export default createReactClass({
});
}
}
- },
+ };
- onPhoneCountryChanged: function(phoneCountry) {
+ onPhoneCountryChanged = phoneCountry => {
this.setState({ phoneCountry: phoneCountry });
- },
+ };
- onPhoneNumberChanged: function(phoneNumber) {
+ onPhoneNumberChanged = phoneNumber => {
this.setState({
phoneNumber: phoneNumber,
});
- },
+ };
- onPhoneNumberBlur: function(phoneNumber) {
+ onPhoneNumberBlur = phoneNumber => {
// Validate the phone number entered
if (!PHONE_NUMBER_REGEX.test(phoneNumber)) {
this.setState({
@@ -339,15 +333,15 @@ export default createReactClass({
canTryLogin: true,
});
}
- },
+ };
- onRegisterClick: function(ev) {
+ onRegisterClick = ev => {
ev.preventDefault();
ev.stopPropagation();
this.props.onRegisterClick();
- },
+ };
- onTryRegisterClick: function(ev) {
+ onTryRegisterClick = ev => {
const step = this._getCurrentFlowStep();
if (step === 'm.login.sso' || step === 'm.login.cas') {
// If we're showing SSO it means that registration is also probably disabled,
@@ -361,23 +355,23 @@ export default createReactClass({
// Don't intercept - just go through to the register page
this.onRegisterClick(ev);
}
- },
+ };
- async onServerDetailsNextPhaseClick() {
+ onServerDetailsNextPhaseClick = () => {
this.setState({
phase: PHASE_LOGIN,
});
- },
+ };
- onEditServerDetailsClick(ev) {
+ onEditServerDetailsClick = ev => {
ev.preventDefault();
ev.stopPropagation();
this.setState({
phase: PHASE_SERVER_DETAILS,
});
- },
+ };
- _initLoginLogic: async function(hsUrl, isUrl) {
+ async _initLoginLogic(hsUrl, isUrl) {
hsUrl = hsUrl || this.props.serverConfig.hsUrl;
isUrl = isUrl || this.props.serverConfig.isUrl;
@@ -465,9 +459,9 @@ export default createReactClass({
busy: false,
});
});
- },
+ }
- _isSupportedFlow: function(flow) {
+ _isSupportedFlow(flow) {
// technically the flow can have multiple steps, but no one does this
// for login and loginLogic doesn't support it so we can ignore it.
if (!this._stepRendererMap[flow.type]) {
@@ -475,11 +469,11 @@ export default createReactClass({
return false;
}
return true;
- },
+ }
- _getCurrentFlowStep: function() {
+ _getCurrentFlowStep() {
return this._loginLogic ? this._loginLogic.getCurrentFlowStep() : null;
- },
+ }
_errorTextFromError(err) {
let errCode = err.errcode;
@@ -526,7 +520,7 @@ export default createReactClass({
}
return errorText;
- },
+ }
renderServerComponent() {
const ServerConfig = sdk.getComponent("auth.ServerConfig");
@@ -552,7 +546,7 @@ export default createReactClass({
delayTimeMs={250}
{...serverDetailsProps}
/>;
- },
+ }
renderLoginComponentForStep() {
if (PHASES_ENABLED && this.state.phase !== PHASE_LOGIN) {
@@ -572,9 +566,9 @@ export default createReactClass({
}
return null;
- },
+ }
- _renderPasswordStep: function() {
+ _renderPasswordStep() {
const PasswordLogin = sdk.getComponent('auth.PasswordLogin');
let onEditServerDetailsClick = null;
@@ -603,9 +597,9 @@ export default createReactClass({
busy={this.props.isSyncing || this.state.busyLoggingIn}
/>
);
- },
+ }
- _renderSsoStep: function(loginType) {
+ _renderSsoStep(loginType) {
const SignInToText = sdk.getComponent('views.auth.SignInToText');
let onEditServerDetailsClick = null;
@@ -634,9 +628,9 @@ export default createReactClass({
/>
);
- },
+ }
- render: function() {
+ render() {
const Loader = sdk.getComponent("elements.Spinner");
const InlineSpinner = sdk.getComponent("elements.InlineSpinner");
const AuthHeader = sdk.getComponent("auth.AuthHeader");
@@ -704,5 +698,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/structures/auth/PostRegistration.js b/src/components/structures/auth/PostRegistration.js
index 687ab9a195..aa36de6596 100644
--- a/src/components/structures/auth/PostRegistration.js
+++ b/src/components/structures/auth/PostRegistration.js
@@ -15,29 +15,24 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
import AuthPage from "../../views/auth/AuthPage";
-export default createReactClass({
- displayName: 'PostRegistration',
-
- propTypes: {
+export default class PostRegistration extends React.Component {
+ static propTypes = {
onComplete: PropTypes.func.isRequired,
- },
+ };
- getInitialState: function() {
- return {
- avatarUrl: null,
- errorString: null,
- busy: false,
- };
- },
+ state = {
+ avatarUrl: null,
+ errorString: null,
+ busy: false,
+ };
- componentDidMount: function() {
+ componentDidMount() {
// There is some assymetry between ChangeDisplayName and ChangeAvatar,
// as ChangeDisplayName will auto-get the name but ChangeAvatar expects
// the URL to be passed to you (because it's also used for room avatars).
@@ -55,9 +50,9 @@ export default createReactClass({
busy: false,
});
});
- },
+ }
- render: function() {
+ render() {
const ChangeDisplayName = sdk.getComponent('settings.ChangeDisplayName');
const ChangeAvatar = sdk.getComponent('settings.ChangeAvatar');
const AuthHeader = sdk.getComponent('auth.AuthHeader');
@@ -78,5 +73,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js
index 13e48f6287..408d97382c 100644
--- a/src/components/structures/auth/Registration.js
+++ b/src/components/structures/auth/Registration.js
@@ -19,7 +19,6 @@ limitations under the License.
import Matrix from 'matrix-js-sdk';
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import { _t, _td } from '../../../languageHandler';
@@ -43,10 +42,8 @@ const PHASE_REGISTRATION = 1;
// Enable phases for registration
const PHASES_ENABLED = true;
-export default createReactClass({
- displayName: 'Registration',
-
- propTypes: {
+export default class Registration extends React.Component {
+ static propTypes = {
// Called when the user has logged in. Params:
// - object with userId, deviceId, homeserverUrl, identityServerUrl, accessToken
// - The user's password, if available and applicable (may be cached in memory
@@ -65,12 +62,13 @@ export default createReactClass({
onLoginClick: PropTypes.func.isRequired,
onServerConfigChange: PropTypes.func.isRequired,
defaultDeviceDisplayName: PropTypes.string,
- },
+ };
+
+ constructor(props) {
+ super(props);
- getInitialState: function() {
const serverType = ServerType.getTypeFromServerConfig(this.props.serverConfig);
-
- return {
+ this.state = {
busy: false,
errorText: null,
// We remember the values entered by the user because
@@ -118,12 +116,12 @@ export default createReactClass({
// this is the user ID that's logged in.
differentLoggedInUserId: null,
};
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
this._unmounted = false;
this._replaceClient();
- },
+ }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
UNSAFE_componentWillReceiveProps(newProps) {
@@ -142,7 +140,7 @@ export default createReactClass({
phase: this.getDefaultPhaseForServerType(serverType),
});
}
- },
+ }
getDefaultPhaseForServerType(type) {
switch (type) {
@@ -155,9 +153,9 @@ export default createReactClass({
case ServerType.ADVANCED:
return PHASE_SERVER_DETAILS;
}
- },
+ }
- onServerTypeChange(type) {
+ onServerTypeChange = type => {
this.setState({
serverType: type,
});
@@ -184,9 +182,9 @@ export default createReactClass({
this.setState({
phase: this.getDefaultPhaseForServerType(type),
});
- },
+ };
- _replaceClient: async function(serverConfig) {
+ async _replaceClient(serverConfig) {
this.setState({
errorText: null,
serverDeadError: null,
@@ -286,18 +284,18 @@ export default createReactClass({
showGenericError(e);
}
}
- },
+ }
- onFormSubmit: function(formVals) {
+ onFormSubmit = formVals => {
this.setState({
errorText: "",
busy: true,
formVals: formVals,
doingUIAuth: true,
});
- },
+ };
- _requestEmailToken: function(emailAddress, clientSecret, sendAttempt, sessionId) {
+ _requestEmailToken = (emailAddress, clientSecret, sendAttempt, sessionId) => {
return this.state.matrixClient.requestRegisterEmailToken(
emailAddress,
clientSecret,
@@ -309,9 +307,9 @@ export default createReactClass({
session_id: sessionId,
}),
);
- },
+ }
- _onUIAuthFinished: async function(success, response, extra) {
+ _onUIAuthFinished = async (success, response, extra) => {
if (!success) {
let msg = response.message || response.toString();
// can we give a better error message?
@@ -395,9 +393,9 @@ export default createReactClass({
}
this.setState(newState);
- },
+ };
- _setupPushers: function() {
+ _setupPushers() {
if (!this.props.brand) {
return Promise.resolve();
}
@@ -418,15 +416,15 @@ export default createReactClass({
}, (error) => {
console.error("Couldn't get pushers: " + error);
});
- },
+ }
- onLoginClick: function(ev) {
+ onLoginClick = ev => {
ev.preventDefault();
ev.stopPropagation();
this.props.onLoginClick();
- },
+ };
- onGoToFormClicked(ev) {
+ onGoToFormClicked = ev => {
ev.preventDefault();
ev.stopPropagation();
this._replaceClient();
@@ -435,23 +433,23 @@ export default createReactClass({
doingUIAuth: false,
phase: PHASE_REGISTRATION,
});
- },
+ };
- async onServerDetailsNextPhaseClick() {
+ onServerDetailsNextPhaseClick = async () => {
this.setState({
phase: PHASE_REGISTRATION,
});
- },
+ };
- onEditServerDetailsClick(ev) {
+ onEditServerDetailsClick = ev => {
ev.preventDefault();
ev.stopPropagation();
this.setState({
phase: PHASE_SERVER_DETAILS,
});
- },
+ };
- _makeRegisterRequest: function(auth) {
+ _makeRegisterRequest = auth => {
// We inhibit login if we're trying to register with an email address: this
// avoids a lot of complex race conditions that can occur if we try to log
// the user in one one or both of the tabs they might end up with after
@@ -471,20 +469,20 @@ export default createReactClass({
if (auth) registerParams.auth = auth;
if (inhibitLogin !== undefined && inhibitLogin !== null) registerParams.inhibit_login = inhibitLogin;
return this.state.matrixClient.registerRequest(registerParams);
- },
+ };
- _getUIAuthInputs: function() {
+ _getUIAuthInputs() {
return {
emailAddress: this.state.formVals.email,
phoneCountry: this.state.formVals.phoneCountry,
phoneNumber: this.state.formVals.phoneNumber,
};
- },
+ }
// Links to the login page shown after registration is completed are routed through this
// which checks the user hasn't already logged in somewhere else (perhaps we should do
// this more generally?)
- _onLoginClickWithCheck: async function(ev) {
+ _onLoginClickWithCheck = async ev => {
ev.preventDefault();
const sessionLoaded = await Lifecycle.loadSession({ignoreGuest: true});
@@ -492,7 +490,7 @@ export default createReactClass({
// ok fine, there's still no session: really go to the login page
this.props.onLoginClick();
}
- },
+ };
renderServerComponent() {
const ServerTypeSelector = sdk.getComponent("auth.ServerTypeSelector");
@@ -553,7 +551,7 @@ export default createReactClass({
/>
{serverDetails}
;
- },
+ }
renderRegisterComponent() {
if (PHASES_ENABLED && this.state.phase !== PHASE_REGISTRATION) {
@@ -608,9 +606,9 @@ export default createReactClass({
serverRequiresIdServer={this.state.serverRequiresIdServer}
/>;
}
- },
+ }
- render: function() {
+ render() {
const AuthHeader = sdk.getComponent('auth.AuthHeader');
const AuthBody = sdk.getComponent("auth.AuthBody");
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
@@ -706,5 +704,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/auth/AuthFooter.js b/src/components/views/auth/AuthFooter.js
index 1309800772..3de5a19350 100644
--- a/src/components/views/auth/AuthFooter.js
+++ b/src/components/views/auth/AuthFooter.js
@@ -18,16 +18,13 @@ limitations under the License.
import { _t } from '../../../languageHandler';
import React from 'react';
-import createReactClass from 'create-react-class';
-export default createReactClass({
- displayName: 'AuthFooter',
-
- render: function() {
+export default class AuthFooter extends React.Component {
+ render() {
return (
);
- },
-});
+ }
+}
diff --git a/src/components/views/auth/AuthHeader.js b/src/components/views/auth/AuthHeader.js
index 6e787ba77c..57499e397c 100644
--- a/src/components/views/auth/AuthHeader.js
+++ b/src/components/views/auth/AuthHeader.js
@@ -17,17 +17,14 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
-export default createReactClass({
- displayName: 'AuthHeader',
-
- propTypes: {
+export default class AuthHeader extends React.Component {
+ static propTypes = {
disableLanguageSelector: PropTypes.bool,
- },
+ };
- render: function() {
+ render() {
const AuthHeaderLogo = sdk.getComponent('auth.AuthHeaderLogo');
const LanguageSelector = sdk.getComponent('views.auth.LanguageSelector');
@@ -37,5 +34,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/auth/CaptchaForm.js b/src/components/views/auth/CaptchaForm.js
index e162603b01..783d519621 100644
--- a/src/components/views/auth/CaptchaForm.js
+++ b/src/components/views/auth/CaptchaForm.js
@@ -15,7 +15,6 @@ limitations under the License.
*/
import React, {createRef} from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
@@ -24,36 +23,31 @@ const DIV_ID = 'mx_recaptcha';
/**
* A pure UI component which displays a captcha form.
*/
-export default createReactClass({
- displayName: 'CaptchaForm',
-
- propTypes: {
+export default class CaptchaForm extends React.Component {
+ static propTypes = {
sitePublicKey: PropTypes.string,
// called with the captcha response
onCaptchaResponse: PropTypes.func,
- },
+ };
- getDefaultProps: function() {
- return {
- onCaptchaResponse: () => {},
- };
- },
+ static defaultProps = {
+ onCaptchaResponse: () => {},
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this.state = {
errorText: null,
};
- },
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this._captchaWidgetId = null;
this._recaptchaContainer = createRef();
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
// Just putting a script tag into the returned jsx doesn't work, annoyingly,
// so we do this instead.
if (global.grecaptcha) {
@@ -68,13 +62,13 @@ export default createReactClass({
);
this._recaptchaContainer.current.appendChild(scriptTag);
}
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
this._resetRecaptcha();
- },
+ }
- _renderRecaptcha: function(divId) {
+ _renderRecaptcha(divId) {
if (!global.grecaptcha) {
console.error("grecaptcha not loaded!");
throw new Error("Recaptcha did not load successfully");
@@ -93,15 +87,15 @@ export default createReactClass({
sitekey: publicKey,
callback: this.props.onCaptchaResponse,
});
- },
+ }
- _resetRecaptcha: function() {
+ _resetRecaptcha() {
if (this._captchaWidgetId !== null) {
global.grecaptcha.reset(this._captchaWidgetId);
}
- },
+ }
- _onCaptchaLoaded: function() {
+ _onCaptchaLoaded() {
console.log("Loaded recaptcha script.");
try {
this._renderRecaptcha(DIV_ID);
@@ -110,9 +104,9 @@ export default createReactClass({
errorText: e.toString(),
});
}
- },
+ }
- render: function() {
+ render() {
let error = null;
if (this.state.errorText) {
error = (
@@ -131,5 +125,5 @@ export default createReactClass({
{ error }
);
- },
-});
+ }
+}
diff --git a/src/components/views/auth/CustomServerDialog.js b/src/components/views/auth/CustomServerDialog.js
index 7b2c8f88aa..138f8c4689 100644
--- a/src/components/views/auth/CustomServerDialog.js
+++ b/src/components/views/auth/CustomServerDialog.js
@@ -16,14 +16,11 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
import SdkConfig from '../../../SdkConfig';
-export default createReactClass({
- displayName: 'CustomServerDialog',
-
- render: function() {
+export default class CustomServerDialog extends React.Component {
+ render() {
const brand = SdkConfig.get().brand;
return (
@@ -46,5 +43,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/auth/InteractiveAuthEntryComponents.js b/src/components/views/auth/InteractiveAuthEntryComponents.js
index 7080eb3602..628c177d94 100644
--- a/src/components/views/auth/InteractiveAuthEntryComponents.js
+++ b/src/components/views/auth/InteractiveAuthEntryComponents.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React, {createRef} from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import url from 'url';
import classnames from 'classnames';
@@ -75,14 +74,10 @@ import AccessibleButton from "../elements/AccessibleButton";
export const DEFAULT_PHASE = 0;
-export const PasswordAuthEntry = createReactClass({
- displayName: 'PasswordAuthEntry',
+export class PasswordAuthEntry extends React.Component {
+ static LOGIN_TYPE = "m.login.password";
- statics: {
- LOGIN_TYPE: "m.login.password",
- },
-
- propTypes: {
+ static propTypes = {
matrixClient: PropTypes.object.isRequired,
submitAuthDict: PropTypes.func.isRequired,
errorText: PropTypes.string,
@@ -90,19 +85,17 @@ export const PasswordAuthEntry = createReactClass({
// happen?
busy: PropTypes.bool,
onPhaseChange: PropTypes.func.isRequired,
- },
+ };
- componentDidMount: function() {
+ componentDidMount() {
this.props.onPhaseChange(DEFAULT_PHASE);
- },
+ }
- getInitialState: function() {
- return {
- password: "",
- };
- },
+ state = {
+ password: "",
+ };
- _onSubmit: function(e) {
+ _onSubmit = e => {
e.preventDefault();
if (this.props.busy) return;
@@ -117,16 +110,16 @@ export const PasswordAuthEntry = createReactClass({
},
password: this.state.password,
});
- },
+ };
- _onPasswordFieldChange: function(ev) {
+ _onPasswordFieldChange = ev => {
// enable the submit button iff the password is non-empty
this.setState({
password: ev.target.value,
});
- },
+ };
- render: function() {
+ render() {
const passwordBoxClass = classnames({
"error": this.props.errorText,
});
@@ -176,36 +169,32 @@ export const PasswordAuthEntry = createReactClass({
{ errorSection }
);
- },
-});
+ }
+}
-export const RecaptchaAuthEntry = createReactClass({
- displayName: 'RecaptchaAuthEntry',
+export class RecaptchaAuthEntry extends React.Component {
+ static LOGIN_TYPE = "m.login.recaptcha";
- statics: {
- LOGIN_TYPE: "m.login.recaptcha",
- },
-
- propTypes: {
+ static propTypes = {
submitAuthDict: PropTypes.func.isRequired,
stageParams: PropTypes.object.isRequired,
errorText: PropTypes.string,
busy: PropTypes.bool,
onPhaseChange: PropTypes.func.isRequired,
- },
+ };
- componentDidMount: function() {
+ componentDidMount() {
this.props.onPhaseChange(DEFAULT_PHASE);
- },
+ }
- _onCaptchaResponse: function(response) {
+ _onCaptchaResponse = response => {
this.props.submitAuthDict({
type: RecaptchaAuthEntry.LOGIN_TYPE,
response: response,
});
- },
+ };
- render: function() {
+ render() {
if (this.props.busy) {
const Loader = sdk.getComponent("elements.Spinner");
return ;
@@ -241,31 +230,24 @@ export const RecaptchaAuthEntry = createReactClass({
{ errorSection }
);
- },
-});
+ }
+}
-export const TermsAuthEntry = createReactClass({
- displayName: 'TermsAuthEntry',
+export class TermsAuthEntry extends React.Component {
+ static LOGIN_TYPE = "m.login.terms";
- statics: {
- LOGIN_TYPE: "m.login.terms",
- },
-
- propTypes: {
+ static propTypes = {
submitAuthDict: PropTypes.func.isRequired,
stageParams: PropTypes.object.isRequired,
errorText: PropTypes.string,
busy: PropTypes.bool,
showContinue: PropTypes.bool,
onPhaseChange: PropTypes.func.isRequired,
- },
+ };
- componentDidMount: function() {
- this.props.onPhaseChange(DEFAULT_PHASE);
- },
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Move this to constructor
- componentWillMount: function() {
// example stageParams:
//
// {
@@ -310,17 +292,22 @@ export const TermsAuthEntry = createReactClass({
pickedPolicies.push(langPolicy);
}
- this.setState({
- "toggledPolicies": initToggles,
- "policies": pickedPolicies,
- });
- },
+ this.state = {
+ toggledPolicies: initToggles,
+ policies: pickedPolicies,
+ };
+ }
- tryContinue: function() {
+
+ componentDidMount() {
+ this.props.onPhaseChange(DEFAULT_PHASE);
+ }
+
+ tryContinue = () => {
this._trySubmit();
- },
+ };
- _togglePolicy: function(policyId) {
+ _togglePolicy(policyId) {
const newToggles = {};
for (const policy of this.state.policies) {
let checked = this.state.toggledPolicies[policy.id];
@@ -329,9 +316,9 @@ export const TermsAuthEntry = createReactClass({
newToggles[policy.id] = checked;
}
this.setState({"toggledPolicies": newToggles});
- },
+ }
- _trySubmit: function() {
+ _trySubmit = () => {
let allChecked = true;
for (const policy of this.state.policies) {
const checked = this.state.toggledPolicies[policy.id];
@@ -340,9 +327,9 @@ export const TermsAuthEntry = createReactClass({
if (allChecked) this.props.submitAuthDict({type: TermsAuthEntry.LOGIN_TYPE});
else this.setState({errorText: _t("Please review and accept all of the homeserver's policies")});
- },
+ };
- render: function() {
+ render() {
if (this.props.busy) {
const Loader = sdk.getComponent("elements.Spinner");
return ;
@@ -387,17 +374,13 @@ export const TermsAuthEntry = createReactClass({
{ submitButton }
);
- },
-});
+ }
+}
-export const EmailIdentityAuthEntry = createReactClass({
- displayName: 'EmailIdentityAuthEntry',
+export class EmailIdentityAuthEntry extends React.Component {
+ static LOGIN_TYPE = "m.login.email.identity";
- statics: {
- LOGIN_TYPE: "m.login.email.identity",
- },
-
- propTypes: {
+ static propTypes = {
matrixClient: PropTypes.object.isRequired,
submitAuthDict: PropTypes.func.isRequired,
authSessionId: PropTypes.string.isRequired,
@@ -407,13 +390,13 @@ export const EmailIdentityAuthEntry = createReactClass({
fail: PropTypes.func.isRequired,
setEmailSid: PropTypes.func.isRequired,
onPhaseChange: PropTypes.func.isRequired,
- },
+ };
- componentDidMount: function() {
+ componentDidMount() {
this.props.onPhaseChange(DEFAULT_PHASE);
- },
+ }
- render: function() {
+ render() {
// This component is now only displayed once the token has been requested,
// so we know the email has been sent. It can also get loaded after the user
// has clicked the validation link if the server takes a while to propagate
@@ -434,17 +417,13 @@ export const EmailIdentityAuthEntry = createReactClass({
);
}
- },
-});
+ }
+}
-export const MsisdnAuthEntry = createReactClass({
- displayName: 'MsisdnAuthEntry',
+export class MsisdnAuthEntry extends React.Component {
+ static LOGIN_TYPE = "m.login.msisdn";
- statics: {
- LOGIN_TYPE: "m.login.msisdn",
- },
-
- propTypes: {
+ static propTypes = {
inputs: PropTypes.shape({
phoneCountry: PropTypes.string,
phoneNumber: PropTypes.string,
@@ -454,16 +433,14 @@ export const MsisdnAuthEntry = createReactClass({
submitAuthDict: PropTypes.func.isRequired,
matrixClient: PropTypes.object,
onPhaseChange: PropTypes.func.isRequired,
- },
+ };
- getInitialState: function() {
- return {
- token: '',
- requestingToken: false,
- };
- },
+ state = {
+ token: '',
+ requestingToken: false,
+ };
- componentDidMount: function() {
+ componentDidMount() {
this.props.onPhaseChange(DEFAULT_PHASE);
this._submitUrl = null;
@@ -477,12 +454,12 @@ export const MsisdnAuthEntry = createReactClass({
}).finally(() => {
this.setState({requestingToken: false});
});
- },
+ }
/*
* Requests a verification token by SMS.
*/
- _requestMsisdnToken: function() {
+ _requestMsisdnToken() {
return this.props.matrixClient.requestRegisterMsisdnToken(
this.props.inputs.phoneCountry,
this.props.inputs.phoneNumber,
@@ -493,15 +470,15 @@ export const MsisdnAuthEntry = createReactClass({
this._sid = result.sid;
this._msisdn = result.msisdn;
});
- },
+ }
- _onTokenChange: function(e) {
+ _onTokenChange = e => {
this.setState({
token: e.target.value,
});
- },
+ };
- _onFormSubmit: async function(e) {
+ _onFormSubmit = async e => {
e.preventDefault();
if (this.state.token == '') return;
@@ -552,9 +529,9 @@ export const MsisdnAuthEntry = createReactClass({
this.props.fail(e);
console.log("Failed to submit msisdn token");
}
- },
+ };
- render: function() {
+ render() {
if (this.state.requestingToken) {
const Loader = sdk.getComponent("elements.Spinner");
return ;
@@ -598,8 +575,8 @@ export const MsisdnAuthEntry = createReactClass({
);
}
- },
-});
+ }
+}
export class SSOAuthEntry extends React.Component {
static propTypes = {
@@ -686,46 +663,46 @@ export class SSOAuthEntry extends React.Component {
}
}
-export const FallbackAuthEntry = createReactClass({
- displayName: 'FallbackAuthEntry',
-
- propTypes: {
+export class FallbackAuthEntry extends React.Component {
+ static propTypes = {
matrixClient: PropTypes.object.isRequired,
authSessionId: PropTypes.string.isRequired,
loginType: PropTypes.string.isRequired,
submitAuthDict: PropTypes.func.isRequired,
errorText: PropTypes.string,
onPhaseChange: PropTypes.func.isRequired,
- },
+ };
- componentDidMount: function() {
- this.props.onPhaseChange(DEFAULT_PHASE);
- },
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
// we have to make the user click a button, as browsers will block
// the popup if we open it immediately.
this._popupWindow = null;
window.addEventListener("message", this._onReceiveMessage);
this._fallbackButton = createRef();
- },
+ }
- componentWillUnmount: function() {
+
+ componentDidMount() {
+ this.props.onPhaseChange(DEFAULT_PHASE);
+ }
+
+ componentWillUnmount() {
window.removeEventListener("message", this._onReceiveMessage);
if (this._popupWindow) {
this._popupWindow.close();
}
- },
+ }
- focus: function() {
+ focus = () => {
if (this._fallbackButton.current) {
this._fallbackButton.current.focus();
}
- },
+ };
- _onShowFallbackClick: function(e) {
+ _onShowFallbackClick = e => {
e.preventDefault();
e.stopPropagation();
@@ -735,18 +712,18 @@ export const FallbackAuthEntry = createReactClass({
);
this._popupWindow = window.open(url);
this._popupWindow.opener = null;
- },
+ };
- _onReceiveMessage: function(event) {
+ _onReceiveMessage = event => {
if (
event.data === "authDone" &&
event.origin === this.props.matrixClient.getHomeserverUrl()
) {
this.props.submitAuthDict({});
}
- },
+ };
- render: function() {
+ render() {
let errorSection;
if (this.props.errorText) {
errorSection = (
@@ -761,8 +738,8 @@ export const FallbackAuthEntry = createReactClass({
{errorSection}
);
- },
-});
+ }
+}
const AuthEntryComponents = [
PasswordAuthEntry,
diff --git a/src/components/views/auth/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js
index 17c65fa94e..bd10c829e3 100644
--- a/src/components/views/auth/RegistrationForm.js
+++ b/src/components/views/auth/RegistrationForm.js
@@ -18,7 +18,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import * as Email from '../../../email';
@@ -42,10 +41,8 @@ const PASSWORD_MIN_SCORE = 3; // safely unguessable: moderate protection from of
/**
* A pure UI component which displays a registration form.
*/
-export default createReactClass({
- displayName: 'RegistrationForm',
-
- propTypes: {
+export default class RegistrationForm extends React.Component {
+ static propTypes = {
// Values pre-filled in the input boxes when the component loads
defaultEmail: PropTypes.string,
defaultPhoneCountry: PropTypes.string,
@@ -58,17 +55,17 @@ export default createReactClass({
serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired,
canSubmit: PropTypes.bool,
serverRequiresIdServer: PropTypes.bool,
- },
+ };
- getDefaultProps: function() {
- return {
- onValidationChange: console.error,
- canSubmit: true,
- };
- },
+ static defaultProps = {
+ onValidationChange: console.error,
+ canSubmit: true,
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this.state = {
// Field error codes by field ID
fieldValid: {},
// The ISO2 country code selected in the phone number entry
@@ -80,9 +77,9 @@ export default createReactClass({
passwordConfirm: this.props.defaultPassword || "",
passwordComplexity: null,
};
- },
+ }
- onSubmit: async function(ev) {
+ onSubmit = async ev => {
ev.preventDefault();
if (!this.props.canSubmit) return;
@@ -118,7 +115,7 @@ export default createReactClass({
title: _t("Warning!"),
description: desc,
button: _t("Continue"),
- onFinished: function(confirmed) {
+ onFinished(confirmed) {
if (confirmed) {
self._doSubmit(ev);
}
@@ -127,9 +124,9 @@ export default createReactClass({
} else {
self._doSubmit(ev);
}
- },
+ };
- _doSubmit: function(ev) {
+ _doSubmit(ev) {
const email = this.state.email.trim();
const promise = this.props.onRegisterClick({
username: this.state.username.trim(),
@@ -145,7 +142,7 @@ export default createReactClass({
ev.target.disabled = false;
});
}
- },
+ }
async verifyFieldsBeforeSubmit() {
// Blur the active element if any, so we first run its blur validation,
@@ -196,12 +193,12 @@ export default createReactClass({
invalidField.focus();
invalidField.validate({ allowEmpty: false, focused: true });
return false;
- },
+ }
/**
* @returns {boolean} true if all fields were valid last time they were validated.
*/
- allFieldsValid: function() {
+ allFieldsValid() {
const keys = Object.keys(this.state.fieldValid);
for (let i = 0; i < keys.length; ++i) {
if (!this.state.fieldValid[keys[i]]) {
@@ -209,7 +206,7 @@ export default createReactClass({
}
}
return true;
- },
+ }
findFirstInvalidField(fieldIDs) {
for (const fieldID of fieldIDs) {
@@ -218,34 +215,34 @@ export default createReactClass({
}
}
return null;
- },
+ }
- markFieldValid: function(fieldID, valid) {
+ markFieldValid(fieldID, valid) {
const { fieldValid } = this.state;
fieldValid[fieldID] = valid;
this.setState({
fieldValid,
});
- },
+ }
- onEmailChange(ev) {
+ onEmailChange = ev => {
this.setState({
email: ev.target.value,
});
- },
+ };
- async onEmailValidate(fieldState) {
- const result = await this.validateEmailRules(fieldState);
+ onEmailValidate = async fieldState => {
+ const result = await RegistrationForm.validateEmailRules(fieldState);
this.markFieldValid(FIELD_EMAIL, result.valid);
return result;
- },
+ };
- validateEmailRules: withValidation({
+ static validateEmailRules = withValidation({
description: () => _t("Use an email address to recover your account"),
rules: [
{
key: "required",
- test: function({ value, allowEmpty }) {
+ test({ value, allowEmpty }) {
return allowEmpty || !this._authStepIsRequired('m.login.email.identity') || !!value;
},
invalid: () => _t("Enter email address (required on this homeserver)"),
@@ -256,31 +253,31 @@ export default createReactClass({
invalid: () => _t("Doesn't look like a valid email address"),
},
],
- }),
+ });
- onPasswordChange(ev) {
+ onPasswordChange = ev => {
this.setState({
password: ev.target.value,
});
- },
+ };
- onPasswordValidate(result) {
+ onPasswordValidate = result => {
this.markFieldValid(FIELD_PASSWORD, result.valid);
- },
+ };
- onPasswordConfirmChange(ev) {
+ onPasswordConfirmChange = ev => {
this.setState({
passwordConfirm: ev.target.value,
});
- },
+ };
- async onPasswordConfirmValidate(fieldState) {
- const result = await this.validatePasswordConfirmRules(fieldState);
+ onPasswordConfirmValidate = async fieldState => {
+ const result = await RegistrationForm.validatePasswordConfirmRules(fieldState);
this.markFieldValid(FIELD_PASSWORD_CONFIRM, result.valid);
return result;
- },
+ };
- validatePasswordConfirmRules: withValidation({
+ static validatePasswordConfirmRules = withValidation({
rules: [
{
key: "required",
@@ -289,39 +286,39 @@ export default createReactClass({
},
{
key: "match",
- test: function({ value }) {
+ test({ value }) {
return !value || value === this.state.password;
},
invalid: () => _t("Passwords don't match"),
},
],
- }),
+ });
- onPhoneCountryChange(newVal) {
+ onPhoneCountryChange = newVal => {
this.setState({
phoneCountry: newVal.iso2,
phonePrefix: newVal.prefix,
});
- },
+ };
- onPhoneNumberChange(ev) {
+ onPhoneNumberChange = ev => {
this.setState({
phoneNumber: ev.target.value,
});
- },
+ };
- async onPhoneNumberValidate(fieldState) {
- const result = await this.validatePhoneNumberRules(fieldState);
+ onPhoneNumberValidate = async fieldState => {
+ const result = await RegistrationForm.validatePhoneNumberRules(fieldState);
this.markFieldValid(FIELD_PHONE_NUMBER, result.valid);
return result;
- },
+ };
- validatePhoneNumberRules: withValidation({
+ static validatePhoneNumberRules = withValidation({
description: () => _t("Other users can invite you to rooms using your contact details"),
rules: [
{
key: "required",
- test: function({ value, allowEmpty }) {
+ test({ value, allowEmpty }) {
return allowEmpty || !this._authStepIsRequired('m.login.msisdn') || !!value;
},
invalid: () => _t("Enter phone number (required on this homeserver)"),
@@ -332,21 +329,21 @@ export default createReactClass({
invalid: () => _t("Doesn't look like a valid phone number"),
},
],
- }),
+ });
- onUsernameChange(ev) {
+ onUsernameChange = ev => {
this.setState({
username: ev.target.value,
});
- },
+ };
- async onUsernameValidate(fieldState) {
- const result = await this.validateUsernameRules(fieldState);
+ onUsernameValidate = async fieldState => {
+ const result = await RegistrationForm.validateUsernameRules(fieldState);
this.markFieldValid(FIELD_USERNAME, result.valid);
return result;
- },
+ };
- validateUsernameRules: withValidation({
+ static validateUsernameRules = withValidation({
description: () => _t("Use lowercase letters, numbers, dashes and underscores only"),
rules: [
{
@@ -360,7 +357,7 @@ export default createReactClass({
invalid: () => _t("Some characters not allowed"),
},
],
- }),
+ });
/**
* A step is required if all flows include that step.
@@ -372,7 +369,7 @@ export default createReactClass({
return this.props.flows.every((flow) => {
return flow.stages.includes(step);
});
- },
+ }
/**
* A step is used if any flows include that step.
@@ -384,7 +381,7 @@ export default createReactClass({
return this.props.flows.some((flow) => {
return flow.stages.includes(step);
});
- },
+ }
_showEmail() {
const haveIs = Boolean(this.props.serverConfig.isUrl);
@@ -395,7 +392,7 @@ export default createReactClass({
return false;
}
return true;
- },
+ }
_showPhoneNumber() {
const threePidLogin = !SdkConfig.get().disable_3pid_login;
@@ -408,7 +405,7 @@ export default createReactClass({
return false;
}
return true;
- },
+ }
renderEmail() {
if (!this._showEmail()) {
@@ -426,7 +423,7 @@ export default createReactClass({
onChange={this.onEmailChange}
onValidate={this.onEmailValidate}
/>;
- },
+ }
renderPassword() {
return ;
- },
+ }
renderPasswordConfirm() {
const Field = sdk.getComponent('elements.Field');
@@ -451,7 +448,7 @@ export default createReactClass({
onChange={this.onPasswordConfirmChange}
onValidate={this.onPasswordConfirmValidate}
/>;
- },
+ }
renderPhoneNumber() {
if (!this._showPhoneNumber()) {
@@ -477,7 +474,7 @@ export default createReactClass({
onChange={this.onPhoneNumberChange}
onValidate={this.onPhoneNumberValidate}
/>;
- },
+ }
renderUsername() {
const Field = sdk.getComponent('elements.Field');
@@ -491,9 +488,9 @@ export default createReactClass({
onChange={this.onUsernameChange}
onValidate={this.onUsernameValidate}
/>;
- },
+ }
- render: function() {
+ render() {
let yourMatrixAccountText = _t('Create your Matrix account on %(serverName)s', {
serverName: this.props.serverConfig.hsName,
});
@@ -578,5 +575,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js
index 6fa54058a0..d760c8defa 100644
--- a/src/components/views/context_menus/MessageContextMenu.js
+++ b/src/components/views/context_menus/MessageContextMenu.js
@@ -19,7 +19,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import {EventStatus} from 'matrix-js-sdk';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
@@ -37,10 +36,8 @@ function canCancel(eventStatus) {
return eventStatus === EventStatus.QUEUED || eventStatus === EventStatus.NOT_SENT;
}
-export default createReactClass({
- displayName: 'MessageContextMenu',
-
- propTypes: {
+export default class MessageContextMenu extends React.Component {
+ static propTypes = {
/* the MatrixEvent associated with the context menu */
mxEvent: PropTypes.object.isRequired,
@@ -52,28 +49,26 @@ export default createReactClass({
/* callback called when the menu is dismissed */
onFinished: PropTypes.func,
- },
+ };
- getInitialState: function() {
- return {
- canRedact: false,
- canPin: false,
- };
- },
+ state = {
+ canRedact: false,
+ canPin: false,
+ };
- componentDidMount: function() {
+ componentDidMount() {
MatrixClientPeg.get().on('RoomMember.powerLevel', this._checkPermissions);
this._checkPermissions();
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
const cli = MatrixClientPeg.get();
if (cli) {
cli.removeListener('RoomMember.powerLevel', this._checkPermissions);
}
- },
+ }
- _checkPermissions: function() {
+ _checkPermissions = () => {
const cli = MatrixClientPeg.get();
const room = cli.getRoom(this.props.mxEvent.getRoomId());
@@ -84,47 +79,47 @@ export default createReactClass({
if (!SettingsStore.getValue("feature_pinning")) canPin = false;
this.setState({canRedact, canPin});
- },
+ };
- _isPinned: function() {
+ _isPinned() {
const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
const pinnedEvent = room.currentState.getStateEvents('m.room.pinned_events', '');
if (!pinnedEvent) return false;
const content = pinnedEvent.getContent();
return content.pinned && Array.isArray(content.pinned) && content.pinned.includes(this.props.mxEvent.getId());
- },
+ }
- onResendClick: function() {
+ onResendClick = () => {
Resend.resend(this.props.mxEvent);
this.closeMenu();
- },
+ };
- onResendEditClick: function() {
+ onResendEditClick = () => {
Resend.resend(this.props.mxEvent.replacingEvent());
this.closeMenu();
- },
+ };
- onResendRedactionClick: function() {
+ onResendRedactionClick = () => {
Resend.resend(this.props.mxEvent.localRedactionEvent());
this.closeMenu();
- },
+ };
- onResendReactionsClick: function() {
+ onResendReactionsClick = () => {
for (const reaction of this._getUnsentReactions()) {
Resend.resend(reaction);
}
this.closeMenu();
- },
+ };
- onReportEventClick: function() {
+ onReportEventClick = () => {
const ReportEventDialog = sdk.getComponent("dialogs.ReportEventDialog");
Modal.createTrackedDialog('Report Event', '', ReportEventDialog, {
mxEvent: this.props.mxEvent,
}, 'mx_Dialog_reportEvent');
this.closeMenu();
- },
+ };
- onViewSourceClick: function() {
+ onViewSourceClick = () => {
const ev = this.props.mxEvent.replacingEvent() || this.props.mxEvent;
const ViewSource = sdk.getComponent('structures.ViewSource');
Modal.createTrackedDialog('View Event Source', '', ViewSource, {
@@ -133,9 +128,9 @@ export default createReactClass({
content: ev.event,
}, 'mx_Dialog_viewsource');
this.closeMenu();
- },
+ };
- onViewClearSourceClick: function() {
+ onViewClearSourceClick = () => {
const ev = this.props.mxEvent.replacingEvent() || this.props.mxEvent;
const ViewSource = sdk.getComponent('structures.ViewSource');
Modal.createTrackedDialog('View Clear Event Source', '', ViewSource, {
@@ -145,9 +140,9 @@ export default createReactClass({
content: ev._clearEvent,
}, 'mx_Dialog_viewsource');
this.closeMenu();
- },
+ };
- onRedactClick: function() {
+ onRedactClick = () => {
const ConfirmRedactDialog = sdk.getComponent("dialogs.ConfirmRedactDialog");
Modal.createTrackedDialog('Confirm Redact Dialog', '', ConfirmRedactDialog, {
onFinished: async (proceed) => {
@@ -176,9 +171,9 @@ export default createReactClass({
},
}, 'mx_Dialog_confirmredact');
this.closeMenu();
- },
+ };
- onCancelSendClick: function() {
+ onCancelSendClick = () => {
const mxEvent = this.props.mxEvent;
const editEvent = mxEvent.replacingEvent();
const redactEvent = mxEvent.localRedactionEvent();
@@ -199,17 +194,17 @@ export default createReactClass({
Resend.removeFromQueue(this.props.mxEvent);
}
this.closeMenu();
- },
+ };
- onForwardClick: function() {
+ onForwardClick = () => {
dis.dispatch({
action: 'forward_event',
event: this.props.mxEvent,
});
this.closeMenu();
- },
+ };
- onPinClick: function() {
+ onPinClick = () => {
MatrixClientPeg.get().getStateEvent(this.props.mxEvent.getRoomId(), 'm.room.pinned_events', '')
.catch((e) => {
// Intercept the Event Not Found error and fall through the promise chain with no event.
@@ -230,28 +225,28 @@ export default createReactClass({
cli.sendStateEvent(this.props.mxEvent.getRoomId(), 'm.room.pinned_events', {pinned: eventIds}, '');
});
this.closeMenu();
- },
+ };
- closeMenu: function() {
+ closeMenu = () => {
if (this.props.onFinished) this.props.onFinished();
- },
+ };
- onUnhidePreviewClick: function() {
+ onUnhidePreviewClick = () => {
if (this.props.eventTileOps) {
this.props.eventTileOps.unhideWidget();
}
this.closeMenu();
- },
+ };
- onQuoteClick: function() {
+ onQuoteClick = () => {
dis.dispatch({
action: 'quote',
event: this.props.mxEvent,
});
this.closeMenu();
- },
+ };
- onPermalinkClick: function(e: Event) {
+ onPermalinkClick = (e: Event) => {
e.preventDefault();
const ShareDialog = sdk.getComponent("dialogs.ShareDialog");
Modal.createTrackedDialog('share room message dialog', '', ShareDialog, {
@@ -259,12 +254,12 @@ export default createReactClass({
permalinkCreator: this.props.permalinkCreator,
});
this.closeMenu();
- },
+ };
- onCollapseReplyThreadClick: function() {
+ onCollapseReplyThreadClick = () => {
this.props.collapseReplyThread();
this.closeMenu();
- },
+ };
_getReactions(filter) {
const cli = MatrixClientPeg.get();
@@ -277,17 +272,17 @@ export default createReactClass({
relation.event_id === eventId &&
filter(e);
});
- },
+ }
_getPendingReactions() {
return this._getReactions(e => canCancel(e.status));
- },
+ }
_getUnsentReactions() {
return this._getReactions(e => e.status === EventStatus.NOT_SENT);
- },
+ }
- render: function() {
+ render() {
const cli = MatrixClientPeg.get();
const me = cli.getUserId();
const mxEvent = this.props.mxEvent;
@@ -489,5 +484,5 @@ export default createReactClass({
{ reportEventButton }
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/AddressPickerDialog.js b/src/components/views/dialogs/AddressPickerDialog.js
index 8ddd89dc65..2cd09874b2 100644
--- a/src/components/views/dialogs/AddressPickerDialog.js
+++ b/src/components/views/dialogs/AddressPickerDialog.js
@@ -19,7 +19,6 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import { _t, _td } from '../../../languageHandler';
import * as sdk from '../../../index';
@@ -45,10 +44,8 @@ const addressTypeName = {
};
-export default createReactClass({
- displayName: "AddressPickerDialog",
-
- propTypes: {
+export default class AddressPickerDialog extends React.Component {
+ static propTypes = {
title: PropTypes.string.isRequired,
description: PropTypes.node,
// Extra node inserted after picker input, dropdown and errors
@@ -66,26 +63,28 @@ export default createReactClass({
// Whether the current user should be included in the addresses returned. Only
// applicable when pickerType is `user`. Default: false.
includeSelf: PropTypes.bool,
- },
+ };
- getDefaultProps: function() {
- return {
- value: "",
- focus: true,
- validAddressTypes: addressTypes,
- pickerType: 'user',
- includeSelf: false,
- };
- },
+ static defaultProps = {
+ value: "",
+ focus: true,
+ validAddressTypes: addressTypes,
+ pickerType: 'user',
+ includeSelf: false,
+ };
+
+ constructor(props) {
+ super(props);
+
+ this._textinput = createRef();
- getInitialState: function() {
let validAddressTypes = this.props.validAddressTypes;
// Remove email from validAddressTypes if no IS is configured. It may be added at a later stage by the user
if (!MatrixClientPeg.get().getIdentityServerUrl() && validAddressTypes.includes("email")) {
validAddressTypes = validAddressTypes.filter(type => type !== "email");
}
- return {
+ this.state = {
// Whether to show an error message because of an invalid address
invalidAddressError: false,
// List of UserAddressType objects representing
@@ -106,19 +105,14 @@ export default createReactClass({
// dialog is open and represents the supported list of address types at this time.
validAddressTypes,
};
- },
+ }
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
- this._textinput = createRef();
- },
-
- componentDidMount: function() {
+ componentDidMount() {
if (this.props.focus) {
// Set the cursor at the end of the text input
this._textinput.current.value = this.props.value;
}
- },
+ }
getPlaceholder() {
const { placeholder } = this.props;
@@ -127,9 +121,9 @@ export default createReactClass({
}
// Otherwise it's a function, as checked by prop types.
return placeholder(this.state.validAddressTypes);
- },
+ }
- onButtonClick: function() {
+ onButtonClick = () => {
let selectedList = this.state.selectedList.slice();
// Check the text input field to see if user has an unconverted address
// If there is and it's valid add it to the local selectedList
@@ -138,13 +132,13 @@ export default createReactClass({
if (selectedList === null) return;
}
this.props.onFinished(true, selectedList);
- },
+ };
- onCancel: function() {
+ onCancel = () => {
this.props.onFinished(false);
- },
+ };
- onKeyDown: function(e) {
+ onKeyDown = e => {
const textInput = this._textinput.current ? this._textinput.current.value : undefined;
if (e.key === Key.ESCAPE) {
@@ -181,9 +175,9 @@ export default createReactClass({
e.preventDefault();
this._addAddressesToList([textInput]);
}
- },
+ };
- onQueryChanged: function(ev) {
+ onQueryChanged = ev => {
const query = ev.target.value;
if (this.queryChangedDebouncer) {
clearTimeout(this.queryChangedDebouncer);
@@ -216,28 +210,24 @@ export default createReactClass({
searchError: null,
});
}
- },
+ };
- onDismissed: function(index) {
- return () => {
- const selectedList = this.state.selectedList.slice();
- selectedList.splice(index, 1);
- this.setState({
- selectedList,
- suggestedList: [],
- query: "",
- });
- if (this._cancelThreepidLookup) this._cancelThreepidLookup();
- };
- },
+ onDismissed = index => () => {
+ const selectedList = this.state.selectedList.slice();
+ selectedList.splice(index, 1);
+ this.setState({
+ selectedList,
+ suggestedList: [],
+ query: "",
+ });
+ if (this._cancelThreepidLookup) this._cancelThreepidLookup();
+ };
- onClick: function(index) {
- return () => {
- this.onSelected(index);
- };
- },
+ onClick = index => () => {
+ this.onSelected(index);
+ };
- onSelected: function(index) {
+ onSelected = index => {
const selectedList = this.state.selectedList.slice();
selectedList.push(this._getFilteredSuggestions()[index]);
this.setState({
@@ -246,9 +236,9 @@ export default createReactClass({
query: "",
});
if (this._cancelThreepidLookup) this._cancelThreepidLookup();
- },
+ };
- _doNaiveGroupSearch: function(query) {
+ _doNaiveGroupSearch(query) {
const lowerCaseQuery = query.toLowerCase();
this.setState({
busy: true,
@@ -280,9 +270,9 @@ export default createReactClass({
busy: false,
});
});
- },
+ }
- _doNaiveGroupRoomSearch: function(query) {
+ _doNaiveGroupRoomSearch(query) {
const lowerCaseQuery = query.toLowerCase();
const results = [];
GroupStore.getGroupRooms(this.props.groupId).forEach((r) => {
@@ -302,9 +292,9 @@ export default createReactClass({
this.setState({
busy: false,
});
- },
+ }
- _doRoomSearch: function(query) {
+ _doRoomSearch(query) {
const lowerCaseQuery = query.toLowerCase();
const rooms = MatrixClientPeg.get().getRooms();
const results = [];
@@ -359,9 +349,9 @@ export default createReactClass({
this.setState({
busy: false,
});
- },
+ }
- _doUserDirectorySearch: function(query) {
+ _doUserDirectorySearch(query) {
this.setState({
busy: true,
query,
@@ -393,9 +383,9 @@ export default createReactClass({
busy: false,
});
});
- },
+ }
- _doLocalSearch: function(query) {
+ _doLocalSearch(query) {
this.setState({
query,
searchError: null,
@@ -417,9 +407,9 @@ export default createReactClass({
});
});
this._processResults(results, query);
- },
+ }
- _processResults: function(results, query) {
+ _processResults(results, query) {
const suggestedList = [];
results.forEach((result) => {
if (result.room_id) {
@@ -485,9 +475,9 @@ export default createReactClass({
}, () => {
if (this.addressSelector) this.addressSelector.moveSelectionTop();
});
- },
+ }
- _addAddressesToList: function(addressTexts) {
+ _addAddressesToList(addressTexts) {
const selectedList = this.state.selectedList.slice();
let hasError = false;
@@ -529,9 +519,9 @@ export default createReactClass({
});
if (this._cancelThreepidLookup) this._cancelThreepidLookup();
return hasError ? null : selectedList;
- },
+ }
- _lookupThreepid: async function(medium, address) {
+ async _lookupThreepid(medium, address) {
let cancelled = false;
// Note that we can't safely remove this after we're done
// because we don't know that it's the same one, so we just
@@ -577,9 +567,9 @@ export default createReactClass({
searchError: _t('Something went wrong!'),
});
}
- },
+ }
- _getFilteredSuggestions: function() {
+ _getFilteredSuggestions() {
// map addressType => set of addresses to avoid O(n*m) operation
const selectedAddresses = {};
this.state.selectedList.forEach(({address, addressType}) => {
@@ -591,17 +581,17 @@ export default createReactClass({
return this.state.suggestedList.filter(({address, addressType}) => {
return !(selectedAddresses[addressType] && selectedAddresses[addressType].has(address));
});
- },
+ }
- _onPaste: function(e) {
+ _onPaste = e => {
// Prevent the text being pasted into the textarea
e.preventDefault();
const text = e.clipboardData.getData("text");
// Process it as a list of addresses to add instead
this._addAddressesToList(text.split(/[\s,]+/));
- },
+ };
- onUseDefaultIdentityServerClick(e) {
+ onUseDefaultIdentityServerClick = e => {
e.preventDefault();
// Update the IS in account data. Actually using it may trigger terms.
@@ -612,15 +602,15 @@ export default createReactClass({
const { validAddressTypes } = this.state;
validAddressTypes.push('email');
this.setState({ validAddressTypes });
- },
+ };
- onManageSettingsClick(e) {
+ onManageSettingsClick = e => {
e.preventDefault();
dis.fire(Action.ViewUserSettings);
this.onCancel();
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
const AddressSelector = sdk.getComponent("elements.AddressSelector");
@@ -738,5 +728,5 @@ export default createReactClass({
onCancel={this.onCancel} />
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/AskInviteAnywayDialog.js b/src/components/views/dialogs/AskInviteAnywayDialog.js
index 7a12d2bd20..c69400977a 100644
--- a/src/components/views/dialogs/AskInviteAnywayDialog.js
+++ b/src/components/views/dialogs/AskInviteAnywayDialog.js
@@ -16,37 +16,36 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import SettingsStore from "../../../settings/SettingsStore";
import {SettingLevel} from "../../../settings/SettingLevel";
-export default createReactClass({
- propTypes: {
+export default class AskInviteAnywayDialog extends React.Component {
+ static propTypes = {
unknownProfileUsers: PropTypes.array.isRequired, // [ {userId, errorText}... ]
onInviteAnyways: PropTypes.func.isRequired,
onGiveUp: PropTypes.func.isRequired,
onFinished: PropTypes.func.isRequired,
- },
+ };
- _onInviteClicked: function() {
+ _onInviteClicked = () => {
this.props.onInviteAnyways();
this.props.onFinished(true);
- },
+ };
- _onInviteNeverWarnClicked: function() {
+ _onInviteNeverWarnClicked = () => {
SettingsStore.setValue("promptBeforeInviteUnknownUsers", null, SettingLevel.ACCOUNT, false);
this.props.onInviteAnyways();
this.props.onFinished(true);
- },
+ };
- _onGiveUpClicked: function() {
+ _onGiveUpClicked = () => {
this.props.onGiveUp();
this.props.onFinished(false);
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const errorList = this.props.unknownProfileUsers
@@ -78,5 +77,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js
index 353298032c..55760e54fc 100644
--- a/src/components/views/dialogs/BaseDialog.js
+++ b/src/components/views/dialogs/BaseDialog.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import FocusLock from 'react-focus-lock';
import PropTypes from 'prop-types';
import classNames from 'classnames';
@@ -34,10 +33,8 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
* Includes a div for the title, and a keypress handler which cancels the
* dialog on escape.
*/
-export default createReactClass({
- displayName: 'BaseDialog',
-
- propTypes: {
+export default class BaseDialog extends React.Component {
+ static propTypes = {
// onFinished callback to call when Escape is pressed
// Take a boolean which is true if the dialog was dismissed
// with a positive / confirm action or false if it was
@@ -81,21 +78,20 @@ export default createReactClass({
PropTypes.object,
PropTypes.arrayOf(PropTypes.string),
]),
- },
+ };
- getDefaultProps: function() {
- return {
- hasCancel: true,
- fixedWidth: true,
- };
- },
+ static defaultProps = {
+ hasCancel: true,
+ fixedWidth: true,
+ };
+
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Move this to constructor
- UNSAFE_componentWillMount() {
this._matrixClient = MatrixClientPeg.get();
- },
+ }
- _onKeyDown: function(e) {
+ _onKeyDown = (e) => {
if (this.props.onKeyDown) {
this.props.onKeyDown(e);
}
@@ -104,13 +100,13 @@ export default createReactClass({
e.preventDefault();
this.props.onFinished(false);
}
- },
+ };
- _onCancelClick: function(e) {
+ _onCancelClick = (e) => {
this.props.onFinished(false);
- },
+ };
- render: function() {
+ render() {
let cancelButton;
if (this.props.hasCancel) {
cancelButton = (
@@ -161,5 +157,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/ConfirmRedactDialog.js b/src/components/views/dialogs/ConfirmRedactDialog.js
index 71139155ec..3106df1d5b 100644
--- a/src/components/views/dialogs/ConfirmRedactDialog.js
+++ b/src/components/views/dialogs/ConfirmRedactDialog.js
@@ -15,17 +15,14 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
/*
* A dialog for confirming a redaction.
*/
-export default createReactClass({
- displayName: 'ConfirmRedactDialog',
-
- render: function() {
+export default class ConfirmRedactDialog extends React.Component {
+ render() {
const QuestionDialog = sdk.getComponent('views.dialogs.QuestionDialog');
return (
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/ConfirmUserActionDialog.js b/src/components/views/dialogs/ConfirmUserActionDialog.js
index 2495c46327..44f57f047e 100644
--- a/src/components/views/dialogs/ConfirmUserActionDialog.js
+++ b/src/components/views/dialogs/ConfirmUserActionDialog.js
@@ -15,7 +15,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { MatrixClient } from 'matrix-js-sdk';
import * as sdk from '../../../index';
@@ -30,9 +29,8 @@ import { GroupMemberType } from '../../../groups';
* to make it obvious what is going to happen.
* Also tweaks the style for 'dangerous' actions (albeit only with colour)
*/
-export default createReactClass({
- displayName: 'ConfirmUserActionDialog',
- propTypes: {
+export default class ConfirmUserActionDialog extends React.Component {
+ static propTypes = {
// matrix-js-sdk (room) member object. Supply either this or 'groupMember'
member: PropTypes.object,
// group member object. Supply either this or 'member'
@@ -48,35 +46,36 @@ export default createReactClass({
askReason: PropTypes.bool,
danger: PropTypes.bool,
onFinished: PropTypes.func.isRequired,
- },
+ };
- getDefaultProps: () => ({
+ static defaultProps = {
danger: false,
askReason: false,
- }),
+ };
+
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Move this to constructor
- UNSAFE_componentWillMount: function() {
this._reasonField = null;
- },
+ }
- onOk: function() {
+ onOk = () => {
let reason;
if (this._reasonField) {
reason = this._reasonField.value;
}
this.props.onFinished(true, reason);
- },
+ };
- onCancel: function() {
+ onCancel = () => {
this.props.onFinished(false);
- },
+ };
- _collectReasonField: function(e) {
+ _collectReasonField = e => {
this._reasonField = e;
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
const MemberAvatar = sdk.getComponent("views.avatars.MemberAvatar");
@@ -134,5 +133,5 @@ export default createReactClass({
onCancel={this.onCancel} />
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/CreateGroupDialog.js b/src/components/views/dialogs/CreateGroupDialog.js
index 10285ccee0..6636153c98 100644
--- a/src/components/views/dialogs/CreateGroupDialog.js
+++ b/src/components/views/dialogs/CreateGroupDialog.js
@@ -15,46 +15,42 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import dis from '../../../dispatcher/dispatcher';
import { _t } from '../../../languageHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
-export default createReactClass({
- displayName: 'CreateGroupDialog',
- propTypes: {
+export default class CreateGroupDialog extends React.Component {
+ static propTypes = {
onFinished: PropTypes.func.isRequired,
- },
+ };
- getInitialState: function() {
- return {
- groupName: '',
- groupId: '',
- groupError: null,
- creating: false,
- createError: null,
- };
- },
+ state = {
+ groupName: '',
+ groupId: '',
+ groupError: null,
+ creating: false,
+ createError: null,
+ };
- _onGroupNameChange: function(e) {
+ _onGroupNameChange = e => {
this.setState({
groupName: e.target.value,
});
- },
+ };
- _onGroupIdChange: function(e) {
+ _onGroupIdChange = e => {
this.setState({
groupId: e.target.value,
});
- },
+ };
- _onGroupIdBlur: function(e) {
+ _onGroupIdBlur = e => {
this._checkGroupId();
- },
+ };
- _checkGroupId: function(e) {
+ _checkGroupId(e) {
let error = null;
if (!this.state.groupId) {
error = _t("Community IDs cannot be empty.");
@@ -67,9 +63,9 @@ export default createReactClass({
createError: null,
});
return error;
- },
+ }
- _onFormSubmit: function(e) {
+ _onFormSubmit = e => {
e.preventDefault();
if (this._checkGroupId()) return;
@@ -94,13 +90,13 @@ export default createReactClass({
}).finally(() => {
this.setState({creating: false});
});
- },
+ };
- _onCancel: function() {
+ _onCancel = () => {
this.props.onFinished(false);
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const Spinner = sdk.getComponent('elements.Spinner');
@@ -171,5 +167,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/CreateRoomDialog.js b/src/components/views/dialogs/CreateRoomDialog.js
index 4890626527..0fc8cf50b2 100644
--- a/src/components/views/dialogs/CreateRoomDialog.js
+++ b/src/components/views/dialogs/CreateRoomDialog.js
@@ -16,7 +16,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
@@ -28,16 +27,17 @@ import {privateShouldBeEncrypted} from "../../../createRoom";
import TagOrderStore from "../../../stores/TagOrderStore";
import GroupStore from "../../../stores/GroupStore";
-export default createReactClass({
- displayName: 'CreateRoomDialog',
- propTypes: {
+export default class CreateRoomDialog extends React.Component {
+ static propTypes = {
onFinished: PropTypes.func.isRequired,
defaultPublic: PropTypes.bool,
- },
+ };
+
+ constructor(props) {
+ super(props);
- getInitialState() {
const config = SdkConfig.get();
- return {
+ this.state = {
isPublic: this.props.defaultPublic || false,
isEncrypted: privateShouldBeEncrypted(),
name: "",
@@ -47,7 +47,7 @@ export default createReactClass({
noFederate: config.default_federate === false,
nameIsValid: false,
};
- },
+ }
_roomCreateOptions() {
const opts = {};
@@ -77,27 +77,27 @@ export default createReactClass({
}
return opts;
- },
+ }
componentDidMount() {
this._detailsRef.addEventListener("toggle", this.onDetailsToggled);
// move focus to first field when showing dialog
this._nameFieldRef.focus();
- },
+ }
componentWillUnmount() {
this._detailsRef.removeEventListener("toggle", this.onDetailsToggled);
- },
+ }
- _onKeyDown: function(event) {
+ _onKeyDown = event => {
if (event.key === Key.ENTER) {
this.onOk();
event.preventDefault();
event.stopPropagation();
}
- },
+ };
- onOk: async function() {
+ onOk = async () => {
const activeElement = document.activeElement;
if (activeElement) {
activeElement.blur();
@@ -123,51 +123,51 @@ export default createReactClass({
field.validate({ allowEmpty: false, focused: true });
}
}
- },
+ };
- onCancel: function() {
+ onCancel = () => {
this.props.onFinished(false);
- },
+ };
- onNameChange(ev) {
+ onNameChange = ev => {
this.setState({name: ev.target.value});
- },
+ };
- onTopicChange(ev) {
+ onTopicChange = ev => {
this.setState({topic: ev.target.value});
- },
+ };
- onPublicChange(isPublic) {
+ onPublicChange = isPublic => {
this.setState({isPublic});
- },
+ };
- onEncryptedChange(isEncrypted) {
+ onEncryptedChange = isEncrypted => {
this.setState({isEncrypted});
- },
+ };
- onAliasChange(alias) {
+ onAliasChange = alias => {
this.setState({alias});
- },
+ };
- onDetailsToggled(ev) {
+ onDetailsToggled = ev => {
this.setState({detailsOpen: ev.target.open});
- },
+ };
- onNoFederateChange(noFederate) {
+ onNoFederateChange = noFederate => {
this.setState({noFederate});
- },
+ };
- collectDetailsRef(ref) {
+ collectDetailsRef = ref => {
this._detailsRef = ref;
- },
+ };
- async onNameValidate(fieldState) {
- const result = await this._validateRoomName(fieldState);
+ onNameValidate = async fieldState => {
+ const result = await CreateRoomDialog._validateRoomName(fieldState);
this.setState({nameIsValid: result.valid});
return result;
- },
+ };
- _validateRoomName: withValidation({
+ static _validateRoomName = withValidation({
rules: [
{
key: "required",
@@ -175,9 +175,9 @@ export default createReactClass({
invalid: () => _t("Please enter a name for the room"),
},
],
- }),
+ });
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
const Field = sdk.getComponent('views.elements.Field');
@@ -275,5 +275,5 @@ export default createReactClass({
onCancel={this.onCancel} />
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/ErrorDialog.js b/src/components/views/dialogs/ErrorDialog.js
index fbc5509457..acebdcd854 100644
--- a/src/components/views/dialogs/ErrorDialog.js
+++ b/src/components/views/dialogs/ErrorDialog.js
@@ -26,14 +26,12 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
-export default createReactClass({
- displayName: 'ErrorDialog',
- propTypes: {
+export default class ErrorDialog extends React.Component {
+ static propTypes = {
title: PropTypes.string,
description: PropTypes.oneOfType([
PropTypes.element,
@@ -43,18 +41,16 @@ export default createReactClass({
focus: PropTypes.bool,
onFinished: PropTypes.func.isRequired,
headerImage: PropTypes.string,
- },
+ };
- getDefaultProps: function() {
- return {
- focus: true,
- title: null,
- description: null,
- button: null,
- };
- },
+ static defaultProps = {
+ focus: true,
+ title: null,
+ description: null,
+ button: null,
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
return (
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/InfoDialog.js b/src/components/views/dialogs/InfoDialog.js
index b63f6ba9c6..8125bc3edd 100644
--- a/src/components/views/dialogs/InfoDialog.js
+++ b/src/components/views/dialogs/InfoDialog.js
@@ -17,15 +17,13 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import classNames from "classnames";
-export default createReactClass({
- displayName: 'InfoDialog',
- propTypes: {
+export default class InfoDialog extends React.Component {
+ static propTypes = {
className: PropTypes.string,
title: PropTypes.string,
description: PropTypes.node,
@@ -33,21 +31,19 @@ export default createReactClass({
onFinished: PropTypes.func,
hasCloseButton: PropTypes.bool,
onKeyDown: PropTypes.func,
- },
+ };
- getDefaultProps: function() {
- return {
- title: '',
- description: '',
- hasCloseButton: false,
- };
- },
+ static defaultProps = {
+ title: '',
+ description: '',
+ hasCloseButton: false,
+ };
- onFinished: function() {
+ onFinished = () => {
this.props.onFinished();
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
return (
@@ -69,5 +65,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/InteractiveAuthDialog.js b/src/components/views/dialogs/InteractiveAuthDialog.js
index b06ce63ecd..22291225ad 100644
--- a/src/components/views/dialogs/InteractiveAuthDialog.js
+++ b/src/components/views/dialogs/InteractiveAuthDialog.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
@@ -27,10 +26,8 @@ import AccessibleButton from '../elements/AccessibleButton';
import {ERROR_USER_CANCELLED} from "../../structures/InteractiveAuth";
import {SSOAuthEntry} from "../auth/InteractiveAuthEntryComponents";
-export default createReactClass({
- displayName: 'InteractiveAuthDialog',
-
- propTypes: {
+export default class InteractiveAuthDialog extends React.Component {
+ static propTypes = {
// matrix client to use for UI auth requests
matrixClient: PropTypes.object.isRequired,
@@ -70,19 +67,17 @@ export default createReactClass({
//
// Default is defined in _getDefaultDialogAesthetics()
aestheticsForStagePhases: PropTypes.object,
- },
+ };
- getInitialState: function() {
- return {
- authError: null,
+ state = {
+ authError: null,
- // See _onUpdateStagePhase()
- uiaStage: null,
- uiaStagePhase: null,
- };
- },
+ // See _onUpdateStagePhase()
+ uiaStage: null,
+ uiaStagePhase: null,
+ };
- _getDefaultDialogAesthetics: function() {
+ _getDefaultDialogAesthetics() {
const ssoAesthetics = {
[SSOAuthEntry.PHASE_PREAUTH]: {
title: _t("Use Single Sign On to continue"),
@@ -102,9 +97,9 @@ export default createReactClass({
[SSOAuthEntry.LOGIN_TYPE]: ssoAesthetics,
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: ssoAesthetics,
};
- },
+ }
- _onAuthFinished: function(success, result) {
+ _onAuthFinished = (success, result) => {
if (success) {
this.props.onFinished(true, result);
} else {
@@ -116,18 +111,18 @@ export default createReactClass({
});
}
}
- },
+ };
- _onUpdateStagePhase: function(newStage, newPhase) {
+ _onUpdateStagePhase = (newStage, newPhase) => {
// We copy the stage and stage phase params into state for title selection in render()
this.setState({uiaStage: newStage, uiaStagePhase: newPhase});
- },
+ };
- _onDismissClick: function() {
+ _onDismissClick = () => {
this.props.onFinished(false);
- },
+ };
- render: function() {
+ render() {
const InteractiveAuth = sdk.getComponent("structures.InteractiveAuth");
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
@@ -190,5 +185,5 @@ export default createReactClass({
{ content }
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/QuestionDialog.js b/src/components/views/dialogs/QuestionDialog.js
index 07a1eae5d5..d6de60195f 100644
--- a/src/components/views/dialogs/QuestionDialog.js
+++ b/src/components/views/dialogs/QuestionDialog.js
@@ -16,14 +16,12 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
-export default createReactClass({
- displayName: 'QuestionDialog',
- propTypes: {
+export default class QuestionDialog extends React.Component {
+ static propTypes = {
title: PropTypes.string,
description: PropTypes.node,
extraButtons: PropTypes.node,
@@ -34,29 +32,27 @@ export default createReactClass({
headerImage: PropTypes.string,
quitOnly: PropTypes.bool, // quitOnly doesn't show the cancel button just the quit [x].
fixedWidth: PropTypes.bool,
- },
+ };
- getDefaultProps: function() {
- return {
- title: "",
- description: "",
- extraButtons: null,
- focus: true,
- hasCancelButton: true,
- danger: false,
- quitOnly: false,
- };
- },
+ static defaultProps = {
+ title: "",
+ description: "",
+ extraButtons: null,
+ focus: true,
+ hasCancelButton: true,
+ danger: false,
+ quitOnly: false,
+ };
- onOk: function() {
+ onOk = () => {
this.props.onFinished(true);
- },
+ };
- onCancel: function() {
+ onCancel = () => {
this.props.onFinished(false);
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
let primaryButtonClass = "";
@@ -88,5 +84,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/RoomUpgradeDialog.js b/src/components/views/dialogs/RoomUpgradeDialog.js
index c45d82303b..85e97444ed 100644
--- a/src/components/views/dialogs/RoomUpgradeDialog.js
+++ b/src/components/views/dialogs/RoomUpgradeDialog.js
@@ -15,38 +15,33 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';
-export default createReactClass({
- displayName: 'RoomUpgradeDialog',
-
- propTypes: {
+export default class RoomUpgradeDialog extends React.Component {
+ static propTypes = {
room: PropTypes.object.isRequired,
onFinished: PropTypes.func.isRequired,
- },
+ };
- componentDidMount: async function() {
+ state = {
+ busy: true,
+ };
+
+ async componentDidMount() {
const recommended = await this.props.room.getRecommendedVersion();
this._targetVersion = recommended.version;
this.setState({busy: false});
- },
+ }
- getInitialState: function() {
- return {
- busy: true,
- };
- },
-
- _onCancelClick: function() {
+ _onCancelClick = () => {
this.props.onFinished(false);
- },
+ };
- _onUpgradeClick: function() {
+ _onUpgradeClick = () => {
this.setState({busy: true});
MatrixClientPeg.get().upgradeRoom(this.props.room.roomId, this._targetVersion).then(() => {
this.props.onFinished(true);
@@ -59,9 +54,9 @@ export default createReactClass({
}).finally(() => {
this.setState({busy: false});
});
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
const Spinner = sdk.getComponent('views.elements.Spinner');
@@ -106,5 +101,5 @@ export default createReactClass({
{buttons}
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/SessionRestoreErrorDialog.js b/src/components/views/dialogs/SessionRestoreErrorDialog.js
index 3706172085..bae6b19fbe 100644
--- a/src/components/views/dialogs/SessionRestoreErrorDialog.js
+++ b/src/components/views/dialogs/SessionRestoreErrorDialog.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
@@ -25,20 +24,18 @@ import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';
-export default createReactClass({
- displayName: 'SessionRestoreErrorDialog',
-
- propTypes: {
+export default class SessionRestoreErrorDialog extends React.Component {
+ static propTypes = {
error: PropTypes.string.isRequired,
onFinished: PropTypes.func.isRequired,
- },
+ };
- _sendBugReport: function() {
+ _sendBugReport = () => {
const BugReportDialog = sdk.getComponent("dialogs.BugReportDialog");
Modal.createTrackedDialog('Session Restore Error', 'Send Bug Report Dialog', BugReportDialog, {});
- },
+ };
- _onClearStorageClick: function() {
+ _onClearStorageClick = () => {
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
Modal.createTrackedDialog('Session Restore Confirm Logout', '', QuestionDialog, {
title: _t("Sign out"),
@@ -48,15 +45,15 @@ export default createReactClass({
danger: true,
onFinished: this.props.onFinished,
});
- },
+ };
- _onRefreshClick: function() {
+ _onRefreshClick = () => {
// Is this likely to help? Probably not, but giving only one button
// that clears your storage seems awful.
window.location.reload(true);
- },
+ };
- render: function() {
+ render() {
const brand = SdkConfig.get().brand;
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
@@ -110,5 +107,5 @@ export default createReactClass({
{ dialogButtons }
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/SetEmailDialog.js b/src/components/views/dialogs/SetEmailDialog.js
index 2e38d6a7c4..75a6a74352 100644
--- a/src/components/views/dialogs/SetEmailDialog.js
+++ b/src/components/views/dialogs/SetEmailDialog.js
@@ -16,7 +16,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import * as Email from '../../../email';
@@ -30,26 +29,23 @@ import Modal from '../../../Modal';
*
* On success, `onFinished(true)` is called.
*/
-export default createReactClass({
- displayName: 'SetEmailDialog',
- propTypes: {
+export default class SetEmailDialog extends React.Component {
+ static propTypes = {
onFinished: PropTypes.func.isRequired,
- },
+ };
- getInitialState: function() {
- return {
- emailAddress: '',
- emailBusy: false,
- };
- },
+ state = {
+ emailAddress: '',
+ emailBusy: false,
+ };
- onEmailAddressChanged: function(value) {
+ onEmailAddressChanged = value => {
this.setState({
emailAddress: value,
});
- },
+ };
- onSubmit: function() {
+ onSubmit = () => {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
@@ -81,21 +77,21 @@ export default createReactClass({
});
});
this.setState({emailBusy: true});
- },
+ };
- onCancelled: function() {
+ onCancelled = () => {
this.props.onFinished(false);
- },
+ };
- onEmailDialogFinished: function(ok) {
+ onEmailDialogFinished = ok => {
if (ok) {
this.verifyEmailAddress();
} else {
this.setState({emailBusy: false});
}
- },
+ };
- verifyEmailAddress: function() {
+ verifyEmailAddress() {
this._addThreepid.checkEmailLinkClicked().then(() => {
this.props.onFinished(true);
}, (err) => {
@@ -119,9 +115,9 @@ export default createReactClass({
});
}
});
- },
+ }
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const Spinner = sdk.getComponent('elements.Spinner');
const EditableText = sdk.getComponent('elements.EditableText');
@@ -161,5 +157,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/SetMxIdDialog.js b/src/components/views/dialogs/SetMxIdDialog.js
index f99d065e7e..c580575f1a 100644
--- a/src/components/views/dialogs/SetMxIdDialog.js
+++ b/src/components/views/dialogs/SetMxIdDialog.js
@@ -16,7 +16,6 @@ limitations under the License.
*/
import React, {createRef} from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
@@ -34,18 +33,22 @@ const USERNAME_CHECK_DEBOUNCE_MS = 250;
*
* On success, `onFinished(true, newDisplayName)` is called.
*/
-export default createReactClass({
- displayName: 'SetMxIdDialog',
- propTypes: {
+export default class SetMxIdDialog extends React.Component {
+ static propTypes = {
onFinished: PropTypes.func.isRequired,
// Called when the user requests to register with a different homeserver
onDifferentServerClicked: PropTypes.func.isRequired,
// Called if the user wants to switch to login instead
onLoginClick: PropTypes.func.isRequired,
- },
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this._input_value = createRef();
+ this._uiAuth = createRef();
+
+ this.state = {
// The entered username
username: '',
// Indicate ongoing work on the username
@@ -60,21 +63,15 @@ export default createReactClass({
// Indicate error with auth
authError: '',
};
- },
+ }
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
- this._input_value = createRef();
- this._uiAuth = createRef();
- },
-
- componentDidMount: function() {
+ componentDidMount() {
this._input_value.current.select();
this._matrixClient = MatrixClientPeg.get();
- },
+ }
- onValueChange: function(ev) {
+ onValueChange = ev => {
this.setState({
username: ev.target.value,
usernameBusy: true,
@@ -99,24 +96,24 @@ export default createReactClass({
});
}, USERNAME_CHECK_DEBOUNCE_MS);
});
- },
+ };
- onKeyUp: function(ev) {
+ onKeyUp = ev => {
if (ev.key === Key.ENTER) {
this.onSubmit();
}
- },
+ };
- onSubmit: function(ev) {
+ onSubmit = ev => {
if (this._uiAuth.current) {
this._uiAuth.current.tryContinue();
}
this.setState({
doingUIAuth: true,
});
- },
+ };
- _doUsernameCheck: function() {
+ _doUsernameCheck() {
// We do a quick check ahead of the username availability API to ensure the
// user ID roughly looks okay from a Matrix perspective.
if (!SAFE_LOCALPART_REGEX.test(this.state.username)) {
@@ -167,13 +164,13 @@ export default createReactClass({
this.setState(newState);
},
);
- },
+ }
- _generatePassword: function() {
+ _generatePassword() {
return Math.random().toString(36).slice(2);
- },
+ }
- _makeRegisterRequest: function(auth) {
+ _makeRegisterRequest = auth => {
// Not upgrading - changing mxids
const guestAccessToken = null;
if (!this._generatedPassword) {
@@ -187,9 +184,9 @@ export default createReactClass({
{},
guestAccessToken,
);
- },
+ };
- _onUIAuthFinished: function(success, response) {
+ _onUIAuthFinished = (success, response) => {
this.setState({
doingUIAuth: false,
});
@@ -207,9 +204,9 @@ export default createReactClass({
accessToken: response.access_token,
password: this._generatedPassword,
});
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const InteractiveAuth = sdk.getComponent('structures.InteractiveAuth');
@@ -303,5 +300,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/SetPasswordDialog.js b/src/components/views/dialogs/SetPasswordDialog.js
index fcc6e67656..3649190ac9 100644
--- a/src/components/views/dialogs/SetPasswordDialog.js
+++ b/src/components/views/dialogs/SetPasswordDialog.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
@@ -63,32 +62,25 @@ const WarmFuzzy = function(props) {
*
* On success, `onFinished()` when finished
*/
-export default createReactClass({
- displayName: 'SetPasswordDialog',
- propTypes: {
+export default class SetPasswordDialog extends React.Component {
+ static propTypes = {
onFinished: PropTypes.func.isRequired,
- },
+ };
- getInitialState: function() {
- return {
- error: null,
- };
- },
+ state = {
+ error: null,
+ };
- componentDidMount: function() {
- console.info('SetPasswordDialog component did mount');
- },
-
- _onPasswordChanged: function(res) {
+ _onPasswordChanged = res => {
Modal.createDialog(WarmFuzzy, {
didSetEmail: res.didSetEmail,
onFinished: () => {
this.props.onFinished();
},
});
- },
+ };
- _onPasswordChangeError: function(err) {
+ _onPasswordChangeError = err => {
let errMsg = err.error || "";
if (err.httpStatus === 403) {
errMsg = _t('Failed to change password. Is your password correct?');
@@ -101,9 +93,9 @@ export default createReactClass({
this.setState({
error: errMsg,
});
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const ChangePassword = sdk.getComponent('views.settings.ChangePassword');
@@ -132,5 +124,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/dialogs/TextInputDialog.js b/src/components/views/dialogs/TextInputDialog.js
index d7ca3f144d..571ed7e413 100644
--- a/src/components/views/dialogs/TextInputDialog.js
+++ b/src/components/views/dialogs/TextInputDialog.js
@@ -15,14 +15,12 @@ limitations under the License.
*/
import React, {createRef} from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import Field from "../elements/Field";
-export default createReactClass({
- displayName: 'TextInputDialog',
- propTypes: {
+export default class TextInputDialog extends React.Component {
+ static propTypes = {
title: PropTypes.string,
description: PropTypes.oneOfType([
PropTypes.element,
@@ -36,39 +34,36 @@ export default createReactClass({
hasCancel: PropTypes.bool,
validator: PropTypes.func, // result of withValidation
fixedWidth: PropTypes.bool,
- },
+ };
- getDefaultProps: function() {
- return {
- title: "",
- value: "",
- description: "",
- focus: true,
- hasCancel: true,
- };
- },
+ static defaultProps = {
+ title: "",
+ value: "",
+ description: "",
+ focus: true,
+ hasCancel: true,
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this._field = createRef();
+
+ this.state = {
value: this.props.value,
valid: false,
};
- },
+ }
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
- this._field = createRef();
- },
-
- componentDidMount: function() {
+ componentDidMount() {
if (this.props.focus) {
// Set the cursor at the end of the text input
// this._field.current.value = this.props.value;
this._field.current.focus();
}
- },
+ }
- onOk: async function(ev) {
+ onOk = async ev => {
ev.preventDefault();
if (this.props.validator) {
await this._field.current.validate({ allowEmpty: false });
@@ -80,27 +75,27 @@ export default createReactClass({
}
}
this.props.onFinished(true, this.state.value);
- },
+ };
- onCancel: function() {
+ onCancel = () => {
this.props.onFinished(false);
- },
+ };
- onChange: function(ev) {
+ onChange = ev => {
this.setState({
value: ev.target.value,
});
- },
+ };
- onValidate: async function(fieldState) {
+ onValidate = async fieldState => {
const result = await this.props.validator(fieldState);
this.setState({
valid: result.valid,
});
return result;
- },
+ };
- render: function() {
+ render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
return (
@@ -137,5 +132,5 @@ export default createReactClass({
/>
);
- },
-});
+ }
+}
diff --git a/src/components/views/elements/ActionButton.js b/src/components/views/elements/ActionButton.js
index 7536d66653..bec016bce0 100644
--- a/src/components/views/elements/ActionButton.js
+++ b/src/components/views/elements/ActionButton.js
@@ -16,16 +16,13 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import AccessibleButton from './AccessibleButton';
import dis from '../../../dispatcher/dispatcher';
import * as sdk from '../../../index';
import Analytics from '../../../Analytics';
-export default createReactClass({
- displayName: 'RoleButton',
-
- propTypes: {
+export default class ActionButton extends React.Component {
+ static propTypes = {
size: PropTypes.string,
tooltip: PropTypes.bool,
action: PropTypes.string.isRequired,
@@ -33,39 +30,35 @@ export default createReactClass({
label: PropTypes.string.isRequired,
iconPath: PropTypes.string,
className: PropTypes.string,
- },
+ };
- getDefaultProps: function() {
- return {
- size: "25",
- tooltip: false,
- };
- },
+ static defaultProps = {
+ size: "25",
+ tooltip: false,
+ };
- getInitialState: function() {
- return {
- showTooltip: false,
- };
- },
+ state = {
+ showTooltip: false,
+ };
- _onClick: function(ev) {
+ _onClick = (ev) => {
ev.stopPropagation();
Analytics.trackEvent('Action Button', 'click', this.props.action);
dis.dispatch({action: this.props.action});
- },
+ };
- _onMouseEnter: function() {
+ _onMouseEnter = () => {
if (this.props.tooltip) this.setState({showTooltip: true});
if (this.props.mouseOverAction) {
dis.dispatch({action: this.props.mouseOverAction});
}
- },
+ };
- _onMouseLeave: function() {
+ _onMouseLeave = () => {
this.setState({showTooltip: false});
- },
+ };
- render: function() {
+ render() {
const TintableSvg = sdk.getComponent("elements.TintableSvg");
let tooltip;
@@ -94,5 +87,5 @@ export default createReactClass({
{ tooltip }
);
- },
-});
+ }
+}
diff --git a/src/components/views/elements/AddressSelector.js b/src/components/views/elements/AddressSelector.js
index ab29723a45..45cdbeced8 100644
--- a/src/components/views/elements/AddressSelector.js
+++ b/src/components/views/elements/AddressSelector.js
@@ -17,15 +17,12 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import classNames from 'classnames';
import { UserAddressType } from '../../../UserAddress';
-export default createReactClass({
- displayName: 'AddressSelector',
-
- propTypes: {
+export default class AddressSelector extends React.Component {
+ static propTypes = {
onSelected: PropTypes.func.isRequired,
// List of the addresses to display
@@ -37,90 +34,91 @@ export default createReactClass({
// Element to put as a header on top of the list
header: PropTypes.node,
- },
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this.state = {
selected: this.props.selected === undefined ? 0 : this.props.selected,
hover: false,
};
- },
+ }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
- UNSAFE_componentWillReceiveProps: function(props) {
+ UNSAFE_componentWillReceiveProps(props) {
// Make sure the selected item isn't outside the list bounds
const selected = this.state.selected;
const maxSelected = this._maxSelected(props.addressList);
if (selected > maxSelected) {
this.setState({ selected: maxSelected });
}
- },
+ }
- componentDidUpdate: function() {
+ componentDidUpdate() {
// As the user scrolls with the arrow keys keep the selected item
// at the top of the window.
if (this.scrollElement && this.props.addressList.length > 0 && !this.state.hover) {
const elementHeight = this.addressListElement.getBoundingClientRect().height;
this.scrollElement.scrollTop = (this.state.selected * elementHeight) - elementHeight;
}
- },
+ }
- moveSelectionTop: function() {
+ moveSelectionTop = () => {
if (this.state.selected > 0) {
this.setState({
selected: 0,
hover: false,
});
}
- },
+ };
- moveSelectionUp: function() {
+ moveSelectionUp = () => {
if (this.state.selected > 0) {
this.setState({
selected: this.state.selected - 1,
hover: false,
});
}
- },
+ };
- moveSelectionDown: function() {
+ moveSelectionDown = () => {
if (this.state.selected < this._maxSelected(this.props.addressList)) {
this.setState({
selected: this.state.selected + 1,
hover: false,
});
}
- },
+ };
- chooseSelection: function() {
+ chooseSelection = () => {
this.selectAddress(this.state.selected);
- },
+ };
- onClick: function(index) {
+ onClick = index => {
this.selectAddress(index);
- },
+ };
- onMouseEnter: function(index) {
+ onMouseEnter = index => {
this.setState({
selected: index,
hover: true,
});
- },
+ };
- onMouseLeave: function() {
+ onMouseLeave = () => {
this.setState({ hover: false });
- },
+ };
- selectAddress: function(index) {
+ selectAddress = index => {
// Only try to select an address if one exists
if (this.props.addressList.length !== 0) {
this.props.onSelected(index);
this.setState({ hover: false });
}
- },
+ };
- createAddressListTiles: function() {
- const self = this;
+ createAddressListTiles() {
const AddressTile = sdk.getComponent("elements.AddressTile");
const maxSelected = this._maxSelected(this.props.addressList);
const addressList = [];
@@ -157,15 +155,15 @@ export default createReactClass({
}
}
return addressList;
- },
+ }
- _maxSelected: function(list) {
+ _maxSelected(list) {
const listSize = list.length === 0 ? 0 : list.length - 1;
const maxSelected = listSize > (this.props.truncateAt - 1) ? (this.props.truncateAt - 1) : listSize;
return maxSelected;
- },
+ }
- render: function() {
+ render() {
const classes = classNames({
"mx_AddressSelector": true,
"mx_AddressSelector_empty": this.props.addressList.length === 0,
@@ -177,5 +175,5 @@ export default createReactClass({
{ this.createAddressListTiles() }
);
- },
-});
+ }
+}
diff --git a/src/components/views/elements/AddressTile.js b/src/components/views/elements/AddressTile.js
index e5ea2e5d20..dc6c6b2914 100644
--- a/src/components/views/elements/AddressTile.js
+++ b/src/components/views/elements/AddressTile.js
@@ -17,7 +17,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import classNames from 'classnames';
import * as sdk from "../../../index";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
@@ -25,25 +24,21 @@ import { _t } from '../../../languageHandler';
import { UserAddressType } from '../../../UserAddress.js';
-export default createReactClass({
- displayName: 'AddressTile',
-
- propTypes: {
+export default class AddressTile extends React.Component {
+ static propTypes = {
address: UserAddressType.isRequired,
canDismiss: PropTypes.bool,
onDismissed: PropTypes.func,
justified: PropTypes.bool,
- },
+ };
- getDefaultProps: function() {
- return {
- canDismiss: false,
- onDismissed: function() {}, // NOP
- justified: false,
- };
- },
+ static defaultProps = {
+ canDismiss: false,
+ onDismissed: function() {}, // NOP
+ justified: false,
+ };
- render: function() {
+ render() {
const address = this.props.address;
const name = address.displayName || address.address;
@@ -144,5 +139,5 @@ export default createReactClass({
{ dismiss }
);
- },
-});
+ }
+}
diff --git a/src/components/views/elements/DialogButtons.js b/src/components/views/elements/DialogButtons.js
index 9223b5ade8..001292b6b7 100644
--- a/src/components/views/elements/DialogButtons.js
+++ b/src/components/views/elements/DialogButtons.js
@@ -18,16 +18,13 @@ limitations under the License.
import React from "react";
import PropTypes from "prop-types";
-import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
/**
* Basic container for buttons in modal dialogs.
*/
-export default createReactClass({
- displayName: "DialogButtons",
-
- propTypes: {
+export default class DialogButtons extends React.Component {
+ static propTypes = {
// The primary button which is styled differently and has default focus.
primaryButton: PropTypes.node.isRequired,
@@ -57,20 +54,18 @@ export default createReactClass({
// disables only the primary button
primaryDisabled: PropTypes.bool,
- },
+ };
- getDefaultProps: function() {
- return {
- hasCancel: true,
- disabled: false,
- };
- },
+ static defaultProps = {
+ hasCancel: true,
+ disabled: false,
+ };
- _onCancelClick: function() {
+ _onCancelClick = () => {
this.props.onCancel();
- },
+ };
- render: function() {
+ render() {
let primaryButtonClassName = "mx_Dialog_primary";
if (this.props.primaryButtonClass) {
primaryButtonClassName += " " + this.props.primaryButtonClass;
@@ -104,5 +99,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/elements/EditableText.js b/src/components/views/elements/EditableText.js
index 82f5eef125..5a2c042b83 100644
--- a/src/components/views/elements/EditableText.js
+++ b/src/components/views/elements/EditableText.js
@@ -17,13 +17,10 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import {Key} from "../../../Keyboard";
-export default createReactClass({
- displayName: 'EditableText',
-
- propTypes: {
+export default class EditableText extends React.Component {
+ static propTypes = {
onValueChanged: PropTypes.func,
initialValue: PropTypes.string,
label: PropTypes.string,
@@ -36,60 +33,62 @@ export default createReactClass({
// Will cause onValueChanged(value, true) to fire on blur
blurToSubmit: PropTypes.bool,
editable: PropTypes.bool,
- },
+ };
- Phases: {
+ static Phases = {
Display: "display",
Edit: "edit",
- },
+ };
- getDefaultProps: function() {
- return {
- onValueChanged: function() {},
- initialValue: '',
- label: '',
- placeholder: '',
- editable: true,
- className: "mx_EditableText",
- placeholderClassName: "mx_EditableText_placeholder",
- blurToSubmit: false,
- };
- },
+ static defaultProps = {
+ onValueChanged() {},
+ initialValue: '',
+ label: '',
+ placeholder: '',
+ editable: true,
+ className: "mx_EditableText",
+ placeholderClassName: "mx_EditableText_placeholder",
+ blurToSubmit: false,
+ };
- getInitialState: function() {
- return {
- phase: this.Phases.Display,
- };
- },
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Replace with appropriate lifecycle event
- UNSAFE_componentWillReceiveProps: function(nextProps) {
- if (nextProps.initialValue !== this.props.initialValue) {
- this.value = nextProps.initialValue;
- if (this._editable_div.current) {
- this.showPlaceholder(!this.value);
- }
- }
- },
-
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
// we track value as an JS object field rather than in React state
// as React doesn't play nice with contentEditable.
this.value = '';
this.placeholder = false;
this._editable_div = createRef();
- },
- componentDidMount: function() {
+ this.state = {
+ phase: EditableText.Phases.Display,
+ };
+ }
+
+
+ state = {
+ phase: EditableText.Phases.Display,
+ };
+
+ // TODO: [REACT-WARNING] Replace with appropriate lifecycle event
+ UNSAFE_componentWillReceiveProps(nextProps) {
+ if (nextProps.initialValue !== this.props.initialValue) {
+ this.value = nextProps.initialValue;
+ if (this._editable_div.current) {
+ this.showPlaceholder(!this.value);
+ }
+ }
+ }
+
+ componentDidMount() {
this.value = this.props.initialValue;
if (this._editable_div.current) {
this.showPlaceholder(!this.value);
}
- },
+ }
- showPlaceholder: function(show) {
+ showPlaceholder = show => {
if (show) {
this._editable_div.current.textContent = this.props.placeholder;
this._editable_div.current.setAttribute("class", this.props.className
@@ -101,38 +100,36 @@ export default createReactClass({
this._editable_div.current.setAttribute("class", this.props.className);
this.placeholder = false;
}
- },
+ };
- getValue: function() {
- return this.value;
- },
+ getValue = () => this.value;
- setValue: function(value) {
+ setValue = value => {
this.value = value;
this.showPlaceholder(!this.value);
- },
+ };
- edit: function() {
+ edit = () => {
this.setState({
- phase: this.Phases.Edit,
+ phase: EditableText.Phases.Edit,
});
- },
+ };
- cancelEdit: function() {
+ cancelEdit = () => {
this.setState({
- phase: this.Phases.Display,
+ phase: EditableText.Phases.Display,
});
this.value = this.props.initialValue;
this.showPlaceholder(!this.value);
this.onValueChanged(false);
this._editable_div.current.blur();
- },
+ };
- onValueChanged: function(shouldSubmit) {
+ onValueChanged = shouldSubmit => {
this.props.onValueChanged(this.value, shouldSubmit);
- },
+ };
- onKeyDown: function(ev) {
+ onKeyDown = ev => {
// console.log("keyDown: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder);
if (this.placeholder) {
@@ -145,9 +142,9 @@ export default createReactClass({
}
// console.log("keyDown: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder);
- },
+ };
- onKeyUp: function(ev) {
+ onKeyUp = ev => {
// console.log("keyUp: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder);
if (!ev.target.textContent) {
@@ -163,17 +160,17 @@ export default createReactClass({
}
// console.log("keyUp: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder);
- },
+ };
- onClickDiv: function(ev) {
+ onClickDiv = ev => {
if (!this.props.editable) return;
this.setState({
- phase: this.Phases.Edit,
+ phase: EditableText.Phases.Edit,
});
- },
+ };
- onFocus: function(ev) {
+ onFocus = ev => {
//ev.target.setSelectionRange(0, ev.target.textContent.length);
const node = ev.target.childNodes[0];
@@ -186,21 +183,21 @@ export default createReactClass({
sel.removeAllRanges();
sel.addRange(range);
}
- },
+ };
- onFinish: function(ev, shouldSubmit) {
+ onFinish = (ev, shouldSubmit) => {
const self = this;
const submit = (ev.key === Key.ENTER) || shouldSubmit;
this.setState({
- phase: this.Phases.Display,
+ phase: EditableText.Phases.Display,
}, () => {
if (this.value !== this.props.initialValue) {
self.onValueChanged(submit);
}
});
- },
+ };
- onBlur: function(ev) {
+ onBlur = ev => {
const sel = window.getSelection();
sel.removeAllRanges();
@@ -211,13 +208,13 @@ export default createReactClass({
}
this.showPlaceholder(!this.value);
- },
+ };
- render: function() {
+ render() {
const {className, editable, initialValue, label, labelClassName} = this.props;
let editableEl;
- if (!editable || (this.state.phase === this.Phases.Display && (label || labelClassName) && !this.value)) {
+ if (!editable || (this.state.phase === EditableText.Phases.Display && (label || labelClassName) && !this.value)) {
// show the label
editableEl =
{ label || initialValue }
@@ -234,5 +231,5 @@ export default createReactClass({
}
return editableEl;
- },
-});
+ }
+}
diff --git a/src/components/views/elements/InlineSpinner.js b/src/components/views/elements/InlineSpinner.js
index ce3c738f3b..73316157f4 100644
--- a/src/components/views/elements/InlineSpinner.js
+++ b/src/components/views/elements/InlineSpinner.js
@@ -15,14 +15,11 @@ limitations under the License.
*/
import React from "react";
-import createReactClass from 'create-react-class';
import {_t} from "../../../languageHandler";
import SettingsStore from "../../../settings/SettingsStore";
-export default createReactClass({
- displayName: 'InlineSpinner',
-
- render: function() {
+export default class InlineSpinner extends React.Component {
+ render() {
const w = this.props.w || 16;
const h = this.props.h || 16;
const imgClass = this.props.imgClassName || "";
@@ -45,5 +42,5 @@ export default createReactClass({
/>
);
- },
-});
+ }
+}
diff --git a/src/components/views/elements/MemberEventListSummary.js b/src/components/views/elements/MemberEventListSummary.js
index 956b69ca7b..e16b52c8a2 100644
--- a/src/components/views/elements/MemberEventListSummary.js
+++ b/src/components/views/elements/MemberEventListSummary.js
@@ -18,17 +18,14 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
import { formatCommaSeparatedList } from '../../../utils/FormattingUtils';
import * as sdk from "../../../index";
import {MatrixEvent} from "matrix-js-sdk";
import {isValid3pidInvite} from "../../../RoomInvite";
-export default createReactClass({
- displayName: 'MemberEventListSummary',
-
- propTypes: {
+export default class MemberEventListSummary extends React.Component {
+ static propTypes = {
// An array of member events to summarise
events: PropTypes.arrayOf(PropTypes.instanceOf(MatrixEvent)).isRequired,
// An array of EventTiles to render when expanded
@@ -43,17 +40,15 @@ export default createReactClass({
onToggle: PropTypes.func,
// Whether or not to begin with state.expanded=true
startExpanded: PropTypes.bool,
- },
+ };
- getDefaultProps: function() {
- return {
- summaryLength: 1,
- threshold: 3,
- avatarsMaxLength: 5,
- };
- },
+ static defaultProps = {
+ summaryLength: 1,
+ threshold: 3,
+ avatarsMaxLength: 5,
+ };
- shouldComponentUpdate: function(nextProps) {
+ shouldComponentUpdate(nextProps) {
// Update if
// - The number of summarised events has changed
// - or if the summary is about to toggle to become collapsed
@@ -62,7 +57,7 @@ export default createReactClass({
nextProps.events.length !== this.props.events.length ||
nextProps.events.length < this.props.threshold
);
- },
+ }
/**
* Generate the text for users aggregated by their transition sequences (`eventAggregates`) where
@@ -73,7 +68,7 @@ export default createReactClass({
* `Object.keys(eventAggregates)`.
* @returns {string} the textual summary of the aggregated events that occurred.
*/
- _generateSummary: function(eventAggregates, orderedTransitionSequences) {
+ _generateSummary(eventAggregates, orderedTransitionSequences) {
const summaries = orderedTransitionSequences.map((transitions) => {
const userNames = eventAggregates[transitions];
const nameList = this._renderNameList(userNames);
@@ -105,7 +100,7 @@ export default createReactClass({
}
return summaries.join(", ");
- },
+ }
/**
* @param {string[]} users an array of user display names or user IDs.
@@ -113,9 +108,9 @@ export default createReactClass({
* more items in `users` than `this.props.summaryLength`, which is the number of names
* included before "and [n] others".
*/
- _renderNameList: function(users) {
+ _renderNameList(users) {
return formatCommaSeparatedList(users, this.props.summaryLength);
- },
+ }
/**
* Canonicalise an array of transitions such that some pairs of transitions become
@@ -124,7 +119,7 @@ export default createReactClass({
* @param {string[]} transitions an array of transitions.
* @returns {string[]} an array of transitions.
*/
- _getCanonicalTransitions: function(transitions) {
+ _getCanonicalTransitions(transitions) {
const modMap = {
'joined': {
'after': 'left',
@@ -155,7 +150,7 @@ export default createReactClass({
res.push(transition);
}
return res;
- },
+ }
/**
* Transform an array of transitions into an array of transitions and how many times
@@ -171,7 +166,7 @@ export default createReactClass({
* @param {string[]} transitions the array of transitions to transform.
* @returns {object[]} an array of coalesced transitions.
*/
- _coalesceRepeatedTransitions: function(transitions) {
+ _coalesceRepeatedTransitions(transitions) {
const res = [];
for (let i = 0; i < transitions.length; i++) {
if (res.length > 0 && res[res.length - 1].transitionType === transitions[i]) {
@@ -184,7 +179,7 @@ export default createReactClass({
}
}
return res;
- },
+ }
/**
* For a certain transition, t, describe what happened to the users that
@@ -268,11 +263,11 @@ export default createReactClass({
}
return res;
- },
+ }
- _getTransitionSequence: function(events) {
+ _getTransitionSequence(events) {
return events.map(this._getTransition);
- },
+ }
/**
* Label a given membership event, `e`, where `getContent().membership` has
@@ -282,7 +277,7 @@ export default createReactClass({
* @returns {string?} the transition type given to this event. This defaults to `null`
* if a transition is not recognised.
*/
- _getTransition: function(e) {
+ _getTransition(e) {
if (e.mxEvent.getType() === 'm.room.third_party_invite') {
// Handle 3pid invites the same as invites so they get bundled together
if (!isValid3pidInvite(e.mxEvent)) {
@@ -323,9 +318,9 @@ export default createReactClass({
}
default: return null;
}
- },
+ }
- _getAggregate: function(userEvents) {
+ _getAggregate(userEvents) {
// A map of aggregate type to arrays of display names. Each aggregate type
// is a comma-delimited string of transitions, e.g. "joined,left,kicked".
// The array of display names is the array of users who went through that
@@ -364,9 +359,9 @@ export default createReactClass({
names: aggregate,
indices: aggregateIndices,
};
- },
+ }
- render: function() {
+ render() {
const eventsToRender = this.props.events;
// Map user IDs to an array of objects:
@@ -420,5 +415,5 @@ export default createReactClass({
children={this.props.children}
summaryMembers={avatarMembers}
summaryText={this._generateSummary(aggregate.names, orderedTransitionSequences)} />;
- },
-});
+ }
+}
diff --git a/src/components/views/elements/PersistentApp.js b/src/components/views/elements/PersistentApp.js
index a146debc45..bdf5f60234 100644
--- a/src/components/views/elements/PersistentApp.js
+++ b/src/components/views/elements/PersistentApp.js
@@ -16,49 +16,44 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import RoomViewStore from '../../../stores/RoomViewStore';
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
import WidgetUtils from '../../../utils/WidgetUtils';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
-export default createReactClass({
- displayName: 'PersistentApp',
+export default class PersistentApp extends React.Component {
+ state = {
+ roomId: RoomViewStore.getRoomId(),
+ persistentWidgetId: ActiveWidgetStore.getPersistentWidgetId(),
+ };
- getInitialState: function() {
- return {
- roomId: RoomViewStore.getRoomId(),
- persistentWidgetId: ActiveWidgetStore.getPersistentWidgetId(),
- };
- },
-
- componentDidMount: function() {
+ componentDidMount() {
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
ActiveWidgetStore.on('update', this._onActiveWidgetStoreUpdate);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
if (this._roomStoreToken) {
this._roomStoreToken.remove();
}
ActiveWidgetStore.removeListener('update', this._onActiveWidgetStoreUpdate);
- },
+ }
- _onRoomViewStoreUpdate: function(payload) {
+ _onRoomViewStoreUpdate = payload => {
if (RoomViewStore.getRoomId() === this.state.roomId) return;
this.setState({
roomId: RoomViewStore.getRoomId(),
});
- },
+ };
- _onActiveWidgetStoreUpdate: function() {
+ _onActiveWidgetStoreUpdate = () => {
this.setState({
persistentWidgetId: ActiveWidgetStore.getPersistentWidgetId(),
});
- },
+ };
- render: function() {
+ render() {
if (this.state.persistentWidgetId) {
const persistentWidgetInRoomId = ActiveWidgetStore.getRoomId(this.state.persistentWidgetId);
if (this.state.roomId !== persistentWidgetInRoomId) {
@@ -91,6 +86,6 @@ export default createReactClass({
}
}
return null;
- },
-});
+ }
+}
diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js
index 03a1aeed85..58537d4865 100644
--- a/src/components/views/elements/Pill.js
+++ b/src/components/views/elements/Pill.js
@@ -16,7 +16,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import dis from '../../../dispatcher/dispatcher';
import classNames from 'classnames';
@@ -32,27 +31,29 @@ import {Action} from "../../../dispatcher/actions";
// HttpUtils transformTags to relative links. This excludes event URLs (with `[^\/]*`)
const REGEX_LOCAL_PERMALINK = /^#\/(?:user|room|group)\/(([#!@+])[^/]*)$/;
-const Pill = createReactClass({
- statics: {
- isPillUrl: (url) => {
- return !!getPrimaryPermalinkEntity(url);
- },
- isMessagePillUrl: (url) => {
- return !!REGEX_LOCAL_PERMALINK.exec(url);
- },
- roomNotifPos: (text) => {
- return text.indexOf("@room");
- },
- roomNotifLen: () => {
- return "@room".length;
- },
- TYPE_USER_MENTION: 'TYPE_USER_MENTION',
- TYPE_ROOM_MENTION: 'TYPE_ROOM_MENTION',
- TYPE_GROUP_MENTION: 'TYPE_GROUP_MENTION',
- TYPE_AT_ROOM_MENTION: 'TYPE_AT_ROOM_MENTION', // '@room' mention
- },
+class Pill extends React.Component {
+ static isPillUrl(url) {
+ return !!getPrimaryPermalinkEntity(url);
+ }
- props: {
+ static isMessagePillUrl(url) {
+ return !!REGEX_LOCAL_PERMALINK.exec(url);
+ }
+
+ static roomNotifPos(text) {
+ return text.indexOf("@room");
+ }
+
+ static roomNotifLen() {
+ return "@room".length;
+ }
+
+ static TYPE_USER_MENTION = 'TYPE_USER_MENTION';
+ static TYPE_ROOM_MENTION = 'TYPE_ROOM_MENTION';
+ static TYPE_GROUP_MENTION = 'TYPE_GROUP_MENTION';
+ static TYPE_AT_ROOM_MENTION = 'TYPE_AT_ROOM_MENTION'; // '@room' mention
+
+ static propTypes = {
// The Type of this Pill. If url is given, this is auto-detected.
type: PropTypes.string,
// The URL to pillify (no validation is done, see isPillUrl and isMessagePillUrl)
@@ -65,23 +66,21 @@ const Pill = createReactClass({
shouldShowPillAvatar: PropTypes.bool,
// Whether to render this pill as if it were highlit by a selection
isSelected: PropTypes.bool,
- },
+ };
- getInitialState() {
- return {
- // ID/alias of the room/user
- resourceId: null,
- // Type of pill
- pillType: null,
+ state = {
+ // ID/alias of the room/user
+ resourceId: null,
+ // Type of pill
+ pillType: null,
- // The member related to the user pill
- member: null,
- // The group related to the group pill
- group: null,
- // The room related to the room pill
- room: null,
- };
- },
+ // The member related to the user pill
+ member: null,
+ // The group related to the group pill
+ group: null,
+ // The room related to the room pill
+ room: null,
+ };
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
async UNSAFE_componentWillReceiveProps(nextProps) {
@@ -155,7 +154,7 @@ const Pill = createReactClass({
}
}
this.setState({resourceId, pillType, member, group, room});
- },
+ }
componentDidMount() {
this._unmounted = false;
@@ -163,13 +162,13 @@ const Pill = createReactClass({
// eslint-disable-next-line new-cap
this.UNSAFE_componentWillReceiveProps(this.props); // HACK: We shouldn't be calling lifecycle functions ourselves.
- },
+ }
componentWillUnmount() {
this._unmounted = true;
- },
+ }
- doProfileLookup: function(userId, member) {
+ doProfileLookup(userId, member) {
MatrixClientPeg.get().getProfileInfo(userId).then((resp) => {
if (this._unmounted) {
return;
@@ -188,15 +187,16 @@ const Pill = createReactClass({
}).catch((err) => {
console.error('Could not retrieve profile data for ' + userId + ':', err);
});
- },
+ }
- onUserPillClicked: function() {
+ onUserPillClicked = () => {
dis.dispatch({
action: Action.ViewUser,
member: this.state.member,
});
- },
- render: function() {
+ };
+
+ render() {
const BaseAvatar = sdk.getComponent('views.avatars.BaseAvatar');
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
const RoomAvatar = sdk.getComponent('avatars.RoomAvatar');
@@ -285,7 +285,7 @@ const Pill = createReactClass({
// Deliberately render nothing if the URL isn't recognised
return null;
}
- },
-});
+ }
+}
export default Pill;
diff --git a/src/components/views/elements/PowerSelector.js b/src/components/views/elements/PowerSelector.js
index 948b4835d5..4d00832d8d 100644
--- a/src/components/views/elements/PowerSelector.js
+++ b/src/components/views/elements/PowerSelector.js
@@ -16,16 +16,13 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as Roles from '../../../Roles';
import { _t } from '../../../languageHandler';
import Field from "./Field";
import {Key} from "../../../Keyboard";
-export default createReactClass({
- displayName: 'PowerSelector',
-
- propTypes: {
+export default class PowerSelector extends React.Component {
+ static propTypes = {
value: PropTypes.number.isRequired,
// The maximum value that can be set with the power selector
maxValue: PropTypes.number.isRequired,
@@ -42,10 +39,17 @@ export default createReactClass({
// The name to annotate the selector with
label: PropTypes.string,
- },
+ }
- getInitialState: function() {
- return {
+ static defaultProps = {
+ maxValue: Infinity,
+ usersDefault: 0,
+ };
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
levelRoleMap: {},
// List of power levels to show in the drop-down
options: [],
@@ -53,26 +57,16 @@ export default createReactClass({
customValue: this.props.value,
selectValue: 0,
};
- },
- getDefaultProps: function() {
- return {
- maxValue: Infinity,
- usersDefault: 0,
- };
- },
-
- componentDidMount: function() {
- // TODO: [REACT-WARNING] Move this to class constructor
this._initStateFromProps(this.props);
- },
+ }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
- UNSAFE_componentWillReceiveProps: function(newProps) {
+ UNSAFE_componentWillReceiveProps(newProps) {
this._initStateFromProps(newProps);
- },
+ }
- _initStateFromProps: function(newProps) {
+ _initStateFromProps(newProps) {
// This needs to be done now because levelRoleMap has translated strings
const levelRoleMap = Roles.levelRoleMap(newProps.usersDefault);
const options = Object.keys(levelRoleMap).filter(level => {
@@ -92,9 +86,9 @@ export default createReactClass({
customLevel: newProps.value,
selectValue: isCustom ? "SELECT_VALUE_CUSTOM" : newProps.value,
});
- },
+ }
- onSelectChange: function(event) {
+ onSelectChange = event => {
const isCustom = event.target.value === "SELECT_VALUE_CUSTOM";
if (isCustom) {
this.setState({custom: true});
@@ -102,20 +96,20 @@ export default createReactClass({
this.props.onChange(event.target.value, this.props.powerLevelKey);
this.setState({selectValue: event.target.value});
}
- },
+ };
- onCustomChange: function(event) {
+ onCustomChange = event => {
this.setState({customValue: event.target.value});
- },
+ };
- onCustomBlur: function(event) {
+ onCustomBlur = event => {
event.preventDefault();
event.stopPropagation();
this.props.onChange(parseInt(this.state.customValue), this.props.powerLevelKey);
- },
+ };
- onCustomKeyDown: function(event) {
+ onCustomKeyDown = event => {
if (event.key === Key.ENTER) {
event.preventDefault();
event.stopPropagation();
@@ -127,9 +121,9 @@ export default createReactClass({
// handle the onBlur safely.
event.target.blur();
}
- },
+ };
- render: function() {
+ render() {
let picker;
const label = typeof this.props.label === "undefined" ? _t("Power level") : this.props.label;
if (this.state.custom) {
@@ -166,5 +160,5 @@ export default createReactClass({
{ picker }
);
- },
-});
+ }
+}
diff --git a/src/components/views/elements/TagTile.js b/src/components/views/elements/TagTile.js
index db5eedc274..b1a526eb0d 100644
--- a/src/components/views/elements/TagTile.js
+++ b/src/components/views/elements/TagTile.js
@@ -18,7 +18,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import classNames from 'classnames';
import * as sdk from '../../../index';
import dis from '../../../dispatcher/dispatcher';
@@ -37,10 +36,8 @@ import SettingsStore from "../../../settings/SettingsStore";
// - Rooms that are part of the group
// - Direct messages with members of the group
// with the intention that this could be expanded to arbitrary tags in future.
-export default createReactClass({
- displayName: 'TagTile',
-
- propTypes: {
+export default class TagTile extends React.Component {
+ static propTypes = {
// A string tag such as "m.favourite" or a group ID such as "+groupid:domain.bla"
// For now, only group IDs are handled.
tag: PropTypes.string,
@@ -48,20 +45,16 @@ export default createReactClass({
openMenu: PropTypes.func,
menuDisplayed: PropTypes.bool,
selected: PropTypes.bool,
- },
+ };
- statics: {
- contextType: MatrixClientContext,
- },
+ static contextType = MatrixClientContext;
- getInitialState() {
- return {
- // Whether the mouse is over the tile
- hover: false,
- // The profile data of the group if this.props.tag is a group ID
- profile: null,
- };
- },
+ state = {
+ // Whether the mouse is over the tile
+ hover: false,
+ // The profile data of the group if this.props.tag is a group ID
+ profile: null,
+ };
componentDidMount() {
this.unmounted = false;
@@ -71,16 +64,16 @@ export default createReactClass({
// New rooms or members may have been added to the group, fetch async
this._refreshGroup(this.props.tag);
}
- },
+ }
componentWillUnmount() {
this.unmounted = true;
if (this.props.tag[0] === '+') {
FlairStore.removeListener('updateGroupProfile', this._onFlairStoreUpdated);
}
- },
+ }
- _onFlairStoreUpdated() {
+ _onFlairStoreUpdated = () => {
if (this.unmounted) return;
FlairStore.getGroupProfileCached(
this.context,
@@ -91,14 +84,14 @@ export default createReactClass({
}).catch((err) => {
console.warn('Could not fetch group profile for ' + this.props.tag, err);
});
- },
+ };
_refreshGroup(groupId) {
GroupStore.refreshGroupRooms(groupId);
GroupStore.refreshGroupMembers(groupId);
- },
+ }
- onClick: function(e) {
+ onClick = e => {
e.preventDefault();
e.stopPropagation();
dis.dispatch({
@@ -111,27 +104,27 @@ export default createReactClass({
// New rooms or members may have been added to the group, fetch async
this._refreshGroup(this.props.tag);
}
- },
+ };
- onMouseOver: function() {
+ onMouseOver = () => {
if (SettingsStore.getValue("feature_communities_v2_prototypes")) return;
this.setState({ hover: true });
- },
+ };
- onMouseLeave: function() {
+ onMouseLeave = () => {
this.setState({ hover: false });
- },
+ };
- openMenu: function(e) {
+ openMenu = e => {
// Prevent the TagTile onClick event firing as well
e.stopPropagation();
e.preventDefault();
if (SettingsStore.getValue("feature_communities_v2_prototypes")) return;
this.setState({ hover: false });
this.props.openMenu();
- },
+ };
- render: function() {
+ render() {
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
const profile = this.state.profile || {};
const name = profile.name || this.props.tag;
@@ -192,5 +185,5 @@ export default createReactClass({
{badgeElement}
;
- },
-});
+ }
+}
diff --git a/src/components/views/elements/TintableSvg.js b/src/components/views/elements/TintableSvg.js
index 66625c7b87..df55b0a854 100644
--- a/src/components/views/elements/TintableSvg.js
+++ b/src/components/views/elements/TintableSvg.js
@@ -17,49 +17,44 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import Tinter from "../../../Tinter";
-const TintableSvg = createReactClass({
- displayName: 'TintableSvg',
-
- propTypes: {
+class TintableSvg extends React.Component {
+ static propTypes = {
src: PropTypes.string.isRequired,
width: PropTypes.string.isRequired,
height: PropTypes.string.isRequired,
className: PropTypes.string,
- },
+ };
- statics: {
- // list of currently mounted TintableSvgs
- mounts: {},
- idSequence: 0,
- },
+ // list of currently mounted TintableSvgs
+ static mounts = {};
+ static idSequence = 0;
- componentDidMount: function() {
+ componentDidMount() {
this.fixups = [];
this.id = TintableSvg.idSequence++;
TintableSvg.mounts[this.id] = this;
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
delete TintableSvg.mounts[this.id];
- },
+ }
- tint: function() {
+ tint = () => {
// TODO: only bother running this if the global tint settings have changed
// since we loaded!
Tinter.applySvgFixups(this.fixups);
- },
+ };
- onLoad: function(event) {
+ onLoad = event => {
// console.log("TintableSvg.onLoad for " + this.props.src);
this.fixups = Tinter.calcSvgFixups([event.target]);
Tinter.applySvgFixups(this.fixups);
- },
+ };
- render: function() {
+ render() {
return (
);
- },
-});
+ }
+}
// Register with the Tinter so that we will be told if the tint changes
Tinter.registerTintable(function() {
diff --git a/src/components/views/elements/TooltipButton.js b/src/components/views/elements/TooltipButton.js
index 5c8d53fbcc..240d763bdc 100644
--- a/src/components/views/elements/TooltipButton.js
+++ b/src/components/views/elements/TooltipButton.js
@@ -16,31 +16,26 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
-export default createReactClass({
- displayName: 'TooltipButton',
+export default class TooltipButton extends React.Component {
+ state = {
+ hover: false,
+ };
- getInitialState: function() {
- return {
- hover: false,
- };
- },
-
- onMouseOver: function() {
+ onMouseOver = () => {
this.setState({
hover: true,
});
- },
+ };
- onMouseLeave: function() {
+ onMouseLeave = () => {
this.setState({
hover: false,
});
- },
+ };
- render: function() {
+ render() {
const Tooltip = sdk.getComponent("elements.Tooltip");
const tip = this.state.hover ?
);
- },
-});
+ }
+}
diff --git a/src/components/views/elements/TruncatedList.js b/src/components/views/elements/TruncatedList.js
index 9ce2395638..81eb057e36 100644
--- a/src/components/views/elements/TruncatedList.js
+++ b/src/components/views/elements/TruncatedList.js
@@ -17,13 +17,10 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
-export default createReactClass({
- displayName: 'TruncatedList',
-
- propTypes: {
+export default class TruncatedList extends React.Component {
+ static propTypes = {
// The number of elements to show before truncating. If negative, no truncation is done.
truncateAt: PropTypes.number,
// The className to apply to the wrapping div
@@ -40,20 +37,18 @@ export default createReactClass({
// A function which will be invoked when an overflow element is required.
// This will be inserted after the children.
createOverflowElement: PropTypes.func,
- },
+ };
- getDefaultProps: function() {
- return {
- truncateAt: 2,
- createOverflowElement: function(overflowCount, totalCount) {
- return (
- { _t("And %(count)s more...", {count: overflowCount}) }
- );
- },
- };
- },
+ static defaultProps ={
+ truncateAt: 2,
+ createOverflowElement(overflowCount, totalCount) {
+ return (
+ { _t("And %(count)s more...", {count: overflowCount}) }
+ );
+ },
+ };
- _getChildren: function(start, end) {
+ _getChildren(start, end) {
if (this.props.getChildren && this.props.getChildCount) {
return this.props.getChildren(start, end);
} else {
@@ -64,9 +59,9 @@ export default createReactClass({
return c != null;
}).slice(start, end);
}
- },
+ }
- _getChildCount: function() {
+ _getChildCount() {
if (this.props.getChildren && this.props.getChildCount) {
return this.props.getChildCount();
} else {
@@ -74,9 +69,9 @@ export default createReactClass({
return c != null;
}).length;
}
- },
+ }
- render: function() {
+ render() {
let overflowNode = null;
const totalChildren = this._getChildCount();
@@ -98,5 +93,5 @@ export default createReactClass({
{ overflowNode }
);
- },
-});
+ }
+}
diff --git a/src/components/views/groups/GroupInviteTile.js b/src/components/views/groups/GroupInviteTile.js
index bc5334f2de..7efb8cf427 100644
--- a/src/components/views/groups/GroupInviteTile.js
+++ b/src/components/views/groups/GroupInviteTile.js
@@ -18,7 +18,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import dis from '../../../dispatcher/dispatcher';
import {_t} from '../../../languageHandler';
@@ -29,50 +28,48 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {RovingTabIndexWrapper} from "../../../accessibility/RovingTabIndex";
// XXX this class copies a lot from RoomTile.js
-export default createReactClass({
- displayName: 'GroupInviteTile',
-
- propTypes: {
+export default class GroupInviteTile extends React.Component {
+ static propTypes: {
group: PropTypes.object.isRequired,
- },
+ };
- statics: {
- contextType: MatrixClientContext,
- },
+ static contextType = MatrixClientContext;
- getInitialState: function() {
- return ({
+ constructor(props) {
+ super(props);
+
+ this.state = {
hover: false,
badgeHover: false,
menuDisplayed: false,
selected: this.props.group.groupId === null, // XXX: this needs linking to LoggedInView/GroupView state
- });
- },
+ };
+ }
- onClick: function(e) {
+ onClick = e => {
dis.dispatch({
action: 'view_group',
group_id: this.props.group.groupId,
});
- },
+ };
- onMouseEnter: function() {
+ onMouseEnter = () => {
const state = {hover: true};
// Only allow non-guests to access the context menu
if (!this.context.isGuest()) {
state.badgeHover = true;
}
this.setState(state);
- },
+ };
- onMouseLeave: function() {
+ onMouseLeave = () => {
this.setState({
badgeHover: false,
hover: false,
});
- },
+ };
- _showContextMenu: function(boundingClientRect) {
+ _showContextMenu(boundingClientRect) {
// Only allow non-guests to access the context menu
if (MatrixClientPeg.get().isGuest()) return;
@@ -86,17 +83,17 @@ export default createReactClass({
}
this.setState(state);
- },
+ }
- onContextMenuButtonClick: function(e) {
+ onContextMenuButtonClick = e => {
// Prevent the RoomTile onClick event firing as well
e.stopPropagation();
e.preventDefault();
this._showContextMenu(e.target.getBoundingClientRect());
- },
+ };
- onContextMenu: function(e) {
+ onContextMenu = e => {
// Prevent the native context menu
e.preventDefault();
@@ -105,15 +102,15 @@ export default createReactClass({
top: e.clientY,
height: 0,
});
- },
+ };
- closeMenu: function() {
+ closeMenu = () => {
this.setState({
contextMenuPosition: null,
});
- },
+ };
- render: function() {
+ render() {
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
@@ -197,5 +194,5 @@ export default createReactClass({
{ contextMenu }
;
- },
-});
+ }
+}
diff --git a/src/components/views/groups/GroupMemberList.js b/src/components/views/groups/GroupMemberList.js
index 031b875409..600a466601 100644
--- a/src/components/views/groups/GroupMemberList.js
+++ b/src/components/views/groups/GroupMemberList.js
@@ -16,7 +16,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
import dis from '../../../dispatcher/dispatcher';
@@ -30,33 +29,29 @@ import {Action} from "../../../dispatcher/actions";
const INITIAL_LOAD_NUM_MEMBERS = 30;
-export default createReactClass({
- displayName: 'GroupMemberList',
-
- propTypes: {
+export default class GroupMemberList extends React.Component {
+ static propTypes = {
groupId: PropTypes.string.isRequired,
- },
+ };
- getInitialState: function() {
- return {
- members: null,
- membersError: null,
- invitedMembers: null,
- invitedMembersError: null,
- truncateAt: INITIAL_LOAD_NUM_MEMBERS,
- };
- },
+ state = {
+ members: null,
+ membersError: null,
+ invitedMembers: null,
+ invitedMembersError: null,
+ truncateAt: INITIAL_LOAD_NUM_MEMBERS,
+ };
- componentDidMount: function() {
+ componentDidMount() {
this._unmounted = false;
this._initGroupStore(this.props.groupId);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
this._unmounted = true;
- },
+ }
- _initGroupStore: function(groupId) {
+ _initGroupStore(groupId) {
GroupStore.registerListener(groupId, () => {
this._fetchMembers();
});
@@ -73,17 +68,17 @@ export default createReactClass({
});
}
});
- },
+ }
- _fetchMembers: function() {
+ _fetchMembers() {
if (this._unmounted) return;
this.setState({
members: GroupStore.getGroupMembers(this.props.groupId),
invitedMembers: GroupStore.getGroupInvitedMembers(this.props.groupId),
});
- },
+ }
- _createOverflowTile: function(overflowCount, totalCount) {
+ _createOverflowTile = (overflowCount, totalCount) => {
// For now we'll pretend this is any entity. It should probably be a separate tile.
const EntityTile = sdk.getComponent("rooms.EntityTile");
const BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
@@ -94,19 +89,19 @@ export default createReactClass({
} name={text} presenceState="online" suppressOnHover={true}
onClick={this._showFullMemberList} />
);
- },
+ };
- _showFullMemberList: function() {
+ _showFullMemberList = () => {
this.setState({
truncateAt: -1,
});
- },
+ };
- onSearchQueryChanged: function(ev) {
+ onSearchQueryChanged = ev => {
this.setState({ searchQuery: ev.target.value });
- },
+ };
- makeGroupMemberTiles: function(query, memberList, memberListError) {
+ makeGroupMemberTiles(query, memberList, memberListError) {
if (memberListError) {
return { _t("Failed to load group members") }
;
}
@@ -160,9 +155,9 @@ export default createReactClass({
>
{ memberTiles }
;
- },
+ }
- onInviteToGroupButtonClick() {
+ onInviteToGroupButtonClick = () => {
showGroupInviteDialog(this.props.groupId).then(() => {
dis.dispatch({
action: Action.SetRightPanelPhase,
@@ -170,9 +165,9 @@ export default createReactClass({
refireParams: { groupId: this.props.groupId },
});
});
- },
+ };
- render: function() {
+ render() {
if (this.state.fetching || this.state.fetchingInvitedMembers) {
const Spinner = sdk.getComponent("elements.Spinner");
return (
@@ -230,5 +225,5 @@ export default createReactClass({
{ inputBox }
);
- },
-});
+ }
+}
diff --git a/src/components/views/groups/GroupMemberTile.js b/src/components/views/groups/GroupMemberTile.js
index 05e3f6ac2a..13617cf681 100644
--- a/src/components/views/groups/GroupMemberTile.js
+++ b/src/components/views/groups/GroupMemberTile.js
@@ -18,37 +18,28 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import dis from '../../../dispatcher/dispatcher';
import { GroupMemberType } from '../../../groups';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
-export default createReactClass({
- displayName: 'GroupMemberTile',
-
- propTypes: {
+export default class GroupMemberTile extends React.Component {
+ static propTypes = {
groupId: PropTypes.string.isRequired,
member: GroupMemberType.isRequired,
- },
+ };
- getInitialState: function() {
- return {};
- },
+ static contextType = MatrixClientContext;
- statics: {
- contextType: MatrixClientContext,
- },
-
- onClick: function(e) {
+ onClick = e => {
dis.dispatch({
action: 'view_group_user',
member: this.props.member,
groupId: this.props.groupId,
});
- },
+ };
- render: function() {
+ render() {
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
const EntityTile = sdk.getComponent('rooms.EntityTile');
@@ -74,5 +65,5 @@ export default createReactClass({
powerStatus={this.props.member.isPrivileged ? EntityTile.POWER_STATUS_ADMIN : null}
/>
);
- },
-});
+ }
+}
diff --git a/src/components/views/groups/GroupPublicityToggle.js b/src/components/views/groups/GroupPublicityToggle.js
index 81f0f469ef..d42059551e 100644
--- a/src/components/views/groups/GroupPublicityToggle.js
+++ b/src/components/views/groups/GroupPublicityToggle.js
@@ -16,44 +16,39 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import GroupStore from '../../../stores/GroupStore';
import ToggleSwitch from "../elements/ToggleSwitch";
-export default createReactClass({
- displayName: 'GroupPublicityToggle',
-
- propTypes: {
+export default class GroupPublicityToggle extends React.Component {
+ static propTypes = {
groupId: PropTypes.string.isRequired,
- },
+ };
- getInitialState() {
- return {
- busy: false,
- ready: false,
- isGroupPublicised: false, // assume false as expects a boolean
- };
- },
+ state = {
+ busy: false,
+ ready: false,
+ isGroupPublicised: false, // assume false as expects a boolean
+ };
- componentDidMount: function() {
+ componentDidMount() {
this._initGroupStore(this.props.groupId);
- },
+ }
- _initGroupStore: function(groupId) {
+ _initGroupStore(groupId) {
this._groupStoreToken = GroupStore.registerListener(groupId, () => {
this.setState({
isGroupPublicised: Boolean(GroupStore.getGroupPublicity(groupId)),
ready: GroupStore.isStateReady(groupId, GroupStore.STATE_KEY.Summary),
});
});
- },
+ }
componentWillUnmount() {
if (this._groupStoreToken) this._groupStoreToken.unregister();
- },
+ }
- _onPublicityToggle: function() {
+ _onPublicityToggle = () => {
this.setState({
busy: true,
// Optimistic early update
@@ -64,7 +59,7 @@ export default createReactClass({
busy: false,
});
});
- },
+ };
render() {
const GroupTile = sdk.getComponent('groups.GroupTile');
@@ -76,5 +71,5 @@ export default createReactClass({
disabled={!this.state.ready || this.state.busy}
onChange={this._onPublicityToggle} />
;
- },
-});
+ }
+}
diff --git a/src/components/views/groups/GroupRoomInfo.js b/src/components/views/groups/GroupRoomInfo.js
index 8c9b39675e..e891d553aa 100644
--- a/src/components/views/groups/GroupRoomInfo.js
+++ b/src/components/views/groups/GroupRoomInfo.js
@@ -17,7 +17,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import dis from '../../../dispatcher/dispatcher';
import Modal from '../../../Modal';
import * as sdk from '../../../index';
@@ -26,30 +25,24 @@ import GroupStore from '../../../stores/GroupStore';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
-export default createReactClass({
- displayName: 'GroupRoomInfo',
+export default class GroupRoomInfo extends React.Component {
+ static contextType = MatrixClientContext;
- statics: {
- contextType: MatrixClientContext,
- },
-
- propTypes: {
+ static propTypes = {
groupId: PropTypes.string,
groupRoomId: PropTypes.string,
- },
+ };
- getInitialState: function() {
- return {
- isUserPrivilegedInGroup: null,
- groupRoom: null,
- groupRoomPublicityLoading: false,
- groupRoomRemoveLoading: false,
- };
- },
+ state = {
+ isUserPrivilegedInGroup: null,
+ groupRoom: null,
+ groupRoomPublicityLoading: false,
+ groupRoomRemoveLoading: false,
+ };
- componentDidMount: function() {
+ componentDidMount() {
this._initGroupStore(this.props.groupId);
- },
+ }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
UNSAFE_componentWillReceiveProps(newProps) {
@@ -57,19 +50,19 @@ export default createReactClass({
this._unregisterGroupStore(this.props.groupId);
this._initGroupStore(newProps.groupId);
}
- },
+ }
componentWillUnmount() {
this._unregisterGroupStore(this.props.groupId);
- },
+ }
_initGroupStore(groupId) {
GroupStore.registerListener(groupId, this.onGroupStoreUpdated);
- },
+ }
_unregisterGroupStore(groupId) {
GroupStore.unregisterListener(this.onGroupStoreUpdated);
- },
+ }
_updateGroupRoom() {
this.setState({
@@ -77,16 +70,16 @@ export default createReactClass({
(r) => r.roomId === this.props.groupRoomId,
),
});
- },
+ }
- onGroupStoreUpdated: function() {
+ onGroupStoreUpdated = () => {
this.setState({
isUserPrivilegedInGroup: GroupStore.isUserPrivileged(this.props.groupId),
});
this._updateGroupRoom();
- },
+ };
- _onRemove: function(e) {
+ _onRemove = e => {
const groupId = this.props.groupId;
const roomName = this.state.groupRoom.displayname;
e.preventDefault();
@@ -119,15 +112,15 @@ export default createReactClass({
});
},
});
- },
+ };
- _onCancel: function(e) {
+ _onCancel = e => {
dis.dispatch({
action: "view_group_room_list",
});
- },
+ };
- _changeGroupRoomPublicity(e) {
+ _changeGroupRoomPublicity = e => {
const isPublic = e.target.value === "public";
this.setState({
groupRoomPublicityLoading: true,
@@ -150,9 +143,9 @@ export default createReactClass({
groupRoomPublicityLoading: false,
});
});
- },
+ };
- render: function() {
+ render() {
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
const InlineSpinner = sdk.getComponent('elements.InlineSpinner');
if (this.state.groupRoomRemoveLoading || !this.state.groupRoom) {
@@ -235,5 +228,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/groups/GroupRoomList.js b/src/components/views/groups/GroupRoomList.js
index 18ab0f288a..9bb46db47c 100644
--- a/src/components/views/groups/GroupRoomList.js
+++ b/src/components/views/groups/GroupRoomList.js
@@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
import GroupStore from '../../../stores/GroupStore';
@@ -25,34 +24,32 @@ import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
const INITIAL_LOAD_NUM_ROOMS = 30;
-export default createReactClass({
- propTypes: {
+export default class GroupRoomList extends React.Component {
+ static propTypes = {
groupId: PropTypes.string.isRequired,
- },
+ };
- getInitialState: function() {
- return {
- rooms: null,
- truncateAt: INITIAL_LOAD_NUM_ROOMS,
- searchQuery: "",
- };
- },
+ state = {
+ rooms: null,
+ truncateAt: INITIAL_LOAD_NUM_ROOMS,
+ searchQuery: "",
+ };
- componentDidMount: function() {
+ componentDidMount() {
this._unmounted = false;
this._initGroupStore(this.props.groupId);
- },
+ }
componentWillUnmount() {
this._unmounted = true;
this._unregisterGroupStore();
- },
+ }
_unregisterGroupStore() {
GroupStore.unregisterListener(this.onGroupStoreUpdated);
- },
+ }
- _initGroupStore: function(groupId) {
+ _initGroupStore(groupId) {
GroupStore.registerListener(groupId, this.onGroupStoreUpdated);
// XXX: This should be more fluxy - let's get the error from GroupStore .getError or something
// XXX: This is also leaked - we should remove it when unmounting
@@ -62,16 +59,16 @@ export default createReactClass({
rooms: null,
});
});
- },
+ }
- onGroupStoreUpdated: function() {
+ onGroupStoreUpdated = () => {
if (this._unmounted) return;
this.setState({
rooms: GroupStore.getGroupRooms(this.props.groupId),
});
- },
+ };
- _createOverflowTile: function(overflowCount, totalCount) {
+ _createOverflowTile = (overflowCount, totalCount) => {
// For now we'll pretend this is any entity. It should probably be a separate tile.
const EntityTile = sdk.getComponent("rooms.EntityTile");
const BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
@@ -82,25 +79,25 @@ export default createReactClass({
} name={text} presenceState="online" suppressOnHover={true}
onClick={this._showFullRoomList} />
);
- },
+ };
- _showFullRoomList: function() {
+ _showFullRoomList = () => {
this.setState({
truncateAt: -1,
});
- },
+ };
- onSearchQueryChanged: function(ev) {
+ onSearchQueryChanged = ev => {
this.setState({ searchQuery: ev.target.value });
- },
+ };
- onAddRoomToGroupButtonClick() {
+ onAddRoomToGroupButtonClick = () => {
showGroupAddRoomDialog(this.props.groupId).then(() => {
this.forceUpdate();
});
- },
+ };
- makeGroupRoomTiles: function(query) {
+ makeGroupRoomTiles(query) {
const GroupRoomTile = sdk.getComponent("groups.GroupRoomTile");
query = (query || "").toLowerCase();
@@ -123,9 +120,9 @@ export default createReactClass({
});
return roomList;
- },
+ }
- render: function() {
+ render() {
if (this.state.rooms === null) {
return null;
}
@@ -160,5 +157,5 @@ export default createReactClass({
{ inputBox }
);
- },
-});
+ }
+}
diff --git a/src/components/views/groups/GroupRoomTile.js b/src/components/views/groups/GroupRoomTile.js
index fd6969a49a..85aa56d055 100644
--- a/src/components/views/groups/GroupRoomTile.js
+++ b/src/components/views/groups/GroupRoomTile.js
@@ -16,29 +16,28 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import dis from '../../../dispatcher/dispatcher';
import { GroupRoomType } from '../../../groups';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
-const GroupRoomTile = createReactClass({
- displayName: 'GroupRoomTile',
-
- propTypes: {
+class GroupRoomTile extends React.Component {
+ static propTypes = {
groupId: PropTypes.string.isRequired,
groupRoom: GroupRoomType.isRequired,
- },
+ };
- onClick: function(e) {
+ static contextType = MatrixClientContext
+
+ onClick = e => {
dis.dispatch({
action: 'view_group_room',
groupId: this.props.groupId,
groupRoomId: this.props.groupRoom.roomId,
});
- },
+ };
- render: function() {
+ render() {
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
const avatarUrl = this.context.mxcUrlToHttp(
@@ -63,10 +62,7 @@ const GroupRoomTile = createReactClass({
);
- },
-});
-
-GroupRoomTile.contextType = MatrixClientContext;
-
+ }
+}
export default GroupRoomTile;
diff --git a/src/components/views/groups/GroupTile.js b/src/components/views/groups/GroupTile.js
index 906bcbaf99..dcc749b01f 100644
--- a/src/components/views/groups/GroupTile.js
+++ b/src/components/views/groups/GroupTile.js
@@ -16,7 +16,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import { Draggable, Droppable } from 'react-beautiful-dnd';
import * as sdk from '../../../index';
import dis from '../../../dispatcher/dispatcher';
@@ -25,53 +24,45 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
function nop() {}
-const GroupTile = createReactClass({
- displayName: 'GroupTile',
-
- propTypes: {
+class GroupTile extends React.Component {
+ static propTypes = {
groupId: PropTypes.string.isRequired,
// Whether to show the short description of the group on the tile
showDescription: PropTypes.bool,
// Height of the group avatar in pixels
avatarHeight: PropTypes.number,
draggable: PropTypes.bool,
- },
+ };
- statics: {
- contextType: MatrixClientContext,
- },
+ static contextType = MatrixClientContext;
- getInitialState() {
- return {
- profile: null,
- };
- },
+ static defaultProps = {
+ showDescription: true,
+ avatarHeight: 50,
+ draggable: true,
+ };
- getDefaultProps() {
- return {
- showDescription: true,
- avatarHeight: 50,
- draggable: true,
- };
- },
+ state = {
+ profile: null,
+ };
- componentDidMount: function() {
+ componentDidMount() {
FlairStore.getGroupProfileCached(this.context, this.props.groupId).then((profile) => {
this.setState({profile});
}).catch((err) => {
console.error('Error whilst getting cached profile for GroupTile', err);
});
- },
+ }
- onMouseDown: function(e) {
+ onMouseDown = e => {
e.preventDefault();
dis.dispatch({
action: 'view_group',
group_id: this.props.groupId,
});
- },
+ };
- render: function() {
+ render() {
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
const profile = this.state.profile || {};
@@ -135,7 +126,7 @@ const GroupTile = createReactClass({
{ this.props.groupId }
;
- },
-});
+ }
+}
export default GroupTile;
diff --git a/src/components/views/groups/GroupUserSettings.js b/src/components/views/groups/GroupUserSettings.js
index 8f57eccd05..9209106c8f 100644
--- a/src/components/views/groups/GroupUserSettings.js
+++ b/src/components/views/groups/GroupUserSettings.js
@@ -15,33 +15,26 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
-export default createReactClass({
- displayName: 'GroupUserSettings',
+export default class GroupUserSettings extends React.Component {
+ static contextType = MatrixClientContext;
- statics: {
- contextType: MatrixClientContext,
- },
+ state = {
+ error: null,
+ groups: null,
+ };
- getInitialState() {
- return {
- error: null,
- groups: null,
- };
- },
-
- componentDidMount: function() {
+ componentDidMount() {
this.context.getJoinedGroups().then((result) => {
this.setState({groups: result.groups || [], error: null});
}, (err) => {
console.error(err);
this.setState({groups: null, error: err});
});
- },
+ }
render() {
let text = "";
@@ -70,5 +63,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js
index 2f2521f02d..cc140a4352 100644
--- a/src/components/views/messages/MFileBody.js
+++ b/src/components/views/messages/MFileBody.js
@@ -17,7 +17,6 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import filesize from 'filesize';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
@@ -117,16 +116,8 @@ function computedStyle(element) {
return cssText;
}
-export default createReactClass({
- displayName: 'MFileBody',
-
- getInitialState: function() {
- return {
- decryptedBlob: (this.props.decryptedBlob ? this.props.decryptedBlob : null),
- };
- },
-
- propTypes: {
+export default class MFileBody extends React.Component {
+ static propTypes = {
/* the MatrixEvent to show */
mxEvent: PropTypes.object.isRequired,
/* already decrypted blob */
@@ -135,7 +126,19 @@ export default createReactClass({
onHeightChanged: PropTypes.func,
/* the shape of the tile, used */
tileShape: PropTypes.string,
- },
+ };
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ decryptedBlob: (this.props.decryptedBlob ? this.props.decryptedBlob : null),
+ };
+
+ this._iframe = createRef();
+ this._dummyLink = createRef();
+ this._downloadImage = createRef();
+ }
/**
* Extracts a human readable label for the file attachment to use as
@@ -144,7 +147,7 @@ export default createReactClass({
* @params {Object} content The "content" key of the matrix event.
* @return {string} the human readable link text for the attachment.
*/
- presentableTextForFile: function(content) {
+ presentableTextForFile(content) {
let linkText = _t("Attachment");
if (content.body && content.body.length > 0) {
// The content body should be the name of the file including a
@@ -163,40 +166,33 @@ export default createReactClass({
linkText += ' (' + filesize(content.info.size) + ')';
}
return linkText;
- },
+ }
- _getContentUrl: function() {
+ _getContentUrl() {
const content = this.props.mxEvent.getContent();
return MatrixClientPeg.get().mxcUrlToHttp(content.url);
- },
+ }
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
- this._iframe = createRef();
- this._dummyLink = createRef();
- this._downloadImage = createRef();
- },
-
- componentDidMount: function() {
+ componentDidMount() {
// Add this to the list of mounted components to receive notifications
// when the tint changes.
this.id = nextMountId++;
mounts[this.id] = this;
this.tint();
- },
+ }
- componentDidUpdate: function(prevProps, prevState) {
+ componentDidUpdate(prevProps, prevState) {
if (this.props.onHeightChanged && !prevState.decryptedBlob && this.state.decryptedBlob) {
this.props.onHeightChanged();
}
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
// Remove this from the list of mounted components
delete mounts[this.id];
- },
+ }
- tint: function() {
+ tint = () => {
// Update our tinted copy of require("../../../../res/img/download.svg")
if (this._downloadImage.current) {
this._downloadImage.current.src = tintedDownloadImageURL;
@@ -210,9 +206,9 @@ export default createReactClass({
style: computedStyle(this._dummyLink.current),
}, "*");
}
- },
+ };
- render: function() {
+ render() {
const content = this.props.mxEvent.getContent();
const text = this.presentableTextForFile(content);
const isEncrypted = content.file !== undefined;
@@ -378,5 +374,5 @@ export default createReactClass({
{ _t("Invalid file%(extra)s", { extra: extra }) }
;
}
- },
-});
+ }
+}
diff --git a/src/components/views/messages/MVideoBody.js b/src/components/views/messages/MVideoBody.js
index fdc04deffc..86bf41699b 100644
--- a/src/components/views/messages/MVideoBody.js
+++ b/src/components/views/messages/MVideoBody.js
@@ -17,7 +17,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import MFileBody from './MFileBody';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { decryptFile } from '../../../utils/DecryptFile';
@@ -25,27 +24,23 @@ import { _t } from '../../../languageHandler';
import SettingsStore from "../../../settings/SettingsStore";
import InlineSpinner from '../elements/InlineSpinner';
-export default createReactClass({
- displayName: 'MVideoBody',
-
- propTypes: {
+export default class MVideoBody extends React.Component {
+ static propTypes = {
/* the MatrixEvent to show */
mxEvent: PropTypes.object.isRequired,
/* called when the video has loaded */
onHeightChanged: PropTypes.func.isRequired,
- },
+ };
- getInitialState: function() {
- return {
- decryptedUrl: null,
- decryptedThumbnailUrl: null,
- decryptedBlob: null,
- error: null,
- };
- },
+ state = {
+ decryptedUrl: null,
+ decryptedThumbnailUrl: null,
+ decryptedBlob: null,
+ error: null,
+ };
- thumbScale: function(fullWidth, fullHeight, thumbWidth, thumbHeight) {
+ thumbScale(fullWidth, fullHeight, thumbWidth, thumbHeight) {
if (!fullWidth || !fullHeight) {
// Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even
// log this because it's spammy
@@ -64,18 +59,18 @@ export default createReactClass({
// height is the dominant dimension so scaling will be fixed on that
return heightMulti;
}
- },
+ }
- _getContentUrl: function() {
+ _getContentUrl() {
const content = this.props.mxEvent.getContent();
if (content.file !== undefined) {
return this.state.decryptedUrl;
} else {
return MatrixClientPeg.get().mxcUrlToHttp(content.url);
}
- },
+ }
- _getThumbUrl: function() {
+ _getThumbUrl() {
const content = this.props.mxEvent.getContent();
if (content.file !== undefined) {
return this.state.decryptedThumbnailUrl;
@@ -84,9 +79,9 @@ export default createReactClass({
} else {
return null;
}
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
const content = this.props.mxEvent.getContent();
if (content.file !== undefined && this.state.decryptedUrl === null) {
let thumbnailPromise = Promise.resolve(null);
@@ -118,18 +113,18 @@ export default createReactClass({
});
});
}
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
if (this.state.decryptedUrl) {
URL.revokeObjectURL(this.state.decryptedUrl);
}
if (this.state.decryptedThumbnailUrl) {
URL.revokeObjectURL(this.state.decryptedThumbnailUrl);
}
- },
+ }
- render: function() {
+ render() {
const content = this.props.mxEvent.getContent();
if (this.state.error !== null) {
@@ -182,5 +177,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/messages/MessageEvent.js b/src/components/views/messages/MessageEvent.js
index c3e5af2eb6..f93813fe79 100644
--- a/src/components/views/messages/MessageEvent.js
+++ b/src/components/views/messages/MessageEvent.js
@@ -16,17 +16,14 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import SettingsStore from "../../../settings/SettingsStore";
import {Mjolnir} from "../../../mjolnir/Mjolnir";
import RedactedBody from "./RedactedBody";
import UnknownBody from "./UnknownBody";
-export default createReactClass({
- displayName: 'MessageEvent',
-
- propTypes: {
+export default class MessageEvent extends React.Component {
+ static propTypes = {
/* the MatrixEvent to show */
mxEvent: PropTypes.object.isRequired,
@@ -47,22 +44,23 @@ export default createReactClass({
/* the maximum image height to use, if the event is an image */
maxImageHeight: PropTypes.number,
- },
+ };
+
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this._body = createRef();
- },
+ }
- getEventTileOps: function() {
+ getEventTileOps = () => {
return this._body.current && this._body.current.getEventTileOps ? this._body.current.getEventTileOps() : null;
- },
+ };
- onTileUpdate: function() {
+ onTileUpdate = () => {
this.forceUpdate();
- },
+ };
- render: function() {
+ render() {
const bodyTypes = {
'm.text': sdk.getComponent('messages.TextualBody'),
'm.notice': sdk.getComponent('messages.TextualBody'),
@@ -123,5 +121,5 @@ export default createReactClass({
onHeightChanged={this.props.onHeightChanged}
onMessageAllowed={this.onTileUpdate}
/>;
- },
-});
+ }
+}
diff --git a/src/components/views/messages/RoomAvatarEvent.js b/src/components/views/messages/RoomAvatarEvent.js
index 78df6aa4a8..f526d080cc 100644
--- a/src/components/views/messages/RoomAvatarEvent.js
+++ b/src/components/views/messages/RoomAvatarEvent.js
@@ -18,22 +18,19 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
import Modal from '../../../Modal';
import AccessibleButton from '../elements/AccessibleButton';
-export default createReactClass({
- displayName: 'RoomAvatarEvent',
-
- propTypes: {
+export default class RoomAvatarEvent extends React.Component {
+ static propTypes = {
/* the MatrixEvent to show */
mxEvent: PropTypes.object.isRequired,
- },
+ };
- onAvatarClick: function() {
+ onAvatarClick = () => {
const cli = MatrixClientPeg.get();
const ev = this.props.mxEvent;
const httpUrl = cli.mxcUrlToHttp(ev.getContent().url);
@@ -50,9 +47,9 @@ export default createReactClass({
name: text,
};
Modal.createDialog(ImageView, params, "mx_Dialog_lightbox");
- },
+ };
- render: function() {
+ render() {
const ev = this.props.mxEvent;
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
const RoomAvatar = sdk.getComponent("avatars.RoomAvatar");
@@ -86,5 +83,5 @@ export default createReactClass({
}
);
- },
-});
+ }
+}
diff --git a/src/components/views/messages/RoomCreate.js b/src/components/views/messages/RoomCreate.js
index 95bc460636..22d5ebba1e 100644
--- a/src/components/views/messages/RoomCreate.js
+++ b/src/components/views/messages/RoomCreate.js
@@ -17,22 +17,19 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import dis from '../../../dispatcher/dispatcher';
import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks';
import { _t } from '../../../languageHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
-export default createReactClass({
- displayName: 'RoomCreate',
-
- propTypes: {
+export default class RoomCreate extends React.Component {
+ static propTypes = {
/* the MatrixEvent to show */
mxEvent: PropTypes.object.isRequired,
- },
+ };
- _onLinkClicked: function(e) {
+ _onLinkClicked = e => {
e.preventDefault();
const predecessor = this.props.mxEvent.getContent()['predecessor'];
@@ -43,9 +40,9 @@ export default createReactClass({
highlighted: true,
room_id: predecessor['room_id'],
});
- },
+ };
- render: function() {
+ render() {
const predecessor = this.props.mxEvent.getContent()['predecessor'];
if (predecessor === undefined) {
return
; // We should never have been instaniated in this case
@@ -66,5 +63,5 @@ export default createReactClass({
{_t("Click here to see older messages.")}
;
- },
-});
+ }
+}
diff --git a/src/components/views/messages/SenderProfile.js b/src/components/views/messages/SenderProfile.js
index 5064c4d2b2..afe2d6d118 100644
--- a/src/components/views/messages/SenderProfile.js
+++ b/src/components/views/messages/SenderProfile.js
@@ -16,31 +16,25 @@
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import Flair from '../elements/Flair.js';
import FlairStore from '../../../stores/FlairStore';
import { _t } from '../../../languageHandler';
import {getUserNameColorClass} from '../../../utils/FormattingUtils';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
-export default createReactClass({
- displayName: 'SenderProfile',
- propTypes: {
+export default class SenderProfile extends React.Component {
+ static propTypes = {
mxEvent: PropTypes.object.isRequired, // event whose sender we're showing
text: PropTypes.string, // Text to show. Defaults to sender name
onClick: PropTypes.func,
- },
+ };
- statics: {
- contextType: MatrixClientContext,
- },
+ static contextType = MatrixClientContext;
- getInitialState() {
- return {
- userGroups: null,
- relatedGroups: [],
- };
- },
+ state = {
+ userGroups: null,
+ relatedGroups: [],
+ };
componentDidMount() {
this.unmounted = false;
@@ -54,20 +48,20 @@ export default createReactClass({
});
this.context.on('RoomState.events', this.onRoomStateEvents);
- },
+ }
componentWillUnmount() {
this.unmounted = true;
this.context.removeListener('RoomState.events', this.onRoomStateEvents);
- },
+ }
- onRoomStateEvents(event) {
+ onRoomStateEvents = event => {
if (event.getType() === 'm.room.related_groups' &&
event.getRoomId() === this.props.mxEvent.getRoomId()
) {
this._updateRelatedGroups();
}
- },
+ };
_updateRelatedGroups() {
if (this.unmounted) return;
@@ -78,7 +72,7 @@ export default createReactClass({
this.setState({
relatedGroups: relatedGroupsEvent ? relatedGroupsEvent.getContent().groups || [] : [],
});
- },
+ }
_getDisplayedGroups(userGroups, relatedGroups) {
let displayedGroups = userGroups || [];
@@ -90,7 +84,7 @@ export default createReactClass({
displayedGroups = [];
}
return displayedGroups;
- },
+ }
render() {
const {mxEvent} = this.props;
@@ -138,5 +132,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js
index df72398b1c..e83262ce69 100644
--- a/src/components/views/messages/TextualBody.js
+++ b/src/components/views/messages/TextualBody.js
@@ -19,7 +19,6 @@ limitations under the License.
import React, {createRef} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import highlight from 'highlight.js';
import * as HtmlUtils from '../../../HtmlUtils';
import {formatDate} from '../../../DateUtils';
@@ -37,10 +36,8 @@ import {toRightOf} from "../../structures/ContextMenu";
import {copyPlaintext} from "../../../utils/strings";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
-export default createReactClass({
- displayName: 'TextualBody',
-
- propTypes: {
+export default class TextualBody extends React.Component {
+ static propTypes = {
/* the MatrixEvent to show */
mxEvent: PropTypes.object.isRequired,
@@ -58,10 +55,14 @@ export default createReactClass({
/* the shape of the tile, used */
tileShape: PropTypes.string,
- },
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this._content = createRef();
+
+ this.state = {
// the URLs (if any) to be previewed with a LinkPreviewWidget
// inside this TextualBody.
links: [],
@@ -69,20 +70,15 @@ export default createReactClass({
// track whether the preview widget is hidden
widgetHidden: false,
};
- },
+ }
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
- this._content = createRef();
- },
-
- componentDidMount: function() {
+ componentDidMount() {
this._unmounted = false;
this._pills = [];
if (!this.props.editState) {
this._applyFormatting();
}
- },
+ }
_applyFormatting() {
this.activateSpoilers([this._content.current]);
@@ -119,9 +115,9 @@ export default createReactClass({
}
this._addCodeCopyButton();
}
- },
+ }
- componentDidUpdate: function(prevProps) {
+ componentDidUpdate(prevProps) {
if (!this.props.editState) {
const stoppedEditing = prevProps.editState && !this.props.editState;
const messageWasEdited = prevProps.replacingEventId !== this.props.replacingEventId;
@@ -129,14 +125,14 @@ export default createReactClass({
this._applyFormatting();
}
}
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
this._unmounted = true;
unmountPills(this._pills);
- },
+ }
- shouldComponentUpdate: function(nextProps, nextState) {
+ shouldComponentUpdate(nextProps, nextState) {
//console.info("shouldComponentUpdate: ShowUrlPreview for %s is %s", this.props.mxEvent.getId(), this.props.showUrlPreview);
// exploit that events are immutable :)
@@ -148,9 +144,9 @@ export default createReactClass({
nextProps.editState !== this.props.editState ||
nextState.links !== this.state.links ||
nextState.widgetHidden !== this.state.widgetHidden);
- },
+ }
- calculateUrlPreview: function() {
+ calculateUrlPreview() {
//console.info("calculateUrlPreview: ShowUrlPreview for %s is %s", this.props.mxEvent.getId(), this.props.showUrlPreview);
if (this.props.showUrlPreview) {
@@ -176,9 +172,9 @@ export default createReactClass({
this.setState({ links: [] });
}
}
- },
+ }
- activateSpoilers: function(nodes) {
+ activateSpoilers(nodes) {
let node = nodes[0];
while (node) {
if (node.tagName === "SPAN" && typeof node.getAttribute("data-mx-spoiler") === "string") {
@@ -204,9 +200,9 @@ export default createReactClass({
node = node.nextSibling;
}
- },
+ }
- findLinks: function(nodes) {
+ findLinks(nodes) {
let links = [];
for (let i = 0; i < nodes.length; i++) {
@@ -223,9 +219,9 @@ export default createReactClass({
}
}
return links;
- },
+ }
- isLinkPreviewable: function(node) {
+ isLinkPreviewable(node) {
// don't try to preview relative links
if (!node.getAttribute("href").startsWith("http://") &&
!node.getAttribute("href").startsWith("https://")) {
@@ -256,7 +252,7 @@ export default createReactClass({
return true;
}
}
- },
+ }
_addCodeCopyButton() {
// Add 'copy' buttons to pre blocks
@@ -288,41 +284,39 @@ export default createReactClass({
div.appendChild(p);
div.appendChild(button);
});
- },
+ }
- onCancelClick: function(event) {
+ onCancelClick = event => {
this.setState({ widgetHidden: true });
// FIXME: persist this somewhere smarter than local storage
if (global.localStorage) {
global.localStorage.setItem("hide_preview_" + this.props.mxEvent.getId(), "1");
}
this.forceUpdate();
- },
+ };
- onEmoteSenderClick: function(event) {
+ onEmoteSenderClick = event => {
const mxEvent = this.props.mxEvent;
dis.dispatch({
action: 'insert_mention',
user_id: mxEvent.getSender(),
});
- },
+ };
- getEventTileOps: function() {
- return {
- isWidgetHidden: () => {
- return this.state.widgetHidden;
- },
+ getEventTileOps = () => ({
+ isWidgetHidden: () => {
+ return this.state.widgetHidden;
+ },
- unhideWidget: () => {
- this.setState({ widgetHidden: false });
- if (global.localStorage) {
- global.localStorage.removeItem("hide_preview_" + this.props.mxEvent.getId());
- }
- },
- };
- },
+ unhideWidget: () => {
+ this.setState({widgetHidden: false});
+ if (global.localStorage) {
+ global.localStorage.removeItem("hide_preview_" + this.props.mxEvent.getId());
+ }
+ },
+ });
- onStarterLinkClick: function(starterLink, ev) {
+ onStarterLinkClick = (starterLink, ev) => {
ev.preventDefault();
// We need to add on our scalar token to the starter link, but we may not have one!
// In addition, we can't fetch one on click and then go to it immediately as that
@@ -353,7 +347,7 @@ export default createReactClass({
"Do you wish to continue?", { integrationsUrl: integrationsUrl }) }
,
button: _t("Continue"),
- onFinished: function(confirmed) {
+ onFinished(confirmed) {
if (!confirmed) {
return;
}
@@ -367,14 +361,14 @@ export default createReactClass({
},
});
});
- },
+ };
- _openHistoryDialog: async function() {
+ _openHistoryDialog = async () => {
const MessageEditHistoryDialog = sdk.getComponent("views.dialogs.MessageEditHistoryDialog");
Modal.createDialog(MessageEditHistoryDialog, {mxEvent: this.props.mxEvent});
- },
+ };
- _renderEditedMarker: function() {
+ _renderEditedMarker() {
const date = this.props.mxEvent.replacingEventDate();
const dateString = date && formatDate(date);
@@ -397,9 +391,9 @@ export default createReactClass({
{`(${_t("edited")})`}
);
- },
+ }
- render: function() {
+ render() {
if (this.props.editState) {
const EditMessageComposer = sdk.getComponent('rooms.EditMessageComposer');
return ;
@@ -468,5 +462,5 @@ export default createReactClass({
);
}
- },
-});
+ }
+}
diff --git a/src/components/views/messages/TextualEvent.js b/src/components/views/messages/TextualEvent.js
index 1f48516f75..99e94147f7 100644
--- a/src/components/views/messages/TextualEvent.js
+++ b/src/components/views/messages/TextualEvent.js
@@ -17,22 +17,19 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as TextForEvent from "../../../TextForEvent";
-export default createReactClass({
- displayName: 'TextualEvent',
-
- propTypes: {
+export default class TextualEvent extends React.Component {
+ static propTypes = {
/* the MatrixEvent to show */
mxEvent: PropTypes.object.isRequired,
- },
+ };
- render: function() {
+ render() {
const text = TextForEvent.textForEvent(this.props.mxEvent);
if (text == null || text.length === 0) return null;
return (
{ text }
);
- },
-});
+ }
+}
diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js
index fa5c1baf8f..114e9b2894 100644
--- a/src/components/views/room_settings/UrlPreviewSettings.js
+++ b/src/components/views/room_settings/UrlPreviewSettings.js
@@ -19,7 +19,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from "../../../index";
import { _t, _td } from '../../../languageHandler';
import SettingsStore from "../../../settings/SettingsStore";
@@ -29,20 +28,18 @@ import {Action} from "../../../dispatcher/actions";
import {SettingLevel} from "../../../settings/SettingLevel";
-export default createReactClass({
- displayName: 'UrlPreviewSettings',
-
- propTypes: {
+export default class UrlPreviewSettings extends React.Component {
+ static propTypes = {
room: PropTypes.object,
- },
+ };
- _onClickUserSettings: (e) => {
+ _onClickUserSettings = (e) => {
e.preventDefault();
e.stopPropagation();
dis.fire(Action.ViewUserSettings);
- },
+ };
- render: function() {
+ render() {
const SettingsFlag = sdk.getComponent("elements.SettingsFlag");
const roomId = this.props.room.roomId;
const isEncrypted = MatrixClientPeg.get().isRoomEncrypted(roomId);
@@ -110,5 +107,5 @@ export default createReactClass({
{ previewsForRoomAccount }
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/AppsDrawer.js b/src/components/views/rooms/AppsDrawer.js
index 8cf7a54da2..ed76e9137a 100644
--- a/src/components/views/rooms/AppsDrawer.js
+++ b/src/components/views/rooms/AppsDrawer.js
@@ -17,7 +17,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import AppTile from '../elements/AppTile';
import Modal from '../../../Modal';
@@ -34,50 +33,50 @@ import SettingsStore from "../../../settings/SettingsStore";
// The maximum number of widgets that can be added in a room
const MAX_WIDGETS = 2;
-export default createReactClass({
- displayName: 'AppsDrawer',
-
- propTypes: {
+export default class AppsDrawer extends React.Component {
+ static propTypes = {
userId: PropTypes.string.isRequired,
room: PropTypes.object.isRequired,
showApps: PropTypes.bool, // Should apps be rendered
hide: PropTypes.bool, // If rendered, should apps drawer be visible
- },
+ };
- getDefaultProps: () => ({
+ static defaultProps = {
showApps: true,
hide: false,
- }),
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this.state = {
apps: this._getApps(),
};
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
ScalarMessaging.startListening();
MatrixClientPeg.get().on('RoomState.events', this.onRoomStateEvents);
WidgetEchoStore.on('update', this._updateApps);
this.dispatcherRef = dis.register(this.onAction);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
ScalarMessaging.stopListening();
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener('RoomState.events', this.onRoomStateEvents);
}
WidgetEchoStore.removeListener('update', this._updateApps);
if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
- },
+ }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
UNSAFE_componentWillReceiveProps(newProps) {
// Room has changed probably, update apps
this._updateApps();
- },
+ }
- onAction: function(action) {
+ onAction = (action) => {
const hideWidgetKey = this.props.room.roomId + '_hide_widget_drawer';
switch (action.action) {
case 'appsDrawer':
@@ -93,16 +92,16 @@ export default createReactClass({
break;
}
- },
+ };
- onRoomStateEvents: function(ev, state) {
+ onRoomStateEvents = (ev, state) => {
if (ev.getRoomId() !== this.props.room.roomId || ev.getType() !== 'im.vector.modular.widgets') {
return;
}
this._updateApps();
- },
+ };
- _getApps: function() {
+ _getApps() {
const widgets = WidgetEchoStore.getEchoedRoomWidgets(
this.props.room.roomId, WidgetUtils.getRoomWidgets(this.props.room),
);
@@ -111,33 +110,33 @@ export default createReactClass({
ev.getStateKey(), ev.getContent(), ev.getSender(), ev.getRoomId(), ev.getId(),
);
});
- },
+ }
- _updateApps: function() {
+ _updateApps = () => {
const apps = this._getApps();
this.setState({
apps: apps,
});
- },
+ };
- _canUserModify: function() {
+ _canUserModify() {
try {
return WidgetUtils.canUserModifyWidgets(this.props.room.roomId);
} catch (err) {
console.error(err);
return false;
}
- },
+ }
- _launchManageIntegrations: function() {
+ _launchManageIntegrations() {
if (SettingsStore.getValue("feature_many_integration_managers")) {
IntegrationManagers.sharedInstance().openAll();
} else {
IntegrationManagers.sharedInstance().getPrimaryManager().open(this.props.room, 'add_integ');
}
- },
+ }
- onClickAddWidget: function(e) {
+ onClickAddWidget = (e) => {
e.preventDefault();
// Display a warning dialog if the max number of widgets have already been added to the room
const apps = this._getApps();
@@ -152,9 +151,9 @@ export default createReactClass({
return;
}
this._launchManageIntegrations();
- },
+ };
- render: function() {
+ render() {
const apps = this.state.apps.map((app, index, arr) => {
const capWhitelist = WidgetUtils.getCapWhitelistForAppTypeInRoomId(app.type, this.props.room.roomId);
@@ -211,5 +210,5 @@ export default createReactClass({
{ this._canUserModify() && addWidget }
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/AuxPanel.js b/src/components/views/rooms/AuxPanel.js
index 521aeec406..fc31d66160 100644
--- a/src/components/views/rooms/AuxPanel.js
+++ b/src/components/views/rooms/AuxPanel.js
@@ -17,7 +17,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import * as sdk from '../../../index';
import dis from "../../../dispatcher/dispatcher";
@@ -31,10 +30,8 @@ import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
import CallView from "../voip/CallView";
-export default createReactClass({
- displayName: 'AuxPanel',
-
- propTypes: {
+export default class AuxPanel extends React.Component {
+ static propTypes = {
// js-sdk room object
room: PropTypes.object.isRequired,
userId: PropTypes.string.isRequired,
@@ -58,42 +55,46 @@ export default createReactClass({
// content in a way that is likely to make it change size.
onResize: PropTypes.func,
fullHeight: PropTypes.bool,
- },
+ };
- getDefaultProps: () => ({
+ static defaultProps = {
showApps: true,
hideAppsDrawer: false,
- }),
+ };
- getInitialState: function() {
- return { counters: this._computeCounters() };
- },
+ constructor(props) {
+ super(props);
- componentDidMount: function() {
+ this.state = {
+ counters: this._computeCounters(),
+ };
+ }
+
+ componentDidMount() {
const cli = MatrixClientPeg.get();
cli.on("RoomState.events", this._rateLimitedUpdate);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
const cli = MatrixClientPeg.get();
if (cli) {
cli.removeListener("RoomState.events", this._rateLimitedUpdate);
}
- },
+ }
- shouldComponentUpdate: function(nextProps, nextState) {
+ shouldComponentUpdate(nextProps, nextState) {
return (!ObjectUtils.shallowEqual(this.props, nextProps) ||
!ObjectUtils.shallowEqual(this.state, nextState));
- },
+ }
- componentDidUpdate: function(prevProps, prevState) {
+ componentDidUpdate(prevProps, prevState) {
// most changes are likely to cause a resize
if (this.props.onResize) {
this.props.onResize();
}
- },
+ }
- onConferenceNotificationClick: function(ev, type) {
+ onConferenceNotificationClick = (ev, type) => {
dis.dispatch({
action: 'place_call',
type: type,
@@ -101,15 +102,15 @@ export default createReactClass({
});
ev.stopPropagation();
ev.preventDefault();
- },
+ };
- _rateLimitedUpdate: new RateLimitedFunc(function() {
+ _rateLimitedUpdate = new RateLimitedFunc(() => {
if (SettingsStore.getValue("feature_state_counters")) {
this.setState({counters: this._computeCounters()});
}
- }, 500),
+ }, 500);
- _computeCounters: function() {
+ _computeCounters() {
let counters = [];
if (this.props.room && SettingsStore.getValue("feature_state_counters")) {
@@ -140,9 +141,9 @@ export default createReactClass({
}
return counters;
- },
+ }
- render: function() {
+ render() {
const TintableSvg = sdk.getComponent("elements.TintableSvg");
let fileDropTarget = null;
@@ -274,5 +275,5 @@ export default createReactClass({
{ this.props.children }
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/EntityTile.js b/src/components/views/rooms/EntityTile.js
index d880e824da..9017e4aa3e 100644
--- a/src/components/views/rooms/EntityTile.js
+++ b/src/components/views/rooms/EntityTile.js
@@ -18,7 +18,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import AccessibleButton from '../elements/AccessibleButton';
import { _t } from '../../../languageHandler';
@@ -51,10 +50,8 @@ function presenceClassForMember(presenceState, lastActiveAgo, showPresence) {
}
}
-const EntityTile = createReactClass({
- displayName: 'EntityTile',
-
- propTypes: {
+class EntityTile extends React.Component {
+ static propTypes = {
name: PropTypes.string,
title: PropTypes.string,
avatarJsx: PropTypes.any, //
@@ -70,33 +67,29 @@ const EntityTile = createReactClass({
showPresence: PropTypes.bool,
subtextLabel: PropTypes.string,
e2eStatus: PropTypes.string,
- },
+ };
- getDefaultProps: function() {
- return {
- shouldComponentUpdate: function(nextProps, nextState) { return true; },
- onClick: function() {},
- presenceState: "offline",
- presenceLastActiveAgo: 0,
- presenceLastTs: 0,
- showInviteButton: false,
- suppressOnHover: false,
- showPresence: true,
- };
- },
+ static defaultProps = {
+ shouldComponentUpdate: function(nextProps, nextState) { return true; },
+ onClick: function() {},
+ presenceState: "offline",
+ presenceLastActiveAgo: 0,
+ presenceLastTs: 0,
+ showInviteButton: false,
+ suppressOnHover: false,
+ showPresence: true,
+ };
- getInitialState: function() {
- return {
- hover: false,
- };
- },
+ state = {
+ hover: false,
+ };
- shouldComponentUpdate: function(nextProps, nextState) {
+ shouldComponentUpdate(nextProps, nextState) {
if (this.state.hover !== nextState.hover) return true;
return this.props.shouldComponentUpdate(nextProps, nextState);
- },
+ }
- render: function() {
+ render() {
const mainClassNames = {
"mx_EntityTile": true,
"mx_EntityTile_noHover": this.props.suppressOnHover,
@@ -193,8 +186,8 @@ const EntityTile = createReactClass({
);
- },
-});
+ }
+}
EntityTile.POWER_STATUS_MODERATOR = "moderator";
EntityTile.POWER_STATUS_ADMIN = "admin";
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index 2f00447287..d1738301d9 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -20,7 +20,6 @@ limitations under the License.
import ReplyThread from "../elements/ReplyThread";
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import classNames from "classnames";
import { _t, _td } from '../../../languageHandler';
import * as TextForEvent from "../../../TextForEvent";
@@ -127,10 +126,8 @@ const MAX_READ_AVATARS = 5;
// | '--------------------------------------' |
// '----------------------------------------------------------'
-export default createReactClass({
- displayName: 'EventTile',
-
- propTypes: {
+export default class EventTile extends React.Component {
+ static propTypes = {
/* the MatrixEvent to show */
mxEvent: PropTypes.object.isRequired,
@@ -209,17 +206,19 @@ export default createReactClass({
// whether to use the irc layout
useIRCLayout: PropTypes.bool,
- },
+ };
- getDefaultProps: function() {
- return {
- // no-op function because onHeightChanged is optional yet some sub-components assume its existence
- onHeightChanged: function() {},
- };
- },
+ static defaultProps = {
+ // no-op function because onHeightChanged is optional yet some sub-components assume its existence
+ onHeightChanged: function() {},
+ };
- getInitialState: function() {
- return {
+ static contextType = MatrixClientContext;
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
// Whether the action bar is focused.
actionBarFocused: false,
// Whether all read receipts are being displayed. If not, only display
@@ -232,23 +231,16 @@ export default createReactClass({
// The Relations model from the JS SDK for reactions to `mxEvent`
reactions: this.getReactions(),
};
- },
- statics: {
- contextType: MatrixClientContext,
- },
-
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
// don't do RR animations until we are mounted
this._suppressReadReceiptAnimation = true;
this._verifyEvent(this.props.mxEvent);
this._tile = createRef();
this._replyThread = createRef();
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
this._suppressReadReceiptAnimation = false;
const client = this.context;
client.on("deviceVerificationChanged", this.onDeviceVerificationChanged);
@@ -257,26 +249,26 @@ export default createReactClass({
if (this.props.showReactions) {
this.props.mxEvent.on("Event.relationsCreated", this._onReactionsCreated);
}
- },
+ }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
- UNSAFE_componentWillReceiveProps: function(nextProps) {
+ UNSAFE_componentWillReceiveProps(nextProps) {
// re-check the sender verification as outgoing events progress through
// the send process.
if (nextProps.eventSendStatus !== this.props.eventSendStatus) {
this._verifyEvent(nextProps.mxEvent);
}
- },
+ }
- shouldComponentUpdate: function(nextProps, nextState) {
+ shouldComponentUpdate(nextProps, nextState) {
if (!ObjectUtils.shallowEqual(this.state, nextState)) {
return true;
}
return !this._propsEqual(this.props, nextProps);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
const client = this.context;
client.removeListener("deviceVerificationChanged", this.onDeviceVerificationChanged);
client.removeListener("userTrustStatusChanged", this.onUserVerificationChanged);
@@ -284,31 +276,31 @@ export default createReactClass({
if (this.props.showReactions) {
this.props.mxEvent.removeListener("Event.relationsCreated", this._onReactionsCreated);
}
- },
+ }
/** called when the event is decrypted after we show it.
*/
- _onDecrypted: function() {
+ _onDecrypted = () => {
// we need to re-verify the sending device.
// (we call onHeightChanged in _verifyEvent to handle the case where decryption
// has caused a change in size of the event tile)
this._verifyEvent(this.props.mxEvent);
this.forceUpdate();
- },
+ };
- onDeviceVerificationChanged: function(userId, device) {
+ onDeviceVerificationChanged = (userId, device) => {
if (userId === this.props.mxEvent.getSender()) {
this._verifyEvent(this.props.mxEvent);
}
- },
+ };
- onUserVerificationChanged: function(userId, _trustStatus) {
+ onUserVerificationChanged = (userId, _trustStatus) => {
if (userId === this.props.mxEvent.getSender()) {
this._verifyEvent(this.props.mxEvent);
}
- },
+ };
- _verifyEvent: async function(mxEvent) {
+ async _verifyEvent(mxEvent) {
if (!mxEvent.isEncrypted()) {
return;
}
@@ -360,9 +352,9 @@ export default createReactClass({
this.setState({
verified: E2E_STATE.VERIFIED,
}, this.props.onHeightChanged); // Decryption may have caused a change in size
- },
+ }
- _propsEqual: function(objA, objB) {
+ _propsEqual(objA, objB) {
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
@@ -408,9 +400,9 @@ export default createReactClass({
}
}
return true;
- },
+ }
- shouldHighlight: function() {
+ shouldHighlight() {
const actions = this.context.getPushActionsForEvent(this.props.mxEvent.replacingEvent() || this.props.mxEvent);
if (!actions || !actions.tweaks) { return false; }
@@ -420,15 +412,15 @@ export default createReactClass({
}
return actions.tweaks.highlight;
- },
+ }
- toggleAllReadAvatars: function() {
+ toggleAllReadAvatars = () => {
this.setState({
allReadAvatars: !this.state.allReadAvatars,
});
- },
+ };
- getReadAvatars: function() {
+ getReadAvatars() {
// return early if there are no read receipts
if (!this.props.readReceipts || this.props.readReceipts.length === 0) {
return ( );
@@ -494,17 +486,17 @@ export default createReactClass({
{ remText }
{ avatars }
;
- },
+ }
- onSenderProfileClick: function(event) {
+ onSenderProfileClick = event => {
const mxEvent = this.props.mxEvent;
dis.dispatch({
action: 'insert_mention',
user_id: mxEvent.getSender(),
});
- },
+ };
- onRequestKeysClick: function() {
+ onRequestKeysClick = () => {
this.setState({
// Indicate in the UI that the keys have been requested (this is expected to
// be reset if the component is mounted in the future).
@@ -515,9 +507,9 @@ export default createReactClass({
// is received for the request with the required keys, the event could be
// decrypted successfully.
this.context.cancelAndResendEventRoomKeyRequest(this.props.mxEvent);
- },
+ };
- onPermalinkClicked: function(e) {
+ onPermalinkClicked = e => {
// This allows the permalink to be opened in a new tab/window or copied as
// matrix.to, but also for it to enable routing within Element when clicked.
e.preventDefault();
@@ -527,9 +519,9 @@ export default createReactClass({
highlighted: true,
room_id: this.props.mxEvent.getRoomId(),
});
- },
+ };
- _renderE2EPadlock: function() {
+ _renderE2EPadlock() {
const ev = this.props.mxEvent;
// event could not be decrypted
@@ -570,23 +562,19 @@ export default createReactClass({
// no padlock needed
return null;
- },
+ }
- onActionBarFocusChange(focused) {
+ onActionBarFocusChange = focused => {
this.setState({
actionBarFocused: focused,
});
- },
+ };
- getTile() {
- return this._tile.current;
- },
+ getTile = () => this._tile.current;
- getReplyThread() {
- return this._replyThread.current;
- },
+ getReplyThread = () => this._replyThread.current;
- getReactions() {
+ getReactions = () => {
if (
!this.props.showReactions ||
!this.props.getRelationsForEvent
@@ -602,9 +590,9 @@ export default createReactClass({
console.trace("Stacktrace for https://github.com/vector-im/element-web/issues/11120");
}
return this.props.getRelationsForEvent(eventId, "m.annotation", "m.reaction");
- },
+ };
- _onReactionsCreated(relationType, eventType) {
+ _onReactionsCreated = (relationType, eventType) => {
if (relationType !== "m.annotation" || eventType !== "m.reaction") {
return;
}
@@ -612,9 +600,9 @@ export default createReactClass({
this.setState({
reactions: this.getReactions(),
});
- },
+ };
- render: function() {
+ render() {
const MessageTimestamp = sdk.getComponent('messages.MessageTimestamp');
const SenderProfile = sdk.getComponent('messages.SenderProfile');
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
@@ -947,8 +935,8 @@ export default createReactClass({
);
}
}
- },
-});
+ }
+}
// XXX this'll eventually be dynamic based on the fields once we have extensible event types
const messageTypes = ['m.room.message', 'm.sticker'];
diff --git a/src/components/views/rooms/ForwardMessage.js b/src/components/views/rooms/ForwardMessage.js
index 03ca32c5e6..8daea8dc17 100644
--- a/src/components/views/rooms/ForwardMessage.js
+++ b/src/components/views/rooms/ForwardMessage.js
@@ -17,49 +17,46 @@
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
import dis from '../../../dispatcher/dispatcher';
import {Key} from '../../../Keyboard';
-export default createReactClass({
- displayName: 'ForwardMessage',
-
- propTypes: {
+export default class ForwardMessage extends React.Component {
+ static propTypes = {
onCancelClick: PropTypes.func.isRequired,
- },
+ };
- componentDidMount: function() {
+ componentDidMount() {
dis.dispatch({
action: 'panel_disable',
middleDisabled: true,
});
document.addEventListener('keydown', this._onKeyDown);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
dis.dispatch({
action: 'panel_disable',
middleDisabled: false,
});
document.removeEventListener('keydown', this._onKeyDown);
- },
+ }
- _onKeyDown: function(ev) {
+ _onKeyDown = ev => {
switch (ev.key) {
case Key.ESCAPE:
this.props.onCancelClick();
break;
}
- },
+ };
- render: function() {
+ render() {
return (
{ _t('Please select the destination room for this message') }
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/LinkPreviewWidget.js b/src/components/views/rooms/LinkPreviewWidget.js
index d1c1ce04f9..a3d59e5137 100644
--- a/src/components/views/rooms/LinkPreviewWidget.js
+++ b/src/components/views/rooms/LinkPreviewWidget.js
@@ -17,7 +17,6 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import { AllHtmlEntities } from 'html-entities';
import {linkifyElement} from '../../../HtmlUtils';
import SettingsStore from "../../../settings/SettingsStore";
@@ -27,24 +26,21 @@ import Modal from "../../../Modal";
import * as ImageUtils from "../../../ImageUtils";
import { _t } from "../../../languageHandler";
-export default createReactClass({
- displayName: 'LinkPreviewWidget',
-
- propTypes: {
+export default class LinkPreviewWidget extends React.Component {
+ static propTypes = {
link: PropTypes.string.isRequired, // the URL being previewed
mxEvent: PropTypes.object.isRequired, // the Event associated with the preview
onCancelClick: PropTypes.func, // called when the preview's cancel ('hide') button is clicked
onHeightChanged: PropTypes.func, // called when the preview's contents has loaded
- },
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this.state = {
preview: null,
};
- },
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this.unmounted = false;
MatrixClientPeg.get().getUrlPreview(this.props.link, this.props.mxEvent.getTs()).then((res)=>{
if (this.unmounted) {
@@ -59,25 +55,25 @@ export default createReactClass({
});
this._description = createRef();
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
if (this._description.current) {
linkifyElement(this._description.current);
}
- },
+ }
- componentDidUpdate: function() {
+ componentDidUpdate() {
if (this._description.current) {
linkifyElement(this._description.current);
}
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
this.unmounted = true;
- },
+ }
- onImageClick: function(ev) {
+ onImageClick = ev => {
const p = this.state.preview;
if (ev.button != 0 || ev.metaKey) return;
ev.preventDefault();
@@ -98,9 +94,9 @@ export default createReactClass({
};
Modal.createDialog(ImageView, params, "mx_Dialog_lightbox");
- },
+ };
- render: function() {
+ render() {
const p = this.state.preview;
if (!p || Object.keys(p).length === 0) {
return
;
@@ -149,5 +145,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js
index e2d7e3f8e0..920e3cf691 100644
--- a/src/components/views/rooms/MemberList.js
+++ b/src/components/views/rooms/MemberList.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
import SdkConfig from '../../../SdkConfig';
import dis from '../../../dispatcher/dispatcher';
@@ -36,23 +35,19 @@ const SHOW_MORE_INCREMENT = 100;
// matches all ASCII punctuation: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
const SORT_REGEX = /[\x21-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]+/g;
-export default createReactClass({
- displayName: 'MemberList',
+export default class MemberList extends React.Component {
+ constructor(props) {
+ super(props);
- getInitialState: function() {
const cli = MatrixClientPeg.get();
if (cli.hasLazyLoadMembersEnabled()) {
// show an empty list
- return this._getMembersState([]);
+ this.state = this._getMembersState([]);
} else {
- return this._getMembersState(this.roomMembers());
+ this.state = this._getMembersState(this.roomMembers());
}
- },
- // TODO: [REACT-WARNING] Move this to constructor
- UNSAFE_componentWillMount: function() {
this._mounted = true;
- const cli = MatrixClientPeg.get();
if (cli.hasLazyLoadMembersEnabled()) {
this._showMembersAccordingToMembershipWithLL();
cli.on("Room.myMembership", this.onMyMembership);
@@ -66,9 +61,9 @@ export default createReactClass({
if (enablePresenceByHsUrl && enablePresenceByHsUrl[hsUrl] !== undefined) {
this._showPresence = enablePresenceByHsUrl[hsUrl];
}
- },
+ }
- _listenForMembersChanges: function() {
+ _listenForMembersChanges() {
const cli = MatrixClientPeg.get();
cli.on("RoomState.members", this.onRoomStateMember);
cli.on("RoomMember.name", this.onRoomMemberName);
@@ -80,9 +75,9 @@ export default createReactClass({
cli.on("User.presence", this.onUserPresenceChange);
cli.on("User.currentlyActive", this.onUserPresenceChange);
// cli.on("Room.timeline", this.onRoomTimeline);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
this._mounted = false;
const cli = MatrixClientPeg.get();
if (cli) {
@@ -98,14 +93,14 @@ export default createReactClass({
// cancel any pending calls to the rate_limited_funcs
this._updateList.cancelPendingCall();
- },
+ }
/**
* If lazy loading is enabled, either:
* show a spinner and load the members if the user is joined,
* or show the members available so far if the user is invited
*/
- _showMembersAccordingToMembershipWithLL: async function() {
+ async _showMembersAccordingToMembershipWithLL() {
const cli = MatrixClientPeg.get();
if (cli.hasLazyLoadMembersEnabled()) {
const cli = MatrixClientPeg.get();
@@ -125,9 +120,9 @@ export default createReactClass({
this.setState(this._getMembersState(this.roomMembers()));
}
}
- },
+ }
- _getMembersState: function(members) {
+ _getMembersState(members) {
// set the state after determining _showPresence to make sure it's
// taken into account while rerendering
return {
@@ -142,9 +137,9 @@ export default createReactClass({
truncateAtInvited: INITIAL_LOAD_NUM_INVITED,
searchQuery: "",
};
- },
+ }
- onUserPresenceChange(event, user) {
+ onUserPresenceChange = (event, user) => {
// Attach a SINGLE listener for global presence changes then locate the
// member tile and re-render it. This is more efficient than every tile
// ever attaching their own listener.
@@ -153,9 +148,9 @@ export default createReactClass({
if (tile) {
this._updateList(); // reorder the membership list
}
- },
+ };
- onRoom: function(room) {
+ onRoom = room => {
if (room.roomId !== this.props.roomId) {
return;
}
@@ -163,40 +158,40 @@ export default createReactClass({
// we need to wait till the room is fully populated with state
// before refreshing the member list else we get a stale list.
this._showMembersAccordingToMembershipWithLL();
- },
+ };
- onMyMembership: function(room, membership, oldMembership) {
+ onMyMembership = (room, membership, oldMembership) => {
if (room.roomId === this.props.roomId && membership === "join") {
this._showMembersAccordingToMembershipWithLL();
}
- },
+ };
- onRoomStateMember: function(ev, state, member) {
+ onRoomStateMember = (ev, state, member) => {
if (member.roomId !== this.props.roomId) {
return;
}
this._updateList();
- },
+ };
- onRoomMemberName: function(ev, member) {
+ onRoomMemberName = (ev, member) => {
if (member.roomId !== this.props.roomId) {
return;
}
this._updateList();
- },
+ };
- onRoomStateEvent: function(event, state) {
+ onRoomStateEvent = (event, state) => {
if (event.getRoomId() === this.props.roomId &&
event.getType() === "m.room.third_party_invite") {
this._updateList();
}
- },
+ };
- _updateList: rate_limited_func(function() {
+ _updateList = rate_limited_func(() => {
this._updateListNow();
- }, 500),
+ }, 500);
- _updateListNow: function() {
+ _updateListNow() {
// console.log("Updating memberlist");
const newState = {
loading: false,
@@ -205,9 +200,9 @@ export default createReactClass({
newState.filteredJoinedMembers = this._filterMembers(newState.members, 'join', this.state.searchQuery);
newState.filteredInvitedMembers = this._filterMembers(newState.members, 'invite', this.state.searchQuery);
this.setState(newState);
- },
+ }
- getMembersWithUser: function() {
+ getMembersWithUser() {
if (!this.props.roomId) return [];
const cli = MatrixClientPeg.get();
const room = cli.getRoom(this.props.roomId);
@@ -228,9 +223,9 @@ export default createReactClass({
});
return allMembers;
- },
+ }
- roomMembers: function() {
+ roomMembers() {
const ConferenceHandler = CallHandler.getConferenceHandler();
const allMembers = this.getMembersWithUser();
@@ -244,17 +239,17 @@ export default createReactClass({
});
filteredAndSortedMembers.sort(this.memberSort);
return filteredAndSortedMembers;
- },
+ }
- _createOverflowTileJoined: function(overflowCount, totalCount) {
+ _createOverflowTileJoined(overflowCount, totalCount) {
return this._createOverflowTile(overflowCount, totalCount, this._showMoreJoinedMemberList);
- },
+ }
- _createOverflowTileInvited: function(overflowCount, totalCount) {
+ _createOverflowTileInvited(overflowCount, totalCount) {
return this._createOverflowTile(overflowCount, totalCount, this._showMoreInvitedMemberList);
- },
+ }
- _createOverflowTile: function(overflowCount, totalCount, onClick) {
+ _createOverflowTile(overflowCount, totalCount, onClick) {
// For now we'll pretend this is any entity. It should probably be a separate tile.
const EntityTile = sdk.getComponent("rooms.EntityTile");
const BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
@@ -265,33 +260,33 @@ export default createReactClass({
} name={text} presenceState="online" suppressOnHover={true}
onClick={onClick} />
);
- },
+ }
- _showMoreJoinedMemberList: function() {
+ _showMoreJoinedMemberList = () => {
this.setState({
truncateAtJoined: this.state.truncateAtJoined + SHOW_MORE_INCREMENT,
});
- },
+ };
- _showMoreInvitedMemberList: function() {
+ _showMoreInvitedMemberList = () => {
this.setState({
truncateAtInvited: this.state.truncateAtInvited + SHOW_MORE_INCREMENT,
});
- },
+ };
- memberString: function(member) {
+ memberString(member) {
if (!member) {
return "(null)";
} else {
const u = member.user;
return "(" + member.name + ", " + member.powerLevel + ", " + (u ? u.lastActiveAgo : "") + ", " + (u ? u.getLastActiveTs() : "") + ", " + (u ? u.currentlyActive : "") + ", " + (u ? u.presence : "") + ")";
}
- },
+ }
// returns negative if a comes before b,
// returns 0 if a and b are equivalent in ordering
// returns positive if a comes after b.
- memberSort: function(memberA, memberB) {
+ memberSort = (memberA, memberB) => {
// order by presence, with "active now" first.
// ...and then by power level
// ...and then by last active
@@ -348,24 +343,24 @@ export default createReactClass({
ignorePunctuation: true,
sensitivity: "base",
});
- },
+ };
- onSearchQueryChanged: function(searchQuery) {
+ onSearchQueryChanged = searchQuery => {
this.setState({
searchQuery,
filteredJoinedMembers: this._filterMembers(this.state.members, 'join', searchQuery),
filteredInvitedMembers: this._filterMembers(this.state.members, 'invite', searchQuery),
});
- },
+ };
- _onPending3pidInviteClick: function(inviteEvent) {
+ _onPending3pidInviteClick = inviteEvent => {
dis.dispatch({
action: 'view_3pid_invite',
event: inviteEvent,
});
- },
+ };
- _filterMembers: function(members, membership, query) {
+ _filterMembers(members, membership, query) {
return members.filter((m) => {
if (query) {
query = query.toLowerCase();
@@ -379,9 +374,9 @@ export default createReactClass({
return m.membership === membership;
});
- },
+ }
- _getPending3PidInvites: function() {
+ _getPending3PidInvites() {
// include 3pid invites (m.room.third_party_invite) state events.
// The HS may have already converted these into m.room.member invites so
// we shouldn't add them if the 3pid invite state key (token) is in the
@@ -399,9 +394,9 @@ export default createReactClass({
return true;
});
}
- },
+ }
- _makeMemberTiles: function(members) {
+ _makeMemberTiles(members) {
const MemberTile = sdk.getComponent("rooms.MemberTile");
const EntityTile = sdk.getComponent("rooms.EntityTile");
@@ -415,30 +410,30 @@ export default createReactClass({
onClick={() => this._onPending3pidInviteClick(m)} />;
}
});
- },
+ }
- _getChildrenJoined: function(start, end) {
+ _getChildrenJoined(start, end) {
return this._makeMemberTiles(this.state.filteredJoinedMembers.slice(start, end));
- },
+ }
- _getChildCountJoined: function() {
+ _getChildCountJoined() {
return this.state.filteredJoinedMembers.length;
- },
+ }
- _getChildrenInvited: function(start, end) {
+ _getChildrenInvited(start, end) {
let targets = this.state.filteredInvitedMembers;
if (end > this.state.filteredInvitedMembers.length) {
targets = targets.concat(this._getPending3PidInvites());
}
return this._makeMemberTiles(targets.slice(start, end));
- },
+ }
- _getChildCountInvited: function() {
+ _getChildCountInvited() {
return this.state.filteredInvitedMembers.length + (this._getPending3PidInvites() || []).length;
- },
+ }
- render: function() {
+ render() {
if (this.state.loading) {
const Spinner = sdk.getComponent("elements.Spinner");
return
;
@@ -501,9 +496,9 @@ export default createReactClass({
onSearch={ this.onSearchQueryChanged } />
);
- },
+ }
- onInviteButtonClick: function() {
+ onInviteButtonClick = () => {
if (MatrixClientPeg.get().isGuest()) {
dis.dispatch({action: 'require_registration'});
return;
@@ -514,5 +509,5 @@ export default createReactClass({
action: 'view_invite',
roomId: this.props.roomId,
});
- },
-});
+ };
+}
diff --git a/src/components/views/rooms/MemberTile.js b/src/components/views/rooms/MemberTile.js
index ebb8b7999d..a43b42b6d3 100644
--- a/src/components/views/rooms/MemberTile.js
+++ b/src/components/views/rooms/MemberTile.js
@@ -18,34 +18,31 @@ limitations under the License.
import SettingsStore from "../../../settings/SettingsStore";
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from "../../../index";
import dis from "../../../dispatcher/dispatcher";
import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import {Action} from "../../../dispatcher/actions";
-export default createReactClass({
- displayName: 'MemberTile',
-
- propTypes: {
+export default class MemberTile extends React.Component {
+ static propTypes = {
member: PropTypes.any.isRequired, // RoomMember
showPresence: PropTypes.bool,
- },
+ };
- getDefaultProps: function() {
- return {
- showPresence: true,
- };
- },
+ static defaultProps = {
+ showPresence: true,
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this.state = {
statusMessage: this.getStatusMessage(),
isRoomEncrypted: false,
e2eStatus: null,
};
- },
+ }
componentDidMount() {
const cli = MatrixClientPeg.get();
@@ -72,7 +69,7 @@ export default createReactClass({
cli.on("RoomState.events", this.onRoomStateEvents);
}
}
- },
+ }
componentWillUnmount() {
const cli = MatrixClientPeg.get();
@@ -90,9 +87,9 @@ export default createReactClass({
cli.removeListener("userTrustStatusChanged", this.onUserTrustStatusChanged);
cli.removeListener("deviceVerificationChanged", this.onDeviceVerificationChanged);
}
- },
+ }
- onRoomStateEvents: function(ev) {
+ onRoomStateEvents = ev => {
if (ev.getType() !== "m.room.encryption") return;
const { roomId } = this.props.member;
if (ev.getRoomId() !== roomId) return;
@@ -104,19 +101,19 @@ export default createReactClass({
isRoomEncrypted: true,
});
this.updateE2EStatus();
- },
+ };
- onUserTrustStatusChanged: function(userId, trustStatus) {
+ onUserTrustStatusChanged = (userId, trustStatus) => {
if (userId !== this.props.member.userId) return;
this.updateE2EStatus();
- },
+ };
- onDeviceVerificationChanged: function(userId, deviceId, deviceInfo) {
+ onDeviceVerificationChanged = (userId, deviceId, deviceInfo) => {
if (userId !== this.props.member.userId) return;
this.updateE2EStatus();
- },
+ };
- updateE2EStatus: async function() {
+ async updateE2EStatus() {
const cli = MatrixClientPeg.get();
const { userId } = this.props.member;
const isMe = userId === cli.getUserId();
@@ -142,7 +139,7 @@ export default createReactClass({
this.setState({
e2eStatus: anyDeviceUnverified ? "warning" : "verified",
});
- },
+ }
getStatusMessage() {
const { user } = this.props.member;
@@ -150,16 +147,16 @@ export default createReactClass({
return "";
}
return user._unstable_statusMessage;
- },
+ }
- _onStatusMessageCommitted() {
+ _onStatusMessageCommitted = () => {
// The `User` object has observed a status message change.
this.setState({
statusMessage: this.getStatusMessage(),
});
- },
+ };
- shouldComponentUpdate: function(nextProps, nextState) {
+ shouldComponentUpdate(nextProps, nextState) {
if (
this.member_last_modified_time === undefined ||
this.member_last_modified_time < nextProps.member.getLastModifiedTime()
@@ -180,27 +177,27 @@ export default createReactClass({
return true;
}
return false;
- },
+ }
- onClick: function(e) {
+ onClick = e => {
dis.dispatch({
action: Action.ViewUser,
member: this.props.member,
});
- },
+ };
- _getDisplayName: function() {
+ _getDisplayName() {
return this.props.member.name;
- },
+ }
- getPowerLabel: function() {
+ getPowerLabel() {
return _t("%(userName)s (power %(powerLevelNumber)s)", {
userName: this.props.member.userId,
powerLevelNumber: this.props.member.powerLevel,
});
- },
+ }
- render: function() {
+ render() {
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
const EntityTile = sdk.getComponent('rooms.EntityTile');
@@ -260,5 +257,5 @@ export default createReactClass({
onClick={this.onClick}
/>
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/PinnedEventTile.js b/src/components/views/rooms/PinnedEventTile.js
index 924385d226..9fad0c2391 100644
--- a/src/components/views/rooms/PinnedEventTile.js
+++ b/src/components/views/rooms/PinnedEventTile.js
@@ -16,7 +16,6 @@ limitations under the License.
import React from "react";
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import dis from "../../../dispatcher/dispatcher";
import AccessibleButton from "../elements/AccessibleButton";
@@ -25,22 +24,23 @@ import MemberAvatar from "../avatars/MemberAvatar";
import { _t } from '../../../languageHandler';
import {formatFullDate} from '../../../DateUtils';
-export default createReactClass({
- displayName: 'PinnedEventTile',
- propTypes: {
+export default class PinnedEventTile extends React.Component {
+ static propTypes = {
mxRoom: PropTypes.object.isRequired,
mxEvent: PropTypes.object.isRequired,
onUnpinned: PropTypes.func,
- },
- onTileClicked: function() {
+ };
+
+ onTileClicked = () => {
dis.dispatch({
action: 'view_room',
event_id: this.props.mxEvent.getId(),
highlighted: true,
room_id: this.props.mxEvent.getRoomId(),
});
- },
- onUnpinClicked: function() {
+ };
+
+ onUnpinClicked = () => {
const pinnedEvents = this.props.mxRoom.currentState.getStateEvents("m.room.pinned_events", "");
if (!pinnedEvents || !pinnedEvents.getContent().pinned) {
// Nothing to do: already unpinned
@@ -56,11 +56,13 @@ export default createReactClass({
});
} else if (this.props.onUnpinned) this.props.onUnpinned();
}
- },
- _canUnpin: function() {
+ };
+
+ _canUnpin() {
return this.props.mxRoom.currentState.mayClientSendStateEvent('m.room.pinned_events', MatrixClientPeg.get());
- },
- render: function() {
+ }
+
+ render() {
const sender = this.props.mxEvent.getSender();
// Get the latest sender profile rather than historical
const senderProfile = this.props.mxRoom.getMember(sender);
@@ -100,5 +102,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/PinnedEventsPanel.js b/src/components/views/rooms/PinnedEventsPanel.js
index 8630c0340e..3ea0299976 100644
--- a/src/components/views/rooms/PinnedEventsPanel.js
+++ b/src/components/views/rooms/PinnedEventsPanel.js
@@ -17,46 +17,42 @@ limitations under the License.
import React from "react";
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import AccessibleButton from "../elements/AccessibleButton";
import PinnedEventTile from "./PinnedEventTile";
import { _t } from '../../../languageHandler';
import PinningUtils from "../../../utils/PinningUtils";
-export default createReactClass({
- displayName: 'PinnedEventsPanel',
- propTypes: {
+export default class PinnedEventsPanel extends React.Component {
+ static propTypes = {
// The Room from the js-sdk we're going to show pinned events for
room: PropTypes.object.isRequired,
onCancelClick: PropTypes.func,
- },
+ };
- getInitialState: function() {
- return {
- loading: true,
- };
- },
+ state = {
+ loading: true,
+ };
- componentDidMount: function() {
+ componentDidMount() {
this._updatePinnedMessages();
MatrixClientPeg.get().on("RoomState.events", this._onStateEvent);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("RoomState.events", this._onStateEvent);
}
- },
+ }
- _onStateEvent: function(ev) {
+ _onStateEvent = ev => {
if (ev.getRoomId() === this.props.room.roomId && ev.getType() === "m.room.pinned_events") {
this._updatePinnedMessages();
}
- },
+ };
- _updatePinnedMessages: function() {
+ _updatePinnedMessages = () => {
const pinnedEvents = this.props.room.currentState.getStateEvents("m.room.pinned_events", "");
if (!pinnedEvents || !pinnedEvents.getContent().pinned) {
this.setState({ loading: false, pinned: [] });
@@ -85,9 +81,9 @@ export default createReactClass({
}
this._updateReadState();
- },
+ };
- _updateReadState: function() {
+ _updateReadState() {
const pinnedEvents = this.props.room.currentState.getStateEvents("m.room.pinned_events", "");
if (!pinnedEvents) return; // nothing to read
@@ -107,9 +103,9 @@ export default createReactClass({
event_ids: readStateEvents,
});
}
- },
+ }
- _getPinnedTiles: function() {
+ _getPinnedTiles() {
if (this.state.pinned.length === 0) {
return ({ _t("No pinned messages.") }
);
}
@@ -120,9 +116,9 @@ export default createReactClass({
mxEvent={context.event}
onUnpinned={this._updatePinnedMessages} />);
});
- },
+ }
- render: function() {
+ render() {
let tiles = { _t("Loading...") }
;
if (this.state && !this.state.loading) {
tiles = this._getPinnedTiles();
@@ -139,5 +135,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/PresenceLabel.js b/src/components/views/rooms/PresenceLabel.js
index f9dcd7e89d..ff1460ca21 100644
--- a/src/components/views/rooms/PresenceLabel.js
+++ b/src/components/views/rooms/PresenceLabel.js
@@ -16,15 +16,12 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
-export default createReactClass({
- displayName: 'PresenceLabel',
-
- propTypes: {
+export default class PresenceLabel extends React.Component {
+ static propTypes = {
// number of milliseconds ago this user was last active.
// zero = unknown
activeAgo: PropTypes.number,
@@ -35,18 +32,16 @@ export default createReactClass({
// offline, online, etc
presenceState: PropTypes.string,
- },
+ };
- getDefaultProps: function() {
- return {
- ago: -1,
- presenceState: null,
- };
- },
+ static defaultProps = {
+ activeAgo: -1,
+ presenceState: null,
+ };
// Return duration as a string using appropriate time units
// XXX: This would be better handled using a culture-aware library, but we don't use one yet.
- getDuration: function(time) {
+ getDuration(time) {
if (!time) return;
const t = parseInt(time / 1000);
const s = t % 60;
@@ -66,9 +61,9 @@ export default createReactClass({
return _t("%(duration)sh", {duration: h});
}
return _t("%(duration)sd", {duration: d});
- },
+ }
- getPrettyPresence: function(presence, activeAgo, currentlyActive) {
+ getPrettyPresence(presence, activeAgo, currentlyActive) {
if (!currentlyActive && activeAgo !== undefined && activeAgo > 0) {
const duration = this.getDuration(activeAgo);
if (presence === "online") return _t("Online for %(duration)s", { duration: duration });
@@ -81,13 +76,13 @@ export default createReactClass({
if (presence === "offline") return _t("Offline");
return _t("Unknown");
}
- },
+ }
- render: function() {
+ render() {
return (
{ this.getPrettyPresence(this.props.presenceState, this.props.activeAgo, this.props.currentlyActive) }
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/ReadReceiptMarker.js b/src/components/views/rooms/ReadReceiptMarker.js
index 1c490f019e..c19247ef5a 100644
--- a/src/components/views/rooms/ReadReceiptMarker.js
+++ b/src/components/views/rooms/ReadReceiptMarker.js
@@ -17,7 +17,6 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import '../../../VelocityBounce';
import { _t } from '../../../languageHandler';
import {formatDate} from '../../../DateUtils';
@@ -33,10 +32,8 @@ try {
} catch (e) {
}
-export default createReactClass({
- displayName: 'ReadReceiptMarker',
-
- propTypes: {
+export default class ReadReceiptMarker extends React.Component {
+ static propTypes = {
// the RoomMember to show the RR for
member: PropTypes.object,
// userId to fallback the avatar to
@@ -70,30 +67,27 @@ export default createReactClass({
// True to show twelve hour format, false otherwise
showTwelveHour: PropTypes.bool,
- },
+ };
- getDefaultProps: function() {
- return {
- leftOffset: 0,
- };
- },
+ static defaultProps = {
+ leftOffset: 0,
+ };
- getInitialState: function() {
- // if we are going to animate the RR, we don't show it on first render,
- // and instead just add a placeholder to the DOM; once we've been
- // mounted, we start an animation which moves the RR from its old
- // position.
- return {
+ constructor(props) {
+ super(props);
+
+ this._avatar = createRef();
+
+ this.state = {
+ // if we are going to animate the RR, we don't show it on first render,
+ // and instead just add a placeholder to the DOM; once we've been
+ // mounted, we start an animation which moves the RR from its old
+ // position.
suppressDisplay: !this.props.suppressAnimation,
};
- },
+ }
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
- this._avatar = createRef();
- },
-
- componentWillUnmount: function() {
+ componentWillUnmount() {
// before we remove the rr, store its location in the map, so that if
// it reappears, it can be animated from the right place.
const rrInfo = this.props.readReceiptInfo;
@@ -112,9 +106,9 @@ export default createReactClass({
rrInfo.top = avatarNode.offsetTop;
rrInfo.left = avatarNode.offsetLeft;
rrInfo.parent = avatarNode.offsetParent;
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
if (!this.state.suppressDisplay) {
// we've already done our display - nothing more to do.
return;
@@ -172,10 +166,9 @@ export default createReactClass({
startStyles: startStyles,
enterTransitionOpts: enterTransitionOpts,
});
- },
+ }
-
- render: function() {
+ render() {
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
if (this.state.suppressDisplay) {
return
;
@@ -222,5 +215,5 @@ export default createReactClass({
/>
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/RoomDetailList.js b/src/components/views/rooms/RoomDetailList.js
index 5b45cfc29a..d8205aeb21 100644
--- a/src/components/views/rooms/RoomDetailList.js
+++ b/src/components/views/rooms/RoomDetailList.js
@@ -19,35 +19,32 @@ import dis from '../../../dispatcher/dispatcher';
import React from 'react';
import { _t } from '../../../languageHandler';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import classNames from 'classnames';
import {roomShape} from './RoomDetailRow';
-export default createReactClass({
- displayName: 'RoomDetailList',
-
- propTypes: {
+export default class RoomDetailList extends React.Component {
+ static propTypes = {
rooms: PropTypes.arrayOf(roomShape),
className: PropTypes.string,
- },
+ };
- getRows: function() {
+ getRows() {
if (!this.props.rooms) return [];
const RoomDetailRow = sdk.getComponent('rooms.RoomDetailRow');
return this.props.rooms.map((room, index) => {
return ;
});
- },
+ }
- onDetailsClick: function(ev, room) {
+ onDetailsClick = (ev, room) => {
dis.dispatch({
action: 'view_room',
room_id: room.roomId,
room_alias: room.canonicalAlias || (room.aliases || [])[0],
});
- },
+ };
render() {
const rows = this.getRows();
@@ -64,5 +61,5 @@ export default createReactClass({
return
{ rooms }
;
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/RoomDetailRow.js b/src/components/views/rooms/RoomDetailRow.js
index a88fae9e42..667f821922 100644
--- a/src/components/views/rooms/RoomDetailRow.js
+++ b/src/components/views/rooms/RoomDetailRow.js
@@ -20,7 +20,6 @@ import { _t } from '../../../languageHandler';
import { linkifyElement } from '../../../HtmlUtils';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo";
export function getDisplayAliasForRoom(room) {
@@ -40,47 +39,48 @@ export const roomShape = PropTypes.shape({
guestCanJoin: PropTypes.bool,
});
-export default createReactClass({
- propTypes: {
+export default class RoomDetailRow extends React.Component {
+ static propTypes = {
room: roomShape,
// passes ev, room as args
onClick: PropTypes.func,
onMouseDown: PropTypes.func,
- },
+ };
- _linkifyTopic: function() {
+ constructor(props) {
+ super(props);
+
+ this._topic = createRef();
+ }
+
+ componentDidMount() {
+ this._linkifyTopic();
+ }
+
+ componentDidUpdate() {
+ this._linkifyTopic();
+ }
+
+ _linkifyTopic() {
if (this._topic.current) {
linkifyElement(this._topic.current);
}
- },
+ }
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
- this._topic = createRef();
- },
-
- componentDidMount: function() {
- this._linkifyTopic();
- },
-
- componentDidUpdate: function() {
- this._linkifyTopic();
- },
-
- onClick: function(ev) {
+ onClick = (ev) => {
ev.preventDefault();
if (this.props.onClick) {
this.props.onClick(ev, this.props.room);
}
- },
+ };
- onTopicClick: function(ev) {
+ onTopicClick = (ev) => {
// When clicking a link in the topic, prevent the event being propagated
// to `onClick`.
ev.stopPropagation();
- },
+ };
- render: function() {
+ render() {
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
const room = this.props.room;
@@ -118,5 +118,5 @@ export default createReactClass({
{ room.numJoinedMembers }
;
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js
index fe5b12c1c0..2a44f53d21 100644
--- a/src/components/views/rooms/RoomHeader.js
+++ b/src/components/views/rooms/RoomHeader.js
@@ -17,7 +17,6 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import classNames from 'classnames';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
@@ -35,10 +34,8 @@ import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
import {DefaultTagID} from "../../../stores/room-list/models";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
-export default createReactClass({
- displayName: 'RoomHeader',
-
- propTypes: {
+export default class RoomHeader extends React.Component {
+ static propTypes = {
room: PropTypes.object,
oobData: PropTypes.object,
inRoom: PropTypes.bool,
@@ -48,22 +45,21 @@ export default createReactClass({
onLeaveClick: PropTypes.func,
onCancelClick: PropTypes.func,
e2eStatus: PropTypes.string,
- },
+ };
- getDefaultProps: function() {
- return {
- editing: false,
- inRoom: false,
- onCancelClick: null,
- };
- },
+ static defaultProps = {
+ editing: false,
+ inRoom: false,
+ onCancelClick: null,
+ };
+
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this._topic = createRef();
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
const cli = MatrixClientPeg.get();
cli.on("RoomState.events", this._onRoomStateEvents);
cli.on("Room.accountData", this._onRoomAccountData);
@@ -74,15 +70,15 @@ export default createReactClass({
if (this.props.room) {
this.props.room.on("Room.name", this._onRoomNameChange);
}
- },
+ }
- componentDidUpdate: function() {
+ componentDidUpdate() {
if (this._topic.current) {
linkifyElement(this._topic.current);
}
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
if (this.props.room) {
this.props.room.removeListener("Room.name", this._onRoomNameChange);
}
@@ -91,41 +87,41 @@ export default createReactClass({
cli.removeListener("RoomState.events", this._onRoomStateEvents);
cli.removeListener("Room.accountData", this._onRoomAccountData);
}
- },
+ }
- _onRoomStateEvents: function(event, state) {
+ _onRoomStateEvents = (event, state) => {
if (!this.props.room || event.getRoomId() !== this.props.room.roomId) {
return;
}
// redisplay the room name, topic, etc.
this._rateLimitedUpdate();
- },
+ };
- _onRoomAccountData: function(event, room) {
+ _onRoomAccountData = (event, room) => {
if (!this.props.room || room.roomId !== this.props.room.roomId) return;
if (event.getType() !== "im.vector.room.read_pins") return;
this._rateLimitedUpdate();
- },
+ };
- _rateLimitedUpdate: new RateLimitedFunc(function() {
+ _rateLimitedUpdate = new RateLimitedFunc(function() {
/* eslint-disable babel/no-invalid-this */
this.forceUpdate();
- }, 500),
+ }, 500);
- _onRoomNameChange: function(room) {
+ _onRoomNameChange = (room) => {
this.forceUpdate();
- },
+ };
- onShareRoomClick: function(ev) {
+ onShareRoomClick = (ev) => {
const ShareDialog = sdk.getComponent("dialogs.ShareDialog");
Modal.createTrackedDialog('share room dialog', '', ShareDialog, {
target: this.props.room,
});
- },
+ };
- _hasUnreadPins: function() {
+ _hasUnreadPins() {
const currentPinEvent = this.props.room.currentState.getStateEvents("m.room.pinned_events", '');
if (!currentPinEvent) return false;
if (currentPinEvent.getContent().pinned && currentPinEvent.getContent().pinned.length <= 0) {
@@ -142,16 +138,16 @@ export default createReactClass({
// There's pins, and we haven't read any of them
return true;
- },
+ }
- _hasPins: function() {
+ _hasPins() {
const currentPinEvent = this.props.room.currentState.getStateEvents("m.room.pinned_events", '');
if (!currentPinEvent) return false;
return !(currentPinEvent.getContent().pinned && currentPinEvent.getContent().pinned.length <= 0);
- },
+ }
- render: function() {
+ render() {
let searchStatus = null;
let cancelButton = null;
let settingsButton = null;
@@ -301,5 +297,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/RoomPreviewBar.js b/src/components/views/rooms/RoomPreviewBar.js
index dc3893785d..f42e18372a 100644
--- a/src/components/views/rooms/RoomPreviewBar.js
+++ b/src/components/views/rooms/RoomPreviewBar.js
@@ -18,7 +18,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import dis from '../../../dispatcher/dispatcher';
@@ -46,10 +45,8 @@ const MessageCase = Object.freeze({
OtherError: "OtherError",
});
-export default createReactClass({
- displayName: 'RoomPreviewBar',
-
- propTypes: {
+export default class RoomPreviewBar extends React.Component {
+ static propTypes = {
onJoinClick: PropTypes.func,
onRejectClick: PropTypes.func,
onRejectAndIgnoreClick: PropTypes.func,
@@ -86,36 +83,32 @@ export default createReactClass({
// If given, this will be how the room is referred to (eg.
// in error messages).
roomAlias: PropTypes.string,
- },
+ };
- getDefaultProps: function() {
- return {
- onJoinClick: function() {},
- };
- },
+ static defaultProps = {
+ onJoinClick() {},
+ };
- getInitialState: function() {
- return {
- busy: false,
- };
- },
+ state = {
+ busy: false,
+ };
- componentDidMount: function() {
+ componentDidMount() {
this._checkInvitedEmail();
CommunityPrototypeStore.instance.on(UPDATE_EVENT, this._onCommunityUpdate);
- },
+ }
- componentDidUpdate: function(prevProps, prevState) {
+ componentDidUpdate(prevProps, prevState) {
if (this.props.invitedEmail !== prevProps.invitedEmail || this.props.inviterName !== prevProps.inviterName) {
this._checkInvitedEmail();
}
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
CommunityPrototypeStore.instance.off(UPDATE_EVENT, this._onCommunityUpdate);
- },
+ }
- _checkInvitedEmail: async function() {
+ async _checkInvitedEmail() {
// If this is an invite and we've been told what email address was
// invited, fetch the user's account emails and discovery bindings so we
// can check them against the email that was invited.
@@ -148,14 +141,14 @@ export default createReactClass({
}
this.setState({busy: false});
}
- },
+ }
- _onCommunityUpdate: function (roomId) {
+ _onCommunityUpdate = (roomId) => {
if (this.props.room && this.props.room.roomId !== roomId) {
return;
}
this.forceUpdate(); // we have nothing to update
- },
+ };
_getMessageCase() {
const isGuest = MatrixClientPeg.get().isGuest();
@@ -207,7 +200,7 @@ export default createReactClass({
} else {
return MessageCase.ViewingRoom;
}
- },
+ }
_getKickOrBanInfo() {
const myMember = this._getMyMember();
@@ -221,9 +214,9 @@ export default createReactClass({
kickerMember.name : myMember.events.member.getSender();
const reason = myMember.events.member.getContent().reason;
return {memberName, reason};
- },
+ }
- _joinRule: function() {
+ _joinRule() {
const room = this.props.room;
if (room) {
const joinRules = room.currentState.getStateEvents('m.room.join_rules', '');
@@ -231,14 +224,14 @@ export default createReactClass({
return joinRules.getContent().join_rule;
}
}
- },
+ }
- _communityProfile: function() {
+ _communityProfile() {
if (this.props.room) return CommunityPrototypeStore.instance.getInviteProfile(this.props.room.roomId);
return {displayName: null, avatarMxc: null};
- },
+ }
- _roomName: function(atStart = false) {
+ _roomName(atStart = false) {
let name = this.props.room ? this.props.room.name : this.props.roomAlias;
const profile = this._communityProfile();
if (profile.displayName) name = profile.displayName;
@@ -249,16 +242,16 @@ export default createReactClass({
} else {
return _t("this room");
}
- },
+ }
_getMyMember() {
return (
this.props.room &&
this.props.room.getMember(MatrixClientPeg.get().getUserId())
);
- },
+ }
- _getInviteMember: function() {
+ _getInviteMember() {
const {room} = this.props;
if (!room) {
return;
@@ -270,7 +263,7 @@ export default createReactClass({
}
const inviterUserId = inviteEvent.events.member.getSender();
return room.currentState.getMember(inviterUserId);
- },
+ }
_isDMInvite() {
const myMember = this._getMyMember();
@@ -280,7 +273,7 @@ export default createReactClass({
const memberEvent = myMember.events.member;
const memberContent = memberEvent.getContent();
return memberContent.membership === "invite" && memberContent.is_direct;
- },
+ }
_makeScreenAfterLogin() {
return {
@@ -293,17 +286,17 @@ export default createReactClass({
inviter_name: this.props.oobData ? this.props.oobData.inviterName : null,
}
};
- },
+ }
- onLoginClick: function() {
+ onLoginClick = () => {
dis.dispatch({ action: 'start_login', screenAfterLogin: this._makeScreenAfterLogin() });
- },
+ };
- onRegisterClick: function() {
+ onRegisterClick = () => {
dis.dispatch({ action: 'start_registration', screenAfterLogin: this._makeScreenAfterLogin() });
- },
+ };
- render: function() {
+ render() {
const brand = SdkConfig.get().brand;
const Spinner = sdk.getComponent('elements.Spinner');
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
@@ -597,5 +590,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/RoomUpgradeWarningBar.js b/src/components/views/rooms/RoomUpgradeWarningBar.js
index 7d5bc89034..531428198e 100644
--- a/src/components/views/rooms/RoomUpgradeWarningBar.js
+++ b/src/components/views/rooms/RoomUpgradeWarningBar.js
@@ -16,29 +16,26 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
-export default createReactClass({
- displayName: 'RoomUpgradeWarningBar',
-
- propTypes: {
+export default class RoomUpgradeWarningBar extends React.Component {
+ static propTypes = {
room: PropTypes.object.isRequired,
recommendation: PropTypes.object.isRequired,
- },
+ };
- componentDidMount: function() {
+ componentDidMount() {
const tombstone = this.props.room.currentState.getStateEvents("m.room.tombstone", "");
this.setState({upgraded: tombstone && tombstone.getContent().replacement_room});
MatrixClientPeg.get().on("RoomState.events", this._onStateEvents);
- },
+ }
- _onStateEvents: function(event, state) {
+ _onStateEvents = (event, state) => {
if (!this.props.room || event.getRoomId() !== this.props.room.roomId) {
return;
}
@@ -47,14 +44,14 @@ export default createReactClass({
const tombstone = this.props.room.currentState.getStateEvents("m.room.tombstone", "");
this.setState({upgraded: tombstone && tombstone.getContent().replacement_room});
- },
+ };
- onUpgradeClick: function() {
+ onUpgradeClick = () => {
const RoomUpgradeDialog = sdk.getComponent('dialogs.RoomUpgradeDialog');
Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, {room: this.props.room});
- },
+ };
- render: function() {
+ render() {
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
let doUpgradeWarnings = (
@@ -117,5 +114,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/SearchBar.js b/src/components/views/rooms/SearchBar.js
index 1d2e7ed602..767f5a35f5 100644
--- a/src/components/views/rooms/SearchBar.js
+++ b/src/components/views/rooms/SearchBar.js
@@ -15,35 +15,31 @@ limitations under the License.
*/
import React, {createRef} from 'react';
-import createReactClass from 'create-react-class';
import AccessibleButton from "../elements/AccessibleButton";
import classNames from "classnames";
import { _t } from '../../../languageHandler';
import {Key} from "../../../Keyboard";
-export default createReactClass({
- displayName: 'SearchBar',
+export default class SearchBar extends React.Component {
+ constructor(props) {
+ super(props);
- getInitialState: function() {
- return ({
- scope: 'Room',
- });
- },
-
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this._search_term = createRef();
- },
- onThisRoomClick: function() {
+ this.state = {
+ scope: 'Room',
+ };
+ }
+
+ onThisRoomClick = () => {
this.setState({ scope: 'Room' }, () => this._searchIfQuery());
- },
+ };
- onAllRoomsClick: function() {
+ onAllRoomsClick = () => {
this.setState({ scope: 'All' }, () => this._searchIfQuery());
- },
+ };
- onSearchChange: function(e) {
+ onSearchChange = (e) => {
switch (e.key) {
case Key.ENTER:
this.onSearch();
@@ -52,19 +48,19 @@ export default createReactClass({
this.props.onCancelClick();
break;
}
- },
+ };
- _searchIfQuery: function() {
+ _searchIfQuery() {
if (this._search_term.current.value) {
this.onSearch();
}
- },
+ }
- onSearch: function() {
+ onSearch = () => {
this.props.onSearch(this._search_term.current.value, this.state.scope);
- },
+ };
- render: function() {
+ render() {
const searchButtonClasses = classNames("mx_SearchBar_searchButton", {
mx_SearchBar_searching: this.props.searchInProgress,
});
@@ -92,5 +88,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/SearchResultTile.js b/src/components/views/rooms/SearchResultTile.js
index 57856a3a5b..136bd23729 100644
--- a/src/components/views/rooms/SearchResultTile.js
+++ b/src/components/views/rooms/SearchResultTile.js
@@ -17,14 +17,11 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import {haveTileForEvent} from "./EventTile";
-export default createReactClass({
- displayName: 'SearchResult',
-
- propTypes: {
+export default class SearchResultTile extends React.Component {
+ static propTypes = {
// a matrix-js-sdk SearchResult containing the details of this result
searchResult: PropTypes.object.isRequired,
@@ -35,9 +32,9 @@ export default createReactClass({
resultLink: PropTypes.string,
onHeightChanged: PropTypes.func,
- },
+ };
- render: function() {
+ render() {
const DateSeparator = sdk.getComponent('messages.DateSeparator');
const EventTile = sdk.getComponent('rooms.EventTile');
const result = this.props.searchResult;
@@ -66,5 +63,5 @@ export default createReactClass({
{ ret }
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/SimpleRoomHeader.js b/src/components/views/rooms/SimpleRoomHeader.js
index f22d9fc1d0..1c78253eff 100644
--- a/src/components/views/rooms/SimpleRoomHeader.js
+++ b/src/components/views/rooms/SimpleRoomHeader.js
@@ -16,7 +16,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import AccessibleButton from '../elements/AccessibleButton';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
@@ -37,18 +36,16 @@ export function CancelButton(props) {
* A stripped-down room header used for things like the user settings
* and room directory.
*/
-export default createReactClass({
- displayName: 'SimpleRoomHeader',
-
- propTypes: {
+export default class SimpleRoomHeader extends React.Component {
+ static propTypes = {
title: PropTypes.string,
onCancelClick: PropTypes.func,
// `src` to a TintableSvg. Optional.
icon: PropTypes.string,
- },
+ };
- render: function() {
+ render() {
let cancelButton;
let icon;
if (this.props.onCancelClick) {
@@ -73,5 +70,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/TopUnreadMessagesBar.js b/src/components/views/rooms/TopUnreadMessagesBar.js
index 23d41059c4..9ac3c49ef4 100644
--- a/src/components/views/rooms/TopUnreadMessagesBar.js
+++ b/src/components/views/rooms/TopUnreadMessagesBar.js
@@ -18,19 +18,16 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import { _t } from '../../../languageHandler';
import AccessibleButton from '../elements/AccessibleButton';
-export default createReactClass({
- displayName: 'TopUnreadMessagesBar',
-
- propTypes: {
+export default class TopUnreadMessagesBar extends React.Component {
+ static propTypes = {
onScrollUpClick: PropTypes.func,
onCloseClick: PropTypes.func,
- },
+ };
- render: function() {
+ render() {
return (
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js
index b56a75582f..c796142e78 100644
--- a/src/components/views/rooms/WhoIsTypingTile.js
+++ b/src/components/views/rooms/WhoIsTypingTile.js
@@ -17,16 +17,13 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as WhoIsTyping from '../../../WhoIsTyping';
import Timer from '../../../utils/Timer';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import MemberAvatar from '../avatars/MemberAvatar';
-export default createReactClass({
- displayName: 'WhoIsTypingTile',
-
- propTypes: {
+export default class WhoIsTypingTile extends React.Component {
+ static propTypes = {
// the room this statusbar is representing.
room: PropTypes.object.isRequired,
onShown: PropTypes.func,
@@ -34,32 +31,28 @@ export default createReactClass({
// Number of names to display in typing indication. E.g. set to 3, will
// result in "X, Y, Z and 100 others are typing."
whoIsTypingLimit: PropTypes.number,
- },
+ };
- getDefaultProps: function() {
- return {
- whoIsTypingLimit: 3,
- };
- },
+ static defaultProps = {
+ whoIsTypingLimit: 3,
+ };
- getInitialState: function() {
- return {
- usersTyping: WhoIsTyping.usersTypingApartFromMe(this.props.room),
- // a map with userid => Timer to delay
- // hiding the "x is typing" message for a
- // user so hiding it can coincide
- // with the sent message by the other side
- // resulting in less timeline jumpiness
- delayedStopTypingTimers: {},
- };
- },
+ state = {
+ usersTyping: WhoIsTyping.usersTypingApartFromMe(this.props.room),
+ // a map with userid => Timer to delay
+ // hiding the "x is typing" message for a
+ // user so hiding it can coincide
+ // with the sent message by the other side
+ // resulting in less timeline jumpiness
+ delayedStopTypingTimers: {},
+ };
- componentDidMount: function() {
+ componentDidMount() {
MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping);
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
- },
+ }
- componentDidUpdate: function(_, prevState) {
+ componentDidUpdate(_, prevState) {
const wasVisible = this._isVisible(prevState);
const isVisible = this._isVisible(this.state);
if (this.props.onShown && !wasVisible && isVisible) {
@@ -67,9 +60,9 @@ export default createReactClass({
} else if (this.props.onHidden && wasVisible && !isVisible) {
this.props.onHidden();
}
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
// we may have entirely lost our client as we're logging out before clicking login on the guest bar...
const client = MatrixClientPeg.get();
if (client) {
@@ -77,17 +70,17 @@ export default createReactClass({
client.removeListener("Room.timeline", this.onRoomTimeline);
}
Object.values(this.state.delayedStopTypingTimers).forEach((t) => t.abort());
- },
+ }
- _isVisible: function(state) {
+ _isVisible(state) {
return state.usersTyping.length !== 0 || Object.keys(state.delayedStopTypingTimers).length !== 0;
- },
+ }
- isVisible: function() {
+ isVisible = () => {
return this._isVisible(this.state);
- },
+ };
- onRoomTimeline: function(event, room) {
+ onRoomTimeline = (event, room) => {
if (room && room.roomId === this.props.room.roomId) {
const userId = event.getSender();
// remove user from usersTyping
@@ -96,15 +89,15 @@ export default createReactClass({
// abort timer if any
this._abortUserTimer(userId);
}
- },
+ };
- onRoomMemberTyping: function(ev, member) {
+ onRoomMemberTyping = (ev, member) => {
const usersTyping = WhoIsTyping.usersTypingApartFromMeAndIgnored(this.props.room);
this.setState({
delayedStopTypingTimers: this._updateDelayedStopTypingTimers(usersTyping),
usersTyping,
});
- },
+ };
_updateDelayedStopTypingTimers(usersTyping) {
const usersThatStoppedTyping = this.state.usersTyping.filter((a) => {
@@ -142,26 +135,26 @@ export default createReactClass({
}, delayedStopTypingTimers);
return delayedStopTypingTimers;
- },
+ }
- _abortUserTimer: function(userId) {
+ _abortUserTimer(userId) {
const timer = this.state.delayedStopTypingTimers[userId];
if (timer) {
timer.abort();
this._removeUserTimer(userId);
}
- },
+ }
- _removeUserTimer: function(userId) {
+ _removeUserTimer(userId) {
const timer = this.state.delayedStopTypingTimers[userId];
if (timer) {
const delayedStopTypingTimers = Object.assign({}, this.state.delayedStopTypingTimers);
delete delayedStopTypingTimers[userId];
this.setState({delayedStopTypingTimers});
}
- },
+ }
- _renderTypingIndicatorAvatars: function(users, limit) {
+ _renderTypingIndicatorAvatars(users, limit) {
let othersCount = 0;
if (users.length > limit) {
othersCount = users.length - limit + 1;
@@ -190,9 +183,9 @@ export default createReactClass({
}
return avatars;
- },
+ }
- render: function() {
+ render() {
let usersTyping = this.state.usersTyping;
const stoppedUsersOnTimer = Object.keys(this.state.delayedStopTypingTimers)
.map((userId) => this.props.room.getMember(userId));
@@ -222,5 +215,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/settings/ChangeAvatar.js b/src/components/views/settings/ChangeAvatar.js
index d8baafd1bb..a6fc60ceb9 100644
--- a/src/components/views/settings/ChangeAvatar.js
+++ b/src/components/views/settings/ChangeAvatar.js
@@ -16,14 +16,12 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
-export default createReactClass({
- displayName: 'ChangeAvatar',
- propTypes: {
+export default class ChangeAvatar extends React.Component {
+ static propTypes = {
initialAvatarUrl: PropTypes.string,
room: PropTypes.object,
// if false, you need to call changeAvatar.onFileSelected yourself.
@@ -31,36 +29,36 @@ export default createReactClass({
width: PropTypes.number,
height: PropTypes.number,
className: PropTypes.string,
- },
+ };
- Phases: {
+ static Phases = {
Display: "display",
Uploading: "uploading",
Error: "error",
- },
+ };
- getDefaultProps: function() {
- return {
- showUploadSection: true,
- className: "",
- width: 80,
- height: 80,
- };
- },
+ static defaultProps = {
+ showUploadSection: true,
+ className: "",
+ width: 80,
+ height: 80,
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this.state = {
avatarUrl: this.props.initialAvatarUrl,
- phase: this.Phases.Display,
+ phase: ChangeAvatar.Phases.Display,
};
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents);
- },
+ }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
- UNSAFE_componentWillReceiveProps: function(newProps) {
+ UNSAFE_componentWillReceiveProps(newProps) {
if (this.avatarSet) {
// don't clobber what the user has just set
return;
@@ -68,15 +66,15 @@ export default createReactClass({
this.setState({
avatarUrl: newProps.initialAvatarUrl,
});
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents);
}
- },
+ }
- onRoomStateEvents: function(ev) {
+ onRoomStateEvents = (ev) => {
if (!this.props.room) {
return;
}
@@ -90,13 +88,13 @@ export default createReactClass({
this.avatarSet = false;
this.setState({}); // force update
}
- },
+ };
- setAvatarFromFile: function(file) {
+ setAvatarFromFile(file) {
let newUrl = null;
this.setState({
- phase: this.Phases.Uploading,
+ phase: ChangeAvatar.Phases.Uploading,
});
const self = this;
const httpPromise = MatrixClientPeg.get().uploadContent(file).then(function(url) {
@@ -115,31 +113,31 @@ export default createReactClass({
httpPromise.then(function() {
self.setState({
- phase: self.Phases.Display,
+ phase: ChangeAvatar.Phases.Display,
avatarUrl: MatrixClientPeg.get().mxcUrlToHttp(newUrl),
});
}, function(error) {
self.setState({
- phase: self.Phases.Error,
+ phase: ChangeAvatar.Phases.Error,
});
self.onError(error);
});
return httpPromise;
- },
+ }
- onFileSelected: function(ev) {
+ onFileSelected = (ev) => {
this.avatarSet = true;
return this.setAvatarFromFile(ev.target.files[0]);
- },
+ };
- onError: function(error) {
+ onError = (error) => {
this.setState({
errorText: _t("Failed to upload profile picture!"),
});
- },
+ };
- render: function() {
+ render() {
let avatarImg;
// Having just set an avatar we just display that since it will take a little
// time to propagate through to the RoomAvatar.
@@ -165,8 +163,8 @@ export default createReactClass({
}
switch (this.state.phase) {
- case this.Phases.Display:
- case this.Phases.Error:
+ case ChangeAvatar.Phases.Display:
+ case ChangeAvatar.Phases.Error:
return (
@@ -175,11 +173,11 @@ export default createReactClass({
{ uploadSection }
);
- case this.Phases.Uploading:
+ case ChangeAvatar.Phases.Uploading:
var Loader = sdk.getComponent("elements.Spinner");
return (
);
}
- },
-});
+ }
+}
diff --git a/src/components/views/settings/ChangeDisplayName.js b/src/components/views/settings/ChangeDisplayName.js
index fdc55a4f52..538e52d0ca 100644
--- a/src/components/views/settings/ChangeDisplayName.js
+++ b/src/components/views/settings/ChangeDisplayName.js
@@ -17,15 +17,12 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
-export default createReactClass({
- displayName: 'ChangeDisplayName',
-
- _getDisplayName: async function() {
+export default class ChangeDisplayName extends React.Component {
+ _getDisplayName = async () => {
const cli = MatrixClientPeg.get();
try {
const res = await cli.getProfileInfo(cli.getUserId());
@@ -33,16 +30,16 @@ export default createReactClass({
} catch (e) {
throw new Error("Failed to fetch display name");
}
- },
+ };
- _changeDisplayName: function(newDisplayname) {
+ _changeDisplayName = (newDisplayname) => {
const cli = MatrixClientPeg.get();
return cli.setDisplayName(newDisplayname).catch(function(e) {
throw new Error("Failed to set display name", e);
});
- },
+ };
- render: function() {
+ render() {
const EditableTextContainer = sdk.getComponent('elements.EditableTextContainer');
return (
);
- },
-});
+ }
+}
diff --git a/src/components/views/settings/ChangePassword.js b/src/components/views/settings/ChangePassword.js
index 47fcae5c6f..725f04dede 100644
--- a/src/components/views/settings/ChangePassword.js
+++ b/src/components/views/settings/ChangePassword.js
@@ -18,7 +18,6 @@ limitations under the License.
import Field from "../elements/Field";
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import dis from "../../../dispatcher/dispatcher";
import AccessibleButton from '../elements/AccessibleButton';
@@ -28,10 +27,8 @@ import Modal from "../../../Modal";
import sessionStore from '../../../stores/SessionStore';
-export default createReactClass({
- displayName: 'ChangePassword',
-
- propTypes: {
+export default class ChangePassword extends React.Component {
+ static propTypes = {
onFinished: PropTypes.func,
onError: PropTypes.func,
onCheckPassword: PropTypes.func,
@@ -41,65 +38,61 @@ export default createReactClass({
confirm: PropTypes.bool,
// Whether to autoFocus the new password input
autoFocusNewPasswordInput: PropTypes.bool,
- },
+ };
- Phases: {
+ static Phases = {
Edit: "edit",
Uploading: "uploading",
Error: "error",
- },
+ };
- getDefaultProps: function() {
- return {
- onFinished: function() {},
- onError: function() {},
- onCheckPassword: function(oldPass, newPass, confirmPass) {
- if (newPass !== confirmPass) {
- return {
- error: _t("New passwords don't match"),
- };
- } else if (!newPass || newPass.length === 0) {
- return {
- error: _t("Passwords can't be empty"),
- };
- }
- },
- confirm: true,
- };
- },
+ static defaultProps = {
+ onFinished() {},
+ onError() {},
+ onCheckPassword(oldPass, newPass, confirmPass) {
+ if (newPass !== confirmPass) {
+ return {
+ error: _t("New passwords don't match"),
+ };
+ } else if (!newPass || newPass.length === 0) {
+ return {
+ error: _t("Passwords can't be empty"),
+ };
+ }
+ },
+ confirm: true,
+ }
- getInitialState: function() {
- return {
- phase: this.Phases.Edit,
- cachedPassword: null,
- oldPassword: "",
- newPassword: "",
- newPasswordConfirm: "",
- };
- },
+ state = {
+ phase: ChangePassword.Phases.Edit,
+ cachedPassword: null,
+ oldPassword: "",
+ newPassword: "",
+ newPasswordConfirm: "",
+ };
- componentDidMount: function() {
+ componentDidMount() {
this._sessionStore = sessionStore;
this._sessionStoreToken = this._sessionStore.addListener(
this._setStateFromSessionStore,
);
this._setStateFromSessionStore();
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
if (this._sessionStoreToken) {
this._sessionStoreToken.remove();
}
- },
+ }
- _setStateFromSessionStore: function() {
+ _setStateFromSessionStore = () => {
this.setState({
cachedPassword: this._sessionStore.getCachedPassword(),
});
- },
+ };
- changePassword: function(oldPassword, newPassword) {
+ changePassword(oldPassword, newPassword) {
const cli = MatrixClientPeg.get();
if (!this.props.confirm) {
@@ -136,9 +129,9 @@ export default createReactClass({
}
},
});
- },
+ }
- _changePassword: function(cli, oldPassword, newPassword) {
+ _changePassword(cli, oldPassword, newPassword) {
const authDict = {
type: 'm.login.password',
identifier: {
@@ -152,7 +145,7 @@ export default createReactClass({
};
this.setState({
- phase: this.Phases.Uploading,
+ phase: ChangePassword.Phases.Uploading,
});
cli.setPassword(authDict, newPassword).then(() => {
@@ -172,51 +165,51 @@ export default createReactClass({
this.props.onError(err);
}).finally(() => {
this.setState({
- phase: this.Phases.Edit,
+ phase: ChangePassword.Phases.Edit,
oldPassword: "",
newPassword: "",
newPasswordConfirm: "",
});
});
- },
+ }
- _optionallySetEmail: function() {
+ _optionallySetEmail() {
// Ask for an email otherwise the user has no way to reset their password
const SetEmailDialog = sdk.getComponent("dialogs.SetEmailDialog");
const modal = Modal.createTrackedDialog('Do you want to set an email address?', '', SetEmailDialog, {
title: _t('Do you want to set an email address?'),
});
return modal.finished.then(([confirmed]) => confirmed);
- },
+ }
- _onExportE2eKeysClicked: function() {
+ _onExportE2eKeysClicked = () => {
Modal.createTrackedDialogAsync('Export E2E Keys', 'Change Password',
import('../../../async-components/views/dialogs/ExportE2eKeysDialog'),
{
matrixClient: MatrixClientPeg.get(),
},
);
- },
+ };
- onChangeOldPassword(ev) {
+ onChangeOldPassword = (ev) => {
this.setState({
oldPassword: ev.target.value,
});
- },
+ };
- onChangeNewPassword(ev) {
+ onChangeNewPassword = (ev) => {
this.setState({
newPassword: ev.target.value,
});
- },
+ };
- onChangeNewPasswordConfirm(ev) {
+ onChangeNewPasswordConfirm = (ev) => {
this.setState({
newPasswordConfirm: ev.target.value,
});
- },
+ };
- onClickChange: function(ev) {
+ onClickChange = (ev) => {
ev.preventDefault();
const oldPassword = this.state.cachedPassword || this.state.oldPassword;
const newPassword = this.state.newPassword;
@@ -229,9 +222,9 @@ export default createReactClass({
} else {
this.changePassword(oldPassword, newPassword);
}
- },
+ };
- render: function() {
+ render() {
// TODO: Live validation on `new pw == confirm pw`
const rowClassName = this.props.rowClassName;
@@ -252,7 +245,7 @@ export default createReactClass({
}
switch (this.state.phase) {
- case this.Phases.Edit:
+ case ChangePassword.Phases.Edit:
const passwordLabel = this.state.cachedPassword ?
_t('Password') : _t('New Password');
return (
@@ -282,7 +275,7 @@ export default createReactClass({
);
- case this.Phases.Uploading:
+ case ChangePassword.Phases.Uploading:
var Loader = sdk.getComponent("elements.Spinner");
return (
@@ -290,5 +283,5 @@ export default createReactClass({
);
}
- },
-});
+ }
+}
diff --git a/src/components/views/settings/Notifications.js b/src/components/views/settings/Notifications.js
index 5c16e1ed4f..6eaf55279b 100644
--- a/src/components/views/settings/Notifications.js
+++ b/src/components/views/settings/Notifications.js
@@ -16,7 +16,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
@@ -65,46 +64,42 @@ function portLegacyActions(actions) {
}
}
-export default createReactClass({
- displayName: 'Notifications',
-
- phases: {
+export default class Notifications extends React.Component {
+ static phases = {
LOADING: "LOADING", // The component is loading or sending data to the hs
DISPLAY: "DISPLAY", // The component is ready and display data
ERROR: "ERROR", // There was an error
- },
+ };
- getInitialState: function() {
- return {
- phase: this.phases.LOADING,
- masterPushRule: undefined, // The master rule ('.m.rule.master')
- vectorPushRules: [], // HS default push rules displayed in Vector UI
- vectorContentRules: { // Keyword push rules displayed in Vector UI
- vectorState: PushRuleVectorState.ON,
- rules: [],
- },
- externalPushRules: [], // Push rules (except content rule) that have been defined outside Vector UI
- externalContentRules: [], // Keyword push rules that have been defined outside Vector UI
- threepids: [], // used for email notifications
- };
- },
+ state = {
+ phase: Notifications.phases.LOADING,
+ masterPushRule: undefined, // The master rule ('.m.rule.master')
+ vectorPushRules: [], // HS default push rules displayed in Vector UI
+ vectorContentRules: { // Keyword push rules displayed in Vector UI
+ vectorState: PushRuleVectorState.ON,
+ rules: [],
+ },
+ externalPushRules: [], // Push rules (except content rule) that have been defined outside Vector UI
+ externalContentRules: [], // Keyword push rules that have been defined outside Vector UI
+ threepids: [], // used for email notifications
+ };
- componentDidMount: function() {
+ componentDidMount() {
this._refreshFromServer();
- },
+ }
- onEnableNotificationsChange: function(checked) {
+ onEnableNotificationsChange = (checked) => {
const self = this;
this.setState({
- phase: this.phases.LOADING,
+ phase: Notifications.phases.LOADING,
});
MatrixClientPeg.get().setPushRuleEnabled('global', self.state.masterPushRule.kind, self.state.masterPushRule.rule_id, !checked).then(function() {
self._refreshFromServer();
});
- },
+ };
- onEnableDesktopNotificationsChange: function(checked) {
+ onEnableDesktopNotificationsChange = (checked) => {
SettingsStore.setValue(
"notificationsEnabled", null,
SettingLevel.DEVICE,
@@ -112,9 +107,9 @@ export default createReactClass({
).finally(() => {
this.forceUpdate();
});
- },
+ };
- onEnableDesktopNotificationBodyChange: function(checked) {
+ onEnableDesktopNotificationBodyChange = (checked) => {
SettingsStore.setValue(
"notificationBodyEnabled", null,
SettingLevel.DEVICE,
@@ -122,9 +117,9 @@ export default createReactClass({
).finally(() => {
this.forceUpdate();
});
- },
+ };
- onEnableAudioNotificationsChange: function(checked) {
+ onEnableAudioNotificationsChange = (checked) => {
SettingsStore.setValue(
"audioNotificationsEnabled", null,
SettingLevel.DEVICE,
@@ -132,7 +127,7 @@ export default createReactClass({
).finally(() => {
this.forceUpdate();
});
- },
+ };
/*
* Returns the email pusher (pusher of type 'email') for a given
@@ -140,7 +135,7 @@ export default createReactClass({
* pushers are unique over (app ID, pushkey), there will be at most
* one such pusher.
*/
- getEmailPusher: function(pushers, address) {
+ getEmailPusher(pushers, address) {
if (pushers === undefined) {
return undefined;
}
@@ -150,9 +145,9 @@ export default createReactClass({
}
}
return undefined;
- },
+ }
- onEnableEmailNotificationsChange: function(address, checked) {
+ onEnableEmailNotificationsChange = (address, checked) => {
let emailPusherPromise;
if (checked) {
const data = {};
@@ -181,9 +176,9 @@ export default createReactClass({
description: _t('An error occurred whilst saving your email notification preferences.'),
});
});
- },
+ };
- onNotifStateButtonClicked: function(event) {
+ onNotifStateButtonClicked = (event) => {
// FIXME: use .bind() rather than className metadata here surely
const vectorRuleId = event.target.className.split("-")[0];
const newPushRuleVectorState = event.target.className.split("-")[1];
@@ -196,11 +191,9 @@ export default createReactClass({
this._setPushRuleVectorState(rule, newPushRuleVectorState);
}
}
- },
-
- onKeywordsClicked: function(event) {
- const self = this;
+ };
+ onKeywordsClicked = (event) => {
// Compute the keywords list to display
let keywords = [];
for (const i in this.state.vectorContentRules.rules) {
@@ -223,7 +216,7 @@ export default createReactClass({
description: _t('Enter keywords separated by a comma:'),
button: _t('OK'),
value: keywords,
- onFinished: function onFinished(should_leave, newValue) {
+ onFinished: (should_leave, newValue) => {
if (should_leave && newValue !== keywords) {
let newKeywords = newValue.split(',');
for (const i in newKeywords) {
@@ -238,25 +231,25 @@ export default createReactClass({
return array;
}, []);
- self._setKeywords(newKeywords);
+ this._setKeywords(newKeywords);
}
},
});
- },
+ };
- getRule: function(vectorRuleId) {
+ getRule(vectorRuleId) {
for (const i in this.state.vectorPushRules) {
const rule = this.state.vectorPushRules[i];
if (rule.vectorRuleId === vectorRuleId) {
return rule;
}
}
- },
+ }
- _setPushRuleVectorState: function(rule, newPushRuleVectorState) {
+ _setPushRuleVectorState(rule, newPushRuleVectorState) {
if (rule && rule.vectorState !== newPushRuleVectorState) {
this.setState({
- phase: this.phases.LOADING,
+ phase: Notifications.phases.LOADING,
});
const self = this;
@@ -288,9 +281,9 @@ export default createReactClass({
});
});
}
- },
+ }
- _setKeywordsPushRuleVectorState: function(newPushRuleVectorState) {
+ _setKeywordsPushRuleVectorState(newPushRuleVectorState) {
// Is there really a change?
if (this.state.vectorContentRules.vectorState === newPushRuleVectorState
|| this.state.vectorContentRules.rules.length === 0) {
@@ -301,7 +294,7 @@ export default createReactClass({
const cli = MatrixClientPeg.get();
this.setState({
- phase: this.phases.LOADING,
+ phase: Notifications.phases.LOADING,
});
// Update all rules in self.state.vectorContentRules
@@ -356,11 +349,11 @@ export default createReactClass({
onFinished: self._refreshFromServer,
});
});
- },
+ }
- _setKeywords: function(newKeywords) {
+ _setKeywords(newKeywords) {
this.setState({
- phase: this.phases.LOADING,
+ phase: Notifications.phases.LOADING,
});
const self = this;
@@ -440,19 +433,19 @@ export default createReactClass({
self._refreshFromServer();
}, onError);
}, onError);
- },
+ }
// Create a push rule but disabled
- _addDisabledPushRule: function(scope, kind, ruleId, body) {
+ _addDisabledPushRule(scope, kind, ruleId, body) {
const cli = MatrixClientPeg.get();
return cli.addPushRule(scope, kind, ruleId, body).then(() =>
cli.setPushRuleEnabled(scope, kind, ruleId, false),
);
- },
+ }
// Check if any legacy im.vector rules need to be ported to the new API
// for overriding the actions of default rules.
- _portRulesToNewAPI: function(rulesets) {
+ _portRulesToNewAPI(rulesets) {
const needsUpdate = [];
const cli = MatrixClientPeg.get();
@@ -485,9 +478,9 @@ export default createReactClass({
// Otherwise return the rules that we already have.
return rulesets;
}
- },
+ }
- _refreshFromServer: function() {
+ _refreshFromServer = () => {
const self = this;
const pushRulesPromise = MatrixClientPeg.get().getPushRules().then(self._portRulesToNewAPI).then(function(rulesets) {
/// XXX seriously? wtf is this?
@@ -636,12 +629,12 @@ export default createReactClass({
Promise.all([pushRulesPromise, pushersPromise]).then(function() {
self.setState({
- phase: self.phases.DISPLAY,
+ phase: Notifications.phases.DISPLAY,
});
}, function(error) {
console.error(error);
self.setState({
- phase: self.phases.ERROR,
+ phase: Notifications.phases.ERROR,
});
}).finally(() => {
// actually explicitly update our state having been deep-manipulating it
@@ -655,9 +648,9 @@ export default createReactClass({
});
MatrixClientPeg.get().getThreePids().then((r) => this.setState({threepids: r.threepids}));
- },
+ };
- _onClearNotifications: function() {
+ _onClearNotifications = () => {
const cli = MatrixClientPeg.get();
cli.getRooms().forEach(r => {
@@ -666,9 +659,9 @@ export default createReactClass({
if (events.length) cli.sendReadReceipt(events.pop());
}
});
- },
+ };
- _updatePushRuleActions: function(rule, actions, enabled) {
+ _updatePushRuleActions(rule, actions, enabled) {
const cli = MatrixClientPeg.get();
return cli.setPushRuleActions(
@@ -681,9 +674,9 @@ export default createReactClass({
);
}
});
- },
+ }
- renderNotifRulesTableRow: function(title, className, pushRuleVectorState) {
+ renderNotifRulesTableRow(title, className, pushRuleVectorState) {
return (
@@ -712,9 +705,9 @@ export default createReactClass({
);
- },
+ }
- renderNotifRulesTableRows: function() {
+ renderNotifRulesTableRows() {
const rows = [];
for (const i in this.state.vectorPushRules) {
const rule = this.state.vectorPushRules[i];
@@ -726,9 +719,9 @@ export default createReactClass({
rows.push(this.renderNotifRulesTableRow(rule.description, rule.vectorRuleId, rule.vectorState));
}
return rows;
- },
+ }
- hasEmailPusher: function(pushers, address) {
+ hasEmailPusher(pushers, address) {
if (pushers === undefined) {
return false;
}
@@ -738,17 +731,17 @@ export default createReactClass({
}
}
return false;
- },
+ }
- emailNotificationsRow: function(address, label) {
+ emailNotificationsRow(address, label) {
return
;
- },
+ }
- render: function() {
+ render() {
let spinner;
- if (this.state.phase === this.phases.LOADING) {
+ if (this.state.phase === Notifications.phases.LOADING) {
const Loader = sdk.getComponent("elements.Spinner");
spinner =
;
}
@@ -910,5 +903,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/voip/VideoFeed.js b/src/components/views/voip/VideoFeed.js
index 527b071942..a0330f8cb1 100644
--- a/src/components/views/voip/VideoFeed.js
+++ b/src/components/views/voip/VideoFeed.js
@@ -17,44 +17,42 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
-export default createReactClass({
- displayName: 'VideoFeed',
-
- propTypes: {
+export default class VideoFeed extends React.Component {
+ static propTypes = {
// maxHeight style attribute for the video element
maxHeight: PropTypes.number,
// a callback which is called when the video element is resized
// due to a change in video metadata
onResize: PropTypes.func,
- },
+ };
+
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount() {
this._vid = createRef();
- },
+ }
componentDidMount() {
this._vid.current.addEventListener('resize', this.onResize);
- },
+ }
componentWillUnmount() {
this._vid.current.removeEventListener('resize', this.onResize);
- },
+ }
- onResize: function(e) {
+ onResize = (e) => {
if (this.props.onResize) {
this.props.onResize(e);
}
- },
+ };
- render: function() {
+ render() {
return (
);
- },
-});
+ }
+}
diff --git a/src/components/views/voip/VideoView.js b/src/components/views/voip/VideoView.js
index a51ab70da9..374a12e82d 100644
--- a/src/components/views/voip/VideoView.js
+++ b/src/components/views/voip/VideoView.js
@@ -18,7 +18,6 @@ limitations under the License.
import React, {createRef} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import classNames from 'classnames';
import * as sdk from '../../../index';
@@ -35,10 +34,8 @@ function getFullScreenElement() {
);
}
-export default createReactClass({
- displayName: 'VideoView',
-
- propTypes: {
+export default class VideoView extends React.Component {
+ static propTypes = {
// maxHeight style attribute for the video element
maxHeight: PropTypes.number,
@@ -48,27 +45,28 @@ export default createReactClass({
// a callback which is called when the video element is resized due to
// a change in video metadata
onResize: PropTypes.func,
- },
+ };
+
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this._local = createRef();
this._remote = createRef();
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
this.dispatcherRef = dis.register(this.onAction);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
dis.unregister(this.dispatcherRef);
- },
+ }
- getRemoteVideoElement: function() {
+ getRemoteVideoElement = () => {
return ReactDOM.findDOMNode(this._remote.current);
- },
+ };
- getRemoteAudioElement: function() {
+ getRemoteAudioElement = () => {
// this needs to be somewhere at the top of the DOM which
// always exists to avoid audio interruptions.
// Might as well just use DOM.
@@ -78,17 +76,17 @@ export default createReactClass({
+ "You need to add an to the DOM.");
}
return remoteAudioElement;
- },
+ };
- getLocalVideoElement: function() {
+ getLocalVideoElement = () => {
return ReactDOM.findDOMNode(this._local.current);
- },
+ };
- setContainer: function(c) {
+ setContainer = (c) => {
this.container = c;
- },
+ };
- onAction: function(payload) {
+ onAction = (payload) => {
switch (payload.action) {
case 'video_fullscreen': {
if (!this.container) {
@@ -117,9 +115,9 @@ export default createReactClass({
break;
}
}
- },
+ };
- render: function() {
+ render() {
const VideoFeed = sdk.getComponent('voip.VideoFeed');
// if we're fullscreen, we don't want to set a maxHeight on the video element.
@@ -140,5 +138,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/test/components/structures/MessagePanel-test.js b/test/components/structures/MessagePanel-test.js
index 3ac70bdac9..235ae94010 100644
--- a/test/components/structures/MessagePanel-test.js
+++ b/test/components/structures/MessagePanel-test.js
@@ -18,9 +18,7 @@ limitations under the License.
import SettingsStore from "../../../src/settings/SettingsStore";
import React from 'react';
-import createReactClass from 'create-react-class';
import ReactDOM from "react-dom";
-import PropTypes from "prop-types";
const TestUtils = require('react-dom/test-utils');
const expect = require('expect');
import { EventEmitter } from "events";
@@ -47,21 +45,19 @@ let client;
const room = new Matrix.Room();
// wrap MessagePanel with a component which provides the MatrixClient in the context.
-const WrappedMessagePanel = createReactClass({
- getInitialState: function() {
- return {
- resizeNotifier: new EventEmitter(),
- };
- },
+class WrappedMessagePanel extends React.Component {
+ state = {
+ resizeNotifier: new EventEmitter(),
+ };
- render: function() {
+ render() {
return
;
- },
-});
+ }
+}
describe('MessagePanel', function() {
const clock = mockclock.clock();
@@ -214,7 +210,7 @@ describe('MessagePanel', function() {
room: roomId,
user: alice,
content: {
- "join_rule": "invite"
+ "join_rule": "invite",
},
ts: ts0 + 2,
}),
diff --git a/test/components/stub-component.js b/test/components/stub-component.js
index a5c3b44409..72ffde3483 100644
--- a/test/components/stub-component.js
+++ b/test/components/stub-component.js
@@ -2,19 +2,19 @@
*/
import React from 'react';
-import createReactClass from 'create-react-class';
-export default function(opts) {
- opts = opts || {};
- if (!opts.displayName) {
- opts.displayName = 'StubComponent';
- }
-
- if (!opts.render) {
- opts.render = function() {
+export default function({displayName = "StubComponent", render} = {}) {
+ if (!render) {
+ render = function() {
return { this.displayName }
;
};
}
- return createReactClass(opts);
+ return class extends React.Component {
+ static displayName = displayName;
+
+ render() {
+ return render();
+ }
+ };
}
From ac9108a9a6e1301df5f076efe74365487ff01000 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 29 Aug 2020 12:16:14 +0100
Subject: [PATCH 20/63] i18n
---
src/i18n/strings/en_EN.json | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 442f07499c..02382d4ff7 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -1200,7 +1200,6 @@
"%(count)s unread messages.|other": "%(count)s unread messages.",
"%(count)s unread messages.|one": "1 unread message.",
"Unread messages.": "Unread messages.",
- "Add a topic": "Add a topic",
"Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.",
"This room has already been upgraded.": "This room has already been upgraded.",
"This room is running room version , which this homeserver has marked as unstable .": "This room is running room version , which this homeserver has marked as unstable .",
@@ -1556,8 +1555,6 @@
"Room directory": "Room directory",
"Sign in with single sign-on": "Sign in with single sign-on",
"And %(count)s more...|other": "And %(count)s more...",
- "ex. @bob:example.com": "ex. @bob:example.com",
- "Add User": "Add User",
"Home": "Home",
"Enter a server name": "Enter a server name",
"Looks good": "Looks good",
@@ -1886,10 +1883,6 @@
"Warning : You should only set up key backup from a trusted computer.": "Warning : You should only set up key backup from a trusted computer.",
"Access your secure message history and set up secure messaging by entering your recovery key.": "Access your secure message history and set up secure messaging by entering your recovery key.",
"If you've forgotten your recovery key you can set up new recovery options ": "If you've forgotten your recovery key you can set up new recovery options ",
- "Private Chat": "Private Chat",
- "Public Chat": "Public Chat",
- "Custom": "Custom",
- "Address (optional)": "Address (optional)",
"Reject invitation": "Reject invitation",
"Are you sure you want to reject the invitation?": "Are you sure you want to reject the invitation?",
"Unable to reject invite": "Unable to reject invite",
@@ -1983,11 +1976,6 @@
"Sign in to your Matrix account on %(serverName)s": "Sign in to your Matrix account on %(serverName)s",
"Sign in to your Matrix account on ": "Sign in to your Matrix account on ",
"Sign in with SSO": "Sign in with SSO",
- "Sorry, your browser is not able to run %(brand)s.": "Sorry, your browser is not able to run %(brand)s.",
- "%(brand)s uses many advanced browser features, some of which are not available or experimental in your current browser.": "%(brand)s uses many advanced browser features, some of which are not available or experimental in your current browser.",
- "Please install Chrome , Firefox , or Safari for the best experience.": "Please install Chrome , Firefox , or Safari for the best experience.",
- "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!",
- "I understand the risks and wish to continue": "I understand the risks and wish to continue",
"Couldn't load page": "Couldn't load page",
"You must register to use this functionality": "You must register to use this functionality",
"You must join the room to see its files": "You must join the room to see its files",
From 34b960d8cb7539115818d561948a79720d5cd8b0 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 29 Aug 2020 12:17:50 +0100
Subject: [PATCH 21/63] fix naming conflict
---
src/components/structures/auth/Login.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js
index e56a9ea5e9..44a03929cf 100644
--- a/src/components/structures/auth/Login.js
+++ b/src/components/structures/auth/Login.js
@@ -55,7 +55,7 @@ _td("General failure");
/**
* A wire component which glues together login UI components and Login logic
*/
-export default class Login extends React.Component {
+export default class LoginComponent extends React.Component {
static propTypes = {
// Called when the user has logged in. Params:
// - The object returned by the login API
From 78812b6f855d4e41ff997aed2af0e69622bd0811 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 29 Aug 2020 12:51:37 +0100
Subject: [PATCH 22/63] Fix some stuff
---
src/components/structures/EmbeddedPage.js | 4 +--
src/components/structures/RightPanel.js | 4 +--
src/components/structures/RoomView.js | 10 ++++--
src/components/structures/TimelinePanel.js | 21 ++++++------
src/components/views/elements/ReplyThread.js | 4 +--
.../views/groups/GroupInviteTile.js | 4 +--
src/components/views/rooms/EventTile.js | 10 ++++--
src/components/views/rooms/MemberList.js | 32 +++++++++----------
.../views/rooms/SendMessageComposer.js | 4 +--
9 files changed, 51 insertions(+), 42 deletions(-)
diff --git a/src/components/structures/EmbeddedPage.js b/src/components/structures/EmbeddedPage.js
index 49ba3d1227..cbfeff7582 100644
--- a/src/components/structures/EmbeddedPage.js
+++ b/src/components/structures/EmbeddedPage.js
@@ -43,8 +43,8 @@ export default class EmbeddedPage extends React.PureComponent {
static contextType = MatrixClientContext;
- constructor(props) {
- super(props);
+ constructor(props, context) {
+ super(props, context);
this._dispatcherRef = null;
diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js
index a4e3254e4c..24fee80c2a 100644
--- a/src/components/structures/RightPanel.js
+++ b/src/components/structures/RightPanel.js
@@ -42,8 +42,8 @@ export default class RightPanel extends React.Component {
static contextType = MatrixClientContext;
- constructor(props) {
- super(props);
+ constructor(props, context) {
+ super(props, context);
this.state = {
phase: this._getPhaseFromProps(),
isUserPrivilegedInGroup: null,
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index 157f7266fa..e1a075f770 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -99,8 +99,8 @@ export default class RoomView extends React.Component {
static contextType = MatrixClientContext;
- constructor(props) {
- super(props);
+ constructor(props, context) {
+ super(props, context);
const llMembers = this.context.hasLazyLoadMembersEnabled();
this.state = {
@@ -186,7 +186,6 @@ export default class RoomView extends React.Component {
// Start listening for RoomViewStore updates
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
this._rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this._onRightPanelStoreUpdate);
- this._onRoomViewStoreUpdate(true);
WidgetEchoStore.on('update', this._onWidgetEchoStoreUpdate);
this._showReadReceiptsWatchRef = SettingsStore.watchSetting("showReadReceipts", null,
@@ -198,6 +197,11 @@ export default class RoomView extends React.Component {
this._layoutWatcherRef = SettingsStore.watchSetting("useIRCLayout", null, this.onLayoutChange);
}
+ // TODO: [REACT-WARNING] Move into constructor
+ UNSAFE_componentWillMount() {
+ this._onRoomViewStoreUpdate(true);
+ }
+
_onReadReceiptsChange = () => {
this.setState({
showReadReceipts: SettingsStore.getValue("showReadReceipts", this.state.roomId),
diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js
index d9cec2e054..d1c977f2ca 100644
--- a/src/components/structures/TimelinePanel.js
+++ b/src/components/structures/TimelinePanel.js
@@ -134,13 +134,6 @@ class TimelinePanel extends React.Component {
this._messagePanel = createRef();
- if (this.props.manageReadReceipts) {
- this.updateReadReceiptOnUserActivity();
- }
- if (this.props.manageReadMarkers) {
- this.updateReadMarkerOnUserActivity();
- }
-
// XXX: we could track RM per TimelineSet rather than per Room.
// but for now we just do it per room for simplicity.
let initialReadMarker = null;
@@ -225,6 +218,16 @@ class TimelinePanel extends React.Component {
MatrixClientPeg.get().on("Event.decrypted", this.onEventDecrypted);
MatrixClientPeg.get().on("Event.replaced", this.onEventReplaced);
MatrixClientPeg.get().on("sync", this.onSync);
+ }
+
+ // TODO: [REACT-WARNING] Move into constructor
+ UNSAFE_componentWillMount() {
+ if (this.props.manageReadReceipts) {
+ this.updateReadReceiptOnUserActivity();
+ }
+ if (this.props.manageReadMarkers) {
+ this.updateReadMarkerOnUserActivity();
+ }
this._initTimeline(this.props);
}
@@ -1360,9 +1363,7 @@ class TimelinePanel extends React.Component {
});
}
- getRelationsForEvent(...args) {
- return this.props.timelineSet.getRelationsForEvent(...args);
- }
+ getRelationsForEvent = (...args) => this.props.timelineSet.getRelationsForEvent(...args);
render() {
const MessagePanel = sdk.getComponent("structures.MessagePanel");
diff --git a/src/components/views/elements/ReplyThread.js b/src/components/views/elements/ReplyThread.js
index 409bf9e01f..b52c42a894 100644
--- a/src/components/views/elements/ReplyThread.js
+++ b/src/components/views/elements/ReplyThread.js
@@ -45,8 +45,8 @@ export default class ReplyThread extends React.Component {
static contextType = MatrixClientContext;
- constructor(props) {
- super(props);
+ constructor(props, context) {
+ super(props, context);
this.state = {
// The loaded events to be rendered as linear-replies
diff --git a/src/components/views/groups/GroupInviteTile.js b/src/components/views/groups/GroupInviteTile.js
index 7efb8cf427..0c09b6ed05 100644
--- a/src/components/views/groups/GroupInviteTile.js
+++ b/src/components/views/groups/GroupInviteTile.js
@@ -35,8 +35,8 @@ export default class GroupInviteTile extends React.Component {
static contextType = MatrixClientContext;
- constructor(props) {
- super(props);
+ constructor(props, context) {
+ super(props, context);
this.state = {
hover: false,
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index d1738301d9..608505adb5 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -215,8 +215,8 @@ export default class EventTile extends React.Component {
static contextType = MatrixClientContext;
- constructor(props) {
- super(props);
+ constructor(props, context) {
+ super(props, context);
this.state = {
// Whether the action bar is focused.
@@ -234,12 +234,16 @@ export default class EventTile extends React.Component {
// don't do RR animations until we are mounted
this._suppressReadReceiptAnimation = true;
- this._verifyEvent(this.props.mxEvent);
this._tile = createRef();
this._replyThread = createRef();
}
+ // TODO: [REACT-WARNING] Move into constructor
+ UNSAFE_componentWillMount() {
+ this._verifyEvent(this.props.mxEvent);
+ }
+
componentDidMount() {
this._suppressReadReceiptAnimation = false;
const client = this.context;
diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js
index 920e3cf691..33b98f977d 100644
--- a/src/components/views/rooms/MemberList.js
+++ b/src/components/views/rooms/MemberList.js
@@ -47,13 +47,6 @@ export default class MemberList extends React.Component {
this.state = this._getMembersState(this.roomMembers());
}
- this._mounted = true;
- if (cli.hasLazyLoadMembersEnabled()) {
- this._showMembersAccordingToMembershipWithLL();
- cli.on("Room.myMembership", this.onMyMembership);
- } else {
- this._listenForMembersChanges();
- }
cli.on("Room", this.onRoom); // invites & joining after peek
const enablePresenceByHsUrl = SdkConfig.get()["enable_presence_by_hs_url"];
const hsUrl = MatrixClientPeg.get().baseUrl;
@@ -63,6 +56,17 @@ export default class MemberList extends React.Component {
}
}
+ componentDidMount() {
+ const cli = MatrixClientPeg.get();
+ this._mounted = true;
+ if (cli.hasLazyLoadMembersEnabled()) {
+ this._showMembersAccordingToMembershipWithLL();
+ cli.on("Room.myMembership", this.onMyMembership);
+ } else {
+ this._listenForMembersChanges();
+ }
+ }
+
_listenForMembersChanges() {
const cli = MatrixClientPeg.get();
cli.on("RoomState.members", this.onRoomStateMember);
@@ -412,24 +416,20 @@ export default class MemberList extends React.Component {
});
}
- _getChildrenJoined(start, end) {
- return this._makeMemberTiles(this.state.filteredJoinedMembers.slice(start, end));
- }
+ _getChildrenJoined = (start, end) => this._makeMemberTiles(this.state.filteredJoinedMembers.slice(start, end));
- _getChildCountJoined() {
- return this.state.filteredJoinedMembers.length;
- }
+ _getChildCountJoined = () => this.state.filteredJoinedMembers.length;
- _getChildrenInvited(start, end) {
+ _getChildrenInvited = (start, end) => {
let targets = this.state.filteredInvitedMembers;
if (end > this.state.filteredInvitedMembers.length) {
targets = targets.concat(this._getPending3PidInvites());
}
return this._makeMemberTiles(targets.slice(start, end));
- }
+ };
- _getChildCountInvited() {
+ _getChildCountInvited = () => {
return this.state.filteredInvitedMembers.length + (this._getPending3PidInvites() || []).length;
}
diff --git a/src/components/views/rooms/SendMessageComposer.js b/src/components/views/rooms/SendMessageComposer.js
index 6a7b2fc753..25dcf8ccd5 100644
--- a/src/components/views/rooms/SendMessageComposer.js
+++ b/src/components/views/rooms/SendMessageComposer.js
@@ -99,8 +99,8 @@ export default class SendMessageComposer extends React.Component {
static contextType = MatrixClientContext;
- constructor(props) {
- super(props);
+ constructor(props, context) {
+ super(props, context);
this.model = null;
this._editorRef = null;
this.currentlyComposedEditorState = null;
From 517dee413e79559caafb502d526eb48c737a1349 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 29 Aug 2020 12:57:11 +0100
Subject: [PATCH 23/63] Delint
---
src/components/structures/TimelinePanel.js | 2 ++
src/components/structures/auth/Login.js | 3 ++-
src/components/structures/auth/Registration.js | 1 +
src/components/views/auth/RegistrationForm.js | 2 +-
src/components/views/dialogs/BaseDialog.js | 2 +-
src/components/views/dialogs/SetEmailDialog.js | 2 +-
src/components/views/dialogs/SetMxIdDialog.js | 2 +-
src/components/views/elements/EditableText.js | 5 ++++-
src/components/views/elements/Pill.js | 1 +
src/components/views/elements/PowerSelector.js | 1 +
src/components/views/groups/GroupRoomInfo.js | 1 +
src/components/views/rooms/AppsDrawer.js | 1 +
src/components/views/rooms/EventTile.js | 2 ++
13 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js
index d1c977f2ca..daa18bb290 100644
--- a/src/components/structures/TimelinePanel.js
+++ b/src/components/structures/TimelinePanel.js
@@ -221,6 +221,7 @@ class TimelinePanel extends React.Component {
}
// TODO: [REACT-WARNING] Move into constructor
+ // eslint-disable-next-line camelcase
UNSAFE_componentWillMount() {
if (this.props.manageReadReceipts) {
this.updateReadReceiptOnUserActivity();
@@ -233,6 +234,7 @@ class TimelinePanel extends React.Component {
}
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
+ // eslint-disable-next-line camelcase
UNSAFE_componentWillReceiveProps(newProps) {
if (newProps.timelineSet !== this.props.timelineSet) {
// throw new Error("changing timelineSet on a TimelinePanel is not supported");
diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js
index 44a03929cf..9a639ed58a 100644
--- a/src/components/structures/auth/Login.js
+++ b/src/components/structures/auth/Login.js
@@ -52,7 +52,7 @@ _td("Invalid base_url for m.identity_server");
_td("Identity server URL does not appear to be a valid identity server");
_td("General failure");
-/**
+/*
* A wire component which glues together login UI components and Login logic
*/
export default class LoginComponent extends React.Component {
@@ -133,6 +133,7 @@ export default class LoginComponent extends React.Component {
}
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
+ // eslint-disable-next-line camelcase
UNSAFE_componentWillReceiveProps(newProps) {
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js
index 408d97382c..630e04da9c 100644
--- a/src/components/structures/auth/Registration.js
+++ b/src/components/structures/auth/Registration.js
@@ -124,6 +124,7 @@ export default class Registration extends React.Component {
}
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
+ // eslint-disable-next-line camelcase
UNSAFE_componentWillReceiveProps(newProps) {
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
diff --git a/src/components/views/auth/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js
index bd10c829e3..ca3e30bf41 100644
--- a/src/components/views/auth/RegistrationForm.js
+++ b/src/components/views/auth/RegistrationForm.js
@@ -38,7 +38,7 @@ const FIELD_PASSWORD_CONFIRM = 'field_password_confirm';
const PASSWORD_MIN_SCORE = 3; // safely unguessable: moderate protection from offline slow-hash scenario.
-/**
+/*
* A pure UI component which displays a registration form.
*/
export default class RegistrationForm extends React.Component {
diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js
index 55760e54fc..9ba5368ee5 100644
--- a/src/components/views/dialogs/BaseDialog.js
+++ b/src/components/views/dialogs/BaseDialog.js
@@ -27,7 +27,7 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { _t } from "../../../languageHandler";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
-/**
+/*
* Basic container for modal dialogs.
*
* Includes a div for the title, and a keypress handler which cancels the
diff --git a/src/components/views/dialogs/SetEmailDialog.js b/src/components/views/dialogs/SetEmailDialog.js
index 75a6a74352..6514d94dc9 100644
--- a/src/components/views/dialogs/SetEmailDialog.js
+++ b/src/components/views/dialogs/SetEmailDialog.js
@@ -24,7 +24,7 @@ import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';
-/**
+/*
* Prompt the user to set an email address.
*
* On success, `onFinished(true)` is called.
diff --git a/src/components/views/dialogs/SetMxIdDialog.js b/src/components/views/dialogs/SetMxIdDialog.js
index c580575f1a..090def5e54 100644
--- a/src/components/views/dialogs/SetMxIdDialog.js
+++ b/src/components/views/dialogs/SetMxIdDialog.js
@@ -28,7 +28,7 @@ import { SAFE_LOCALPART_REGEX } from '../../../Registration';
// sending a request to the server
const USERNAME_CHECK_DEBOUNCE_MS = 250;
-/**
+/*
* Prompt the user to set a display name.
*
* On success, `onFinished(true, newDisplayName)` is called.
diff --git a/src/components/views/elements/EditableText.js b/src/components/views/elements/EditableText.js
index 5a2c042b83..e28fcffbf8 100644
--- a/src/components/views/elements/EditableText.js
+++ b/src/components/views/elements/EditableText.js
@@ -72,6 +72,7 @@ export default class EditableText extends React.Component {
};
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
+ // eslint-disable-next-line camelcase
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.initialValue !== this.props.initialValue) {
this.value = nextProps.initialValue;
@@ -214,7 +215,9 @@ export default class EditableText extends React.Component {
const {className, editable, initialValue, label, labelClassName} = this.props;
let editableEl;
- if (!editable || (this.state.phase === EditableText.Phases.Display && (label || labelClassName) && !this.value)) {
+ if (!editable || (this.state.phase === EditableText.Phases.Display &&
+ (label || labelClassName) && !this.value)
+ ) {
// show the label
editableEl =
{ label || initialValue }
diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js
index 58537d4865..8247225a2b 100644
--- a/src/components/views/elements/Pill.js
+++ b/src/components/views/elements/Pill.js
@@ -83,6 +83,7 @@ class Pill extends React.Component {
};
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
+ // eslint-disable-next-line camelcase
async UNSAFE_componentWillReceiveProps(nextProps) {
let resourceId;
let prefix;
diff --git a/src/components/views/elements/PowerSelector.js b/src/components/views/elements/PowerSelector.js
index 4d00832d8d..e5f217dd90 100644
--- a/src/components/views/elements/PowerSelector.js
+++ b/src/components/views/elements/PowerSelector.js
@@ -62,6 +62,7 @@ export default class PowerSelector extends React.Component {
}
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
+ // eslint-disable-next-line camelcase
UNSAFE_componentWillReceiveProps(newProps) {
this._initStateFromProps(newProps);
}
diff --git a/src/components/views/groups/GroupRoomInfo.js b/src/components/views/groups/GroupRoomInfo.js
index e891d553aa..50bbd26029 100644
--- a/src/components/views/groups/GroupRoomInfo.js
+++ b/src/components/views/groups/GroupRoomInfo.js
@@ -45,6 +45,7 @@ export default class GroupRoomInfo extends React.Component {
}
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
+ // eslint-disable-next-line camelcase
UNSAFE_componentWillReceiveProps(newProps) {
if (newProps.groupId !== this.props.groupId) {
this._unregisterGroupStore(this.props.groupId);
diff --git a/src/components/views/rooms/AppsDrawer.js b/src/components/views/rooms/AppsDrawer.js
index ed76e9137a..50f53d20c2 100644
--- a/src/components/views/rooms/AppsDrawer.js
+++ b/src/components/views/rooms/AppsDrawer.js
@@ -71,6 +71,7 @@ export default class AppsDrawer extends React.Component {
}
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
+ // eslint-disable-next-line camelcase
UNSAFE_componentWillReceiveProps(newProps) {
// Room has changed probably, update apps
this._updateApps();
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index 608505adb5..647ef585d7 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -240,6 +240,7 @@ export default class EventTile extends React.Component {
}
// TODO: [REACT-WARNING] Move into constructor
+ // eslint-disable-next-line camelcase
UNSAFE_componentWillMount() {
this._verifyEvent(this.props.mxEvent);
}
@@ -256,6 +257,7 @@ export default class EventTile extends React.Component {
}
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
+ // eslint-disable-next-line camelcase
UNSAFE_componentWillReceiveProps(nextProps) {
// re-check the sender verification as outgoing events progress through
// the send process.
From c120458b813617b5e98864470a855e4acc0c99c0 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 29 Aug 2020 13:02:45 +0100
Subject: [PATCH 24/63] fix test stub
---
test/components/stub-component.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/components/stub-component.js b/test/components/stub-component.js
index 72ffde3483..e242c06707 100644
--- a/test/components/stub-component.js
+++ b/test/components/stub-component.js
@@ -6,7 +6,7 @@ import React from 'react';
export default function({displayName = "StubComponent", render} = {}) {
if (!render) {
render = function() {
- return
{ this.displayName }
;
+ return
{ displayName }
;
};
}
From 646c9f1a83645db0e596e0472183c681e503930d Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 29 Aug 2020 13:19:05 +0100
Subject: [PATCH 25/63] Fix this contexts
---
src/components/structures/auth/Login.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js
index 9a639ed58a..53769fb5a6 100644
--- a/src/components/structures/auth/Login.js
+++ b/src/components/structures/auth/Login.js
@@ -569,7 +569,7 @@ export default class LoginComponent extends React.Component {
return null;
}
- _renderPasswordStep() {
+ _renderPasswordStep = () => {
const PasswordLogin = sdk.getComponent('auth.PasswordLogin');
let onEditServerDetailsClick = null;
@@ -598,9 +598,9 @@ export default class LoginComponent extends React.Component {
busy={this.props.isSyncing || this.state.busyLoggingIn}
/>
);
- }
+ };
- _renderSsoStep(loginType) {
+ _renderSsoStep = loginType => {
const SignInToText = sdk.getComponent('views.auth.SignInToText');
let onEditServerDetailsClick = null;
@@ -629,7 +629,7 @@ export default class LoginComponent extends React.Component {
/>
);
- }
+ };
render() {
const Loader = sdk.getComponent("elements.Spinner");
From 85f2f46d133905661cca0b2244ee9bb9e6ce1fc9 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 29 Aug 2020 13:38:28 +0100
Subject: [PATCH 26/63] fix tests
---
src/components/structures/InteractiveAuth.js | 21 +++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/src/components/structures/InteractiveAuth.js b/src/components/structures/InteractiveAuth.js
index 4c186bce30..c8fcd7e9ca 100644
--- a/src/components/structures/InteractiveAuth.js
+++ b/src/components/structures/InteractiveAuth.js
@@ -110,6 +110,18 @@ export default class InteractiveAuthComponent extends React.Component {
requestEmailToken: this._requestEmailToken,
});
+ this._intervalId = null;
+ if (this.props.poll) {
+ this._intervalId = setInterval(() => {
+ this._authLogic.poll();
+ }, 2000);
+ }
+
+ this._stageComponent = createRef();
+ }
+
+ // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
+ UNSAFE_componentWillMount() { // eslint-disable-line camelcase
this._authLogic.attemptAuth().then((result) => {
const extra = {
emailSid: this._authLogic.getEmailSid(),
@@ -128,15 +140,6 @@ export default class InteractiveAuthComponent extends React.Component {
errorText: msg,
});
});
-
- this._intervalId = null;
- if (this.props.poll) {
- this._intervalId = setInterval(() => {
- this._authLogic.poll();
- }, 2000);
- }
-
- this._stageComponent = createRef();
}
componentWillUnmount() {
From da97d8885b8a9145c933d7cce7c713446f817f6c Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 29 Aug 2020 13:51:43 +0100
Subject: [PATCH 27/63] Fix react error about functional components can't take
props
---
src/components/views/messages/UnknownBody.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/components/views/messages/UnknownBody.js b/src/components/views/messages/UnknownBody.js
index 6c00921b45..786facc340 100644
--- a/src/components/views/messages/UnknownBody.js
+++ b/src/components/views/messages/UnknownBody.js
@@ -15,13 +15,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import React from "react";
+import React, {forwardRef} from "react";
-export default ({mxEvent}) => {
+export default forwardRef(({mxEvent}, ref) => {
const text = mxEvent.getContent().body;
return (
-
+
{ text }
);
-};
+});
From 3c5eb1f42ce7d892fe916a7b89ba48cbd4a095fa Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Sat, 29 Aug 2020 18:28:15 +0100
Subject: [PATCH 28/63] fix Registration Form
---
src/components/views/auth/RegistrationForm.js | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/components/views/auth/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js
index ca3e30bf41..c07486d3bd 100644
--- a/src/components/views/auth/RegistrationForm.js
+++ b/src/components/views/auth/RegistrationForm.js
@@ -232,12 +232,12 @@ export default class RegistrationForm extends React.Component {
};
onEmailValidate = async fieldState => {
- const result = await RegistrationForm.validateEmailRules(fieldState);
+ const result = await this.validateEmailRules(fieldState);
this.markFieldValid(FIELD_EMAIL, result.valid);
return result;
};
- static validateEmailRules = withValidation({
+ validateEmailRules = withValidation({
description: () => _t("Use an email address to recover your account"),
rules: [
{
@@ -272,12 +272,12 @@ export default class RegistrationForm extends React.Component {
};
onPasswordConfirmValidate = async fieldState => {
- const result = await RegistrationForm.validatePasswordConfirmRules(fieldState);
+ const result = await this.validatePasswordConfirmRules(fieldState);
this.markFieldValid(FIELD_PASSWORD_CONFIRM, result.valid);
return result;
};
- static validatePasswordConfirmRules = withValidation({
+ validatePasswordConfirmRules = withValidation({
rules: [
{
key: "required",
@@ -308,12 +308,12 @@ export default class RegistrationForm extends React.Component {
};
onPhoneNumberValidate = async fieldState => {
- const result = await RegistrationForm.validatePhoneNumberRules(fieldState);
+ const result = await this.validatePhoneNumberRules(fieldState);
this.markFieldValid(FIELD_PHONE_NUMBER, result.valid);
return result;
};
- static validatePhoneNumberRules = withValidation({
+ validatePhoneNumberRules = withValidation({
description: () => _t("Other users can invite you to rooms using your contact details"),
rules: [
{
@@ -338,12 +338,12 @@ export default class RegistrationForm extends React.Component {
};
onUsernameValidate = async fieldState => {
- const result = await RegistrationForm.validateUsernameRules(fieldState);
+ const result = await this.validateUsernameRules(fieldState);
this.markFieldValid(FIELD_USERNAME, result.valid);
return result;
};
- static validateUsernameRules = withValidation({
+ validateUsernameRules = withValidation({
description: () => _t("Use lowercase letters, numbers, dashes and underscores only"),
rules: [
{
From 93d67a668943a6e511e1735041e8a3b31a1e6bd9 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Mon, 31 Aug 2020 10:12:12 -0600
Subject: [PATCH 29/63] Wire up members button to member view
Ideally this would open up the group members panel, but that's exceedingly difficult. Instead, we switch to the general chat and rename the button to be a bit more helpful.
---
src/RoomInvite.js | 10 +---------
src/components/structures/UserMenu.tsx | 23 ++++++++++++++++++++++-
src/components/views/rooms/MemberList.js | 13 ++++++++++++-
src/i18n/strings/en_EN.json | 1 +
src/stores/CommunityPrototypeStore.ts | 15 +++++++++++++++
src/stores/TagOrderStore.js | 1 +
6 files changed, 52 insertions(+), 11 deletions(-)
diff --git a/src/RoomInvite.js b/src/RoomInvite.js
index ed3fe1452e..b82cc0a8e7 100644
--- a/src/RoomInvite.js
+++ b/src/RoomInvite.js
@@ -67,15 +67,7 @@ export function showCommunityRoomInviteDialog(roomId, communityName) {
}
export function showCommunityInviteDialog(communityId) {
- const rooms = GroupStore.getGroupRooms(communityId)
- .map(r => MatrixClientPeg.get().getRoom(r.roomId))
- .filter(r => !!r);
- let chat = rooms.find(r => {
- const idState = r.currentState.getStateEvents("im.vector.general_chat", "");
- if (!idState || idState.getContent()['groupId'] !== communityId) return false;
- return true;
- });
- if (!chat) chat = rooms[0];
+ const chat = CommunityPrototypeStore.instance.getGeneralChat(communityId);
if (chat) {
const name = CommunityPrototypeStore.instance.getCommunityName(communityId);
showCommunityRoomInviteDialog(chat.roomId, name);
diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx
index 8e62402141..a583af2603 100644
--- a/src/components/structures/UserMenu.tsx
+++ b/src/components/structures/UserMenu.tsx
@@ -46,6 +46,9 @@ import { CommunityPrototypeStore } from "../../stores/CommunityPrototypeStore";
import * as fbEmitter from "fbemitter";
import TagOrderStore from "../../stores/TagOrderStore";
import { showCommunityInviteDialog } from "../../RoomInvite";
+import dis from "../../dispatcher/dispatcher";
+import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
+import ErrorDialog from "../views/dialogs/ErrorDialog";
interface IProps {
isMinimized: boolean;
@@ -211,7 +214,25 @@ export default class UserMenu extends React.Component {
ev.preventDefault();
ev.stopPropagation();
- console.log("TODO@onCommunityMembersClick");
+ // We'd ideally just pop open a right panel with the member list, but the current
+ // way the right panel is structured makes this exceedingly difficult. Instead, we'll
+ // switch to the general room and open the member list there as it should be in sync
+ // anyways.
+ const chat = CommunityPrototypeStore.instance.getGeneralChat(TagOrderStore.getSelectedPrototypeTag());
+ if (chat) {
+ dis.dispatch({
+ action: 'view_room',
+ room_id: chat.roomId,
+ }, true);
+ dis.dispatch({action: Action.SetRightPanelPhase, phase: RightPanelPhases.RoomMemberList});
+ } else {
+ // "This should never happen" clauses go here for the prototype.
+ Modal.createTrackedDialog('Failed to find general chat', '', ErrorDialog, {
+ title: _t('Failed to find the general chat for this community'),
+ description: _t("Failed to find the general chat for this community"),
+ });
+ }
+ this.setState({contextMenuPosition: null}); // also close the menu
};
private onCommunityInviteClick = (ev: ButtonEvent) => {
diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js
index e2d7e3f8e0..06ce8ddda8 100644
--- a/src/components/views/rooms/MemberList.js
+++ b/src/components/views/rooms/MemberList.js
@@ -27,6 +27,8 @@ import rate_limited_func from "../../../ratelimitedfunc";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import * as sdk from "../../../index";
import CallHandler from "../../../CallHandler";
+import TagOrderStore from "../../../stores/TagOrderStore";
+import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
const INITIAL_LOAD_NUM_MEMBERS = 30;
const INITIAL_LOAD_NUM_INVITED = 5;
@@ -464,10 +466,19 @@ export default createReactClass({
}
}
+ let inviteButtonText = _t("Invite to this room");
+ const communityId = TagOrderStore.getSelectedPrototypeTag();
+ if (communityId) {
+ const chat = CommunityPrototypeStore.instance.getGeneralChat(communityId);
+ if (chat && chat.roomId === this.props.roomId) {
+ inviteButtonText = _t("Invite to this community");
+ }
+ }
+
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
inviteButton =
- { _t('Invite to this room') }
+ { inviteButtonText }
;
}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index c798c8eff1..d8e159244f 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -2121,6 +2121,7 @@
"Uploading %(filename)s and %(count)s others|other": "Uploading %(filename)s and %(count)s others",
"Uploading %(filename)s and %(count)s others|zero": "Uploading %(filename)s",
"Uploading %(filename)s and %(count)s others|one": "Uploading %(filename)s and %(count)s other",
+ "Failed to find the general chat for this community": "Failed to find the general chat for this community",
"Notification settings": "Notification settings",
"Security & privacy": "Security & privacy",
"All settings": "All settings",
diff --git a/src/stores/CommunityPrototypeStore.ts b/src/stores/CommunityPrototypeStore.ts
index eec0a8aab8..1dfcbb766a 100644
--- a/src/stores/CommunityPrototypeStore.ts
+++ b/src/stores/CommunityPrototypeStore.ts
@@ -24,6 +24,8 @@ import * as utils from "matrix-js-sdk/src/utils";
import { UPDATE_EVENT } from "./AsyncStore";
import FlairStore from "./FlairStore";
import TagOrderStore from "./TagOrderStore";
+import { MatrixClientPeg } from "../MatrixClientPeg";
+import GroupStore from "./GroupStore";
interface IState {
// nothing of value - we use account data
@@ -54,6 +56,19 @@ export class CommunityPrototypeStore extends AsyncStoreWithClient {
return profile?.name || communityId;
}
+ public getGeneralChat(communityId: string): Room {
+ const rooms = GroupStore.getGroupRooms(communityId)
+ .map(r => MatrixClientPeg.get().getRoom(r.roomId))
+ .filter(r => !!r);
+ let chat = rooms.find(r => {
+ const idState = r.currentState.getStateEvents("im.vector.general_chat", "");
+ if (!idState || idState.getContent()['groupId'] !== communityId) return false;
+ return true;
+ });
+ if (!chat) chat = rooms[0];
+ return chat; // can be null
+ }
+
protected async onAction(payload: ActionPayload): Promise {
if (!this.matrixClient || !SettingsStore.getValue("feature_communities_v2_prototypes")) {
return;
diff --git a/src/stores/TagOrderStore.js b/src/stores/TagOrderStore.js
index 2eb35e6dc2..6651d207a1 100644
--- a/src/stores/TagOrderStore.js
+++ b/src/stores/TagOrderStore.js
@@ -168,6 +168,7 @@ class TagOrderStore extends Store {
if (!allowMultiple && newTags.length === 1) {
// We're in prototype behaviour: select the general chat for the community
+ // XXX: This is duplicated with the CommunityPrototypeStore as a cyclical reference
const rooms = GroupStore.getGroupRooms(newTags[0])
.map(r => MatrixClientPeg.get().getRoom(r.roomId))
.filter(r => !!r);
From 724e3f690518a7215b1b3bbfe7f05e8c019727b4 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Mon, 31 Aug 2020 10:19:05 -0600
Subject: [PATCH 30/63] Run all selected prototype community logic through one
store
---
src/components/structures/UserMenu.tsx | 4 ++--
src/components/views/dialogs/CreateRoomDialog.js | 9 ++++-----
src/components/views/dialogs/InviteDialog.js | 9 ++++-----
src/components/views/rooms/MemberList.js | 10 +++-------
src/components/views/rooms/RoomList.tsx | 4 ++--
src/i18n/strings/en_EN.json | 2 +-
src/stores/CommunityPrototypeStore.ts | 16 +++++++++++++++-
src/stores/TagOrderStore.js | 7 -------
8 files changed, 31 insertions(+), 30 deletions(-)
diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx
index a583af2603..baa5d661a3 100644
--- a/src/components/structures/UserMenu.tsx
+++ b/src/components/structures/UserMenu.tsx
@@ -218,7 +218,7 @@ export default class UserMenu extends React.Component {
// way the right panel is structured makes this exceedingly difficult. Instead, we'll
// switch to the general room and open the member list there as it should be in sync
// anyways.
- const chat = CommunityPrototypeStore.instance.getGeneralChat(TagOrderStore.getSelectedPrototypeTag());
+ const chat = CommunityPrototypeStore.instance.getSelectedCommunityGeneralChat();
if (chat) {
dis.dispatch({
action: 'view_room',
@@ -239,7 +239,7 @@ export default class UserMenu extends React.Component {
ev.preventDefault();
ev.stopPropagation();
- showCommunityInviteDialog(TagOrderStore.getSelectedPrototypeTag());
+ showCommunityInviteDialog(CommunityPrototypeStore.instance.getSelectedCommunityId());
this.setState({contextMenuPosition: null}); // also close the menu
};
diff --git a/src/components/views/dialogs/CreateRoomDialog.js b/src/components/views/dialogs/CreateRoomDialog.js
index bdd3de07c0..5d370af341 100644
--- a/src/components/views/dialogs/CreateRoomDialog.js
+++ b/src/components/views/dialogs/CreateRoomDialog.js
@@ -25,7 +25,6 @@ import { _t } from '../../../languageHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import {Key} from "../../../Keyboard";
import {privateShouldBeEncrypted} from "../../../createRoom";
-import TagOrderStore from "../../../stores/TagOrderStore";
import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
export default createReactClass({
@@ -72,8 +71,8 @@ export default createReactClass({
opts.encryption = this.state.isEncrypted;
}
- if (TagOrderStore.getSelectedPrototypeTag()) {
- opts.associatedWithCommunity = TagOrderStore.getSelectedPrototypeTag();
+ if (CommunityPrototypeStore.instance.getSelectedCommunityId()) {
+ opts.associatedWithCommunity = CommunityPrototypeStore.instance.getSelectedCommunityId();
}
return opts;
@@ -198,7 +197,7 @@ export default createReactClass({
"Private rooms can be found and joined by invitation only. Public rooms can be " +
"found and joined by anyone.",
)};
- if (TagOrderStore.getSelectedPrototypeTag()) {
+ if (CommunityPrototypeStore.instance.getSelectedCommunityId()) {
publicPrivateLabel = {_t(
"Private rooms can be found and joined by invitation only. Public rooms can be " +
"found and joined by anyone in this community.",
@@ -239,7 +238,7 @@ export default createReactClass({
}
let title = this.state.isPublic ? _t('Create a public room') : _t('Create a private room');
- if (TagOrderStore.getSelectedPrototypeTag()) {
+ if (CommunityPrototypeStore.instance.getSelectedCommunityId()) {
const name = CommunityPrototypeStore.instance.getSelectedCommunityName();
title = _t("Create a room in %(communityName)s", {communityName: name});
}
diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js
index c2fd7e5b0e..80d8f1fc2c 100644
--- a/src/components/views/dialogs/InviteDialog.js
+++ b/src/components/views/dialogs/InviteDialog.js
@@ -37,7 +37,6 @@ import {Key} from "../../../Keyboard";
import {Action} from "../../../dispatcher/actions";
import {DefaultTagID} from "../../../stores/room-list/models";
import RoomListStore from "../../../stores/room-list/RoomListStore";
-import TagOrderStore from "../../../stores/TagOrderStore";
import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
@@ -913,7 +912,7 @@ export default class InviteDialog extends React.PureComponent {
_onCommunityInviteClick = (e) => {
this.props.onFinished();
- showCommunityInviteDialog(TagOrderStore.getSelectedPrototypeTag());
+ showCommunityInviteDialog(CommunityPrototypeStore.instance.getSelectedCommunityId());
};
_renderSection(kind: "recents"|"suggestions") {
@@ -924,8 +923,8 @@ export default class InviteDialog extends React.PureComponent {
let sectionName = kind === 'recents' ? _t("Recent Conversations") : _t("Suggestions");
let sectionSubname = null;
- if (kind === 'suggestions' && TagOrderStore.getSelectedPrototypeTag()) {
- const communityName = CommunityPrototypeStore.instance.getCommunityName(TagOrderStore.getSelectedPrototypeTag());
+ if (kind === 'suggestions' && CommunityPrototypeStore.instance.getSelectedCommunityId()) {
+ const communityName = CommunityPrototypeStore.instance.getSelectedCommunityName();
sectionSubname = _t("May include members not in %(communityName)s", {communityName});
}
@@ -1097,7 +1096,7 @@ export default class InviteDialog extends React.PureComponent {
return {userId} ;
}},
);
- if (TagOrderStore.getSelectedPrototypeTag()) {
+ if (CommunityPrototypeStore.instance.getSelectedCommunityId()) {
const communityName = CommunityPrototypeStore.instance.getSelectedCommunityName();
helpText = _t(
"Start a conversation with someone using their name, username (like ) or email address. " +
diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js
index 06ce8ddda8..15b629921c 100644
--- a/src/components/views/rooms/MemberList.js
+++ b/src/components/views/rooms/MemberList.js
@@ -27,7 +27,6 @@ import rate_limited_func from "../../../ratelimitedfunc";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import * as sdk from "../../../index";
import CallHandler from "../../../CallHandler";
-import TagOrderStore from "../../../stores/TagOrderStore";
import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
const INITIAL_LOAD_NUM_MEMBERS = 30;
@@ -467,12 +466,9 @@ export default createReactClass({
}
let inviteButtonText = _t("Invite to this room");
- const communityId = TagOrderStore.getSelectedPrototypeTag();
- if (communityId) {
- const chat = CommunityPrototypeStore.instance.getGeneralChat(communityId);
- if (chat && chat.roomId === this.props.roomId) {
- inviteButtonText = _t("Invite to this community");
- }
+ const chat = CommunityPrototypeStore.instance.getSelectedCommunityGeneralChat();
+ if (chat && chat.roomId === this.props.roomId) {
+ inviteButtonText = _t("Invite to this community");
}
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx
index 92c5982276..72e016d8e7 100644
--- a/src/components/views/rooms/RoomList.tsx
+++ b/src/components/views/rooms/RoomList.tsx
@@ -45,7 +45,7 @@ import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays";
import { objectShallowClone, objectWithOnly } from "../../../utils/objects";
import { IconizedContextMenuOption, IconizedContextMenuOptionList } from "../context_menus/IconizedContextMenu";
import AccessibleButton from "../elements/AccessibleButton";
-import TagOrderStore from "../../../stores/TagOrderStore";
+import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
interface IProps {
onKeyDown: (ev: React.KeyboardEvent) => void;
@@ -130,7 +130,7 @@ const TAG_AESTHETICS: {
}}
/>
{
return CommunityPrototypeStore.internalInstance;
}
+ public getSelectedCommunityId(): string {
+ if (SettingsStore.getValue("feature_communities_v2_prototypes")) {
+ return TagOrderStore.getSelectedTags()[0];
+ }
+ return null; // no selection as far as this function is concerned
+ }
+
public getSelectedCommunityName(): string {
- return CommunityPrototypeStore.instance.getCommunityName(TagOrderStore.getSelectedPrototypeTag());
+ return CommunityPrototypeStore.instance.getCommunityName(this.getSelectedCommunityId());
+ }
+
+ public getSelectedCommunityGeneralChat(): Room {
+ const communityId = this.getSelectedCommunityId();
+ if (communityId) {
+ return this.getGeneralChat(communityId);
+ }
}
public getCommunityName(communityId: string): string {
diff --git a/src/stores/TagOrderStore.js b/src/stores/TagOrderStore.js
index 6651d207a1..3dfdc5feaf 100644
--- a/src/stores/TagOrderStore.js
+++ b/src/stores/TagOrderStore.js
@@ -286,13 +286,6 @@ class TagOrderStore extends Store {
getSelectedTags() {
return this._state.selectedTags;
}
-
- getSelectedPrototypeTag() {
- if (SettingsStore.getValue("feature_communities_v2_prototypes")) {
- return this.getSelectedTags()[0];
- }
- return null; // no selection as far as this function is concerned
- }
}
if (global.singletonTagOrderStore === undefined) {
From 133f981fa8cb4b1efd55c4263e70e9995c3f6c39 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Mon, 31 Aug 2020 10:22:29 -0600
Subject: [PATCH 31/63] Run the tag selection behaviour through the prototype
store too
---
src/stores/CommunityPrototypeStore.ts | 10 ++++++++++
src/stores/TagOrderStore.js | 20 --------------------
2 files changed, 10 insertions(+), 20 deletions(-)
diff --git a/src/stores/CommunityPrototypeStore.ts b/src/stores/CommunityPrototypeStore.ts
index 1bc0a46376..501ebfde17 100644
--- a/src/stores/CommunityPrototypeStore.ts
+++ b/src/stores/CommunityPrototypeStore.ts
@@ -26,6 +26,7 @@ import FlairStore from "./FlairStore";
import TagOrderStore from "./TagOrderStore";
import { MatrixClientPeg } from "../MatrixClientPeg";
import GroupStore from "./GroupStore";
+import dis from "../dispatcher/dispatcher";
interface IState {
// nothing of value - we use account data
@@ -111,6 +112,15 @@ export class CommunityPrototypeStore extends AsyncStoreWithClient {
if (payload.event_type.startsWith("im.vector.group_info.")) {
this.emit(UPDATE_EVENT, payload.event_type.substring("im.vector.group_info.".length));
}
+ } else if (payload.action === "select_tag") {
+ // Automatically select the general chat when switching communities
+ const chat = this.getGeneralChat(payload.tag);
+ if (chat) {
+ dis.dispatch({
+ action: 'view_room',
+ room_id: chat.roomId,
+ });
+ }
}
}
diff --git a/src/stores/TagOrderStore.js b/src/stores/TagOrderStore.js
index 3dfdc5feaf..2b72a963b0 100644
--- a/src/stores/TagOrderStore.js
+++ b/src/stores/TagOrderStore.js
@@ -166,26 +166,6 @@ class TagOrderStore extends Store {
selectedTags: newTags,
});
- if (!allowMultiple && newTags.length === 1) {
- // We're in prototype behaviour: select the general chat for the community
- // XXX: This is duplicated with the CommunityPrototypeStore as a cyclical reference
- const rooms = GroupStore.getGroupRooms(newTags[0])
- .map(r => MatrixClientPeg.get().getRoom(r.roomId))
- .filter(r => !!r);
- let chat = rooms.find(r => {
- const idState = r.currentState.getStateEvents("im.vector.general_chat", "");
- if (!idState || idState.getContent()['groupId'] !== newTags[0]) return false;
- return true;
- });
- if (!chat) chat = rooms[0];
- if (chat) {
- dis.dispatch({
- action: 'view_room',
- room_id: chat.roomId,
- });
- }
- }
-
Analytics.trackEvent('FilterStore', 'select_tag');
}
break;
From fdbaddbace0495353020d2b02c81183c08148ff8 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Mon, 31 Aug 2020 10:52:08 -0600
Subject: [PATCH 32/63] Add a simple edit dialog for communities
---
res/css/_components.scss | 1 +
.../_EditCommunityPrototypeDialog.scss | 77 ++++++++
src/components/structures/UserMenu.tsx | 6 +-
.../dialogs/EditCommunityPrototypeDialog.tsx | 166 ++++++++++++++++++
src/i18n/strings/en_EN.json | 2 +
src/stores/CommunityPrototypeStore.ts | 4 +
6 files changed, 255 insertions(+), 1 deletion(-)
create mode 100644 res/css/views/dialogs/_EditCommunityPrototypeDialog.scss
create mode 100644 src/components/views/dialogs/EditCommunityPrototypeDialog.tsx
diff --git a/res/css/_components.scss b/res/css/_components.scss
index 24d2ffa2b0..45ed6b3300 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -68,6 +68,7 @@
@import "./views/dialogs/_CreateRoomDialog.scss";
@import "./views/dialogs/_DeactivateAccountDialog.scss";
@import "./views/dialogs/_DevtoolsDialog.scss";
+@import "./views/dialogs/_EditCommunityPrototypeDialog.scss";
@import "./views/dialogs/_GroupAddressPicker.scss";
@import "./views/dialogs/_IncomingSasDialog.scss";
@import "./views/dialogs/_InviteDialog.scss";
diff --git a/res/css/views/dialogs/_EditCommunityPrototypeDialog.scss b/res/css/views/dialogs/_EditCommunityPrototypeDialog.scss
new file mode 100644
index 0000000000..75a56bf6b3
--- /dev/null
+++ b/res/css/views/dialogs/_EditCommunityPrototypeDialog.scss
@@ -0,0 +1,77 @@
+/*
+Copyright 2020 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.
+*/
+
+// XXX: many of these styles are shared with the create dialog
+.mx_EditCommunityPrototypeDialog {
+ &.mx_Dialog_fixedWidth {
+ width: 360px;
+ }
+
+ .mx_Dialog_content {
+ margin-bottom: 12px;
+
+ .mx_AccessibleButton.mx_AccessibleButton_kind_primary {
+ display: block;
+ height: 32px;
+ font-size: $font-16px;
+ line-height: 32px;
+ }
+
+ .mx_EditCommunityPrototypeDialog_rowAvatar {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ }
+
+ .mx_EditCommunityPrototypeDialog_avatarContainer {
+ margin-top: 20px;
+ margin-bottom: 20px;
+
+ .mx_EditCommunityPrototypeDialog_avatar,
+ .mx_EditCommunityPrototypeDialog_placeholderAvatar {
+ width: 96px;
+ height: 96px;
+ border-radius: 96px;
+ }
+
+ .mx_EditCommunityPrototypeDialog_placeholderAvatar {
+ background-color: #368bd6; // hardcoded for both themes
+
+ &::before {
+ display: inline-block;
+ background-color: #fff; // hardcoded because the background is
+ mask-repeat: no-repeat;
+ mask-size: 96px;
+ width: 96px;
+ height: 96px;
+ mask-position: center;
+ content: '';
+ vertical-align: middle;
+ mask-image: url('$(res)/img/element-icons/add-photo.svg');
+ }
+ }
+ }
+
+ .mx_EditCommunityPrototypeDialog_tip {
+ margin-left: 20px;
+
+ & > b, & > span {
+ display: block;
+ color: $muted-fg-color;
+ }
+ }
+ }
+}
diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx
index baa5d661a3..93b1e2f820 100644
--- a/src/components/structures/UserMenu.tsx
+++ b/src/components/structures/UserMenu.tsx
@@ -49,6 +49,7 @@ import { showCommunityInviteDialog } from "../../RoomInvite";
import dis from "../../dispatcher/dispatcher";
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
import ErrorDialog from "../views/dialogs/ErrorDialog";
+import EditCommunityPrototypeDialog from "../views/dialogs/EditCommunityPrototypeDialog";
interface IProps {
isMinimized: boolean;
@@ -207,7 +208,10 @@ export default class UserMenu extends React.Component {
ev.preventDefault();
ev.stopPropagation();
- console.log("TODO@onCommunitySettingsClick");
+ Modal.createTrackedDialog('Edit Community', '', EditCommunityPrototypeDialog, {
+ communityId: CommunityPrototypeStore.instance.getSelectedCommunityId(),
+ });
+ this.setState({contextMenuPosition: null}); // also close the menu
};
private onCommunityMembersClick = (ev: ButtonEvent) => {
diff --git a/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx b/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx
new file mode 100644
index 0000000000..66b49ea7b7
--- /dev/null
+++ b/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx
@@ -0,0 +1,166 @@
+/*
+Copyright 2020 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, { ChangeEvent } from 'react';
+import BaseDialog from "./BaseDialog";
+import { _t } from "../../../languageHandler";
+import { IDialogProps } from "./IDialogProps";
+import Field from "../elements/Field";
+import AccessibleButton from "../elements/AccessibleButton";
+import { MatrixClientPeg } from "../../../MatrixClientPeg";
+import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
+import FlairStore from "../../../stores/FlairStore";
+
+interface IProps extends IDialogProps {
+ communityId: string;
+}
+
+interface IState {
+ name: string;
+ error: string;
+ busy: boolean;
+ currentAvatarUrl: string;
+ avatarFile: File;
+ avatarPreview: string;
+}
+
+// XXX: This is a lot of duplication from the create dialog, just in a different shape
+export default class EditCommunityPrototypeDialog extends React.PureComponent {
+ private avatarUploadRef: React.RefObject = React.createRef();
+
+ constructor(props: IProps) {
+ super(props);
+
+ const profile = CommunityPrototypeStore.instance.getCommunityProfile(props.communityId);
+
+ this.state = {
+ name: profile?.name || "",
+ error: null,
+ busy: false,
+ avatarFile: null,
+ avatarPreview: null,
+ currentAvatarUrl: profile?.avatarUrl,
+ };
+ }
+
+ private onNameChange = (ev: ChangeEvent) => {
+ this.setState({name: ev.target.value});
+ };
+
+ private onSubmit = async (ev) => {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ if (this.state.busy) return;
+
+ // We'll create the community now to see if it's taken, leaving it active in
+ // the background for the user to look at while they invite people.
+ this.setState({busy: true});
+ try {
+ let avatarUrl = this.state.currentAvatarUrl || ""; // must be a string for synapse to accept it
+ if (this.state.avatarFile) {
+ avatarUrl = await MatrixClientPeg.get().uploadContent(this.state.avatarFile);
+ }
+
+ await MatrixClientPeg.get().setGroupProfile(this.props.communityId, {
+ name: this.state.name,
+ avatar_url: avatarUrl,
+ });
+
+ // ask the flair store to update the profile too
+ await FlairStore.refreshGroupProfile(MatrixClientPeg.get(), this.props.communityId);
+
+ // we did it, so close the dialog
+ this.props.onFinished(true);
+ } catch (e) {
+ console.error(e);
+ this.setState({
+ busy: false,
+ error: _t("There was an error updating your community. The server is unable to process your request."),
+ });
+ }
+ };
+
+ private onAvatarChanged = (e: ChangeEvent) => {
+ if (!e.target.files || !e.target.files.length) {
+ this.setState({avatarFile: null});
+ } else {
+ this.setState({busy: true});
+ const file = e.target.files[0];
+ const reader = new FileReader();
+ reader.onload = (ev: ProgressEvent) => {
+ this.setState({avatarFile: file, busy: false, avatarPreview: ev.target.result as string});
+ };
+ reader.readAsDataURL(file);
+ }
+ };
+
+ private onChangeAvatar = () => {
+ if (this.avatarUploadRef.current) this.avatarUploadRef.current.click();
+ };
+
+ public render() {
+ let preview = ;
+ if (!this.state.avatarPreview) {
+ if (this.state.currentAvatarUrl) {
+ const url = MatrixClientPeg.get().mxcUrlToHttp(this.state.currentAvatarUrl);
+ preview = ;
+ } else {
+ preview =
+ }
+ }
+
+ return (
+
+
+
+ );
+ }
+}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index c43fc9d878..9265aec319 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -1687,6 +1687,8 @@
"Verification Requests": "Verification Requests",
"Toolbox": "Toolbox",
"Developer Tools": "Developer Tools",
+ "There was an error updating your community. The server is unable to process your request.": "There was an error updating your community. The server is unable to process your request.",
+ "Update community": "Update community",
"An error has occurred.": "An error has occurred.",
"Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.",
"Verifying this user will mark their session as trusted, and also mark your session as trusted to them.": "Verifying this user will mark their session as trusted, and also mark your session as trusted to them.",
diff --git a/src/stores/CommunityPrototypeStore.ts b/src/stores/CommunityPrototypeStore.ts
index 501ebfde17..db747d105c 100644
--- a/src/stores/CommunityPrototypeStore.ts
+++ b/src/stores/CommunityPrototypeStore.ts
@@ -71,6 +71,10 @@ export class CommunityPrototypeStore extends AsyncStoreWithClient {
return profile?.name || communityId;
}
+ public getCommunityProfile(communityId: string): { name?: string, avatarUrl?: string } {
+ return FlairStore.getGroupProfileCachedFast(this.matrixClient, communityId);
+ }
+
public getGeneralChat(communityId: string): Room {
const rooms = GroupStore.getGroupRooms(communityId)
.map(r => MatrixClientPeg.get().getRoom(r.roomId))
From 7f7414ed5afe0817f67e71d22571dadcdbf82175 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Mon, 31 Aug 2020 10:59:37 -0600
Subject: [PATCH 33/63] Appease the linter
---
src/stores/FlairStore.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/stores/FlairStore.js b/src/stores/FlairStore.js
index 67d9616741..cb181c5c69 100644
--- a/src/stores/FlairStore.js
+++ b/src/stores/FlairStore.js
@@ -152,9 +152,9 @@ class FlairStore extends EventEmitter {
* Gets the profile for the given group if known, otherwise returns null.
* This triggers `getGroupProfileCached` if needed, though the result of the
* call will not be returned by this function.
- * @param matrixClient The matrix client to use to fetch the profile, if needed.
- * @param groupId The group ID to get the profile for.
- * @returns The profile if known, otherwise null.
+ * @param matrixClient {MatrixClient} The matrix client to use to fetch the profile, if needed.
+ * @param groupId {string} The group ID to get the profile for.
+ * @returns {*} The profile if known, otherwise null.
*/
getGroupProfileCachedFast(matrixClient, groupId) {
if (!matrixClient || !groupId) return null;
From b4f62e9c8863d5a2bef077d567011ad81284ae9a Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Mon, 31 Aug 2020 11:07:29 -0600
Subject: [PATCH 34/63] use valid jsdoc
---
src/RoomInvite.js | 1 -
src/stores/FlairStore.js | 4 ++--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/RoomInvite.js b/src/RoomInvite.js
index b82cc0a8e7..7eb7f5dbb2 100644
--- a/src/RoomInvite.js
+++ b/src/RoomInvite.js
@@ -24,7 +24,6 @@ import * as sdk from './';
import { _t } from './languageHandler';
import {KIND_DM, KIND_INVITE} from "./components/views/dialogs/InviteDialog";
import CommunityPrototypeInviteDialog from "./components/views/dialogs/CommunityPrototypeInviteDialog";
-import GroupStore from "./stores/GroupStore";
import {CommunityPrototypeStore} from "./stores/CommunityPrototypeStore";
/**
diff --git a/src/stores/FlairStore.js b/src/stores/FlairStore.js
index cb181c5c69..53d07d0452 100644
--- a/src/stores/FlairStore.js
+++ b/src/stores/FlairStore.js
@@ -152,8 +152,8 @@ class FlairStore extends EventEmitter {
* Gets the profile for the given group if known, otherwise returns null.
* This triggers `getGroupProfileCached` if needed, though the result of the
* call will not be returned by this function.
- * @param matrixClient {MatrixClient} The matrix client to use to fetch the profile, if needed.
- * @param groupId {string} The group ID to get the profile for.
+ * @param {MatrixClient} matrixClient The matrix client to use to fetch the profile, if needed.
+ * @param {string} groupId The group ID to get the profile for.
* @returns {*} The profile if known, otherwise null.
*/
getGroupProfileCachedFast(matrixClient, groupId) {
From 78d5b87fbc816b78f6615bd004de0642179d0498 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Mon, 31 Aug 2020 11:20:28 -0600
Subject: [PATCH 35/63] Use a different border variable for compatibility with
custom themes
---
res/css/structures/_UserMenu.scss | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/res/css/structures/_UserMenu.scss b/res/css/structures/_UserMenu.scss
index 8c944935ed..6fa2f2578e 100644
--- a/res/css/structures/_UserMenu.scss
+++ b/res/css/structures/_UserMenu.scss
@@ -36,7 +36,7 @@ limitations under the License.
// we cheat opacity on the theme colour with an after selector here
&::after {
content: '';
- border-bottom: 1px solid $roomsublist-divider-color;
+ border-bottom: 1px solid $primary-fg-color; // XXX: Variable abuse
opacity: 0.2;
display: block;
padding-top: 8px;
@@ -154,7 +154,7 @@ limitations under the License.
width: 85%;
opacity: 0.2;
border: none;
- border-bottom: 1px solid $roomsublist-divider-color;
+ border-bottom: 1px solid $primary-fg-color; // XXX: Variable abuse
}
&.mx_IconizedContextMenu {
From 656a815991dbdb86fcb98ae2cc28903e9abf9b6e Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Tue, 1 Sep 2020 09:07:46 +0100
Subject: [PATCH 36/63] delint some more
---
.../dialogs/CreateCommunityPrototypeDialog.tsx | 6 ++----
src/components/views/elements/EventTilePreview.tsx | 14 +++++++-------
2 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx b/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx
index dbfc208583..1d9d92b9c9 100644
--- a/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx
+++ b/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx
@@ -163,11 +163,9 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
);
if (this.state.error) {
+ const classes = "mx_CreateCommunityPrototypeDialog_subtext mx_CreateCommunityPrototypeDialog_subtext_error";
helpText = (
-
+
{this.state.error}
);
diff --git a/src/components/views/elements/EventTilePreview.tsx b/src/components/views/elements/EventTilePreview.tsx
index 98f6850e6b..61e5f5381d 100644
--- a/src/components/views/elements/EventTilePreview.tsx
+++ b/src/components/views/elements/EventTilePreview.tsx
@@ -45,6 +45,7 @@ interface IState {
displayname: string;
avatar_url: string;
}
+/* eslint-enable camelcase */
const AVATAR_SIZE = 32;
@@ -64,18 +65,18 @@ export default class EventTilePreview extends React.Component {
const client = MatrixClientPeg.get();
const userId = client.getUserId();
const profileInfo = await client.getProfileInfo(userId);
- const avatar_url = Avatar.avatarUrlForUser(
+ const avatarUrl = Avatar.avatarUrlForUser(
{avatarUrl: profileInfo.avatar_url},
AVATAR_SIZE, AVATAR_SIZE, "crop");
this.setState({
userId,
displayname: profileInfo.displayname,
- avatar_url,
+ avatar_url: avatarUrl,
});
}
- private fakeEvent({userId, displayname, avatar_url}: IState) {
+ private fakeEvent({userId, displayname, avatar_url: avatarUrl}: IState) {
// Fake it till we make it
const event = new MatrixEvent(JSON.parse(`{
"type": "m.room.message",
@@ -85,12 +86,12 @@ export default class EventTilePreview extends React.Component {
"msgtype": "m.text",
"body": "${this.props.message}",
"displayname": "${displayname}",
- "avatar_url": "${avatar_url}"
+ "avatar_url": "${avatarUrl}"
},
"msgtype": "m.text",
"body": "${this.props.message}",
"displayname": "${displayname}",
- "avatar_url": "${avatar_url}"
+ "avatar_url": "${avatarUrl}"
},
"unsigned": {
"age": 97
@@ -104,7 +105,7 @@ export default class EventTilePreview extends React.Component {
name: displayname,
userId: userId,
getAvatarUrl: (..._) => {
- return avatar_url;
+ return avatarUrl;
},
};
@@ -124,4 +125,3 @@ export default class EventTilePreview extends React.Component {
;
}
}
-/* eslint-enable camelcase */
From 6c39213116c1d36336875607d6d8b8d3caac6188 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Tue, 1 Sep 2020 15:37:07 +0100
Subject: [PATCH 37/63] remove unused class TextHighlighter
---
src/HtmlUtils.tsx | 26 --------------------------
1 file changed, 26 deletions(-)
diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx
index 2ce9e40aa6..bd314c2e5f 100644
--- a/src/HtmlUtils.tsx
+++ b/src/HtmlUtils.tsx
@@ -339,32 +339,6 @@ class HtmlHighlighter extends BaseHighlighter {
}
}
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-class TextHighlighter extends BaseHighlighter {
- private key = 0;
-
- /* create a node to hold the given content
- *
- * snippet: content of the span
- * highlight: true to highlight as a search match
- *
- * returns a React node
- */
- protected processSnippet(snippet: string, highlight: boolean): React.ReactNode {
- const key = this.key++;
-
- let node =
- { snippet }
- ;
-
- if (highlight && this.highlightLink) {
- node = { node } ;
- }
-
- return node;
- }
-}
-
interface IContent {
format?: string;
// eslint-disable-next-line camelcase
From d668f8018b943257559a0e5db5b3dec0d2f1e8d0 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Tue, 1 Sep 2020 15:59:19 +0100
Subject: [PATCH 38/63] undo some delint
---
.../CommunityPrototypeInviteDialog.tsx | 46 +++++++++++--------
1 file changed, 26 insertions(+), 20 deletions(-)
diff --git a/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx b/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx
index 4a454c8cbb..1c8a4ad6f6 100644
--- a/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx
+++ b/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx
@@ -167,24 +167,28 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent<
public render() {
const emailAddresses = [];
this.state.emailTargets.forEach((address, i) => {
- emailAddresses.push( this.onAddressChange(e, i)}
- label={_t("Email address")}
- placeholder={_t("Email address")}
- onBlur={() => this.onAddressBlur(i)}
- />);
+ emailAddresses.push((
+ this.onAddressChange(e, i)}
+ label={_t("Email address")}
+ placeholder={_t("Email address")}
+ onBlur={() => this.onAddressBlur(i)}
+ />
+ ));
});
// Push a clean input
- emailAddresses.push( this.onAddressChange(e, emailAddresses.length)}
- label={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
- placeholder={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
- />);
+ emailAddresses.push((
+ this.onAddressChange(e, emailAddresses.length)}
+ label={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
+ placeholder={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
+ />
+ ));
let peopleIntro = null;
const people = [];
@@ -194,11 +198,13 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent<
people.push(this.renderPerson(person, i));
});
if (humansToPresent.length < this.state.people.length) {
- people.push({_t("Show more")} );
+ people.push((
+ {_t("Show more")}
+ ));
}
}
if (this.state.people.length > 0) {
From bb248670a615583da1db2f285ebb77a6f1311caf Mon Sep 17 00:00:00 2001
From: RiotRobot
Date: Tue, 1 Sep 2020 17:02:49 +0100
Subject: [PATCH 39/63] Upgrade matrix-js-sdk to 8.2.0
---
package.json | 2 +-
yarn.lock | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/package.json b/package.json
index b59c32f121..fe81cd8bcb 100644
--- a/package.json
+++ b/package.json
@@ -79,7 +79,7 @@
"is-ip": "^2.0.0",
"linkifyjs": "^2.1.9",
"lodash": "^4.17.19",
- "matrix-js-sdk": "8.2.0-rc.1",
+ "matrix-js-sdk": "8.2.0",
"minimist": "^1.2.5",
"pako": "^1.0.11",
"parse5": "^5.1.1",
diff --git a/yarn.lock b/yarn.lock
index 12c29e98a7..86c208c465 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6475,10 +6475,10 @@ mathml-tag-names@^2.0.1:
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
-matrix-js-sdk@8.2.0-rc.1:
- version "8.2.0-rc.1"
- resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-8.2.0-rc.1.tgz#1870ab25af7062def4b757ca5da04199df269241"
- integrity sha512-vZTZOIoYXTFTO+NgBnP+mJMdwNwlIF8GQPeqra+esyoKcas7jVumAwektu3SXhFJPy9vnmufs7zXx4geiNNkpA==
+matrix-js-sdk@8.2.0:
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-8.2.0.tgz#6fbdadcdc563e41671d407d772a4d52ec8adc480"
+ integrity sha512-yKF/H1Matgf4b7bfa/gOPNcgMEujogC1r89Au8ZYKfv3dmNdJupE9ktdGJ28QVeKIyF5Ew1stLI4MdGWT1gYPw==
dependencies:
"@babel/runtime" "^7.8.3"
another-json "^0.2.0"
From 69e5ed56ae3403b966a752c2bde5ee081c3a8fba Mon Sep 17 00:00:00 2001
From: RiotRobot
Date: Tue, 1 Sep 2020 17:36:20 +0100
Subject: [PATCH 40/63] Prepare changelog for v3.3.0
---
CHANGELOG.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ae9027696c..47bffe432f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+Changes in [3.3.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.3.0) (2020-09-01)
+===================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.3.0-rc.1...v3.3.0)
+
+ * Upgrade to JS SDK 8.2.0
+
Changes in [3.3.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.3.0-rc.1) (2020-08-26)
=============================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.2.0...v3.3.0-rc.1)
From d1d823dcc7fad600f6c72bd118f41a53c66766b1 Mon Sep 17 00:00:00 2001
From: RiotRobot
Date: Tue, 1 Sep 2020 17:36:21 +0100
Subject: [PATCH 41/63] v3.3.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index fe81cd8bcb..62f225cc34 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "matrix-react-sdk",
- "version": "3.3.0-rc.1",
+ "version": "3.3.0",
"description": "SDK for matrix.org using React",
"author": "matrix.org",
"repository": {
From 0d290c9bd2604343610e1fc3b17bbdb941ad2ad6 Mon Sep 17 00:00:00 2001
From: RiotRobot
Date: Tue, 1 Sep 2020 17:39:09 +0100
Subject: [PATCH 42/63] Reset matrix-js-sdk back to develop branch
---
package.json | 2 +-
yarn.lock | 935 ++-------------------------------------------------
2 files changed, 24 insertions(+), 913 deletions(-)
diff --git a/package.json b/package.json
index c2756de280..fc5ed57a77 100644
--- a/package.json
+++ b/package.json
@@ -79,7 +79,7 @@
"is-ip": "^2.0.0",
"linkifyjs": "^2.1.9",
"lodash": "^4.17.19",
- "matrix-js-sdk": "8.2.0",
+ "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
"minimist": "^1.2.5",
"pako": "^1.0.11",
"parse5": "^5.1.1",
diff --git a/yarn.lock b/yarn.lock
index 86c208c465..5bd2be1567 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1832,161 +1832,6 @@
dependencies:
eslint-visitor-keys "^1.1.0"
-"@webassemblyjs/ast@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"
- integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==
- dependencies:
- "@webassemblyjs/helper-module-context" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/wast-parser" "1.9.0"
-
-"@webassemblyjs/floating-point-hex-parser@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4"
- integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==
-
-"@webassemblyjs/helper-api-error@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2"
- integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==
-
-"@webassemblyjs/helper-buffer@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00"
- integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==
-
-"@webassemblyjs/helper-code-frame@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27"
- integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==
- dependencies:
- "@webassemblyjs/wast-printer" "1.9.0"
-
-"@webassemblyjs/helper-fsm@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8"
- integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==
-
-"@webassemblyjs/helper-module-context@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07"
- integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
-
-"@webassemblyjs/helper-wasm-bytecode@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790"
- integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==
-
-"@webassemblyjs/helper-wasm-section@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346"
- integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-buffer" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/wasm-gen" "1.9.0"
-
-"@webassemblyjs/ieee754@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4"
- integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==
- dependencies:
- "@xtuc/ieee754" "^1.2.0"
-
-"@webassemblyjs/leb128@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95"
- integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==
- dependencies:
- "@xtuc/long" "4.2.2"
-
-"@webassemblyjs/utf8@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab"
- integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==
-
-"@webassemblyjs/wasm-edit@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf"
- integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-buffer" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/helper-wasm-section" "1.9.0"
- "@webassemblyjs/wasm-gen" "1.9.0"
- "@webassemblyjs/wasm-opt" "1.9.0"
- "@webassemblyjs/wasm-parser" "1.9.0"
- "@webassemblyjs/wast-printer" "1.9.0"
-
-"@webassemblyjs/wasm-gen@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c"
- integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/ieee754" "1.9.0"
- "@webassemblyjs/leb128" "1.9.0"
- "@webassemblyjs/utf8" "1.9.0"
-
-"@webassemblyjs/wasm-opt@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61"
- integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-buffer" "1.9.0"
- "@webassemblyjs/wasm-gen" "1.9.0"
- "@webassemblyjs/wasm-parser" "1.9.0"
-
-"@webassemblyjs/wasm-parser@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e"
- integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-api-error" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/ieee754" "1.9.0"
- "@webassemblyjs/leb128" "1.9.0"
- "@webassemblyjs/utf8" "1.9.0"
-
-"@webassemblyjs/wast-parser@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914"
- integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/floating-point-hex-parser" "1.9.0"
- "@webassemblyjs/helper-api-error" "1.9.0"
- "@webassemblyjs/helper-code-frame" "1.9.0"
- "@webassemblyjs/helper-fsm" "1.9.0"
- "@xtuc/long" "4.2.2"
-
-"@webassemblyjs/wast-printer@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899"
- integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/wast-parser" "1.9.0"
- "@xtuc/long" "4.2.2"
-
-"@xtuc/ieee754@^1.2.0":
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
- integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
-
-"@xtuc/long@4.2.2":
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
- integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
-
abab@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a"
@@ -2015,7 +1860,7 @@ acorn@^5.5.3:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==
-acorn@^6.0.1, acorn@^6.4.1:
+acorn@^6.0.1:
version "6.4.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==
@@ -2067,7 +1912,7 @@ ajv-errors@^1.0.0:
resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d"
integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==
-ajv-keywords@^3.1.0, ajv-keywords@^3.4.1:
+ajv-keywords@^3.1.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da"
integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==
@@ -2258,15 +2103,6 @@ asap@~2.0.3:
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
-asn1.js@^4.0.0:
- version "4.10.1"
- resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
- integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==
- dependencies:
- bn.js "^4.0.0"
- inherits "^2.0.1"
- minimalistic-assert "^1.0.0"
-
asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
@@ -2286,14 +2122,6 @@ assert-plus@1.0.0, assert-plus@^1.0.0:
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
-assert@^1.1.1:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb"
- integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==
- dependencies:
- object-assign "^4.1.1"
- util "0.10.3"
-
assign-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
@@ -2498,16 +2326,6 @@ blueimp-canvas-to-blob@^3.27.0:
resolved "https://registry.yarnpkg.com/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.27.0.tgz#a2bd5c43587b95dedf0f6998603452d1bfcc9b9e"
integrity sha512-AcIj+hCw6WquxzJuzC6KzgYmqxLFeTWe88KuY2BEIsW1zbEOfoinDAGlhyvFNGt+U3JElkVSK7anA1FaSdmmfA==
-bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.4.0:
- version "4.11.9"
- resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
- integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
-
-bn.js@^5.1.1:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0"
- integrity sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==
-
boolbase@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
@@ -2544,11 +2362,6 @@ braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
-brorand@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
- integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
-
browser-encrypt-attachment@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/browser-encrypt-attachment/-/browser-encrypt-attachment-0.3.0.tgz#205a94caadf0dc7e81413941812f655bd190ff1c"
@@ -2571,67 +2384,6 @@ browser-resolve@^1.11.3:
dependencies:
resolve "1.1.7"
-browserify-aes@^1.0.0, browserify-aes@^1.0.4:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
- integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==
- dependencies:
- buffer-xor "^1.0.3"
- cipher-base "^1.0.0"
- create-hash "^1.1.0"
- evp_bytestokey "^1.0.3"
- inherits "^2.0.1"
- safe-buffer "^5.0.1"
-
-browserify-cipher@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0"
- integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==
- dependencies:
- browserify-aes "^1.0.4"
- browserify-des "^1.0.0"
- evp_bytestokey "^1.0.0"
-
-browserify-des@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c"
- integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==
- dependencies:
- cipher-base "^1.0.1"
- des.js "^1.0.0"
- inherits "^2.0.1"
- safe-buffer "^5.1.2"
-
-browserify-rsa@^4.0.0, browserify-rsa@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
- integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=
- dependencies:
- bn.js "^4.1.0"
- randombytes "^2.0.1"
-
-browserify-sign@^4.0.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.0.tgz#545d0b1b07e6b2c99211082bf1b12cce7a0b0e11"
- integrity sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==
- dependencies:
- bn.js "^5.1.1"
- browserify-rsa "^4.0.1"
- create-hash "^1.2.0"
- create-hmac "^1.1.7"
- elliptic "^6.5.2"
- inherits "^2.0.4"
- parse-asn1 "^5.1.5"
- readable-stream "^3.6.0"
- safe-buffer "^5.2.0"
-
-browserify-zlib@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f"
- integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==
- dependencies:
- pako "~1.0.5"
-
browserslist@^4.12.0, browserslist@^4.8.5:
version "4.12.0"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.12.0.tgz#06c6d5715a1ede6c51fc39ff67fd647f740b656d"
@@ -2679,20 +2431,6 @@ buffer-from@^1.0.0, buffer-from@^1.1.1:
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
-buffer-xor@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
- integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=
-
-buffer@^4.3.0:
- version "4.9.2"
- resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
- integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==
- dependencies:
- base64-js "^1.0.2"
- ieee754 "^1.1.4"
- isarray "^1.0.0"
-
buffer@^5.4.3:
version "5.6.0"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786"
@@ -2701,12 +2439,7 @@ buffer@^5.4.3:
base64-js "^1.0.2"
ieee754 "^1.1.4"
-builtin-status-codes@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
- integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
-
-cacache@^12.0.0, cacache@^12.0.2:
+cacache@^12.0.0:
version "12.0.4"
resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c"
integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==
@@ -2885,21 +2618,6 @@ chokidar@^2.1.8:
optionalDependencies:
fsevents "^1.2.7"
-chokidar@^3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.0.tgz#b30611423ce376357c765b9b8f904b9fba3c0be8"
- integrity sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==
- dependencies:
- anymatch "~3.1.1"
- braces "~3.0.2"
- glob-parent "~5.1.0"
- is-binary-path "~2.1.0"
- is-glob "~4.0.1"
- normalize-path "~3.0.0"
- readdirp "~3.4.0"
- optionalDependencies:
- fsevents "~2.1.2"
-
chokidar@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.1.tgz#e905bdecf10eaa0a0b1db0c664481cc4cbc22ba1"
@@ -2920,26 +2638,11 @@ chownr@^1.1.1:
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
-chrome-trace-event@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4"
- integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==
- dependencies:
- tslib "^1.9.0"
-
ci-info@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
-cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
- integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==
- dependencies:
- inherits "^2.0.1"
- safe-buffer "^5.0.1"
-
class-utils@^0.3.5:
version "0.3.6"
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
@@ -3112,16 +2815,6 @@ concurrently@^4.1.2:
tree-kill "^1.2.1"
yargs "^12.0.5"
-console-browserify@^1.1.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
- integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==
-
-constants-browserify@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
- integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
-
contains-path@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
@@ -3205,37 +2898,6 @@ crc-32@^0.3.0:
resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-0.3.0.tgz#6a3d3687f5baec41f7e9b99fe1953a2e5d19775e"
integrity sha1-aj02h/W67EH36bmf4ZU6Ll0Zd14=
-create-ecdh@^4.0.0:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
- integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==
- dependencies:
- bn.js "^4.1.0"
- elliptic "^6.0.0"
-
-create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
- integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
- dependencies:
- cipher-base "^1.0.1"
- inherits "^2.0.1"
- md5.js "^1.3.4"
- ripemd160 "^2.0.1"
- sha.js "^2.4.0"
-
-create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
- version "1.1.7"
- resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
- integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
- dependencies:
- cipher-base "^1.0.3"
- create-hash "^1.1.0"
- inherits "^2.0.1"
- ripemd160 "^2.0.0"
- safe-buffer "^5.0.1"
- sha.js "^2.4.8"
-
create-react-class@^15.6.3:
version "15.6.3"
resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.3.tgz#2d73237fb3f970ae6ebe011a9e66f46dbca80036"
@@ -3265,23 +2927,6 @@ cross-spawn@^7.0.2:
shebang-command "^2.0.0"
which "^2.0.1"
-crypto-browserify@^3.11.0:
- version "3.12.0"
- resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
- integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==
- dependencies:
- browserify-cipher "^1.0.0"
- browserify-sign "^4.0.0"
- create-ecdh "^4.0.0"
- create-hash "^1.1.0"
- create-hmac "^1.1.0"
- diffie-hellman "^5.0.0"
- inherits "^2.0.1"
- pbkdf2 "^3.0.3"
- public-encrypt "^4.0.0"
- randombytes "^2.0.0"
- randomfill "^1.0.3"
-
css-select@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
@@ -3452,19 +3097,6 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
-des.js@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843"
- integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==
- dependencies:
- inherits "^2.0.1"
- minimalistic-assert "^1.0.0"
-
-detect-file@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
- integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
-
detect-newline@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2"
@@ -3493,15 +3125,6 @@ diff-sequences@^24.9.0:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
-diffie-hellman@^5.0.0:
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
- integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==
- dependencies:
- bn.js "^4.1.0"
- miller-rabin "^4.0.0"
- randombytes "^2.0.0"
-
dijkstrajs@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.1.tgz#d3cd81221e3ea40742cfcde556d4e99e98ddc71b"
@@ -3565,11 +3188,6 @@ dom-serializer@~0.1.1:
domelementtype "^1.3.0"
entities "^1.1.1"
-domain-browser@^1.1.1:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
- integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
-
domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
@@ -3656,19 +3274,6 @@ electron-to-chromium@^1.3.413:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.464.tgz#fe13feaa08f6f865d3c89d5d72e54c194f463aa5"
integrity sha512-Oo+0+CN9d2z6FToQW6Hwvi9ez09Y/usKwr0tsDsyg43a871zVJCi1nR0v03djLbRNcaCKjtrnVf2XJhTxEpPCg==
-elliptic@^6.0.0, elliptic@^6.5.2:
- version "6.5.3"
- resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
- integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
- dependencies:
- bn.js "^4.4.0"
- brorand "^1.0.1"
- hash.js "^1.0.0"
- hmac-drbg "^1.0.0"
- inherits "^2.0.1"
- minimalistic-assert "^1.0.0"
- minimalistic-crypto-utils "^1.0.0"
-
emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
@@ -3708,24 +3313,6 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
-enhanced-resolve@^4.1.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66"
- integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==
- dependencies:
- graceful-fs "^4.1.2"
- memory-fs "^0.5.0"
- tapable "^1.0.0"
-
-enhanced-resolve@^4.1.1:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz#3b806f3bfafc1ec7de69551ef93cca46c1704126"
- integrity sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==
- dependencies:
- graceful-fs "^4.1.2"
- memory-fs "^0.5.0"
- tapable "^1.0.0"
-
enquirer@^2.3.5:
version "2.3.5"
resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.5.tgz#3ab2b838df0a9d8ab9e7dff235b0e8712ef92381"
@@ -3811,13 +3398,6 @@ err-code@^1.0.0:
resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960"
integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=
-errno@^0.1.3, errno@~0.1.7:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
- integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
- dependencies:
- prr "~1.0.1"
-
error-ex@^1.2.0, error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
@@ -4049,14 +3629,6 @@ eslint-rule-composer@^0.3.0:
resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9"
integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==
-eslint-scope@^4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
- integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==
- dependencies:
- esrecurse "^4.1.0"
- estraverse "^4.1.1"
-
eslint-scope@^5.0.0, eslint-scope@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5"
@@ -4233,19 +3805,6 @@ esutils@^2.0.2:
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
-events@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59"
- integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==
-
-evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02"
- integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==
- dependencies:
- md5.js "^1.3.4"
- safe-buffer "^5.1.1"
-
except@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/except/-/except-0.1.3.tgz#98261c91958551536b44482238e9783fb73d292a"
@@ -4296,13 +3855,6 @@ expand-brackets@^2.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
-expand-tilde@^2.0.0, expand-tilde@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
- integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
- dependencies:
- homedir-polyfill "^1.0.1"
-
expect@^1.20.2:
version "1.20.2"
resolved "https://registry.yarnpkg.com/expect/-/expect-1.20.2.tgz#d458fe4c56004036bae3232416a3f6361f04f965"
@@ -4515,7 +4067,7 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
-find-cache-dir@^2.0.0, find-cache-dir@^2.1.0:
+find-cache-dir@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7"
integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==
@@ -4546,16 +4098,6 @@ find-up@^3.0.0:
dependencies:
locate-path "^3.0.0"
-findup-sync@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1"
- integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==
- dependencies:
- detect-file "^1.0.0"
- is-glob "^4.0.0"
- micromatch "^3.0.4"
- resolve-dir "^1.0.1"
-
flat-cache@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
@@ -4790,15 +4332,6 @@ glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
once "^1.3.0"
path-is-absolute "^1.0.0"
-global-modules@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
- integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
- dependencies:
- global-prefix "^1.0.1"
- is-windows "^1.0.1"
- resolve-dir "^1.0.0"
-
global-modules@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
@@ -4806,17 +4339,6 @@ global-modules@^2.0.0:
dependencies:
global-prefix "^3.0.0"
-global-prefix@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
- integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=
- dependencies:
- expand-tilde "^2.0.2"
- homedir-polyfill "^1.0.1"
- ini "^1.3.4"
- is-windows "^1.0.1"
- which "^1.2.14"
-
global-prefix@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97"
@@ -4945,37 +4467,11 @@ has@^1.0.1, has@^1.0.3:
dependencies:
function-bind "^1.1.1"
-hash-base@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33"
- integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==
- dependencies:
- inherits "^2.0.4"
- readable-stream "^3.6.0"
- safe-buffer "^5.2.0"
-
-hash.js@^1.0.0, hash.js@^1.0.3:
- version "1.1.7"
- resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
- integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
- dependencies:
- inherits "^2.0.3"
- minimalistic-assert "^1.0.1"
-
highlight.js@^10.1.2:
version "10.1.2"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.1.2.tgz#c20db951ba1c22c055010648dfffd7b2a968e00c"
integrity sha512-Q39v/Mn5mfBlMff9r+zzA+gWxRsCRKwEMvYTiisLr/XUiFI/4puWt0Ojdko3R3JCNWGdOWaA5g/Yxqa23kC5AA==
-hmac-drbg@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
- integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=
- dependencies:
- hash.js "^1.0.3"
- minimalistic-assert "^1.0.0"
- minimalistic-crypto-utils "^1.0.1"
-
hoist-non-react-statics@^3.3.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
@@ -4983,13 +4479,6 @@ hoist-non-react-statics@^3.3.0:
dependencies:
react-is "^16.7.0"
-homedir-polyfill@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
- integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
- dependencies:
- parse-passwd "^1.0.0"
-
hosted-git-info@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.0.tgz#dd8af49cd01e73cc8e61ba13e217a772fd4ecd2d"
@@ -5075,11 +4564,6 @@ http-signature@~1.2.0:
jsprim "^1.2.2"
sshpk "^1.7.0"
-https-browserify@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
- integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
-
https-proxy-agent@^2.2.1:
version "2.2.4"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
@@ -5189,22 +4673,12 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
+inherits@2, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-inherits@2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
- integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
-
-inherits@2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
- integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
-
-ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
+ini@^1.3.5, ini@~1.3.0:
version "1.3.5"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
@@ -5237,11 +4711,6 @@ internal-slot@^1.0.2:
has "^1.0.3"
side-channel "^1.0.2"
-interpret@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
- integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
-
invariant@^2.2.2, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
@@ -5603,7 +5072,7 @@ is-whitespace-character@^1.0.0:
resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7"
integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==
-is-windows@^1.0.1, is-windows@^1.0.2:
+is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
@@ -6125,7 +5594,7 @@ jsesc@~0.5.0:
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
-json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
+json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
@@ -6286,12 +5755,7 @@ load-json-file@^4.0.0:
pify "^3.0.0"
strip-bom "^3.0.0"
-loader-runner@^2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
- integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==
-
-loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0:
+loader-utils@^1.0.2, loader-utils@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
@@ -6475,10 +5939,9 @@ mathml-tag-names@^2.0.1:
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
-matrix-js-sdk@8.2.0:
+"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop":
version "8.2.0"
- resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-8.2.0.tgz#6fbdadcdc563e41671d407d772a4d52ec8adc480"
- integrity sha512-yKF/H1Matgf4b7bfa/gOPNcgMEujogC1r89Au8ZYKfv3dmNdJupE9ktdGJ28QVeKIyF5Ew1stLI4MdGWT1gYPw==
+ resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/c6992e2056901502af19e40ba0d1103c4c1f61ed"
dependencies:
"@babel/runtime" "^7.8.3"
another-json "^0.2.0"
@@ -6503,15 +5966,6 @@ matrix-react-test-utils@^0.2.2:
resolved "https://registry.yarnpkg.com/matrix-react-test-utils/-/matrix-react-test-utils-0.2.2.tgz#c87144d3b910c7edc544a6699d13c7c2bf02f853"
integrity sha512-49+7gfV6smvBIVbeloql+37IeWMTD+fiywalwCqk8Dnz53zAFjKSltB3rmWHso1uecLtQEcPtCijfhzcLXAxTQ==
-md5.js@^1.3.4:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
- integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==
- dependencies:
- hash-base "^3.0.0"
- inherits "^2.0.1"
- safe-buffer "^5.1.2"
-
mdast-util-compact@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz#d531bb7667b5123abf20859be086c4d06c894593"
@@ -6538,22 +5992,6 @@ memoize-one@^3.0.1:
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-3.1.1.tgz#ef609811e3bc28970eac2884eece64d167830d17"
integrity sha512-YqVh744GsMlZu6xkhGslPSqSurOv6P+kLN2J3ysBZfagLcL5FdRK/0UpgLoL8hwjjEvvAVkjJZyFP+1T6p1vgA==
-memory-fs@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
- integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=
- dependencies:
- errno "^0.1.3"
- readable-stream "^2.0.1"
-
-memory-fs@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c"
- integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==
- dependencies:
- errno "^0.1.3"
- readable-stream "^2.0.1"
-
meow@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4"
@@ -6579,7 +6017,7 @@ merge2@^1.2.3:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4:
+micromatch@^3.1.10, micromatch@^3.1.4:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
@@ -6598,14 +6036,6 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.2"
-miller-rabin@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
- integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==
- dependencies:
- bn.js "^4.0.0"
- brorand "^1.0.1"
-
mime-db@1.44.0:
version "1.44.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
@@ -6623,16 +6053,6 @@ mimic-fn@^2.0.0, mimic-fn@^2.1.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
-minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
- integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
-
-minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
- integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
-
"minimatch@2 || 3", minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@@ -6682,7 +6102,7 @@ mixin-deep@^1.2.0:
for-in "^1.0.2"
is-extendable "^1.0.1"
-mkdirp@^0.5.1, mkdirp@^0.5.3:
+mkdirp@^0.5.1:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
@@ -6759,11 +6179,6 @@ nearley@^2.7.10:
randexp "0.4.6"
semver "^5.4.1"
-neo-async@^2.5.0, neo-async@^2.6.1:
- version "2.6.1"
- resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
- integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==
-
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
@@ -6791,35 +6206,6 @@ node-int64@^0.4.0:
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=
-node-libs-browser@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
- integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==
- dependencies:
- assert "^1.1.1"
- browserify-zlib "^0.2.0"
- buffer "^4.3.0"
- console-browserify "^1.1.0"
- constants-browserify "^1.0.0"
- crypto-browserify "^3.11.0"
- domain-browser "^1.1.1"
- events "^3.0.0"
- https-browserify "^1.0.0"
- os-browserify "^0.3.0"
- path-browserify "0.0.1"
- process "^0.11.10"
- punycode "^1.2.4"
- querystring-es3 "^0.2.0"
- readable-stream "^2.3.3"
- stream-browserify "^2.0.1"
- stream-http "^2.7.2"
- string_decoder "^1.0.0"
- timers-browserify "^2.0.4"
- tty-browserify "0.0.0"
- url "^0.11.0"
- util "^0.11.0"
- vm-browserify "^1.0.1"
-
node-modules-regexp@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40"
@@ -7038,11 +6424,6 @@ optionator@^0.9.1:
type-check "^0.4.0"
word-wrap "^1.2.3"
-os-browserify@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
- integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
-
os-locale@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
@@ -7129,7 +6510,7 @@ p-try@^2.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
-pako@^1.0.11, pako@~1.0.5:
+pako@^1.0.11:
version "1.0.11"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
@@ -7150,18 +6531,6 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
-parse-asn1@^5.0.0, parse-asn1@^5.1.5:
- version "5.1.5"
- resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e"
- integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==
- dependencies:
- asn1.js "^4.0.0"
- browserify-aes "^1.0.0"
- create-hash "^1.1.0"
- evp_bytestokey "^1.0.0"
- pbkdf2 "^3.0.3"
- safe-buffer "^5.1.1"
-
parse-color@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-color/-/parse-color-1.0.0.tgz#7b748b95a83f03f16a94f535e52d7f3d94658619"
@@ -7196,11 +6565,6 @@ parse-json@^4.0.0:
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
-parse-passwd@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
- integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
-
parse5@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
@@ -7223,11 +6587,6 @@ pascalcase@^0.1.1:
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
-path-browserify@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
- integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==
-
path-dirname@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
@@ -7277,17 +6636,6 @@ path-type@^3.0.0:
dependencies:
pify "^3.0.0"
-pbkdf2@^3.0.3:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94"
- integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==
- dependencies:
- create-hash "^1.1.2"
- create-hmac "^1.1.4"
- ripemd160 "^2.0.1"
- safe-buffer "^5.0.1"
- sha.js "^2.4.8"
-
performance-now@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
@@ -7516,11 +6864,6 @@ process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
-process@^0.11.10:
- version "0.11.10"
- resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
- integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
-
progress@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
@@ -7580,28 +6923,11 @@ prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2,
object-assign "^4.1.1"
react-is "^16.8.1"
-prr@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
- integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
-
psl@^1.1.28:
version "1.8.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
-public-encrypt@^4.0.0:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0"
- integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==
- dependencies:
- bn.js "^4.1.0"
- browserify-rsa "^4.0.0"
- create-hash "^1.1.0"
- parse-asn1 "^5.0.0"
- randombytes "^2.0.1"
- safe-buffer "^5.1.2"
-
pump@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
@@ -7632,11 +6958,6 @@ punycode@1.3.2:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
-punycode@^1.2.4:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
- integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
-
punycode@^2.1.0, punycode@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
@@ -7677,11 +6998,6 @@ qs@~6.5.2:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
-querystring-es3@^0.2.0:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
- integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=
-
querystring@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
@@ -7717,21 +7033,6 @@ randexp@0.4.6:
discontinuous-range "1.0.0"
ret "~0.1.10"
-randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
- integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
- dependencies:
- safe-buffer "^5.1.0"
-
-randomfill@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458"
- integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==
- dependencies:
- randombytes "^2.0.5"
- safe-buffer "^5.1.0"
-
rc@1.2.8, rc@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
@@ -7906,7 +7207,7 @@ read-pkg@^4.0.1:
parse-json "^4.0.0"
pify "^3.0.0"
-"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
+"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.6, readable-stream@~2.3.6:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
@@ -7919,7 +7220,7 @@ read-pkg@^4.0.1:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
-readable-stream@^3.1.1, readable-stream@^3.6.0:
+readable-stream@^3.1.1:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
@@ -8211,14 +7512,6 @@ resolve-cwd@^2.0.0:
dependencies:
resolve-from "^3.0.0"
-resolve-dir@^1.0.0, resolve-dir@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
- integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
- dependencies:
- expand-tilde "^2.0.0"
- global-modules "^1.0.0"
-
resolve-from@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
@@ -8278,14 +7571,6 @@ rimraf@^2.5.4, rimraf@^2.6.3, rimraf@^2.7.1:
dependencies:
glob "^7.1.3"
-ripemd160@^2.0.0, ripemd160@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
- integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==
- dependencies:
- hash-base "^3.0.0"
- inherits "^2.0.1"
-
rollup-plugin-terser@^5.1.1:
version "5.3.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.3.0.tgz#9c0dd33d5771df9630cd027d6a2559187f65885e"
@@ -8343,7 +7628,7 @@ rxjs@^6.6.0:
dependencies:
tslib "^1.9.0"
-safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
+safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@@ -8437,13 +7722,6 @@ serialize-javascript@^2.1.2:
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==
-serialize-javascript@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-3.1.0.tgz#8bf3a9170712664ef2561b44b691eafe399214ea"
- integrity sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==
- dependencies:
- randombytes "^2.1.0"
-
set-blocking@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
@@ -8459,19 +7737,11 @@ set-value@^2.0.0, set-value@^2.0.1:
is-plain-object "^2.0.3"
split-string "^3.0.1"
-setimmediate@^1.0.4, setimmediate@^1.0.5:
+setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
-sha.js@^2.4.0, sha.js@^2.4.8:
- version "2.4.11"
- resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
- integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
- dependencies:
- inherits "^2.0.1"
- safe-buffer "^5.0.1"
-
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -8584,11 +7854,6 @@ socks@~2.3.2:
ip "1.1.5"
smart-buffer "^4.1.0"
-source-list-map@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
- integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
-
source-map-loader@^0.2.4:
version "0.2.4"
resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-0.2.4.tgz#c18b0dc6e23bf66f6792437557c569a11e072271"
@@ -8734,14 +7999,6 @@ stealthy-require@^1.1.1:
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
-stream-browserify@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
- integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==
- dependencies:
- inherits "~2.0.1"
- readable-stream "^2.0.2"
-
stream-each@^1.1.0:
version "1.2.3"
resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
@@ -8750,17 +8007,6 @@ stream-each@^1.1.0:
end-of-stream "^1.1.0"
stream-shift "^1.0.0"
-stream-http@^2.7.2:
- version "2.8.3"
- resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc"
- integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==
- dependencies:
- builtin-status-codes "^3.0.0"
- inherits "^2.0.1"
- readable-stream "^2.3.6"
- to-arraybuffer "^1.0.0"
- xtend "^4.0.0"
-
stream-shift@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
@@ -8878,7 +8124,7 @@ string.prototype.trimstart@^1.0.0:
define-properties "^1.1.3"
es-abstract "^1.17.5"
-string_decoder@^1.0.0, string_decoder@^1.1.1:
+string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
@@ -9101,32 +8347,12 @@ table@^5.0.0, table@^5.2.3:
slice-ansi "^2.1.0"
string-width "^3.0.0"
-tapable@^1.0.0, tapable@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
- integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
-
tar-js@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/tar-js/-/tar-js-0.3.0.tgz#6949aabfb0ba18bb1562ae51a439fd0f30183a17"
integrity sha1-aUmqv7C6GLsVYq5RpDn9DzAYOhc=
-terser-webpack-plugin@^1.4.3:
- version "1.4.4"
- resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.4.tgz#2c63544347324baafa9a56baaddf1634c8abfc2f"
- integrity sha512-U4mACBHIegmfoEe5fdongHESNJWqsGU+W0S/9+BmYGVQDw1+c2Ow05TpMhxjPK1sRb7cuYq1BPl1e5YHJMTCqA==
- dependencies:
- cacache "^12.0.2"
- find-cache-dir "^2.1.0"
- is-wsl "^1.1.0"
- schema-utils "^1.0.0"
- serialize-javascript "^3.1.0"
- source-map "^0.6.1"
- terser "^4.1.2"
- webpack-sources "^1.4.0"
- worker-farm "^1.7.0"
-
-terser@^4.1.2, terser@^4.6.2:
+terser@^4.6.2:
version "4.7.0"
resolved "https://registry.yarnpkg.com/terser/-/terser-4.7.0.tgz#15852cf1a08e3256a80428e865a2fa893ffba006"
integrity sha512-Lfb0RiZcjRDXCC3OSHJpEkxJ9Qeqs6mp2v4jf2MHfy8vGERmVDuvjXdd/EnP5Deme5F2yBRBymKmKHCBg2echw==
@@ -9173,13 +8399,6 @@ through@^2.3.6:
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
-timers-browserify@^2.0.4:
- version "2.0.11"
- resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f"
- integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==
- dependencies:
- setimmediate "^1.0.4"
-
tmatch@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/tmatch/-/tmatch-2.0.1.tgz#0c56246f33f30da1b8d3d72895abaf16660f38cf"
@@ -9197,11 +8416,6 @@ tmpl@1.0.x:
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=
-to-arraybuffer@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
- integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
-
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
@@ -9306,11 +8520,6 @@ tsutils@^3.17.1:
dependencies:
tslib "^1.8.1"
-tty-browserify@0.0.0:
- version "0.0.0"
- resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
- integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=
-
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
@@ -9573,26 +8782,12 @@ util.promisify@^1.0.0:
has-symbols "^1.0.1"
object.getownpropertydescriptors "^2.1.0"
-util@0.10.3:
- version "0.10.3"
- resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
- integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk=
- dependencies:
- inherits "2.0.1"
-
-util@^0.11.0:
- version "0.11.1"
- resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61"
- integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==
- dependencies:
- inherits "2.0.3"
-
uuid@^3.3.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
-v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.1:
+v8-compile-cache@^2.0.3:
version "2.1.1"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==
@@ -9649,11 +8844,6 @@ vfile@^3.0.0:
unist-util-stringify-position "^1.0.0"
vfile-message "^1.0.0"
-vm-browserify@^1.0.1:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
- integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
-
w3c-hr-time@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
@@ -9675,24 +8865,6 @@ walker@^1.0.7, walker@~1.0.5:
dependencies:
makeerror "1.0.x"
-watchpack-chokidar2@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0"
- integrity sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==
- dependencies:
- chokidar "^2.1.8"
-
-watchpack@^1.6.1:
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.2.tgz#c02e4d4d49913c3e7e122c3325365af9d331e9aa"
- integrity sha512-ymVbbQP40MFTp+cNMvpyBpBtygHnPzPkHqoIwRRj/0B8KhqQwV8LaKjtbaxF2lK4vl8zN9wCxS46IFCU5K4W0g==
- dependencies:
- graceful-fs "^4.1.2"
- neo-async "^2.5.0"
- optionalDependencies:
- chokidar "^3.4.0"
- watchpack-chokidar2 "^2.0.0"
-
webcrypto-core@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.1.2.tgz#c522a9e5596688f2b6bb19e2d336f68efa8bdd57"
@@ -9709,60 +8881,6 @@ webidl-conversions@^4.0.2:
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
-webpack-cli@^3.3.12:
- version "3.3.12"
- resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.12.tgz#94e9ada081453cd0aa609c99e500012fd3ad2d4a"
- integrity sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==
- dependencies:
- chalk "^2.4.2"
- cross-spawn "^6.0.5"
- enhanced-resolve "^4.1.1"
- findup-sync "^3.0.0"
- global-modules "^2.0.0"
- import-local "^2.0.0"
- interpret "^1.4.0"
- loader-utils "^1.4.0"
- supports-color "^6.1.0"
- v8-compile-cache "^2.1.1"
- yargs "^13.3.2"
-
-webpack-sources@^1.4.0, webpack-sources@^1.4.1:
- version "1.4.3"
- resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
- integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
- dependencies:
- source-list-map "^2.0.0"
- source-map "~0.6.1"
-
-webpack@^4.43.0:
- version "4.43.0"
- resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.43.0.tgz#c48547b11d563224c561dad1172c8aa0b8a678e6"
- integrity sha512-GW1LjnPipFW2Y78OOab8NJlCflB7EFskMih2AHdvjbpKMeDJqEgSx24cXXXiPS65+WSwVyxtDsJH6jGX2czy+g==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-module-context" "1.9.0"
- "@webassemblyjs/wasm-edit" "1.9.0"
- "@webassemblyjs/wasm-parser" "1.9.0"
- acorn "^6.4.1"
- ajv "^6.10.2"
- ajv-keywords "^3.4.1"
- chrome-trace-event "^1.0.2"
- enhanced-resolve "^4.1.0"
- eslint-scope "^4.0.3"
- json-parse-better-errors "^1.0.2"
- loader-runner "^2.4.0"
- loader-utils "^1.2.3"
- memory-fs "^0.4.1"
- micromatch "^3.1.10"
- mkdirp "^0.5.3"
- neo-async "^2.6.1"
- node-libs-browser "^2.2.1"
- schema-utils "^1.0.0"
- tapable "^1.1.3"
- terser-webpack-plugin "^1.4.3"
- watchpack "^1.6.1"
- webpack-sources "^1.4.1"
-
what-input@^5.2.10:
version "5.2.10"
resolved "https://registry.yarnpkg.com/what-input/-/what-input-5.2.10.tgz#f79f5b65cf95d75e55e6d580bb0a6b98174cad4e"
@@ -9834,7 +8952,7 @@ which-module@^2.0.0:
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
-which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1:
+which@^1.2.9, which@^1.3.0, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -9853,13 +8971,6 @@ word-wrap@^1.2.3, word-wrap@~1.2.3:
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
-worker-farm@^1.7.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8"
- integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==
- dependencies:
- errno "~0.1.7"
-
wrap-ansi@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
@@ -9971,7 +9082,7 @@ yargs@^12.0.5:
y18n "^3.2.1 || ^4.0.0"
yargs-parser "^11.1.1"
-yargs@^13.2.4, yargs@^13.3.0, yargs@^13.3.2:
+yargs@^13.2.4, yargs@^13.3.0:
version "13.3.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==
From dd87e9a2f1725ed505300c9ad8b87e26a906ff01 Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Wed, 2 Sep 2020 14:13:36 +0100
Subject: [PATCH 43/63] During verification, only check user trust status
As part of new device verification, we were waiting for "cross-signing ready"
which means _both_ the public keys are trusted by this device _and_ private keys
are available. There's no guarantee that the private keys will ever arrive, so
it's too strict to wait for this as a blocking flow. This relaxes things to wait
only for the current device to trust public keys.
Fixes https://github.com/vector-im/element-web/issues/14970
---
src/stores/SetupEncryptionStore.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/stores/SetupEncryptionStore.js b/src/stores/SetupEncryptionStore.js
index 63b8c428eb..ee3b9c9de5 100644
--- a/src/stores/SetupEncryptionStore.js
+++ b/src/stores/SetupEncryptionStore.js
@@ -137,10 +137,10 @@ export class SetupEncryptionStore extends EventEmitter {
}
}
- _onUserTrustStatusChanged = async (userId) => {
+ _onUserTrustStatusChanged = (userId) => {
if (userId !== MatrixClientPeg.get().getUserId()) return;
- const crossSigningReady = await MatrixClientPeg.get().isCrossSigningReady();
- if (crossSigningReady) {
+ const publicKeysTrusted = MatrixClientPeg.get().getCrossSigningId();
+ if (publicKeysTrusted) {
this.phase = PHASE_DONE;
this.emit("update");
}
@@ -150,7 +150,7 @@ export class SetupEncryptionStore extends EventEmitter {
this._setActiveVerificationRequest(request);
}
- onVerificationRequestChange = async () => {
+ onVerificationRequestChange = () => {
if (this.verificationRequest.cancelled) {
this.verificationRequest.off("change", this.onVerificationRequestChange);
this.verificationRequest = null;
@@ -161,8 +161,8 @@ export class SetupEncryptionStore extends EventEmitter {
// At this point, the verification has finished, we just need to wait for
// cross signing to be ready to use, so wait for the user trust status to
// change (or change to DONE if it's already ready).
- const crossSigningReady = await MatrixClientPeg.get().isCrossSigningReady();
- this.phase = crossSigningReady ? PHASE_DONE : PHASE_BUSY;
+ const publicKeysTrusted = MatrixClientPeg.get().getCrossSigningId();
+ this.phase = publicKeysTrusted ? PHASE_DONE : PHASE_BUSY;
this.emit("update");
}
}
From 4262a99f678feec1194e85c0ef5abc5e7262ea5b Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Wed, 2 Sep 2020 14:29:41 +0100
Subject: [PATCH 44/63] Tune cross-signing toasts when 4S is missing
For the case where cross-signing is trusted on device but secret storage does
not exist, we were showing "verify this device", which is not the best match
from the existing toasts. This tunes the checks to instead show "set up
encryption" which is at least a bit closer.
Part of https://github.com/vector-im/element-web/issues/14970
---
src/DeviceListener.ts | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts
index b05f0fcd68..156d8db61b 100644
--- a/src/DeviceListener.ts
+++ b/src/DeviceListener.ts
@@ -220,7 +220,10 @@ export default class DeviceListener {
await cli.downloadKeys([cli.getUserId()]);
// cross signing isn't enabled - nag to enable it
// There are 3 different toasts for:
- if (cli.getStoredCrossSigningForUser(cli.getUserId())) {
+ if (
+ !cli.getCrossSigningId() &&
+ cli.getStoredCrossSigningForUser(cli.getUserId())
+ ) {
// Cross-signing on account but this device doesn't trust the master key (verify this session)
showSetupEncryptionToast(SetupKind.VERIFY_THIS_SESSION);
} else {
From 9b12355b2a30831e56abc9a1bb9f6a3159dc0937 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Wed, 2 Sep 2020 08:59:24 -0600
Subject: [PATCH 45/63] Appease the linter
---
.../views/dialogs/EditCommunityPrototypeDialog.tsx | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx b/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx
index 66b49ea7b7..3071854b3e 100644
--- a/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx
+++ b/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx
@@ -145,9 +145,10 @@ export default class EditCommunityPrototypeDialog extends React.PureComponent
-
- {preview}
-
+ {preview}
{_t("Add image (optional)")}
From beb77799f6a19486e1621667096ce587cbe39018 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Wed, 2 Sep 2020 17:26:23 +0100
Subject: [PATCH 46/63] Respect user preference for whether pills should have
an avatar or not
---
src/components/views/elements/ReplyThread.js | 10 ++++++++--
src/components/views/settings/BridgeTile.js | 5 +++--
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/src/components/views/elements/ReplyThread.js b/src/components/views/elements/ReplyThread.js
index 409bf9e01f..d9fd456a0e 100644
--- a/src/components/views/elements/ReplyThread.js
+++ b/src/components/views/elements/ReplyThread.js
@@ -331,8 +331,14 @@ export default class ReplyThread extends React.Component {
{
_t('In reply to ', {}, {
'a': (sub) => { sub } ,
- 'pill': ,
+ 'pill': (
+
+ ),
})
}
;
diff --git a/src/components/views/settings/BridgeTile.js b/src/components/views/settings/BridgeTile.js
index 5b74e44c9e..e9c58518e4 100644
--- a/src/components/views/settings/BridgeTile.js
+++ b/src/components/views/settings/BridgeTile.js
@@ -24,6 +24,7 @@ import {makeUserPermalink} from "../../../utils/permalinks/Permalinks";
import BaseAvatar from "../avatars/BaseAvatar";
import AccessibleButton from "../elements/AccessibleButton";
import {replaceableComponent} from "../../../utils/replaceableComponent";
+import SettingsStore from "../../../settings/SettingsStore";
@replaceableComponent("views.settings.BridgeTile")
export default class BridgeTile extends React.PureComponent {
@@ -56,7 +57,7 @@ export default class BridgeTile extends React.PureComponent {
type={Pill.TYPE_USER_MENTION}
room={this.props.room}
url={makeUserPermalink(content.creator)}
- shouldShowPillAvatar={true}
+ shouldShowPillAvatar={SettingsStore.getValue("Pill.shouldShowPillAvatar")}
/>,
});
}
@@ -66,7 +67,7 @@ export default class BridgeTile extends React.PureComponent {
type={Pill.TYPE_USER_MENTION}
room={this.props.room}
url={makeUserPermalink(this.props.ev.getSender())}
- shouldShowPillAvatar={true}
+ shouldShowPillAvatar={SettingsStore.getValue("Pill.shouldShowPillAvatar")}
/>,
});
From 24006588d57bf024def307b789ca5cae3ff53957 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 3 Sep 2020 10:34:19 +0100
Subject: [PATCH 47/63] iterate PR
---
src/components/views/elements/EditableText.js | 5 -----
src/components/views/rooms/MemberList.js | 3 ++-
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/src/components/views/elements/EditableText.js b/src/components/views/elements/EditableText.js
index e28fcffbf8..49eb331aef 100644
--- a/src/components/views/elements/EditableText.js
+++ b/src/components/views/elements/EditableText.js
@@ -60,13 +60,8 @@ export default class EditableText extends React.Component {
this.placeholder = false;
this._editable_div = createRef();
-
- this.state = {
- phase: EditableText.Phases.Display,
- };
}
-
state = {
phase: EditableText.Phases.Display,
};
diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js
index 33b98f977d..212e9bfad8 100644
--- a/src/components/views/rooms/MemberList.js
+++ b/src/components/views/rooms/MemberList.js
@@ -56,7 +56,8 @@ export default class MemberList extends React.Component {
}
}
- componentDidMount() {
+ // eslint-disable-next-line camelcase
+ UNSAFE_componentWillMount() {
const cli = MatrixClientPeg.get();
this._mounted = true;
if (cli.hasLazyLoadMembersEnabled()) {
From 7efa9ba77d0e170432578ab76a1455c804939fa6 Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Thu, 3 Sep 2020 13:23:50 +0100
Subject: [PATCH 48/63] Fix DOM nesting error in cross-signing panel
The spinner can't be inside a `` element. This also changes to block spinner
to match key backup.
---
src/components/views/settings/CrossSigningPanel.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/views/settings/CrossSigningPanel.js b/src/components/views/settings/CrossSigningPanel.js
index 847bcf3da3..2562fa141b 100644
--- a/src/components/views/settings/CrossSigningPanel.js
+++ b/src/components/views/settings/CrossSigningPanel.js
@@ -163,8 +163,8 @@ export default class CrossSigningPanel extends React.PureComponent {
let summarisedStatus;
if (homeserverSupportsCrossSigning === undefined) {
- const InlineSpinner = sdk.getComponent('views.elements.InlineSpinner');
- summarisedStatus =
;
+ const Spinner = sdk.getComponent('views.elements.Spinner');
+ summarisedStatus = ;
} else if (!homeserverSupportsCrossSigning) {
summarisedStatus = {_t(
"Your homeserver does not support cross-signing.",
From 18d25acf4f0b826ea3e6ae1abce4f98e1879519f Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Thu, 3 Sep 2020 13:43:14 +0100
Subject: [PATCH 49/63] Organise cross-signing / secret storage rageshake
details
This changes to a common prefix for cross-signing and secret storage details so
they appear all together in the alpha-sorted report.
---
src/rageshake/submit-rageshake.ts | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/src/rageshake/submit-rageshake.ts b/src/rageshake/submit-rageshake.ts
index 448562b68a..dd60cde16d 100644
--- a/src/rageshake/submit-rageshake.ts
+++ b/src/rageshake/submit-rageshake.ts
@@ -90,32 +90,31 @@ async function collectBugReport(opts: IOpts = {}, gzipLogs = true) {
body.append('device_keys', keys.join(', '));
body.append('cross_signing_key', client.getCrossSigningId());
- body.append('device_keys', keys.join(', '));
-
// add cross-signing status information
const crossSigning = client._crypto._crossSigningInfo;
const secretStorage = client._crypto._secretStorage;
+ body.append("cross_signing_ready", String(await client.isCrossSigningReady()));
+ body.append("cross_signing_supported_by_hs",
+ String(await client.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")));
body.append("cross_signing_key", crossSigning.getId());
- body.append("cross_signing_pk_in_ssss",
+ body.append("cross_signing_pk_in_secret_storage",
String(!!(await crossSigning.isStoredInSecretStorage(secretStorage))));
- body.append("ssss_key_in_account", String(!!(await secretStorage.hasKey())));
const pkCache = client.getCrossSigningCacheCallbacks();
- body.append("master_pk_cached",
+ body.append("cross_signing_master_pk_cached",
String(!!(pkCache && await pkCache.getCrossSigningKeyCache("master"))));
- body.append("self_signing_pk_cached",
+ body.append("cross_signing_self_signing_pk_cached",
String(!!(pkCache && await pkCache.getCrossSigningKeyCache("self_signing"))));
- body.append("user_signing_pk_cached",
+ body.append("cross_signing_user_signing_pk_cached",
String(!!(pkCache && await pkCache.getCrossSigningKeyCache("user_signing"))));
+ body.append("secret_storage_ready", String(await client.isSecretStorageReady()));
+ body.append("secret_storage_key_in_account", String(!!(await secretStorage.hasKey())));
+
const sessionBackupKeyFromCache = await client._crypto.getSessionBackupPrivateKey();
body.append("session_backup_key_cached", String(!!sessionBackupKeyFromCache));
body.append("session_backup_key_well_formed", String(sessionBackupKeyFromCache instanceof Uint8Array));
- body.append("cross_signing_supported_by_hs",
- String(await client.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")));
- body.append("cross_signing_ready", String(await client.isCrossSigningReady()));
- body.append("secret_storage_ready", String(await client.isSecretStorageReady()));
}
}
From fb2bde94faec98e647e87445e3590215b477350f Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Thu, 3 Sep 2020 14:50:49 +0100
Subject: [PATCH 50/63] Rename CrossSigningManager to SecurityManager
The file encompasses bits of cross-signing and also secret storage / secure
backup.
---
src/DeviceListener.ts | 2 +-
src/MatrixClientPeg.ts | 2 +-
src/{CrossSigningManager.js => SecurityManager.js} | 4 ++--
.../views/dialogs/keybackup/CreateKeyBackupDialog.js | 2 +-
.../views/dialogs/secretstorage/CreateSecretStorageDialog.js | 2 +-
.../views/dialogs/keybackup/RestoreKeyBackupDialog.js | 2 +-
src/components/views/settings/CrossSigningPanel.js | 2 +-
src/stores/SetupEncryptionStore.js | 2 +-
src/toasts/SetupEncryptionToast.ts | 2 +-
src/verification.js | 2 +-
10 files changed, 11 insertions(+), 11 deletions(-)
rename src/{CrossSigningManager.js => SecurityManager.js} (98%)
diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts
index 156d8db61b..aa0508924d 100644
--- a/src/DeviceListener.ts
+++ b/src/DeviceListener.ts
@@ -30,7 +30,7 @@ import {
showToast as showUnverifiedSessionsToast,
} from "./toasts/UnverifiedSessionToast";
import { privateShouldBeEncrypted } from "./createRoom";
-import { isSecretStorageBeingAccessed, accessSecretStorage } from "./CrossSigningManager";
+import { isSecretStorageBeingAccessed, accessSecretStorage } from "./SecurityManager";
import { isSecureBackupRequired } from './utils/WellKnownUtils';
import { isLoggedIn } from './components/structures/MatrixChat';
diff --git a/src/MatrixClientPeg.ts b/src/MatrixClientPeg.ts
index be16f5fe10..9589130e7f 100644
--- a/src/MatrixClientPeg.ts
+++ b/src/MatrixClientPeg.ts
@@ -31,7 +31,7 @@ import {verificationMethods} from 'matrix-js-sdk/src/crypto';
import MatrixClientBackedSettingsHandler from "./settings/handlers/MatrixClientBackedSettingsHandler";
import * as StorageManager from './utils/StorageManager';
import IdentityAuthClient from './IdentityAuthClient';
-import { crossSigningCallbacks } from './CrossSigningManager';
+import { crossSigningCallbacks } from './SecurityManager';
import {SHOW_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
export interface IMatrixClientCreds {
diff --git a/src/CrossSigningManager.js b/src/SecurityManager.js
similarity index 98%
rename from src/CrossSigningManager.js
rename to src/SecurityManager.js
index 0353bfc5ae..891f43b705 100644
--- a/src/CrossSigningManager.js
+++ b/src/SecurityManager.js
@@ -1,5 +1,5 @@
/*
-Copyright 2019 The Matrix.org Foundation C.I.C.
+Copyright 2019, 2020 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.
@@ -142,7 +142,7 @@ const onSecretRequested = async function({
return;
}
if (!deviceTrust || !deviceTrust.isVerified()) {
- console.log(`CrossSigningManager: Ignoring request from untrusted device ${deviceId}`);
+ console.log(`Ignoring secret request from untrusted device ${deviceId}`);
return;
}
if (
diff --git a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js
index c3aef9109a..ab39a094db 100644
--- a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js
+++ b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js
@@ -21,7 +21,7 @@ import * as sdk from '../../../../index';
import {MatrixClientPeg} from '../../../../MatrixClientPeg';
import PropTypes from 'prop-types';
import {_t, _td} from '../../../../languageHandler';
-import { accessSecretStorage } from '../../../../CrossSigningManager';
+import { accessSecretStorage } from '../../../../SecurityManager';
import AccessibleButton from "../../../../components/views/elements/AccessibleButton";
import {copyNode} from "../../../../utils/strings";
import PassphraseField from "../../../../components/views/auth/PassphraseField";
diff --git a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js
index 0a1a0b02b3..07ff3c9b76 100644
--- a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js
+++ b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js
@@ -22,7 +22,7 @@ import {MatrixClientPeg} from '../../../../MatrixClientPeg';
import FileSaver from 'file-saver';
import {_t, _td} from '../../../../languageHandler';
import Modal from '../../../../Modal';
-import { promptForBackupPassphrase } from '../../../../CrossSigningManager';
+import { promptForBackupPassphrase } from '../../../../SecurityManager';
import {copyNode} from "../../../../utils/strings";
import {SSOAuthEntry} from "../../../../components/views/auth/InteractiveAuthEntryComponents";
import PassphraseField from "../../../../components/views/auth/PassphraseField";
diff --git a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js
index dd34dfbbf0..2362133460 100644
--- a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js
+++ b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js
@@ -21,7 +21,7 @@ import * as sdk from '../../../../index';
import {MatrixClientPeg} from '../../../../MatrixClientPeg';
import { MatrixClient } from 'matrix-js-sdk';
import { _t } from '../../../../languageHandler';
-import { accessSecretStorage } from '../../../../CrossSigningManager';
+import { accessSecretStorage } from '../../../../SecurityManager';
const RESTORE_TYPE_PASSPHRASE = 0;
const RESTORE_TYPE_RECOVERYKEY = 1;
diff --git a/src/components/views/settings/CrossSigningPanel.js b/src/components/views/settings/CrossSigningPanel.js
index 2562fa141b..656fa15a95 100644
--- a/src/components/views/settings/CrossSigningPanel.js
+++ b/src/components/views/settings/CrossSigningPanel.js
@@ -19,7 +19,7 @@ import React from 'react';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
-import { accessSecretStorage } from '../../../CrossSigningManager';
+import { accessSecretStorage } from '../../../SecurityManager';
import Modal from '../../../Modal';
export default class CrossSigningPanel extends React.PureComponent {
diff --git a/src/stores/SetupEncryptionStore.js b/src/stores/SetupEncryptionStore.js
index ee3b9c9de5..981ce6eca9 100644
--- a/src/stores/SetupEncryptionStore.js
+++ b/src/stores/SetupEncryptionStore.js
@@ -16,7 +16,7 @@ limitations under the License.
import EventEmitter from 'events';
import { MatrixClientPeg } from '../MatrixClientPeg';
-import { accessSecretStorage, AccessCancelledError } from '../CrossSigningManager';
+import { accessSecretStorage, AccessCancelledError } from '../SecurityManager';
import { PHASE_DONE as VERIF_PHASE_DONE } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
export const PHASE_INTRO = 0;
diff --git a/src/toasts/SetupEncryptionToast.ts b/src/toasts/SetupEncryptionToast.ts
index d35bbf1c88..9dbc4acafc 100644
--- a/src/toasts/SetupEncryptionToast.ts
+++ b/src/toasts/SetupEncryptionToast.ts
@@ -19,7 +19,7 @@ import * as sdk from "../index";
import { _t } from "../languageHandler";
import DeviceListener from "../DeviceListener";
import SetupEncryptionDialog from "../components/views/dialogs/SetupEncryptionDialog";
-import { accessSecretStorage } from "../CrossSigningManager";
+import { accessSecretStorage } from "../SecurityManager";
import ToastStore from "../stores/ToastStore";
import GenericToast from "../components/views/toasts/GenericToast";
diff --git a/src/verification.js b/src/verification.js
index 36fb8b0e4f..819370f239 100644
--- a/src/verification.js
+++ b/src/verification.js
@@ -21,7 +21,7 @@ import * as sdk from './index';
import { _t } from './languageHandler';
import {RightPanelPhases} from "./stores/RightPanelStorePhases";
import {findDMForUser} from './createRoom';
-import {accessSecretStorage} from './CrossSigningManager';
+import {accessSecretStorage} from './SecurityManager';
import {verificationMethods} from 'matrix-js-sdk/src/crypto';
import {Action} from './dispatcher/actions';
From 1479690ac45ad4e8fe188235908d410f0693838c Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Fri, 28 Aug 2020 10:45:20 +0100
Subject: [PATCH 51/63] RightPanel use room instead of roomId
---
src/components/structures/RightPanel.js | 20 ++++++++++----------
src/components/structures/RoomView.js | 2 +-
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js
index a4e3254e4c..beba09d359 100644
--- a/src/components/structures/RightPanel.js
+++ b/src/components/structures/RightPanel.js
@@ -34,7 +34,7 @@ import {Action} from "../../dispatcher/actions";
export default class RightPanel extends React.Component {
static get propTypes() {
return {
- roomId: PropTypes.string, // if showing panels for a given room, this is set
+ room: PropTypes.string, // if showing panels for a given room, this is set
groupId: PropTypes.string, // if showing panels for a given group, this is set
user: PropTypes.object, // used if we know the user ahead of opening the panel
};
@@ -161,13 +161,13 @@ export default class RightPanel extends React.Component {
}
onRoomStateMember(ev, state, member) {
- if (member.roomId !== this.props.roomId) {
+ if (member.roomId !== this.props.room.roomId) {
return;
}
// redraw the badge on the membership list
- if (this.state.phase === RightPanelPhases.RoomMemberList && member.roomId === this.props.roomId) {
+ if (this.state.phase === RightPanelPhases.RoomMemberList && member.roomId === this.props.room.roomId) {
this._delayedUpdate();
- } else if (this.state.phase === RightPanelPhases.RoomMemberInfo && member.roomId === this.props.roomId &&
+ } else if (this.state.phase === RightPanelPhases.RoomMemberInfo && member.roomId === this.props.room.roomId &&
member.userId === this.state.member.userId) {
// refresh the member info (e.g. new power level)
this._delayedUpdate();
@@ -226,8 +226,8 @@ export default class RightPanel extends React.Component {
switch (this.state.phase) {
case RightPanelPhases.RoomMemberList:
- if (this.props.roomId) {
- panel = ;
+ if (this.props.room.roomId) {
+ panel = ;
}
break;
case RightPanelPhases.GroupMemberList:
@@ -242,8 +242,8 @@ export default class RightPanel extends React.Component {
case RightPanelPhases.EncryptionPanel:
panel = ;
break;
case RightPanelPhases.Room3pidMemberInfo:
- panel = ;
+ panel = ;
break;
case RightPanelPhases.GroupMemberInfo:
panel = ;
break;
case RightPanelPhases.FilePanel:
- panel = ;
+ panel = ;
break;
}
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index a79e5b0aa8..f576de8dae 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -2064,7 +2064,7 @@ export default createReactClass({
const showRightPanel = !forceHideRightPanel && this.state.room && this.state.showRightPanel;
const rightPanel = showRightPanel
- ?
+ ?
: null;
const timelineClasses = classNames("mx_RoomView_timeline", {
From 8b4250c1429478c40666a0eb55db6073d82a1e51 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Fri, 28 Aug 2020 10:46:29 +0100
Subject: [PATCH 52/63] expose RightPanelStore in window
---
src/@types/global.d.ts | 2 ++
src/stores/RightPanelStore.ts | 2 ++
2 files changed, 4 insertions(+)
diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts
index 84340d8219..1a361e7b55 100644
--- a/src/@types/global.d.ts
+++ b/src/@types/global.d.ts
@@ -28,6 +28,7 @@ import SettingsStore from "../settings/SettingsStore";
import {ActiveRoomObserver} from "../ActiveRoomObserver";
import {Notifier} from "../Notifier";
import type {Renderer} from "react-dom";
+import RightPanelStore from "../stores/RightPanelStore";
declare global {
interface Window {
@@ -49,6 +50,7 @@ declare global {
singletonModalManager: ModalManager;
mxSettingsStore: SettingsStore;
mxNotifier: typeof Notifier;
+ mxRightPanelStore: RightPanelStore;
}
interface Document {
diff --git a/src/stores/RightPanelStore.ts b/src/stores/RightPanelStore.ts
index c1799978ad..34445d007b 100644
--- a/src/stores/RightPanelStore.ts
+++ b/src/stores/RightPanelStore.ts
@@ -223,3 +223,5 @@ export default class RightPanelStore extends Store {
return RightPanelStore.instance;
}
}
+
+window.mxRightPanelStore = RightPanelStore.getSharedInstance();
From c7e40d0751f7594891d9ef91eb95b59f1eb87d8a Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 3 Sep 2020 15:00:14 +0100
Subject: [PATCH 53/63] Fix MemberAvatar props interface
---
src/components/views/avatars/MemberAvatar.tsx | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/src/components/views/avatars/MemberAvatar.tsx b/src/components/views/avatars/MemberAvatar.tsx
index 1d23d85b0f..8fd51d3715 100644
--- a/src/components/views/avatars/MemberAvatar.tsx
+++ b/src/components/views/avatars/MemberAvatar.tsx
@@ -16,23 +16,24 @@ limitations under the License.
*/
import React from 'react';
+import {RoomMember} from "matrix-js-sdk/src/models/room-member";
+
import dis from "../../../dispatcher/dispatcher";
import {Action} from "../../../dispatcher/actions";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import BaseAvatar from "./BaseAvatar";
interface IProps {
- // TODO: replace with correct type
- member: any;
- fallbackUserId: string;
+ member: RoomMember;
+ fallbackUserId?: string;
width: number;
height: number;
- resizeMethod: string;
+ resizeMethod?: string;
// The onClick to give the avatar
- onClick: React.MouseEventHandler;
+ onClick?: React.MouseEventHandler;
// Whether the onClick of the avatar should be overriden to dispatch `Action.ViewUser`
- viewUserOnClick: boolean;
- title: string;
+ viewUserOnClick?: boolean;
+ title?: string;
}
interface IState {
From ad9be61477b72bef1a3db5e8a26bec88b92aa3a6 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 3 Sep 2020 15:01:32 +0100
Subject: [PATCH 54/63] Move HeaderButtons to an abstract class
---
src/components/views/right_panel/GroupHeaderButtons.tsx | 2 --
src/components/views/right_panel/HeaderButtons.tsx | 4 +---
src/components/views/right_panel/RoomHeaderButtons.tsx | 4 ----
3 files changed, 1 insertion(+), 9 deletions(-)
diff --git a/src/components/views/right_panel/GroupHeaderButtons.tsx b/src/components/views/right_panel/GroupHeaderButtons.tsx
index 44237e401f..c468658eb6 100644
--- a/src/components/views/right_panel/GroupHeaderButtons.tsx
+++ b/src/components/views/right_panel/GroupHeaderButtons.tsx
@@ -46,8 +46,6 @@ export default class GroupHeaderButtons extends HeaderButtons {
}
protected onAction(payload: ActionPayload) {
- super.onAction(payload);
-
if (payload.action === Action.ViewUser) {
if ((payload as ViewUserPayload).member) {
this.setPhase(RightPanelPhases.RoomMemberInfo, {member: payload.member});
diff --git a/src/components/views/right_panel/HeaderButtons.tsx b/src/components/views/right_panel/HeaderButtons.tsx
index bbb783ccb9..e922959bbb 100644
--- a/src/components/views/right_panel/HeaderButtons.tsx
+++ b/src/components/views/right_panel/HeaderButtons.tsx
@@ -65,9 +65,7 @@ export default abstract class HeaderButtons extends React.Component) {
dis.dispatch({
diff --git a/src/components/views/right_panel/RoomHeaderButtons.tsx b/src/components/views/right_panel/RoomHeaderButtons.tsx
index 7ac547f499..671d9b0068 100644
--- a/src/components/views/right_panel/RoomHeaderButtons.tsx
+++ b/src/components/views/right_panel/RoomHeaderButtons.tsx
@@ -36,13 +36,9 @@ const MEMBER_PHASES = [
export default class RoomHeaderButtons extends HeaderButtons {
constructor(props) {
super(props, HeaderKind.Room);
- this.onMembersClicked = this.onMembersClicked.bind(this);
- this.onFilesClicked = this.onFilesClicked.bind(this);
- this.onNotificationsClicked = this.onNotificationsClicked.bind(this);
}
protected onAction(payload: ActionPayload) {
- super.onAction(payload);
if (payload.action === Action.ViewUser) {
if (payload.member) {
this.setPhase(RightPanelPhases.RoomMemberInfo, {member: payload.member});
From 6d4de4d22b4dc0d8e18c1bae452ed89e690b5ad5 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 3 Sep 2020 11:48:29 +0100
Subject: [PATCH 55/63] tidy up ScrollPanel comments
---
src/components/structures/ScrollPanel.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js
index 51113f4f56..4ff101c0e9 100644
--- a/src/components/structures/ScrollPanel.js
+++ b/src/components/structures/ScrollPanel.js
@@ -97,7 +97,7 @@ export default createReactClass({
/* startAtBottom: if set to true, the view is assumed to start
* scrolled to the bottom.
- * XXX: It's likley this is unecessary and can be derived from
+ * XXX: It's likely this is unnecessary and can be derived from
* stickyBottom, but I'm adding an extra parameter to ensure
* behaviour stays the same for other uses of ScrollPanel.
* If so, let's remove this parameter down the line.
@@ -141,6 +141,7 @@ export default createReactClass({
/* style: styles to add to the top-level div
*/
style: PropTypes.object,
+
/* resizeNotifier: ResizeNotifier to know when middle column has changed size
*/
resizeNotifier: PropTypes.object,
From 3a8499259e248179b8b3a5f10968942583fc31fc Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Fri, 28 Aug 2020 10:47:30 +0100
Subject: [PATCH 56/63] factor out the useIsEncrypted hook
---
src/hooks/useIsEncrypted.ts | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 src/hooks/useIsEncrypted.ts
diff --git a/src/hooks/useIsEncrypted.ts b/src/hooks/useIsEncrypted.ts
new file mode 100644
index 0000000000..79f3e539cd
--- /dev/null
+++ b/src/hooks/useIsEncrypted.ts
@@ -0,0 +1,36 @@
+/*
+Copyright 2020 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 {useCallback, useState} from "react";
+import {MatrixClient} from "matrix-js-sdk/src/client";
+import {MatrixEvent} from "matrix-js-sdk/src/models/event";
+import {Room} from "matrix-js-sdk/src/models/room";
+
+import {useEventEmitter} from "./useEventEmitter";
+
+// Hook to simplify watching whether a Matrix room is encrypted, returns undefined if room is undefined
+export function useIsEncrypted(cli: MatrixClient, room?: Room): boolean | undefined {
+ const [isEncrypted, setIsEncrypted] = useState(room ? cli.isRoomEncrypted(room.roomId) : undefined);
+
+ const update = useCallback((event: MatrixEvent) => {
+ if (room && event.getType() === "m.room.encryption") {
+ setIsEncrypted(cli.isRoomEncrypted(room.roomId));
+ }
+ }, [cli, room]);
+ useEventEmitter(room ? room.currentState : undefined, "RoomState.events", update);
+
+ return isEncrypted;
+}
From 280690cf3c7618b3873e87750c1ee826a942d46b Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Fri, 28 Aug 2020 10:59:52 +0100
Subject: [PATCH 57/63] use useIsEncrypted hook in UserInfo
---
src/components/views/right_panel/UserInfo.js | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js
index 71ee86a1ea..518bb133ce 100644
--- a/src/components/views/right_panel/UserInfo.js
+++ b/src/components/views/right_panel/UserInfo.js
@@ -45,6 +45,7 @@ import EncryptionPanel from "./EncryptionPanel";
import { useAsyncMemo } from '../../../hooks/useAsyncMemo';
import { verifyUser, legacyVerifyUser, verifyDevice } from '../../../verification';
import {Action} from "../../../dispatcher/actions";
+import {useIsEncrypted} from "../../../hooks/useIsEncrypted";
const _disambiguateDevices = (devices) => {
const names = Object.create(null);
@@ -124,18 +125,6 @@ async function openDMForUser(matrixClient, userId) {
createRoom(createRoomOptions);
}
-function useIsEncrypted(cli, room) {
- const [isEncrypted, setIsEncrypted] = useState(room ? cli.isRoomEncrypted(room.roomId) : undefined);
-
- const update = useCallback((event) => {
- if (event.getType() === "m.room.encryption") {
- setIsEncrypted(cli.isRoomEncrypted(room.roomId));
- }
- }, [cli, room]);
- useEventEmitter(room ? room.currentState : undefined, "RoomState.events", update);
- return isEncrypted;
-}
-
function useHasCrossSigningKeys(cli, member, canVerify, setUpdating) {
return useAsyncMemo(async () => {
if (!canVerify) {
@@ -1485,7 +1474,7 @@ const UserInfoHeader = ({onClose, member, e2eStatus}) => {
const UserInfo = ({user, groupId, roomId, onClose, phase=RightPanelPhases.RoomMemberInfo, ...props}) => {
const cli = useContext(MatrixClientContext);
- // Load room if we are given a room id and memoize it
+ // Load room if we are given a room id and memoize it - this can be undefined for User Info/Group Member Info
const room = useMemo(() => roomId ? cli.getRoom(roomId) : null, [cli, roomId]);
// fetch latest room member if we have a room, so we don't show historical information, falling back to user
const member = useMemo(() => room ? (room.getMember(user.userId) || user) : user, [room, user]);
From da6cc5c2e94b4af0b478ab85214378e5dd584d2e Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Thu, 3 Sep 2020 15:20:46 +0100
Subject: [PATCH 58/63] Tweak Security settings section headers
This brings us slightly closer to the version Design is working from in terms of
section naming.
Prep for https://github.com/vector-im/element-web/issues/13895
---
res/css/views/settings/tabs/_SettingsTab.scss | 3 ++-
.../views/settings/E2eAdvancedPanel.js | 2 +-
.../tabs/user/SecurityUserSettingsTab.js | 26 ++++++++++++-------
src/i18n/strings/en_EN.json | 15 ++++++-----
4 files changed, 27 insertions(+), 19 deletions(-)
diff --git a/res/css/views/settings/tabs/_SettingsTab.scss b/res/css/views/settings/tabs/_SettingsTab.scss
index e3a61e6825..5f00ed86f7 100644
--- a/res/css/views/settings/tabs/_SettingsTab.scss
+++ b/res/css/views/settings/tabs/_SettingsTab.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2019 New Vector Ltd
+Copyright 2019, 2020 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.
@@ -22,6 +22,7 @@ limitations under the License.
font-size: $font-20px;
font-weight: 600;
color: $primary-fg-color;
+ margin-bottom: 10px;
}
.mx_SettingsTab_heading:nth-child(n + 2) {
diff --git a/src/components/views/settings/E2eAdvancedPanel.js b/src/components/views/settings/E2eAdvancedPanel.js
index 2ba6190a9b..0650630901 100644
--- a/src/components/views/settings/E2eAdvancedPanel.js
+++ b/src/components/views/settings/E2eAdvancedPanel.js
@@ -25,7 +25,7 @@ const SETTING_MANUALLY_VERIFY_ALL_SESSIONS = "e2ee.manuallyVerifyAllSessions";
const E2eAdvancedPanel = props => {
const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');
return
-
{_t("Advanced")}
+
{_t("Encryption")}
{warning}
- {_t("Security & Privacy")}
+ {_t("Where you’re logged in")}
- {_t("Where you’re logged in")}
{_t(
"Manage the names of and sign out of your sessions below or " +
@@ -351,11 +350,15 @@ export default class SecurityUserSettingsTab extends React.Component {
- {keyBackup}
- {eventIndex}
- {crossSigning}
- {this._renderCurrentDeviceInfo()}
-
+
{_t("Encryption")}
+
+ {keyBackup}
+ {eventIndex}
+ {crossSigning}
+ {this._renderCurrentDeviceInfo()}
+
+
{_t("Privacy")}
+
{_t("Analytics")}
{_t(
@@ -372,9 +375,12 @@ export default class SecurityUserSettingsTab extends React.Component {
- {this._renderIgnoredUsers()}
- {this._renderManageInvites()}
-
+
{_t("Advanced")}
+
+ {this._renderIgnoredUsers()}
+ {this._renderManageInvites()}
+
+
);
}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index bc0845386d..95b6c23a77 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -62,11 +62,6 @@
"Server may be unavailable, overloaded, or you hit a bug.": "Server may be unavailable, overloaded, or you hit a bug.",
"The server does not support the room version specified.": "The server does not support the room version specified.",
"Failure to create room": "Failure to create room",
- "Cancel entering passphrase?": "Cancel entering passphrase?",
- "Are you sure you want to cancel entering passphrase?": "Are you sure you want to cancel entering passphrase?",
- "Go Back": "Go Back",
- "Cancel": "Cancel",
- "Setting up keys": "Setting up keys",
"Sun": "Sun",
"Mon": "Mon",
"Tue": "Tue",
@@ -142,6 +137,11 @@
"Missing room_id in request": "Missing room_id in request",
"Room %(roomId)s not visible": "Room %(roomId)s not visible",
"Missing user_id in request": "Missing user_id in request",
+ "Cancel entering passphrase?": "Cancel entering passphrase?",
+ "Are you sure you want to cancel entering passphrase?": "Are you sure you want to cancel entering passphrase?",
+ "Go Back": "Go Back",
+ "Cancel": "Cancel",
+ "Setting up keys": "Setting up keys",
"Messages": "Messages",
"Actions": "Actions",
"Advanced": "Advanced",
@@ -684,6 +684,7 @@
"Public Name": "Public Name",
"Last seen": "Last seen",
"Failed to set display name": "Failed to set display name",
+ "Encryption": "Encryption",
"Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.",
"Securely cache encrypted messages locally for them to appear in search results, using ": "Securely cache encrypted messages locally for them to appear in search results, using ",
" to store messages from ": " to store messages from ",
@@ -907,10 +908,10 @@
"Message search": "Message search",
"Cross-signing": "Cross-signing",
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.",
- "Security & Privacy": "Security & Privacy",
"Where you’re logged in": "Where you’re logged in",
"Manage the names of and sign out of your sessions below or
verify them in your User Profile .": "Manage the names of and sign out of your sessions below or
verify them in your User Profile .",
"A session's public name is visible to people you communicate with": "A session's public name is visible to people you communicate with",
+ "Privacy": "Privacy",
"%(brand)s collects anonymous analytics to allow us to improve the application.": "%(brand)s collects anonymous analytics to allow us to improve the application.",
"Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.",
"Learn more about how we use analytics.": "Learn more about how we use analytics.",
@@ -993,7 +994,7 @@
"Members only (since the point in time of selecting this option)": "Members only (since the point in time of selecting this option)",
"Members only (since they were invited)": "Members only (since they were invited)",
"Members only (since they joined)": "Members only (since they joined)",
- "Encryption": "Encryption",
+ "Security & Privacy": "Security & Privacy",
"Once enabled, encryption cannot be disabled.": "Once enabled, encryption cannot be disabled.",
"Encrypted": "Encrypted",
"Who can access this room?": "Who can access this room?",
From bdfb77077ae4e3bdf3a20937614f81300b453af4 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 3 Sep 2020 16:08:10 +0100
Subject: [PATCH 59/63] Fix RightPanel propTypes
---
src/components/structures/RightPanel.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js
index beba09d359..53459b9457 100644
--- a/src/components/structures/RightPanel.js
+++ b/src/components/structures/RightPanel.js
@@ -21,6 +21,8 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
+import {Room} from "matrix-js-sdk/src/models/room";
+
import * as sdk from '../../index';
import dis from '../../dispatcher/dispatcher';
import RateLimitedFunc from '../../ratelimitedfunc';
@@ -34,7 +36,7 @@ import {Action} from "../../dispatcher/actions";
export default class RightPanel extends React.Component {
static get propTypes() {
return {
- room: PropTypes.string, // if showing panels for a given room, this is set
+ room: PropTypes.instanceOf(Room), // if showing panels for a given room, this is set
groupId: PropTypes.string, // if showing panels for a given group, this is set
user: PropTypes.object, // used if we know the user ahead of opening the panel
};
From 4ef3ef40dbdb1f9c6b772b1a5bcf1883b715ee09 Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett"
Date: Thu, 3 Sep 2020 16:47:56 +0100
Subject: [PATCH 60/63] Change to import
---
src/components/views/settings/CrossSigningPanel.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/views/settings/CrossSigningPanel.js b/src/components/views/settings/CrossSigningPanel.js
index 656fa15a95..3eeb072e2d 100644
--- a/src/components/views/settings/CrossSigningPanel.js
+++ b/src/components/views/settings/CrossSigningPanel.js
@@ -21,6 +21,7 @@ import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
import { accessSecretStorage } from '../../../SecurityManager';
import Modal from '../../../Modal';
+import Spinner from '../elements/Spinner';
export default class CrossSigningPanel extends React.PureComponent {
constructor(props) {
@@ -163,7 +164,6 @@ export default class CrossSigningPanel extends React.PureComponent {
let summarisedStatus;
if (homeserverSupportsCrossSigning === undefined) {
- const Spinner = sdk.getComponent('views.elements.Spinner');
summarisedStatus = ;
} else if (!homeserverSupportsCrossSigning) {
summarisedStatus = {_t(
From 05c3f5c38102a72fd44d4c2d5b5c084b6c65b5fb Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 3 Sep 2020 17:05:33 +0100
Subject: [PATCH 61/63] remove redundant key
---
src/components/structures/FilePanel.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/structures/FilePanel.js b/src/components/structures/FilePanel.js
index 5a2d858c9d..8aa1192458 100644
--- a/src/components/structures/FilePanel.js
+++ b/src/components/structures/FilePanel.js
@@ -216,7 +216,7 @@ class FilePanel extends React.Component {
// "(" + this.state.timelineSet._timelines.join(", ") + ")" + " with key " + this.props.roomId);
return (
-
Date: Fri, 4 Sep 2020 09:24:12 +0100
Subject: [PATCH 62/63] Fix soft crash from TruncatedList in the
createReactClass conversion
---
src/components/views/rooms/MemberList.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js
index e84b27b590..1fdc67eee7 100644
--- a/src/components/views/rooms/MemberList.js
+++ b/src/components/views/rooms/MemberList.js
@@ -247,15 +247,15 @@ export default class MemberList extends React.Component {
return filteredAndSortedMembers;
}
- _createOverflowTileJoined(overflowCount, totalCount) {
+ _createOverflowTileJoined = (overflowCount, totalCount) => {
return this._createOverflowTile(overflowCount, totalCount, this._showMoreJoinedMemberList);
- }
+ };
- _createOverflowTileInvited(overflowCount, totalCount) {
+ _createOverflowTileInvited = (overflowCount, totalCount) => {
return this._createOverflowTile(overflowCount, totalCount, this._showMoreInvitedMemberList);
- }
+ };
- _createOverflowTile(overflowCount, totalCount, onClick) {
+ _createOverflowTile = (overflowCount, totalCount, onClick) => {
// For now we'll pretend this is any entity. It should probably be a separate tile.
const EntityTile = sdk.getComponent("rooms.EntityTile");
const BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
@@ -266,7 +266,7 @@ export default class MemberList extends React.Component {
} name={text} presenceState="online" suppressOnHover={true}
onClick={onClick} />
);
- }
+ };
_showMoreJoinedMemberList = () => {
this.setState({
From f28c396b1eec1f91b52e01c1db3c227ba2370ed3 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Fri, 4 Sep 2020 12:14:43 +0100
Subject: [PATCH 63/63] Fix HeaderButtons handler bindings
---
.../views/right_panel/GroupHeaderButtons.tsx | 10 ++++------
.../views/right_panel/RoomHeaderButtons.tsx | 12 ++++++------
2 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/src/components/views/right_panel/GroupHeaderButtons.tsx b/src/components/views/right_panel/GroupHeaderButtons.tsx
index c468658eb6..dd4a82e645 100644
--- a/src/components/views/right_panel/GroupHeaderButtons.tsx
+++ b/src/components/views/right_panel/GroupHeaderButtons.tsx
@@ -41,8 +41,6 @@ interface IProps {}
export default class GroupHeaderButtons extends HeaderButtons {
constructor(props: IProps) {
super(props, HeaderKind.Group);
- this.onMembersClicked = this.onMembersClicked.bind(this);
- this.onRoomsClicked = this.onRoomsClicked.bind(this);
}
protected onAction(payload: ActionPayload) {
@@ -68,7 +66,7 @@ export default class GroupHeaderButtons extends HeaderButtons {
}
}
- private onMembersClicked() {
+ private onMembersClicked = () => {
if (this.state.phase === RightPanelPhases.GroupMemberInfo) {
// send the active phase to trigger a toggle
this.setPhase(RightPanelPhases.GroupMemberInfo);
@@ -76,12 +74,12 @@ export default class GroupHeaderButtons extends HeaderButtons {
// This toggles for us, if needed
this.setPhase(RightPanelPhases.GroupMemberList);
}
- }
+ };
- private onRoomsClicked() {
+ private onRoomsClicked = () => {
// This toggles for us, if needed
this.setPhase(RightPanelPhases.GroupRoomList);
- }
+ };
renderButtons() {
return [
diff --git a/src/components/views/right_panel/RoomHeaderButtons.tsx b/src/components/views/right_panel/RoomHeaderButtons.tsx
index 671d9b0068..7d732b8ae3 100644
--- a/src/components/views/right_panel/RoomHeaderButtons.tsx
+++ b/src/components/views/right_panel/RoomHeaderButtons.tsx
@@ -54,7 +54,7 @@ export default class RoomHeaderButtons extends HeaderButtons {
}
}
- private onMembersClicked() {
+ private onMembersClicked = () => {
if (this.state.phase === RightPanelPhases.RoomMemberInfo) {
// send the active phase to trigger a toggle
// XXX: we should pass refireParams here but then it won't collapse as we desire it to
@@ -63,17 +63,17 @@ export default class RoomHeaderButtons extends HeaderButtons {
// This toggles for us, if needed
this.setPhase(RightPanelPhases.RoomMemberList);
}
- }
+ };
- private onFilesClicked() {
+ private onFilesClicked = () => {
// This toggles for us, if needed
this.setPhase(RightPanelPhases.FilePanel);
- }
+ };
- private onNotificationsClicked() {
+ private onNotificationsClicked = () => {
// This toggles for us, if needed
this.setPhase(RightPanelPhases.NotificationPanel);
- }
+ };
public renderButtons() {
return [