diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx index 726ff547ff..9d9d57d8a6 100644 --- a/src/components/structures/ContextMenu.tsx +++ b/src/components/structures/ContextMenu.tsx @@ -22,6 +22,7 @@ import classNames from "classnames"; import {Key} from "../../Keyboard"; import {Writeable} from "../../@types/common"; +import {replaceableComponent} from "../../utils/replaceableComponent"; // Shamelessly ripped off Modal.js. There's probably a better way // of doing reusable widgets like dialog boxes & menus where we go and @@ -91,6 +92,7 @@ interface IState { // Generic ContextMenu Portal wrapper // all options inside the menu should be of role=menuitem/menuitemcheckbox/menuitemradiobutton and have tabIndex={-1} // this will allow the ContextMenu to manage its own focus using arrow keys as per the ARIA guidelines. +@replaceableComponent("structures.ContextMenu") export class ContextMenu extends React.PureComponent<IProps, IState> { private initialFocus: HTMLElement; @@ -467,6 +469,7 @@ export const useContextMenu = <T extends any = HTMLElement>(): ContextMenuTuple< return [isOpen, button, open, close, setIsOpen]; }; +@replaceableComponent("structures.LegacyContextMenu") export default class LegacyContextMenu extends ContextMenu { render() { return this.renderMenu(false); diff --git a/src/components/structures/CustomRoomTagPanel.js b/src/components/structures/CustomRoomTagPanel.js index a79bdafeb5..73359f17a5 100644 --- a/src/components/structures/CustomRoomTagPanel.js +++ b/src/components/structures/CustomRoomTagPanel.js @@ -21,7 +21,9 @@ import * as sdk from '../../index'; import dis from '../../dispatcher/dispatcher'; import classNames from 'classnames'; import * as FormattingUtils from '../../utils/FormattingUtils'; +import {replaceableComponent} from "../../utils/replaceableComponent"; +@replaceableComponent("structures.CustomRoomTagPanel") class CustomRoomTagPanel extends React.Component { constructor(props) { super(props); diff --git a/src/components/structures/FilePanel.js b/src/components/structures/FilePanel.js index 0e4df4621d..9f5a0b6211 100644 --- a/src/components/structures/FilePanel.js +++ b/src/components/structures/FilePanel.js @@ -26,10 +26,12 @@ import { _t } from '../../languageHandler'; import BaseCard from "../views/right_panel/BaseCard"; import {RightPanelPhases} from "../../stores/RightPanelStorePhases"; import DesktopBuildsNotice, {WarningKind} from "../views/elements/DesktopBuildsNotice"; +import {replaceableComponent} from "../../utils/replaceableComponent"; /* * Component which shows the filtered file using a TimelinePanel */ +@replaceableComponent("structures.FilePanel") class FilePanel extends React.Component { static propTypes = { roomId: PropTypes.string.isRequired, diff --git a/src/components/structures/GenericErrorPage.js b/src/components/structures/GenericErrorPage.js index ab7d4f9311..cfd2016d47 100644 --- a/src/components/structures/GenericErrorPage.js +++ b/src/components/structures/GenericErrorPage.js @@ -16,7 +16,9 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; +import {replaceableComponent} from "../../utils/replaceableComponent"; +@replaceableComponent("structures.GenericErrorPage") export default class GenericErrorPage extends React.PureComponent { static propTypes = { title: PropTypes.object.isRequired, // jsx for title diff --git a/src/components/structures/GroupFilterPanel.js b/src/components/structures/GroupFilterPanel.js index 96aa1ba728..976b2d81a5 100644 --- a/src/components/structures/GroupFilterPanel.js +++ b/src/components/structures/GroupFilterPanel.js @@ -30,7 +30,9 @@ import MatrixClientContext from "../../contexts/MatrixClientContext"; import AutoHideScrollbar from "./AutoHideScrollbar"; import SettingsStore from "../../settings/SettingsStore"; import UserTagTile from "../views/elements/UserTagTile"; +import {replaceableComponent} from "../../utils/replaceableComponent"; +@replaceableComponent("structures.GroupFilterPanel") class GroupFilterPanel extends React.Component { static contextType = MatrixClientContext; diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index bbc4187298..b4b871a0b4 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -39,6 +39,7 @@ import {Group} from "matrix-js-sdk"; import {allSettled, sleep} from "../../utils/promise"; import RightPanelStore from "../../stores/RightPanelStore"; import AutoHideScrollbar from "./AutoHideScrollbar"; +import {replaceableComponent} from "../../utils/replaceableComponent"; const LONG_DESC_PLACEHOLDER = _td( `<h1>HTML for your community's page</h1> @@ -391,6 +392,7 @@ class FeaturedUser extends React.Component { const GROUP_JOINPOLICY_OPEN = "open"; const GROUP_JOINPOLICY_INVITE = "invite"; +@replaceableComponent("structures.GroupView") export default class GroupView extends React.Component { static propTypes = { groupId: PropTypes.string.isRequired, diff --git a/src/components/structures/HostSignupAction.tsx b/src/components/structures/HostSignupAction.tsx index 9cf84a9379..769775d549 100644 --- a/src/components/structures/HostSignupAction.tsx +++ b/src/components/structures/HostSignupAction.tsx @@ -22,11 +22,13 @@ import { import { _t } from "../../languageHandler"; import { HostSignupStore } from "../../stores/HostSignupStore"; import SdkConfig from "../../SdkConfig"; +import {replaceableComponent} from "../../utils/replaceableComponent"; interface IProps {} interface IState {} +@replaceableComponent("structures.HostSignupAction") export default class HostSignupAction extends React.PureComponent<IProps, IState> { private openDialog = async () => { await HostSignupStore.instance.setHostSignupActive(true); diff --git a/src/components/structures/IndicatorScrollbar.js b/src/components/structures/IndicatorScrollbar.js index cd5510de9d..341ab2df71 100644 --- a/src/components/structures/IndicatorScrollbar.js +++ b/src/components/structures/IndicatorScrollbar.js @@ -17,7 +17,9 @@ limitations under the License. import React from "react"; import PropTypes from "prop-types"; import AutoHideScrollbar from "./AutoHideScrollbar"; +import {replaceableComponent} from "../../utils/replaceableComponent"; +@replaceableComponent("structures.IndicatorScrollbar") export default class IndicatorScrollbar extends React.Component { static propTypes = { // If true, the scrollbar will append mx_IndicatorScrollbar_leftOverflowIndicator diff --git a/src/components/structures/InteractiveAuth.js b/src/components/structures/InteractiveAuth.js index ac7049ed88..9b61f71fd7 100644 --- a/src/components/structures/InteractiveAuth.js +++ b/src/components/structures/InteractiveAuth.js @@ -22,9 +22,11 @@ import PropTypes from 'prop-types'; import getEntryComponentForLoginType from '../views/auth/InteractiveAuthEntryComponents'; import * as sdk from '../../index'; +import {replaceableComponent} from "../../utils/replaceableComponent"; export const ERROR_USER_CANCELLED = new Error("User cancelled auth session"); +@replaceableComponent("structures.InteractiveAuthComponent") export default class InteractiveAuthComponent extends React.Component { static propTypes = { // matrix client to use for UI auth requests diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx index 82dd9443cc..88c7a71b35 100644 --- a/src/components/structures/LeftPanel.tsx +++ b/src/components/structures/LeftPanel.tsx @@ -40,6 +40,7 @@ import { MatrixClientPeg } from "../../MatrixClientPeg"; import RoomListNumResults from "../views/rooms/RoomListNumResults"; import LeftPanelWidget from "./LeftPanelWidget"; import SpacePanel from "../views/spaces/SpacePanel"; +import {replaceableComponent} from "../../utils/replaceableComponent"; interface IProps { isMinimized: boolean; @@ -60,6 +61,7 @@ const cssClasses = [ "mx_RoomSublist_showNButton", ]; +@replaceableComponent("structures.LeftPanel") export default class LeftPanel extends React.Component<IProps, IState> { private listContainerRef: React.RefObject<HTMLDivElement> = createRef(); private groupFilterPanelWatcherRef: string; diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index 3e6d56fd54..15e90a383a 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -56,6 +56,7 @@ import Modal from "../../Modal"; import { ICollapseConfig } from "../../resizer/distributors/collapse"; import HostSignupContainer from '../views/host_signup/HostSignupContainer'; import { IOpts } from "../../createRoom"; +import {replaceableComponent} from "../../utils/replaceableComponent"; // We need to fetch each pinned message individually (if we don't already have it) // so each pinned message may trigger a request. Limit the number per room for sanity. @@ -128,6 +129,7 @@ interface IState { * * Components mounted below us can access the matrix client via the react context. */ +@replaceableComponent("structures.LoggedInView") class LoggedInView extends React.Component<IProps, IState> { static displayName = 'LoggedInView'; diff --git a/src/components/structures/MainSplit.js b/src/components/structures/MainSplit.js index 47dfe83ad6..5818d303fc 100644 --- a/src/components/structures/MainSplit.js +++ b/src/components/structures/MainSplit.js @@ -17,7 +17,9 @@ limitations under the License. import React from 'react'; import { Resizable } from 're-resizable'; +import {replaceableComponent} from "../../utils/replaceableComponent"; +@replaceableComponent("structures.MainSplit") export default class MainSplit extends React.Component { _onResizeStart = () => { this.props.resizeNotifier.startResizing(); diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 1700b627db..0272633e8f 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -84,6 +84,7 @@ import DialPadModal from "../views/voip/DialPadModal"; import { showToast as showMobileGuideToast } from '../../toasts/MobileGuideToast'; import SpaceStore from "../../stores/SpaceStore"; import SpaceRoomDirectory from "./SpaceRoomDirectory"; +import {replaceableComponent} from "../../utils/replaceableComponent"; /** constants for MatrixChat.state.view */ export enum Views { @@ -208,6 +209,7 @@ interface IState { roomJustCreatedOpts?: IOpts; } +@replaceableComponent("structures.MatrixChat") export default class MatrixChat extends React.PureComponent<IProps, IState> { static displayName = "MatrixChat"; diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 9deda54bee..0f9ef70ec1 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -34,6 +34,7 @@ import {textForEvent} from "../../TextForEvent"; import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResizer"; import DMRoomMap from "../../utils/DMRoomMap"; import NewRoomIntro from "../views/rooms/NewRoomIntro"; +import {replaceableComponent} from "../../utils/replaceableComponent"; const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes const continuedTypes = ['m.sticker', 'm.room.message']; @@ -66,6 +67,7 @@ const isMembershipChange = (e) => e.getType() === 'm.room.member' || e.getType() /* (almost) stateless UI component which builds the event tiles in the room timeline. */ +@replaceableComponent("structures.MessagePanel") export default class MessagePanel extends React.Component { static propTypes = { // true to give the component a 'display: none' style. diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js index e0551eecdb..2ab11dad25 100644 --- a/src/components/structures/MyGroups.js +++ b/src/components/structures/MyGroups.js @@ -24,7 +24,9 @@ import dis from '../../dispatcher/dispatcher'; import AccessibleButton from '../views/elements/AccessibleButton'; import MatrixClientContext from "../../contexts/MatrixClientContext"; import AutoHideScrollbar from "./AutoHideScrollbar"; +import {replaceableComponent} from "../../utils/replaceableComponent"; +@replaceableComponent("structures.MyGroups") export default class MyGroups extends React.Component { static contextType = MatrixClientContext; diff --git a/src/components/structures/NonUrgentToastContainer.tsx b/src/components/structures/NonUrgentToastContainer.tsx index 8d415df4dd..7c193ec9d7 100644 --- a/src/components/structures/NonUrgentToastContainer.tsx +++ b/src/components/structures/NonUrgentToastContainer.tsx @@ -18,6 +18,7 @@ import * as React from "react"; import { ComponentClass } from "../../@types/common"; import NonUrgentToastStore from "../../stores/NonUrgentToastStore"; import { UPDATE_EVENT } from "../../stores/AsyncStore"; +import {replaceableComponent} from "../../utils/replaceableComponent"; interface IProps { } @@ -26,6 +27,7 @@ interface IState { toasts: ComponentClass[], } +@replaceableComponent("structures.NonUrgentToastContainer") export default class NonUrgentToastContainer extends React.PureComponent<IProps, IState> { public constructor(props, context) { super(props, context); diff --git a/src/components/structures/NotificationPanel.js b/src/components/structures/NotificationPanel.js index b4eb6c187b..41aafc8b13 100644 --- a/src/components/structures/NotificationPanel.js +++ b/src/components/structures/NotificationPanel.js @@ -23,10 +23,12 @@ import { _t } from '../../languageHandler'; import {MatrixClientPeg} from "../../MatrixClientPeg"; import * as sdk from "../../index"; import BaseCard from "../views/right_panel/BaseCard"; +import {replaceableComponent} from "../../utils/replaceableComponent"; /* * Component which shows the global notification list using a TimelinePanel */ +@replaceableComponent("structures.NotificationPanel") class NotificationPanel extends React.Component { static propTypes = { onClose: PropTypes.func.isRequired, diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 3d9df2e927..5bcb3b2450 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -34,7 +34,9 @@ import MatrixClientContext from "../../contexts/MatrixClientContext"; import {Action} from "../../dispatcher/actions"; import RoomSummaryCard from "../views/right_panel/RoomSummaryCard"; import WidgetCard from "../views/right_panel/WidgetCard"; +import {replaceableComponent} from "../../utils/replaceableComponent"; +@replaceableComponent("structures.RightPanel") export default class RightPanel extends React.Component { static get propTypes() { return { diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index 7387e1aac0..363c67262b 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -34,6 +34,7 @@ import GroupFilterOrderStore from "../../stores/GroupFilterOrderStore"; import GroupStore from "../../stores/GroupStore"; import FlairStore from "../../stores/FlairStore"; import CountlyAnalytics from "../../CountlyAnalytics"; +import {replaceableComponent} from "../../utils/replaceableComponent"; const MAX_NAME_LENGTH = 80; const MAX_TOPIC_LENGTH = 800; @@ -42,6 +43,7 @@ function track(action) { Analytics.trackEvent('RoomDirectory', action); } +@replaceableComponent("structures.RoomDirectory") export default class RoomDirectory extends React.Component { static propTypes = { initialText: PropTypes.string, diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx index a64e40bc65..fda09f9774 100644 --- a/src/components/structures/RoomSearch.tsx +++ b/src/components/structures/RoomSearch.tsx @@ -25,6 +25,7 @@ import AccessibleButton from "../views/elements/AccessibleButton"; import { Action } from "../../dispatcher/actions"; import RoomListStore from "../../stores/room-list/RoomListStore"; import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition"; +import {replaceableComponent} from "../../utils/replaceableComponent"; interface IProps { isMinimized: boolean; @@ -37,6 +38,7 @@ interface IState { focused: boolean; } +@replaceableComponent("structures.RoomSearch") export default class RoomSearch extends React.PureComponent<IProps, IState> { private dispatcherRef: string; private inputRef: React.RefObject<HTMLInputElement> = createRef(); diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js index aa4bceba74..8b70998be0 100644 --- a/src/components/structures/RoomStatusBar.js +++ b/src/components/structures/RoomStatusBar.js @@ -23,6 +23,7 @@ import Resend from '../../Resend'; import dis from '../../dispatcher/dispatcher'; import {messageForResourceLimitError, messageForSendError} from '../../utils/ErrorUtils'; import {Action} from "../../dispatcher/actions"; +import {replaceableComponent} from "../../utils/replaceableComponent"; const STATUS_BAR_HIDDEN = 0; const STATUS_BAR_EXPANDED = 1; @@ -35,6 +36,7 @@ function getUnsentMessages(room) { }); } +@replaceableComponent("structures.RoomStatusBar") export default class RoomStatusBar extends React.Component { static propTypes = { // the room this statusbar is representing. diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 90f6daf6cb..b57638413b 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -82,6 +82,7 @@ import { Container, WidgetLayoutStore } from "../../stores/widgets/WidgetLayoutS import { objectHasDiff } from "../../utils/objects"; import SpaceRoomView from "./SpaceRoomView"; import { IOpts } from "../../createRoom"; +import {replaceableComponent} from "../../utils/replaceableComponent"; const DEBUG = false; let debuglog = function(msg: string) {}; @@ -195,6 +196,7 @@ export interface IState { dragCounter: number; } +@replaceableComponent("structures.RoomView") export default class RoomView extends React.Component<IProps, IState> { private readonly dispatcherRef: string; private readonly roomStoreToken: EventSubscription; diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 744400df3c..3a9b2b8a77 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -19,6 +19,7 @@ import PropTypes from 'prop-types'; import { Key } from '../../Keyboard'; import Timer from '../../utils/Timer'; import AutoHideScrollbar from "./AutoHideScrollbar"; +import {replaceableComponent} from "../../utils/replaceableComponent"; const DEBUG_SCROLL = false; @@ -83,6 +84,7 @@ if (DEBUG_SCROLL) { * offset as normal. */ +@replaceableComponent("structures.ScrollPanel") export default class ScrollPanel extends React.Component { static propTypes = { /* stickyBottom: if set to true, then once the user hits the bottom of diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js index c1e3ad0cf2..6daa8526bc 100644 --- a/src/components/structures/SearchBox.js +++ b/src/components/structures/SearchBox.js @@ -22,7 +22,9 @@ import dis from '../../dispatcher/dispatcher'; import {throttle} from 'lodash'; import AccessibleButton from '../../components/views/elements/AccessibleButton'; import classNames from 'classnames'; +import {replaceableComponent} from "../../utils/replaceableComponent"; +@replaceableComponent("structures.SearchBox") export default class SearchBox extends React.Component { static propTypes = { onSearch: PropTypes.func, diff --git a/src/components/structures/TabbedView.tsx b/src/components/structures/TabbedView.tsx index 21f9f3f5d6..0097d55cf5 100644 --- a/src/components/structures/TabbedView.tsx +++ b/src/components/structures/TabbedView.tsx @@ -20,6 +20,7 @@ import * as React from "react"; import {_t} from '../../languageHandler'; import * as sdk from "../../index"; import AutoHideScrollbar from './AutoHideScrollbar'; +import {replaceableComponent} from "../../utils/replaceableComponent"; /** * Represents a tab for the TabbedView. @@ -45,6 +46,7 @@ interface IState { activeTabIndex: number; } +@replaceableComponent("structures.TabbedView") export default class TabbedView extends React.Component<IProps, IState> { constructor(props: IProps) { super(props); diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index 6bc1f70ba1..f32b8ed0a9 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -37,6 +37,7 @@ import EditorStateTransfer from '../../utils/EditorStateTransfer'; import {haveTileForEvent} from "../views/rooms/EventTile"; import {UIFeature} from "../../settings/UIFeature"; import {objectHasDiff} from "../../utils/objects"; +import {replaceableComponent} from "../../utils/replaceableComponent"; const PAGINATE_SIZE = 20; const INITIAL_SIZE = 20; @@ -55,6 +56,7 @@ if (DEBUG) { * * Also responsible for handling and sending read receipts. */ +@replaceableComponent("structures.TimelinePanel") class TimelinePanel extends React.Component { static propTypes = { // The js-sdk EventTimelineSet object for the timeline sequence we are diff --git a/src/components/structures/ToastContainer.tsx b/src/components/structures/ToastContainer.tsx index 513cca82c3..1fd3e3419f 100644 --- a/src/components/structures/ToastContainer.tsx +++ b/src/components/structures/ToastContainer.tsx @@ -17,12 +17,14 @@ limitations under the License. import * as React from "react"; import ToastStore, {IToast} from "../../stores/ToastStore"; import classNames from "classnames"; +import {replaceableComponent} from "../../utils/replaceableComponent"; interface IState { toasts: IToast<any>[]; countSeen: number; } +@replaceableComponent("structures.ToastContainer") export default class ToastContainer extends React.Component<{}, IState> { constructor(props, context) { super(props, context); diff --git a/src/components/structures/UploadBar.tsx b/src/components/structures/UploadBar.tsx index b9d157ee00..4a1fd4313d 100644 --- a/src/components/structures/UploadBar.tsx +++ b/src/components/structures/UploadBar.tsx @@ -25,6 +25,7 @@ import { Action } from "../../dispatcher/actions"; import ProgressBar from "../views/elements/ProgressBar"; import AccessibleButton from "../views/elements/AccessibleButton"; import { IUpload } from "../../models/IUpload"; +import {replaceableComponent} from "../../utils/replaceableComponent"; interface IProps { room: Room; @@ -35,6 +36,7 @@ interface IState { uploadsHere: IUpload[]; } +@replaceableComponent("structures.UploadBar") export default class UploadBar extends React.Component<IProps, IState> { private dispatcherRef: string; private mounted: boolean; diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index b31a5f4b8e..0543cc4d07 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -56,6 +56,7 @@ import HostSignupAction from "./HostSignupAction"; import { IHostSignupConfig } from "../views/dialogs/HostSignupDialogTypes"; import SpaceStore, { UPDATE_SELECTED_SPACE } from "../../stores/SpaceStore"; import RoomName from "../views/elements/RoomName"; +import {replaceableComponent} from "../../utils/replaceableComponent"; interface IProps { isMinimized: boolean; @@ -69,6 +70,7 @@ interface IState { selectedSpace?: Room; } +@replaceableComponent("structures.UserMenu") export default class UserMenu extends React.Component<IProps, IState> { private dispatcherRef: string; private themeWatcherRef: string; diff --git a/src/components/structures/UserView.js b/src/components/structures/UserView.js index 8e21771bb9..dc05193ece 100644 --- a/src/components/structures/UserView.js +++ b/src/components/structures/UserView.js @@ -23,7 +23,9 @@ import * as sdk from "../../index"; import Modal from '../../Modal'; import { _t } from '../../languageHandler'; import HomePage from "./HomePage"; +import {replaceableComponent} from "../../utils/replaceableComponent"; +@replaceableComponent("structures.UserView") export default class UserView extends React.Component { static get propTypes() { return { diff --git a/src/components/structures/ViewSource.js b/src/components/structures/ViewSource.js index ca6c0d4226..b762ad3fca 100644 --- a/src/components/structures/ViewSource.js +++ b/src/components/structures/ViewSource.js @@ -21,8 +21,10 @@ import PropTypes from 'prop-types'; import SyntaxHighlight from '../views/elements/SyntaxHighlight'; import {_t} from "../../languageHandler"; import * as sdk from "../../index"; +import {replaceableComponent} from "../../utils/replaceableComponent"; +@replaceableComponent("structures.ViewSource") export default class ViewSource extends React.Component { static propTypes = { content: PropTypes.object.isRequired, diff --git a/src/components/structures/auth/CompleteSecurity.js b/src/components/structures/auth/CompleteSecurity.js index c73691611d..eee5667052 100644 --- a/src/components/structures/auth/CompleteSecurity.js +++ b/src/components/structures/auth/CompleteSecurity.js @@ -26,7 +26,9 @@ import { PHASE_CONFIRM_SKIP, } from '../../../stores/SetupEncryptionStore'; import SetupEncryptionBody from "./SetupEncryptionBody"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("structures.auth.CompleteSecurity") export default class CompleteSecurity extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/structures/auth/E2eSetup.js b/src/components/structures/auth/E2eSetup.js index d97a972718..4e51ae828c 100644 --- a/src/components/structures/auth/E2eSetup.js +++ b/src/components/structures/auth/E2eSetup.js @@ -19,7 +19,9 @@ import PropTypes from 'prop-types'; import AuthPage from '../../views/auth/AuthPage'; import CompleteSecurityBody from '../../views/auth/CompleteSecurityBody'; import CreateCrossSigningDialog from '../../views/dialogs/security/CreateCrossSigningDialog'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("structures.auth.E2eSetup") export default class E2eSetup extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/structures/auth/ForgotPassword.js b/src/components/structures/auth/ForgotPassword.js index 5a39fe9fd9..31a5de0222 100644 --- a/src/components/structures/auth/ForgotPassword.js +++ b/src/components/structures/auth/ForgotPassword.js @@ -27,6 +27,7 @@ import classNames from 'classnames'; import AuthPage from "../../views/auth/AuthPage"; import CountlyAnalytics from "../../../CountlyAnalytics"; import ServerPicker from "../../views/elements/ServerPicker"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // Phases // Show the forgot password inputs @@ -38,6 +39,7 @@ const PHASE_EMAIL_SENT = 3; // User has clicked the link in email and completed reset const PHASE_DONE = 4; +@replaceableComponent("structures.auth.ForgotPassword") export default class ForgotPassword extends React.Component { static propTypes = { serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired, diff --git a/src/components/structures/auth/Login.tsx b/src/components/structures/auth/Login.tsx index 96fc39a437..3ab73fb9ac 100644 --- a/src/components/structures/auth/Login.tsx +++ b/src/components/structures/auth/Login.tsx @@ -35,6 +35,7 @@ import InlineSpinner from "../../views/elements/InlineSpinner"; import Spinner from "../../views/elements/Spinner"; import SSOButtons from "../../views/elements/SSOButtons"; import ServerPicker from "../../views/elements/ServerPicker"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // These are used in several places, and come from the js-sdk's autodiscovery // stuff. We define them here so that they'll be picked up by i18n. @@ -99,6 +100,7 @@ interface IState { /* * A wire component which glues together login UI components and Login logic */ +@replaceableComponent("structures.auth.LoginComponent") export default class LoginComponent extends React.PureComponent<IProps, IState> { private unmounted = false; private loginLogic: Login; diff --git a/src/components/structures/auth/Registration.tsx b/src/components/structures/auth/Registration.tsx index f9d338902c..32bdddb82a 100644 --- a/src/components/structures/auth/Registration.tsx +++ b/src/components/structures/auth/Registration.tsx @@ -30,6 +30,7 @@ import Login, {ISSOFlow} from "../../../Login"; import dis from "../../../dispatcher/dispatcher"; import SSOButtons from "../../views/elements/SSOButtons"; import ServerPicker from '../../views/elements/ServerPicker'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { serverConfig: ValidatedServerConfig; @@ -109,6 +110,7 @@ interface IState { ssoFlow?: ISSOFlow; } +@replaceableComponent("structures.auth.Registration") export default class Registration extends React.Component<IProps, IState> { loginLogic: Login; diff --git a/src/components/structures/auth/SetupEncryptionBody.js b/src/components/structures/auth/SetupEncryptionBody.js index 3e7264dfec..f66c434edd 100644 --- a/src/components/structures/auth/SetupEncryptionBody.js +++ b/src/components/structures/auth/SetupEncryptionBody.js @@ -28,6 +28,7 @@ import { PHASE_CONFIRM_SKIP, PHASE_FINISHED, } from '../../../stores/SetupEncryptionStore'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; function keyHasPassphrase(keyInfo) { return ( @@ -37,6 +38,7 @@ function keyHasPassphrase(keyInfo) { ); } +@replaceableComponent("structures.auth.SetupEncryptionBody") export default class SetupEncryptionBody extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/structures/auth/SoftLogout.js b/src/components/structures/auth/SoftLogout.js index a7fe340457..08db3b2efe 100644 --- a/src/components/structures/auth/SoftLogout.js +++ b/src/components/structures/auth/SoftLogout.js @@ -26,6 +26,7 @@ import {sendLoginRequest} from "../../../Login"; import AuthPage from "../../views/auth/AuthPage"; import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY} from "../../../BasePlatform"; import SSOButtons from "../../views/elements/SSOButtons"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const LOGIN_VIEW = { LOADING: 1, @@ -41,6 +42,7 @@ const FLOWS_TO_VIEWS = { "m.login.sso": LOGIN_VIEW.SSO, }; +@replaceableComponent("structures.auth.SoftLogout") export default class SoftLogout extends React.Component { static propTypes = { // Query parameters from MatrixChat diff --git a/src/components/views/auth/AuthBody.js b/src/components/views/auth/AuthBody.js index 7881486a5f..2cb72b5e1d 100644 --- a/src/components/views/auth/AuthBody.js +++ b/src/components/views/auth/AuthBody.js @@ -15,7 +15,9 @@ limitations under the License. */ import React from 'react'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.auth.AuthBody") export default class AuthBody extends React.PureComponent { render() { return <div className="mx_AuthBody"> diff --git a/src/components/views/auth/AuthFooter.js b/src/components/views/auth/AuthFooter.js index 3de5a19350..f167e16283 100644 --- a/src/components/views/auth/AuthFooter.js +++ b/src/components/views/auth/AuthFooter.js @@ -18,7 +18,9 @@ limitations under the License. import { _t } from '../../../languageHandler'; import React from 'react'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.auth.AuthFooter") 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 57499e397c..323299b3a8 100644 --- a/src/components/views/auth/AuthHeader.js +++ b/src/components/views/auth/AuthHeader.js @@ -18,7 +18,9 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.auth.AuthHeader") export default class AuthHeader extends React.Component { static propTypes = { disableLanguageSelector: PropTypes.bool, diff --git a/src/components/views/auth/AuthHeaderLogo.js b/src/components/views/auth/AuthHeaderLogo.js index 2f27885322..b4e04799bb 100644 --- a/src/components/views/auth/AuthHeaderLogo.js +++ b/src/components/views/auth/AuthHeaderLogo.js @@ -15,7 +15,9 @@ limitations under the License. */ import React from 'react'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.auth.AuthHeaderLogo") export default class AuthHeaderLogo extends React.PureComponent { render() { return <div className="mx_AuthHeaderLogo"> diff --git a/src/components/views/auth/CaptchaForm.js b/src/components/views/auth/CaptchaForm.js index e2d7d594fa..50de24d403 100644 --- a/src/components/views/auth/CaptchaForm.js +++ b/src/components/views/auth/CaptchaForm.js @@ -18,12 +18,14 @@ import React, {createRef} from 'react'; import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; import CountlyAnalytics from "../../../CountlyAnalytics"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const DIV_ID = 'mx_recaptcha'; /** * A pure UI component which displays a captcha form. */ +@replaceableComponent("views.auth.CaptchaForm") export default class CaptchaForm extends React.Component { static propTypes = { sitePublicKey: PropTypes.string, diff --git a/src/components/views/auth/CompleteSecurityBody.js b/src/components/views/auth/CompleteSecurityBody.js index 734af3192c..6647bb1200 100644 --- a/src/components/views/auth/CompleteSecurityBody.js +++ b/src/components/views/auth/CompleteSecurityBody.js @@ -15,7 +15,9 @@ limitations under the License. */ import React from 'react'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.auth.CompleteSecurityBody") export default class CompleteSecurityBody extends React.PureComponent { render() { return <div className="mx_CompleteSecurityBody"> diff --git a/src/components/views/auth/CountryDropdown.js b/src/components/views/auth/CountryDropdown.js index 3296b574a4..e21f112865 100644 --- a/src/components/views/auth/CountryDropdown.js +++ b/src/components/views/auth/CountryDropdown.js @@ -22,6 +22,7 @@ import * as sdk from '../../../index'; import {COUNTRIES, getEmojiFlag} from '../../../phonenumber'; import SdkConfig from "../../../SdkConfig"; import { _t } from "../../../languageHandler"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const COUNTRIES_BY_ISO2 = {}; for (const c of COUNTRIES) { @@ -40,6 +41,7 @@ function countryMatchesSearchQuery(query, country) { return false; } +@replaceableComponent("views.auth.CountryDropdown") export default class CountryDropdown extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/auth/InteractiveAuthEntryComponents.js b/src/components/views/auth/InteractiveAuthEntryComponents.js index 7dc1976641..6cbecd22ee 100644 --- a/src/components/views/auth/InteractiveAuthEntryComponents.js +++ b/src/components/views/auth/InteractiveAuthEntryComponents.js @@ -26,6 +26,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import AccessibleButton from "../elements/AccessibleButton"; import Spinner from "../elements/Spinner"; import CountlyAnalytics from "../../../CountlyAnalytics"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; /* This file contains a collection of components which are used by the * InteractiveAuth to prompt the user to enter the information needed @@ -75,6 +76,7 @@ import CountlyAnalytics from "../../../CountlyAnalytics"; export const DEFAULT_PHASE = 0; +@replaceableComponent("views.auth.PasswordAuthEntry") export class PasswordAuthEntry extends React.Component { static LOGIN_TYPE = "m.login.password"; @@ -173,6 +175,7 @@ export class PasswordAuthEntry extends React.Component { } } +@replaceableComponent("views.auth.RecaptchaAuthEntry") export class RecaptchaAuthEntry extends React.Component { static LOGIN_TYPE = "m.login.recaptcha"; @@ -235,6 +238,7 @@ export class RecaptchaAuthEntry extends React.Component { } } +@replaceableComponent("views.auth.TermsAuthEntry") export class TermsAuthEntry extends React.Component { static LOGIN_TYPE = "m.login.terms"; @@ -385,6 +389,7 @@ export class TermsAuthEntry extends React.Component { } } +@replaceableComponent("views.auth.EmailIdentityAuthEntry") export class EmailIdentityAuthEntry extends React.Component { static LOGIN_TYPE = "m.login.email.identity"; @@ -432,6 +437,7 @@ export class EmailIdentityAuthEntry extends React.Component { } } +@replaceableComponent("views.auth.MsisdnAuthEntry") export class MsisdnAuthEntry extends React.Component { static LOGIN_TYPE = "m.login.msisdn"; @@ -578,6 +584,7 @@ export class MsisdnAuthEntry extends React.Component { } } +@replaceableComponent("views.auth.SSOAuthEntry") export class SSOAuthEntry extends React.Component { static propTypes = { matrixClient: PropTypes.object.isRequired, @@ -708,6 +715,7 @@ export class SSOAuthEntry extends React.Component { } } +@replaceableComponent("views.auth.FallbackAuthEntry") export class FallbackAuthEntry extends React.Component { static propTypes = { matrixClient: PropTypes.object.isRequired, diff --git a/src/components/views/auth/PassphraseField.tsx b/src/components/views/auth/PassphraseField.tsx index e240ad61ca..274c244b2a 100644 --- a/src/components/views/auth/PassphraseField.tsx +++ b/src/components/views/auth/PassphraseField.tsx @@ -22,6 +22,7 @@ import SdkConfig from "../../../SdkConfig"; import withValidation, {IFieldState, IValidationResult} from "../elements/Validation"; import {_t, _td} from "../../../languageHandler"; import Field, {IInputProps} from "../elements/Field"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps extends Omit<IInputProps, "onValidate"> { autoFocus?: boolean; @@ -40,6 +41,7 @@ interface IProps extends Omit<IInputProps, "onValidate"> { onValidate(result: IValidationResult); } +@replaceableComponent("views.auth.PassphraseField") class PassphraseField extends PureComponent<IProps> { static defaultProps = { label: _td("Password"), diff --git a/src/components/views/auth/PasswordLogin.tsx b/src/components/views/auth/PasswordLogin.tsx index b2a3d62f55..2a42804a61 100644 --- a/src/components/views/auth/PasswordLogin.tsx +++ b/src/components/views/auth/PasswordLogin.tsx @@ -26,6 +26,7 @@ import withValidation from "../elements/Validation"; import * as Email from "../../../email"; import Field from "../elements/Field"; import CountryDropdown from "./CountryDropdown"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // For validating phone numbers without country codes const PHONE_NUMBER_REGEX = /^[0-9()\-\s]*$/; @@ -66,6 +67,7 @@ enum LoginField { * A pure UI component which displays a username/password form. * The email/username/phone fields are fully-controlled, the password field is not. */ +@replaceableComponent("views.auth.PasswordLogin") export default class PasswordLogin extends React.PureComponent<IProps, IState> { static defaultProps = { onUsernameChanged: function() {}, diff --git a/src/components/views/auth/RegistrationForm.tsx b/src/components/views/auth/RegistrationForm.tsx index e42ed88f99..85e0933be9 100644 --- a/src/components/views/auth/RegistrationForm.tsx +++ b/src/components/views/auth/RegistrationForm.tsx @@ -30,6 +30,7 @@ import PassphraseField from "./PassphraseField"; import CountlyAnalytics from "../../../CountlyAnalytics"; import Field from '../elements/Field'; import RegistrationEmailPromptDialog from '../dialogs/RegistrationEmailPromptDialog'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; enum RegistrationField { Email = "field_email", @@ -80,6 +81,7 @@ interface IState { /* * A pure UI component which displays a registration form. */ +@replaceableComponent("views.auth.RegistrationForm") export default class RegistrationForm extends React.PureComponent<IProps, IState> { static defaultProps = { onValidationChange: console.error, diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index 0205f4e0b9..fca66fcf9b 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -24,10 +24,12 @@ import {_td} from "../../../languageHandler"; import SettingsStore from "../../../settings/SettingsStore"; import {UIFeature} from "../../../settings/UIFeature"; import CountlyAnalytics from "../../../CountlyAnalytics"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // translatable strings for Welcome pages _td("Sign in with SSO"); +@replaceableComponent("views.auth.Welcome") export default class Welcome extends React.PureComponent { constructor(props) { super(props); diff --git a/src/components/views/avatars/DecoratedRoomAvatar.tsx b/src/components/views/avatars/DecoratedRoomAvatar.tsx index d7e012467b..e95022687a 100644 --- a/src/components/views/avatars/DecoratedRoomAvatar.tsx +++ b/src/components/views/avatars/DecoratedRoomAvatar.tsx @@ -30,6 +30,7 @@ import {MatrixClientPeg} from "../../../MatrixClientPeg"; import {_t} from "../../../languageHandler"; import TextWithTooltip from "../elements/TextWithTooltip"; import DMRoomMap from "../../../utils/DMRoomMap"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { room: Room; @@ -68,6 +69,7 @@ function tooltipText(variant: Icon) { } } +@replaceableComponent("views.avatars.DecoratedRoomAvatar") export default class DecoratedRoomAvatar extends React.PureComponent<IProps, IState> { private _dmUser: User; private isUnmounted = false; diff --git a/src/components/views/avatars/GroupAvatar.tsx b/src/components/views/avatars/GroupAvatar.tsx index 51327605c0..a033257871 100644 --- a/src/components/views/avatars/GroupAvatar.tsx +++ b/src/components/views/avatars/GroupAvatar.tsx @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import BaseAvatar from './BaseAvatar'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; export interface IProps { groupId?: string; @@ -28,6 +29,7 @@ export interface IProps { onClick?: React.MouseEventHandler; } +@replaceableComponent("views.avatars.GroupAvatar") export default class GroupAvatar extends React.Component<IProps> { public static defaultProps = { width: 36, diff --git a/src/components/views/avatars/MemberAvatar.tsx b/src/components/views/avatars/MemberAvatar.tsx index 60b043016b..641046aa55 100644 --- a/src/components/views/avatars/MemberAvatar.tsx +++ b/src/components/views/avatars/MemberAvatar.tsx @@ -22,6 +22,7 @@ import dis from "../../../dispatcher/dispatcher"; import {Action} from "../../../dispatcher/actions"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import BaseAvatar from "./BaseAvatar"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps extends Omit<React.ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url"> { member: RoomMember; @@ -42,6 +43,7 @@ interface IState { imageUrl?: string; } +@replaceableComponent("views.avatars.MemberAvatar") export default class MemberAvatar extends React.Component<IProps, IState> { public static defaultProps = { width: 40, diff --git a/src/components/views/avatars/MemberStatusMessageAvatar.js b/src/components/views/avatars/MemberStatusMessageAvatar.js index d5d927106c..acf190f17f 100644 --- a/src/components/views/avatars/MemberStatusMessageAvatar.js +++ b/src/components/views/avatars/MemberStatusMessageAvatar.js @@ -23,7 +23,9 @@ import classNames from 'classnames'; import StatusMessageContextMenu from "../context_menus/StatusMessageContextMenu"; import SettingsStore from "../../../settings/SettingsStore"; import {ContextMenu, ContextMenuButton} from "../../structures/ContextMenu"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.avatars.MemberStatusMessageAvatar") export default class MemberStatusMessageAvatar extends React.Component { static propTypes = { member: PropTypes.object.isRequired, diff --git a/src/components/views/avatars/RoomAvatar.tsx b/src/components/views/avatars/RoomAvatar.tsx index 952b9d4cb6..0a59f6e36a 100644 --- a/src/components/views/avatars/RoomAvatar.tsx +++ b/src/components/views/avatars/RoomAvatar.tsx @@ -23,6 +23,7 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; import * as Avatar from '../../../Avatar'; import {ResizeMethod} from "../../../Avatar"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps extends Omit<ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url" | "onClick"> { // Room may be left unset here, but if it is, @@ -42,6 +43,7 @@ interface IState { urls: string[]; } +@replaceableComponent("views.avatars.RoomAvatar") export default class RoomAvatar extends React.Component<IProps, IState> { public static defaultProps = { width: 36, diff --git a/src/components/views/context_menus/CallContextMenu.tsx b/src/components/views/context_menus/CallContextMenu.tsx index 3557976326..97473059a6 100644 --- a/src/components/views/context_menus/CallContextMenu.tsx +++ b/src/components/views/context_menus/CallContextMenu.tsx @@ -22,11 +22,13 @@ import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; import CallHandler from '../../../CallHandler'; import InviteDialog, { KIND_CALL_TRANSFER } from '../dialogs/InviteDialog'; import Modal from '../../../Modal'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps extends IContextMenuProps { call: MatrixCall; } +@replaceableComponent("views.context_menus.CallContextMenu") export default class CallContextMenu extends React.Component<IProps> { static propTypes = { // js-sdk User object. Not required because it might not exist. diff --git a/src/components/views/context_menus/DialpadContextMenu.tsx b/src/components/views/context_menus/DialpadContextMenu.tsx index e3aed0179b..17abce0c61 100644 --- a/src/components/views/context_menus/DialpadContextMenu.tsx +++ b/src/components/views/context_menus/DialpadContextMenu.tsx @@ -19,6 +19,7 @@ import { _t } from '../../../languageHandler'; import { ContextMenu, IProps as IContextMenuProps } from '../../structures/ContextMenu'; import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; import Dialpad from '../voip/DialPad'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps extends IContextMenuProps { call: MatrixCall; @@ -28,6 +29,7 @@ interface IState { value: string; } +@replaceableComponent("views.context_menus.DialpadContextMenu") export default class DialpadContextMenu extends React.Component<IProps, IState> { constructor(props) { super(props); diff --git a/src/components/views/context_menus/GenericElementContextMenu.js b/src/components/views/context_menus/GenericElementContextMenu.js index cea684b663..e04e3f7695 100644 --- a/src/components/views/context_menus/GenericElementContextMenu.js +++ b/src/components/views/context_menus/GenericElementContextMenu.js @@ -16,6 +16,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; /* * This component can be used to display generic HTML content in a contextual @@ -23,6 +24,7 @@ import PropTypes from 'prop-types'; */ +@replaceableComponent("views.context_menus.GenericElementContextMenu") export default class GenericElementContextMenu extends React.Component { static propTypes = { element: PropTypes.element.isRequired, diff --git a/src/components/views/context_menus/GenericTextContextMenu.js b/src/components/views/context_menus/GenericTextContextMenu.js index 068f83be5f..3d3add006f 100644 --- a/src/components/views/context_menus/GenericTextContextMenu.js +++ b/src/components/views/context_menus/GenericTextContextMenu.js @@ -16,7 +16,9 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.context_menus.GenericTextContextMenu") export default class GenericTextContextMenu extends React.Component { static propTypes = { message: PropTypes.string.isRequired, diff --git a/src/components/views/context_menus/GroupInviteTileContextMenu.js b/src/components/views/context_menus/GroupInviteTileContextMenu.js index 27ef76452f..11a9d90ac2 100644 --- a/src/components/views/context_menus/GroupInviteTileContextMenu.js +++ b/src/components/views/context_menus/GroupInviteTileContextMenu.js @@ -23,7 +23,9 @@ import Modal from '../../../Modal'; import {Group} from 'matrix-js-sdk'; import GroupStore from "../../../stores/GroupStore"; import {MenuItem} from "../../structures/ContextMenu"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.context_menus.GroupInviteTileContextMenu") export default class GroupInviteTileContextMenu extends React.Component { static propTypes = { group: PropTypes.instanceOf(Group).isRequired, diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index 98d0aad578..f97b429abc 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -32,11 +32,13 @@ import { isUrlPermitted } from '../../../HtmlUtils'; import { isContentActionable } from '../../../utils/EventUtils'; import {MenuItem} from "../../structures/ContextMenu"; import {EventType} from "matrix-js-sdk/src/@types/event"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; function canCancel(eventStatus) { return eventStatus === EventStatus.QUEUED || eventStatus === EventStatus.NOT_SENT; } +@replaceableComponent("views.context_menus.MessageContextMenu") export default class MessageContextMenu extends React.Component { static propTypes = { /* the MatrixEvent associated with the context menu */ diff --git a/src/components/views/context_menus/StatusMessageContextMenu.js b/src/components/views/context_menus/StatusMessageContextMenu.js index 5e6f06dd5d..41f0e0ba61 100644 --- a/src/components/views/context_menus/StatusMessageContextMenu.js +++ b/src/components/views/context_menus/StatusMessageContextMenu.js @@ -20,7 +20,9 @@ import { _t } from '../../../languageHandler'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import * as sdk from '../../../index'; import AccessibleButton from '../elements/AccessibleButton'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.context_menus.StatusMessageContextMenu") export default class StatusMessageContextMenu extends React.Component { static propTypes = { // js-sdk User object. Not required because it might not exist. diff --git a/src/components/views/context_menus/TagTileContextMenu.js b/src/components/views/context_menus/TagTileContextMenu.js index 8d690483a8..8dea62690c 100644 --- a/src/components/views/context_menus/TagTileContextMenu.js +++ b/src/components/views/context_menus/TagTileContextMenu.js @@ -22,7 +22,9 @@ import dis from '../../../dispatcher/dispatcher'; import TagOrderActions from '../../../actions/TagOrderActions'; import {MenuItem} from "../../structures/ContextMenu"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.context_menus.TagTileContextMenu") export default class TagTileContextMenu extends React.Component { static propTypes = { tag: PropTypes.string.isRequired, diff --git a/src/components/views/dialogs/AddressPickerDialog.js b/src/components/views/dialogs/AddressPickerDialog.js index 2cd09874b2..929d688e47 100644 --- a/src/components/views/dialogs/AddressPickerDialog.js +++ b/src/components/views/dialogs/AddressPickerDialog.js @@ -33,6 +33,7 @@ import { abbreviateUrl } from '../../../utils/UrlUtils'; import {sleep} from "../../../utils/promise"; import {Key} from "../../../Keyboard"; import {Action} from "../../../dispatcher/actions"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const TRUNCATE_QUERY_LIST = 40; const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200; @@ -43,7 +44,7 @@ const addressTypeName = { 'email': _td("email address"), }; - +@replaceableComponent("views.dialogs.AddressPickerDialog") export default class AddressPickerDialog extends React.Component { static propTypes = { title: PropTypes.string.isRequired, diff --git a/src/components/views/dialogs/AskInviteAnywayDialog.js b/src/components/views/dialogs/AskInviteAnywayDialog.js index c69400977a..e6cd45ba6b 100644 --- a/src/components/views/dialogs/AskInviteAnywayDialog.js +++ b/src/components/views/dialogs/AskInviteAnywayDialog.js @@ -20,7 +20,9 @@ import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import {SettingLevel} from "../../../settings/SettingLevel"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.AskInviteAnywayDialog") export default class AskInviteAnywayDialog extends React.Component { static propTypes = { unknownProfileUsers: PropTypes.array.isRequired, // [ {userId, errorText}... ] diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index 9ba5368ee5..0858e53e50 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -26,6 +26,7 @@ import AccessibleButton from '../elements/AccessibleButton'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import { _t } from "../../../languageHandler"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; /* * Basic container for modal dialogs. @@ -33,6 +34,7 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext"; * Includes a div for the title, and a keypress handler which cancels the * dialog on escape. */ +@replaceableComponent("views.dialogs.BaseDialog") export default class BaseDialog extends React.Component { static propTypes = { // onFinished callback to call when Escape is pressed diff --git a/src/components/views/dialogs/BugReportDialog.js b/src/components/views/dialogs/BugReportDialog.js index c4dd0a1430..8948c14c7c 100644 --- a/src/components/views/dialogs/BugReportDialog.js +++ b/src/components/views/dialogs/BugReportDialog.js @@ -25,7 +25,9 @@ import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; import sendBugReport, {downloadBugReport} from '../../../rageshake/submit-rageshake'; import AccessibleButton from "../elements/AccessibleButton"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.BugReportDialog") export default class BugReportDialog extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx b/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx index 1c8a4ad6f6..d1080566ac 100644 --- a/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx +++ b/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx @@ -31,6 +31,7 @@ import {inviteMultipleToRoom, showAnyInviteErrors} from "../../../RoomInvite"; import StyledCheckbox from "../elements/StyledCheckbox"; import Modal from "../../../Modal"; import ErrorDialog from "./ErrorDialog"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps extends IDialogProps { roomId: string; @@ -52,6 +53,7 @@ interface IState { busy: boolean; } +@replaceableComponent("views.dialogs.CommunityPrototypeInviteDialog") export default class CommunityPrototypeInviteDialog extends React.PureComponent<IProps, IState> { constructor(props: IProps) { super(props); diff --git a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js index 0622dd7dfb..37d5510756 100644 --- a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js +++ b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; /* * A dialog for confirming a redaction. @@ -30,6 +31,7 @@ import { _t } from '../../../languageHandler'; * * To avoid this, we keep the dialog open as long as /redact is in progress. */ +@replaceableComponent("views.dialogs.ConfirmAndWaitRedactDialog") export default class ConfirmAndWaitRedactDialog extends React.PureComponent { constructor(props) { super(props); diff --git a/src/components/views/dialogs/ConfirmRedactDialog.js b/src/components/views/dialogs/ConfirmRedactDialog.js index 2216f9a93a..bd63d3acc1 100644 --- a/src/components/views/dialogs/ConfirmRedactDialog.js +++ b/src/components/views/dialogs/ConfirmRedactDialog.js @@ -17,10 +17,12 @@ limitations under the License. import React from 'react'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; /* * A dialog for confirming a redaction. */ +@replaceableComponent("views.dialogs.ConfirmRedactDialog") export default class ConfirmRedactDialog extends React.Component { render() { const TextInputDialog = sdk.getComponent('views.dialogs.TextInputDialog'); diff --git a/src/components/views/dialogs/ConfirmUserActionDialog.js b/src/components/views/dialogs/ConfirmUserActionDialog.js index 44f57f047e..8827f161f1 100644 --- a/src/components/views/dialogs/ConfirmUserActionDialog.js +++ b/src/components/views/dialogs/ConfirmUserActionDialog.js @@ -20,6 +20,7 @@ import { MatrixClient } from 'matrix-js-sdk'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { GroupMemberType } from '../../../groups'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; /* * A dialog for confirming an operation on another user. @@ -29,6 +30,7 @@ import { GroupMemberType } from '../../../groups'; * to make it obvious what is going to happen. * Also tweaks the style for 'dangerous' actions (albeit only with colour) */ +@replaceableComponent("views.dialogs.ConfirmUserActionDialog") export default class ConfirmUserActionDialog extends React.Component { static propTypes = { // matrix-js-sdk (room) member object. Supply either this or 'groupMember' diff --git a/src/components/views/dialogs/ConfirmWipeDeviceDialog.js b/src/components/views/dialogs/ConfirmWipeDeviceDialog.js index 41ef9131fa..4faaad0f7e 100644 --- a/src/components/views/dialogs/ConfirmWipeDeviceDialog.js +++ b/src/components/views/dialogs/ConfirmWipeDeviceDialog.js @@ -18,7 +18,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import {_t} from "../../../languageHandler"; import * as sdk from "../../../index"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.ConfirmWipeDeviceDialog") export default class ConfirmWipeDeviceDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx b/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx index 1d9d92b9c9..9b4484d661 100644 --- a/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx +++ b/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx @@ -25,6 +25,7 @@ import InfoTooltip from "../elements/InfoTooltip"; import dis from "../../../dispatcher/dispatcher"; import {showCommunityRoomInviteDialog} from "../../../RoomInvite"; import GroupStore from "../../../stores/GroupStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps extends IDialogProps { } @@ -38,6 +39,7 @@ interface IState { avatarPreview: string; } +@replaceableComponent("views.dialogs.CreateCommunityPrototypeDialog") export default class CreateCommunityPrototypeDialog extends React.PureComponent<IProps, IState> { private avatarUploadRef: React.RefObject<HTMLInputElement> = React.createRef(); diff --git a/src/components/views/dialogs/CreateGroupDialog.js b/src/components/views/dialogs/CreateGroupDialog.js index 6636153c98..e6c7a67aca 100644 --- a/src/components/views/dialogs/CreateGroupDialog.js +++ b/src/components/views/dialogs/CreateGroupDialog.js @@ -20,7 +20,9 @@ import * as sdk from '../../../index'; import dis from '../../../dispatcher/dispatcher'; import { _t } from '../../../languageHandler'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.CreateGroupDialog") export default class CreateGroupDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/CreateRoomDialog.js b/src/components/views/dialogs/CreateRoomDialog.js index 0771b0ec45..e9dc6e2be0 100644 --- a/src/components/views/dialogs/CreateRoomDialog.js +++ b/src/components/views/dialogs/CreateRoomDialog.js @@ -27,7 +27,9 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {Key} from "../../../Keyboard"; import {privateShouldBeEncrypted} from "../../../createRoom"; import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.CreateRoomDialog") export default class CreateRoomDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/DeactivateAccountDialog.js b/src/components/views/dialogs/DeactivateAccountDialog.js index fca8c42546..4e52549d51 100644 --- a/src/components/views/dialogs/DeactivateAccountDialog.js +++ b/src/components/views/dialogs/DeactivateAccountDialog.js @@ -26,7 +26,9 @@ import { _t } from '../../../languageHandler'; import InteractiveAuth, {ERROR_USER_CANCELLED} from "../../structures/InteractiveAuth"; import {DEFAULT_PHASE, PasswordAuthEntry, SSOAuthEntry} from "../auth/InteractiveAuthEntryComponents"; import StyledCheckbox from "../elements/StyledCheckbox"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.DeactivateAccountDialog") export default class DeactivateAccountDialog extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/dialogs/DevtoolsDialog.js b/src/components/views/dialogs/DevtoolsDialog.js index 814378bb51..9b24aaa571 100644 --- a/src/components/views/dialogs/DevtoolsDialog.js +++ b/src/components/views/dialogs/DevtoolsDialog.js @@ -38,6 +38,7 @@ import {SETTINGS} from "../../../settings/Settings"; import SettingsStore, {LEVEL_ORDER} from "../../../settings/SettingsStore"; import Modal from "../../../Modal"; import ErrorDialog from "./ErrorDialog"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; class GenericEditor extends React.PureComponent { // static propTypes = {onBack: PropTypes.func.isRequired}; @@ -1089,6 +1090,7 @@ const Entries = [ SettingsExplorer, ]; +@replaceableComponent("views.dialogs.DevtoolsDialog") export default class DevtoolsDialog extends React.PureComponent { static propTypes = { roomId: PropTypes.string.isRequired, diff --git a/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx b/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx index 3071854b3e..504d563bd9 100644 --- a/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx +++ b/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx @@ -23,6 +23,7 @@ import AccessibleButton from "../elements/AccessibleButton"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore"; import FlairStore from "../../../stores/FlairStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps extends IDialogProps { communityId: string; @@ -38,6 +39,7 @@ interface IState { } // XXX: This is a lot of duplication from the create dialog, just in a different shape +@replaceableComponent("views.dialogs.EditCommunityPrototypeDialog") export default class EditCommunityPrototypeDialog extends React.PureComponent<IProps, IState> { private avatarUploadRef: React.RefObject<HTMLInputElement> = React.createRef(); diff --git a/src/components/views/dialogs/ErrorDialog.js b/src/components/views/dialogs/ErrorDialog.js index 3bfa635adf..5197c68b5a 100644 --- a/src/components/views/dialogs/ErrorDialog.js +++ b/src/components/views/dialogs/ErrorDialog.js @@ -29,7 +29,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.ErrorDialog") export default class ErrorDialog extends React.Component { static propTypes = { title: PropTypes.string, diff --git a/src/components/views/dialogs/HostSignupDialog.tsx b/src/components/views/dialogs/HostSignupDialog.tsx index 45a03b7cf0..c8bc907136 100644 --- a/src/components/views/dialogs/HostSignupDialog.tsx +++ b/src/components/views/dialogs/HostSignupDialog.tsx @@ -31,6 +31,7 @@ import { IPostmessageResponseData, PostmessageAction, } from "./HostSignupDialogTypes"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const HOST_SIGNUP_KEY = "host_signup"; @@ -42,6 +43,7 @@ interface IState { minimized: boolean; } +@replaceableComponent("views.dialogs.HostSignupDialog") export default class HostSignupDialog extends React.PureComponent<IProps, IState> { private iframeRef: React.RefObject<HTMLIFrameElement> = React.createRef(); private readonly config: IHostSignupConfig; diff --git a/src/components/views/dialogs/IncomingSasDialog.js b/src/components/views/dialogs/IncomingSasDialog.js index 2a4ff9cec3..d65ec7563f 100644 --- a/src/components/views/dialogs/IncomingSasDialog.js +++ b/src/components/views/dialogs/IncomingSasDialog.js @@ -19,6 +19,7 @@ import PropTypes from 'prop-types'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const PHASE_START = 0; const PHASE_SHOW_SAS = 1; @@ -26,6 +27,7 @@ const PHASE_WAIT_FOR_PARTNER_TO_CONFIRM = 2; const PHASE_VERIFIED = 3; const PHASE_CANCELLED = 4; +@replaceableComponent("views.dialogs.IncomingSasDialog") export default class IncomingSasDialog extends React.Component { static propTypes = { verifier: PropTypes.object.isRequired, diff --git a/src/components/views/dialogs/IntegrationsDisabledDialog.js b/src/components/views/dialogs/IntegrationsDisabledDialog.js index 7c996fbeab..0e9878f4bc 100644 --- a/src/components/views/dialogs/IntegrationsDisabledDialog.js +++ b/src/components/views/dialogs/IntegrationsDisabledDialog.js @@ -20,7 +20,9 @@ import {_t} from "../../../languageHandler"; import * as sdk from "../../../index"; import dis from '../../../dispatcher/dispatcher'; import {Action} from "../../../dispatcher/actions"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.IntegrationsDisabledDialog") export default class IntegrationsDisabledDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/IntegrationsImpossibleDialog.js b/src/components/views/dialogs/IntegrationsImpossibleDialog.js index 68bedc711d..9bc9d02ba6 100644 --- a/src/components/views/dialogs/IntegrationsImpossibleDialog.js +++ b/src/components/views/dialogs/IntegrationsImpossibleDialog.js @@ -19,7 +19,9 @@ import PropTypes from 'prop-types'; import {_t} from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; import * as sdk from "../../../index"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.IntegrationsImpossibleDialog") export default class IntegrationsImpossibleDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/InteractiveAuthDialog.js b/src/components/views/dialogs/InteractiveAuthDialog.js index 22291225ad..28a9bf673a 100644 --- a/src/components/views/dialogs/InteractiveAuthDialog.js +++ b/src/components/views/dialogs/InteractiveAuthDialog.js @@ -25,7 +25,9 @@ import { _t } from '../../../languageHandler'; import AccessibleButton from '../elements/AccessibleButton'; import {ERROR_USER_CANCELLED} from "../../structures/InteractiveAuth"; import {SSOAuthEntry} from "../auth/InteractiveAuthEntryComponents"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.InteractiveAuthDialog") export default class InteractiveAuthDialog extends React.Component { static propTypes = { // matrix client to use for UI auth requests diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index 9bc5b6476f..db9077291e 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -42,6 +42,7 @@ import {UIFeature} from "../../../settings/UIFeature"; import CountlyAnalytics from "../../../CountlyAnalytics"; import {Room} from "matrix-js-sdk/src/models/room"; import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // we have a number of types defined from the Matrix spec which can't reasonably be altered here. /* eslint-disable camelcase */ @@ -337,6 +338,7 @@ interface IInviteDialogState { errorText: string, } +@replaceableComponent("views.dialogs.InviteDialog") export default class InviteDialog extends React.PureComponent<IInviteDialogProps, IInviteDialogState> { static defaultProps = { kind: KIND_DM, diff --git a/src/components/views/dialogs/LogoutDialog.js b/src/components/views/dialogs/LogoutDialog.js index af36dba2b6..7bced46d43 100644 --- a/src/components/views/dialogs/LogoutDialog.js +++ b/src/components/views/dialogs/LogoutDialog.js @@ -22,7 +22,9 @@ import dis from '../../../dispatcher/dispatcher'; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import RestoreKeyBackupDialog from './security/RestoreKeyBackupDialog'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.LogoutDialog") export default class LogoutDialog extends React.Component { defaultProps = { onFinished: function() {}, diff --git a/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.js b/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.js index 4b9d7239e6..3151edd796 100644 --- a/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.js +++ b/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.js @@ -24,7 +24,9 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg'; import * as sdk from '../../../index'; import * as FormattingUtils from '../../../utils/FormattingUtils'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.ManualDeviceKeyVerificationDialog") export default class ManualDeviceKeyVerificationDialog extends React.Component { static propTypes = { userId: PropTypes.string.isRequired, diff --git a/src/components/views/dialogs/MessageEditHistoryDialog.js b/src/components/views/dialogs/MessageEditHistoryDialog.js index 2bdf2be35c..7585561c0c 100644 --- a/src/components/views/dialogs/MessageEditHistoryDialog.js +++ b/src/components/views/dialogs/MessageEditHistoryDialog.js @@ -21,7 +21,9 @@ import { _t } from '../../../languageHandler'; import * as sdk from "../../../index"; import {wantsDateSeparator} from '../../../DateUtils'; import SettingsStore from '../../../settings/SettingsStore'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.MessageEditHistoryDialog") export default class MessageEditHistoryDialog extends React.PureComponent { static propTypes = { mxEvent: PropTypes.object.isRequired, diff --git a/src/components/views/dialogs/ModalWidgetDialog.tsx b/src/components/views/dialogs/ModalWidgetDialog.tsx index 92fb406965..59eaab7b81 100644 --- a/src/components/views/dialogs/ModalWidgetDialog.tsx +++ b/src/components/views/dialogs/ModalWidgetDialog.tsx @@ -38,6 +38,7 @@ import {MatrixClientPeg} from "../../../MatrixClientPeg"; import {OwnProfileStore} from "../../../stores/OwnProfileStore"; import { arrayFastClone } from "../../../utils/arrays"; import { ElementWidget } from "../../../stores/widgets/StopGapWidget"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { widgetDefinition: IModalWidgetOpenRequestData; @@ -53,6 +54,7 @@ interface IState { const MAX_BUTTONS = 3; +@replaceableComponent("views.dialogs.ModalWidgetDialog") export default class ModalWidgetDialog extends React.PureComponent<IProps, IState> { private readonly widget: Widget; private readonly possibleButtons: ModalButtonID[]; diff --git a/src/components/views/dialogs/ReportEventDialog.js b/src/components/views/dialogs/ReportEventDialog.js index f5509dec4d..67ed0f8f53 100644 --- a/src/components/views/dialogs/ReportEventDialog.js +++ b/src/components/views/dialogs/ReportEventDialog.js @@ -22,10 +22,12 @@ import {MatrixEvent} from "matrix-js-sdk"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import SdkConfig from '../../../SdkConfig'; import Markdown from '../../../Markdown'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; /* * A dialog for reporting an event. */ +@replaceableComponent("views.dialogs.ReportEventDialog") export default class ReportEventDialog extends PureComponent { static propTypes = { mxEvent: PropTypes.instanceOf(MatrixEvent).isRequired, diff --git a/src/components/views/dialogs/RoomSettingsDialog.js b/src/components/views/dialogs/RoomSettingsDialog.js index 368f2aeccd..9c2f23ef22 100644 --- a/src/components/views/dialogs/RoomSettingsDialog.js +++ b/src/components/views/dialogs/RoomSettingsDialog.js @@ -30,6 +30,7 @@ import {MatrixClientPeg} from "../../../MatrixClientPeg"; import dis from "../../../dispatcher/dispatcher"; import SettingsStore from "../../../settings/SettingsStore"; import {UIFeature} from "../../../settings/UIFeature"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; export const ROOM_GENERAL_TAB = "ROOM_GENERAL_TAB"; export const ROOM_SECURITY_TAB = "ROOM_SECURITY_TAB"; @@ -38,6 +39,7 @@ export const ROOM_NOTIFICATIONS_TAB = "ROOM_NOTIFICATIONS_TAB"; export const ROOM_BRIDGES_TAB = "ROOM_BRIDGES_TAB"; export const ROOM_ADVANCED_TAB = "ROOM_ADVANCED_TAB"; +@replaceableComponent("views.dialogs.RoomSettingsDialog") export default class RoomSettingsDialog extends React.Component { static propTypes = { roomId: PropTypes.string.isRequired, diff --git a/src/components/views/dialogs/RoomUpgradeDialog.js b/src/components/views/dialogs/RoomUpgradeDialog.js index 85e97444ed..8f9ed42ada 100644 --- a/src/components/views/dialogs/RoomUpgradeDialog.js +++ b/src/components/views/dialogs/RoomUpgradeDialog.js @@ -20,7 +20,9 @@ import * as sdk from '../../../index'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.RoomUpgradeDialog") export default class RoomUpgradeDialog extends React.Component { static propTypes = { room: PropTypes.object.isRequired, diff --git a/src/components/views/dialogs/RoomUpgradeWarningDialog.js b/src/components/views/dialogs/RoomUpgradeWarningDialog.js index c83528c5ba..452ac56dff 100644 --- a/src/components/views/dialogs/RoomUpgradeWarningDialog.js +++ b/src/components/views/dialogs/RoomUpgradeWarningDialog.js @@ -22,7 +22,9 @@ import * as sdk from "../../../index"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import Modal from "../../../Modal"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.RoomUpgradeWarningDialog") export default class RoomUpgradeWarningDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/ServerOfflineDialog.tsx b/src/components/views/dialogs/ServerOfflineDialog.tsx index 81f628343b..52ff056907 100644 --- a/src/components/views/dialogs/ServerOfflineDialog.tsx +++ b/src/components/views/dialogs/ServerOfflineDialog.tsx @@ -28,10 +28,12 @@ import AccessibleButton from "../elements/AccessibleButton"; import { UPDATE_EVENT } from "../../../stores/AsyncStore"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { IDialogProps } from "./IDialogProps"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps extends IDialogProps { } +@replaceableComponent("views.dialogs.ServerOfflineDialog") export default class ServerOfflineDialog extends React.PureComponent<IProps> { public componentDidMount() { EchoStore.instance.on(UPDATE_EVENT, this.onEchosUpdated); diff --git a/src/components/views/dialogs/ServerPickerDialog.tsx b/src/components/views/dialogs/ServerPickerDialog.tsx index 7ca115760e..4abc0a88b1 100644 --- a/src/components/views/dialogs/ServerPickerDialog.tsx +++ b/src/components/views/dialogs/ServerPickerDialog.tsx @@ -26,6 +26,7 @@ import Field from "../elements/Field"; import StyledRadioButton from "../elements/StyledRadioButton"; import TextWithTooltip from "../elements/TextWithTooltip"; import withValidation, {IFieldState} from "../elements/Validation"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { title?: string; @@ -38,6 +39,7 @@ interface IState { otherHomeserver: string; } +@replaceableComponent("views.dialogs.ServerPickerDialog") export default class ServerPickerDialog extends React.PureComponent<IProps, IState> { private readonly defaultServer: ValidatedServerConfig; private readonly fieldRef = createRef<Field>(); diff --git a/src/components/views/dialogs/SessionRestoreErrorDialog.js b/src/components/views/dialogs/SessionRestoreErrorDialog.js index bae6b19fbe..50d7fbea09 100644 --- a/src/components/views/dialogs/SessionRestoreErrorDialog.js +++ b/src/components/views/dialogs/SessionRestoreErrorDialog.js @@ -22,8 +22,9 @@ import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; - +@replaceableComponent("views.dialogs.SessionRestoreErrorDialog") export default class SessionRestoreErrorDialog extends React.Component { static propTypes = { error: PropTypes.string.isRequired, diff --git a/src/components/views/dialogs/SetEmailDialog.js b/src/components/views/dialogs/SetEmailDialog.js index 6514d94dc9..0f8f410a6a 100644 --- a/src/components/views/dialogs/SetEmailDialog.js +++ b/src/components/views/dialogs/SetEmailDialog.js @@ -22,6 +22,7 @@ import * as Email from '../../../email'; import AddThreepid from '../../../AddThreepid'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; /* @@ -29,6 +30,7 @@ import Modal from '../../../Modal'; * * On success, `onFinished(true)` is called. */ +@replaceableComponent("views.dialogs.SetEmailDialog") export default class SetEmailDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/ShareDialog.tsx b/src/components/views/dialogs/ShareDialog.tsx index 5264031cc6..df1206a4f0 100644 --- a/src/components/views/dialogs/ShareDialog.tsx +++ b/src/components/views/dialogs/ShareDialog.tsx @@ -34,6 +34,7 @@ import AccessibleTooltipButton from '../elements/AccessibleTooltipButton'; import { IDialogProps } from "./IDialogProps"; import SettingsStore from "../../../settings/SettingsStore"; import {UIFeature} from "../../../settings/UIFeature"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const socials = [ { @@ -73,6 +74,7 @@ interface IState { permalinkCreator: RoomPermalinkCreator; } +@replaceableComponent("views.dialogs.ShareDialog") export default class ShareDialog extends React.PureComponent<IProps, IState> { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/StorageEvictedDialog.js b/src/components/views/dialogs/StorageEvictedDialog.js index a22f302807..15c5347644 100644 --- a/src/components/views/dialogs/StorageEvictedDialog.js +++ b/src/components/views/dialogs/StorageEvictedDialog.js @@ -20,7 +20,9 @@ import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.StorageEvictedDialog") export default class StorageEvictedDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/TabbedIntegrationManagerDialog.js b/src/components/views/dialogs/TabbedIntegrationManagerDialog.js index 9f5c9f6a11..07e29adcff 100644 --- a/src/components/views/dialogs/TabbedIntegrationManagerDialog.js +++ b/src/components/views/dialogs/TabbedIntegrationManagerDialog.js @@ -22,7 +22,9 @@ import * as sdk from '../../../index'; import {dialogTermsInteractionCallback, TermsNotSignedError} from "../../../Terms"; import classNames from 'classnames'; import * as ScalarMessaging from "../../../ScalarMessaging"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.TabbedIntegrationManagerDialog") export default class TabbedIntegrationManagerDialog extends React.Component { static propTypes = { /** diff --git a/src/components/views/dialogs/TermsDialog.js b/src/components/views/dialogs/TermsDialog.js index 402605c545..72e6c3f3a0 100644 --- a/src/components/views/dialogs/TermsDialog.js +++ b/src/components/views/dialogs/TermsDialog.js @@ -21,6 +21,7 @@ import * as sdk from '../../../index'; import { _t, pickBestLanguage } from '../../../languageHandler'; import Matrix from 'matrix-js-sdk'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; class TermsCheckbox extends React.PureComponent { static propTypes = { @@ -41,6 +42,7 @@ class TermsCheckbox extends React.PureComponent { } } +@replaceableComponent("views.dialogs.TermsDialog") export default class TermsDialog extends React.PureComponent { static propTypes = { /** diff --git a/src/components/views/dialogs/TextInputDialog.js b/src/components/views/dialogs/TextInputDialog.js index 69cc4390be..97abd209c0 100644 --- a/src/components/views/dialogs/TextInputDialog.js +++ b/src/components/views/dialogs/TextInputDialog.js @@ -19,7 +19,9 @@ import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import Field from "../elements/Field"; import { _t, _td } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.TextInputDialog") export default class TextInputDialog extends React.Component { static propTypes = { title: PropTypes.string, diff --git a/src/components/views/dialogs/UploadConfirmDialog.js b/src/components/views/dialogs/UploadConfirmDialog.js index e3521eb282..2ff16b9440 100644 --- a/src/components/views/dialogs/UploadConfirmDialog.js +++ b/src/components/views/dialogs/UploadConfirmDialog.js @@ -20,7 +20,9 @@ import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import filesize from "filesize"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.UploadConfirmDialog") export default class UploadConfirmDialog extends React.Component { static propTypes = { file: PropTypes.object.isRequired, diff --git a/src/components/views/dialogs/UploadFailureDialog.js b/src/components/views/dialogs/UploadFailureDialog.js index 4be1656f66..d220d6c684 100644 --- a/src/components/views/dialogs/UploadFailureDialog.js +++ b/src/components/views/dialogs/UploadFailureDialog.js @@ -21,12 +21,14 @@ import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import ContentMessages from '../../../ContentMessages'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; /* * Tells the user about files we know cannot be uploaded before we even try uploading * them. This is named fairly generically but the only thing we check right now is * the size of the file. */ +@replaceableComponent("views.dialogs.UploadFailureDialog") export default class UploadFailureDialog extends React.Component { static propTypes = { badFiles: PropTypes.arrayOf(PropTypes.object).isRequired, diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.js index 3291fa2387..eb9eaeb5dd 100644 --- a/src/components/views/dialogs/UserSettingsDialog.js +++ b/src/components/views/dialogs/UserSettingsDialog.js @@ -33,6 +33,7 @@ import * as sdk from "../../../index"; import SdkConfig from "../../../SdkConfig"; import MjolnirUserSettingsTab from "../settings/tabs/user/MjolnirUserSettingsTab"; import {UIFeature} from "../../../settings/UIFeature"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; export const USER_GENERAL_TAB = "USER_GENERAL_TAB"; export const USER_APPEARANCE_TAB = "USER_APPEARANCE_TAB"; @@ -45,6 +46,7 @@ export const USER_LABS_TAB = "USER_LABS_TAB"; export const USER_MJOLNIR_TAB = "USER_MJOLNIR_TAB"; export const USER_HELP_TAB = "USER_HELP_TAB"; +@replaceableComponent("views.dialogs.UserSettingsDialog") export default class UserSettingsDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/VerificationRequestDialog.js b/src/components/views/dialogs/VerificationRequestDialog.js index 3a6e9a2d10..574beebbc6 100644 --- a/src/components/views/dialogs/VerificationRequestDialog.js +++ b/src/components/views/dialogs/VerificationRequestDialog.js @@ -19,7 +19,9 @@ import PropTypes from 'prop-types'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.VerificationRequestDialog") export default class VerificationRequestDialog extends React.Component { static propTypes = { verificationRequest: PropTypes.object, diff --git a/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx b/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx index 535e0b7b8e..70fe7fe5e3 100644 --- a/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx +++ b/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx @@ -29,6 +29,7 @@ import StyledCheckbox from "../elements/StyledCheckbox"; import DialogButtons from "../elements/DialogButtons"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import { CapabilityText } from "../../../widgets/CapabilityText"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; export function getRememberedCapabilitiesForWidget(widget: Widget): Capability[] { return JSON.parse(localStorage.getItem(`widget_${widget.id}_approved_caps`) || "[]"); @@ -54,6 +55,7 @@ interface IState { rememberSelection: boolean; } +@replaceableComponent("views.dialogs.WidgetCapabilitiesPromptDialog") export default class WidgetCapabilitiesPromptDialog extends React.PureComponent<IProps, IState> { private eventPermissionsMap = new Map<Capability, WidgetEventCapability>(); diff --git a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js index c01d3d39b8..f45adf9738 100644 --- a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js +++ b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js @@ -21,7 +21,9 @@ import * as sdk from "../../../index"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import {Widget} from "matrix-widget-api"; import {OIDCState, WidgetPermissionStore} from "../../../stores/widgets/WidgetPermissionStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.WidgetOpenIDPermissionsDialog") export default class WidgetOpenIDPermissionsDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.js b/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.js index abc1586205..43fb25f152 100644 --- a/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.js +++ b/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.js @@ -18,7 +18,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import {_t} from "../../../../languageHandler"; import * as sdk from "../../../../index"; +import {replaceableComponent} from "../../../../utils/replaceableComponent"; +@replaceableComponent("views.dialogs.security.ConfirmDestroyCrossSigningDialog") export default class ConfirmDestroyCrossSigningDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/security/CreateCrossSigningDialog.js b/src/components/views/dialogs/security/CreateCrossSigningDialog.js index be546d2616..fedcc02f89 100644 --- a/src/components/views/dialogs/security/CreateCrossSigningDialog.js +++ b/src/components/views/dialogs/security/CreateCrossSigningDialog.js @@ -25,12 +25,14 @@ import DialogButtons from '../../elements/DialogButtons'; import BaseDialog from '../BaseDialog'; import Spinner from '../../elements/Spinner'; import InteractiveAuthDialog from '../InteractiveAuthDialog'; +import {replaceableComponent} from "../../../../utils/replaceableComponent"; /* * Walks the user through the process of creating a cross-signing keys. In most * cases, only a spinner is shown, but for more complex auth like SSO, the user * may need to complete some steps to proceed. */ +@replaceableComponent("views.dialogs.security.CreateCrossSigningDialog") export default class CreateCrossSigningDialog extends React.PureComponent { static propTypes = { accountPassword: PropTypes.string, diff --git a/src/components/views/dialogs/security/SetupEncryptionDialog.js b/src/components/views/dialogs/security/SetupEncryptionDialog.js index 9ce3144534..3c15ea9f1d 100644 --- a/src/components/views/dialogs/security/SetupEncryptionDialog.js +++ b/src/components/views/dialogs/security/SetupEncryptionDialog.js @@ -20,6 +20,7 @@ import SetupEncryptionBody from '../../../structures/auth/SetupEncryptionBody'; import BaseDialog from '../BaseDialog'; import { _t } from '../../../../languageHandler'; import { SetupEncryptionStore, PHASE_DONE } from '../../../../stores/SetupEncryptionStore'; +import {replaceableComponent} from "../../../../utils/replaceableComponent"; function iconFromPhase(phase) { if (phase === PHASE_DONE) { @@ -29,6 +30,7 @@ function iconFromPhase(phase) { } } +@replaceableComponent("views.dialogs.security.SetupEncryptionDialog") export default class SetupEncryptionDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, diff --git a/src/components/views/elements/AccessibleTooltipButton.tsx b/src/components/views/elements/AccessibleTooltipButton.tsx index b7c7b78e63..3bb264fb3e 100644 --- a/src/components/views/elements/AccessibleTooltipButton.tsx +++ b/src/components/views/elements/AccessibleTooltipButton.tsx @@ -20,6 +20,7 @@ import classNames from 'classnames'; import AccessibleButton from "./AccessibleButton"; import Tooltip from './Tooltip'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface ITooltipProps extends React.ComponentProps<typeof AccessibleButton> { title: string; @@ -33,6 +34,7 @@ interface IState { hover: boolean; } +@replaceableComponent("views.elements.AccessibleTooltipButton") export default class AccessibleTooltipButton extends React.PureComponent<ITooltipProps, IState> { constructor(props: ITooltipProps) { super(props); diff --git a/src/components/views/elements/ActionButton.js b/src/components/views/elements/ActionButton.js index bec016bce0..1714891cb5 100644 --- a/src/components/views/elements/ActionButton.js +++ b/src/components/views/elements/ActionButton.js @@ -20,7 +20,9 @@ import AccessibleButton from './AccessibleButton'; import dis from '../../../dispatcher/dispatcher'; import * as sdk from '../../../index'; import Analytics from '../../../Analytics'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.ActionButton") export default class ActionButton extends React.Component { static propTypes = { size: PropTypes.string, diff --git a/src/components/views/elements/AddressSelector.js b/src/components/views/elements/AddressSelector.js index 2a71622bb8..33b2906870 100644 --- a/src/components/views/elements/AddressSelector.js +++ b/src/components/views/elements/AddressSelector.js @@ -20,7 +20,9 @@ import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import classNames from 'classnames'; import { UserAddressType } from '../../../UserAddress'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.AddressSelector") export default class AddressSelector extends React.Component { static propTypes = { onSelected: PropTypes.func.isRequired, diff --git a/src/components/views/elements/AddressTile.js b/src/components/views/elements/AddressTile.js index dc6c6b2914..4a216dbae4 100644 --- a/src/components/views/elements/AddressTile.js +++ b/src/components/views/elements/AddressTile.js @@ -22,8 +22,9 @@ import * as sdk from "../../../index"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import { _t } from '../../../languageHandler'; import { UserAddressType } from '../../../UserAddress.js'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; - +@replaceableComponent("views.elements.AddressTile") export default class AddressTile extends React.Component { static propTypes = { address: UserAddressType.isRequired, diff --git a/src/components/views/elements/AppPermission.js b/src/components/views/elements/AppPermission.js index ec8bffc32f..65e40ef19a 100644 --- a/src/components/views/elements/AppPermission.js +++ b/src/components/views/elements/AppPermission.js @@ -24,7 +24,9 @@ import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; import WidgetUtils from "../../../utils/WidgetUtils"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.AppPermission") export default class AppPermission extends React.Component { static propTypes = { url: PropTypes.string.isRequired, diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 2a72621ccc..e206fda797 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -38,7 +38,9 @@ import {ElementWidgetActions} from "../../../stores/widgets/ElementWidgetActions import {MatrixCapabilities} from "matrix-widget-api"; import RoomWidgetContextMenu from "../context_menus/WidgetContextMenu"; import WidgetAvatar from "../avatars/WidgetAvatar"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.AppTile") export default class AppTile extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/elements/DesktopCapturerSourcePicker.tsx b/src/components/views/elements/DesktopCapturerSourcePicker.tsx index 6ae465c362..2d066a7ed7 100644 --- a/src/components/views/elements/DesktopCapturerSourcePicker.tsx +++ b/src/components/views/elements/DesktopCapturerSourcePicker.tsx @@ -19,6 +19,7 @@ import { _t } from '../../../languageHandler'; import BaseDialog from "..//dialogs/BaseDialog" import AccessibleButton from './AccessibleButton'; import {getDesktopCapturerSources} from "matrix-js-sdk/src/webrtc/call"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; export interface DesktopCapturerSource { id: string; @@ -69,6 +70,7 @@ export interface DesktopCapturerSourcePickerIProps { onFinished(source: DesktopCapturerSource): void; } +@replaceableComponent("views.elements.DesktopCapturerSourcePicker") export default class DesktopCapturerSourcePicker extends React.Component< DesktopCapturerSourcePickerIProps, DesktopCapturerSourcePickerIState diff --git a/src/components/views/elements/DialogButtons.js b/src/components/views/elements/DialogButtons.js index 3417485eb8..dcb1cee077 100644 --- a/src/components/views/elements/DialogButtons.js +++ b/src/components/views/elements/DialogButtons.js @@ -19,10 +19,12 @@ limitations under the License. import React from "react"; import PropTypes from "prop-types"; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; /** * Basic container for buttons in modal dialogs. */ +@replaceableComponent("views.elements.DialogButtons") export default class DialogButtons extends React.Component { static propTypes = { // The primary button which is styled differently and has default focus. diff --git a/src/components/views/elements/DirectorySearchBox.js b/src/components/views/elements/DirectorySearchBox.js index 644b69417b..6447bb3cd8 100644 --- a/src/components/views/elements/DirectorySearchBox.js +++ b/src/components/views/elements/DirectorySearchBox.js @@ -18,7 +18,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.DirectorySearchBox") export default class DirectorySearchBox extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/elements/Draggable.tsx b/src/components/views/elements/Draggable.tsx index a6eb8323f3..6032721a48 100644 --- a/src/components/views/elements/Draggable.tsx +++ b/src/components/views/elements/Draggable.tsx @@ -15,6 +15,7 @@ limitations under the License. */ import React from 'react'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { className: string; @@ -33,6 +34,7 @@ export interface ILocationState { currentY: number; } +@replaceableComponent("views.elements.Draggable") export default class Draggable extends React.Component<IProps, IState> { constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/Dropdown.js b/src/components/views/elements/Dropdown.js index 6b3efb5ee1..981c0becc0 100644 --- a/src/components/views/elements/Dropdown.js +++ b/src/components/views/elements/Dropdown.js @@ -22,6 +22,7 @@ import classnames from 'classnames'; import AccessibleButton from './AccessibleButton'; import { _t } from '../../../languageHandler'; import {Key} from "../../../Keyboard"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; class MenuOption extends React.Component { constructor(props) { @@ -83,6 +84,7 @@ MenuOption.propTypes = { * * TODO: Port NetworkDropdown to use this. */ +@replaceableComponent("views.elements.Dropdown") export default class Dropdown extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/elements/EditableItemList.js b/src/components/views/elements/EditableItemList.js index 5a07a400d7..ff62f169fa 100644 --- a/src/components/views/elements/EditableItemList.js +++ b/src/components/views/elements/EditableItemList.js @@ -19,6 +19,7 @@ import PropTypes from 'prop-types'; import {_t} from '../../../languageHandler'; import Field from "./Field"; import AccessibleButton from "./AccessibleButton"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; export class EditableItem extends React.Component { static propTypes = { @@ -85,6 +86,7 @@ export class EditableItem extends React.Component { } } +@replaceableComponent("views.elements.EditableItemList") export default class EditableItemList extends React.Component { static propTypes = { id: PropTypes.string.isRequired, diff --git a/src/components/views/elements/EditableText.js b/src/components/views/elements/EditableText.js index 49eb331aef..638fd02553 100644 --- a/src/components/views/elements/EditableText.js +++ b/src/components/views/elements/EditableText.js @@ -18,7 +18,9 @@ limitations under the License. import React, {createRef} from 'react'; import PropTypes from 'prop-types'; import {Key} from "../../../Keyboard"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.EditableText") export default class EditableText extends React.Component { static propTypes = { onValueChanged: PropTypes.func, diff --git a/src/components/views/elements/EditableTextContainer.js b/src/components/views/elements/EditableTextContainer.js index bbc5560557..e925220089 100644 --- a/src/components/views/elements/EditableTextContainer.js +++ b/src/components/views/elements/EditableTextContainer.js @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; /** * A component which wraps an EditableText, with a spinner while updates take @@ -29,6 +30,7 @@ import * as sdk from '../../../index'; * similarly asynchronous way. If this is not provided, the initial value is * taken from the 'initialValue' property. */ +@replaceableComponent("views.elements.EditableTextContainer") export default class EditableTextContainer extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/elements/ErrorBoundary.js b/src/components/views/elements/ErrorBoundary.js index 9fe6861250..9037287f49 100644 --- a/src/components/views/elements/ErrorBoundary.js +++ b/src/components/views/elements/ErrorBoundary.js @@ -21,11 +21,13 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg'; import PlatformPeg from '../../../PlatformPeg'; import Modal from '../../../Modal'; import SdkConfig from "../../../SdkConfig"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; /** * This error boundary component can be used to wrap large content areas and * catch exceptions during rendering in the component tree below them. */ +@replaceableComponent("views.elements.ErrorBoundary") export default class ErrorBoundary extends React.PureComponent { constructor(props) { super(props); diff --git a/src/components/views/elements/EventTilePreview.tsx b/src/components/views/elements/EventTilePreview.tsx index 49c97831bc..c539f2be1c 100644 --- a/src/components/views/elements/EventTilePreview.tsx +++ b/src/components/views/elements/EventTilePreview.tsx @@ -24,6 +24,7 @@ import EventTile from '../rooms/EventTile'; import SettingsStore from "../../../settings/SettingsStore"; import {Layout} from "../../../settings/Layout"; import {UIFeature} from "../../../settings/UIFeature"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { /** @@ -52,6 +53,7 @@ interface IState { const AVATAR_SIZE = 32; +@replaceableComponent("views.elements.EventTilePreview") export default class EventTilePreview extends React.Component<IProps, IState> { constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/Flair.js b/src/components/views/elements/Flair.js index 645444b300..75998cb721 100644 --- a/src/components/views/elements/Flair.js +++ b/src/components/views/elements/Flair.js @@ -19,6 +19,7 @@ import PropTypes from 'prop-types'; import FlairStore from '../../../stores/FlairStore'; import dis from '../../../dispatcher/dispatcher'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; class FlairAvatar extends React.Component { @@ -62,6 +63,7 @@ FlairAvatar.propTypes = { FlairAvatar.contextType = MatrixClientContext; +@replaceableComponent("views.elements.Flair") export default class Flair extends React.Component { constructor() { super(); diff --git a/src/components/views/elements/IRCTimelineProfileResizer.tsx b/src/components/views/elements/IRCTimelineProfileResizer.tsx index ecd63816de..cd1ccf2fc4 100644 --- a/src/components/views/elements/IRCTimelineProfileResizer.tsx +++ b/src/components/views/elements/IRCTimelineProfileResizer.tsx @@ -18,6 +18,7 @@ import React from 'react'; import SettingsStore from "../../../settings/SettingsStore"; import Draggable, {ILocationState} from './Draggable'; import { SettingLevel } from "../../../settings/SettingLevel"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { // Current room @@ -31,6 +32,7 @@ interface IState { IRCLayoutRoot: HTMLElement; } +@replaceableComponent("views.elements.IRCTimelineProfileResizer") export default class IRCTimelineProfileResizer extends React.Component<IProps, IState> { constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/ImageView.js b/src/components/views/elements/ImageView.js index e39075cedc..96b6de832d 100644 --- a/src/components/views/elements/ImageView.js +++ b/src/components/views/elements/ImageView.js @@ -26,7 +26,9 @@ import Modal from "../../../Modal"; import * as sdk from "../../../index"; import {Key} from "../../../Keyboard"; import FocusLock from "react-focus-lock"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.ImageView") export default class ImageView extends React.Component { static propTypes = { src: PropTypes.string.isRequired, // the source of the image being displayed diff --git a/src/components/views/elements/InfoTooltip.tsx b/src/components/views/elements/InfoTooltip.tsx index dd21c95b74..8f7f1ea53f 100644 --- a/src/components/views/elements/InfoTooltip.tsx +++ b/src/components/views/elements/InfoTooltip.tsx @@ -20,6 +20,7 @@ import classNames from 'classnames'; import Tooltip from './Tooltip'; import { _t } from "../../../languageHandler"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface ITooltipProps { tooltip?: React.ReactNode; @@ -30,6 +31,7 @@ interface IState { hover: boolean; } +@replaceableComponent("views.elements.InfoTooltip") export default class InfoTooltip extends React.PureComponent<ITooltipProps, IState> { constructor(props: ITooltipProps) { super(props); diff --git a/src/components/views/elements/InlineSpinner.js b/src/components/views/elements/InlineSpinner.js index 73316157f4..3654a1f34c 100644 --- a/src/components/views/elements/InlineSpinner.js +++ b/src/components/views/elements/InlineSpinner.js @@ -17,7 +17,9 @@ limitations under the License. import React from "react"; import {_t} from "../../../languageHandler"; import SettingsStore from "../../../settings/SettingsStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.InlineSpinner") export default class InlineSpinner extends React.Component { render() { const w = this.props.w || 16; diff --git a/src/components/views/elements/LabelledToggleSwitch.js b/src/components/views/elements/LabelledToggleSwitch.js index 78beb2aa91..e6378f0e6a 100644 --- a/src/components/views/elements/LabelledToggleSwitch.js +++ b/src/components/views/elements/LabelledToggleSwitch.js @@ -17,7 +17,9 @@ limitations under the License. import React from 'react'; import PropTypes from "prop-types"; import ToggleSwitch from "./ToggleSwitch"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.LabelledToggleSwitch") export default class LabelledToggleSwitch extends React.Component { static propTypes = { // The value for the toggle switch diff --git a/src/components/views/elements/LanguageDropdown.js b/src/components/views/elements/LanguageDropdown.js index 03ec456af5..2e961be700 100644 --- a/src/components/views/elements/LanguageDropdown.js +++ b/src/components/views/elements/LanguageDropdown.js @@ -22,6 +22,7 @@ import * as sdk from '../../../index'; import * as languageHandler from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import { _t } from "../../../languageHandler"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; function languageMatchesSearchQuery(query, language) { if (language.label.toUpperCase().includes(query.toUpperCase())) return true; @@ -29,6 +30,7 @@ function languageMatchesSearchQuery(query, language) { return false; } +@replaceableComponent("views.elements.LanguageDropdown") export default class LanguageDropdown extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/elements/LazyRenderList.js b/src/components/views/elements/LazyRenderList.js index 7572dced0b..f2c8148cd2 100644 --- a/src/components/views/elements/LazyRenderList.js +++ b/src/components/views/elements/LazyRenderList.js @@ -16,6 +16,7 @@ limitations under the License. import React from "react"; import PropTypes from 'prop-types'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; class ItemRange { constructor(topCount, renderCount, bottomCount) { @@ -55,6 +56,7 @@ class ItemRange { } } +@replaceableComponent("views.elements.LazyRenderList") export default class LazyRenderList extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/elements/MemberEventListSummary.tsx b/src/components/views/elements/MemberEventListSummary.tsx index 073bedf207..0290ef6d83 100644 --- a/src/components/views/elements/MemberEventListSummary.tsx +++ b/src/components/views/elements/MemberEventListSummary.tsx @@ -24,6 +24,7 @@ import { _t } from '../../../languageHandler'; import { formatCommaSeparatedList } from '../../../utils/FormattingUtils'; import { isValid3pidInvite } from "../../../RoomInvite"; import EventListSummary from "./EventListSummary"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { // An array of member events to summarise @@ -69,6 +70,7 @@ enum TransitionType { const SEP = ","; +@replaceableComponent("views.elements.MemberEventListSummary") export default class MemberEventListSummary extends React.Component<IProps> { static defaultProps = { summaryLength: 1, diff --git a/src/components/views/elements/PersistedElement.js b/src/components/views/elements/PersistedElement.js index 3732f644b8..f504b3e97f 100644 --- a/src/components/views/elements/PersistedElement.js +++ b/src/components/views/elements/PersistedElement.js @@ -24,6 +24,7 @@ import dis from '../../../dispatcher/dispatcher'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import {isNullOrUndefined} from "matrix-js-sdk/src/utils"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // Shamelessly ripped off Modal.js. There's probably a better way // of doing reusable widgets like dialog boxes & menus where we go and @@ -56,6 +57,7 @@ function getOrCreateContainer(containerId) { * children are made visible and are positioned into a div that is given the same * bounding rect as the parent of PE. */ +@replaceableComponent("views.elements.PersistedElement") export default class PersistedElement extends React.Component { static propTypes = { // Unique identifier for this PersistedElement instance diff --git a/src/components/views/elements/PersistentApp.js b/src/components/views/elements/PersistentApp.js index 7801076c66..5df373e4fe 100644 --- a/src/components/views/elements/PersistentApp.js +++ b/src/components/views/elements/PersistentApp.js @@ -21,7 +21,9 @@ import ActiveWidgetStore from '../../../stores/ActiveWidgetStore'; import WidgetUtils from '../../../utils/WidgetUtils'; import * as sdk from '../../../index'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.PersistentApp") export default class PersistentApp extends React.Component { state = { roomId: RoomViewStore.getRoomId(), diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js index c6806c289e..b0d4fc7fa2 100644 --- a/src/components/views/elements/Pill.js +++ b/src/components/views/elements/Pill.js @@ -27,7 +27,9 @@ import {getPrimaryPermalinkEntity, parseAppLocalLink} from "../../../utils/perma import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {Action} from "../../../dispatcher/actions"; import Tooltip from './Tooltip'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.Pill") class Pill extends React.Component { static roomNotifPos(text) { return text.indexOf("@room"); diff --git a/src/components/views/elements/PowerSelector.js b/src/components/views/elements/PowerSelector.js index 66922df0f8..622bed9890 100644 --- a/src/components/views/elements/PowerSelector.js +++ b/src/components/views/elements/PowerSelector.js @@ -20,7 +20,9 @@ import * as Roles from '../../../Roles'; import { _t } from '../../../languageHandler'; import Field from "./Field"; import {Key} from "../../../Keyboard"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.PowerSelector") export default class PowerSelector extends React.Component { static propTypes = { value: PropTypes.number.isRequired, diff --git a/src/components/views/elements/ReplyThread.js b/src/components/views/elements/ReplyThread.js index 27d773b099..2e0cc50435 100644 --- a/src/components/views/elements/ReplyThread.js +++ b/src/components/views/elements/ReplyThread.js @@ -31,10 +31,12 @@ import {Action} from "../../../dispatcher/actions"; import sanitizeHtml from "sanitize-html"; import {UIFeature} from "../../../settings/UIFeature"; import {PERMITTED_URL_SCHEMES} from "../../../HtmlUtils"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // This component does no cycle detection, simply because the only way to make such a cycle would be to // craft event_id's, using a homeserver that generates predictable event IDs; even then the impact would // be low as each event being loaded (after the first) is triggered by an explicit user action. +@replaceableComponent("views.elements.ReplyThread") export default class ReplyThread extends React.Component { static propTypes = { // the latest event in this chain of replies diff --git a/src/components/views/elements/RoomAliasField.js b/src/components/views/elements/RoomAliasField.js index 04bbe1c3de..1db154c2cd 100644 --- a/src/components/views/elements/RoomAliasField.js +++ b/src/components/views/elements/RoomAliasField.js @@ -19,8 +19,10 @@ import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import withValidation from './Validation'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // Controlled form component wrapping Field for inputting a room alias scoped to a given domain +@replaceableComponent("views.elements.RoomAliasField") export default class RoomAliasField extends React.PureComponent { static propTypes = { domain: PropTypes.string.isRequired, diff --git a/src/components/views/elements/SettingsFlag.tsx b/src/components/views/elements/SettingsFlag.tsx index 03e91fac62..4f885ab47d 100644 --- a/src/components/views/elements/SettingsFlag.tsx +++ b/src/components/views/elements/SettingsFlag.tsx @@ -21,6 +21,7 @@ import { _t } from '../../../languageHandler'; import ToggleSwitch from "./ToggleSwitch"; import StyledCheckbox from "./StyledCheckbox"; import { SettingLevel } from "../../../settings/SettingLevel"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { // The setting must be a boolean @@ -39,6 +40,7 @@ interface IState { value: boolean; } +@replaceableComponent("views.elements.SettingsFlag") export default class SettingsFlag extends React.Component<IProps, IState> { constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx index b7c8e1b533..b513f90460 100644 --- a/src/components/views/elements/Slider.tsx +++ b/src/components/views/elements/Slider.tsx @@ -15,6 +15,7 @@ limitations under the License. */ import * as React from 'react'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { // A callback for the selected value @@ -34,6 +35,7 @@ interface IProps { disabled: boolean; } +@replaceableComponent("views.elements.Slider") export default class Slider extends React.Component<IProps> { // offset is a terrible inverse approximation. // if the values represents some function f(x) = y where x is the diff --git a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx index c647f6e410..06e1efe415 100644 --- a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx +++ b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx @@ -21,6 +21,7 @@ import * as sdk from '../../../index'; import PlatformPeg from "../../../PlatformPeg"; import SettingsStore from "../../../settings/SettingsStore"; import { _t } from "../../../languageHandler"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; function languageMatchesSearchQuery(query, language) { if (language.label.toUpperCase().includes(query.toUpperCase())) return true; @@ -39,6 +40,7 @@ interface SpellCheckLanguagesDropdownIState { languages: any, } +@replaceableComponent("views.elements.SpellCheckLanguagesDropdown") export default class SpellCheckLanguagesDropdown extends React.Component<SpellCheckLanguagesDropdownIProps, SpellCheckLanguagesDropdownIState> { constructor(props) { diff --git a/src/components/views/elements/Spoiler.js b/src/components/views/elements/Spoiler.js index b75967b225..33b4382a2c 100644 --- a/src/components/views/elements/Spoiler.js +++ b/src/components/views/elements/Spoiler.js @@ -15,7 +15,9 @@ */ import React from 'react'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.Spoiler") export default class Spoiler extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/elements/StyledCheckbox.tsx b/src/components/views/elements/StyledCheckbox.tsx index f8d2665d07..2454d1336b 100644 --- a/src/components/views/elements/StyledCheckbox.tsx +++ b/src/components/views/elements/StyledCheckbox.tsx @@ -16,6 +16,7 @@ limitations under the License. import React from "react"; import { randomString } from "matrix-js-sdk/src/randomstring"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps extends React.InputHTMLAttributes<HTMLInputElement> { } @@ -23,6 +24,7 @@ interface IProps extends React.InputHTMLAttributes<HTMLInputElement> { interface IState { } +@replaceableComponent("views.elements.StyledCheckbox") export default class StyledCheckbox extends React.PureComponent<IProps, IState> { private id: string; diff --git a/src/components/views/elements/StyledRadioButton.tsx b/src/components/views/elements/StyledRadioButton.tsx index 2efd084861..835394e055 100644 --- a/src/components/views/elements/StyledRadioButton.tsx +++ b/src/components/views/elements/StyledRadioButton.tsx @@ -16,6 +16,7 @@ limitations under the License. import React from 'react'; import classnames from 'classnames'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps extends React.InputHTMLAttributes<HTMLInputElement> { outlined?: boolean; @@ -24,6 +25,7 @@ interface IProps extends React.InputHTMLAttributes<HTMLInputElement> { interface IState { } +@replaceableComponent("views.elements.StyledRadioButton") export default class StyledRadioButton extends React.PureComponent<IProps, IState> { public static readonly defaultProps = { className: '', diff --git a/src/components/views/elements/SyntaxHighlight.js b/src/components/views/elements/SyntaxHighlight.js index a4dc97d46e..f9874c5367 100644 --- a/src/components/views/elements/SyntaxHighlight.js +++ b/src/components/views/elements/SyntaxHighlight.js @@ -17,7 +17,9 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import {highlightBlock} from 'highlight.js'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.SyntaxHighlight") export default class SyntaxHighlight extends React.Component { static propTypes = { className: PropTypes.string, diff --git a/src/components/views/elements/TagTile.js b/src/components/views/elements/TagTile.js index 6c9a01a840..663acd6329 100644 --- a/src/components/views/elements/TagTile.js +++ b/src/components/views/elements/TagTile.js @@ -30,12 +30,14 @@ import GroupFilterOrderStore from '../../../stores/GroupFilterOrderStore'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import AccessibleButton from "./AccessibleButton"; import SettingsStore from "../../../settings/SettingsStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // A class for a child of GroupFilterPanel (possibly wrapped in a DNDTagTile) that represents // a thing to click on for the user to filter the visible rooms in the RoomList to: // - 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. +@replaceableComponent("views.elements.TagTile") 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" diff --git a/src/components/views/elements/TextWithTooltip.js b/src/components/views/elements/TextWithTooltip.js index b0405dc4c9..e4ad234ae2 100644 --- a/src/components/views/elements/TextWithTooltip.js +++ b/src/components/views/elements/TextWithTooltip.js @@ -17,7 +17,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.TextWithTooltip") export default class TextWithTooltip extends React.Component { static propTypes = { class: PropTypes.string, diff --git a/src/components/views/elements/TintableSvg.js b/src/components/views/elements/TintableSvg.js index df55b0a854..690deeedcd 100644 --- a/src/components/views/elements/TintableSvg.js +++ b/src/components/views/elements/TintableSvg.js @@ -18,7 +18,9 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import Tinter from "../../../Tinter"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.TintableSvg") class TintableSvg extends React.Component { static propTypes = { src: PropTypes.string.isRequired, diff --git a/src/components/views/elements/Tooltip.tsx b/src/components/views/elements/Tooltip.tsx index 03b9eb08d0..b2dd00de18 100644 --- a/src/components/views/elements/Tooltip.tsx +++ b/src/components/views/elements/Tooltip.tsx @@ -21,6 +21,7 @@ limitations under the License. import React, {Component, CSSProperties} from 'react'; import ReactDOM from 'react-dom'; import classNames from 'classnames'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const MIN_TOOLTIP_HEIGHT = 25; @@ -39,6 +40,7 @@ interface IProps { yOffset?: number; } +@replaceableComponent("views.elements.Tooltip") export default class Tooltip extends React.Component<IProps> { private tooltipContainer: HTMLElement; private tooltip: void | Element | Component<Element, any, any>; diff --git a/src/components/views/elements/TooltipButton.js b/src/components/views/elements/TooltipButton.js index 240d763bdc..c5ebb3b1aa 100644 --- a/src/components/views/elements/TooltipButton.js +++ b/src/components/views/elements/TooltipButton.js @@ -17,7 +17,9 @@ limitations under the License. import React from 'react'; import * as sdk from '../../../index'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.TooltipButton") export default class TooltipButton extends React.Component { state = { hover: false, diff --git a/src/components/views/elements/TruncatedList.js b/src/components/views/elements/TruncatedList.js index 81eb057e36..0509775545 100644 --- a/src/components/views/elements/TruncatedList.js +++ b/src/components/views/elements/TruncatedList.js @@ -18,7 +18,9 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.elements.TruncatedList") export default class TruncatedList extends React.Component { static propTypes = { // The number of elements to show before truncating. If negative, no truncation is done. diff --git a/src/components/views/elements/UserTagTile.tsx b/src/components/views/elements/UserTagTile.tsx index e7c74bb10e..d3e07a0a34 100644 --- a/src/components/views/elements/UserTagTile.tsx +++ b/src/components/views/elements/UserTagTile.tsx @@ -21,6 +21,7 @@ import GroupFilterOrderStore from "../../../stores/GroupFilterOrderStore"; import AccessibleTooltipButton from "./AccessibleTooltipButton"; import classNames from "classnames"; import { _t } from "../../../languageHandler"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { } @@ -29,6 +30,7 @@ interface IState { selected: boolean; } +@replaceableComponent("views.elements.UserTagTile") export default class UserTagTile extends React.PureComponent<IProps, IState> { private tagStoreRef: fbEmitter.EventSubscription; diff --git a/src/components/views/emojipicker/Category.tsx b/src/components/views/emojipicker/Category.tsx index c4feaac8ae..4c7852def3 100644 --- a/src/components/views/emojipicker/Category.tsx +++ b/src/components/views/emojipicker/Category.tsx @@ -21,6 +21,7 @@ import { CATEGORY_HEADER_HEIGHT, EMOJI_HEIGHT, EMOJIS_PER_ROW } from "./EmojiPic import LazyRenderList from "../elements/LazyRenderList"; import {DATA_BY_CATEGORY, IEmoji} from "../../../emoji"; import Emoji from './Emoji'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const OVERFLOW_ROWS = 3; @@ -47,6 +48,7 @@ interface IProps { onMouseLeave(emoji: IEmoji): void; } +@replaceableComponent("views.emojipicker.Category") class Category extends React.PureComponent<IProps> { private renderEmojiRow = (rowIndex: number) => { const { onClick, onMouseEnter, onMouseLeave, selectedEmojis, emojis } = this.props; diff --git a/src/components/views/emojipicker/Emoji.tsx b/src/components/views/emojipicker/Emoji.tsx index 5d715fb935..5d7665ce98 100644 --- a/src/components/views/emojipicker/Emoji.tsx +++ b/src/components/views/emojipicker/Emoji.tsx @@ -19,6 +19,7 @@ import React from 'react'; import {MenuItem} from "../../structures/ContextMenu"; import {IEmoji} from "../../../emoji"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { emoji: IEmoji; @@ -28,6 +29,7 @@ interface IProps { onMouseLeave(emoji: IEmoji): void; } +@replaceableComponent("views.emojipicker.Emoji") class Emoji extends React.PureComponent<IProps> { render() { const { onClick, onMouseEnter, onMouseLeave, emoji, selectedEmojis } = this.props; diff --git a/src/components/views/emojipicker/EmojiPicker.tsx b/src/components/views/emojipicker/EmojiPicker.tsx index bf0481c51c..6d7b90c8a6 100644 --- a/src/components/views/emojipicker/EmojiPicker.tsx +++ b/src/components/views/emojipicker/EmojiPicker.tsx @@ -26,6 +26,7 @@ import Search from "./Search"; import Preview from "./Preview"; import QuickReactions from "./QuickReactions"; import Category, {ICategory, CategoryKey} from "./Category"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; export const CATEGORY_HEADER_HEIGHT = 22; export const EMOJI_HEIGHT = 37; @@ -47,6 +48,7 @@ interface IState { viewportHeight: number; } +@replaceableComponent("views.emojipicker.EmojiPicker") class EmojiPicker extends React.Component<IProps, IState> { private readonly recentlyUsed: IEmoji[]; private readonly memoizedDataByCategory: Record<CategoryKey, IEmoji[]>; diff --git a/src/components/views/emojipicker/Header.tsx b/src/components/views/emojipicker/Header.tsx index 9a93722483..693f86ad73 100644 --- a/src/components/views/emojipicker/Header.tsx +++ b/src/components/views/emojipicker/Header.tsx @@ -21,12 +21,14 @@ import classNames from "classnames"; import {_t} from "../../../languageHandler"; import {Key} from "../../../Keyboard"; import {CategoryKey, ICategory} from "./Category"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { categories: ICategory[]; onAnchorClick(id: CategoryKey): void } +@replaceableComponent("views.emojipicker.Header") class Header extends React.PureComponent<IProps> { private findNearestEnabled(index: number, delta: number) { index += this.props.categories.length; diff --git a/src/components/views/emojipicker/Preview.tsx b/src/components/views/emojipicker/Preview.tsx index 69bfdf4d1c..e0952ec73e 100644 --- a/src/components/views/emojipicker/Preview.tsx +++ b/src/components/views/emojipicker/Preview.tsx @@ -18,11 +18,13 @@ limitations under the License. import React from 'react'; import {IEmoji} from "../../../emoji"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { emoji: IEmoji; } +@replaceableComponent("views.emojipicker.Preview") class Preview extends React.PureComponent<IProps> { render() { const { diff --git a/src/components/views/emojipicker/QuickReactions.tsx b/src/components/views/emojipicker/QuickReactions.tsx index 0477ecfb93..a250aca458 100644 --- a/src/components/views/emojipicker/QuickReactions.tsx +++ b/src/components/views/emojipicker/QuickReactions.tsx @@ -20,6 +20,7 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import {getEmojiFromUnicode, IEmoji} from "../../../emoji"; import Emoji from "./Emoji"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // We use the variation-selector Heart in Quick Reactions for some reason const QUICK_REACTIONS = ["👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀"].map(emoji => { @@ -39,6 +40,7 @@ interface IState { hover?: IEmoji; } +@replaceableComponent("views.emojipicker.QuickReactions") class QuickReactions extends React.Component<IProps, IState> { constructor(props) { super(props); diff --git a/src/components/views/emojipicker/ReactionPicker.tsx b/src/components/views/emojipicker/ReactionPicker.tsx index dbef0eadbe..e86d183aba 100644 --- a/src/components/views/emojipicker/ReactionPicker.tsx +++ b/src/components/views/emojipicker/ReactionPicker.tsx @@ -21,6 +21,7 @@ import {MatrixEvent} from "matrix-js-sdk/src/models/event"; import EmojiPicker from "./EmojiPicker"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import dis from "../../../dispatcher/dispatcher"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { mxEvent: MatrixEvent; @@ -32,6 +33,7 @@ interface IState { selectedEmojis: Set<string>; } +@replaceableComponent("views.emojipicker.ReactionPicker") class ReactionPicker extends React.Component<IProps, IState> { constructor(props) { super(props); diff --git a/src/components/views/emojipicker/Search.tsx b/src/components/views/emojipicker/Search.tsx index fe1fecec7b..abe3e026be 100644 --- a/src/components/views/emojipicker/Search.tsx +++ b/src/components/views/emojipicker/Search.tsx @@ -19,6 +19,7 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import {Key} from "../../../Keyboard"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { query: string; @@ -26,6 +27,7 @@ interface IProps { onEnter(): void; } +@replaceableComponent("views.emojipicker.Search") class Search extends React.PureComponent<IProps> { private inputRef = React.createRef<HTMLInputElement>(); diff --git a/src/components/views/groups/GroupInviteTile.js b/src/components/views/groups/GroupInviteTile.js index 0c09b6ed05..dc48c01acb 100644 --- a/src/components/views/groups/GroupInviteTile.js +++ b/src/components/views/groups/GroupInviteTile.js @@ -26,8 +26,10 @@ import {MatrixClientPeg} from "../../../MatrixClientPeg"; import {ContextMenu, ContextMenuButton, toRightOf} from "../../structures/ContextMenu"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {RovingTabIndexWrapper} from "../../../accessibility/RovingTabIndex"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // XXX this class copies a lot from RoomTile.js +@replaceableComponent("views.groups.GroupInviteTile") export default class GroupInviteTile extends React.Component { static propTypes: { group: PropTypes.object.isRequired, diff --git a/src/components/views/groups/GroupMemberList.js b/src/components/views/groups/GroupMemberList.js index 600a466601..d5b3f9aec7 100644 --- a/src/components/views/groups/GroupMemberList.js +++ b/src/components/views/groups/GroupMemberList.js @@ -26,9 +26,11 @@ import AccessibleButton from '../elements/AccessibleButton'; import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; import {Action} from "../../../dispatcher/actions"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const INITIAL_LOAD_NUM_MEMBERS = 30; +@replaceableComponent("views.groups.GroupMemberList") export default class GroupMemberList extends React.Component { static propTypes = { groupId: PropTypes.string.isRequired, diff --git a/src/components/views/groups/GroupMemberTile.js b/src/components/views/groups/GroupMemberTile.js index 13617cf681..e8285803b0 100644 --- a/src/components/views/groups/GroupMemberTile.js +++ b/src/components/views/groups/GroupMemberTile.js @@ -22,7 +22,9 @@ import * as sdk from '../../../index'; import dis from '../../../dispatcher/dispatcher'; import { GroupMemberType } from '../../../groups'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.groups.GroupMemberTile") export default class GroupMemberTile extends React.Component { static propTypes = { groupId: PropTypes.string.isRequired, diff --git a/src/components/views/groups/GroupPublicityToggle.js b/src/components/views/groups/GroupPublicityToggle.js index d42059551e..5399125d9f 100644 --- a/src/components/views/groups/GroupPublicityToggle.js +++ b/src/components/views/groups/GroupPublicityToggle.js @@ -19,7 +19,9 @@ import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import GroupStore from '../../../stores/GroupStore'; import ToggleSwitch from "../elements/ToggleSwitch"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.groups.GroupPublicityTile") export default class GroupPublicityToggle extends React.Component { static propTypes = { groupId: PropTypes.string.isRequired, diff --git a/src/components/views/groups/GroupRoomInfo.js b/src/components/views/groups/GroupRoomInfo.js index 50bbd26029..227a17e995 100644 --- a/src/components/views/groups/GroupRoomInfo.js +++ b/src/components/views/groups/GroupRoomInfo.js @@ -24,7 +24,9 @@ import { _t } from '../../../languageHandler'; import GroupStore from '../../../stores/GroupStore'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.groups.GroupRoomInfo") export default class GroupRoomInfo extends React.Component { static contextType = MatrixClientContext; diff --git a/src/components/views/groups/GroupRoomList.js b/src/components/views/groups/GroupRoomList.js index 9bb46db47c..f8a90f9222 100644 --- a/src/components/views/groups/GroupRoomList.js +++ b/src/components/views/groups/GroupRoomList.js @@ -21,9 +21,11 @@ import PropTypes from 'prop-types'; import { showGroupAddRoomDialog } from '../../../GroupAddressPicker'; import AccessibleButton from '../elements/AccessibleButton'; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const INITIAL_LOAD_NUM_ROOMS = 30; +@replaceableComponent("views.groups.GroupRoomList") export default class GroupRoomList extends React.Component { static propTypes = { groupId: PropTypes.string.isRequired, diff --git a/src/components/views/groups/GroupRoomTile.js b/src/components/views/groups/GroupRoomTile.js index 85aa56d055..8b25437f71 100644 --- a/src/components/views/groups/GroupRoomTile.js +++ b/src/components/views/groups/GroupRoomTile.js @@ -20,7 +20,9 @@ import * as sdk from '../../../index'; import dis from '../../../dispatcher/dispatcher'; import { GroupRoomType } from '../../../groups'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.groups.GroupRoomTile") class GroupRoomTile extends React.Component { static propTypes = { groupId: PropTypes.string.isRequired, diff --git a/src/components/views/groups/GroupTile.js b/src/components/views/groups/GroupTile.js index dcc749b01f..bb1714c9f2 100644 --- a/src/components/views/groups/GroupTile.js +++ b/src/components/views/groups/GroupTile.js @@ -21,9 +21,11 @@ import * as sdk from '../../../index'; import dis from '../../../dispatcher/dispatcher'; import FlairStore from '../../../stores/FlairStore'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; function nop() {} +@replaceableComponent("views.groups.GroupTile") class GroupTile extends React.Component { static propTypes = { groupId: PropTypes.string.isRequired, diff --git a/src/components/views/groups/GroupUserSettings.js b/src/components/views/groups/GroupUserSettings.js index 9209106c8f..5b537d7377 100644 --- a/src/components/views/groups/GroupUserSettings.js +++ b/src/components/views/groups/GroupUserSettings.js @@ -18,7 +18,9 @@ import React from 'react'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.groups.GroupUserSettings") export default class GroupUserSettings extends React.Component { static contextType = MatrixClientContext; diff --git a/src/components/views/messages/DateSeparator.js b/src/components/views/messages/DateSeparator.js index ef4b5d16d1..82ce8dc4ae 100644 --- a/src/components/views/messages/DateSeparator.js +++ b/src/components/views/messages/DateSeparator.js @@ -19,6 +19,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; import {formatFullDateNoTime} from '../../../DateUtils'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; function getdaysArray() { return [ @@ -32,6 +33,7 @@ function getdaysArray() { ]; } +@replaceableComponent("views.messages.DateSeparator") export default class DateSeparator extends React.Component { static propTypes = { ts: PropTypes.number.isRequired, diff --git a/src/components/views/messages/EditHistoryMessage.js b/src/components/views/messages/EditHistoryMessage.js index cc098d04cd..c5002b3308 100644 --- a/src/components/views/messages/EditHistoryMessage.js +++ b/src/components/views/messages/EditHistoryMessage.js @@ -27,12 +27,14 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; import classNames from 'classnames'; import RedactedBody from "./RedactedBody"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; function getReplacedContent(event) { const originalContent = event.getOriginalContent(); return originalContent["m.new_content"] || originalContent; } +@replaceableComponent("views.messages.EditHistoryMessage") export default class EditHistoryMessage extends React.PureComponent { static propTypes = { // the message event being edited diff --git a/src/components/views/messages/MAudioBody.js b/src/components/views/messages/MAudioBody.js index ac42b485d7..498e2db12a 100644 --- a/src/components/views/messages/MAudioBody.js +++ b/src/components/views/messages/MAudioBody.js @@ -21,7 +21,9 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg'; import { decryptFile } from '../../../utils/DecryptFile'; import { _t } from '../../../languageHandler'; import InlineSpinner from '../elements/InlineSpinner'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.MAudioBody") export default class MAudioBody extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js index 676f0b7986..e9893f99b6 100644 --- a/src/components/views/messages/MFileBody.js +++ b/src/components/views/messages/MFileBody.js @@ -26,6 +26,7 @@ import Tinter from '../../../Tinter'; import request from 'browser-request'; import Modal from '../../../Modal'; import AccessibleButton from "../elements/AccessibleButton"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // A cached tinted copy of require("../../../../res/img/download.svg") @@ -116,6 +117,7 @@ function computedStyle(element) { return cssText; } +@replaceableComponent("views.messages.MFileBody") export default class MFileBody extends React.Component { static propTypes = { /* the MatrixEvent to show */ diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index 771d12accd..59c5b4e66b 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -27,7 +27,9 @@ import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import InlineSpinner from '../elements/InlineSpinner'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.MImageBody") export default class MImageBody extends React.Component { static propTypes = { /* the MatrixEvent to show */ diff --git a/src/components/views/messages/MJitsiWidgetEvent.tsx b/src/components/views/messages/MJitsiWidgetEvent.tsx index 6031ede8fa..626efe1f36 100644 --- a/src/components/views/messages/MJitsiWidgetEvent.tsx +++ b/src/components/views/messages/MJitsiWidgetEvent.tsx @@ -21,11 +21,13 @@ import WidgetStore from "../../../stores/WidgetStore"; import EventTileBubble from "./EventTileBubble"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { Container, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { mxEvent: MatrixEvent; } +@replaceableComponent("views.messages.MJitsiWidgetEvent") export default class MJitsiWidgetEvent extends React.PureComponent<IProps> { constructor(props) { super(props); diff --git a/src/components/views/messages/MKeyVerificationConclusion.js b/src/components/views/messages/MKeyVerificationConclusion.js index 880299d29d..75d20131c0 100644 --- a/src/components/views/messages/MKeyVerificationConclusion.js +++ b/src/components/views/messages/MKeyVerificationConclusion.js @@ -22,7 +22,9 @@ import { _t } from '../../../languageHandler'; import {getNameForEventRoom, userLabelForEventRoom} from '../../../utils/KeyVerificationStateObserver'; import EventTileBubble from "./EventTileBubble"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.MKeyVerificationConclusion") export default class MKeyVerificationConclusion extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/messages/MKeyVerificationRequest.js b/src/components/views/messages/MKeyVerificationRequest.js index d9594091c5..988606a766 100644 --- a/src/components/views/messages/MKeyVerificationRequest.js +++ b/src/components/views/messages/MKeyVerificationRequest.js @@ -25,7 +25,9 @@ import dis from "../../../dispatcher/dispatcher"; import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; import {Action} from "../../../dispatcher/actions"; import EventTileBubble from "./EventTileBubble"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.MKeyVerificationRequest") export default class MKeyVerificationRequest extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/messages/MStickerBody.js b/src/components/views/messages/MStickerBody.js index 9839080661..54eb7649b4 100644 --- a/src/components/views/messages/MStickerBody.js +++ b/src/components/views/messages/MStickerBody.js @@ -17,7 +17,9 @@ limitations under the License. import React from 'react'; import MImageBody from './MImageBody'; import * as sdk from '../../../index'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.MStickerBody") export default class MStickerBody extends MImageBody { // Mostly empty to prevent default behaviour of MImageBody onClick(ev) { diff --git a/src/components/views/messages/MVideoBody.tsx b/src/components/views/messages/MVideoBody.tsx index ce4a4eda76..89985dee7d 100644 --- a/src/components/views/messages/MVideoBody.tsx +++ b/src/components/views/messages/MVideoBody.tsx @@ -22,6 +22,7 @@ import { decryptFile } from '../../../utils/DecryptFile'; import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import InlineSpinner from '../elements/InlineSpinner'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { /* the MatrixEvent to show */ @@ -38,6 +39,7 @@ interface IState { fetchingData: boolean, } +@replaceableComponent("views.messages.MVideoBody") export default class MVideoBody extends React.PureComponent<IProps, IState> { private videoRef = React.createRef<HTMLVideoElement>(); diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js index c94f296eac..c33debe3f5 100644 --- a/src/components/views/messages/MessageActionBar.js +++ b/src/components/views/messages/MessageActionBar.js @@ -28,6 +28,7 @@ import { isContentActionable, canEditContent } from '../../../utils/EventUtils'; import RoomContext from "../../../contexts/RoomContext"; import Toolbar from "../../../accessibility/Toolbar"; import {RovingAccessibleTooltipButton, useRovingTabIndex} from "../../../accessibility/RovingTabIndex"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const OptionsButton = ({mxEvent, getTile, getReplyThread, permalinkCreator, onFocusChange}) => { const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu(); @@ -101,6 +102,7 @@ const ReactButton = ({mxEvent, reactions, onFocusChange}) => { </React.Fragment>; }; +@replaceableComponent("views.messages.MessageActionBar") export default class MessageActionBar extends React.PureComponent { static propTypes = { mxEvent: PropTypes.object.isRequired, diff --git a/src/components/views/messages/MessageEvent.js b/src/components/views/messages/MessageEvent.js index f93813fe79..866e0f521d 100644 --- a/src/components/views/messages/MessageEvent.js +++ b/src/components/views/messages/MessageEvent.js @@ -21,7 +21,9 @@ import SettingsStore from "../../../settings/SettingsStore"; import {Mjolnir} from "../../../mjolnir/Mjolnir"; import RedactedBody from "./RedactedBody"; import UnknownBody from "./UnknownBody"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.MessageEvent") export default class MessageEvent extends React.Component { static propTypes = { /* the MatrixEvent to show */ diff --git a/src/components/views/messages/MessageTimestamp.js b/src/components/views/messages/MessageTimestamp.js index 199a6f47ce..c9bdb8937e 100644 --- a/src/components/views/messages/MessageTimestamp.js +++ b/src/components/views/messages/MessageTimestamp.js @@ -18,7 +18,9 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import {formatFullDate, formatTime} from '../../../DateUtils'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.MessageTimestamp") export default class MessageTimestamp extends React.Component { static propTypes = { ts: PropTypes.number.isRequired, diff --git a/src/components/views/messages/MjolnirBody.js b/src/components/views/messages/MjolnirBody.js index baaee91657..4368fd936c 100644 --- a/src/components/views/messages/MjolnirBody.js +++ b/src/components/views/messages/MjolnirBody.js @@ -17,7 +17,9 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import {_t} from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.MjolnirBody") export default class MjolnirBody extends React.Component { static propTypes = { mxEvent: PropTypes.object.isRequired, diff --git a/src/components/views/messages/ReactionsRow.js b/src/components/views/messages/ReactionsRow.js index 3451cdbb2d..d5c8ea2ac9 100644 --- a/src/components/views/messages/ReactionsRow.js +++ b/src/components/views/messages/ReactionsRow.js @@ -21,10 +21,12 @@ import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { isContentActionable } from '../../../utils/EventUtils'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // The maximum number of reactions to initially show on a message. const MAX_ITEMS_WHEN_LIMITED = 8; +@replaceableComponent("views.messages.ReactionsRow") export default class ReactionsRow extends React.PureComponent { static propTypes = { // The event we're displaying reactions for diff --git a/src/components/views/messages/ReactionsRowButton.js b/src/components/views/messages/ReactionsRowButton.js index bb8d9a3b6e..06421c02a2 100644 --- a/src/components/views/messages/ReactionsRowButton.js +++ b/src/components/views/messages/ReactionsRowButton.js @@ -23,7 +23,9 @@ import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { formatCommaSeparatedList } from '../../../utils/FormattingUtils'; import dis from "../../../dispatcher/dispatcher"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.ReactionsRowButton") export default class ReactionsRowButton extends React.PureComponent { static propTypes = { // The event we're displaying reactions for diff --git a/src/components/views/messages/ReactionsRowButtonTooltip.js b/src/components/views/messages/ReactionsRowButtonTooltip.js index 2b90175722..5ecdfe311d 100644 --- a/src/components/views/messages/ReactionsRowButtonTooltip.js +++ b/src/components/views/messages/ReactionsRowButtonTooltip.js @@ -22,7 +22,9 @@ import * as sdk from '../../../index'; import { unicodeToShortcode } from '../../../HtmlUtils'; import { _t } from '../../../languageHandler'; import { formatCommaSeparatedList } from '../../../utils/FormattingUtils'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.ReactionsRowButtonTooltip") export default class ReactionsRowButtonTooltip extends React.PureComponent { static propTypes = { // The event we're displaying reactions for diff --git a/src/components/views/messages/RoomAvatarEvent.js b/src/components/views/messages/RoomAvatarEvent.js index f526d080cc..ba860216f0 100644 --- a/src/components/views/messages/RoomAvatarEvent.js +++ b/src/components/views/messages/RoomAvatarEvent.js @@ -23,7 +23,9 @@ import { _t } from '../../../languageHandler'; import * as sdk from '../../../index'; import Modal from '../../../Modal'; import AccessibleButton from '../elements/AccessibleButton'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.RoomAvatarEvent") export default class RoomAvatarEvent extends React.Component { static propTypes = { /* the MatrixEvent to show */ diff --git a/src/components/views/messages/RoomCreate.js b/src/components/views/messages/RoomCreate.js index 479592aa42..3e02884c02 100644 --- a/src/components/views/messages/RoomCreate.js +++ b/src/components/views/messages/RoomCreate.js @@ -23,7 +23,9 @@ import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks'; import { _t } from '../../../languageHandler'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import EventTileBubble from "./EventTileBubble"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.RoomCreate") export default class RoomCreate extends React.Component { static propTypes = { /* the MatrixEvent to show */ diff --git a/src/components/views/messages/SenderProfile.js b/src/components/views/messages/SenderProfile.js index d2db05252c..bd10526799 100644 --- a/src/components/views/messages/SenderProfile.js +++ b/src/components/views/messages/SenderProfile.js @@ -20,7 +20,9 @@ import Flair from '../elements/Flair.js'; import FlairStore from '../../../stores/FlairStore'; import {getUserNameColorClass} from '../../../utils/FormattingUtils'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.SenderProfile") export default class SenderProfile extends React.Component { static propTypes = { mxEvent: PropTypes.object.isRequired, // event whose sender we're showing diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index 04db7bd725..b0eb6f2f35 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -35,7 +35,9 @@ import {isPermalinkHost} from "../../../utils/permalinks/Permalinks"; import {toRightOf} from "../../structures/ContextMenu"; import {copyPlaintext} from "../../../utils/strings"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.TextualBody") export default class TextualBody extends React.Component { static propTypes = { /* the MatrixEvent to show */ diff --git a/src/components/views/messages/TextualEvent.js b/src/components/views/messages/TextualEvent.js index 99e94147f7..a020cc6c52 100644 --- a/src/components/views/messages/TextualEvent.js +++ b/src/components/views/messages/TextualEvent.js @@ -18,7 +18,9 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import * as TextForEvent from "../../../TextForEvent"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.TextualEvent") export default class TextualEvent extends React.Component { static propTypes = { /* the MatrixEvent to show */ diff --git a/src/components/views/messages/TileErrorBoundary.js b/src/components/views/messages/TileErrorBoundary.js index 9b67e32548..0e9a7b6128 100644 --- a/src/components/views/messages/TileErrorBoundary.js +++ b/src/components/views/messages/TileErrorBoundary.js @@ -20,7 +20,9 @@ import { _t } from '../../../languageHandler'; import * as sdk from '../../../index'; import Modal from '../../../Modal'; import SdkConfig from "../../../SdkConfig"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.TileErrorBoundary") export default class TileErrorBoundary extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/messages/ViewSourceEvent.js b/src/components/views/messages/ViewSourceEvent.js index 9064fc3b68..adc7a248cd 100644 --- a/src/components/views/messages/ViewSourceEvent.js +++ b/src/components/views/messages/ViewSourceEvent.js @@ -17,7 +17,9 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.messages.ViewSourceEvent") export default class ViewSourceEvent extends React.PureComponent { static propTypes = { /* the MatrixEvent to show */ diff --git a/src/components/views/right_panel/GroupHeaderButtons.tsx b/src/components/views/right_panel/GroupHeaderButtons.tsx index dd4a82e645..f006975b08 100644 --- a/src/components/views/right_panel/GroupHeaderButtons.tsx +++ b/src/components/views/right_panel/GroupHeaderButtons.tsx @@ -26,6 +26,7 @@ import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; import {Action} from "../../../dispatcher/actions"; import {ActionPayload} from "../../../dispatcher/payloads"; import {ViewUserPayload} from "../../../dispatcher/payloads/ViewUserPayload"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const GROUP_PHASES = [ RightPanelPhases.GroupMemberInfo, @@ -38,6 +39,7 @@ const ROOM_PHASES = [ interface IProps {} +@replaceableComponent("views.right_panel.GroupHeaderButtons") export default class GroupHeaderButtons extends HeaderButtons { constructor(props: IProps) { super(props, HeaderKind.Group); diff --git a/src/components/views/right_panel/HeaderButton.tsx b/src/components/views/right_panel/HeaderButton.tsx index 7f682e2d89..2bc360e380 100644 --- a/src/components/views/right_panel/HeaderButton.tsx +++ b/src/components/views/right_panel/HeaderButton.tsx @@ -22,6 +22,7 @@ import React from 'react'; import classNames from 'classnames'; import Analytics from '../../../Analytics'; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { // Whether this button is highlighted @@ -41,6 +42,7 @@ interface IProps { // TODO: replace this, the composer buttons and the right panel buttons with a unified // representation +@replaceableComponent("views.right_panel.HeaderButton") export default class HeaderButton extends React.Component<IProps> { constructor(props: IProps) { super(props); diff --git a/src/components/views/right_panel/HeaderButtons.tsx b/src/components/views/right_panel/HeaderButtons.tsx index 543c7c067f..2144292679 100644 --- a/src/components/views/right_panel/HeaderButtons.tsx +++ b/src/components/views/right_panel/HeaderButtons.tsx @@ -28,6 +28,7 @@ import { SetRightPanelPhaseRefireParams, } from '../../../dispatcher/payloads/SetRightPanelPhasePayload'; import {EventSubscription} from "fbemitter"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; export enum HeaderKind { Room = "room", @@ -41,6 +42,7 @@ interface IState { interface IProps {} +@replaceableComponent("views.right_panel.HeaderButtons") export default abstract class HeaderButtons extends React.Component<IProps, IState> { private storeToken: EventSubscription; private dispatcherRef: string; diff --git a/src/components/views/right_panel/RoomHeaderButtons.tsx b/src/components/views/right_panel/RoomHeaderButtons.tsx index c2364546fd..0571622e64 100644 --- a/src/components/views/right_panel/RoomHeaderButtons.tsx +++ b/src/components/views/right_panel/RoomHeaderButtons.tsx @@ -26,6 +26,7 @@ import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; import {Action} from "../../../dispatcher/actions"; import {ActionPayload} from "../../../dispatcher/payloads"; import RightPanelStore from "../../../stores/RightPanelStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const ROOM_INFO_PHASES = [ RightPanelPhases.RoomSummary, @@ -37,6 +38,7 @@ const ROOM_INFO_PHASES = [ RightPanelPhases.Room3pidMemberInfo, ]; +@replaceableComponent("views.right_panel.RoomHeaderButtons") export default class RoomHeaderButtons extends HeaderButtons { constructor(props) { super(props, HeaderKind.Room); diff --git a/src/components/views/right_panel/VerificationPanel.tsx b/src/components/views/right_panel/VerificationPanel.tsx index f584a63209..ac01c953b9 100644 --- a/src/components/views/right_panel/VerificationPanel.tsx +++ b/src/components/views/right_panel/VerificationPanel.tsx @@ -36,6 +36,7 @@ import { PHASE_CANCELLED, } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; import Spinner from "../elements/Spinner"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // XXX: Should be defined in matrix-js-sdk enum VerificationPhase { @@ -65,6 +66,7 @@ interface IState { reciprocateQREvent?: ReciprocateQRCode; } +@replaceableComponent("views.right_panel.VerificationPanel") export default class VerificationPanel extends React.PureComponent<IProps, IState> { private hasVerifier: boolean; diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js index eb9276b729..ee8232ebd7 100644 --- a/src/components/views/room_settings/AliasSettings.js +++ b/src/components/views/room_settings/AliasSettings.js @@ -26,6 +26,7 @@ import ErrorDialog from "../dialogs/ErrorDialog"; import AccessibleButton from "../elements/AccessibleButton"; import Modal from "../../../Modal"; import RoomPublishSetting from "./RoomPublishSetting"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; class EditableAliasesList extends EditableItemList { constructor(props) { @@ -74,6 +75,7 @@ class EditableAliasesList extends EditableItemList { } } +@replaceableComponent("views.room_settings.AliasSettings") export default class AliasSettings extends React.Component { static propTypes = { roomId: PropTypes.string.isRequired, diff --git a/src/components/views/room_settings/RelatedGroupSettings.js b/src/components/views/room_settings/RelatedGroupSettings.js index af3f58f9db..f82e238722 100644 --- a/src/components/views/room_settings/RelatedGroupSettings.js +++ b/src/components/views/room_settings/RelatedGroupSettings.js @@ -22,9 +22,11 @@ import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; import ErrorDialog from "../dialogs/ErrorDialog"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const GROUP_ID_REGEX = /\+\S+:\S+/; +@replaceableComponent("views.room_settings.RelatedGroupSettings") export default class RelatedGroupSettings extends React.Component { static propTypes = { roomId: PropTypes.string.isRequired, diff --git a/src/components/views/room_settings/RoomProfileSettings.js b/src/components/views/room_settings/RoomProfileSettings.js index 65acc802dc..563368384b 100644 --- a/src/components/views/room_settings/RoomProfileSettings.js +++ b/src/components/views/room_settings/RoomProfileSettings.js @@ -20,8 +20,10 @@ import {_t} from "../../../languageHandler"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import Field from "../elements/Field"; import * as sdk from "../../../index"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // TODO: Merge with ProfileSettings? +@replaceableComponent("views.room_settings.RoomProfileSettings") export default class RoomProfileSettings extends React.Component { static propTypes = { roomId: PropTypes.string.isRequired, diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js index 114e9b2894..7b04e296e5 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.js +++ b/src/components/views/room_settings/UrlPreviewSettings.js @@ -26,8 +26,9 @@ import dis from "../../../dispatcher/dispatcher"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import {Action} from "../../../dispatcher/actions"; import {SettingLevel} from "../../../settings/SettingLevel"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; - +@replaceableComponent("views.room_settings.UrlPreviewSettings") export default class UrlPreviewSettings extends React.Component { static propTypes = { room: PropTypes.object, diff --git a/src/components/views/rooms/AppsDrawer.js b/src/components/views/rooms/AppsDrawer.js index aa7120bbe6..3ef8d71682 100644 --- a/src/components/views/rooms/AppsDrawer.js +++ b/src/components/views/rooms/AppsDrawer.js @@ -35,7 +35,9 @@ import PercentageDistributor from "../../../resizer/distributors/percentage"; import {Container, WidgetLayoutStore} from "../../../stores/widgets/WidgetLayoutStore"; import {clamp, percentageOf, percentageWithin} from "../../../utils/numbers"; import {useStateCallback} from "../../../hooks/useStateCallback"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.AppsDrawer") export default class AppsDrawer extends React.Component { static propTypes = { userId: PropTypes.string.isRequired, diff --git a/src/components/views/rooms/Autocomplete.tsx b/src/components/views/rooms/Autocomplete.tsx index 15af75084a..a4dcba11a3 100644 --- a/src/components/views/rooms/Autocomplete.tsx +++ b/src/components/views/rooms/Autocomplete.tsx @@ -23,6 +23,7 @@ import {Room} from 'matrix-js-sdk/src/models/room'; import SettingsStore from "../../../settings/SettingsStore"; import Autocompleter from '../../../autocomplete/Autocompleter'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const COMPOSER_SELECTED = 0; @@ -49,6 +50,7 @@ interface IState { forceComplete: boolean; } +@replaceableComponent("views.rooms.Autocomplete") export default class Autocomplete extends React.PureComponent<IProps, IState> { autocompleter: Autocompleter; queryRequested: string; diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx index d193b98ec1..3d431f7c67 100644 --- a/src/components/views/rooms/AuxPanel.tsx +++ b/src/components/views/rooms/AuxPanel.tsx @@ -27,6 +27,7 @@ import {UIFeature} from "../../../settings/UIFeature"; import { ResizeNotifier } from "../../../utils/ResizeNotifier"; import CallViewForRoom from '../voip/CallViewForRoom'; import {objectHasDiff} from "../../../utils/objects"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { // js-sdk room object @@ -58,6 +59,7 @@ interface IState { counters: Counter[], } +@replaceableComponent("views.rooms.AuxPanel") export default class AuxPanel extends React.Component<IProps, IState> { static defaultProps = { showApps: true, diff --git a/src/components/views/rooms/BasicMessageComposer.tsx b/src/components/views/rooms/BasicMessageComposer.tsx index 017ce77166..5ab2b82a32 100644 --- a/src/components/views/rooms/BasicMessageComposer.tsx +++ b/src/components/views/rooms/BasicMessageComposer.tsx @@ -46,6 +46,7 @@ import {IDiff} from "../../../editor/diff"; import AutocompleteWrapperModel from "../../../editor/autocomplete"; import DocumentPosition from "../../../editor/position"; import {ICompletion} from "../../../autocomplete/Autocompleter"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // matches emoticons which follow the start of a line or whitespace const REGEX_EMOTICON_WHITESPACE = new RegExp('(?:^|\\s)(' + EMOTICON_REGEX.source + ')\\s$'); @@ -105,6 +106,7 @@ interface IState { completionIndex?: number; } +@replaceableComponent("views.rooms.BasicMessageEditor") export default class BasicMessageEditor extends React.Component<IProps, IState> { private editorRef = createRef<HTMLDivElement>(); private autocompleteRef = createRef<Autocomplete>(); diff --git a/src/components/views/rooms/EditMessageComposer.js b/src/components/views/rooms/EditMessageComposer.js index c59b3555b9..6ecb2bd549 100644 --- a/src/components/views/rooms/EditMessageComposer.js +++ b/src/components/views/rooms/EditMessageComposer.js @@ -34,6 +34,7 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {Action} from "../../../dispatcher/actions"; import SettingsStore from "../../../settings/SettingsStore"; import CountlyAnalytics from "../../../CountlyAnalytics"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; function _isReply(mxEvent) { const relatesTo = mxEvent.getContent()["m.relates_to"]; @@ -102,6 +103,7 @@ function createEditContent(model, editedEvent) { }, contentBody); } +@replaceableComponent("views.rooms.EditMessageComposer") export default class EditMessageComposer extends React.Component { static propTypes = { // the message event being edited diff --git a/src/components/views/rooms/EntityTile.js b/src/components/views/rooms/EntityTile.js index 9017e4aa3e..75b03739b9 100644 --- a/src/components/views/rooms/EntityTile.js +++ b/src/components/views/rooms/EntityTile.js @@ -23,6 +23,7 @@ import AccessibleButton from '../elements/AccessibleButton'; import { _t } from '../../../languageHandler'; import classNames from "classnames"; import E2EIcon from './E2EIcon'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const PRESENCE_CLASS = { "offline": "mx_EntityTile_offline", @@ -50,6 +51,7 @@ function presenceClassForMember(presenceState, lastActiveAgo, showPresence) { } } +@replaceableComponent("views.rooms.EntityTile") class EntityTile extends React.Component { static propTypes = { name: PropTypes.string, diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index a705e92d9c..1366d9b603 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -39,6 +39,7 @@ import {WidgetType} from "../../../widgets/WidgetType"; import RoomAvatar from "../avatars/RoomAvatar"; import {WIDGET_LAYOUT_EVENT_TYPE} from "../../../stores/widgets/WidgetLayoutStore"; import {objectHasDiff} from "../../../utils/objects"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const eventTileTypes = { 'm.room.message': 'messages.MessageEvent', @@ -146,6 +147,7 @@ const MAX_READ_AVATARS = 5; // | '--------------------------------------' | // '----------------------------------------------------------' +@replaceableComponent("views.rooms.EventTile") export default class EventTile extends React.Component { static propTypes = { /* the MatrixEvent to show */ diff --git a/src/components/views/rooms/ForwardMessage.js b/src/components/views/rooms/ForwardMessage.js index b85dd2c8df..dd894c0dcf 100644 --- a/src/components/views/rooms/ForwardMessage.js +++ b/src/components/views/rooms/ForwardMessage.js @@ -19,8 +19,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; import {Key} from '../../../Keyboard'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; - +@replaceableComponent("views.rooms.ForwardMessage") export default class ForwardMessage extends React.Component { static propTypes = { onCancelClick: PropTypes.func.isRequired, diff --git a/src/components/views/rooms/LinkPreviewWidget.js b/src/components/views/rooms/LinkPreviewWidget.js index 2a053bf467..39c9f0bcf7 100644 --- a/src/components/views/rooms/LinkPreviewWidget.js +++ b/src/components/views/rooms/LinkPreviewWidget.js @@ -25,7 +25,9 @@ import * as sdk from "../../../index"; import Modal from "../../../Modal"; import * as ImageUtils from "../../../ImageUtils"; import { _t } from "../../../languageHandler"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.LinkPreviewWidget") export default class LinkPreviewWidget extends React.Component { static propTypes = { link: PropTypes.string.isRequired, // the URL being previewed diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index d4d618c821..593132a283 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -29,6 +29,7 @@ import BaseCard from "../right_panel/BaseCard"; import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; import RoomAvatar from "../avatars/RoomAvatar"; import RoomName from "../elements/RoomName"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const INITIAL_LOAD_NUM_MEMBERS = 30; const INITIAL_LOAD_NUM_INVITED = 5; @@ -38,6 +39,7 @@ const SHOW_MORE_INCREMENT = 100; // matches all ASCII punctuation: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ const SORT_REGEX = /[\x21-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]+/g; +@replaceableComponent("views.rooms.MemberList") export default class MemberList extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/rooms/MemberTile.js b/src/components/views/rooms/MemberTile.js index a43b42b6d3..f8df7ed78f 100644 --- a/src/components/views/rooms/MemberTile.js +++ b/src/components/views/rooms/MemberTile.js @@ -23,7 +23,9 @@ import dis from "../../../dispatcher/dispatcher"; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import {Action} from "../../../dispatcher/actions"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.MemberTile") export default class MemberTile extends React.Component { static propTypes = { member: PropTypes.any.isRequired, // RoomMember diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index c03178cdf7..ccf097c4fd 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -32,6 +32,7 @@ import {UIFeature} from "../../../settings/UIFeature"; import WidgetStore from "../../../stores/WidgetStore"; import {UPDATE_EVENT} from "../../../stores/AsyncStore"; import ActiveWidgetStore from "../../../stores/ActiveWidgetStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; function ComposerAvatar(props) { const MemberStatusMessageAvatar = sdk.getComponent('avatars.MemberStatusMessageAvatar'); @@ -168,6 +169,7 @@ class UploadButton extends React.Component { } } +@replaceableComponent("views.rooms.MessageComposer") export default class MessageComposer extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/rooms/MessageComposerFormatBar.js b/src/components/views/rooms/MessageComposerFormatBar.js index 71aef1e833..d2539b1ef4 100644 --- a/src/components/views/rooms/MessageComposerFormatBar.js +++ b/src/components/views/rooms/MessageComposerFormatBar.js @@ -19,7 +19,9 @@ import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; import classNames from 'classnames'; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.MessageComposerFormatBar") export default class MessageComposerFormatBar extends React.PureComponent { static propTypes = { onAction: PropTypes.func.isRequired, diff --git a/src/components/views/rooms/NotificationBadge.tsx b/src/components/views/rooms/NotificationBadge.tsx index 8b996d3238..36a52e260d 100644 --- a/src/components/views/rooms/NotificationBadge.tsx +++ b/src/components/views/rooms/NotificationBadge.tsx @@ -21,6 +21,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import AccessibleButton from "../elements/AccessibleButton"; import { XOR } from "../../../@types/common"; import { NOTIFICATION_STATE_UPDATE, NotificationState } from "../../../stores/notifications/NotificationState"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { notification: NotificationState; @@ -48,6 +49,7 @@ interface IState { showCounts: boolean; // whether or not to show counts. Independent of props.forceCount } +@replaceableComponent("views.rooms.NotificationBadge") export default class NotificationBadge extends React.PureComponent<XOR<IProps, IClickableProps>, IState> { private countWatcherRef: string; diff --git a/src/components/views/rooms/PinnedEventTile.js b/src/components/views/rooms/PinnedEventTile.js index 9fad0c2391..2259cad7fb 100644 --- a/src/components/views/rooms/PinnedEventTile.js +++ b/src/components/views/rooms/PinnedEventTile.js @@ -23,7 +23,9 @@ import MessageEvent from "../messages/MessageEvent"; import MemberAvatar from "../avatars/MemberAvatar"; import { _t } from '../../../languageHandler'; import {formatFullDate} from '../../../DateUtils'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.PinnedEventTile") export default class PinnedEventTile extends React.Component { static propTypes = { mxRoom: PropTypes.object.isRequired, diff --git a/src/components/views/rooms/PinnedEventsPanel.js b/src/components/views/rooms/PinnedEventsPanel.js index 3ea0299976..285829bf63 100644 --- a/src/components/views/rooms/PinnedEventsPanel.js +++ b/src/components/views/rooms/PinnedEventsPanel.js @@ -22,7 +22,9 @@ import AccessibleButton from "../elements/AccessibleButton"; import PinnedEventTile from "./PinnedEventTile"; import { _t } from '../../../languageHandler'; import PinningUtils from "../../../utils/PinningUtils"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.PinnedEventsPanel") export default class PinnedEventsPanel extends React.Component { static propTypes = { // The Room from the js-sdk we're going to show pinned events for diff --git a/src/components/views/rooms/PresenceLabel.js b/src/components/views/rooms/PresenceLabel.js index ff1460ca21..ca21afe63d 100644 --- a/src/components/views/rooms/PresenceLabel.js +++ b/src/components/views/rooms/PresenceLabel.js @@ -18,8 +18,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; - +@replaceableComponent("views.rooms.PresenceLabel") export default class PresenceLabel extends React.Component { static propTypes = { // number of milliseconds ago this user was last active. diff --git a/src/components/views/rooms/ReadReceiptMarker.js b/src/components/views/rooms/ReadReceiptMarker.js index ba2b3064fd..ade84cbef3 100644 --- a/src/components/views/rooms/ReadReceiptMarker.js +++ b/src/components/views/rooms/ReadReceiptMarker.js @@ -23,6 +23,7 @@ import {formatDate} from '../../../DateUtils'; import Velociraptor from "../../../Velociraptor"; import * as sdk from "../../../index"; import {toPx} from "../../../utils/units"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; let bounce = false; try { @@ -32,6 +33,7 @@ try { } catch (e) { } +@replaceableComponent("views.rooms.ReadReceiptMarker") export default class ReadReceiptMarker extends React.PureComponent { static propTypes = { // the RoomMember to show the RR for diff --git a/src/components/views/rooms/ReplyPreview.js b/src/components/views/rooms/ReplyPreview.js index c7872d95ed..0d99be4f53 100644 --- a/src/components/views/rooms/ReplyPreview.js +++ b/src/components/views/rooms/ReplyPreview.js @@ -23,6 +23,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import PropTypes from "prop-types"; import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks"; import {UIFeature} from "../../../settings/UIFeature"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; function cancelQuoting() { dis.dispatch({ @@ -31,6 +32,7 @@ function cancelQuoting() { }); } +@replaceableComponent("views.rooms.ReplyPreview") export default class ReplyPreview extends React.Component { static propTypes = { permalinkCreator: PropTypes.instanceOf(RoomPermalinkCreator).isRequired, diff --git a/src/components/views/rooms/RoomBreadcrumbs.tsx b/src/components/views/rooms/RoomBreadcrumbs.tsx index ff60ab7779..ea0ff233da 100644 --- a/src/components/views/rooms/RoomBreadcrumbs.tsx +++ b/src/components/views/rooms/RoomBreadcrumbs.tsx @@ -27,6 +27,7 @@ import RoomListStore from "../../../stores/room-list/RoomListStore"; import { DefaultTagID } from "../../../stores/room-list/models"; import { RovingAccessibleTooltipButton } from "../../../accessibility/RovingTabIndex"; import Toolbar from "../../../accessibility/Toolbar"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { } @@ -42,6 +43,7 @@ interface IState { skipFirst: boolean; } +@replaceableComponent("views.rooms.RoomBreadcrumbs") export default class RoomBreadcrumbs extends React.PureComponent<IProps, IState> { private isMounted = true; diff --git a/src/components/views/rooms/RoomDetailList.js b/src/components/views/rooms/RoomDetailList.js index d8205aeb21..be22cda199 100644 --- a/src/components/views/rooms/RoomDetailList.js +++ b/src/components/views/rooms/RoomDetailList.js @@ -22,7 +22,9 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import {roomShape} from './RoomDetailRow'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.RoomDetailList") export default class RoomDetailList extends React.Component { static propTypes = { rooms: PropTypes.arrayOf(roomShape), diff --git a/src/components/views/rooms/RoomDetailRow.js b/src/components/views/rooms/RoomDetailRow.js index 667f821922..e7c259cd98 100644 --- a/src/components/views/rooms/RoomDetailRow.js +++ b/src/components/views/rooms/RoomDetailRow.js @@ -21,6 +21,7 @@ import { linkifyElement } from '../../../HtmlUtils'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import PropTypes from 'prop-types'; import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; export function getDisplayAliasForRoom(room) { return room.canonicalAlias || (room.aliases ? room.aliases[0] : ""); @@ -39,6 +40,7 @@ export const roomShape = PropTypes.shape({ guestCanJoin: PropTypes.bool, }); +@replaceableComponent("views.rooms.RoomDetailRow") export default class RoomDetailRow extends React.Component { static propTypes = { room: roomShape, diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index 6736600bc8..f856f7f6ef 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -32,7 +32,9 @@ import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import RoomTopic from "../elements/RoomTopic"; import RoomName from "../elements/RoomName"; import {PlaceCallType} from "../../../CallHandler"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.RoomHeader") export default class RoomHeader extends React.Component { static propTypes = { room: PropTypes.object, diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx index f7da6571da..ff6e3793bf 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/RoomList.tsx @@ -50,6 +50,7 @@ import CallHandler from "../../../CallHandler"; import SpaceStore from "../../../stores/SpaceStore"; import { showAddExistingRooms, showCreateNewRoom } from "../../../utils/space"; import { EventType } from "matrix-js-sdk/src/@types/event"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { onKeyDown: (ev: React.KeyboardEvent) => void; @@ -256,6 +257,7 @@ function customTagAesthetics(tagId: TagID): ITagAesthetics { }; } +@replaceableComponent("views.rooms.RoomList") export default class RoomList extends React.PureComponent<IProps, IState> { private dispatcherRef; private customTagStoreRef; diff --git a/src/components/views/rooms/RoomPreviewBar.js b/src/components/views/rooms/RoomPreviewBar.js index dc68068157..36038da61c 100644 --- a/src/components/views/rooms/RoomPreviewBar.js +++ b/src/components/views/rooms/RoomPreviewBar.js @@ -27,6 +27,7 @@ import SdkConfig from "../../../SdkConfig"; import IdentityAuthClient from '../../../IdentityAuthClient'; import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore"; import {UPDATE_EVENT} from "../../../stores/AsyncStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const MessageCase = Object.freeze({ NotLoggedIn: "NotLoggedIn", @@ -45,6 +46,7 @@ const MessageCase = Object.freeze({ OtherError: "OtherError", }); +@replaceableComponent("views.rooms.RoomPreviewBar") export default class RoomPreviewBar extends React.Component { static propTypes = { onJoinClick: PropTypes.func, diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx index a2574bf60c..cb98ba85e4 100644 --- a/src/components/views/rooms/RoomSublist.tsx +++ b/src/components/views/rooms/RoomSublist.tsx @@ -51,6 +51,7 @@ import { objectExcluding, objectHasDiff } from "../../../utils/objects"; import TemporaryTile from "./TemporaryTile"; import { ListNotificationState } from "../../../stores/notifications/ListNotificationState"; import IconizedContextMenu from "../context_menus/IconizedContextMenu"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const SHOW_N_BUTTON_HEIGHT = 28; // As defined by CSS const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS @@ -98,6 +99,7 @@ interface IState { filteredExtraTiles?: TemporaryTile[]; } +@replaceableComponent("views.rooms.RoomSublist") export default class RoomSublist extends React.Component<IProps, IState> { private headerButton = createRef<HTMLDivElement>(); private sublistRef = createRef<HTMLDivElement>(); diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index 835447dc18..07de70fe45 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -51,6 +51,7 @@ import IconizedContextMenu, { IconizedContextMenuRadio, } from "../context_menus/IconizedContextMenu"; import { CommunityPrototypeStore, IRoomProfile } from "../../../stores/CommunityPrototypeStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { room: Room; @@ -78,6 +79,7 @@ const contextMenuBelow = (elementRect: PartialDOMRect) => { return {left, top, chevronFace}; }; +@replaceableComponent("views.rooms.RoomTile") export default class RoomTile extends React.PureComponent<IProps, IState> { private dispatcherRef: string; private roomTileRef = createRef<HTMLDivElement>(); diff --git a/src/components/views/rooms/RoomUpgradeWarningBar.js b/src/components/views/rooms/RoomUpgradeWarningBar.js index 877cfb39d7..a2d4f92d35 100644 --- a/src/components/views/rooms/RoomUpgradeWarningBar.js +++ b/src/components/views/rooms/RoomUpgradeWarningBar.js @@ -21,7 +21,9 @@ import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; import {MatrixClientPeg} from "../../../MatrixClientPeg"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.RoomUpgradeWarningBar") export default class RoomUpgradeWarningBar extends React.Component { static propTypes = { room: PropTypes.object.isRequired, diff --git a/src/components/views/rooms/SearchBar.js b/src/components/views/rooms/SearchBar.js index ac637673e4..029516c932 100644 --- a/src/components/views/rooms/SearchBar.js +++ b/src/components/views/rooms/SearchBar.js @@ -21,7 +21,9 @@ import classNames from "classnames"; import { _t } from '../../../languageHandler'; import {Key} from "../../../Keyboard"; import DesktopBuildsNotice, {WarningKind} from "../elements/DesktopBuildsNotice"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.SearchBar") export default class SearchBar extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/rooms/SearchResultTile.js b/src/components/views/rooms/SearchResultTile.js index 29def9e368..dcfd633e76 100644 --- a/src/components/views/rooms/SearchResultTile.js +++ b/src/components/views/rooms/SearchResultTile.js @@ -21,7 +21,9 @@ import * as sdk from '../../../index'; import {haveTileForEvent} from "./EventTile"; import SettingsStore from "../../../settings/SettingsStore"; import {UIFeature} from "../../../settings/UIFeature"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.SearchResultTile") export default class SearchResultTile extends React.Component { static propTypes = { // a matrix-js-sdk SearchResult containing the details of this result diff --git a/src/components/views/rooms/SendMessageComposer.js b/src/components/views/rooms/SendMessageComposer.js index 673df949f7..ba3076c07d 100644 --- a/src/components/views/rooms/SendMessageComposer.js +++ b/src/components/views/rooms/SendMessageComposer.js @@ -48,6 +48,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import CountlyAnalytics from "../../../CountlyAnalytics"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import EMOJI_REGEX from 'emojibase-regex'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; function addReplyToMessageContent(content, repliedToEvent, permalinkCreator) { const replyContent = ReplyThread.makeReplyMixIn(repliedToEvent); @@ -111,6 +112,7 @@ export function isQuickReaction(model) { return false; } +@replaceableComponent("views.rooms.SendMessageComposer") export default class SendMessageComposer extends React.Component { static propTypes = { room: PropTypes.object.isRequired, diff --git a/src/components/views/rooms/SimpleRoomHeader.js b/src/components/views/rooms/SimpleRoomHeader.js index 1c78253eff..b2a66f6670 100644 --- a/src/components/views/rooms/SimpleRoomHeader.js +++ b/src/components/views/rooms/SimpleRoomHeader.js @@ -19,6 +19,7 @@ import PropTypes from 'prop-types'; import AccessibleButton from '../elements/AccessibleButton'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // cancel button which is shared between room header and simple room header export function CancelButton(props) { @@ -36,6 +37,7 @@ export function CancelButton(props) { * A stripped-down room header used for things like the user settings * and room directory. */ +@replaceableComponent("views.rooms.SimpleRoomHeader") export default class SimpleRoomHeader extends React.Component { static propTypes = { title: PropTypes.string, diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index 5446d15671..44d31d7146 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -30,6 +30,7 @@ import {WidgetType} from "../../../widgets/WidgetType"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import {Action} from "../../../dispatcher/actions"; import {WidgetMessagingStore} from "../../../stores/widgets/WidgetMessagingStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // This should be below the dialog level (4000), but above the rest of the UI (1000-2000). // We sit in a context menu, so this should be given to the context menu. @@ -38,6 +39,7 @@ const STICKERPICKER_Z_INDEX = 3500; // Key to store the widget's AppTile under in PersistedElement const PERSISTED_ELEMENT_KEY = "stickerPicker"; +@replaceableComponent("views.rooms.Stickerpicker") export default class Stickerpicker extends React.Component { static currentWidget; diff --git a/src/components/views/rooms/TemporaryTile.tsx b/src/components/views/rooms/TemporaryTile.tsx index eec3105880..a9765faa5d 100644 --- a/src/components/views/rooms/TemporaryTile.tsx +++ b/src/components/views/rooms/TemporaryTile.tsx @@ -22,6 +22,7 @@ import { } from "../../../accessibility/RovingTabIndex"; import NotificationBadge from "./NotificationBadge"; import { NotificationState } from "../../../stores/notifications/NotificationState"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { isMinimized: boolean; @@ -37,6 +38,7 @@ interface IState { } // TODO: Remove with community invites in the room list: https://github.com/vector-im/element-web/issues/14456 +@replaceableComponent("views.rooms.TemporaryTile") export default class TemporaryTile extends React.Component<IProps, IState> { constructor(props: IProps) { super(props); diff --git a/src/components/views/rooms/ThirdPartyMemberInfo.js b/src/components/views/rooms/ThirdPartyMemberInfo.js index 73510c2b4f..5e2d82a1b2 100644 --- a/src/components/views/rooms/ThirdPartyMemberInfo.js +++ b/src/components/views/rooms/ThirdPartyMemberInfo.js @@ -25,7 +25,9 @@ import Modal from "../../../Modal"; import {isValid3pidInvite} from "../../../RoomInvite"; import RoomAvatar from "../avatars/RoomAvatar"; import RoomName from "../elements/RoomName"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.ThirdPartyMemberInfo") export default class ThirdPartyMemberInfo extends React.Component { static propTypes = { event: PropTypes.instanceOf(MatrixEvent).isRequired, diff --git a/src/components/views/rooms/TopUnreadMessagesBar.js b/src/components/views/rooms/TopUnreadMessagesBar.js index 9ac3c49ef4..cba99ac913 100644 --- a/src/components/views/rooms/TopUnreadMessagesBar.js +++ b/src/components/views/rooms/TopUnreadMessagesBar.js @@ -20,7 +20,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; import AccessibleButton from '../elements/AccessibleButton'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.TopUnreadMessagesBar") export default class TopUnreadMessagesBar extends React.Component { static propTypes = { onScrollUpClick: PropTypes.func, diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index 905cbe6d09..a25b43fc3a 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -21,7 +21,9 @@ import * as WhoIsTyping from '../../../WhoIsTyping'; import Timer from '../../../utils/Timer'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import MemberAvatar from '../avatars/MemberAvatar'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.rooms.WhoIsTypingTile") export default class WhoIsTypingTile extends React.Component { static propTypes = { // the room this statusbar is representing. diff --git a/src/components/views/settings/BridgeTile.tsx b/src/components/views/settings/BridgeTile.tsx index 58499ebd25..b33219ad4a 100644 --- a/src/components/views/settings/BridgeTile.tsx +++ b/src/components/views/settings/BridgeTile.tsx @@ -26,6 +26,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import {MatrixEvent} from "matrix-js-sdk/src/models/event"; import { Room } from "matrix-js-sdk/src/models/room"; import { isUrlPermitted } from '../../../HtmlUtils'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { ev: MatrixEvent; @@ -64,6 +65,7 @@ interface IBridgeStateEvent { }; } +@replaceableComponent("views.settings.BridgeTile") export default class BridgeTile extends React.PureComponent<IProps> { static propTypes = { ev: PropTypes.object.isRequired, diff --git a/src/components/views/settings/ChangeAvatar.js b/src/components/views/settings/ChangeAvatar.js index 7ab2936584..8067046ffd 100644 --- a/src/components/views/settings/ChangeAvatar.js +++ b/src/components/views/settings/ChangeAvatar.js @@ -20,7 +20,9 @@ import {MatrixClientPeg} from "../../../MatrixClientPeg"; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import Spinner from '../elements/Spinner'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.ChangeAvatar") export default class ChangeAvatar extends React.Component { static propTypes = { initialAvatarUrl: PropTypes.string, diff --git a/src/components/views/settings/ChangeDisplayName.js b/src/components/views/settings/ChangeDisplayName.js index 538e52d0ca..cae4a22be9 100644 --- a/src/components/views/settings/ChangeDisplayName.js +++ b/src/components/views/settings/ChangeDisplayName.js @@ -20,7 +20,9 @@ import React from 'react'; import * as sdk from '../../../index'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.ChangeDisplayName") export default class ChangeDisplayName extends React.Component { _getDisplayName = async () => { const cli = MatrixClientPeg.get(); diff --git a/src/components/views/settings/ChangePassword.js b/src/components/views/settings/ChangePassword.js index 22b758b1ca..aa635ef974 100644 --- a/src/components/views/settings/ChangePassword.js +++ b/src/components/views/settings/ChangePassword.js @@ -27,6 +27,7 @@ import * as sdk from "../../../index"; import Modal from "../../../Modal"; import PassphraseField from "../auth/PassphraseField"; import CountlyAnalytics from "../../../CountlyAnalytics"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const FIELD_OLD_PASSWORD = 'field_old_password'; const FIELD_NEW_PASSWORD = 'field_new_password'; @@ -34,6 +35,7 @@ const FIELD_NEW_PASSWORD_CONFIRM = 'field_new_password_confirm'; const PASSWORD_MIN_SCORE = 3; // safely unguessable: moderate protection from offline slow-hash scenario. +@replaceableComponent("views.settings.ChangePassword") export default class ChangePassword extends React.Component { static propTypes = { onFinished: PropTypes.func, diff --git a/src/components/views/settings/CrossSigningPanel.js b/src/components/views/settings/CrossSigningPanel.js index 1c548bd9d8..e5f57d1af2 100644 --- a/src/components/views/settings/CrossSigningPanel.js +++ b/src/components/views/settings/CrossSigningPanel.js @@ -23,7 +23,9 @@ import Modal from '../../../Modal'; import Spinner from '../elements/Spinner'; import InteractiveAuthDialog from '../dialogs/InteractiveAuthDialog'; import ConfirmDestroyCrossSigningDialog from '../dialogs/security/ConfirmDestroyCrossSigningDialog'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.CrossSigningPanel") export default class CrossSigningPanel extends React.PureComponent { constructor(props) { super(props); diff --git a/src/components/views/settings/DevicesPanel.js b/src/components/views/settings/DevicesPanel.js index dc3ce9e03d..e7d300b0f8 100644 --- a/src/components/views/settings/DevicesPanel.js +++ b/src/components/views/settings/DevicesPanel.js @@ -24,7 +24,9 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; import {SSOAuthEntry} from "../auth/InteractiveAuthEntryComponents"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.DevicesPanel") export default class DevicesPanel extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/settings/DevicesPanelEntry.js b/src/components/views/settings/DevicesPanelEntry.js index 567b144a92..93d4c78476 100644 --- a/src/components/views/settings/DevicesPanelEntry.js +++ b/src/components/views/settings/DevicesPanelEntry.js @@ -22,7 +22,9 @@ import { _t } from '../../../languageHandler'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {formatDate} from '../../../DateUtils'; import StyledCheckbox from '../elements/StyledCheckbox'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.DevicesPanelEntry") export default class DevicesPanelEntry extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index ec6ccacc9a..d78b99fc5d 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -25,7 +25,9 @@ import AccessibleButton from "../elements/AccessibleButton"; import {formatBytes, formatCountLong} from "../../../utils/FormattingUtils"; import EventIndexPeg from "../../../indexing/EventIndexPeg"; import {SettingLevel} from "../../../settings/SettingLevel"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.EventIndexPanel") export default class EventIndexPanel extends React.Component { constructor() { super(); diff --git a/src/components/views/settings/IntegrationManager.js b/src/components/views/settings/IntegrationManager.js index da11832cf5..b058625139 100644 --- a/src/components/views/settings/IntegrationManager.js +++ b/src/components/views/settings/IntegrationManager.js @@ -21,7 +21,9 @@ import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import dis from '../../../dispatcher/dispatcher'; import {Key} from "../../../Keyboard"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.IntegrationManager") export default class IntegrationManager extends React.Component { static propTypes = { // false to display an error saying that we couldn't connect to the integration manager diff --git a/src/components/views/settings/Notifications.js b/src/components/views/settings/Notifications.js index 1337991dc3..25fe434994 100644 --- a/src/components/views/settings/Notifications.js +++ b/src/components/views/settings/Notifications.js @@ -32,6 +32,7 @@ import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import AccessibleButton from "../elements/AccessibleButton"; import {SettingLevel} from "../../../settings/SettingLevel"; import {UIFeature} from "../../../settings/UIFeature"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // TODO: this "view" component still has far too much application logic in it, // which should be factored out to other files. @@ -65,6 +66,7 @@ function portLegacyActions(actions) { } } +@replaceableComponent("views.settings.Notifications") export default class Notifications extends React.Component { static phases = { LOADING: "LOADING", // The component is loading or sending data to the hs diff --git a/src/components/views/settings/ProfileSettings.js b/src/components/views/settings/ProfileSettings.js index 89d7cf6c2b..30dcdc3c47 100644 --- a/src/components/views/settings/ProfileSettings.js +++ b/src/components/views/settings/ProfileSettings.js @@ -23,7 +23,9 @@ import * as sdk from "../../../index"; import {OwnProfileStore} from "../../../stores/OwnProfileStore"; import Modal from "../../../Modal"; import ErrorDialog from "../dialogs/ErrorDialog"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.ProfileSettings") export default class ProfileSettings extends React.Component { constructor() { super(); diff --git a/src/components/views/settings/SecureBackupPanel.js b/src/components/views/settings/SecureBackupPanel.js index 080d83b2cf..310114c8af 100644 --- a/src/components/views/settings/SecureBackupPanel.js +++ b/src/components/views/settings/SecureBackupPanel.js @@ -26,7 +26,9 @@ import AccessibleButton from '../elements/AccessibleButton'; import QuestionDialog from '../dialogs/QuestionDialog'; import RestoreKeyBackupDialog from '../dialogs/security/RestoreKeyBackupDialog'; import { accessSecretStorage } from '../../../SecurityManager'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.SecureBackupPanel") export default class SecureBackupPanel extends React.PureComponent { constructor(props) { super(props); diff --git a/src/components/views/settings/SetIdServer.js b/src/components/views/settings/SetIdServer.js index e05fe4f1c3..fa2a36476d 100644 --- a/src/components/views/settings/SetIdServer.js +++ b/src/components/views/settings/SetIdServer.js @@ -27,6 +27,7 @@ import IdentityAuthClient from "../../../IdentityAuthClient"; import {abbreviateUrl, unabbreviateUrl} from "../../../utils/UrlUtils"; import { getDefaultIdentityServerUrl, doesIdentityServerHaveTerms } from '../../../utils/IdentityServerUtils'; import {timeout} from "../../../utils/promise"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; // We'll wait up to this long when checking for 3PID bindings on the IS. const REACHABILITY_TIMEOUT = 10000; // ms @@ -58,6 +59,7 @@ async function checkIdentityServerUrl(u) { } } +@replaceableComponent("views.settings.SetIdServer") export default class SetIdServer extends React.Component { static propTypes = { // Whether or not the ID server is missing terms. This affects the text diff --git a/src/components/views/settings/SetIntegrationManager.js b/src/components/views/settings/SetIntegrationManager.js index e6fb3f6e1c..29cc5d7131 100644 --- a/src/components/views/settings/SetIntegrationManager.js +++ b/src/components/views/settings/SetIntegrationManager.js @@ -20,7 +20,9 @@ import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; import * as sdk from '../../../index'; import SettingsStore from "../../../settings/SettingsStore"; import {SettingLevel} from "../../../settings/SettingLevel"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.SetIntegrationManager") export default class SetIntegrationManager extends React.Component { constructor() { super(); diff --git a/src/components/views/settings/SpellCheckSettings.tsx b/src/components/views/settings/SpellCheckSettings.tsx index d08f263b5f..e5455c8c68 100644 --- a/src/components/views/settings/SpellCheckSettings.tsx +++ b/src/components/views/settings/SpellCheckSettings.tsx @@ -18,6 +18,7 @@ import React from 'react'; import SpellCheckLanguagesDropdown from "../../../components/views/elements/SpellCheckLanguagesDropdown"; import AccessibleButton from "../../../components/views/elements/AccessibleButton"; import {_t} from "../../../languageHandler"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface ExistingSpellCheckLanguageIProps { language: string, @@ -53,6 +54,7 @@ export class ExistingSpellCheckLanguage extends React.Component<ExistingSpellChe } } +@replaceableComponent("views.settings.SpellCheckLanguages") export default class SpellCheckLanguages extends React.Component<SpellCheckLanguagesIProps, SpellCheckLanguagesIState> { constructor(props) { super(props); diff --git a/src/components/views/settings/account/EmailAddresses.js b/src/components/views/settings/account/EmailAddresses.js index a8de7693a9..1ebd374173 100644 --- a/src/components/views/settings/account/EmailAddresses.js +++ b/src/components/views/settings/account/EmailAddresses.js @@ -25,6 +25,7 @@ import * as Email from "../../../../email"; import AddThreepid from "../../../../AddThreepid"; import * as sdk from '../../../../index'; import Modal from '../../../../Modal'; +import {replaceableComponent} from "../../../../utils/replaceableComponent"; /* TODO: Improve the UX for everything in here. @@ -112,6 +113,7 @@ export class ExistingEmailAddress extends React.Component { } } +@replaceableComponent("views.settings.account.EmailAddresses") export default class EmailAddresses extends React.Component { static propTypes = { emails: PropTypes.array.isRequired, diff --git a/src/components/views/settings/account/PhoneNumbers.js b/src/components/views/settings/account/PhoneNumbers.js index df54b5ca1f..5725fdb909 100644 --- a/src/components/views/settings/account/PhoneNumbers.js +++ b/src/components/views/settings/account/PhoneNumbers.js @@ -25,6 +25,7 @@ import AddThreepid from "../../../../AddThreepid"; import CountryDropdown from "../../auth/CountryDropdown"; import * as sdk from '../../../../index'; import Modal from '../../../../Modal'; +import {replaceableComponent} from "../../../../utils/replaceableComponent"; /* TODO: Improve the UX for everything in here. @@ -107,6 +108,7 @@ export class ExistingPhoneNumber extends React.Component { } } +@replaceableComponent("views.settings.account.PhoneNumbers") export default class PhoneNumbers extends React.Component { static propTypes = { msisdns: PropTypes.array.isRequired, diff --git a/src/components/views/settings/discovery/EmailAddresses.js b/src/components/views/settings/discovery/EmailAddresses.js index f9a1ba1818..0493597537 100644 --- a/src/components/views/settings/discovery/EmailAddresses.js +++ b/src/components/views/settings/discovery/EmailAddresses.js @@ -23,6 +23,7 @@ import {MatrixClientPeg} from "../../../../MatrixClientPeg"; import * as sdk from '../../../../index'; import Modal from '../../../../Modal'; import AddThreepid from '../../../../AddThreepid'; +import {replaceableComponent} from "../../../../utils/replaceableComponent"; /* TODO: Improve the UX for everything in here. @@ -233,6 +234,7 @@ export class EmailAddress extends React.Component { } } +@replaceableComponent("views.settings.discovery.EmailAddresses") export default class EmailAddresses extends React.Component { static propTypes = { emails: PropTypes.array.isRequired, diff --git a/src/components/views/settings/discovery/PhoneNumbers.js b/src/components/views/settings/discovery/PhoneNumbers.js index 03f459ee15..5cbcdfe47e 100644 --- a/src/components/views/settings/discovery/PhoneNumbers.js +++ b/src/components/views/settings/discovery/PhoneNumbers.js @@ -23,6 +23,7 @@ import {MatrixClientPeg} from "../../../../MatrixClientPeg"; import * as sdk from '../../../../index'; import Modal from '../../../../Modal'; import AddThreepid from '../../../../AddThreepid'; +import {replaceableComponent} from "../../../../utils/replaceableComponent"; /* TODO: Improve the UX for everything in here. @@ -246,6 +247,7 @@ export class PhoneNumber extends React.Component { } } +@replaceableComponent("views.settings.discovery.PhoneNumbers") export default class PhoneNumbers extends React.Component { static propTypes = { msisdns: PropTypes.array.isRequired, diff --git a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js index 2fa61a0ee6..28aad65129 100644 --- a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js +++ b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js @@ -22,7 +22,9 @@ import * as sdk from "../../../../.."; import AccessibleButton from "../../../elements/AccessibleButton"; import Modal from "../../../../../Modal"; import dis from "../../../../../dispatcher/dispatcher"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.tabs.room.AdvancedRoomSettingsTab") export default class AdvancedRoomSettingsTab extends React.Component { static propTypes = { roomId: PropTypes.string.isRequired, diff --git a/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx b/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx index 3c74bd4c1a..8d886a191e 100644 --- a/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx @@ -21,6 +21,7 @@ import {MatrixEvent} from "matrix-js-sdk/src/models/event"; import {_t} from "../../../../../languageHandler"; import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import BridgeTile from "../../BridgeTile"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; const BRIDGE_EVENT_TYPES = [ "uk.half-shot.bridge", @@ -33,6 +34,7 @@ interface IProps { roomId: string; } +@replaceableComponent("views.settings.tabs.room.BridgeSettingsTab") export default class BridgeSettingsTab extends React.Component<IProps> { private renderBridgeCard(event: MatrixEvent, room: Room) { const content = event.getContent(); diff --git a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js index 9b8004d9d6..cd4a043622 100644 --- a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js +++ b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.js @@ -24,7 +24,9 @@ import dis from "../../../../../dispatcher/dispatcher"; import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; import SettingsStore from "../../../../../settings/SettingsStore"; import {UIFeature} from "../../../../../settings/UIFeature"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.tabs.room.GeneralRoomSettingsTab") export default class GeneralRoomSettingsTab extends React.Component { static propTypes = { roomId: PropTypes.string.isRequired, diff --git a/src/components/views/settings/tabs/room/NotificationSettingsTab.js b/src/components/views/settings/tabs/room/NotificationSettingsTab.js index dd88b5018f..baefb5ae20 100644 --- a/src/components/views/settings/tabs/room/NotificationSettingsTab.js +++ b/src/components/views/settings/tabs/room/NotificationSettingsTab.js @@ -22,7 +22,9 @@ import AccessibleButton from "../../../elements/AccessibleButton"; import Notifier from "../../../../../Notifier"; import SettingsStore from '../../../../../settings/SettingsStore'; import {SettingLevel} from "../../../../../settings/SettingLevel"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.tabs.room.NotificationsSettingsTab") export default class NotificationsSettingsTab extends React.Component { static propTypes = { roomId: PropTypes.string.isRequired, diff --git a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.js b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.js index 49d683c42a..09498e0d4a 100644 --- a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.js +++ b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.js @@ -21,6 +21,7 @@ import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import * as sdk from "../../../../.."; import AccessibleButton from "../../../elements/AccessibleButton"; import Modal from "../../../../../Modal"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; const plEventsToLabels = { // These will be translated for us later. @@ -103,6 +104,7 @@ export class BannedUser extends React.Component { } } +@replaceableComponent("views.settings.tabs.room.RolesRoomSettingsTab") export default class RolesRoomSettingsTab extends React.Component { static propTypes = { roomId: PropTypes.string.isRequired, diff --git a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js index f72e78fa3f..ce883c6d23 100644 --- a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js +++ b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js @@ -26,7 +26,9 @@ import StyledRadioGroup from '../../../elements/StyledRadioGroup'; import {SettingLevel} from "../../../../../settings/SettingLevel"; import SettingsStore from "../../../../../settings/SettingsStore"; import {UIFeature} from "../../../../../settings/UIFeature"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.tabs.room.SecurityRoomSettingsTab") export default class SecurityRoomSettingsTab extends React.Component { static propTypes = { roomId: PropTypes.string.isRequired, diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx index 80a20d8afa..d6e01d194c 100644 --- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx @@ -36,6 +36,7 @@ import StyledRadioGroup from "../../../elements/StyledRadioGroup"; import { SettingLevel } from "../../../../../settings/SettingLevel"; import {UIFeature} from "../../../../../settings/UIFeature"; import {Layout} from "../../../../../settings/Layout"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; interface IProps { } @@ -64,7 +65,7 @@ interface IState extends IThemeState { layout: Layout; } - +@replaceableComponent("views.settings.tabs.user.AppearanceUserSettingsTab") export default class AppearanceUserSettingsTab extends React.Component<IProps, IState> { private readonly MESSAGE_PREVIEW_TEXT = _t("Hey you. You're the best!"); diff --git a/src/components/views/settings/tabs/user/FlairUserSettingsTab.js b/src/components/views/settings/tabs/user/FlairUserSettingsTab.js index 26e0033233..28e80f3030 100644 --- a/src/components/views/settings/tabs/user/FlairUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/FlairUserSettingsTab.js @@ -17,7 +17,9 @@ limitations under the License. import React from 'react'; import {_t} from "../../../../../languageHandler"; import GroupUserSettings from "../../../groups/GroupUserSettings"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.tabs.user.FlairUserSettingsTab") export default class FlairUserSettingsTab extends React.Component { render() { return ( diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index b17ab18c39..314acf5d65 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -39,7 +39,9 @@ import { getThreepidsWithBindStatus } from '../../../../../boundThreepids'; import Spinner from "../../../elements/Spinner"; import {SettingLevel} from "../../../../../settings/SettingLevel"; import {UIFeature} from "../../../../../settings/UIFeature"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.tabs.user.GeneralUserSettingsTab") export default class GeneralUserSettingsTab extends React.Component { static propTypes = { closeSettingsFn: PropTypes.func.isRequired, diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.js b/src/components/views/settings/tabs/user/HelpUserSettingsTab.js index 85ba22a353..e16ee686f5 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.js @@ -27,7 +27,9 @@ import * as sdk from "../../../../../"; import PlatformPeg from "../../../../../PlatformPeg"; import * as KeyboardShortcuts from "../../../../../accessibility/KeyboardShortcuts"; import UpdateCheckButton from "../../UpdateCheckButton"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.tabs.user.HelpUserSettingsTab") export default class HelpUserSettingsTab extends React.Component { static propTypes = { closeSettingsFn: PropTypes.func.isRequired, diff --git a/src/components/views/settings/tabs/user/LabsUserSettingsTab.js b/src/components/views/settings/tabs/user/LabsUserSettingsTab.js index 91bc9abcad..f515f1862b 100644 --- a/src/components/views/settings/tabs/user/LabsUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/LabsUserSettingsTab.js @@ -21,6 +21,7 @@ import SettingsStore from "../../../../../settings/SettingsStore"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import * as sdk from "../../../../../index"; import {SettingLevel} from "../../../../../settings/SettingLevel"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; export class LabsSettingToggle extends React.Component { static propTypes = { @@ -40,6 +41,7 @@ export class LabsSettingToggle extends React.Component { } } +@replaceableComponent("views.settings.tabs.user.LabsUserSettingsTab") export default class LabsUserSettingsTab extends React.Component { constructor() { super(); diff --git a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.js b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.js index 510d6076a0..91f6728a7a 100644 --- a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.js @@ -23,7 +23,9 @@ import {BanList, RULE_SERVER, RULE_USER} from "../../../../../mjolnir/BanList"; import Modal from "../../../../../Modal"; import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import * as sdk from "../../../../../index"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.tabs.user.MjolnirUserSettingsTab") export default class MjolnirUserSettingsTab extends React.Component { constructor() { super(); diff --git a/src/components/views/settings/tabs/user/NotificationUserSettingsTab.js b/src/components/views/settings/tabs/user/NotificationUserSettingsTab.js index 2e649cb7f8..8a71d1bf15 100644 --- a/src/components/views/settings/tabs/user/NotificationUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/NotificationUserSettingsTab.js @@ -17,7 +17,9 @@ limitations under the License. import React from 'react'; import {_t} from "../../../../../languageHandler"; import * as sdk from "../../../../../index"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.tabs.user.NotificationUserSettingsTab") export default class NotificationUserSettingsTab extends React.Component { constructor() { super(); diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js index ae9cad4cfa..238f875e22 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js @@ -23,7 +23,9 @@ import Field from "../../../elements/Field"; import * as sdk from "../../../../.."; import PlatformPeg from "../../../../../PlatformPeg"; import {SettingLevel} from "../../../../../settings/SettingLevel"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.tabs.user.PreferencesUserSettingsTab") export default class PreferencesUserSettingsTab extends React.Component { static ROOM_LIST_SETTINGS = [ 'breadcrumbs', diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js index a0d9016ce2..8a70811399 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js @@ -34,6 +34,7 @@ import SettingsStore from "../../../../../settings/SettingsStore"; import {UIFeature} from "../../../../../settings/UIFeature"; import {isE2eAdvancedPanelPossible} from "../../E2eAdvancedPanel"; import CountlyAnalytics from "../../../../../CountlyAnalytics"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; export class IgnoredUser extends React.Component { static propTypes = { @@ -59,6 +60,7 @@ export class IgnoredUser extends React.Component { } } +@replaceableComponent("views.settings.tabs.user.SecurityUserSettingsTab") export default class SecurityUserSettingsTab extends React.Component { static propTypes = { closeSettingsFn: PropTypes.func.isRequired, diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js index a78cc10b92..bc6fe796b8 100644 --- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js @@ -25,7 +25,9 @@ import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import * as sdk from "../../../../../index"; import Modal from "../../../../../Modal"; import {SettingLevel} from "../../../../../settings/SettingLevel"; +import {replaceableComponent} from "../../../../../utils/replaceableComponent"; +@replaceableComponent("views.settings.tabs.user.VoiceUserSettingsTab") export default class VoiceUserSettingsTab extends React.Component { constructor() { super(); diff --git a/src/components/views/terms/InlineTermsAgreement.js b/src/components/views/terms/InlineTermsAgreement.js index 5f6e276976..473a97642c 100644 --- a/src/components/views/terms/InlineTermsAgreement.js +++ b/src/components/views/terms/InlineTermsAgreement.js @@ -20,7 +20,9 @@ import {_t, pickBestLanguage} from "../../../languageHandler"; import * as sdk from "../../.."; import {objectClone} from "../../../utils/objects"; import StyledCheckbox from "../elements/StyledCheckbox"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.terms.InlineTermsAgreement") export default class InlineTermsAgreement extends React.Component { static propTypes = { policiesAndServicePairs: PropTypes.array.isRequired, // array of service/policy pairs diff --git a/src/components/views/toasts/NonUrgentEchoFailureToast.tsx b/src/components/views/toasts/NonUrgentEchoFailureToast.tsx index 76d0328e8b..abf5b10692 100644 --- a/src/components/views/toasts/NonUrgentEchoFailureToast.tsx +++ b/src/components/views/toasts/NonUrgentEchoFailureToast.tsx @@ -19,7 +19,9 @@ import { _t } from "../../../languageHandler"; import AccessibleButton from "../elements/AccessibleButton"; import Modal from "../../../Modal"; import ServerOfflineDialog from "../dialogs/ServerOfflineDialog"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.toasts.NonUrgentEchoFailureToast") export default class NonUrgentEchoFailureToast extends React.PureComponent { private openDialog = () => { Modal.createTrackedDialog('Local Echo Server Error', '', ServerOfflineDialog, {}); diff --git a/src/components/views/toasts/VerificationRequestToast.tsx b/src/components/views/toasts/VerificationRequestToast.tsx index 8c8a74b2be..010c8fd12f 100644 --- a/src/components/views/toasts/VerificationRequestToast.tsx +++ b/src/components/views/toasts/VerificationRequestToast.tsx @@ -29,6 +29,7 @@ import GenericToast from "./GenericToast"; import {VerificationRequest} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; import {DeviceInfo} from "matrix-js-sdk/src/crypto/deviceinfo"; import {Action} from "../../../dispatcher/actions"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { toastKey: string; @@ -40,6 +41,7 @@ interface IState { device?: DeviceInfo; } +@replaceableComponent("views.toasts.VerificationRequestToast") export default class VerificationRequestToast extends React.PureComponent<IProps, IState> { private intervalHandle: NodeJS.Timeout; diff --git a/src/components/views/verification/VerificationCancelled.js b/src/components/views/verification/VerificationCancelled.js index fc2a287359..0bbaea1804 100644 --- a/src/components/views/verification/VerificationCancelled.js +++ b/src/components/views/verification/VerificationCancelled.js @@ -18,7 +18,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.verification.VerificationCancelled") export default class VerificationCancelled extends React.Component { static propTypes = { onDone: PropTypes.func.isRequired, diff --git a/src/components/views/verification/VerificationComplete.js b/src/components/views/verification/VerificationComplete.js index 2214711b1f..cf2a72591c 100644 --- a/src/components/views/verification/VerificationComplete.js +++ b/src/components/views/verification/VerificationComplete.js @@ -18,7 +18,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +@replaceableComponent("views.verification.VerificationComplete") export default class VerificationComplete extends React.Component { static propTypes = { onDone: PropTypes.func.isRequired, diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js index 09374b91af..36f99b2140 100644 --- a/src/components/views/verification/VerificationShowSas.js +++ b/src/components/views/verification/VerificationShowSas.js @@ -21,11 +21,13 @@ import {PendingActionSpinner} from "../right_panel/EncryptionInfo"; import AccessibleButton from "../elements/AccessibleButton"; import DialogButtons from "../elements/DialogButtons"; import { fixupColorFonts } from '../../../utils/FontManager'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; function capFirst(s) { return s.charAt(0).toUpperCase() + s.slice(1); } +@replaceableComponent("views.verification.VerificationShowSas") export default class VerificationShowSas extends React.Component { static propTypes = { pending: PropTypes.bool, diff --git a/src/components/views/voip/CallContainer.tsx b/src/components/views/voip/CallContainer.tsx index 51925cb147..9d0047fc54 100644 --- a/src/components/views/voip/CallContainer.tsx +++ b/src/components/views/voip/CallContainer.tsx @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import IncomingCallBox from './IncomingCallBox'; import CallPreview from './CallPreview'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { @@ -26,6 +27,7 @@ interface IState { } +@replaceableComponent("views.voip.CallContainer") export default class CallContainer extends React.PureComponent<IProps, IState> { public render() { return <div className="mx_CallContainer"> diff --git a/src/components/views/voip/CallPreview.tsx b/src/components/views/voip/CallPreview.tsx index c08e52181b..29de068b0c 100644 --- a/src/components/views/voip/CallPreview.tsx +++ b/src/components/views/voip/CallPreview.tsx @@ -26,6 +26,7 @@ import PersistentApp from "../elements/PersistentApp"; import SettingsStore from "../../../settings/SettingsStore"; import { CallEvent, CallState, MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const SHOW_CALL_IN_STATES = [ CallState.Connected, @@ -85,6 +86,7 @@ function getPrimarySecondaryCalls(calls: MatrixCall[]): [MatrixCall, MatrixCall[ * CallPreview shows a small version of CallView hovering over the UI in 'picture-in-picture' * (PiP mode). It displays the call(s) which is *not* in the room the user is currently viewing. */ +@replaceableComponent("views.voip.CallPreview") export default class CallPreview extends React.Component<IProps, IState> { private roomStoreToken: any; private dispatcherRef: string; diff --git a/src/components/views/voip/CallView.tsx b/src/components/views/voip/CallView.tsx index 7cac682794..9bdc8fb11d 100644 --- a/src/components/views/voip/CallView.tsx +++ b/src/components/views/voip/CallView.tsx @@ -31,6 +31,7 @@ import {alwaysAboveLeftOf, alwaysAboveRightOf, ChevronFace, ContextMenuButton} f import CallContextMenu from '../context_menus/CallContextMenu'; import { avatarUrlForMember } from '../../../Avatar'; import DialpadContextMenu from '../context_menus/DialpadContextMenu'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { // The call for us to display @@ -100,6 +101,7 @@ const BOTTOM_PADDING = 10; const BOTTOM_MARGIN_TOP_BOTTOM = 10; // top margin plus bottom margin const CONTEXT_MENU_VPADDING = 8; // How far the context menu sits above the button (px) +@replaceableComponent("views.voip.CallView") export default class CallView extends React.Component<IProps, IState> { private dispatcherRef: string; private contentRef = createRef<HTMLDivElement>(); diff --git a/src/components/views/voip/CallViewForRoom.tsx b/src/components/views/voip/CallViewForRoom.tsx index 4cb4e66fbe..97960d1e0b 100644 --- a/src/components/views/voip/CallViewForRoom.tsx +++ b/src/components/views/voip/CallViewForRoom.tsx @@ -19,6 +19,7 @@ import React from 'react'; import CallHandler from '../../../CallHandler'; import CallView from './CallView'; import dis from '../../../dispatcher/dispatcher'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { // What room we should display the call for @@ -40,6 +41,7 @@ interface IState { * Wrapper for CallView that always display the call in a given room, * or nothing if there is no call in that room. */ +@replaceableComponent("views.voip.CallViewForRoom") export default class CallViewForRoom extends React.Component<IProps, IState> { private dispatcherRef: string; diff --git a/src/components/views/voip/DialPad.tsx b/src/components/views/voip/DialPad.tsx index da88f49adf..68092fb0be 100644 --- a/src/components/views/voip/DialPad.tsx +++ b/src/components/views/voip/DialPad.tsx @@ -16,6 +16,7 @@ limitations under the License. import * as React from "react"; import AccessibleButton from "../elements/AccessibleButton"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; const BUTTONS = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#']; @@ -59,6 +60,7 @@ interface IProps { onDialPress?: (string) => void; } +@replaceableComponent("views.voip.DialPad") export default class Dialpad extends React.PureComponent<IProps> { render() { const buttonNodes = []; diff --git a/src/components/views/voip/DialPadModal.tsx b/src/components/views/voip/DialPadModal.tsx index 9f031a48a3..cdd5bc6641 100644 --- a/src/components/views/voip/DialPadModal.tsx +++ b/src/components/views/voip/DialPadModal.tsx @@ -25,6 +25,7 @@ import dis from '../../../dispatcher/dispatcher'; import Modal from "../../../Modal"; import ErrorDialog from "../../views/dialogs/ErrorDialog"; import CallHandler from "../../../CallHandler"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { onFinished: (boolean) => void; @@ -34,6 +35,7 @@ interface IState { value: string; } +@replaceableComponent("views.voip.DialPadModal") export default class DialpadModal extends React.PureComponent<IProps, IState> { constructor(props) { super(props); diff --git a/src/components/views/voip/IncomingCallBox.tsx b/src/components/views/voip/IncomingCallBox.tsx index a495093d85..0ca2a196c2 100644 --- a/src/components/views/voip/IncomingCallBox.tsx +++ b/src/components/views/voip/IncomingCallBox.tsx @@ -25,6 +25,7 @@ import CallHandler from '../../../CallHandler'; import RoomAvatar from '../avatars/RoomAvatar'; import FormButton from '../elements/FormButton'; import { CallState } from 'matrix-js-sdk/src/webrtc/call'; +import {replaceableComponent} from "../../../utils/replaceableComponent"; interface IProps { } @@ -33,6 +34,7 @@ interface IState { incomingCall: any; } +@replaceableComponent("views.voip.IncomingCallBox") export default class IncomingCallBox extends React.Component<IProps, IState> { private dispatcherRef: string; diff --git a/src/components/views/voip/VideoFeed.tsx b/src/components/views/voip/VideoFeed.tsx index 5210f28eb1..23dbe4d46b 100644 --- a/src/components/views/voip/VideoFeed.tsx +++ b/src/components/views/voip/VideoFeed.tsx @@ -18,6 +18,7 @@ import classnames from 'classnames'; import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; import React, {createRef} from 'react'; import SettingsStore from "../../../settings/SettingsStore"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; export enum VideoFeedType { Local, @@ -37,6 +38,7 @@ interface IProps { onResize?: (e: Event) => void, } +@replaceableComponent("views.voip.VideoFeed") export default class VideoFeed extends React.Component<IProps> { private vid = createRef<HTMLVideoElement>(); diff --git a/test/accessibility/RovingTabIndex-test.js b/test/accessibility/RovingTabIndex-test.js index 8be4a2976c..5aa93f99f3 100644 --- a/test/accessibility/RovingTabIndex-test.js +++ b/test/accessibility/RovingTabIndex-test.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import '../skinned-sdk'; // Must be first for skinning to work import React from "react"; import Adapter from "enzyme-adapter-react-16"; import { configure, mount } from "enzyme"; diff --git a/test/components/views/messages/MKeyVerificationConclusion-test.js b/test/components/views/messages/MKeyVerificationConclusion-test.js index 689151fe3f..45e122295b 100644 --- a/test/components/views/messages/MKeyVerificationConclusion-test.js +++ b/test/components/views/messages/MKeyVerificationConclusion-test.js @@ -1,3 +1,4 @@ +import '../../../skinned-sdk'; // Must be first for skinning to work import React from 'react'; import TestRenderer from 'react-test-renderer'; import { EventEmitter } from 'events'; diff --git a/test/components/views/rooms/SendMessageComposer-test.js b/test/components/views/rooms/SendMessageComposer-test.js index 6eeac7ceea..64a90eee81 100644 --- a/test/components/views/rooms/SendMessageComposer-test.js +++ b/test/components/views/rooms/SendMessageComposer-test.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import '../../../skinned-sdk'; // Must be first for skinning to work import Adapter from "enzyme-adapter-react-16"; import { configure, mount } from "enzyme"; import React from "react"; diff --git a/test/createRoom-test.js b/test/createRoom-test.js index f7e8617c3f..ed8f9779f7 100644 --- a/test/createRoom-test.js +++ b/test/createRoom-test.js @@ -1,3 +1,4 @@ +import './skinned-sdk'; // Must be first for skinning to work import {_waitForMember, canEncryptToAllUsers} from '../src/createRoom'; import {EventEmitter} from 'events'; diff --git a/test/editor/deserialize-test.js b/test/editor/deserialize-test.js index 112ac7d02b..07b75aaae5 100644 --- a/test/editor/deserialize-test.js +++ b/test/editor/deserialize-test.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import '../skinned-sdk'; // Must be first for skinning to work import {parseEvent} from "../../src/editor/deserialize"; import {createPartCreator} from "./mock";