From 997d6d40bfbb8a9a4ce49c6599bffb61ca69ea1d Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 2 Mar 2022 13:42:44 -0700 Subject: [PATCH 01/47] Step 1: Remove all usage of `@replaceableComponent` --- src/components/structures/ContextMenu.tsx | 2 -- src/components/structures/FilePanel.tsx | 2 -- src/components/structures/GenericErrorPage.tsx | 3 --- src/components/structures/HostSignupAction.tsx | 2 -- src/components/structures/IndicatorScrollbar.tsx | 2 -- src/components/structures/InteractiveAuth.tsx | 2 -- src/components/structures/LeftPanel.tsx | 2 -- src/components/structures/LoggedInView.tsx | 2 -- src/components/structures/MainSplit.tsx | 2 -- src/components/structures/MatrixChat.tsx | 2 -- src/components/structures/MessagePanel.tsx | 2 -- src/components/structures/NonUrgentToastContainer.tsx | 2 -- src/components/structures/NotificationPanel.tsx | 2 -- src/components/structures/RightPanel.tsx | 2 -- src/components/structures/RoomDirectory.tsx | 2 -- src/components/structures/RoomSearch.tsx | 2 -- src/components/structures/RoomStatusBar.tsx | 2 -- src/components/structures/RoomView.tsx | 2 -- src/components/structures/ScrollPanel.tsx | 2 -- src/components/structures/SearchBox.tsx | 2 -- src/components/structures/TabbedView.tsx | 2 -- src/components/structures/ThreadView.tsx | 2 -- src/components/structures/TimelinePanel.tsx | 2 -- src/components/structures/ToastContainer.tsx | 2 -- src/components/structures/UploadBar.tsx | 2 -- src/components/structures/UserMenu.tsx | 2 -- src/components/structures/UserView.tsx | 2 -- src/components/structures/ViewSource.tsx | 2 -- src/components/structures/auth/CompleteSecurity.tsx | 2 -- src/components/structures/auth/E2eSetup.tsx | 2 -- src/components/structures/auth/ForgotPassword.tsx | 2 -- src/components/structures/auth/Login.tsx | 2 -- src/components/structures/auth/Registration.tsx | 2 -- src/components/structures/auth/SetupEncryptionBody.tsx | 2 -- src/components/structures/auth/SoftLogout.tsx | 2 -- src/components/views/audio_messages/AudioPlayer.tsx | 2 -- src/components/views/audio_messages/AudioPlayerBase.tsx | 2 -- src/components/views/audio_messages/Clock.tsx | 2 -- src/components/views/audio_messages/DurationClock.tsx | 2 -- .../views/audio_messages/LiveRecordingClock.tsx | 2 -- .../views/audio_messages/LiveRecordingWaveform.tsx | 2 -- src/components/views/audio_messages/PlayPauseButton.tsx | 2 -- src/components/views/audio_messages/PlaybackClock.tsx | 2 -- src/components/views/audio_messages/PlaybackWaveform.tsx | 2 -- src/components/views/audio_messages/RecordingPlayback.tsx | 2 -- src/components/views/audio_messages/SeekBar.tsx | 2 -- src/components/views/audio_messages/Waveform.tsx | 3 --- src/components/views/auth/AuthBody.tsx | 3 --- src/components/views/auth/AuthFooter.tsx | 2 -- src/components/views/auth/AuthHeader.tsx | 2 -- src/components/views/auth/AuthHeaderLogo.tsx | 3 --- src/components/views/auth/AuthPage.tsx | 2 -- src/components/views/auth/CaptchaForm.tsx | 2 -- src/components/views/auth/CompleteSecurityBody.tsx | 3 --- src/components/views/auth/CountryDropdown.tsx | 2 -- src/components/views/auth/EmailField.tsx | 2 -- .../views/auth/InteractiveAuthEntryComponents.tsx | 8 -------- src/components/views/auth/PassphraseConfirmField.tsx | 2 -- src/components/views/auth/PassphraseField.tsx | 2 -- src/components/views/auth/PasswordLogin.tsx | 2 -- src/components/views/auth/RegistrationForm.tsx | 2 -- src/components/views/auth/Welcome.tsx | 2 -- src/components/views/avatars/DecoratedRoomAvatar.tsx | 2 -- src/components/views/avatars/MemberAvatar.tsx | 2 -- src/components/views/avatars/RoomAvatar.tsx | 2 -- src/components/views/context_menus/CallContextMenu.tsx | 2 -- src/components/views/context_menus/DialpadContextMenu.tsx | 2 -- .../views/context_menus/GenericElementContextMenu.tsx | 3 --- .../views/context_menus/GenericTextContextMenu.tsx | 3 --- src/components/views/context_menus/MessageContextMenu.tsx | 2 -- src/components/views/dialogs/AskInviteAnywayDialog.tsx | 2 -- src/components/views/dialogs/BaseDialog.tsx | 2 -- src/components/views/dialogs/BugReportDialog.tsx | 2 -- .../views/dialogs/ConfirmAndWaitRedactDialog.tsx | 2 -- src/components/views/dialogs/ConfirmRedactDialog.tsx | 2 -- src/components/views/dialogs/ConfirmUserActionDialog.tsx | 2 -- src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx | 2 -- src/components/views/dialogs/CreateRoomDialog.tsx | 2 -- src/components/views/dialogs/DeactivateAccountDialog.tsx | 2 -- src/components/views/dialogs/ErrorDialog.tsx | 2 -- src/components/views/dialogs/HostSignupDialog.tsx | 2 -- src/components/views/dialogs/IncomingSasDialog.tsx | 2 -- .../views/dialogs/IntegrationsDisabledDialog.tsx | 2 -- .../views/dialogs/IntegrationsImpossibleDialog.tsx | 2 -- src/components/views/dialogs/InteractiveAuthDialog.tsx | 2 -- src/components/views/dialogs/InviteDialog.tsx | 2 -- src/components/views/dialogs/LogoutDialog.tsx | 2 -- .../views/dialogs/ManualDeviceKeyVerificationDialog.tsx | 2 -- src/components/views/dialogs/MessageEditHistoryDialog.tsx | 2 -- src/components/views/dialogs/ModalWidgetDialog.tsx | 2 -- src/components/views/dialogs/ReportEventDialog.tsx | 2 -- src/components/views/dialogs/RoomSettingsDialog.tsx | 2 -- src/components/views/dialogs/RoomUpgradeDialog.tsx | 2 -- src/components/views/dialogs/RoomUpgradeWarningDialog.tsx | 2 -- src/components/views/dialogs/ServerOfflineDialog.tsx | 2 -- src/components/views/dialogs/ServerPickerDialog.tsx | 2 -- src/components/views/dialogs/SeshatResetDialog.tsx | 2 -- .../views/dialogs/SessionRestoreErrorDialog.tsx | 2 -- src/components/views/dialogs/SetEmailDialog.tsx | 2 -- src/components/views/dialogs/ShareDialog.tsx | 2 -- src/components/views/dialogs/StorageEvictedDialog.tsx | 2 -- .../views/dialogs/TabbedIntegrationManagerDialog.tsx | 2 -- src/components/views/dialogs/TermsDialog.tsx | 2 -- src/components/views/dialogs/TextInputDialog.tsx | 2 -- src/components/views/dialogs/UploadConfirmDialog.tsx | 2 -- src/components/views/dialogs/UploadFailureDialog.tsx | 2 -- src/components/views/dialogs/UserSettingsDialog.tsx | 2 -- .../views/dialogs/VerificationRequestDialog.tsx | 2 -- .../views/dialogs/WidgetCapabilitiesPromptDialog.tsx | 2 -- .../views/dialogs/WidgetOpenIDPermissionsDialog.tsx | 2 -- .../dialogs/security/ConfirmDestroyCrossSigningDialog.tsx | 2 -- .../views/dialogs/security/CreateCrossSigningDialog.tsx | 2 -- .../views/dialogs/security/SetupEncryptionDialog.tsx | 2 -- src/components/views/elements/AccessibleTooltipButton.tsx | 2 -- src/components/views/elements/ActionButton.tsx | 2 -- src/components/views/elements/AddressSelector.tsx | 2 -- src/components/views/elements/AddressTile.tsx | 2 -- src/components/views/elements/AppPermission.tsx | 2 -- src/components/views/elements/AppTile.tsx | 2 -- .../views/elements/DesktopCapturerSourcePicker.tsx | 2 -- src/components/views/elements/DialogButtons.tsx | 2 -- src/components/views/elements/DirectorySearchBox.tsx | 2 -- src/components/views/elements/Draggable.tsx | 3 --- src/components/views/elements/Dropdown.tsx | 2 -- src/components/views/elements/EditableItemList.tsx | 2 -- src/components/views/elements/EditableText.tsx | 2 -- src/components/views/elements/EditableTextContainer.tsx | 2 -- src/components/views/elements/ErrorBoundary.tsx | 2 -- src/components/views/elements/EventListSummary.tsx | 2 -- src/components/views/elements/EventTilePreview.tsx | 2 -- .../views/elements/IRCTimelineProfileResizer.tsx | 2 -- src/components/views/elements/ImageView.tsx | 2 -- src/components/views/elements/InfoTooltip.tsx | 2 -- src/components/views/elements/InlineSpinner.tsx | 2 -- src/components/views/elements/InviteReason.tsx | 2 -- src/components/views/elements/LabelledToggleSwitch.tsx | 2 -- src/components/views/elements/LanguageDropdown.tsx | 2 -- src/components/views/elements/LazyRenderList.tsx | 3 --- src/components/views/elements/PersistedElement.tsx | 2 -- src/components/views/elements/PersistentApp.tsx | 2 -- src/components/views/elements/Pill.js | 2 -- src/components/views/elements/PowerSelector.tsx | 2 -- src/components/views/elements/ReplyChain.tsx | 2 -- src/components/views/elements/RoomAliasField.tsx | 2 -- src/components/views/elements/SettingsFlag.tsx | 2 -- src/components/views/elements/Slider.tsx | 3 --- .../views/elements/SpellCheckLanguagesDropdown.tsx | 2 -- src/components/views/elements/Spoiler.tsx | 3 --- src/components/views/elements/StyledCheckbox.tsx | 3 --- src/components/views/elements/StyledRadioButton.tsx | 3 --- src/components/views/elements/SyntaxHighlight.tsx | 3 --- src/components/views/elements/TagComposer.tsx | 2 -- src/components/views/elements/TextWithTooltip.tsx | 2 -- src/components/views/elements/Tooltip.tsx | 2 -- src/components/views/elements/TooltipButton.tsx | 2 -- src/components/views/elements/TruncatedList.tsx | 2 -- .../views/elements/crypto/VerificationQRCode.tsx | 2 -- src/components/views/emojipicker/Category.tsx | 2 -- src/components/views/emojipicker/Emoji.tsx | 2 -- src/components/views/emojipicker/EmojiPicker.tsx | 2 -- src/components/views/emojipicker/Header.tsx | 2 -- src/components/views/emojipicker/Preview.tsx | 2 -- src/components/views/emojipicker/QuickReactions.tsx | 2 -- src/components/views/emojipicker/ReactionPicker.tsx | 2 -- src/components/views/emojipicker/Search.tsx | 2 -- src/components/views/location/LocationPicker.tsx | 2 -- src/components/views/location/LocationViewDialog.tsx | 2 -- src/components/views/messages/DateSeparator.tsx | 2 -- src/components/views/messages/DownloadActionButton.tsx | 2 -- src/components/views/messages/EditHistoryMessage.tsx | 2 -- src/components/views/messages/MAudioBody.tsx | 2 -- src/components/views/messages/MFileBody.tsx | 2 -- src/components/views/messages/MImageBody.tsx | 2 -- src/components/views/messages/MJitsiWidgetEvent.tsx | 2 -- .../views/messages/MKeyVerificationConclusion.tsx | 2 -- src/components/views/messages/MKeyVerificationRequest.tsx | 2 -- src/components/views/messages/MLocationBody.tsx | 2 -- src/components/views/messages/MPollBody.tsx | 2 -- src/components/views/messages/MStickerBody.tsx | 2 -- src/components/views/messages/MVideoBody.tsx | 2 -- src/components/views/messages/MVoiceMessageBody.tsx | 2 -- src/components/views/messages/MVoiceOrAudioBody.tsx | 2 -- src/components/views/messages/MessageActionBar.tsx | 2 -- src/components/views/messages/MessageEvent.tsx | 2 -- src/components/views/messages/MessageTimestamp.tsx | 2 -- src/components/views/messages/MjolnirBody.tsx | 2 -- src/components/views/messages/ReactionsRow.tsx | 2 -- src/components/views/messages/ReactionsRowButton.tsx | 2 -- .../views/messages/ReactionsRowButtonTooltip.tsx | 2 -- src/components/views/messages/RoomAvatarEvent.tsx | 2 -- src/components/views/messages/RoomCreate.tsx | 2 -- src/components/views/messages/SenderProfile.tsx | 2 -- src/components/views/messages/TextualBody.tsx | 2 -- src/components/views/messages/TextualEvent.tsx | 2 -- src/components/views/messages/TileErrorBoundary.tsx | 2 -- src/components/views/messages/ViewSourceEvent.tsx | 2 -- src/components/views/right_panel/HeaderButton.tsx | 2 -- src/components/views/right_panel/HeaderButtons.tsx | 2 -- src/components/views/right_panel/RoomHeaderButtons.tsx | 2 -- src/components/views/right_panel/TimelineCard.tsx | 2 -- src/components/views/right_panel/VerificationPanel.tsx | 2 -- src/components/views/room_settings/AliasSettings.tsx | 2 -- .../views/room_settings/RoomProfileSettings.tsx | 2 -- src/components/views/room_settings/RoomPublishSetting.tsx | 2 -- src/components/views/room_settings/UrlPreviewSettings.tsx | 2 -- src/components/views/rooms/AppsDrawer.tsx | 2 -- src/components/views/rooms/Autocomplete.tsx | 2 -- src/components/views/rooms/AuxPanel.tsx | 2 -- src/components/views/rooms/BasicMessageComposer.tsx | 2 -- src/components/views/rooms/EditMessageComposer.tsx | 2 -- src/components/views/rooms/EntityTile.tsx | 2 -- src/components/views/rooms/EventTile.tsx | 2 -- src/components/views/rooms/LinkPreviewWidget.tsx | 2 -- src/components/views/rooms/MemberList.tsx | 2 -- src/components/views/rooms/MemberTile.tsx | 2 -- src/components/views/rooms/MessageComposer.tsx | 2 -- src/components/views/rooms/MessageComposerFormatBar.tsx | 2 -- src/components/views/rooms/NotificationBadge.tsx | 2 -- src/components/views/rooms/PinnedEventTile.tsx | 2 -- src/components/views/rooms/PresenceLabel.tsx | 2 -- src/components/views/rooms/ReadReceiptMarker.tsx | 2 -- src/components/views/rooms/ReplyPreview.tsx | 2 -- src/components/views/rooms/ReplyTile.tsx | 2 -- src/components/views/rooms/RoomBreadcrumbs.tsx | 2 -- src/components/views/rooms/RoomDetailList.tsx | 2 -- src/components/views/rooms/RoomDetailRow.js | 2 -- src/components/views/rooms/RoomHeader.tsx | 2 -- src/components/views/rooms/RoomList.tsx | 2 -- src/components/views/rooms/RoomPreviewBar.tsx | 2 -- src/components/views/rooms/RoomSublist.tsx | 2 -- src/components/views/rooms/RoomTile.tsx | 2 -- src/components/views/rooms/RoomUpgradeWarningBar.tsx | 2 -- src/components/views/rooms/SearchBar.tsx | 2 -- src/components/views/rooms/SearchResultTile.tsx | 2 -- src/components/views/rooms/SendMessageComposer.tsx | 2 -- src/components/views/rooms/Stickerpicker.tsx | 2 -- src/components/views/rooms/ThirdPartyMemberInfo.tsx | 2 -- src/components/views/rooms/TopUnreadMessagesBar.tsx | 2 -- src/components/views/rooms/VoiceRecordComposerTile.tsx | 2 -- src/components/views/rooms/WhoIsTypingTile.tsx | 2 -- src/components/views/settings/BridgeTile.tsx | 2 -- src/components/views/settings/ChangeAvatar.tsx | 2 -- src/components/views/settings/ChangeDisplayName.tsx | 2 -- src/components/views/settings/ChangePassword.tsx | 2 -- src/components/views/settings/CrossSigningPanel.tsx | 2 -- src/components/views/settings/CryptographyPanel.tsx | 2 -- src/components/views/settings/DevicesPanel.tsx | 2 -- src/components/views/settings/DevicesPanelEntry.tsx | 2 -- src/components/views/settings/EventIndexPanel.tsx | 2 -- src/components/views/settings/FontScalingPanel.tsx | 2 -- src/components/views/settings/IntegrationManager.tsx | 2 -- src/components/views/settings/ProfileSettings.tsx | 2 -- src/components/views/settings/SecureBackupPanel.tsx | 2 -- src/components/views/settings/SetIdServer.tsx | 2 -- src/components/views/settings/SetIntegrationManager.tsx | 2 -- src/components/views/settings/SpellCheckSettings.tsx | 2 -- src/components/views/settings/ThemeChoicePanel.tsx | 2 -- src/components/views/settings/account/EmailAddresses.tsx | 2 -- src/components/views/settings/account/PhoneNumbers.tsx | 2 -- .../views/settings/discovery/EmailAddresses.tsx | 2 -- src/components/views/settings/discovery/PhoneNumbers.tsx | 2 -- .../views/settings/tabs/room/AdvancedRoomSettingsTab.tsx | 2 -- .../views/settings/tabs/room/BridgeSettingsTab.tsx | 2 -- .../views/settings/tabs/room/GeneralRoomSettingsTab.tsx | 2 -- .../views/settings/tabs/room/NotificationSettingsTab.tsx | 2 -- .../views/settings/tabs/room/RolesRoomSettingsTab.tsx | 2 -- .../views/settings/tabs/room/SecurityRoomSettingsTab.tsx | 2 -- .../settings/tabs/user/AppearanceUserSettingsTab.tsx | 2 -- .../views/settings/tabs/user/GeneralUserSettingsTab.tsx | 2 -- .../views/settings/tabs/user/HelpUserSettingsTab.tsx | 2 -- .../views/settings/tabs/user/LabsUserSettingsTab.tsx | 2 -- .../views/settings/tabs/user/MjolnirUserSettingsTab.tsx | 2 -- .../settings/tabs/user/NotificationUserSettingsTab.tsx | 2 -- .../settings/tabs/user/PreferencesUserSettingsTab.tsx | 2 -- .../views/settings/tabs/user/SecurityUserSettingsTab.tsx | 2 -- .../views/settings/tabs/user/VoiceUserSettingsTab.tsx | 2 -- src/components/views/terms/InlineTermsAgreement.tsx | 2 -- src/components/views/toasts/NonUrgentEchoFailureToast.tsx | 2 -- src/components/views/toasts/VerificationRequestToast.tsx | 2 -- .../views/verification/VerificationCancelled.tsx | 2 -- .../views/verification/VerificationComplete.tsx | 2 -- src/components/views/verification/VerificationShowSas.tsx | 2 -- src/components/views/voip/CallView.tsx | 2 -- src/components/views/voip/CallViewForRoom.tsx | 2 -- src/components/views/voip/DialPad.tsx | 2 -- src/components/views/voip/DialPadModal.tsx | 2 -- src/components/views/voip/PictureInPictureDragger.tsx | 2 -- src/components/views/voip/PipContainer.tsx | 2 -- src/components/views/voip/PipView.tsx | 2 -- src/components/views/voip/VideoFeed.tsx | 2 -- src/toasts/IncomingCallToast.tsx | 2 -- 291 files changed, 602 deletions(-) diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx index 2231618994..2f233c02ed 100644 --- a/src/components/structures/ContextMenu.tsx +++ b/src/components/structures/ContextMenu.tsx @@ -22,7 +22,6 @@ import classNames from "classnames"; import FocusLock from "react-focus-lock"; import { Writeable } from "../../@types/common"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import UIStore from "../../stores/UIStore"; import { checkInputableElement, RovingTabIndexProvider } from "../../accessibility/RovingTabIndex"; import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts"; @@ -105,7 +104,6 @@ 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 default class ContextMenu extends React.PureComponent { private readonly initialFocus: HTMLElement; diff --git a/src/components/structures/FilePanel.tsx b/src/components/structures/FilePanel.tsx index 8466c26bac..d248c6556f 100644 --- a/src/components/structures/FilePanel.tsx +++ b/src/components/structures/FilePanel.tsx @@ -29,7 +29,6 @@ import EventIndexPeg from "../../indexing/EventIndexPeg"; import { _t } from '../../languageHandler'; import DesktopBuildsNotice, { WarningKind } from "../views/elements/DesktopBuildsNotice"; import BaseCard from "../views/right_panel/BaseCard"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import ResizeNotifier from '../../utils/ResizeNotifier'; import TimelinePanel from "./TimelinePanel"; import Spinner from "../views/elements/Spinner"; @@ -51,7 +50,6 @@ interface IState { /* * Component which shows the filtered file using a TimelinePanel */ -@replaceableComponent("structures.FilePanel") class FilePanel extends React.Component { static contextType = RoomContext; diff --git a/src/components/structures/GenericErrorPage.tsx b/src/components/structures/GenericErrorPage.tsx index 25892f46df..f9a68753a0 100644 --- a/src/components/structures/GenericErrorPage.tsx +++ b/src/components/structures/GenericErrorPage.tsx @@ -16,14 +16,11 @@ limitations under the License. import React from 'react'; -import { replaceableComponent } from "../../utils/replaceableComponent"; - interface IProps { title: React.ReactNode; message: React.ReactNode; } -@replaceableComponent("structures.GenericErrorPage") export default class GenericErrorPage extends React.PureComponent { render() { return
diff --git a/src/components/structures/HostSignupAction.tsx b/src/components/structures/HostSignupAction.tsx index 5b2bafa03c..6ba37eb9aa 100644 --- a/src/components/structures/HostSignupAction.tsx +++ b/src/components/structures/HostSignupAction.tsx @@ -23,7 +23,6 @@ import { import { _t } from "../../languageHandler"; import { HostSignupStore } from "../../stores/HostSignupStore"; import SdkConfig from "../../SdkConfig"; -import { replaceableComponent } from "../../utils/replaceableComponent"; interface IProps { onClick?(): void; @@ -31,7 +30,6 @@ interface IProps { interface IState {} -@replaceableComponent("structures.HostSignupAction") export default class HostSignupAction extends React.PureComponent { private openDialog = async () => { this.props.onClick?.(); diff --git a/src/components/structures/IndicatorScrollbar.tsx b/src/components/structures/IndicatorScrollbar.tsx index 307541cb0b..4b122345b3 100644 --- a/src/components/structures/IndicatorScrollbar.tsx +++ b/src/components/structures/IndicatorScrollbar.tsx @@ -17,7 +17,6 @@ limitations under the License. import React, { ComponentProps, createRef } from "react"; import AutoHideScrollbar from "./AutoHideScrollbar"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import UIStore, { UI_EVENTS } from "../../stores/UIStore"; interface IProps extends Omit, "onWheel"> { @@ -40,7 +39,6 @@ interface IState { rightIndicatorOffset: string; } -@replaceableComponent("structures.IndicatorScrollbar") export default class IndicatorScrollbar extends React.Component { private autoHideScrollbar = createRef(); private scrollElement: HTMLDivElement; diff --git a/src/components/structures/InteractiveAuth.tsx b/src/components/structures/InteractiveAuth.tsx index 01b55c1542..94c54b32e3 100644 --- a/src/components/structures/InteractiveAuth.tsx +++ b/src/components/structures/InteractiveAuth.tsx @@ -28,7 +28,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import getEntryComponentForLoginType, { IStageComponent } from '../views/auth/InteractiveAuthEntryComponents'; import Spinner from "../views/elements/Spinner"; -import { replaceableComponent } from "../../utils/replaceableComponent"; export const ERROR_USER_CANCELLED = new Error("User cancelled auth session"); @@ -89,7 +88,6 @@ interface IState { submitButtonEnabled: boolean; } -@replaceableComponent("structures.InteractiveAuthComponent") export default class InteractiveAuthComponent extends React.Component { private readonly authLogic: InteractiveAuth; private readonly intervalId: number = null; diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx index 987e8c2966..771183b45b 100644 --- a/src/components/structures/LeftPanel.tsx +++ b/src/components/structures/LeftPanel.tsx @@ -27,7 +27,6 @@ import { Action } from "../../dispatcher/actions"; import RoomSearch from "./RoomSearch"; import ResizeNotifier from "../../utils/ResizeNotifier"; import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import SpaceStore from "../../stores/spaces/SpaceStore"; import { MetaSpace, SpaceKey, UPDATE_SELECTED_SPACE } from "../../stores/spaces"; import { getKeyBindingsManager } from "../../KeyBindingsManager"; @@ -62,7 +61,6 @@ interface IState { activeSpace: SpaceKey; } -@replaceableComponent("structures.LeftPanel") export default class LeftPanel extends React.Component { private listContainerRef = createRef(); private roomSearchRef = createRef(); diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index ff8616e29f..7de08843b5 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -52,7 +52,6 @@ import HostSignupContainer from '../views/host_signup/HostSignupContainer'; import { getKeyBindingsManager } from '../../KeyBindingsManager'; import { IOpts } from "../../createRoom"; import SpacePanel from "../views/spaces/SpacePanel"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import CallHandler, { CallHandlerEvent } from '../../CallHandler'; import AudioFeedArrayForCall from '../views/voip/AudioFeedArrayForCall'; import { OwnProfileStore } from '../../stores/OwnProfileStore'; @@ -127,7 +126,6 @@ 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.tsx b/src/components/structures/MainSplit.tsx index 7cf6964c1f..a90758b442 100644 --- a/src/components/structures/MainSplit.tsx +++ b/src/components/structures/MainSplit.tsx @@ -19,7 +19,6 @@ import React from 'react'; import { NumberSize, Resizable } from 're-resizable'; import { Direction } from "re-resizable/lib/resizer"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import ResizeNotifier from "../../utils/ResizeNotifier"; interface IProps { @@ -28,7 +27,6 @@ interface IProps { panel?: JSX.Element; } -@replaceableComponent("structures.MainSplit") export default class MainSplit extends React.Component { private onResizeStart = (): void => { this.props.resizeNotifier.startResizing(); diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 302989ed5f..9c1589d58c 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -89,7 +89,6 @@ import { UIFeature } from "../../settings/UIFeature"; import DialPadModal from "../views/voip/DialPadModal"; import { showToast as showMobileGuideToast } from '../../toasts/MobileGuideToast'; import { shouldUseLoginForWelcome } from "../../utils/pages"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import RoomListStore from "../../stores/room-list/RoomListStore"; import { RoomUpdateCause } from "../../stores/room-list/models"; import SecurityCustomisations from "../../customisations/Security"; @@ -207,7 +206,6 @@ interface IState { forceTimeline?: boolean; // see props } -@replaceableComponent("structures.MatrixChat") export default class MatrixChat extends React.PureComponent { static displayName = "MatrixChat"; diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index f7e338fafa..7758375a69 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -37,7 +37,6 @@ import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResiz import DMRoomMap from "../../utils/DMRoomMap"; import NewRoomIntro from "../views/rooms/NewRoomIntro"; import HistoryTile from "../views/rooms/HistoryTile"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import defaultDispatcher from '../../dispatcher/dispatcher'; import CallEventGrouper from "./CallEventGrouper"; import WhoIsTypingTile from '../views/rooms/WhoIsTypingTile'; @@ -199,7 +198,6 @@ interface IReadReceiptForUser { /* (almost) stateless UI component which builds the event tiles in the room timeline. */ -@replaceableComponent("structures.MessagePanel") export default class MessagePanel extends React.Component { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/structures/NonUrgentToastContainer.tsx b/src/components/structures/NonUrgentToastContainer.tsx index 7872c2596c..10cb1ad427 100644 --- a/src/components/structures/NonUrgentToastContainer.tsx +++ b/src/components/structures/NonUrgentToastContainer.tsx @@ -19,7 +19,6 @@ 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 { } @@ -28,7 +27,6 @@ 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.tsx b/src/components/structures/NotificationPanel.tsx index 6af271bcc2..e5f094773b 100644 --- a/src/components/structures/NotificationPanel.tsx +++ b/src/components/structures/NotificationPanel.tsx @@ -20,7 +20,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { _t } from '../../languageHandler'; import { MatrixClientPeg } from "../../MatrixClientPeg"; import BaseCard from "../views/right_panel/BaseCard"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import TimelinePanel from "./TimelinePanel"; import Spinner from "../views/elements/Spinner"; import { Layout } from "../../settings/enums/Layout"; @@ -38,7 +37,6 @@ interface IState { /* * Component which shows the global notification list using a TimelinePanel */ -@replaceableComponent("structures.NotificationPanel") export default class NotificationPanel extends React.PureComponent { static contextType = RoomContext; diff --git a/src/components/structures/RightPanel.tsx b/src/components/structures/RightPanel.tsx index 3bf0ed26b9..5b1bf3f1ed 100644 --- a/src/components/structures/RightPanel.tsx +++ b/src/components/structures/RightPanel.tsx @@ -28,7 +28,6 @@ import RightPanelStore from "../../stores/right-panel/RightPanelStore"; import MatrixClientContext from "../../contexts/MatrixClientContext"; import RoomSummaryCard from "../views/right_panel/RoomSummaryCard"; import WidgetCard from "../views/right_panel/WidgetCard"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import SettingsStore from "../../settings/SettingsStore"; import MemberList from "../views/rooms/MemberList"; import UserInfo from "../views/right_panel/UserInfo"; @@ -60,7 +59,6 @@ interface IState { cardState?: IRightPanelCardState; } -@replaceableComponent("structures.RightPanel") export default class RightPanel extends React.Component { static contextType = MatrixClientContext; public context!: React.ContextType; diff --git a/src/components/structures/RoomDirectory.tsx b/src/components/structures/RoomDirectory.tsx index 5cb90f1086..2a07c3f81b 100644 --- a/src/components/structures/RoomDirectory.tsx +++ b/src/components/structures/RoomDirectory.tsx @@ -31,7 +31,6 @@ import { instanceForInstanceId, protocolNameForInstanceId } from '../../utils/Di import Analytics from '../../Analytics'; import NetworkDropdown, { ALL_ROOMS, Protocols } from "../views/directory/NetworkDropdown"; import SettingsStore from "../../settings/SettingsStore"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import { mediaFromMxc } from "../../customisations/Media"; import { IDialogProps } from "../views/dialogs/IDialogProps"; import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton"; @@ -71,7 +70,6 @@ interface IState { filterString: string; } -@replaceableComponent("structures.RoomDirectory") export default class RoomDirectory extends React.Component { private unmounted = false; private nextBatch: string = null; diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx index 5591e382ea..9421292764 100644 --- a/src/components/structures/RoomSearch.tsx +++ b/src/components/structures/RoomSearch.tsx @@ -26,7 +26,6 @@ import { Action } from "../../dispatcher/actions"; import RoomListStore from "../../stores/room-list/RoomListStore"; import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition"; import { getKeyBindingsManager } from "../../KeyBindingsManager"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import SpaceStore from "../../stores/spaces/SpaceStore"; import { UPDATE_SELECTED_SPACE } from "../../stores/spaces"; import { isMac, Key } from "../../Keyboard"; @@ -50,7 +49,6 @@ interface IState { spotlightBetaEnabled: boolean; } -@replaceableComponent("structures.RoomSearch") export default class RoomSearch extends React.PureComponent { private readonly dispatcherRef: string; private readonly betaRef: string; diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 514c3a507c..94b9905bec 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -24,7 +24,6 @@ import Resend from '../../Resend'; import dis from '../../dispatcher/dispatcher'; import { messageForResourceLimitError } from '../../utils/ErrorUtils'; import { Action } from "../../dispatcher/actions"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import NotificationBadge from "../views/rooms/NotificationBadge"; import { StaticNotificationState } from "../../stores/notifications/StaticNotificationState"; import AccessibleButton from "../views/elements/AccessibleButton"; @@ -82,7 +81,6 @@ interface IState { isResending: boolean; } -@replaceableComponent("structures.RoomStatusBar") export default class RoomStatusBar extends React.PureComponent { private unmounted = false; public static contextType = MatrixClientContext; diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index ffd80e0222..d52786c39b 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -86,7 +86,6 @@ import { getKeyBindingsManager } from '../../KeyBindingsManager'; import { objectHasDiff } from "../../utils/objects"; import SpaceRoomView from "./SpaceRoomView"; import { IOpts } from "../../createRoom"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import EditorStateTransfer from "../../utils/EditorStateTransfer"; import ErrorDialog from '../views/dialogs/ErrorDialog'; import SearchResultTile from '../views/rooms/SearchResultTile'; @@ -220,7 +219,6 @@ export interface IRoomState { narrow: boolean; } -@replaceableComponent("structures.RoomView") export class RoomView extends React.Component { private readonly dispatcherRef: string; private readonly roomStoreToken: EventSubscription; diff --git a/src/components/structures/ScrollPanel.tsx b/src/components/structures/ScrollPanel.tsx index d650cfc962..d580f02bc0 100644 --- a/src/components/structures/ScrollPanel.tsx +++ b/src/components/structures/ScrollPanel.tsx @@ -19,7 +19,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import Timer from '../../utils/Timer'; import AutoHideScrollbar from "./AutoHideScrollbar"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import { getKeyBindingsManager } from "../../KeyBindingsManager"; import ResizeNotifier from "../../utils/ResizeNotifier"; import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts"; @@ -170,7 +169,6 @@ interface IPreventShrinkingState { offsetNode: HTMLElement; } -@replaceableComponent("structures.ScrollPanel") export default class ScrollPanel extends React.Component { static defaultProps = { stickyBottom: true, diff --git a/src/components/structures/SearchBox.tsx b/src/components/structures/SearchBox.tsx index 5789e5adf1..bcf3dcc875 100644 --- a/src/components/structures/SearchBox.tsx +++ b/src/components/structures/SearchBox.tsx @@ -20,7 +20,6 @@ import { throttle } from 'lodash'; import classNames from 'classnames'; import AccessibleButton from '../../components/views/elements/AccessibleButton'; -import { replaceableComponent } from "../../utils/replaceableComponent"; import { getKeyBindingsManager } from "../../KeyBindingsManager"; import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts"; @@ -43,7 +42,6 @@ interface IState { blurred: boolean; } -@replaceableComponent("structures.SearchBox") export default class SearchBox extends React.Component { private search = createRef(); diff --git a/src/components/structures/TabbedView.tsx b/src/components/structures/TabbedView.tsx index ea116b7d8e..91e64946ad 100644 --- a/src/components/structures/TabbedView.tsx +++ b/src/components/structures/TabbedView.tsx @@ -22,7 +22,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { _t } from '../../languageHandler'; import AutoHideScrollbar from './AutoHideScrollbar'; -import { replaceableComponent } from "../../utils/replaceableComponent"; import AccessibleButton from "../views/elements/AccessibleButton"; import { PosthogScreenTracker, ScreenName } from "../../PosthogTrackers"; @@ -64,7 +63,6 @@ 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/ThreadView.tsx b/src/components/structures/ThreadView.tsx index 13fdc2d31a..600426a8b8 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -25,7 +25,6 @@ import classNames from "classnames"; import BaseCard from "../views/right_panel/BaseCard"; import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import ResizeNotifier from '../../utils/ResizeNotifier'; import MessageComposer from '../views/rooms/MessageComposer'; import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks'; @@ -72,7 +71,6 @@ interface IState { narrow: boolean; } -@replaceableComponent("structures.ThreadView") export default class ThreadView extends React.Component { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 96b892245b..dd372b9381 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -41,7 +41,6 @@ import { Action } from '../../dispatcher/actions'; import Timer from '../../utils/Timer'; import shouldHideEvent from '../../shouldHideEvent'; import { haveTileForEvent } from "../views/rooms/EventTile"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import { arrayFastClone } from "../../utils/arrays"; import MessagePanel from "./MessagePanel"; import { IScrollState } from "./ScrollPanel"; @@ -211,7 +210,6 @@ interface IEventIndexOpts { * * Also responsible for handling and sending read receipts. */ -@replaceableComponent("structures.TimelinePanel") class TimelinePanel extends React.Component { static contextType = RoomContext; diff --git a/src/components/structures/ToastContainer.tsx b/src/components/structures/ToastContainer.tsx index 0b71fa9dc9..7f2969e5af 100644 --- a/src/components/structures/ToastContainer.tsx +++ b/src/components/structures/ToastContainer.tsx @@ -18,14 +18,12 @@ import * as React from "react"; import classNames from "classnames"; import ToastStore, { IToast } from "../../stores/ToastStore"; -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 eb4ef51681..e3dc77a466 100644 --- a/src/components/structures/UploadBar.tsx +++ b/src/components/structures/UploadBar.tsx @@ -27,7 +27,6 @@ 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"; import MatrixClientContext from "../../contexts/MatrixClientContext"; interface IProps { @@ -40,7 +39,6 @@ interface IState { uploadsHere: IUpload[]; } -@replaceableComponent("structures.UploadBar") export default class UploadBar extends React.Component { static contextType = MatrixClientContext; diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index e245a73a9f..c00bb6170e 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -53,7 +53,6 @@ import { UIFeature } from "../../settings/UIFeature"; import HostSignupAction from "./HostSignupAction"; import SpaceStore from "../../stores/spaces/SpaceStore"; import { UPDATE_SELECTED_SPACE } from "../../stores/spaces"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import MatrixClientContext from "../../contexts/MatrixClientContext"; import { SettingUpdatedPayload } from "../../dispatcher/payloads/SettingUpdatedPayload"; import UserIdentifierCustomisations from "../../customisations/UserIdentifier"; @@ -143,7 +142,6 @@ const below = (rect: PartialDOMRect) => { }; }; -@replaceableComponent("structures.UserMenu") export default class UserMenu extends React.Component { private dispatcherRef: string; private themeWatcherRef: string; diff --git a/src/components/structures/UserView.tsx b/src/components/structures/UserView.tsx index 657b9ab6ff..9ba9d808c9 100644 --- a/src/components/structures/UserView.tsx +++ b/src/components/structures/UserView.tsx @@ -23,7 +23,6 @@ import { MatrixClientPeg } from "../../MatrixClientPeg"; import Modal from '../../Modal'; import { _t } from '../../languageHandler'; import HomePage from "./HomePage"; -import { replaceableComponent } from "../../utils/replaceableComponent"; import ErrorDialog from "../views/dialogs/ErrorDialog"; import MainSplit from "./MainSplit"; import RightPanel from "./RightPanel"; @@ -41,7 +40,6 @@ interface IState { member?: RoomMember; } -@replaceableComponent("structures.UserView") export default class UserView extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/structures/ViewSource.tsx b/src/components/structures/ViewSource.tsx index bd2f3cdb29..477dd4ca9a 100644 --- a/src/components/structures/ViewSource.tsx +++ b/src/components/structures/ViewSource.tsx @@ -24,7 +24,6 @@ import { _t } from "../../languageHandler"; import MatrixClientContext from "../../contexts/MatrixClientContext"; import { canEditContent } from "../../utils/EventUtils"; import { MatrixClientPeg } from '../../MatrixClientPeg'; -import { replaceableComponent } from "../../utils/replaceableComponent"; import { IDialogProps } from "../views/dialogs/IDialogProps"; import BaseDialog from "../views/dialogs/BaseDialog"; import { DevtoolsContext } from "../views/dialogs/devtools/BaseTool"; @@ -39,7 +38,6 @@ interface IState { isEditing: boolean; } -@replaceableComponent("structures.ViewSource") export default class ViewSource extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/structures/auth/CompleteSecurity.tsx b/src/components/structures/auth/CompleteSecurity.tsx index 7043878a72..c187e2d789 100644 --- a/src/components/structures/auth/CompleteSecurity.tsx +++ b/src/components/structures/auth/CompleteSecurity.tsx @@ -19,7 +19,6 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import { SetupEncryptionStore, Phase } from '../../../stores/SetupEncryptionStore'; import SetupEncryptionBody from "./SetupEncryptionBody"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AccessibleButton from '../../views/elements/AccessibleButton'; import CompleteSecurityBody from "../../views/auth/CompleteSecurityBody"; import AuthPage from "../../views/auth/AuthPage"; @@ -33,7 +32,6 @@ interface IState { lostKeys: boolean; } -@replaceableComponent("structures.auth.CompleteSecurity") export default class CompleteSecurity extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/structures/auth/E2eSetup.tsx b/src/components/structures/auth/E2eSetup.tsx index 96d6a0dc0b..ebd88b882c 100644 --- a/src/components/structures/auth/E2eSetup.tsx +++ b/src/components/structures/auth/E2eSetup.tsx @@ -19,7 +19,6 @@ import React from 'react'; import AuthPage from '../../views/auth/AuthPage'; import CompleteSecurityBody from '../../views/auth/CompleteSecurityBody'; import CreateCrossSigningDialog from '../../views/dialogs/security/CreateCrossSigningDialog'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { onFinished: () => void; @@ -27,7 +26,6 @@ interface IProps { tokenLogin?: boolean; } -@replaceableComponent("structures.auth.E2eSetup") export default class E2eSetup extends React.Component { render() { return ( diff --git a/src/components/structures/auth/ForgotPassword.tsx b/src/components/structures/auth/ForgotPassword.tsx index 14b201afc6..58b0073c44 100644 --- a/src/components/structures/auth/ForgotPassword.tsx +++ b/src/components/structures/auth/ForgotPassword.tsx @@ -28,7 +28,6 @@ import AuthPage from "../../views/auth/AuthPage"; import ServerPicker from "../../views/elements/ServerPicker"; import EmailField from "../../views/auth/EmailField"; import PassphraseField from '../../views/auth/PassphraseField'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { PASSWORD_MIN_SCORE } from '../../views/auth/RegistrationForm'; import InlineSpinner from '../../views/elements/InlineSpinner'; import Spinner from "../../views/elements/Spinner"; @@ -81,7 +80,6 @@ enum ForgotPasswordField { PasswordConfirm = 'field_password_confirm', } -@replaceableComponent("structures.auth.ForgotPassword") export default class ForgotPassword extends React.Component { private reset: PasswordReset; diff --git a/src/components/structures/auth/Login.tsx b/src/components/structures/auth/Login.tsx index c5e8a05665..0b99066414 100644 --- a/src/components/structures/auth/Login.tsx +++ b/src/components/structures/auth/Login.tsx @@ -34,7 +34,6 @@ 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"; import AuthBody from "../../views/auth/AuthBody"; import AuthHeader from "../../views/auth/AuthHeader"; import AccessibleButton from '../../views/elements/AccessibleButton'; @@ -103,7 +102,6 @@ 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 828ca8d79d..ecb4691e1b 100644 --- a/src/components/structures/auth/Registration.tsx +++ b/src/components/structures/auth/Registration.tsx @@ -30,7 +30,6 @@ 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"; import RegistrationForm from '../../views/auth/RegistrationForm'; import AccessibleButton from '../../views/elements/AccessibleButton'; import AuthBody from "../../views/auth/AuthBody"; @@ -110,7 +109,6 @@ 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.tsx b/src/components/structures/auth/SetupEncryptionBody.tsx index 8783ae3f58..2553f8fbaa 100644 --- a/src/components/structures/auth/SetupEncryptionBody.tsx +++ b/src/components/structures/auth/SetupEncryptionBody.tsx @@ -25,7 +25,6 @@ import { MatrixClientPeg } from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; import VerificationRequestDialog from '../../views/dialogs/VerificationRequestDialog'; import { SetupEncryptionStore, Phase } from '../../../stores/SetupEncryptionStore'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import EncryptionPanel from "../../views/right_panel/EncryptionPanel"; import AccessibleButton from '../../views/elements/AccessibleButton'; import Spinner from '../../views/elements/Spinner'; @@ -49,7 +48,6 @@ interface IState { lostKeys: boolean; } -@replaceableComponent("structures.auth.SetupEncryptionBody") export default class SetupEncryptionBody extends React.Component { constructor(props) { super(props); diff --git a/src/components/structures/auth/SoftLogout.tsx b/src/components/structures/auth/SoftLogout.tsx index f24230806a..7a366d7122 100644 --- a/src/components/structures/auth/SoftLogout.tsx +++ b/src/components/structures/auth/SoftLogout.tsx @@ -27,7 +27,6 @@ import { ISSOFlow, LoginFlow, 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"; import ConfirmWipeDeviceDialog from '../../views/dialogs/ConfirmWipeDeviceDialog'; import Field from '../../views/elements/Field'; import AccessibleButton from '../../views/elements/AccessibleButton'; @@ -70,7 +69,6 @@ interface IState { flows: LoginFlow[]; } -@replaceableComponent("structures.auth.SoftLogout") export default class SoftLogout extends React.Component { public constructor(props: IProps) { super(props); diff --git a/src/components/views/audio_messages/AudioPlayer.tsx b/src/components/views/audio_messages/AudioPlayer.tsx index 84b96632f1..26055d1bb8 100644 --- a/src/components/views/audio_messages/AudioPlayer.tsx +++ b/src/components/views/audio_messages/AudioPlayer.tsx @@ -17,7 +17,6 @@ limitations under the License. import React, { createRef, ReactNode, RefObject } from "react"; import PlayPauseButton from "./PlayPauseButton"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { formatBytes } from "../../../utils/FormattingUtils"; import DurationClock from "./DurationClock"; import { _t } from "../../../languageHandler"; @@ -27,7 +26,6 @@ import AudioPlayerBase from "./AudioPlayerBase"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; -@replaceableComponent("views.audio_messages.AudioPlayer") export default class AudioPlayer extends AudioPlayerBase { private playPauseRef: RefObject = createRef(); private seekRef: RefObject = createRef(); diff --git a/src/components/views/audio_messages/AudioPlayerBase.tsx b/src/components/views/audio_messages/AudioPlayerBase.tsx index 1ce0ed1e95..52b9a79214 100644 --- a/src/components/views/audio_messages/AudioPlayerBase.tsx +++ b/src/components/views/audio_messages/AudioPlayerBase.tsx @@ -19,7 +19,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { Playback, PlaybackState } from "../../../audio/Playback"; import { UPDATE_EVENT } from "../../../stores/AsyncStore"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { _t } from "../../../languageHandler"; interface IProps { @@ -35,7 +34,6 @@ interface IState { error?: boolean; } -@replaceableComponent("views.audio_messages.AudioPlayerBase") export default abstract class AudioPlayerBase extends React.PureComponent { constructor(props: IProps) { super(props); diff --git a/src/components/views/audio_messages/Clock.tsx b/src/components/views/audio_messages/Clock.tsx index 13ffaa7d76..f978d8837c 100644 --- a/src/components/views/audio_messages/Clock.tsx +++ b/src/components/views/audio_messages/Clock.tsx @@ -17,7 +17,6 @@ limitations under the License. import React, { HTMLProps } from "react"; import { formatSeconds } from "../../../DateUtils"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; export interface IProps extends Pick, "aria-live"> { seconds: number; @@ -27,7 +26,6 @@ export interface IProps extends Pick, "aria-live"> { * Simply converts seconds into minutes and seconds. Note that hours will not be * displayed, making it possible to see "82:29". */ -@replaceableComponent("views.audio_messages.Clock") export default class Clock extends React.Component { public constructor(props) { super(props); diff --git a/src/components/views/audio_messages/DurationClock.tsx b/src/components/views/audio_messages/DurationClock.tsx index e0c180123a..47dc8e8375 100644 --- a/src/components/views/audio_messages/DurationClock.tsx +++ b/src/components/views/audio_messages/DurationClock.tsx @@ -16,7 +16,6 @@ limitations under the License. import React from "react"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Clock from "./Clock"; import { Playback } from "../../../audio/Playback"; @@ -31,7 +30,6 @@ interface IState { /** * A clock which shows a clip's maximum duration. */ -@replaceableComponent("views.audio_messages.DurationClock") export default class DurationClock extends React.PureComponent { public constructor(props) { super(props); diff --git a/src/components/views/audio_messages/LiveRecordingClock.tsx b/src/components/views/audio_messages/LiveRecordingClock.tsx index aa88d999be..34e4c559fe 100644 --- a/src/components/views/audio_messages/LiveRecordingClock.tsx +++ b/src/components/views/audio_messages/LiveRecordingClock.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from "react"; import { IRecordingUpdate, VoiceRecording } from "../../../audio/VoiceRecording"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Clock from "./Clock"; import { MarkedExecution } from "../../../utils/MarkedExecution"; @@ -32,7 +31,6 @@ interface IState { /** * A clock for a live recording. */ -@replaceableComponent("views.audio_messages.LiveRecordingClock") export default class LiveRecordingClock extends React.PureComponent { private seconds = 0; private scheduledUpdate = new MarkedExecution( diff --git a/src/components/views/audio_messages/LiveRecordingWaveform.tsx b/src/components/views/audio_messages/LiveRecordingWaveform.tsx index 13ba7b9f96..c9c122c98a 100644 --- a/src/components/views/audio_messages/LiveRecordingWaveform.tsx +++ b/src/components/views/audio_messages/LiveRecordingWaveform.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from "react"; import { IRecordingUpdate, RECORDING_PLAYBACK_SAMPLES, VoiceRecording } from "../../../audio/VoiceRecording"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { arrayFastResample, arraySeed } from "../../../utils/arrays"; import Waveform from "./Waveform"; import { MarkedExecution } from "../../../utils/MarkedExecution"; @@ -33,7 +32,6 @@ interface IState { /** * A waveform which shows the waveform of a live recording */ -@replaceableComponent("views.audio_messages.LiveRecordingWaveform") export default class LiveRecordingWaveform extends React.PureComponent { public static defaultProps = { progress: 1, diff --git a/src/components/views/audio_messages/PlayPauseButton.tsx b/src/components/views/audio_messages/PlayPauseButton.tsx index 5562a33ab5..1a2da04a38 100644 --- a/src/components/views/audio_messages/PlayPauseButton.tsx +++ b/src/components/views/audio_messages/PlayPauseButton.tsx @@ -17,7 +17,6 @@ limitations under the License. import React, { ReactNode } from "react"; import classNames from "classnames"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import { _t } from "../../../languageHandler"; import { Playback, PlaybackState } from "../../../audio/Playback"; @@ -35,7 +34,6 @@ interface IProps extends Omit { public constructor(props) { super(props); diff --git a/src/components/views/audio_messages/PlaybackClock.tsx b/src/components/views/audio_messages/PlaybackClock.tsx index c792d1c483..3f05ad0b89 100644 --- a/src/components/views/audio_messages/PlaybackClock.tsx +++ b/src/components/views/audio_messages/PlaybackClock.tsx @@ -16,7 +16,6 @@ limitations under the License. import React from "react"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Clock from "./Clock"; import { Playback, PlaybackState } from "../../../audio/Playback"; import { UPDATE_EVENT } from "../../../stores/AsyncStore"; @@ -39,7 +38,6 @@ interface IState { /** * A clock for a playback of a recording. */ -@replaceableComponent("views.audio_messages.PlaybackClock") export default class PlaybackClock extends React.PureComponent { public constructor(props) { super(props); diff --git a/src/components/views/audio_messages/PlaybackWaveform.tsx b/src/components/views/audio_messages/PlaybackWaveform.tsx index 70bf0ebeef..712044ca78 100644 --- a/src/components/views/audio_messages/PlaybackWaveform.tsx +++ b/src/components/views/audio_messages/PlaybackWaveform.tsx @@ -16,7 +16,6 @@ limitations under the License. import React from "react"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { arraySeed, arrayTrimFill } from "../../../utils/arrays"; import Waveform from "./Waveform"; import { Playback, PLAYBACK_WAVEFORM_SAMPLES } from "../../../audio/Playback"; @@ -34,7 +33,6 @@ interface IState { /** * A waveform which shows the waveform of a previously recorded recording */ -@replaceableComponent("views.audio_messages.PlaybackWaveform") export default class PlaybackWaveform extends React.PureComponent { public constructor(props) { super(props); diff --git a/src/components/views/audio_messages/RecordingPlayback.tsx b/src/components/views/audio_messages/RecordingPlayback.tsx index 05fca276fe..7440a6c57e 100644 --- a/src/components/views/audio_messages/RecordingPlayback.tsx +++ b/src/components/views/audio_messages/RecordingPlayback.tsx @@ -18,12 +18,10 @@ import React, { ReactNode } from "react"; import PlayPauseButton from "./PlayPauseButton"; import PlaybackClock from "./PlaybackClock"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import PlaybackWaveform from "./PlaybackWaveform"; import AudioPlayerBase from "./AudioPlayerBase"; import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext"; -@replaceableComponent("views.audio_messages.RecordingPlayback") export default class RecordingPlayback extends AudioPlayerBase { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/views/audio_messages/SeekBar.tsx b/src/components/views/audio_messages/SeekBar.tsx index 817f3e0452..d86d11c95e 100644 --- a/src/components/views/audio_messages/SeekBar.tsx +++ b/src/components/views/audio_messages/SeekBar.tsx @@ -17,7 +17,6 @@ limitations under the License. import React, { ChangeEvent, CSSProperties, ReactNode } from "react"; import { Playback, PlaybackState } from "../../../audio/Playback"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { MarkedExecution } from "../../../utils/MarkedExecution"; import { percentageOf } from "../../../utils/numbers"; @@ -43,7 +42,6 @@ interface ISeekCSS extends CSSProperties { const ARROW_SKIP_SECONDS = 5; // arbitrary -@replaceableComponent("views.audio_messages.SeekBar") export default class SeekBar extends React.PureComponent { // We use an animation frame request to avoid overly spamming prop updates, even if we aren't // really using anything demanding on the CSS front. diff --git a/src/components/views/audio_messages/Waveform.tsx b/src/components/views/audio_messages/Waveform.tsx index dedd95c7e1..deccc23ac6 100644 --- a/src/components/views/audio_messages/Waveform.tsx +++ b/src/components/views/audio_messages/Waveform.tsx @@ -17,8 +17,6 @@ limitations under the License. import React, { CSSProperties } from "react"; import classNames from "classnames"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - interface WaveformCSSProperties extends CSSProperties { '--barHeight': number; } @@ -39,7 +37,6 @@ interface IState { * For CSS purposes, a mx_Waveform_bar_100pct class is added when the bar should be * "filled", as a demonstration of the progress property. */ -@replaceableComponent("views.audio_messages.Waveform") export default class Waveform extends React.PureComponent { public static defaultProps = { progress: 1, diff --git a/src/components/views/auth/AuthBody.tsx b/src/components/views/auth/AuthBody.tsx index 22bb919141..4532ceeaf4 100644 --- a/src/components/views/auth/AuthBody.tsx +++ b/src/components/views/auth/AuthBody.tsx @@ -16,9 +16,6 @@ limitations under the License. import React from 'react'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - -@replaceableComponent("views.auth.AuthBody") export default class AuthBody extends React.PureComponent { public render(): React.ReactNode { return
diff --git a/src/components/views/auth/AuthFooter.tsx b/src/components/views/auth/AuthFooter.tsx index d936e346e6..46e389cb46 100644 --- a/src/components/views/auth/AuthFooter.tsx +++ b/src/components/views/auth/AuthFooter.tsx @@ -19,9 +19,7 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; -@replaceableComponent("views.auth.AuthFooter") export default class AuthFooter extends React.Component { public render(): React.ReactNode { return ( diff --git a/src/components/views/auth/AuthHeader.tsx b/src/components/views/auth/AuthHeader.tsx index 27768c9e6e..90e9e888af 100644 --- a/src/components/views/auth/AuthHeader.tsx +++ b/src/components/views/auth/AuthHeader.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from 'react'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AuthHeaderLogo from "./AuthHeaderLogo"; import LanguageSelector from "./LanguageSelector"; @@ -25,7 +24,6 @@ interface IProps { disableLanguageSelector?: boolean; } -@replaceableComponent("views.auth.AuthHeader") export default class AuthHeader extends React.Component { public render(): React.ReactNode { return ( diff --git a/src/components/views/auth/AuthHeaderLogo.tsx b/src/components/views/auth/AuthHeaderLogo.tsx index 29e5737238..72a2df7b83 100644 --- a/src/components/views/auth/AuthHeaderLogo.tsx +++ b/src/components/views/auth/AuthHeaderLogo.tsx @@ -16,9 +16,6 @@ limitations under the License. import React from 'react'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - -@replaceableComponent("views.auth.AuthHeaderLogo") export default class AuthHeaderLogo extends React.PureComponent { public render(): React.ReactNode { return
diff --git a/src/components/views/auth/AuthPage.tsx b/src/components/views/auth/AuthPage.tsx index d13c8dd6ae..344e890ebb 100644 --- a/src/components/views/auth/AuthPage.tsx +++ b/src/components/views/auth/AuthPage.tsx @@ -18,10 +18,8 @@ limitations under the License. import React from 'react'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AuthFooter from "./AuthFooter"; -@replaceableComponent("views.auth.AuthPage") export default class AuthPage extends React.PureComponent { public render(): React.ReactNode { return ( diff --git a/src/components/views/auth/CaptchaForm.tsx b/src/components/views/auth/CaptchaForm.tsx index 887f174c00..7f718bae6d 100644 --- a/src/components/views/auth/CaptchaForm.tsx +++ b/src/components/views/auth/CaptchaForm.tsx @@ -18,7 +18,6 @@ import React, { createRef } from 'react'; import { logger } from "matrix-js-sdk/src/logger"; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; const DIV_ID = 'mx_recaptcha'; @@ -35,7 +34,6 @@ interface ICaptchaFormState { /** * A pure UI component which displays a captcha form. */ -@replaceableComponent("views.auth.CaptchaForm") export default class CaptchaForm extends React.Component { static defaultProps = { onCaptchaResponse: () => {}, diff --git a/src/components/views/auth/CompleteSecurityBody.tsx b/src/components/views/auth/CompleteSecurityBody.tsx index 349016add5..ecc6eace7d 100644 --- a/src/components/views/auth/CompleteSecurityBody.tsx +++ b/src/components/views/auth/CompleteSecurityBody.tsx @@ -16,9 +16,6 @@ limitations under the License. import React from 'react'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - -@replaceableComponent("views.auth.CompleteSecurityBody") export default class CompleteSecurityBody extends React.PureComponent { public render(): React.ReactNode { return
diff --git a/src/components/views/auth/CountryDropdown.tsx b/src/components/views/auth/CountryDropdown.tsx index d4a3987ccb..0318c4b95d 100644 --- a/src/components/views/auth/CountryDropdown.tsx +++ b/src/components/views/auth/CountryDropdown.tsx @@ -19,7 +19,6 @@ import React from 'react'; import { COUNTRIES, getEmojiFlag, PhoneNumberCountryDefinition } from '../../../phonenumber'; import SdkConfig from "../../../SdkConfig"; import { _t } from "../../../languageHandler"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Dropdown from "../elements/Dropdown"; const COUNTRIES_BY_ISO2 = {}; @@ -53,7 +52,6 @@ interface IState { defaultCountry: PhoneNumberCountryDefinition; } -@replaceableComponent("views.auth.CountryDropdown") export default class CountryDropdown extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/auth/EmailField.tsx b/src/components/views/auth/EmailField.tsx index f274f1fdfa..2aa6204cfa 100644 --- a/src/components/views/auth/EmailField.tsx +++ b/src/components/views/auth/EmailField.tsx @@ -16,7 +16,6 @@ limitations under the License. import React, { PureComponent, RefCallback, RefObject } from "react"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Field, { IInputProps } from "../elements/Field"; import { _t, _td } from "../../../languageHandler"; import withValidation, { IFieldState, IValidationResult } from "../elements/Validation"; @@ -39,7 +38,6 @@ interface IProps extends Omit { onValidate?(result: IValidationResult): void; } -@replaceableComponent("views.auth.EmailField") class EmailField extends PureComponent { static defaultProps = { label: _td("Email"), diff --git a/src/components/views/auth/InteractiveAuthEntryComponents.tsx b/src/components/views/auth/InteractiveAuthEntryComponents.tsx index e4b9a7422e..11a28d1e05 100644 --- a/src/components/views/auth/InteractiveAuthEntryComponents.tsx +++ b/src/components/views/auth/InteractiveAuthEntryComponents.tsx @@ -24,7 +24,6 @@ import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import AccessibleButton from "../elements/AccessibleButton"; import Spinner from "../elements/Spinner"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { LocalisedPolicy, Policies } from '../../../Terms'; import Field from '../elements/Field'; import CaptchaForm from "./CaptchaForm"; @@ -93,7 +92,6 @@ interface IPasswordAuthEntryState { password: string; } -@replaceableComponent("views.auth.PasswordAuthEntry") export class PasswordAuthEntry extends React.Component { static LOGIN_TYPE = AuthType.Password; @@ -191,7 +189,6 @@ interface IRecaptchaAuthEntryProps extends IAuthEntryProps { } /* eslint-enable camelcase */ -@replaceableComponent("views.auth.RecaptchaAuthEntry") export class RecaptchaAuthEntry extends React.Component { static LOGIN_TYPE = AuthType.Recaptcha; @@ -262,7 +259,6 @@ interface ITermsAuthEntryState { errorText?: string; } -@replaceableComponent("views.auth.TermsAuthEntry") export class TermsAuthEntry extends React.Component { static LOGIN_TYPE = AuthType.Terms; @@ -409,7 +405,6 @@ interface IEmailIdentityAuthEntryProps extends IAuthEntryProps { }; } -@replaceableComponent("views.auth.EmailIdentityAuthEntry") export class EmailIdentityAuthEntry extends React.Component { static LOGIN_TYPE = AuthType.Email; @@ -472,7 +467,6 @@ interface IMsisdnAuthEntryState { errorText: string; } -@replaceableComponent("views.auth.MsisdnAuthEntry") export class MsisdnAuthEntry extends React.Component { static LOGIN_TYPE = AuthType.Msisdn; @@ -623,7 +617,6 @@ interface ISSOAuthEntryState { attemptFailed: boolean; } -@replaceableComponent("views.auth.SSOAuthEntry") export class SSOAuthEntry extends React.Component { static LOGIN_TYPE = AuthType.Sso; static UNSTABLE_LOGIN_TYPE = AuthType.SsoUnstable; @@ -743,7 +736,6 @@ export class SSOAuthEntry extends React.Component { private popupWindow: Window; private fallbackButton = createRef(); diff --git a/src/components/views/auth/PassphraseConfirmField.tsx b/src/components/views/auth/PassphraseConfirmField.tsx index 3a2b6f89b7..e30e25a00e 100644 --- a/src/components/views/auth/PassphraseConfirmField.tsx +++ b/src/components/views/auth/PassphraseConfirmField.tsx @@ -16,7 +16,6 @@ limitations under the License. import React, { PureComponent, RefCallback, RefObject } from "react"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Field, { IInputProps } from "../elements/Field"; import withValidation, { IFieldState, IValidationResult } from "../elements/Validation"; import { _t, _td } from "../../../languageHandler"; @@ -35,7 +34,6 @@ interface IProps extends Omit { onValidate?(result: IValidationResult); } -@replaceableComponent("views.auth.EmailField") class PassphraseConfirmField extends PureComponent { static defaultProps = { label: _td("Confirm password"), diff --git a/src/components/views/auth/PassphraseField.tsx b/src/components/views/auth/PassphraseField.tsx index 5a9aa0b85f..94353669ff 100644 --- a/src/components/views/auth/PassphraseField.tsx +++ b/src/components/views/auth/PassphraseField.tsx @@ -22,7 +22,6 @@ 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 { autoFocus?: boolean; @@ -41,7 +40,6 @@ interface IProps extends Omit { onValidate?(result: IValidationResult); } -@replaceableComponent("views.auth.PassphraseField") class PassphraseField extends PureComponent { static defaultProps = { label: _td("Password"), diff --git a/src/components/views/auth/PasswordLogin.tsx b/src/components/views/auth/PasswordLogin.tsx index 9142358674..db22393112 100644 --- a/src/components/views/auth/PasswordLogin.tsx +++ b/src/components/views/auth/PasswordLogin.tsx @@ -24,7 +24,6 @@ import AccessibleButton from "../elements/AccessibleButton"; import withValidation, { IValidationResult } from "../elements/Validation"; import Field from "../elements/Field"; import CountryDropdown from "./CountryDropdown"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import EmailField from "./EmailField"; // For validating phone numbers without country codes @@ -66,7 +65,6 @@ 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 { static defaultProps = { onUsernameChanged: function() {}, diff --git a/src/components/views/auth/RegistrationForm.tsx b/src/components/views/auth/RegistrationForm.tsx index 2665e1789f..b57ddf5009 100644 --- a/src/components/views/auth/RegistrationForm.tsx +++ b/src/components/views/auth/RegistrationForm.tsx @@ -31,7 +31,6 @@ import EmailField from "./EmailField"; import PassphraseField from "./PassphraseField"; import Field from '../elements/Field'; import RegistrationEmailPromptDialog from '../dialogs/RegistrationEmailPromptDialog'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import CountryDropdown from "./CountryDropdown"; import PassphraseConfirmField from "./PassphraseConfirmField"; @@ -92,7 +91,6 @@ interface IState { /* * A pure UI component which displays a registration form. */ -@replaceableComponent("views.auth.RegistrationForm") export default class RegistrationForm extends React.PureComponent { static defaultProps = { onValidationChange: logger.error, diff --git a/src/components/views/auth/Welcome.tsx b/src/components/views/auth/Welcome.tsx index 2ac974610b..ad35ee0186 100644 --- a/src/components/views/auth/Welcome.tsx +++ b/src/components/views/auth/Welcome.tsx @@ -23,7 +23,6 @@ import AuthPage from "./AuthPage"; import { _td } from "../../../languageHandler"; import SettingsStore from "../../../settings/SettingsStore"; import { UIFeature } from "../../../settings/UIFeature"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import LanguageSelector from "./LanguageSelector"; // translatable strings for Welcome pages @@ -33,7 +32,6 @@ interface IProps { } -@replaceableComponent("views.auth.Welcome") export default class Welcome extends React.PureComponent { public render(): React.ReactNode { // FIXME: Using an import will result in wrench-element-tests failures diff --git a/src/components/views/avatars/DecoratedRoomAvatar.tsx b/src/components/views/avatars/DecoratedRoomAvatar.tsx index dffd3cfbb4..06ee20cc08 100644 --- a/src/components/views/avatars/DecoratedRoomAvatar.tsx +++ b/src/components/views/avatars/DecoratedRoomAvatar.tsx @@ -32,7 +32,6 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { _t } from "../../../languageHandler"; import TextWithTooltip from "../elements/TextWithTooltip"; import DMRoomMap from "../../../utils/DMRoomMap"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IOOBData } from "../../../stores/ThreepidInviteStore"; import TooltipTarget from "../elements/TooltipTarget"; @@ -78,7 +77,6 @@ function tooltipText(variant: Icon) { } } -@replaceableComponent("views.avatars.DecoratedRoomAvatar") export default class DecoratedRoomAvatar extends React.PureComponent { private _dmUser: User; private isUnmounted = false; diff --git a/src/components/views/avatars/MemberAvatar.tsx b/src/components/views/avatars/MemberAvatar.tsx index e00b9b4b85..5b25f51cd5 100644 --- a/src/components/views/avatars/MemberAvatar.tsx +++ b/src/components/views/avatars/MemberAvatar.tsx @@ -23,7 +23,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import dis from "../../../dispatcher/dispatcher"; import { Action } from "../../../dispatcher/actions"; import BaseAvatar from "./BaseAvatar"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; import { CardContext } from '../right_panel/BaseCard'; import UserIdentifierCustomisations from '../../../customisations/UserIdentifier'; @@ -52,7 +51,6 @@ interface IState { imageUrl?: string; } -@replaceableComponent("views.avatars.MemberAvatar") export default class MemberAvatar extends React.PureComponent { public static defaultProps = { width: 40, diff --git a/src/components/views/avatars/RoomAvatar.tsx b/src/components/views/avatars/RoomAvatar.tsx index 9625b64138..f50232fb22 100644 --- a/src/components/views/avatars/RoomAvatar.tsx +++ b/src/components/views/avatars/RoomAvatar.tsx @@ -28,7 +28,6 @@ import { MatrixClientPeg } from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; import * as Avatar from '../../../Avatar'; import DMRoomMap from "../../../utils/DMRoomMap"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; import { IOOBData } from '../../../stores/ThreepidInviteStore'; @@ -52,7 +51,6 @@ interface IState { urls: string[]; } -@replaceableComponent("views.avatars.RoomAvatar") export default class RoomAvatar extends React.Component { public static defaultProps = { width: 36, diff --git a/src/components/views/context_menus/CallContextMenu.tsx b/src/components/views/context_menus/CallContextMenu.tsx index ec835d1e31..8c9e07dfcc 100644 --- a/src/components/views/context_menus/CallContextMenu.tsx +++ b/src/components/views/context_menus/CallContextMenu.tsx @@ -21,13 +21,11 @@ import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; import { _t } from '../../../languageHandler'; import ContextMenu, { IProps as IContextMenuProps, MenuItem } from '../../structures/ContextMenu'; import CallHandler from '../../../CallHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps extends IContextMenuProps { call: MatrixCall; } -@replaceableComponent("views.context_menus.CallContextMenu") export default class CallContextMenu extends React.Component { 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 70a5aae2e8..f6530452d0 100644 --- a/src/components/views/context_menus/DialpadContextMenu.tsx +++ b/src/components/views/context_menus/DialpadContextMenu.tsx @@ -22,7 +22,6 @@ import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; import ContextMenu, { IProps as IContextMenuProps } from '../../structures/ContextMenu'; import Field from "../elements/Field"; import DialPad from '../voip/DialPad'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps extends IContextMenuProps { call: MatrixCall; @@ -32,7 +31,6 @@ interface IState { value: string; } -@replaceableComponent("views.context_menus.DialpadContextMenu") export default class DialpadContextMenu extends React.Component { private numberEntryFieldRef: React.RefObject = createRef(); diff --git a/src/components/views/context_menus/GenericElementContextMenu.tsx b/src/components/views/context_menus/GenericElementContextMenu.tsx index d5ebfca26e..7b53dc0ed9 100644 --- a/src/components/views/context_menus/GenericElementContextMenu.tsx +++ b/src/components/views/context_menus/GenericElementContextMenu.tsx @@ -16,8 +16,6 @@ limitations under the License. import React from 'react'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - interface IProps { element: React.ReactNode; // Function to be called when the parent window is resized @@ -30,7 +28,6 @@ interface IProps { * This component can be used to display generic HTML content in a contextual * menu. */ -@replaceableComponent("views.context_menus.GenericElementContextMenu") export default class GenericElementContextMenu extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/context_menus/GenericTextContextMenu.tsx b/src/components/views/context_menus/GenericTextContextMenu.tsx index d25c708622..0f6cc708a1 100644 --- a/src/components/views/context_menus/GenericTextContextMenu.tsx +++ b/src/components/views/context_menus/GenericTextContextMenu.tsx @@ -16,13 +16,10 @@ limitations under the License. import React from 'react'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - interface IProps { message: string; } -@replaceableComponent("views.context_menus.GenericTextContextMenu") export default class GenericTextContextMenu extends React.Component { public render(): JSX.Element { return
diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx index 8899c13a60..5adbcb9a9d 100644 --- a/src/components/views/context_menus/MessageContextMenu.tsx +++ b/src/components/views/context_menus/MessageContextMenu.tsx @@ -32,7 +32,6 @@ import SettingsStore from '../../../settings/SettingsStore'; import { isUrlPermitted } from '../../../HtmlUtils'; import { isContentActionable } from '../../../utils/EventUtils'; import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from './IconizedContextMenu'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { ReadPinsEventId } from "../right_panel/PinnedMessagesCard"; import ForwardDialog from "../dialogs/ForwardDialog"; import { Action } from "../../../dispatcher/actions"; @@ -88,7 +87,6 @@ interface IState { canPin: boolean; } -@replaceableComponent("views.context_menus.MessageContextMenu") export default class MessageContextMenu extends React.Component { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/views/dialogs/AskInviteAnywayDialog.tsx b/src/components/views/dialogs/AskInviteAnywayDialog.tsx index 1815a43d57..bd691a1ed4 100644 --- a/src/components/views/dialogs/AskInviteAnywayDialog.tsx +++ b/src/components/views/dialogs/AskInviteAnywayDialog.tsx @@ -19,7 +19,6 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import { SettingLevel } from "../../../settings/SettingLevel"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; interface IProps { @@ -32,7 +31,6 @@ interface IProps { onFinished: (success: boolean) => void; } -@replaceableComponent("views.dialogs.AskInviteAnywayDialog") export default class AskInviteAnywayDialog extends React.Component { private onInviteClicked = (): void => { this.props.onInviteAnyways(); diff --git a/src/components/views/dialogs/BaseDialog.tsx b/src/components/views/dialogs/BaseDialog.tsx index 519e38601c..5eb0c6ac82 100644 --- a/src/components/views/dialogs/BaseDialog.tsx +++ b/src/components/views/dialogs/BaseDialog.tsx @@ -25,7 +25,6 @@ import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { _t } from "../../../languageHandler"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Heading from '../typography/Heading'; import { IDialogProps } from "./IDialogProps"; import { PosthogScreenTracker, ScreenName } from "../../../PosthogTrackers"; @@ -81,7 +80,6 @@ interface IProps extends IDialogProps { * 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 { private matrixClient: MatrixClient; diff --git a/src/components/views/dialogs/BugReportDialog.tsx b/src/components/views/dialogs/BugReportDialog.tsx index 2fa3f3b33f..eae2673521 100644 --- a/src/components/views/dialogs/BugReportDialog.tsx +++ b/src/components/views/dialogs/BugReportDialog.tsx @@ -24,7 +24,6 @@ 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"; import QuestionDialog from "./QuestionDialog"; import BaseDialog from "./BaseDialog"; import Field from '../elements/Field'; @@ -50,7 +49,6 @@ interface IState { downloadProgress: string; } -@replaceableComponent("views.dialogs.BugReportDialog") export default class BugReportDialog extends React.Component { private unmounted: boolean; diff --git a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx index fbf603c44d..f56f4f6194 100644 --- a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx +++ b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import ConfirmRedactDialog from './ConfirmRedactDialog'; import ErrorDialog from './ErrorDialog'; import BaseDialog from "./BaseDialog"; @@ -45,7 +44,6 @@ interface IState { * * 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.tsx b/src/components/views/dialogs/ConfirmRedactDialog.tsx index 6839c0f7bd..9a9f3627d2 100644 --- a/src/components/views/dialogs/ConfirmRedactDialog.tsx +++ b/src/components/views/dialogs/ConfirmRedactDialog.tsx @@ -20,7 +20,6 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import ErrorDialog from './ErrorDialog'; import TextInputDialog from "./TextInputDialog"; @@ -31,7 +30,6 @@ interface IProps { /* * A dialog for confirming a redaction. */ -@replaceableComponent("views.dialogs.ConfirmRedactDialog") export default class ConfirmRedactDialog extends React.Component { render() { return ( diff --git a/src/components/views/dialogs/ConfirmUserActionDialog.tsx b/src/components/views/dialogs/ConfirmUserActionDialog.tsx index c10ead0b72..8a41c8f2de 100644 --- a/src/components/views/dialogs/ConfirmUserActionDialog.tsx +++ b/src/components/views/dialogs/ConfirmUserActionDialog.tsx @@ -19,7 +19,6 @@ import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import classNames from "classnames"; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import MemberAvatar from '../avatars/MemberAvatar'; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; @@ -55,7 +54,6 @@ interface IState { * 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 defaultProps = { danger: false, diff --git a/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx b/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx index 33e26ff7a7..a61b47c04f 100644 --- a/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx +++ b/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from 'react'; import { _t } from "../../../languageHandler"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; @@ -25,7 +24,6 @@ interface IProps { onFinished: (success: boolean) => void; } -@replaceableComponent("views.dialogs.ConfirmWipeDeviceDialog") export default class ConfirmWipeDeviceDialog extends React.Component { private onConfirm = (): void => { this.props.onFinished(true); diff --git a/src/components/views/dialogs/CreateRoomDialog.tsx b/src/components/views/dialogs/CreateRoomDialog.tsx index 4b7b0caa8f..da6d0212f3 100644 --- a/src/components/views/dialogs/CreateRoomDialog.tsx +++ b/src/components/views/dialogs/CreateRoomDialog.tsx @@ -26,7 +26,6 @@ import withValidation, { IFieldState } from '../elements/Validation'; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { IOpts, privateShouldBeEncrypted } from "../../../createRoom"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Heading from "../typography/Heading"; import Field from "../elements/Field"; import StyledRadioGroup from "../elements/StyledRadioGroup"; @@ -61,7 +60,6 @@ interface IState { canChangeEncryption: boolean; } -@replaceableComponent("views.dialogs.CreateRoomDialog") export default class CreateRoomDialog extends React.Component { private readonly supportsRestricted: boolean; private nameField = createRef(); diff --git a/src/components/views/dialogs/DeactivateAccountDialog.tsx b/src/components/views/dialogs/DeactivateAccountDialog.tsx index aece59ef84..bf2f636d5d 100644 --- a/src/components/views/dialogs/DeactivateAccountDialog.tsx +++ b/src/components/views/dialogs/DeactivateAccountDialog.tsx @@ -26,7 +26,6 @@ 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"; import BaseDialog from "./BaseDialog"; interface IProps { @@ -46,7 +45,6 @@ interface IState { continueKind: string; } -@replaceableComponent("views.dialogs.DeactivateAccountDialog") export default class DeactivateAccountDialog extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/dialogs/ErrorDialog.tsx b/src/components/views/dialogs/ErrorDialog.tsx index e19d93f918..286124c6bf 100644 --- a/src/components/views/dialogs/ErrorDialog.tsx +++ b/src/components/views/dialogs/ErrorDialog.tsx @@ -28,7 +28,6 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; interface IProps { @@ -44,7 +43,6 @@ interface IState { onFinished: (success: boolean) => void; } -@replaceableComponent("views.dialogs.ErrorDialog") export default class ErrorDialog extends React.Component { public static defaultProps = { focus: true, diff --git a/src/components/views/dialogs/HostSignupDialog.tsx b/src/components/views/dialogs/HostSignupDialog.tsx index 5f82ba8086..91c29c68d1 100644 --- a/src/components/views/dialogs/HostSignupDialog.tsx +++ b/src/components/views/dialogs/HostSignupDialog.tsx @@ -32,7 +32,6 @@ import { IPostmessageResponseData, PostmessageAction, } from "./HostSignupDialogTypes"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IConfigOptions } from "../../../IConfigOptions"; import { SnakedObject } from "../../../utils/SnakedObject"; @@ -46,7 +45,6 @@ interface IState { minimized: boolean; } -@replaceableComponent("views.dialogs.HostSignupDialog") export default class HostSignupDialog extends React.PureComponent { private iframeRef: React.RefObject = React.createRef(); private readonly config: SnakedObject; diff --git a/src/components/views/dialogs/IncomingSasDialog.tsx b/src/components/views/dialogs/IncomingSasDialog.tsx index d856412c67..2b15749c8d 100644 --- a/src/components/views/dialogs/IncomingSasDialog.tsx +++ b/src/components/views/dialogs/IncomingSasDialog.tsx @@ -21,7 +21,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; import VerificationComplete from "../verification/VerificationComplete"; import VerificationCancelled from "../verification/VerificationCancelled"; @@ -54,7 +53,6 @@ interface IState { sas: IGeneratedSas; } -@replaceableComponent("views.dialogs.IncomingSasDialog") export default class IncomingSasDialog extends React.Component { private showSasEvent: ISasEvent; diff --git a/src/components/views/dialogs/IntegrationsDisabledDialog.tsx b/src/components/views/dialogs/IntegrationsDisabledDialog.tsx index d5c08211da..a48d808fed 100644 --- a/src/components/views/dialogs/IntegrationsDisabledDialog.tsx +++ b/src/components/views/dialogs/IntegrationsDisabledDialog.tsx @@ -19,14 +19,12 @@ import React from 'react'; import { _t } from "../../../languageHandler"; import dis from '../../../dispatcher/dispatcher'; import { Action } from "../../../dispatcher/actions"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; import { IDialogProps } from "./IDialogProps"; interface IProps extends IDialogProps {} -@replaceableComponent("views.dialogs.IntegrationsDisabledDialog") export default class IntegrationsDisabledDialog extends React.Component { private onAcknowledgeClick = (): void => { this.props.onFinished(); diff --git a/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx b/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx index 0e7db93c53..73c7fbc629 100644 --- a/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx +++ b/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx @@ -18,14 +18,12 @@ import React from 'react'; import { _t } from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IDialogProps } from "./IDialogProps"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; interface IProps extends IDialogProps {} -@replaceableComponent("views.dialogs.IntegrationsImpossibleDialog") export default class IntegrationsImpossibleDialog extends React.Component { private onAcknowledgeClick = (): void => { this.props.onFinished(); diff --git a/src/components/views/dialogs/InteractiveAuthDialog.tsx b/src/components/views/dialogs/InteractiveAuthDialog.tsx index c6a7d414bf..46bad5fd0e 100644 --- a/src/components/views/dialogs/InteractiveAuthDialog.tsx +++ b/src/components/views/dialogs/InteractiveAuthDialog.tsx @@ -24,7 +24,6 @@ import { _t } from '../../../languageHandler'; import AccessibleButton from '../elements/AccessibleButton'; import InteractiveAuth, { ERROR_USER_CANCELLED } from "../../structures/InteractiveAuth"; import { SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import { IDialogProps } from "./IDialogProps"; @@ -83,7 +82,6 @@ interface IState { uiaStagePhase: number | string; } -@replaceableComponent("views.dialogs.InteractiveAuthDialog") export default class InteractiveAuthDialog extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index 36b2bd54e2..cf58a372ba 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -49,7 +49,6 @@ import { DefaultTagID } from "../../../stores/room-list/models"; import RoomListStore from "../../../stores/room-list/RoomListStore"; import SettingsStore from "../../../settings/SettingsStore"; import { UIFeature } from "../../../settings/UIFeature"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; import { getAddressType } from "../../../UserAddress"; import BaseAvatar from '../avatars/BaseAvatar'; @@ -387,7 +386,6 @@ interface IInviteDialogState { errorText: string; } -@replaceableComponent("views.dialogs.InviteDialog") export default class InviteDialog extends React.PureComponent { static defaultProps = { kind: KIND_DM, diff --git a/src/components/views/dialogs/LogoutDialog.tsx b/src/components/views/dialogs/LogoutDialog.tsx index cca6935258..4131d7d455 100644 --- a/src/components/views/dialogs/LogoutDialog.tsx +++ b/src/components/views/dialogs/LogoutDialog.tsx @@ -24,7 +24,6 @@ import dis from '../../../dispatcher/dispatcher'; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import RestoreKeyBackupDialog from './security/RestoreKeyBackupDialog'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import QuestionDialog from "./QuestionDialog"; import BaseDialog from "./BaseDialog"; import Spinner from "../elements/Spinner"; @@ -41,7 +40,6 @@ interface IState { error?: string; } -@replaceableComponent("views.dialogs.LogoutDialog") export default class LogoutDialog extends React.Component { static defaultProps = { onFinished: function() {}, diff --git a/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.tsx b/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.tsx index 6b94eb9c7a..ef5a40a8b0 100644 --- a/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.tsx +++ b/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.tsx @@ -24,7 +24,6 @@ import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo"; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import * as FormattingUtils from '../../../utils/FormattingUtils'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import QuestionDialog from "./QuestionDialog"; import { IDialogProps } from "./IDialogProps"; @@ -33,7 +32,6 @@ interface IProps extends IDialogProps { device: DeviceInfo; } -@replaceableComponent("views.dialogs.ManualDeviceKeyVerificationDialog") export default class ManualDeviceKeyVerificationDialog extends React.Component { private onLegacyFinished = (confirm: boolean): void => { if (confirm) { diff --git a/src/components/views/dialogs/MessageEditHistoryDialog.tsx b/src/components/views/dialogs/MessageEditHistoryDialog.tsx index 2a9e02cc04..2dedfb5293 100644 --- a/src/components/views/dialogs/MessageEditHistoryDialog.tsx +++ b/src/components/views/dialogs/MessageEditHistoryDialog.tsx @@ -25,7 +25,6 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { _t } from '../../../languageHandler'; import { wantsDateSeparator } from '../../../DateUtils'; import SettingsStore from '../../../settings/SettingsStore'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import ScrollPanel from "../../structures/ScrollPanel"; import Spinner from "../elements/Spinner"; @@ -48,7 +47,6 @@ interface IState { isTwelveHour: boolean; } -@replaceableComponent("views.dialogs.MessageEditHistoryDialog") export default class MessageEditHistoryDialog extends React.PureComponent { constructor(props: IProps) { super(props); diff --git a/src/components/views/dialogs/ModalWidgetDialog.tsx b/src/components/views/dialogs/ModalWidgetDialog.tsx index 95e873cada..84564c22cf 100644 --- a/src/components/views/dialogs/ModalWidgetDialog.tsx +++ b/src/components/views/dialogs/ModalWidgetDialog.tsx @@ -39,7 +39,6 @@ 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"; import { ELEMENT_CLIENT_ID } from "../../../identifiers"; import SettingsStore from "../../../settings/SettingsStore"; @@ -57,7 +56,6 @@ interface IState { const MAX_BUTTONS = 3; -@replaceableComponent("views.dialogs.ModalWidgetDialog") export default class ModalWidgetDialog extends React.PureComponent { private readonly widget: Widget; private readonly possibleButtons: ModalButtonID[]; diff --git a/src/components/views/dialogs/ReportEventDialog.tsx b/src/components/views/dialogs/ReportEventDialog.tsx index af09e55ee6..94102f7b12 100644 --- a/src/components/views/dialogs/ReportEventDialog.tsx +++ b/src/components/views/dialogs/ReportEventDialog.tsx @@ -23,7 +23,6 @@ import { IDialogProps } from "./IDialogProps"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import SdkConfig from '../../../SdkConfig'; import Markdown from '../../../Markdown'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import SettingsStore from "../../../settings/SettingsStore"; import StyledRadioButton from "../elements/StyledRadioButton"; import BaseDialog from "./BaseDialog"; @@ -89,7 +88,6 @@ type Moderation = { * a well-formed state event `m.room.moderation.moderated_by` * /`org.matrix.msc3215.room.moderation.moderated_by`? */ -@replaceableComponent("views.dialogs.ReportEventDialog") export default class ReportEventDialog extends React.Component { // If the room supports moderation, the moderation information. private moderation?: Moderation; diff --git a/src/components/views/dialogs/RoomSettingsDialog.tsx b/src/components/views/dialogs/RoomSettingsDialog.tsx index 3806e9288c..ce8d24cd3f 100644 --- a/src/components/views/dialogs/RoomSettingsDialog.tsx +++ b/src/components/views/dialogs/RoomSettingsDialog.tsx @@ -30,7 +30,6 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg"; import dis from "../../../dispatcher/dispatcher"; import SettingsStore from "../../../settings/SettingsStore"; import { UIFeature } from "../../../settings/UIFeature"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import { Action } from '../../../dispatcher/actions'; @@ -51,7 +50,6 @@ interface IState { roomName: string; } -@replaceableComponent("views.dialogs.RoomSettingsDialog") export default class RoomSettingsDialog extends React.Component { private dispatcherRef: string; diff --git a/src/components/views/dialogs/RoomUpgradeDialog.tsx b/src/components/views/dialogs/RoomUpgradeDialog.tsx index bcca0e3829..8ff2181d75 100644 --- a/src/components/views/dialogs/RoomUpgradeDialog.tsx +++ b/src/components/views/dialogs/RoomUpgradeDialog.tsx @@ -19,7 +19,6 @@ import { Room } from "matrix-js-sdk/src/models/room"; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { upgradeRoom } from "../../../utils/RoomUpgrade"; import { IDialogProps } from "./IDialogProps"; import BaseDialog from "./BaseDialog"; @@ -35,7 +34,6 @@ interface IState { busy: boolean; } -@replaceableComponent("views.dialogs.RoomUpgradeDialog") export default class RoomUpgradeDialog extends React.Component { private targetVersion: string; diff --git a/src/components/views/dialogs/RoomUpgradeWarningDialog.tsx b/src/components/views/dialogs/RoomUpgradeWarningDialog.tsx index 0da8fb97d3..a34674ff63 100644 --- a/src/components/views/dialogs/RoomUpgradeWarningDialog.tsx +++ b/src/components/views/dialogs/RoomUpgradeWarningDialog.tsx @@ -23,7 +23,6 @@ import SdkConfig from "../../../SdkConfig"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import Modal from "../../../Modal"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IDialogProps } from "./IDialogProps"; import BugReportDialog from './BugReportDialog'; import BaseDialog from "./BaseDialog"; @@ -50,7 +49,6 @@ interface IState { total?: number; } -@replaceableComponent("views.dialogs.RoomUpgradeWarningDialog") export default class RoomUpgradeWarningDialog extends React.Component { private readonly isPrivate: boolean; private readonly currentVersion: string; diff --git a/src/components/views/dialogs/ServerOfflineDialog.tsx b/src/components/views/dialogs/ServerOfflineDialog.tsx index 6cf07f6bd6..de068d9a79 100644 --- a/src/components/views/dialogs/ServerOfflineDialog.tsx +++ b/src/components/views/dialogs/ServerOfflineDialog.tsx @@ -29,12 +29,10 @@ 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 { 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 b1433978dd..0761bb6b9d 100644 --- a/src/components/views/dialogs/ServerPickerDialog.tsx +++ b/src/components/views/dialogs/ServerPickerDialog.tsx @@ -27,7 +27,6 @@ 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; @@ -40,7 +39,6 @@ interface IState { otherHomeserver: string; } -@replaceableComponent("views.dialogs.ServerPickerDialog") export default class ServerPickerDialog extends React.PureComponent { private readonly defaultServer: ValidatedServerConfig; private readonly fieldRef = createRef(); diff --git a/src/components/views/dialogs/SeshatResetDialog.tsx b/src/components/views/dialogs/SeshatResetDialog.tsx index 1c048dd9fa..369106188b 100644 --- a/src/components/views/dialogs/SeshatResetDialog.tsx +++ b/src/components/views/dialogs/SeshatResetDialog.tsx @@ -17,12 +17,10 @@ limitations under the License. import React from 'react'; import { _t } from "../../../languageHandler"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; import { IDialogProps } from "./IDialogProps"; -@replaceableComponent("views.dialogs.SeshatResetDialog") export default class SeshatResetDialog extends React.PureComponent { render() { return ( diff --git a/src/components/views/dialogs/SessionRestoreErrorDialog.tsx b/src/components/views/dialogs/SessionRestoreErrorDialog.tsx index ad0c8e939a..72b35671ba 100644 --- a/src/components/views/dialogs/SessionRestoreErrorDialog.tsx +++ b/src/components/views/dialogs/SessionRestoreErrorDialog.tsx @@ -21,7 +21,6 @@ import React from 'react'; import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import QuestionDialog from "./QuestionDialog"; import BugReportDialog from "./BugReportDialog"; import BaseDialog from "./BaseDialog"; @@ -32,7 +31,6 @@ interface IProps extends IDialogProps { error: Error; } -@replaceableComponent("views.dialogs.SessionRestoreErrorDialog") export default class SessionRestoreErrorDialog extends React.Component { private sendBugReport = (): void => { Modal.createTrackedDialog('Session Restore Error', 'Send Bug Report Dialog', BugReportDialog, { diff --git a/src/components/views/dialogs/SetEmailDialog.tsx b/src/components/views/dialogs/SetEmailDialog.tsx index 6e5f0cf050..773f56db02 100644 --- a/src/components/views/dialogs/SetEmailDialog.tsx +++ b/src/components/views/dialogs/SetEmailDialog.tsx @@ -22,7 +22,6 @@ import * as Email from '../../../email'; import AddThreepid from '../../../AddThreepid'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Spinner from "../elements/Spinner"; import ErrorDialog from "./ErrorDialog"; import QuestionDialog from "./QuestionDialog"; @@ -44,7 +43,6 @@ interface IState { * * On success, `onFinished(true)` is called. */ -@replaceableComponent("views.dialogs.SetEmailDialog") export default class SetEmailDialog extends React.Component { private addThreepid: AddThreepid; diff --git a/src/components/views/dialogs/ShareDialog.tsx b/src/components/views/dialogs/ShareDialog.tsx index a411c18571..cb06d09d80 100644 --- a/src/components/views/dialogs/ShareDialog.tsx +++ b/src/components/views/dialogs/ShareDialog.tsx @@ -29,7 +29,6 @@ import StyledCheckbox from '../elements/StyledCheckbox'; import { IDialogProps } from "./IDialogProps"; import SettingsStore from "../../../settings/SettingsStore"; import { UIFeature } from "../../../settings/UIFeature"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import CopyableText from "../elements/CopyableText"; @@ -71,7 +70,6 @@ interface IState { permalinkCreator: RoomPermalinkCreator; } -@replaceableComponent("views.dialogs.ShareDialog") export default class ShareDialog extends React.PureComponent { protected closeCopiedTooltip: () => void; diff --git a/src/components/views/dialogs/StorageEvictedDialog.tsx b/src/components/views/dialogs/StorageEvictedDialog.tsx index acbb62b43d..cd01fef2b8 100644 --- a/src/components/views/dialogs/StorageEvictedDialog.tsx +++ b/src/components/views/dialogs/StorageEvictedDialog.tsx @@ -19,7 +19,6 @@ import React from 'react'; import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; import BugReportDialog from "./BugReportDialog"; @@ -28,7 +27,6 @@ import AccessibleButton from '../elements/AccessibleButton'; interface IProps extends IDialogProps { } -@replaceableComponent("views.dialogs.StorageEvictedDialog") export default class StorageEvictedDialog extends React.Component { private sendBugReport = (ev: React.MouseEvent): void => { ev.preventDefault(); diff --git a/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx b/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx index 7ab425a5f6..5a5d6e3822 100644 --- a/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx +++ b/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx @@ -22,7 +22,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { IntegrationManagers } from "../../../integrations/IntegrationManagers"; import { dialogTermsInteractionCallback, TermsNotSignedError } from "../../../Terms"; import * as ScalarMessaging from "../../../ScalarMessaging"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IntegrationManagerInstance } from "../../../integrations/IntegrationManagerInstance"; import ScalarAuthClient from "../../../ScalarAuthClient"; import AccessibleButton from "../elements/AccessibleButton"; @@ -55,7 +54,6 @@ interface IState { currentScalarClient: ScalarAuthClient; } -@replaceableComponent("views.dialogs.TabbedIntegrationManagerDialog") export default class TabbedIntegrationManagerDialog extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/dialogs/TermsDialog.tsx b/src/components/views/dialogs/TermsDialog.tsx index f2f713a75f..aa3825ab3d 100644 --- a/src/components/views/dialogs/TermsDialog.tsx +++ b/src/components/views/dialogs/TermsDialog.tsx @@ -19,7 +19,6 @@ import React from 'react'; import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types"; import { _t, pickBestLanguage } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import DialogButtons from "../elements/DialogButtons"; import BaseDialog from "./BaseDialog"; @@ -66,7 +65,6 @@ interface IState { agreedUrls: any; } -@replaceableComponent("views.dialogs.TermsDialog") export default class TermsDialog extends React.PureComponent { constructor(props) { super(props); diff --git a/src/components/views/dialogs/TextInputDialog.tsx b/src/components/views/dialogs/TextInputDialog.tsx index 2667c131b9..7a13fd3d45 100644 --- a/src/components/views/dialogs/TextInputDialog.tsx +++ b/src/components/views/dialogs/TextInputDialog.tsx @@ -18,7 +18,6 @@ import React, { ChangeEvent, createRef } from 'react'; import Field from "../elements/Field"; import { _t, _td } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IFieldState, IValidationResult } from "../elements/Validation"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; @@ -43,7 +42,6 @@ interface IState { valid: boolean; } -@replaceableComponent("views.dialogs.TextInputDialog") export default class TextInputDialog extends React.Component { private field = createRef(); diff --git a/src/components/views/dialogs/UploadConfirmDialog.tsx b/src/components/views/dialogs/UploadConfirmDialog.tsx index 0b6c4d0add..c705da1ac3 100644 --- a/src/components/views/dialogs/UploadConfirmDialog.tsx +++ b/src/components/views/dialogs/UploadConfirmDialog.tsx @@ -19,7 +19,6 @@ import React from 'react'; import filesize from "filesize"; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { getBlobSafeMimeType } from '../../../utils/blobs'; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; @@ -31,7 +30,6 @@ interface IProps { onFinished: (uploadConfirmed: boolean, uploadAll?: boolean) => void; } -@replaceableComponent("views.dialogs.UploadConfirmDialog") export default class UploadConfirmDialog extends React.Component { private readonly objectUrl: string; private readonly mimeType: string; diff --git a/src/components/views/dialogs/UploadFailureDialog.tsx b/src/components/views/dialogs/UploadFailureDialog.tsx index 8226a82170..8a25671ea0 100644 --- a/src/components/views/dialogs/UploadFailureDialog.tsx +++ b/src/components/views/dialogs/UploadFailureDialog.tsx @@ -19,7 +19,6 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import ContentMessages from '../../../ContentMessages'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; import { IDialogProps } from "./IDialogProps"; @@ -35,7 +34,6 @@ interface IProps extends IDialogProps { * 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 { private onCancelClick = (): void => { this.props.onFinished(false); diff --git a/src/components/views/dialogs/UserSettingsDialog.tsx b/src/components/views/dialogs/UserSettingsDialog.tsx index ab25f689f2..a170b71929 100644 --- a/src/components/views/dialogs/UserSettingsDialog.tsx +++ b/src/components/views/dialogs/UserSettingsDialog.tsx @@ -31,7 +31,6 @@ import HelpUserSettingsTab from "../settings/tabs/user/HelpUserSettingsTab"; import SdkConfig from "../../../SdkConfig"; import MjolnirUserSettingsTab from "../settings/tabs/user/MjolnirUserSettingsTab"; import { UIFeature } from "../../../settings/UIFeature"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import { IDialogProps } from "./IDialogProps"; import SidebarUserSettingsTab from "../settings/tabs/user/SidebarUserSettingsTab"; @@ -59,7 +58,6 @@ interface IState { mjolnirEnabled: boolean; } -@replaceableComponent("views.dialogs.UserSettingsDialog") export default class UserSettingsDialog extends React.Component { private mjolnirWatcher: string; diff --git a/src/components/views/dialogs/VerificationRequestDialog.tsx b/src/components/views/dialogs/VerificationRequestDialog.tsx index f73cda91f4..8830ee29f7 100644 --- a/src/components/views/dialogs/VerificationRequestDialog.tsx +++ b/src/components/views/dialogs/VerificationRequestDialog.tsx @@ -20,7 +20,6 @@ import { User } from 'matrix-js-sdk/src/models/user'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import EncryptionPanel from "../right_panel/EncryptionPanel"; @@ -35,7 +34,6 @@ interface IState { verificationRequest: VerificationRequest; } -@replaceableComponent("views.dialogs.VerificationRequestDialog") export default class VerificationRequestDialog extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx b/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx index b794592b2f..17be7d4150 100644 --- a/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx +++ b/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx @@ -32,7 +32,6 @@ 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"; interface IProps extends IDialogProps { requestedCapabilities: Set; @@ -50,7 +49,6 @@ interface IState { rememberSelection: boolean; } -@replaceableComponent("views.dialogs.WidgetCapabilitiesPromptDialog") export default class WidgetCapabilitiesPromptDialog extends React.PureComponent { private eventPermissionsMap = new Map(); diff --git a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx index 4faf4e5237..68c2991ed8 100644 --- a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx +++ b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx @@ -22,7 +22,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { _t } from "../../../languageHandler"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import { OIDCState, WidgetPermissionStore } from "../../../stores/widgets/WidgetPermissionStore"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IDialogProps } from "./IDialogProps"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; @@ -37,7 +36,6 @@ interface IState { rememberSelection: boolean; } -@replaceableComponent("views.dialogs.WidgetOpenIDPermissionsDialog") export default class WidgetOpenIDPermissionsDialog extends React.PureComponent { constructor(props: IProps) { super(props); diff --git a/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.tsx b/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.tsx index 3496d00fea..e5d2aee926 100644 --- a/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.tsx +++ b/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from 'react'; import { _t } from "../../../../languageHandler"; -import { replaceableComponent } from "../../../../utils/replaceableComponent"; import BaseDialog from "../BaseDialog"; import DialogButtons from "../../elements/DialogButtons"; @@ -25,7 +24,6 @@ interface IProps { onFinished: (success: boolean) => void; } -@replaceableComponent("views.dialogs.security.ConfirmDestroyCrossSigningDialog") export default class ConfirmDestroyCrossSigningDialog extends React.Component { private onConfirm = (): void => { this.props.onFinished(true); diff --git a/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx b/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx index f60f8a9c19..ca5b1db9fb 100644 --- a/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx +++ b/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx @@ -27,7 +27,6 @@ import DialogButtons from '../../elements/DialogButtons'; import BaseDialog from '../BaseDialog'; import Spinner from '../../elements/Spinner'; import InteractiveAuthDialog from '../InteractiveAuthDialog'; -import { replaceableComponent } from "../../../../utils/replaceableComponent"; interface IProps { accountPassword?: string; @@ -46,7 +45,6 @@ interface IState { * 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 { constructor(props: IProps) { super(props); diff --git a/src/components/views/dialogs/security/SetupEncryptionDialog.tsx b/src/components/views/dialogs/security/SetupEncryptionDialog.tsx index 965924bf1f..1a94540502 100644 --- a/src/components/views/dialogs/security/SetupEncryptionDialog.tsx +++ b/src/components/views/dialogs/security/SetupEncryptionDialog.tsx @@ -20,7 +20,6 @@ import SetupEncryptionBody from '../../../structures/auth/SetupEncryptionBody'; import BaseDialog from '../BaseDialog'; import { _t } from '../../../../languageHandler'; import { SetupEncryptionStore, Phase } from '../../../../stores/SetupEncryptionStore'; -import { replaceableComponent } from "../../../../utils/replaceableComponent"; import { IDialogProps } from "../IDialogProps"; function iconFromPhase(phase: Phase) { @@ -36,7 +35,6 @@ interface IState { icon: string; } -@replaceableComponent("views.dialogs.security.SetupEncryptionDialog") export default class SetupEncryptionDialog extends React.Component { private store: SetupEncryptionStore; diff --git a/src/components/views/elements/AccessibleTooltipButton.tsx b/src/components/views/elements/AccessibleTooltipButton.tsx index be3bbcfdb9..d7a001460e 100644 --- a/src/components/views/elements/AccessibleTooltipButton.tsx +++ b/src/components/views/elements/AccessibleTooltipButton.tsx @@ -19,7 +19,6 @@ import React, { SyntheticEvent } from 'react'; import AccessibleButton from "./AccessibleButton"; import Tooltip, { Alignment } from './Tooltip'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps extends React.ComponentProps { title: string; @@ -36,7 +35,6 @@ interface IState { hover: boolean; } -@replaceableComponent("views.elements.AccessibleTooltipButton") export default class AccessibleTooltipButton extends React.PureComponent { constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/ActionButton.tsx b/src/components/views/elements/ActionButton.tsx index 9b1484918f..9d8038f99e 100644 --- a/src/components/views/elements/ActionButton.tsx +++ b/src/components/views/elements/ActionButton.tsx @@ -19,7 +19,6 @@ import React from 'react'; import AccessibleButton from './AccessibleButton'; import dis from '../../../dispatcher/dispatcher'; import Analytics from '../../../Analytics'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Tooltip from './Tooltip'; interface IProps { @@ -37,7 +36,6 @@ interface IState { showTooltip: boolean; } -@replaceableComponent("views.elements.ActionButton") export default class ActionButton extends React.Component { static defaultProps: Partial = { size: "25", diff --git a/src/components/views/elements/AddressSelector.tsx b/src/components/views/elements/AddressSelector.tsx index f1203fbee5..a084e69098 100644 --- a/src/components/views/elements/AddressSelector.tsx +++ b/src/components/views/elements/AddressSelector.tsx @@ -18,7 +18,6 @@ limitations under the License. import React, { createRef } from 'react'; import classNames from 'classnames'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IUserAddress } from '../../../UserAddress'; import AddressTile from './AddressTile'; @@ -41,7 +40,6 @@ interface IState { hover: boolean; } -@replaceableComponent("views.elements.AddressSelector") export default class AddressSelector extends React.Component { private scrollElement = createRef(); private addressListElement = createRef(); diff --git a/src/components/views/elements/AddressTile.tsx b/src/components/views/elements/AddressTile.tsx index d8738e69f3..8aafa0381b 100644 --- a/src/components/views/elements/AddressTile.tsx +++ b/src/components/views/elements/AddressTile.tsx @@ -19,7 +19,6 @@ import React from 'react'; import classNames from 'classnames'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; import { IUserAddress } from '../../../UserAddress'; import BaseAvatar from '../avatars/BaseAvatar'; @@ -33,7 +32,6 @@ interface IProps { showAddress?: boolean; } -@replaceableComponent("views.elements.AddressTile") export default class AddressTile extends React.Component { static defaultProps: Partial = { canDismiss: false, diff --git a/src/components/views/elements/AppPermission.tsx b/src/components/views/elements/AppPermission.tsx index 11bbd6204d..fd53981bca 100644 --- a/src/components/views/elements/AppPermission.tsx +++ b/src/components/views/elements/AppPermission.tsx @@ -24,7 +24,6 @@ import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; import WidgetUtils from "../../../utils/WidgetUtils"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import MemberAvatar from '../avatars/MemberAvatar'; import BaseAvatar from '../avatars/BaseAvatar'; import AccessibleButton from './AccessibleButton'; @@ -44,7 +43,6 @@ interface IState { widgetDomain: string; } -@replaceableComponent("views.elements.AppPermission") export default class AppPermission extends React.Component { static defaultProps: Partial = { onPermissionGranted: () => {}, diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index 0a33b23908..4141c9394a 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -39,7 +39,6 @@ import { StopGapWidget } from "../../../stores/widgets/StopGapWidget"; import { ElementWidgetActions } from "../../../stores/widgets/ElementWidgetActions"; import WidgetContextMenu from "../context_menus/WidgetContextMenu"; import WidgetAvatar from "../avatars/WidgetAvatar"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import CallHandler from '../../../CallHandler'; import { IApp } from "../../../stores/WidgetStore"; import { Container, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore"; @@ -101,7 +100,6 @@ interface IState { requiresClient: boolean; } -@replaceableComponent("views.elements.AppTile") export default class AppTile extends React.Component { public static contextType = MatrixClientContext; context: ContextType; diff --git a/src/components/views/elements/DesktopCapturerSourcePicker.tsx b/src/components/views/elements/DesktopCapturerSourcePicker.tsx index 57bf24b777..f355cc2a5e 100644 --- a/src/components/views/elements/DesktopCapturerSourcePicker.tsx +++ b/src/components/views/elements/DesktopCapturerSourcePicker.tsx @@ -21,7 +21,6 @@ import { _t } from '../../../languageHandler'; import BaseDialog from "..//dialogs/BaseDialog"; import DialogButtons from "./DialogButtons"; import AccessibleButton from './AccessibleButton'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import TabbedView, { Tab, TabLocation } from '../../structures/TabbedView'; import PlatformPeg from "../../../PlatformPeg"; @@ -90,7 +89,6 @@ export interface PickerIProps { onFinished(sourceId: string): void; } -@replaceableComponent("views.elements.DesktopCapturerSourcePicker") export default class DesktopCapturerSourcePicker extends React.Component< PickerIProps, PickerIState diff --git a/src/components/views/elements/DialogButtons.tsx b/src/components/views/elements/DialogButtons.tsx index 480e364630..ed0d6cd9e6 100644 --- a/src/components/views/elements/DialogButtons.tsx +++ b/src/components/views/elements/DialogButtons.tsx @@ -19,7 +19,6 @@ limitations under the License. import React from "react"; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { // The primary button which is styled differently and has default focus. @@ -61,7 +60,6 @@ interface IProps { /** * Basic container for buttons in modal dialogs. */ -@replaceableComponent("views.elements.DialogButtons") export default class DialogButtons extends React.Component { public static defaultProps: Partial = { hasCancel: true, diff --git a/src/components/views/elements/DirectorySearchBox.tsx b/src/components/views/elements/DirectorySearchBox.tsx index 015065f45e..d4f20817e1 100644 --- a/src/components/views/elements/DirectorySearchBox.tsx +++ b/src/components/views/elements/DirectorySearchBox.tsx @@ -17,7 +17,6 @@ limitations under the License. import React, { ChangeEvent, createRef } from 'react'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AccessibleButton from "./AccessibleButton"; interface IProps { @@ -34,7 +33,6 @@ interface IState { value: string; } -@replaceableComponent("views.elements.DirectorySearchBox") export default class DirectorySearchBox extends React.Component { private input = createRef(); diff --git a/src/components/views/elements/Draggable.tsx b/src/components/views/elements/Draggable.tsx index e9e24a57e4..a6eb8323f3 100644 --- a/src/components/views/elements/Draggable.tsx +++ b/src/components/views/elements/Draggable.tsx @@ -16,8 +16,6 @@ limitations under the License. import React from 'react'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - interface IProps { className: string; dragFunc: (currentLocation: ILocationState, event: MouseEvent) => ILocationState; @@ -35,7 +33,6 @@ export interface ILocationState { currentY: number; } -@replaceableComponent("views.elements.Draggable") export default class Draggable extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/Dropdown.tsx b/src/components/views/elements/Dropdown.tsx index 9f071cafa9..4f572875a5 100644 --- a/src/components/views/elements/Dropdown.tsx +++ b/src/components/views/elements/Dropdown.tsx @@ -20,7 +20,6 @@ import classnames from 'classnames'; import AccessibleButton, { ButtonEvent } from './AccessibleButton'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; @@ -107,7 +106,6 @@ interface IState { * but somewhat simpler as react-select is 79KB of minified * javascript. */ -@replaceableComponent("views.elements.Dropdown") export default class Dropdown extends React.Component { private readonly buttonRef = createRef(); private dropdownRootElement: HTMLDivElement = null; diff --git a/src/components/views/elements/EditableItemList.tsx b/src/components/views/elements/EditableItemList.tsx index a6d1d3f06f..d33990b570 100644 --- a/src/components/views/elements/EditableItemList.tsx +++ b/src/components/views/elements/EditableItemList.tsx @@ -19,7 +19,6 @@ import React from "react"; import { _t } from '../../../languageHandler'; import Field from "./Field"; import AccessibleButton from "./AccessibleButton"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IItemProps { index?: number; @@ -107,7 +106,6 @@ interface IProps { onNewItemChanged?(item: string): void; } -@replaceableComponent("views.elements.EditableItemList") export default class EditableItemList

extends React.PureComponent { protected onItemAdded = (e) => { e.stopPropagation(); diff --git a/src/components/views/elements/EditableText.tsx b/src/components/views/elements/EditableText.tsx index 8a9e4ed91a..344db02c3d 100644 --- a/src/components/views/elements/EditableText.tsx +++ b/src/components/views/elements/EditableText.tsx @@ -19,7 +19,6 @@ import React, { createRef } from 'react'; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; enum Phases { Display = "display", @@ -45,7 +44,6 @@ interface IState { phase: Phases; } -@replaceableComponent("views.elements.EditableText") export default class EditableText extends React.Component { // we track value as an JS object field rather than in React state // as React doesn't play nice with contentEditable. diff --git a/src/components/views/elements/EditableTextContainer.tsx b/src/components/views/elements/EditableTextContainer.tsx index ede1e8a655..d452cf10f0 100644 --- a/src/components/views/elements/EditableTextContainer.tsx +++ b/src/components/views/elements/EditableTextContainer.tsx @@ -16,7 +16,6 @@ limitations under the License. import React from 'react'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Spinner from "./Spinner"; import EditableText from "./EditableText"; @@ -56,7 +55,6 @@ interface IState { * 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 { private unmounted = false; public static defaultProps: Partial = { diff --git a/src/components/views/elements/ErrorBoundary.tsx b/src/components/views/elements/ErrorBoundary.tsx index 45fb9eafd4..91e56b82be 100644 --- a/src/components/views/elements/ErrorBoundary.tsx +++ b/src/components/views/elements/ErrorBoundary.tsx @@ -22,7 +22,6 @@ import { MatrixClientPeg } from '../../../MatrixClientPeg'; import PlatformPeg from '../../../PlatformPeg'; import Modal from '../../../Modal'; import SdkConfig from "../../../SdkConfig"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BugReportDialog from '../dialogs/BugReportDialog'; import AccessibleButton from './AccessibleButton'; @@ -34,7 +33,6 @@ interface IState { * 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<{}, IState> { constructor(props) { super(props); diff --git a/src/components/views/elements/EventListSummary.tsx b/src/components/views/elements/EventListSummary.tsx index 748c3b353b..1fc99c774a 100644 --- a/src/components/views/elements/EventListSummary.tsx +++ b/src/components/views/elements/EventListSummary.tsx @@ -25,7 +25,6 @@ import { _t } from '../../../languageHandler'; import { formatCommaSeparatedList } from '../../../utils/FormattingUtils'; import { isValid3pidInvite } from "../../../RoomInvite"; import GenericEventListSummary from "./GenericEventListSummary"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases'; import { jsxJoin } from '../../../utils/ReactUtils'; import { Layout } from '../../../settings/enums/Layout'; @@ -79,7 +78,6 @@ enum TransitionType { const SEP = ","; -@replaceableComponent("views.elements.EventListSummary") export default class EventListSummary extends React.Component { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/views/elements/EventTilePreview.tsx b/src/components/views/elements/EventTilePreview.tsx index 069a743d7f..86f8eeaf20 100644 --- a/src/components/views/elements/EventTilePreview.tsx +++ b/src/components/views/elements/EventTilePreview.tsx @@ -22,7 +22,6 @@ import { RoomMember } from 'matrix-js-sdk/src/models/room-member'; import * as Avatar from '../../../Avatar'; import EventTile from '../rooms/EventTile'; import { Layout } from "../../../settings/enums/Layout"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Spinner from './Spinner'; interface IProps { @@ -63,7 +62,6 @@ interface IState { const AVATAR_SIZE = 32; -@replaceableComponent("views.elements.EventTilePreview") export default class EventTilePreview extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/IRCTimelineProfileResizer.tsx b/src/components/views/elements/IRCTimelineProfileResizer.tsx index 13b0022e72..c0e37d93d7 100644 --- a/src/components/views/elements/IRCTimelineProfileResizer.tsx +++ b/src/components/views/elements/IRCTimelineProfileResizer.tsx @@ -19,7 +19,6 @@ 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 @@ -33,7 +32,6 @@ interface IState { IRCLayoutRoot: HTMLElement; } -@replaceableComponent("views.elements.IRCTimelineProfileResizer") export default class IRCTimelineProfileResizer extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index df9b128885..fd24bc745a 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -31,7 +31,6 @@ import SettingsStore from "../../../settings/SettingsStore"; import { formatFullDate } from "../../../DateUtils"; import dis from '../../../dispatcher/dispatcher'; import { Action } from '../../../dispatcher/actions'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; import { normalizeWheelEvent } from "../../../utils/Mouse"; import { IDialogProps } from '../dialogs/IDialogProps'; @@ -90,7 +89,6 @@ interface IState { contextMenuDisplayed: boolean; } -@replaceableComponent("views.elements.ImageView") export default class ImageView extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/elements/InfoTooltip.tsx b/src/components/views/elements/InfoTooltip.tsx index f77a07bd21..d34a6f9bb0 100644 --- a/src/components/views/elements/InfoTooltip.tsx +++ b/src/components/views/elements/InfoTooltip.tsx @@ -20,7 +20,6 @@ import classNames from 'classnames'; import { Alignment } from './Tooltip'; import { _t } from "../../../languageHandler"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import TooltipTarget from './TooltipTarget'; export enum InfoTooltipKind { @@ -35,7 +34,6 @@ interface ITooltipProps { kind?: InfoTooltipKind; } -@replaceableComponent("views.elements.InfoTooltip") export default class InfoTooltip extends React.PureComponent { constructor(props: ITooltipProps) { super(props); diff --git a/src/components/views/elements/InlineSpinner.tsx b/src/components/views/elements/InlineSpinner.tsx index 3a404430db..385e317cda 100644 --- a/src/components/views/elements/InlineSpinner.tsx +++ b/src/components/views/elements/InlineSpinner.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from "react"; import { _t } from "../../../languageHandler"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { w?: number; @@ -25,7 +24,6 @@ interface IProps { children?: React.ReactNode; } -@replaceableComponent("views.elements.InlineSpinner") export default class InlineSpinner extends React.PureComponent { static defaultProps = { w: 16, diff --git a/src/components/views/elements/InviteReason.tsx b/src/components/views/elements/InviteReason.tsx index 13a62d463c..d3f7e34031 100644 --- a/src/components/views/elements/InviteReason.tsx +++ b/src/components/views/elements/InviteReason.tsx @@ -19,7 +19,6 @@ import React from "react"; import { sanitizedHtmlNode } from "../../../HtmlUtils"; import { _t } from "../../../languageHandler"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { reason: string; @@ -30,7 +29,6 @@ interface IState { hidden: boolean; } -@replaceableComponent("views.elements.InviteReason") export default class InviteReason extends React.PureComponent { constructor(props) { super(props); diff --git a/src/components/views/elements/LabelledToggleSwitch.tsx b/src/components/views/elements/LabelledToggleSwitch.tsx index 24647df502..952c92ac42 100644 --- a/src/components/views/elements/LabelledToggleSwitch.tsx +++ b/src/components/views/elements/LabelledToggleSwitch.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from "react"; import ToggleSwitch from "./ToggleSwitch"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { // The value for the toggle switch @@ -35,7 +34,6 @@ interface IProps { onChange(checked: boolean): void; } -@replaceableComponent("views.elements.LabelledToggleSwitch") export default class LabelledToggleSwitch extends React.PureComponent { render() { // This is a minimal version of a SettingsFlag diff --git a/src/components/views/elements/LanguageDropdown.tsx b/src/components/views/elements/LanguageDropdown.tsx index c6c52ee4e8..7d19dbfce1 100644 --- a/src/components/views/elements/LanguageDropdown.tsx +++ b/src/components/views/elements/LanguageDropdown.tsx @@ -20,7 +20,6 @@ import React from 'react'; import * as languageHandler from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import { _t } from "../../../languageHandler"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Spinner from "./Spinner"; import Dropdown from "./Dropdown"; @@ -42,7 +41,6 @@ interface IState { langs: string[]; } -@replaceableComponent("views.elements.LanguageDropdown") export default class LanguageDropdown extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/LazyRenderList.tsx b/src/components/views/elements/LazyRenderList.tsx index 6a1920bec9..d573a38104 100644 --- a/src/components/views/elements/LazyRenderList.tsx +++ b/src/components/views/elements/LazyRenderList.tsx @@ -16,8 +16,6 @@ limitations under the License. import React from "react"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - class ItemRange { constructor( public topCount: number, @@ -84,7 +82,6 @@ interface IState { renderRange: ItemRange; } -@replaceableComponent("views.elements.LazyRenderList") export default class LazyRenderList extends React.Component, IState> { public static defaultProps: Partial> = { overflowItems: 20, diff --git a/src/components/views/elements/PersistedElement.tsx b/src/components/views/elements/PersistedElement.tsx index 97a197d2bf..cd8239a1f1 100644 --- a/src/components/views/elements/PersistedElement.tsx +++ b/src/components/views/elements/PersistedElement.tsx @@ -22,7 +22,6 @@ import { isNullOrUndefined } from "matrix-js-sdk/src/utils"; import dis from '../../../dispatcher/dispatcher'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { ActionPayload } from "../../../dispatcher/payloads"; export const getPersistKey = (appId: string) => 'widget_' + appId; @@ -70,7 +69,6 @@ interface IProps { * 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 { private resizeObserver: ResizeObserver; private dispatcherRef: string; diff --git a/src/components/views/elements/PersistentApp.tsx b/src/components/views/elements/PersistentApp.tsx index fd78237bfb..5851c1c614 100644 --- a/src/components/views/elements/PersistentApp.tsx +++ b/src/components/views/elements/PersistentApp.tsx @@ -19,7 +19,6 @@ import React, { ContextType } from 'react'; import { Room } from "matrix-js-sdk/src/models/room"; import WidgetUtils from '../../../utils/WidgetUtils'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AppTile from "./AppTile"; import { IApp } from '../../../stores/WidgetStore'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; @@ -30,7 +29,6 @@ interface IProps { pointerEvents?: string; } -@replaceableComponent("views.elements.PersistentApp") export default class PersistentApp extends React.Component { public static contextType = MatrixClientContext; context: ContextType; diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js index 610135ef99..f4e9817f8c 100644 --- a/src/components/views/elements/Pill.js +++ b/src/components/views/elements/Pill.js @@ -27,9 +27,7 @@ import { getPrimaryPermalinkEntity, parsePermalink } from "../../../utils/permal 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.tsx b/src/components/views/elements/PowerSelector.tsx index 2cf028e225..3a9e87d158 100644 --- a/src/components/views/elements/PowerSelector.tsx +++ b/src/components/views/elements/PowerSelector.tsx @@ -19,7 +19,6 @@ import React from 'react'; import * as Roles from '../../../Roles'; import { _t } from '../../../languageHandler'; import Field from "./Field"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; @@ -55,7 +54,6 @@ interface IState { customLevel?: number; } -@replaceableComponent("views.elements.PowerSelector") export default class PowerSelector extends React.Component { public static defaultProps: Partial = { maxValue: Infinity, diff --git a/src/components/views/elements/ReplyChain.tsx b/src/components/views/elements/ReplyChain.tsx index 6b8d7314ea..11498c5a55 100644 --- a/src/components/views/elements/ReplyChain.tsx +++ b/src/components/views/elements/ReplyChain.tsx @@ -29,7 +29,6 @@ import SettingsStore from "../../../settings/SettingsStore"; import { Layout } from "../../../settings/enums/Layout"; import { getUserNameColorClass } from "../../../utils/FormattingUtils"; import { Action } from "../../../dispatcher/actions"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Spinner from './Spinner'; import ReplyTile from "../rooms/ReplyTile"; import Pill from './Pill'; @@ -76,7 +75,6 @@ interface IState { // 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.ReplyChain") export default class ReplyChain extends React.Component { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/views/elements/RoomAliasField.tsx b/src/components/views/elements/RoomAliasField.tsx index a8cf278a30..e99b3b3ea7 100644 --- a/src/components/views/elements/RoomAliasField.tsx +++ b/src/components/views/elements/RoomAliasField.tsx @@ -18,7 +18,6 @@ import React, { createRef, KeyboardEventHandler } from "react"; import { _t } from '../../../languageHandler'; import withValidation from './Validation'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Field, { IValidateOpts } from "./Field"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; @@ -39,7 +38,6 @@ interface IState { } // 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 contextType = MatrixClientContext; public context!: React.ContextType; diff --git a/src/components/views/elements/SettingsFlag.tsx b/src/components/views/elements/SettingsFlag.tsx index a0af045c26..3437440f00 100644 --- a/src/components/views/elements/SettingsFlag.tsx +++ b/src/components/views/elements/SettingsFlag.tsx @@ -22,7 +22,6 @@ 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 @@ -41,7 +40,6 @@ interface IState { value: boolean; } -@replaceableComponent("views.elements.SettingsFlag") export default class SettingsFlag extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx index a4c3147a73..a5103f2bd8 100644 --- a/src/components/views/elements/Slider.tsx +++ b/src/components/views/elements/Slider.tsx @@ -16,8 +16,6 @@ limitations under the License. import * as React from 'react'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - interface IProps { // A callback for the selected value onSelectionChange: (value: number) => void; @@ -36,7 +34,6 @@ interface IProps { disabled: boolean; } -@replaceableComponent("views.elements.Slider") export default class Slider extends React.Component { // 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 972dac909a..126898a4ff 100644 --- a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx +++ b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx @@ -20,7 +20,6 @@ import Dropdown from "../../views/elements/Dropdown"; import PlatformPeg from "../../../PlatformPeg"; import SettingsStore from "../../../settings/SettingsStore"; import { _t } from "../../../languageHandler"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Spinner from "./Spinner"; function languageMatchesSearchQuery(query, language) { @@ -40,7 +39,6 @@ interface SpellCheckLanguagesDropdownIState { languages: any; } -@replaceableComponent("views.elements.SpellCheckLanguagesDropdown") export default class SpellCheckLanguagesDropdown extends React.Component { constructor(props) { diff --git a/src/components/views/elements/Spoiler.tsx b/src/components/views/elements/Spoiler.tsx index 4613f8914b..7d47bb030e 100644 --- a/src/components/views/elements/Spoiler.tsx +++ b/src/components/views/elements/Spoiler.tsx @@ -16,8 +16,6 @@ import React from 'react'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - interface IProps { reason?: string; contentHtml: string; @@ -27,7 +25,6 @@ interface IState { visible: boolean; } -@replaceableComponent("views.elements.Spoiler") export default class Spoiler extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/StyledCheckbox.tsx b/src/components/views/elements/StyledCheckbox.tsx index 6fe59562bb..333fbb8adb 100644 --- a/src/components/views/elements/StyledCheckbox.tsx +++ b/src/components/views/elements/StyledCheckbox.tsx @@ -18,8 +18,6 @@ import React from "react"; import { randomString } from "matrix-js-sdk/src/randomstring"; import classnames from 'classnames'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - export enum CheckboxStyle { Solid = "solid", Outline = "outline", @@ -34,7 +32,6 @@ interface IProps extends React.InputHTMLAttributes { interface IState { } -@replaceableComponent("views.elements.StyledCheckbox") export default class StyledCheckbox extends React.PureComponent { private id: string; diff --git a/src/components/views/elements/StyledRadioButton.tsx b/src/components/views/elements/StyledRadioButton.tsx index 25f525ebf4..14cc7d22ef 100644 --- a/src/components/views/elements/StyledRadioButton.tsx +++ b/src/components/views/elements/StyledRadioButton.tsx @@ -17,8 +17,6 @@ limitations under the License. import React from 'react'; import classnames from 'classnames'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - interface IProps extends React.InputHTMLAttributes { inputRef?: React.RefObject; outlined?: boolean; @@ -31,7 +29,6 @@ interface IProps extends React.InputHTMLAttributes { interface IState { } -@replaceableComponent("views.elements.StyledRadioButton") export default class StyledRadioButton extends React.PureComponent { public static readonly defaultProps = { className: '', diff --git a/src/components/views/elements/SyntaxHighlight.tsx b/src/components/views/elements/SyntaxHighlight.tsx index bc4b3111f3..861eb18e83 100644 --- a/src/components/views/elements/SyntaxHighlight.tsx +++ b/src/components/views/elements/SyntaxHighlight.tsx @@ -17,14 +17,11 @@ limitations under the License. import React from 'react'; import hljs from 'highlight.js'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; - interface IProps { language?: string; children: string; } -@replaceableComponent("views.elements.SyntaxHighlight") export default class SyntaxHighlight extends React.PureComponent { public render(): JSX.Element { const { children: content, language } = this.props; diff --git a/src/components/views/elements/TagComposer.tsx b/src/components/views/elements/TagComposer.tsx index 9937020fff..19f3523f06 100644 --- a/src/components/views/elements/TagComposer.tsx +++ b/src/components/views/elements/TagComposer.tsx @@ -16,7 +16,6 @@ limitations under the License. import React, { ChangeEvent, FormEvent } from "react"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Field from "./Field"; import { _t } from "../../../languageHandler"; import AccessibleButton from "./AccessibleButton"; @@ -38,7 +37,6 @@ interface IState { * A simple, controlled, composer for entering string tags. Contains a simple * input, add button, and per-tag remove button. */ -@replaceableComponent("views.elements.TagComposer") export default class TagComposer extends React.PureComponent { public constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/TextWithTooltip.tsx b/src/components/views/elements/TextWithTooltip.tsx index 2b5926f3d7..c8fa5376b8 100644 --- a/src/components/views/elements/TextWithTooltip.tsx +++ b/src/components/views/elements/TextWithTooltip.tsx @@ -17,7 +17,6 @@ import React from 'react'; import classNames from 'classnames'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import TooltipTarget from './TooltipTarget'; interface IProps { @@ -28,7 +27,6 @@ interface IProps { onClick?: (ev?: React.MouseEvent) => void; } -@replaceableComponent("views.elements.TextWithTooltip") export default class TextWithTooltip extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/elements/Tooltip.tsx b/src/components/views/elements/Tooltip.tsx index 47b81c7a2e..189bee393f 100644 --- a/src/components/views/elements/Tooltip.tsx +++ b/src/components/views/elements/Tooltip.tsx @@ -21,7 +21,6 @@ import React, { CSSProperties } from 'react'; import ReactDOM from 'react-dom'; import classNames from 'classnames'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import UIStore from "../../../stores/UIStore"; const MIN_TOOLTIP_HEIGHT = 25; @@ -55,7 +54,6 @@ export interface ITooltipProps { maxParentWidth?: number; } -@replaceableComponent("views.elements.Tooltip") export default class Tooltip extends React.Component { private tooltipContainer: HTMLElement; private parent: Element; diff --git a/src/components/views/elements/TooltipButton.tsx b/src/components/views/elements/TooltipButton.tsx index e6b3f6c520..c863ea31b9 100644 --- a/src/components/views/elements/TooltipButton.tsx +++ b/src/components/views/elements/TooltipButton.tsx @@ -17,14 +17,12 @@ limitations under the License. import React from 'react'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import TooltipTarget from './TooltipTarget'; interface IProps { helpText: React.ReactNode | string; } -@replaceableComponent("views.elements.TooltipButton") export default class TooltipButton extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/elements/TruncatedList.tsx b/src/components/views/elements/TruncatedList.tsx index 31c5391b07..56d05515df 100644 --- a/src/components/views/elements/TruncatedList.tsx +++ b/src/components/views/elements/TruncatedList.tsx @@ -18,7 +18,6 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { // The number of elements to show before truncating. If negative, no truncation is done. @@ -38,7 +37,6 @@ interface IProps { createOverflowElement?: (overflowCount: number, totalCount: number) => React.ReactNode; } -@replaceableComponent("views.elements.TruncatedList") export default class TruncatedList extends React.Component { static defaultProps ={ truncateAt: 2, diff --git a/src/components/views/elements/crypto/VerificationQRCode.tsx b/src/components/views/elements/crypto/VerificationQRCode.tsx index a5efb1b6ce..16f150af6b 100644 --- a/src/components/views/elements/crypto/VerificationQRCode.tsx +++ b/src/components/views/elements/crypto/VerificationQRCode.tsx @@ -17,14 +17,12 @@ limitations under the License. import React from "react"; import { QRCodeData } from "matrix-js-sdk/src/crypto/verification/QRCode"; -import { replaceableComponent } from "../../../../utils/replaceableComponent"; import QRCode from "../QRCode"; interface IProps { qrCodeData: QRCodeData; } -@replaceableComponent("views.elements.crypto.VerificationQRCode") export default class VerificationQRCode extends React.PureComponent { public render(): JSX.Element { return ( diff --git a/src/components/views/emojipicker/Category.tsx b/src/components/views/emojipicker/Category.tsx index 395ff1cbc8..7cd5b96bee 100644 --- a/src/components/views/emojipicker/Category.tsx +++ b/src/components/views/emojipicker/Category.tsx @@ -21,7 +21,6 @@ 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; @@ -48,7 +47,6 @@ interface IProps { onMouseLeave(emoji: IEmoji): void; } -@replaceableComponent("views.emojipicker.Category") class Category extends React.PureComponent { 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 48194ff7d7..91eada12b3 100644 --- a/src/components/views/emojipicker/Emoji.tsx +++ b/src/components/views/emojipicker/Emoji.tsx @@ -19,7 +19,6 @@ import React from 'react'; import { MenuItem } from "../../structures/ContextMenu"; import { IEmoji } from "../../../emoji"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { emoji: IEmoji; @@ -29,7 +28,6 @@ interface IProps { onMouseLeave(emoji: IEmoji): void; } -@replaceableComponent("views.emojipicker.Emoji") class Emoji extends React.PureComponent { 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 99f8b561ee..e064df405a 100644 --- a/src/components/views/emojipicker/EmojiPicker.tsx +++ b/src/components/views/emojipicker/EmojiPicker.tsx @@ -26,7 +26,6 @@ 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 = 20; export const EMOJI_HEIGHT = 35; @@ -50,7 +49,6 @@ interface IState { viewportHeight: number; } -@replaceableComponent("views.emojipicker.EmojiPicker") class EmojiPicker extends React.Component { private readonly recentlyUsed: IEmoji[]; private readonly memoizedDataByCategory: Record; diff --git a/src/components/views/emojipicker/Header.tsx b/src/components/views/emojipicker/Header.tsx index e364d87eae..e430ac974b 100644 --- a/src/components/views/emojipicker/Header.tsx +++ b/src/components/views/emojipicker/Header.tsx @@ -20,7 +20,6 @@ import classNames from "classnames"; import { _t } from "../../../languageHandler"; import { CategoryKey, ICategory } from "./Category"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; @@ -29,7 +28,6 @@ interface IProps { onAnchorClick(id: CategoryKey): void; } -@replaceableComponent("views.emojipicker.Header") class Header extends React.PureComponent { 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 710b4545df..bcbbec1feb 100644 --- a/src/components/views/emojipicker/Preview.tsx +++ b/src/components/views/emojipicker/Preview.tsx @@ -18,13 +18,11 @@ 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 { render() { const { unicode, label, shortcodes: [shortcode] } = this.props.emoji; diff --git a/src/components/views/emojipicker/QuickReactions.tsx b/src/components/views/emojipicker/QuickReactions.tsx index 4c654a0806..c0336a759d 100644 --- a/src/components/views/emojipicker/QuickReactions.tsx +++ b/src/components/views/emojipicker/QuickReactions.tsx @@ -20,7 +20,6 @@ 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 => { @@ -40,7 +39,6 @@ interface IState { hover?: IEmoji; } -@replaceableComponent("views.emojipicker.QuickReactions") class QuickReactions extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/emojipicker/ReactionPicker.tsx b/src/components/views/emojipicker/ReactionPicker.tsx index df18949233..c53f5a64f9 100644 --- a/src/components/views/emojipicker/ReactionPicker.tsx +++ b/src/components/views/emojipicker/ReactionPicker.tsx @@ -23,7 +23,6 @@ import { EventType, RelationType } from 'matrix-js-sdk/src/@types/event'; import EmojiPicker from "./EmojiPicker"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import dis from "../../../dispatcher/dispatcher"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { Action } from '../../../dispatcher/actions'; import RoomContext from "../../../contexts/RoomContext"; import { FocusComposerPayload } from '../../../dispatcher/payloads/FocusComposerPayload'; @@ -38,7 +37,6 @@ interface IState { selectedEmojis: Set; } -@replaceableComponent("views.emojipicker.ReactionPicker") class ReactionPicker extends React.Component { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/views/emojipicker/Search.tsx b/src/components/views/emojipicker/Search.tsx index 98273e926b..de09421010 100644 --- a/src/components/views/emojipicker/Search.tsx +++ b/src/components/views/emojipicker/Search.tsx @@ -18,7 +18,6 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; @@ -28,7 +27,6 @@ interface IProps { onEnter(): void; } -@replaceableComponent("views.emojipicker.Search") class Search extends React.PureComponent { private inputRef = React.createRef(); diff --git a/src/components/views/location/LocationPicker.tsx b/src/components/views/location/LocationPicker.tsx index 4eaef0365b..c7e72c1949 100644 --- a/src/components/views/location/LocationPicker.tsx +++ b/src/components/views/location/LocationPicker.tsx @@ -23,7 +23,6 @@ import classNames from 'classnames'; import { Icon as LocationIcon } from '../../../../res/img/element-icons/location.svg'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import MatrixClientContext from '../../../contexts/MatrixClientContext'; import Modal from '../../../Modal'; import SdkConfig from '../../../SdkConfig'; @@ -54,7 +53,6 @@ interface IState { const isSharingOwnLocation = (shareType: LocationShareType): boolean => shareType === LocationShareType.Own || shareType === LocationShareType.Live; -@replaceableComponent("views.location.LocationPicker") class LocationPicker extends React.Component { public static contextType = MatrixClientContext; public context!: React.ContextType; diff --git a/src/components/views/location/LocationViewDialog.tsx b/src/components/views/location/LocationViewDialog.tsx index 2c6e154ac0..236bd754d9 100644 --- a/src/components/views/location/LocationViewDialog.tsx +++ b/src/components/views/location/LocationViewDialog.tsx @@ -18,7 +18,6 @@ import React from 'react'; import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; import { ClientEvent, IClientWellKnown, MatrixClient } from 'matrix-js-sdk/src/client'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "../dialogs/BaseDialog"; import { IDialogProps } from "../dialogs/IDialogProps"; import { LocationBodyContent } from '../messages/MLocationBody'; @@ -34,7 +33,6 @@ interface IState { error: Error; } -@replaceableComponent("views.location.LocationViewDialog") export default class LocationViewDialog extends React.Component { private coords: GeolocationCoordinates; private map?: maplibregl.Map; diff --git a/src/components/views/messages/DateSeparator.tsx b/src/components/views/messages/DateSeparator.tsx index e7aeb3e155..54dde16dac 100644 --- a/src/components/views/messages/DateSeparator.tsx +++ b/src/components/views/messages/DateSeparator.tsx @@ -21,7 +21,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { _t } from '../../../languageHandler'; import { formatFullDateNoTime } from '../../../DateUtils'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import dis from '../../../dispatcher/dispatcher'; import { Action } from '../../../dispatcher/actions'; @@ -61,7 +60,6 @@ interface IState { jumpToDateEnabled: boolean; } -@replaceableComponent("views.messages.DateSeparator") export default class DateSeparator extends React.Component { private settingWatcherRef = null; diff --git a/src/components/views/messages/DownloadActionButton.tsx b/src/components/views/messages/DownloadActionButton.tsx index b4ed4af0d3..e9152579d7 100644 --- a/src/components/views/messages/DownloadActionButton.tsx +++ b/src/components/views/messages/DownloadActionButton.tsx @@ -22,7 +22,6 @@ import { MediaEventHelper } from "../../../utils/MediaEventHelper"; import { RovingAccessibleTooltipButton } from "../../../accessibility/RovingTabIndex"; import Spinner from "../elements/Spinner"; import { _t, _td } from "../../../languageHandler"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { FileDownloader } from "../../../utils/FileDownloader"; interface IProps { @@ -40,7 +39,6 @@ interface IState { tooltip: string; } -@replaceableComponent("views.messages.DownloadActionButton") export default class DownloadActionButton extends React.PureComponent { private downloader = new FileDownloader(); diff --git a/src/components/views/messages/EditHistoryMessage.tsx b/src/components/views/messages/EditHistoryMessage.tsx index 116bfe8268..30922b62e5 100644 --- a/src/components/views/messages/EditHistoryMessage.tsx +++ b/src/components/views/messages/EditHistoryMessage.tsx @@ -26,7 +26,6 @@ import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; import RedactedBody from "./RedactedBody"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AccessibleButton from "../elements/AccessibleButton"; import ConfirmAndWaitRedactDialog from "../dialogs/ConfirmAndWaitRedactDialog"; import ViewSource from "../../structures/ViewSource"; @@ -50,7 +49,6 @@ interface IState { sendStatus: EventStatus; } -@replaceableComponent("views.messages.EditHistoryMessage") export default class EditHistoryMessage extends React.PureComponent { private content = createRef(); private pills: Element[] = []; diff --git a/src/components/views/messages/MAudioBody.tsx b/src/components/views/messages/MAudioBody.tsx index 5af03135b5..9d20c667e8 100644 --- a/src/components/views/messages/MAudioBody.tsx +++ b/src/components/views/messages/MAudioBody.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from "react"; import { logger } from "matrix-js-sdk/src/logger"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { Playback } from "../../../audio/Playback"; import InlineSpinner from '../elements/InlineSpinner'; import { _t } from "../../../languageHandler"; @@ -35,7 +34,6 @@ interface IState { playback?: Playback; } -@replaceableComponent("views.messages.MAudioBody") export default class MAudioBody extends React.PureComponent { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/views/messages/MFileBody.tsx b/src/components/views/messages/MFileBody.tsx index 383a2cce2e..2556616b7a 100644 --- a/src/components/views/messages/MFileBody.tsx +++ b/src/components/views/messages/MFileBody.tsx @@ -21,7 +21,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; import AccessibleButton from "../elements/AccessibleButton"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromContent } from "../../../customisations/Media"; import ErrorDialog from "../dialogs/ErrorDialog"; import { presentableTextForFile } from "../../../utils/FileUtils"; @@ -106,7 +105,6 @@ interface IState { decryptedBlob?: Blob; } -@replaceableComponent("views.messages.MFileBody") export default class MFileBody extends React.Component { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/views/messages/MImageBody.tsx b/src/components/views/messages/MImageBody.tsx index d5d8ebf471..0f9fe45a29 100644 --- a/src/components/views/messages/MImageBody.tsx +++ b/src/components/views/messages/MImageBody.tsx @@ -28,7 +28,6 @@ import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import Spinner from '../elements/Spinner'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { Media, mediaFromContent } from "../../../customisations/Media"; import { BLURHASH_FIELD, createThumbnail } from "../../../ContentMessages"; import { IMediaEventContent } from '../../../customisations/models/IMediaEventContent'; @@ -60,7 +59,6 @@ interface IState { placeholder: Placeholder; } -@replaceableComponent("views.messages.MImageBody") export default class MImageBody extends React.Component { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/views/messages/MJitsiWidgetEvent.tsx b/src/components/views/messages/MJitsiWidgetEvent.tsx index 03448bf0d2..86796aac17 100644 --- a/src/components/views/messages/MJitsiWidgetEvent.tsx +++ b/src/components/views/messages/MJitsiWidgetEvent.tsx @@ -22,14 +22,12 @@ 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; timestamp?: JSX.Element; } -@replaceableComponent("views.messages.MJitsiWidgetEvent") export default class MJitsiWidgetEvent extends React.PureComponent { constructor(props) { super(props); diff --git a/src/components/views/messages/MKeyVerificationConclusion.tsx b/src/components/views/messages/MKeyVerificationConclusion.tsx index 1e5312c4a5..9f1be7e76e 100644 --- a/src/components/views/messages/MKeyVerificationConclusion.tsx +++ b/src/components/views/messages/MKeyVerificationConclusion.tsx @@ -28,7 +28,6 @@ import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; import { getNameForEventRoom, userLabelForEventRoom } from '../../../utils/KeyVerificationStateObserver'; import EventTileBubble from "./EventTileBubble"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { /* the MatrixEvent to show */ @@ -36,7 +35,6 @@ interface IProps { timestamp?: JSX.Element; } -@replaceableComponent("views.messages.MKeyVerificationConclusion") export default class MKeyVerificationConclusion extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/messages/MKeyVerificationRequest.tsx b/src/components/views/messages/MKeyVerificationRequest.tsx index 457fbfc819..fb1210b33c 100644 --- a/src/components/views/messages/MKeyVerificationRequest.tsx +++ b/src/components/views/messages/MKeyVerificationRequest.tsx @@ -24,7 +24,6 @@ import { _t } from '../../../languageHandler'; import { getNameForEventRoom, userLabelForEventRoom } from '../../../utils/KeyVerificationStateObserver'; import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases'; import EventTileBubble from "./EventTileBubble"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AccessibleButton from '../elements/AccessibleButton'; import RightPanelStore from '../../../stores/right-panel/RightPanelStore'; @@ -33,7 +32,6 @@ interface IProps { timestamp?: JSX.Element; } -@replaceableComponent("views.messages.MKeyVerificationRequest") export default class MKeyVerificationRequest extends React.Component { public componentDidMount() { const request = this.props.mxEvent.verificationRequest; diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index d824917dad..f56b1ae906 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -24,7 +24,6 @@ import { } from 'matrix-js-sdk/src/@types/location'; import { ClientEvent, IClientWellKnown } from 'matrix-js-sdk/src/client'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IBodyProps } from "./IBodyProps"; import { _t } from '../../../languageHandler'; import MemberAvatar from '../avatars/MemberAvatar'; @@ -47,7 +46,6 @@ interface IState { error: Error; } -@replaceableComponent("views.messages.MLocationBody") export default class MLocationBody extends React.Component { public static contextType = MatrixClientContext; public context!: React.ContextType; diff --git a/src/components/views/messages/MPollBody.tsx b/src/components/views/messages/MPollBody.tsx index 3b05c09f7a..bea4266d2e 100644 --- a/src/components/views/messages/MPollBody.tsx +++ b/src/components/views/messages/MPollBody.tsx @@ -32,7 +32,6 @@ import { import { RelatedRelations } from "matrix-js-sdk/src/models/related-relations"; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Modal from '../../../Modal'; import { IBodyProps } from "./IBodyProps"; import { formatCommaSeparatedList } from '../../../utils/FormattingUtils'; @@ -210,7 +209,6 @@ export function launchPollEditor(mxEvent: MatrixEvent, getRelationsForEvent?: Ge } } -@replaceableComponent("views.messages.MPollBody") export default class MPollBody extends React.Component { public static contextType = MatrixClientContext; public context!: React.ContextType; diff --git a/src/components/views/messages/MStickerBody.tsx b/src/components/views/messages/MStickerBody.tsx index 192cf1dd97..c29d4c225b 100644 --- a/src/components/views/messages/MStickerBody.tsx +++ b/src/components/views/messages/MStickerBody.tsx @@ -17,11 +17,9 @@ limitations under the License. import React from 'react'; import MImageBody from './MImageBody'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { BLURHASH_FIELD } from "../../../ContentMessages"; import Tooltip from "../elements/Tooltip"; -@replaceableComponent("views.messages.MStickerBody") export default class MStickerBody extends MImageBody { // Mostly empty to prevent default behaviour of MImageBody protected onClick = (ev: React.MouseEvent) => { diff --git a/src/components/views/messages/MVideoBody.tsx b/src/components/views/messages/MVideoBody.tsx index 631618ae01..cacd19c5a8 100644 --- a/src/components/views/messages/MVideoBody.tsx +++ b/src/components/views/messages/MVideoBody.tsx @@ -21,7 +21,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import InlineSpinner from '../elements/InlineSpinner'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromContent } from "../../../customisations/Media"; import { BLURHASH_FIELD } from "../../../ContentMessages"; import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent"; @@ -40,7 +39,6 @@ interface IState { blurhashUrl: string; } -@replaceableComponent("views.messages.MVideoBody") export default class MVideoBody extends React.PureComponent { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/views/messages/MVoiceMessageBody.tsx b/src/components/views/messages/MVoiceMessageBody.tsx index 847f15bc9c..65521225ba 100644 --- a/src/components/views/messages/MVoiceMessageBody.tsx +++ b/src/components/views/messages/MVoiceMessageBody.tsx @@ -16,14 +16,12 @@ limitations under the License. import React from "react"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import InlineSpinner from '../elements/InlineSpinner'; import { _t } from "../../../languageHandler"; import RecordingPlayback from "../audio_messages/RecordingPlayback"; import MAudioBody from "./MAudioBody"; import MFileBody from "./MFileBody"; -@replaceableComponent("views.messages.MVoiceMessageBody") export default class MVoiceMessageBody extends MAudioBody { // A voice message is an audio file but rendered in a special way. public render() { diff --git a/src/components/views/messages/MVoiceOrAudioBody.tsx b/src/components/views/messages/MVoiceOrAudioBody.tsx index cec042a7ff..fb6391087a 100644 --- a/src/components/views/messages/MVoiceOrAudioBody.tsx +++ b/src/components/views/messages/MVoiceOrAudioBody.tsx @@ -17,12 +17,10 @@ limitations under the License. import React from "react"; import MAudioBody from "./MAudioBody"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import MVoiceMessageBody from "./MVoiceMessageBody"; import { IBodyProps } from "./IBodyProps"; import { isVoiceMessage } from "../../../utils/EventUtils"; -@replaceableComponent("views.messages.MVoiceOrAudioBody") export default class MVoiceOrAudioBody extends React.PureComponent { public render() { if (!this.props.forExport && isVoiceMessage(this.props.mxEvent)) { diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx index 3dabbea89f..673d664f81 100644 --- a/src/components/views/messages/MessageActionBar.tsx +++ b/src/components/views/messages/MessageActionBar.tsx @@ -29,7 +29,6 @@ import { isContentActionable, canEditContent, editEvent } from '../../../utils/E import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext"; import Toolbar from "../../../accessibility/Toolbar"; import { RovingAccessibleTooltipButton, useRovingTabIndex } from "../../../accessibility/RovingTabIndex"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import MessageContextMenu, { canCancel } from "../context_menus/MessageContextMenu"; import Resend from "../../../Resend"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; @@ -170,7 +169,6 @@ interface IMessageActionBarProps { ) => Relations; } -@replaceableComponent("views.messages.MessageActionBar") export default class MessageActionBar extends React.PureComponent { public static contextType = RoomContext; diff --git a/src/components/views/messages/MessageEvent.tsx b/src/components/views/messages/MessageEvent.tsx index 68281beaee..18c145175d 100644 --- a/src/components/views/messages/MessageEvent.tsx +++ b/src/components/views/messages/MessageEvent.tsx @@ -25,7 +25,6 @@ import SettingsStore from "../../../settings/SettingsStore"; import { Mjolnir } from "../../../mjolnir/Mjolnir"; import RedactedBody from "./RedactedBody"; import UnknownBody from "./UnknownBody"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IMediaBody } from "./IMediaBody"; import { IOperableEventTile } from "../context_menus/MessageContextMenu"; import { MediaEventHelper } from "../../../utils/MediaEventHelper"; @@ -45,7 +44,6 @@ interface IProps extends Omit { isSeeingThroughMessageHiddenForModeration?: boolean; } -@replaceableComponent("views.messages.MessageEvent") export default class MessageEvent extends React.Component implements IMediaBody, IOperableEventTile { private body: React.RefObject = createRef(); private mediaHelper: MediaEventHelper; diff --git a/src/components/views/messages/MessageTimestamp.tsx b/src/components/views/messages/MessageTimestamp.tsx index cbf37f47f6..9b5c280705 100644 --- a/src/components/views/messages/MessageTimestamp.tsx +++ b/src/components/views/messages/MessageTimestamp.tsx @@ -18,7 +18,6 @@ limitations under the License. import React from 'react'; import { formatFullDate, formatTime, formatFullTime, formatRelativeTime } from '../../../DateUtils'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { ts: number; @@ -28,7 +27,6 @@ interface IProps { showRelative?: boolean; } -@replaceableComponent("views.messages.MessageTimestamp") export default class MessageTimestamp extends React.Component { public render() { const date = new Date(this.props.ts); diff --git a/src/components/views/messages/MjolnirBody.tsx b/src/components/views/messages/MjolnirBody.tsx index 14956554f1..b3ca769ba5 100644 --- a/src/components/views/messages/MjolnirBody.tsx +++ b/src/components/views/messages/MjolnirBody.tsx @@ -18,7 +18,6 @@ import React from 'react'; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AccessibleButton from '../elements/AccessibleButton'; interface IProps { @@ -26,7 +25,6 @@ interface IProps { onMessageAllowed: () => void; } -@replaceableComponent("views.messages.MjolnirBody") export default class MjolnirBody extends React.Component { private onAllowClick = (e: React.MouseEvent): void => { e.preventDefault(); diff --git a/src/components/views/messages/ReactionsRow.tsx b/src/components/views/messages/ReactionsRow.tsx index 7cce3238b7..0c06474635 100644 --- a/src/components/views/messages/ReactionsRow.tsx +++ b/src/components/views/messages/ReactionsRow.tsx @@ -21,7 +21,6 @@ import { Relations, RelationsEvent } from "matrix-js-sdk/src/models/relations"; import { _t } from '../../../languageHandler'; import { isContentActionable } from '../../../utils/EventUtils'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { ContextMenuTooltipButton } from "../../../accessibility/context_menu/ContextMenuTooltipButton"; import ContextMenu, { aboveLeftOf, useContextMenu } from "../../structures/ContextMenu"; import ReactionPicker from "../emojipicker/ReactionPicker"; @@ -74,7 +73,6 @@ interface IState { showAll: boolean; } -@replaceableComponent("views.messages.ReactionsRow") export default class ReactionsRow extends React.PureComponent { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/views/messages/ReactionsRowButton.tsx b/src/components/views/messages/ReactionsRowButton.tsx index 242428ed36..d3fcb2faa6 100644 --- a/src/components/views/messages/ReactionsRowButton.tsx +++ b/src/components/views/messages/ReactionsRowButton.tsx @@ -21,7 +21,6 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { _t } from '../../../languageHandler'; import { formatCommaSeparatedList } from '../../../utils/FormattingUtils'; import dis from "../../../dispatcher/dispatcher"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import ReactionsRowButtonTooltip from "./ReactionsRowButtonTooltip"; import AccessibleButton from "../elements/AccessibleButton"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; @@ -46,7 +45,6 @@ interface IState { tooltipVisible: boolean; } -@replaceableComponent("views.messages.ReactionsRowButton") export default class ReactionsRowButton extends React.PureComponent { static contextType = MatrixClientContext; diff --git a/src/components/views/messages/ReactionsRowButtonTooltip.tsx b/src/components/views/messages/ReactionsRowButtonTooltip.tsx index 9c43c0df77..cb714d1fba 100644 --- a/src/components/views/messages/ReactionsRowButtonTooltip.tsx +++ b/src/components/views/messages/ReactionsRowButtonTooltip.tsx @@ -20,7 +20,6 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { unicodeToShortcode } from '../../../HtmlUtils'; import { _t } from '../../../languageHandler'; import { formatCommaSeparatedList } from '../../../utils/FormattingUtils'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Tooltip from "../elements/Tooltip"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; @@ -34,7 +33,6 @@ interface IProps { visible: boolean; } -@replaceableComponent("views.messages.ReactionsRowButtonTooltip") export default class ReactionsRowButtonTooltip extends React.PureComponent { static contextType = MatrixClientContext; diff --git a/src/components/views/messages/RoomAvatarEvent.tsx b/src/components/views/messages/RoomAvatarEvent.tsx index 9cb91c7c44..3cac4d29c5 100644 --- a/src/components/views/messages/RoomAvatarEvent.tsx +++ b/src/components/views/messages/RoomAvatarEvent.tsx @@ -23,7 +23,6 @@ import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; import AccessibleButton from '../elements/AccessibleButton'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; import RoomAvatar from "../avatars/RoomAvatar"; import ImageView from "../elements/ImageView"; @@ -33,7 +32,6 @@ interface IProps { mxEvent: MatrixEvent; } -@replaceableComponent("views.messages.RoomAvatarEvent") export default class RoomAvatarEvent extends React.Component { private onAvatarClick = (): void => { const cli = MatrixClientPeg.get(); diff --git a/src/components/views/messages/RoomCreate.tsx b/src/components/views/messages/RoomCreate.tsx index c2d407c8b9..bd723a5c48 100644 --- a/src/components/views/messages/RoomCreate.tsx +++ b/src/components/views/messages/RoomCreate.tsx @@ -24,7 +24,6 @@ import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks'; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import EventTileBubble from "./EventTileBubble"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; interface IProps { @@ -33,7 +32,6 @@ interface IProps { timestamp?: JSX.Element; } -@replaceableComponent("views.messages.RoomCreate") export default class RoomCreate extends React.Component { private onLinkClicked = (e: React.MouseEvent): void => { e.preventDefault(); diff --git a/src/components/views/messages/SenderProfile.tsx b/src/components/views/messages/SenderProfile.tsx index 694b74da66..da7d1206d1 100644 --- a/src/components/views/messages/SenderProfile.tsx +++ b/src/components/views/messages/SenderProfile.tsx @@ -19,7 +19,6 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MsgType } from "matrix-js-sdk/src/@types/event"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import DisambiguatedProfile from "./DisambiguatedProfile"; import RoomContext, { TimelineRenderingType } from '../../../contexts/RoomContext'; import SettingsStore from "../../../settings/SettingsStore"; @@ -30,7 +29,6 @@ interface IProps { onClick?(): void; } -@replaceableComponent("views.messages.SenderProfile") export default class SenderProfile extends React.PureComponent { public static contextType = MatrixClientContext; public context!: React.ContextType; diff --git a/src/components/views/messages/TextualBody.tsx b/src/components/views/messages/TextualBody.tsx index 9ec9980fb8..3584b5130f 100644 --- a/src/components/views/messages/TextualBody.tsx +++ b/src/components/views/messages/TextualBody.tsx @@ -33,7 +33,6 @@ import { IntegrationManagers } from "../../../integrations/IntegrationManagers"; import { isPermalinkHost, tryTransformPermalinkToLocalHref } from "../../../utils/permalinks/Permalinks"; import { copyPlaintext } from "../../../utils/strings"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import UIStore from "../../../stores/UIStore"; import { ComposerInsertPayload } from "../../../dispatcher/payloads/ComposerInsertPayload"; import { Action } from "../../../dispatcher/actions"; @@ -59,7 +58,6 @@ interface IState { widgetHidden: boolean; } -@replaceableComponent("views.messages.TextualBody") export default class TextualBody extends React.Component { private readonly contentRef = createRef(); diff --git a/src/components/views/messages/TextualEvent.tsx b/src/components/views/messages/TextualEvent.tsx index 8fc116b5d0..c92d7b55c7 100644 --- a/src/components/views/messages/TextualEvent.tsx +++ b/src/components/views/messages/TextualEvent.tsx @@ -19,13 +19,11 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import RoomContext from "../../../contexts/RoomContext"; import * as TextForEvent from "../../../TextForEvent"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { mxEvent: MatrixEvent; } -@replaceableComponent("views.messages.TextualEvent") export default class TextualEvent extends React.Component { static contextType = RoomContext; diff --git a/src/components/views/messages/TileErrorBoundary.tsx b/src/components/views/messages/TileErrorBoundary.tsx index 9f3b751dd3..c30a68bb96 100644 --- a/src/components/views/messages/TileErrorBoundary.tsx +++ b/src/components/views/messages/TileErrorBoundary.tsx @@ -21,7 +21,6 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; import SdkConfig from "../../../SdkConfig"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BugReportDialog from '../dialogs/BugReportDialog'; import AccessibleButton from '../elements/AccessibleButton'; import SettingsStore from "../../../settings/SettingsStore"; @@ -37,7 +36,6 @@ interface IState { error: Error; } -@replaceableComponent("views.messages.TileErrorBoundary") export default class TileErrorBoundary extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/messages/ViewSourceEvent.tsx b/src/components/views/messages/ViewSourceEvent.tsx index ad833936e4..b4cca0b5cc 100644 --- a/src/components/views/messages/ViewSourceEvent.tsx +++ b/src/components/views/messages/ViewSourceEvent.tsx @@ -18,7 +18,6 @@ import React from 'react'; import { MatrixEvent, MatrixEventEvent } from 'matrix-js-sdk/src/matrix'; import classNames from 'classnames'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { _t } from '../../../languageHandler'; import AccessibleButton from '../elements/AccessibleButton'; @@ -31,7 +30,6 @@ interface IState { expanded: boolean; } -@replaceableComponent("views.messages.ViewSourceEvent") export default class ViewSourceEvent extends React.PureComponent { constructor(props) { super(props); diff --git a/src/components/views/right_panel/HeaderButton.tsx b/src/components/views/right_panel/HeaderButton.tsx index 7f6c22fbd3..7b32b1993a 100644 --- a/src/components/views/right_panel/HeaderButton.tsx +++ b/src/components/views/right_panel/HeaderButton.tsx @@ -23,7 +23,6 @@ import classNames from 'classnames'; import Analytics from '../../../Analytics'; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { ButtonEvent } from "../elements/AccessibleButton"; interface IProps { @@ -41,7 +40,6 @@ 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 { private onClick = (ev: ButtonEvent) => { Analytics.trackEvent(...this.props.analytics); diff --git a/src/components/views/right_panel/HeaderButtons.tsx b/src/components/views/right_panel/HeaderButtons.tsx index a3f2f6bb9f..a152a8871f 100644 --- a/src/components/views/right_panel/HeaderButtons.tsx +++ b/src/components/views/right_panel/HeaderButtons.tsx @@ -24,7 +24,6 @@ import dis from '../../../dispatcher/dispatcher'; import RightPanelStore from "../../../stores/right-panel/RightPanelStore"; import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases'; import { IRightPanelCardState } from '../../../stores/right-panel/RightPanelStoreIPanelState'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { UPDATE_EVENT } from '../../../stores/AsyncStore'; import { NotificationColor } from '../../../stores/notifications/NotificationColor'; @@ -40,7 +39,6 @@ interface IState { interface IProps {} -@replaceableComponent("views.right_panel.HeaderButtons") export default abstract class HeaderButtons

extends React.Component { private unmounted = false; private dispatcherRef: string; diff --git a/src/components/views/right_panel/RoomHeaderButtons.tsx b/src/components/views/right_panel/RoomHeaderButtons.tsx index aa2a8ffd63..f44b8a181c 100644 --- a/src/components/views/right_panel/RoomHeaderButtons.tsx +++ b/src/components/views/right_panel/RoomHeaderButtons.tsx @@ -29,7 +29,6 @@ import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePha import { Action } from "../../../dispatcher/actions"; import { ActionPayload } from "../../../dispatcher/payloads"; import RightPanelStore from "../../../stores/right-panel/RightPanelStore"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { useSettingValue } from "../../../hooks/useSettings"; import { useReadPinnedEvents, usePinnedEvents } from './PinnedMessagesCard'; import { showThreadPanel } from "../../../dispatcher/dispatch-actions/threads"; @@ -125,7 +124,6 @@ interface IProps { excludedRightPanelPhaseButtons?: Array; } -@replaceableComponent("views.right_panel.RoomHeaderButtons") export default class RoomHeaderButtons extends HeaderButtons { private static readonly THREAD_PHASES = [ RightPanelPhases.ThreadPanel, diff --git a/src/components/views/right_panel/TimelineCard.tsx b/src/components/views/right_panel/TimelineCard.tsx index bd7d4361cb..82f651281c 100644 --- a/src/components/views/right_panel/TimelineCard.tsx +++ b/src/components/views/right_panel/TimelineCard.tsx @@ -33,7 +33,6 @@ import EditorStateTransfer from '../../../utils/EditorStateTransfer'; import RoomContext, { TimelineRenderingType } from '../../../contexts/RoomContext'; import dis from '../../../dispatcher/dispatcher'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from '../../../utils/replaceableComponent'; import { ActionPayload } from '../../../dispatcher/payloads'; import { Action } from '../../../dispatcher/actions'; import RoomViewStore from '../../../stores/RoomViewStore'; @@ -71,7 +70,6 @@ interface IState { showReadReceipts?: boolean; } -@replaceableComponent("structures.TimelineCard") export default class TimelineCard extends React.Component { static contextType = RoomContext; diff --git a/src/components/views/right_panel/VerificationPanel.tsx b/src/components/views/right_panel/VerificationPanel.tsx index f08c197962..65a24b21ad 100644 --- a/src/components/views/right_panel/VerificationPanel.tsx +++ b/src/components/views/right_panel/VerificationPanel.tsx @@ -33,7 +33,6 @@ import { _t } from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; import E2EIcon, { E2EState } from "../rooms/E2EIcon"; import Spinner from "../elements/Spinner"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AccessibleButton from "../elements/AccessibleButton"; import VerificationShowSas from "../verification/VerificationShowSas"; @@ -54,7 +53,6 @@ interface IState { reciprocateQREvent?: ReciprocateQRCode["reciprocateQREvent"]; } -@replaceableComponent("views.right_panel.VerificationPanel") export default class VerificationPanel extends React.PureComponent { private hasVerifier: boolean; diff --git a/src/components/views/room_settings/AliasSettings.tsx b/src/components/views/room_settings/AliasSettings.tsx index ec84544aae..df1d57661b 100644 --- a/src/components/views/room_settings/AliasSettings.tsx +++ b/src/components/views/room_settings/AliasSettings.tsx @@ -26,7 +26,6 @@ import ErrorDialog from "../dialogs/ErrorDialog"; import AccessibleButton from "../elements/AccessibleButton"; import Modal from "../../../Modal"; import RoomPublishSetting from "./RoomPublishSetting"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import RoomAliasField from "../elements/RoomAliasField"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import SettingsFieldset from "../settings/SettingsFieldset"; @@ -95,7 +94,6 @@ interface IState { newAltAlias?: string; } -@replaceableComponent("views.room_settings.AliasSettings") export default class AliasSettings extends React.Component { public static contextType = MatrixClientContext; context: ContextType; diff --git a/src/components/views/room_settings/RoomProfileSettings.tsx b/src/components/views/room_settings/RoomProfileSettings.tsx index eb0c6ded1a..aff117681c 100644 --- a/src/components/views/room_settings/RoomProfileSettings.tsx +++ b/src/components/views/room_settings/RoomProfileSettings.tsx @@ -19,7 +19,6 @@ import React, { createRef } from 'react'; import { _t } from "../../../languageHandler"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import Field from "../elements/Field"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; import AccessibleButton from "../elements/AccessibleButton"; import AvatarSetting from "../settings/AvatarSetting"; @@ -43,7 +42,6 @@ interface IState { } // TODO: Merge with ProfileSettings? -@replaceableComponent("views.room_settings.RoomProfileSettings") export default class RoomProfileSettings extends React.Component { private avatarUpload = createRef(); diff --git a/src/components/views/room_settings/RoomPublishSetting.tsx b/src/components/views/room_settings/RoomPublishSetting.tsx index 19eab62a8a..250635013d 100644 --- a/src/components/views/room_settings/RoomPublishSetting.tsx +++ b/src/components/views/room_settings/RoomPublishSetting.tsx @@ -20,7 +20,6 @@ import { Visibility } from "matrix-js-sdk/src/@types/partials"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import { _t } from "../../../languageHandler"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import DirectoryCustomisations from '../../../customisations/Directory'; interface IProps { @@ -33,7 +32,6 @@ interface IState { isRoomPublished: boolean; } -@replaceableComponent("views.room_settings.RoomPublishSetting") export default class RoomPublishSetting extends React.PureComponent { constructor(props, context) { super(props, context); diff --git a/src/components/views/room_settings/UrlPreviewSettings.tsx b/src/components/views/room_settings/UrlPreviewSettings.tsx index 7c94db16c3..5810ea7ad7 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.tsx +++ b/src/components/views/room_settings/UrlPreviewSettings.tsx @@ -26,7 +26,6 @@ import dis from "../../../dispatcher/dispatcher"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { Action } from "../../../dispatcher/actions"; import { SettingLevel } from "../../../settings/SettingLevel"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import SettingsFlag from "../elements/SettingsFlag"; import SettingsFieldset from '../settings/SettingsFieldset'; import AccessibleButton from '../elements/AccessibleButton'; @@ -35,7 +34,6 @@ interface IProps { room: Room; } -@replaceableComponent("views.room_settings.UrlPreviewSettings") export default class UrlPreviewSettings extends React.Component { private onClickUserSettings = (e: React.MouseEvent): void => { e.preventDefault(); diff --git a/src/components/views/rooms/AppsDrawer.tsx b/src/components/views/rooms/AppsDrawer.tsx index eebba4f67c..22afea2490 100644 --- a/src/components/views/rooms/AppsDrawer.tsx +++ b/src/components/views/rooms/AppsDrawer.tsx @@ -32,7 +32,6 @@ 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"; import UIStore from "../../../stores/UIStore"; import { IApp } from "../../../stores/WidgetStore"; import { ActionPayload } from "../../../dispatcher/payloads"; @@ -54,7 +53,6 @@ interface IState { resizing: boolean; } -@replaceableComponent("views.rooms.AppsDrawer") export default class AppsDrawer extends React.Component { private unmounted = false; private resizeContainer: HTMLDivElement; diff --git a/src/components/views/rooms/Autocomplete.tsx b/src/components/views/rooms/Autocomplete.tsx index d8d65ca113..58a659f537 100644 --- a/src/components/views/rooms/Autocomplete.tsx +++ b/src/components/views/rooms/Autocomplete.tsx @@ -22,7 +22,6 @@ import { Room } from 'matrix-js-sdk/src/models/room'; import Autocompleter, { ICompletion, ISelectionRange, IProviderCompletions } from '../../../autocomplete/Autocompleter'; import SettingsStore from "../../../settings/SettingsStore"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import RoomContext from '../../../contexts/RoomContext'; const MAX_PROVIDER_MATCHES = 20; @@ -50,7 +49,6 @@ interface IState { forceComplete: boolean; } -@replaceableComponent("views.rooms.Autocomplete") export default class Autocomplete extends React.PureComponent { autocompleter: Autocompleter; queryRequested: string; diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx index 8c723429c5..a7f9a12229 100644 --- a/src/components/views/rooms/AuxPanel.tsx +++ b/src/components/views/rooms/AuxPanel.tsx @@ -29,7 +29,6 @@ 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 @@ -51,7 +50,6 @@ interface IState { counters: Counter[]; } -@replaceableComponent("views.rooms.AuxPanel") export default class AuxPanel extends React.Component { static defaultProps = { showApps: true, diff --git a/src/components/views/rooms/BasicMessageComposer.tsx b/src/components/views/rooms/BasicMessageComposer.tsx index fe5669f8c4..89981bda90 100644 --- a/src/components/views/rooms/BasicMessageComposer.tsx +++ b/src/components/views/rooms/BasicMessageComposer.tsx @@ -43,7 +43,6 @@ import AutocompleteWrapperModel from "../../../editor/autocomplete"; import DocumentPosition from '../../../editor/position'; import { ICompletion } from "../../../autocomplete/Autocompleter"; import { getKeyBindingsManager } from '../../../KeyBindingsManager'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { ALTERNATE_KEY_NAME, KeyBindingAction } from '../../../accessibility/KeyboardShortcuts'; import { _t } from "../../../languageHandler"; @@ -112,7 +111,6 @@ interface IState { surroundWith: boolean; } -@replaceableComponent("views.rooms.BasicMessageEditor") export default class BasicMessageEditor extends React.Component { public readonly editorRef = createRef(); private autocompleteRef = createRef(); diff --git a/src/components/views/rooms/EditMessageComposer.tsx b/src/components/views/rooms/EditMessageComposer.tsx index b7564a5102..337ff7de25 100644 --- a/src/components/views/rooms/EditMessageComposer.tsx +++ b/src/components/views/rooms/EditMessageComposer.tsx @@ -35,7 +35,6 @@ import BasicMessageComposer, { REGEX_EMOTICON } from "./BasicMessageComposer"; import { CommandCategories } from '../../../SlashCommands'; import { Action } from "../../../dispatcher/actions"; import { getKeyBindingsManager } from '../../../KeyBindingsManager'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import SendHistoryManager from '../../../SendHistoryManager'; import { ActionPayload } from "../../../dispatcher/payloads"; import AccessibleButton from '../elements/AccessibleButton'; @@ -122,7 +121,6 @@ interface IState { saveDisabled: boolean; } -@replaceableComponent("views.rooms.EditMessageComposer") class EditMessageComposer extends React.Component { static contextType = RoomContext; context!: React.ContextType; diff --git a/src/components/views/rooms/EntityTile.tsx b/src/components/views/rooms/EntityTile.tsx index 1b459008de..c06d473299 100644 --- a/src/components/views/rooms/EntityTile.tsx +++ b/src/components/views/rooms/EntityTile.tsx @@ -22,7 +22,6 @@ import classNames from "classnames"; import AccessibleButton from '../elements/AccessibleButton'; import { _t, _td } from '../../../languageHandler'; import E2EIcon, { E2EState } from './E2EIcon'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseAvatar from '../avatars/BaseAvatar'; import PresenceLabel from "./PresenceLabel"; @@ -85,7 +84,6 @@ interface IState { hover: boolean; } -@replaceableComponent("views.rooms.EntityTile") export default class EntityTile extends React.PureComponent { static defaultProps = { onClick: () => {}, diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index b73ec31e29..d830a4f5a1 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -45,7 +45,6 @@ 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"; import Tooltip from "../elements/Tooltip"; import EditorStateTransfer from "../../../utils/EditorStateTransfer"; import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks'; @@ -347,7 +346,6 @@ interface IState { } // MUST be rendered within a RoomContext with a set timelineRenderingType -@replaceableComponent("views.rooms.EventTile") export class UnwrappedEventTile extends React.Component { private suppressReadReceiptAnimation: boolean; private isListeningForReceipts: boolean; diff --git a/src/components/views/rooms/LinkPreviewWidget.tsx b/src/components/views/rooms/LinkPreviewWidget.tsx index 5e7154dc8a..d14c504dd8 100644 --- a/src/components/views/rooms/LinkPreviewWidget.tsx +++ b/src/components/views/rooms/LinkPreviewWidget.tsx @@ -23,7 +23,6 @@ import { linkifyElement } from '../../../HtmlUtils'; import SettingsStore from "../../../settings/SettingsStore"; import Modal from "../../../Modal"; import * as ImageUtils from "../../../ImageUtils"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; import ImageView from '../elements/ImageView'; @@ -33,7 +32,6 @@ interface IProps { mxEvent: MatrixEvent; // the Event associated with the preview } -@replaceableComponent("views.rooms.LinkPreviewWidget") export default class LinkPreviewWidget extends React.Component { private readonly description = createRef(); private image = createRef(); diff --git a/src/components/views/rooms/MemberList.tsx b/src/components/views/rooms/MemberList.tsx index 8a9a728684..0500a33b92 100644 --- a/src/components/views/rooms/MemberList.tsx +++ b/src/components/views/rooms/MemberList.tsx @@ -36,7 +36,6 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg"; import BaseCard from "../right_panel/BaseCard"; import RoomAvatar from "../avatars/RoomAvatar"; import RoomName from "../elements/RoomName"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import SettingsStore from "../../../settings/SettingsStore"; import TruncatedList from '../elements/TruncatedList'; import Spinner from "../elements/Spinner"; @@ -74,7 +73,6 @@ interface IState { truncateAtInvited: number; } -@replaceableComponent("views.rooms.MemberList") export default class MemberList extends React.Component { private showPresence = true; private mounted = false; diff --git a/src/components/views/rooms/MemberTile.tsx b/src/components/views/rooms/MemberTile.tsx index 24039adef2..b652771a43 100644 --- a/src/components/views/rooms/MemberTile.tsx +++ b/src/components/views/rooms/MemberTile.tsx @@ -30,7 +30,6 @@ import dis from "../../../dispatcher/dispatcher"; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { Action } from "../../../dispatcher/actions"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import EntityTile, { PowerStatus } from "./EntityTile"; import MemberAvatar from "./../avatars/MemberAvatar"; import DisambiguatedProfile from "../messages/DisambiguatedProfile"; @@ -47,7 +46,6 @@ interface IState { e2eStatus: string; } -@replaceableComponent("views.rooms.MemberTile") export default class MemberTile extends React.Component { private userLastModifiedTime: number; private memberLastModifiedTime: number; diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 6bd41fcf93..aed4536aa0 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -35,7 +35,6 @@ import { aboveLeftOf, AboveLeftOf } from "../../structures/ContextMenu"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import ReplyPreview from "./ReplyPreview"; import { UPDATE_EVENT } from "../../../stores/AsyncStore"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import VoiceRecordComposerTile from "./VoiceRecordComposerTile"; import { VoiceRecordingStore } from "../../../stores/VoiceRecordingStore"; import { RecordingState, VoiceRecording } from "../../../audio/VoiceRecording"; @@ -91,7 +90,6 @@ interface IState { showPollsButton: boolean; } -@replaceableComponent("views.rooms.MessageComposer") export default class MessageComposer extends React.Component { private dispatcherRef: string; private messageComposerInput = createRef(); diff --git a/src/components/views/rooms/MessageComposerFormatBar.tsx b/src/components/views/rooms/MessageComposerFormatBar.tsx index b45be7b1c0..3258ce51af 100644 --- a/src/components/views/rooms/MessageComposerFormatBar.tsx +++ b/src/components/views/rooms/MessageComposerFormatBar.tsx @@ -19,7 +19,6 @@ import classNames from 'classnames'; import { _t } from '../../../languageHandler'; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; export enum Formatting { Bold = "bold", @@ -39,7 +38,6 @@ interface IState { visible: boolean; } -@replaceableComponent("views.rooms.MessageComposerFormatBar") export default class MessageComposerFormatBar extends React.PureComponent { private readonly formatBarRef = createRef(); diff --git a/src/components/views/rooms/NotificationBadge.tsx b/src/components/views/rooms/NotificationBadge.tsx index 09a35125d2..51745209aa 100644 --- a/src/components/views/rooms/NotificationBadge.tsx +++ b/src/components/views/rooms/NotificationBadge.tsx @@ -22,7 +22,6 @@ import SettingsStore from "../../../settings/SettingsStore"; import AccessibleButton from "../elements/AccessibleButton"; import { XOR } from "../../../@types/common"; import { NotificationState, NotificationStateEvents } from "../../../stores/notifications/NotificationState"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import Tooltip from "../elements/Tooltip"; import { _t } from "../../../languageHandler"; import { NotificationColor } from "../../../stores/notifications/NotificationColor"; @@ -55,7 +54,6 @@ interface IState { showTooltip: boolean; } -@replaceableComponent("views.rooms.NotificationBadge") export default class NotificationBadge extends React.PureComponent, IState> { private countWatcherRef: string; diff --git a/src/components/views/rooms/PinnedEventTile.tsx b/src/components/views/rooms/PinnedEventTile.tsx index 3aa3677a25..8f6247b5f6 100644 --- a/src/components/views/rooms/PinnedEventTile.tsx +++ b/src/components/views/rooms/PinnedEventTile.tsx @@ -29,7 +29,6 @@ import MessageEvent from "../messages/MessageEvent"; import MemberAvatar from "../avatars/MemberAvatar"; import { _t } from '../../../languageHandler'; import { formatDate } from '../../../DateUtils'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import { getUserNameColorClass } from "../../../utils/FormattingUtils"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; @@ -42,7 +41,6 @@ interface IProps { const AVATAR_SIZE = 24; -@replaceableComponent("views.rooms.PinnedEventTile") export default class PinnedEventTile extends React.Component { public static contextType = MatrixClientContext; diff --git a/src/components/views/rooms/PresenceLabel.tsx b/src/components/views/rooms/PresenceLabel.tsx index 0ae3047f01..91361db770 100644 --- a/src/components/views/rooms/PresenceLabel.tsx +++ b/src/components/views/rooms/PresenceLabel.tsx @@ -18,7 +18,6 @@ import React from 'react'; import { UnstableValue } from "matrix-js-sdk/src/NamespacedValue"; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; const BUSY_PRESENCE_NAME = new UnstableValue("busy", "org.matrix.msc3026.busy"); @@ -33,7 +32,6 @@ interface IProps { presenceState?: string; } -@replaceableComponent("views.rooms.PresenceLabel") export default class PresenceLabel extends React.Component { static defaultProps = { activeAgo: -1, diff --git a/src/components/views/rooms/ReadReceiptMarker.tsx b/src/components/views/rooms/ReadReceiptMarker.tsx index c83d6e1881..916d886447 100644 --- a/src/components/views/rooms/ReadReceiptMarker.tsx +++ b/src/components/views/rooms/ReadReceiptMarker.tsx @@ -23,7 +23,6 @@ import { _t } from '../../../languageHandler'; import { formatDate } from '../../../DateUtils'; import NodeAnimator from "../../../NodeAnimator"; import { toPx } from "../../../utils/units"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import MemberAvatar from '../avatars/MemberAvatar'; export interface IReadReceiptInfo { @@ -77,7 +76,6 @@ interface IReadReceiptMarkerStyle { left: number; } -@replaceableComponent("views.rooms.ReadReceiptMarker") export default class ReadReceiptMarker extends React.PureComponent { private avatar: React.RefObject = createRef(); diff --git a/src/components/views/rooms/ReplyPreview.tsx b/src/components/views/rooms/ReplyPreview.tsx index 69c0e14a45..72340e9981 100644 --- a/src/components/views/rooms/ReplyPreview.tsx +++ b/src/components/views/rooms/ReplyPreview.tsx @@ -20,7 +20,6 @@ import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; import dis from '../../../dispatcher/dispatcher'; import { _t } from '../../../languageHandler'; import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import ReplyTile from './ReplyTile'; import RoomContext, { TimelineRenderingType } from '../../../contexts/RoomContext'; @@ -37,7 +36,6 @@ interface IProps { replyToEvent: MatrixEvent; } -@replaceableComponent("views.rooms.ReplyPreview") export default class ReplyPreview extends React.Component { public static contextType = RoomContext; diff --git a/src/components/views/rooms/ReplyTile.tsx b/src/components/views/rooms/ReplyTile.tsx index 3668397dc1..95d249dd16 100644 --- a/src/components/views/rooms/ReplyTile.tsx +++ b/src/components/views/rooms/ReplyTile.tsx @@ -28,7 +28,6 @@ import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks'; import SenderProfile from "../messages/SenderProfile"; import MImageReplyBody from "../messages/MImageReplyBody"; import * as sdk from '../../../index'; -import { replaceableComponent } from '../../../utils/replaceableComponent'; import { getEventDisplayInfo, isVoiceMessage } from '../../../utils/EventUtils'; import MFileBody from "../messages/MFileBody"; import MVoiceMessageBody from "../messages/MVoiceMessageBody"; @@ -46,7 +45,6 @@ interface IProps { ); } -@replaceableComponent("views.rooms.ReplyTile") export default class ReplyTile extends React.PureComponent { private anchorElement = createRef(); diff --git a/src/components/views/rooms/RoomBreadcrumbs.tsx b/src/components/views/rooms/RoomBreadcrumbs.tsx index f4fc41c459..af06f41bf4 100644 --- a/src/components/views/rooms/RoomBreadcrumbs.tsx +++ b/src/components/views/rooms/RoomBreadcrumbs.tsx @@ -26,7 +26,6 @@ import Analytics from "../../../Analytics"; import { UPDATE_EVENT } from "../../../stores/AsyncStore"; import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex"; import Toolbar from "../../../accessibility/Toolbar"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { Action } from "../../../dispatcher/actions"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; @@ -71,7 +70,6 @@ const RoomBreadcrumbTile = ({ room, onClick }: { room: Room, onClick: (ev: Butto ); }; -@replaceableComponent("views.rooms.RoomBreadcrumbs") export default class RoomBreadcrumbs extends React.PureComponent { private isMounted = true; diff --git a/src/components/views/rooms/RoomDetailList.tsx b/src/components/views/rooms/RoomDetailList.tsx index 50a8f69d5e..eb909d1659 100644 --- a/src/components/views/rooms/RoomDetailList.tsx +++ b/src/components/views/rooms/RoomDetailList.tsx @@ -21,7 +21,6 @@ import classNames from 'classnames'; import dis from '../../../dispatcher/dispatcher'; import { Action } from '../../../dispatcher/actions'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import RoomDetailRow from "./RoomDetailRow"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; @@ -30,7 +29,6 @@ interface IProps { className?: string; } -@replaceableComponent("views.rooms.RoomDetailList") export default class RoomDetailList extends React.Component { private getRows(): JSX.Element[] { if (!this.props.rooms) return []; diff --git a/src/components/views/rooms/RoomDetailRow.js b/src/components/views/rooms/RoomDetailRow.js index 99ba410431..72d40cf6e0 100644 --- a/src/components/views/rooms/RoomDetailRow.js +++ b/src/components/views/rooms/RoomDetailRow.js @@ -20,7 +20,6 @@ import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { linkifyElement } from '../../../HtmlUtils'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; import { getDisplayAliasForAliasSet } from '../../../Rooms'; @@ -41,7 +40,6 @@ 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.tsx b/src/components/views/rooms/RoomHeader.tsx index 9df1ba663c..b9d3936cb8 100644 --- a/src/components/views/rooms/RoomHeader.tsx +++ b/src/components/views/rooms/RoomHeader.tsx @@ -30,7 +30,6 @@ import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import RoomTopic from "../elements/RoomTopic"; import RoomName from "../elements/RoomName"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { E2EStatus } from '../../../utils/ShieldUtils'; import { IOOBData } from '../../../stores/ThreepidInviteStore'; import { SearchScope } from './SearchBar'; @@ -67,7 +66,6 @@ interface IState { contextMenuPosition?: DOMRect; } -@replaceableComponent("views.rooms.RoomHeader") export default class RoomHeader extends React.Component { static defaultProps = { editing: false, diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx index d54ac55ffb..6444cbfe67 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/RoomList.tsx @@ -51,7 +51,6 @@ import { UPDATE_SUGGESTED_ROOMS, } from "../../../stores/spaces"; import { shouldShowSpaceInvite, showAddExistingRooms, showCreateNewRoom, showSpaceInvite } from "../../../utils/space"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import RoomAvatar from "../avatars/RoomAvatar"; import { shouldShowComponent } from "../../../customisations/helpers/UIComponents"; import { UIComponent } from "../../../settings/UIFeature"; @@ -349,7 +348,6 @@ const TAG_AESTHETICS: ITagAestheticsMap = { }, }; -@replaceableComponent("views.rooms.RoomList") export default class RoomList extends React.PureComponent { private dispatcherRef; private roomStoreToken: fbEmitter.EventSubscription; diff --git a/src/components/views/rooms/RoomPreviewBar.tsx b/src/components/views/rooms/RoomPreviewBar.tsx index 97a1f3e8e4..600c6c7cb1 100644 --- a/src/components/views/rooms/RoomPreviewBar.tsx +++ b/src/components/views/rooms/RoomPreviewBar.tsx @@ -27,7 +27,6 @@ import dis from '../../../dispatcher/dispatcher'; import { _t } from '../../../languageHandler'; import SdkConfig from "../../../SdkConfig"; import IdentityAuthClient from '../../../IdentityAuthClient'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import InviteReason from "../elements/InviteReason"; import { IOOBData } from "../../../stores/ThreepidInviteStore"; import Spinner from "../elements/Spinner"; @@ -98,7 +97,6 @@ interface IState { threePidFetchError?: MatrixError; } -@replaceableComponent("views.rooms.RoomPreviewBar") export default class RoomPreviewBar extends React.Component { static defaultProps = { onJoinClick() {}, diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx index 3f03d11a76..f0a6616714 100644 --- a/src/components/views/rooms/RoomSublist.tsx +++ b/src/components/views/rooms/RoomSublist.tsx @@ -54,7 +54,6 @@ import { objectExcluding, objectHasDiff } from "../../../utils/objects"; import ExtraTile from "./ExtraTile"; import { ListNotificationState } from "../../../stores/notifications/ListNotificationState"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; @@ -104,7 +103,6 @@ interface IState { filteredExtraTiles?: ReactComponentElement[]; } -@replaceableComponent("views.rooms.RoomSublist") export default class RoomSublist extends React.Component { private headerButton = createRef(); private sublistRef = createRef(); diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index bdea7ea9f8..6fbe956361 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -57,7 +57,6 @@ import IconizedContextMenu, { } from "../context_menus/IconizedContextMenu"; import VoiceChannelStore, { VoiceChannelEvent, IJitsiParticipant } from "../../../stores/VoiceChannelStore"; import { getConnectedMembers } from "../../../utils/VoiceChannelUtils"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import PosthogTrackers from "../../../PosthogTrackers"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; @@ -100,7 +99,6 @@ export const contextMenuBelow = (elementRect: PartialDOMRect) => { return { left, top, chevronFace }; }; -@replaceableComponent("views.rooms.RoomTile") export default class RoomTile extends React.PureComponent { private dispatcherRef: string; private roomTileRef = createRef(); diff --git a/src/components/views/rooms/RoomUpgradeWarningBar.tsx b/src/components/views/rooms/RoomUpgradeWarningBar.tsx index a9b121919b..47d19b8b5e 100644 --- a/src/components/views/rooms/RoomUpgradeWarningBar.tsx +++ b/src/components/views/rooms/RoomUpgradeWarningBar.tsx @@ -21,7 +21,6 @@ import { RoomStateEvent } from 'matrix-js-sdk/src/models/room-state'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import RoomUpgradeDialog from '../dialogs/RoomUpgradeDialog'; import AccessibleButton from '../elements/AccessibleButton'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; @@ -34,7 +33,6 @@ interface IState { upgraded?: boolean; } -@replaceableComponent("views.rooms.RoomUpgradeWarningBar") export default class RoomUpgradeWarningBar extends React.PureComponent { static contextType = MatrixClientContext; public context!: React.ContextType; diff --git a/src/components/views/rooms/SearchBar.tsx b/src/components/views/rooms/SearchBar.tsx index 7331a93e05..c42131bba0 100644 --- a/src/components/views/rooms/SearchBar.tsx +++ b/src/components/views/rooms/SearchBar.tsx @@ -21,7 +21,6 @@ import classNames from "classnames"; import AccessibleButton from "../elements/AccessibleButton"; import { _t } from '../../../languageHandler'; import DesktopBuildsNotice, { WarningKind } from "../elements/DesktopBuildsNotice"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { PosthogScreenTracker } from '../../../PosthogTrackers'; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; @@ -42,7 +41,6 @@ export enum SearchScope { All = "All", } -@replaceableComponent("views.rooms.SearchBar") export default class SearchBar extends React.Component { private searchTerm: RefObject = createRef(); diff --git a/src/components/views/rooms/SearchResultTile.tsx b/src/components/views/rooms/SearchResultTile.tsx index 9dd673dff2..85bd5c0ed6 100644 --- a/src/components/views/rooms/SearchResultTile.tsx +++ b/src/components/views/rooms/SearchResultTile.tsx @@ -22,7 +22,6 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext"; import SettingsStore from "../../../settings/SettingsStore"; import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import DateSeparator from "../messages/DateSeparator"; import EventTile, { haveTileForEvent } from "./EventTile"; import { shouldFormContinuation } from "../../structures/MessagePanel"; @@ -40,7 +39,6 @@ interface IProps { permalinkCreator?: RoomPermalinkCreator; } -@replaceableComponent("views.rooms.SearchResultTile") export default class SearchResultTile extends React.Component { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx index 2bbf8294f7..713f46d435 100644 --- a/src/components/views/rooms/SendMessageComposer.tsx +++ b/src/components/views/rooms/SendMessageComposer.tsx @@ -47,7 +47,6 @@ import { containsEmoji } from "../../../effects/utils"; import { CHAT_EFFECTS } from '../../../effects'; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { getKeyBindingsManager } from '../../../KeyBindingsManager'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import SettingsStore from '../../../settings/SettingsStore'; import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; import { ActionPayload } from "../../../dispatcher/payloads"; @@ -147,7 +146,6 @@ interface ISendMessageComposerProps extends MatrixClientProps { toggleStickerPickerOpen: () => void; } -@replaceableComponent("views.rooms.SendMessageComposer") export class SendMessageComposer extends React.Component { static contextType = RoomContext; public context!: React.ContextType; diff --git a/src/components/views/rooms/Stickerpicker.tsx b/src/components/views/rooms/Stickerpicker.tsx index c5de28b1d8..d6595e61fb 100644 --- a/src/components/views/rooms/Stickerpicker.tsx +++ b/src/components/views/rooms/Stickerpicker.tsx @@ -30,7 +30,6 @@ import SettingsStore from "../../../settings/SettingsStore"; import ContextMenu, { ChevronFace } from "../../structures/ContextMenu"; import { WidgetType } from "../../../widgets/WidgetType"; import { WidgetMessagingStore } from "../../../stores/widgets/WidgetMessagingStore"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { ActionPayload } from '../../../dispatcher/payloads'; import ScalarAuthClient from '../../../ScalarAuthClient'; import GenericElementContextMenu from "../context_menus/GenericElementContextMenu"; @@ -59,7 +58,6 @@ interface IState { widgetId: string; } -@replaceableComponent("views.rooms.Stickerpicker") export default class Stickerpicker extends React.PureComponent { static defaultProps = { threadId: null, diff --git a/src/components/views/rooms/ThirdPartyMemberInfo.tsx b/src/components/views/rooms/ThirdPartyMemberInfo.tsx index b12348f842..6ff87cf52a 100644 --- a/src/components/views/rooms/ThirdPartyMemberInfo.tsx +++ b/src/components/views/rooms/ThirdPartyMemberInfo.tsx @@ -28,7 +28,6 @@ import Modal from "../../../Modal"; import { isValid3pidInvite } from "../../../RoomInvite"; import RoomAvatar from "../avatars/RoomAvatar"; import RoomName from "../elements/RoomName"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import ErrorDialog from '../dialogs/ErrorDialog'; import AccessibleButton from '../elements/AccessibleButton'; @@ -45,7 +44,6 @@ interface IState { senderName: string; } -@replaceableComponent("views.rooms.ThirdPartyMemberInfo") export default class ThirdPartyMemberInfo extends React.Component { private room: Room; diff --git a/src/components/views/rooms/TopUnreadMessagesBar.tsx b/src/components/views/rooms/TopUnreadMessagesBar.tsx index a9cb451783..f39b5ed58c 100644 --- a/src/components/views/rooms/TopUnreadMessagesBar.tsx +++ b/src/components/views/rooms/TopUnreadMessagesBar.tsx @@ -18,14 +18,12 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import AccessibleButton from '../elements/AccessibleButton'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { onScrollUpClick?: (e: React.MouseEvent) => void; onCloseClick?: (e: React.MouseEvent) => void; } -@replaceableComponent("views.rooms.TopUnreadMessagesBar") export default class TopUnreadMessagesBar extends React.PureComponent { public render(): JSX.Element { return ( diff --git a/src/components/views/rooms/VoiceRecordComposerTile.tsx b/src/components/views/rooms/VoiceRecordComposerTile.tsx index 448883645e..f31fc8f9fc 100644 --- a/src/components/views/rooms/VoiceRecordComposerTile.tsx +++ b/src/components/views/rooms/VoiceRecordComposerTile.tsx @@ -25,7 +25,6 @@ import { _t } from "../../../languageHandler"; import { IUpload, RecordingState, VoiceRecording } from "../../../audio/VoiceRecording"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import LiveRecordingWaveform from "../audio_messages/LiveRecordingWaveform"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import LiveRecordingClock from "../audio_messages/LiveRecordingClock"; import { VoiceRecordingStore } from "../../../stores/VoiceRecordingStore"; import { UPDATE_EVENT } from "../../../stores/AsyncStore"; @@ -52,7 +51,6 @@ interface IState { /** * Container tile for rendering the voice message recorder in the composer. */ -@replaceableComponent("views.rooms.VoiceRecordComposerTile") export default class VoiceRecordComposerTile extends React.PureComponent { public constructor(props) { super(props); diff --git a/src/components/views/rooms/WhoIsTypingTile.tsx b/src/components/views/rooms/WhoIsTypingTile.tsx index f0df814c87..e736a67012 100644 --- a/src/components/views/rooms/WhoIsTypingTile.tsx +++ b/src/components/views/rooms/WhoIsTypingTile.tsx @@ -24,7 +24,6 @@ import * as WhoIsTyping from '../../../WhoIsTyping'; import Timer from '../../../utils/Timer'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import MemberAvatar from '../avatars/MemberAvatar'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { compare } from "../../../utils/strings"; interface IProps { @@ -47,7 +46,6 @@ interface IState { delayedStopTypingTimers: Record; } -@replaceableComponent("views.rooms.WhoIsTypingTile") export default class WhoIsTypingTile extends React.Component { static defaultProps = { whoIsTypingLimit: 3, diff --git a/src/components/views/settings/BridgeTile.tsx b/src/components/views/settings/BridgeTile.tsx index 5fa06e3ff3..7cc3d5e114 100644 --- a/src/components/views/settings/BridgeTile.tsx +++ b/src/components/views/settings/BridgeTile.tsx @@ -26,7 +26,6 @@ import { makeUserPermalink } from "../../../utils/permalinks/Permalinks"; import BaseAvatar from "../avatars/BaseAvatar"; import SettingsStore from "../../../settings/SettingsStore"; import { isUrlPermitted } from '../../../HtmlUtils'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; interface IProps { @@ -66,7 +65,6 @@ interface IBridgeStateEvent { }; } -@replaceableComponent("views.settings.BridgeTile") export default class BridgeTile extends React.PureComponent { static propTypes = { ev: PropTypes.object.isRequired, diff --git a/src/components/views/settings/ChangeAvatar.tsx b/src/components/views/settings/ChangeAvatar.tsx index 98cc17f75d..e56de0b204 100644 --- a/src/components/views/settings/ChangeAvatar.tsx +++ b/src/components/views/settings/ChangeAvatar.tsx @@ -23,7 +23,6 @@ import { EventType } from "matrix-js-sdk/src/@types/event"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { _t } from '../../../languageHandler'; import Spinner from '../elements/Spinner'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; import RoomAvatar from '../avatars/RoomAvatar'; import BaseAvatar from '../avatars/BaseAvatar'; @@ -50,7 +49,6 @@ enum Phases { Error = "error", } -@replaceableComponent("views.settings.ChangeAvatar") export default class ChangeAvatar extends React.Component { public static defaultProps = { showUploadSection: true, diff --git a/src/components/views/settings/ChangeDisplayName.tsx b/src/components/views/settings/ChangeDisplayName.tsx index 3e1ff0cb7d..e3af9f51dd 100644 --- a/src/components/views/settings/ChangeDisplayName.tsx +++ b/src/components/views/settings/ChangeDisplayName.tsx @@ -18,10 +18,8 @@ import React from 'react'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import EditableTextContainer from "../elements/EditableTextContainer"; -@replaceableComponent("views.settings.ChangeDisplayName") export default class ChangeDisplayName extends React.Component { private getDisplayName = async (): Promise => { const cli = MatrixClientPeg.get(); diff --git a/src/components/views/settings/ChangePassword.tsx b/src/components/views/settings/ChangePassword.tsx index 0c5520f3a3..f736e5f6f5 100644 --- a/src/components/views/settings/ChangePassword.tsx +++ b/src/components/views/settings/ChangePassword.tsx @@ -26,7 +26,6 @@ import withValidation, { IFieldState, IValidationResult } from '../elements/Vali import { _t, _td } from '../../../languageHandler'; import Modal from "../../../Modal"; import PassphraseField from "../auth/PassphraseField"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { PASSWORD_MIN_SCORE } from '../auth/RegistrationForm'; import SetEmailDialog from "../dialogs/SetEmailDialog"; import QuestionDialog from "../dialogs/QuestionDialog"; @@ -63,7 +62,6 @@ interface IState { newPasswordConfirm: string; } -@replaceableComponent("views.settings.ChangePassword") export default class ChangePassword extends React.Component { public static defaultProps: Partial = { onFinished() {}, diff --git a/src/components/views/settings/CrossSigningPanel.tsx b/src/components/views/settings/CrossSigningPanel.tsx index e5e018be6a..5c6e650c9f 100644 --- a/src/components/views/settings/CrossSigningPanel.tsx +++ b/src/components/views/settings/CrossSigningPanel.tsx @@ -25,7 +25,6 @@ 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"; import SetupEncryptionDialog from '../dialogs/security/SetupEncryptionDialog'; import { accessSecretStorage } from '../../../SecurityManager'; import AccessibleButton from "../elements/AccessibleButton"; @@ -41,7 +40,6 @@ interface IState { crossSigningReady?: boolean; } -@replaceableComponent("views.settings.CrossSigningPanel") export default class CrossSigningPanel extends React.PureComponent<{}, IState> { private unmounted = false; diff --git a/src/components/views/settings/CryptographyPanel.tsx b/src/components/views/settings/CryptographyPanel.tsx index 365c24ab40..dd580058af 100644 --- a/src/components/views/settings/CryptographyPanel.tsx +++ b/src/components/views/settings/CryptographyPanel.tsx @@ -19,7 +19,6 @@ import React, { ComponentType } from 'react'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AccessibleButton from "../elements/AccessibleButton"; import * as FormattingUtils from "../../../utils/FormattingUtils"; import SettingsStore from "../../../settings/SettingsStore"; @@ -32,7 +31,6 @@ interface IProps { interface IState { } -@replaceableComponent("views.settings.CryptographyPanel") export default class CryptographyPanel extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/settings/DevicesPanel.tsx b/src/components/views/settings/DevicesPanel.tsx index 0b19d5605e..4779c013be 100644 --- a/src/components/views/settings/DevicesPanel.tsx +++ b/src/components/views/settings/DevicesPanel.tsx @@ -24,7 +24,6 @@ import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; import { SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import InteractiveAuthDialog from "../dialogs/InteractiveAuthDialog"; import DevicesPanelEntry from "./DevicesPanelEntry"; import Spinner from "../elements/Spinner"; @@ -42,7 +41,6 @@ interface IState { deleting?: boolean; } -@replaceableComponent("views.settings.DevicesPanel") export default class DevicesPanel extends React.Component { private unmounted = false; diff --git a/src/components/views/settings/DevicesPanelEntry.tsx b/src/components/views/settings/DevicesPanelEntry.tsx index dccfc70598..33a5939aa2 100644 --- a/src/components/views/settings/DevicesPanelEntry.tsx +++ b/src/components/views/settings/DevicesPanelEntry.tsx @@ -23,7 +23,6 @@ import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { formatDate } from '../../../DateUtils'; import StyledCheckbox from '../elements/StyledCheckbox'; import { CheckboxStyle } from '../elements/StyledCheckbox'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AccessibleButton from "../elements/AccessibleButton"; import Field from "../elements/Field"; import TextWithTooltip from "../elements/TextWithTooltip"; @@ -47,7 +46,6 @@ interface IState { displayName: string; } -@replaceableComponent("views.settings.DevicesPanelEntry") export default class DevicesPanelEntry extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/settings/EventIndexPanel.tsx b/src/components/views/settings/EventIndexPanel.tsx index 9966e38de8..03ae821d5c 100644 --- a/src/components/views/settings/EventIndexPanel.tsx +++ b/src/components/views/settings/EventIndexPanel.tsx @@ -24,7 +24,6 @@ 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"; import SeshatResetDialog from '../dialogs/SeshatResetDialog'; import InlineSpinner from '../elements/InlineSpinner'; @@ -35,7 +34,6 @@ interface IState { eventIndexingEnabled: boolean; } -@replaceableComponent("views.settings.EventIndexPanel") export default class EventIndexPanel extends React.Component<{}, IState> { constructor(props) { super(props); diff --git a/src/components/views/settings/FontScalingPanel.tsx b/src/components/views/settings/FontScalingPanel.tsx index a9950dfcd9..55a36d256d 100644 --- a/src/components/views/settings/FontScalingPanel.tsx +++ b/src/components/views/settings/FontScalingPanel.tsx @@ -27,7 +27,6 @@ import { Layout } from "../../../settings/enums/Layout"; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { SettingLevel } from "../../../settings/SettingLevel"; import { _t } from "../../../languageHandler"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { } @@ -45,7 +44,6 @@ interface IState { avatarUrl: string; } -@replaceableComponent("views.settings.tabs.user.FontScalingPanel") export default class FontScalingPanel extends React.Component { private readonly MESSAGE_PREVIEW_TEXT = _t("Hey you. You're the best!"); diff --git a/src/components/views/settings/IntegrationManager.tsx b/src/components/views/settings/IntegrationManager.tsx index c2faa126d2..d9a45860dc 100644 --- a/src/components/views/settings/IntegrationManager.tsx +++ b/src/components/views/settings/IntegrationManager.tsx @@ -18,7 +18,6 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import dis from '../../../dispatcher/dispatcher'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { ActionPayload } from '../../../dispatcher/payloads'; import Spinner from "../elements/Spinner"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; @@ -42,7 +41,6 @@ interface IState { errored: boolean; } -@replaceableComponent("views.settings.IntegrationManager") export default class IntegrationManager extends React.Component { private dispatcherRef: string; diff --git a/src/components/views/settings/ProfileSettings.tsx b/src/components/views/settings/ProfileSettings.tsx index 2088ec3abe..9db1d49d83 100644 --- a/src/components/views/settings/ProfileSettings.tsx +++ b/src/components/views/settings/ProfileSettings.tsx @@ -24,7 +24,6 @@ import { getHostingLink } from '../../../utils/HostingLink'; import { OwnProfileStore } from "../../../stores/OwnProfileStore"; import Modal from "../../../Modal"; import ErrorDialog from "../dialogs/ErrorDialog"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; import AccessibleButton from '../elements/AccessibleButton'; import AvatarSetting from './AvatarSetting'; @@ -41,7 +40,6 @@ interface IState { enableProfileSave?: boolean; } -@replaceableComponent("views.settings.ProfileSettings") export default class ProfileSettings extends React.Component<{}, IState> { private avatarUpload: React.RefObject = createRef(); diff --git a/src/components/views/settings/SecureBackupPanel.tsx b/src/components/views/settings/SecureBackupPanel.tsx index ab489ad0ef..da5df6c7a7 100644 --- a/src/components/views/settings/SecureBackupPanel.tsx +++ b/src/components/views/settings/SecureBackupPanel.tsx @@ -30,7 +30,6 @@ 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"; interface IState { loading: boolean; @@ -45,7 +44,6 @@ interface IState { sessionsRemaining: number; } -@replaceableComponent("views.settings.SecureBackupPanel") export default class SecureBackupPanel extends React.PureComponent<{}, IState> { private unmounted = false; diff --git a/src/components/views/settings/SetIdServer.tsx b/src/components/views/settings/SetIdServer.tsx index d38e908332..d50ae3d361 100644 --- a/src/components/views/settings/SetIdServer.tsx +++ b/src/components/views/settings/SetIdServer.tsx @@ -27,7 +27,6 @@ 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"; import { ActionPayload } from '../../../dispatcher/payloads'; import InlineSpinner from '../elements/InlineSpinner'; import AccessibleButton from '../elements/AccessibleButton'; @@ -80,7 +79,6 @@ interface IState { checking: boolean; } -@replaceableComponent("views.settings.SetIdServer") export default class SetIdServer extends React.Component { private dispatcherRef: string; diff --git a/src/components/views/settings/SetIntegrationManager.tsx b/src/components/views/settings/SetIntegrationManager.tsx index 100afea9a6..557cbaea61 100644 --- a/src/components/views/settings/SetIntegrationManager.tsx +++ b/src/components/views/settings/SetIntegrationManager.tsx @@ -22,7 +22,6 @@ import { IntegrationManagers } from "../../../integrations/IntegrationManagers"; import { IntegrationManagerInstance } from "../../../integrations/IntegrationManagerInstance"; import SettingsStore from "../../../settings/SettingsStore"; import { SettingLevel } from "../../../settings/SettingLevel"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import ToggleSwitch from "../elements/ToggleSwitch"; interface IProps { @@ -34,7 +33,6 @@ interface IState { provisioningEnabled: boolean; } -@replaceableComponent("views.settings.SetIntegrationManager") export default class SetIntegrationManager extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/settings/SpellCheckSettings.tsx b/src/components/views/settings/SpellCheckSettings.tsx index 2864be34fc..83c3492a87 100644 --- a/src/components/views/settings/SpellCheckSettings.tsx +++ b/src/components/views/settings/SpellCheckSettings.tsx @@ -19,7 +19,6 @@ 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; @@ -55,7 +54,6 @@ export class ExistingSpellCheckLanguage extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/settings/ThemeChoicePanel.tsx b/src/components/views/settings/ThemeChoicePanel.tsx index 3296acff7e..cc4545e9ea 100644 --- a/src/components/views/settings/ThemeChoicePanel.tsx +++ b/src/components/views/settings/ThemeChoicePanel.tsx @@ -29,7 +29,6 @@ import StyledCheckbox from '../elements/StyledCheckbox'; import Field from '../elements/Field'; import StyledRadioGroup from "../elements/StyledRadioGroup"; import { SettingLevel } from "../../../settings/SettingLevel"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import PosthogTrackers from "../../../PosthogTrackers"; interface IProps { @@ -50,7 +49,6 @@ interface IState extends IThemeState { customThemeMessage: CustomThemeMessage; } -@replaceableComponent("views.settings.tabs.user.ThemeChoicePanel") export default class ThemeChoicePanel extends React.Component { private themeTimer: number; diff --git a/src/components/views/settings/account/EmailAddresses.tsx b/src/components/views/settings/account/EmailAddresses.tsx index 75a72f192c..9ee1ae742b 100644 --- a/src/components/views/settings/account/EmailAddresses.tsx +++ b/src/components/views/settings/account/EmailAddresses.tsx @@ -26,7 +26,6 @@ import AccessibleButton from "../../elements/AccessibleButton"; import * as Email from "../../../../email"; import AddThreepid from "../../../../AddThreepid"; import Modal from '../../../../Modal'; -import { replaceableComponent } from "../../../../utils/replaceableComponent"; import ErrorDialog from "../../dialogs/ErrorDialog"; /* @@ -136,7 +135,6 @@ interface IState { newEmailAddress: string; } -@replaceableComponent("views.settings.account.EmailAddresses") export default class EmailAddresses extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/settings/account/PhoneNumbers.tsx b/src/components/views/settings/account/PhoneNumbers.tsx index 770bdb889d..d2751fddbb 100644 --- a/src/components/views/settings/account/PhoneNumbers.tsx +++ b/src/components/views/settings/account/PhoneNumbers.tsx @@ -26,7 +26,6 @@ import AccessibleButton from "../../elements/AccessibleButton"; import AddThreepid from "../../../../AddThreepid"; import CountryDropdown from "../../auth/CountryDropdown"; import Modal from '../../../../Modal'; -import { replaceableComponent } from "../../../../utils/replaceableComponent"; import ErrorDialog from "../../dialogs/ErrorDialog"; import { PhoneNumberCountryDefinition } from "../../../../phonenumber"; @@ -136,7 +135,6 @@ interface IState { newPhoneNumberCode: string; } -@replaceableComponent("views.settings.account.PhoneNumbers") export default class PhoneNumbers extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/settings/discovery/EmailAddresses.tsx b/src/components/views/settings/discovery/EmailAddresses.tsx index 316e20202e..8d94797ef0 100644 --- a/src/components/views/settings/discovery/EmailAddresses.tsx +++ b/src/components/views/settings/discovery/EmailAddresses.tsx @@ -23,7 +23,6 @@ import { _t } from "../../../../languageHandler"; import { MatrixClientPeg } from "../../../../MatrixClientPeg"; import Modal from '../../../../Modal'; import AddThreepid from '../../../../AddThreepid'; -import { replaceableComponent } from "../../../../utils/replaceableComponent"; import ErrorDialog from "../../dialogs/ErrorDialog"; import AccessibleButton from "../../elements/AccessibleButton"; @@ -244,7 +243,6 @@ interface IProps { emails: IThreepid[]; } -@replaceableComponent("views.settings.discovery.EmailAddresses") export default class EmailAddresses extends React.Component { public render(): JSX.Element { let content; diff --git a/src/components/views/settings/discovery/PhoneNumbers.tsx b/src/components/views/settings/discovery/PhoneNumbers.tsx index 13bef06e4b..add8759a85 100644 --- a/src/components/views/settings/discovery/PhoneNumbers.tsx +++ b/src/components/views/settings/discovery/PhoneNumbers.tsx @@ -23,7 +23,6 @@ import { _t } from "../../../../languageHandler"; import { MatrixClientPeg } from "../../../../MatrixClientPeg"; import Modal from '../../../../Modal'; import AddThreepid from '../../../../AddThreepid'; -import { replaceableComponent } from "../../../../utils/replaceableComponent"; import ErrorDialog from "../../dialogs/ErrorDialog"; import Field from "../../elements/Field"; import AccessibleButton from "../../elements/AccessibleButton"; @@ -260,7 +259,6 @@ interface IProps { msisdns: IThreepid[]; } -@replaceableComponent("views.settings.discovery.PhoneNumbers") export default class PhoneNumbers extends React.Component { public render(): JSX.Element { let content; diff --git a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.tsx index 97f388d893..15b87b084f 100644 --- a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.tsx @@ -24,7 +24,6 @@ import RoomUpgradeDialog from "../../../dialogs/RoomUpgradeDialog"; import Modal from "../../../../../Modal"; import dis from "../../../../../dispatcher/dispatcher"; import { Action } from '../../../../../dispatcher/actions'; -import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import CopyableText from "../../../elements/CopyableText"; import { ViewRoomPayload } from "../../../../../dispatcher/payloads/ViewRoomPayload"; @@ -46,7 +45,6 @@ interface IState { upgraded?: boolean; } -@replaceableComponent("views.settings.tabs.room.AdvancedRoomSettingsTab") export default class AdvancedRoomSettingsTab extends React.Component { constructor(props, context) { super(props, context); diff --git a/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx b/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx index 58cb7447f9..1e1b54dc93 100644 --- a/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx @@ -21,7 +21,6 @@ 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", @@ -34,7 +33,6 @@ interface IProps { roomId: string; } -@replaceableComponent("views.settings.tabs.room.BridgeSettingsTab") export default class BridgeSettingsTab extends React.Component { private renderBridgeCard(event: MatrixEvent, room: Room) { const content = event.getContent(); diff --git a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx index 0e5f188d2d..e531f0c2a6 100644 --- a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx @@ -23,7 +23,6 @@ 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"; import UrlPreviewSettings from "../../../room_settings/UrlPreviewSettings"; import AliasSettings from "../../../room_settings/AliasSettings"; import PosthogTrackers from "../../../../../PosthogTrackers"; @@ -36,7 +35,6 @@ interface IState { isRoomPublished: boolean; } -@replaceableComponent("views.settings.tabs.room.GeneralRoomSettingsTab") export default class GeneralRoomSettingsTab extends React.Component { public static contextType = MatrixClientContext; context: ContextType; diff --git a/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx b/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx index cf732bc052..6084d500ce 100644 --- a/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx @@ -23,7 +23,6 @@ import AccessibleButton from "../../../elements/AccessibleButton"; import Notifier from "../../../../../Notifier"; import SettingsStore from '../../../../../settings/SettingsStore'; import { SettingLevel } from "../../../../../settings/SettingLevel"; -import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import { RoomEchoChamber } from "../../../../../stores/local-echo/RoomEchoChamber"; import { EchoChamber } from '../../../../../stores/local-echo/EchoChamber'; import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; @@ -43,7 +42,6 @@ interface IState { uploadedFile: File; } -@replaceableComponent("views.settings.tabs.room.NotificationsSettingsTab") export default class NotificationsSettingsTab extends React.Component { private readonly roomProps: RoomEchoChamber; private soundUpload = createRef(); diff --git a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx index 27d72a46f0..e519ec0bf7 100644 --- a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx @@ -25,7 +25,6 @@ import { _t, _td } from "../../../../../languageHandler"; import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import AccessibleButton from "../../../elements/AccessibleButton"; import Modal from "../../../../../Modal"; -import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import { compare } from "../../../../../utils/strings"; import ErrorDialog from '../../../dialogs/ErrorDialog'; import PowerSelector from "../../../elements/PowerSelector"; @@ -120,7 +119,6 @@ interface IProps { roomId: string; } -@replaceableComponent("views.settings.tabs.room.RolesRoomSettingsTab") export default class RolesRoomSettingsTab extends React.Component { componentDidMount() { MatrixClientPeg.get().on(RoomStateEvent.Update, this.onRoomStateUpdate); diff --git a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx index eed93c31f2..b9e2d94594 100644 --- a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx @@ -30,7 +30,6 @@ 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"; import AccessibleButton from "../../../elements/AccessibleButton"; import SettingsFlag from '../../../elements/SettingsFlag'; import createRoom, { IOpts } from '../../../../../createRoom'; @@ -55,7 +54,6 @@ interface IState { showAdvancedSection: boolean; } -@replaceableComponent("views.settings.tabs.room.SecurityRoomSettingsTab") export default class SecurityRoomSettingsTab extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx index 5561df050d..30e7882f10 100644 --- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx @@ -26,7 +26,6 @@ import Field from '../../../elements/Field'; import { SettingLevel } from "../../../../../settings/SettingLevel"; import { UIFeature } from "../../../../../settings/UIFeature"; import { Layout } from "../../../../../settings/enums/Layout"; -import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import LayoutSwitcher from "../../LayoutSwitcher"; import FontScalingPanel from '../../FontScalingPanel'; import ThemeChoicePanel from '../../ThemeChoicePanel'; @@ -46,7 +45,6 @@ interface IState { avatarUrl: string; } -@replaceableComponent("views.settings.tabs.user.AppearanceUserSettingsTab") export default class AppearanceUserSettingsTab extends React.Component { private readonly MESSAGE_PREVIEW_TEXT = _t("Hey you. You're the best!"); diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx index 14851b5bec..7db27b009e 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx @@ -40,7 +40,6 @@ import { getThreepidsWithBindStatus } from '../../../../../boundThreepids'; import Spinner from "../../../elements/Spinner"; import { SettingLevel } from "../../../../../settings/SettingLevel"; import { UIFeature } from "../../../../../settings/UIFeature"; -import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import { ActionPayload } from "../../../../../dispatcher/payloads"; import ErrorDialog from "../../../dialogs/ErrorDialog"; import AccountPhoneNumbers from "../../account/PhoneNumbers"; @@ -78,7 +77,6 @@ interface IState { idServerName: string; } -@replaceableComponent("views.settings.tabs.user.GeneralUserSettingsTab") export default class GeneralUserSettingsTab extends React.Component { private readonly dispatcherRef: string; diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx index 119cc27d35..527dd1ae44 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx @@ -25,7 +25,6 @@ import createRoom from "../../../../../createRoom"; import Modal from "../../../../../Modal"; import PlatformPeg from "../../../../../PlatformPeg"; import UpdateCheckButton from "../../UpdateCheckButton"; -import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import BugReportDialog from '../../../dialogs/BugReportDialog'; import { OpenToTabPayload } from "../../../../../dispatcher/payloads/OpenToTabPayload"; import { Action } from "../../../../../dispatcher/actions"; @@ -42,7 +41,6 @@ interface IState { canUpdate: boolean; } -@replaceableComponent("views.settings.tabs.user.HelpUserSettingsTab") export default class HelpUserSettingsTab extends React.Component { constructor(props) { super(props); diff --git a/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx b/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx index c632f2207d..9e0b31b2ad 100644 --- a/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/LabsUserSettingsTab.tsx @@ -21,7 +21,6 @@ import { _t } from "../../../../../languageHandler"; import SettingsStore from "../../../../../settings/SettingsStore"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import { SettingLevel } from "../../../../../settings/SettingLevel"; -import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import SdkConfig from "../../../../../SdkConfig"; import BetaCard from "../../../beta/BetaCard"; import SettingsFlag from '../../../elements/SettingsFlag'; @@ -52,7 +51,6 @@ interface IState { showJumpToDate: boolean; } -@replaceableComponent("views.settings.tabs.user.LabsUserSettingsTab") export default class LabsUserSettingsTab extends React.Component<{}, IState> { constructor(props: {}) { super(props); diff --git a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx index 88000892e4..709b3e8c56 100644 --- a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx @@ -24,7 +24,6 @@ import { ListRule } from "../../../../../mjolnir/ListRule"; import { BanList, RULE_SERVER, RULE_USER } from "../../../../../mjolnir/BanList"; import Modal from "../../../../../Modal"; import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; -import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import ErrorDialog from "../../../dialogs/ErrorDialog"; import QuestionDialog from "../../../dialogs/QuestionDialog"; import AccessibleButton from "../../../elements/AccessibleButton"; @@ -36,7 +35,6 @@ interface IState { newList: string; } -@replaceableComponent("views.settings.tabs.user.MjolnirUserSettingsTab") export default class MjolnirUserSettingsTab extends React.Component<{}, IState> { constructor(props) { super(props); diff --git a/src/components/views/settings/tabs/user/NotificationUserSettingsTab.tsx b/src/components/views/settings/tabs/user/NotificationUserSettingsTab.tsx index 429472c7f5..b49cf3920e 100644 --- a/src/components/views/settings/tabs/user/NotificationUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/NotificationUserSettingsTab.tsx @@ -17,10 +17,8 @@ limitations under the License. import React from 'react'; import { _t } from "../../../../../languageHandler"; -import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import Notifications from "../../Notifications"; -@replaceableComponent("views.settings.tabs.user.NotificationUserSettingsTab") export default class NotificationUserSettingsTab extends React.Component { render() { return ( diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx index e70bb4b5d3..e6457605cc 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx @@ -23,7 +23,6 @@ import SettingsStore from "../../../../../settings/SettingsStore"; import Field from "../../../elements/Field"; import PlatformPeg from "../../../../../PlatformPeg"; import { SettingLevel } from "../../../../../settings/SettingLevel"; -import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import SettingsFlag from '../../../elements/SettingsFlag'; import AccessibleButton from "../../../elements/AccessibleButton"; import dis from "../../../../../dispatcher/dispatcher"; @@ -49,7 +48,6 @@ interface IState { readMarkerOutOfViewThresholdMs: string; } -@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.tsx b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx index aa66d0203a..a88e244fe5 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx @@ -30,7 +30,6 @@ import SecureBackupPanel from "../../SecureBackupPanel"; import SettingsStore from "../../../../../settings/SettingsStore"; import { UIFeature } from "../../../../../settings/UIFeature"; import E2eAdvancedPanel, { isE2eAdvancedPanelPossible } from "../../E2eAdvancedPanel"; -import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import { ActionPayload } from "../../../../../dispatcher/payloads"; import CryptographyPanel from "../../CryptographyPanel"; import DevicesPanel from "../../DevicesPanel"; @@ -76,7 +75,6 @@ interface IState { invitedRoomIds: Set; } -@replaceableComponent("views.settings.tabs.user.SecurityUserSettingsTab") export default class SecurityUserSettingsTab extends React.Component { private dispatcherRef: string; diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx index b187e300a2..18a0b0b288 100644 --- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx @@ -26,7 +26,6 @@ import AccessibleButton from "../../../elements/AccessibleButton"; import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import Modal from "../../../../../Modal"; import { SettingLevel } from "../../../../../settings/SettingLevel"; -import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import SettingsFlag from '../../../elements/SettingsFlag'; import ErrorDialog from '../../../dialogs/ErrorDialog'; @@ -46,7 +45,6 @@ interface IState extends Record { mediaDevices: IMediaDevices; } -@replaceableComponent("views.settings.tabs.user.VoiceUserSettingsTab") export default class VoiceUserSettingsTab extends React.Component<{}, IState> { constructor(props: {}) { super(props); diff --git a/src/components/views/terms/InlineTermsAgreement.tsx b/src/components/views/terms/InlineTermsAgreement.tsx index a7ba47aa7c..2cca51e670 100644 --- a/src/components/views/terms/InlineTermsAgreement.tsx +++ b/src/components/views/terms/InlineTermsAgreement.tsx @@ -19,7 +19,6 @@ import React from "react"; import { _t, pickBestLanguage } from "../../../languageHandler"; import { objectClone } from "../../../utils/objects"; import StyledCheckbox from "../elements/StyledCheckbox"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import AccessibleButton from "../elements/AccessibleButton"; interface IProps { @@ -40,7 +39,6 @@ interface Policy { name: string; } -@replaceableComponent("views.terms.InlineTermsAgreement") export default class InlineTermsAgreement extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/toasts/NonUrgentEchoFailureToast.tsx b/src/components/views/toasts/NonUrgentEchoFailureToast.tsx index 91407a4fa5..931cb3b3f1 100644 --- a/src/components/views/toasts/NonUrgentEchoFailureToast.tsx +++ b/src/components/views/toasts/NonUrgentEchoFailureToast.tsx @@ -20,9 +20,7 @@ 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 341be988c4..b424f43900 100644 --- a/src/components/views/toasts/VerificationRequestToast.tsx +++ b/src/components/views/toasts/VerificationRequestToast.tsx @@ -31,7 +31,6 @@ import ToastStore from "../../../stores/ToastStore"; import Modal from "../../../Modal"; import GenericToast from "./GenericToast"; import { Action } from "../../../dispatcher/actions"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import VerificationRequestDialog from "../dialogs/VerificationRequestDialog"; import RightPanelStore from "../../../stores/right-panel/RightPanelStore"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; @@ -47,7 +46,6 @@ interface IState { ip?: string; } -@replaceableComponent("views.toasts.VerificationRequestToast") export default class VerificationRequestToast extends React.PureComponent { private intervalHandle: number; diff --git a/src/components/views/verification/VerificationCancelled.tsx b/src/components/views/verification/VerificationCancelled.tsx index 2a08dfaa68..3cc7b9b620 100644 --- a/src/components/views/verification/VerificationCancelled.tsx +++ b/src/components/views/verification/VerificationCancelled.tsx @@ -17,14 +17,12 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import DialogButtons from "../elements/DialogButtons"; interface IProps { onDone: () => void; } -@replaceableComponent("views.verification.VerificationCancelled") export default class VerificationCancelled extends React.Component { public render(): React.ReactNode { return

diff --git a/src/components/views/verification/VerificationComplete.tsx b/src/components/views/verification/VerificationComplete.tsx index 88bdd70d22..48419d5ea0 100644 --- a/src/components/views/verification/VerificationComplete.tsx +++ b/src/components/views/verification/VerificationComplete.tsx @@ -17,14 +17,12 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import DialogButtons from "../elements/DialogButtons"; interface IProps { onDone: () => void; } -@replaceableComponent("views.verification.VerificationComplete") export default class VerificationComplete extends React.Component { public render(): React.ReactNode { return
diff --git a/src/components/views/verification/VerificationShowSas.tsx b/src/components/views/verification/VerificationShowSas.tsx index 2615a57b4b..e9c5fcf441 100644 --- a/src/components/views/verification/VerificationShowSas.tsx +++ b/src/components/views/verification/VerificationShowSas.tsx @@ -22,7 +22,6 @@ import { _t, _td } from '../../../languageHandler'; import { PendingActionSpinner } from "../right_panel/EncryptionInfo"; import AccessibleButton from "../elements/AccessibleButton"; import { fixupColorFonts } from '../../../utils/FontManager'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { pending?: boolean; @@ -44,7 +43,6 @@ function capFirst(s) { return s.charAt(0).toUpperCase() + s.slice(1); } -@replaceableComponent("views.verification.VerificationShowSas") export default class VerificationShowSas extends React.Component { constructor(props: IProps) { super(props); diff --git a/src/components/views/voip/CallView.tsx b/src/components/views/voip/CallView.tsx index a809adcf41..af7180c5a2 100644 --- a/src/components/views/voip/CallView.tsx +++ b/src/components/views/voip/CallView.tsx @@ -30,7 +30,6 @@ import VideoFeed from './VideoFeed'; import RoomAvatar from "../avatars/RoomAvatar"; import AccessibleButton from '../elements/AccessibleButton'; import { avatarUrlForMember } from '../../../Avatar'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import DesktopCapturerSourcePicker from "../elements/DesktopCapturerSourcePicker"; import Modal from '../../../Modal'; import CallViewSidebar from './CallViewSidebar'; @@ -103,7 +102,6 @@ function exitFullscreen() { if (exitMethod) exitMethod.call(document); } -@replaceableComponent("views.voip.CallView") export default class CallView extends React.Component { private dispatcherRef: string; private contentRef = createRef(); diff --git a/src/components/views/voip/CallViewForRoom.tsx b/src/components/views/voip/CallViewForRoom.tsx index 25fbf4a501..1a44387654 100644 --- a/src/components/views/voip/CallViewForRoom.tsx +++ b/src/components/views/voip/CallViewForRoom.tsx @@ -21,7 +21,6 @@ import { Resizable } from "re-resizable"; import CallHandler, { CallHandlerEvent } from '../../../CallHandler'; import CallView from './CallView'; import ResizeNotifier from "../../../utils/ResizeNotifier"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { // What room we should display the call for @@ -40,7 +39,6 @@ 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 { constructor(props: IProps) { super(props); diff --git a/src/components/views/voip/DialPad.tsx b/src/components/views/voip/DialPad.tsx index 4af98a4a35..5e584f6b70 100644 --- a/src/components/views/voip/DialPad.tsx +++ b/src/components/views/voip/DialPad.tsx @@ -17,7 +17,6 @@ limitations under the License. import * as React from "react"; import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import { _t } from "../../../languageHandler"; const BUTTONS = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#']; @@ -66,7 +65,6 @@ interface IProps { onDialPress?: () => void; } -@replaceableComponent("views.voip.DialPad") export default class Dialpad extends React.PureComponent { render() { const buttonNodes = []; diff --git a/src/components/views/voip/DialPadModal.tsx b/src/components/views/voip/DialPadModal.tsx index 6432ccf5e1..321cd4b070 100644 --- a/src/components/views/voip/DialPadModal.tsx +++ b/src/components/views/voip/DialPadModal.tsx @@ -20,7 +20,6 @@ import { createRef } from "react"; import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; import Field from "../elements/Field"; import DialPad from './DialPad'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import DialPadBackspaceButton from "../elements/DialPadBackspaceButton"; import CallHandler from "../../../CallHandler"; @@ -32,7 +31,6 @@ interface IState { value: string; } -@replaceableComponent("views.voip.DialPadModal") export default class DialpadModal extends React.PureComponent { private numberEntryFieldRef: React.RefObject = createRef(); diff --git a/src/components/views/voip/PictureInPictureDragger.tsx b/src/components/views/voip/PictureInPictureDragger.tsx index 126f60fdc0..be32ab2cd9 100644 --- a/src/components/views/voip/PictureInPictureDragger.tsx +++ b/src/components/views/voip/PictureInPictureDragger.tsx @@ -19,7 +19,6 @@ import React, { createRef } from 'react'; import UIStore from '../../../stores/UIStore'; import { lerp } from '../../../utils/AnimationUtils'; import { MarkedExecution } from '../../../utils/MarkedExecution'; -import { replaceableComponent } from '../../../utils/replaceableComponent'; const PIP_VIEW_WIDTH = 336; const PIP_VIEW_HEIGHT = 232; @@ -56,7 +55,6 @@ interface IState { * PictureInPictureDragger 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.PictureInPictureDragger") export default class PictureInPictureDragger extends React.Component { private callViewWrapper = createRef(); private initX = 0; diff --git a/src/components/views/voip/PipContainer.tsx b/src/components/views/voip/PipContainer.tsx index 1d3438aec6..2d74b5d131 100644 --- a/src/components/views/voip/PipContainer.tsx +++ b/src/components/views/voip/PipContainer.tsx @@ -18,7 +18,6 @@ limitations under the License. import React from 'react'; import PipView from './PipView'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { @@ -28,7 +27,6 @@ interface IState { } -@replaceableComponent("views.voip.PiPContainer") export default class PiPContainer extends React.PureComponent { public render() { return
diff --git a/src/components/views/voip/PipView.tsx b/src/components/views/voip/PipView.tsx index b3f3b0695d..3bd26c2043 100644 --- a/src/components/views/voip/PipView.tsx +++ b/src/components/views/voip/PipView.tsx @@ -26,7 +26,6 @@ import CallHandler, { CallHandlerEvent } from '../../../CallHandler'; import PersistentApp from "../elements/PersistentApp"; import SettingsStore from "../../../settings/SettingsStore"; import { MatrixClientPeg } from '../../../MatrixClientPeg'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; import PictureInPictureDragger from './PictureInPictureDragger'; import dis from '../../../dispatcher/dispatcher'; import { Action } from "../../../dispatcher/actions"; @@ -105,7 +104,6 @@ function getPrimarySecondaryCallsForPip(roomId: string): [MatrixCall, MatrixCall * and all widgets that are active but not shown in any other possible container. */ -@replaceableComponent("views.voip.PipView") export default class PipView extends React.Component { private roomStoreToken: EventSubscription; private settingsWatcherRef: string; diff --git a/src/components/views/voip/VideoFeed.tsx b/src/components/views/voip/VideoFeed.tsx index 81c00959c1..a9f83e9bc2 100644 --- a/src/components/views/voip/VideoFeed.tsx +++ b/src/components/views/voip/VideoFeed.tsx @@ -23,7 +23,6 @@ import { SDPStreamMetadataPurpose } from 'matrix-js-sdk/src/webrtc/callEventType import SettingsStore from "../../../settings/SettingsStore"; import MemberAvatar from "../avatars/MemberAvatar"; -import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { call: MatrixCall; @@ -48,7 +47,6 @@ interface IState { videoMuted: boolean; } -@replaceableComponent("views.voip.VideoFeed") export default class VideoFeed extends React.PureComponent { private element: HTMLVideoElement; diff --git a/src/toasts/IncomingCallToast.tsx b/src/toasts/IncomingCallToast.tsx index 555a14653e..7b27744c95 100644 --- a/src/toasts/IncomingCallToast.tsx +++ b/src/toasts/IncomingCallToast.tsx @@ -21,7 +21,6 @@ import React from 'react'; import { CallType, MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; import classNames from 'classnames'; -import { replaceableComponent } from '../utils/replaceableComponent'; import CallHandler, { CallHandlerEvent } from '../CallHandler'; import { MatrixClientPeg } from '../MatrixClientPeg'; import { _t } from '../languageHandler'; @@ -39,7 +38,6 @@ interface IState { silenced: boolean; } -@replaceableComponent("views.voip.IncomingCallToast") export default class IncomingCallToast extends React.Component { constructor(props: IProps) { super(props); From 15b84bd9a65e16cbbcea6cb0bb8552ba44e15705 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 2 Mar 2022 13:49:44 -0700 Subject: [PATCH 02/47] Step 2: Remove the decorator --- babel.config.js | 1 - package.json | 1 - src/utils/replaceableComponent.ts | 43 ----------------------------- test/end-to-end-tests/tsconfig.json | 4 +-- tsconfig.json | 4 +-- yarn.lock | 27 ++---------------- 6 files changed, 6 insertions(+), 74 deletions(-) delete mode 100644 src/utils/replaceableComponent.ts diff --git a/babel.config.js b/babel.config.js index f00e83652c..ac94a29559 100644 --- a/babel.config.js +++ b/babel.config.js @@ -13,7 +13,6 @@ module.exports = { "@babel/preset-react", ], "plugins": [ - ["@babel/plugin-proposal-decorators", {legacy: true}], "@babel/plugin-proposal-export-default-from", "@babel/plugin-proposal-numeric-separator", "@babel/plugin-proposal-class-properties", diff --git a/package.json b/package.json index abba2bb753..dd4586917e 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,6 @@ "@babel/eslint-plugin": "^7.12.10", "@babel/parser": "^7.12.11", "@babel/plugin-proposal-class-properties": "^7.12.1", - "@babel/plugin-proposal-decorators": "^7.12.12", "@babel/plugin-proposal-export-default-from": "^7.12.1", "@babel/plugin-proposal-numeric-separator": "^7.12.7", "@babel/plugin-proposal-object-rest-spread": "^7.12.1", diff --git a/src/utils/replaceableComponent.ts b/src/utils/replaceableComponent.ts deleted file mode 100644 index 3f085adbf0..0000000000 --- a/src/utils/replaceableComponent.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* -Copyright 2019 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import * as React from 'react'; - -import * as sdk from '../index'; - -/** - * Replaces a component with a skinned version if a skinned version exists. - * This decorator should only be applied to components which can be skinned. For - * the react-sdk this means all components should be decorated with this. - * - * The decoration works by assuming the skin has been loaded prior to the - * decorator being called. If that's not the case, the developer will find - * out quickly through various amounts of errors and explosions. - * - * For a bit more detail on how this works, see docs/skinning.md - * @param {string} name The dot-path name of the component being replaced. - * @param {React.Component} origComponent The component that can be replaced - * with a skinned version. If no skinned version is available, this component - * will be used. Note that this is automatically provided to the function and - * thus is optional for purposes of types. - * @returns {ClassDecorator} The decorator. - */ -export function replaceableComponent(name: string, origComponent?: React.Component): ClassDecorator { - // Decorators return a function to override the class (origComponent). This - // ultimately assumes that `getComponent()` won't throw an error and instead - // return a falsey value like `null` when the skin doesn't have a component. - return () => sdk.getComponent(name) || origComponent; -} diff --git a/test/end-to-end-tests/tsconfig.json b/test/end-to-end-tests/tsconfig.json index 7c818bd866..e4ab37b568 100644 --- a/test/end-to-end-tests/tsconfig.json +++ b/test/end-to-end-tests/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "experimentalDecorators": true, - "emitDecoratorMetadata": true, + "experimentalDecorators": false, + "emitDecoratorMetadata": false, "resolveJsonModule": true, "module": "commonjs", "moduleResolution": "node", diff --git a/tsconfig.json b/tsconfig.json index ff416f630c..ec0d70c8e0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "experimentalDecorators": true, - "emitDecoratorMetadata": true, + "experimentalDecorators": false, + "emitDecoratorMetadata": false, "resolveJsonModule": true, "esModuleInterop": true, "module": "commonjs", diff --git a/yarn.lock b/yarn.lock index 02515a76fb..ef46068322 100644 --- a/yarn.lock +++ b/yarn.lock @@ -132,7 +132,7 @@ browserslist "^4.17.5" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.1": +"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7": version "7.17.1" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz#9699f14a88833a7e055ce57dcd3ffdcd25186b21" integrity sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ== @@ -370,17 +370,6 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-proposal-decorators@^7.12.12": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.2.tgz#c36372ddfe0360cac1ee331a238310bddca11493" - integrity sha512-WH8Z95CwTq/W8rFbMqb9p3hicpt4RX4f0K659ax2VHxgOyT6qQmUaEVEjIh4WR9Eh9NymkVn5vwsrE68fAQNUw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.1" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/plugin-syntax-decorators" "^7.17.0" - charcodes "^0.2.0" - "@babel/plugin-proposal-dynamic-import@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz#c19c897eaa46b27634a00fee9fb7d829158704b2" @@ -519,13 +508,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-decorators@^7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz#a2be3b2c9fe7d78bd4994e790896bc411e2f166d" - integrity sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" @@ -2850,11 +2832,6 @@ character-reference-invalid@^1.0.0: resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== -charcodes@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/charcodes/-/charcodes-0.2.0.tgz#5208d327e6cc05f99eb80ffc814707572d1f14e4" - integrity sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ== - cheerio-select@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-1.5.0.tgz#faf3daeb31b17c5e1a9dabcee288aaf8aafa5823" @@ -6295,7 +6272,7 @@ matrix-events-sdk@^0.0.1-beta.7: bs58 "^4.0.1" content-type "^1.0.4" loglevel "^1.7.1" - matrix-events-sdk "^0.0.1-beta.7" + matrix-events-sdk "^0.0.1-beta.6" p-retry "^4.5.0" qs "^6.9.6" request "^2.88.2" From 26dc2ba45ebd741b5e6912c8939dda1303fe5fd5 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 2 Mar 2022 14:09:24 -0700 Subject: [PATCH 03/47] Step 3.1: Stop using `getComponent` in tests --- test/components/structures/MessagePanel-test.js | 10 ++++++---- test/components/structures/auth/Login-test.tsx | 13 +++++-------- .../components/structures/auth/Registration-test.js | 9 +++------ .../views/beacon/LeftPanelLiveShareWarning-test.tsx | 1 - .../views/beacon/RoomLiveShareWarning-test.tsx | 1 - .../views/beacon/StyledLiveBeaconIcon-test.tsx | 1 - .../views/dialogs/AccessSecretStorageDialog-test.js | 4 +--- .../views/dialogs/InteractiveAuthDialog-test.js | 6 +----- .../views/elements/EventListSummary-test.js | 4 ++-- .../views/location/LiveDurationDropdown-test.tsx | 1 - .../views/location/LocationButton-test.tsx | 3 --- test/components/views/location/MapError-test.tsx | 1 - .../views/messages/DateSeparator-test.tsx | 4 +--- .../views/messages/MLocationBody-test.tsx | 3 --- test/components/views/messages/MPollBody-test.tsx | 4 +--- test/components/views/messages/TextualBody-test.js | 3 +-- .../views/right_panel/PinnedMessagesCard-test.tsx | 1 - .../components/views/rooms/MessageComposer-test.tsx | 1 - .../views/rooms/MessageComposerButtons-test.tsx | 4 +--- test/components/views/rooms/RoomList-test.js | 10 ++++------ test/components/views/rooms/RoomTile-test.tsx | 1 - .../views/rooms/SearchResultTile-test.tsx | 4 +--- .../views/voip/VoiceChannelRadio-test.tsx | 1 - 23 files changed, 27 insertions(+), 63 deletions(-) diff --git a/test/components/structures/MessagePanel-test.js b/test/components/structures/MessagePanel-test.js index 6f703b772d..1471c52eb8 100644 --- a/test/components/structures/MessagePanel-test.js +++ b/test/components/structures/MessagePanel-test.js @@ -24,7 +24,6 @@ import { mount } from "enzyme"; import * as TestUtils from "react-dom/test-utils"; import { MatrixClientPeg } from '../../../src/MatrixClientPeg'; -import sdk from '../../skinned-sdk'; import MessagePanel, { shouldFormContinuation } from "../../../src/components/structures/MessagePanel"; import SettingsStore from "../../../src/settings/SettingsStore"; import MatrixClientContext from "../../../src/contexts/MatrixClientContext"; @@ -32,6 +31,9 @@ import RoomContext from "../../../src/contexts/RoomContext"; import DMRoomMap from "../../../src/utils/DMRoomMap"; import { UnwrappedEventTile } from "../../../src/components/views/rooms/EventTile"; import * as TestUtilsMatrix from "../../test-utils"; +import EventListSummary from "../../../src/components/views/elements/EventListSummary"; +import GenericEventListSummary from "../../../src/components/views/elements/GenericEventListSummary"; +import DateSeparator from "../../../src/components/views/messages/DateSeparator"; let client; const room = new Matrix.Room("!roomId:server_name"); @@ -298,7 +300,7 @@ describe('MessagePanel', function() { expect(tiles.length).toEqual(2); const summaryTiles = TestUtils.scryRenderedComponentsWithType( - res, sdk.getComponent('elements.EventListSummary'), + res, EventListSummary, ); expect(summaryTiles.length).toEqual(1); }); @@ -443,7 +445,7 @@ describe('MessagePanel', function() { expect(tiles.at(0).props().mxEvent.getType()).toEqual("m.room.create"); expect(tiles.at(1).props().mxEvent.getType()).toEqual("m.room.encryption"); - const summaryTiles = res.find(sdk.getComponent('views.elements.GenericEventListSummary')); + const summaryTiles = res.find(GenericEventListSummary); const summaryTile = summaryTiles.at(0); const summaryEventTiles = summaryTile.find(UnwrappedEventTile); @@ -483,7 +485,7 @@ describe('MessagePanel', function() { events={events} />, ); - const Dates = res.find(sdk.getComponent('messages.DateSeparator')); + const Dates = res.find(DateSeparator); expect(Dates.length).toEqual(1); }); diff --git a/test/components/structures/auth/Login-test.tsx b/test/components/structures/auth/Login-test.tsx index 6d4acda762..af7e2599f0 100644 --- a/test/components/structures/auth/Login-test.tsx +++ b/test/components/structures/auth/Login-test.tsx @@ -20,9 +20,10 @@ import ReactTestUtils from 'react-dom/test-utils'; import { mocked } from 'jest-mock'; import { createClient, MatrixClient } from "matrix-js-sdk/src/matrix"; -import sdk from '../../../skinned-sdk'; import SdkConfig from '../../../../src/SdkConfig'; import { mkServerConfig } from "../../../test-utils"; +import Login from "../../../../src/components/structures/auth/Login"; +import PasswordLogin from "../../../../src/components/views/auth/PasswordLogin"; jest.mock("matrix-js-sdk/src/matrix"); @@ -30,10 +31,6 @@ const flushPromises = async () => await new Promise(process.nextTick); jest.useRealTimers(); -const Login = sdk.getComponent( - 'structures.auth.Login', -); - describe('Login', function() { let parentDiv; const mockClient = mocked({ @@ -80,7 +77,7 @@ describe('Login', function() { const form = ReactTestUtils.findRenderedComponentWithType( root, - sdk.getComponent('auth.PasswordLogin'), + PasswordLogin, ); expect(form).toBeTruthy(); @@ -94,7 +91,7 @@ describe('Login', function() { const form = ReactTestUtils.findRenderedComponentWithType( root, - sdk.getComponent('auth.PasswordLogin'), + PasswordLogin, ); expect(form).toBeTruthy(); @@ -118,7 +115,7 @@ describe('Login', function() { const root = render(); await flushPromises(); - const form = ReactTestUtils.findRenderedComponentWithType(root, sdk.getComponent('auth.PasswordLogin')); + const form = ReactTestUtils.findRenderedComponentWithType(root, PasswordLogin); expect(form).toBeTruthy(); const ssoButton = ReactTestUtils.findRenderedDOMComponentWithClass(root, "mx_SSOButton"); diff --git a/test/components/structures/auth/Registration-test.js b/test/components/structures/auth/Registration-test.js index 5e9d3c4d61..7a6fb0c976 100644 --- a/test/components/structures/auth/Registration-test.js +++ b/test/components/structures/auth/Registration-test.js @@ -19,17 +19,14 @@ import ReactDOM from 'react-dom'; import ReactTestUtils from 'react-dom/test-utils'; import { createClient } from 'matrix-js-sdk/src/matrix'; -import sdk from '../../../skinned-sdk'; import SdkConfig, { DEFAULTS } from '../../../../src/SdkConfig'; import { createTestClient, mkServerConfig } from "../../../test-utils"; +import Registration from "../../../../src/components/structures/auth/Registration"; +import RegistrationForm from "../../../../src/components/views/auth/RegistrationForm"; jest.mock('matrix-js-sdk/src/matrix'); jest.useFakeTimers(); -const Registration = sdk.getComponent( - 'structures.auth.Registration', -); - describe('Registration', function() { let parentDiv; @@ -79,7 +76,7 @@ describe('Registration', function() { const form = ReactTestUtils.findRenderedComponentWithType( root, - sdk.getComponent('auth.RegistrationForm'), + RegistrationForm, ); expect(form).toBeTruthy(); }); diff --git a/test/components/views/beacon/LeftPanelLiveShareWarning-test.tsx b/test/components/views/beacon/LeftPanelLiveShareWarning-test.tsx index 7ad06fcf12..680e61b89f 100644 --- a/test/components/views/beacon/LeftPanelLiveShareWarning-test.tsx +++ b/test/components/views/beacon/LeftPanelLiveShareWarning-test.tsx @@ -18,7 +18,6 @@ import React from 'react'; import { mocked } from 'jest-mock'; import { mount } from 'enzyme'; -import '../../../skinned-sdk'; import LeftPanelLiveShareWarning from '../../../../src/components/views/beacon/LeftPanelLiveShareWarning'; import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../../src/stores/OwnBeaconStore'; import { flushPromises } from '../../../test-utils'; diff --git a/test/components/views/beacon/RoomLiveShareWarning-test.tsx b/test/components/views/beacon/RoomLiveShareWarning-test.tsx index 93835c21a3..062ea04feb 100644 --- a/test/components/views/beacon/RoomLiveShareWarning-test.tsx +++ b/test/components/views/beacon/RoomLiveShareWarning-test.tsx @@ -20,7 +20,6 @@ import { mount } from 'enzyme'; import { Room, Beacon, BeaconEvent } from 'matrix-js-sdk/src/matrix'; import { logger } from 'matrix-js-sdk/src/logger'; -import '../../../skinned-sdk'; import RoomLiveShareWarning from '../../../../src/components/views/beacon/RoomLiveShareWarning'; import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../../src/stores/OwnBeaconStore'; import { diff --git a/test/components/views/beacon/StyledLiveBeaconIcon-test.tsx b/test/components/views/beacon/StyledLiveBeaconIcon-test.tsx index 38fc8391d5..f239a26470 100644 --- a/test/components/views/beacon/StyledLiveBeaconIcon-test.tsx +++ b/test/components/views/beacon/StyledLiveBeaconIcon-test.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from 'react'; import { mount } from 'enzyme'; -import '../../../skinned-sdk'; import StyledLiveBeaconIcon from '../../../../src/components/views/beacon/StyledLiveBeaconIcon'; describe('', () => { diff --git a/test/components/views/dialogs/AccessSecretStorageDialog-test.js b/test/components/views/dialogs/AccessSecretStorageDialog-test.js index b429da4bc6..d90b23baac 100644 --- a/test/components/views/dialogs/AccessSecretStorageDialog-test.js +++ b/test/components/views/dialogs/AccessSecretStorageDialog-test.js @@ -18,12 +18,10 @@ import React from 'react'; import { mount } from 'enzyme'; import { act } from 'react-dom/test-utils'; -import sdk from '../../../skinned-sdk'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import { stubClient } from '../../../test-utils'; import { findById, flushPromises } from '../../../test-utils'; - -const AccessSecretStorageDialog = sdk.getComponent("dialogs.security.AccessSecretStorageDialog"); +import AccessSecretStorageDialog from "../../../../src/components/views/dialogs/security/AccessSecretStorageDialog"; describe("AccessSecretStorageDialog", function() { it("Closes the dialog if _onRecoveryKeyNext is called with a valid key", async () => { diff --git a/test/components/views/dialogs/InteractiveAuthDialog-test.js b/test/components/views/dialogs/InteractiveAuthDialog-test.js index 86c803be2c..798a30886c 100644 --- a/test/components/views/dialogs/InteractiveAuthDialog-test.js +++ b/test/components/views/dialogs/InteractiveAuthDialog-test.js @@ -20,13 +20,9 @@ import ReactTestUtils from 'react-dom/test-utils'; import MatrixReactTestUtils from 'matrix-react-test-utils'; import { sleep } from "matrix-js-sdk/src/utils"; -import sdk from '../../../skinned-sdk'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import * as TestUtilsMatrix from '../../../test-utils'; - -const InteractiveAuthDialog = sdk.getComponent( - 'views.dialogs.InteractiveAuthDialog', -); +import InteractiveAuthDialog from "../../../../src/components/views/dialogs/InteractiveAuthDialog"; describe('InteractiveAuthDialog', function() { let parentDiv; diff --git a/test/components/views/elements/EventListSummary-test.js b/test/components/views/elements/EventListSummary-test.js index 0fb21ecced..9ca5863aee 100644 --- a/test/components/views/elements/EventListSummary-test.js +++ b/test/components/views/elements/EventListSummary-test.js @@ -2,11 +2,11 @@ import React from 'react'; import ReactTestUtils from 'react-dom/test-utils'; import ShallowRenderer from "react-test-renderer/shallow"; -import sdk from '../../../skinned-sdk'; import * as testUtils from '../../../test-utils'; +import _EventListSummary from "../../../../src/components/views/elements/EventListSummary"; // Give ELS a matrixClient in its child context -const EventListSummary = testUtils.wrapInMatrixClientContext(sdk.getComponent('views.elements.EventListSummary')); +const EventListSummary = testUtils.wrapInMatrixClientContext(_EventListSummary); describe('EventListSummary', function() { // Generate dummy event tiles for use in simulating an expanded MELS diff --git a/test/components/views/location/LiveDurationDropdown-test.tsx b/test/components/views/location/LiveDurationDropdown-test.tsx index 864639db06..b07b9b9d22 100644 --- a/test/components/views/location/LiveDurationDropdown-test.tsx +++ b/test/components/views/location/LiveDurationDropdown-test.tsx @@ -18,7 +18,6 @@ import React from 'react'; import { mount } from 'enzyme'; import { act } from 'react-dom/test-utils'; -import '../../../skinned-sdk'; import LiveDurationDropdown, { DEFAULT_DURATION_MS } from '../../../../src/components/views/location/LiveDurationDropdown'; import { findById, mockPlatformPeg } from '../../../test-utils'; diff --git a/test/components/views/location/LocationButton-test.tsx b/test/components/views/location/LocationButton-test.tsx index 2737fa8354..2a247d472d 100644 --- a/test/components/views/location/LocationButton-test.tsx +++ b/test/components/views/location/LocationButton-test.tsx @@ -14,11 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import sdk from "../../../skinned-sdk"; import { textForLocation } from "../../../../src/components/views/location/shareLocation"; -sdk.getComponent("LocationPicker"); - describe("LocationButton", () => { describe("textForLocation", () => { it("with no description, simply dumps URI and date", () => { diff --git a/test/components/views/location/MapError-test.tsx b/test/components/views/location/MapError-test.tsx index 706e8e9188..2fa9cf3cd0 100644 --- a/test/components/views/location/MapError-test.tsx +++ b/test/components/views/location/MapError-test.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from 'react'; import { mount } from 'enzyme'; -import '../../../skinned-sdk'; import { MapError } from '../../../../src/components/views/location/MapError'; import { LocationShareError } from '../../../../src/utils/location'; diff --git a/test/components/views/messages/DateSeparator-test.tsx b/test/components/views/messages/DateSeparator-test.tsx index 89987114b1..8e5b7ea3ca 100644 --- a/test/components/views/messages/DateSeparator-test.tsx +++ b/test/components/views/messages/DateSeparator-test.tsx @@ -18,17 +18,15 @@ import React from "react"; import { mount } from "enzyme"; import { mocked } from "jest-mock"; -import sdk from "../../../skinned-sdk"; import { formatFullDateNoTime } from "../../../../src/DateUtils"; import SettingsStore from "../../../../src/settings/SettingsStore"; import { UIFeature } from "../../../../src/settings/UIFeature"; import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; import { getMockClientWithEventEmitter } from "../../../test-utils"; +import DateSeparator from "../../../../src/components/views/messages/DateSeparator"; jest.mock("../../../../src/settings/SettingsStore"); -const DateSeparator = sdk.getComponent("views.messages.DateSeparator"); - describe("DateSeparator", () => { const HOUR_MS = 3600000; const DAY_MS = HOUR_MS * 24; diff --git a/test/components/views/messages/MLocationBody-test.tsx b/test/components/views/messages/MLocationBody-test.tsx index 1954609efa..e80a738534 100644 --- a/test/components/views/messages/MLocationBody-test.tsx +++ b/test/components/views/messages/MLocationBody-test.tsx @@ -29,7 +29,6 @@ import { TEXT_NODE_TYPE } from "matrix-js-sdk/src/@types/extensible_events"; import maplibregl from 'maplibre-gl'; import { logger } from 'matrix-js-sdk/src/logger'; -import sdk from "../../../skinned-sdk"; import MLocationBody, { isSelfLocation, } from "../../../../src/components/views/messages/MLocationBody"; @@ -44,8 +43,6 @@ jest.mock("../../../../src/utils/WellKnownUtils", () => ({ getTileServerWellKnown: jest.fn(), })); -sdk.getComponent("views.messages.MLocationBody"); - describe("MLocationBody", () => { describe("isSelfLocation", () => { it("Returns true for a full m.asset event", () => { diff --git a/test/components/views/messages/MPollBody-test.tsx b/test/components/views/messages/MPollBody-test.tsx index b2c39ece21..28c0ceea34 100644 --- a/test/components/views/messages/MPollBody-test.tsx +++ b/test/components/views/messages/MPollBody-test.tsx @@ -31,7 +31,6 @@ import { } from "matrix-events-sdk"; import { MockedObject } from "jest-mock"; -import sdk from "../../../skinned-sdk"; import { UserVote, allVotes, @@ -43,11 +42,10 @@ import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import { IBodyProps } from "../../../../src/components/views/messages/IBodyProps"; import { getMockClientWithEventEmitter } from "../../../test-utils"; import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; +import MPollBody from "../../../../src/components/views/messages/MPollBody"; const CHECKED = "mx_MPollBody_option_checked"; -const MPollBody = sdk.getComponent("views.messages.MPollBody"); - const mockClient = getMockClientWithEventEmitter({ getUserId: jest.fn().mockReturnValue("@me:example.com"), sendEvent: jest.fn().mockReturnValue(Promise.resolve({ "event_id": "fake_send_id" })), diff --git a/test/components/views/messages/TextualBody-test.js b/test/components/views/messages/TextualBody-test.js index 5018663feb..702dd87bf4 100644 --- a/test/components/views/messages/TextualBody-test.js +++ b/test/components/views/messages/TextualBody-test.js @@ -17,14 +17,13 @@ limitations under the License. import React from "react"; import { mount } from "enzyme"; -import sdk from "../../../skinned-sdk"; import { mkEvent, mkStubRoom } from "../../../test-utils"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import * as languageHandler from "../../../../src/languageHandler"; import * as TestUtils from "../../../test-utils"; import DMRoomMap from "../../../../src/utils/DMRoomMap"; +import _TextualBody from "../../../../src/components/views/messages/TextualBody"; -const _TextualBody = sdk.getComponent("views.messages.TextualBody"); const TextualBody = TestUtils.wrapInMatrixClientContext(_TextualBody); describe("", () => { diff --git a/test/components/views/right_panel/PinnedMessagesCard-test.tsx b/test/components/views/right_panel/PinnedMessagesCard-test.tsx index dce93be59f..da30ae50ee 100644 --- a/test/components/views/right_panel/PinnedMessagesCard-test.tsx +++ b/test/components/views/right_panel/PinnedMessagesCard-test.tsx @@ -31,7 +31,6 @@ import { PollEndEvent, } from "matrix-events-sdk"; -import "../../../skinned-sdk"; import { stubClient, mkStubRoom, diff --git a/test/components/views/rooms/MessageComposer-test.tsx b/test/components/views/rooms/MessageComposer-test.tsx index af7c67fe2b..e756a7653c 100644 --- a/test/components/views/rooms/MessageComposer-test.tsx +++ b/test/components/views/rooms/MessageComposer-test.tsx @@ -19,7 +19,6 @@ import { mount, ReactWrapper } from "enzyme"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import '../../../skinned-sdk'; // Must be first for skinning to work import { createTestClient, mkEvent, mkStubRoom, stubClient } from "../../../test-utils"; import MessageComposer from "../../../../src/components/views/rooms/MessageComposer"; import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; diff --git a/test/components/views/rooms/MessageComposerButtons-test.tsx b/test/components/views/rooms/MessageComposerButtons-test.tsx index 436fbd21f4..31d8d1d6b6 100644 --- a/test/components/views/rooms/MessageComposerButtons-test.tsx +++ b/test/components/views/rooms/MessageComposerButtons-test.tsx @@ -19,15 +19,13 @@ import { mount, ReactWrapper } from "enzyme"; import { Room } from "matrix-js-sdk/src/models/room"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; -import sdk from "../../../skinned-sdk"; import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; import { Layout } from "../../../../src/settings/enums/Layout"; import RoomContext, { TimelineRenderingType } from "../../../../src/contexts/RoomContext"; import { createTestClient } from "../../../test-utils"; import { IRoomState } from "../../../../src/components/structures/RoomView"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; - -const MessageComposerButtons = sdk.getComponent("views.rooms.MessageComposerButtons"); +import MessageComposerButtons from "../../../../src/components/views/rooms/MessageComposerButtons"; describe("MessageComposerButtons", () => { it("Renders emoji and upload buttons in wide mode", () => { diff --git a/test/components/views/rooms/RoomList-test.js b/test/components/views/rooms/RoomList-test.js index 28d4409122..f13f24da8b 100644 --- a/test/components/views/rooms/RoomList-test.js +++ b/test/components/views/rooms/RoomList-test.js @@ -5,12 +5,14 @@ import { MatrixClient, Room, RoomMember } from 'matrix-js-sdk/src/matrix'; import * as TestUtils from '../../../test-utils'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; -import sdk from '../../../skinned-sdk'; import dis from '../../../../src/dispatcher/dispatcher'; import DMRoomMap from '../../../../src/utils/DMRoomMap'; import { DefaultTagID } from "../../../../src/stores/room-list/models"; import RoomListStore, { RoomListStoreClass } from "../../../../src/stores/room-list/RoomListStore"; import RoomListLayoutStore from "../../../../src/stores/room-list/RoomListLayoutStore"; +import RoomList from "../../../../src/components/views/rooms/RoomList"; +import RoomSublist from "../../../../src/components/views/rooms/RoomSublist"; +import RoomTile from "../../../../src/components/views/rooms/RoomTile"; function generateRoomId() { return '!' + Math.random().toString().slice(2, 10) + ':domain'; @@ -54,7 +56,6 @@ describe('RoomList', () => { parentDiv = document.createElement('div'); document.body.appendChild(parentDiv); - const RoomList = sdk.getComponent('views.rooms.RoomList'); const WrappedRoomList = TestUtils.wrapInMatrixClientContext(RoomList); root = ReactDOM.render( {}} />, @@ -119,10 +120,7 @@ describe('RoomList', () => { }); function expectRoomInSubList(room, subListTest) { - const RoomSubList = sdk.getComponent('views.rooms.RoomSublist'); - const RoomTile = sdk.getComponent('views.rooms.RoomTile'); - - const subLists = ReactTestUtils.scryRenderedComponentsWithType(root, RoomSubList); + const subLists = ReactTestUtils.scryRenderedComponentsWithType(root, RoomSublist); const containingSubList = subLists.find(subListTest); let expectedRoomTile; diff --git a/test/components/views/rooms/RoomTile-test.tsx b/test/components/views/rooms/RoomTile-test.tsx index 4e960afe46..1bac119dee 100644 --- a/test/components/views/rooms/RoomTile-test.tsx +++ b/test/components/views/rooms/RoomTile-test.tsx @@ -21,7 +21,6 @@ import { mocked } from "jest-mock"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; -import "../../../skinned-sdk"; import { stubClient, mockStateEventImplementation, diff --git a/test/components/views/rooms/SearchResultTile-test.tsx b/test/components/views/rooms/SearchResultTile-test.tsx index b87934315f..9f0e2d8576 100644 --- a/test/components/views/rooms/SearchResultTile-test.tsx +++ b/test/components/views/rooms/SearchResultTile-test.tsx @@ -20,12 +20,10 @@ import { SearchResult } from "matrix-js-sdk/src/models/search-result"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { EventType } from "matrix-js-sdk/src/@types/event"; -import sdk from "../../../skinned-sdk"; import { createTestClient } from "../../../test-utils"; import EventTile from "../../../../src/components/views/rooms/EventTile"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; - -const SearchResultTile = sdk.getComponent("views.rooms.SearchResultTile"); +import SearchResultTile from "../../../../src/components/views/rooms/SearchResultTile"; describe("SearchResultTile", () => { beforeAll(() => { diff --git a/test/components/views/voip/VoiceChannelRadio-test.tsx b/test/components/views/voip/VoiceChannelRadio-test.tsx index b42ac0e089..50779dd9f7 100644 --- a/test/components/views/voip/VoiceChannelRadio-test.tsx +++ b/test/components/views/voip/VoiceChannelRadio-test.tsx @@ -19,7 +19,6 @@ import { mount } from "enzyme"; import { act } from "react-dom/test-utils"; import { mocked } from "jest-mock"; -import "../../../skinned-sdk"; import { stubClient, mkStubRoom, wrapInMatrixClientContext } from "../../../test-utils"; import { stubVoiceChannelStore } from "../../../test-utils/voice"; import _VoiceChannelRadio from "../../../../src/components/views/voip/VoiceChannelRadio"; From d977865b8efcebe119e6b8c30b4add28db1a9b98 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 2 Mar 2022 14:24:06 -0700 Subject: [PATCH 04/47] Step 3.1.1: Remove tests that are infeasible to convert --- .../views/rooms/RoomSettings-test.js | 188 ------------------ 1 file changed, 188 deletions(-) delete mode 100644 test/components/views/rooms/RoomSettings-test.js diff --git a/test/components/views/rooms/RoomSettings-test.js b/test/components/views/rooms/RoomSettings-test.js deleted file mode 100644 index f05262d102..0000000000 --- a/test/components/views/rooms/RoomSettings-test.js +++ /dev/null @@ -1,188 +0,0 @@ -// TODO: Rewrite room settings tests for dialog support -import React from 'react'; -import ReactDOM from 'react-dom'; - -import * as testUtils from '../../../test-utils'; -import sdk from '../../../skinned-sdk'; -import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; -import SettingsStore from '../../../../src/settings/SettingsStore'; - -describe.skip('RoomSettings', () => { - const WrappedRoomSettings = testUtils.wrapInMatrixClientContext(sdk.getComponent('views.rooms.RoomSettings')); - - let parentDiv = null; - let client = null; - let roomSettings = null; - const room = testUtils.mkStubRoom('!DdJkzRliezrwpNebLk:matrix.org'); - - function expectSentStateEvent(roomId, eventType, expectedEventContent) { - let found = false; - for (const call of client.sendStateEvent.mock.calls) { - const [ - actualRoomId, - actualEventType, - actualEventContent, - ] = call.slice(0, 3); - - if (roomId === actualRoomId && actualEventType === eventType) { - expect(actualEventContent).toEqual(expectedEventContent); - found = true; - break; - } - } - expect(found).toBe(true); - } - - beforeEach(function(done) { - testUtils.stubClient(); - client = MatrixClientPeg.get(); - client.credentials = { userId: '@me:domain.com' }; - - client.setRoomName = jest.fn().mockReturnValue(Promise.resolve()); - client.setRoomTopic = jest.fn().mockReturnValue(Promise.resolve()); - client.setRoomDirectoryVisibility = jest.fn().mockReturnValue(Promise.resolve()); - - // Covers any room state event (e.g. name, avatar, topic) - client.sendStateEvent = jest.fn().mockReturnValue(Promise.resolve()); - - // Covers room tagging - client.setRoomTag = jest.fn().mockReturnValue(Promise.resolve()); - client.deleteRoomTag = jest.fn().mockReturnValue(Promise.resolve()); - - // Covers any setting in the SettingsStore - // (including local client settings not stored via matrix) - SettingsStore.setValue = jest.fn().mockReturnValue(Promise.resolve()); - - parentDiv = document.createElement('div'); - document.body.appendChild(parentDiv); - - const gatherWrappedRef = (r) => {roomSettings = r;}; - - // get use wrappedRef because we're using wrapInMatrixClientContext - ReactDOM.render( - , - parentDiv, - done, - ); - }); - - afterEach((done) => { - if (parentDiv) { - ReactDOM.unmountComponentAtNode(parentDiv); - parentDiv.remove(); - parentDiv = null; - } - done(); - }); - - it('should not set when no setting is changed', (done) => { - roomSettings.save().then(() => { - expect(client.sendStateEvent).not.toHaveBeenCalled(); - expect(client.setRoomTag).not.toHaveBeenCalled(); - expect(client.deleteRoomTag).not.toHaveBeenCalled(); - done(); - }); - }); - - // XXX: Apparently we do call SettingsStore.setValue - xit('should not settings via the SettingsStore when no setting is changed', (done) => { - roomSettings.save().then(() => { - expect(SettingsStore.setValue).not.toHaveBeenCalled(); - done(); - }); - }); - - it('should set room name when it has changed', (done) => { - const name = "My Room Name"; - roomSettings.setName(name); - - roomSettings.save().then(() => { - expect(client.setRoomName.mock.calls[0].slice(0, 2)) - .toEqual(['!DdJkzRliezrwpNebLk:matrix.org', name]); - - done(); - }); - }); - - it('should set room topic when it has changed', (done) => { - const topic = "this is a topic"; - roomSettings.setTopic(topic); - - roomSettings.save().then(() => { - expect(client.setRoomTopic.mock.calls[0].slice(0, 2)) - .toEqual(['!DdJkzRliezrwpNebLk:matrix.org', topic]); - - done(); - }); - }); - - it('should set history visibility when it has changed', (done) => { - const historyVisibility = "translucent"; - roomSettings.setState({ - history_visibility: historyVisibility, - }); - - roomSettings.save().then(() => { - expectSentStateEvent( - "!DdJkzRliezrwpNebLk:matrix.org", - "m.room.history_visibility", { history_visibility: historyVisibility }, - ); - done(); - }); - }); - - // XXX: Can't test this because we `getRoomDirectoryVisibility` in `componentDidMount` - xit('should set room directory publicity when set to true', (done) => { - const isRoomPublished = true; - roomSettings.setState({ - isRoomPublished, - }, () => { - roomSettings.save().then(() => { - expect(client.setRoomDirectoryVisibility.calls[0].arguments.slice(0, 2)) - .toEqual("!DdJkzRliezrwpNebLk:matrix.org", isRoomPublished ? "public" : "private"); - done(); - }); - }); - }); - - it('should set power levels when changed', (done) => { - roomSettings.onPowerLevelsChanged(42, "invite"); - - roomSettings.save().then(() => { - expectSentStateEvent( - "!DdJkzRliezrwpNebLk:matrix.org", - "m.room.power_levels", { invite: 42 }, - ); - done(); - }); - }); - - it('should set event power levels when changed', (done) => { - roomSettings.onPowerLevelsChanged(42, "event_levels_m.room.message"); - - roomSettings.save().then(() => { - // We expect all state events to be set to the state_default (50) - // See powerLevelDescriptors in RoomSettings - expectSentStateEvent( - "!DdJkzRliezrwpNebLk:matrix.org", - "m.room.power_levels", { - events: { - 'm.room.message': 42, - 'm.room.avatar': 50, - 'm.room.name': 50, - 'm.room.canonical_alias': 50, - 'm.room.history_visibility': 50, - 'm.room.power_levels': 50, - 'm.room.topic': 50, - // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) - 'im.vector.modular.widgets': 50, - }, - }, - ); - done(); - }); - }); -}); From b667ef9f18d18b547ff39cf5c3ce37420849bd2e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 2 Mar 2022 16:33:40 -0700 Subject: [PATCH 05/47] Step 3.2: Stop using `getComponent` in code --- src/Analytics.tsx | 4 +- src/AsyncWrapper.tsx | 8 ++-- src/ContentMessages.ts | 10 ++--- src/MatrixClientPeg.ts | 5 +-- src/SecurityManager.ts | 4 +- src/Terms.ts | 4 +- src/components/structures/HomePage.tsx | 4 +- src/components/views/auth/Welcome.tsx | 5 +-- src/components/views/dialogs/InfoDialog.tsx | 6 +-- .../views/dialogs/QuestionDialog.tsx | 7 +-- .../security/AccessSecretStorageDialog.tsx | 11 ++--- .../security/RestoreKeyBackupDialog.tsx | 11 ++--- src/components/views/elements/Field.tsx | 4 +- src/components/views/elements/Pill.js | 6 +-- .../views/messages/MessageEvent.tsx | 43 +++++++++++-------- .../views/right_panel/EncryptionPanel.tsx | 4 +- src/components/views/rooms/RoomDetailRow.js | 4 +- src/stores/RoomViewStore.tsx | 7 +-- 18 files changed, 54 insertions(+), 93 deletions(-) diff --git a/src/Analytics.tsx b/src/Analytics.tsx index 23b278929a..639950574d 100644 --- a/src/Analytics.tsx +++ b/src/Analytics.tsx @@ -23,7 +23,7 @@ import { getCurrentLanguage, _t, _td, IVariables } from './languageHandler'; import PlatformPeg from './PlatformPeg'; import SdkConfig from './SdkConfig'; import Modal from './Modal'; -import * as sdk from './index'; +import ErrorDialog from "./components/views/dialogs/ErrorDialog"; import { SnakedObject } from "./utils/SnakedObject"; import { IConfigOptions } from "./IConfigOptions"; @@ -406,14 +406,12 @@ export class Analytics { { expl: _td('Your device resolution'), value: resolution }, ]; - // FIXME: Using an import will result in test failures const piwikConfig = SdkConfig.get("piwik"); let piwik: Optional>>; if (typeof piwikConfig === 'object') { piwik = new SnakedObject(piwikConfig); } const cookiePolicyUrl = piwik?.get("policy_url"); - const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog'); const cookiePolicyLink = _t( "Our complete cookie policy can be found here.", {}, diff --git a/src/AsyncWrapper.tsx b/src/AsyncWrapper.tsx index 166e4f21e3..07a06f20d4 100644 --- a/src/AsyncWrapper.tsx +++ b/src/AsyncWrapper.tsx @@ -17,9 +17,11 @@ limitations under the License. import React, { ComponentType } from "react"; import { logger } from "matrix-js-sdk/src/logger"; -import * as sdk from './index'; import { _t } from './languageHandler'; import { IDialogProps } from "./components/views/dialogs/IDialogProps"; +import BaseDialog from "./components/views/dialogs/BaseDialog"; +import DialogButtons from "./components/views/elements/DialogButtons"; +import Spinner from "./components/views/elements/Spinner"; type AsyncImport = { default: T }; @@ -78,9 +80,6 @@ export default class AsyncWrapper extends React.Component { const Component = this.state.component; return ; } else if (this.state.error) { - // FIXME: Using an import will result in test failures - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return { _t("Unable to load! Check your network connectivity and try again.") } { ; } else { // show a spinner until the component is loaded. - const Spinner = sdk.getComponent("elements.Spinner"); return ; } } diff --git a/src/ContentMessages.ts b/src/ContentMessages.ts index babe4563f7..ed0999fe07 100644 --- a/src/ContentMessages.ts +++ b/src/ContentMessages.ts @@ -28,7 +28,6 @@ import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread"; import { IEncryptedFile, IMediaEventInfo } from "./customisations/models/IMediaEventContent"; import dis from './dispatcher/dispatcher'; -import * as sdk from './index'; import { _t } from './languageHandler'; import Modal from './Modal'; import Spinner from "./components/views/elements/Spinner"; @@ -47,6 +46,9 @@ import { decorateStartSendingTime, sendRoundTripMetric } from "./sendTimePerform import { TimelineRenderingType } from "./contexts/RoomContext"; import RoomViewStore from "./stores/RoomViewStore"; import { addReplyToMessageContent } from "./utils/Reply"; +import ErrorDialog from "./components/views/dialogs/ErrorDialog"; +import UploadFailureDialog from "./components/views/dialogs/UploadFailureDialog"; +import UploadConfirmDialog from "./components/views/dialogs/UploadConfirmDialog"; const MAX_WIDTH = 800; const MAX_HEIGHT = 600; @@ -485,8 +487,6 @@ export default class ContentMessages { } if (tooBigFiles.length > 0) { - // FIXME: Using an import will result in Element crashing - const UploadFailureDialog = sdk.getComponent("dialogs.UploadFailureDialog"); const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Failure', '', UploadFailureDialog, { badFiles: tooBigFiles, totalFiles: files.length, @@ -503,8 +503,6 @@ export default class ContentMessages { for (let i = 0; i < okFiles.length; ++i) { const file = okFiles[i]; if (!uploadAll) { - // FIXME: Using an import will result in Element crashing - const UploadConfirmDialog = sdk.getComponent("dialogs.UploadConfirmDialog"); const { finished } = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation', '', UploadConfirmDialog, { file, @@ -686,8 +684,6 @@ export default class ContentMessages { { fileName: upload.fileName }, ); } - // FIXME: Using an import will result in Element crashing - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Upload failed', '', ErrorDialog, { title: _t('Upload Failed'), description: desc, diff --git a/src/MatrixClientPeg.ts b/src/MatrixClientPeg.ts index c8502b0795..7949518fc2 100644 --- a/src/MatrixClientPeg.ts +++ b/src/MatrixClientPeg.ts @@ -27,7 +27,6 @@ import { verificationMethods } from 'matrix-js-sdk/src/crypto'; import { SHOW_QR_CODE_METHOD } from "matrix-js-sdk/src/crypto/verification/QRCode"; import { logger } from "matrix-js-sdk/src/logger"; -import * as sdk from './index'; import createMatrixClient from './utils/createMatrixClient'; import SettingsStore from './settings/SettingsStore'; import MatrixActionCreators from './actions/MatrixActionCreators'; @@ -37,6 +36,7 @@ import * as StorageManager from './utils/StorageManager'; import IdentityAuthClient from './IdentityAuthClient'; import { crossSigningCallbacks, tryToUnlockSecretStorageWithDehydrationKey } from './SecurityManager'; import SecurityCustomisations from "./customisations/Security"; +import CryptoStoreTooNewDialog from "./components/views/dialogs/CryptoStoreTooNewDialog"; export interface IMatrixClientCreds { homeserverUrl: string; @@ -200,9 +200,6 @@ class MatrixClientPegClass implements IMatrixClientPeg { } catch (e) { if (e && e.name === 'InvalidCryptoStoreError') { // The js-sdk found a crypto DB too new for it to use - // FIXME: Using an import will result in test failures - const CryptoStoreTooNewDialog = - sdk.getComponent("views.dialogs.CryptoStoreTooNewDialog"); Modal.createDialog(CryptoStoreTooNewDialog); } // this can happen for a number of reasons, the most likely being diff --git a/src/SecurityManager.ts b/src/SecurityManager.ts index 0383b50fc4..f3d254d059 100644 --- a/src/SecurityManager.ts +++ b/src/SecurityManager.ts @@ -25,7 +25,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { ComponentType } from "react"; import Modal from './Modal'; -import * as sdk from './index'; import { MatrixClientPeg } from './MatrixClientPeg'; import { _t } from './languageHandler'; import { isSecureBackupRequired } from './utils/WellKnownUtils'; @@ -34,6 +33,7 @@ import RestoreKeyBackupDialog from './components/views/dialogs/security/RestoreK import SettingsStore from "./settings/SettingsStore"; import SecurityCustomisations from "./customisations/Security"; import QuestionDialog from "./components/views/dialogs/QuestionDialog"; +import InteractiveAuthDialog from "./components/views/dialogs/InteractiveAuthDialog"; // This stores the secret storage private keys in memory for the JS SDK. This is // only meant to act as a cache to avoid prompting the user multiple times @@ -360,8 +360,6 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f throw new Error("Secret storage creation canceled"); } } else { - // FIXME: Using an import will result in test failures - const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog"); await cli.bootstrapCrossSigning({ authUploadDeviceSigningKeys: async (makeRequest) => { const { finished } = Modal.createTrackedDialog( diff --git a/src/Terms.ts b/src/Terms.ts index 4b1480f536..aa94309ae3 100644 --- a/src/Terms.ts +++ b/src/Terms.ts @@ -19,8 +19,8 @@ import { SERVICE_TYPES } from 'matrix-js-sdk/src/service-types'; import { logger } from "matrix-js-sdk/src/logger"; import { MatrixClientPeg } from './MatrixClientPeg'; -import * as sdk from '.'; import Modal from './Modal'; +import TermsDialog from "./components/views/dialogs/TermsDialog"; export class TermsNotSignedError extends Error {} @@ -189,8 +189,6 @@ export async function dialogTermsInteractionCallback( extraClassNames?: string, ): Promise { logger.log("Terms that need agreement", policiesAndServicePairs); - // FIXME: Using an import will result in test failures - const TermsDialog = sdk.getComponent("views.dialogs.TermsDialog"); const { finished } = Modal.createTrackedDialog<[boolean, string[]]>('Terms of Service', '', TermsDialog, { policiesAndServicePairs, diff --git a/src/components/structures/HomePage.tsx b/src/components/structures/HomePage.tsx index 6ee31114ef..fdcb52a687 100644 --- a/src/components/structures/HomePage.tsx +++ b/src/components/structures/HomePage.tsx @@ -21,7 +21,6 @@ import AutoHideScrollbar from './AutoHideScrollbar'; import { getHomePageUrl } from "../../utils/pages"; import { _tDom } from "../../languageHandler"; import SdkConfig from "../../SdkConfig"; -import * as sdk from "../../index"; import dis from "../../dispatcher/dispatcher"; import { Action } from "../../dispatcher/actions"; import BaseAvatar from "../views/avatars/BaseAvatar"; @@ -33,6 +32,7 @@ import MatrixClientContext from "../../contexts/MatrixClientContext"; import MiniAvatarUploader, { AVATAR_SIZE } from "../views/elements/MiniAvatarUploader"; import Analytics from "../../Analytics"; import PosthogTrackers from "../../PosthogTrackers"; +import EmbeddedPage from "./EmbeddedPage"; const onClickSendDm = () => { Analytics.trackEvent('home_page', 'button', 'dm'); @@ -94,8 +94,6 @@ const HomePage: React.FC = ({ justRegistered = false }) => { const pageUrl = getHomePageUrl(config); if (pageUrl) { - // FIXME: Using an import will result in wrench-element-tests failures - const EmbeddedPage = sdk.getComponent('structures.EmbeddedPage'); return ; } diff --git a/src/components/views/auth/Welcome.tsx b/src/components/views/auth/Welcome.tsx index ad35ee0186..e76dabb4db 100644 --- a/src/components/views/auth/Welcome.tsx +++ b/src/components/views/auth/Welcome.tsx @@ -17,13 +17,13 @@ limitations under the License. import React from 'react'; import classNames from "classnames"; -import * as sdk from "../../../index"; import SdkConfig from '../../../SdkConfig'; import AuthPage from "./AuthPage"; import { _td } from "../../../languageHandler"; import SettingsStore from "../../../settings/SettingsStore"; import { UIFeature } from "../../../settings/UIFeature"; import LanguageSelector from "./LanguageSelector"; +import EmbeddedPage from "../../structures/EmbeddedPage"; // translatable strings for Welcome pages _td("Sign in with SSO"); @@ -34,9 +34,6 @@ interface IProps { export default class Welcome extends React.PureComponent { public render(): React.ReactNode { - // FIXME: Using an import will result in wrench-element-tests failures - const EmbeddedPage = sdk.getComponent("structures.EmbeddedPage"); - const pagesConfig = SdkConfig.getObject("embedded_pages"); let pageUrl = null; if (pagesConfig) { diff --git a/src/components/views/dialogs/InfoDialog.tsx b/src/components/views/dialogs/InfoDialog.tsx index ddcea275a9..dd9c985f8e 100644 --- a/src/components/views/dialogs/InfoDialog.tsx +++ b/src/components/views/dialogs/InfoDialog.tsx @@ -19,8 +19,9 @@ import React, { ReactNode, KeyboardEvent } from 'react'; import classNames from "classnames"; import { _t } from '../../../languageHandler'; -import * as sdk from '../../../index'; import { IDialogProps } from "./IDialogProps"; +import BaseDialog from "./BaseDialog"; +import DialogButtons from "../elements/DialogButtons"; interface IProps extends IDialogProps { title?: string; @@ -44,9 +45,6 @@ export default class InfoDialog extends React.Component { }; render() { - // FIXME: Using a regular import will break the app - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return ( { }; public render(): JSX.Element { - // Converting these to imports breaks wrench tests - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - let primaryButtonClass = ""; if (this.props.danger) { primaryButtonClass = "danger"; diff --git a/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx b/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx index 090eac783e..f0dca76bfb 100644 --- a/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx +++ b/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx @@ -20,7 +20,6 @@ import React, { ChangeEvent, FormEvent } from 'react'; import { ISecretStorageKeyInfo } from "matrix-js-sdk/src/crypto/api"; import { logger } from "matrix-js-sdk/src/logger"; -import * as sdk from '../../../../index'; import { MatrixClientPeg } from '../../../../MatrixClientPeg'; import Field from '../../elements/Field'; import AccessibleButton from '../../elements/AccessibleButton'; @@ -28,6 +27,9 @@ import { _t } from '../../../../languageHandler'; import { IDialogProps } from "../IDialogProps"; import { accessSecretStorage } from "../../../../SecurityManager"; import Modal from "../../../../Modal"; +import InteractiveAuthDialog from "../InteractiveAuthDialog"; +import DialogButtons from "../../elements/DialogButtons"; +import BaseDialog from "../BaseDialog"; // Maximum acceptable size of a key file. It's 59 characters including the spaces we encode, // so this should be plenty and allow for people putting extra whitespace in the file because @@ -230,8 +232,6 @@ export default class AccessSecretStorageDialog extends React.PureComponent { - // XXX: Making this an import breaks the app. - const InteractiveAuthDialog = sdk.getComponent("views.dialogs.InteractiveAuthDialog"); const { finished } = Modal.createTrackedDialog( 'Cross-signing keys dialog', '', InteractiveAuthDialog, { @@ -273,10 +273,6 @@ export default class AccessSecretStorageDialog extends React.PureComponent
; } else if (hasPassphrase && !this.state.forceRecoveryKey) { - const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); title = _t("Security Phrase"); titleClass = ['mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_securePhraseTitle']; diff --git a/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx index 3db78f6877..719c31c48f 100644 --- a/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx +++ b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx @@ -24,8 +24,11 @@ import { logger } from "matrix-js-sdk/src/logger"; import { MatrixClientPeg } from '../../../../MatrixClientPeg'; import { _t } from '../../../../languageHandler'; import { accessSecretStorage } from '../../../../SecurityManager'; -import * as sdk from '../../../../index'; import { IDialogProps } from "../IDialogProps"; +import Spinner from '../../elements/Spinner'; +import DialogButtons from "../../elements/DialogButtons"; +import AccessibleButton from "../../elements/AccessibleButton"; +import BaseDialog from "../BaseDialog"; enum RestoreType { Passphrase = "passphrase", @@ -298,12 +301,6 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { ); // Handle displaying feedback on validity - // FIXME: Using an import will result in test failures - const Tooltip = sdk.getComponent("elements.Tooltip"); let fieldTooltip; if (tooltipContent || this.state.feedback) { fieldTooltip = { @@ -70,23 +78,25 @@ export default class MessageEvent extends React.Component implements IMe } } - private get bodyTypes(): Record { + private get bodyTypes(): Record { return { - [MsgType.Text]: sdk.getComponent('messages.TextualBody'), - [MsgType.Notice]: sdk.getComponent('messages.TextualBody'), - [MsgType.Emote]: sdk.getComponent('messages.TextualBody'), - [MsgType.Image]: sdk.getComponent('messages.MImageBody'), - [MsgType.File]: sdk.getComponent('messages.MFileBody'), - [MsgType.Audio]: sdk.getComponent('messages.MVoiceOrAudioBody'), - [MsgType.Video]: sdk.getComponent('messages.MVideoBody'), + [MsgType.Text]: TextualBody, + [MsgType.Notice]: TextualBody, + [MsgType.Emote]: TextualBody, + [MsgType.Image]: MImageBody, + [MsgType.File]: MFileBody, + [MsgType.Audio]: MVoiceOrAudioBody, + [MsgType.Video]: MVideoBody, ...(this.props.overrideBodyTypes || {}), }; } - private get evTypes(): Record { + private get evTypes(): Record { return { - [EventType.Sticker]: sdk.getComponent('messages.MStickerBody'), + [EventType.Sticker]: MStickerBody, + [M_POLL_START.name]: MPollBody, + [M_POLL_START.altName]: MPollBody, ...(this.props.overrideEventTypes || {}), }; @@ -108,7 +118,7 @@ export default class MessageEvent extends React.Component implements IMe const content = this.props.mxEvent.getContent(); const type = this.props.mxEvent.getType(); const msgtype = content.msgtype; - let BodyType: ReactAnyComponent = RedactedBody; + let BodyType: typeof React.Component | ReactAnyComponent = RedactedBody; if (!this.props.mxEvent.isRedacted()) { // only resolve BodyType if event is not redacted if (type && this.evTypes[type]) { @@ -123,17 +133,12 @@ export default class MessageEvent extends React.Component implements IMe BodyType = UnknownBody; } - // TODO: move to eventTypes when Polls spec stabilises - if (M_POLL_START.matches(type)) { - BodyType = sdk.getComponent('messages.MPollBody'); - } - // TODO: move to eventTypes when location sharing spec stabilises if ( M_LOCATION.matches(type) || (type === EventType.RoomMessage && msgtype === MsgType.Location) ) { - BodyType = sdk.getComponent('messages.MLocationBody'); + BodyType = MLocationBody; } } @@ -147,7 +152,7 @@ export default class MessageEvent extends React.Component implements IMe const serverBanned = Mjolnir.sharedInstance().isServerBanned(userDomain); if (userBanned || serverBanned) { - BodyType = sdk.getComponent('messages.MjolnirBody'); + BodyType = MjolnirBody; } } } diff --git a/src/components/views/right_panel/EncryptionPanel.tsx b/src/components/views/right_panel/EncryptionPanel.tsx index 2cfd4851e0..c2dfd7a379 100644 --- a/src/components/views/right_panel/EncryptionPanel.tsx +++ b/src/components/views/right_panel/EncryptionPanel.tsx @@ -30,10 +30,10 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { ensureDMExists } from "../../../createRoom"; import { useTypedEventEmitter } from "../../../hooks/useEventEmitter"; import Modal from "../../../Modal"; -import * as sdk from "../../../index"; import { _t } from "../../../languageHandler"; import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases'; import RightPanelStore from "../../../stores/right-panel/RightPanelStore"; +import ErrorDialog from "../dialogs/ErrorDialog"; // cancellation codes which constitute a key mismatch const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"]; @@ -84,8 +84,6 @@ const EncryptionPanel: React.FC = (props: IProps) => { const changeHandler = useCallback(() => { // handle transitions -> cancelled for mismatches which fire a modal instead of showing a card if (request && request.cancelled && MISMATCHES.includes(request.cancellationCode)) { - // FIXME: Using an import will result in test failures - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog("Verification failed", "insecure", ErrorDialog, { headerImage: require("../../../../res/img/e2e/warning.svg").default, title: _t("Your messages are not secure"), diff --git a/src/components/views/rooms/RoomDetailRow.js b/src/components/views/rooms/RoomDetailRow.js index 72d40cf6e0..47071adf85 100644 --- a/src/components/views/rooms/RoomDetailRow.js +++ b/src/components/views/rooms/RoomDetailRow.js @@ -17,11 +17,11 @@ limitations under the License. import React, { createRef } from 'react'; import PropTypes from 'prop-types'; -import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { linkifyElement } from '../../../HtmlUtils'; import { mediaFromMxc } from "../../../customisations/Media"; import { getDisplayAliasForAliasSet } from '../../../Rooms'; +import BaseAvatar from "../avatars/BaseAvatar"; export function getDisplayAliasForRoom(room) { return getDisplayAliasForAliasSet(room.canonicalAlias, room.aliases); @@ -82,8 +82,6 @@ export default class RoomDetailRow extends React.Component { }; render() { - const BaseAvatar = sdk.getComponent('avatars.BaseAvatar'); - const room = this.props.room; const name = room.name || getDisplayAliasForRoom(room) || _t('Unnamed room'); diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index 90ba1f8844..44f049c27e 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -28,7 +28,6 @@ import { ClientEvent } from "matrix-js-sdk/src/client"; import dis from '../dispatcher/dispatcher'; import { MatrixClientPeg } from '../MatrixClientPeg'; -import * as sdk from '../index'; import Modal from '../Modal'; import { _t } from '../languageHandler'; import { getCachedRoomIDForAlias, storeRoomAliasInCache } from '../RoomAliasCache'; @@ -45,6 +44,8 @@ import { JoinRoomPayload } from "../dispatcher/payloads/JoinRoomPayload"; import { JoinRoomReadyPayload } from "../dispatcher/payloads/JoinRoomReadyPayload"; import { JoinRoomErrorPayload } from "../dispatcher/payloads/JoinRoomErrorPayload"; import { ViewRoomErrorPayload } from "../dispatcher/payloads/ViewRoomErrorPayload"; +import RoomSettingsDialog from "../components/views/dialogs/RoomSettingsDialog"; +import ErrorDialog from "../components/views/dialogs/ErrorDialog"; const NUM_JOIN_RETRY = 5; @@ -211,8 +212,6 @@ class RoomViewStore extends Store { } break; case 'open_room_settings': { - // FIXME: Using an import will result in test failures - const RoomSettingsDialog = sdk.getComponent("dialogs.RoomSettingsDialog"); Modal.createTrackedDialog('Room settings', '', RoomSettingsDialog, { roomId: payload.room_id || this.state.roomId, initialTabId: payload.initial_tab_id, @@ -402,8 +401,6 @@ class RoomViewStore extends Store { } } - // FIXME: Using an import will result in test failures - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, { title: _t("Failed to join room"), description: msg, From 7e21da0c7f9daff3b58a572416b230cf09e16e98 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 2 Mar 2022 16:38:53 -0700 Subject: [PATCH 06/47] Step 4: Disable/remove bulk of skinner code --- src/@types/global.d.ts | 2 - src/Skinner.ts | 121 ----------------------------------------- src/index.ts | 12 +--- test/minimal-sdk.js | 2 +- test/skinned-sdk.js | 2 +- 5 files changed, 3 insertions(+), 136 deletions(-) delete mode 100644 src/Skinner.ts diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index b793dea22d..c3f739c731 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -50,7 +50,6 @@ import { SetupEncryptionStore } from "../stores/SetupEncryptionStore"; import { RoomScrollStateStore } from "../stores/RoomScrollStateStore"; import { ConsoleLogger, IndexedDBLogStore } from "../rageshake/rageshake"; import ActiveWidgetStore from "../stores/ActiveWidgetStore"; -import { Skinner } from "../Skinner"; import AutoRageshakeStore from "../stores/AutoRageshakeStore"; import { IConfigOptions } from "../IConfigOptions"; @@ -107,7 +106,6 @@ declare global { mxSetupEncryptionStore?: SetupEncryptionStore; mxRoomScrollStateStore?: RoomScrollStateStore; mxActiveWidgetStore?: ActiveWidgetStore; - mxSkinner?: Skinner; mxOnRecaptchaLoaded?: () => void; electron?: Electron; mxSendSentryReport: (userText: string, issueUrl: string, error: Error) => Promise; diff --git a/src/Skinner.ts b/src/Skinner.ts deleted file mode 100644 index 6b20781b59..0000000000 --- a/src/Skinner.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React from "react"; - -export interface IComponents { - [key: string]: React.Component; -} - -export interface ISkinObject { - components: IComponents; -} - -export class Skinner { - public components: IComponents = null; - - public getComponent(name: string): React.Component { - if (!name) throw new Error(`Invalid component name: ${name}`); - if (this.components === null) { - throw new Error( - `Attempted to get a component (${name}) before a skin has been loaded.`+ - " This is probably because either:"+ - " a) Your app has not called sdk.loadSkin(), or"+ - " b) A component has called getComponent at the root level", - ); - } - - const doLookup = (components: IComponents): React.Component => { - if (!components) return null; - let comp = components[name]; - // XXX: Temporarily also try 'views.' as we're currently - // leaving the 'views.' off views. - if (!comp) { - comp = components['views.' + name]; - } - return comp; - }; - - // Check the skin first - const comp = doLookup(this.components); - - // Just return nothing instead of erroring - the consumer should be smart enough to - // handle this at this point. - if (!comp) { - return null; - } - - // components have to be functions or forwardRef objects with a render function. - const validType = typeof comp === 'function' || comp.render; - if (!validType) { - throw new Error(`Not a valid component: ${name} (type = ${typeof(comp)}).`); - } - return comp; - } - - public load(skinObject: ISkinObject): void { - if (this.components !== null) { - throw new Error( - "Attempted to load a skin while a skin is already loaded"+ - "If you want to change the active skin, call resetSkin first"); - } - this.components = {}; - const compKeys = Object.keys(skinObject.components); - for (let i = 0; i < compKeys.length; ++i) { - const comp = skinObject.components[compKeys[i]]; - this.addComponent(compKeys[i], comp); - } - - // Now that we have a skin, load our components too - // eslint-disable-next-line @typescript-eslint/no-var-requires - const idx = require("./component-index"); - if (!idx || !idx.components) throw new Error("Invalid react-sdk component index"); - for (const c in idx.components) { - if (!this.components[c]) this.components[c] = idx.components[c]; - } - } - - public addComponent(name: string, comp: any) { - let slot = name; - if (comp.replaces !== undefined) { - if (comp.replaces.indexOf('.') > -1) { - slot = comp.replaces; - } else { - slot = name.substr(0, name.lastIndexOf('.') + 1) + comp.replaces.split('.').pop(); - } - } - this.components[slot] = comp; - } - - public reset(): void { - this.components = null; - } -} - -// We define one Skinner globally, because the intention is -// very much that it is a singleton. Relying on there only being one -// copy of the module can be dicey and not work as browserify's -// behaviour with multiple copies of files etc. is erratic at best. -// XXX: We can still end up with the same file twice in the resulting -// JS bundle which is nonideal. -// See https://derickbailey.com/2016/03/09/creating-a-true-singleton-in-node-js-with-es6-symbols/ -// or https://nodejs.org/api/modules.html#modules_module_caching_caveats -// ("Modules are cached based on their resolved filename") -if (window.mxSkinner === undefined) { - window.mxSkinner = new Skinner(); -} -export default window.mxSkinner; - diff --git a/src/index.ts b/src/index.ts index c57722376f..9b4d431983 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,21 +15,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import Skinner, { ISkinObject } from './Skinner'; - // Import the js-sdk so the proper `request` object can be set. This does some // magic with the browser injection to make all subsequent imports work fine. import "matrix-js-sdk/src/browser-index"; -export function loadSkin(skinObject: ISkinObject): void { - Skinner.load(skinObject); -} - -export function resetSkin(): void { - Skinner.reset(); -} - export function getComponent(componentName: string): any { - return Skinner.getComponent(componentName); + // return Skinner.getComponent(componentName); } diff --git a/test/minimal-sdk.js b/test/minimal-sdk.js index f39893f78c..fb40ebd3c5 100644 --- a/test/minimal-sdk.js +++ b/test/minimal-sdk.js @@ -24,6 +24,6 @@ import * as sdk from "../src/index"; const components = {}; -sdk.loadSkin({ components }); +// sdk.loadSkin({ components }); export default sdk; diff --git a/test/skinned-sdk.js b/test/skinned-sdk.js index 0a3cc85a3b..aa4fffe8e6 100644 --- a/test/skinned-sdk.js +++ b/test/skinned-sdk.js @@ -23,6 +23,6 @@ components['views.messages.MessageTimestamp'] = stubComponent({ displayName: 'Me components['views.messages.SenderProfile'] = stubComponent({ displayName: 'SenderProfile' }); components['views.rooms.SearchBar'] = stubComponent(); -sdk.loadSkin({ components }); +// sdk.loadSkin({ components }); export default sdk; From 115ae198c869efd504ee2d8acd58b6b58039fe54 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 4 Mar 2022 16:42:16 -0700 Subject: [PATCH 07/47] Step 5: Fix newly-discovered TS issues --- src/components/structures/EmbeddedPage.tsx | 2 +- .../views/dialogs/security/AccessSecretStorageDialog.tsx | 4 ++-- src/components/views/elements/DialogButtons.tsx | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/structures/EmbeddedPage.tsx b/src/components/structures/EmbeddedPage.tsx index 4b309a1838..9ba250c985 100644 --- a/src/components/structures/EmbeddedPage.tsx +++ b/src/components/structures/EmbeddedPage.tsx @@ -37,7 +37,7 @@ interface IProps { // Whether to wrap the page in a scrollbar scrollbar?: boolean; // Map of keys to replace with values, e.g {$placeholder: "value"} - replaceMap?: Map; + replaceMap?: Record; } interface IState { diff --git a/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx b/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx index f0dca76bfb..a50ac2bb94 100644 --- a/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx +++ b/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx @@ -174,7 +174,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent) => { + private onPassPhraseNext = async (ev: FormEvent | React.MouseEvent) => { ev.preventDefault(); if (this.state.passPhrase.length <= 0) return; @@ -189,7 +189,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent) => { + private onRecoveryKeyNext = async (ev: FormEvent | React.MouseEvent) => { ev.preventDefault(); if (!this.state.recoveryKeyValid) return; diff --git a/src/components/views/elements/DialogButtons.tsx b/src/components/views/elements/DialogButtons.tsx index ed0d6cd9e6..2a3554e876 100644 --- a/src/components/views/elements/DialogButtons.tsx +++ b/src/components/views/elements/DialogButtons.tsx @@ -30,8 +30,9 @@ interface IProps { // If true, make the primary button a form submit button (input type="submit") primaryIsSubmit?: boolean; - // onClick handler for the primary button. - onPrimaryButtonClick?: (ev: React.MouseEvent) => void; + // onClick handler for the primary button. Note that the returned promise, if + // returning a promise, is not used. + onPrimaryButtonClick?: (ev: React.MouseEvent) => (void | Promise); // should there be a cancel button? default: true hasCancel?: boolean; From 9350c50f8783f95edd6eeff27bc8594bd796803a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Mar 2022 23:16:25 -0600 Subject: [PATCH 08/47] Step 6: Refactor event rendering to stop using `getComponent` We move all of the event tile rendering into a factory manager for a couple reasons: 1. `EventTile` is uncomfortably large for a file 2. A simple map isn't possible anymore (can't convert the existing maps like `eventTileTypes` to `Record` because the types are actually incompatible) So, by having a factory manager place we can more easily render components without having to use `getComponent()` all over the place, and without lying to ourselves about how simple the event rendering path is. This change also moves quite a bit of the rendering path into the new `EventTileFactory` file so it can be easily seen by future developers. --- src/Unread.ts | 4 +- src/components/structures/MessagePanel.tsx | 7 +- src/components/structures/RoomView.tsx | 4 +- src/components/structures/TimelinePanel.tsx | 4 +- .../views/messages/MessageEvent.tsx | 6 +- src/components/views/rooms/EventTile.tsx | 286 ++++--------- src/components/views/rooms/ReplyTile.tsx | 51 +-- .../views/rooms/SearchResultTile.tsx | 5 +- src/events/EventTileFactory.tsx | 376 ++++++++++++++++++ src/index.ts | 5 - src/utils/EventUtils.ts | 45 ++- src/utils/exportUtils/HtmlExport.tsx | 5 +- src/utils/exportUtils/JSONExport.ts | 4 +- src/utils/exportUtils/PlainTextExport.ts | 4 +- 14 files changed, 523 insertions(+), 283 deletions(-) create mode 100644 src/events/EventTileFactory.tsx diff --git a/src/Unread.ts b/src/Unread.ts index 91e192b371..95046db29d 100644 --- a/src/Unread.ts +++ b/src/Unread.ts @@ -20,7 +20,7 @@ import { EventType } from "matrix-js-sdk/src/@types/event"; import { MatrixClientPeg } from "./MatrixClientPeg"; import shouldHideEvent from './shouldHideEvent'; -import { haveTileForEvent } from "./components/views/rooms/EventTile"; +import { haveRendererForEvent } from "./events/EventTileFactory"; /** * Returns true if this event arriving in a room should affect the room's @@ -46,7 +46,7 @@ export function eventTriggersUnreadCount(ev: MatrixEvent): boolean { } if (ev.isRedacted()) return false; - return haveTileForEvent(ev); + return haveRendererForEvent(ev); } export function doesRoomHaveUnreadMessages(room: Room): boolean { diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index 7758375a69..a5a9164bb7 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -31,7 +31,7 @@ import SettingsStore from '../../settings/SettingsStore'; import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext"; import { Layout } from "../../settings/enums/Layout"; import { _t } from "../../languageHandler"; -import EventTile, { UnwrappedEventTile, haveTileForEvent, IReadReceiptProps } from "../views/rooms/EventTile"; +import EventTile, { UnwrappedEventTile, IReadReceiptProps } from "../views/rooms/EventTile"; import { hasText } from "../../TextForEvent"; import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResizer"; import DMRoomMap from "../../utils/DMRoomMap"; @@ -52,6 +52,7 @@ import EditorStateTransfer from "../../utils/EditorStateTransfer"; import { Action } from '../../dispatcher/actions'; import { getEventDisplayInfo } from "../../utils/EventUtils"; import { IReadReceiptInfo } from "../views/rooms/ReadReceiptMarker"; +import { haveRendererForEvent } from "../../events/EventTileFactory"; const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes const continuedTypes = [EventType.Sticker, EventType.RoomMessage]; @@ -95,7 +96,7 @@ export function shouldFormContinuation( timelineRenderingType !== TimelineRenderingType.Thread) return false; // if we don't have tile for previous event then it was shown by showHiddenEvents and has no SenderProfile - if (!haveTileForEvent(prevEvent, showHiddenEvents)) return false; + if (!haveRendererForEvent(prevEvent, showHiddenEvents)) return false; return true; } @@ -488,7 +489,7 @@ export default class MessagePanel extends React.Component { return true; } - if (!haveTileForEvent(mxEv, this.showHiddenEvents)) { + if (!haveRendererForEvent(mxEv, this.showHiddenEvents)) { return false; // no tile = no show } diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index d52786c39b..906c32c0d9 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -55,7 +55,6 @@ import SettingsStore from "../../settings/SettingsStore"; import { Layout } from "../../settings/enums/Layout"; import AccessibleButton from "../views/elements/AccessibleButton"; import RightPanelStore from "../../stores/right-panel/RightPanelStore"; -import { haveTileForEvent } from "../views/rooms/EventTile"; import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext"; import MatrixClientContext, { MatrixClientProps, withMatrixClientHOC } from "../../contexts/MatrixClientContext"; import { E2EStatus, shieldStatusForRoom } from '../../utils/ShieldUtils'; @@ -108,6 +107,7 @@ import { DoAfterSyncPreparedPayload } from '../../dispatcher/payloads/DoAfterSyn import FileDropTarget from './FileDropTarget'; import Measured from '../views/elements/Measured'; import { FocusComposerPayload } from '../../dispatcher/payloads/FocusComposerPayload'; +import { haveRendererForEvent } from "../../events/EventTileFactory"; const DEBUG = false; let debuglog = function(msg: string) {}; @@ -1451,7 +1451,7 @@ export class RoomView extends React.Component { continue; } - if (!haveTileForEvent(mxEv, this.state.showHiddenEventsInTimeline)) { + if (!haveRendererForEvent(mxEv, this.state.showHiddenEventsInTimeline)) { // XXX: can this ever happen? It will make the result count // not match the displayed count. continue; diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index dd372b9381..52094a84c9 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -40,7 +40,6 @@ import dis from "../../dispatcher/dispatcher"; import { Action } from '../../dispatcher/actions'; import Timer from '../../utils/Timer'; import shouldHideEvent from '../../shouldHideEvent'; -import { haveTileForEvent } from "../views/rooms/EventTile"; import { arrayFastClone } from "../../utils/arrays"; import MessagePanel from "./MessagePanel"; import { IScrollState } from "./ScrollPanel"; @@ -54,6 +53,7 @@ import CallEventGrouper, { buildCallEventGroupers } from "./CallEventGrouper"; import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload"; import { getKeyBindingsManager } from "../../KeyBindingsManager"; import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts"; +import { haveRendererForEvent } from "../../events/EventTileFactory"; const PAGINATE_SIZE = 20; const INITIAL_SIZE = 20; @@ -1473,7 +1473,7 @@ class TimelinePanel extends React.Component { const shouldIgnore = !!ev.status || // local echo (ignoreOwn && ev.getSender() === myUserId); // own message - const isWithoutTile = !haveTileForEvent(ev, this.context?.showHiddenEventsInTimeline) || + const isWithoutTile = !haveRendererForEvent(ev, this.context?.showHiddenEventsInTimeline) || shouldHideEvent(ev, this.context); if (isWithoutTile || !node) { diff --git a/src/components/views/messages/MessageEvent.tsx b/src/components/views/messages/MessageEvent.tsx index b0277cd464..90fd844672 100644 --- a/src/components/views/messages/MessageEvent.tsx +++ b/src/components/views/messages/MessageEvent.tsx @@ -41,10 +41,10 @@ import MLocationBody from "./MLocationBody"; import MjolnirBody from "./MjolnirBody"; // onMessageAllowed is handled internally -interface IProps extends Omit { +interface IProps extends Omit { /* overrides for the msgtype-specific components, used by ReplyTile to override file rendering */ - overrideBodyTypes?: Record; - overrideEventTypes?: Record; + overrideBodyTypes?: Record; + overrideEventTypes?: Record; // helper function to access relations for this event getRelationsForEvent?: (eventId: string, relationType: string, eventType: string) => Relations; diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index d830a4f5a1..aa2e38ea8d 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -17,7 +17,7 @@ limitations under the License. import React, { createRef, forwardRef, MouseEvent, RefObject } from 'react'; import classNames from "classnames"; -import { EventType, MsgType, RelationType } from "matrix-js-sdk/src/@types/event"; +import { EventType, MsgType } from "matrix-js-sdk/src/@types/event"; import { EventStatus, MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event"; import { Relations } from "matrix-js-sdk/src/models/relations"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; @@ -25,25 +25,19 @@ import { Thread, ThreadEvent } from 'matrix-js-sdk/src/models/thread'; import { logger } from "matrix-js-sdk/src/logger"; import { NotificationCountType, Room, RoomEvent } from 'matrix-js-sdk/src/models/room'; import { CallErrorCode } from "matrix-js-sdk/src/webrtc/call"; -import { M_POLL_START } from "matrix-events-sdk"; import { CryptoEvent } from "matrix-js-sdk/src/crypto"; import { UserTrustLevel } from 'matrix-js-sdk/src/crypto/CrossSigning'; import ReplyChain from "../elements/ReplyChain"; import { _t } from '../../../languageHandler'; -import { hasText } from "../../../TextForEvent"; -import * as sdk from "../../../index"; import dis from '../../../dispatcher/dispatcher'; import { Layout } from "../../../settings/enums/Layout"; import { formatTime } from "../../../DateUtils"; import { MatrixClientPeg } from '../../../MatrixClientPeg'; -import { ALL_RULE_TYPES } from "../../../mjolnir/BanList"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import { E2EState } from "./E2EIcon"; import { toRem } from "../../../utils/units"; -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 Tooltip from "../elements/Tooltip"; import EditorStateTransfer from "../../../utils/EditorStateTransfer"; @@ -62,7 +56,6 @@ import MessageActionBar from "../messages/MessageActionBar"; import ReactionsRow from '../messages/ReactionsRow'; import { getEventDisplayInfo } from '../../../utils/EventUtils'; import SettingsStore from "../../../settings/SettingsStore"; -import MKeyVerificationConclusion from "../messages/MKeyVerificationConclusion"; import { showThread } from '../../../dispatcher/dispatch-actions/threads'; import { MessagePreviewStore } from '../../../stores/room-list/MessagePreviewStore'; import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext"; @@ -81,123 +74,11 @@ import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { shouldDisplayReply } from '../../../utils/Reply'; import PosthogTrackers from "../../../PosthogTrackers"; import TileErrorBoundary from '../messages/TileErrorBoundary'; -import ThreadSummary, { ThreadMessagePreview } from './ThreadSummary'; +import { haveRendererForEvent, isMessageEvent, renderTile } from "../../../events/EventTileFactory"; +import ThreadSummary, { ThreadMessagePreview } from "./ThreadSummary"; export type GetRelationsForEvent = (eventId: string, relationType: string, eventType: string) => Relations; -const eventTileTypes = { - [EventType.RoomMessage]: 'messages.MessageEvent', - [EventType.Sticker]: 'messages.MessageEvent', - [M_POLL_START.name]: 'messages.MessageEvent', - [M_POLL_START.altName]: 'messages.MessageEvent', - [EventType.KeyVerificationCancel]: 'messages.MKeyVerificationConclusion', - [EventType.KeyVerificationDone]: 'messages.MKeyVerificationConclusion', - [EventType.CallInvite]: 'messages.CallEvent', -}; - -const stateEventTileTypes = { - [EventType.RoomEncryption]: 'messages.EncryptionEvent', - [EventType.RoomCanonicalAlias]: 'messages.TextualEvent', - [EventType.RoomCreate]: 'messages.RoomCreate', - [EventType.RoomMember]: 'messages.TextualEvent', - [EventType.RoomName]: 'messages.TextualEvent', - [EventType.RoomAvatar]: 'messages.RoomAvatarEvent', - [EventType.RoomThirdPartyInvite]: 'messages.TextualEvent', - [EventType.RoomHistoryVisibility]: 'messages.TextualEvent', - [EventType.RoomTopic]: 'messages.TextualEvent', - [EventType.RoomPowerLevels]: 'messages.TextualEvent', - [EventType.RoomPinnedEvents]: 'messages.TextualEvent', - [EventType.RoomServerAcl]: 'messages.TextualEvent', - // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) - 'im.vector.modular.widgets': 'messages.TextualEvent', - [WIDGET_LAYOUT_EVENT_TYPE]: 'messages.TextualEvent', - [EventType.RoomTombstone]: 'messages.TextualEvent', - [EventType.RoomJoinRules]: 'messages.TextualEvent', - [EventType.RoomGuestAccess]: 'messages.TextualEvent', -}; - -const stateEventSingular = new Set([ - EventType.RoomEncryption, - EventType.RoomCanonicalAlias, - EventType.RoomCreate, - EventType.RoomName, - EventType.RoomAvatar, - EventType.RoomHistoryVisibility, - EventType.RoomTopic, - EventType.RoomPowerLevels, - EventType.RoomPinnedEvents, - EventType.RoomServerAcl, - WIDGET_LAYOUT_EVENT_TYPE, - EventType.RoomTombstone, - EventType.RoomJoinRules, - EventType.RoomGuestAccess, -]); - -// Add all the Mjolnir stuff to the renderer -for (const evType of ALL_RULE_TYPES) { - stateEventTileTypes[evType] = 'messages.TextualEvent'; -} - -export function getHandlerTile(ev: MatrixEvent): string { - const type = ev.getType(); - - // don't show verification requests we're not involved in, - // not even when showing hidden events - if (type === EventType.RoomMessage) { - const content = ev.getContent(); - if (content && content.msgtype === MsgType.KeyVerificationRequest) { - const me = MatrixClientPeg.get()?.getUserId(); - if (ev.getSender() !== me && content.to !== me) { - return undefined; - } else { - return "messages.MKeyVerificationRequest"; - } - } - } - // these events are sent by both parties during verification, but we only want to render one - // tile once the verification concludes, so filter out the one from the other party. - if (type === EventType.KeyVerificationDone) { - const me = MatrixClientPeg.get()?.getUserId(); - if (ev.getSender() !== me) { - return undefined; - } - } - - // sometimes MKeyVerificationConclusion declines to render. Jankily decline to render and - // fall back to showing hidden events, if we're viewing hidden events - // XXX: This is extremely a hack. Possibly these components should have an interface for - // declining to render? - if (type === EventType.KeyVerificationCancel || type === EventType.KeyVerificationDone) { - if (!MKeyVerificationConclusion.shouldRender(ev, ev.verificationRequest)) { - return; - } - } - - // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) - if (type === "im.vector.modular.widgets") { - let type = ev.getContent()['type']; - if (!type) { - // deleted/invalid widget - try the past widget type - type = ev.getPrevContent()['type']; - } - - if (WidgetType.JITSI.matches(type)) { - return "messages.MJitsiWidgetEvent"; - } - } - - if (ev.isState()) { - if (stateEventSingular.has(type) && ev.getStateKey() !== "") return undefined; - return stateEventTileTypes[type]; - } - - if (ev.isRedacted()) { - return "messages.MessageEvent"; - } - - return eventTileTypes[type]; -} - // Our component structure for EventTiles on the timeline is: // // .-EventTile------------------------------------------------. @@ -1054,7 +935,7 @@ export class UnwrappedEventTile extends React.Component { const msgtype = this.props.mxEvent.getContent().msgtype; const eventType = this.props.mxEvent.getType() as EventType; const { - tileHandler, + hasRenderer, isBubbleMessage, isInfoMessage, isLeftAlignedBubbleMessage, @@ -1065,7 +946,7 @@ export class UnwrappedEventTile extends React.Component { // This shouldn't happen: the caller should check we support this type // before trying to instantiate us - if (!tileHandler) { + if (!hasRenderer) { const { mxEvent } = this.props; logger.warn(`Event type not supported: type:${eventType} isState:${mxEvent.isState()}`); return
@@ -1075,7 +956,6 @@ export class UnwrappedEventTile extends React.Component {
; } - const EventTileType = sdk.getComponent(tileHandler); const isProbablyMedia = MediaEventHelper.isEligible(this.props.mxEvent); const lineClasses = classNames("mx_EventTile_line", { @@ -1154,7 +1034,7 @@ export class UnwrappedEventTile extends React.Component { ) { avatarSize = 24; needsSenderProfile = true; - } else if (tileHandler === 'messages.RoomCreate' || isBubbleMessage) { + } else if (eventType === EventType.RoomCreate || isBubbleMessage) { avatarSize = 0; needsSenderProfile = false; } else if (isInfoMessage) { @@ -1322,20 +1202,21 @@ export class UnwrappedEventTile extends React.Component { msgOption = readAvatars; } - const replyChain = haveTileForEvent(this.props.mxEvent) && shouldDisplayReply(this.props.mxEvent) - ? - : null; + const replyChain = + (haveRendererForEvent(this.props.mxEvent) && shouldDisplayReply(this.props.mxEvent)) + ? + : null; const isOwnEvent = this.props.mxEvent?.sender?.userId === MatrixClientPeg.get().getUserId(); @@ -1362,16 +1243,19 @@ export class UnwrappedEventTile extends React.Component {
,
- + { renderTile(TimelineRenderingType.Notification, { + ...this.props, + + // overrides + ref: this.tile, + isSeeingThroughMessageHiddenForModeration, + + // appease TS + highlights: this.props.highlights, + highlightLink: this.props.highlightLink, + onHeightChanged: this.props.onHeightChanged, + permalinkCreator: this.props.permalinkCreator, + }) }
, ]); } @@ -1403,17 +1287,19 @@ export class UnwrappedEventTile extends React.Component {
,
{ replyChain } - + { renderTile(TimelineRenderingType.Thread, { + ...this.props, + + // overrides + ref: this.tile, + isSeeingThroughMessageHiddenForModeration, + + // appease TS + highlights: this.props.highlights, + highlightLink: this.props.highlightLink, + onHeightChanged: this.props.onHeightChanged, + permalinkCreator: this.props.permalinkCreator, + }) } { actionBar } { timestamp }
, @@ -1485,16 +1371,19 @@ export class UnwrappedEventTile extends React.Component { "data-scroll-tokens": scrollToken, }, [
- + { renderTile(TimelineRenderingType.File, { + ...this.props, + + // overrides + ref: this.tile, + isSeeingThroughMessageHiddenForModeration, + + // appease TS + highlights: this.props.highlights, + highlightLink: this.props.highlightLink, + onHeightChanged: this.props.onHeightChanged, + permalinkCreator: this.props.permalinkCreator, + }) }
, { { groupTimestamp } { groupPadlock } { replyChain } - + { renderTile(this.context.timelineRenderingType, { + ...this.props, + + // overrides + ref: this.tile, + isSeeingThroughMessageHiddenForModeration, + timestamp: bubbleTimestamp, + + // appease TS + highlights: this.props.highlights, + highlightLink: this.props.highlightLink, + onHeightChanged: this.props.onHeightChanged, + permalinkCreator: this.props.permalinkCreator, + }) } { keyRequestInfo } { actionBar } { this.props.layout === Layout.IRC && <> @@ -1577,31 +1464,6 @@ const SafeEventTile = forwardRef((props: IProps, ref: RefObject diff --git a/src/components/views/rooms/ReplyTile.tsx b/src/components/views/rooms/ReplyTile.tsx index 95d249dd16..1d23e7a56a 100644 --- a/src/components/views/rooms/ReplyTile.tsx +++ b/src/components/views/rooms/ReplyTile.tsx @@ -27,11 +27,11 @@ import { Action } from '../../../dispatcher/actions'; import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks'; import SenderProfile from "../messages/SenderProfile"; import MImageReplyBody from "../messages/MImageReplyBody"; -import * as sdk from '../../../index'; import { getEventDisplayInfo, isVoiceMessage } from '../../../utils/EventUtils'; import MFileBody from "../messages/MFileBody"; import MVoiceMessageBody from "../messages/MVoiceMessageBody"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; +import { renderReplyTile } from "../../../events/EventTileFactory"; interface IProps { mxEvent: MatrixEvent; @@ -109,10 +109,10 @@ export default class ReplyTile extends React.PureComponent { const msgType = mxEvent.getContent().msgtype; const evType = mxEvent.getType() as EventType; - const { tileHandler, isInfoMessage, isSeeingThroughMessageHiddenForModeration } = getEventDisplayInfo(mxEvent); + const { hasRenderer, isInfoMessage, isSeeingThroughMessageHiddenForModeration } = getEventDisplayInfo(mxEvent); // This shouldn't happen: the caller should check we support this type // before trying to instantiate us - if (!tileHandler) { + if (!hasRenderer) { const { mxEvent } = this.props; logger.warn(`Event type not supported: type:${mxEvent.getType()} isState:${mxEvent.isState()}`); return
@@ -120,8 +120,6 @@ export default class ReplyTile extends React.PureComponent {
; } - const EventTileType = sdk.getComponent(tileHandler); - const classes = classNames("mx_ReplyTile", { mx_ReplyTile_info: isInfoMessage && !mxEvent.isRedacted(), mx_ReplyTile_audio: msgType === MsgType.Audio, @@ -135,10 +133,10 @@ export default class ReplyTile extends React.PureComponent { let sender; const needsSenderProfile = ( - !isInfoMessage && - msgType !== MsgType.Image && - tileHandler !== EventType.RoomCreate && - evType !== EventType.Sticker + !isInfoMessage + && msgType !== MsgType.Image + && evType !== EventType.Sticker + && evType !== EventType.RoomCreate ); if (needsSenderProfile) { @@ -147,13 +145,13 @@ export default class ReplyTile extends React.PureComponent { />; } - const msgtypeOverrides = { + const msgtypeOverrides: Record = { [MsgType.Image]: MImageReplyBody, // Override audio and video body with file body. We also hide the download/decrypt button using CSS [MsgType.Audio]: isVoiceMessage(mxEvent) ? MVoiceMessageBody : MFileBody, [MsgType.Video]: MFileBody, }; - const evOverrides = { + const evOverrides: Record = { // Use MImageReplyBody so that the sticker isn't taking up a lot of space [EventType.Sticker]: MImageReplyBody, }; @@ -162,20 +160,23 @@ export default class ReplyTile extends React.PureComponent {
); diff --git a/src/components/views/rooms/SearchResultTile.tsx b/src/components/views/rooms/SearchResultTile.tsx index 85bd5c0ed6..a3d646aed3 100644 --- a/src/components/views/rooms/SearchResultTile.tsx +++ b/src/components/views/rooms/SearchResultTile.tsx @@ -23,10 +23,11 @@ import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContex import SettingsStore from "../../../settings/SettingsStore"; import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks'; import DateSeparator from "../messages/DateSeparator"; -import EventTile, { haveTileForEvent } from "./EventTile"; +import EventTile from "./EventTile"; import { shouldFormContinuation } from "../../structures/MessagePanel"; import { wantsDateSeparator } from "../../../DateUtils"; import CallEventGrouper, { buildCallEventGroupers } from "../../structures/CallEventGrouper"; +import { haveRendererForEvent } from "../../../events/EventTileFactory"; interface IProps { // a matrix-js-sdk SearchResult containing the details of this result @@ -77,7 +78,7 @@ export default class SearchResultTile extends React.Component { highlights = this.props.searchHighlights; } - if (haveTileForEvent(mxEv, this.context?.showHiddenEventsInTimeline)) { + if (haveRendererForEvent(mxEv, this.context?.showHiddenEventsInTimeline)) { // do we need a date separator since the last event? const prevEv = timeline[j - 1]; // is this a continuation of the previous message? diff --git a/src/events/EventTileFactory.tsx b/src/events/EventTileFactory.tsx new file mode 100644 index 0000000000..ceb2abab95 --- /dev/null +++ b/src/events/EventTileFactory.tsx @@ -0,0 +1,376 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { EventType, MsgType, RelationType } from "matrix-js-sdk/src/@types/event"; +import { M_POLL_START, Optional } from "matrix-events-sdk"; +import { MatrixClient } from "matrix-js-sdk/src/client"; + +import EditorStateTransfer from "../utils/EditorStateTransfer"; +import { RoomPermalinkCreator } from "../utils/permalinks/Permalinks"; +import CallEventGrouper from "../components/structures/CallEventGrouper"; +import { GetRelationsForEvent } from "../components/views/rooms/EventTile"; +import { TimelineRenderingType } from "../contexts/RoomContext"; +import MessageEvent from "../components/views/messages/MessageEvent"; +import MKeyVerificationConclusion from "../components/views/messages/MKeyVerificationConclusion"; +import CallEvent from "../components/views/messages/CallEvent"; +import TextualEvent from "../components/views/messages/TextualEvent"; +import EncryptionEvent from "../components/views/messages/EncryptionEvent"; +import RoomCreate from "../components/views/messages/RoomCreate"; +import RoomAvatarEvent from "../components/views/messages/RoomAvatarEvent"; +import { WIDGET_LAYOUT_EVENT_TYPE } from "../stores/widgets/WidgetLayoutStore"; +import { ALL_RULE_TYPES } from "../mjolnir/BanList"; +import { MatrixClientPeg } from "../MatrixClientPeg"; +import MKeyVerificationRequest from "../components/views/messages/MKeyVerificationRequest"; +import { WidgetType } from "../widgets/WidgetType"; +import MJitsiWidgetEvent from "../components/views/messages/MJitsiWidgetEvent"; +import { hasText } from "../TextForEvent"; +import { getMessageModerationState, MessageModerationState } from "../utils/EventUtils"; +import HiddenBody from "../components/views/messages/HiddenBody"; +import SettingsStore from "../settings/SettingsStore"; +import ViewSourceEvent from "../components/views/messages/ViewSourceEvent"; + +// Subset of EventTile's IProps plus some mixins +export interface EventTileTypeProps { + ref?: React.RefObject; // `any` because it's effectively impossible to convince TS of a reasonable type + mxEvent: MatrixEvent; + highlights: string[]; + highlightLink: string; + showUrlPreview?: boolean; + onHeightChanged: () => void; + forExport?: boolean; + getRelationsForEvent?: GetRelationsForEvent; + editState?: EditorStateTransfer; + replacingEventId?: string; + permalinkCreator: RoomPermalinkCreator; + callEventGrouper?: CallEventGrouper; + isSeeingThroughMessageHiddenForModeration?: boolean; + timestamp?: JSX.Element; + maxImageHeight?: number; // pixels + overrideBodyTypes?: Record; + overrideEventTypes?: Record; +} + +type FactoryProps = Omit; +type Factory = (ref: Optional>, props: X) => JSX.Element; +type FactoryMap = Record; + +const MessageEventFactory: Factory = (ref, props) => ; +const KeyVerificationConclFactory: Factory = (ref, props) => ; +const CallEventFactory: Factory = (ref, props) => ( + +); +const TextualEventFactory: Factory = (ref, props) => ; +const VerificationReqFactory: Factory = (ref, props) => ; +const HiddenEventFactory: Factory = (ref, props) => ; + +// These factories are exported for reference comparison against pickFactory() +export const JitsiEventFactory: Factory = (ref, props) => ; +export const JSONEventFactory: Factory = (ref, props) => ; + +const EVENT_TILE_TYPES: FactoryMap = { + [EventType.RoomMessage]: MessageEventFactory, // note that verification requests are handled in pickFactory() + [EventType.Sticker]: MessageEventFactory, + [M_POLL_START.name]: MessageEventFactory, + [M_POLL_START.altName]: MessageEventFactory, + [EventType.KeyVerificationCancel]: KeyVerificationConclFactory, + [EventType.KeyVerificationDone]: KeyVerificationConclFactory, + [EventType.CallInvite]: CallEventFactory, // note that this requires a special factory type +}; + +const STATE_EVENT_TILE_TYPES: FactoryMap = { + [EventType.RoomEncryption]: (ref, props) => , + [EventType.RoomCanonicalAlias]: TextualEventFactory, + [EventType.RoomCreate]: (ref, props) => , + [EventType.RoomMember]: TextualEventFactory, + [EventType.RoomName]: TextualEventFactory, + [EventType.RoomAvatar]: (ref, props) => , + [EventType.RoomThirdPartyInvite]: TextualEventFactory, + [EventType.RoomHistoryVisibility]: TextualEventFactory, + [EventType.RoomTopic]: TextualEventFactory, + [EventType.RoomPowerLevels]: TextualEventFactory, + [EventType.RoomPinnedEvents]: TextualEventFactory, + [EventType.RoomServerAcl]: TextualEventFactory, + // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) + 'im.vector.modular.widgets': TextualEventFactory, // note that Jitsi widgets are special in pickFactory() + [WIDGET_LAYOUT_EVENT_TYPE]: TextualEventFactory, + [EventType.RoomTombstone]: TextualEventFactory, + [EventType.RoomJoinRules]: TextualEventFactory, + [EventType.RoomGuestAccess]: TextualEventFactory, +}; + +// Add all the Mjolnir stuff to the renderer too +for (const evType of ALL_RULE_TYPES) { + STATE_EVENT_TILE_TYPES[evType] = TextualEventFactory; +} + +// These events should be recorded in the STATE_EVENT_TILE_TYPES +const SINGULAR_STATE_EVENTS = new Set([ + EventType.RoomEncryption, + EventType.RoomCanonicalAlias, + EventType.RoomCreate, + EventType.RoomName, + EventType.RoomAvatar, + EventType.RoomHistoryVisibility, + EventType.RoomTopic, + EventType.RoomPowerLevels, + EventType.RoomPinnedEvents, + EventType.RoomServerAcl, + WIDGET_LAYOUT_EVENT_TYPE, + EventType.RoomTombstone, + EventType.RoomJoinRules, + EventType.RoomGuestAccess, +]); + +/** + * Find an event tile factory for the given conditions. + * @param mxEvent The event. + * @param cli The matrix client to reference when needed. + * @param asHiddenEv When true, treat the event as always hidden. + * @returns The factory, or falsy if not possible. + */ +export function pickFactory(mxEvent: MatrixEvent, cli: MatrixClient, asHiddenEv?: boolean): Optional { + const evType = mxEvent.getType(); // cache this to reduce call stack execution hits + + // Note: we avoid calling SettingsStore unless absolutely necessary - this code is on the critical path. + + if (asHiddenEv && SettingsStore.getValue("showHiddenEventsInTimeline")) { + return JSONEventFactory; + } + + const noEventFactoryFactory: (() => Optional) = () => SettingsStore.getValue("showHiddenEventsInTimeline") + ? JSONEventFactory + : undefined; // just don't render things that we shouldn't render + + // We run all the event type checks first as they might override the factory entirely. + + const moderationState = getMessageModerationState(mxEvent, cli); + if (moderationState === MessageModerationState.HIDDEN_TO_CURRENT_USER) { + return HiddenEventFactory; + } + + if (evType === EventType.RoomMessage) { + // don't show verification requests we're not involved in, + // not even when showing hidden events + const content = mxEvent.getContent(); + if (content?.msgtype === MsgType.KeyVerificationRequest) { + const me = cli.getUserId(); + if (mxEvent.getSender() !== me && content['to'] !== me) { + return noEventFactoryFactory(); // not for/from us + } else { + // override the factory + return VerificationReqFactory; + } + } + } else if (evType === EventType.KeyVerificationDone) { + // these events are sent by both parties during verification, but we only want to render one + // tile once the verification concludes, so filter out the one from the other party. + const me = cli.getUserId(); + if (mxEvent.getSender() !== me) { + return noEventFactoryFactory(); + } + } + + if (evType === EventType.KeyVerificationCancel || evType === EventType.KeyVerificationDone) { + // sometimes MKeyVerificationConclusion declines to render. Jankily decline to render and + // fall back to showing hidden events, if we're viewing hidden events + // XXX: This is extremely a hack. Possibly these components should have an interface for + // declining to render? + if (!MKeyVerificationConclusion.shouldRender(mxEvent, mxEvent.verificationRequest)) { + return noEventFactoryFactory(); + } + } + + // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) + if (evType === "im.vector.modular.widgets") { + let type = mxEvent.getContent()['type']; + if (!type) { + // deleted/invalid widget - try the past widget type + type = mxEvent.getPrevContent()['type']; + } + + if (WidgetType.JITSI.matches(type)) { + // override the factory + return JitsiEventFactory; + } + } + + // Try and pick a state event factory, if we can. + if (mxEvent.isState()) { + if (SINGULAR_STATE_EVENTS.has(evType) && mxEvent.getStateKey() !== '') { + return noEventFactoryFactory(); // improper event type to render + } + return STATE_EVENT_TILE_TYPES[evType] ?? noEventFactoryFactory(); + } + + // Blanket override for all events. The MessageEvent component handles redacted states for us. + if (mxEvent.isRedacted()) { + return MessageEventFactory; + } + + return EVENT_TILE_TYPES[evType] ?? noEventFactoryFactory(); +} + +/** + * Render an event as a tile + * @param renderType The render type. Used to inform properties given to the eventual component. + * @param props The properties to provide to the eventual component. + * @param cli Optional client instance to use, otherwise the default MatrixClientPeg will be used. + * @returns The tile as JSX, or falsy if unable to render. + */ +export function renderTile( + renderType: TimelineRenderingType, + props: EventTileTypeProps, + cli?: MatrixClient, +): Optional { + cli = cli ?? MatrixClientPeg.get(); // because param defaults don't do the correct thing + + const factory = pickFactory(props.mxEvent, cli); + if (!factory) return undefined; + + // Note that we split off the ones we actually care about here just to be sure that we're + // not going to accidentally send things we shouldn't from lazy callers. Eg: EventTile's + // lazy calls of `renderTile(..., this.props)` will have a lot more than we actually care + // about. + const { + ref, + mxEvent, + forExport, + replacingEventId, + editState, + highlights, + highlightLink, + showUrlPreview, + permalinkCreator, + onHeightChanged, + callEventGrouper, + getRelationsForEvent, + isSeeingThroughMessageHiddenForModeration, + timestamp, + } = props; + + switch (renderType) { + case TimelineRenderingType.File: + case TimelineRenderingType.Notification: + case TimelineRenderingType.Thread: + // We only want a subset of props, so we don't end up causing issues for downstream components. + return factory(props.ref, { + mxEvent, + highlights, + highlightLink, + showUrlPreview, + onHeightChanged, + editState, + replacingEventId, + getRelationsForEvent, + isSeeingThroughMessageHiddenForModeration, + permalinkCreator, + }); + default: + // NEARLY ALL THE OPTIONS! + return factory(ref, { + mxEvent, + forExport, + replacingEventId, + editState, + highlights, + highlightLink, + showUrlPreview, + permalinkCreator, + onHeightChanged, + callEventGrouper, + getRelationsForEvent, + isSeeingThroughMessageHiddenForModeration, + timestamp, + }); + } +} + +/** + * A version of renderTile() specifically for replies. + * @param props The properties to specify on the eventual object. + * @param cli Optional client instance to use, otherwise the default MatrixClientPeg will be used. + * @returns The tile as JSX, or falsy if unable to render. + */ +export function renderReplyTile( + props: EventTileTypeProps, + cli?: MatrixClient, +): Optional { + cli = cli ?? MatrixClientPeg.get(); // because param defaults don't do the correct thing + + const factory = pickFactory(props.mxEvent, cli); + if (!factory) return undefined; + + // See renderTile() for why we split off so much + const { + ref, + mxEvent, + highlights, + highlightLink, + onHeightChanged, + showUrlPreview, + overrideBodyTypes, + overrideEventTypes, + replacingEventId, + maxImageHeight, + getRelationsForEvent, + isSeeingThroughMessageHiddenForModeration, + permalinkCreator, + } = props; + + return factory(ref, { + mxEvent, + highlights, + highlightLink, + onHeightChanged, + showUrlPreview, + overrideBodyTypes, + overrideEventTypes, + replacingEventId, + maxImageHeight, + getRelationsForEvent, + isSeeingThroughMessageHiddenForModeration, + permalinkCreator, + }); +} + +// XXX: this'll eventually be dynamic based on the fields once we have extensible event types +const messageTypes = [EventType.RoomMessage, EventType.Sticker]; +export function isMessageEvent(ev: MatrixEvent): boolean { + return (messageTypes.includes(ev.getType() as EventType)) || M_POLL_START.matches(ev.getType()); +} + +export function haveRendererForEvent(mxEvent: MatrixEvent, showHiddenEvents?: boolean): boolean { + // Only show "Message deleted" tile for plain message events, encrypted events, + // and state events as they'll likely still contain enough keys to be relevant. + if (mxEvent.isRedacted() && !mxEvent.isEncrypted() && !isMessageEvent(mxEvent) && !mxEvent.isState()) { + return false; + } + + // No tile for replacement events since they update the original tile + if (mxEvent.isRelation(RelationType.Replace)) return false; + + const handler = pickFactory(mxEvent, MatrixClientPeg.get()); + if (!handler) return false; + if (handler === TextualEventFactory) { + return hasText(mxEvent, showHiddenEvents); + } else if (handler === STATE_EVENT_TILE_TYPES[EventType.RoomCreate]) { + return Boolean(mxEvent.getContent()['predecessor']); + } else { + return true; + } +} diff --git a/src/index.ts b/src/index.ts index 9b4d431983..6d942597b5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,8 +18,3 @@ limitations under the License. // Import the js-sdk so the proper `request` object can be set. This does some // magic with the browser injection to make all subsequent imports work fine. import "matrix-js-sdk/src/browser-index"; - -export function getComponent(componentName: string): any { - // return Skinner.getComponent(componentName); -} - diff --git a/src/utils/EventUtils.ts b/src/utils/EventUtils.ts index a8d27d3f79..4300ee26e0 100644 --- a/src/utils/EventUtils.ts +++ b/src/utils/EventUtils.ts @@ -1,5 +1,5 @@ /* -Copyright 2019 - 2021 The Matrix.org Foundation C.I.C. +Copyright 2019 - 2022 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,12 +23,13 @@ import { M_POLL_START } from "matrix-events-sdk"; import { MatrixClientPeg } from '../MatrixClientPeg'; import shouldHideEvent from "../shouldHideEvent"; -import { getHandlerTile, GetRelationsForEvent, haveTileForEvent } from "../components/views/rooms/EventTile"; +import { GetRelationsForEvent } from "../components/views/rooms/EventTile"; import SettingsStore from "../settings/SettingsStore"; import defaultDispatcher from "../dispatcher/dispatcher"; import { TimelineRenderingType } from "../contexts/RoomContext"; import { launchPollEditor } from "../components/views/messages/MPollBody"; import { Action } from "../dispatcher/actions"; +import { haveRendererForEvent, JitsiEventFactory, JSONEventFactory, pickFactory } from "../events/EventTileFactory"; /** * Returns whether an event should allow actions like reply, reactions, edit, etc. @@ -134,7 +135,7 @@ export function findEditableEvent({ /** * How we should render a message depending on its moderation state. */ -enum MessageModerationState { +export enum MessageModerationState { /** * The message is visible to all. */ @@ -158,7 +159,9 @@ enum MessageModerationState { * If MSC3531 is deactivated in settings, all messages are considered visible * to all. */ -export function getMessageModerationState(mxEvent: MatrixEvent): MessageModerationState { +export function getMessageModerationState(mxEvent: MatrixEvent, client?: MatrixClient): MessageModerationState { + client = client ?? MatrixClientPeg.get(); // because param defaults don't do the correct thing + if (!SettingsStore.getValue("feature_msc3531_hide_messages_pending_moderation")) { return MessageModerationState.VISIBLE_FOR_ALL; } @@ -171,7 +174,6 @@ export function getMessageModerationState(mxEvent: MatrixEvent): MessageModerati // pending moderation. However, if we're the author or a moderator, // we still need to display it. - const client = MatrixClientPeg.get(); if (mxEvent.sender?.userId === client.getUserId()) { // We're the author, show the message. return MessageModerationState.SEE_THROUGH_FOR_CURRENT_USER; @@ -196,7 +198,7 @@ export function getMessageModerationState(mxEvent: MatrixEvent): MessageModerati export function getEventDisplayInfo(mxEvent: MatrixEvent, hideEvent?: boolean): { isInfoMessage: boolean; - tileHandler: string; + hasRenderer: boolean; isBubbleMessage: boolean; isLeftAlignedBubbleMessage: boolean; noBubbleEvent: boolean; @@ -207,15 +209,11 @@ export function getEventDisplayInfo(mxEvent: MatrixEvent, hideEvent?: boolean): const eventType = mxEvent.getType(); let isSeeingThroughMessageHiddenForModeration = false; - let tileHandler; if (SettingsStore.getValue("feature_msc3531_hide_messages_pending_moderation")) { switch (getMessageModerationState(mxEvent)) { case MessageModerationState.VISIBLE_FOR_ALL: - // Default behavior, nothing to do. - break; case MessageModerationState.HIDDEN_TO_CURRENT_USER: - // Hide message. - tileHandler = "messages.HiddenBody"; + // Nothing specific to do here break; case MessageModerationState.SEE_THROUGH_FOR_CURRENT_USER: // Show message with a marker. @@ -223,9 +221,9 @@ export function getEventDisplayInfo(mxEvent: MatrixEvent, hideEvent?: boolean): break; } } - if (!tileHandler) { - tileHandler = getHandlerTile(mxEvent); - } + + // TODO: Thread a MatrixClient through to here + let factory = pickFactory(mxEvent, MatrixClientPeg.get()); // Info messages are basically information about commands processed on a room let isBubbleMessage = ( @@ -233,7 +231,7 @@ export function getEventDisplayInfo(mxEvent: MatrixEvent, hideEvent?: boolean): (eventType === EventType.RoomMessage && msgtype?.startsWith("m.key.verification")) || (eventType === EventType.RoomCreate) || (eventType === EventType.RoomEncryption) || - (tileHandler === "messages.MJitsiWidgetEvent") + (factory === JitsiEventFactory) ); const isLeftAlignedBubbleMessage = ( !isBubbleMessage && @@ -263,15 +261,20 @@ export function getEventDisplayInfo(mxEvent: MatrixEvent, hideEvent?: boolean): // source tile when there's no regular tile for an event and also for // replace relations (which otherwise would display as a confusing // duplicate of the thing they are replacing). - if ((hideEvent || !haveTileForEvent(mxEvent)) && SettingsStore.getValue("showHiddenEventsInTimeline")) { - tileHandler = "messages.ViewSourceEvent"; - isBubbleMessage = false; - // Reuse info message avatar and sender profile styling - isInfoMessage = true; + if (hideEvent || !haveRendererForEvent(mxEvent)) { + // forcefully ask for a factory for a hidden event (hidden event + // setting is checked internally) + // TODO: Thread a MatrixClient through to here + factory = pickFactory(mxEvent, MatrixClientPeg.get(), true); + if (factory === JSONEventFactory) { + isBubbleMessage = false; + // Reuse info message avatar and sender profile styling + isInfoMessage = true; + } } return { - tileHandler, + hasRenderer: !!factory, isInfoMessage, isBubbleMessage, isLeftAlignedBubbleMessage, diff --git a/src/utils/exportUtils/HtmlExport.tsx b/src/utils/exportUtils/HtmlExport.tsx index a7afeda928..89ac6146ca 100644 --- a/src/utils/exportUtils/HtmlExport.tsx +++ b/src/utils/exportUtils/HtmlExport.tsx @@ -31,7 +31,7 @@ import { formatFullDateNoDayNoTime, wantsDateSeparator } from "../../DateUtils"; import { RoomPermalinkCreator } from "../permalinks/Permalinks"; import { _t } from "../../languageHandler"; import * as Avatar from "../../Avatar"; -import EventTile, { haveTileForEvent } from "../../components/views/rooms/EventTile"; +import EventTile from "../../components/views/rooms/EventTile"; import DateSeparator from "../../components/views/messages/DateSeparator"; import BaseAvatar from "../../components/views/avatars/BaseAvatar"; import { ExportType } from "./exportUtils"; @@ -39,6 +39,7 @@ import { IExportOptions } from "./exportUtils"; import MatrixClientContext from "../../contexts/MatrixClientContext"; import getExportCSS from "./exportCSS"; import { textForEvent } from "../../TextForEvent"; +import { haveRendererForEvent } from "../../events/EventTileFactory"; import exportJS from "!!raw-loader!./exportJS"; @@ -406,7 +407,7 @@ export default class HTMLExporter extends Exporter { total: events.length, }), false, true); if (this.cancelled) return this.cleanUp(); - if (!haveTileForEvent(event)) continue; + if (!haveRendererForEvent(event)) continue; content += this.needsDateSeparator(event, prevEvent) ? this.getDateSeparator(event) : ""; const shouldBeJoined = !this.needsDateSeparator(event, prevEvent) && diff --git a/src/utils/exportUtils/JSONExport.ts b/src/utils/exportUtils/JSONExport.ts index 27fdb5a847..673420327e 100644 --- a/src/utils/exportUtils/JSONExport.ts +++ b/src/utils/exportUtils/JSONExport.ts @@ -21,9 +21,9 @@ import { logger } from "matrix-js-sdk/src/logger"; import Exporter from "./Exporter"; import { formatFullDateNoDay, formatFullDateNoDayNoTime } from "../../DateUtils"; -import { haveTileForEvent } from "../../components/views/rooms/EventTile"; import { ExportType, IExportOptions } from "./exportUtils"; import { _t } from "../../languageHandler"; +import { haveRendererForEvent } from "../../events/EventTileFactory"; export default class JSONExporter extends Exporter { protected totalSize = 0; @@ -85,7 +85,7 @@ export default class JSONExporter extends Exporter { total: events.length, }), false, true); if (this.cancelled) return this.cleanUp(); - if (!haveTileForEvent(event)) continue; + if (!haveRendererForEvent(event)) continue; this.messages.push(await this.getJSONString(event)); } return this.createJSONString(); diff --git a/src/utils/exportUtils/PlainTextExport.ts b/src/utils/exportUtils/PlainTextExport.ts index edabb80fe0..d41d06d35c 100644 --- a/src/utils/exportUtils/PlainTextExport.ts +++ b/src/utils/exportUtils/PlainTextExport.ts @@ -21,9 +21,9 @@ import { logger } from "matrix-js-sdk/src/logger"; import Exporter from "./Exporter"; import { formatFullDateNoDay } from "../../DateUtils"; import { _t } from "../../languageHandler"; -import { haveTileForEvent } from "../../components/views/rooms/EventTile"; import { ExportType, IExportOptions } from "./exportUtils"; import { textForEvent } from "../../TextForEvent"; +import { haveRendererForEvent } from "../../events/EventTileFactory"; export default class PlainTextExporter extends Exporter { protected totalSize: number; @@ -112,7 +112,7 @@ export default class PlainTextExporter extends Exporter { total: events.length, }), false, true); if (this.cancelled) return this.cleanUp(); - if (!haveTileForEvent(event)) continue; + if (!haveRendererForEvent(event)) continue; const textForEvent = await this.plainTextForEvent(event); content += textForEvent && `${new Date(event.getTs()).toLocaleString()} - ${textForEvent}\n`; } From a987ead7d2cc6708fe42eff9bd8beee1381a2de4 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Mar 2022 23:22:53 -0600 Subject: [PATCH 09/47] Step 8.1: Remove skinning setup from all tests --- scripts/make-react-component.js | 10 ++----- test/CallHandler-test.ts | 2 -- test/DecryptionFailureTracker-test.js | 1 - test/DeviceListener-test.ts | 1 - test/Image-test.ts | 1 - test/Reply-test.ts | 1 - test/TextForEvent-test.ts | 2 -- test/accessibility/RovingTabIndex-test.tsx | 1 - test/audio/Playback-test.ts | 2 -- .../structures/CallEventGrouper-test.ts | 1 - .../components/structures/RightPanel-test.tsx | 2 -- .../structures/ThreadPanel-test.tsx | 1 - .../audio_messages/RecordingPlayback-test.tsx | 1 - .../views/context_menus/ContextMenu-test.tsx | 1 - .../context_menus/MessageContextMenu-test.tsx | 1 - .../context_menus/SpaceContextMenu-test.tsx | 1 - .../views/dialogs/ExportDialog-test.tsx | 1 - .../views/dialogs/ForwardDialog-test.js | 2 -- .../views/elements/AppTile-test.tsx | 2 -- .../views/elements/InteractiveTooltip-test.ts | 1 - .../views/elements/PollCreateDialog-test.tsx | 2 -- .../views/elements/ReplyChain-test.tsx | 1 - .../views/elements/StyledRadioGroup-test.tsx | 1 - .../views/elements/TooltipTarget-test.tsx | 2 -- .../views/location/LocationPicker-test.tsx | 1 - .../views/location/LocationShareMenu-test.tsx | 1 - .../MKeyVerificationConclusion-test.js | 1 - .../views/right_panel/UserInfo-test.tsx | 1 - .../views/rooms/MemberList-test.tsx | 2 -- .../views/rooms/RoomHeader-test.tsx | 1 - .../views/rooms/RoomPreviewBar-test.tsx | 1 - .../views/rooms/SendMessageComposer-test.tsx | 1 - .../views/settings/CryptographyPanel-test.tsx | 2 -- .../views/settings/FontScalingPanel-test.tsx | 1 - .../views/settings/Notifications-test.tsx | 1 - .../views/settings/ThemeChoicePanel-test.tsx | 1 - .../views/spaces/QuickThemeSwitcher-test.tsx | 1 - .../views/spaces/SpacePanel-test.tsx | 1 - .../SpaceSettingsVisibilityTab-test.tsx | 2 -- test/createRoom-test.js | 1 - test/editor/caret-test.js | 1 - test/editor/deserialize-test.js | 1 - test/editor/model-test.js | 1 - test/editor/operations-test.js | 1 - test/editor/position-test.js | 1 - test/editor/range-test.js | 1 - test/editor/serialize-test.js | 1 - test/minimal-sdk.js | 29 ------------------- test/skinned-sdk.js | 28 ------------------ test/stores/RoomViewStore-test.js | 1 - test/stores/SpaceStore-test.ts | 1 - test/stores/VoiceChannelStore-test.ts | 1 - test/stores/VoiceRecordingStore-test.ts | 1 - test/stores/WidgetLayoutStore-test.ts | 1 - .../RoomNotificationState-test.ts | 1 - test/stores/room-list/SpaceWatcher-test.ts | 1 - test/utils/export-test.tsx | 1 - 57 files changed, 3 insertions(+), 129 deletions(-) delete mode 100644 test/minimal-sdk.js delete mode 100644 test/skinned-sdk.js diff --git a/scripts/make-react-component.js b/scripts/make-react-component.js index 063914fafe..56616c3350 100755 --- a/scripts/make-react-component.js +++ b/scripts/make-react-component.js @@ -6,7 +6,7 @@ const path = require('path'); * Unsophisticated script to create a styled, unit-tested react component. * -filePath / -f : path to the component to be created, including new component name, excluding extension, relative to src * -withStyle / -s : optional, flag to create a style file for the component. Defaults to false. - * + * * eg: * ``` * node srcipts/make-react-component.js -f components/toasts/NewToast -s @@ -15,7 +15,7 @@ const path = require('path'); * - src/components/toasts/NewToast.tsx * - test/components/toasts/NewToast-test.tsx * - res/css/components/toasts/_NewToast.scss - * + * */ const TEMPLATES = { @@ -34,7 +34,6 @@ export default %%ComponentName%%; import React from 'react'; import { mount } from 'enzyme'; -import '%%SkinnedSdkPath%%'; import %%ComponentName%% from '%%RelativeComponentPath%%'; describe('<%%ComponentName%% />', () => { @@ -85,10 +84,8 @@ const makeFile = async ({ const relativePathToComponent = path.parse(path.relative(path.dirname(newFilePath), componentFilePath || '')); const importComponentPath = path.join(relativePathToComponent.dir, relativePathToComponent.name); - const skinnedSdkPath = path.relative(path.dirname(newFilePath), 'test/skinned-sdk') - try { - await fs.writeFile(newFilePath, fillTemplate(template, componentName, importComponentPath, skinnedSdkPath), { flag: 'wx' }); + await fs.writeFile(newFilePath, fillTemplate(template, componentName, importComponentPath), { flag: 'wx' }); console.log(`Created ${path.relative(process.cwd(), newFilePath)}`); return newFilePath; } catch (error) { @@ -104,7 +101,6 @@ const makeFile = async ({ const fillTemplate = (template, componentName, relativeComponentFilePath, skinnedSdkPath) => template.replace(/%%ComponentName%%/g, componentName) .replace(/%%RelativeComponentPath%%/g, relativeComponentFilePath) - .replace(/%%SkinnedSdkPath%%/g, skinnedSdkPath) const makeReactComponent = async () => { diff --git a/test/CallHandler-test.ts b/test/CallHandler-test.ts index 53d341a6f4..01c1085032 100644 --- a/test/CallHandler-test.ts +++ b/test/CallHandler-test.ts @@ -14,8 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import './skinned-sdk'; - import { IProtocol } from 'matrix-js-sdk/src/matrix'; import { CallEvent, CallState, CallType } from 'matrix-js-sdk/src/webrtc/call'; import EventEmitter from 'events'; diff --git a/test/DecryptionFailureTracker-test.js b/test/DecryptionFailureTracker-test.js index 430cb80e50..b0494f97aa 100644 --- a/test/DecryptionFailureTracker-test.js +++ b/test/DecryptionFailureTracker-test.js @@ -16,7 +16,6 @@ limitations under the License. import { MatrixEvent } from 'matrix-js-sdk/src/matrix'; -import './skinned-sdk'; // Must be first for skinning to work import { DecryptionFailureTracker } from '../src/DecryptionFailureTracker'; class MockDecryptionError extends Error { diff --git a/test/DeviceListener-test.ts b/test/DeviceListener-test.ts index 957e622b35..0640567441 100644 --- a/test/DeviceListener-test.ts +++ b/test/DeviceListener-test.ts @@ -19,7 +19,6 @@ import { EventEmitter } from "events"; import { mocked } from "jest-mock"; import { Room } from "matrix-js-sdk/src/matrix"; -import './skinned-sdk'; import DeviceListener from "../src/DeviceListener"; import { MatrixClientPeg } from "../src/MatrixClientPeg"; import * as SetupEncryptionToast from "../src/toasts/SetupEncryptionToast"; diff --git a/test/Image-test.ts b/test/Image-test.ts index 41a63eb0ce..6352cf8a18 100644 --- a/test/Image-test.ts +++ b/test/Image-test.ts @@ -17,7 +17,6 @@ limitations under the License. import fs from "fs"; import path from "path"; -import './skinned-sdk'; import { blobIsAnimated, mayBeAnimated } from "../src/utils/Image"; describe("Image", () => { diff --git a/test/Reply-test.ts b/test/Reply-test.ts index 54863341cc..a485ee5ab0 100644 --- a/test/Reply-test.ts +++ b/test/Reply-test.ts @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import './skinned-sdk'; import { getNestedReplyText, getParentEventId, diff --git a/test/TextForEvent-test.ts b/test/TextForEvent-test.ts index 749dc8d113..75b54aeb66 100644 --- a/test/TextForEvent-test.ts +++ b/test/TextForEvent-test.ts @@ -1,5 +1,3 @@ -import './skinned-sdk'; - import { EventType, MatrixEvent } from "matrix-js-sdk/src/matrix"; import TestRenderer from 'react-test-renderer'; diff --git a/test/accessibility/RovingTabIndex-test.tsx b/test/accessibility/RovingTabIndex-test.tsx index e487098e10..fc1c48f041 100644 --- a/test/accessibility/RovingTabIndex-test.tsx +++ b/test/accessibility/RovingTabIndex-test.tsx @@ -14,7 +14,6 @@ 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 * as React from "react"; import { mount, ReactWrapper } from "enzyme"; diff --git a/test/audio/Playback-test.ts b/test/audio/Playback-test.ts index 7d9a7633b2..a1637d75be 100644 --- a/test/audio/Playback-test.ts +++ b/test/audio/Playback-test.ts @@ -17,8 +17,6 @@ limitations under the License. import { mocked } from 'jest-mock'; import { logger } from 'matrix-js-sdk/src/logger'; -import '../skinned-sdk'; // Must be first for skinning to work - import { createAudioContext, decodeOgg } from '../../src/audio/compat'; import { Playback, PlaybackState } from "../../src/audio/Playback"; diff --git a/test/components/structures/CallEventGrouper-test.ts b/test/components/structures/CallEventGrouper-test.ts index a5c2bb4c16..5cd3a273c6 100644 --- a/test/components/structures/CallEventGrouper-test.ts +++ b/test/components/structures/CallEventGrouper-test.ts @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import "../../skinned-sdk"; import { MatrixClient, MatrixEvent } from 'matrix-js-sdk/src/matrix'; import { EventType } from "matrix-js-sdk/src/@types/event"; import { CallState } from "matrix-js-sdk/src/webrtc/call"; diff --git a/test/components/structures/RightPanel-test.tsx b/test/components/structures/RightPanel-test.tsx index 4ae120978f..7d68d1753d 100644 --- a/test/components/structures/RightPanel-test.tsx +++ b/test/components/structures/RightPanel-test.tsx @@ -19,8 +19,6 @@ import TestRenderer from "react-test-renderer"; import { jest } from "@jest/globals"; import { Room } from "matrix-js-sdk/src/models/room"; -// We can't use the usual `skinned-sdk`, as it stubs out the RightPanel -import "../../minimal-sdk"; import RightPanel from "../../../src/components/structures/RightPanel"; import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; import ResizeNotifier from "../../../src/utils/ResizeNotifier"; diff --git a/test/components/structures/ThreadPanel-test.tsx b/test/components/structures/ThreadPanel-test.tsx index aaee488409..24616cca1a 100644 --- a/test/components/structures/ThreadPanel-test.tsx +++ b/test/components/structures/ThreadPanel-test.tsx @@ -16,7 +16,6 @@ limitations under the License. import React from 'react'; import { shallow, mount } from "enzyme"; -import '../../skinned-sdk'; import { ThreadFilterType, diff --git a/test/components/views/audio_messages/RecordingPlayback-test.tsx b/test/components/views/audio_messages/RecordingPlayback-test.tsx index f8a6c0ef92..6a75939bcd 100644 --- a/test/components/views/audio_messages/RecordingPlayback-test.tsx +++ b/test/components/views/audio_messages/RecordingPlayback-test.tsx @@ -20,7 +20,6 @@ import { mocked } from 'jest-mock'; import { logger } from 'matrix-js-sdk/src/logger'; import { act } from 'react-dom/test-utils'; -import '../../../skinned-sdk'; import RecordingPlayback from '../../../../src/components/views/audio_messages/RecordingPlayback'; import { Playback } from '../../../../src/audio/Playback'; import RoomContext, { TimelineRenderingType } from '../../../../src/contexts/RoomContext'; diff --git a/test/components/views/context_menus/ContextMenu-test.tsx b/test/components/views/context_menus/ContextMenu-test.tsx index 3ea0fbac55..46dbbe31fe 100644 --- a/test/components/views/context_menus/ContextMenu-test.tsx +++ b/test/components/views/context_menus/ContextMenu-test.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from "react"; import { mount } from "enzyme"; -import "../../../skinned-sdk"; import ContextMenu, { ChevronFace } from "../../../../src/components/structures/ContextMenu"; import UIStore from "../../../../src/stores/UIStore"; diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index 5755a7d280..567e54b418 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -21,7 +21,6 @@ import { Room } from 'matrix-js-sdk/src/models/room'; import { PendingEventOrdering } from 'matrix-js-sdk/src/matrix'; import { ExtensibleEvent, MessageEvent, M_POLL_KIND_DISCLOSED, PollStartEvent } from 'matrix-events-sdk'; -import '../../../skinned-sdk'; import * as TestUtils from '../../../test-utils'; import MessageContextMenu from '../../../../src/components/views/context_menus/MessageContextMenu'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; diff --git a/test/components/views/context_menus/SpaceContextMenu-test.tsx b/test/components/views/context_menus/SpaceContextMenu-test.tsx index fd0fdb682b..5288c57ec6 100644 --- a/test/components/views/context_menus/SpaceContextMenu-test.tsx +++ b/test/components/views/context_menus/SpaceContextMenu-test.tsx @@ -20,7 +20,6 @@ import { Room } from 'matrix-js-sdk/src/matrix'; import { mocked } from 'jest-mock'; import { act } from 'react-dom/test-utils'; -import '../../../skinned-sdk'; import SpaceContextMenu from '../../../../src/components/views/context_menus/SpaceContextMenu'; import MatrixClientContext from '../../../../src/contexts/MatrixClientContext'; import { findByTestId } from '../../../test-utils'; diff --git a/test/components/views/dialogs/ExportDialog-test.tsx b/test/components/views/dialogs/ExportDialog-test.tsx index 252acc7526..a23c719717 100644 --- a/test/components/views/dialogs/ExportDialog-test.tsx +++ b/test/components/views/dialogs/ExportDialog-test.tsx @@ -20,7 +20,6 @@ import { mocked } from 'jest-mock'; import { act } from "react-dom/test-utils"; import { Room } from 'matrix-js-sdk/src/matrix'; -import '../../../skinned-sdk'; import ExportDialog from '../../../../src/components/views/dialogs/ExportDialog'; import { ExportType, ExportFormat } from '../../../../src/utils/exportUtils/exportUtils'; import { createTestClient, mkStubRoom } from '../../../test-utils'; diff --git a/test/components/views/dialogs/ForwardDialog-test.js b/test/components/views/dialogs/ForwardDialog-test.js index 2d26015079..835f73bbf6 100644 --- a/test/components/views/dialogs/ForwardDialog-test.js +++ b/test/components/views/dialogs/ForwardDialog-test.js @@ -14,8 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import "../../../skinned-sdk"; - import React from "react"; import { mount } from "enzyme"; import { act } from "react-dom/test-utils"; diff --git a/test/components/views/elements/AppTile-test.tsx b/test/components/views/elements/AppTile-test.tsx index 7f035131a3..8843a9c602 100644 --- a/test/components/views/elements/AppTile-test.tsx +++ b/test/components/views/elements/AppTile-test.tsx @@ -20,8 +20,6 @@ import { jest } from "@jest/globals"; import { Room } from "matrix-js-sdk/src/models/room"; import { MatrixWidgetType } from "matrix-widget-api"; -// We can't use the usual `skinned-sdk`, as it stubs out the RightPanel -import "../../../minimal-sdk"; import RightPanel from "../../../../src/components/structures/RightPanel"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import ResizeNotifier from "../../../../src/utils/ResizeNotifier"; diff --git a/test/components/views/elements/InteractiveTooltip-test.ts b/test/components/views/elements/InteractiveTooltip-test.ts index fcf3da8eb5..68efca41bd 100644 --- a/test/components/views/elements/InteractiveTooltip-test.ts +++ b/test/components/views/elements/InteractiveTooltip-test.ts @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import '../../../skinned-sdk'; import { Direction, mouseWithinRegion } from "../../../../src/components/views/elements/InteractiveTooltip"; describe("InteractiveTooltip", () => { diff --git a/test/components/views/elements/PollCreateDialog-test.tsx b/test/components/views/elements/PollCreateDialog-test.tsx index 779b68e16b..41d2591b64 100644 --- a/test/components/views/elements/PollCreateDialog-test.tsx +++ b/test/components/views/elements/PollCreateDialog-test.tsx @@ -14,8 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -// skinned-sdk should be the first import in most tests -import '../../../skinned-sdk'; import React from "react"; import { mount, ReactWrapper } from "enzyme"; import { Room } from "matrix-js-sdk/src/models/room"; diff --git a/test/components/views/elements/ReplyChain-test.tsx b/test/components/views/elements/ReplyChain-test.tsx index 955f321b5b..bcc33c1fed 100644 --- a/test/components/views/elements/ReplyChain-test.tsx +++ b/test/components/views/elements/ReplyChain-test.tsx @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import "../../../skinned-sdk"; import * as testUtils from '../../../test-utils'; import { getParentEventId } from "../../../../src/utils/Reply"; diff --git a/test/components/views/elements/StyledRadioGroup-test.tsx b/test/components/views/elements/StyledRadioGroup-test.tsx index b82920b92b..d567be3394 100644 --- a/test/components/views/elements/StyledRadioGroup-test.tsx +++ b/test/components/views/elements/StyledRadioGroup-test.tsx @@ -13,7 +13,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import "../../../skinned-sdk"; import React from 'react'; import { mount } from 'enzyme'; diff --git a/test/components/views/elements/TooltipTarget-test.tsx b/test/components/views/elements/TooltipTarget-test.tsx index cdb550a6d0..cf7657bc40 100644 --- a/test/components/views/elements/TooltipTarget-test.tsx +++ b/test/components/views/elements/TooltipTarget-test.tsx @@ -1,5 +1,3 @@ -// skinned-sdk should be the first import in most tests -import '../../../skinned-sdk'; import React from "react"; import { renderIntoDocument, diff --git a/test/components/views/location/LocationPicker-test.tsx b/test/components/views/location/LocationPicker-test.tsx index ac8c6da238..f9b8255736 100644 --- a/test/components/views/location/LocationPicker-test.tsx +++ b/test/components/views/location/LocationPicker-test.tsx @@ -23,7 +23,6 @@ import { MatrixClient } from 'matrix-js-sdk/src/client'; import { mocked } from 'jest-mock'; import { logger } from 'matrix-js-sdk/src/logger'; -import "../../../skinned-sdk"; // Must be first for skinning to work import LocationPicker from "../../../../src/components/views/location/LocationPicker"; import { LocationShareType } from "../../../../src/components/views/location/shareLocation"; import MatrixClientContext from '../../../../src/contexts/MatrixClientContext'; diff --git a/test/components/views/location/LocationShareMenu-test.tsx b/test/components/views/location/LocationShareMenu-test.tsx index b79d6936ba..901e6c0852 100644 --- a/test/components/views/location/LocationShareMenu-test.tsx +++ b/test/components/views/location/LocationShareMenu-test.tsx @@ -24,7 +24,6 @@ import { M_BEACON_INFO } from 'matrix-js-sdk/src/@types/beacon'; import { M_ASSET, LocationAssetType } from 'matrix-js-sdk/src/@types/location'; import { logger } from 'matrix-js-sdk/src/logger'; -import '../../../skinned-sdk'; import LocationShareMenu from '../../../../src/components/views/location/LocationShareMenu'; import MatrixClientContext from '../../../../src/contexts/MatrixClientContext'; import { ChevronFace } from '../../../../src/components/structures/ContextMenu'; diff --git a/test/components/views/messages/MKeyVerificationConclusion-test.js b/test/components/views/messages/MKeyVerificationConclusion-test.js index 025dc82d45..ade7f644f9 100644 --- a/test/components/views/messages/MKeyVerificationConclusion-test.js +++ b/test/components/views/messages/MKeyVerificationConclusion-test.js @@ -1,4 +1,3 @@ -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/right_panel/UserInfo-test.tsx b/test/components/views/right_panel/UserInfo-test.tsx index c834f77db4..9966a994c4 100644 --- a/test/components/views/right_panel/UserInfo-test.tsx +++ b/test/components/views/right_panel/UserInfo-test.tsx @@ -21,7 +21,6 @@ import { act } from "react-dom/test-utils"; import { Room, User, MatrixClient } from 'matrix-js-sdk/src/matrix'; import { Phase, VerificationRequest } from 'matrix-js-sdk/src/crypto/verification/request/VerificationRequest'; -import "../../../skinned-sdk"; import UserInfo from '../../../../src/components/views/right_panel/UserInfo'; import { RightPanelPhases } from '../../../../src/stores/right-panel/RightPanelStorePhases'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; diff --git a/test/components/views/rooms/MemberList-test.tsx b/test/components/views/rooms/MemberList-test.tsx index b65ef052ff..a542fe1aac 100644 --- a/test/components/views/rooms/MemberList-test.tsx +++ b/test/components/views/rooms/MemberList-test.tsx @@ -14,8 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import "../../../skinned-sdk"; - import React from 'react'; import ReactTestUtils from 'react-dom/test-utils'; import ReactDOM from 'react-dom'; diff --git a/test/components/views/rooms/RoomHeader-test.tsx b/test/components/views/rooms/RoomHeader-test.tsx index 889dcc255c..c8030ad7c9 100644 --- a/test/components/views/rooms/RoomHeader-test.tsx +++ b/test/components/views/rooms/RoomHeader-test.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { mount, ReactWrapper } from 'enzyme'; import { Room, PendingEventOrdering, MatrixEvent, MatrixClient } from 'matrix-js-sdk/src/matrix'; -import "../../../skinned-sdk"; import * as TestUtils from '../../../test-utils'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import DMRoomMap from '../../../../src/utils/DMRoomMap'; diff --git a/test/components/views/rooms/RoomPreviewBar-test.tsx b/test/components/views/rooms/RoomPreviewBar-test.tsx index 132b0e1cc9..d41b4a338a 100644 --- a/test/components/views/rooms/RoomPreviewBar-test.tsx +++ b/test/components/views/rooms/RoomPreviewBar-test.tsx @@ -23,7 +23,6 @@ import { } from 'react-dom/test-utils'; import { Room, RoomMember, MatrixError, IContent } from 'matrix-js-sdk/src/matrix'; -import "../../../skinned-sdk"; import { stubClient } from '../../../test-utils'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import DMRoomMap from '../../../../src/utils/DMRoomMap'; diff --git a/test/components/views/rooms/SendMessageComposer-test.tsx b/test/components/views/rooms/SendMessageComposer-test.tsx index d2f54c3358..30ecd31586 100644 --- a/test/components/views/rooms/SendMessageComposer-test.tsx +++ b/test/components/views/rooms/SendMessageComposer-test.tsx @@ -20,7 +20,6 @@ import { sleep } from "matrix-js-sdk/src/utils"; import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { mount } from 'enzyme'; -import '../../../skinned-sdk'; // Must be first for skinning to work import SendMessageComposer, { createMessageContent, isQuickReaction, diff --git a/test/components/views/settings/CryptographyPanel-test.tsx b/test/components/views/settings/CryptographyPanel-test.tsx index c3bf816bd7..6748d6858f 100644 --- a/test/components/views/settings/CryptographyPanel-test.tsx +++ b/test/components/views/settings/CryptographyPanel-test.tsx @@ -1,5 +1,3 @@ -import '../../../skinned-sdk'; - import React, { ReactElement } from 'react'; import ReactDOM from 'react-dom'; import { MatrixClient } from 'matrix-js-sdk/src/matrix'; diff --git a/test/components/views/settings/FontScalingPanel-test.tsx b/test/components/views/settings/FontScalingPanel-test.tsx index 84f5cd0945..f18830b348 100644 --- a/test/components/views/settings/FontScalingPanel-test.tsx +++ b/test/components/views/settings/FontScalingPanel-test.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from 'react'; import { mount } from "enzyme"; -import '../../../skinned-sdk'; import * as TestUtils from "../../../test-utils"; import FontScalingPanel from '../../../../src/components/views/settings/FontScalingPanel'; diff --git a/test/components/views/settings/Notifications-test.tsx b/test/components/views/settings/Notifications-test.tsx index a6f905bdd2..b1abbebed4 100644 --- a/test/components/views/settings/Notifications-test.tsx +++ b/test/components/views/settings/Notifications-test.tsx @@ -14,7 +14,6 @@ limitations under the License. import React from 'react'; import { mount } from 'enzyme'; -import '../../../skinned-sdk'; import { IPushRule, IPushRules, RuleId, IPusher } from 'matrix-js-sdk/src/matrix'; import { IThreepid, ThreepidMedium } from 'matrix-js-sdk/src/@types/threepids'; import { act } from 'react-dom/test-utils'; diff --git a/test/components/views/settings/ThemeChoicePanel-test.tsx b/test/components/views/settings/ThemeChoicePanel-test.tsx index 073a89b818..0d0a71c86c 100644 --- a/test/components/views/settings/ThemeChoicePanel-test.tsx +++ b/test/components/views/settings/ThemeChoicePanel-test.tsx @@ -17,7 +17,6 @@ limitations under the License. import React from 'react'; import { mount } from "enzyme"; -import '../../../skinned-sdk'; import * as TestUtils from "../../../test-utils"; import ThemeChoicePanel from '../../../../src/components/views/settings/ThemeChoicePanel'; diff --git a/test/components/views/spaces/QuickThemeSwitcher-test.tsx b/test/components/views/spaces/QuickThemeSwitcher-test.tsx index a297ac8ef3..c443963778 100644 --- a/test/components/views/spaces/QuickThemeSwitcher-test.tsx +++ b/test/components/views/spaces/QuickThemeSwitcher-test.tsx @@ -19,7 +19,6 @@ import { mount } from 'enzyme'; import { mocked } from 'jest-mock'; import { act } from 'react-dom/test-utils'; -import '../../../skinned-sdk'; import QuickThemeSwitcher from '../../../../src/components/views/spaces/QuickThemeSwitcher'; import { getOrderedThemes } from '../../../../src/theme'; import ThemeChoicePanel from '../../../../src/components/views/settings/ThemeChoicePanel'; diff --git a/test/components/views/spaces/SpacePanel-test.tsx b/test/components/views/spaces/SpacePanel-test.tsx index 7f2c3a95b7..e328c51188 100644 --- a/test/components/views/spaces/SpacePanel-test.tsx +++ b/test/components/views/spaces/SpacePanel-test.tsx @@ -20,7 +20,6 @@ import { mocked } from 'jest-mock'; import { MatrixClient } from 'matrix-js-sdk/src/matrix'; import { act } from "react-dom/test-utils"; -import '../../../skinned-sdk'; import SpacePanel from '../../../../src/components/views/spaces/SpacePanel'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import { SpaceKey } from '../../../../src/stores/spaces'; diff --git a/test/components/views/spaces/SpaceSettingsVisibilityTab-test.tsx b/test/components/views/spaces/SpaceSettingsVisibilityTab-test.tsx index 976e030b3b..78cc602863 100644 --- a/test/components/views/spaces/SpaceSettingsVisibilityTab-test.tsx +++ b/test/components/views/spaces/SpaceSettingsVisibilityTab-test.tsx @@ -1,5 +1,3 @@ -// skinned-sdk should be the first import in most tests -import '../../../skinned-sdk'; import React from "react"; import { mocked } from 'jest-mock'; import { diff --git a/test/createRoom-test.js b/test/createRoom-test.js index fd37e0091e..84eaabdafc 100644 --- a/test/createRoom-test.js +++ b/test/createRoom-test.js @@ -1,4 +1,3 @@ -import './skinned-sdk'; // Must be first for skinning to work import { EventEmitter } from 'events'; import { waitForMember, canEncryptToAllUsers } from '../src/createRoom'; diff --git a/test/editor/caret-test.js b/test/editor/caret-test.js index 33b40e1c64..e1a66a4431 100644 --- a/test/editor/caret-test.js +++ b/test/editor/caret-test.js @@ -14,7 +14,6 @@ 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 { getLineAndNodePosition } from "../../src/editor/caret"; import EditorModel from "../../src/editor/model"; import { createPartCreator } from "./mock"; diff --git a/test/editor/deserialize-test.js b/test/editor/deserialize-test.js index 050254401d..7ee522caf7 100644 --- a/test/editor/deserialize-test.js +++ b/test/editor/deserialize-test.js @@ -14,7 +14,6 @@ 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"; diff --git a/test/editor/model-test.js b/test/editor/model-test.js index 3d0aa5cf64..8ed4e78bbf 100644 --- a/test/editor/model-test.js +++ b/test/editor/model-test.js @@ -14,7 +14,6 @@ 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 EditorModel from "../../src/editor/model"; import { createPartCreator, createRenderer } from "./mock"; diff --git a/test/editor/operations-test.js b/test/editor/operations-test.js index 1db5660840..b9ab4cc4e8 100644 --- a/test/editor/operations-test.js +++ b/test/editor/operations-test.js @@ -14,7 +14,6 @@ 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 EditorModel from "../../src/editor/model"; import { createPartCreator, createRenderer } from "./mock"; import { diff --git a/test/editor/position-test.js b/test/editor/position-test.js index ea8658b216..813a8e9f7f 100644 --- a/test/editor/position-test.js +++ b/test/editor/position-test.js @@ -14,7 +14,6 @@ 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 EditorModel from "../../src/editor/model"; import { createPartCreator } from "./mock"; diff --git a/test/editor/range-test.js b/test/editor/range-test.js index 42ec6de60d..d0122146a5 100644 --- a/test/editor/range-test.js +++ b/test/editor/range-test.js @@ -14,7 +14,6 @@ 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 EditorModel from "../../src/editor/model"; import { createPartCreator, createRenderer } from "./mock"; diff --git a/test/editor/serialize-test.js b/test/editor/serialize-test.js index 085a8afdba..691130bd34 100644 --- a/test/editor/serialize-test.js +++ b/test/editor/serialize-test.js @@ -14,7 +14,6 @@ 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 EditorModel from "../../src/editor/model"; import { htmlSerializeIfNeeded } from "../../src/editor/serialize"; import { createPartCreator } from "./mock"; diff --git a/test/minimal-sdk.js b/test/minimal-sdk.js deleted file mode 100644 index fb40ebd3c5..0000000000 --- a/test/minimal-sdk.js +++ /dev/null @@ -1,29 +0,0 @@ -/* -Copyright 2022 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/* - * minimal-sdk.js - * - * Starts up the skin system with even less than `skinned-sdk`. - */ - -import * as sdk from "../src/index"; - -const components = {}; - -// sdk.loadSkin({ components }); - -export default sdk; diff --git a/test/skinned-sdk.js b/test/skinned-sdk.js deleted file mode 100644 index aa4fffe8e6..0000000000 --- a/test/skinned-sdk.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - * skinned-sdk.js - * - * Skins the react-sdk with a few stub components which we expect the - * application to provide - */ - -/* this is a convenient place to ensure we load the compatibility libraries we expect our - * app to provide - */ - -import * as sdk from "../src/index"; -import stubComponent from "./components/stub-component"; - -const components = {}; -components['structures.LeftPanel'] = stubComponent(); -components['structures.RightPanel'] = stubComponent(); -components['structures.RoomDirectory'] = stubComponent(); -components['views.globals.GuestWarningBar'] = stubComponent(); -components['views.globals.NewVersionBar'] = stubComponent(); -components['views.elements.Spinner'] = stubComponent({ displayName: 'Spinner' }); -components['views.messages.MessageTimestamp'] = stubComponent({ displayName: 'MessageTimestamp' }); -components['views.messages.SenderProfile'] = stubComponent({ displayName: 'SenderProfile' }); -components['views.rooms.SearchBar'] = stubComponent(); - -// sdk.loadSkin({ components }); - -export default sdk; diff --git a/test/stores/RoomViewStore-test.js b/test/stores/RoomViewStore-test.js index 6c9e8d47f9..bc2bd2e936 100644 --- a/test/stores/RoomViewStore-test.js +++ b/test/stores/RoomViewStore-test.js @@ -14,7 +14,6 @@ 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 RoomViewStore from '../../src/stores/RoomViewStore'; import { Action } from '../../src/dispatcher/actions'; import { MatrixClientPeg as peg } from '../../src/MatrixClientPeg'; diff --git a/test/stores/SpaceStore-test.ts b/test/stores/SpaceStore-test.ts index 60faa55804..47c3f974b2 100644 --- a/test/stores/SpaceStore-test.ts +++ b/test/stores/SpaceStore-test.ts @@ -21,7 +21,6 @@ import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { defer } from "matrix-js-sdk/src/utils"; import { ClientEvent, RoomEvent, MatrixEvent } from 'matrix-js-sdk/src/matrix'; -import "../skinned-sdk"; // Must be first for skinning to work import SpaceStore from "../../src/stores/spaces/SpaceStore"; import { MetaSpace, diff --git a/test/stores/VoiceChannelStore-test.ts b/test/stores/VoiceChannelStore-test.ts index cf70e7314c..46f85fbc86 100644 --- a/test/stores/VoiceChannelStore-test.ts +++ b/test/stores/VoiceChannelStore-test.ts @@ -16,7 +16,6 @@ limitations under the License. import { ClientWidgetApi, MatrixWidgetType } from "matrix-widget-api"; -import "../skinned-sdk"; import { stubClient } from "../test-utils"; import WidgetStore from "../../src/stores/WidgetStore"; import { WidgetMessagingStore } from "../../src/stores/widgets/WidgetMessagingStore"; diff --git a/test/stores/VoiceRecordingStore-test.ts b/test/stores/VoiceRecordingStore-test.ts index 1c8bb86cb3..7be07bed6f 100644 --- a/test/stores/VoiceRecordingStore-test.ts +++ b/test/stores/VoiceRecordingStore-test.ts @@ -17,7 +17,6 @@ limitations under the License. import { MatrixClient } from "matrix-js-sdk/src/matrix"; -import "../skinned-sdk"; // Must be first for skinning to work import { VoiceRecording } from '../../src/audio/VoiceRecording'; import { VoiceRecordingStore } from '../../src/stores/VoiceRecordingStore'; import { MatrixClientPeg } from "../../src/MatrixClientPeg"; diff --git a/test/stores/WidgetLayoutStore-test.ts b/test/stores/WidgetLayoutStore-test.ts index 139c31b176..eb41d1231a 100644 --- a/test/stores/WidgetLayoutStore-test.ts +++ b/test/stores/WidgetLayoutStore-test.ts @@ -14,7 +14,6 @@ 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 { Room } from "matrix-js-sdk/src/matrix"; import WidgetStore, { IApp } from "../../src/stores/WidgetStore"; diff --git a/test/stores/notifications/RoomNotificationState-test.ts b/test/stores/notifications/RoomNotificationState-test.ts index befa1a0008..904e068909 100644 --- a/test/stores/notifications/RoomNotificationState-test.ts +++ b/test/stores/notifications/RoomNotificationState-test.ts @@ -17,7 +17,6 @@ limitations under the License. import { Room } from "matrix-js-sdk/src/models/room"; import { MatrixEventEvent, MatrixEvent } from "matrix-js-sdk/src/matrix"; -import "../../skinned-sdk"; import { stubClient } from "../../test-utils"; import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; import { RoomNotificationState } from "../../../src/stores/notifications/RoomNotificationState"; diff --git a/test/stores/room-list/SpaceWatcher-test.ts b/test/stores/room-list/SpaceWatcher-test.ts index b870da6aa1..9664c9dd8c 100644 --- a/test/stores/room-list/SpaceWatcher-test.ts +++ b/test/stores/room-list/SpaceWatcher-test.ts @@ -15,7 +15,6 @@ limitations under the License. */ import { mocked } from 'jest-mock'; -import "../../skinned-sdk"; // Must be first for skinning to work import { SpaceWatcher } from "../../../src/stores/room-list/SpaceWatcher"; import type { RoomListStoreClass } from "../../../src/stores/room-list/RoomListStore"; import SettingsStore from "../../../src/settings/SettingsStore"; diff --git a/test/utils/export-test.tsx b/test/utils/export-test.tsx index f385df5c2a..1c09ecf6de 100644 --- a/test/utils/export-test.tsx +++ b/test/utils/export-test.tsx @@ -27,7 +27,6 @@ import { import { MatrixClientPeg } from "../../src/MatrixClientPeg"; import { IExportOptions, ExportType, ExportFormat } from "../../src/utils/exportUtils/exportUtils"; -import '../skinned-sdk'; import PlainTextExporter from "../../src/utils/exportUtils/PlainTextExport"; import HTMLExporter from "../../src/utils/exportUtils/HtmlExport"; import * as TestUtilsMatrix from '../test-utils'; From 8d2dba41024224de7d37cdbe6747999149481591 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 8 Mar 2022 15:08:19 -0700 Subject: [PATCH 10/47] Step 8.2: Fix wiring of jest test setup to avoid import cycle issues --- test/setup/setupConfig.ts | 21 +++++++++++++ test/setup/setupLanguage.ts | 20 ++++++++++++ test/setup/setupManualMocks.ts | 55 +++++++++++++++++++++++++++++++++ test/setupTests.js | 56 ++++++---------------------------- 4 files changed, 106 insertions(+), 46 deletions(-) create mode 100644 test/setup/setupConfig.ts create mode 100644 test/setup/setupLanguage.ts create mode 100644 test/setup/setupManualMocks.ts diff --git a/test/setup/setupConfig.ts b/test/setup/setupConfig.ts new file mode 100644 index 0000000000..e67493412d --- /dev/null +++ b/test/setup/setupConfig.ts @@ -0,0 +1,21 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import SdkConfig, { DEFAULTS } from '../../src/SdkConfig'; + +// uninitialised SdkConfig causes lots of warnings in console +// init with defaults +SdkConfig.put(DEFAULTS); diff --git a/test/setup/setupLanguage.ts b/test/setup/setupLanguage.ts new file mode 100644 index 0000000000..5c6834d012 --- /dev/null +++ b/test/setup/setupLanguage.ts @@ -0,0 +1,20 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import * as languageHandler from "../../src/languageHandler"; + +languageHandler.setLanguage('en'); +languageHandler.setMissingEntryGenerator(key => key.split("|", 2)[1]); diff --git a/test/setup/setupManualMocks.ts b/test/setup/setupManualMocks.ts new file mode 100644 index 0000000000..162529ef64 --- /dev/null +++ b/test/setup/setupManualMocks.ts @@ -0,0 +1,55 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { TextDecoder, TextEncoder } from "util"; + +// jest 27 removes setImmediate from jsdom +// polyfill until setImmediate use in client can be removed +// @ts-ignore - we know the contract is wrong. That's why we're stubbing it. +global.setImmediate = callback => setTimeout(callback, 0); + +// Stub ResizeObserver +// @ts-ignore - we know it's a duplicate (that's why we're stubbing it) +class ResizeObserver { + observe() {} // do nothing + unobserve() {} // do nothing + disconnect() {} // do nothing +} +window.ResizeObserver = ResizeObserver; + +// matchMedia is not included in jsdom +const mockMatchMedia = jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), +})); +global.matchMedia = mockMatchMedia; + +// maplibre requires a createObjectURL mock +global.URL.createObjectURL = jest.fn(); + +// polyfilling TextEncoder as it is not available on JSDOM +// view https://github.com/facebook/jest/issues/9983 +global.TextEncoder = TextEncoder; +global.TextDecoder = TextDecoder; + +// prevent errors whenever a component tries to manually scroll. +window.HTMLElement.prototype.scrollIntoView = jest.fn(); diff --git a/test/setupTests.js b/test/setupTests.js index 0ff021eaa2..649a914c09 100644 --- a/test/setupTests.js +++ b/test/setupTests.js @@ -1,53 +1,17 @@ -import { TextEncoder, TextDecoder } from 'util'; import Adapter from "@wojtekmaj/enzyme-adapter-react-17"; import { configure } from "enzyme"; import "blob-polyfill"; // https://github.com/jsdom/jsdom/issues/2555 -import * as languageHandler from "../src/languageHandler"; -import SdkConfig, { DEFAULTS } from '../src/SdkConfig'; - -languageHandler.setLanguage('en'); -languageHandler.setMissingEntryGenerator(key => key.split("|", 2)[1]); - -// uninitialised SdkConfig causes lots of warnings in console -// init with defaults -SdkConfig.put(DEFAULTS); - +// Enable the jest & enzyme mocks require('jest-fetch-mock').enableMocks(); - -// jest 27 removes setImmediate from jsdom -// polyfill until setImmediate use in client can be removed -global.setImmediate = callback => setTimeout(callback, 0); - -// Stub ResizeObserver -class ResizeObserver { - observe() {} // do nothing - unobserve() {} // do nothing - disconnect() {} // do nothing -} -window.ResizeObserver = ResizeObserver; - -// polyfilling TextEncoder as it is not available on JSDOM -// view https://github.com/facebook/jest/issues/9983 -global.TextEncoder = TextEncoder; -global.TextDecoder = TextDecoder; - configure({ adapter: new Adapter() }); -// maplibre requires a createObjectURL mock -global.URL.createObjectURL = jest.fn(); - -// matchMedia is not included in jsdom -const mockMatchMedia = jest.fn().mockImplementation(query => ({ - matches: false, - media: query, - onchange: null, - addListener: jest.fn(), // Deprecated - removeListener: jest.fn(), // Deprecated - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - dispatchEvent: jest.fn(), -})); -global.matchMedia = mockMatchMedia; - -window.HTMLElement.prototype.scrollIntoView = jest.fn(); +// Very carefully enable the mocks for everything else in +// a specific order. We use this order to ensure we properly +// establish an application state that actually works. +// +// These are also require() calls to make sure they get called +// synchronously. +require("./setup/setupManualMocks"); // must be first +require("./setup/setupLanguage"); +require("./setup/setupConfig"); From d5ed1eb66e558f93a6510559af1b0d4013e0b6f0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Mar 2022 23:26:30 -0600 Subject: [PATCH 11/47] Step 8.3: Convert `RoomViewStore` to a more modern singleton for imports --- src/ActiveRoomObserver.ts | 9 +++--- src/ContentMessages.ts | 4 +-- src/Notifier.ts | 4 +-- src/ScalarMessaging.ts | 4 +-- src/SlashCommands.tsx | 6 ++-- src/audio/PlaybackQueue.ts | 6 ++-- src/components/structures/RoomView.tsx | 30 +++++++++---------- src/components/structures/SpaceHierarchy.tsx | 4 +-- .../views/context_menus/RoomContextMenu.tsx | 6 ++-- .../views/dialogs/SpotlightDialog.tsx | 4 +-- src/components/views/elements/AppTile.tsx | 4 +-- .../views/right_panel/TimelineCard.tsx | 14 ++++----- src/components/views/right_panel/UserInfo.tsx | 4 +-- src/components/views/rooms/RoomList.tsx | 8 ++--- .../views/spaces/QuickSettingsButton.tsx | 4 +-- src/components/views/voip/PipView.tsx | 8 ++--- src/stores/RoomViewStore.tsx | 24 +++++++-------- src/stores/right-panel/RightPanelStore.ts | 8 ++--- src/stores/room-list/RoomListStore.ts | 6 ++-- src/stores/spaces/SpaceStore.ts | 8 ++--- src/stores/widgets/StopGapWidget.ts | 8 ++--- src/utils/membership.ts | 4 +-- src/utils/space.tsx | 8 ++--- test/stores/RoomViewStore-test.js | 16 +++++----- 24 files changed, 99 insertions(+), 102 deletions(-) diff --git a/src/ActiveRoomObserver.ts b/src/ActiveRoomObserver.ts index ef64192203..bcdc249fea 100644 --- a/src/ActiveRoomObserver.ts +++ b/src/ActiveRoomObserver.ts @@ -16,7 +16,7 @@ limitations under the License. import { logger } from "matrix-js-sdk/src/logger"; -import RoomViewStore from './stores/RoomViewStore'; +import { RoomViewStore } from './stores/RoomViewStore'; type Listener = (isActive: boolean) => void; @@ -31,11 +31,12 @@ type Listener = (isActive: boolean) => void; */ export class ActiveRoomObserver { private listeners: {[key: string]: Listener[]} = {}; - private _activeRoomId = RoomViewStore.getRoomId(); + private _activeRoomId = RoomViewStore.instance.getRoomId(); + private readonly roomStoreToken: EventSubscription; constructor() { // TODO: We could self-destruct when the last listener goes away, or at least stop listening. - RoomViewStore.addListener(this.onRoomViewStoreUpdate); + this.roomStoreToken = RoomViewStore.instance.addListener(this.onRoomViewStoreUpdate); } public get activeRoomId(): string { @@ -71,7 +72,7 @@ export class ActiveRoomObserver { if (this._activeRoomId) this.emit(this._activeRoomId, false); // update our cache - this._activeRoomId = RoomViewStore.getRoomId(); + this._activeRoomId = RoomViewStore.instance.getRoomId(); // and emit for the new one if (this._activeRoomId) this.emit(this._activeRoomId, true); diff --git a/src/ContentMessages.ts b/src/ContentMessages.ts index ed0999fe07..7dc5b7f4a8 100644 --- a/src/ContentMessages.ts +++ b/src/ContentMessages.ts @@ -44,7 +44,7 @@ import { BlurhashEncoder } from "./BlurhashEncoder"; import SettingsStore from "./settings/SettingsStore"; import { decorateStartSendingTime, sendRoundTripMetric } from "./sendTimePerformanceMetrics"; import { TimelineRenderingType } from "./contexts/RoomContext"; -import RoomViewStore from "./stores/RoomViewStore"; +import { RoomViewStore } from "./stores/RoomViewStore"; import { addReplyToMessageContent } from "./utils/Reply"; import ErrorDialog from "./components/views/dialogs/ErrorDialog"; import UploadFailureDialog from "./components/views/dialogs/UploadFailureDialog"; @@ -468,7 +468,7 @@ export default class ContentMessages { return; } - const replyToEvent = RoomViewStore.getQuotingEvent(); + const replyToEvent = RoomViewStore.instance.getQuotingEvent(); if (!this.mediaConfig) { // hot-path optimization to not flash a spinner if we don't need to const modal = Modal.createDialog(Spinner, null, 'mx_Dialog_spinner'); await this.ensureMediaConfigFetched(matrixClient); diff --git a/src/Notifier.ts b/src/Notifier.ts index 3f17ae0091..62e2f09370 100644 --- a/src/Notifier.ts +++ b/src/Notifier.ts @@ -37,7 +37,7 @@ import SettingsStore from "./settings/SettingsStore"; import { hideToast as hideNotificationsToast } from "./toasts/DesktopNotificationsToast"; import { SettingLevel } from "./settings/SettingLevel"; import { isPushNotifyDisabled } from "./settings/controllers/NotificationControllers"; -import RoomViewStore from "./stores/RoomViewStore"; +import { RoomViewStore } from "./stores/RoomViewStore"; import UserActivity from "./UserActivity"; import { mediaFromMxc } from "./customisations/Media"; import ErrorDialog from "./components/views/dialogs/ErrorDialog"; @@ -401,7 +401,7 @@ export const Notifier = { const actions = MatrixClientPeg.get().getPushActionsForEvent(ev); if (actions?.notify) { - if (RoomViewStore.getRoomId() === room.roomId && + if (RoomViewStore.instance.getRoomId() === room.roomId && UserActivity.sharedInstance().userActiveRecently() && !Modal.hasDialogs() ) { diff --git a/src/ScalarMessaging.ts b/src/ScalarMessaging.ts index b0b8b3a0d4..a380c760b5 100644 --- a/src/ScalarMessaging.ts +++ b/src/ScalarMessaging.ts @@ -241,7 +241,7 @@ import { logger } from "matrix-js-sdk/src/logger"; import { MatrixClientPeg } from './MatrixClientPeg'; import dis from './dispatcher/dispatcher'; import WidgetUtils from './utils/WidgetUtils'; -import RoomViewStore from './stores/RoomViewStore'; +import { RoomViewStore } from './stores/RoomViewStore'; import { _t } from './languageHandler'; import { IntegrationManagers } from "./integrations/IntegrationManagers"; import { WidgetType } from "./widgets/WidgetType"; @@ -638,7 +638,7 @@ const onMessage = function(event: MessageEvent): void { } } - if (roomId !== RoomViewStore.getRoomId()) { + if (roomId !== RoomViewStore.instance.getRoomId()) { sendError(event, _t('Room %(roomId)s not visible', { roomId: roomId })); return; } diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index 59a25cdef2..75897bbb0a 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -61,7 +61,7 @@ import InfoDialog from "./components/views/dialogs/InfoDialog"; import SlashCommandHelpDialog from "./components/views/dialogs/SlashCommandHelpDialog"; import { shouldShowComponent } from "./customisations/helpers/UIComponents"; import { TimelineRenderingType } from './contexts/RoomContext'; -import RoomViewStore from "./stores/RoomViewStore"; +import { RoomViewStore } from "./stores/RoomViewStore"; import { XOR } from "./@types/common"; import { PosthogAnalytics } from "./PosthogAnalytics"; import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload"; @@ -851,7 +851,7 @@ export const Commands = [ description: _td('Define the power level of a user'), isEnabled(): boolean { const cli = MatrixClientPeg.get(); - const room = cli.getRoom(RoomViewStore.getRoomId()); + const room = cli.getRoom(RoomViewStore.instance.getRoomId()); return room?.currentState.maySendStateEvent(EventType.RoomPowerLevels, cli.getUserId()); }, runFn: function(roomId, args) { @@ -891,7 +891,7 @@ export const Commands = [ description: _td('Deops user with given id'), isEnabled(): boolean { const cli = MatrixClientPeg.get(); - const room = cli.getRoom(RoomViewStore.getRoomId()); + const room = cli.getRoom(RoomViewStore.instance.getRoomId()); return room?.currentState.maySendStateEvent(EventType.RoomPowerLevels, cli.getUserId()); }, runFn: function(roomId, args) { diff --git a/src/audio/PlaybackQueue.ts b/src/audio/PlaybackQueue.ts index d470b6b94c..d90051d0f1 100644 --- a/src/audio/PlaybackQueue.ts +++ b/src/audio/PlaybackQueue.ts @@ -25,7 +25,7 @@ import { MatrixClientPeg } from "../MatrixClientPeg"; import { arrayFastClone } from "../utils/arrays"; import { PlaybackManager } from "./PlaybackManager"; import { isVoiceMessage } from "../utils/EventUtils"; -import RoomViewStore from "../stores/RoomViewStore"; +import { RoomViewStore } from "../stores/RoomViewStore"; /** * Audio playback queue management for a given room. This keeps track of where the user @@ -51,8 +51,8 @@ export class PlaybackQueue { constructor(private room: Room) { this.loadClocks(); - RoomViewStore.addListener(() => { - if (RoomViewStore.getRoomId() === this.room.roomId) { + RoomViewStore.instance.addListener(() => { + if (RoomViewStore.instance.getRoomId() === this.room.roomId) { // Reset the state of the playbacks before they start mounting and enqueuing updates. // We reset the entirety of the queue, including order, to ensure the user isn't left // confused with what order the messages are playing in. diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 906c32c0d9..d57f1651d2 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -48,7 +48,7 @@ import * as Rooms from '../../Rooms'; import eventSearch, { searchPagination } from '../../Searching'; import MainSplit from './MainSplit'; import RightPanel from './RightPanel'; -import RoomViewStore from '../../stores/RoomViewStore'; +import { RoomViewStore } from '../../stores/RoomViewStore'; import RoomScrollStateStore, { ScrollState } from '../../stores/RoomScrollStateStore'; import WidgetEchoStore from '../../stores/WidgetEchoStore'; import SettingsStore from "../../settings/SettingsStore"; @@ -296,7 +296,7 @@ export class RoomView extends React.Component { context.on(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged); context.on(MatrixEventEvent.Decrypted, this.onEventDecrypted); // Start listening for RoomViewStore updates - this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate); + this.roomStoreToken = RoomViewStore.instance.addListener(this.onRoomViewStoreUpdate); RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate); @@ -387,7 +387,7 @@ export class RoomView extends React.Component { return; } - if (!initial && this.state.roomId !== RoomViewStore.getRoomId()) { + if (!initial && this.state.roomId !== RoomViewStore.instance.getRoomId()) { // RoomView explicitly does not support changing what room // is being viewed: instead it should just be re-mounted when // switching rooms. Therefore, if the room ID changes, we @@ -402,28 +402,28 @@ export class RoomView extends React.Component { return; } - const roomId = RoomViewStore.getRoomId(); + const roomId = RoomViewStore.instance.getRoomId(); const newState: Pick = { roomId, - roomAlias: RoomViewStore.getRoomAlias(), - roomLoading: RoomViewStore.isRoomLoading(), - roomLoadError: RoomViewStore.getRoomLoadError(), - joining: RoomViewStore.isJoining(), - replyToEvent: RoomViewStore.getQuotingEvent(), + roomAlias: RoomViewStore.instance.getRoomAlias(), + roomLoading: RoomViewStore.instance.isRoomLoading(), + roomLoadError: RoomViewStore.instance.getRoomLoadError(), + joining: RoomViewStore.instance.isJoining(), + replyToEvent: RoomViewStore.instance.getQuotingEvent(), // we should only peek once we have a ready client - shouldPeek: this.state.matrixClientIsReady && RoomViewStore.shouldPeek(), + shouldPeek: this.state.matrixClientIsReady && RoomViewStore.instance.shouldPeek(), showReadReceipts: SettingsStore.getValue("showReadReceipts", roomId), showRedactions: SettingsStore.getValue("showRedactions", roomId), showJoinLeaves: SettingsStore.getValue("showJoinLeaves", roomId), showAvatarChanges: SettingsStore.getValue("showAvatarChanges", roomId), showDisplaynameChanges: SettingsStore.getValue("showDisplaynameChanges", roomId), - wasContextSwitch: RoomViewStore.getWasContextSwitch(), + wasContextSwitch: RoomViewStore.instance.getWasContextSwitch(), initialEventId: null, // default to clearing this, will get set later in the method if needed showRightPanel: RightPanelStore.instance.isOpenForRoom(roomId), }; - const initialEventId = RoomViewStore.getInitialEventId(); + const initialEventId = RoomViewStore.instance.getInitialEventId(); if (initialEventId) { const room = this.context.getRoom(roomId); let initialEvent = room?.findEventById(initialEventId); @@ -448,17 +448,17 @@ export class RoomView extends React.Component { showThread({ rootEvent: thread.rootEvent, initialEvent, - highlighted: RoomViewStore.isInitialEventHighlighted(), + highlighted: RoomViewStore.instance.isInitialEventHighlighted(), }); } else { newState.initialEventId = initialEventId; - newState.isInitialEventHighlighted = RoomViewStore.isInitialEventHighlighted(); + newState.isInitialEventHighlighted = RoomViewStore.instance.isInitialEventHighlighted(); if (thread && initialEvent?.isThreadRoot) { showThread({ rootEvent: thread.rootEvent, initialEvent, - highlighted: RoomViewStore.isInitialEventHighlighted(), + highlighted: RoomViewStore.instance.isInitialEventHighlighted(), }); } } diff --git a/src/components/structures/SpaceHierarchy.tsx b/src/components/structures/SpaceHierarchy.tsx index 625a252365..756cacab1f 100644 --- a/src/components/structures/SpaceHierarchy.tsx +++ b/src/components/structures/SpaceHierarchy.tsx @@ -60,7 +60,7 @@ import MatrixClientContext from "../../contexts/MatrixClientContext"; import { useTypedEventEmitterState } from "../../hooks/useEventEmitter"; import { IOOBData } from "../../stores/ThreepidInviteStore"; import { awaitRoomDownSync } from "../../utils/RoomUpgrade"; -import RoomViewStore from "../../stores/RoomViewStore"; +import { RoomViewStore } from "../../stores/RoomViewStore"; import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload"; import { JoinRoomReadyPayload } from "../../dispatcher/payloads/JoinRoomReadyPayload"; import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts"; @@ -371,7 +371,7 @@ export const joinRoom = (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: st metricsTrigger: "SpaceHierarchy", }); }, err => { - RoomViewStore.showJoinRoomError(err, roomId); + RoomViewStore.instance.showJoinRoomError(err, roomId); }); return prom; diff --git a/src/components/views/context_menus/RoomContextMenu.tsx b/src/components/views/context_menus/RoomContextMenu.tsx index 1d2ca8f171..132942aa1e 100644 --- a/src/components/views/context_menus/RoomContextMenu.tsx +++ b/src/components/views/context_menus/RoomContextMenu.tsx @@ -37,7 +37,7 @@ import Modal from "../../../Modal"; import ExportDialog from "../dialogs/ExportDialog"; import { useSettingValue } from "../../../hooks/useSettings"; import { usePinnedEvents } from "../right_panel/PinnedMessagesCard"; -import RoomViewStore from "../../../stores/RoomViewStore"; +import { RoomViewStore } from "../../../stores/RoomViewStore"; import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases'; import { ROOM_NOTIFICATIONS_TAB } from "../dialogs/RoomSettingsDialog"; import { useEventEmitterState } from "../../../hooks/useEventEmitter"; @@ -280,7 +280,7 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => { }; const ensureViewingRoom = (ev: ButtonEvent) => { - if (RoomViewStore.getRoomId() === room.roomId) return; + if (RoomViewStore.instance.getRoomId() === room.roomId) return; dis.dispatch({ action: Action.ViewRoom, room_id: room.roomId, @@ -361,7 +361,7 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => { ev.stopPropagation(); Modal.createDialog(DevtoolsDialog, { - roomId: RoomViewStore.getRoomId(), + roomId: RoomViewStore.instance.getRoomId(), }, "mx_DevtoolsDialog_wrapper"); onFinished(); }} diff --git a/src/components/views/dialogs/SpotlightDialog.tsx b/src/components/views/dialogs/SpotlightDialog.tsx index 7568e45f0f..da13b85919 100644 --- a/src/components/views/dialogs/SpotlightDialog.tsx +++ b/src/components/views/dialogs/SpotlightDialog.tsx @@ -58,7 +58,7 @@ import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar"; import { Action } from "../../../dispatcher/actions"; import Modal from "../../../Modal"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; -import RoomViewStore from "../../../stores/RoomViewStore"; +import { RoomViewStore } from "../../../stores/RoomViewStore"; import { showStartChatInviteDialog } from "../../../RoomInvite"; import SettingsStore from "../../../settings/SettingsStore"; import { SettingLevel } from "../../../settings/SettingLevel"; @@ -559,7 +559,7 @@ const SpotlightDialog: React.FC = ({ initialText = "", onFinished }) =>

{ _t("Recently viewed") }

{ BreadcrumbsStore.instance.rooms - .filter(r => r.roomId !== RoomViewStore.getRoomId()) + .filter(r => r.roomId !== RoomViewStore.instance.getRoomId()) .map(room => ( { ); if (isActiveWidget) { // We just left the room that the active widget was from. - if (this.props.room && RoomViewStore.getRoomId() !== this.props.room.roomId) { + if (this.props.room && RoomViewStore.instance.getRoomId() !== this.props.room.roomId) { // If we are not actively looking at the room then destroy this widget entirely. this.endWidgetActions(); } else if (WidgetType.JITSI.matches(this.props.app.type)) { diff --git a/src/components/views/right_panel/TimelineCard.tsx b/src/components/views/right_panel/TimelineCard.tsx index 82f651281c..fd9d42d1a7 100644 --- a/src/components/views/right_panel/TimelineCard.tsx +++ b/src/components/views/right_panel/TimelineCard.tsx @@ -35,7 +35,7 @@ import dis from '../../../dispatcher/dispatcher'; import { _t } from '../../../languageHandler'; import { ActionPayload } from '../../../dispatcher/payloads'; import { Action } from '../../../dispatcher/actions'; -import RoomViewStore from '../../../stores/RoomViewStore'; +import { RoomViewStore } from '../../../stores/RoomViewStore'; import ContentMessages from '../../../ContentMessages'; import UploadBar from '../../structures/UploadBar'; import SettingsStore from '../../../settings/SettingsStore'; @@ -92,7 +92,7 @@ export default class TimelineCard extends React.Component { } public componentDidMount(): void { - this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate); + this.roomStoreToken = RoomViewStore.instance.addListener(this.onRoomViewStoreUpdate); this.dispatcherRef = dis.register(this.onAction); this.readReceiptsSettingWatcher = SettingsStore.watchSetting("showReadReceipts", null, (...[,,, value]) => this.setState({ showReadReceipts: value as boolean }), @@ -119,12 +119,12 @@ export default class TimelineCard extends React.Component { private onRoomViewStoreUpdate = async (initial?: boolean): Promise => { const newState: Pick = { - // roomLoading: RoomViewStore.isRoomLoading(), - // roomLoadError: RoomViewStore.getRoomLoadError(), + // roomLoading: RoomViewStore.instance.isRoomLoading(), + // roomLoadError: RoomViewStore.instance.getRoomLoadError(), - initialEventId: RoomViewStore.getInitialEventId(), - isInitialEventHighlighted: RoomViewStore.isInitialEventHighlighted(), - replyToEvent: RoomViewStore.getQuotingEvent(), + initialEventId: RoomViewStore.instance.getInitialEventId(), + isInitialEventHighlighted: RoomViewStore.instance.isInitialEventHighlighted(), + replyToEvent: RoomViewStore.instance.getQuotingEvent(), }; this.setState(newState); diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 2aa9046056..263a64c609 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -37,7 +37,7 @@ import createRoom, { findDMForUser, privateShouldBeEncrypted } from '../../../cr import DMRoomMap from '../../../utils/DMRoomMap'; import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton'; import SdkConfig from '../../../SdkConfig'; -import RoomViewStore from "../../../stores/RoomViewStore"; +import { RoomViewStore } from "../../../stores/RoomViewStore"; import MultiInviter from "../../../utils/MultiInviter"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import E2EIcon from "../rooms/E2EIcon"; @@ -425,7 +425,7 @@ const UserOptionsSection: React.FC<{ } if (canInvite && (member?.membership ?? 'leave') === 'leave' && shouldShowComponent(UIComponent.InviteUsers)) { - const roomId = member && member.roomId ? member.roomId : RoomViewStore.getRoomId(); + const roomId = member && member.roomId ? member.roomId : RoomViewStore.instance.getRoomId(); const onInviteUserButton = async (ev: ButtonEvent) => { try { // We use a MultiInviter to re-use the invite logic, even though diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx index 6444cbfe67..1d1c49aab1 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/RoomList.tsx @@ -23,7 +23,7 @@ import { _t, _td } from "../../../languageHandler"; import { IState as IRovingTabIndexState, RovingTabIndexProvider } from "../../../accessibility/RovingTabIndex"; import ResizeNotifier from "../../../utils/ResizeNotifier"; import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore"; -import RoomViewStore from "../../../stores/RoomViewStore"; +import { RoomViewStore } from "../../../stores/RoomViewStore"; import { ITagMap } from "../../../stores/room-list/algorithms/models"; import { DefaultTagID, TagID } from "../../../stores/room-list/models"; import defaultDispatcher from "../../../dispatcher/dispatcher"; @@ -368,7 +368,7 @@ export default class RoomList extends React.PureComponent { public componentDidMount(): void { this.dispatcherRef = defaultDispatcher.register(this.onAction); - this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate); + this.roomStoreToken = RoomViewStore.instance.addListener(this.onRoomViewStoreUpdate); SpaceStore.instance.on(UPDATE_SUGGESTED_ROOMS, this.updateSuggestedRooms); RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.updateLists); this.updateLists(); // trigger the first update @@ -383,14 +383,14 @@ export default class RoomList extends React.PureComponent { private onRoomViewStoreUpdate = () => { this.setState({ - currentRoomId: RoomViewStore.getRoomId(), + currentRoomId: RoomViewStore.instance.getRoomId(), }); }; private onAction = (payload: ActionPayload) => { if (payload.action === Action.ViewRoomDelta) { const viewRoomDeltaPayload = payload as ViewRoomDeltaPayload; - const currentRoomId = RoomViewStore.getRoomId(); + const currentRoomId = RoomViewStore.instance.getRoomId(); const room = this.getRoomDelta(currentRoomId, viewRoomDeltaPayload.delta, viewRoomDeltaPayload.unread); if (room) { defaultDispatcher.dispatch({ diff --git a/src/components/views/spaces/QuickSettingsButton.tsx b/src/components/views/spaces/QuickSettingsButton.tsx index 9206e35664..8c3ee07199 100644 --- a/src/components/views/spaces/QuickSettingsButton.tsx +++ b/src/components/views/spaces/QuickSettingsButton.tsx @@ -36,7 +36,7 @@ import { Icon as FavoriteIcon } from '../../../../res/img/element-icons/roomlist import SettingsStore from "../../../settings/SettingsStore"; import Modal from "../../../Modal"; import DevtoolsDialog from "../dialogs/DevtoolsDialog"; -import RoomViewStore from "../../../stores/RoomViewStore"; +import { RoomViewStore } from "../../../stores/RoomViewStore"; const QuickSettingsButton = ({ isPanelCollapsed = false }) => { const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu(); @@ -72,7 +72,7 @@ const QuickSettingsButton = ({ isPanelCollapsed = false }) => { onClick={() => { closeMenu(); Modal.createDialog(DevtoolsDialog, { - roomId: RoomViewStore.getRoomId(), + roomId: RoomViewStore.instance.getRoomId(), }, "mx_DevtoolsDialog_wrapper"); }} kind="danger_outline" diff --git a/src/components/views/voip/PipView.tsx b/src/components/views/voip/PipView.tsx index 3bd26c2043..ae7dd7a1af 100644 --- a/src/components/views/voip/PipView.tsx +++ b/src/components/views/voip/PipView.tsx @@ -21,7 +21,7 @@ import { logger } from "matrix-js-sdk/src/logger"; import classNames from 'classnames'; import CallView from "./CallView"; -import RoomViewStore from '../../../stores/RoomViewStore'; +import { RoomViewStore } from '../../../stores/RoomViewStore'; import CallHandler, { CallHandlerEvent } from '../../../CallHandler'; import PersistentApp from "../elements/PersistentApp"; import SettingsStore from "../../../settings/SettingsStore"; @@ -111,7 +111,7 @@ export default class PipView extends React.Component { constructor(props: IProps) { super(props); - const roomId = RoomViewStore.getRoomId(); + const roomId = RoomViewStore.instance.getRoomId(); const [primaryCall, secondaryCalls] = getPrimarySecondaryCallsForPip(roomId); @@ -129,7 +129,7 @@ export default class PipView extends React.Component { public componentDidMount() { CallHandler.instance.addListener(CallHandlerEvent.CallChangeRoom, this.updateCalls); CallHandler.instance.addListener(CallHandlerEvent.CallState, this.updateCalls); - this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate); + this.roomStoreToken = RoomViewStore.instance.addListener(this.onRoomViewStoreUpdate); MatrixClientPeg.get().on(CallEvent.RemoteHoldUnhold, this.onCallRemoteHold); const room = MatrixClientPeg.get()?.getRoom(this.state.viewedRoomId); if (room) { @@ -162,7 +162,7 @@ export default class PipView extends React.Component { } private onRoomViewStoreUpdate = () => { - const newRoomId = RoomViewStore.getRoomId(); + const newRoomId = RoomViewStore.instance.getRoomId(); const oldRoomId = this.state.viewedRoomId; if (newRoomId === oldRoomId) return; // The WidgetLayoutStore observer always tracks the currently viewed Room, diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index 44f049c27e..1177444d98 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -1,7 +1,7 @@ /* Copyright 2017 Vector Creations Ltd Copyright 2017, 2018 New Vector Ltd -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2019 - 2022 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -84,14 +84,16 @@ const INITIAL_STATE = { * with a subset of the js-sdk. * ``` */ -class RoomViewStore extends Store { +export class RoomViewStore extends Store { + public static readonly instance = new RoomViewStore(); + private state = INITIAL_STATE; // initialize state - constructor() { + public constructor() { super(dis); } - setState(newState: Partial) { + private setState(newState: Partial) { // If values haven't changed, there's nothing to do. // This only tries a shallow comparison, so unchanged objects will slip // through, but that's probably okay for now. @@ -110,7 +112,7 @@ class RoomViewStore extends Store { this.__emitChange(); } - __onDispatch(payload) { // eslint-disable-line @typescript-eslint/naming-convention + protected __onDispatch(payload) { // eslint-disable-line @typescript-eslint/naming-convention switch (payload.action) { // view_room: // - room_alias: '#somealias:matrix.org' @@ -367,7 +369,7 @@ class RoomViewStore extends Store { } } - private static getInvitingUserId(roomId: string): string { + private getInvitingUserId(roomId: string): string { const cli = MatrixClientPeg.get(); const room = cli.getRoom(roomId); if (room && room.getMyMembership() === "invite") { @@ -389,7 +391,7 @@ class RoomViewStore extends Store { { _t("Please contact your homeserver administrator.") }
; } else if (err.httpStatus === 404) { - const invitingUserId = RoomViewStore.getInvitingUserId(roomId); + const invitingUserId = this.getInvitingUserId(roomId); // only provide a better error message for invites if (invitingUserId) { // if the inviting user is on the same HS, there can only be one cause: they left. @@ -466,7 +468,7 @@ class RoomViewStore extends Store { // // Not joined // } // } else { - // if (RoomViewStore.isJoining()) { + // if (RoomViewStore.instance.isJoining()) { // // show spinner // } else { // // show join prompt @@ -494,9 +496,3 @@ class RoomViewStore extends Store { return this.state.wasContextSwitch; } } - -let singletonRoomViewStore: RoomViewStore = null; -if (!singletonRoomViewStore) { - singletonRoomViewStore = new RoomViewStore(); -} -export default singletonRoomViewStore; diff --git a/src/stores/right-panel/RightPanelStore.ts b/src/stores/right-panel/RightPanelStore.ts index 5a86dd38c5..0fa5616428 100644 --- a/src/stores/right-panel/RightPanelStore.ts +++ b/src/stores/right-panel/RightPanelStore.ts @@ -31,7 +31,7 @@ import { IRightPanelCard, IRightPanelForRoom, } from './RightPanelStoreIPanelState'; -import RoomViewStore from '../RoomViewStore'; +import { RoomViewStore } from '../RoomViewStore'; /** * A class for tracking the state of the right panel between layouts and @@ -55,9 +55,9 @@ export default class RightPanelStore extends ReadyWatchingStore { } protected async onReady(): Promise { - this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate); + this.roomStoreToken = RoomViewStore.instance.addListener(this.onRoomViewStoreUpdate); this.matrixClient.on(CryptoEvent.VerificationRequest, this.onVerificationRequestUpdate); - this.viewedRoomId = RoomViewStore.getRoomId(); + this.viewedRoomId = RoomViewStore.instance.getRoomId(); this.loadCacheFromSettings(); this.emitAndUpdateSettings(); } @@ -338,7 +338,7 @@ export default class RightPanelStore extends ReadyWatchingStore { private onRoomViewStoreUpdate = () => { const oldRoomId = this.viewedRoomId; - this.viewedRoomId = RoomViewStore.getRoomId(); + this.viewedRoomId = RoomViewStore.instance.getRoomId(); // load values from byRoomCache with the viewedRoomId. this.loadCacheFromSettings(); diff --git a/src/stores/room-list/RoomListStore.ts b/src/stores/room-list/RoomListStore.ts index 22237b801f..125b045c9a 100644 --- a/src/stores/room-list/RoomListStore.ts +++ b/src/stores/room-list/RoomListStore.ts @@ -27,7 +27,7 @@ import { ActionPayload } from "../../dispatcher/payloads"; import defaultDispatcher from "../../dispatcher/dispatcher"; import { readReceiptChangeIsFor } from "../../utils/read-receipts"; import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./filters/IFilterCondition"; -import RoomViewStore from "../RoomViewStore"; +import { RoomViewStore } from "../RoomViewStore"; import { Algorithm, LIST_UPDATED_EVENT } from "./algorithms/Algorithm"; import { EffectiveMembership, getEffectiveMembership } from "../../utils/membership"; import RoomListLayoutStore from "./RoomListLayoutStore"; @@ -111,7 +111,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient { this.readyStore.useUnitTestClient(forcedClient); } - RoomViewStore.addListener(() => this.handleRVSUpdate({})); + RoomViewStore.instance.addListener(() => this.handleRVSUpdate({})); this.algorithm.on(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated); this.algorithm.on(FILTER_CHANGED, this.onAlgorithmFilterUpdated); this.setupWatchers(); @@ -134,7 +134,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient { private handleRVSUpdate({ trigger = true }) { if (!this.matrixClient) return; // We assume there won't be RVS updates without a client - const activeRoomId = RoomViewStore.getRoomId(); + const activeRoomId = RoomViewStore.instance.getRoomId(); if (!activeRoomId && this.algorithm.stickyRoom) { this.algorithm.setStickyRoom(null); } else if (activeRoomId) { diff --git a/src/stores/spaces/SpaceStore.ts b/src/stores/spaces/SpaceStore.ts index 6e98868712..6293a11902 100644 --- a/src/stores/spaces/SpaceStore.ts +++ b/src/stores/spaces/SpaceStore.ts @@ -34,7 +34,7 @@ import { RoomNotificationStateStore } from "../notifications/RoomNotificationSta import { DefaultTagID } from "../room-list/models"; import { EnhancedMap, mapDiff } from "../../utils/maps"; import { setDiff, setHasDiff } from "../../utils/sets"; -import RoomViewStore from "../RoomViewStore"; +import { RoomViewStore } from "../RoomViewStore"; import { Action } from "../../dispatcher/actions"; import { arrayHasDiff, arrayHasOrderChange } from "../../utils/arrays"; import { reorderLexicographically } from "../../utils/stringOrderField"; @@ -804,7 +804,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { }; private switchSpaceIfNeeded = () => { - const roomId = RoomViewStore.getRoomId(); + const roomId = RoomViewStore.instance.getRoomId(); if (!this.isRoomInSpace(this.activeSpace, roomId) && !this.matrixClient.getRoom(roomId)?.isSpaceRoom()) { this.switchToRelatedSpace(roomId); } @@ -855,7 +855,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { } // if the room currently being viewed was just joined then switch to its related space - if (newMembership === "join" && room.roomId === RoomViewStore.getRoomId()) { + if (newMembership === "join" && room.roomId === RoomViewStore.instance.getRoomId()) { this.switchToRelatedSpace(room.roomId); } } @@ -882,7 +882,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { this.emit(room.roomId); } - if (membership === "join" && room.roomId === RoomViewStore.getRoomId()) { + if (membership === "join" && room.roomId === RoomViewStore.instance.getRoomId()) { // if the user was looking at the space and then joined: select that space this.setActiveSpace(room.roomId, false); } else if (membership === "leave" && room.roomId === this.activeSpace) { diff --git a/src/stores/widgets/StopGapWidget.ts b/src/stores/widgets/StopGapWidget.ts index 2ddd0d1761..723d335652 100644 --- a/src/stores/widgets/StopGapWidget.ts +++ b/src/stores/widgets/StopGapWidget.ts @@ -39,7 +39,7 @@ import { ClientEvent } from "matrix-js-sdk/src/client"; import { StopGapWidgetDriver } from "./StopGapWidgetDriver"; import { WidgetMessagingStore } from "./WidgetMessagingStore"; -import RoomViewStore from "../RoomViewStore"; +import { RoomViewStore } from "../RoomViewStore"; import { MatrixClientPeg } from "../../MatrixClientPeg"; import { OwnProfileStore } from "../OwnProfileStore"; import WidgetUtils from '../../utils/WidgetUtils'; @@ -175,7 +175,7 @@ export class StopGapWidget extends EventEmitter { if (this.roomId) return this.roomId; - return RoomViewStore.getRoomId(); + return RoomViewStore.instance.getRoomId(); } public get widgetApi(): ClientWidgetApi { @@ -361,13 +361,13 @@ export class StopGapWidget extends EventEmitter { // TODO: Open the right integration manager for the widget if (SettingsStore.getValue("feature_many_integration_managers")) { IntegrationManagers.sharedInstance().openAll( - MatrixClientPeg.get().getRoom(RoomViewStore.getRoomId()), + MatrixClientPeg.get().getRoom(RoomViewStore.instance.getRoomId()), `type_${integType}`, integId, ); } else { IntegrationManagers.sharedInstance().getPrimaryManager().open( - MatrixClientPeg.get().getRoom(RoomViewStore.getRoomId()), + MatrixClientPeg.get().getRoom(RoomViewStore.instance.getRoomId()), `type_${integType}`, integId, ); diff --git a/src/utils/membership.ts b/src/utils/membership.ts index 4a92fb303f..93cf0fc981 100644 --- a/src/utils/membership.ts +++ b/src/utils/membership.ts @@ -24,7 +24,7 @@ import { _t } from "../languageHandler"; import Modal, { IHandle } from "../Modal"; import ErrorDialog from "../components/views/dialogs/ErrorDialog"; import dis from "../dispatcher/dispatcher"; -import RoomViewStore from "../stores/RoomViewStore"; +import { RoomViewStore } from "../stores/RoomViewStore"; import Spinner from "../components/views/elements/Spinner"; import { isMetaSpace } from "../stores/spaces"; import SpaceStore from "../stores/spaces/SpaceStore"; @@ -186,7 +186,7 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner = if (!isMetaSpace(SpaceStore.instance.activeSpace) && SpaceStore.instance.activeSpace !== roomId && - RoomViewStore.getRoomId() === roomId + RoomViewStore.instance.getRoomId() === roomId ) { dis.dispatch({ action: Action.ViewRoom, diff --git a/src/utils/space.tsx b/src/utils/space.tsx index 442a411af8..e2b05c8ddf 100644 --- a/src/utils/space.tsx +++ b/src/utils/space.tsx @@ -33,7 +33,7 @@ import CreateSubspaceDialog from "../components/views/dialogs/CreateSubspaceDial import AddExistingSubspaceDialog from "../components/views/dialogs/AddExistingSubspaceDialog"; import defaultDispatcher from "../dispatcher/dispatcher"; import dis from "../dispatcher/dispatcher"; -import RoomViewStore from "../stores/RoomViewStore"; +import { RoomViewStore } from "../stores/RoomViewStore"; import { Action } from "../dispatcher/actions"; import { leaveRoomBehaviour } from "./membership"; import Spinner from "../components/views/elements/Spinner"; @@ -83,7 +83,7 @@ export const showAddExistingRooms = (space: Room): void => { onAddSubspaceClick: () => showAddExistingSubspace(space), space, onFinished: (added: boolean) => { - if (added && RoomViewStore.getRoomId() === space.roomId) { + if (added && RoomViewStore.instance.getRoomId() === space.roomId) { defaultDispatcher.fire(Action.UpdateSpaceHierarchy); } }, @@ -142,7 +142,7 @@ export const showAddExistingSubspace = (space: Room): void => { space, onCreateSubspaceClick: () => showCreateNewSubspace(space), onFinished: (added: boolean) => { - if (added && RoomViewStore.getRoomId() === space.roomId) { + if (added && RoomViewStore.instance.getRoomId() === space.roomId) { defaultDispatcher.fire(Action.UpdateSpaceHierarchy); } }, @@ -160,7 +160,7 @@ export const showCreateNewSubspace = (space: Room): void => { space, onAddExistingSpaceClick: () => showAddExistingSubspace(space), onFinished: (added: boolean) => { - if (added && RoomViewStore.getRoomId() === space.roomId) { + if (added && RoomViewStore.instance.getRoomId() === space.roomId) { defaultDispatcher.fire(Action.UpdateSpaceHierarchy); } }, diff --git a/test/stores/RoomViewStore-test.js b/test/stores/RoomViewStore-test.js index bc2bd2e936..d948fa6496 100644 --- a/test/stores/RoomViewStore-test.js +++ b/test/stores/RoomViewStore-test.js @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import RoomViewStore from '../../src/stores/RoomViewStore'; +import { RoomViewStore } from '../../src/stores/RoomViewStore'; import { Action } from '../../src/dispatcher/actions'; import { MatrixClientPeg as peg } from '../../src/MatrixClientPeg'; import * as testUtils from '../test-utils'; -const dispatch = testUtils.getDispatchForStore(RoomViewStore); +const dispatch = testUtils.getDispatchForStore(RoomViewStore.instance); jest.mock('../../src/utils/DMRoomMap', () => { const mock = { @@ -41,7 +41,7 @@ describe('RoomViewStore', function() { peg.get().off = jest.fn(); // Reset the state of the store - RoomViewStore.reset(); + RoomViewStore.instance.reset(); }); it('can be used to view a room by ID and join', function(done) { @@ -52,16 +52,16 @@ describe('RoomViewStore', function() { dispatch({ action: Action.ViewRoom, room_id: '!randomcharacters:aser.ver' }); dispatch({ action: 'join_room' }); - expect(RoomViewStore.isJoining()).toBe(true); + expect(RoomViewStore.instance.isJoining()).toBe(true); }); it('can be used to view a room by alias and join', function(done) { - const token = RoomViewStore.addListener(() => { + const token = RoomViewStore.instance.addListener(() => { // Wait until the room alias has resolved and the room ID is - if (!RoomViewStore.isRoomLoading()) { - expect(RoomViewStore.getRoomId()).toBe("!randomcharacters:aser.ver"); + if (!RoomViewStore.instance.isRoomLoading()) { + expect(RoomViewStore.instance.getRoomId()).toBe("!randomcharacters:aser.ver"); dispatch({ action: 'join_room' }); - expect(RoomViewStore.isJoining()).toBe(true); + expect(RoomViewStore.instance.isJoining()).toBe(true); } }); From 109ecbf070319d0fac3fb56b5a51698f596fc032 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 8 Mar 2022 15:29:41 -0700 Subject: [PATCH 12/47] Step 8.4.1: Use `RoomViewStore` in SGWidgetDriver over `ActiveRoomObserver` It wasn't using the listener functionality anyways, so just go straight to the source for which room is being viewed. --- src/stores/widgets/StopGapWidgetDriver.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stores/widgets/StopGapWidgetDriver.ts b/src/stores/widgets/StopGapWidgetDriver.ts index 4fa9d6d9a6..c33bbe06cf 100644 --- a/src/stores/widgets/StopGapWidgetDriver.ts +++ b/src/stores/widgets/StopGapWidgetDriver.ts @@ -37,7 +37,6 @@ import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread"; import { iterableDiff, iterableIntersection } from "../../utils/iterables"; import { MatrixClientPeg } from "../../MatrixClientPeg"; -import ActiveRoomObserver from "../../ActiveRoomObserver"; import Modal from "../../Modal"; import WidgetOpenIDPermissionsDialog from "../../components/views/dialogs/WidgetOpenIDPermissionsDialog"; import WidgetCapabilitiesPromptDialog from "../../components/views/dialogs/WidgetCapabilitiesPromptDialog"; @@ -49,6 +48,7 @@ import { containsEmoji } from "../../effects/utils"; import dis from "../../dispatcher/dispatcher"; import { tryTransformPermalinkToLocalHref } from "../../utils/permalinks/Permalinks"; import SettingsStore from "../../settings/SettingsStore"; +import { RoomViewStore } from "../RoomViewStore"; // TODO: Purge this from the universe @@ -150,7 +150,7 @@ export class StopGapWidgetDriver extends WidgetDriver { targetRoomId: string = null, ): Promise { const client = MatrixClientPeg.get(); - const roomId = targetRoomId || ActiveRoomObserver.activeRoomId; + const roomId = targetRoomId || RoomViewStore.instance.getRoomId(); if (!client || !roomId) throw new Error("Not in a room or not attached to a client"); @@ -188,7 +188,7 @@ export class StopGapWidgetDriver extends WidgetDriver { const targetRooms = roomIds ? (roomIds.includes(Symbols.AnyRoom) ? client.getVisibleRooms() : roomIds.map(r => client.getRoom(r))) - : [client.getRoom(ActiveRoomObserver.activeRoomId)]; + : [client.getRoom(RoomViewStore.instance.getRoomId())]; return targetRooms.filter(r => !!r); } From d89fcf17fbbda69ab82021e0ee99429113ccde45 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Mar 2022 23:29:02 -0600 Subject: [PATCH 13/47] Step 8.4.2: Refactor `ActiveRoomObserver` out of existence The `RoomTile` was the last class to use it. Note that we also update the RVS to change its `instance` declaration type to fix a few tests. --- src/@types/global.d.ts | 2 - src/ActiveRoomObserver.ts | 85 ------------------------- src/components/views/rooms/RoomTile.tsx | 27 ++++---- src/stores/RoomViewStore.tsx | 38 +++++++++++ 4 files changed, 50 insertions(+), 102 deletions(-) delete mode 100644 src/ActiveRoomObserver.ts diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index c3f739c731..d0f266470c 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -29,7 +29,6 @@ import RoomListLayoutStore from "../stores/room-list/RoomListLayoutStore"; import { IntegrationManagers } from "../integrations/IntegrationManagers"; import { ModalManager } from "../Modal"; import SettingsStore from "../settings/SettingsStore"; -import { ActiveRoomObserver } from "../ActiveRoomObserver"; import { Notifier } from "../Notifier"; import type { Renderer } from "react-dom"; import RightPanelStore from "../stores/right-panel/RightPanelStore"; @@ -82,7 +81,6 @@ declare global { mxDeviceListener: DeviceListener; mxRoomListStore: RoomListStoreClass; mxRoomListLayoutStore: RoomListLayoutStore; - mxActiveRoomObserver: ActiveRoomObserver; mxPlatformPeg: PlatformPeg; mxIntegrationManagers: typeof IntegrationManagers; singletonModalManager: ModalManager; diff --git a/src/ActiveRoomObserver.ts b/src/ActiveRoomObserver.ts deleted file mode 100644 index bcdc249fea..0000000000 --- a/src/ActiveRoomObserver.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* -Copyright 2017 - 2022 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { logger } from "matrix-js-sdk/src/logger"; - -import { RoomViewStore } from './stores/RoomViewStore'; - -type Listener = (isActive: boolean) => void; - -/** - * Consumes changes from the RoomViewStore and notifies specific things - * about when the active room changes. Unlike listening for RoomViewStore - * changes, you can subscribe to only changes relevant to a particular - * room. - * - * TODO: If we introduce an observer for something else, factor out - * the adding / removing of listeners & emitting into a common class. - */ -export class ActiveRoomObserver { - private listeners: {[key: string]: Listener[]} = {}; - private _activeRoomId = RoomViewStore.instance.getRoomId(); - private readonly roomStoreToken: EventSubscription; - - constructor() { - // TODO: We could self-destruct when the last listener goes away, or at least stop listening. - this.roomStoreToken = RoomViewStore.instance.addListener(this.onRoomViewStoreUpdate); - } - - public get activeRoomId(): string { - return this._activeRoomId; - } - - public addListener(roomId, listener) { - if (!this.listeners[roomId]) this.listeners[roomId] = []; - this.listeners[roomId].push(listener); - } - - public removeListener(roomId, listener) { - if (this.listeners[roomId]) { - const i = this.listeners[roomId].indexOf(listener); - if (i > -1) { - this.listeners[roomId].splice(i, 1); - } - } else { - logger.warn("Unregistering unrecognised listener (roomId=" + roomId + ")"); - } - } - - private emit(roomId, isActive: boolean) { - if (!this.listeners[roomId]) return; - - for (const l of this.listeners[roomId]) { - l.call(null, isActive); - } - } - - private onRoomViewStoreUpdate = () => { - // emit for the old room ID - if (this._activeRoomId) this.emit(this._activeRoomId, false); - - // update our cache - this._activeRoomId = RoomViewStore.instance.getRoomId(); - - // and emit for the new one - if (this._activeRoomId) this.emit(this._activeRoomId, true); - }; -} - -if (window.mxActiveRoomObserver === undefined) { - window.mxActiveRoomObserver = new ActiveRoomObserver(); -} -export default window.mxActiveRoomObserver; diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index 6fbe956361..1d04d7be75 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -28,7 +28,6 @@ import dis from '../../../dispatcher/dispatcher'; import defaultDispatcher from '../../../dispatcher/dispatcher'; import { Action } from "../../../dispatcher/actions"; import SettingsStore from "../../../settings/SettingsStore"; -import ActiveRoomObserver from "../../../ActiveRoomObserver"; import { _t } from "../../../languageHandler"; import { ChevronFace, ContextMenuTooltipButton } from "../../structures/ContextMenu"; import { DefaultTagID, TagID } from "../../../stores/room-list/models"; @@ -61,6 +60,7 @@ import PosthogTrackers from "../../../PosthogTrackers"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; +import { RoomViewStore } from "../../../stores/RoomViewStore"; enum VoiceConnectionState { Disconnected, @@ -110,7 +110,7 @@ export default class RoomTile extends React.PureComponent { super(props); this.state = { - selected: ActiveRoomObserver.activeRoomId === this.props.room.roomId, + selected: RoomViewStore.instance.getRoomId() === this.props.room.roomId, notificationsMenuPosition: null, generalMenuPosition: null, // generatePreview() will return nothing if the user has previews disabled @@ -177,7 +177,7 @@ export default class RoomTile extends React.PureComponent { } this.updateVoiceMembers(); - ActiveRoomObserver.addListener(this.props.room.roomId, this.onActiveRoomUpdate); + RoomViewStore.instance.addRoomListener(this.props.room.roomId, this.onActiveRoomUpdate); this.dispatcherRef = defaultDispatcher.register(this.onAction); MessagePreviewStore.instance.on( MessagePreviewStore.getPreviewChangedEventName(this.props.room), @@ -185,21 +185,18 @@ export default class RoomTile extends React.PureComponent { ); this.notificationState.on(NotificationStateEvents.Update, this.onNotificationUpdate); this.roomProps.on(PROPERTY_UPDATED, this.onRoomPropertyUpdate); - this.props.room?.on(RoomEvent.Name, this.onRoomNameUpdate); - this.props.room?.currentState?.on(RoomStateEvent.Events, this.updateVoiceMembers); + this.props.room.on(RoomEvent.Name, this.onRoomNameUpdate); + this.props.room.currentState.on(RoomStateEvent.Events, this.updateVoiceMembers); } public componentWillUnmount() { - if (this.props.room) { - ActiveRoomObserver.removeListener(this.props.room.roomId, this.onActiveRoomUpdate); - MessagePreviewStore.instance.off( - MessagePreviewStore.getPreviewChangedEventName(this.props.room), - this.onRoomPreviewChanged, - ); - this.props.room.currentState.off(RoomStateEvent.Events, this.updateVoiceMembers); - this.props.room.off(RoomEvent.Name, this.onRoomNameUpdate); - } - ActiveRoomObserver.removeListener(this.props.room.roomId, this.onActiveRoomUpdate); + RoomViewStore.instance.removeRoomListener(this.props.room.roomId, this.onActiveRoomUpdate); + MessagePreviewStore.instance.off( + MessagePreviewStore.getPreviewChangedEventName(this.props.room), + this.onRoomPreviewChanged, + ); + this.props.room.off(RoomEvent.Name, this.onRoomNameUpdate); + this.props.room.currentState.off(RoomStateEvent.Events, this.updateVoiceMembers); defaultDispatcher.unregister(this.dispatcherRef); this.notificationState.off(NotificationStateEvents.Update, this.onNotificationUpdate); this.roomProps.off(PROPERTY_UPDATED, this.onRoomPropertyUpdate); diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index 1177444d98..e8ed6a62c4 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -79,20 +79,52 @@ const INITIAL_STATE = { wasContextSwitch: false, }; +type Listener = (isActive: boolean) => void; + /** * A class for storing application state for RoomView. This is the RoomView's interface * with a subset of the js-sdk. * ``` */ export class RoomViewStore extends Store { + // Important: This cannot be a dynamic getter (lazily-constructed instance) because + // otherwise we'll miss view_room dispatches during startup, breaking relaunches of + // the app. We need to eagerly create the instance. public static readonly instance = new RoomViewStore(); private state = INITIAL_STATE; // initialize state + // Keep these out of state to avoid causing excessive/recursive updates + private roomIdActivityListeners: Record = {}; + public constructor() { super(dis); } + public addRoomListener(roomId: string, fn: Listener) { + if (!this.roomIdActivityListeners[roomId]) this.roomIdActivityListeners[roomId] = []; + this.roomIdActivityListeners[roomId].push(fn); + } + + public removeRoomListener(roomId: string, fn: Listener) { + if (this.roomIdActivityListeners[roomId]) { + const i = this.roomIdActivityListeners[roomId].indexOf(fn); + if (i > -1) { + this.roomIdActivityListeners[roomId].splice(i, 1); + } + } else { + logger.warn("Unregistering unrecognised listener (roomId=" + roomId + ")"); + } + } + + private emitForRoom(roomId: string, isActive: boolean) { + if (!this.roomIdActivityListeners[roomId]) return; + + for (const fn of this.roomIdActivityListeners[roomId]) { + fn.call(null, isActive); + } + } + private setState(newState: Partial) { // If values haven't changed, there's nothing to do. // This only tries a shallow comparison, so unchanged objects will slip @@ -108,7 +140,13 @@ export class RoomViewStore extends Store { return; } + const lastRoomId = this.state.roomId; this.state = Object.assign(this.state, newState); + if (lastRoomId !== this.state.roomId) { + if (lastRoomId) this.emitForRoom(lastRoomId, false); + if (this.state.roomId) this.emitForRoom(this.state.roomId, true); + } + this.__emitChange(); } From 56b099c171dca513d960f6bfb9d43ba8c97de094 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 23 Mar 2022 17:37:13 -0600 Subject: [PATCH 14/47] Step 8.4.3: Improve PlaybackQueue listener efficiency --- src/audio/PlaybackQueue.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/audio/PlaybackQueue.ts b/src/audio/PlaybackQueue.ts index d90051d0f1..72ed8cf169 100644 --- a/src/audio/PlaybackQueue.ts +++ b/src/audio/PlaybackQueue.ts @@ -51,15 +51,15 @@ export class PlaybackQueue { constructor(private room: Room) { this.loadClocks(); - RoomViewStore.instance.addListener(() => { - if (RoomViewStore.instance.getRoomId() === this.room.roomId) { - // Reset the state of the playbacks before they start mounting and enqueuing updates. - // We reset the entirety of the queue, including order, to ensure the user isn't left - // confused with what order the messages are playing in. - this.currentPlaybackId = null; // this in particular stops autoplay when the room is switched to - this.recentFullPlays = new Set(); - this.playbackIdOrder = []; - } + RoomViewStore.instance.addRoomListener(this.room.roomId, (isActive) => { + if (!isActive) return; + + // Reset the state of the playbacks before they start mounting and enqueuing updates. + // We reset the entirety of the queue, including order, to ensure the user isn't left + // confused with what order the messages are playing in. + this.currentPlaybackId = null; // this in particular stops autoplay when the room is switched to + this.recentFullPlays = new Set(); + this.playbackIdOrder = []; }); } From 1126fdbd993e9fe277da3446769ca9ad72df7468 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 15:33:09 -0600 Subject: [PATCH 15/47] Step 8.5: Move isLoggedIn helper --- src/DeviceListener.ts | 2 +- src/components/structures/MatrixChat.tsx | 9 -------- src/utils/login.ts | 27 ++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 src/utils/login.ts diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts index 05f86453f1..adba51d135 100644 --- a/src/DeviceListener.ts +++ b/src/DeviceListener.ts @@ -36,9 +36,9 @@ import { } from "./toasts/UnverifiedSessionToast"; import { accessSecretStorage, isSecretStorageBeingAccessed } from "./SecurityManager"; import { isSecureBackupRequired } from './utils/WellKnownUtils'; -import { isLoggedIn } from './components/structures/MatrixChat'; import { ActionPayload } from "./dispatcher/payloads"; import { Action } from "./dispatcher/actions"; +import { isLoggedIn } from "./utils/login"; const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000; diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 9c1589d58c..c0b307156b 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -2093,12 +2093,3 @@ export default class MatrixChat extends React.PureComponent { ; } } - -export function isLoggedIn(): boolean { - // JRS: Maybe we should move the step that writes this to the window out of - // `element-web` and into this file? Better yet, we should probably create a - // store to hold this state. - // See also https://github.com/vector-im/element-web/issues/15034. - const app = window.matrixChat; - return app && (app as MatrixChat).state.view === Views.LOGGED_IN; -} diff --git a/src/utils/login.ts b/src/utils/login.ts new file mode 100644 index 0000000000..8e66909952 --- /dev/null +++ b/src/utils/login.ts @@ -0,0 +1,27 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import type MatrixChat from "../components/structures/MatrixChat"; +import Views from "../Views"; + +export function isLoggedIn(): boolean { + // JRS: Maybe we should move the step that writes this to the window out of + // `element-web` and into this file? Better yet, we should probably create a + // store to hold this state. + // See also https://github.com/vector-im/element-web/issues/15034. + const app = window.matrixChat; + return app && (app as MatrixChat).state.view === Views.LOGGED_IN; +} From 90270ee468bfc17ad652e38bbbf208d1b5f1c2c6 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 15:33:22 -0600 Subject: [PATCH 16/47] Step 8.5: Move room i18n helpers --- src/Rooms.ts | 48 -------------- .../views/dialogs/ForwardDialog.tsx | 2 +- .../views/dialogs/SpotlightDialog.tsx | 2 +- .../views/rooms/RecentlyViewedButton.tsx | 2 +- src/utils/i18n-helpers.ts | 66 +++++++++++++++++++ 5 files changed, 69 insertions(+), 51 deletions(-) create mode 100644 src/utils/i18n-helpers.ts diff --git a/src/Rooms.ts b/src/Rooms.ts index 9bb43c3d8c..32419080ac 100644 --- a/src/Rooms.ts +++ b/src/Rooms.ts @@ -19,9 +19,6 @@ import { EventType } from "matrix-js-sdk/src/@types/event"; import { MatrixClientPeg } from './MatrixClientPeg'; import AliasCustomisations from './customisations/Alias'; -import DMRoomMap from "./utils/DMRoomMap"; -import SpaceStore from "./stores/spaces/SpaceStore"; -import { _t } from "./languageHandler"; /** * Given a room object, return the alias we should use for it, @@ -157,48 +154,3 @@ function guessDMRoomTargetId(room: Room, myUserId: string): string { if (oldestUser === undefined) return myUserId; return oldestUser.userId; } - -export function spaceContextDetailsText(space: Room): string { - if (!space.isSpaceRoom()) return undefined; - - const [parent, secondParent, ...otherParents] = SpaceStore.instance.getKnownParents(space.roomId); - if (secondParent && !otherParents?.length) { - // exactly 2 edge case for improved i18n - return _t("%(space1Name)s and %(space2Name)s", { - space1Name: space.client.getRoom(parent)?.name, - space2Name: space.client.getRoom(secondParent)?.name, - }); - } else if (parent) { - return _t("%(spaceName)s and %(count)s others", { - spaceName: space.client.getRoom(parent)?.name, - count: otherParents.length, - }); - } - - return space.getCanonicalAlias(); -} - -export function roomContextDetailsText(room: Room): string { - if (room.isSpaceRoom()) return undefined; - - const dmPartner = DMRoomMap.shared().getUserIdForRoomId(room.roomId); - if (dmPartner) { - return dmPartner; - } - - const [parent, secondParent, ...otherParents] = SpaceStore.instance.getKnownParents(room.roomId); - if (secondParent && !otherParents?.length) { - // exactly 2 edge case for improved i18n - return _t("%(space1Name)s and %(space2Name)s", { - space1Name: room.client.getRoom(parent)?.name, - space2Name: room.client.getRoom(secondParent)?.name, - }); - } else if (parent) { - return _t("%(spaceName)s and %(count)s others", { - spaceName: room.client.getRoom(parent)?.name, - count: otherParents.length, - }); - } - - return room.getCanonicalAlias(); -} diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index d3f38fa9d1..0a063df9c7 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -43,10 +43,10 @@ import QueryMatcher from "../../../autocomplete/QueryMatcher"; import TruncatedList from "../elements/TruncatedList"; import EntityTile from "../rooms/EntityTile"; import BaseAvatar from "../avatars/BaseAvatar"; -import { roomContextDetailsText } from "../../../Rooms"; import { Action } from "../../../dispatcher/actions"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { ButtonEvent } from "../elements/AccessibleButton"; +import { roomContextDetailsText } from "../../../utils/i18n-helpers"; const AVATAR_SIZE = 30; diff --git a/src/components/views/dialogs/SpotlightDialog.tsx b/src/components/views/dialogs/SpotlightDialog.tsx index da13b85919..8b4e8ed701 100644 --- a/src/components/views/dialogs/SpotlightDialog.tsx +++ b/src/components/views/dialogs/SpotlightDialog.tsx @@ -53,7 +53,6 @@ import DMRoomMap from "../../../utils/DMRoomMap"; import { mediaFromMxc } from "../../../customisations/Media"; import BaseAvatar from "../avatars/BaseAvatar"; import Spinner from "../elements/Spinner"; -import { roomContextDetailsText, spaceContextDetailsText } from "../../../Rooms"; import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar"; import { Action } from "../../../dispatcher/actions"; import Modal from "../../../Modal"; @@ -74,6 +73,7 @@ import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { PosthogAnalytics } from "../../../PosthogAnalytics"; import { getCachedRoomIDForAlias } from "../../../RoomAliasCache"; +import { roomContextDetailsText, spaceContextDetailsText } from "../../../utils/i18n-helpers"; const MAX_RECENT_SEARCHES = 10; const SECTION_LIMIT = 50; // only show 50 results per section for performance reasons diff --git a/src/components/views/rooms/RecentlyViewedButton.tsx b/src/components/views/rooms/RecentlyViewedButton.tsx index 5a5ec1520e..9fd71d50e2 100644 --- a/src/components/views/rooms/RecentlyViewedButton.tsx +++ b/src/components/views/rooms/RecentlyViewedButton.tsx @@ -23,10 +23,10 @@ import { useEventEmitterState } from "../../../hooks/useEventEmitter"; import { _t } from "../../../languageHandler"; import dis from "../../../dispatcher/dispatcher"; import InteractiveTooltip, { Direction } from "../elements/InteractiveTooltip"; -import { roomContextDetailsText } from "../../../Rooms"; import { Action } from "../../../dispatcher/actions"; import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; +import { roomContextDetailsText } from "../../../utils/i18n-helpers"; const RecentlyViewedButton = () => { const tooltipRef = useRef(); diff --git a/src/utils/i18n-helpers.ts b/src/utils/i18n-helpers.ts new file mode 100644 index 0000000000..ce1d04f9f4 --- /dev/null +++ b/src/utils/i18n-helpers.ts @@ -0,0 +1,66 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Room } from "matrix-js-sdk/src/models/room"; + +import SpaceStore from "../stores/spaces/SpaceStore"; +import { _t } from "../languageHandler"; +import DMRoomMap from "./DMRoomMap"; + +export function spaceContextDetailsText(space: Room): string { + if (!space.isSpaceRoom()) return undefined; + + const [parent, secondParent, ...otherParents] = SpaceStore.instance.getKnownParents(space.roomId); + if (secondParent && !otherParents?.length) { + // exactly 2 edge case for improved i18n + return _t("%(space1Name)s and %(space2Name)s", { + space1Name: space.client.getRoom(parent)?.name, + space2Name: space.client.getRoom(secondParent)?.name, + }); + } else if (parent) { + return _t("%(spaceName)s and %(count)s others", { + spaceName: space.client.getRoom(parent)?.name, + count: otherParents.length, + }); + } + + return space.getCanonicalAlias(); +} + +export function roomContextDetailsText(room: Room): string { + if (room.isSpaceRoom()) return undefined; + + const dmPartner = DMRoomMap.shared().getUserIdForRoomId(room.roomId); + if (dmPartner) { + return dmPartner; + } + + const [parent, secondParent, ...otherParents] = SpaceStore.instance.getKnownParents(room.roomId); + if (secondParent && !otherParents?.length) { + // exactly 2 edge case for improved i18n + return _t("%(space1Name)s and %(space2Name)s", { + space1Name: room.client.getRoom(parent)?.name, + space2Name: room.client.getRoom(secondParent)?.name, + }); + } else if (parent) { + return _t("%(spaceName)s and %(count)s others", { + spaceName: room.client.getRoom(parent)?.name, + count: otherParents.length, + }); + } + + return room.getCanonicalAlias(); +} From 1c8ac2c2e5ef00f079a15974d898298e70b653ef Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 15:25:44 -0600 Subject: [PATCH 17/47] Step 8.5: Move leave behaviour --- src/SlashCommands.tsx | 3 +- src/components/structures/MatrixChat.tsx | 2 +- .../views/context_menus/SpaceContextMenu.tsx | 2 +- .../views/spaces/SpaceSettingsGeneralTab.tsx | 2 +- src/utils/leave-behaviour.ts | 158 ++++++++++++++++++ src/utils/membership.ts | 124 +------------- src/utils/space.tsx | 19 --- .../context_menus/SpaceContextMenu-test.tsx | 7 +- 8 files changed, 169 insertions(+), 148 deletions(-) create mode 100644 src/utils/leave-behaviour.ts diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index 75897bbb0a..75254afb3c 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -46,7 +46,7 @@ import BugReportDialog from "./components/views/dialogs/BugReportDialog"; import { ensureDMExists } from "./createRoom"; import { ViewUserPayload } from "./dispatcher/payloads/ViewUserPayload"; import { Action } from "./dispatcher/actions"; -import { EffectiveMembership, getEffectiveMembership, leaveRoomBehaviour } from "./utils/membership"; +import { EffectiveMembership, getEffectiveMembership } from "./utils/membership"; import SdkConfig from "./SdkConfig"; import SettingsStore from "./settings/SettingsStore"; import { UIComponent, UIFeature } from "./settings/UIFeature"; @@ -66,6 +66,7 @@ import { XOR } from "./@types/common"; import { PosthogAnalytics } from "./PosthogAnalytics"; import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload"; import VoipUserMapper from './VoipUserMapper'; +import { leaveRoomBehaviour } from "./utils/leave-behaviour"; // XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816 interface HTMLInputEvent extends Event { diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index c0b307156b..82a832d85e 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -83,7 +83,6 @@ import { UPDATE_STATUS_INDICATOR, } from "../../stores/notifications/RoomNotificationStateStore"; import { SettingLevel } from "../../settings/SettingLevel"; -import { leaveRoomBehaviour } from "../../utils/membership"; import ThreepidInviteStore, { IThreepidInvite, IThreepidInviteWireFormat } from "../../stores/ThreepidInviteStore"; import { UIFeature } from "../../settings/UIFeature"; import DialPadModal from "../views/voip/DialPadModal"; @@ -129,6 +128,7 @@ import { ViewStartChatOrReusePayload } from '../../dispatcher/payloads/ViewStart import { IConfigOptions } from "../../IConfigOptions"; import { SnakedObject } from "../../utils/SnakedObject"; import InfoDialog from '../views/dialogs/InfoDialog'; +import { leaveRoomBehaviour } from "../../utils/leave-behaviour"; // legacy export export { default as Views } from "../../Views"; diff --git a/src/components/views/context_menus/SpaceContextMenu.tsx b/src/components/views/context_menus/SpaceContextMenu.tsx index aab270e2e8..d9286c618b 100644 --- a/src/components/views/context_menus/SpaceContextMenu.tsx +++ b/src/components/views/context_menus/SpaceContextMenu.tsx @@ -22,7 +22,6 @@ import { IProps as IContextMenuProps } from "../../structures/ContextMenu"; import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from "./IconizedContextMenu"; import { _t } from "../../../languageHandler"; import { - leaveSpace, shouldShowSpaceSettings, showCreateNewRoom, showCreateNewSubspace, @@ -30,6 +29,7 @@ import { showSpacePreferences, showSpaceSettings, } from "../../../utils/space"; +import { leaveSpace } from "../../../utils/leave-behaviour"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import { ButtonEvent } from "../elements/AccessibleButton"; import defaultDispatcher from "../../../dispatcher/dispatcher"; diff --git a/src/components/views/spaces/SpaceSettingsGeneralTab.tsx b/src/components/views/spaces/SpaceSettingsGeneralTab.tsx index 4752c0f6db..b572122da1 100644 --- a/src/components/views/spaces/SpaceSettingsGeneralTab.tsx +++ b/src/components/views/spaces/SpaceSettingsGeneralTab.tsx @@ -26,7 +26,7 @@ import SpaceBasicSettings from "./SpaceBasicSettings"; import { avatarUrlForRoom } from "../../../Avatar"; import { IDialogProps } from "../dialogs/IDialogProps"; import { getTopic } from "../elements/RoomTopic"; -import { leaveSpace } from "../../../utils/space"; +import { leaveSpace } from "../../../utils/leave-behaviour"; interface IProps extends IDialogProps { matrixClient: MatrixClient; diff --git a/src/utils/leave-behaviour.ts b/src/utils/leave-behaviour.ts new file mode 100644 index 0000000000..2d87e4d4dd --- /dev/null +++ b/src/utils/leave-behaviour.ts @@ -0,0 +1,158 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { sleep } from "matrix-js-sdk/src/utils"; +import React from "react"; +import { EventStatus } from "matrix-js-sdk/src/models/event-status"; +import { MatrixEventEvent } from "matrix-js-sdk/src/models/event"; +import { Room } from "matrix-js-sdk/src/models/room"; + +import Modal, { IHandle } from "../Modal"; +import Spinner from "../components/views/elements/Spinner"; +import { MatrixClientPeg } from "../MatrixClientPeg"; +import { _t } from "../languageHandler"; +import ErrorDialog from "../components/views/dialogs/ErrorDialog"; +import { isMetaSpace } from "../stores/spaces"; +import SpaceStore from "../stores/spaces/SpaceStore"; +import { RoomViewStore } from "../stores/RoomViewStore"; +import dis from "../dispatcher/dispatcher"; +import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload"; +import { Action } from "../dispatcher/actions"; +import { ViewHomePagePayload } from "../dispatcher/payloads/ViewHomePagePayload"; +import LeaveSpaceDialog from "../components/views/dialogs/LeaveSpaceDialog"; +import { AfterLeaveRoomPayload } from "../dispatcher/payloads/AfterLeaveRoomPayload"; +import { bulkSpaceBehaviour } from "./space"; + +export async function leaveRoomBehaviour(roomId: string, retry = true, spinner = true) { + let spinnerModal: IHandle; + if (spinner) { + spinnerModal = Modal.createDialog(Spinner, null, 'mx_Dialog_spinner'); + } + + const cli = MatrixClientPeg.get(); + let leavingAllVersions = true; + const history = cli.getRoomUpgradeHistory(roomId); + if (history && history.length > 0) { + const currentRoom = history[history.length - 1]; + if (currentRoom.roomId !== roomId) { + // The user is trying to leave an older version of the room. Let them through + // without making them leave the current version of the room. + leavingAllVersions = false; + } + } + + const room = cli.getRoom(roomId); + // await any queued messages being sent so that they do not fail + await Promise.all(room.getPendingEvents().filter(ev => { + return [EventStatus.QUEUED, EventStatus.ENCRYPTING, EventStatus.SENDING].includes(ev.status); + }).map(ev => new Promise((resolve, reject) => { + const handler = () => { + if (ev.status === EventStatus.NOT_SENT) { + spinnerModal?.close(); + reject(ev.error); + } + + if (!ev.status || ev.status === EventStatus.SENT) { + ev.off(MatrixEventEvent.Status, handler); + resolve(); + } + }; + + ev.on(MatrixEventEvent.Status, handler); + }))); + + let results: { [roomId: string]: Error & { errcode?: string, message: string, data?: Record } } = {}; + if (!leavingAllVersions) { + try { + await cli.leave(roomId); + } catch (e) { + if (e?.data?.errcode) { + const message = e.data.error || _t("Unexpected server error trying to leave the room"); + results[roomId] = Object.assign(new Error(message), { errcode: e.data.errcode, data: e.data }); + } else { + results[roomId] = e || new Error("Failed to leave room for unknown causes"); + } + } + } else { + results = await cli.leaveRoomChain(roomId, retry); + } + + if (retry) { + const limitExceededError = Object.values(results).find(e => e?.errcode === "M_LIMIT_EXCEEDED"); + if (limitExceededError) { + await sleep(limitExceededError.data.retry_after_ms ?? 100); + return leaveRoomBehaviour(roomId, false, false); + } + } + + spinnerModal?.close(); + + const errors = Object.entries(results).filter(r => !!r[1]); + if (errors.length > 0) { + const messages = []; + for (const roomErr of errors) { + const err = roomErr[1]; // [0] is the roomId + let message = _t("Unexpected server error trying to leave the room"); + if (err.errcode && err.message) { + if (err.errcode === 'M_CANNOT_LEAVE_SERVER_NOTICE_ROOM') { + Modal.createTrackedDialog('Error Leaving Room', '', ErrorDialog, { + title: _t("Can't leave Server Notices room"), + description: _t( + "This room is used for important messages from the Homeserver, " + + "so you cannot leave it.", + ), + }); + return; + } + message = results[roomId].message; + } + messages.push(message, React.createElement('BR')); // createElement to avoid using a tsx file in utils + } + Modal.createTrackedDialog('Error Leaving Room', '', ErrorDialog, { + title: _t("Error leaving room"), + description: messages, + }); + return; + } + + if (!isMetaSpace(SpaceStore.instance.activeSpace) && + SpaceStore.instance.activeSpace !== roomId && + RoomViewStore.instance.getRoomId() === roomId + ) { + dis.dispatch({ + action: Action.ViewRoom, + room_id: SpaceStore.instance.activeSpace, + metricsTrigger: undefined, // other + }); + } else { + dis.dispatch({ action: Action.ViewHomePage }); + } +} + +export const leaveSpace = (space: Room) => { + Modal.createTrackedDialog("Leave Space", "", LeaveSpaceDialog, { + space, + onFinished: async (leave: boolean, rooms: Room[]) => { + if (!leave) return; + await bulkSpaceBehaviour(space, rooms, room => leaveRoomBehaviour(room.roomId)); + + dis.dispatch({ + action: Action.AfterLeaveRoom, + room_id: space.roomId, + }); + }, + }, "mx_LeaveSpaceDialog_wrapper"); +}; diff --git a/src/utils/membership.ts b/src/utils/membership.ts index 93cf0fc981..394db19cc9 100644 --- a/src/utils/membership.ts +++ b/src/utils/membership.ts @@ -1,5 +1,5 @@ /* -Copyright 2020 The Matrix.org Foundation C.I.C. +Copyright 2020 - 2022 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,22 +15,6 @@ limitations under the License. */ import { Room } from "matrix-js-sdk/src/models/room"; -import { sleep } from "matrix-js-sdk/src/utils"; -import { EventStatus, MatrixEventEvent } from "matrix-js-sdk/src/models/event"; -import React from "react"; - -import { MatrixClientPeg } from "../MatrixClientPeg"; -import { _t } from "../languageHandler"; -import Modal, { IHandle } from "../Modal"; -import ErrorDialog from "../components/views/dialogs/ErrorDialog"; -import dis from "../dispatcher/dispatcher"; -import { RoomViewStore } from "../stores/RoomViewStore"; -import Spinner from "../components/views/elements/Spinner"; -import { isMetaSpace } from "../stores/spaces"; -import SpaceStore from "../stores/spaces/SpaceStore"; -import { Action } from "../dispatcher/actions"; -import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload"; -import { ViewHomePagePayload } from "../dispatcher/payloads/ViewHomePagePayload"; /** * Approximation of a membership status for a given room. @@ -91,109 +75,3 @@ export function isJoinedOrNearlyJoined(membership: string): boolean { const effective = getEffectiveMembership(membership); return effective === EffectiveMembership.Join || effective === EffectiveMembership.Invite; } - -export async function leaveRoomBehaviour(roomId: string, retry = true, spinner = true) { - let spinnerModal: IHandle; - if (spinner) { - spinnerModal = Modal.createDialog(Spinner, null, 'mx_Dialog_spinner'); - } - - const cli = MatrixClientPeg.get(); - let leavingAllVersions = true; - const history = cli.getRoomUpgradeHistory(roomId); - if (history && history.length > 0) { - const currentRoom = history[history.length - 1]; - if (currentRoom.roomId !== roomId) { - // The user is trying to leave an older version of the room. Let them through - // without making them leave the current version of the room. - leavingAllVersions = false; - } - } - - const room = cli.getRoom(roomId); - // await any queued messages being sent so that they do not fail - await Promise.all(room.getPendingEvents().filter(ev => { - return [EventStatus.QUEUED, EventStatus.ENCRYPTING, EventStatus.SENDING].includes(ev.status); - }).map(ev => new Promise((resolve, reject) => { - const handler = () => { - if (ev.status === EventStatus.NOT_SENT) { - spinnerModal?.close(); - reject(ev.error); - } - - if (!ev.status || ev.status === EventStatus.SENT) { - ev.off(MatrixEventEvent.Status, handler); - resolve(); - } - }; - - ev.on(MatrixEventEvent.Status, handler); - }))); - - let results: { [roomId: string]: Error & { errcode?: string, message: string, data?: Record } } = {}; - if (!leavingAllVersions) { - try { - await cli.leave(roomId); - } catch (e) { - if (e?.data?.errcode) { - const message = e.data.error || _t("Unexpected server error trying to leave the room"); - results[roomId] = Object.assign(new Error(message), { errcode: e.data.errcode, data: e.data }); - } else { - results[roomId] = e || new Error("Failed to leave room for unknown causes"); - } - } - } else { - results = await cli.leaveRoomChain(roomId, retry); - } - - if (retry) { - const limitExceededError = Object.values(results).find(e => e?.errcode === "M_LIMIT_EXCEEDED"); - if (limitExceededError) { - await sleep(limitExceededError.data.retry_after_ms ?? 100); - return leaveRoomBehaviour(roomId, false, false); - } - } - - spinnerModal?.close(); - - const errors = Object.entries(results).filter(r => !!r[1]); - if (errors.length > 0) { - const messages = []; - for (const roomErr of errors) { - const err = roomErr[1]; // [0] is the roomId - let message = _t("Unexpected server error trying to leave the room"); - if (err.errcode && err.message) { - if (err.errcode === 'M_CANNOT_LEAVE_SERVER_NOTICE_ROOM') { - Modal.createTrackedDialog('Error Leaving Room', '', ErrorDialog, { - title: _t("Can't leave Server Notices room"), - description: _t( - "This room is used for important messages from the Homeserver, " + - "so you cannot leave it.", - ), - }); - return; - } - message = results[roomId].message; - } - messages.push(message, React.createElement('BR')); // createElement to avoid using a tsx file in utils - } - Modal.createTrackedDialog('Error Leaving Room', '', ErrorDialog, { - title: _t("Error leaving room"), - description: messages, - }); - return; - } - - if (!isMetaSpace(SpaceStore.instance.activeSpace) && - SpaceStore.instance.activeSpace !== roomId && - RoomViewStore.instance.getRoomId() === roomId - ) { - dis.dispatch({ - action: Action.ViewRoom, - room_id: SpaceStore.instance.activeSpace, - metricsTrigger: undefined, // other - }); - } else { - dis.dispatch({ action: Action.ViewHomePage }); - } -} diff --git a/src/utils/space.tsx b/src/utils/space.tsx index e2b05c8ddf..8fb737440f 100644 --- a/src/utils/space.tsx +++ b/src/utils/space.tsx @@ -32,16 +32,12 @@ import { showRoomInviteDialog } from "../RoomInvite"; import CreateSubspaceDialog from "../components/views/dialogs/CreateSubspaceDialog"; import AddExistingSubspaceDialog from "../components/views/dialogs/AddExistingSubspaceDialog"; import defaultDispatcher from "../dispatcher/dispatcher"; -import dis from "../dispatcher/dispatcher"; import { RoomViewStore } from "../stores/RoomViewStore"; import { Action } from "../dispatcher/actions"; -import { leaveRoomBehaviour } from "./membership"; import Spinner from "../components/views/elements/Spinner"; -import LeaveSpaceDialog from "../components/views/dialogs/LeaveSpaceDialog"; import SpacePreferencesDialog, { SpacePreferenceTab } from "../components/views/dialogs/SpacePreferencesDialog"; import PosthogTrackers from "../PosthogTrackers"; import { ButtonEvent } from "../components/views/elements/AccessibleButton"; -import { AfterLeaveRoomPayload } from "../dispatcher/payloads/AfterLeaveRoomPayload"; import { shouldShowComponent } from "../customisations/helpers/UIComponents"; import { UIComponent } from "../settings/UIFeature"; @@ -185,21 +181,6 @@ export const bulkSpaceBehaviour = async ( } }; -export const leaveSpace = (space: Room) => { - Modal.createTrackedDialog("Leave Space", "", LeaveSpaceDialog, { - space, - onFinished: async (leave: boolean, rooms: Room[]) => { - if (!leave) return; - await bulkSpaceBehaviour(space, rooms, room => leaveRoomBehaviour(room.roomId)); - - dis.dispatch({ - action: Action.AfterLeaveRoom, - room_id: space.roomId, - }); - }, - }, "mx_LeaveSpaceDialog_wrapper"); -}; - export const showSpacePreferences = (space: Room, initialTabId?: SpacePreferenceTab): Promise => { return Modal.createTrackedDialog("Space preferences", "", SpacePreferencesDialog, { initialTabId, diff --git a/test/components/views/context_menus/SpaceContextMenu-test.tsx b/test/components/views/context_menus/SpaceContextMenu-test.tsx index 5288c57ec6..53b762ef86 100644 --- a/test/components/views/context_menus/SpaceContextMenu-test.tsx +++ b/test/components/views/context_menus/SpaceContextMenu-test.tsx @@ -24,13 +24,13 @@ import SpaceContextMenu from '../../../../src/components/views/context_menus/Spa import MatrixClientContext from '../../../../src/contexts/MatrixClientContext'; import { findByTestId } from '../../../test-utils'; import { - leaveSpace, shouldShowSpaceSettings, showCreateNewRoom, showCreateNewSubspace, showSpaceInvite, showSpaceSettings, } from '../../../../src/utils/space'; +import { leaveSpace } from "../../../../src/utils/leave-behaviour"; import { shouldShowComponent } from '../../../../src/customisations/helpers/UIComponents'; import { UIComponent } from '../../../../src/settings/UIFeature'; @@ -39,7 +39,6 @@ jest.mock('../../../../src/customisations/helpers/UIComponents', () => ({ })); jest.mock('../../../../src/utils/space', () => ({ - leaveSpace: jest.fn(), shouldShowSpaceSettings: jest.fn(), showCreateNewRoom: jest.fn(), showCreateNewSubspace: jest.fn(), @@ -48,6 +47,10 @@ jest.mock('../../../../src/utils/space', () => ({ showSpaceSettings: jest.fn(), })); +jest.mock('../../../../src/utils/leave-behaviour', () => ({ + leaveSpace: jest.fn(), +})); + describe('', () => { const userId = '@test:server'; const mockClient = { From 211e00539a51df7573291104ee989c8ddabf4567 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 15:26:09 -0600 Subject: [PATCH 18/47] Step 8.5: Move call event type --- src/CallHandler.tsx | 3 --- src/VoipUserMapper.ts | 3 ++- src/call-types.ts | 19 +++++++++++++++++++ src/createRoom.ts | 2 +- 4 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 src/call-types.ts diff --git a/src/CallHandler.tsx b/src/CallHandler.tsx index dc2d60db0e..b4e8ae75e6 100644 --- a/src/CallHandler.tsx +++ b/src/CallHandler.tsx @@ -67,9 +67,6 @@ export const PROTOCOL_SIP_NATIVE = 'im.vector.protocol.sip_native'; export const PROTOCOL_SIP_VIRTUAL = 'im.vector.protocol.sip_virtual'; const CHECK_PROTOCOLS_ATTEMPTS = 3; -// Event type for room account data and room creation content used to mark rooms as virtual rooms -// (and store the ID of their native room) -export const VIRTUAL_ROOM_EVENT_TYPE = 'im.vector.is_virtual_room'; enum AudioID { Ring = 'ringAudio', diff --git a/src/VoipUserMapper.ts b/src/VoipUserMapper.ts index cb39d9affb..90f920bc9b 100644 --- a/src/VoipUserMapper.ts +++ b/src/VoipUserMapper.ts @@ -21,7 +21,8 @@ import { EventType } from 'matrix-js-sdk/src/@types/event'; import { ensureVirtualRoomExists, findDMForUser } from './createRoom'; import { MatrixClientPeg } from "./MatrixClientPeg"; import DMRoomMap from "./utils/DMRoomMap"; -import CallHandler, { VIRTUAL_ROOM_EVENT_TYPE } from './CallHandler'; +import CallHandler from './CallHandler'; +import { VIRTUAL_ROOM_EVENT_TYPE } from "./call-types"; // Functions for mapping virtual users & rooms. Currently the only lookup // is sip virtual: there could be others in the future. diff --git a/src/call-types.ts b/src/call-types.ts new file mode 100644 index 0000000000..c12491e102 --- /dev/null +++ b/src/call-types.ts @@ -0,0 +1,19 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Event type for room account data and room creation content used to mark rooms as virtual rooms +// (and store the ID of their native room) +export const VIRTUAL_ROOM_EVENT_TYPE = 'im.vector.is_virtual_room'; diff --git a/src/createRoom.ts b/src/createRoom.ts index 91eb1b45e9..92efb9477d 100644 --- a/src/createRoom.ts +++ b/src/createRoom.ts @@ -39,7 +39,7 @@ import DMRoomMap from "./utils/DMRoomMap"; import { getAddressType } from "./UserAddress"; import { getE2EEWellKnown } from "./utils/WellKnownUtils"; import { isJoinedOrNearlyJoined } from "./utils/membership"; -import { VIRTUAL_ROOM_EVENT_TYPE } from "./CallHandler"; +import { VIRTUAL_ROOM_EVENT_TYPE } from "./call-types"; import SpaceStore from "./stores/spaces/SpaceStore"; import { makeSpaceParentEvent } from "./utils/space"; import { VOICE_CHANNEL_MEMBER, addVoiceChannel } from "./utils/VoiceChannelUtils"; From 888d470c569245c8c79a31fe0f33c05ff639aba9 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 15:32:22 -0600 Subject: [PATCH 19/47] Step 8.5: Move various room utilities out of `createRoom` --- src/CallHandler.tsx | 3 +- src/VoipUserMapper.ts | 3 +- .../views/dialogs/CreateRoomDialog.tsx | 3 +- src/components/views/dialogs/InviteDialog.tsx | 8 +-- src/components/views/right_panel/UserInfo.tsx | 4 +- src/components/views/rooms/NewRoomIntro.tsx | 2 +- .../tabs/user/SecurityUserSettingsTab.tsx | 2 +- src/createRoom.ts | 66 +------------------ src/utils/direct-messages.ts | 46 +++++++++++++ src/utils/membership.ts | 27 ++++++++ src/utils/rooms.ts | 26 ++++++++ src/verification.ts | 2 +- test/createRoom-test.js | 43 +----------- test/utils/membership-test.ts | 58 ++++++++++++++++ 14 files changed, 176 insertions(+), 117 deletions(-) create mode 100644 src/utils/direct-messages.ts create mode 100644 src/utils/rooms.ts create mode 100644 test/utils/membership-test.ts diff --git a/src/CallHandler.tsx b/src/CallHandler.tsx index b4e8ae75e6..a8082e668b 100644 --- a/src/CallHandler.tsx +++ b/src/CallHandler.tsx @@ -54,12 +54,13 @@ import { Action } from './dispatcher/actions'; import VoipUserMapper from './VoipUserMapper'; import { addManagedHybridWidget, isManagedHybridWidgetEnabled } from './widgets/ManagedHybrid'; import SdkConfig from './SdkConfig'; -import { ensureDMExists, findDMForUser } from './createRoom'; +import { ensureDMExists } from './createRoom'; import { Container, WidgetLayoutStore } from './stores/widgets/WidgetLayoutStore'; import IncomingCallToast, { getIncomingCallToastKey } from './toasts/IncomingCallToast'; import ToastStore from './stores/ToastStore'; import Resend from './Resend'; import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload"; +import { findDMForUser } from "./utils/direct-messages"; export const PROTOCOL_PSTN = 'm.protocol.pstn'; export const PROTOCOL_PSTN_PREFIXED = 'im.vector.protocol.pstn'; diff --git a/src/VoipUserMapper.ts b/src/VoipUserMapper.ts index 90f920bc9b..f7026da394 100644 --- a/src/VoipUserMapper.ts +++ b/src/VoipUserMapper.ts @@ -18,11 +18,12 @@ import { Room } from 'matrix-js-sdk/src/models/room'; import { logger } from "matrix-js-sdk/src/logger"; import { EventType } from 'matrix-js-sdk/src/@types/event'; -import { ensureVirtualRoomExists, findDMForUser } from './createRoom'; +import { ensureVirtualRoomExists } from './createRoom'; import { MatrixClientPeg } from "./MatrixClientPeg"; import DMRoomMap from "./utils/DMRoomMap"; import CallHandler from './CallHandler'; import { VIRTUAL_ROOM_EVENT_TYPE } from "./call-types"; +import { findDMForUser } from "./utils/direct-messages"; // Functions for mapping virtual users & rooms. Currently the only lookup // is sip virtual: there could be others in the future. diff --git a/src/components/views/dialogs/CreateRoomDialog.tsx b/src/components/views/dialogs/CreateRoomDialog.tsx index da6d0212f3..fdf916d6a4 100644 --- a/src/components/views/dialogs/CreateRoomDialog.tsx +++ b/src/components/views/dialogs/CreateRoomDialog.tsx @@ -25,7 +25,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import withValidation, { IFieldState } from '../elements/Validation'; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; -import { IOpts, privateShouldBeEncrypted } from "../../../createRoom"; +import { IOpts } from "../../../createRoom"; import Heading from "../typography/Heading"; import Field from "../elements/Field"; import StyledRadioGroup from "../elements/StyledRadioGroup"; @@ -37,6 +37,7 @@ import SpaceStore from "../../../stores/spaces/SpaceStore"; import JoinRuleDropdown from "../elements/JoinRuleDropdown"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; +import { privateShouldBeEncrypted } from "../../../utils/rooms"; interface IProps { defaultPublic?: boolean; diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index cf58a372ba..23a8549343 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -34,11 +34,7 @@ import dis from "../../../dispatcher/dispatcher"; import IdentityAuthClient from "../../../IdentityAuthClient"; import Modal from "../../../Modal"; import { humanizeTime } from "../../../utils/humanize"; -import createRoom, { - canEncryptToAllUsers, - findDMForUser, - privateShouldBeEncrypted, -} from "../../../createRoom"; +import createRoom, { canEncryptToAllUsers } from "../../../createRoom"; import { IInviteResult, inviteMultipleToRoom, @@ -68,6 +64,8 @@ import { ScreenName } from '../../../PosthogTrackers'; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; +import { privateShouldBeEncrypted } from "../../../utils/rooms"; +import { findDMForUser } from "../../../utils/direct-messages"; // we have a number of types defined from the Matrix spec which can't reasonably be altered here. /* eslint-disable camelcase */ diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 263a64c609..01da603300 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -33,7 +33,7 @@ import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import dis from '../../../dispatcher/dispatcher'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; -import createRoom, { findDMForUser, privateShouldBeEncrypted } from '../../../createRoom'; +import createRoom from '../../../createRoom'; import DMRoomMap from '../../../utils/DMRoomMap'; import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton'; import SdkConfig from '../../../SdkConfig'; @@ -79,6 +79,8 @@ import { useUserStatusMessage } from "../../../hooks/useUserStatusMessage"; import UserIdentifierCustomisations from '../../../customisations/UserIdentifier'; import PosthogTrackers from "../../../PosthogTrackers"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; +import { findDMForUser } from "../../../utils/direct-messages"; +import { privateShouldBeEncrypted } from "../../../utils/rooms"; export interface IDevice { deviceId: string; diff --git a/src/components/views/rooms/NewRoomIntro.tsx b/src/components/views/rooms/NewRoomIntro.tsx index 667145d0a9..363e687c9f 100644 --- a/src/components/views/rooms/NewRoomIntro.tsx +++ b/src/components/views/rooms/NewRoomIntro.tsx @@ -33,12 +33,12 @@ import { ViewUserPayload } from "../../../dispatcher/payloads/ViewUserPayload"; import { Action } from "../../../dispatcher/actions"; import SpaceStore from "../../../stores/spaces/SpaceStore"; import { showSpaceInvite } from "../../../utils/space"; -import { privateShouldBeEncrypted } from "../../../createRoom"; import EventTileBubble from "../messages/EventTileBubble"; import { ROOM_SECURITY_TAB } from "../dialogs/RoomSettingsDialog"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { shouldShowComponent } from "../../../customisations/helpers/UIComponents"; import { UIComponent } from "../../../settings/UIFeature"; +import { privateShouldBeEncrypted } from "../../../utils/rooms"; function hasExpectedEncryptionSettings(matrixClient: MatrixClient, room: Room): boolean { const isEncrypted: boolean = matrixClient.isRoomEncrypted(room.roomId); diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx index a88e244fe5..e577cd873f 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx @@ -24,7 +24,6 @@ import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import AccessibleButton from "../../../elements/AccessibleButton"; import Analytics from "../../../../../Analytics"; import dis from "../../../../../dispatcher/dispatcher"; -import { privateShouldBeEncrypted } from "../../../../../createRoom"; import { SettingLevel } from "../../../../../settings/SettingLevel"; import SecureBackupPanel from "../../SecureBackupPanel"; import SettingsStore from "../../../../../settings/SettingsStore"; @@ -39,6 +38,7 @@ import EventIndexPanel from "../../EventIndexPanel"; import InlineSpinner from "../../../elements/InlineSpinner"; import { PosthogAnalytics } from "../../../../../PosthogAnalytics"; import { showDialog as showAnalyticsLearnMoreDialog } from "../../../dialogs/AnalyticsLearnMoreDialog"; +import { privateShouldBeEncrypted } from "../../../../../utils/rooms"; interface IIgnoredUserProps { userId: string; diff --git a/src/createRoom.ts b/src/createRoom.ts index 92efb9477d..30f495e3bd 100644 --- a/src/createRoom.ts +++ b/src/createRoom.ts @@ -17,7 +17,6 @@ limitations under the License. import { MatrixClient } from "matrix-js-sdk/src/client"; import { Room } from "matrix-js-sdk/src/models/room"; -import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { EventType, RoomCreateTypeField, RoomType } from "matrix-js-sdk/src/@types/event"; import { ICreateRoomOpts } from "matrix-js-sdk/src/@types/requests"; import { @@ -28,17 +27,13 @@ import { Visibility, } from "matrix-js-sdk/src/@types/partials"; import { logger } from "matrix-js-sdk/src/logger"; -import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { MatrixClientPeg } from './MatrixClientPeg'; import Modal from './Modal'; import { _t } from './languageHandler'; import dis from "./dispatcher/dispatcher"; import * as Rooms from "./Rooms"; -import DMRoomMap from "./utils/DMRoomMap"; import { getAddressType } from "./UserAddress"; -import { getE2EEWellKnown } from "./utils/WellKnownUtils"; -import { isJoinedOrNearlyJoined } from "./utils/membership"; import { VIRTUAL_ROOM_EVENT_TYPE } from "./call-types"; import SpaceStore from "./stores/spaces/SpaceStore"; import { makeSpaceParentEvent } from "./utils/space"; @@ -47,6 +42,9 @@ import { Action } from "./dispatcher/actions"; import ErrorDialog from "./components/views/dialogs/ErrorDialog"; import Spinner from "./components/views/elements/Spinner"; import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload"; +import { findDMForUser } from "./utils/direct-messages"; +import { privateShouldBeEncrypted } from "./utils/rooms"; +import { waitForMember } from "./utils/membership"; // we define a number of interfaces which take their names from the js-sdk /* eslint-disable camelcase */ @@ -313,55 +311,6 @@ export default async function createRoom(opts: IOpts): Promise { }); } -export function findDMForUser(client: MatrixClient, userId: string): Room { - const roomIds = DMRoomMap.shared().getDMRoomsForUserId(userId); - const rooms = roomIds.map(id => client.getRoom(id)); - const suitableDMRooms = rooms.filter(r => { - // Validate that we are joined and the other person is also joined. We'll also make sure - // that the room also looks like a DM (until we have canonical DMs to tell us). For now, - // a DM is a room of two people that contains those two people exactly. This does mean - // that bots, assistants, etc will ruin a room's DM-ness, though this is a problem for - // canonical DMs to solve. - if (r && r.getMyMembership() === "join") { - const members = r.currentState.getMembers(); - const joinedMembers = members.filter(m => isJoinedOrNearlyJoined(m.membership)); - const otherMember = joinedMembers.find(m => m.userId === userId); - return otherMember && joinedMembers.length === 2; - } - return false; - }).sort((r1, r2) => { - return r2.getLastActiveTimestamp() - - r1.getLastActiveTimestamp(); - }); - if (suitableDMRooms.length) { - return suitableDMRooms[0]; - } -} - -/* - * Try to ensure the user is already in the megolm session before continuing - * NOTE: this assumes you've just created the room and there's not been an opportunity - * for other code to run, so we shouldn't miss RoomState.newMember when it comes by. - */ -export async function waitForMember(client: MatrixClient, roomId: string, userId: string, opts = { timeout: 1500 }) { - const { timeout } = opts; - let handler; - return new Promise((resolve) => { - handler = function(_, __, member: RoomMember) { // eslint-disable-line @typescript-eslint/naming-convention - if (member.userId !== userId) return; - if (member.roomId !== roomId) return; - resolve(true); - }; - client.on(RoomStateEvent.NewMember, handler); - - /* We don't want to hang if this goes wrong, so we proceed and hope the other - user is already in the megolm session */ - setTimeout(resolve, timeout, false); - }).finally(() => { - client.removeListener(RoomStateEvent.NewMember, handler); - }); -} - /* * Ensure that for every user in a room, there is at least one device that we * can encrypt to. @@ -424,12 +373,3 @@ export async function ensureDMExists(client: MatrixClient, userId: string): Prom } return roomId; } - -export function privateShouldBeEncrypted(): boolean { - const e2eeWellKnown = getE2EEWellKnown(); - if (e2eeWellKnown) { - const defaultDisabled = e2eeWellKnown["default"] === false; - return !defaultDisabled; - } - return true; -} diff --git a/src/utils/direct-messages.ts b/src/utils/direct-messages.ts new file mode 100644 index 0000000000..6d187b8b7a --- /dev/null +++ b/src/utils/direct-messages.ts @@ -0,0 +1,46 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { Room } from "matrix-js-sdk/src/models/room"; + +import DMRoomMap from "./DMRoomMap"; +import { isJoinedOrNearlyJoined } from "./membership"; + +export function findDMForUser(client: MatrixClient, userId: string): Room { + const roomIds = DMRoomMap.shared().getDMRoomsForUserId(userId); + const rooms = roomIds.map(id => client.getRoom(id)); + const suitableDMRooms = rooms.filter(r => { + // Validate that we are joined and the other person is also joined. We'll also make sure + // that the room also looks like a DM (until we have canonical DMs to tell us). For now, + // a DM is a room of two people that contains those two people exactly. This does mean + // that bots, assistants, etc will ruin a room's DM-ness, though this is a problem for + // canonical DMs to solve. + if (r && r.getMyMembership() === "join") { + const members = r.currentState.getMembers(); + const joinedMembers = members.filter(m => isJoinedOrNearlyJoined(m.membership)); + const otherMember = joinedMembers.find(m => m.userId === userId); + return otherMember && joinedMembers.length === 2; + } + return false; + }).sort((r1, r2) => { + return r2.getLastActiveTimestamp() - + r1.getLastActiveTimestamp(); + }); + if (suitableDMRooms.length) { + return suitableDMRooms[0]; + } +} diff --git a/src/utils/membership.ts b/src/utils/membership.ts index 394db19cc9..1a48f1261c 100644 --- a/src/utils/membership.ts +++ b/src/utils/membership.ts @@ -15,6 +15,9 @@ limitations under the License. */ import { Room } from "matrix-js-sdk/src/models/room"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { RoomMember } from "matrix-js-sdk/src/models/room-member"; +import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; /** * Approximation of a membership status for a given room. @@ -75,3 +78,27 @@ export function isJoinedOrNearlyJoined(membership: string): boolean { const effective = getEffectiveMembership(membership); return effective === EffectiveMembership.Join || effective === EffectiveMembership.Invite; } + +/** + * Try to ensure the user is already in the megolm session before continuing + * NOTE: this assumes you've just created the room and there's not been an opportunity + * for other code to run, so we shouldn't miss RoomState.newMember when it comes by. + */ +export async function waitForMember(client: MatrixClient, roomId: string, userId: string, opts = { timeout: 1500 }) { + const { timeout } = opts; + let handler; + return new Promise((resolve) => { + handler = function(_, __, member: RoomMember) { // eslint-disable-line @typescript-eslint/naming-convention + if (member.userId !== userId) return; + if (member.roomId !== roomId) return; + resolve(true); + }; + client.on(RoomStateEvent.NewMember, handler); + + /* We don't want to hang if this goes wrong, so we proceed and hope the other + user is already in the megolm session */ + setTimeout(resolve, timeout, false); + }).finally(() => { + client.removeListener(RoomStateEvent.NewMember, handler); + }); +} diff --git a/src/utils/rooms.ts b/src/utils/rooms.ts new file mode 100644 index 0000000000..bd6fcf9d97 --- /dev/null +++ b/src/utils/rooms.ts @@ -0,0 +1,26 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { getE2EEWellKnown } from "./WellKnownUtils"; + +export function privateShouldBeEncrypted(): boolean { + const e2eeWellKnown = getE2EEWellKnown(); + if (e2eeWellKnown) { + const defaultDisabled = e2eeWellKnown["default"] === false; + return !defaultDisabled; + } + return true; +} diff --git a/src/verification.ts b/src/verification.ts index 5b3d72cb00..197ae051dd 100644 --- a/src/verification.ts +++ b/src/verification.ts @@ -22,13 +22,13 @@ import { MatrixClientPeg } from './MatrixClientPeg'; import dis from "./dispatcher/dispatcher"; import Modal from './Modal'; import { RightPanelPhases } from "./stores/right-panel/RightPanelStorePhases"; -import { findDMForUser } from './createRoom'; import { accessSecretStorage } from './SecurityManager'; import UntrustedDeviceDialog from "./components/views/dialogs/UntrustedDeviceDialog"; import { IDevice } from "./components/views/right_panel/UserInfo"; import ManualDeviceKeyVerificationDialog from "./components/views/dialogs/ManualDeviceKeyVerificationDialog"; import RightPanelStore from "./stores/right-panel/RightPanelStore"; import { IRightPanelCardState } from "./stores/right-panel/RightPanelStoreIPanelState"; +import { findDMForUser } from "./utils/direct-messages"; async function enable4SIfNeeded() { const cli = MatrixClientPeg.get(); diff --git a/test/createRoom-test.js b/test/createRoom-test.js index 84eaabdafc..05cc2ebb1a 100644 --- a/test/createRoom-test.js +++ b/test/createRoom-test.js @@ -1,45 +1,4 @@ -import { EventEmitter } from 'events'; - -import { waitForMember, canEncryptToAllUsers } from '../src/createRoom'; - -/* Shorter timeout, we've got tests to run */ -const timeout = 30; - -describe("waitForMember", () => { - let client; - - beforeEach(() => { - client = new EventEmitter(); - }); - - it("resolves with false if the timeout is reached", (done) => { - waitForMember(client, "", "", { timeout: 0 }).then((r) => { - expect(r).toBe(false); - done(); - }); - }); - - it("resolves with false if the timeout is reached, even if other RoomState.newMember events fire", (done) => { - const roomId = "!roomId:domain"; - const userId = "@clientId:domain"; - waitForMember(client, roomId, userId, { timeout }).then((r) => { - expect(r).toBe(false); - done(); - }); - client.emit("RoomState.newMember", undefined, undefined, { roomId, userId: "@anotherClient:domain" }); - }); - - it("resolves with true if RoomState.newMember fires", (done) => { - const roomId = "!roomId:domain"; - const userId = "@clientId:domain"; - waitForMember(client, roomId, userId, { timeout }).then((r) => { - expect(r).toBe(true); - expect(client.listeners("RoomState.newMember").length).toBe(0); - done(); - }); - client.emit("RoomState.newMember", undefined, undefined, { roomId, userId }); - }); -}); +import { canEncryptToAllUsers } from '../src/createRoom'; describe("canEncryptToAllUsers", () => { const trueUser = { diff --git a/test/utils/membership-test.ts b/test/utils/membership-test.ts new file mode 100644 index 0000000000..84fa13580c --- /dev/null +++ b/test/utils/membership-test.ts @@ -0,0 +1,58 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { EventEmitter } from "events"; + +import { waitForMember } from "../../src/utils/membership"; + +/* Shorter timeout, we've got tests to run */ +const timeout = 30; + +describe("waitForMember", () => { + let client; + + beforeEach(() => { + client = new EventEmitter(); + }); + + it("resolves with false if the timeout is reached", (done) => { + waitForMember(client, "", "", { timeout: 0 }).then((r) => { + expect(r).toBe(false); + done(); + }); + }); + + it("resolves with false if the timeout is reached, even if other RoomState.newMember events fire", (done) => { + const roomId = "!roomId:domain"; + const userId = "@clientId:domain"; + waitForMember(client, roomId, userId, { timeout }).then((r) => { + expect(r).toBe(false); + done(); + }); + client.emit("RoomState.newMember", undefined, undefined, { roomId, userId: "@anotherClient:domain" }); + }); + + it("resolves with true if RoomState.newMember fires", (done) => { + const roomId = "!roomId:domain"; + const userId = "@clientId:domain"; + waitForMember(client, roomId, userId, { timeout }).then((r) => { + expect(r).toBe(true); + expect(client.listeners("RoomState.newMember").length).toBe(0); + done(); + }); + client.emit("RoomState.newMember", undefined, undefined, { roomId, userId }); + }); +}); From fe032ed9423fe4182ddee258b53cb0d08dffda28 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 15:13:11 -0600 Subject: [PATCH 20/47] Step 8.5: Move specific image utilities out of ContentMessages --- src/ContentMessages.ts | 106 +-------------- src/components/views/messages/MImageBody.tsx | 2 +- .../views/messages/MStickerBody.tsx | 2 +- src/components/views/messages/MVideoBody.tsx | 2 +- src/utils/image-media.ts | 121 ++++++++++++++++++ 5 files changed, 125 insertions(+), 108 deletions(-) create mode 100644 src/utils/image-media.ts diff --git a/src/ContentMessages.ts b/src/ContentMessages.ts index 7dc5b7f4a8..884943608f 100644 --- a/src/ContentMessages.ts +++ b/src/ContentMessages.ts @@ -40,7 +40,6 @@ import { UploadStartedPayload, } from "./dispatcher/payloads/UploadPayload"; import { IUpload } from "./models/IUpload"; -import { BlurhashEncoder } from "./BlurhashEncoder"; import SettingsStore from "./settings/SettingsStore"; import { decorateStartSendingTime, sendRoundTripMetric } from "./sendTimePerformanceMetrics"; import { TimelineRenderingType } from "./contexts/RoomContext"; @@ -49,20 +48,14 @@ import { addReplyToMessageContent } from "./utils/Reply"; import ErrorDialog from "./components/views/dialogs/ErrorDialog"; import UploadFailureDialog from "./components/views/dialogs/UploadFailureDialog"; import UploadConfirmDialog from "./components/views/dialogs/UploadConfirmDialog"; - -const MAX_WIDTH = 800; -const MAX_HEIGHT = 600; +import { createThumbnail } from "./utils/image-media"; // scraped out of a macOS hidpi (5660ppm) screenshot png // 5669 px (x-axis) , 5669 px (y-axis) , per metre const PHYS_HIDPI = [0x00, 0x00, 0x16, 0x25, 0x00, 0x00, 0x16, 0x25, 0x01]; -export const BLURHASH_FIELD = "xyz.amorgan.blurhash"; // MSC2448 - export class UploadCanceledError extends Error {} -type ThumbnailableElement = HTMLImageElement | HTMLVideoElement; - interface IMediaConfig { "m.upload.size"?: number; } @@ -78,103 +71,6 @@ interface IContent { url?: string; } -interface IThumbnail { - info: { - // eslint-disable-next-line camelcase - thumbnail_info: { - w: number; - h: number; - mimetype: string; - size: number; - }; - w: number; - h: number; - [BLURHASH_FIELD]: string; - }; - thumbnail: Blob; -} - -/** - * Create a thumbnail for a image DOM element. - * The image will be smaller than MAX_WIDTH and MAX_HEIGHT. - * The thumbnail will have the same aspect ratio as the original. - * Draws the element into a canvas using CanvasRenderingContext2D.drawImage - * Then calls Canvas.toBlob to get a blob object for the image data. - * - * Since it needs to calculate the dimensions of the source image and the - * thumbnailed image it returns an info object filled out with information - * about the original image and the thumbnail. - * - * @param {HTMLElement} element The element to thumbnail. - * @param {number} inputWidth The width of the image in the input element. - * @param {number} inputHeight the width of the image in the input element. - * @param {string} mimeType The mimeType to save the blob as. - * @param {boolean} calculateBlurhash Whether to calculate a blurhash of the given image too. - * @return {Promise} A promise that resolves with an object with an info key - * and a thumbnail key. - */ -export async function createThumbnail( - element: ThumbnailableElement, - inputWidth: number, - inputHeight: number, - mimeType: string, - calculateBlurhash = true, -): Promise { - let targetWidth = inputWidth; - let targetHeight = inputHeight; - if (targetHeight > MAX_HEIGHT) { - targetWidth = Math.floor(targetWidth * (MAX_HEIGHT / targetHeight)); - targetHeight = MAX_HEIGHT; - } - if (targetWidth > MAX_WIDTH) { - targetHeight = Math.floor(targetHeight * (MAX_WIDTH / targetWidth)); - targetWidth = MAX_WIDTH; - } - - let canvas: HTMLCanvasElement | OffscreenCanvas; - let context: CanvasRenderingContext2D; - try { - canvas = new window.OffscreenCanvas(targetWidth, targetHeight); - context = canvas.getContext("2d"); - } catch (e) { - // Fallback support for other browsers (Safari and Firefox for now) - canvas = document.createElement("canvas"); - (canvas as HTMLCanvasElement).width = targetWidth; - (canvas as HTMLCanvasElement).height = targetHeight; - context = canvas.getContext("2d"); - } - - context.drawImage(element, 0, 0, targetWidth, targetHeight); - - let thumbnailPromise: Promise; - - if (window.OffscreenCanvas) { - thumbnailPromise = (canvas as OffscreenCanvas).convertToBlob({ type: mimeType }); - } else { - thumbnailPromise = new Promise(resolve => (canvas as HTMLCanvasElement).toBlob(resolve, mimeType)); - } - - const imageData = context.getImageData(0, 0, targetWidth, targetHeight); - // thumbnailPromise and blurhash promise are being awaited concurrently - const blurhash = calculateBlurhash ? await BlurhashEncoder.instance.getBlurhash(imageData) : undefined; - const thumbnail = await thumbnailPromise; - - return { - info: { - thumbnail_info: { - w: targetWidth, - h: targetHeight, - mimetype: thumbnail.type, - size: thumbnail.size, - }, - w: inputWidth, - h: inputHeight, - [BLURHASH_FIELD]: blurhash, - }, - thumbnail, - }; -} - /** * Load a file into a newly created image element. * diff --git a/src/components/views/messages/MImageBody.tsx b/src/components/views/messages/MImageBody.tsx index 0f9fe45a29..4ef8e8d497 100644 --- a/src/components/views/messages/MImageBody.tsx +++ b/src/components/views/messages/MImageBody.tsx @@ -29,7 +29,7 @@ import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import Spinner from '../elements/Spinner'; import { Media, mediaFromContent } from "../../../customisations/Media"; -import { BLURHASH_FIELD, createThumbnail } from "../../../ContentMessages"; +import { BLURHASH_FIELD, createThumbnail } from "../../../utils/image-media"; import { IMediaEventContent } from '../../../customisations/models/IMediaEventContent'; import ImageView from '../elements/ImageView'; import { IBodyProps } from "./IBodyProps"; diff --git a/src/components/views/messages/MStickerBody.tsx b/src/components/views/messages/MStickerBody.tsx index c29d4c225b..eb56d8d2e5 100644 --- a/src/components/views/messages/MStickerBody.tsx +++ b/src/components/views/messages/MStickerBody.tsx @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import MImageBody from './MImageBody'; -import { BLURHASH_FIELD } from "../../../ContentMessages"; +import { BLURHASH_FIELD } from "../../../utils/image-media"; import Tooltip from "../elements/Tooltip"; export default class MStickerBody extends MImageBody { diff --git a/src/components/views/messages/MVideoBody.tsx b/src/components/views/messages/MVideoBody.tsx index cacd19c5a8..f4733df19f 100644 --- a/src/components/views/messages/MVideoBody.tsx +++ b/src/components/views/messages/MVideoBody.tsx @@ -22,7 +22,7 @@ import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import InlineSpinner from '../elements/InlineSpinner'; import { mediaFromContent } from "../../../customisations/Media"; -import { BLURHASH_FIELD } from "../../../ContentMessages"; +import { BLURHASH_FIELD } from "../../../utils/image-media"; import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent"; import { IBodyProps } from "./IBodyProps"; import MFileBody from "./MFileBody"; diff --git a/src/utils/image-media.ts b/src/utils/image-media.ts new file mode 100644 index 0000000000..a57e4b841a --- /dev/null +++ b/src/utils/image-media.ts @@ -0,0 +1,121 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { BlurhashEncoder } from "../BlurhashEncoder"; + +type ThumbnailableElement = HTMLImageElement | HTMLVideoElement; + +interface IThumbnail { + info: { + // eslint-disable-next-line camelcase + thumbnail_info: { + w: number; + h: number; + mimetype: string; + size: number; + }; + w: number; + h: number; + [BLURHASH_FIELD]: string; + }; + thumbnail: Blob; +} + +export const BLURHASH_FIELD = "xyz.amorgan.blurhash"; // MSC2448 + +const MAX_WIDTH = 800; +const MAX_HEIGHT = 600; + +/** + * Create a thumbnail for a image DOM element. + * The image will be smaller than MAX_WIDTH and MAX_HEIGHT. + * The thumbnail will have the same aspect ratio as the original. + * Draws the element into a canvas using CanvasRenderingContext2D.drawImage + * Then calls Canvas.toBlob to get a blob object for the image data. + * + * Since it needs to calculate the dimensions of the source image and the + * thumbnailed image it returns an info object filled out with information + * about the original image and the thumbnail. + * + * @param {HTMLElement} element The element to thumbnail. + * @param {number} inputWidth The width of the image in the input element. + * @param {number} inputHeight the width of the image in the input element. + * @param {string} mimeType The mimeType to save the blob as. + * @param {boolean} calculateBlurhash Whether to calculate a blurhash of the given image too. + * @return {Promise} A promise that resolves with an object with an info key + * and a thumbnail key. + */ +export async function createThumbnail( + element: ThumbnailableElement, + inputWidth: number, + inputHeight: number, + mimeType: string, + calculateBlurhash = true, +): Promise { + let targetWidth = inputWidth; + let targetHeight = inputHeight; + if (targetHeight > MAX_HEIGHT) { + targetWidth = Math.floor(targetWidth * (MAX_HEIGHT / targetHeight)); + targetHeight = MAX_HEIGHT; + } + if (targetWidth > MAX_WIDTH) { + targetHeight = Math.floor(targetHeight * (MAX_WIDTH / targetWidth)); + targetWidth = MAX_WIDTH; + } + + let canvas: HTMLCanvasElement | OffscreenCanvas; + let context: CanvasRenderingContext2D; + try { + canvas = new window.OffscreenCanvas(targetWidth, targetHeight); + context = canvas.getContext("2d"); + } catch (e) { + // Fallback support for other browsers (Safari and Firefox for now) + canvas = document.createElement("canvas"); + (canvas as HTMLCanvasElement).width = targetWidth; + (canvas as HTMLCanvasElement).height = targetHeight; + context = canvas.getContext("2d"); + } + + context.drawImage(element, 0, 0, targetWidth, targetHeight); + + let thumbnailPromise: Promise; + + if (window.OffscreenCanvas) { + thumbnailPromise = (canvas as OffscreenCanvas).convertToBlob({ type: mimeType }); + } else { + thumbnailPromise = new Promise(resolve => (canvas as HTMLCanvasElement).toBlob(resolve, mimeType)); + } + + const imageData = context.getImageData(0, 0, targetWidth, targetHeight); + // thumbnailPromise and blurhash promise are being awaited concurrently + const blurhash = calculateBlurhash ? await BlurhashEncoder.instance.getBlurhash(imageData) : undefined; + const thumbnail = await thumbnailPromise; + + return { + info: { + thumbnail_info: { + w: targetWidth, + h: targetHeight, + mimetype: thumbnail.type, + size: thumbnail.size, + }, + w: inputWidth, + h: inputHeight, + [BLURHASH_FIELD]: blurhash, + }, + thumbnail, + }; +} From 66401c844fb78bd969e8f905c8d3d01181512b4c Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 15:35:01 -0600 Subject: [PATCH 21/47] Step 8.5: Move right panel context --- src/components/views/avatars/MemberAvatar.tsx | 2 +- .../views/messages/MessageActionBar.tsx | 2 +- src/components/views/right_panel/BaseCard.tsx | 2 +- src/components/views/right_panel/context.ts | 19 +++++++++++++++++++ src/components/views/rooms/ThreadSummary.tsx | 2 +- 5 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 src/components/views/right_panel/context.ts diff --git a/src/components/views/avatars/MemberAvatar.tsx b/src/components/views/avatars/MemberAvatar.tsx index 5b25f51cd5..c5dd1bfd3c 100644 --- a/src/components/views/avatars/MemberAvatar.tsx +++ b/src/components/views/avatars/MemberAvatar.tsx @@ -24,7 +24,7 @@ import dis from "../../../dispatcher/dispatcher"; import { Action } from "../../../dispatcher/actions"; import BaseAvatar from "./BaseAvatar"; import { mediaFromMxc } from "../../../customisations/Media"; -import { CardContext } from '../right_panel/BaseCard'; +import { CardContext } from '../right_panel/context'; import UserIdentifierCustomisations from '../../../customisations/UserIdentifier'; import SettingsStore from "../../../settings/SettingsStore"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx index 673d664f81..89eb844495 100644 --- a/src/components/views/messages/MessageActionBar.tsx +++ b/src/components/views/messages/MessageActionBar.tsx @@ -38,7 +38,7 @@ import SettingsStore from '../../../settings/SettingsStore'; import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks'; import ReplyChain from '../elements/ReplyChain'; import ReactionPicker from "../emojipicker/ReactionPicker"; -import { CardContext } from '../right_panel/BaseCard'; +import { CardContext } from '../right_panel/context'; import { showThread } from "../../../dispatcher/dispatch-actions/threads"; import { shouldDisplayReply } from '../../../utils/Reply'; import { Key } from "../../../Keyboard"; diff --git a/src/components/views/right_panel/BaseCard.tsx b/src/components/views/right_panel/BaseCard.tsx index 3d76f72b3f..ae4a2942a2 100644 --- a/src/components/views/right_panel/BaseCard.tsx +++ b/src/components/views/right_panel/BaseCard.tsx @@ -22,8 +22,8 @@ import { _t } from "../../../languageHandler"; import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; import RightPanelStore from '../../../stores/right-panel/RightPanelStore'; import { backLabelForPhase } from '../../../stores/right-panel/RightPanelStorePhases'; +import { CardContext } from './context'; -export const CardContext = React.createContext({ isCard: false }); interface IProps { header?: ReactNode; footer?: ReactNode; diff --git a/src/components/views/right_panel/context.ts b/src/components/views/right_panel/context.ts new file mode 100644 index 0000000000..5fe04b8670 --- /dev/null +++ b/src/components/views/right_panel/context.ts @@ -0,0 +1,19 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; + +export const CardContext = React.createContext({ isCard: false }); diff --git a/src/components/views/rooms/ThreadSummary.tsx b/src/components/views/rooms/ThreadSummary.tsx index 9adec2e1ac..9a13814f89 100644 --- a/src/components/views/rooms/ThreadSummary.tsx +++ b/src/components/views/rooms/ThreadSummary.tsx @@ -19,7 +19,7 @@ import { Thread, ThreadEvent } from "matrix-js-sdk/src/models/thread"; import { MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event"; import { _t } from "../../../languageHandler"; -import { CardContext } from "../right_panel/BaseCard"; +import { CardContext } from "../right_panel/context"; import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; import { showThread } from "../../../dispatcher/dispatch-actions/threads"; import PosthogTrackers from "../../../PosthogTrackers"; From 4144d0ba576c5daa9d9310da8615d139b2b1f87a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 15:50:04 -0600 Subject: [PATCH 22/47] Step 8.5: Isolate RightPanelStore from RoomViewStore --- src/dispatcher/actions.ts | 6 +++ .../payloads/ActiveRoomChangedPayload.ts | 27 +++++++++++ src/stores/ReadyWatchingStore.ts | 6 +++ src/stores/RoomViewStore.tsx | 32 ++++++++++--- src/stores/right-panel/RightPanelStore.ts | 45 ++++++++++--------- .../components/structures/RightPanel-test.tsx | 2 + .../views/elements/AppTile-test.tsx | 2 + 7 files changed, 91 insertions(+), 29 deletions(-) create mode 100644 src/dispatcher/payloads/ActiveRoomChangedPayload.ts diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 497401ba2a..5dbdd24540 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -259,4 +259,10 @@ export enum Action { * Fired when clicking user name from group view */ ViewStartChatOrReuse = "view_start_chat_or_reuse", + + /** + * Fired when the user's active room changed, possibly from/to a non-room view. + * Payload: ActiveRoomChangedPayload + */ + ActiveRoomChanged = "active_room_changed", } diff --git a/src/dispatcher/payloads/ActiveRoomChangedPayload.ts b/src/dispatcher/payloads/ActiveRoomChangedPayload.ts new file mode 100644 index 0000000000..3768cca5e4 --- /dev/null +++ b/src/dispatcher/payloads/ActiveRoomChangedPayload.ts @@ -0,0 +1,27 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Optional } from "matrix-events-sdk"; + +import { Action } from "../actions"; +import { ActionPayload } from "../payloads"; + +export interface ActiveRoomChangedPayload extends ActionPayload { + action: Action.ActiveRoomChanged; + + oldRoomId: Optional; + newRoomId: Optional; +} diff --git a/src/stores/ReadyWatchingStore.ts b/src/stores/ReadyWatchingStore.ts index 4d03a482b5..c44664a08e 100644 --- a/src/stores/ReadyWatchingStore.ts +++ b/src/stores/ReadyWatchingStore.ts @@ -60,7 +60,13 @@ export abstract class ReadyWatchingStore extends EventEmitter implements IDestro // Default implementation is to do nothing. } + protected onDispatcherAction(payload: ActionPayload) { + // Default implementation is to do nothing. + } + private onAction = async (payload: ActionPayload) => { + this.onDispatcherAction(payload); + if (payload.action === 'MatrixActions.sync') { // Only set the client on the transition into the PREPARED state. // Everything after this is unnecessary (we only need to know once we have a client) diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index e8ed6a62c4..a346d90e26 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -24,7 +24,7 @@ import { ViewRoom as ViewRoomEvent } from "matrix-analytics-events/types/typescr import { JoinedRoom as JoinedRoomEvent } from "matrix-analytics-events/types/typescript/JoinedRoom"; import { JoinRule } from "matrix-js-sdk/src/@types/partials"; import { Room } from "matrix-js-sdk/src/models/room"; -import { ClientEvent } from "matrix-js-sdk/src/client"; +import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client"; import dis from '../dispatcher/dispatcher'; import { MatrixClientPeg } from '../MatrixClientPeg'; @@ -46,6 +46,7 @@ import { JoinRoomErrorPayload } from "../dispatcher/payloads/JoinRoomErrorPayloa import { ViewRoomErrorPayload } from "../dispatcher/payloads/ViewRoomErrorPayload"; import RoomSettingsDialog from "../components/views/dialogs/RoomSettingsDialog"; import ErrorDialog from "../components/views/dialogs/ErrorDialog"; +import { ActiveRoomChangedPayload } from "../dispatcher/payloads/ActiveRoomChangedPayload"; const NUM_JOIN_RETRY = 5; @@ -93,6 +94,7 @@ export class RoomViewStore extends Store { public static readonly instance = new RoomViewStore(); private state = INITIAL_STATE; // initialize state + private forcedMatrixClient: MatrixClient; // Keep these out of state to avoid causing excessive/recursive updates private roomIdActivityListeners: Record = {}; @@ -101,6 +103,14 @@ export class RoomViewStore extends Store { super(dis); } + private get matrixClient(): MatrixClient { + return this.forcedMatrixClient || MatrixClientPeg.get(); + } + + public useUnitTestClient(client: MatrixClient) { + this.forcedMatrixClient = client; + } + public addRoomListener(roomId: string, fn: Listener) { if (!this.roomIdActivityListeners[roomId]) this.roomIdActivityListeners[roomId] = []; this.roomIdActivityListeners[roomId].push(fn); @@ -145,6 +155,14 @@ export class RoomViewStore extends Store { if (lastRoomId !== this.state.roomId) { if (lastRoomId) this.emitForRoom(lastRoomId, false); if (this.state.roomId) this.emitForRoom(this.state.roomId, true); + + // Fired so we can reduce dependency on event emitters to this store, which is relatively + // central to the application and can easily cause import cycles. + dis.dispatch({ + action: Action.ActiveRoomChanged, + oldRoomId: lastRoomId, + newRoomId: this.state.roomId, + } as ActiveRoomChangedPayload); } this.__emitChange(); @@ -197,7 +215,7 @@ export class RoomViewStore extends Store { this.setState({ shouldPeek: false }); } - const cli = MatrixClientPeg.get(); + const cli = this.matrixClient; const updateMetrics = () => { const room = cli.getRoom(payload.roomId); @@ -280,7 +298,7 @@ export class RoomViewStore extends Store { trigger: payload.metricsTrigger, viaKeyboard: payload.metricsViaKeyboard, isDM: !!DMRoomMap.shared().getUserIdForRoomId(payload.room_id), - isSpace: MatrixClientPeg.get().getRoom(payload.room_id)?.isSpaceRoom(), + isSpace: this.matrixClient.getRoom(payload.room_id)?.isSpaceRoom(), activeSpace, }); } @@ -339,7 +357,7 @@ export class RoomViewStore extends Store { wasContextSwitch: payload.context_switch, }); try { - const result = await MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias); + const result = await this.matrixClient.getRoomIdForAlias(payload.room_alias); storeRoomAliasInCache(payload.room_alias, result.room_id); roomId = result.room_id; } catch (err) { @@ -376,7 +394,7 @@ export class RoomViewStore extends Store { joining: true, }); - const cli = MatrixClientPeg.get(); + const cli = this.matrixClient; // take a copy of roomAlias & roomId as they may change by the time the join is complete const { roomAlias, roomId } = this.state; const address = roomAlias || roomId; @@ -408,7 +426,7 @@ export class RoomViewStore extends Store { } private getInvitingUserId(roomId: string): string { - const cli = MatrixClientPeg.get(); + const cli = this.matrixClient; const room = cli.getRoom(roomId); if (room && room.getMyMembership() === "invite") { const myMember = room.getMember(cli.getUserId()); @@ -433,7 +451,7 @@ export class RoomViewStore extends Store { // only provide a better error message for invites if (invitingUserId) { // if the inviting user is on the same HS, there can only be one cause: they left. - if (invitingUserId.endsWith(`:${MatrixClientPeg.get().getDomain()}`)) { + if (invitingUserId.endsWith(`:${this.matrixClient.getDomain()}`)) { msg = _t("The person who invited you already left the room."); } else { msg = _t("The person who invited you already left the room, or their server is offline."); diff --git a/src/stores/right-panel/RightPanelStore.ts b/src/stores/right-panel/RightPanelStore.ts index 0fa5616428..c40e8aef4a 100644 --- a/src/stores/right-panel/RightPanelStore.ts +++ b/src/stores/right-panel/RightPanelStore.ts @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { EventSubscription } from 'fbemitter'; import { logger } from "matrix-js-sdk/src/logger"; import { CryptoEvent } from "matrix-js-sdk/src/crypto"; +import { Optional } from "matrix-events-sdk"; import defaultDispatcher from '../../dispatcher/dispatcher'; import { pendingVerificationRequestForUser } from '../../verification'; @@ -31,7 +31,9 @@ import { IRightPanelCard, IRightPanelForRoom, } from './RightPanelStoreIPanelState'; -import { RoomViewStore } from '../RoomViewStore'; +import { ActionPayload } from "../../dispatcher/payloads"; +import { Action } from "../../dispatcher/actions"; +import { ActiveRoomChangedPayload } from "../../dispatcher/payloads/ActiveRoomChangedPayload"; /** * A class for tracking the state of the right panel between layouts and @@ -41,30 +43,32 @@ import { RoomViewStore } from '../RoomViewStore'; */ export default class RightPanelStore extends ReadyWatchingStore { private static internalInstance: RightPanelStore; - private viewedRoomId: string; private global?: IRightPanelForRoom = null; private byRoom: { [roomId: string]: IRightPanelForRoom; } = {}; - - private roomStoreToken: EventSubscription; + private viewedRoomId: Optional; private constructor() { super(defaultDispatcher); } protected async onReady(): Promise { - this.roomStoreToken = RoomViewStore.instance.addListener(this.onRoomViewStoreUpdate); this.matrixClient.on(CryptoEvent.VerificationRequest, this.onVerificationRequestUpdate); - this.viewedRoomId = RoomViewStore.instance.getRoomId(); this.loadCacheFromSettings(); this.emitAndUpdateSettings(); } protected async onNotReady(): Promise { this.matrixClient.off(CryptoEvent.VerificationRequest, this.onVerificationRequestUpdate); - this.roomStoreToken.remove(); + } + + protected onDispatcherAction(payload: ActionPayload) { + if (payload.action !== Action.ActiveRoomChanged) return; + + const changePayload = payload; + this.handleViewedRoomChange(changePayload.oldRoomId, changePayload.newRoomId); } // Getters @@ -336,23 +340,20 @@ export default class RightPanelStore extends ReadyWatchingStore { } }; - private onRoomViewStoreUpdate = () => { - const oldRoomId = this.viewedRoomId; - this.viewedRoomId = RoomViewStore.instance.getRoomId(); + private handleViewedRoomChange(oldRoomId: Optional, newRoomId: Optional) { + this.viewedRoomId = newRoomId; // load values from byRoomCache with the viewedRoomId. this.loadCacheFromSettings(); - // if we're switching to a room, clear out any stale MemberInfo cards + // when we're switching to a room, clear out any stale MemberInfo cards // in order to fix https://github.com/vector-im/element-web/issues/21487 - if (oldRoomId !== this.viewedRoomId) { - if (this.currentCard?.phase !== RightPanelPhases.EncryptionPanel) { - const panel = this.byRoom[this.viewedRoomId]; - if (panel?.history) { - panel.history = panel.history.filter( - (card) => card.phase != RightPanelPhases.RoomMemberInfo && - card.phase != RightPanelPhases.Room3pidMemberInfo, - ); - } + if (this.currentCard?.phase !== RightPanelPhases.EncryptionPanel) { + const panel = this.byRoom[this.viewedRoomId]; + if (panel?.history) { + panel.history = panel.history.filter( + (card) => card.phase != RightPanelPhases.RoomMemberInfo && + card.phase != RightPanelPhases.Room3pidMemberInfo, + ); } } @@ -374,7 +375,7 @@ export default class RightPanelStore extends ReadyWatchingStore { }; } this.emitAndUpdateSettings(); - }; + } private get isViewingRoom(): boolean { return !!this.viewedRoomId; diff --git a/test/components/structures/RightPanel-test.tsx b/test/components/structures/RightPanel-test.tsx index 7d68d1753d..a845a7ed80 100644 --- a/test/components/structures/RightPanel-test.tsx +++ b/test/components/structures/RightPanel-test.tsx @@ -32,6 +32,7 @@ import { RightPanelPhases } from "../../../src/stores/right-panel/RightPanelStor import RightPanelStore from "../../../src/stores/right-panel/RightPanelStore"; import { UPDATE_EVENT } from "../../../src/stores/AsyncStore"; import { WidgetLayoutStore } from "../../../src/stores/widgets/WidgetLayoutStore"; +import { RoomViewStore } from "../../../src/stores/RoomViewStore"; describe("RightPanel", () => { it("renders info from only one room during room changes", async () => { @@ -75,6 +76,7 @@ describe("RightPanel", () => { // @ts-ignore await WidgetLayoutStore.instance.onReady(); RightPanelStore.instance.useUnitTestClient(cli); + RoomViewStore.instance.useUnitTestClient(cli); // @ts-ignore await RightPanelStore.instance.onReady(); diff --git a/test/components/views/elements/AppTile-test.tsx b/test/components/views/elements/AppTile-test.tsx index 8843a9c602..2b07c214eb 100644 --- a/test/components/views/elements/AppTile-test.tsx +++ b/test/components/views/elements/AppTile-test.tsx @@ -36,6 +36,7 @@ import WidgetStore, { IApp } from "../../../../src/stores/WidgetStore"; import AppTile from "../../../../src/components/views/elements/AppTile"; import { Container, WidgetLayoutStore } from "../../../../src/stores/widgets/WidgetLayoutStore"; import AppsDrawer from "../../../../src/components/views/rooms/AppsDrawer"; +import { RoomViewStore } from "../../../../src/stores/RoomViewStore"; describe("AppTile", () => { let cli; @@ -108,6 +109,7 @@ describe("AppTile", () => { // @ts-ignore await WidgetLayoutStore.instance.onReady(); RightPanelStore.instance.useUnitTestClient(cli); + RoomViewStore.instance.useUnitTestClient(cli); // @ts-ignore await RightPanelStore.instance.onReady(); }); From cfbad115c7cdde8dc030b4955632784de8b0fea9 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 15:54:06 -0600 Subject: [PATCH 23/47] Step 8.5: Move event rendering utilities --- src/components/structures/MessagePanel.tsx | 2 +- src/components/views/rooms/EventTile.tsx | 2 +- src/components/views/rooms/ReplyTile.tsx | 3 +- src/utils/EventRenderingUtils.ts | 112 +++++++++++++++++++++ src/utils/EventUtils.ts | 89 ---------------- 5 files changed, 116 insertions(+), 92 deletions(-) create mode 100644 src/utils/EventRenderingUtils.ts diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index a5a9164bb7..4f7a6ca724 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -50,7 +50,7 @@ import Spinner from "../views/elements/Spinner"; import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks"; import EditorStateTransfer from "../../utils/EditorStateTransfer"; import { Action } from '../../dispatcher/actions'; -import { getEventDisplayInfo } from "../../utils/EventUtils"; +import { getEventDisplayInfo } from "../../utils/EventRenderingUtils"; import { IReadReceiptInfo } from "../views/rooms/ReadReceiptMarker"; import { haveRendererForEvent } from "../../events/EventTileFactory"; diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index aa2e38ea8d..bee349a8cc 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -54,7 +54,7 @@ import TooltipButton from '../elements/TooltipButton'; import ReadReceiptMarker, { IReadReceiptInfo } from "./ReadReceiptMarker"; import MessageActionBar from "../messages/MessageActionBar"; import ReactionsRow from '../messages/ReactionsRow'; -import { getEventDisplayInfo } from '../../../utils/EventUtils'; +import { getEventDisplayInfo } from '../../../utils/EventRenderingUtils'; import SettingsStore from "../../../settings/SettingsStore"; import { showThread } from '../../../dispatcher/dispatch-actions/threads'; import { MessagePreviewStore } from '../../../stores/room-list/MessagePreviewStore'; diff --git a/src/components/views/rooms/ReplyTile.tsx b/src/components/views/rooms/ReplyTile.tsx index 1d23e7a56a..bfd592f698 100644 --- a/src/components/views/rooms/ReplyTile.tsx +++ b/src/components/views/rooms/ReplyTile.tsx @@ -27,7 +27,8 @@ import { Action } from '../../../dispatcher/actions'; import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks'; import SenderProfile from "../messages/SenderProfile"; import MImageReplyBody from "../messages/MImageReplyBody"; -import { getEventDisplayInfo, isVoiceMessage } from '../../../utils/EventUtils'; +import { isVoiceMessage } from '../../../utils/EventUtils'; +import { getEventDisplayInfo } from "../../../utils/EventRenderingUtils"; import MFileBody from "../messages/MFileBody"; import MVoiceMessageBody from "../messages/MVoiceMessageBody"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; diff --git a/src/utils/EventRenderingUtils.ts b/src/utils/EventRenderingUtils.ts new file mode 100644 index 0000000000..62cca4bd9e --- /dev/null +++ b/src/utils/EventRenderingUtils.ts @@ -0,0 +1,112 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { EventType, MsgType } from "matrix-js-sdk/src/@types/event"; +import { M_POLL_START } from "matrix-events-sdk"; +import { M_LOCATION } from "matrix-js-sdk/src/@types/location"; + +import SettingsStore from "../settings/SettingsStore"; +import { haveRendererForEvent, JitsiEventFactory, JSONEventFactory, pickFactory } from "../events/EventTileFactory"; +import { MatrixClientPeg } from "../MatrixClientPeg"; +import { getMessageModerationState, MessageModerationState } from "./EventUtils"; + +export function getEventDisplayInfo(mxEvent: MatrixEvent, hideEvent?: boolean): { + isInfoMessage: boolean; + hasRenderer: boolean; + isBubbleMessage: boolean; + isLeftAlignedBubbleMessage: boolean; + noBubbleEvent: boolean; + isSeeingThroughMessageHiddenForModeration: boolean; +} { + const content = mxEvent.getContent(); + const msgtype = content.msgtype; + const eventType = mxEvent.getType(); + + let isSeeingThroughMessageHiddenForModeration = false; + if (SettingsStore.getValue("feature_msc3531_hide_messages_pending_moderation")) { + switch (getMessageModerationState(mxEvent)) { + case MessageModerationState.VISIBLE_FOR_ALL: + case MessageModerationState.HIDDEN_TO_CURRENT_USER: + // Nothing specific to do here + break; + case MessageModerationState.SEE_THROUGH_FOR_CURRENT_USER: + // Show message with a marker. + isSeeingThroughMessageHiddenForModeration = true; + break; + } + } + + // TODO: Thread a MatrixClient through to here + let factory = pickFactory(mxEvent, MatrixClientPeg.get()); + + // Info messages are basically information about commands processed on a room + let isBubbleMessage = ( + eventType.startsWith("m.key.verification") || + (eventType === EventType.RoomMessage && msgtype?.startsWith("m.key.verification")) || + (eventType === EventType.RoomCreate) || + (eventType === EventType.RoomEncryption) || + (factory === JitsiEventFactory) + ); + const isLeftAlignedBubbleMessage = ( + !isBubbleMessage && + eventType === EventType.CallInvite + ); + let isInfoMessage = ( + !isBubbleMessage && + !isLeftAlignedBubbleMessage && + eventType !== EventType.RoomMessage && + eventType !== EventType.RoomMessageEncrypted && + eventType !== EventType.Sticker && + eventType !== EventType.RoomCreate && + !M_POLL_START.matches(eventType) + ); + // Some non-info messages want to be rendered in the appropriate bubble column but without the bubble background + const noBubbleEvent = ( + (eventType === EventType.RoomMessage && msgtype === MsgType.Emote) || + M_POLL_START.matches(eventType) || + M_LOCATION.matches(eventType) || + ( + eventType === EventType.RoomMessage && + M_LOCATION.matches(msgtype) + ) + ); + + // If we're showing hidden events in the timeline, we should use the + // source tile when there's no regular tile for an event and also for + // replace relations (which otherwise would display as a confusing + // duplicate of the thing they are replacing). + if (hideEvent || !haveRendererForEvent(mxEvent)) { + // forcefully ask for a factory for a hidden event (hidden event + // setting is checked internally) + // TODO: Thread a MatrixClient through to here + factory = pickFactory(mxEvent, MatrixClientPeg.get(), true); + if (factory === JSONEventFactory) { + isBubbleMessage = false; + // Reuse info message avatar and sender profile styling + isInfoMessage = true; + } + } + + return { + hasRenderer: !!factory, + isInfoMessage, + isBubbleMessage, + isLeftAlignedBubbleMessage, + noBubbleEvent, + isSeeingThroughMessageHiddenForModeration, + }; +} diff --git a/src/utils/EventUtils.ts b/src/utils/EventUtils.ts index 4300ee26e0..49ec5c29b3 100644 --- a/src/utils/EventUtils.ts +++ b/src/utils/EventUtils.ts @@ -18,7 +18,6 @@ import { EventStatus, MatrixEvent } from 'matrix-js-sdk/src/models/event'; import { EventType, EVENT_VISIBILITY_CHANGE_TYPE, MsgType, RelationType } from "matrix-js-sdk/src/@types/event"; import { MatrixClient } from 'matrix-js-sdk/src/client'; import { logger } from 'matrix-js-sdk/src/logger'; -import { M_LOCATION } from 'matrix-js-sdk/src/@types/location'; import { M_POLL_START } from "matrix-events-sdk"; import { MatrixClientPeg } from '../MatrixClientPeg'; @@ -29,7 +28,6 @@ import defaultDispatcher from "../dispatcher/dispatcher"; import { TimelineRenderingType } from "../contexts/RoomContext"; import { launchPollEditor } from "../components/views/messages/MPollBody"; import { Action } from "../dispatcher/actions"; -import { haveRendererForEvent, JitsiEventFactory, JSONEventFactory, pickFactory } from "../events/EventTileFactory"; /** * Returns whether an event should allow actions like reply, reactions, edit, etc. @@ -196,93 +194,6 @@ export function getMessageModerationState(mxEvent: MatrixEvent, client?: MatrixC return MessageModerationState.HIDDEN_TO_CURRENT_USER; } -export function getEventDisplayInfo(mxEvent: MatrixEvent, hideEvent?: boolean): { - isInfoMessage: boolean; - hasRenderer: boolean; - isBubbleMessage: boolean; - isLeftAlignedBubbleMessage: boolean; - noBubbleEvent: boolean; - isSeeingThroughMessageHiddenForModeration: boolean; -} { - const content = mxEvent.getContent(); - const msgtype = content.msgtype; - const eventType = mxEvent.getType(); - - let isSeeingThroughMessageHiddenForModeration = false; - if (SettingsStore.getValue("feature_msc3531_hide_messages_pending_moderation")) { - switch (getMessageModerationState(mxEvent)) { - case MessageModerationState.VISIBLE_FOR_ALL: - case MessageModerationState.HIDDEN_TO_CURRENT_USER: - // Nothing specific to do here - break; - case MessageModerationState.SEE_THROUGH_FOR_CURRENT_USER: - // Show message with a marker. - isSeeingThroughMessageHiddenForModeration = true; - break; - } - } - - // TODO: Thread a MatrixClient through to here - let factory = pickFactory(mxEvent, MatrixClientPeg.get()); - - // Info messages are basically information about commands processed on a room - let isBubbleMessage = ( - eventType.startsWith("m.key.verification") || - (eventType === EventType.RoomMessage && msgtype?.startsWith("m.key.verification")) || - (eventType === EventType.RoomCreate) || - (eventType === EventType.RoomEncryption) || - (factory === JitsiEventFactory) - ); - const isLeftAlignedBubbleMessage = ( - !isBubbleMessage && - eventType === EventType.CallInvite - ); - let isInfoMessage = ( - !isBubbleMessage && - !isLeftAlignedBubbleMessage && - eventType !== EventType.RoomMessage && - eventType !== EventType.RoomMessageEncrypted && - eventType !== EventType.Sticker && - eventType !== EventType.RoomCreate && - !M_POLL_START.matches(eventType) - ); - // Some non-info messages want to be rendered in the appropriate bubble column but without the bubble background - const noBubbleEvent = ( - (eventType === EventType.RoomMessage && msgtype === MsgType.Emote) || - M_POLL_START.matches(eventType) || - M_LOCATION.matches(eventType) || - ( - eventType === EventType.RoomMessage && - M_LOCATION.matches(msgtype) - ) - ); - - // If we're showing hidden events in the timeline, we should use the - // source tile when there's no regular tile for an event and also for - // replace relations (which otherwise would display as a confusing - // duplicate of the thing they are replacing). - if (hideEvent || !haveRendererForEvent(mxEvent)) { - // forcefully ask for a factory for a hidden event (hidden event - // setting is checked internally) - // TODO: Thread a MatrixClient through to here - factory = pickFactory(mxEvent, MatrixClientPeg.get(), true); - if (factory === JSONEventFactory) { - isBubbleMessage = false; - // Reuse info message avatar and sender profile styling - isInfoMessage = true; - } - } - - return { - hasRenderer: !!factory, - isInfoMessage, - isBubbleMessage, - isLeftAlignedBubbleMessage, - noBubbleEvent, - isSeeingThroughMessageHiddenForModeration, - }; -} - export function isVoiceMessage(mxEvent: MatrixEvent): boolean { const content = mxEvent.getContent(); // MSC2516 is a legacy identifier. See https://github.com/matrix-org/matrix-doc/pull/3245 From f5e6cbafb2682a779660e77bfaf924a793f3d104 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 15:54:44 -0600 Subject: [PATCH 24/47] Step 8.5: Move pinned events custom event type --- .../views/context_menus/MessageContextMenu.tsx | 2 +- .../views/right_panel/PinnedMessagesCard.tsx | 3 +-- src/components/views/right_panel/types.ts | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 src/components/views/right_panel/types.ts diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx index 5adbcb9a9d..cffd83a4e0 100644 --- a/src/components/views/context_menus/MessageContextMenu.tsx +++ b/src/components/views/context_menus/MessageContextMenu.tsx @@ -32,7 +32,7 @@ import SettingsStore from '../../../settings/SettingsStore'; import { isUrlPermitted } from '../../../HtmlUtils'; import { isContentActionable } from '../../../utils/EventUtils'; import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from './IconizedContextMenu'; -import { ReadPinsEventId } from "../right_panel/PinnedMessagesCard"; +import { ReadPinsEventId } from "../right_panel/types"; import ForwardDialog from "../dialogs/ForwardDialog"; import { Action } from "../../../dispatcher/actions"; import ReportEventDialog from '../dialogs/ReportEventDialog'; diff --git a/src/components/views/right_panel/PinnedMessagesCard.tsx b/src/components/views/right_panel/PinnedMessagesCard.tsx index 1b110a76c3..def0985863 100644 --- a/src/components/views/right_panel/PinnedMessagesCard.tsx +++ b/src/components/views/right_panel/PinnedMessagesCard.tsx @@ -31,6 +31,7 @@ import { useAsyncMemo } from "../../../hooks/useAsyncMemo"; import PinnedEventTile from "../rooms/PinnedEventTile"; import { useRoomState } from "../../../hooks/useRoomState"; import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext"; +import { ReadPinsEventId } from "./types"; interface IProps { room: Room; @@ -56,8 +57,6 @@ export const usePinnedEvents = (room: Room): string[] => { return pinnedEvents; }; -export const ReadPinsEventId = "im.vector.room.read_pins"; - export const useReadPinnedEvents = (room: Room): Set => { const [readPinnedEvents, setReadPinnedEvents] = useState>(new Set()); diff --git a/src/components/views/right_panel/types.ts b/src/components/views/right_panel/types.ts new file mode 100644 index 0000000000..f7a6d60f55 --- /dev/null +++ b/src/components/views/right_panel/types.ts @@ -0,0 +1,17 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export const ReadPinsEventId = "im.vector.room.read_pins"; From 51f90a1a73a13f832c6ca25cd88c7188a22ba4cd Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 15:55:57 -0600 Subject: [PATCH 25/47] Step 8.5: Move room settings opener to a DialogOpener --- src/Lifecycle.ts | 2 ++ src/stores/RoomViewStore.tsx | 8 ------ src/utils/DialogOpener.ts | 54 ++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 src/utils/DialogOpener.ts diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index 85f0535851..340c4fa2ca 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -59,6 +59,7 @@ import SessionRestoreErrorDialog from "./components/views/dialogs/SessionRestore import StorageEvictedDialog from "./components/views/dialogs/StorageEvictedDialog"; import { setSentryUser } from "./sentry"; import SdkConfig from "./SdkConfig"; +import { DialogOpener } from "./utils/DialogOpener"; const HOMESERVER_URL_KEY = "mx_hs_url"; const ID_SERVER_URL_KEY = "mx_is_url"; @@ -790,6 +791,7 @@ async function startMatrixClient(startSyncing = true): Promise { TypingStore.sharedInstance().reset(); ToastStore.sharedInstance().reset(); + DialogOpener.instance.prepare(); Notifier.start(); UserActivity.sharedInstance().start(); DMRoomMap.makeShared().start(); diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index a346d90e26..d802845eee 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -44,7 +44,6 @@ import { JoinRoomPayload } from "../dispatcher/payloads/JoinRoomPayload"; import { JoinRoomReadyPayload } from "../dispatcher/payloads/JoinRoomReadyPayload"; import { JoinRoomErrorPayload } from "../dispatcher/payloads/JoinRoomErrorPayload"; import { ViewRoomErrorPayload } from "../dispatcher/payloads/ViewRoomErrorPayload"; -import RoomSettingsDialog from "../components/views/dialogs/RoomSettingsDialog"; import ErrorDialog from "../components/views/dialogs/ErrorDialog"; import { ActiveRoomChangedPayload } from "../dispatcher/payloads/ActiveRoomChangedPayload"; @@ -269,13 +268,6 @@ export class RoomViewStore extends Store { } } break; - case 'open_room_settings': { - Modal.createTrackedDialog('Room settings', '', RoomSettingsDialog, { - roomId: payload.room_id || this.state.roomId, - initialTabId: payload.initial_tab_id, - }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); - break; - } } } diff --git a/src/utils/DialogOpener.ts b/src/utils/DialogOpener.ts new file mode 100644 index 0000000000..3908a5af1e --- /dev/null +++ b/src/utils/DialogOpener.ts @@ -0,0 +1,54 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import defaultDispatcher from "../dispatcher/dispatcher"; +import { ActionPayload } from "../dispatcher/payloads"; +import Modal from "../Modal"; +import RoomSettingsDialog from "../components/views/dialogs/RoomSettingsDialog"; +import { RoomViewStore } from "../stores/RoomViewStore"; + +/** + * Auxiliary class to listen for dialog opening over the dispatcher and + * open the required dialogs. Not all dialogs run through here, but the + * ones which cause import cycles are good candidates. + */ +export class DialogOpener { + public static readonly instance = new DialogOpener(); + + private isRegistered = false; + + private constructor() { + } + + // We could do this in the constructor, but then we wouldn't have + // a function to call from Lifecycle to capture the class. + public prepare() { + if (this.isRegistered) return; + defaultDispatcher.register(this.onDispatch); + this.isRegistered = true; + } + + private onDispatch = (payload: ActionPayload) => { + switch (payload.action) { + case 'open_room_settings': + Modal.createTrackedDialog('Room settings', '', RoomSettingsDialog, { + roomId: payload.room_id || RoomViewStore.instance.getRoomId(), + initialTabId: payload.initial_tab_id, + }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); + break; + } + }; +} From 8dab169c52c4b2e91acb4b6a279d10e094d80786 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 16:00:47 -0600 Subject: [PATCH 26/47] Step 8.5: Move forward dialog construction --- .../context_menus/MessageContextMenu.tsx | 8 ++--- src/dispatcher/actions.ts | 6 ++++ .../payloads/OpenForwardDialogPayload.ts | 29 +++++++++++++++++++ src/utils/DialogOpener.ts | 10 +++++++ 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 src/dispatcher/payloads/OpenForwardDialogPayload.ts diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx index cffd83a4e0..00b0a69778 100644 --- a/src/components/views/context_menus/MessageContextMenu.tsx +++ b/src/components/views/context_menus/MessageContextMenu.tsx @@ -33,7 +33,6 @@ import { isUrlPermitted } from '../../../HtmlUtils'; import { isContentActionable } from '../../../utils/EventUtils'; import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from './IconizedContextMenu'; import { ReadPinsEventId } from "../right_panel/types"; -import ForwardDialog from "../dialogs/ForwardDialog"; import { Action } from "../../../dispatcher/actions"; import ReportEventDialog from '../dialogs/ReportEventDialog'; import ViewSource from '../../structures/ViewSource'; @@ -47,6 +46,7 @@ import { WidgetLayoutStore } from '../../../stores/widgets/WidgetLayoutStore'; import EndPollDialog from '../dialogs/EndPollDialog'; import { isPollEnded } from '../messages/MPollBody'; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; +import { OpenForwardDialogPayload } from "../../../dispatcher/payloads/OpenForwardDialogPayload"; import { createMapSiteLink } from '../../../utils/location'; export function canCancel(status: EventStatus): boolean { @@ -177,11 +177,11 @@ export default class MessageContextMenu extends React.Component }; private onForwardClick = (): void => { - Modal.createTrackedDialog('Forward Message', '', ForwardDialog, { - matrixClient: MatrixClientPeg.get(), + dis.dispatch({ + action: Action.OpenForwardDialog, event: this.props.mxEvent, permalinkCreator: this.props.permalinkCreator, - }); + } as OpenForwardDialogPayload); this.closeMenu(); }; diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 5dbdd24540..12053e204d 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -265,4 +265,10 @@ export enum Action { * Payload: ActiveRoomChangedPayload */ ActiveRoomChanged = "active_room_changed", + + /** + * Fired when the forward dialog needs to be opened. + * Payload: OpenForwardDialogPayload + */ + OpenForwardDialog = "open_forward_dialog", } diff --git a/src/dispatcher/payloads/OpenForwardDialogPayload.ts b/src/dispatcher/payloads/OpenForwardDialogPayload.ts new file mode 100644 index 0000000000..4a5a9b1c84 --- /dev/null +++ b/src/dispatcher/payloads/OpenForwardDialogPayload.ts @@ -0,0 +1,29 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { Optional } from "matrix-events-sdk"; + +import { Action } from "../actions"; +import { ActionPayload } from "../payloads"; +import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks"; + +export interface OpenForwardDialogPayload extends ActionPayload { + action: Action.OpenForwardDialog; + + event: MatrixEvent; + permalinkCreator: Optional; +} diff --git a/src/utils/DialogOpener.ts b/src/utils/DialogOpener.ts index 3908a5af1e..ca4ab85b13 100644 --- a/src/utils/DialogOpener.ts +++ b/src/utils/DialogOpener.ts @@ -19,6 +19,9 @@ import { ActionPayload } from "../dispatcher/payloads"; import Modal from "../Modal"; import RoomSettingsDialog from "../components/views/dialogs/RoomSettingsDialog"; import { RoomViewStore } from "../stores/RoomViewStore"; +import ForwardDialog from "../components/views/dialogs/ForwardDialog"; +import { MatrixClientPeg } from "../MatrixClientPeg"; +import { Action } from "../dispatcher/actions"; /** * Auxiliary class to listen for dialog opening over the dispatcher and @@ -49,6 +52,13 @@ export class DialogOpener { initialTabId: payload.initial_tab_id, }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); break; + case Action.OpenForwardDialog: + Modal.createTrackedDialog('Forward Message', '', ForwardDialog, { + matrixClient: MatrixClientPeg.get(), + event: payload.event, + permalinkCreator: payload.permalinkCreator, + }); + break; } }; } From 226700ba9563be823aa4385015ce037e3464eae0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 16:02:33 -0600 Subject: [PATCH 27/47] Step 8.5: Move report event dialog construction --- .../context_menus/MessageContextMenu.tsx | 9 ++++--- src/dispatcher/actions.ts | 6 +++++ .../payloads/OpenReportEventDialogPayload.ts | 26 +++++++++++++++++++ src/utils/DialogOpener.ts | 6 +++++ 4 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 src/dispatcher/payloads/OpenReportEventDialogPayload.ts diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx index 00b0a69778..b4f476a5cd 100644 --- a/src/components/views/context_menus/MessageContextMenu.tsx +++ b/src/components/views/context_menus/MessageContextMenu.tsx @@ -34,7 +34,6 @@ import { isContentActionable } from '../../../utils/EventUtils'; import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from './IconizedContextMenu'; import { ReadPinsEventId } from "../right_panel/types"; import { Action } from "../../../dispatcher/actions"; -import ReportEventDialog from '../dialogs/ReportEventDialog'; import ViewSource from '../../structures/ViewSource'; import { createRedactEventDialog } from '../dialogs/ConfirmRedactDialog'; import ShareDialog from '../dialogs/ShareDialog'; @@ -47,6 +46,7 @@ import EndPollDialog from '../dialogs/EndPollDialog'; import { isPollEnded } from '../messages/MPollBody'; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { OpenForwardDialogPayload } from "../../../dispatcher/payloads/OpenForwardDialogPayload"; +import { OpenReportEventDialogPayload } from "../../../dispatcher/payloads/OpenReportEventDialogPayload"; import { createMapSiteLink } from '../../../utils/location'; export function canCancel(status: EventStatus): boolean { @@ -154,9 +154,10 @@ export default class MessageContextMenu extends React.Component }; private onReportEventClick = (): void => { - Modal.createTrackedDialog('Report Event', '', ReportEventDialog, { - mxEvent: this.props.mxEvent, - }, 'mx_Dialog_reportEvent'); + dis.dispatch({ + action: Action.OpenReportEventDialog, + event: this.props.mxEvent, + } as OpenReportEventDialogPayload); this.closeMenu(); }; diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 12053e204d..165438e86b 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -271,4 +271,10 @@ export enum Action { * Payload: OpenForwardDialogPayload */ OpenForwardDialog = "open_forward_dialog", + + /** + * Fired when the "report event" dialog needs to be opened. + * Payload: OpenReportEventDialogPayload. + */ + OpenReportEventDialog = "open_report_event_dialog", } diff --git a/src/dispatcher/payloads/OpenReportEventDialogPayload.ts b/src/dispatcher/payloads/OpenReportEventDialogPayload.ts new file mode 100644 index 0000000000..1af103871d --- /dev/null +++ b/src/dispatcher/payloads/OpenReportEventDialogPayload.ts @@ -0,0 +1,26 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; + +import { Action } from "../actions"; +import { ActionPayload } from "../payloads"; + +export interface OpenReportEventDialogPayload extends ActionPayload { + action: Action.OpenReportEventDialog; + + event: MatrixEvent; +} diff --git a/src/utils/DialogOpener.ts b/src/utils/DialogOpener.ts index ca4ab85b13..1b21b1b871 100644 --- a/src/utils/DialogOpener.ts +++ b/src/utils/DialogOpener.ts @@ -22,6 +22,7 @@ import { RoomViewStore } from "../stores/RoomViewStore"; import ForwardDialog from "../components/views/dialogs/ForwardDialog"; import { MatrixClientPeg } from "../MatrixClientPeg"; import { Action } from "../dispatcher/actions"; +import ReportEventDialog from "../components/views/dialogs/ReportEventDialog"; /** * Auxiliary class to listen for dialog opening over the dispatcher and @@ -59,6 +60,11 @@ export class DialogOpener { permalinkCreator: payload.permalinkCreator, }); break; + case Action.OpenReportEventDialog: + Modal.createTrackedDialog('Report Event', '', ReportEventDialog, { + event: payload.event, + }, 'mx_Dialog_reportEvent'); + break; } }; } From bcf413734ba655efee0f03c0c26f50487c24a6e6 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 16:09:07 -0600 Subject: [PATCH 28/47] Step 8.5: Move tabbed integration manager dialog construction --- src/dispatcher/actions.ts | 6 ++++ ...enTabbedIntegrationManagerDialogPayload.ts | 29 +++++++++++++++++++ src/integrations/IntegrationManagers.ts | 18 ++++++++---- src/utils/DialogOpener.ts | 12 ++++++++ 4 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 src/dispatcher/payloads/OpenTabbedIntegrationManagerDialogPayload.ts diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 165438e86b..5662da1de5 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -277,4 +277,10 @@ export enum Action { * Payload: OpenReportEventDialogPayload. */ OpenReportEventDialog = "open_report_event_dialog", + + /** + * Fired when the tabbed integration manager dialog needs to be opened. + * Payload: OpenTabbedIntegrationManagerDialogPayload + */ + OpenTabbedIntegrationManagerDialog = "open_tabbed_imanager_dialog", } diff --git a/src/dispatcher/payloads/OpenTabbedIntegrationManagerDialogPayload.ts b/src/dispatcher/payloads/OpenTabbedIntegrationManagerDialogPayload.ts new file mode 100644 index 0000000000..891d126169 --- /dev/null +++ b/src/dispatcher/payloads/OpenTabbedIntegrationManagerDialogPayload.ts @@ -0,0 +1,29 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Room } from "matrix-js-sdk/src/models/room"; +import { Optional } from "matrix-events-sdk"; + +import { ActionPayload } from "../payloads"; +import { Action } from "../actions"; + +export interface OpenTabbedIntegrationManagerDialogPayload extends ActionPayload { + action: Action.OpenTabbedIntegrationManagerDialog; + + room: Optional; + screen: Optional; + integrationId: Optional; +} diff --git a/src/integrations/IntegrationManagers.ts b/src/integrations/IntegrationManagers.ts index 68c82ab55c..32bb224f74 100644 --- a/src/integrations/IntegrationManagers.ts +++ b/src/integrations/IntegrationManagers.ts @@ -16,7 +16,7 @@ limitations under the License. import url from 'url'; import { logger } from "matrix-js-sdk/src/logger"; -import { MatrixClient, ClientEvent } from "matrix-js-sdk/src/client"; +import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client"; import type { MatrixEvent } from "matrix-js-sdk/src/models/event"; import type { Room } from "matrix-js-sdk/src/models/room"; @@ -24,12 +24,16 @@ import SdkConfig from '../SdkConfig'; import Modal from '../Modal'; import { IntegrationManagerInstance, Kind } from "./IntegrationManagerInstance"; import IntegrationsImpossibleDialog from "../components/views/dialogs/IntegrationsImpossibleDialog"; -import TabbedIntegrationManagerDialog from "../components/views/dialogs/TabbedIntegrationManagerDialog"; import IntegrationsDisabledDialog from "../components/views/dialogs/IntegrationsDisabledDialog"; import WidgetUtils from "../utils/WidgetUtils"; import { MatrixClientPeg } from "../MatrixClientPeg"; import SettingsStore from "../settings/SettingsStore"; import { compare } from "../utils/strings"; +import defaultDispatcher from "../dispatcher/dispatcher"; +import { + OpenTabbedIntegrationManagerDialogPayload, +} from "../dispatcher/payloads/OpenTabbedIntegrationManagerDialogPayload"; +import { Action } from "../dispatcher/actions"; const KIND_PREFERENCE = [ // Ordered: first is most preferred, last is least preferred. @@ -186,10 +190,12 @@ export class IntegrationManagers { return this.openNoManagerDialog(); } - Modal.createTrackedDialog( - 'Tabbed Integration Manager', '', TabbedIntegrationManagerDialog, - { room, screen, integrationId }, 'mx_TabbedIntegrationManagerDialog', - ); + defaultDispatcher.dispatch({ + action: Action.OpenTabbedIntegrationManagerDialog, + room, + screen, + integrationId, + }); } showDisabledDialog(): void { diff --git a/src/utils/DialogOpener.ts b/src/utils/DialogOpener.ts index 1b21b1b871..b18c88ea6f 100644 --- a/src/utils/DialogOpener.ts +++ b/src/utils/DialogOpener.ts @@ -23,6 +23,7 @@ import ForwardDialog from "../components/views/dialogs/ForwardDialog"; import { MatrixClientPeg } from "../MatrixClientPeg"; import { Action } from "../dispatcher/actions"; import ReportEventDialog from "../components/views/dialogs/ReportEventDialog"; +import TabbedIntegrationManagerDialog from "../components/views/dialogs/TabbedIntegrationManagerDialog"; /** * Auxiliary class to listen for dialog opening over the dispatcher and @@ -65,6 +66,17 @@ export class DialogOpener { event: payload.event, }, 'mx_Dialog_reportEvent'); break; + case Action.OpenTabbedIntegrationManagerDialog: + Modal.createTrackedDialog( + 'Tabbed Integration Manager', '', TabbedIntegrationManagerDialog, + { + room: payload.room, + screen: payload.screen, + integrationId: payload.integrationId, + }, + 'mx_TabbedIntegrationManagerDialog', + ); + break; } }; } From c8582c7199806c0b21bf9103761907bb706f9333 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 16:11:01 -0600 Subject: [PATCH 29/47] Step 8.5: Move logout call during deactivation --- src/Lifecycle.ts | 8 ++++++++ src/components/views/dialogs/DeactivateAccountDialog.tsx | 5 +++-- src/dispatcher/actions.ts | 9 +++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index 340c4fa2ca..645963a8bd 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -60,10 +60,18 @@ import StorageEvictedDialog from "./components/views/dialogs/StorageEvictedDialo import { setSentryUser } from "./sentry"; import SdkConfig from "./SdkConfig"; import { DialogOpener } from "./utils/DialogOpener"; +import { Action } from "./dispatcher/actions"; const HOMESERVER_URL_KEY = "mx_hs_url"; const ID_SERVER_URL_KEY = "mx_is_url"; +dis.register((payload) => { + if (payload.action === Action.TriggerLogout) { + // noinspection JSIgnoredPromiseFromCall - we don't care if it fails + onLoggedOut(); + } +}); + interface ILoadSessionOpts { enableGuest?: boolean; guestHsUrl?: string; diff --git a/src/components/views/dialogs/DeactivateAccountDialog.tsx b/src/components/views/dialogs/DeactivateAccountDialog.tsx index bf2f636d5d..a505d5e647 100644 --- a/src/components/views/dialogs/DeactivateAccountDialog.tsx +++ b/src/components/views/dialogs/DeactivateAccountDialog.tsx @@ -21,12 +21,13 @@ import { logger } from "matrix-js-sdk/src/logger"; import Analytics from '../../../Analytics'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; -import * as Lifecycle from '../../../Lifecycle'; 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 BaseDialog from "./BaseDialog"; +import defaultDispatcher from "../../../dispatcher/dispatcher"; +import { Action } from "../../../dispatcher/actions"; interface IProps { onFinished: (success: boolean) => void; @@ -122,7 +123,7 @@ export default class DeactivateAccountDialog extends React.Component { // Deactivation worked - logout & close this dialog Analytics.trackEvent('Account', 'Deactivate Account'); - Lifecycle.onLoggedOut(); + defaultDispatcher.fire(Action.TriggerLogout); this.props.onFinished(true); }).catch(e => { logger.error(e); diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 5662da1de5..adfbc874a4 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -283,4 +283,13 @@ export enum Action { * Payload: OpenTabbedIntegrationManagerDialogPayload */ OpenTabbedIntegrationManagerDialog = "open_tabbed_imanager_dialog", + + /** + * Fired when something within the application has determined that a logout, + * or logout-like behaviour, needs to happen. Specifically meant to target + * storage deletion rather than calling the logout API. + * + * No payload. + */ + TriggerLogout = "trigger_logout", } From 528482f74d062f4eae68cf87553e754c8c3e1046 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 16:13:36 -0600 Subject: [PATCH 30/47] Step 8.5: Move some space settings dialog construction --- .../views/dialogs/SpacePreferencesDialog.tsx | 5 +-- src/dispatcher/actions.ts | 10 +++++ .../payloads/OpenSpacePreferencesPayload.ts | 38 +++++++++++++++++++ .../payloads/OpenSpaceSettingsPayload.ts | 29 ++++++++++++++ src/utils/DialogOpener.ts | 14 +++++++ src/utils/space.tsx | 26 +++++++------ 6 files changed, 106 insertions(+), 16 deletions(-) create mode 100644 src/dispatcher/payloads/OpenSpacePreferencesPayload.ts create mode 100644 src/dispatcher/payloads/OpenSpaceSettingsPayload.ts diff --git a/src/components/views/dialogs/SpacePreferencesDialog.tsx b/src/components/views/dialogs/SpacePreferencesDialog.tsx index d8a1afa342..1d35aa30ef 100644 --- a/src/components/views/dialogs/SpacePreferencesDialog.tsx +++ b/src/components/views/dialogs/SpacePreferencesDialog.tsx @@ -26,10 +26,7 @@ import { useSettingValue } from "../../../hooks/useSettings"; import SettingsStore from "../../../settings/SettingsStore"; import { SettingLevel } from "../../../settings/SettingLevel"; import RoomName from "../elements/RoomName"; - -export enum SpacePreferenceTab { - Appearance = "SPACE_PREFERENCE_APPEARANCE_TAB", -} +import { SpacePreferenceTab } from "../../../dispatcher/payloads/OpenSpacePreferencesPayload"; interface IProps extends IDialogProps { space: Room; diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index adfbc874a4..647dea43bf 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -292,4 +292,14 @@ export enum Action { * No payload. */ TriggerLogout = "trigger_logout", + + /** + * Opens the user's preferences for the given space. Used with a OpenSpacePreferencesPayload. + */ + OpenSpacePreferences = "open_space_preferences", + + /** + * Opens the settings for the given space. Used with a OpenSpaceSettingsPayload. + */ + OpenSpaceSettings = "open_space_settings", } diff --git a/src/dispatcher/payloads/OpenSpacePreferencesPayload.ts b/src/dispatcher/payloads/OpenSpacePreferencesPayload.ts new file mode 100644 index 0000000000..36b340441b --- /dev/null +++ b/src/dispatcher/payloads/OpenSpacePreferencesPayload.ts @@ -0,0 +1,38 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Room } from "matrix-js-sdk/src/models/room"; + +import { ActionPayload } from "../payloads"; +import { Action } from "../actions"; + +export enum SpacePreferenceTab { + Appearance = "SPACE_PREFERENCE_APPEARANCE_TAB", +} + +export interface OpenSpacePreferencesPayload extends ActionPayload { + action: Action.OpenSpacePreferences; + + /** + * The space to open preferences for. + */ + space: Room; + + /** + * Optional tab to open specifically, otherwise the dialog's internal default. + */ + initialTabId?: SpacePreferenceTab; +} diff --git a/src/dispatcher/payloads/OpenSpaceSettingsPayload.ts b/src/dispatcher/payloads/OpenSpaceSettingsPayload.ts new file mode 100644 index 0000000000..e366b6a08e --- /dev/null +++ b/src/dispatcher/payloads/OpenSpaceSettingsPayload.ts @@ -0,0 +1,29 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Room } from "matrix-js-sdk/src/models/room"; + +import { ActionPayload } from "../payloads"; +import { Action } from "../actions"; + +export interface OpenSpaceSettingsPayload extends ActionPayload { + action: Action.OpenSpaceSettings; + + /** + * The space to open settings for. + */ + space: Room; +} diff --git a/src/utils/DialogOpener.ts b/src/utils/DialogOpener.ts index b18c88ea6f..dfba761410 100644 --- a/src/utils/DialogOpener.ts +++ b/src/utils/DialogOpener.ts @@ -24,6 +24,8 @@ import { MatrixClientPeg } from "../MatrixClientPeg"; import { Action } from "../dispatcher/actions"; import ReportEventDialog from "../components/views/dialogs/ReportEventDialog"; import TabbedIntegrationManagerDialog from "../components/views/dialogs/TabbedIntegrationManagerDialog"; +import SpacePreferencesDialog from "../components/views/dialogs/SpacePreferencesDialog"; +import SpaceSettingsDialog from "../components/views/dialogs/SpaceSettingsDialog"; /** * Auxiliary class to listen for dialog opening over the dispatcher and @@ -77,6 +79,18 @@ export class DialogOpener { 'mx_TabbedIntegrationManagerDialog', ); break; + case Action.OpenSpacePreferences: + Modal.createTrackedDialog("Space preferences", "", SpacePreferencesDialog, { + initialTabId: payload.initalTabId, + space: payload.space, + }, null, false, true); + break; + case Action.OpenSpaceSettings: + Modal.createTrackedDialog("Space Settings", "", SpaceSettingsDialog, { + matrixClient: payload.space.client, + space: payload.space, + }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); + break; } }; } diff --git a/src/utils/space.tsx b/src/utils/space.tsx index 8fb737440f..d710275dba 100644 --- a/src/utils/space.tsx +++ b/src/utils/space.tsx @@ -21,7 +21,6 @@ import { JoinRule } from "matrix-js-sdk/src/@types/partials"; import { calculateRoomVia } from "./permalinks/Permalinks"; import Modal from "../Modal"; -import SpaceSettingsDialog from "../components/views/dialogs/SpaceSettingsDialog"; import AddExistingToSpaceDialog from "../components/views/dialogs/AddExistingToSpaceDialog"; import CreateRoomDialog from "../components/views/dialogs/CreateRoomDialog"; import createRoom, { IOpts } from "../createRoom"; @@ -35,11 +34,13 @@ import defaultDispatcher from "../dispatcher/dispatcher"; import { RoomViewStore } from "../stores/RoomViewStore"; import { Action } from "../dispatcher/actions"; import Spinner from "../components/views/elements/Spinner"; -import SpacePreferencesDialog, { SpacePreferenceTab } from "../components/views/dialogs/SpacePreferencesDialog"; import PosthogTrackers from "../PosthogTrackers"; import { ButtonEvent } from "../components/views/elements/AccessibleButton"; import { shouldShowComponent } from "../customisations/helpers/UIComponents"; import { UIComponent } from "../settings/UIFeature"; +import { OpenSpacePreferencesPayload, SpacePreferenceTab } from "../dispatcher/payloads/OpenSpacePreferencesPayload"; +import { OpenSpaceSettingsPayload } from "../dispatcher/payloads/OpenSpaceSettingsPayload"; +import dis from "../dispatcher/dispatcher"; export const shouldShowSpaceSettings = (space: Room) => { const userId = space.client.getUserId(); @@ -59,12 +60,12 @@ export const makeSpaceParentEvent = (room: Room, canonical = false) => ({ state_key: room.roomId, }); -export const showSpaceSettings = (space: Room) => { - Modal.createTrackedDialog("Space Settings", "", SpaceSettingsDialog, { - matrixClient: space.client, +export function showSpaceSettings(space: Room) { + dis.dispatch({ + action: Action.OpenSpaceSettings, space, - }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); -}; + }); +} export const showAddExistingRooms = (space: Room): void => { Modal.createTrackedDialog( @@ -181,9 +182,10 @@ export const bulkSpaceBehaviour = async ( } }; -export const showSpacePreferences = (space: Room, initialTabId?: SpacePreferenceTab): Promise => { - return Modal.createTrackedDialog("Space preferences", "", SpacePreferencesDialog, { - initialTabId, +export function showSpacePreferences(space: Room, initialTabId?: SpacePreferenceTab) { + dis.dispatch({ + action: Action.OpenSpacePreferences, space, - }, null, false, true).finished; -}; + initialTabId, + }); +} From cd98106afbc603bd7bc1495a4ddc056cf1357a82 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 16:30:53 -0600 Subject: [PATCH 31/47] Step 8.5: Move call transfer invite dialog construction --- src/CallHandler.tsx | 24 ++++++---- src/RoomInvite.tsx | 3 +- src/components/views/dialogs/InviteDialog.tsx | 33 +------------ .../views/dialogs/InviteDialogTypes.ts | 47 +++++++++++++++++++ src/dispatcher/actions.ts | 5 ++ .../payloads/OpenInviteDialogPayload.ts | 37 +++++++++++++++ src/utils/DialogOpener.ts | 10 ++++ 7 files changed, 117 insertions(+), 42 deletions(-) create mode 100644 src/components/views/dialogs/InviteDialogTypes.ts create mode 100644 src/dispatcher/payloads/OpenInviteDialogPayload.ts diff --git a/src/CallHandler.tsx b/src/CallHandler.tsx index a8082e668b..8e197e900f 100644 --- a/src/CallHandler.tsx +++ b/src/CallHandler.tsx @@ -44,7 +44,6 @@ import { WidgetType } from "./widgets/WidgetType"; import { SettingLevel } from "./settings/SettingLevel"; import QuestionDialog from "./components/views/dialogs/QuestionDialog"; import ErrorDialog from "./components/views/dialogs/ErrorDialog"; -import InviteDialog, { KIND_CALL_TRANSFER } from "./components/views/dialogs/InviteDialog"; import WidgetStore from "./stores/WidgetStore"; import { WidgetMessagingStore } from "./stores/widgets/WidgetMessagingStore"; import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions"; @@ -61,6 +60,8 @@ import ToastStore from './stores/ToastStore'; import Resend from './Resend'; import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload"; import { findDMForUser } from "./utils/direct-messages"; +import { KIND_CALL_TRANSFER } from "./components/views/dialogs/InviteDialogTypes"; +import { OpenInviteDialogPayload } from "./dispatcher/payloads/OpenInviteDialogPayload"; export const PROTOCOL_PSTN = 'm.protocol.pstn'; export const PROTOCOL_PSTN_PREFIXED = 'im.vector.protocol.pstn'; @@ -1092,15 +1093,18 @@ export default class CallHandler extends EventEmitter { */ public showTransferDialog(call: MatrixCall): void { call.setRemoteOnHold(true); - const { finished } = Modal.createTrackedDialog( - 'Transfer Call', '', InviteDialog, { kind: KIND_CALL_TRANSFER, call }, - /*className=*/"mx_InviteDialog_transferWrapper", /*isPriority=*/false, /*isStatic=*/true, - ); - finished.then((results: boolean[]) => { - if (results.length === 0 || results[0] === false) { - call.setRemoteOnHold(false); - } - }); + dis.dispatch({ + action: Action.OpenInviteDialog, + kind: KIND_CALL_TRANSFER, + call, + analyticsName: "Transfer Call", + className: "mx_InviteDialog_transferWrapper", + onFinishedCallback: (results) => { + if (results.length === 0 || results[0] === false) { + call.setRemoteOnHold(false); + } + }, + } as OpenInviteDialogPayload); } private addCallForRoom(roomId: string, call: MatrixCall, changedRooms = false): void { diff --git a/src/RoomInvite.tsx b/src/RoomInvite.tsx index fae3f5dfeb..8abfc5ce39 100644 --- a/src/RoomInvite.tsx +++ b/src/RoomInvite.tsx @@ -24,10 +24,11 @@ import { MatrixClientPeg } from './MatrixClientPeg'; import MultiInviter, { CompletionStates } from './utils/MultiInviter'; import Modal from './Modal'; import { _t } from './languageHandler'; -import InviteDialog, { KIND_DM, KIND_INVITE, Member } from "./components/views/dialogs/InviteDialog"; +import InviteDialog from "./components/views/dialogs/InviteDialog"; import BaseAvatar from "./components/views/avatars/BaseAvatar"; import { mediaFromMxc } from "./customisations/Media"; import ErrorDialog from "./components/views/dialogs/ErrorDialog"; +import { KIND_DM, KIND_INVITE, Member } from "./components/views/dialogs/InviteDialogTypes"; export interface IInviteResult { states: CompletionStates; diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index 23a8549343..ed79958e3c 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -66,6 +66,7 @@ import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import { privateShouldBeEncrypted } from "../../../utils/rooms"; import { findDMForUser } from "../../../utils/direct-messages"; +import { AnyInviteKind, KIND_CALL_TRANSFER, KIND_DM, KIND_INVITE, Member } from './InviteDialogTypes'; // we have a number of types defined from the Matrix spec which can't reasonably be altered here. /* eslint-disable camelcase */ @@ -76,13 +77,6 @@ interface IRecentUser { lastActive: number; } -export const KIND_DM = "dm"; -export const KIND_INVITE = "invite"; -// NB. This dialog needs the 'mx_InviteDialog_transferWrapper' wrapper class to have the correct -// padding on the bottom (because all modals have 24px padding on all sides), so this needs to -// be passed when creating the modal -export const KIND_CALL_TRANSFER = "call_transfer"; - const INITIAL_ROOMS_SHOWN = 3; // Number of rooms to show at first const INCREMENT_ROOMS_SHOWN = 5; // Number of rooms to add when 'show more' is clicked @@ -91,29 +85,6 @@ enum TabId { DialPad = 'dialpad', } -// This is the interface that is expected by various components in the Invite Dialog and RoomInvite. -// It is a bit awkward because it also matches the RoomMember class from the js-sdk with some extra support -// for 3PIDs/email addresses. -export abstract class Member { - /** - * The display name of this Member. For users this should be their profile's display - * name or user ID if none set. For 3PIDs this should be the 3PID address (email). - */ - public abstract get name(): string; - - /** - * The ID of this Member. For users this should be their user ID. For 3PIDs this should - * be the 3PID address (email). - */ - public abstract get userId(): string; - - /** - * Gets the MXC URL of this Member's avatar. For users this should be their profile's - * avatar MXC URL or null if none set. For 3PIDs this should always be null. - */ - public abstract getMxcAvatarUrl(): string; -} - class DirectoryMember extends Member { private readonly _userId: string; private readonly displayName?: string; @@ -352,7 +323,7 @@ interface IInviteDialogProps { // The kind of invite being performed. Assumed to be KIND_DM if // not provided. - kind: string; + kind: AnyInviteKind; // The room ID this dialog is for. Only required for KIND_INVITE. roomId: string; diff --git a/src/components/views/dialogs/InviteDialogTypes.ts b/src/components/views/dialogs/InviteDialogTypes.ts new file mode 100644 index 0000000000..e9ec7f4927 --- /dev/null +++ b/src/components/views/dialogs/InviteDialogTypes.ts @@ -0,0 +1,47 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export const KIND_DM = "dm"; +export const KIND_INVITE = "invite"; +// NB. This dialog needs the 'mx_InviteDialog_transferWrapper' wrapper class to have the correct +// padding on the bottom (because all modals have 24px padding on all sides), so this needs to +// be passed when creating the modal +export const KIND_CALL_TRANSFER = "call_transfer"; + +export type AnyInviteKind = typeof KIND_INVITE | typeof KIND_DM | typeof KIND_CALL_TRANSFER; + +// This is the interface that is expected by various components in the Invite Dialog and RoomInvite. +// It is a bit awkward because it also matches the RoomMember class from the js-sdk with some extra support +// for 3PIDs/email addresses. +export abstract class Member { + /** + * The display name of this Member. For users this should be their profile's display + * name or user ID if none set. For 3PIDs this should be the 3PID address (email). + */ + public abstract get name(): string; + + /** + * The ID of this Member. For users this should be their user ID. For 3PIDs this should + * be the 3PID address (email). + */ + public abstract get userId(): string; + + /** + * Gets the MXC URL of this Member's avatar. For users this should be their profile's + * avatar MXC URL or null if none set. For 3PIDs this should always be null. + */ + public abstract getMxcAvatarUrl(): string; +} diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 647dea43bf..496faa4661 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -302,4 +302,9 @@ export enum Action { * Opens the settings for the given space. Used with a OpenSpaceSettingsPayload. */ OpenSpaceSettings = "open_space_settings", + + /** + * Opens the invite dialog. Used with a OpenInviteDialogPayload. + */ + OpenInviteDialog = "open_invite_dialog", } diff --git a/src/dispatcher/payloads/OpenInviteDialogPayload.ts b/src/dispatcher/payloads/OpenInviteDialogPayload.ts new file mode 100644 index 0000000000..286781a45a --- /dev/null +++ b/src/dispatcher/payloads/OpenInviteDialogPayload.ts @@ -0,0 +1,37 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Optional } from "matrix-events-sdk"; +import { MatrixCall } from "matrix-js-sdk/src/webrtc/call"; + +import { ActionPayload } from "../payloads"; +import { Action } from "../actions"; +import { + AnyInviteKind, +} from "../../components/views/dialogs/InviteDialogTypes"; + +export interface OpenInviteDialogPayload extends ActionPayload { + action: Action.OpenInviteDialog; + + kind: AnyInviteKind; + onFinishedCallback: Optional<(results: boolean[]) => void>; + + call?: MatrixCall; + roomId?: string; + + analyticsName: string; + className: string; +} diff --git a/src/utils/DialogOpener.ts b/src/utils/DialogOpener.ts index dfba761410..1c3d8c3e8d 100644 --- a/src/utils/DialogOpener.ts +++ b/src/utils/DialogOpener.ts @@ -26,6 +26,7 @@ import ReportEventDialog from "../components/views/dialogs/ReportEventDialog"; import TabbedIntegrationManagerDialog from "../components/views/dialogs/TabbedIntegrationManagerDialog"; import SpacePreferencesDialog from "../components/views/dialogs/SpacePreferencesDialog"; import SpaceSettingsDialog from "../components/views/dialogs/SpaceSettingsDialog"; +import InviteDialog from "../components/views/dialogs/InviteDialog"; /** * Auxiliary class to listen for dialog opening over the dispatcher and @@ -91,6 +92,15 @@ export class DialogOpener { space: payload.space, }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); break; + case Action.OpenInviteDialog: + Modal.createTrackedDialog(payload.analyticsName, '', InviteDialog, { + kind: payload.kind, + call: payload.call, + roomId: payload.roomId, + }, payload.className, false, true).finished.then((results) => { + payload.onFinishedCallback?.(results); + }); + break; } }; } From 3ab21224df3d9a233d4aad9871018c59963920d9 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 16:42:53 -0600 Subject: [PATCH 32/47] Step 8.5: Move user tab enum --- src/components/structures/LoggedInView.tsx | 2 +- src/components/structures/MatrixChat.tsx | 3 +- src/components/structures/UserMenu.tsx | 2 +- .../views/dialogs/BetaFeedbackDialog.tsx | 2 +- .../views/dialogs/SpotlightDialog.tsx | 2 +- .../views/dialogs/UserSettingsDialog.tsx | 15 +--------- src/components/views/dialogs/UserTab.ts | 29 +++++++++++++++++++ .../views/elements/DesktopBuildsNotice.tsx | 2 +- src/components/views/right_panel/UserInfo.tsx | 2 +- .../tabs/room/NotificationSettingsTab.tsx | 2 +- .../tabs/user/HelpUserSettingsTab.tsx | 2 +- .../tabs/user/PreferencesUserSettingsTab.tsx | 2 +- .../views/spaces/QuickSettingsButton.tsx | 2 +- src/toasts/BulkUnverifiedSessionsToast.ts | 2 +- src/toasts/UnverifiedSessionToast.ts | 2 +- 15 files changed, 44 insertions(+), 27 deletions(-) create mode 100644 src/components/views/dialogs/UserTab.ts diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index 7de08843b5..de60ca71fa 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -62,7 +62,7 @@ import ToastContainer from './ToastContainer'; import UserView from "./UserView"; import BackdropPanel from "./BackdropPanel"; import { mediaFromMxc } from "../../customisations/Media"; -import { UserTab } from "../views/dialogs/UserSettingsDialog"; +import { UserTab } from "../views/dialogs/UserTab"; import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload"; import RightPanelStore from '../../stores/right-panel/RightPanelStore'; import { TimelineRenderingType } from "../../contexts/RoomContext"; diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 82a832d85e..56c41739dd 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -93,7 +93,8 @@ import { RoomUpdateCause } from "../../stores/room-list/models"; import SecurityCustomisations from "../../customisations/Security"; import Spinner from "../views/elements/Spinner"; import QuestionDialog from "../views/dialogs/QuestionDialog"; -import UserSettingsDialog, { UserTab } from '../views/dialogs/UserSettingsDialog'; +import UserSettingsDialog from '../views/dialogs/UserSettingsDialog'; +import { UserTab } from "../views/dialogs/UserTab"; import CreateRoomDialog from '../views/dialogs/CreateRoomDialog'; import RoomDirectory from './RoomDirectory'; import KeySignatureUploadFailedDialog from "../views/dialogs/KeySignatureUploadFailedDialog"; diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index c00bb6170e..27cc08f0bc 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -25,7 +25,7 @@ import { ActionPayload } from "../../dispatcher/payloads"; import { Action } from "../../dispatcher/actions"; import { _t } from "../../languageHandler"; import { ChevronFace, ContextMenuButton } from "./ContextMenu"; -import { UserTab } from "../views/dialogs/UserSettingsDialog"; +import { UserTab } from "../views/dialogs/UserTab"; import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload"; import FeedbackDialog from "../views/dialogs/FeedbackDialog"; import Modal from "../../Modal"; diff --git a/src/components/views/dialogs/BetaFeedbackDialog.tsx b/src/components/views/dialogs/BetaFeedbackDialog.tsx index c5fba52b51..487ba37b01 100644 --- a/src/components/views/dialogs/BetaFeedbackDialog.tsx +++ b/src/components/views/dialogs/BetaFeedbackDialog.tsx @@ -22,7 +22,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import AccessibleButton from "../elements/AccessibleButton"; import defaultDispatcher from "../../../dispatcher/dispatcher"; import { Action } from "../../../dispatcher/actions"; -import { UserTab } from "./UserSettingsDialog"; +import { UserTab } from "./UserTab"; import GenericFeatureFeedbackDialog from "./GenericFeatureFeedbackDialog"; // XXX: Keep this around for re-use in future Betas diff --git a/src/components/views/dialogs/SpotlightDialog.tsx b/src/components/views/dialogs/SpotlightDialog.tsx index 8b4e8ed701..f579e26287 100644 --- a/src/components/views/dialogs/SpotlightDialog.tsx +++ b/src/components/views/dialogs/SpotlightDialog.tsx @@ -64,7 +64,7 @@ import { SettingLevel } from "../../../settings/SettingLevel"; import NotificationBadge from "../rooms/NotificationBadge"; import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore"; import { BetaPill } from "../beta/BetaCard"; -import { UserTab } from "./UserSettingsDialog"; +import { UserTab } from "./UserTab"; import BetaFeedbackDialog from "./BetaFeedbackDialog"; import SdkConfig from "../../../SdkConfig"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; diff --git a/src/components/views/dialogs/UserSettingsDialog.tsx b/src/components/views/dialogs/UserSettingsDialog.tsx index a170b71929..8f5e1a6108 100644 --- a/src/components/views/dialogs/UserSettingsDialog.tsx +++ b/src/components/views/dialogs/UserSettingsDialog.tsx @@ -35,20 +35,7 @@ import BaseDialog from "./BaseDialog"; import { IDialogProps } from "./IDialogProps"; import SidebarUserSettingsTab from "../settings/tabs/user/SidebarUserSettingsTab"; import KeyboardUserSettingsTab from "../settings/tabs/user/KeyboardUserSettingsTab"; - -export enum UserTab { - General = "USER_GENERAL_TAB", - Appearance = "USER_APPEARANCE_TAB", - Notifications = "USER_NOTIFICATIONS_TAB", - Preferences = "USER_PREFERENCES_TAB", - Keyboard = "USER_KEYBOARD_TAB", - Sidebar = "USER_SIDEBAR_TAB", - Voice = "USER_VOICE_TAB", - Security = "USER_SECURITY_TAB", - Labs = "USER_LABS_TAB", - Mjolnir = "USER_MJOLNIR_TAB", - Help = "USER_HELP_TAB", -} +import { UserTab } from "./UserTab"; interface IProps extends IDialogProps { initialTabId?: UserTab; diff --git a/src/components/views/dialogs/UserTab.ts b/src/components/views/dialogs/UserTab.ts new file mode 100644 index 0000000000..b5b2782c0d --- /dev/null +++ b/src/components/views/dialogs/UserTab.ts @@ -0,0 +1,29 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export enum UserTab { + General = "USER_GENERAL_TAB", + Appearance = "USER_APPEARANCE_TAB", + Notifications = "USER_NOTIFICATIONS_TAB", + Preferences = "USER_PREFERENCES_TAB", + Keyboard = "USER_KEYBOARD_TAB", + Sidebar = "USER_SIDEBAR_TAB", + Voice = "USER_VOICE_TAB", + Security = "USER_SECURITY_TAB", + Labs = "USER_LABS_TAB", + Mjolnir = "USER_MJOLNIR_TAB", + Help = "USER_HELP_TAB", +} diff --git a/src/components/views/elements/DesktopBuildsNotice.tsx b/src/components/views/elements/DesktopBuildsNotice.tsx index ac9b591e95..cb664f02d0 100644 --- a/src/components/views/elements/DesktopBuildsNotice.tsx +++ b/src/components/views/elements/DesktopBuildsNotice.tsx @@ -22,7 +22,7 @@ import { _t } from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; import dis from "../../../dispatcher/dispatcher"; import { Action } from "../../../dispatcher/actions"; -import { UserTab } from "../dialogs/UserSettingsDialog"; +import { UserTab } from "../dialogs/UserTab"; import AccessibleButton from "./AccessibleButton"; export enum WarningKind { diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 01da603300..12a2a12f6e 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -49,7 +49,7 @@ import EncryptionPanel from "./EncryptionPanel"; import { useAsyncMemo } from '../../../hooks/useAsyncMemo'; import { legacyVerifyUser, verifyDevice, verifyUser } from '../../../verification'; import { Action } from "../../../dispatcher/actions"; -import { UserTab } from "../dialogs/UserSettingsDialog"; +import { UserTab } from "../dialogs/UserTab"; import { useIsEncrypted } from "../../../hooks/useIsEncrypted"; import BaseCard from "./BaseCard"; import { E2EStatus } from "../../../utils/ShieldUtils"; diff --git a/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx b/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx index 6084d500ce..b13277e744 100644 --- a/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx @@ -30,7 +30,7 @@ import StyledRadioGroup from "../../../elements/StyledRadioGroup"; import { RoomNotifState } from '../../../../../RoomNotifs'; import defaultDispatcher from "../../../../../dispatcher/dispatcher"; import { Action } from "../../../../../dispatcher/actions"; -import { UserTab } from "../../../dialogs/UserSettingsDialog"; +import { UserTab } from "../../../dialogs/UserTab"; interface IProps { roomId: string; diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx index 527dd1ae44..346c0c5bb1 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx @@ -28,7 +28,7 @@ import UpdateCheckButton from "../../UpdateCheckButton"; import BugReportDialog from '../../../dialogs/BugReportDialog'; import { OpenToTabPayload } from "../../../../../dispatcher/payloads/OpenToTabPayload"; import { Action } from "../../../../../dispatcher/actions"; -import { UserTab } from "../../../dialogs/UserSettingsDialog"; +import { UserTab } from "../../../dialogs/UserTab"; import dis from "../../../../../dispatcher/dispatcher"; import CopyableText from "../../../elements/CopyableText"; diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx index e6457605cc..a7a54da66e 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx @@ -26,7 +26,7 @@ import { SettingLevel } from "../../../../../settings/SettingLevel"; import SettingsFlag from '../../../elements/SettingsFlag'; import AccessibleButton from "../../../elements/AccessibleButton"; import dis from "../../../../../dispatcher/dispatcher"; -import { UserTab } from "../../../dialogs/UserSettingsDialog"; +import { UserTab } from "../../../dialogs/UserTab"; import { OpenToTabPayload } from "../../../../../dispatcher/payloads/OpenToTabPayload"; import { Action } from "../../../../../dispatcher/actions"; diff --git a/src/components/views/spaces/QuickSettingsButton.tsx b/src/components/views/spaces/QuickSettingsButton.tsx index 8c3ee07199..2f4ee9315f 100644 --- a/src/components/views/spaces/QuickSettingsButton.tsx +++ b/src/components/views/spaces/QuickSettingsButton.tsx @@ -27,7 +27,7 @@ import { useSettingValue } from "../../../hooks/useSettings"; import { onMetaSpaceChangeFactory } from "../settings/tabs/user/SidebarUserSettingsTab"; import defaultDispatcher from "../../../dispatcher/dispatcher"; import { Action } from "../../../dispatcher/actions"; -import { UserTab } from "../dialogs/UserSettingsDialog"; +import { UserTab } from "../dialogs/UserTab"; import QuickThemeSwitcher from "./QuickThemeSwitcher"; import { Icon as PinUprightIcon } from '../../../../res/img/element-icons/room/pin-upright.svg'; import { Icon as EllipsisIcon } from '../../../../res/img/element-icons/room/ellipsis.svg'; diff --git a/src/toasts/BulkUnverifiedSessionsToast.ts b/src/toasts/BulkUnverifiedSessionsToast.ts index 0a35a91345..6ddb0d7db5 100644 --- a/src/toasts/BulkUnverifiedSessionsToast.ts +++ b/src/toasts/BulkUnverifiedSessionsToast.ts @@ -20,7 +20,7 @@ import DeviceListener from '../DeviceListener'; import GenericToast from "../components/views/toasts/GenericToast"; import ToastStore from "../stores/ToastStore"; import { Action } from "../dispatcher/actions"; -import { UserTab } from "../components/views/dialogs/UserSettingsDialog"; +import { UserTab } from "../components/views/dialogs/UserTab"; const TOAST_KEY = "reviewsessions"; diff --git a/src/toasts/UnverifiedSessionToast.ts b/src/toasts/UnverifiedSessionToast.ts index 05425b93c0..d0db97cd08 100644 --- a/src/toasts/UnverifiedSessionToast.ts +++ b/src/toasts/UnverifiedSessionToast.ts @@ -21,7 +21,7 @@ import DeviceListener from '../DeviceListener'; import ToastStore from "../stores/ToastStore"; import GenericToast from "../components/views/toasts/GenericToast"; import { Action } from "../dispatcher/actions"; -import { UserTab } from "../components/views/dialogs/UserSettingsDialog"; +import { UserTab } from "../components/views/dialogs/UserTab"; function toastKey(deviceId: string) { return "unverified_session_" + deviceId; From 9a75acba17709891a47b01325961e62f77eb5cc7 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 18:01:09 -0600 Subject: [PATCH 33/47] Step 8.5: Move "add existing to space" dialog construction --- src/dispatcher/actions.ts | 5 ++++ .../OpenAddExistingToSpaceDialogPayload.ts | 26 ++++++++++++++++++ src/utils/DialogOpener.ts | 27 +++++++++++++++++++ src/utils/space.tsx | 27 ++++--------------- 4 files changed, 63 insertions(+), 22 deletions(-) create mode 100644 src/dispatcher/payloads/OpenAddExistingToSpaceDialogPayload.ts diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 496faa4661..3fdbccb71b 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -307,4 +307,9 @@ export enum Action { * Opens the invite dialog. Used with a OpenInviteDialogPayload. */ OpenInviteDialog = "open_invite_dialog", + + /** + * Opens a dialog to add an existing object to a space. Used with a OpenAddExistingToSpaceDialogPayload. + */ + OpenAddToExistingSpaceDialog = "open_add_to_existing_space_dialog", } diff --git a/src/dispatcher/payloads/OpenAddExistingToSpaceDialogPayload.ts b/src/dispatcher/payloads/OpenAddExistingToSpaceDialogPayload.ts new file mode 100644 index 0000000000..383677e147 --- /dev/null +++ b/src/dispatcher/payloads/OpenAddExistingToSpaceDialogPayload.ts @@ -0,0 +1,26 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Room } from "matrix-js-sdk/src/models/room"; + +import { ActionPayload } from "../payloads"; +import { Action } from "../actions"; + +export interface OpenAddExistingToSpaceDialogPayload extends ActionPayload { + action: Action.OpenAddToExistingSpaceDialog; + + space: Room; +} diff --git a/src/utils/DialogOpener.ts b/src/utils/DialogOpener.ts index 1c3d8c3e8d..263982add2 100644 --- a/src/utils/DialogOpener.ts +++ b/src/utils/DialogOpener.ts @@ -27,6 +27,10 @@ import TabbedIntegrationManagerDialog from "../components/views/dialogs/TabbedIn import SpacePreferencesDialog from "../components/views/dialogs/SpacePreferencesDialog"; import SpaceSettingsDialog from "../components/views/dialogs/SpaceSettingsDialog"; import InviteDialog from "../components/views/dialogs/InviteDialog"; +import AddExistingToSpaceDialog from "../components/views/dialogs/AddExistingToSpaceDialog"; +import { ButtonEvent } from "../components/views/elements/AccessibleButton"; +import PosthogTrackers from "../PosthogTrackers"; +import { showAddExistingSubspace, showCreateNewRoom } from "./space"; /** * Auxiliary class to listen for dialog opening over the dispatcher and @@ -101,6 +105,29 @@ export class DialogOpener { payload.onFinishedCallback?.(results); }); break; + case Action.OpenAddToExistingSpaceDialog: { + const space = payload.space; + Modal.createTrackedDialog( + "Space Landing", + "Add Existing", + AddExistingToSpaceDialog, + { + onCreateRoomClick: (ev: ButtonEvent) => { + showCreateNewRoom(space); + PosthogTrackers.trackInteraction("WebAddExistingToSpaceDialogCreateRoomButton", ev); + }, + onAddSubspaceClick: () => showAddExistingSubspace(space), + space, + onFinished: (added: boolean) => { + if (added && RoomViewStore.instance.getRoomId() === space.roomId) { + defaultDispatcher.fire(Action.UpdateSpaceHierarchy); + } + }, + }, + "mx_AddExistingToSpaceDialog_wrapper", + ); + break; + } } }; } diff --git a/src/utils/space.tsx b/src/utils/space.tsx index d710275dba..b407e23ffb 100644 --- a/src/utils/space.tsx +++ b/src/utils/space.tsx @@ -21,7 +21,6 @@ import { JoinRule } from "matrix-js-sdk/src/@types/partials"; import { calculateRoomVia } from "./permalinks/Permalinks"; import Modal from "../Modal"; -import AddExistingToSpaceDialog from "../components/views/dialogs/AddExistingToSpaceDialog"; import CreateRoomDialog from "../components/views/dialogs/CreateRoomDialog"; import createRoom, { IOpts } from "../createRoom"; import { _t } from "../languageHandler"; @@ -34,13 +33,12 @@ import defaultDispatcher from "../dispatcher/dispatcher"; import { RoomViewStore } from "../stores/RoomViewStore"; import { Action } from "../dispatcher/actions"; import Spinner from "../components/views/elements/Spinner"; -import PosthogTrackers from "../PosthogTrackers"; -import { ButtonEvent } from "../components/views/elements/AccessibleButton"; import { shouldShowComponent } from "../customisations/helpers/UIComponents"; import { UIComponent } from "../settings/UIFeature"; import { OpenSpacePreferencesPayload, SpacePreferenceTab } from "../dispatcher/payloads/OpenSpacePreferencesPayload"; import { OpenSpaceSettingsPayload } from "../dispatcher/payloads/OpenSpaceSettingsPayload"; import dis from "../dispatcher/dispatcher"; +import { OpenAddExistingToSpaceDialogPayload } from "../dispatcher/payloads/OpenAddExistingToSpaceDialogPayload"; export const shouldShowSpaceSettings = (space: Room) => { const userId = space.client.getUserId(); @@ -68,25 +66,10 @@ export function showSpaceSettings(space: Room) { } export const showAddExistingRooms = (space: Room): void => { - Modal.createTrackedDialog( - "Space Landing", - "Add Existing", - AddExistingToSpaceDialog, - { - onCreateRoomClick: (ev: ButtonEvent) => { - showCreateNewRoom(space); - PosthogTrackers.trackInteraction("WebAddExistingToSpaceDialogCreateRoomButton", ev); - }, - onAddSubspaceClick: () => showAddExistingSubspace(space), - space, - onFinished: (added: boolean) => { - if (added && RoomViewStore.instance.getRoomId() === space.roomId) { - defaultDispatcher.fire(Action.UpdateSpaceHierarchy); - } - }, - }, - "mx_AddExistingToSpaceDialog_wrapper", - ); + dis.dispatch({ + action: Action.OpenAddToExistingSpaceDialog, + space, + } as OpenAddExistingToSpaceDialogPayload); }; export const showCreateNewRoom = async (space: Room): Promise => { From b2b818a780dcf2ddf0e8bcd1bd1a9bce0bb22f6b Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 20:11:56 -0600 Subject: [PATCH 34/47] Step 8.6: Fix TS issues introduced by using imports --- .../views/messages/DateSeparator-test.tsx | 1 + .../views/messages/MPollBody-test.tsx | 8 ++++ .../__snapshots__/DateSeparator-test.tsx.snap | 2 + .../__snapshots__/MPollBody-test.tsx.snap | 42 +++++++++++++++++++ .../rooms/MessageComposerButtons-test.tsx | 24 ++++++++--- 5 files changed, 71 insertions(+), 6 deletions(-) diff --git a/test/components/views/messages/DateSeparator-test.tsx b/test/components/views/messages/DateSeparator-test.tsx index 8e5b7ea3ca..abd809ac95 100644 --- a/test/components/views/messages/DateSeparator-test.tsx +++ b/test/components/views/messages/DateSeparator-test.tsx @@ -36,6 +36,7 @@ describe("DateSeparator", () => { const defaultProps = { ts: nowMs, now, + roomId: "!unused:example.org", }; const RealDate = global.Date; class MockDate extends Date { diff --git a/test/components/views/messages/MPollBody-test.tsx b/test/components/views/messages/MPollBody-test.tsx index 28c0ceea34..5fa55cd46f 100644 --- a/test/components/views/messages/MPollBody-test.tsx +++ b/test/components/views/messages/MPollBody-test.tsx @@ -1072,6 +1072,14 @@ function newMPollBodyFromEvent( } } } + + // We don't use any of these props, but they're required. + highlightLink="unused" + highlights={[]} + mediaEventHelper={null} + onHeightChanged={() => {}} + onMessageAllowed={() => {}} + permalinkCreator={null} />, { wrappingComponent: MatrixClientContext.Provider, wrappingComponentProps: { diff --git a/test/components/views/messages/__snapshots__/DateSeparator-test.tsx.snap b/test/components/views/messages/__snapshots__/DateSeparator-test.tsx.snap index c1ce2c860c..d848ae092f 100644 --- a/test/components/views/messages/__snapshots__/DateSeparator-test.tsx.snap +++ b/test/components/views/messages/__snapshots__/DateSeparator-test.tsx.snap @@ -3,6 +3,7 @@ exports[`DateSeparator renders the date separator correctly 1`] = `

for types because it'll annoy TS more than it helps. +const mockProps: React.ComponentProps = { + addEmoji: () => false, + haveRecording: false, + isStickerPickerOpen: false, + menuPosition: null, + onRecordStartEndClick: () => {}, + setStickerPickerOpen: () => {}, + toggleButtonMenu: () => {}, +}; + describe("MessageComposerButtons", () => { it("Renders emoji and upload buttons in wide mode", () => { const buttons = wrapAndRender( @@ -35,7 +47,7 @@ describe("MessageComposerButtons", () => { showLocationButton={true} showPollsButton={true} showStickersButton={true} - toggleButtonMenu={() => {}} + {...mockProps} />, false, ); @@ -54,7 +66,7 @@ describe("MessageComposerButtons", () => { showLocationButton={true} showPollsButton={true} showStickersButton={true} - toggleButtonMenu={() => {}} + {...mockProps} />, false, ); @@ -79,7 +91,7 @@ describe("MessageComposerButtons", () => { showLocationButton={true} showPollsButton={true} showStickersButton={true} - toggleButtonMenu={() => {}} + {...mockProps} />, true, ); @@ -97,7 +109,7 @@ describe("MessageComposerButtons", () => { showLocationButton={true} showPollsButton={true} showStickersButton={true} - toggleButtonMenu={() => {}} + {...mockProps} />, true, ); @@ -122,7 +134,7 @@ describe("MessageComposerButtons", () => { showLocationButton={true} showPollsButton={true} showStickersButton={true} - toggleButtonMenu={() => {}} + {...mockProps} />, true, ); @@ -146,7 +158,7 @@ describe("MessageComposerButtons", () => { showLocationButton={true} showPollsButton={false} // !! the change from the alternate test showStickersButton={true} - toggleButtonMenu={() => {}} + {...mockProps} />, true, ); From 661b8d595c8277161c276f35b907514d2d83cd62 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 20:37:52 -0600 Subject: [PATCH 35/47] Step 8.7: Introduce `focus-visible` import where needed to repair tests There is an import in `MatrixChat` which no longer gets executed when we don't skin the entire app, so bring it in manually. --- src/components/structures/MatrixChat.tsx | 2 +- test/components/structures/ThreadPanel-test.tsx | 1 + test/components/views/context_menus/SpaceContextMenu-test.tsx | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 56c41739dd..01b3f4cd07 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -32,7 +32,7 @@ import { logger } from "matrix-js-sdk/src/logger"; import { throttle } from "lodash"; import { CryptoEvent } from "matrix-js-sdk/src/crypto"; -// focus-visible is a Polyfill for the :focus-visible CSS pseudo-attribute used by _AccessibleButton.scss +// focus-visible is a Polyfill for the :focus-visible CSS pseudo-attribute used by various components import 'focus-visible'; // what-input helps improve keyboard accessibility import 'what-input'; diff --git a/test/components/structures/ThreadPanel-test.tsx b/test/components/structures/ThreadPanel-test.tsx index 24616cca1a..6a2a65a9ee 100644 --- a/test/components/structures/ThreadPanel-test.tsx +++ b/test/components/structures/ThreadPanel-test.tsx @@ -16,6 +16,7 @@ limitations under the License. import React from 'react'; import { shallow, mount } from "enzyme"; +import 'focus-visible'; // to fix context menus import { ThreadFilterType, diff --git a/test/components/views/context_menus/SpaceContextMenu-test.tsx b/test/components/views/context_menus/SpaceContextMenu-test.tsx index 53b762ef86..4dff077f0f 100644 --- a/test/components/views/context_menus/SpaceContextMenu-test.tsx +++ b/test/components/views/context_menus/SpaceContextMenu-test.tsx @@ -19,6 +19,7 @@ import { mount } from 'enzyme'; import { Room } from 'matrix-js-sdk/src/matrix'; import { mocked } from 'jest-mock'; import { act } from 'react-dom/test-utils'; +import 'focus-visible'; // to fix context menus import SpaceContextMenu from '../../../../src/components/views/context_menus/SpaceContextMenu'; import MatrixClientContext from '../../../../src/contexts/MatrixClientContext'; From 63091e7b66eb2d1f50ccaecd1c1f819226f082bb Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 24 Mar 2022 23:56:09 -0600 Subject: [PATCH 36/47] Step 10.2: Move matrix logo replacement into react-sdk --- res/img/matrix.svg | 153 ++++++++++++++++++ src/components/structures/EmbeddedPage.tsx | 3 +- src/components/structures/static-page-vars.ts | 26 +++ src/components/views/auth/Welcome.tsx | 2 + 4 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 res/img/matrix.svg create mode 100644 src/components/structures/static-page-vars.ts diff --git a/res/img/matrix.svg b/res/img/matrix.svg new file mode 100644 index 0000000000..13adcab25a --- /dev/null +++ b/res/img/matrix.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/structures/EmbeddedPage.tsx b/src/components/structures/EmbeddedPage.tsx index 9ba250c985..2053140ba4 100644 --- a/src/components/structures/EmbeddedPage.tsx +++ b/src/components/structures/EmbeddedPage.tsx @@ -57,8 +57,7 @@ export default class EmbeddedPage extends React.PureComponent { }; } - protected translate(s: string): string { - // default implementation - skins may wish to extend this + private translate(s: string): string { return sanitizeHtml(_t(s)); } diff --git a/src/components/structures/static-page-vars.ts b/src/components/structures/static-page-vars.ts new file mode 100644 index 0000000000..801eeb155a --- /dev/null +++ b/src/components/structures/static-page-vars.ts @@ -0,0 +1,26 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// We're importing via require specifically so the svg becomes a URI rather than a DOM element. +// eslint-disable-next-line @typescript-eslint/no-var-requires +const matrixSvg = require('../../../res/img/matrix.svg').default; + +/** + * Intended to replace $matrixLogo in the welcome page. + */ +export const MATRIX_LOGO_HTML = ` + Matrix +`; diff --git a/src/components/views/auth/Welcome.tsx b/src/components/views/auth/Welcome.tsx index e76dabb4db..dfe2c10782 100644 --- a/src/components/views/auth/Welcome.tsx +++ b/src/components/views/auth/Welcome.tsx @@ -24,6 +24,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import { UIFeature } from "../../../settings/UIFeature"; import LanguageSelector from "./LanguageSelector"; import EmbeddedPage from "../../structures/EmbeddedPage"; +import { MATRIX_LOGO_HTML } from "../../structures/static-page-vars"; // translatable strings for Welcome pages _td("Sign in with SSO"); @@ -54,6 +55,7 @@ export default class Welcome extends React.PureComponent { replaceMap={{ "$riot:ssoUrl": "#/start_sso", "$riot:casUrl": "#/start_cas", + "$matrixLogo": MATRIX_LOGO_HTML, }} /> From 7aeb2c3cdeaeaf0f738362c892d68c3f8e4243c6 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 28 Mar 2022 14:26:03 -0600 Subject: [PATCH 37/47] Step 10.4: Fix end-to-end test branch matching --- scripts/fetchdep.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/fetchdep.sh b/scripts/fetchdep.sh index 15e998ddbe..5d2e65c284 100755 --- a/scripts/fetchdep.sh +++ b/scripts/fetchdep.sh @@ -57,7 +57,10 @@ BRANCH_ARRAY=(${head//:/ }) TRY_ORG=$deforg TRY_BRANCH=${BRANCH_ARRAY[0]} if [[ "$head" == *":"* ]]; then - TRY_ORG=${BRANCH_ARRAY[0]} + # ... but only match that fork if it's a real fork + if [ "${BRANCH_ARRAY[0]}" != "matrix-org" ]; then + TRY_ORG=${BRANCH_ARRAY[0]} + fi TRY_BRANCH=${BRANCH_ARRAY[1]} fi clone ${TRY_ORG} $defrepo ${TRY_BRANCH} From ea6e6429eec489dff078d18cc6126967cc3822c9 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 28 Mar 2022 14:33:09 -0600 Subject: [PATCH 38/47] Step 11: Update i18n & code cleanup --- src/i18n/strings/en_EN.json | 14 +++++++------- test/components/views/rooms/RoomTile-test.tsx | 2 +- .../views/voip/VoiceChannelRadio-test.tsx | 8 ++++++-- test/test-utils/index.ts | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index a99a2480a6..8329ef0ce9 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -387,10 +387,6 @@ "Failed to invite users to the room:": "Failed to invite users to the room:", "We sent the others, but the below people couldn't be invited to ": "We sent the others, but the below people couldn't be invited to ", "Some invites couldn't be sent": "Some invites couldn't be sent", - "%(space1Name)s and %(space2Name)s": "%(space1Name)s and %(space2Name)s", - "%(spaceName)s and %(count)s others|other": "%(spaceName)s and %(count)s others", - "%(spaceName)s and %(count)s others|zero": "%(spaceName)s", - "%(spaceName)s and %(count)s others|one": "%(spaceName)s and %(count)s other", "You need to be logged in.": "You need to be logged in.", "You need to be able to invite users to do that.": "You need to be able to invite users to do that.", "Unable to create widget.": "Unable to create widget.", @@ -685,14 +681,18 @@ "%(num)s hours from now": "%(num)s hours from now", "about a day from now": "about a day from now", "%(num)s days from now": "%(num)s days from now", + "%(space1Name)s and %(space2Name)s": "%(space1Name)s and %(space2Name)s", + "%(spaceName)s and %(count)s others|other": "%(spaceName)s and %(count)s others", + "%(spaceName)s and %(count)s others|zero": "%(spaceName)s", + "%(spaceName)s and %(count)s others|one": "%(spaceName)s and %(count)s other", "%(name)s (%(userId)s)": "%(name)s (%(userId)s)", - "Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions", - "Not a valid %(brand)s keyfile": "Not a valid %(brand)s keyfile", - "Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?", "Unexpected server error trying to leave the room": "Unexpected server error trying to leave the room", "Can't leave Server Notices room": "Can't leave Server Notices room", "This room is used for important messages from the Homeserver, so you cannot leave it.": "This room is used for important messages from the Homeserver, so you cannot leave it.", "Error leaving room": "Error leaving room", + "Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions", + "Not a valid %(brand)s keyfile": "Not a valid %(brand)s keyfile", + "Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?", "Unrecognised address": "Unrecognised address", "You do not have permission to invite people to this room.": "You do not have permission to invite people to this room.", "User %(userId)s is already invited to the room": "User %(userId)s is already invited to the room", diff --git a/test/components/views/rooms/RoomTile-test.tsx b/test/components/views/rooms/RoomTile-test.tsx index 1bac119dee..8eddf2ce02 100644 --- a/test/components/views/rooms/RoomTile-test.tsx +++ b/test/components/views/rooms/RoomTile-test.tsx @@ -26,8 +26,8 @@ import { mockStateEventImplementation, mkRoom, mkEvent, + stubVoiceChannelStore, } from "../../../test-utils"; -import { stubVoiceChannelStore } from "../../../test-utils/voice"; import RoomTile from "../../../../src/components/views/rooms/RoomTile"; import MemberAvatar from "../../../../src/components/views/avatars/MemberAvatar"; import SettingsStore from "../../../../src/settings/SettingsStore"; diff --git a/test/components/views/voip/VoiceChannelRadio-test.tsx b/test/components/views/voip/VoiceChannelRadio-test.tsx index 50779dd9f7..6150d251e7 100644 --- a/test/components/views/voip/VoiceChannelRadio-test.tsx +++ b/test/components/views/voip/VoiceChannelRadio-test.tsx @@ -19,8 +19,12 @@ import { mount } from "enzyme"; import { act } from "react-dom/test-utils"; import { mocked } from "jest-mock"; -import { stubClient, mkStubRoom, wrapInMatrixClientContext } from "../../../test-utils"; -import { stubVoiceChannelStore } from "../../../test-utils/voice"; +import { + stubClient, + mkStubRoom, + wrapInMatrixClientContext, + stubVoiceChannelStore, +} from "../../../test-utils"; import _VoiceChannelRadio from "../../../../src/components/views/voip/VoiceChannelRadio"; import VoiceChannelStore from "../../../../src/stores/VoiceChannelStore"; import DMRoomMap from "../../../../src/utils/DMRoomMap"; diff --git a/test/test-utils/index.ts b/test/test-utils/index.ts index 49abc51598..44069f10fc 100644 --- a/test/test-utils/index.ts +++ b/test/test-utils/index.ts @@ -3,6 +3,6 @@ export * from './client'; export * from './location'; export * from './platform'; export * from './test-utils'; -// TODO @@TR: Export voice.ts, which currently isn't exported here because it causes all tests to depend on skinning +export * from './voice'; export * from './wrappers'; export * from './utilities'; From bd1fd0a7345dd131619114609ae5b8b4eec9d7a1 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 28 Mar 2022 15:17:40 -0600 Subject: [PATCH 39/47] Step 13: Update documentation for skinning --- README.md | 7 ---- docs/skinning.md | 79 ++++++++------------------------------------ res/css/_common.scss | 2 +- 3 files changed, 14 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index 9059c5b5b8..1bfc9c5260 100644 --- a/README.md +++ b/README.md @@ -65,10 +65,6 @@ practices that anyone working with the SDK needs to be be aware of and uphold: component is a view or a structure, and then a broad functional grouping (e.g. 'rooms' here) - * After creating a new component you must run `yarn reskindex` to regenerate - the `component-index.js` for the SDK (used in future for skinning) - - * The view's CSS file MUST have the same name (e.g. view/rooms/MessageTile.css). CSS for matrix-react-sdk currently resides in https://github.com/vector-im/element-web/tree/master/src/skins/vector/css/matrix-react-sdk. @@ -158,9 +154,6 @@ cd matrix-react-sdk git checkout develop yarn link matrix-js-sdk yarn install - -# Generate the `component-index.js` file. -yarn reskindex ``` See the [help for `yarn link`](https://classic.yarnpkg.com/docs/cli/link) for diff --git a/docs/skinning.md b/docs/skinning.md index 229bc78372..0186186c24 100644 --- a/docs/skinning.md +++ b/docs/skinning.md @@ -1,71 +1,18 @@ # Skinning -The react-sdk can be skinned to replace presentation components, CSS, or -other relevant parts of the SDK. Typically consumers will replace entire -components and get the ability for custom CSS as a result. +Skinning in the context of the react-sdk is component replacement rather than CSS. This means you can override (replace) +any accessible component in the project to implement custom behaviour, look & feel, etc. Depending on your approach, +overriding CSS classes to apply custom styling is also possible, though harder to do. -This doc isn't exhaustive on how skinning works, though it should cover -some of the more complicated parts such as component replacement. +At present, the react-sdk offers no stable interface for components - this means properties and state can and do change +at any time without notice. Once we determine the react-sdk to be stable enough to use as a proper SDK, we will adjust +this policy. In the meantime, skinning is done completely at your own risk. -## Loading a skin +The approach you take is up to you - we suggest using a module replacement plugin, as found in +[webpack](https://webpack.js.org/plugins/normal-module-replacement-plugin/), though you're free to use whichever build +system works for you. The react-sdk does not have any particular functions to call to load skins, so simply replace or +extend the components/stores/etc you're after and build. As a reminder though, this is done completely at your own risk +as we cannot guarantee a stable interface at this time. -1. Generate a `component-index.js` (preferably using the tools that the react-sdk -exposes). This can typically be done with a npm script like `"reskindex -h src/header"`. -2. In your app's entry point, add something like this code: - ```javascript - import {loadSkin} from "matrix-react-sdk"; - loadSkin(import("component-index").components); - // The rest of your imports go under this. - ``` -3. Import the remainder of the SDK and bootstrap your app. - -It is extremely important that you **do not** import anything else from the -SDK prior to loading your skin as otherwise the skin might not work. Loading -the skin should be one of the first things your app does, if not the very -first thing. - -Additionally, **do not** provide `loadSkin` with the react-sdk components -themselves otherwise the app might explode. The SDK is already aware of its -components and doesn't need to be told. - -## Replacing components - -Components that replace the react-sdk ones MUST have a `replaces` static -key on the component's class to describe which component it overrides. For -example, if your `VectorAuthPage` component is meant to replace the react-sdk -`AuthPage` component then you'd add `static replaces = 'views.auth.AuthPage';` -to the `VectorAuthPage` class. - -Other than that, the skin just needs to be loaded normally as mentioned above. -Consumers of the SDK likely will not be interested in the rest of this section. - -### SDK developer notes - -Components in the react-sdk MUST be decorated with the `@replaceableComponent` -function. For components that can't use the decorator, they must use a -variation that provides similar functionality. The decorator gives consumers -an opportunity to load skinned components by abusing import ordering and -behaviour. - -Decorators are executed at import time which is why we can abuse the import -ordering behaviour: importing `loadSkin` doesn't trigger any components to -be imported, allowing the consumer to specify a skin. When the consumer does -import a component (for example, `MatrixChat`), it starts to pull in all the -components via `import` statements. When the components get pulled in the -decorator checks with the skinned components to see if it should be replacing -the component being imported. The decorator then effectively replaces the -components when needed by specifying the skinned component as an override for -the SDK's component, which should in theory override critical functions like -`render()` and lifecycle event handlers. - -The decorator also means that older usage of `getComponent()` is no longer -required because components should be replaced by the decorator. Eventually -the react-sdk should only have one usage of `getComponent()`: the decorator. - -The decorator assumes that if `getComponent()` returns null that there is -no skinned version of the component and continues on using the SDK's component. -In previous versions of the SDK, the function would throw an error instead -because it also expected the skin to list the SDK's components as well, however -that is no longer possible due to the above. - -In short, components should always be `import`ed. +Taking a look at [element-web](https://github.com/vector-im/element-web)'s approach to skinning may be worthwhile, as it +overrides some relatively simple components. diff --git a/res/css/_common.scss b/res/css/_common.scss index a4b470d052..5372de51df 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -254,7 +254,7 @@ legend { } // These are magic constants which are excluded from tinting, to let themes -// (which only have CSS, unlike skins) tell the app what their non-tinted +// (which only have CSS) tell the app what their non-tinted // colourscheme is by inspecting the stylesheet DOM. // // They are not used for layout!! From a6564d9ab9fe54e15947300aa74c1c8cba516748 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 28 Mar 2022 15:24:02 -0600 Subject: [PATCH 40/47] Step 14: Remove reskindex --- .eslintignore | 3 +- .github/workflows/test_coverage.yml | 2 +- .gitignore | 1 + header | 17 ----- package.json | 10 +-- scripts/ci/layered.sh | 1 - scripts/reskindex.js | 97 ----------------------------- yarn.lock | 79 ++--------------------- 8 files changed, 10 insertions(+), 200 deletions(-) delete mode 100644 header delete mode 100755 scripts/reskindex.js diff --git a/.eslintignore b/.eslintignore index b715bcd4f6..5d117f54b5 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,6 @@ -src/component-index.js test/end-to-end-tests/node_modules/ test/end-to-end-tests/element/ test/end-to-end-tests/synapse/ test/end-to-end-tests/lib/ +# Legacy skinning file that some people might still have +src/component-index.js diff --git a/.github/workflows/test_coverage.yml b/.github/workflows/test_coverage.yml index 6eb4d883bd..45fec0d008 100644 --- a/.github/workflows/test_coverage.yml +++ b/.github/workflows/test_coverage.yml @@ -25,7 +25,7 @@ jobs: run: "./scripts/ci/install-deps.sh --ignore-scripts" - name: Run tests with coverage - run: "yarn install && yarn reskindex && yarn coverage" + run: "yarn install && yarn coverage" - name: Upload coverage uses: codecov/codecov-action@v2 diff --git a/.gitignore b/.gitignore index 102f4b5ec1..3137cd555b 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ package-lock.json /matrix-react-sdk-*.tgz /.idea +# Legacy skinning file that some people might still have /src/component-index.js .DS_Store diff --git a/header b/header deleted file mode 100644 index 33b7fb9e80..0000000000 --- a/header +++ /dev/null @@ -1,17 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket Ltd -Copyright 2017 Vector Creations Ltd -Copyright 2017, 2018 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ diff --git a/package.json b/package.json index dd4586917e..1e6f4828cc 100644 --- a/package.json +++ b/package.json @@ -22,9 +22,6 @@ "README.md", "package.json" ], - "bin": { - "reskindex": "scripts/reskindex.js" - }, "main": "./src/index.ts", "matrix_src_main": "./src/index.ts", "matrix_lib_main": "./lib/index.ts", @@ -37,16 +34,14 @@ "i18n": "matrix-gen-i18n", "prunei18n": "matrix-prune-i18n", "diff-i18n": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && matrix-gen-i18n && matrix-compare-i18n-files src/i18n/strings/en_EN_orig.json src/i18n/strings/en_EN.json", - "reskindex": "node scripts/reskindex.js -h header", "make-component": "node scripts/make-react-component.js", - "reskindex:watch": "node scripts/reskindex.js -h header -w", "rethemendex": "res/css/rethemendex.sh", "clean": "rimraf lib", "build": "yarn clean && git rev-parse HEAD > git-revision.txt && yarn build:compile && yarn build:types", - "build:compile": "yarn reskindex && babel -d lib --verbose --extensions \".ts,.js,.tsx\" src", + "build:compile": "babel -d lib --verbose --extensions \".ts,.js,.tsx\" src", "build:types": "tsc --emitDeclarationOnly --jsx react", "start": "echo THIS IS FOR LEGACY PURPOSES ONLY. && yarn start:all", - "start:all": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n build,reskindex \"yarn start:build\" \"yarn reskindex:watch\"", + "start:all": "echo THIS IS FOR LEGACY PURPOSES ONLY. && yarn start:build", "start:build": "babel src -w -s -d lib --verbose --extensions \".ts,.js\"", "lint": "yarn lint:types && yarn lint:js && yarn lint:style", "lint:js": "eslint --max-warnings 0 src test", @@ -167,7 +162,6 @@ "babel-jest": "^26.6.3", "blob-polyfill": "^6.0.20211015", "chokidar": "^3.5.1", - "concurrently": "^5.3.0", "enzyme": "^3.11.0", "enzyme-to-json": "^3.6.2", "eslint": "8.9.0", diff --git a/scripts/ci/layered.sh b/scripts/ci/layered.sh index 8ebb7a7548..e66eddf9aa 100755 --- a/scripts/ci/layered.sh +++ b/scripts/ci/layered.sh @@ -31,7 +31,6 @@ yarn link matrix-js-sdk yarn link matrix-analytics-events yarn link yarn install --pure-lockfile -yarn reskindex # Finally, set up element-web scripts/fetchdep.sh vector-im element-web diff --git a/scripts/reskindex.js b/scripts/reskindex.js deleted file mode 100755 index 5eaec4d1d5..0000000000 --- a/scripts/reskindex.js +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env node -const fs = require('fs'); -const { promises: fsp } = fs; -const path = require('path'); -const glob = require('glob'); -const util = require('util'); -const args = require('minimist')(process.argv); -const chokidar = require('chokidar'); - -const componentIndex = path.join('src', 'component-index.js'); -const componentIndexTmp = componentIndex+".tmp"; -const componentsDir = path.join('src', 'components'); -const componentJsGlob = '**/*.js'; -const componentTsGlob = '**/*.tsx'; -let prevFiles = []; - -async function reskindex() { - const jsFiles = glob.sync(componentJsGlob, {cwd: componentsDir}).sort(); - const tsFiles = glob.sync(componentTsGlob, {cwd: componentsDir}).sort(); - const files = [...tsFiles, ...jsFiles]; - if (!filesHaveChanged(files, prevFiles)) { - return; - } - prevFiles = files; - - const header = args.h || args.header; - - const strm = fs.createWriteStream(componentIndexTmp); - // Wait for the open event to ensure the file descriptor is set - await new Promise(resolve => strm.once("open", resolve)); - - if (header) { - strm.write(fs.readFileSync(header)); - strm.write('\n'); - } - - strm.write("/*\n"); - strm.write(" * THIS FILE IS AUTO-GENERATED\n"); - strm.write(" * You can edit it you like, but your changes will be overwritten,\n"); - strm.write(" * so you'd just be trying to swim upstream like a salmon.\n"); - strm.write(" * You are not a salmon.\n"); - strm.write(" */\n\n"); - strm.write("let components = {};\n"); - - for (let i = 0; i < files.length; ++i) { - const file = files[i].replace('.js', '').replace('.tsx', ''); - - const moduleName = (file.replace(/\//g, '.')); - const importName = moduleName.replace(/\./g, "$"); - - strm.write("import " + importName + " from './components/" + file + "';\n"); - strm.write(importName + " && (components['"+moduleName+"'] = " + importName + ");"); - strm.write('\n'); - strm.uncork(); - } - - strm.write("export {components};\n"); - // Ensure the file has been fully written to disk before proceeding - await util.promisify(fs.fsync)(strm.fd); - await util.promisify(strm.end); - await fsp.rename(componentIndexTmp, componentIndex); -} - -// Expects both arrays of file names to be sorted -function filesHaveChanged(files, prevFiles) { - if (files.length !== prevFiles.length) { - return true; - } - // Check for name changes - for (let i = 0; i < files.length; i++) { - if (prevFiles[i] !== files[i]) { - return true; - } - } - return false; -} - -// Wrapper since await at the top level is not well supported yet -function run() { - (async function() { - await reskindex(); - console.log("Reskindex completed"); - })(); -} - -// -w indicates watch mode where any FS events will trigger reskindex -if (!args.w) { - run(); - return; -} - -let watchDebouncer = null; -chokidar.watch(path.join(componentsDir, componentJsGlob)).on('all', (event, path) => { - if (path === componentIndex) return; - if (watchDebouncer) clearTimeout(watchDebouncer); - watchDebouncer = setTimeout(run, 1000); -}); diff --git a/yarn.lock b/yarn.lock index ef46068322..a85dc83ec3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2795,7 +2795,7 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@^2.0.0, chalk@^2.4.2: +chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -3030,21 +3030,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concurrently@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-5.3.0.tgz#7500de6410d043c912b2da27de3202cb489b1e7b" - integrity sha512-8MhqOB6PWlBfA2vJ8a0bSFKATOdWlHiQlk11IfmQBPaHVP8oP2gsh2MObE6UR3hqDHqvaIvLTyceNW6obVuFHQ== - dependencies: - chalk "^2.4.2" - date-fns "^2.0.1" - lodash "^4.17.15" - read-pkg "^4.0.1" - rxjs "^6.5.2" - spawn-command "^0.0.2-1" - supports-color "^6.1.0" - tree-kill "^1.2.2" - yargs "^13.3.0" - content-type@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" @@ -3233,11 +3218,6 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" -date-fns@^2.0.1: - version "2.28.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" - integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== - date-names@^0.1.11: version "0.1.13" resolved "https://registry.yarnpkg.com/date-names/-/date-names-0.1.13.tgz#c4358f6f77c8056e2f5ea68fdbb05f0bf1e53bd0" @@ -5886,11 +5866,6 @@ jsesc@~0.5.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -6583,7 +6558,7 @@ node-releases@^2.0.1: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== -normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: +normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -6892,14 +6867,6 @@ parse-entities@^2.0.0: is-decimal "^1.0.0" is-hexadecimal "^1.0.0" -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -6995,11 +6962,6 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" @@ -7440,15 +7402,6 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237" - integrity sha1-ljYlN48+HE1IyFhytabsfV0JMjc= - dependencies: - normalize-package-data "^2.3.2" - parse-json "^4.0.0" - pify "^3.0.0" - read-pkg@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" @@ -7770,13 +7723,6 @@ rw@^1.3.3: resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" integrity sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q= -rxjs@^6.5.2: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -8040,11 +7986,6 @@ source-map@^0.7.3: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== -spawn-command@^0.0.2-1: - version "0.0.2-1" - resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" - integrity sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A= - spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -8356,13 +8297,6 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -8537,11 +8471,6 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= -tree-kill@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" - integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== - trim-newlines@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" @@ -8562,7 +8491,7 @@ tsconfig-paths@^3.12.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -9134,7 +9063,7 @@ yargs-parser@^21.0.0: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55" integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA== -yargs@^13.2.4, yargs@^13.3.0: +yargs@^13.2.4: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== From 59364ec177984a689e44937909e1485c5ad95ef4 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 31 Mar 2022 19:32:49 -0600 Subject: [PATCH 41/47] Post-merge fixes --- src/components/structures/ThreadView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index 5e4da890b8..fca2c146fb 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -50,7 +50,7 @@ import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts"; import Measured from '../views/elements/Measured'; import PosthogTrackers from "../../PosthogTrackers"; import { ButtonEvent } from "../views/elements/AccessibleButton"; -import RoomViewStore from '../../stores/RoomViewStore'; +import { RoomViewStore } from '../../stores/RoomViewStore'; interface IProps { room: Room; @@ -110,7 +110,7 @@ export default class ThreadView extends React.Component { room.removeListener(ThreadEvent.New, this.onNewThread); SettingsStore.unwatchSetting(this.layoutWatcherRef); - const hasRoomChanged = RoomViewStore.getRoomId() !== roomId; + const hasRoomChanged = RoomViewStore.instance.getRoomId() !== roomId; if (this.props.isInitialEventHighlighted && !hasRoomChanged) { dis.dispatch({ action: Action.ViewRoom, From d5e70dfaa5e8c7a860a6e1e6c5bc3941042c82f5 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 31 Mar 2022 19:34:06 -0600 Subject: [PATCH 42/47] Add [matrix] replacement string to be backwards compatible with $matrixLogo change --- src/components/views/auth/Welcome.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/auth/Welcome.tsx b/src/components/views/auth/Welcome.tsx index dfe2c10782..5f59dbdf52 100644 --- a/src/components/views/auth/Welcome.tsx +++ b/src/components/views/auth/Welcome.tsx @@ -56,6 +56,7 @@ export default class Welcome extends React.PureComponent { "$riot:ssoUrl": "#/start_sso", "$riot:casUrl": "#/start_cas", "$matrixLogo": MATRIX_LOGO_HTML, + "[matrix]": MATRIX_LOGO_HTML, }} /> From 71b356a9a4ee726c8abe4449014cd0c84dcec26e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 31 Mar 2022 19:38:00 -0600 Subject: [PATCH 43/47] Cast dispatcher payloads correctly when firing them --- src/CallHandler.tsx | 4 ++-- src/components/views/context_menus/MessageContextMenu.tsx | 8 ++++---- src/stores/RoomViewStore.tsx | 4 ++-- src/utils/space.tsx | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/CallHandler.tsx b/src/CallHandler.tsx index 8e197e900f..2b934251b7 100644 --- a/src/CallHandler.tsx +++ b/src/CallHandler.tsx @@ -1093,7 +1093,7 @@ export default class CallHandler extends EventEmitter { */ public showTransferDialog(call: MatrixCall): void { call.setRemoteOnHold(true); - dis.dispatch({ + dis.dispatch({ action: Action.OpenInviteDialog, kind: KIND_CALL_TRANSFER, call, @@ -1104,7 +1104,7 @@ export default class CallHandler extends EventEmitter { call.setRemoteOnHold(false); } }, - } as OpenInviteDialogPayload); + }); } private addCallForRoom(roomId: string, call: MatrixCall, changedRooms = false): void { diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx index b4f476a5cd..72a5c862b3 100644 --- a/src/components/views/context_menus/MessageContextMenu.tsx +++ b/src/components/views/context_menus/MessageContextMenu.tsx @@ -154,10 +154,10 @@ export default class MessageContextMenu extends React.Component }; private onReportEventClick = (): void => { - dis.dispatch({ + dis.dispatch({ action: Action.OpenReportEventDialog, event: this.props.mxEvent, - } as OpenReportEventDialogPayload); + }); this.closeMenu(); }; @@ -178,11 +178,11 @@ export default class MessageContextMenu extends React.Component }; private onForwardClick = (): void => { - dis.dispatch({ + dis.dispatch({ action: Action.OpenForwardDialog, event: this.props.mxEvent, permalinkCreator: this.props.permalinkCreator, - } as OpenForwardDialogPayload); + }); this.closeMenu(); }; diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index b48ad3f808..84b02df411 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -157,11 +157,11 @@ export class RoomViewStore extends Store { // Fired so we can reduce dependency on event emitters to this store, which is relatively // central to the application and can easily cause import cycles. - dis.dispatch({ + dis.dispatch({ action: Action.ActiveRoomChanged, oldRoomId: lastRoomId, newRoomId: this.state.roomId, - } as ActiveRoomChangedPayload); + }); } this.__emitChange(); diff --git a/src/utils/space.tsx b/src/utils/space.tsx index b407e23ffb..dc774bb60a 100644 --- a/src/utils/space.tsx +++ b/src/utils/space.tsx @@ -66,10 +66,10 @@ export function showSpaceSettings(space: Room) { } export const showAddExistingRooms = (space: Room): void => { - dis.dispatch({ + dis.dispatch({ action: Action.OpenAddToExistingSpaceDialog, space, - } as OpenAddExistingToSpaceDialogPayload); + }); }; export const showCreateNewRoom = async (space: Room): Promise => { From 087c15171b63253e69af08d91f9c41cad3fad6ce Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 31 Mar 2022 19:38:43 -0600 Subject: [PATCH 44/47] Convert function back to arrow function for consistency --- src/utils/space.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/space.tsx b/src/utils/space.tsx index dc774bb60a..470b374840 100644 --- a/src/utils/space.tsx +++ b/src/utils/space.tsx @@ -165,10 +165,10 @@ export const bulkSpaceBehaviour = async ( } }; -export function showSpacePreferences(space: Room, initialTabId?: SpacePreferenceTab) { +export const showSpacePreferences = (space: Room, initialTabId?: SpacePreferenceTab) => { dis.dispatch({ action: Action.OpenSpacePreferences, space, initialTabId, }); -} +}; From 5137fcf3e8152b9db716a7da3bc1eb93de2e9002 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 31 Mar 2022 19:43:17 -0600 Subject: [PATCH 45/47] Remove unit test function which isn't needed The import ordering no longer requires us to create an injector function. --- src/stores/RoomViewStore.tsx | 21 ++++++------------- .../components/structures/RightPanel-test.tsx | 2 -- .../views/elements/AppTile-test.tsx | 2 -- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index 84b02df411..6112694777 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -93,7 +93,6 @@ export class RoomViewStore extends Store { public static readonly instance = new RoomViewStore(); private state = INITIAL_STATE; // initialize state - private forcedMatrixClient: MatrixClient; // Keep these out of state to avoid causing excessive/recursive updates private roomIdActivityListeners: Record = {}; @@ -102,14 +101,6 @@ export class RoomViewStore extends Store { super(dis); } - private get matrixClient(): MatrixClient { - return this.forcedMatrixClient || MatrixClientPeg.get(); - } - - public useUnitTestClient(client: MatrixClient) { - this.forcedMatrixClient = client; - } - public addRoomListener(roomId: string, fn: Listener) { if (!this.roomIdActivityListeners[roomId]) this.roomIdActivityListeners[roomId] = []; this.roomIdActivityListeners[roomId].push(fn); @@ -214,7 +205,7 @@ export class RoomViewStore extends Store { this.setState({ shouldPeek: false }); } - const cli = this.matrixClient; + const cli = MatrixClientPeg.get(); const updateMetrics = () => { const room = cli.getRoom(payload.roomId); @@ -290,7 +281,7 @@ export class RoomViewStore extends Store { trigger: payload.metricsTrigger, viaKeyboard: payload.metricsViaKeyboard, isDM: !!DMRoomMap.shared().getUserIdForRoomId(payload.room_id), - isSpace: this.matrixClient.getRoom(payload.room_id)?.isSpaceRoom(), + isSpace: MatrixClientPeg.get().getRoom(payload.room_id)?.isSpaceRoom(), activeSpace, }); } @@ -349,7 +340,7 @@ export class RoomViewStore extends Store { wasContextSwitch: payload.context_switch, }); try { - const result = await this.matrixClient.getRoomIdForAlias(payload.room_alias); + const result = await MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias); storeRoomAliasInCache(payload.room_alias, result.room_id); roomId = result.room_id; } catch (err) { @@ -386,7 +377,7 @@ export class RoomViewStore extends Store { joining: true, }); - const cli = this.matrixClient; + const cli = MatrixClientPeg.get(); // take a copy of roomAlias & roomId as they may change by the time the join is complete const { roomAlias, roomId } = this.state; const address = roomAlias || roomId; @@ -418,7 +409,7 @@ export class RoomViewStore extends Store { } private getInvitingUserId(roomId: string): string { - const cli = this.matrixClient; + const cli = MatrixClientPeg.get(); const room = cli.getRoom(roomId); if (room && room.getMyMembership() === "invite") { const myMember = room.getMember(cli.getUserId()); @@ -443,7 +434,7 @@ export class RoomViewStore extends Store { // only provide a better error message for invites if (invitingUserId) { // if the inviting user is on the same HS, there can only be one cause: they left. - if (invitingUserId.endsWith(`:${this.matrixClient.getDomain()}`)) { + if (invitingUserId.endsWith(`:${MatrixClientPeg.get().getDomain()}`)) { description = _t("The person who invited you has already left."); } else { description = _t("The person who invited you has already left, or their server is offline."); diff --git a/test/components/structures/RightPanel-test.tsx b/test/components/structures/RightPanel-test.tsx index a845a7ed80..7d68d1753d 100644 --- a/test/components/structures/RightPanel-test.tsx +++ b/test/components/structures/RightPanel-test.tsx @@ -32,7 +32,6 @@ import { RightPanelPhases } from "../../../src/stores/right-panel/RightPanelStor import RightPanelStore from "../../../src/stores/right-panel/RightPanelStore"; import { UPDATE_EVENT } from "../../../src/stores/AsyncStore"; import { WidgetLayoutStore } from "../../../src/stores/widgets/WidgetLayoutStore"; -import { RoomViewStore } from "../../../src/stores/RoomViewStore"; describe("RightPanel", () => { it("renders info from only one room during room changes", async () => { @@ -76,7 +75,6 @@ describe("RightPanel", () => { // @ts-ignore await WidgetLayoutStore.instance.onReady(); RightPanelStore.instance.useUnitTestClient(cli); - RoomViewStore.instance.useUnitTestClient(cli); // @ts-ignore await RightPanelStore.instance.onReady(); diff --git a/test/components/views/elements/AppTile-test.tsx b/test/components/views/elements/AppTile-test.tsx index 2b07c214eb..8843a9c602 100644 --- a/test/components/views/elements/AppTile-test.tsx +++ b/test/components/views/elements/AppTile-test.tsx @@ -36,7 +36,6 @@ import WidgetStore, { IApp } from "../../../../src/stores/WidgetStore"; import AppTile from "../../../../src/components/views/elements/AppTile"; import { Container, WidgetLayoutStore } from "../../../../src/stores/widgets/WidgetLayoutStore"; import AppsDrawer from "../../../../src/components/views/rooms/AppsDrawer"; -import { RoomViewStore } from "../../../../src/stores/RoomViewStore"; describe("AppTile", () => { let cli; @@ -109,7 +108,6 @@ describe("AppTile", () => { // @ts-ignore await WidgetLayoutStore.instance.onReady(); RightPanelStore.instance.useUnitTestClient(cli); - RoomViewStore.instance.useUnitTestClient(cli); // @ts-ignore await RightPanelStore.instance.onReady(); }); From ac65e5fd2f9cdc4067d92ed401d6a3afc69ca7b2 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 31 Mar 2022 19:52:26 -0600 Subject: [PATCH 46/47] Appease the linter --- src/stores/RoomViewStore.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index 6112694777..aec723d13d 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -24,7 +24,7 @@ import { ViewRoom as ViewRoomEvent } from "matrix-analytics-events/types/typescr import { JoinedRoom as JoinedRoomEvent } from "matrix-analytics-events/types/typescript/JoinedRoom"; import { JoinRule } from "matrix-js-sdk/src/@types/partials"; import { Room } from "matrix-js-sdk/src/models/room"; -import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client"; +import { ClientEvent } from "matrix-js-sdk/src/client"; import dis from '../dispatcher/dispatcher'; import { MatrixClientPeg } from '../MatrixClientPeg'; From 0280c27bfd0f3275d76712ddbea6fbe3ef62207e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 5 Apr 2022 10:57:16 -0600 Subject: [PATCH 47/47] post-merge fixes --- src/components/structures/ThreadPanel.tsx | 2 +- src/components/views/dialogs/CreateRoomDialog.tsx | 2 +- src/components/views/messages/MessageActionBar.tsx | 2 +- src/components/views/rooms/RoomTile.tsx | 2 +- test/components/views/rooms/RoomTile-test.tsx | 3 +-- test/stores/VideoChannelStore-test.ts | 1 - 6 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx index 7d75f91858..4862361639 100644 --- a/src/components/structures/ThreadPanel.tsx +++ b/src/components/structures/ThreadPanel.tsx @@ -37,7 +37,7 @@ import SdkConfig from '../../SdkConfig'; import Modal from '../../Modal'; import BetaFeedbackDialog from '../views/dialogs/BetaFeedbackDialog'; import { Action } from '../../dispatcher/actions'; -import { UserTab } from '../views/dialogs/UserSettingsDialog'; +import { UserTab } from '../views/dialogs/UserTab'; import dis from '../../dispatcher/dispatcher'; interface IProps { diff --git a/src/components/views/dialogs/CreateRoomDialog.tsx b/src/components/views/dialogs/CreateRoomDialog.tsx index 51614abf26..cc6a7c8479 100644 --- a/src/components/views/dialogs/CreateRoomDialog.tsx +++ b/src/components/views/dialogs/CreateRoomDialog.tsx @@ -24,7 +24,7 @@ import SdkConfig from '../../../SdkConfig'; import withValidation, { IFieldState } from '../elements/Validation'; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; -import { IOpts, privateShouldBeEncrypted } from "../../../createRoom"; +import { IOpts } from "../../../createRoom"; import Field from "../elements/Field"; import RoomAliasField from "../elements/RoomAliasField"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx index b5f198e1ff..0b2e58f60c 100644 --- a/src/components/views/messages/MessageActionBar.tsx +++ b/src/components/views/messages/MessageActionBar.tsx @@ -43,7 +43,7 @@ import { showThread } from "../../../dispatcher/dispatch-actions/threads"; import { shouldDisplayReply } from '../../../utils/Reply'; import { Key } from "../../../Keyboard"; import { ALTERNATE_KEY_NAME } from "../../../accessibility/KeyboardShortcuts"; -import { UserTab } from '../dialogs/UserSettingsDialog'; +import { UserTab } from '../dialogs/UserTab'; import { Action } from '../../../dispatcher/actions'; interface IOptionsButtonProps { diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index 2eabfec8f5..46aea8fa0d 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -199,7 +199,7 @@ export default class RoomTile extends React.PureComponent { this.onRoomPreviewChanged, ); this.props.room.off(RoomEvent.Name, this.onRoomNameUpdate); - this.props.room.currentState.off(RoomStateEvent.Events, this.updateVoiceMembers); + this.props.room.currentState.off(RoomStateEvent.Events, this.updateVideoMembers); defaultDispatcher.unregister(this.dispatcherRef); this.notificationState.off(NotificationStateEvents.Update, this.onNotificationUpdate); this.roomProps.off(PROPERTY_UPDATED, this.onRoomPropertyUpdate); diff --git a/test/components/views/rooms/RoomTile-test.tsx b/test/components/views/rooms/RoomTile-test.tsx index 87c605abcb..4ac7a369b6 100644 --- a/test/components/views/rooms/RoomTile-test.tsx +++ b/test/components/views/rooms/RoomTile-test.tsx @@ -26,9 +26,8 @@ import { mockStateEventImplementation, mkRoom, mkEvent, - stubVoiceChannelStore, + stubVideoChannelStore, } from "../../../test-utils"; -import { stubVideoChannelStore } from "../../../test-utils/video"; import RoomTile from "../../../../src/components/views/rooms/RoomTile"; import SettingsStore from "../../../../src/settings/SettingsStore"; import { DefaultTagID } from "../../../../src/stores/room-list/models"; diff --git a/test/stores/VideoChannelStore-test.ts b/test/stores/VideoChannelStore-test.ts index e1420195c1..7b23ce0f4b 100644 --- a/test/stores/VideoChannelStore-test.ts +++ b/test/stores/VideoChannelStore-test.ts @@ -16,7 +16,6 @@ limitations under the License. import { ClientWidgetApi, MatrixWidgetType } from "matrix-widget-api"; -import "../skinned-sdk"; import { stubClient, mkRoom } from "../test-utils"; import { MatrixClientPeg } from "../../src/MatrixClientPeg"; import WidgetStore from "../../src/stores/WidgetStore";