From c230a75eda74622df6b923eb6091286740094637 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 8 Mar 2021 19:35:10 -0700 Subject: [PATCH] Flag structural components as replaceable --- src/components/structures/ContextMenu.tsx | 3 +++ src/components/structures/CustomRoomTagPanel.js | 2 ++ src/components/structures/FilePanel.js | 2 ++ src/components/structures/GenericErrorPage.js | 2 ++ src/components/structures/GroupFilterPanel.js | 2 ++ src/components/structures/GroupView.js | 2 ++ src/components/structures/HostSignupAction.tsx | 2 ++ src/components/structures/IndicatorScrollbar.js | 2 ++ src/components/structures/InteractiveAuth.js | 2 ++ src/components/structures/LeftPanel.tsx | 2 ++ src/components/structures/LoggedInView.tsx | 2 ++ src/components/structures/MainSplit.js | 2 ++ src/components/structures/MatrixChat.tsx | 2 ++ src/components/structures/MessagePanel.js | 2 ++ src/components/structures/MyGroups.js | 2 ++ src/components/structures/NonUrgentToastContainer.tsx | 2 ++ src/components/structures/NotificationPanel.js | 2 ++ src/components/structures/RightPanel.js | 2 ++ src/components/structures/RoomDirectory.js | 2 ++ src/components/structures/RoomSearch.tsx | 2 ++ src/components/structures/RoomStatusBar.js | 2 ++ src/components/structures/RoomView.tsx | 2 ++ src/components/structures/ScrollPanel.js | 2 ++ src/components/structures/SearchBox.js | 2 ++ src/components/structures/TabbedView.tsx | 2 ++ src/components/structures/TimelinePanel.js | 2 ++ src/components/structures/ToastContainer.tsx | 2 ++ src/components/structures/UploadBar.tsx | 2 ++ src/components/structures/UserMenu.tsx | 2 ++ src/components/structures/UserView.js | 2 ++ src/components/structures/ViewSource.js | 2 ++ src/components/structures/auth/CompleteSecurity.js | 2 ++ src/components/structures/auth/E2eSetup.js | 2 ++ src/components/structures/auth/ForgotPassword.js | 2 ++ src/components/structures/auth/Login.tsx | 2 ++ src/components/structures/auth/Registration.tsx | 2 ++ src/components/structures/auth/SetupEncryptionBody.js | 2 ++ src/components/structures/auth/SoftLogout.js | 2 ++ 38 files changed, 77 insertions(+) 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 { private initialFocus: HTMLElement; @@ -467,6 +469,7 @@ export const useContextMenu = (): 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( `

HTML for your community's page

@@ -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 { 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 { private listContainerRef: React.RefObject = 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 { 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 { 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 { 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 { private dispatcherRef: string; private inputRef: React.RefObject = 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 { 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 { 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[]; 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 { 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 { 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 0b969784e5..704a1e7275 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 { 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 { 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