Flag structural components as replaceable

This commit is contained in:
Travis Ralston 2021-03-08 19:35:10 -07:00
parent b12cf7912a
commit c230a75eda
38 changed files with 77 additions and 0 deletions

View file

@ -22,6 +22,7 @@ import classNames from "classnames";
import {Key} from "../../Keyboard"; import {Key} from "../../Keyboard";
import {Writeable} from "../../@types/common"; import {Writeable} from "../../@types/common";
import {replaceableComponent} from "../../utils/replaceableComponent";
// Shamelessly ripped off Modal.js. There's probably a better way // Shamelessly ripped off Modal.js. There's probably a better way
// of doing reusable widgets like dialog boxes & menus where we go and // of doing reusable widgets like dialog boxes & menus where we go and
@ -91,6 +92,7 @@ interface IState {
// Generic ContextMenu Portal wrapper // Generic ContextMenu Portal wrapper
// all options inside the menu should be of role=menuitem/menuitemcheckbox/menuitemradiobutton and have tabIndex={-1} // 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. // 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> { export class ContextMenu extends React.PureComponent<IProps, IState> {
private initialFocus: HTMLElement; private initialFocus: HTMLElement;
@ -467,6 +469,7 @@ export const useContextMenu = <T extends any = HTMLElement>(): ContextMenuTuple<
return [isOpen, button, open, close, setIsOpen]; return [isOpen, button, open, close, setIsOpen];
}; };
@replaceableComponent("structures.LegacyContextMenu")
export default class LegacyContextMenu extends ContextMenu { export default class LegacyContextMenu extends ContextMenu {
render() { render() {
return this.renderMenu(false); return this.renderMenu(false);

View file

@ -21,7 +21,9 @@ import * as sdk from '../../index';
import dis from '../../dispatcher/dispatcher'; import dis from '../../dispatcher/dispatcher';
import classNames from 'classnames'; import classNames from 'classnames';
import * as FormattingUtils from '../../utils/FormattingUtils'; import * as FormattingUtils from '../../utils/FormattingUtils';
import {replaceableComponent} from "../../utils/replaceableComponent";
@replaceableComponent("structures.CustomRoomTagPanel")
class CustomRoomTagPanel extends React.Component { class CustomRoomTagPanel extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);

View file

@ -26,10 +26,12 @@ import { _t } from '../../languageHandler';
import BaseCard from "../views/right_panel/BaseCard"; import BaseCard from "../views/right_panel/BaseCard";
import {RightPanelPhases} from "../../stores/RightPanelStorePhases"; import {RightPanelPhases} from "../../stores/RightPanelStorePhases";
import DesktopBuildsNotice, {WarningKind} from "../views/elements/DesktopBuildsNotice"; import DesktopBuildsNotice, {WarningKind} from "../views/elements/DesktopBuildsNotice";
import {replaceableComponent} from "../../utils/replaceableComponent";
/* /*
* Component which shows the filtered file using a TimelinePanel * Component which shows the filtered file using a TimelinePanel
*/ */
@replaceableComponent("structures.FilePanel")
class FilePanel extends React.Component { class FilePanel extends React.Component {
static propTypes = { static propTypes = {
roomId: PropTypes.string.isRequired, roomId: PropTypes.string.isRequired,

View file

@ -16,7 +16,9 @@ limitations under the License.
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {replaceableComponent} from "../../utils/replaceableComponent";
@replaceableComponent("structures.GenericErrorPage")
export default class GenericErrorPage extends React.PureComponent { export default class GenericErrorPage extends React.PureComponent {
static propTypes = { static propTypes = {
title: PropTypes.object.isRequired, // jsx for title title: PropTypes.object.isRequired, // jsx for title

View file

@ -30,7 +30,9 @@ import MatrixClientContext from "../../contexts/MatrixClientContext";
import AutoHideScrollbar from "./AutoHideScrollbar"; import AutoHideScrollbar from "./AutoHideScrollbar";
import SettingsStore from "../../settings/SettingsStore"; import SettingsStore from "../../settings/SettingsStore";
import UserTagTile from "../views/elements/UserTagTile"; import UserTagTile from "../views/elements/UserTagTile";
import {replaceableComponent} from "../../utils/replaceableComponent";
@replaceableComponent("structures.GroupFilterPanel")
class GroupFilterPanel extends React.Component { class GroupFilterPanel extends React.Component {
static contextType = MatrixClientContext; static contextType = MatrixClientContext;

View file

@ -39,6 +39,7 @@ import {Group} from "matrix-js-sdk";
import {allSettled, sleep} from "../../utils/promise"; import {allSettled, sleep} from "../../utils/promise";
import RightPanelStore from "../../stores/RightPanelStore"; import RightPanelStore from "../../stores/RightPanelStore";
import AutoHideScrollbar from "./AutoHideScrollbar"; import AutoHideScrollbar from "./AutoHideScrollbar";
import {replaceableComponent} from "../../utils/replaceableComponent";
const LONG_DESC_PLACEHOLDER = _td( const LONG_DESC_PLACEHOLDER = _td(
`<h1>HTML for your community's page</h1> `<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_OPEN = "open";
const GROUP_JOINPOLICY_INVITE = "invite"; const GROUP_JOINPOLICY_INVITE = "invite";
@replaceableComponent("structures.GroupView")
export default class GroupView extends React.Component { export default class GroupView extends React.Component {
static propTypes = { static propTypes = {
groupId: PropTypes.string.isRequired, groupId: PropTypes.string.isRequired,

View file

@ -22,11 +22,13 @@ import {
import { _t } from "../../languageHandler"; import { _t } from "../../languageHandler";
import { HostSignupStore } from "../../stores/HostSignupStore"; import { HostSignupStore } from "../../stores/HostSignupStore";
import SdkConfig from "../../SdkConfig"; import SdkConfig from "../../SdkConfig";
import {replaceableComponent} from "../../utils/replaceableComponent";
interface IProps {} interface IProps {}
interface IState {} interface IState {}
@replaceableComponent("structures.HostSignupAction")
export default class HostSignupAction extends React.PureComponent<IProps, IState> { export default class HostSignupAction extends React.PureComponent<IProps, IState> {
private openDialog = async () => { private openDialog = async () => {
await HostSignupStore.instance.setHostSignupActive(true); await HostSignupStore.instance.setHostSignupActive(true);

View file

@ -17,7 +17,9 @@ limitations under the License.
import React from "react"; import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import AutoHideScrollbar from "./AutoHideScrollbar"; import AutoHideScrollbar from "./AutoHideScrollbar";
import {replaceableComponent} from "../../utils/replaceableComponent";
@replaceableComponent("structures.IndicatorScrollbar")
export default class IndicatorScrollbar extends React.Component { export default class IndicatorScrollbar extends React.Component {
static propTypes = { static propTypes = {
// If true, the scrollbar will append mx_IndicatorScrollbar_leftOverflowIndicator // If true, the scrollbar will append mx_IndicatorScrollbar_leftOverflowIndicator

View file

@ -22,9 +22,11 @@ import PropTypes from 'prop-types';
import getEntryComponentForLoginType from '../views/auth/InteractiveAuthEntryComponents'; import getEntryComponentForLoginType from '../views/auth/InteractiveAuthEntryComponents';
import * as sdk from '../../index'; import * as sdk from '../../index';
import {replaceableComponent} from "../../utils/replaceableComponent";
export const ERROR_USER_CANCELLED = new Error("User cancelled auth session"); export const ERROR_USER_CANCELLED = new Error("User cancelled auth session");
@replaceableComponent("structures.InteractiveAuthComponent")
export default class InteractiveAuthComponent extends React.Component { export default class InteractiveAuthComponent extends React.Component {
static propTypes = { static propTypes = {
// matrix client to use for UI auth requests // matrix client to use for UI auth requests

View file

@ -40,6 +40,7 @@ import { MatrixClientPeg } from "../../MatrixClientPeg";
import RoomListNumResults from "../views/rooms/RoomListNumResults"; import RoomListNumResults from "../views/rooms/RoomListNumResults";
import LeftPanelWidget from "./LeftPanelWidget"; import LeftPanelWidget from "./LeftPanelWidget";
import SpacePanel from "../views/spaces/SpacePanel"; import SpacePanel from "../views/spaces/SpacePanel";
import {replaceableComponent} from "../../utils/replaceableComponent";
interface IProps { interface IProps {
isMinimized: boolean; isMinimized: boolean;
@ -60,6 +61,7 @@ const cssClasses = [
"mx_RoomSublist_showNButton", "mx_RoomSublist_showNButton",
]; ];
@replaceableComponent("structures.LeftPanel")
export default class LeftPanel extends React.Component<IProps, IState> { export default class LeftPanel extends React.Component<IProps, IState> {
private listContainerRef: React.RefObject<HTMLDivElement> = createRef(); private listContainerRef: React.RefObject<HTMLDivElement> = createRef();
private groupFilterPanelWatcherRef: string; private groupFilterPanelWatcherRef: string;

View file

@ -56,6 +56,7 @@ import Modal from "../../Modal";
import { ICollapseConfig } from "../../resizer/distributors/collapse"; import { ICollapseConfig } from "../../resizer/distributors/collapse";
import HostSignupContainer from '../views/host_signup/HostSignupContainer'; import HostSignupContainer from '../views/host_signup/HostSignupContainer';
import { IOpts } from "../../createRoom"; import { IOpts } from "../../createRoom";
import {replaceableComponent} from "../../utils/replaceableComponent";
// We need to fetch each pinned message individually (if we don't already have it) // 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. // 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. * Components mounted below us can access the matrix client via the react context.
*/ */
@replaceableComponent("structures.LoggedInView")
class LoggedInView extends React.Component<IProps, IState> { class LoggedInView extends React.Component<IProps, IState> {
static displayName = 'LoggedInView'; static displayName = 'LoggedInView';

View file

@ -17,7 +17,9 @@ limitations under the License.
import React from 'react'; import React from 'react';
import { Resizable } from 're-resizable'; import { Resizable } from 're-resizable';
import {replaceableComponent} from "../../utils/replaceableComponent";
@replaceableComponent("structures.MainSplit")
export default class MainSplit extends React.Component { export default class MainSplit extends React.Component {
_onResizeStart = () => { _onResizeStart = () => {
this.props.resizeNotifier.startResizing(); this.props.resizeNotifier.startResizing();

View file

@ -84,6 +84,7 @@ import DialPadModal from "../views/voip/DialPadModal";
import { showToast as showMobileGuideToast } from '../../toasts/MobileGuideToast'; import { showToast as showMobileGuideToast } from '../../toasts/MobileGuideToast';
import SpaceStore from "../../stores/SpaceStore"; import SpaceStore from "../../stores/SpaceStore";
import SpaceRoomDirectory from "./SpaceRoomDirectory"; import SpaceRoomDirectory from "./SpaceRoomDirectory";
import {replaceableComponent} from "../../utils/replaceableComponent";
/** constants for MatrixChat.state.view */ /** constants for MatrixChat.state.view */
export enum Views { export enum Views {
@ -208,6 +209,7 @@ interface IState {
roomJustCreatedOpts?: IOpts; roomJustCreatedOpts?: IOpts;
} }
@replaceableComponent("structures.MatrixChat")
export default class MatrixChat extends React.PureComponent<IProps, IState> { export default class MatrixChat extends React.PureComponent<IProps, IState> {
static displayName = "MatrixChat"; static displayName = "MatrixChat";

View file

@ -34,6 +34,7 @@ import {textForEvent} from "../../TextForEvent";
import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResizer"; import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResizer";
import DMRoomMap from "../../utils/DMRoomMap"; import DMRoomMap from "../../utils/DMRoomMap";
import NewRoomIntro from "../views/rooms/NewRoomIntro"; import NewRoomIntro from "../views/rooms/NewRoomIntro";
import {replaceableComponent} from "../../utils/replaceableComponent";
const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes
const continuedTypes = ['m.sticker', 'm.room.message']; 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. /* (almost) stateless UI component which builds the event tiles in the room timeline.
*/ */
@replaceableComponent("structures.MessagePanel")
export default class MessagePanel extends React.Component { export default class MessagePanel extends React.Component {
static propTypes = { static propTypes = {
// true to give the component a 'display: none' style. // true to give the component a 'display: none' style.

View file

@ -24,7 +24,9 @@ import dis from '../../dispatcher/dispatcher';
import AccessibleButton from '../views/elements/AccessibleButton'; import AccessibleButton from '../views/elements/AccessibleButton';
import MatrixClientContext from "../../contexts/MatrixClientContext"; import MatrixClientContext from "../../contexts/MatrixClientContext";
import AutoHideScrollbar from "./AutoHideScrollbar"; import AutoHideScrollbar from "./AutoHideScrollbar";
import {replaceableComponent} from "../../utils/replaceableComponent";
@replaceableComponent("structures.MyGroups")
export default class MyGroups extends React.Component { export default class MyGroups extends React.Component {
static contextType = MatrixClientContext; static contextType = MatrixClientContext;

View file

@ -18,6 +18,7 @@ import * as React from "react";
import { ComponentClass } from "../../@types/common"; import { ComponentClass } from "../../@types/common";
import NonUrgentToastStore from "../../stores/NonUrgentToastStore"; import NonUrgentToastStore from "../../stores/NonUrgentToastStore";
import { UPDATE_EVENT } from "../../stores/AsyncStore"; import { UPDATE_EVENT } from "../../stores/AsyncStore";
import {replaceableComponent} from "../../utils/replaceableComponent";
interface IProps { interface IProps {
} }
@ -26,6 +27,7 @@ interface IState {
toasts: ComponentClass[], toasts: ComponentClass[],
} }
@replaceableComponent("structures.NonUrgentToastContainer")
export default class NonUrgentToastContainer extends React.PureComponent<IProps, IState> { export default class NonUrgentToastContainer extends React.PureComponent<IProps, IState> {
public constructor(props, context) { public constructor(props, context) {
super(props, context); super(props, context);

View file

@ -23,10 +23,12 @@ import { _t } from '../../languageHandler';
import {MatrixClientPeg} from "../../MatrixClientPeg"; import {MatrixClientPeg} from "../../MatrixClientPeg";
import * as sdk from "../../index"; import * as sdk from "../../index";
import BaseCard from "../views/right_panel/BaseCard"; import BaseCard from "../views/right_panel/BaseCard";
import {replaceableComponent} from "../../utils/replaceableComponent";
/* /*
* Component which shows the global notification list using a TimelinePanel * Component which shows the global notification list using a TimelinePanel
*/ */
@replaceableComponent("structures.NotificationPanel")
class NotificationPanel extends React.Component { class NotificationPanel extends React.Component {
static propTypes = { static propTypes = {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,

View file

@ -34,7 +34,9 @@ import MatrixClientContext from "../../contexts/MatrixClientContext";
import {Action} from "../../dispatcher/actions"; import {Action} from "../../dispatcher/actions";
import RoomSummaryCard from "../views/right_panel/RoomSummaryCard"; import RoomSummaryCard from "../views/right_panel/RoomSummaryCard";
import WidgetCard from "../views/right_panel/WidgetCard"; import WidgetCard from "../views/right_panel/WidgetCard";
import {replaceableComponent} from "../../utils/replaceableComponent";
@replaceableComponent("structures.RightPanel")
export default class RightPanel extends React.Component { export default class RightPanel extends React.Component {
static get propTypes() { static get propTypes() {
return { return {

View file

@ -34,6 +34,7 @@ import GroupFilterOrderStore from "../../stores/GroupFilterOrderStore";
import GroupStore from "../../stores/GroupStore"; import GroupStore from "../../stores/GroupStore";
import FlairStore from "../../stores/FlairStore"; import FlairStore from "../../stores/FlairStore";
import CountlyAnalytics from "../../CountlyAnalytics"; import CountlyAnalytics from "../../CountlyAnalytics";
import {replaceableComponent} from "../../utils/replaceableComponent";
const MAX_NAME_LENGTH = 80; const MAX_NAME_LENGTH = 80;
const MAX_TOPIC_LENGTH = 800; const MAX_TOPIC_LENGTH = 800;
@ -42,6 +43,7 @@ function track(action) {
Analytics.trackEvent('RoomDirectory', action); Analytics.trackEvent('RoomDirectory', action);
} }
@replaceableComponent("structures.RoomDirectory")
export default class RoomDirectory extends React.Component { export default class RoomDirectory extends React.Component {
static propTypes = { static propTypes = {
initialText: PropTypes.string, initialText: PropTypes.string,

View file

@ -25,6 +25,7 @@ import AccessibleButton from "../views/elements/AccessibleButton";
import { Action } from "../../dispatcher/actions"; import { Action } from "../../dispatcher/actions";
import RoomListStore from "../../stores/room-list/RoomListStore"; import RoomListStore from "../../stores/room-list/RoomListStore";
import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition"; import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition";
import {replaceableComponent} from "../../utils/replaceableComponent";
interface IProps { interface IProps {
isMinimized: boolean; isMinimized: boolean;
@ -37,6 +38,7 @@ interface IState {
focused: boolean; focused: boolean;
} }
@replaceableComponent("structures.RoomSearch")
export default class RoomSearch extends React.PureComponent<IProps, IState> { export default class RoomSearch extends React.PureComponent<IProps, IState> {
private dispatcherRef: string; private dispatcherRef: string;
private inputRef: React.RefObject<HTMLInputElement> = createRef(); private inputRef: React.RefObject<HTMLInputElement> = createRef();

View file

@ -23,6 +23,7 @@ import Resend from '../../Resend';
import dis from '../../dispatcher/dispatcher'; import dis from '../../dispatcher/dispatcher';
import {messageForResourceLimitError, messageForSendError} from '../../utils/ErrorUtils'; import {messageForResourceLimitError, messageForSendError} from '../../utils/ErrorUtils';
import {Action} from "../../dispatcher/actions"; import {Action} from "../../dispatcher/actions";
import {replaceableComponent} from "../../utils/replaceableComponent";
const STATUS_BAR_HIDDEN = 0; const STATUS_BAR_HIDDEN = 0;
const STATUS_BAR_EXPANDED = 1; const STATUS_BAR_EXPANDED = 1;
@ -35,6 +36,7 @@ function getUnsentMessages(room) {
}); });
} }
@replaceableComponent("structures.RoomStatusBar")
export default class RoomStatusBar extends React.Component { export default class RoomStatusBar extends React.Component {
static propTypes = { static propTypes = {
// the room this statusbar is representing. // the room this statusbar is representing.

View file

@ -82,6 +82,7 @@ import { Container, WidgetLayoutStore } from "../../stores/widgets/WidgetLayoutS
import { objectHasDiff } from "../../utils/objects"; import { objectHasDiff } from "../../utils/objects";
import SpaceRoomView from "./SpaceRoomView"; import SpaceRoomView from "./SpaceRoomView";
import { IOpts } from "../../createRoom"; import { IOpts } from "../../createRoom";
import {replaceableComponent} from "../../utils/replaceableComponent";
const DEBUG = false; const DEBUG = false;
let debuglog = function(msg: string) {}; let debuglog = function(msg: string) {};
@ -195,6 +196,7 @@ export interface IState {
dragCounter: number; dragCounter: number;
} }
@replaceableComponent("structures.RoomView")
export default class RoomView extends React.Component<IProps, IState> { export default class RoomView extends React.Component<IProps, IState> {
private readonly dispatcherRef: string; private readonly dispatcherRef: string;
private readonly roomStoreToken: EventSubscription; private readonly roomStoreToken: EventSubscription;

View file

@ -19,6 +19,7 @@ import PropTypes from 'prop-types';
import { Key } from '../../Keyboard'; import { Key } from '../../Keyboard';
import Timer from '../../utils/Timer'; import Timer from '../../utils/Timer';
import AutoHideScrollbar from "./AutoHideScrollbar"; import AutoHideScrollbar from "./AutoHideScrollbar";
import {replaceableComponent} from "../../utils/replaceableComponent";
const DEBUG_SCROLL = false; const DEBUG_SCROLL = false;
@ -83,6 +84,7 @@ if (DEBUG_SCROLL) {
* offset as normal. * offset as normal.
*/ */
@replaceableComponent("structures.ScrollPanel")
export default class ScrollPanel extends React.Component { export default class ScrollPanel extends React.Component {
static propTypes = { static propTypes = {
/* stickyBottom: if set to true, then once the user hits the bottom of /* stickyBottom: if set to true, then once the user hits the bottom of

View file

@ -22,7 +22,9 @@ import dis from '../../dispatcher/dispatcher';
import {throttle} from 'lodash'; import {throttle} from 'lodash';
import AccessibleButton from '../../components/views/elements/AccessibleButton'; import AccessibleButton from '../../components/views/elements/AccessibleButton';
import classNames from 'classnames'; import classNames from 'classnames';
import {replaceableComponent} from "../../utils/replaceableComponent";
@replaceableComponent("structures.SearchBox")
export default class SearchBox extends React.Component { export default class SearchBox extends React.Component {
static propTypes = { static propTypes = {
onSearch: PropTypes.func, onSearch: PropTypes.func,

View file

@ -20,6 +20,7 @@ import * as React from "react";
import {_t} from '../../languageHandler'; import {_t} from '../../languageHandler';
import * as sdk from "../../index"; import * as sdk from "../../index";
import AutoHideScrollbar from './AutoHideScrollbar'; import AutoHideScrollbar from './AutoHideScrollbar';
import {replaceableComponent} from "../../utils/replaceableComponent";
/** /**
* Represents a tab for the TabbedView. * Represents a tab for the TabbedView.
@ -45,6 +46,7 @@ interface IState {
activeTabIndex: number; activeTabIndex: number;
} }
@replaceableComponent("structures.TabbedView")
export default class TabbedView extends React.Component<IProps, IState> { export default class TabbedView extends React.Component<IProps, IState> {
constructor(props: IProps) { constructor(props: IProps) {
super(props); super(props);

View file

@ -37,6 +37,7 @@ import EditorStateTransfer from '../../utils/EditorStateTransfer';
import {haveTileForEvent} from "../views/rooms/EventTile"; import {haveTileForEvent} from "../views/rooms/EventTile";
import {UIFeature} from "../../settings/UIFeature"; import {UIFeature} from "../../settings/UIFeature";
import {objectHasDiff} from "../../utils/objects"; import {objectHasDiff} from "../../utils/objects";
import {replaceableComponent} from "../../utils/replaceableComponent";
const PAGINATE_SIZE = 20; const PAGINATE_SIZE = 20;
const INITIAL_SIZE = 20; const INITIAL_SIZE = 20;
@ -55,6 +56,7 @@ if (DEBUG) {
* *
* Also responsible for handling and sending read receipts. * Also responsible for handling and sending read receipts.
*/ */
@replaceableComponent("structures.TimelinePanel")
class TimelinePanel extends React.Component { class TimelinePanel extends React.Component {
static propTypes = { static propTypes = {
// The js-sdk EventTimelineSet object for the timeline sequence we are // The js-sdk EventTimelineSet object for the timeline sequence we are

View file

@ -17,12 +17,14 @@ limitations under the License.
import * as React from "react"; import * as React from "react";
import ToastStore, {IToast} from "../../stores/ToastStore"; import ToastStore, {IToast} from "../../stores/ToastStore";
import classNames from "classnames"; import classNames from "classnames";
import {replaceableComponent} from "../../utils/replaceableComponent";
interface IState { interface IState {
toasts: IToast<any>[]; toasts: IToast<any>[];
countSeen: number; countSeen: number;
} }
@replaceableComponent("structures.ToastContainer")
export default class ToastContainer extends React.Component<{}, IState> { export default class ToastContainer extends React.Component<{}, IState> {
constructor(props, context) { constructor(props, context) {
super(props, context); super(props, context);

View file

@ -25,6 +25,7 @@ import { Action } from "../../dispatcher/actions";
import ProgressBar from "../views/elements/ProgressBar"; import ProgressBar from "../views/elements/ProgressBar";
import AccessibleButton from "../views/elements/AccessibleButton"; import AccessibleButton from "../views/elements/AccessibleButton";
import { IUpload } from "../../models/IUpload"; import { IUpload } from "../../models/IUpload";
import {replaceableComponent} from "../../utils/replaceableComponent";
interface IProps { interface IProps {
room: Room; room: Room;
@ -35,6 +36,7 @@ interface IState {
uploadsHere: IUpload[]; uploadsHere: IUpload[];
} }
@replaceableComponent("structures.UploadBar")
export default class UploadBar extends React.Component<IProps, IState> { export default class UploadBar extends React.Component<IProps, IState> {
private dispatcherRef: string; private dispatcherRef: string;
private mounted: boolean; private mounted: boolean;

View file

@ -56,6 +56,7 @@ import HostSignupAction from "./HostSignupAction";
import { IHostSignupConfig } from "../views/dialogs/HostSignupDialogTypes"; import { IHostSignupConfig } from "../views/dialogs/HostSignupDialogTypes";
import SpaceStore, { UPDATE_SELECTED_SPACE } from "../../stores/SpaceStore"; import SpaceStore, { UPDATE_SELECTED_SPACE } from "../../stores/SpaceStore";
import RoomName from "../views/elements/RoomName"; import RoomName from "../views/elements/RoomName";
import {replaceableComponent} from "../../utils/replaceableComponent";
interface IProps { interface IProps {
isMinimized: boolean; isMinimized: boolean;
@ -69,6 +70,7 @@ interface IState {
selectedSpace?: Room; selectedSpace?: Room;
} }
@replaceableComponent("structures.UserMenu")
export default class UserMenu extends React.Component<IProps, IState> { export default class UserMenu extends React.Component<IProps, IState> {
private dispatcherRef: string; private dispatcherRef: string;
private themeWatcherRef: string; private themeWatcherRef: string;

View file

@ -23,7 +23,9 @@ import * as sdk from "../../index";
import Modal from '../../Modal'; import Modal from '../../Modal';
import { _t } from '../../languageHandler'; import { _t } from '../../languageHandler';
import HomePage from "./HomePage"; import HomePage from "./HomePage";
import {replaceableComponent} from "../../utils/replaceableComponent";
@replaceableComponent("structures.UserView")
export default class UserView extends React.Component { export default class UserView extends React.Component {
static get propTypes() { static get propTypes() {
return { return {

View file

@ -21,8 +21,10 @@ import PropTypes from 'prop-types';
import SyntaxHighlight from '../views/elements/SyntaxHighlight'; import SyntaxHighlight from '../views/elements/SyntaxHighlight';
import {_t} from "../../languageHandler"; import {_t} from "../../languageHandler";
import * as sdk from "../../index"; import * as sdk from "../../index";
import {replaceableComponent} from "../../utils/replaceableComponent";
@replaceableComponent("structures.ViewSource")
export default class ViewSource extends React.Component { export default class ViewSource extends React.Component {
static propTypes = { static propTypes = {
content: PropTypes.object.isRequired, content: PropTypes.object.isRequired,

View file

@ -26,7 +26,9 @@ import {
PHASE_CONFIRM_SKIP, PHASE_CONFIRM_SKIP,
} from '../../../stores/SetupEncryptionStore'; } from '../../../stores/SetupEncryptionStore';
import SetupEncryptionBody from "./SetupEncryptionBody"; import SetupEncryptionBody from "./SetupEncryptionBody";
import {replaceableComponent} from "../../../utils/replaceableComponent";
@replaceableComponent("structures.auth.CompleteSecurity")
export default class CompleteSecurity extends React.Component { export default class CompleteSecurity extends React.Component {
static propTypes = { static propTypes = {
onFinished: PropTypes.func.isRequired, onFinished: PropTypes.func.isRequired,

View file

@ -19,7 +19,9 @@ import PropTypes from 'prop-types';
import AuthPage from '../../views/auth/AuthPage'; import AuthPage from '../../views/auth/AuthPage';
import CompleteSecurityBody from '../../views/auth/CompleteSecurityBody'; import CompleteSecurityBody from '../../views/auth/CompleteSecurityBody';
import CreateCrossSigningDialog from '../../views/dialogs/security/CreateCrossSigningDialog'; import CreateCrossSigningDialog from '../../views/dialogs/security/CreateCrossSigningDialog';
import {replaceableComponent} from "../../../utils/replaceableComponent";
@replaceableComponent("structures.auth.E2eSetup")
export default class E2eSetup extends React.Component { export default class E2eSetup extends React.Component {
static propTypes = { static propTypes = {
onFinished: PropTypes.func.isRequired, onFinished: PropTypes.func.isRequired,

View file

@ -27,6 +27,7 @@ import classNames from 'classnames';
import AuthPage from "../../views/auth/AuthPage"; import AuthPage from "../../views/auth/AuthPage";
import CountlyAnalytics from "../../../CountlyAnalytics"; import CountlyAnalytics from "../../../CountlyAnalytics";
import ServerPicker from "../../views/elements/ServerPicker"; import ServerPicker from "../../views/elements/ServerPicker";
import {replaceableComponent} from "../../../utils/replaceableComponent";
// Phases // Phases
// Show the forgot password inputs // Show the forgot password inputs
@ -38,6 +39,7 @@ const PHASE_EMAIL_SENT = 3;
// User has clicked the link in email and completed reset // User has clicked the link in email and completed reset
const PHASE_DONE = 4; const PHASE_DONE = 4;
@replaceableComponent("structures.auth.ForgotPassword")
export default class ForgotPassword extends React.Component { export default class ForgotPassword extends React.Component {
static propTypes = { static propTypes = {
serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired, serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired,

View file

@ -35,6 +35,7 @@ import InlineSpinner from "../../views/elements/InlineSpinner";
import Spinner from "../../views/elements/Spinner"; import Spinner from "../../views/elements/Spinner";
import SSOButtons from "../../views/elements/SSOButtons"; import SSOButtons from "../../views/elements/SSOButtons";
import ServerPicker from "../../views/elements/ServerPicker"; 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 // 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. // 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 * 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> { export default class LoginComponent extends React.PureComponent<IProps, IState> {
private unmounted = false; private unmounted = false;
private loginLogic: Login; private loginLogic: Login;

View file

@ -30,6 +30,7 @@ import Login, {ISSOFlow} from "../../../Login";
import dis from "../../../dispatcher/dispatcher"; import dis from "../../../dispatcher/dispatcher";
import SSOButtons from "../../views/elements/SSOButtons"; import SSOButtons from "../../views/elements/SSOButtons";
import ServerPicker from '../../views/elements/ServerPicker'; import ServerPicker from '../../views/elements/ServerPicker';
import {replaceableComponent} from "../../../utils/replaceableComponent";
interface IProps { interface IProps {
serverConfig: ValidatedServerConfig; serverConfig: ValidatedServerConfig;
@ -109,6 +110,7 @@ interface IState {
ssoFlow?: ISSOFlow; ssoFlow?: ISSOFlow;
} }
@replaceableComponent("structures.auth.Registration")
export default class Registration extends React.Component<IProps, IState> { export default class Registration extends React.Component<IProps, IState> {
loginLogic: Login; loginLogic: Login;

View file

@ -28,6 +28,7 @@ import {
PHASE_CONFIRM_SKIP, PHASE_CONFIRM_SKIP,
PHASE_FINISHED, PHASE_FINISHED,
} from '../../../stores/SetupEncryptionStore'; } from '../../../stores/SetupEncryptionStore';
import {replaceableComponent} from "../../../utils/replaceableComponent";
function keyHasPassphrase(keyInfo) { function keyHasPassphrase(keyInfo) {
return ( return (
@ -37,6 +38,7 @@ function keyHasPassphrase(keyInfo) {
); );
} }
@replaceableComponent("structures.auth.SetupEncryptionBody")
export default class SetupEncryptionBody extends React.Component { export default class SetupEncryptionBody extends React.Component {
static propTypes = { static propTypes = {
onFinished: PropTypes.func.isRequired, onFinished: PropTypes.func.isRequired,

View file

@ -26,6 +26,7 @@ import {sendLoginRequest} from "../../../Login";
import AuthPage from "../../views/auth/AuthPage"; import AuthPage from "../../views/auth/AuthPage";
import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY} from "../../../BasePlatform"; import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY} from "../../../BasePlatform";
import SSOButtons from "../../views/elements/SSOButtons"; import SSOButtons from "../../views/elements/SSOButtons";
import {replaceableComponent} from "../../../utils/replaceableComponent";
const LOGIN_VIEW = { const LOGIN_VIEW = {
LOADING: 1, LOADING: 1,
@ -41,6 +42,7 @@ const FLOWS_TO_VIEWS = {
"m.login.sso": LOGIN_VIEW.SSO, "m.login.sso": LOGIN_VIEW.SSO,
}; };
@replaceableComponent("structures.auth.SoftLogout")
export default class SoftLogout extends React.Component { export default class SoftLogout extends React.Component {
static propTypes = { static propTypes = {
// Query parameters from MatrixChat // Query parameters from MatrixChat