From 030b7e90bf8ba09648f539dd378c0909f8773f86 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 12 Jan 2023 13:25:14 +0000 Subject: [PATCH] Enable `@typescript-eslint/explicit-function-return-type` in /src (#9788) * Enable `@typescript-eslint/explicit-member-accessibility` on /src * Prettier * Enable `@typescript-eslint/explicit-function-return-type` in /src * Fix types * tsc strict fixes * Delint * Fix test * Fix bad merge --- .eslintrc.js | 8 +- src/@types/diff-dom.d.ts | 8 +- src/@types/polyfill.ts | 2 +- src/AsyncWrapper.tsx | 8 +- src/Avatar.ts | 7 +- src/BasePlatform.ts | 4 +- src/BlurhashEncoder.ts | 2 +- src/ContentMessages.ts | 30 ++-- src/DateUtils.ts | 4 +- src/DeviceListener.ts | 43 +++--- src/Editing.ts | 5 +- src/HtmlUtils.tsx | 6 +- src/ImageUtils.ts | 2 +- src/Keyboard.ts | 2 +- src/LegacyCallHandler.tsx | 12 +- src/Lifecycle.ts | 4 +- src/Livestream.ts | 6 +- src/Login.ts | 2 +- src/Markdown.ts | 4 +- src/Modal.tsx | 28 ++-- src/PlatformPeg.ts | 6 +- src/PosthogAnalytics.ts | 8 +- src/PosthogTrackers.ts | 8 +- src/Presence.ts | 10 +- src/ScalarAuthClient.ts | 4 +- src/ScalarMessaging.ts | 6 +- src/SdkConfig.ts | 8 +- src/SecurityManager.ts | 16 +- src/SendHistoryManager.ts | 2 +- src/SlashCommands.tsx | 30 ++-- src/SlidingSyncManager.ts | 2 +- src/Terms.ts | 4 +- src/TextForEvent.tsx | 2 +- src/UserActivity.ts | 24 +-- src/accessibility/RovingTabIndex.tsx | 2 +- src/accessibility/Toolbar.tsx | 2 +- .../context_menu/StyledMenuItemCheckbox.tsx | 4 +- .../context_menu/StyledMenuItemRadio.tsx | 4 +- src/actions/actionCreators.ts | 4 +- .../handlers/viewUserDeviceSettings.ts | 2 +- .../eventindex/ManageEventIndexDialog.tsx | 8 +- .../security/CreateKeyBackupDialog.tsx | 2 +- .../security/CreateSecretStorageDialog.tsx | 10 +- .../dialogs/security/ExportE2eKeysDialog.tsx | 2 +- .../dialogs/security/ImportE2eKeysDialog.tsx | 2 +- src/audio/ManagedPlayback.ts | 2 +- src/audio/Playback.ts | 22 +-- src/audio/PlaybackClock.ts | 14 +- src/audio/PlaybackManager.ts | 4 +- src/audio/PlaybackQueue.ts | 10 +- src/audio/RecorderWorklet.ts | 2 +- src/audio/VoiceMessageRecording.ts | 4 +- src/audio/VoiceRecording.ts | 12 +- src/autocomplete/AutocompleteProvider.tsx | 8 +- src/autocomplete/Autocompleter.ts | 4 +- src/autocomplete/CommandProvider.tsx | 2 +- src/autocomplete/EmojiProvider.tsx | 4 +- src/autocomplete/NotifProvider.tsx | 2 +- src/autocomplete/QueryMatcher.ts | 2 +- src/autocomplete/RoomProvider.tsx | 31 ++-- src/autocomplete/SpaceProvider.tsx | 5 +- src/autocomplete/UserProvider.tsx | 10 +- .../structures/AutoHideScrollbar.tsx | 8 +- .../structures/AutocompleteInput.tsx | 12 +- src/components/structures/ContextMenu.tsx | 49 +++--- src/components/structures/EmbeddedPage.tsx | 2 +- src/components/structures/FileDropTarget.tsx | 8 +- src/components/structures/FilePanel.tsx | 2 +- .../structures/GenericErrorPage.tsx | 2 +- src/components/structures/HomePage.tsx | 15 +- .../structures/HostSignupAction.tsx | 2 +- src/components/structures/InteractiveAuth.tsx | 6 +- src/components/structures/LeftPanel.tsx | 26 ++-- .../structures/LegacyCallEventGrouper.ts | 12 +- src/components/structures/LoggedInView.tsx | 34 ++--- src/components/structures/MatrixChat.tsx | 100 ++++++------- src/components/structures/MessagePanel.tsx | 10 +- .../structures/NonUrgentToastContainer.tsx | 6 +- .../structures/NotificationPanel.tsx | 2 +- .../structures/PictureInPictureDragger.tsx | 22 +-- src/components/structures/PipContainer.tsx | 14 +- src/components/structures/RightPanel.tsx | 6 +- src/components/structures/RoomSearch.tsx | 6 +- src/components/structures/RoomSearchView.tsx | 6 +- src/components/structures/RoomStatusBar.tsx | 2 +- src/components/structures/RoomView.tsx | 140 +++++++++--------- src/components/structures/ScrollPanel.tsx | 10 +- src/components/structures/SpaceHierarchy.tsx | 24 +-- src/components/structures/SpaceRoomView.tsx | 66 ++++++--- src/components/structures/SplashPage.tsx | 2 +- src/components/structures/TabbedView.tsx | 6 +- src/components/structures/ThreadPanel.tsx | 23 +-- src/components/structures/ThreadView.tsx | 12 +- src/components/structures/TimelinePanel.tsx | 35 +++-- src/components/structures/ToastContainer.tsx | 6 +- src/components/structures/UploadBar.tsx | 10 +- src/components/structures/UserMenu.tsx | 40 ++--- .../structures/auth/CompleteSecurity.tsx | 2 +- src/components/structures/auth/E2eSetup.tsx | 2 +- .../structures/auth/ForgotPassword.tsx | 16 +- src/components/structures/auth/Login.tsx | 32 ++-- .../structures/auth/Registration.tsx | 49 +++--- .../structures/auth/SetupEncryptionBody.tsx | 26 ++-- src/components/structures/auth/SoftLogout.tsx | 16 +- .../auth/forgot-password/EnterEmail.tsx | 2 +- .../auth/header/AuthHeaderDisplay.tsx | 2 +- .../auth/header/AuthHeaderModifier.tsx | 2 +- .../auth/header/AuthHeaderProvider.tsx | 2 +- .../views/audio_messages/AudioPlayerBase.tsx | 4 +- src/components/views/audio_messages/Clock.tsx | 2 +- .../views/audio_messages/DurationClock.tsx | 4 +- .../audio_messages/LiveRecordingClock.tsx | 6 +- .../audio_messages/LiveRecordingWaveform.tsx | 6 +- .../views/audio_messages/PlayPauseButton.tsx | 4 +- .../views/audio_messages/PlaybackClock.tsx | 6 +- .../views/audio_messages/PlaybackWaveform.tsx | 8 +- .../views/audio_messages/SeekBar.tsx | 10 +- .../views/audio_messages/Waveform.tsx | 2 +- src/components/views/auth/AuthBody.tsx | 2 +- src/components/views/auth/CaptchaForm.tsx | 12 +- src/components/views/auth/EmailField.tsx | 4 +- .../auth/InteractiveAuthEntryComponents.tsx | 62 ++++---- src/components/views/auth/LoginWithQR.tsx | 12 +- src/components/views/auth/LoginWithQRFlow.tsx | 8 +- .../views/auth/PassphraseConfirmField.tsx | 4 +- src/components/views/auth/PassphraseField.tsx | 8 +- src/components/views/auth/PasswordLogin.tsx | 62 ++++---- .../views/auth/RegistrationForm.tsx | 56 +++---- src/components/views/avatars/BaseAvatar.tsx | 2 +- .../views/avatars/DecoratedRoomAvatar.tsx | 8 +- src/components/views/avatars/MemberAvatar.tsx | 2 +- src/components/views/avatars/RoomAvatar.tsx | 10 +- .../views/beacon/BeaconViewDialog.tsx | 2 +- .../beacon/LeftPanelLiveShareWarning.tsx | 2 +- .../views/beacon/LiveTimeRemaining.tsx | 2 +- .../views/beacon/RoomLiveShareWarning.tsx | 14 +- src/components/views/beta/BetaCard.tsx | 8 +- .../views/context_menus/DeviceContextMenu.tsx | 2 +- .../context_menus/DialpadContextMenu.tsx | 10 +- .../views/context_menus/KebabContextMenu.tsx | 4 +- .../context_menus/LegacyCallContextMenu.tsx | 8 +- .../context_menus/MessageContextMenu.tsx | 9 +- .../views/context_menus/RoomContextMenu.tsx | 12 +- .../context_menus/RoomGeneralContextMenu.tsx | 6 +- .../RoomNotificationContextMenu.tsx | 2 +- .../views/context_menus/SpaceContextMenu.tsx | 24 +-- .../context_menus/ThreadListContextMenu.tsx | 6 +- .../views/context_menus/WidgetContextMenu.tsx | 14 +- .../dialogs/AddExistingToSpaceDialog.tsx | 21 ++- .../dialogs/AnalyticsLearnMoreDialog.tsx | 4 +- .../views/dialogs/AskInviteAnywayDialog.tsx | 2 +- .../views/dialogs/BugReportDialog.tsx | 4 +- .../views/dialogs/BulkRedactDialog.tsx | 4 +- .../views/dialogs/ChangelogDialog.tsx | 4 +- .../dialogs/ConfirmAndWaitRedactDialog.tsx | 2 +- .../views/dialogs/ConfirmRedactDialog.tsx | 7 +- .../views/dialogs/ConfirmUserActionDialog.tsx | 4 +- .../views/dialogs/ConfirmWipeDeviceDialog.tsx | 2 +- .../views/dialogs/CreateRoomDialog.tsx | 30 ++-- .../views/dialogs/CreateSubspaceDialog.tsx | 2 +- .../views/dialogs/CryptoStoreTooNewDialog.tsx | 2 +- .../views/dialogs/DeactivateAccountDialog.tsx | 2 +- .../views/dialogs/DevtoolsDialog.tsx | 4 +- .../views/dialogs/EndPollDialog.tsx | 4 +- src/components/views/dialogs/ErrorDialog.tsx | 4 +- src/components/views/dialogs/ExportDialog.tsx | 10 +- .../views/dialogs/ForwardDialog.tsx | 6 +- .../dialogs/GenericFeatureFeedbackDialog.tsx | 2 +- .../views/dialogs/HostSignupDialog.tsx | 24 +-- src/components/views/dialogs/InfoDialog.tsx | 4 +- src/components/views/dialogs/InviteDialog.tsx | 92 ++++++------ .../KeySignatureUploadFailedDialog.tsx | 2 +- src/components/views/dialogs/LogoutDialog.tsx | 4 +- .../ManageRestrictedJoinRuleDialog.tsx | 6 +- .../views/dialogs/ModalWidgetDialog.tsx | 16 +- .../views/dialogs/ModuleUiDialog.tsx | 2 +- .../dialogs/RegistrationEmailPromptDialog.tsx | 2 +- .../views/dialogs/ReportEventDialog.tsx | 4 +- .../views/dialogs/RoomSettingsDialog.tsx | 6 +- .../views/dialogs/RoomUpgradeDialog.tsx | 4 +- .../dialogs/RoomUpgradeWarningDialog.tsx | 10 +- .../views/dialogs/ScrollableBaseModal.tsx | 4 +- .../views/dialogs/ServerOfflineDialog.tsx | 8 +- .../views/dialogs/ServerPickerDialog.tsx | 18 +-- .../views/dialogs/SeshatResetDialog.tsx | 2 +- src/components/views/dialogs/ShareDialog.tsx | 8 +- .../views/dialogs/SpacePreferencesDialog.tsx | 2 +- src/components/views/dialogs/TermsDialog.tsx | 6 +- .../views/dialogs/UploadConfirmDialog.tsx | 10 +- .../views/dialogs/UserSettingsDialog.tsx | 4 +- .../dialogs/VerificationRequestDialog.tsx | 2 +- .../WidgetCapabilitiesPromptDialog.tsx | 12 +- .../views/dialogs/devtools/AccountData.tsx | 24 +-- .../views/dialogs/devtools/BaseTool.tsx | 4 +- .../views/dialogs/devtools/Event.tsx | 14 +- .../views/dialogs/devtools/FilteredList.tsx | 6 +- .../views/dialogs/devtools/RoomState.tsx | 18 +-- .../views/dialogs/devtools/ServerInfo.tsx | 4 +- .../views/dialogs/devtools/ServersInRoom.tsx | 2 +- .../dialogs/devtools/SettingExplorer.tsx | 22 +-- .../dialogs/devtools/VerificationExplorer.tsx | 5 +- .../views/dialogs/devtools/WidgetExplorer.tsx | 4 +- .../security/AccessSecretStorageDialog.tsx | 30 ++-- .../ConfirmDestroyCrossSigningDialog.tsx | 2 +- .../security/CreateCrossSigningDialog.tsx | 2 +- .../security/RestoreKeyBackupDialog.tsx | 4 +- .../security/SetupEncryptionDialog.tsx | 8 +- .../spotlight/RoomResultContextMenus.tsx | 2 +- .../dialogs/spotlight/SpotlightDialog.tsx | 10 +- .../views/directory/NetworkDropdown.tsx | 10 +- .../views/elements/AccessibleButton.tsx | 2 +- .../elements/AccessibleTooltipButton.tsx | 10 +- .../views/elements/AppPermission.tsx | 2 +- src/components/views/elements/AppTile.tsx | 12 +- .../views/elements/CopyableText.tsx | 4 +- .../elements/DesktopCapturerSourcePicker.tsx | 10 +- .../views/elements/DialPadBackspaceButton.tsx | 2 +- src/components/views/elements/Draggable.tsx | 2 +- src/components/views/elements/Dropdown.tsx | 34 ++--- .../views/elements/EditableItemList.tsx | 18 +-- .../views/elements/EffectsOverlay.tsx | 4 +- .../views/elements/ErrorBoundary.tsx | 4 +- .../views/elements/EventListSummary.tsx | 16 +- .../views/elements/EventTilePreview.tsx | 4 +- src/components/views/elements/Field.tsx | 14 +- .../elements/IRCTimelineProfileResizer.tsx | 8 +- src/components/views/elements/ImageView.tsx | 44 +++--- src/components/views/elements/InfoTooltip.tsx | 2 +- .../views/elements/InlineSpinner.tsx | 2 +- .../views/elements/InteractiveTooltip.tsx | 14 +- .../views/elements/InviteReason.tsx | 4 +- .../views/elements/JoinRuleDropdown.tsx | 4 +- .../views/elements/LabelledToggleSwitch.tsx | 2 +- .../views/elements/LanguageDropdown.tsx | 6 +- src/components/views/elements/LearnMore.tsx | 2 +- src/components/views/elements/Measured.tsx | 10 +- .../views/elements/MiniAvatarUploader.tsx | 2 +- .../views/elements/PersistedElement.tsx | 4 +- src/components/views/elements/Pill.tsx | 2 +- .../views/elements/PollCreateDialog.tsx | 12 +- .../views/elements/PowerSelector.tsx | 4 +- src/components/views/elements/ReplyChain.tsx | 10 +- .../views/elements/RoomAliasField.tsx | 35 +++-- .../views/elements/RoomFacePile.tsx | 2 +- src/components/views/elements/RoomTopic.tsx | 2 +- src/components/views/elements/SSOButtons.tsx | 4 +- .../views/elements/SearchWarning.tsx | 2 +- .../views/elements/ServerPicker.tsx | 8 +- .../views/elements/SettingsFlag.tsx | 8 +- src/components/views/elements/Slider.tsx | 2 +- .../elements/SpellCheckLanguagesDropdown.tsx | 23 ++- src/components/views/elements/Spinner.tsx | 2 +- .../views/elements/StyledCheckbox.tsx | 2 +- .../views/elements/StyledRadioButton.tsx | 2 +- .../views/elements/StyledRadioGroup.tsx | 4 +- src/components/views/elements/Tag.tsx | 2 +- src/components/views/elements/TagComposer.tsx | 8 +- .../views/elements/ToggleSwitch.tsx | 4 +- src/components/views/elements/Tooltip.tsx | 8 +- .../views/elements/TooltipButton.tsx | 2 +- .../views/elements/TruncatedList.tsx | 2 +- .../views/elements/UseCaseSelection.tsx | 2 +- .../views/elements/UseCaseSelectionButton.tsx | 2 +- src/components/views/emojipicker/Category.tsx | 4 +- src/components/views/emojipicker/Emoji.tsx | 2 +- .../views/emojipicker/EmojiPicker.tsx | 20 +-- src/components/views/emojipicker/Header.tsx | 10 +- src/components/views/emojipicker/Preview.tsx | 2 +- .../views/emojipicker/QuickReactions.tsx | 6 +- .../views/emojipicker/ReactionPicker.tsx | 12 +- src/components/views/emojipicker/Search.tsx | 6 +- .../views/host_signup/HostSignupContainer.tsx | 2 +- .../views/location/LiveDurationDropdown.tsx | 4 +- .../views/location/LocationButton.tsx | 6 +- .../views/location/LocationPicker.tsx | 20 +-- .../views/location/LocationShareMenu.tsx | 6 +- .../views/location/LocationViewDialog.tsx | 6 +- src/components/views/location/Map.tsx | 19 ++- src/components/views/location/Marker.tsx | 6 +- src/components/views/location/ShareType.tsx | 2 +- src/components/views/location/ZoomButtons.tsx | 4 +- .../views/location/shareLocation.ts | 4 +- .../views/messages/DateSeparator.tsx | 4 +- .../views/messages/DisambiguatedProfile.tsx | 2 +- .../views/messages/DownloadActionButton.tsx | 6 +- .../views/messages/EditHistoryMessage.tsx | 4 +- .../views/messages/JumpToDatePicker.tsx | 2 +- .../views/messages/LegacyCallEvent.tsx | 8 +- src/components/views/messages/MAudioBody.tsx | 6 +- src/components/views/messages/MBeaconBody.tsx | 2 +- src/components/views/messages/MFileBody.tsx | 12 +- src/components/views/messages/MImageBody.tsx | 14 +- .../views/messages/MImageReplyBody.tsx | 2 +- .../views/messages/MJitsiWidgetEvent.tsx | 2 +- .../messages/MKeyVerificationRequest.tsx | 18 +-- .../views/messages/MLocationBody.tsx | 6 +- src/components/views/messages/MPollBody.tsx | 28 ++-- .../views/messages/MStickerBody.tsx | 4 +- src/components/views/messages/MVideoBody.tsx | 12 +- .../views/messages/MVoiceMessageBody.tsx | 2 +- .../views/messages/MVoiceOrAudioBody.tsx | 2 +- .../views/messages/MessageActionBar.tsx | 4 +- .../views/messages/MessageEvent.tsx | 14 +- .../views/messages/MessageTimestamp.tsx | 2 +- .../views/messages/ReactionsRow.tsx | 18 +-- .../views/messages/ReactionsRowButton.tsx | 8 +- .../messages/ReactionsRowButtonTooltip.tsx | 2 +- .../views/messages/SenderProfile.tsx | 2 +- src/components/views/messages/TextualBody.tsx | 21 +-- .../views/messages/TextualEvent.tsx | 2 +- .../views/messages/TileErrorBoundary.tsx | 4 +- .../views/messages/ViewSourceEvent.tsx | 2 +- src/components/views/right_panel/BaseCard.tsx | 2 +- .../views/right_panel/EncryptionInfo.tsx | 2 +- .../views/right_panel/EncryptionPanel.tsx | 4 +- .../views/right_panel/HeaderButton.tsx | 2 +- .../views/right_panel/HeaderButtons.tsx | 10 +- .../views/right_panel/PinnedMessagesCard.tsx | 6 +- .../views/right_panel/RoomHeaderButtons.tsx | 20 +-- .../views/right_panel/RoomSummaryCard.tsx | 18 +-- .../views/right_panel/TimelineCard.tsx | 2 +- src/components/views/right_panel/UserInfo.tsx | 87 +++++++---- .../views/right_panel/VerificationPanel.tsx | 31 ++-- .../views/room_settings/AliasSettings.tsx | 36 ++--- .../room_settings/RoomProfileSettings.tsx | 2 +- .../room_settings/RoomPublishSetting.tsx | 6 +- src/components/views/rooms/Autocomplete.tsx | 12 +- src/components/views/rooms/AuxPanel.tsx | 14 +- .../views/rooms/BasicMessageComposer.tsx | 10 +- .../views/rooms/CollapsibleButton.tsx | 8 +- src/components/views/rooms/E2EIcon.tsx | 4 +- .../views/rooms/EditMessageComposer.tsx | 6 +- src/components/views/rooms/EmojiButton.tsx | 6 +- src/components/views/rooms/EntityTile.tsx | 2 +- src/components/views/rooms/EventTile.tsx | 44 +++--- .../EventTile/EventTileThreadToolbar.tsx | 2 +- src/components/views/rooms/ExtraTile.tsx | 4 +- src/components/views/rooms/HistoryTile.tsx | 2 +- .../views/rooms/LinkPreviewGroup.tsx | 2 +- .../views/rooms/LinkPreviewWidget.tsx | 8 +- src/components/views/rooms/MemberList.tsx | 6 +- src/components/views/rooms/MemberTile.tsx | 6 +- .../views/rooms/MessageComposer.tsx | 42 +++--- .../views/rooms/MessageComposerButtons.tsx | 18 +-- .../views/rooms/MessageComposerFormatBar.tsx | 4 +- src/components/views/rooms/NewRoomIntro.tsx | 8 +- .../views/rooms/NotificationBadge.tsx | 12 +- .../StatelessNotificationBadge.tsx | 2 +- .../UnreadNotificationBadge.tsx | 2 +- .../views/rooms/PinnedEventTile.tsx | 8 +- src/components/views/rooms/PresenceLabel.tsx | 2 +- .../views/rooms/ReadReceiptGroup.tsx | 12 +- .../views/rooms/RecentlyViewedButton.tsx | 2 +- src/components/views/rooms/ReplyPreview.tsx | 2 +- src/components/views/rooms/ReplyTile.tsx | 6 +- .../views/rooms/RoomBreadcrumbs.tsx | 8 +- .../views/rooms/RoomContextDetails.tsx | 2 +- src/components/views/rooms/RoomHeader.tsx | 34 ++--- src/components/views/rooms/RoomInfoLine.tsx | 5 +- src/components/views/rooms/RoomList.tsx | 24 +-- src/components/views/rooms/RoomListHeader.tsx | 10 +- src/components/views/rooms/RoomPreviewBar.tsx | 12 +- .../views/rooms/RoomPreviewCard.tsx | 2 +- src/components/views/rooms/RoomSublist.tsx | 56 +++---- src/components/views/rooms/RoomTile.tsx | 42 +++--- src/components/views/rooms/SearchBar.tsx | 8 +- .../views/rooms/SearchResultTile.tsx | 2 +- .../views/rooms/SendMessageComposer.tsx | 6 +- src/components/views/rooms/Stickerpicker.tsx | 2 +- .../views/rooms/ThirdPartyMemberInfo.tsx | 8 +- src/components/views/rooms/ThreadSummary.tsx | 6 +- .../views/rooms/VoiceRecordComposerTile.tsx | 18 +-- .../views/rooms/WhoIsTypingTile.tsx | 8 +- .../rooms/wysiwyg_composer/ComposerContext.ts | 2 +- .../DynamicImportWysiwygComposer.tsx | 16 +- .../wysiwyg_composer/EditWysiwygComposer.tsx | 6 +- .../wysiwyg_composer/SendWysiwygComposer.tsx | 6 +- .../components/EditionButtons.tsx | 6 +- .../wysiwyg_composer/components/Emoji.tsx | 6 +- .../components/FormattingButtons.tsx | 7 +- .../wysiwyg_composer/components/LinkModal.tsx | 12 +- .../components/PlainTextComposer.tsx | 2 +- .../hooks/useComposerFunctions.ts | 8 +- .../wysiwyg_composer/hooks/useEditing.ts | 11 +- .../hooks/useInitialContent.ts | 2 +- .../hooks/useInputEventProcessor.ts | 2 +- .../wysiwyg_composer/hooks/useIsExpanded.ts | 2 +- .../wysiwyg_composer/hooks/useIsFocused.ts | 5 +- .../hooks/usePlainTextInitialization.ts | 2 +- .../hooks/usePlainTextListeners.ts | 13 +- .../wysiwyg_composer/hooks/useSelection.ts | 8 +- .../hooks/useSetCursorPosition.ts | 2 +- .../hooks/useWysiwygEditActionHandler.ts | 2 +- .../hooks/useWysiwygSendActionHandler.ts | 2 +- .../rooms/wysiwyg_composer/hooks/utils.ts | 4 +- .../rooms/wysiwyg_composer/utils/editing.ts | 4 +- .../rooms/wysiwyg_composer/utils/message.ts | 7 +- .../rooms/wysiwyg_composer/utils/selection.ts | 4 +- .../views/settings/AddPrivilegedUsers.tsx | 10 +- src/components/views/settings/BridgeTile.tsx | 2 +- .../views/settings/CrossSigningPanel.tsx | 12 +- .../views/settings/DevicesPanel.tsx | 2 +- .../views/settings/DevicesPanelEntry.tsx | 6 +- .../views/settings/E2eAdvancedPanel.tsx | 2 +- .../views/settings/EventIndexPanel.tsx | 14 +- .../views/settings/FontScalingPanel.tsx | 6 +- .../views/settings/JoinRuleSettings.tsx | 15 +- .../views/settings/Notifications.tsx | 44 +++--- .../views/settings/SecureBackupPanel.tsx | 10 +- src/components/views/settings/SetIdServer.tsx | 41 +++-- .../views/settings/SpellCheckSettings.tsx | 12 +- .../views/settings/ThemeChoicePanel.tsx | 2 +- .../views/settings/UpdateCheckButton.tsx | 10 +- .../settings/devices/DeviceDetailHeading.tsx | 2 +- .../settings/devices/FilteredDeviceList.tsx | 14 +- .../views/settings/devices/deleteDevices.tsx | 2 +- .../views/settings/devices/filter.ts | 2 +- .../views/settings/devices/useOwnDevices.ts | 4 +- .../settings/discovery/EmailAddresses.tsx | 2 +- .../views/settings/discovery/PhoneNumbers.tsx | 2 +- .../tabs/room/AdvancedRoomSettingsTab.tsx | 6 +- .../settings/tabs/room/BridgeSettingsTab.tsx | 4 +- .../tabs/room/NotificationSettingsTab.tsx | 4 +- .../tabs/room/RolesRoomSettingsTab.tsx | 45 +++--- .../tabs/room/SecurityRoomSettingsTab.tsx | 30 ++-- .../tabs/user/AppearanceUserSettingsTab.tsx | 8 +- .../tabs/user/HelpUserSettingsTab.tsx | 12 +- .../tabs/user/MjolnirUserSettingsTab.tsx | 22 +-- .../tabs/user/NotificationUserSettingsTab.tsx | 2 +- .../tabs/user/PreferencesUserSettingsTab.tsx | 8 +- .../tabs/user/SecurityUserSettingsTab.tsx | 6 +- .../settings/tabs/user/SessionManagerTab.tsx | 14 +- .../tabs/user/SidebarUserSettingsTab.tsx | 2 +- .../tabs/user/VoiceUserSettingsTab.tsx | 10 +- .../views/spaces/QuickSettingsButton.tsx | 4 +- .../views/spaces/QuickThemeSwitcher.tsx | 2 +- .../views/spaces/SpaceBasicSettings.tsx | 8 +- .../views/spaces/SpaceChildrenPicker.tsx | 11 +- .../views/spaces/SpaceCreateMenu.tsx | 23 ++- src/components/views/spaces/SpacePanel.tsx | 20 +-- .../views/spaces/SpacePublicShare.tsx | 4 +- .../views/spaces/SpaceSettingsGeneralTab.tsx | 8 +- .../spaces/SpaceSettingsVisibilityTab.tsx | 8 +- .../views/spaces/SpaceTreeLevel.tsx | 23 +-- .../views/toasts/GenericExpiringToast.tsx | 2 +- .../toasts/NonUrgentEchoFailureToast.tsx | 4 +- .../views/toasts/VerificationRequestToast.tsx | 12 +- .../user-onboarding/UserOnboardingButton.tsx | 4 +- .../UserOnboardingFeedback.tsx | 2 +- .../user-onboarding/UserOnboardingHeader.tsx | 4 +- .../user-onboarding/UserOnboardingList.tsx | 10 +- .../user-onboarding/UserOnboardingPage.tsx | 2 +- .../user-onboarding/UserOnboardingTask.tsx | 2 +- .../verification/VerificationShowSas.tsx | 4 +- src/components/views/voip/AudioFeed.tsx | 14 +- .../voip/AudioFeedArrayForLegacyCall.tsx | 8 +- src/components/views/voip/CallView.tsx | 12 +- src/components/views/voip/DialPad.tsx | 6 +- src/components/views/voip/DialPadModal.tsx | 14 +- src/components/views/voip/LegacyCallView.tsx | 6 +- .../LegacyCallView/LegacyCallViewButtons.tsx | 6 +- .../views/voip/LegacyCallViewForRoom.tsx | 14 +- .../views/voip/LegacyCallViewSidebar.tsx | 2 +- src/components/views/voip/VideoFeed.tsx | 22 +-- src/contexts/MatrixClientContext.tsx | 19 ++- src/contexts/RoomContext.ts | 2 +- src/contexts/SDKContext.ts | 2 +- src/createRoom.ts | 8 +- src/dispatcher/dispatch-actions/threads.ts | 2 +- src/dispatcher/dispatcher.ts | 4 +- src/editor/caret.ts | 33 ++++- src/editor/deserialize.ts | 6 +- src/editor/dom.ts | 35 ++++- src/editor/history.ts | 4 +- src/editor/operations.ts | 8 +- src/editor/parts.ts | 4 +- src/editor/range.ts | 2 +- src/effects/confetti/index.ts | 6 +- src/effects/fireworks/index.ts | 14 +- src/effects/hearts/index.ts | 6 +- src/effects/rainfall/index.ts | 4 +- src/effects/snowfall/index.ts | 6 +- src/effects/spaceinvaders/index.ts | 6 +- src/emoji.ts | 4 +- src/emojipicker/recent.ts | 6 +- src/hooks/spotlight/useDebouncedCallback.ts | 8 +- src/hooks/useAccountData.ts | 6 +- src/hooks/useAnimation.ts | 4 +- src/hooks/useAudioDeviceSelection.ts | 11 +- src/hooks/useDispatcher.ts | 5 +- src/hooks/useEventEmitter.ts | 2 +- src/hooks/useFavouriteMessages.ts | 7 +- src/hooks/useLocalEcho.ts | 2 +- src/hooks/useProfileInfo.ts | 7 +- src/hooks/usePublicRoomDirectory.ts | 14 +- src/hooks/useSettings.ts | 2 +- src/hooks/useSlidingSyncRoomSearch.ts | 6 +- src/hooks/useSmoothAnimation.ts | 2 +- src/hooks/useSpaceResults.ts | 2 +- src/hooks/useStateCallback.ts | 2 +- src/hooks/useStateToggle.ts | 2 +- src/hooks/useTimeout.ts | 6 +- src/hooks/useTimeoutToggle.ts | 10 +- src/hooks/useUserDirectory.ts | 7 +- src/hooks/useUserOnboardingContext.ts | 2 +- src/hooks/useUserOnboardingTasks.ts | 4 +- src/indexing/EventIndex.ts | 84 ++++++----- src/indexing/EventIndexPeg.ts | 14 +- src/integrations/IntegrationManagers.ts | 10 +- src/languageHandler.tsx | 30 ++-- src/linkify-matrix.ts | 6 +- src/mjolnir/BanList.ts | 2 +- src/mjolnir/Mjolnir.ts | 18 +-- src/models/Call.ts | 54 +++---- src/models/RoomUpload.ts | 2 +- src/modules/ModuleRunner.ts | 4 +- src/notifications/ContentRules.ts | 4 +- src/notifications/PushRuleVectorState.ts | 4 +- src/performance/index.ts | 4 +- src/phonenumber.ts | 4 +- src/rageshake/rageshake.ts | 6 +- src/rageshake/submit-rageshake.ts | 16 +- src/resizer/distributors/collapse.ts | 6 +- src/resizer/distributors/fixed.ts | 10 +- src/resizer/distributors/percentage.ts | 6 +- src/resizer/item.ts | 28 ++-- src/resizer/resizer.ts | 14 +- src/resizer/sizer.ts | 12 +- src/sendTimePerformanceMetrics.ts | 6 +- src/settings/SettingsStore.ts | 16 +- src/settings/WatchManager.ts | 11 +- .../controllers/FontSizeController.ts | 2 +- .../controllers/NotificationControllers.ts | 2 +- .../controllers/OrderedMultiController.ts | 2 +- .../PushToMatrixClientController.ts | 2 +- .../controllers/ReloadOnChangeController.ts | 2 +- .../controllers/SystemFontController.ts | 2 +- .../controllers/ThreadBetaController.tsx | 2 +- .../controllers/UseSystemFontController.ts | 2 +- .../AbstractLocalStorageSettingsHandler.ts | 4 +- .../handlers/AccountSettingsHandler.ts | 8 +- .../handlers/DefaultSettingsHandler.ts | 2 +- .../handlers/DeviceSettingsHandler.ts | 6 +- .../handlers/PlatformSettingsHandler.ts | 2 +- .../handlers/RoomAccountSettingsHandler.ts | 6 +- src/settings/handlers/RoomSettingsHandler.ts | 6 +- src/settings/watchers/FontWatcher.ts | 15 +- src/settings/watchers/ThemeWatcher.ts | 14 +- src/stores/AsyncStore.ts | 6 +- src/stores/AsyncStoreWithClient.ts | 6 +- src/stores/AutoRageshakeStore.ts | 8 +- src/stores/BreadcrumbsStore.ts | 14 +- src/stores/CallStore.ts | 12 +- src/stores/HostSignupStore.ts | 4 +- src/stores/LifecycleStore.ts | 6 +- src/stores/ModalWidgetStore.ts | 6 +- src/stores/NonUrgentToastStore.ts | 2 +- src/stores/OwnBeaconStore.ts | 20 +-- src/stores/OwnProfileStore.ts | 10 +- src/stores/ReadyWatchingStore.ts | 12 +- src/stores/RoomViewStore.tsx | 4 +- src/stores/SetupEncryptionStore.ts | 10 +- src/stores/ThreepidInviteStore.ts | 2 +- src/stores/ToastStore.ts | 12 +- src/stores/TypingStore.ts | 2 +- src/stores/UIStore.ts | 2 +- src/stores/WidgetEchoStore.ts | 4 +- src/stores/WidgetStore.ts | 12 +- src/stores/local-echo/EchoContext.ts | 6 +- src/stores/local-echo/EchoStore.ts | 2 +- src/stores/local-echo/EchoTransaction.ts | 6 +- src/stores/local-echo/GenericEchoChamber.ts | 12 +- src/stores/local-echo/RoomEchoChamber.ts | 8 +- .../notifications/ListNotificationState.ts | 10 +- src/stores/notifications/NotificationState.ts | 2 +- .../notifications/RoomNotificationState.ts | 18 +-- .../RoomNotificationStateStore.ts | 4 +- .../notifications/SpaceNotificationState.ts | 10 +- .../SummarizedNotificationState.ts | 2 +- .../notifications/ThreadNotificationState.ts | 4 +- src/stores/right-panel/RightPanelStore.ts | 30 ++-- .../right-panel/RightPanelStorePhases.ts | 2 +- src/stores/room-list/ListLayout.ts | 4 +- src/stores/room-list/MessagePreviewStore.ts | 4 +- src/stores/room-list/RoomListLayoutStore.ts | 4 +- src/stores/room-list/RoomListStore.ts | 38 ++--- src/stores/room-list/SlidingRoomListStore.ts | 26 ++-- src/stores/room-list/SpaceWatcher.ts | 6 +- src/stores/room-list/algorithms/Algorithm.ts | 22 +-- .../list-ordering/ImportanceAlgorithm.ts | 6 +- .../list-ordering/OrderingAlgorithm.ts | 2 +- .../algorithms/tag-sorting/ManualAlgorithm.ts | 2 +- .../algorithms/tag-sorting/RecentAlgorithm.ts | 4 +- .../room-list/filters/SpaceFilterCondition.ts | 2 +- .../room-list/filters/VisibilityProvider.ts | 2 +- src/stores/spaces/SpaceStore.ts | 51 +++---- .../spaces/SpaceTreeLevelLayoutStore.ts | 2 +- src/stores/widgets/StopGapWidget.ts | 12 +- src/stores/widgets/StopGapWidgetDriver.ts | 12 +- src/stores/widgets/WidgetLayoutStore.ts | 32 ++-- src/stores/widgets/WidgetMessagingStore.ts | 6 +- src/stores/widgets/WidgetPermissionStore.ts | 2 +- src/theme.ts | 14 +- src/toasts/AnalyticsToast.tsx | 12 +- src/toasts/BulkUnverifiedSessionsToast.ts | 8 +- src/toasts/DesktopNotificationsToast.ts | 8 +- src/toasts/IncomingCallToast.tsx | 6 +- src/toasts/IncomingLegacyCallToast.tsx | 4 +- src/toasts/MobileGuideToast.ts | 8 +- src/toasts/ServerLimitToast.tsx | 9 +- src/toasts/SetupEncryptionToast.ts | 16 +- src/toasts/UnverifiedSessionToast.ts | 10 +- src/toasts/UpdateToast.tsx | 10 +- src/utils/AnimationUtils.ts | 2 +- src/utils/DMRoomMap.ts | 12 +- src/utils/DialogOpener.ts | 4 +- src/utils/EditorStateTransfer.ts | 2 +- src/utils/ErrorUtils.tsx | 2 +- src/utils/FileDownloader.ts | 2 +- src/utils/FixedRollingArray.ts | 2 +- src/utils/MarkedExecution.ts | 6 +- src/utils/MediaEventHelper.ts | 10 +- src/utils/MessageDiffUtils.tsx | 37 +++-- src/utils/MultiInviter.ts | 8 +- src/utils/PasswordScorer.ts | 2 +- src/utils/ResizeNotifier.ts | 18 +-- src/utils/RoomUpgrade.ts | 2 +- src/utils/Singleflight.ts | 6 +- src/utils/SnakedObject.ts | 2 +- src/utils/StorageManager.ts | 34 +++-- src/utils/Timer.ts | 16 +- src/utils/TypeUtils.ts | 2 +- src/utils/ValidatedServerConfig.ts | 2 +- src/utils/Whenable.ts | 4 +- src/utils/WidgetUtils.ts | 26 ++-- src/utils/beacon/geolocation.ts | 4 +- src/utils/beacon/useOwnLiveBeacons.ts | 4 +- src/utils/createVoiceMessageContent.ts | 4 +- .../snoozeBulkUnverifiedDeviceReminder.ts | 4 +- src/utils/exportUtils/Exporter.ts | 2 +- src/utils/exportUtils/HtmlExport.tsx | 24 +-- src/utils/exportUtils/JSONExport.ts | 8 +- src/utils/exportUtils/PlainTextExport.ts | 8 +- src/utils/leave-behaviour.ts | 8 +- src/utils/local-room.ts | 4 +- src/utils/membership.ts | 14 +- .../permalinks/ElementPermalinkConstructor.ts | 2 +- .../MatrixSchemePermalinkConstructor.ts | 2 +- .../MatrixToPermalinkConstructor.ts | 2 +- src/utils/permalinks/Permalinks.ts | 27 ++-- src/utils/pillify.tsx | 4 +- src/utils/presence.ts | 2 +- src/utils/space.tsx | 11 +- src/utils/strings.ts | 2 +- src/utils/tooltipify.tsx | 4 +- src/utils/useTooltip.tsx | 4 +- src/utils/validate/numberInRange.ts | 8 +- src/utils/video-rooms.ts | 2 +- src/verification.ts | 15 +- .../components/VoiceBroadcastBody.tsx | 2 +- .../components/atoms/VoiceBroadcastHeader.tsx | 2 +- .../atoms/VoiceBroadcastRoomSubtitle.tsx | 2 +- .../molecules/VoiceBroadcastPlaybackBody.tsx | 4 +- .../VoiceBroadcastPreRecordingPip.tsx | 6 +- .../molecules/VoiceBroadcastRecordingPip.tsx | 7 +- .../hooks/useCurrentVoiceBroadcastPlayback.ts | 6 +- .../useCurrentVoiceBroadcastPreRecording.ts | 5 +- .../useCurrentVoiceBroadcastRecording.ts | 8 +- .../hooks/useHasRoomLiveVoiceBroadcast.ts | 2 +- .../hooks/useVoiceBroadcastPlayback.ts | 26 +++- .../hooks/useVoiceBroadcastRecording.tsx | 16 +- .../models/VoiceBroadcastPlayback.ts | 4 +- .../models/VoiceBroadcastRecording.ts | 6 +- .../stores/VoiceBroadcastRecordingsStore.ts | 2 +- .../utils/VoiceBroadcastResumer.ts | 2 +- .../checkVoiceBroadcastPreConditions.tsx | 6 +- ...rCurrentVoiceBroadcastPlaybackIfStopped.ts | 2 +- .../shouldDisplayAsVoiceBroadcastTile.ts | 2 +- .../utils/showCantStartACallDialog.tsx | 2 +- .../utils/startNewVoiceBroadcastRecording.ts | 2 +- .../textForVoiceBroadcastStoppedEvent.tsx | 2 +- src/widgets/Jitsi.ts | 2 +- src/widgets/ManagedHybrid.ts | 2 +- 683 files changed, 3459 insertions(+), 3013 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 30e01f86b5..a65f20893b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -100,8 +100,12 @@ module.exports = { files: ["src/**/*.{ts,tsx}", "test/**/*.{ts,tsx}", "cypress/**/*.ts"], extends: ["plugin:matrix-org/typescript", "plugin:matrix-org/react"], rules: { - // temporary disabled - "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-function-return-type": [ + "error", + { + allowExpressions: true, + }, + ], // Things we do that break the ideal style "prefer-promise-reject-errors": "off", diff --git a/src/@types/diff-dom.d.ts b/src/@types/diff-dom.d.ts index 5998b0e404..bf9150a697 100644 --- a/src/@types/diff-dom.d.ts +++ b/src/@types/diff-dom.d.ts @@ -20,10 +20,10 @@ declare module "diff-dom" { name: string; text?: string; route: number[]; - value: string; - element: unknown; - oldValue: string; - newValue: string; + value: HTMLElement | string; + element: HTMLElement | string; + oldValue: HTMLElement | string; + newValue: HTMLElement | string; } interface IOpts {} diff --git a/src/@types/polyfill.ts b/src/@types/polyfill.ts index d24d2f4463..6434512e75 100644 --- a/src/@types/polyfill.ts +++ b/src/@types/polyfill.ts @@ -15,7 +15,7 @@ limitations under the License. */ // This is intended to fix re-resizer because of its unguarded `instanceof TouchEvent` checks. -export function polyfillTouchEvent() { +export function polyfillTouchEvent(): void { // Firefox doesn't have touch events without touch devices being present, so create a fake // one we can rely on lying about. if (!window.TouchEvent) { diff --git a/src/AsyncWrapper.tsx b/src/AsyncWrapper.tsx index f6f7edd2c2..226f5b692b 100644 --- a/src/AsyncWrapper.tsx +++ b/src/AsyncWrapper.tsx @@ -47,7 +47,7 @@ export default class AsyncWrapper extends React.Component { error: null, }; - public componentDidMount() { + public componentDidMount(): void { // XXX: temporary logging to try to diagnose // https://github.com/vector-im/element-web/issues/3148 logger.log("Starting load of AsyncWrapper for modal"); @@ -69,15 +69,15 @@ export default class AsyncWrapper extends React.Component { }); } - public componentWillUnmount() { + public componentWillUnmount(): void { this.unmounted = true; } - private onWrapperCancelClick = () => { + private onWrapperCancelClick = (): void => { this.props.onFinished(false); }; - public render() { + public render(): JSX.Element { if (this.state.component) { const Component = this.state.component; return ; diff --git a/src/Avatar.ts b/src/Avatar.ts index 30a53e74a0..8a3f10a22c 100644 --- a/src/Avatar.ts +++ b/src/Avatar.ts @@ -137,7 +137,12 @@ export function getInitialLetter(name: string): string { return split(name, "", 1)[0].toUpperCase(); } -export function avatarUrlForRoom(room: Room, width: number, height: number, resizeMethod?: ResizeMethod) { +export function avatarUrlForRoom( + room: Room, + width: number, + height: number, + resizeMethod?: ResizeMethod, +): string | null { if (!room) return null; // null-guard if (room.getMxcAvatarUrl()) { diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts index 46a406271c..22d274ffb1 100644 --- a/src/BasePlatform.ts +++ b/src/BasePlatform.ts @@ -272,7 +272,7 @@ export default abstract class BasePlatform { return null; } - public setLanguage(preferredLangs: string[]) {} + public setLanguage(preferredLangs: string[]): void {} public setSpellCheckEnabled(enabled: boolean): void {} @@ -280,7 +280,7 @@ export default abstract class BasePlatform { return null; } - public setSpellCheckLanguages(preferredLangs: string[]) {} + public setSpellCheckLanguages(preferredLangs: string[]): void {} public getSpellCheckLanguages(): Promise | null { return null; diff --git a/src/BlurhashEncoder.ts b/src/BlurhashEncoder.ts index 56e137cc01..01f84421b6 100644 --- a/src/BlurhashEncoder.ts +++ b/src/BlurhashEncoder.ts @@ -40,7 +40,7 @@ export class BlurhashEncoder { this.worker.onmessage = this.onMessage; } - private onMessage = (ev: MessageEvent) => { + private onMessage = (ev: MessageEvent): void => { const { seq, blurhash } = ev.data; const deferred = this.pendingDeferredMap.get(seq); if (deferred) { diff --git a/src/ContentMessages.ts b/src/ContentMessages.ts index a2fe27d0a9..1381e9431e 100644 --- a/src/ContentMessages.ts +++ b/src/ContentMessages.ts @@ -68,16 +68,20 @@ interface IMediaConfig { * @param {File} imageFile The file to load in an image element. * @return {Promise} A promise that resolves with the html image element. */ -async function loadImageElement(imageFile: File) { +async function loadImageElement(imageFile: File): Promise<{ + width: number; + height: number; + img: HTMLImageElement; +}> { // Load the file into an html element const img = new Image(); const objectUrl = URL.createObjectURL(imageFile); const imgPromise = new Promise((resolve, reject) => { - img.onload = function () { + img.onload = function (): void { URL.revokeObjectURL(objectUrl); resolve(img); }; - img.onerror = function (e) { + img.onerror = function (e): void { reject(e); }; }); @@ -185,13 +189,13 @@ function loadVideoElement(videoFile: File): Promise { const reader = new FileReader(); - reader.onload = function (ev) { + reader.onload = function (ev): void { // Wait until we have enough data to thumbnail the first frame. - video.onloadeddata = async function () { + video.onloadeddata = async function (): Promise { resolve(video); video.pause(); }; - video.onerror = function (e) { + video.onerror = function (e): void { reject(e); }; @@ -206,7 +210,7 @@ function loadVideoElement(videoFile: File): Promise { video.load(); video.play(); }; - reader.onerror = function (e) { + reader.onerror = function (e): void { reject(e); }; reader.readAsDataURL(videoFile); @@ -253,10 +257,10 @@ function infoForVideoFile( function readFileAsArrayBuffer(file: File | Blob): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); - reader.onload = function (e) { + reader.onload = function (e): void { resolve(e.target.result as ArrayBuffer); }; - reader.onerror = function (e) { + reader.onerror = function (e): void { reject(e); }; reader.readAsArrayBuffer(file); @@ -461,7 +465,7 @@ export default class ContentMessages { matrixClient: MatrixClient, replyToEvent: MatrixEvent | undefined, promBefore?: Promise, - ) { + ): Promise { const fileName = file.name || _t("Attachment"); const content: Omit & { info: Partial } = { body: fileName, @@ -491,7 +495,7 @@ export default class ContentMessages { this.inprogress.push(upload); dis.dispatch({ action: Action.UploadStarted, upload }); - function onProgress(progress: UploadProgress) { + function onProgress(progress: UploadProgress): void { upload.onProgress(progress); dis.dispatch({ action: Action.UploadProgress, upload }); } @@ -568,7 +572,7 @@ export default class ContentMessages { } } - private isFileSizeAcceptable(file: File) { + private isFileSizeAcceptable(file: File): boolean { if ( this.mediaConfig !== null && this.mediaConfig["m.upload.size"] !== undefined && @@ -599,7 +603,7 @@ export default class ContentMessages { }); } - public static sharedInstance() { + public static sharedInstance(): ContentMessages { if (window.mxContentMessages === undefined) { window.mxContentMessages = new ContentMessages(); } diff --git a/src/DateUtils.ts b/src/DateUtils.ts index 1dab03121e..5973a7c5f2 100644 --- a/src/DateUtils.ts +++ b/src/DateUtils.ts @@ -188,7 +188,7 @@ export function wantsDateSeparator(prevEventDate: Date, nextEventDate: Date): bo return prevEventDate.getDay() !== nextEventDate.getDay(); } -export function formatFullDateNoDay(date: Date) { +export function formatFullDateNoDay(date: Date): string { return _t("%(date)s at %(time)s", { date: date.toLocaleDateString().replace(/\//g, "-"), time: date.toLocaleTimeString().replace(/:/g, "-"), @@ -205,7 +205,7 @@ export function formatFullDateNoDayISO(date: Date): string { return date.toISOString(); } -export function formatFullDateNoDayNoTime(date: Date) { +export function formatFullDateNoDayNoTime(date: Date): string { return date.getFullYear() + "/" + pad(date.getMonth() + 1) + "/" + pad(date.getDate()); } diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts index 3d33ff0fda..be48717415 100644 --- a/src/DeviceListener.ts +++ b/src/DeviceListener.ts @@ -19,6 +19,7 @@ import { logger } from "matrix-js-sdk/src/logger"; import { CryptoEvent } from "matrix-js-sdk/src/crypto"; import { ClientEvent, EventType, RoomStateEvent } from "matrix-js-sdk/src/matrix"; import { SyncState } from "matrix-js-sdk/src/sync"; +import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup"; import { MatrixClientPeg } from "./MatrixClientPeg"; import dis from "./dispatcher/dispatcher"; @@ -56,7 +57,7 @@ export default class DeviceListener { // has the user dismissed any of the various nag toasts to setup encryption on this device? private dismissedThisDeviceToast = false; // cache of the key backup info - private keyBackupInfo: object = null; + private keyBackupInfo: IKeyBackupInfo | null = null; private keyBackupFetchedAt: number = null; private keyBackupStatusChecked = false; // We keep a list of our own device IDs so we can batch ones that were already @@ -70,12 +71,12 @@ export default class DeviceListener { private enableBulkUnverifiedSessionsReminder = true; private deviceClientInformationSettingWatcherRef: string | undefined; - public static sharedInstance() { + public static sharedInstance(): DeviceListener { if (!window.mxDeviceListener) window.mxDeviceListener = new DeviceListener(); return window.mxDeviceListener; } - public start() { + public start(): void { this.running = true; MatrixClientPeg.get().on(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices); MatrixClientPeg.get().on(CryptoEvent.DevicesUpdated, this.onDevicesUpdated); @@ -98,7 +99,7 @@ export default class DeviceListener { this.updateClientInformation(); } - public stop() { + public stop(): void { this.running = false; if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices); @@ -134,7 +135,7 @@ export default class DeviceListener { * * @param {String[]} deviceIds List of device IDs to dismiss notifications for */ - public async dismissUnverifiedSessions(deviceIds: Iterable) { + public async dismissUnverifiedSessions(deviceIds: Iterable): Promise { logger.log("Dismissing unverified sessions: " + Array.from(deviceIds).join(",")); for (const d of deviceIds) { this.dismissed.add(d); @@ -143,19 +144,19 @@ export default class DeviceListener { this.recheck(); } - public dismissEncryptionSetup() { + public dismissEncryptionSetup(): void { this.dismissedThisDeviceToast = true; this.recheck(); } - private ensureDeviceIdsAtStartPopulated() { + private ensureDeviceIdsAtStartPopulated(): void { if (this.ourDeviceIdsAtStart === null) { const cli = MatrixClientPeg.get(); this.ourDeviceIdsAtStart = new Set(cli.getStoredDevicesForUser(cli.getUserId()).map((d) => d.deviceId)); } } - private onWillUpdateDevices = async (users: string[], initialFetch?: boolean) => { + private onWillUpdateDevices = async (users: string[], initialFetch?: boolean): Promise => { // If we didn't know about *any* devices before (ie. it's fresh login), // then they are all pre-existing devices, so ignore this and set the // devicesAtStart list to the devices that we see after the fetch. @@ -168,26 +169,26 @@ export default class DeviceListener { // before we download any new ones. }; - private onDevicesUpdated = (users: string[]) => { + private onDevicesUpdated = (users: string[]): void => { if (!users.includes(MatrixClientPeg.get().getUserId())) return; this.recheck(); }; - private onDeviceVerificationChanged = (userId: string) => { + private onDeviceVerificationChanged = (userId: string): void => { if (userId !== MatrixClientPeg.get().getUserId()) return; this.recheck(); }; - private onUserTrustStatusChanged = (userId: string) => { + private onUserTrustStatusChanged = (userId: string): void => { if (userId !== MatrixClientPeg.get().getUserId()) return; this.recheck(); }; - private onCrossSingingKeysChanged = () => { + private onCrossSingingKeysChanged = (): void => { this.recheck(); }; - private onAccountData = (ev: MatrixEvent) => { + private onAccountData = (ev: MatrixEvent): void => { // User may have: // * migrated SSSS to symmetric // * uploaded keys to secret storage @@ -202,13 +203,13 @@ export default class DeviceListener { } }; - private onSync = (state: SyncState, prevState?: SyncState) => { + private onSync = (state: SyncState, prevState?: SyncState): void => { if (state === "PREPARED" && prevState === null) { this.recheck(); } }; - private onRoomStateEvents = (ev: MatrixEvent) => { + private onRoomStateEvents = (ev: MatrixEvent): void => { if (ev.getType() !== EventType.RoomEncryption) return; // If a room changes to encrypted, re-check as it may be our first @@ -216,7 +217,7 @@ export default class DeviceListener { this.recheck(); }; - private onAction = ({ action }: ActionPayload) => { + private onAction = ({ action }: ActionPayload): void => { if (action !== Action.OnLoggedIn) return; this.recheck(); this.updateClientInformation(); @@ -224,7 +225,7 @@ export default class DeviceListener { // The server doesn't tell us when key backup is set up, so we poll // & cache the result - private async getKeyBackupInfo() { + private async getKeyBackupInfo(): Promise { const now = new Date().getTime(); if (!this.keyBackupInfo || this.keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL) { this.keyBackupInfo = await MatrixClientPeg.get().getKeyBackupVersion(); @@ -233,7 +234,7 @@ export default class DeviceListener { return this.keyBackupInfo; } - private shouldShowSetupEncryptionToast() { + private shouldShowSetupEncryptionToast(): boolean { // If we're in the middle of a secret storage operation, we're likely // modifying the state involved here, so don't add new toasts to setup. if (isSecretStorageBeingAccessed()) return false; @@ -242,7 +243,7 @@ export default class DeviceListener { return cli && cli.getRooms().some((r) => cli.isRoomEncrypted(r.roomId)); } - private async recheck() { + private async recheck(): Promise { if (!this.running) return; // we have been stopped const cli = MatrixClientPeg.get(); @@ -359,7 +360,7 @@ export default class DeviceListener { this.displayingToastsForDeviceIds = newUnverifiedDeviceIds; } - private checkKeyBackupStatus = async () => { + private checkKeyBackupStatus = async (): Promise => { if (this.keyBackupStatusChecked) { return; } @@ -388,7 +389,7 @@ export default class DeviceListener { } }; - private updateClientInformation = async () => { + private updateClientInformation = async (): Promise => { try { if (this.shouldRecordClientInformation) { await recordClientInformation(MatrixClientPeg.get(), SdkConfig.get(), PlatformPeg.get()); diff --git a/src/Editing.ts b/src/Editing.ts index 57e58cc2a7..e331a3dca1 100644 --- a/src/Editing.ts +++ b/src/Editing.ts @@ -16,5 +16,6 @@ limitations under the License. import { TimelineRenderingType } from "./contexts/RoomContext"; -export const editorRoomKey = (roomId: string, context: TimelineRenderingType) => `mx_edit_room_${roomId}_${context}`; -export const editorStateKey = (eventId: string) => `mx_edit_state_${eventId}`; +export const editorRoomKey = (roomId: string, context: TimelineRenderingType): string => + `mx_edit_room_${roomId}_${context}`; +export const editorStateKey = (eventId: string): string => `mx_edit_state_${eventId}`; diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 19da52f45b..3e67e42256 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -449,9 +449,9 @@ export interface IOptsReturnString extends IOpts { returnString: true; } -const emojiToHtmlSpan = (emoji: string) => +const emojiToHtmlSpan = (emoji: string): string => `${emoji}`; -const emojiToJsxSpan = (emoji: string, key: number) => ( +const emojiToJsxSpan = (emoji: string, key: number): JSX.Element => ( {emoji} @@ -505,7 +505,7 @@ function formatEmojis(message: string, isHtmlMessage: boolean): (JSX.Element | s */ export function bodyToHtml(content: IContent, highlights: Optional, opts: IOptsReturnString): string; export function bodyToHtml(content: IContent, highlights: Optional, opts: IOptsReturnNode): ReactNode; -export function bodyToHtml(content: IContent, highlights: Optional, opts: IOpts = {}) { +export function bodyToHtml(content: IContent, highlights: Optional, opts: IOpts = {}): ReactNode | string { const isFormattedBody = content.format === "org.matrix.custom.html" && !!content.formatted_body; let bodyHasEmoji = false; let isHtmlMessage = false; diff --git a/src/ImageUtils.ts b/src/ImageUtils.ts index 1618aa8f4c..42db71ebab 100644 --- a/src/ImageUtils.ts +++ b/src/ImageUtils.ts @@ -28,7 +28,7 @@ limitations under the License. * consume in the timeline, when performing scroll offset calculations * (e.g. scroll locking) */ -export function thumbHeight(fullWidth: number, fullHeight: number, thumbWidth: number, thumbHeight: number) { +export function thumbHeight(fullWidth: number, fullHeight: number, thumbWidth: number, thumbHeight: number): number { if (!fullWidth || !fullHeight) { // Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even // log this because it's spammy diff --git a/src/Keyboard.ts b/src/Keyboard.ts index 3a425cef31..9d4d3f6152 100644 --- a/src/Keyboard.ts +++ b/src/Keyboard.ts @@ -76,7 +76,7 @@ export const Key = { export const IS_MAC = navigator.platform.toUpperCase().includes("MAC"); -export function isOnlyCtrlOrCmdKeyEvent(ev) { +export function isOnlyCtrlOrCmdKeyEvent(ev: KeyboardEvent): boolean { if (IS_MAC) { return ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey; } else { diff --git a/src/LegacyCallHandler.tsx b/src/LegacyCallHandler.tsx index d81bd73661..82e5cac996 100644 --- a/src/LegacyCallHandler.tsx +++ b/src/LegacyCallHandler.tsx @@ -169,7 +169,7 @@ export default class LegacyCallHandler extends EventEmitter { private silencedCalls = new Set(); // callIds - public static get instance() { + public static get instance(): LegacyCallHandler { if (!window.mxLegacyCallHandler) { window.mxLegacyCallHandler = new LegacyCallHandler(); } @@ -456,7 +456,7 @@ export default class LegacyCallHandler extends EventEmitter { return callsNotInThatRoom; } - public getAllActiveCallsForPip(roomId: string) { + public getAllActiveCallsForPip(roomId: string): MatrixCall[] { const room = MatrixClientPeg.get().getRoom(roomId); if (WidgetLayoutStore.instance.hasMaximisedWidget(room)) { // This checks if there is space for the call view in the aux panel @@ -478,7 +478,7 @@ export default class LegacyCallHandler extends EventEmitter { const audio = document.getElementById(audioId) as HTMLMediaElement; if (audio) { this.addEventListenersForAudioElement(audio); - const playAudio = async () => { + const playAudio = async (): Promise => { try { if (audio.muted) { logger.error( @@ -524,7 +524,7 @@ export default class LegacyCallHandler extends EventEmitter { // TODO: Attach an invisible element for this instead // which listens? const audio = document.getElementById(audioId) as HTMLMediaElement; - const pauseAudio = () => { + const pauseAudio = (): void => { logger.debug(`${logPrefix} pausing audio`); // pause doesn't return a promise, so just do it audio.pause(); @@ -600,7 +600,7 @@ export default class LegacyCallHandler extends EventEmitter { this.setCallListeners(newCall); this.setCallState(newCall, newCall.state); }); - call.on(CallEvent.AssertedIdentityChanged, async () => { + call.on(CallEvent.AssertedIdentityChanged, async (): Promise => { if (!this.matchesCallForThisRoom(call)) return; logger.log(`Call ID ${call.callId} got new asserted identity:`, call.getRemoteAssertedIdentity()); @@ -808,7 +808,7 @@ export default class LegacyCallHandler extends EventEmitter { private showICEFallbackPrompt(): void { const cli = MatrixClientPeg.get(); - const code = (sub) => {sub}; + const code = (sub: string): JSX.Element => {sub}; Modal.createDialog( QuestionDialog, { diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index db6d15c188..30aab429fb 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -219,7 +219,7 @@ export function attemptTokenLogin( }) .then(function (creds) { logger.log("Logged in with token"); - return clearStorage().then(async () => { + return clearStorage().then(async (): Promise => { await persistCredentials(creds); // remember that we just logged in sessionStorage.setItem("mx_fresh_login", String(true)); @@ -406,7 +406,7 @@ async function pickleKeyToAesKey(pickleKey: string): Promise { ); } -async function abortLogin() { +async function abortLogin(): Promise { const signOut = await showStorageEvictedDialog(); if (signOut) { await clearStorage(); diff --git a/src/Livestream.ts b/src/Livestream.ts index d339045c94..563136983b 100644 --- a/src/Livestream.ts +++ b/src/Livestream.ts @@ -20,14 +20,14 @@ import { MatrixClientPeg } from "./MatrixClientPeg"; import SdkConfig from "./SdkConfig"; import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions"; -export function getConfigLivestreamUrl() { +export function getConfigLivestreamUrl(): string | undefined { return SdkConfig.get("audio_stream_url"); } // Dummy rtmp URL used to signal that we want a special audio-only stream const AUDIOSTREAM_DUMMY_URL = "rtmp://audiostream.dummy/"; -async function createLiveStream(roomId: string) { +async function createLiveStream(roomId: string): Promise { const openIdToken = await MatrixClientPeg.get().getOpenIdToken(); const url = getConfigLivestreamUrl() + "/createStream"; @@ -47,7 +47,7 @@ async function createLiveStream(roomId: string) { return respBody["stream_id"]; } -export async function startJitsiAudioLivestream(widgetMessaging: ClientWidgetApi, roomId: string) { +export async function startJitsiAudioLivestream(widgetMessaging: ClientWidgetApi, roomId: string): Promise { const streamId = await createLiveStream(roomId); await widgetMessaging.transport.send(ElementWidgetActions.StartLiveStream, { diff --git a/src/Login.ts b/src/Login.ts index ec769e8cb3..90f8f5d0eb 100644 --- a/src/Login.ts +++ b/src/Login.ts @@ -122,7 +122,7 @@ export default class Login { initial_device_display_name: this.defaultDeviceDisplayName, }; - const tryFallbackHs = (originalError) => { + const tryFallbackHs = (originalError: Error): Promise => { return sendLoginRequest(this.fallbackHsUrl, this.isUrl, "m.login.password", loginParams).catch( (fallbackError) => { logger.log("fallback HS login failed", fallbackError); diff --git a/src/Markdown.ts b/src/Markdown.ts index 404da0ca8d..a32126117d 100644 --- a/src/Markdown.ts +++ b/src/Markdown.ts @@ -56,7 +56,7 @@ function isMultiLine(node: commonmark.Node): boolean { return par.firstChild != par.lastChild; } -function getTextUntilEndOrLinebreak(node: commonmark.Node) { +function getTextUntilEndOrLinebreak(node: commonmark.Node): string { let currentNode = node; let text = ""; while (currentNode !== null && currentNode.type !== "softbreak" && currentNode.type !== "linebreak") { @@ -137,7 +137,7 @@ export default class Markdown { * See: https://github.com/vector-im/element-web/issues/4674 * @param parsed */ - private repairLinks(parsed: commonmark.Node) { + private repairLinks(parsed: commonmark.Node): commonmark.Node { const walker = parsed.walker(); let event: commonmark.NodeWalkingStep = null; let text = ""; diff --git a/src/Modal.tsx b/src/Modal.tsx index 290c082344..1b21f74b5e 100644 --- a/src/Modal.tsx +++ b/src/Modal.tsx @@ -77,7 +77,7 @@ export class ModalManager extends TypedEventEmitter[] = []; - private static getOrCreateContainer() { + private static getOrCreateContainer(): HTMLElement { let container = document.getElementById(DIALOG_CONTAINER_ID); if (!container) { @@ -89,7 +89,7 @@ export class ModalManager extends TypedEventEmitter 0; + public hasDialogs(): boolean { + return !!this.priorityModal || !!this.staticModal || this.modals.length > 0; } public createDialog( Element: React.ComponentType, ...rest: ParametersWithoutFirst - ) { + ): IHandle { return this.createDialogAsync(Promise.resolve(Element), ...rest); } public appendDialog( Element: React.ComponentType, ...rest: ParametersWithoutFirst - ) { + ): IHandle { return this.appendDialogAsync(Promise.resolve(Element), ...rest); } - public closeCurrentModal(reason: string) { + public closeCurrentModal(reason: string): void { const modal = this.getCurrentModal(); if (!modal) { return; @@ -139,7 +139,11 @@ export class ModalManager extends TypedEventEmitter, className?: string, options?: IOptions, - ) { + ): { + modal: IModal; + closeDialog: IHandle["close"]; + onFinishedProm: IHandle["finished"]; + } { const modal: IModal = { onFinished: props ? props.onFinished : null, onBeforeClose: options.onBeforeClose, @@ -173,7 +177,7 @@ export class ModalManager extends TypedEventEmitter["close"], IHandle["finished"]] { const deferred = defer(); return [ - async (...args: T) => { + async (...args: T): Promise => { if (modal.beforeClosePromise) { await modal.beforeClosePromise; } else if (modal.onBeforeClose) { @@ -302,7 +306,7 @@ export class ModalManager extends TypedEventEmitter { + private onBackgroundClick = (): void => { const modal = this.getCurrentModal(); if (!modal) { return; @@ -320,7 +324,7 @@ export class ModalManager extends TypedEventEmitter { // await next tick because sometimes ReactDOM can race with itself and cause the modal to wrongly stick around await sleep(0); diff --git a/src/PlatformPeg.ts b/src/PlatformPeg.ts index ab45f1ab1a..cc7bb8dc17 100644 --- a/src/PlatformPeg.ts +++ b/src/PlatformPeg.ts @@ -32,13 +32,13 @@ import { PlatformSetPayload } from "./dispatcher/payloads/PlatformSetPayload"; * object. */ export class PlatformPeg { - private platform: BasePlatform = null; + private platform: BasePlatform | null = null; /** * Returns the current Platform object for the application. * This should be an instance of a class extending BasePlatform. */ - public get() { + public get(): BasePlatform | null { return this.platform; } @@ -46,7 +46,7 @@ export class PlatformPeg { * Sets the current platform handler object to use for the application. * @param {BasePlatform} platform an instance of a class extending BasePlatform. */ - public set(platform: BasePlatform) { + public set(platform: BasePlatform): void { this.platform = platform; defaultDispatcher.dispatch({ action: Action.PlatformSet, diff --git a/src/PosthogAnalytics.ts b/src/PosthogAnalytics.ts index 3e1773be29..c8a99ab426 100644 --- a/src/PosthogAnalytics.ts +++ b/src/PosthogAnalytics.ts @@ -175,7 +175,7 @@ export class PosthogAnalytics { this.onLayoutUpdated(); } - private onLayoutUpdated = () => { + private onLayoutUpdated = (): void => { let layout: UserProperties["WebLayout"]; switch (SettingsStore.getValue("layout")) { @@ -195,7 +195,7 @@ export class PosthogAnalytics { this.setProperty("WebLayout", layout); }; - private onAction = (payload: ActionPayload) => { + private onAction = (payload: ActionPayload): void => { if (payload.action !== Action.SettingUpdated) return; const settingsPayload = payload as SettingUpdatedPayload; if (["layout", "useCompactLayout"].includes(settingsPayload.settingName)) { @@ -232,7 +232,7 @@ export class PosthogAnalytics { return properties; }; - private registerSuperProperties(properties: Properties) { + private registerSuperProperties(properties: Properties): void { if (this.enabled) { this.posthog.register(properties); } @@ -255,7 +255,7 @@ export class PosthogAnalytics { } // eslint-disable-nextline no-unused-varsx - private capture(eventName: string, properties: Properties, options?: IPostHogEventOptions) { + private capture(eventName: string, properties: Properties, options?: IPostHogEventOptions): void { if (!this.enabled) { return; } diff --git a/src/PosthogTrackers.ts b/src/PosthogTrackers.ts index 09c7225a3d..8a8b02965c 100644 --- a/src/PosthogTrackers.ts +++ b/src/PosthogTrackers.ts @@ -107,20 +107,20 @@ export default class PosthogTrackers { } export class PosthogScreenTracker extends PureComponent<{ screenName: ScreenName }> { - public componentDidMount() { + public componentDidMount(): void { PosthogTrackers.instance.trackOverride(this.props.screenName); } - public componentDidUpdate() { + public componentDidUpdate(): void { // We do not clear the old override here so that we do not send the non-override screen as a transition PosthogTrackers.instance.trackOverride(this.props.screenName); } - public componentWillUnmount() { + public componentWillUnmount(): void { PosthogTrackers.instance.clearOverride(this.props.screenName); } - public render() { + public render(): JSX.Element { return null; // no need to render anything, we just need to hook into the React lifecycle } } diff --git a/src/Presence.ts b/src/Presence.ts index 3684d6f779..c13cc32b60 100644 --- a/src/Presence.ts +++ b/src/Presence.ts @@ -41,7 +41,7 @@ class Presence { * Start listening the user activity to evaluate his presence state. * Any state change will be sent to the homeserver. */ - public async start() { + public async start(): Promise { this.unavailableTimer = new Timer(UNAVAILABLE_TIME_MS); // the user_activity_start action starts the timer this.dispatcherRef = dis.register(this.onAction); @@ -58,7 +58,7 @@ class Presence { /** * Stop tracking user activity */ - public stop() { + public stop(): void { if (this.dispatcherRef) { dis.unregister(this.dispatcherRef); this.dispatcherRef = null; @@ -73,11 +73,11 @@ class Presence { * Get the current presence state. * @returns {string} the presence state (see PRESENCE enum) */ - public getState() { + public getState(): State { return this.state; } - private onAction = (payload: ActionPayload) => { + private onAction = (payload: ActionPayload): void => { if (payload.action === "user_activity") { this.setState(State.Online); this.unavailableTimer.restart(); @@ -89,7 +89,7 @@ class Presence { * If the state has changed, the homeserver will be notified. * @param {string} newState the new presence state (see PRESENCE enum) */ - private async setState(newState: State) { + private async setState(newState: State): Promise { if (newState === this.state) { return; } diff --git a/src/ScalarAuthClient.ts b/src/ScalarAuthClient.ts index baa6e6f632..a775eb3d4e 100644 --- a/src/ScalarAuthClient.ts +++ b/src/ScalarAuthClient.ts @@ -49,7 +49,7 @@ export default class ScalarAuthClient { this.isDefaultManager = apiUrl === configApiUrl && configUiUrl === uiUrl; } - private writeTokenToStore() { + private writeTokenToStore(): void { window.localStorage.setItem("mx_scalar_token_at_" + this.apiUrl, this.scalarToken); if (this.isDefaultManager) { // We remove the old token from storage to migrate upwards. This is safe @@ -72,7 +72,7 @@ export default class ScalarAuthClient { return this.readTokenFromStore(); } - public setTermsInteractionCallback(callback) { + public setTermsInteractionCallback(callback: TermsInteractionCallback): void { this.termsInteractionCallback = callback; } diff --git a/src/ScalarMessaging.ts b/src/ScalarMessaging.ts index b1912c484a..fec671eab4 100644 --- a/src/ScalarMessaging.ts +++ b/src/ScalarMessaging.ts @@ -711,7 +711,7 @@ function returnStateEvent(event: MessageEvent, roomId: string, eventType: s sendResponse(event, stateEvent.getContent()); } -async function getOpenIdToken(event: MessageEvent) { +async function getOpenIdToken(event: MessageEvent): Promise { try { const tokenObject = await MatrixClientPeg.get().getOpenIdToken(); sendResponse(event, tokenObject); @@ -728,7 +728,7 @@ async function sendEvent( content?: IContent; }>, roomId: string, -) { +): Promise { const eventType = event.data.type; const stateKey = event.data.state_key; const content = event.data.content; @@ -786,7 +786,7 @@ async function readEvents( limit?: number; }>, roomId: string, -) { +): Promise { const eventType = event.data.type; const stateKey = event.data.state_key; const limit = event.data.limit; diff --git a/src/SdkConfig.ts b/src/SdkConfig.ts index 75cc5ef059..06fd7f45e6 100644 --- a/src/SdkConfig.ts +++ b/src/SdkConfig.ts @@ -56,7 +56,7 @@ export default class SdkConfig { private static instance: IConfigOptions; private static fallback: SnakedObject; - private static setInstance(i: IConfigOptions) { + private static setInstance(i: IConfigOptions): void { SdkConfig.instance = i; SdkConfig.fallback = new SnakedObject(i); @@ -90,18 +90,18 @@ export default class SdkConfig { return val === undefined ? undefined : null; } - public static put(cfg: Partial) { + public static put(cfg: Partial): void { SdkConfig.setInstance({ ...DEFAULTS, ...cfg }); } /** * Resets the config to be completely empty. */ - public static unset() { + public static unset(): void { SdkConfig.setInstance({}); // safe to cast - defaults will be applied } - public static add(cfg: Partial) { + public static add(cfg: Partial): void { SdkConfig.put({ ...SdkConfig.get(), ...cfg }); } } diff --git a/src/SecurityManager.ts b/src/SecurityManager.ts index ed72417ecc..20db6594b0 100644 --- a/src/SecurityManager.ts +++ b/src/SecurityManager.ts @@ -86,7 +86,7 @@ async function confirmToDismiss(): Promise { type KeyParams = { passphrase: string; recoveryKey: string }; function makeInputToKey(keyInfo: ISecretStorageKeyInfo): (keyParams: KeyParams) => Promise { - return async ({ passphrase, recoveryKey }) => { + return async ({ passphrase, recoveryKey }): Promise => { if (passphrase) { return deriveKey(passphrase, keyInfo.passphrase.salt, keyInfo.passphrase.iterations); } else { @@ -151,7 +151,7 @@ async function getSecretStorageKey({ /* props= */ { keyInfo, - checkPrivateKey: async (input: KeyParams) => { + checkPrivateKey: async (input: KeyParams): Promise => { const key = await inputToKey(input); return MatrixClientPeg.get().checkSecretStorageKey(key, keyInfo); }, @@ -160,7 +160,7 @@ async function getSecretStorageKey({ /* isPriorityModal= */ false, /* isStaticModal= */ false, /* options= */ { - onBeforeClose: async (reason) => { + onBeforeClose: async (reason): Promise => { if (reason === "backgroundClick") { return confirmToDismiss(); } @@ -196,7 +196,7 @@ export async function getDehydrationKey( /* props= */ { keyInfo, - checkPrivateKey: async (input) => { + checkPrivateKey: async (input): Promise => { const key = await inputToKey(input); try { checkFunc(key); @@ -210,7 +210,7 @@ export async function getDehydrationKey( /* isPriorityModal= */ false, /* isStaticModal= */ false, /* options= */ { - onBeforeClose: async (reason) => { + onBeforeClose: async (reason): Promise => { if (reason === "backgroundClick") { return confirmToDismiss(); } @@ -324,7 +324,7 @@ export async function promptForBackupPassphrase(): Promise { * bootstrapped. Optional. * @param {bool} [forceReset] Reset secret storage even if it's already set up */ -export async function accessSecretStorage(func = async () => {}, forceReset = false) { +export async function accessSecretStorage(func = async (): Promise => {}, forceReset = false): Promise { const cli = MatrixClientPeg.get(); secretStorageBeingAccessed = true; try { @@ -342,7 +342,7 @@ export async function accessSecretStorage(func = async () => {}, forceReset = fa /* priority = */ false, /* static = */ true, /* options = */ { - onBeforeClose: async (reason) => { + onBeforeClose: async (reason): Promise => { // If Secure Backup is required, you cannot leave the modal. if (reason === "backgroundClick") { return !isSecureBackupRequired(); @@ -357,7 +357,7 @@ export async function accessSecretStorage(func = async () => {}, forceReset = fa } } else { await cli.bootstrapCrossSigning({ - authUploadDeviceSigningKeys: async (makeRequest) => { + authUploadDeviceSigningKeys: async (makeRequest): Promise => { const { finished } = Modal.createDialog(InteractiveAuthDialog, { title: _t("Setting up keys"), matrixClient: cli, diff --git a/src/SendHistoryManager.ts b/src/SendHistoryManager.ts index 1fd8f839bd..e95641d4c9 100644 --- a/src/SendHistoryManager.ts +++ b/src/SendHistoryManager.ts @@ -60,7 +60,7 @@ export default class SendHistoryManager { }; } - public save(editorModel: EditorModel, replyEvent?: MatrixEvent) { + public save(editorModel: EditorModel, replyEvent?: MatrixEvent): void { const item = SendHistoryManager.createItem(editorModel, replyEvent); this.history.push(item); this.currentIndex = this.history.length; diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index 910c077525..9b23bd4138 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -85,7 +85,7 @@ const singleMxcUpload = async (): Promise => { Modal.createDialog(UploadConfirmDialog, { file, - onFinished: async (shouldContinue) => { + onFinished: async (shouldContinue): Promise => { if (shouldContinue) { const { content_uri: uri } = await MatrixClientPeg.get().uploadContent(file); resolve(uri); @@ -151,11 +151,11 @@ export class Command { this.analyticsName = opts.analyticsName; } - public getCommand() { + public getCommand(): string { return `/${this.command}`; } - public getCommandWithArgs() { + public getCommandWithArgs(): string { return this.getCommand() + " " + this.args; } @@ -184,7 +184,7 @@ export class Command { return this.runFn(roomId, args); } - public getUsage() { + public getUsage(): string { return _t("Usage") + ": " + this.getCommandWithArgs(); } @@ -193,15 +193,15 @@ export class Command { } } -function reject(error) { +function reject(error?: any): RunResult { return { error }; } -function success(promise?: Promise) { +function success(promise?: Promise): RunResult { return { promise }; } -function successSync(value: any) { +function successSync(value: any): RunResult { return success(Promise.resolve(value)); } @@ -319,7 +319,7 @@ export const Commands = [ ); return success( - finished.then(async ([resp]) => { + finished.then(async ([resp]): Promise => { if (!resp?.continue) return; await upgradeRoom(room, args, resp.invite); }), @@ -338,7 +338,7 @@ export const Commands = [ runFn: function (roomId, args) { if (args) { return success( - (async () => { + (async (): Promise => { const unixTimestamp = Date.parse(args); if (!unixTimestamp) { throw newTranslatableError( @@ -501,7 +501,9 @@ export const Commands = [ ? ContentHelpers.parseTopicContent(content) : { text: _t("This room has no topic.") }; - const ref = (e) => e && linkifyElement(e); + const ref = (e): void => { + if (e) linkifyElement(e); + }; const body = topicToHtml(topic.text, topic.html, ref, true); Modal.createDialog(InfoDialog, { @@ -1028,7 +1030,7 @@ export const Commands = [ const fingerprint = matches[3]; return success( - (async () => { + (async (): Promise => { const device = cli.getStoredDevice(userId, deviceId); if (!device) { throw newTranslatableError("Unknown (user, session) pair: (%(userId)s, %(deviceId)s)", { @@ -1205,7 +1207,7 @@ export const Commands = [ }, runFn: (roomId) => { return success( - (async () => { + (async (): Promise => { const room = await VoipUserMapper.sharedInstance().getVirtualRoomForRoom(roomId); if (!room) throw newTranslatableError("No virtual room for this room"); dis.dispatch({ @@ -1231,7 +1233,7 @@ export const Commands = [ } return success( - (async () => { + (async (): Promise => { if (isPhoneNumber) { const results = await LegacyCallHandler.instance.pstnLookup(userId); if (!results || results.length === 0 || !results[0].userid) { @@ -1265,7 +1267,7 @@ export const Commands = [ const [userId, msg] = matches.slice(1); if (userId && userId.startsWith("@") && userId.includes(":")) { return success( - (async () => { + (async (): Promise => { const cli = MatrixClientPeg.get(); const roomId = await ensureDMExists(cli, userId); dis.dispatch({ diff --git a/src/SlidingSyncManager.ts b/src/SlidingSyncManager.ts index f9ce5ed2a4..75a796df19 100644 --- a/src/SlidingSyncManager.ts +++ b/src/SlidingSyncManager.ts @@ -302,7 +302,7 @@ export class SlidingSyncManager { * @param batchSize The number of rooms to return in each request. * @param gapBetweenRequestsMs The number of milliseconds to wait between requests. */ - public async startSpidering(batchSize: number, gapBetweenRequestsMs: number) { + public async startSpidering(batchSize: number, gapBetweenRequestsMs: number): Promise { await sleep(gapBetweenRequestsMs); // wait a bit as this is called on first render so let's let things load const listIndex = this.getOrAllocateListIndex(SlidingSyncManager.ListSearch); let startIndex = batchSize; diff --git a/src/Terms.ts b/src/Terms.ts index 101a778a94..bb18a18cf7 100644 --- a/src/Terms.ts +++ b/src/Terms.ts @@ -75,7 +75,7 @@ export type TermsInteractionCallback = ( export async function startTermsFlow( services: Service[], interactionCallback: TermsInteractionCallback = dialogTermsInteractionCallback, -) { +): Promise { const termsPromises = services.map((s) => MatrixClientPeg.get().getTerms(s.serviceType, s.baseUrl)); /* @@ -176,7 +176,7 @@ export async function startTermsFlow( urlsForService, ); }); - return Promise.all(agreePromises); + await Promise.all(agreePromises); } export async function dialogTermsInteractionCallback( diff --git a/src/TextForEvent.tsx b/src/TextForEvent.tsx index 8be6cd4a40..ef7d518e74 100644 --- a/src/TextForEvent.tsx +++ b/src/TextForEvent.tsx @@ -228,7 +228,7 @@ function textForTombstoneEvent(ev: MatrixEvent): () => string | null { return () => _t("%(senderDisplayName)s upgraded this room.", { senderDisplayName }); } -const onViewJoinRuleSettingsClick = () => { +const onViewJoinRuleSettingsClick = (): void => { defaultDispatcher.dispatch({ action: "open_room_settings", initial_tab_id: ROOM_SECURITY_TAB, diff --git a/src/UserActivity.ts b/src/UserActivity.ts index 0e163564e0..9217aca3c0 100644 --- a/src/UserActivity.ts +++ b/src/UserActivity.ts @@ -50,7 +50,7 @@ export default class UserActivity { this.activeRecentlyTimeout = new Timer(RECENTLY_ACTIVE_THRESHOLD_MS); } - public static sharedInstance() { + public static sharedInstance(): UserActivity { if (window.mxUserActivity === undefined) { window.mxUserActivity = new UserActivity(window, document); } @@ -66,7 +66,7 @@ export default class UserActivity { * later on when the user does become active. * @param {Timer} timer the timer to use */ - public timeWhileActiveNow(timer: Timer) { + public timeWhileActiveNow(timer: Timer): void { this.timeWhile(timer, this.attachedActiveNowTimers); if (this.userActiveNow()) { timer.start(); @@ -82,14 +82,14 @@ export default class UserActivity { * later on when the user does become active. * @param {Timer} timer the timer to use */ - public timeWhileActiveRecently(timer: Timer) { + public timeWhileActiveRecently(timer: Timer): void { this.timeWhile(timer, this.attachedActiveRecentlyTimers); if (this.userActiveRecently()) { timer.start(); } } - private timeWhile(timer: Timer, attachedTimers: Timer[]) { + private timeWhile(timer: Timer, attachedTimers: Timer[]): void { // important this happens first const index = attachedTimers.indexOf(timer); if (index === -1) { @@ -113,7 +113,7 @@ export default class UserActivity { /** * Start listening to user activity */ - public start() { + public start(): void { this.document.addEventListener("mousedown", this.onUserActivity); this.document.addEventListener("mousemove", this.onUserActivity); this.document.addEventListener("keydown", this.onUserActivity); @@ -133,7 +133,7 @@ export default class UserActivity { /** * Stop tracking user activity */ - public stop() { + public stop(): void { this.document.removeEventListener("mousedown", this.onUserActivity); this.document.removeEventListener("mousemove", this.onUserActivity); this.document.removeEventListener("keydown", this.onUserActivity); @@ -152,7 +152,7 @@ export default class UserActivity { * user's attention at any given moment. * @returns {boolean} true if user is currently 'active' */ - public userActiveNow() { + public userActiveNow(): boolean { return this.activeNowTimeout.isRunning(); } @@ -164,11 +164,11 @@ export default class UserActivity { * (or they may have gone to make tea and left the window focused). * @returns {boolean} true if user has been active recently */ - public userActiveRecently() { + public userActiveRecently(): boolean { return this.activeRecentlyTimeout.isRunning(); } - private onPageVisibilityChanged = (e) => { + private onPageVisibilityChanged = (e): void => { if (this.document.visibilityState === "hidden") { this.activeNowTimeout.abort(); this.activeRecentlyTimeout.abort(); @@ -177,12 +177,12 @@ export default class UserActivity { } }; - private onWindowBlurred = () => { + private onWindowBlurred = (): void => { this.activeNowTimeout.abort(); this.activeRecentlyTimeout.abort(); }; - private onUserActivity = (event: MouseEvent) => { + private onUserActivity = (event: MouseEvent): void => { // ignore anything if the window isn't focused if (!this.document.hasFocus()) return; @@ -214,7 +214,7 @@ export default class UserActivity { } }; - private static async runTimersUntilTimeout(attachedTimers: Timer[], timeout: Timer) { + private static async runTimersUntilTimeout(attachedTimers: Timer[], timeout: Timer): Promise { attachedTimers.forEach((t) => t.start()); try { await timeout.finished(); diff --git a/src/accessibility/RovingTabIndex.tsx b/src/accessibility/RovingTabIndex.tsx index beb6eee004..e90aed87a9 100644 --- a/src/accessibility/RovingTabIndex.tsx +++ b/src/accessibility/RovingTabIndex.tsx @@ -87,7 +87,7 @@ interface IAction { }; } -export const reducer = (state: IState, action: IAction) => { +export const reducer: Reducer = (state: IState, action: IAction) => { switch (action.type) { case Type.Register: { if (!state.activeRef) { diff --git a/src/accessibility/Toolbar.tsx b/src/accessibility/Toolbar.tsx index 22ef018241..3b5fbb0943 100644 --- a/src/accessibility/Toolbar.tsx +++ b/src/accessibility/Toolbar.tsx @@ -26,7 +26,7 @@ interface IProps extends Omit, "onKeyDown"> {} // https://www.w3.org/TR/wai-aria-practices-1.1/#toolbar // All buttons passed in children must use RovingTabIndex to set `onFocus`, `isActive`, `ref` const Toolbar: React.FC = ({ children, ...props }) => { - const onKeyDown = (ev: React.KeyboardEvent) => { + const onKeyDown = (ev: React.KeyboardEvent): void => { const target = ev.target as HTMLElement; // Don't interfere with input default keydown behaviour if (target.tagName === "INPUT") return; diff --git a/src/accessibility/context_menu/StyledMenuItemCheckbox.tsx b/src/accessibility/context_menu/StyledMenuItemCheckbox.tsx index 867d3aeaab..ee3a0e4d36 100644 --- a/src/accessibility/context_menu/StyledMenuItemCheckbox.tsx +++ b/src/accessibility/context_menu/StyledMenuItemCheckbox.tsx @@ -33,7 +33,7 @@ interface IProps extends React.ComponentProps { export const StyledMenuItemCheckbox: React.FC = ({ children, label, onChange, onClose, ...props }) => { const [onFocus, isActive, ref] = useRovingTabIndex(); - const onKeyDown = (e: React.KeyboardEvent) => { + const onKeyDown = (e: React.KeyboardEvent): void => { let handled = true; const action = getKeyBindingsManager().getAccessibilityAction(e); @@ -55,7 +55,7 @@ export const StyledMenuItemCheckbox: React.FC = ({ children, label, onCh e.preventDefault(); } }; - const onKeyUp = (e: React.KeyboardEvent) => { + const onKeyUp = (e: React.KeyboardEvent): void => { const action = getKeyBindingsManager().getAccessibilityAction(e); switch (action) { case KeyBindingAction.Space: diff --git a/src/accessibility/context_menu/StyledMenuItemRadio.tsx b/src/accessibility/context_menu/StyledMenuItemRadio.tsx index 6bbf5a1106..2fe8738434 100644 --- a/src/accessibility/context_menu/StyledMenuItemRadio.tsx +++ b/src/accessibility/context_menu/StyledMenuItemRadio.tsx @@ -33,7 +33,7 @@ interface IProps extends React.ComponentProps { export const StyledMenuItemRadio: React.FC = ({ children, label, onChange, onClose, ...props }) => { const [onFocus, isActive, ref] = useRovingTabIndex(); - const onKeyDown = (e: React.KeyboardEvent) => { + const onKeyDown = (e: React.KeyboardEvent): void => { let handled = true; const action = getKeyBindingsManager().getAccessibilityAction(e); @@ -55,7 +55,7 @@ export const StyledMenuItemRadio: React.FC = ({ children, label, onChang e.preventDefault(); } }; - const onKeyUp = (e: React.KeyboardEvent) => { + const onKeyUp = (e: React.KeyboardEvent): void => { const action = getKeyBindingsManager().getAccessibilityAction(e); switch (action) { case KeyBindingAction.Enter: diff --git a/src/actions/actionCreators.ts b/src/actions/actionCreators.ts index 0341f03cac..b6eb263fb9 100644 --- a/src/actions/actionCreators.ts +++ b/src/actions/actionCreators.ts @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { AsyncActionPayload } from "../dispatcher/payloads"; +import { AsyncActionFn, AsyncActionPayload } from "../dispatcher/payloads"; /** * Create an action thunk that will dispatch actions indicating the current @@ -45,7 +45,7 @@ import { AsyncActionPayload } from "../dispatcher/payloads"; * `fn`. */ export function asyncAction(id: string, fn: () => Promise, pendingFn: () => any | null): AsyncActionPayload { - const helper = (dispatch) => { + const helper: AsyncActionFn = (dispatch) => { dispatch({ action: id + ".pending", request: typeof pendingFn === "function" ? pendingFn() : undefined, diff --git a/src/actions/handlers/viewUserDeviceSettings.ts b/src/actions/handlers/viewUserDeviceSettings.ts index e1dc7b3f26..4525ba104d 100644 --- a/src/actions/handlers/viewUserDeviceSettings.ts +++ b/src/actions/handlers/viewUserDeviceSettings.ts @@ -22,7 +22,7 @@ import defaultDispatcher from "../../dispatcher/dispatcher"; * Redirect to the correct device manager section * Based on the labs setting */ -export const viewUserDeviceSettings = (isNewDeviceManagerEnabled: boolean) => { +export const viewUserDeviceSettings = (isNewDeviceManagerEnabled: boolean): void => { defaultDispatcher.dispatch({ action: Action.ViewUserSettings, initialTabId: isNewDeviceManagerEnabled ? UserTab.SessionManager : UserTab.Security, diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx index 98bbb55069..63a132077f 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx @@ -56,7 +56,7 @@ export default class ManageEventIndexDialog extends React.Component { + public updateCurrentRoom = async (room): Promise => { const eventIndex = EventIndexPeg.get(); let stats; @@ -131,17 +131,17 @@ export default class ManageEventIndexDialog extends React.Component { + private onDisable = async (): Promise => { const DisableEventIndexDialog = (await import("./DisableEventIndexDialog")).default; Modal.createDialog(DisableEventIndexDialog, null, null, /* priority = */ false, /* static = */ true); }; - private onCrawlerSleepTimeChange = (e) => { + private onCrawlerSleepTimeChange = (e): void => { this.setState({ crawlerSleepTime: e.target.value }); SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value); }; - public render() { + public render(): JSX.Element { const brand = SdkConfig.get().brand; let crawlerState; diff --git a/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx b/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx index f9df9b09a4..a75b41f602 100644 --- a/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx +++ b/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx @@ -125,7 +125,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent { + await accessSecretStorage(async (): Promise => { info = await MatrixClientPeg.get().prepareKeyBackupVersion(null /* random key */, { secureSecretStorage: true, }); diff --git a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx index 0c976ec599..b595a60a2e 100644 --- a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx +++ b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx @@ -350,7 +350,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent this.recoveryKey, keyBackupInfo: this.state.backupInfo, setupNewKeyBackup: !this.state.backupInfo, - getKeyBackupPassphrase: async () => { + getKeyBackupPassphrase: async (): Promise => { // We may already have the backup key if we earlier went // through the restore backup path, so pass it along // rather than prompting again. @@ -383,7 +383,9 @@ export default class CreateSecretStorageDialog extends React.PureComponent => { // It's possible we'll need the backup key later on for bootstrapping, // so let's stash it here, rather than prompting for it twice. - const keyCallback = (k) => (this.backupKey = k); + const keyCallback = (k: Uint8Array): void => { + this.backupKey = k; + }; const { finished } = Modal.createDialog( RestoreKeyBackupDialog, @@ -420,7 +422,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { + private onPassPhraseNextClick = async (e: React.FormEvent): Promise => { e.preventDefault(); if (!this.passphraseField.current) return; // unmounting @@ -434,7 +436,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { + private onPassPhraseConfirmNextClick = async (e: React.FormEvent): Promise => { e.preventDefault(); if (this.state.passPhrase !== this.state.passPhraseConfirm) return; diff --git a/src/async-components/views/dialogs/security/ExportE2eKeysDialog.tsx b/src/async-components/views/dialogs/security/ExportE2eKeysDialog.tsx index 1998c7c7ed..c8a561e7da 100644 --- a/src/async-components/views/dialogs/security/ExportE2eKeysDialog.tsx +++ b/src/async-components/views/dialogs/security/ExportE2eKeysDialog.tsx @@ -121,7 +121,7 @@ export default class ExportE2eKeysDialog extends React.Component return false; }; - private onPassphraseChange = (ev: React.ChangeEvent, phrase: AnyPassphrase) => { + private onPassphraseChange = (ev: React.ChangeEvent, phrase: AnyPassphrase): void => { this.setState({ [phrase]: ev.target.value, } as Pick); diff --git a/src/async-components/views/dialogs/security/ImportE2eKeysDialog.tsx b/src/async-components/views/dialogs/security/ImportE2eKeysDialog.tsx index b546ffc91a..079271b021 100644 --- a/src/async-components/views/dialogs/security/ImportE2eKeysDialog.tsx +++ b/src/async-components/views/dialogs/security/ImportE2eKeysDialog.tsx @@ -91,7 +91,7 @@ export default class ImportE2eKeysDialog extends React.Component return false; }; - private startImport(file: File, passphrase: string) { + private startImport(file: File, passphrase: string): Promise { this.setState({ errStr: null, phase: Phase.Importing, diff --git a/src/audio/ManagedPlayback.ts b/src/audio/ManagedPlayback.ts index 5db07671f1..c33d032b68 100644 --- a/src/audio/ManagedPlayback.ts +++ b/src/audio/ManagedPlayback.ts @@ -30,7 +30,7 @@ export class ManagedPlayback extends Playback { return super.play(); } - public destroy() { + public destroy(): void { this.manager.destroyPlaybackInstance(this); super.destroy(); } diff --git a/src/audio/Playback.ts b/src/audio/Playback.ts index d5971ad73c..e1ab1a1c59 100644 --- a/src/audio/Playback.ts +++ b/src/audio/Playback.ts @@ -145,7 +145,7 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte return true; // we don't ever care if the event had listeners, so just return "yes" } - public destroy() { + public destroy(): void { // Dev note: It's critical that we call stop() during cleanup to ensure that downstream callers // are aware of the final clock position before the user triggered an unload. // noinspection JSIgnoredPromiseFromCall - not concerned about being called async here @@ -159,7 +159,7 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte } } - public async prepare() { + public async prepare(): Promise { // don't attempt to decode the media again // AudioContext.decodeAudioData detaches the array buffer `this.buf` // meaning it cannot be re-read @@ -190,7 +190,7 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte this.context.decodeAudioData( this.buf, (b) => resolve(b), - async (e) => { + async (e): Promise => { try { // This error handler is largely for Safari as well, which doesn't support Opus/Ogg // very well. @@ -232,12 +232,12 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte this.emit(PlaybackState.Stopped); // signal that we're not decoding anymore } - private onPlaybackEnd = async () => { + private onPlaybackEnd = async (): Promise => { await this.context.suspend(); this.emit(PlaybackState.Stopped); }; - public async play() { + public async play(): Promise { // We can't restart a buffer source, so we need to create a new one if we hit the end if (this.state === PlaybackState.Stopped) { this.disconnectSource(); @@ -256,13 +256,13 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte this.emit(PlaybackState.Playing); } - private disconnectSource() { + private disconnectSource(): void { if (this.element) return; // leave connected, we can (and must) re-use it this.source?.disconnect(); this.source?.removeEventListener("ended", this.onPlaybackEnd); } - private makeNewSourceBuffer() { + private makeNewSourceBuffer(): void { if (this.element && this.source) return; // leave connected, we can (and must) re-use it if (this.element) { @@ -276,22 +276,22 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte this.source.connect(this.context.destination); } - public async pause() { + public async pause(): Promise { await this.context.suspend(); this.emit(PlaybackState.Paused); } - public async stop() { + public async stop(): Promise { await this.onPlaybackEnd(); this.clock.flagStop(); } - public async toggle() { + public async toggle(): Promise { if (this.isPlaying) await this.pause(); else await this.play(); } - public async skipTo(timeSeconds: number) { + public async skipTo(timeSeconds: number): Promise { // Dev note: this function talks a lot about clock desyncs. There is a clock running // independently to the audio context and buffer so that accurate human-perceptible // time can be exposed. The PlaybackClock class has more information, but the short diff --git a/src/audio/PlaybackClock.ts b/src/audio/PlaybackClock.ts index 4f2d8f14aa..1a6d1a2e5d 100644 --- a/src/audio/PlaybackClock.ts +++ b/src/audio/PlaybackClock.ts @@ -89,7 +89,7 @@ export class PlaybackClock implements IDestroyable { return this.observable; } - private checkTime = (force = false) => { + private checkTime = (force = false): void => { const now = this.timeSeconds; // calculated dynamically if (this.lastCheck !== now || force) { this.observable.update([now, this.durationSeconds]); @@ -102,7 +102,7 @@ export class PlaybackClock implements IDestroyable { * The placeholders will be overridden once known. * @param {MatrixEvent} event The event to use for placeholders. */ - public populatePlaceholdersFrom(event: MatrixEvent) { + public populatePlaceholdersFrom(event: MatrixEvent): void { const durationMs = Number(event.getContent()["info"]?.["duration"]); if (Number.isFinite(durationMs)) this.placeholderDuration = durationMs / 1000; } @@ -112,11 +112,11 @@ export class PlaybackClock implements IDestroyable { * This is to ensure the clock isn't skewed into thinking it is ~0.5s into * a clip when the duration is set. */ - public flagLoadTime() { + public flagLoadTime(): void { this.clipStart = this.context.currentTime; } - public flagStart() { + public flagStart(): void { if (this.stopped) { this.clipStart = this.context.currentTime; this.stopped = false; @@ -128,7 +128,7 @@ export class PlaybackClock implements IDestroyable { } } - public flagStop() { + public flagStop(): void { this.stopped = true; // Reset the clock time now so that the update going out will trigger components @@ -136,13 +136,13 @@ export class PlaybackClock implements IDestroyable { this.clipStart = this.context.currentTime; } - public syncTo(contextTime: number, clipTime: number) { + public syncTo(contextTime: number, clipTime: number): void { this.clipStart = contextTime - clipTime; this.stopped = false; // count as a mid-stream pause (if we were stopped) this.checkTime(true); } - public destroy() { + public destroy(): void { this.observable.close(); if (this.timerId) clearInterval(this.timerId); } diff --git a/src/audio/PlaybackManager.ts b/src/audio/PlaybackManager.ts index 01a597d58f..0cc52e7f0e 100644 --- a/src/audio/PlaybackManager.ts +++ b/src/audio/PlaybackManager.ts @@ -38,13 +38,13 @@ export class PlaybackManager { * instances are paused. * @param playback Optional. The playback to leave untouched. */ - public pauseAllExcept(playback?: Playback) { + public pauseAllExcept(playback?: Playback): void { this.instances .filter((p) => p !== playback && p.currentState === PlaybackState.Playing) .forEach((p) => p.pause()); } - public destroyPlaybackInstance(playback: ManagedPlayback) { + public destroyPlaybackInstance(playback: ManagedPlayback): void { this.instances = this.instances.filter((p) => p !== playback); } diff --git a/src/audio/PlaybackQueue.ts b/src/audio/PlaybackQueue.ts index 1ea8a85fa6..7c521b9ca6 100644 --- a/src/audio/PlaybackQueue.ts +++ b/src/audio/PlaybackQueue.ts @@ -75,28 +75,28 @@ export class PlaybackQueue { return queue; } - private persistClocks() { + private persistClocks(): void { localStorage.setItem( `mx_voice_message_clocks_${this.room.roomId}`, JSON.stringify(Array.from(this.clockStates.entries())), ); } - private loadClocks() { + private loadClocks(): void { const val = localStorage.getItem(`mx_voice_message_clocks_${this.room.roomId}`); if (!!val) { this.clockStates = new Map(JSON.parse(val)); } } - public unsortedEnqueue(mxEvent: MatrixEvent, playback: Playback) { + public unsortedEnqueue(mxEvent: MatrixEvent, playback: Playback): void { // We don't ever detach our listeners: we expect the Playback to clean up for us this.playbacks.set(mxEvent.getId(), playback); playback.on(UPDATE_EVENT, (state) => this.onPlaybackStateChange(playback, mxEvent, state)); playback.clockInfo.liveData.onUpdate((clock) => this.onPlaybackClock(playback, mxEvent, clock)); } - private onPlaybackStateChange(playback: Playback, mxEvent: MatrixEvent, newState: PlaybackState) { + private onPlaybackStateChange(playback: Playback, mxEvent: MatrixEvent, newState: PlaybackState): void { // Remember where the user got to in playback const wasLastPlaying = this.currentPlaybackId === mxEvent.getId(); if (newState === PlaybackState.Stopped && this.clockStates.has(mxEvent.getId()) && !wasLastPlaying) { @@ -210,7 +210,7 @@ export class PlaybackQueue { } } - private onPlaybackClock(playback: Playback, mxEvent: MatrixEvent, clocks: number[]) { + private onPlaybackClock(playback: Playback, mxEvent: MatrixEvent, clocks: number[]): void { if (playback.currentState === PlaybackState.Decoding) return; // ignore pre-ready values if (playback.currentState !== PlaybackState.Stopped) { diff --git a/src/audio/RecorderWorklet.ts b/src/audio/RecorderWorklet.ts index 5079ec58a9..0c0cc56cd6 100644 --- a/src/audio/RecorderWorklet.ts +++ b/src/audio/RecorderWorklet.ts @@ -43,7 +43,7 @@ class MxVoiceWorklet extends AudioWorkletProcessor { private nextAmplitudeSecond = 0; private amplitudeIndex = 0; - public process(inputs, outputs, parameters) { + public process(inputs, outputs, parameters): boolean { const currentSecond = roundTimeToTargetFreq(currentTime); // We special case the first ping because there's a fairly good chance that we'll miss the zeroth // update. Firefox for instance takes 0.06 seconds (roughly) to call this function for the first diff --git a/src/audio/VoiceMessageRecording.ts b/src/audio/VoiceMessageRecording.ts index f27fc36135..7d5c491261 100644 --- a/src/audio/VoiceMessageRecording.ts +++ b/src/audio/VoiceMessageRecording.ts @@ -141,7 +141,7 @@ export class VoiceMessageRecording implements IDestroyable { this.voiceRecording.destroy(); } - private onDataAvailable = (data: ArrayBuffer) => { + private onDataAvailable = (data: ArrayBuffer): void => { const buf = new Uint8Array(data); this.buffer = concat(this.buffer, buf); }; @@ -153,6 +153,6 @@ export class VoiceMessageRecording implements IDestroyable { } } -export const createVoiceMessageRecording = (matrixClient: MatrixClient) => { +export const createVoiceMessageRecording = (matrixClient: MatrixClient): VoiceMessageRecording => { return new VoiceMessageRecording(matrixClient, new VoiceRecording()); }; diff --git a/src/audio/VoiceRecording.ts b/src/audio/VoiceRecording.ts index 20434d998d..32fcb5a97a 100644 --- a/src/audio/VoiceRecording.ts +++ b/src/audio/VoiceRecording.ts @@ -110,7 +110,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable { return !MediaDeviceHandler.getAudioNoiseSuppression(); } - private async makeRecorder() { + private async makeRecorder(): Promise { try { this.recorderStream = await navigator.mediaDevices.getUserMedia({ audio: { @@ -212,14 +212,14 @@ export class VoiceRecording extends EventEmitter implements IDestroyable { return !!Recorder.isRecordingSupported(); } - private onAudioProcess = (ev: AudioProcessingEvent) => { + private onAudioProcess = (ev: AudioProcessingEvent): void => { this.processAudioUpdate(ev.playbackTime); // We skip the functionality of the worklet regarding waveform calculations: we // should get that information pretty quick during the playback info. }; - private processAudioUpdate = (timeSeconds: number) => { + private processAudioUpdate = (timeSeconds: number): void => { if (!this.recording) return; this.observable.update({ @@ -260,7 +260,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable { /** * {@link https://github.com/chris-rudmin/opus-recorder#instance-fields ref for recorderSeconds} */ - public get recorderSeconds() { + public get recorderSeconds(): number { return this.recorder.encodedSamplePosition / 48000; } @@ -279,7 +279,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable { } public async stop(): Promise { - return Singleflight.for(this, "stop").do(async () => { + return Singleflight.for(this, "stop").do(async (): Promise => { if (!this.recording) { throw new Error("No recording to stop"); } @@ -307,7 +307,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable { }); } - public destroy() { + public destroy(): void { // noinspection JSIgnoredPromiseFromCall - not concerned about stop() being called async here this.stop(); this.removeAllListeners(); diff --git a/src/autocomplete/AutocompleteProvider.tsx b/src/autocomplete/AutocompleteProvider.tsx index e76c4f1903..546e052f58 100644 --- a/src/autocomplete/AutocompleteProvider.tsx +++ b/src/autocomplete/AutocompleteProvider.tsx @@ -22,7 +22,7 @@ import { TimelineRenderingType } from "../contexts/RoomContext"; import type { ICompletion, ISelectionRange } from "./Autocompleter"; export interface ICommand { - command: string | null; + command: RegExpExecArray | null; range: { start: number; end: number; @@ -59,7 +59,7 @@ export default abstract class AutocompleteProvider { } } - public destroy() { + public destroy(): void { // stub } @@ -70,7 +70,7 @@ export default abstract class AutocompleteProvider { * @param {boolean} force True if the user is forcing completion * @return {object} { command, range } where both objects fields are null if no match */ - public getCurrentCommand(query: string, selection: ISelectionRange, force = false) { + public getCurrentCommand(query: string, selection: ISelectionRange, force = false): ICommand { let commandRegex = this.commandRegex; if (force && this.shouldForceComplete()) { @@ -83,7 +83,7 @@ export default abstract class AutocompleteProvider { commandRegex.lastIndex = 0; - let match; + let match: RegExpExecArray; while ((match = commandRegex.exec(query)) !== null) { const start = match.index; const end = start + match[0].length; diff --git a/src/autocomplete/Autocompleter.ts b/src/autocomplete/Autocompleter.ts index 67a40db158..b609f265f1 100644 --- a/src/autocomplete/Autocompleter.ts +++ b/src/autocomplete/Autocompleter.ts @@ -69,7 +69,7 @@ export default class Autocompleter { }); } - public destroy() { + public destroy(): void { this.providers.forEach((p) => { p.destroy(); }); @@ -88,7 +88,7 @@ export default class Autocompleter { */ // list of results from each provider, each being a list of completions or null if it times out const completionsList: ICompletion[][] = await Promise.all( - this.providers.map(async (provider) => { + this.providers.map(async (provider): Promise => { return timeout( provider.getCompletions(query, selection, force, limit), null, diff --git a/src/autocomplete/CommandProvider.tsx b/src/autocomplete/CommandProvider.tsx index 68850a9a15..caafe98f08 100644 --- a/src/autocomplete/CommandProvider.tsx +++ b/src/autocomplete/CommandProvider.tsx @@ -100,7 +100,7 @@ export default class CommandProvider extends AutocompleteProvider { }); } - public getName() { + public getName(): string { return "*️⃣ " + _t("Commands"); } diff --git a/src/autocomplete/EmojiProvider.tsx b/src/autocomplete/EmojiProvider.tsx index 821edb4a3e..cc25068db8 100644 --- a/src/autocomplete/EmojiProvider.tsx +++ b/src/autocomplete/EmojiProvider.tsx @@ -55,7 +55,7 @@ const SORTED_EMOJI: ISortedEmoji[] = EMOJI.sort((a, b) => { _orderBy: index, })); -function score(query, space) { +function score(query: string, space: string): number { const index = space.indexOf(query); if (index === -1) { return Infinity; @@ -154,7 +154,7 @@ export default class EmojiProvider extends AutocompleteProvider { return []; } - public getName() { + public getName(): string { return "😃 " + _t("Emoji"); } diff --git a/src/autocomplete/NotifProvider.tsx b/src/autocomplete/NotifProvider.tsx index 28f01c178a..5efe0e86f6 100644 --- a/src/autocomplete/NotifProvider.tsx +++ b/src/autocomplete/NotifProvider.tsx @@ -65,7 +65,7 @@ export default class NotifProvider extends AutocompleteProvider { return []; } - public getName() { + public getName(): string { return "❗️ " + _t("Room Notification"); } diff --git a/src/autocomplete/QueryMatcher.ts b/src/autocomplete/QueryMatcher.ts index 23545075bc..1f7b5a5a7f 100644 --- a/src/autocomplete/QueryMatcher.ts +++ b/src/autocomplete/QueryMatcher.ts @@ -61,7 +61,7 @@ export default class QueryMatcher { } } - public setObjects(objects: T[]) { + public setObjects(objects: T[]): void { this._items = new Map(); for (const object of objects) { diff --git a/src/autocomplete/RoomProvider.tsx b/src/autocomplete/RoomProvider.tsx index a225676898..bf102d55bc 100644 --- a/src/autocomplete/RoomProvider.tsx +++ b/src/autocomplete/RoomProvider.tsx @@ -37,7 +37,15 @@ function canonicalScore(displayedAlias: string, room: Room): number { return displayedAlias === room.getCanonicalAlias() ? 0 : 1; } -function matcherObject(room: Room, displayedAlias: string, matchName = "") { +function matcherObject( + room: Room, + displayedAlias: string, + matchName = "", +): { + room: Room; + matchName: string; + displayedAlias: string; +} { return { room, matchName, @@ -46,7 +54,7 @@ function matcherObject(room: Room, displayedAlias: string, matchName = "") { } export default class RoomProvider extends AutocompleteProvider { - protected matcher: QueryMatcher; + protected matcher: QueryMatcher>; public constructor(room: Room, renderingType?: TimelineRenderingType) { super({ commandRegex: ROOM_REGEX, renderingType }); @@ -55,7 +63,7 @@ export default class RoomProvider extends AutocompleteProvider { }); } - protected getRooms() { + protected getRooms(): Room[] { const cli = MatrixClientPeg.get(); // filter out spaces here as they get their own autocomplete provider @@ -68,7 +76,6 @@ export default class RoomProvider extends AutocompleteProvider { force = false, limit = -1, ): Promise { - let completions = []; const { command, range } = this.getCurrentCommand(query, selection, force); if (command) { // the only reason we need to do this is because Fuse only matches on properties @@ -96,15 +103,15 @@ export default class RoomProvider extends AutocompleteProvider { this.matcher.setObjects(matcherObjects); const matchedString = command[0]; - completions = this.matcher.match(matchedString, limit); + let completions = this.matcher.match(matchedString, limit); completions = sortBy(completions, [ (c) => canonicalScore(c.displayedAlias, c.room), (c) => c.displayedAlias.length, ]); completions = uniqBy(completions, (match) => match.room); - completions = completions - .map((room) => { - return { + return completions + .map( + (room): ICompletion => ({ completion: room.displayedAlias, completionId: room.room.roomId, type: "room", @@ -116,14 +123,14 @@ export default class RoomProvider extends AutocompleteProvider { ), range, - }; - }) + }), + ) .filter((completion) => !!completion.completion && completion.completion.length > 0); } - return completions; + return []; } - public getName() { + public getName(): string { return _t("Rooms"); } diff --git a/src/autocomplete/SpaceProvider.tsx b/src/autocomplete/SpaceProvider.tsx index 14f9e2c375..bef3b57354 100644 --- a/src/autocomplete/SpaceProvider.tsx +++ b/src/autocomplete/SpaceProvider.tsx @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { Room } from "matrix-js-sdk/src/models/room"; import React from "react"; import { _t } from "../languageHandler"; @@ -21,13 +22,13 @@ import { MatrixClientPeg } from "../MatrixClientPeg"; import RoomProvider from "./RoomProvider"; export default class SpaceProvider extends RoomProvider { - protected getRooms() { + protected getRooms(): Room[] { return MatrixClientPeg.get() .getVisibleRooms() .filter((r) => r.isSpaceRoom()); } - public getName() { + public getName(): string { return _t("Spaces"); } diff --git a/src/autocomplete/UserProvider.tsx b/src/autocomplete/UserProvider.tsx index 551a7bc141..65de4b1bb4 100644 --- a/src/autocomplete/UserProvider.tsx +++ b/src/autocomplete/UserProvider.tsx @@ -64,7 +64,7 @@ export default class UserProvider extends AutocompleteProvider { MatrixClientPeg.get().on(RoomStateEvent.Update, this.onRoomStateUpdate); } - public destroy() { + public destroy(): void { if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener(RoomEvent.Timeline, this.onRoomTimeline); MatrixClientPeg.get().removeListener(RoomStateEvent.Update, this.onRoomStateUpdate); @@ -77,7 +77,7 @@ export default class UserProvider extends AutocompleteProvider { toStartOfTimeline: boolean, removed: boolean, data: IRoomTimelineData, - ) => { + ): void => { if (!room) return; // notification timeline, we'll get this event again with a room specific timeline if (removed) return; if (room.roomId !== this.room.roomId) return; @@ -93,7 +93,7 @@ export default class UserProvider extends AutocompleteProvider { this.onUserSpoke(ev.sender); }; - private onRoomStateUpdate = (state: RoomState) => { + private onRoomStateUpdate = (state: RoomState): void => { // ignore updates in other rooms if (state.roomId !== this.room.roomId) return; @@ -150,7 +150,7 @@ export default class UserProvider extends AutocompleteProvider { return _t("Users"); } - private makeUsers() { + private makeUsers(): void { const events = this.room.getLiveTimeline().getEvents(); const lastSpoken = {}; @@ -167,7 +167,7 @@ export default class UserProvider extends AutocompleteProvider { this.matcher.setObjects(this.users); } - public onUserSpoke(user: RoomMember) { + public onUserSpoke(user: RoomMember): void { if (!this.users) return; if (!user) return; if (user.userId === MatrixClientPeg.get().credentials.userId) return; diff --git a/src/components/structures/AutoHideScrollbar.tsx b/src/components/structures/AutoHideScrollbar.tsx index 719be59f6c..90fda3fe21 100644 --- a/src/components/structures/AutoHideScrollbar.tsx +++ b/src/components/structures/AutoHideScrollbar.tsx @@ -22,7 +22,7 @@ type DynamicHtmlElementProps = JSX.IntrinsicElements[T] extends HTMLAttributes<{}> ? DynamicElementProps : DynamicElementProps<"div">; type DynamicElementProps = Partial>; -export type IProps = DynamicHtmlElementProps & { +export type IProps = Omit, "onScroll"> & { element?: T; className?: string; onScroll?: (event: Event) => void; @@ -39,7 +39,7 @@ export default class AutoHideScrollbar ex public readonly containerRef: React.RefObject = React.createRef(); - public componentDidMount() { + public componentDidMount(): void { if (this.containerRef.current && this.props.onScroll) { // Using the passive option to not block the main thread // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners @@ -49,13 +49,13 @@ export default class AutoHideScrollbar ex this.props.wrappedRef?.(this.containerRef.current); } - public componentWillUnmount() { + public componentWillUnmount(): void { if (this.containerRef.current && this.props.onScroll) { this.containerRef.current.removeEventListener("scroll", this.props.onScroll); } } - public render() { + public render(): JSX.Element { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { element, className, onScroll, tabIndex, wrappedRef, children, ...otherProps } = this.props; diff --git a/src/components/structures/AutocompleteInput.tsx b/src/components/structures/AutocompleteInput.tsx index 2d09a247c6..9f16211022 100644 --- a/src/components/structures/AutocompleteInput.tsx +++ b/src/components/structures/AutocompleteInput.tsx @@ -52,11 +52,11 @@ export const AutocompleteInput: React.FC = ({ const editorContainerRef = useRef(null); const editorRef = useRef(null); - const focusEditor = () => { + const focusEditor = (): void => { editorRef?.current?.focus(); }; - const onQueryChange = async (e: ChangeEvent) => { + const onQueryChange = async (e: ChangeEvent): Promise => { const value = e.target.value.trim(); setQuery(value); @@ -74,11 +74,11 @@ export const AutocompleteInput: React.FC = ({ setSuggestions(matches); }; - const onClickInputArea = () => { + const onClickInputArea = (): void => { focusEditor(); }; - const onKeyDown = (e: KeyboardEvent) => { + const onKeyDown = (e: KeyboardEvent): void => { const hasModifiers = e.ctrlKey || e.shiftKey || e.metaKey; // when the field is empty and the user hits backspace remove the right-most target @@ -87,7 +87,7 @@ export const AutocompleteInput: React.FC = ({ } }; - const toggleSelection = (completion: ICompletion) => { + const toggleSelection = (completion: ICompletion): void => { const newSelection = [...selection]; const index = selection.findIndex((selection) => selection.completionId === completion.completionId); @@ -101,7 +101,7 @@ export const AutocompleteInput: React.FC = ({ focusEditor(); }; - const removeSelection = (completion: ICompletion) => { + const removeSelection = (completion: ICompletion): void => { const newSelection = [...selection]; const index = selection.findIndex((selection) => selection.completionId === completion.completionId); diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx index 6dbdc4a7eb..978dd07be9 100644 --- a/src/components/structures/ContextMenu.tsx +++ b/src/components/structures/ContextMenu.tsx @@ -64,7 +64,7 @@ export enum ChevronFace { None = "none", } -export interface IProps extends IPosition { +export interface MenuProps extends IPosition { menuWidth?: number; menuHeight?: number; @@ -77,7 +77,9 @@ export interface IProps extends IPosition { menuPaddingRight?: number; zIndex?: number; +} +export interface IProps extends MenuProps { // If true, insert an invisible screen-sized element behind the menu that when clicked will close it. hasBackground?: boolean; // whether this context menu should be focus managed. If false it must handle itself @@ -128,21 +130,21 @@ export default class ContextMenu extends React.PureComponent { this.initialFocus = document.activeElement as HTMLElement; } - public componentDidMount() { + public componentDidMount(): void { Modal.on(ModalManagerEvent.Opened, this.onModalOpen); } - public componentWillUnmount() { + public componentWillUnmount(): void { Modal.off(ModalManagerEvent.Opened, this.onModalOpen); // return focus to the thing which had it before us this.initialFocus.focus(); } - private onModalOpen = () => { + private onModalOpen = (): void => { this.props.onFinished?.(); }; - private collectContextMenuRect = (element: HTMLDivElement) => { + private collectContextMenuRect = (element: HTMLDivElement): void => { // We don't need to clean up when unmounting, so ignore if (!element) return; @@ -159,7 +161,7 @@ export default class ContextMenu extends React.PureComponent { }); }; - private onContextMenu = (e) => { + private onContextMenu = (e: React.MouseEvent): void => { if (this.props.onFinished) { this.props.onFinished(); @@ -184,20 +186,20 @@ export default class ContextMenu extends React.PureComponent { } }; - private onContextMenuPreventBubbling = (e) => { + private onContextMenuPreventBubbling = (e: React.MouseEvent): void => { // stop propagation so that any context menu handlers don't leak out of this context menu // but do not inhibit the default browser menu e.stopPropagation(); }; // Prevent clicks on the background from going through to the component which opened the menu. - private onFinished = (ev: React.MouseEvent) => { + private onFinished = (ev: React.MouseEvent): void => { ev.stopPropagation(); ev.preventDefault(); this.props.onFinished?.(); }; - private onClick = (ev: React.MouseEvent) => { + private onClick = (ev: React.MouseEvent): void => { // Don't allow clicks to escape the context menu wrapper ev.stopPropagation(); @@ -208,7 +210,7 @@ export default class ContextMenu extends React.PureComponent { // We now only handle closing the ContextMenu in this keyDown handler. // All of the item/option navigation is delegated to RovingTabIndex. - private onKeyDown = (ev: React.KeyboardEvent) => { + private onKeyDown = (ev: React.KeyboardEvent): void => { ev.stopPropagation(); // prevent keyboard propagating out of the context menu, we're focus-locked const action = getKeyBindingsManager().getAccessibilityAction(ev); @@ -243,7 +245,7 @@ export default class ContextMenu extends React.PureComponent { } }; - protected renderMenu(hasBackground = this.props.hasBackground) { + protected renderMenu(hasBackground = this.props.hasBackground): JSX.Element { const position: Partial> = {}; const { top, @@ -501,17 +503,13 @@ export const toLeftOrRightOf = (elementRect: DOMRect, chevronOffset = 12): ToRig return toRightOf(elementRect, chevronOffset); }; -export type AboveLeftOf = IPosition & { - chevronFace: ChevronFace; -}; - // Placement method for to position context menu right-aligned and flowing to the left of elementRect, // and either above or below: wherever there is more space (maybe this should be aboveOrBelowLeftOf?) export const aboveLeftOf = ( elementRect: Pick, chevronFace = ChevronFace.None, vPadding = 0, -): AboveLeftOf => { +): MenuProps => { const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace }; const buttonRight = elementRect.right + window.scrollX; @@ -535,7 +533,7 @@ export const aboveRightOf = ( elementRect: Pick, chevronFace = ChevronFace.None, vPadding = 0, -): AboveLeftOf => { +): MenuProps => { const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace }; const buttonLeft = elementRect.left + window.scrollX; @@ -555,11 +553,11 @@ export const aboveRightOf = ( // Placement method for to position context menu right-aligned and flowing to the left of elementRect // and always above elementRect -export const alwaysAboveLeftOf = ( +export const alwaysMenuProps = ( elementRect: Pick, chevronFace = ChevronFace.None, vPadding = 0, -) => { +): IPosition & { chevronFace: ChevronFace } => { const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace }; const buttonRight = elementRect.right + window.scrollX; @@ -578,7 +576,7 @@ export const alwaysAboveRightOf = ( elementRect: Pick, chevronFace = ChevronFace.None, vPadding = 0, -) => { +): IPosition & { chevronFace: ChevronFace } => { const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace }; const buttonLeft = elementRect.left + window.scrollX; @@ -607,12 +605,12 @@ export const useContextMenu = (inputRef?: RefObject } const [isOpen, setIsOpen] = useState(false); - const open = (ev?: SyntheticEvent) => { + const open = (ev?: SyntheticEvent): void => { ev?.preventDefault(); ev?.stopPropagation(); setIsOpen(true); }; - const close = (ev?: SyntheticEvent) => { + const close = (ev?: SyntheticEvent): void => { ev?.preventDefault(); ev?.stopPropagation(); setIsOpen(false); @@ -622,8 +620,11 @@ export const useContextMenu = (inputRef?: RefObject }; // XXX: Deprecated, used only for dynamic Tooltips. Avoid using at all costs. -export function createMenu(ElementClass, props) { - const onFinished = function (...args) { +export function createMenu( + ElementClass: typeof React.Component, + props: Record, +): { close: (...args: any[]) => void } { + const onFinished = function (...args): void { ReactDOM.unmountComponentAtNode(getOrCreateContainer()); props?.onFinished?.apply(null, args); }; diff --git a/src/components/structures/EmbeddedPage.tsx b/src/components/structures/EmbeddedPage.tsx index d531e4fcc4..e3cacf0114 100644 --- a/src/components/structures/EmbeddedPage.tsx +++ b/src/components/structures/EmbeddedPage.tsx @@ -60,7 +60,7 @@ export default class EmbeddedPage extends React.PureComponent { return sanitizeHtml(_t(s)); } - private async fetchEmbed() { + private async fetchEmbed(): Promise { let res: Response; try { diff --git a/src/components/structures/FileDropTarget.tsx b/src/components/structures/FileDropTarget.tsx index ce24bb3783..e8a8fa5e28 100644 --- a/src/components/structures/FileDropTarget.tsx +++ b/src/components/structures/FileDropTarget.tsx @@ -37,7 +37,7 @@ const FileDropTarget: React.FC = ({ parent, onFileDrop }) => { useEffect(() => { if (!parent || parent.ondrop) return; - const onDragEnter = (ev: DragEvent) => { + const onDragEnter = (ev: DragEvent): void => { ev.stopPropagation(); ev.preventDefault(); @@ -55,7 +55,7 @@ const FileDropTarget: React.FC = ({ parent, onFileDrop }) => { })); }; - const onDragLeave = (ev: DragEvent) => { + const onDragLeave = (ev: DragEvent): void => { ev.stopPropagation(); ev.preventDefault(); @@ -65,7 +65,7 @@ const FileDropTarget: React.FC = ({ parent, onFileDrop }) => { })); }; - const onDragOver = (ev: DragEvent) => { + const onDragOver = (ev: DragEvent): void => { ev.stopPropagation(); ev.preventDefault(); @@ -79,7 +79,7 @@ const FileDropTarget: React.FC = ({ parent, onFileDrop }) => { } }; - const onDrop = (ev: DragEvent) => { + const onDrop = (ev: DragEvent): void => { ev.stopPropagation(); ev.preventDefault(); onFileDrop(ev.dataTransfer); diff --git a/src/components/structures/FilePanel.tsx b/src/components/structures/FilePanel.tsx index 6efa4f857a..4390dcf36e 100644 --- a/src/components/structures/FilePanel.tsx +++ b/src/components/structures/FilePanel.tsx @@ -223,7 +223,7 @@ class FilePanel extends React.Component { } } - public render() { + public render(): JSX.Element { if (MatrixClientPeg.get().isGuest()) { return ( diff --git a/src/components/structures/GenericErrorPage.tsx b/src/components/structures/GenericErrorPage.tsx index 4179abe7fd..4261d9b2f4 100644 --- a/src/components/structures/GenericErrorPage.tsx +++ b/src/components/structures/GenericErrorPage.tsx @@ -22,7 +22,7 @@ interface IProps { } export default class GenericErrorPage extends React.PureComponent { - public render() { + public render(): JSX.Element { return (
diff --git a/src/components/structures/HomePage.tsx b/src/components/structures/HomePage.tsx index 54aa635fe7..13fc132516 100644 --- a/src/components/structures/HomePage.tsx +++ b/src/components/structures/HomePage.tsx @@ -33,17 +33,17 @@ import MiniAvatarUploader, { AVATAR_SIZE } from "../views/elements/MiniAvatarUpl import PosthogTrackers from "../../PosthogTrackers"; import EmbeddedPage from "./EmbeddedPage"; -const onClickSendDm = (ev: ButtonEvent) => { +const onClickSendDm = (ev: ButtonEvent): void => { PosthogTrackers.trackInteraction("WebHomeCreateChatButton", ev); dis.dispatch({ action: "view_create_chat" }); }; -const onClickExplore = (ev: ButtonEvent) => { +const onClickExplore = (ev: ButtonEvent): void => { PosthogTrackers.trackInteraction("WebHomeExploreRoomsButton", ev); dis.fire(Action.ViewRoomDirectory); }; -const onClickNewRoom = (ev: ButtonEvent) => { +const onClickNewRoom = (ev: ButtonEvent): void => { PosthogTrackers.trackInteraction("WebHomeCreateRoomButton", ev); dis.dispatch({ action: "view_create_room" }); }; @@ -52,12 +52,17 @@ interface IProps { justRegistered?: boolean; } -const getOwnProfile = (userId: string) => ({ +const getOwnProfile = ( + userId: string, +): { + displayName: string; + avatarUrl: string; +} => ({ displayName: OwnProfileStore.instance.displayName || userId, avatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(AVATAR_SIZE), }); -const UserWelcomeTop = () => { +const UserWelcomeTop: React.FC = () => { const cli = useContext(MatrixClientContext); const userId = cli.getUserId(); const [ownProfile, setOwnProfile] = useState(getOwnProfile(userId)); diff --git a/src/components/structures/HostSignupAction.tsx b/src/components/structures/HostSignupAction.tsx index 7d4652e3ee..757a7360fb 100644 --- a/src/components/structures/HostSignupAction.tsx +++ b/src/components/structures/HostSignupAction.tsx @@ -28,7 +28,7 @@ interface IProps { interface IState {} export default class HostSignupAction extends React.PureComponent { - private openDialog = async () => { + private openDialog = async (): Promise => { this.props.onClick?.(); await HostSignupStore.instance.setHostSignupActive(true); }; diff --git a/src/components/structures/InteractiveAuth.tsx b/src/components/structures/InteractiveAuth.tsx index b5582323bf..99be8705a4 100644 --- a/src/components/structures/InteractiveAuth.tsx +++ b/src/components/structures/InteractiveAuth.tsx @@ -130,7 +130,7 @@ export default class InteractiveAuthComponent extends React.Component { @@ -155,7 +155,7 @@ export default class InteractiveAuthComponent extends React.Component { return SettingsStore.getValue("feature_breadcrumbs_v2") ? BreadcrumbsMode.Labs : BreadcrumbsMode.Legacy; } - public componentDidMount() { + public componentDidMount(): void { UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current); UIStore.instance.on("ListContainer", this.refreshStickyHeaders); // Using the passive option to not block the main thread @@ -97,7 +97,7 @@ export default class LeftPanel extends React.Component { this.listContainerRef.current?.addEventListener("scroll", this.onScroll, { passive: true }); } - public componentWillUnmount() { + public componentWillUnmount(): void { BreadcrumbsStore.instance.off(UPDATE_EVENT, this.onBreadcrumbsUpdate); RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate); SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateActiveSpace); @@ -112,25 +112,25 @@ export default class LeftPanel extends React.Component { } } - private updateActiveSpace = (activeSpace: SpaceKey) => { + private updateActiveSpace = (activeSpace: SpaceKey): void => { this.setState({ activeSpace }); }; - private onDialPad = () => { + private onDialPad = (): void => { dis.fire(Action.OpenDialPad); }; - private onExplore = (ev: ButtonEvent) => { + private onExplore = (ev: ButtonEvent): void => { dis.fire(Action.ViewRoomDirectory); PosthogTrackers.trackInteraction("WebLeftPanelExploreRoomsButton", ev); }; - private refreshStickyHeaders = () => { + private refreshStickyHeaders = (): void => { if (!this.listContainerRef.current) return; // ignore: no headers to sticky this.handleStickyHeaders(this.listContainerRef.current); }; - private onBreadcrumbsUpdate = () => { + private onBreadcrumbsUpdate = (): void => { const newVal = LeftPanel.breadcrumbsMode; if (newVal !== this.state.showBreadcrumbs) { this.setState({ showBreadcrumbs: newVal }); @@ -141,7 +141,7 @@ export default class LeftPanel extends React.Component { } }; - private handleStickyHeaders(list: HTMLDivElement) { + private handleStickyHeaders(list: HTMLDivElement): void { if (this.isDoingStickyHeaders) return; this.isDoingStickyHeaders = true; window.requestAnimationFrame(() => { @@ -150,7 +150,7 @@ export default class LeftPanel extends React.Component { }); } - private doStickyHeaders(list: HTMLDivElement) { + private doStickyHeaders(list: HTMLDivElement): void { const topEdge = list.scrollTop; const bottomEdge = list.offsetHeight + list.scrollTop; const sublists = list.querySelectorAll(".mx_RoomSublist:not(.mx_RoomSublist_hidden)"); @@ -282,20 +282,20 @@ export default class LeftPanel extends React.Component { } } - private onScroll = (ev: Event) => { + private onScroll = (ev: Event): void => { const list = ev.target as HTMLDivElement; this.handleStickyHeaders(list); }; - private onFocus = (ev: React.FocusEvent) => { + private onFocus = (ev: React.FocusEvent): void => { this.focusedElement = ev.target; }; - private onBlur = () => { + private onBlur = (): void => { this.focusedElement = null; }; - private onKeyDown = (ev: React.KeyboardEvent, state?: IRovingTabIndexState) => { + private onKeyDown = (ev: React.KeyboardEvent, state?: IRovingTabIndexState): void => { if (!this.focusedElement) return; const action = getKeyBindingsManager().getRoomListAction(ev); diff --git a/src/components/structures/LegacyCallEventGrouper.ts b/src/components/structures/LegacyCallEventGrouper.ts index 9a4d82a9f8..5365352921 100644 --- a/src/components/structures/LegacyCallEventGrouper.ts +++ b/src/components/structures/LegacyCallEventGrouper.ts @@ -142,7 +142,7 @@ export default class LegacyCallEventGrouper extends EventEmitter { return [...this.events][0]?.getRoomId(); } - private onSilencedCallsChanged = () => { + private onSilencedCallsChanged = (): void => { const newState = LegacyCallHandler.instance.isCallSilenced(this.callId); this.emit(LegacyCallEventGrouperEvent.SilencedChanged, newState); }; @@ -163,20 +163,20 @@ export default class LegacyCallEventGrouper extends EventEmitter { LegacyCallHandler.instance.placeCall(this.roomId, this.isVoice ? CallType.Voice : CallType.Video); }; - public toggleSilenced = () => { + public toggleSilenced = (): void => { const silenced = LegacyCallHandler.instance.isCallSilenced(this.callId); silenced ? LegacyCallHandler.instance.unSilenceCall(this.callId) : LegacyCallHandler.instance.silenceCall(this.callId); }; - private setCallListeners() { + private setCallListeners(): void { if (!this.call) return; this.call.addListener(CallEvent.State, this.setState); this.call.addListener(CallEvent.LengthChanged, this.onLengthChanged); } - private setState = () => { + private setState = (): void => { if (CONNECTING_STATES.includes(this.call?.state)) { this.state = CallState.Connecting; } else if (SUPPORTED_STATES.includes(this.call?.state)) { @@ -190,7 +190,7 @@ export default class LegacyCallEventGrouper extends EventEmitter { this.emit(LegacyCallEventGrouperEvent.StateChanged, this.state); }; - private setCall = () => { + private setCall = (): void => { if (this.call) return; this.call = LegacyCallHandler.instance.getCallById(this.callId); @@ -198,7 +198,7 @@ export default class LegacyCallEventGrouper extends EventEmitter { this.setState(); }; - public add(event: MatrixEvent) { + public add(event: MatrixEvent): void { if (this.events.has(event)) return; // nothing to do this.events.add(event); this.setCall(); diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index 6e18f8a6f7..242bbdc028 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -159,7 +159,7 @@ class LoggedInView extends React.Component { this.resizeHandler = React.createRef(); } - public componentDidMount() { + public componentDidMount(): void { document.addEventListener("keydown", this.onNativeKeyDown, false); LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallState, this.onCallState); @@ -191,7 +191,7 @@ class LoggedInView extends React.Component { this.refreshBackgroundImage(); } - public componentWillUnmount() { + public componentWillUnmount(): void { document.removeEventListener("keydown", this.onNativeKeyDown, false); LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallState, this.onCallState); this._matrixClient.removeListener(ClientEvent.AccountData, this.onAccountData); @@ -221,14 +221,14 @@ class LoggedInView extends React.Component { this.setState({ backgroundImage }); }; - public canResetTimelineInRoom = (roomId: string) => { + public canResetTimelineInRoom = (roomId: string): boolean => { if (!this._roomView.current) { return true; } return this._roomView.current.canResetTimeline(); }; - private createResizer() { + private createResizer(): Resizer { let panelSize; let panelCollapsed; const collapseConfig: ICollapseConfig = { @@ -268,7 +268,7 @@ class LoggedInView extends React.Component { return resizer; } - private loadResizerPreferences() { + private loadResizerPreferences(): void { let lhsSize = parseInt(window.localStorage.getItem("mx_lhs_size"), 10); if (isNaN(lhsSize)) { lhsSize = 350; @@ -276,13 +276,13 @@ class LoggedInView extends React.Component { this.resizer.forHandleWithId("lp-resizer").resize(lhsSize); } - private onAccountData = (event: MatrixEvent) => { + private onAccountData = (event: MatrixEvent): void => { if (event.getType() === "m.ignored_user_list") { dis.dispatch({ action: "ignore_state_changed" }); } }; - private onCompactLayoutChanged = () => { + private onCompactLayoutChanged = (): void => { this.setState({ useCompactLayout: SettingsStore.getValue("useCompactLayout"), }); @@ -311,13 +311,13 @@ class LoggedInView extends React.Component { } }; - private onUsageLimitDismissed = () => { + private onUsageLimitDismissed = (): void => { this.setState({ usageLimitDismissed: true, }); }; - private calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) { + private calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit): void { const error = (syncError?.error as MatrixError)?.errcode === "M_RESOURCE_LIMIT_EXCEEDED"; if (error) { usageLimitEventContent = (syncError?.error as MatrixError).data as IUsageLimit; @@ -337,9 +337,9 @@ class LoggedInView extends React.Component { } } - private updateServerNoticeEvents = async () => { + private updateServerNoticeEvents = async (): Promise => { const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice]; - if (!serverNoticeList) return []; + if (!serverNoticeList) return; const events = []; let pinnedEventTs = 0; @@ -379,7 +379,7 @@ class LoggedInView extends React.Component { }); }; - private onPaste = (ev: ClipboardEvent) => { + private onPaste = (ev: ClipboardEvent): void => { const element = ev.target as HTMLElement; const inputableElement = getInputableElement(element); if (inputableElement === document.activeElement) return; // nothing to do @@ -422,13 +422,13 @@ class LoggedInView extends React.Component { We also listen with a native listener on the document to get keydown events when no element is focused. Bubbling is irrelevant here as the target is the body element. */ - private onReactKeyDown = (ev) => { + private onReactKeyDown = (ev): void => { // events caught while bubbling up on the root element // of this component, so something must be focused. this.onKeyDown(ev); }; - private onNativeKeyDown = (ev) => { + private onNativeKeyDown = (ev): void => { // only pass this if there is no focused element. // if there is, onKeyDown will be called by the // react keydown handler that respects the react bubbling order. @@ -437,7 +437,7 @@ class LoggedInView extends React.Component { } }; - private onKeyDown = (ev) => { + private onKeyDown = (ev): void => { let handled = false; const roomAction = getKeyBindingsManager().getRoomAction(ev); @@ -615,13 +615,13 @@ class LoggedInView extends React.Component { * dispatch a page-up/page-down/etc to the appropriate component * @param {Object} ev The key event */ - private onScrollKeyPressed = (ev) => { + private onScrollKeyPressed = (ev): void => { if (this._roomView.current) { this._roomView.current.handleScrollKey(ev); } }; - public render() { + public render(): JSX.Element { let pageElement; switch (this.props.page_type) { diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 536626f270..df2aa87f2c 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -216,7 +216,7 @@ export default class MatrixChat extends React.PureComponent { realQueryParams: {}, startingFragmentQueryParams: {}, config: {}, - onTokenLoginCompleted: () => {}, + onTokenLoginCompleted: (): void => {}, }; private firstSyncComplete = false; @@ -317,7 +317,7 @@ export default class MatrixChat extends React.PureComponent { this.props.realQueryParams, this.props.defaultDeviceDisplayName, this.getFragmentAfterLogin(), - ).then(async (loggedIn) => { + ).then(async (loggedIn): Promise => { if (this.props.realQueryParams?.loginToken) { // remove the loginToken from the URL regardless this.props.onTokenLoginCompleted(); @@ -353,7 +353,7 @@ export default class MatrixChat extends React.PureComponent { initSentry(SdkConfig.get("sentry")); } - private async postLoginSetup() { + private async postLoginSetup(): Promise { const cli = MatrixClientPeg.get(); const cryptoEnabled = cli.isCryptoEnabled(); if (!cryptoEnabled) { @@ -367,7 +367,7 @@ export default class MatrixChat extends React.PureComponent { // as a proxy to figure out if it's worth prompting the user to verify // from another device. promisesList.push( - (async () => { + (async (): Promise => { crossSigningIsSetUp = await cli.userHasCrossSigningKeys(); })(), ); @@ -417,7 +417,7 @@ export default class MatrixChat extends React.PureComponent { window.addEventListener("resize", this.onWindowResized); } - public componentDidUpdate(prevProps, prevState) { + public componentDidUpdate(prevProps, prevState): void { if (this.shouldTrackPageChange(prevState, this.state)) { const durationMs = this.stopPageChangeTimer(); PosthogTrackers.instance.trackPageChange(this.state.view, this.state.page_type, durationMs); @@ -428,7 +428,7 @@ export default class MatrixChat extends React.PureComponent { } } - public componentWillUnmount() { + public componentWillUnmount(): void { Lifecycle.stopMatrixClient(); dis.unregister(this.dispatcherRef); this.themeWatcher.stop(); @@ -477,7 +477,7 @@ export default class MatrixChat extends React.PureComponent { } } - private getServerProperties() { + private getServerProperties(): { serverConfig: ValidatedServerConfig } { let props = this.state.serverConfig; if (!props) props = this.props.serverConfig; // for unit tests if (!props) props = SdkConfig.get("validated_server_config"); @@ -513,11 +513,11 @@ export default class MatrixChat extends React.PureComponent { // to try logging out. } - private startPageChangeTimer() { + private startPageChangeTimer(): void { PerformanceMonitor.instance.start(PerformanceEntryNames.PAGE_CHANGE); } - private stopPageChangeTimer() { + private stopPageChangeTimer(): number | null { const perfMonitor = PerformanceMonitor.instance; perfMonitor.stop(PerformanceEntryNames.PAGE_CHANGE); @@ -876,13 +876,13 @@ export default class MatrixChat extends React.PureComponent { } }; - private setPage(pageType: PageType) { + private setPage(pageType: PageType): void { this.setState({ page_type: pageType, }); } - private async startRegistration(params: { [key: string]: string }) { + private async startRegistration(params: { [key: string]: string }): Promise { const newState: Partial = { view: Views.REGISTER, }; @@ -916,7 +916,7 @@ export default class MatrixChat extends React.PureComponent { } // switch view to the given room - private async viewRoom(roomInfo: ViewRoomPayload) { + private async viewRoom(roomInfo: ViewRoomPayload): Promise { this.focusComposer = true; if (roomInfo.room_alias) { @@ -992,7 +992,7 @@ export default class MatrixChat extends React.PureComponent { ); } - private viewSomethingBehindModal() { + private viewSomethingBehindModal(): void { if (this.state.view !== Views.LOGGED_IN) { this.viewWelcome(); return; @@ -1002,7 +1002,7 @@ export default class MatrixChat extends React.PureComponent { } } - private viewWelcome() { + private viewWelcome(): void { if (shouldUseLoginForWelcome(SdkConfig.get())) { return this.viewLogin(); } @@ -1014,7 +1014,7 @@ export default class MatrixChat extends React.PureComponent { this.themeWatcher.recheck(); } - private viewLogin(otherState?: any) { + private viewLogin(otherState?: any): void { this.setStateForNewView({ view: Views.LOGIN, ...otherState, @@ -1024,7 +1024,7 @@ export default class MatrixChat extends React.PureComponent { this.themeWatcher.recheck(); } - private viewHome(justRegistered = false) { + private viewHome(justRegistered = false): void { // The home page requires the "logged in" view, so we'll set that. this.setStateForNewView({ view: Views.LOGGED_IN, @@ -1037,7 +1037,7 @@ export default class MatrixChat extends React.PureComponent { this.themeWatcher.recheck(); } - private viewUser(userId: string, subAction: string) { + private viewUser(userId: string, subAction: string): void { // Wait for the first sync so that `getRoom` gives us a room object if it's // in the sync response const waitForSync = this.firstSyncPromise ? this.firstSyncPromise.promise : Promise.resolve(); @@ -1052,7 +1052,7 @@ export default class MatrixChat extends React.PureComponent { }); } - private async createRoom(defaultPublic = false, defaultName?: string, type?: RoomType) { + private async createRoom(defaultPublic = false, defaultName?: string, type?: RoomType): Promise { const modal = Modal.createDialog(CreateRoomDialog, { type, defaultPublic, @@ -1065,7 +1065,7 @@ export default class MatrixChat extends React.PureComponent { } } - private chatCreateOrReuse(userId: string) { + private chatCreateOrReuse(userId: string): void { const snakedConfig = new SnakedObject(this.props.config); // Use a deferred action to reshow the dialog once the user has registered if (MatrixClientPeg.get().isGuest()) { @@ -1115,11 +1115,11 @@ export default class MatrixChat extends React.PureComponent { } } - private leaveRoomWarnings(roomId: string) { + private leaveRoomWarnings(roomId: string): JSX.Element[] { const roomToLeave = MatrixClientPeg.get().getRoom(roomId); const isSpace = roomToLeave?.isSpaceRoom(); // Show a warning if there are additional complications. - const warnings = []; + const warnings: JSX.Element[] = []; const memberCount = roomToLeave.currentState.getJoinedMemberCount(); if (memberCount === 1) { @@ -1153,7 +1153,7 @@ export default class MatrixChat extends React.PureComponent { return warnings; } - private leaveRoom(roomId: string) { + private leaveRoom(roomId: string): void { const roomToLeave = MatrixClientPeg.get().getRoom(roomId); const warnings = this.leaveRoomWarnings(roomId); @@ -1184,7 +1184,7 @@ export default class MatrixChat extends React.PureComponent { }); } - private forgetRoom(roomId: string) { + private forgetRoom(roomId: string): void { const room = MatrixClientPeg.get().getRoom(roomId); MatrixClientPeg.get() .forget(roomId) @@ -1208,7 +1208,7 @@ export default class MatrixChat extends React.PureComponent { }); } - private async copyRoom(roomId: string) { + private async copyRoom(roomId: string): Promise { const roomLink = makeRoomPermalink(roomId); const success = await copyPlaintext(roomLink); if (!success) { @@ -1223,13 +1223,13 @@ export default class MatrixChat extends React.PureComponent { * Starts a chat with the welcome user, if the user doesn't already have one * @returns {string} The room ID of the new room, or null if no room was created */ - private async startWelcomeUserChat() { + private async startWelcomeUserChat(): Promise { // We can end up with multiple tabs post-registration where the user // might then end up with a session and we don't want them all making // a chat with the welcome user: try to de-dupe. // We need to wait for the first sync to complete for this to // work though. - let waitFor; + let waitFor: Promise; if (!this.firstSyncComplete) { waitFor = this.firstSyncPromise.promise; } else { @@ -1254,7 +1254,7 @@ export default class MatrixChat extends React.PureComponent { // run without the update to m.direct, making another welcome // user room (it doesn't wait for new data from the server, just // the saved sync to be loaded). - const saveWelcomeUser = (ev: MatrixEvent) => { + const saveWelcomeUser = (ev: MatrixEvent): void => { if (ev.getType() === EventType.Direct && ev.getContent()[snakedConfig.get("welcome_user_id")]) { MatrixClientPeg.get().store.save(true); MatrixClientPeg.get().removeListener(ClientEvent.AccountData, saveWelcomeUser); @@ -1270,7 +1270,7 @@ export default class MatrixChat extends React.PureComponent { /** * Called when a new logged in session has started */ - private async onLoggedIn() { + private async onLoggedIn(): Promise { ThemeController.isLogin = false; this.themeWatcher.recheck(); StorageManager.tryPersistStorage(); @@ -1301,7 +1301,7 @@ export default class MatrixChat extends React.PureComponent { } } - private async onShowPostLoginScreen(useCase?: UseCase) { + private async onShowPostLoginScreen(useCase?: UseCase): Promise { if (useCase) { PosthogAnalytics.instance.setProperty("ftueUseCaseSelection", useCase); SettingsStore.setValue("FTUE.useCaseSelection", null, SettingLevel.ACCOUNT, useCase); @@ -1370,7 +1370,7 @@ export default class MatrixChat extends React.PureComponent { } } - private initPosthogAnalyticsToast() { + private initPosthogAnalyticsToast(): void { // Show the analytics toast if necessary if (SettingsStore.getValue("pseudonymousAnalyticsOptIn") === null) { showAnalyticsToast(); @@ -1397,7 +1397,7 @@ export default class MatrixChat extends React.PureComponent { ); } - private showScreenAfterLogin() { + private showScreenAfterLogin(): void { // If screenAfterLogin is set, use that, then null it so that a second login will // result in view_home_page, _user_settings or _room_directory if (this.screenAfterLogin && this.screenAfterLogin.screen) { @@ -1415,7 +1415,7 @@ export default class MatrixChat extends React.PureComponent { } } - private viewLastRoom() { + private viewLastRoom(): void { dis.dispatch({ action: Action.ViewRoom, room_id: localStorage.getItem("mx_last_room_id"), @@ -1426,7 +1426,7 @@ export default class MatrixChat extends React.PureComponent { /** * Called when the session is logged out */ - private onLoggedOut() { + private onLoggedOut(): void { this.viewLogin({ ready: false, collapseLhs: false, @@ -1439,7 +1439,7 @@ export default class MatrixChat extends React.PureComponent { /** * Called when the session is softly logged out */ - private onSoftLogout() { + private onSoftLogout(): void { this.notifyNewScreen("soft_logout"); this.setStateForNewView({ view: Views.SOFT_LOGOUT, @@ -1455,7 +1455,7 @@ export default class MatrixChat extends React.PureComponent { * Called just before the matrix client is started * (useful for setting listeners) */ - private onWillStartClient() { + private onWillStartClient(): void { // reset the 'have completed first sync' flag, // since we're about to start the client and therefore about // to do the first sync @@ -1610,7 +1610,7 @@ export default class MatrixChat extends React.PureComponent { break; } }); - cli.on(CryptoEvent.KeyBackupFailed, async (errcode) => { + cli.on(CryptoEvent.KeyBackupFailed, async (errcode): Promise => { let haveNewVersion; let newVersionInfo; // if key backup is still enabled, there must be a new backup in place @@ -1678,7 +1678,7 @@ export default class MatrixChat extends React.PureComponent { * setting up anything that requires the client to be started. * @private */ - private onClientStarted() { + private onClientStarted(): void { const cli = MatrixClientPeg.get(); if (cli.isCryptoEnabled()) { @@ -1700,7 +1700,7 @@ export default class MatrixChat extends React.PureComponent { } } - public showScreen(screen: string, params?: { [key: string]: any }) { + public showScreen(screen: string, params?: { [key: string]: any }): void { const cli = MatrixClientPeg.get(); const isLoggedOutOrGuest = !cli || cli.isGuest(); if (!isLoggedOutOrGuest && AUTH_SCREENS.includes(screen)) { @@ -1861,14 +1861,14 @@ export default class MatrixChat extends React.PureComponent { } } - private notifyNewScreen(screen: string, replaceLast = false) { + private notifyNewScreen(screen: string, replaceLast = false): void { if (this.props.onNewScreen) { this.props.onNewScreen(screen, replaceLast); } this.setPageSubtitle(); } - private onLogoutClick(event: React.MouseEvent) { + private onLogoutClick(event: React.MouseEvent): void { dis.dispatch({ action: "logout", }); @@ -1876,7 +1876,7 @@ export default class MatrixChat extends React.PureComponent { event.preventDefault(); } - private handleResize = () => { + private handleResize = (): void => { const LHS_THRESHOLD = 1000; const width = UIStore.instance.windowWidth; @@ -1892,19 +1892,19 @@ export default class MatrixChat extends React.PureComponent { this.state.resizeNotifier.notifyWindowResized(); }; - private dispatchTimelineResize() { + private dispatchTimelineResize(): void { dis.dispatch({ action: "timeline_resize" }); } - private onRegisterClick = () => { + private onRegisterClick = (): void => { this.showScreen("register"); }; - private onLoginClick = () => { + private onLoginClick = (): void => { this.showScreen("login"); }; - private onForgotPasswordClick = () => { + private onForgotPasswordClick = (): void => { this.showScreen("forgot_password"); }; @@ -1926,7 +1926,7 @@ export default class MatrixChat extends React.PureComponent { }); } - private setPageSubtitle(subtitle = "") { + private setPageSubtitle(subtitle = ""): void { if (this.state.currentRoomId) { const client = MatrixClientPeg.get(); const room = client && client.getRoom(this.state.currentRoomId); @@ -1963,11 +1963,11 @@ export default class MatrixChat extends React.PureComponent { this.setPageSubtitle(); }; - private onServerConfigChange = (serverConfig: ValidatedServerConfig) => { + private onServerConfigChange = (serverConfig: ValidatedServerConfig): void => { this.setState({ serverConfig }); }; - private makeRegistrationUrl = (params: QueryDict) => { + private makeRegistrationUrl = (params: QueryDict): string => { if (this.props.startingFragmentQueryParams.referrer) { params.referrer = this.props.startingFragmentQueryParams.referrer; } @@ -2016,7 +2016,7 @@ export default class MatrixChat extends React.PureComponent { return fragmentAfterLogin; } - public render() { + public render(): JSX.Element { const fragmentAfterLogin = this.getFragmentAfterLogin(); let view = null; @@ -2132,7 +2132,7 @@ export default class MatrixChat extends React.PureComponent { /> ); } else if (this.state.view === Views.USE_CASE_SELECTION) { - view = this.onShowPostLoginScreen(useCase)} />; + view = => this.onShowPostLoginScreen(useCase)} />; } else { logger.error(`Unknown view ${this.state.view}`); } diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index cd3f322369..98e8f79ec7 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -296,19 +296,19 @@ export default class MessagePanel extends React.Component { ); } - public componentDidMount() { + public componentDidMount(): void { this.calculateRoomMembersCount(); this.props.room?.currentState.on(RoomStateEvent.Update, this.calculateRoomMembersCount); this.isMounted = true; } - public componentWillUnmount() { + public componentWillUnmount(): void { this.isMounted = false; this.props.room?.currentState.off(RoomStateEvent.Update, this.calculateRoomMembersCount); SettingsStore.unwatchSetting(this.showTypingNotificationsWatcherRef); } - public componentDidUpdate(prevProps, prevState) { + public componentDidUpdate(prevProps, prevState): void { if (prevProps.layout !== this.props.layout) { this.calculateRoomMembersCount(); } @@ -752,7 +752,7 @@ export default class MessagePanel extends React.Component { const readReceipts = this.readReceiptsByEvent[eventId]; let isLastSuccessful = false; - const isSentState = (s) => !s || s === "sent"; + const isSentState = (s): boolean => !s || s === "sent"; const isSent = isSentState(mxEv.getAssociatedStatus()); const hasNextEvent = nextEvent && this.shouldShowEvent(nextEvent); if (!hasNextEvent && isSent) { @@ -982,7 +982,7 @@ export default class MessagePanel extends React.Component { } } - public render() { + public render(): JSX.Element { let topSpinner; let bottomSpinner; if (this.props.backPaginating) { diff --git a/src/components/structures/NonUrgentToastContainer.tsx b/src/components/structures/NonUrgentToastContainer.tsx index c2926a6448..813522ffcb 100644 --- a/src/components/structures/NonUrgentToastContainer.tsx +++ b/src/components/structures/NonUrgentToastContainer.tsx @@ -37,15 +37,15 @@ export default class NonUrgentToastContainer extends React.PureComponent { + private onUpdateToasts = (): void => { this.setState({ toasts: NonUrgentToastStore.instance.components }); }; - public render() { + public render(): JSX.Element { const toasts = this.state.toasts.map((t, i) => { return (
diff --git a/src/components/structures/NotificationPanel.tsx b/src/components/structures/NotificationPanel.tsx index 9e4365880e..ac351399d4 100644 --- a/src/components/structures/NotificationPanel.tsx +++ b/src/components/structures/NotificationPanel.tsx @@ -55,7 +55,7 @@ export default class NotificationPanel extends React.PureComponent

{_t("You're all caught up")}

diff --git a/src/components/structures/PictureInPictureDragger.tsx b/src/components/structures/PictureInPictureDragger.tsx index 1daea9eb89..19205229c8 100644 --- a/src/components/structures/PictureInPictureDragger.tsx +++ b/src/components/structures/PictureInPictureDragger.tsx @@ -79,7 +79,7 @@ export default class PictureInPictureDragger extends React.Component { this._moving = value; } - public componentDidMount() { + public componentDidMount(): void { document.addEventListener("mousemove", this.onMoving); document.addEventListener("mouseup", this.onEndMoving); UIStore.instance.on(UI_EVENTS.Resize, this.onResize); @@ -87,7 +87,7 @@ export default class PictureInPictureDragger extends React.Component { this.snap(); } - public componentWillUnmount() { + public componentWillUnmount(): void { document.removeEventListener("mousemove", this.onMoving); document.removeEventListener("mouseup", this.onEndMoving); UIStore.instance.off(UI_EVENTS.Resize, this.onResize); @@ -97,7 +97,7 @@ export default class PictureInPictureDragger extends React.Component { if (prevProps.children !== this.props.children) this.snap(true); } - private animationCallback = () => { + private animationCallback = (): void => { if ( !this.moving && Math.abs(this.translationX - this.desiredTranslationX) <= 1 && @@ -119,13 +119,13 @@ export default class PictureInPictureDragger extends React.Component { this.props.onMove?.(); }; - private setStyle = () => { + private setStyle = (): void => { if (!this.callViewWrapper.current) return; // Set the element's style directly, bypassing React for efficiency this.callViewWrapper.current.style.transform = `translateX(${this.translationX}px) translateY(${this.translationY}px)`; }; - private setTranslation(inTranslationX: number, inTranslationY: number) { + private setTranslation(inTranslationX: number, inTranslationY: number): void { const width = this.callViewWrapper.current?.clientWidth || PIP_VIEW_WIDTH; const height = this.callViewWrapper.current?.clientHeight || PIP_VIEW_HEIGHT; @@ -152,7 +152,7 @@ export default class PictureInPictureDragger extends React.Component { this.snap(false); }; - private snap = (animate = false) => { + private snap = (animate = false): void => { const translationX = this.desiredTranslationX; const translationY = this.desiredTranslationY; // We subtract the PiP size from the window size in order to calculate @@ -187,14 +187,14 @@ export default class PictureInPictureDragger extends React.Component { this.scheduledUpdate.mark(); }; - private onStartMoving = (event: React.MouseEvent | MouseEvent) => { + private onStartMoving = (event: React.MouseEvent | MouseEvent): void => { event.preventDefault(); event.stopPropagation(); this.mouseHeld = true; }; - private onMoving = (event: MouseEvent) => { + private onMoving = (event: MouseEvent): void => { if (!this.mouseHeld) return; event.preventDefault(); @@ -210,7 +210,7 @@ export default class PictureInPictureDragger extends React.Component { this.setTranslation(event.pageX - this.initX, event.pageY - this.initY); }; - private onEndMoving = (event: MouseEvent) => { + private onEndMoving = (event: MouseEvent): void => { if (!this.mouseHeld) return; event.preventDefault(); @@ -223,7 +223,7 @@ export default class PictureInPictureDragger extends React.Component { this.snap(true); }; - private onClickCapture = (event: React.MouseEvent) => { + private onClickCapture = (event: React.MouseEvent): void => { // To prevent mouse up events during dragging from being double-counted // as clicks, we cancel clicks before they ever reach the target if (this.moving) { @@ -232,7 +232,7 @@ export default class PictureInPictureDragger extends React.Component { } }; - public render() { + public render(): JSX.Element { const style = { transform: `translateX(${this.translationX}px) translateY(${this.translationY}px)`, }; diff --git a/src/components/structures/PipContainer.tsx b/src/components/structures/PipContainer.tsx index a932c43e7d..416458e6ff 100644 --- a/src/components/structures/PipContainer.tsx +++ b/src/components/structures/PipContainer.tsx @@ -135,7 +135,7 @@ class PipContainerInner extends React.Component { }; } - public componentDidMount() { + public componentDidMount(): void { LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallChangeRoom, this.updateCalls); LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallState, this.updateCalls); SdkContextClass.instance.roomViewStore.addListener(UPDATE_EVENT, this.onRoomViewStoreUpdate); @@ -149,7 +149,7 @@ class PipContainerInner extends React.Component { ActiveWidgetStore.instance.on(ActiveWidgetStoreEvent.Undock, this.onWidgetDockChanges); } - public componentWillUnmount() { + public componentWillUnmount(): void { LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallChangeRoom, this.updateCalls); LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallState, this.updateCalls); const cli = MatrixClientPeg.get(); @@ -164,9 +164,9 @@ class PipContainerInner extends React.Component { ActiveWidgetStore.instance.off(ActiveWidgetStoreEvent.Undock, this.onWidgetDockChanges); } - private onMove = () => this.props.movePersistedElement.current?.(); + private onMove = (): void => this.props.movePersistedElement.current?.(); - private onRoomViewStoreUpdate = () => { + private onRoomViewStoreUpdate = (): void => { const newRoomId = SdkContextClass.instance.roomViewStore.getRoomId(); const oldRoomId = this.state.viewedRoomId; if (newRoomId === oldRoomId) return; @@ -213,7 +213,7 @@ class PipContainerInner extends React.Component { this.updateShowWidgetInPip(); }; - private onCallRemoteHold = () => { + private onCallRemoteHold = (): void => { if (!this.state.viewedRoomId) return; const [primaryCall, secondaryCalls] = getPrimarySecondaryCallsForPip(this.state.viewedRoomId); @@ -238,7 +238,7 @@ class PipContainerInner extends React.Component { public updateShowWidgetInPip( persistentWidgetId = this.state.persistentWidgetId, persistentRoomId = this.state.persistentRoomId, - ) { + ): void { let fromAnotherRoom = false; let notDocked = false; // Sanity check the room - the widget may have been destroyed between render cycles, and @@ -293,7 +293,7 @@ class PipContainerInner extends React.Component { ); } - public render() { + public render(): JSX.Element { const pipMode = true; let pipContent: Array = []; diff --git a/src/components/structures/RightPanel.tsx b/src/components/structures/RightPanel.tsx index 8759160057..3748ee0ec7 100644 --- a/src/components/structures/RightPanel.tsx +++ b/src/components/structures/RightPanel.tsx @@ -101,7 +101,7 @@ export default class RightPanel extends React.Component { }; } - private onRoomStateMember = (ev: MatrixEvent, state: RoomState, member: RoomMember) => { + private onRoomStateMember = (ev: MatrixEvent, state: RoomState, member: RoomMember): void => { if (!this.props.room || member.roomId !== this.props.room.roomId) { return; } @@ -118,11 +118,11 @@ export default class RightPanel extends React.Component { } }; - private onRightPanelStoreUpdate = () => { + private onRightPanelStoreUpdate = (): void => { this.setState({ ...(RightPanel.getDerivedStateFromProps(this.props) as IState) }); }; - private onClose = () => { + private onClose = (): void => { // XXX: There are three different ways of 'closing' this panel depending on what state // things are in... this knows far more than it should do about the state of the rest // of the app and is generally a bit silly. diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx index 6c7ddbe755..a387a2e0d5 100644 --- a/src/components/structures/RoomSearch.tsx +++ b/src/components/structures/RoomSearch.tsx @@ -39,15 +39,15 @@ export default class RoomSearch extends React.PureComponent { this.dispatcherRef = defaultDispatcher.register(this.onAction); } - public componentWillUnmount() { + public componentWillUnmount(): void { defaultDispatcher.unregister(this.dispatcherRef); } - private openSpotlight() { + private openSpotlight(): void { Modal.createDialog(SpotlightDialog, {}, "mx_SpotlightDialog_wrapper", false, true); } - private onAction = (payload: ActionPayload) => { + private onAction = (payload: ActionPayload): void => { if (payload.action === "focus_room_filter") { this.openSpotlight(); } diff --git a/src/components/structures/RoomSearchView.tsx b/src/components/structures/RoomSearchView.tsx index d7a995b5c0..132e2a191b 100644 --- a/src/components/structures/RoomSearchView.tsx +++ b/src/components/structures/RoomSearchView.tsx @@ -37,7 +37,7 @@ import RoomContext from "../../contexts/RoomContext"; import SettingsStore from "../../settings/SettingsStore"; const DEBUG = false; -let debuglog = function (msg: string) {}; +let debuglog = function (msg: string): void {}; /* istanbul ignore next */ if (DEBUG) { @@ -76,7 +76,7 @@ export const RoomSearchView = forwardRef( return searchPromise .then( - async (results) => { + async (results): Promise => { debuglog("search complete"); if (aborted.current) { logger.error("Discarding stale search results"); @@ -209,7 +209,7 @@ export const RoomSearchView = forwardRef( // once dynamic content in the search results load, make the scrollPanel check // the scroll offsets. - const onHeightChanged = () => { + const onHeightChanged = (): void => { const scrollPanel = ref.current; scrollPanel?.checkScroll(); }; diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 7d621afc5d..f370091a8a 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -146,7 +146,7 @@ export default class RoomStatusBar extends React.PureComponent { dis.fire(Action.FocusSendMessageComposer); }; - private onRoomLocalEchoUpdated = (ev: MatrixEvent, room: Room) => { + private onRoomLocalEchoUpdated = (ev: MatrixEvent, room: Room): void => { if (room.roomId !== this.props.room.roomId) return; const messages = getUnsentMessages(this.props.room); this.setState({ diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index eb034fd2b7..8d85b54df7 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -115,7 +115,7 @@ import VoipUserMapper from "../../VoipUserMapper"; import { isCallEvent } from "./LegacyCallEventGrouper"; const DEBUG = false; -let debuglog = function (msg: string) {}; +let debuglog = function (msg: string): void {}; const BROWSER_SUPPORTS_SANDBOX = "sandbox" in document.createElement("iframe"); @@ -248,7 +248,7 @@ function LocalRoomView(props: LocalRoomViewProps): ReactElement { encryptionTile = ; } - const onRetryClicked = () => { + const onRetryClicked = (): void => { room.state = LocalRoomState.NEW; defaultDispatcher.dispatch({ action: "local_room_event", @@ -470,21 +470,21 @@ export class RoomView extends React.Component { ]; } - private onIsResizing = (resizing: boolean) => { + private onIsResizing = (resizing: boolean): void => { this.setState({ resizing }); }; - private onWidgetStoreUpdate = () => { + private onWidgetStoreUpdate = (): void => { if (!this.state.room) return; this.checkWidgets(this.state.room); }; - private onWidgetEchoStoreUpdate = () => { + private onWidgetEchoStoreUpdate = (): void => { if (!this.state.room) return; this.checkWidgets(this.state.room); }; - private onWidgetLayoutChange = () => { + private onWidgetLayoutChange = (): void => { if (!this.state.room) return; dis.dispatch({ action: "appsDrawer", @@ -505,7 +505,7 @@ export class RoomView extends React.Component { }); }; - private getMainSplitContentType = (room: Room) => { + private getMainSplitContentType = (room: Room): MainSplitContentType => { if ( (SettingsStore.getValue("feature_group_calls") && this.context.roomViewStore.isViewingCall()) || isVideoRoom(room) @@ -707,7 +707,7 @@ export class RoomView extends React.Component { } }; - private onActiveCalls = () => { + private onActiveCalls = (): void => { if (this.state.roomId === undefined) return; const activeCall = CallStore.instance.getActiveCall(this.state.roomId); @@ -727,7 +727,7 @@ export class RoomView extends React.Component { this.setState({ activeCall }); }; - private getRoomId = () => { + private getRoomId = (): string => { // According to `onRoomViewStoreUpdate`, `state.roomId` can be null // if we have a room alias we haven't resolved yet. To work around this, // first we'll try the room object if it's there, and then fallback to @@ -736,7 +736,7 @@ export class RoomView extends React.Component { return this.state.room ? this.state.room.roomId : this.state.roomId; }; - private getPermalinkCreatorForRoom(room: Room) { + private getPermalinkCreatorForRoom(room: Room): RoomPermalinkCreator { if (this.permalinkCreators[room.roomId]) return this.permalinkCreators[room.roomId]; this.permalinkCreators[room.roomId] = new RoomPermalinkCreator(room); @@ -750,14 +750,14 @@ export class RoomView extends React.Component { return this.permalinkCreators[room.roomId]; } - private stopAllPermalinkCreators() { + private stopAllPermalinkCreators(): void { if (!this.permalinkCreators) return; for (const roomId of Object.keys(this.permalinkCreators)) { this.permalinkCreators[roomId].stop(); } } - private setupRoom(room: Room, roomId: string, joining: boolean, shouldPeek: boolean) { + private setupRoom(room: Room, roomId: string, joining: boolean, shouldPeek: boolean): void { // if this is an unknown room then we're in one of three states: // - This is a room we can peek into (search engine) (we can /peek) // - This is a room we can publicly join or were invited to. (we can /join) @@ -822,7 +822,7 @@ export class RoomView extends React.Component { } } - private shouldShowApps(room: Room) { + private shouldShowApps(room: Room): boolean { if (!BROWSER_SUPPORTS_SANDBOX || !room) return false; // Check if user has previously chosen to hide the app drawer for this @@ -838,7 +838,7 @@ export class RoomView extends React.Component { return isManuallyShown && widgets.length > 0; } - public componentDidMount() { + public componentDidMount(): void { this.onRoomViewStoreUpdate(true); const call = this.getCallForRoom(); @@ -851,7 +851,7 @@ export class RoomView extends React.Component { window.addEventListener("beforeunload", this.onPageUnload); } - public shouldComponentUpdate(nextProps, nextState) { + public shouldComponentUpdate(nextProps, nextState): boolean { const hasPropsDiff = objectHasDiff(this.props, nextProps); const { upgradeRecommendation, ...state } = this.state; @@ -864,7 +864,7 @@ export class RoomView extends React.Component { return hasPropsDiff || hasStateDiff; } - public componentDidUpdate() { + public componentDidUpdate(): void { // Note: We check the ref here with a flag because componentDidMount, despite // documentation, does not define our messagePanel ref. It looks like our spinner // in render() prevents the ref from being set on first mount, so we try and @@ -877,7 +877,7 @@ export class RoomView extends React.Component { } } - public componentWillUnmount() { + public componentWillUnmount(): void { // set a boolean to say we've been unmounted, which any pending // promises can use to throw away their results. // @@ -947,13 +947,13 @@ export class RoomView extends React.Component { } } - private onRightPanelStoreUpdate = () => { + private onRightPanelStoreUpdate = (): void => { this.setState({ showRightPanel: this.context.rightPanelStore.isOpenForRoom(this.state.roomId), }); }; - private onPageUnload = (event) => { + private onPageUnload = (event): string => { if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) { return (event.returnValue = _t("You seem to be uploading files, are you sure you want to quit?")); } else if (this.getCallForRoom() && this.state.callState !== "ended") { @@ -961,7 +961,7 @@ export class RoomView extends React.Component { } }; - private onReactKeyDown = (ev) => { + private onReactKeyDown = (ev): void => { let handled = false; const action = getKeyBindingsManager().getRoomAction(ev); @@ -1120,12 +1120,12 @@ export class RoomView extends React.Component { } }; - private onLocalRoomEvent(roomId: string) { + private onLocalRoomEvent(roomId: string): void { if (roomId !== this.state.room.roomId) return; createRoomFromLocalRoom(this.context.client, this.state.room as LocalRoom); } - private onRoomTimeline = (ev: MatrixEvent, room: Room | null, toStartOfTimeline: boolean, removed, data) => { + private onRoomTimeline = (ev: MatrixEvent, room: Room | null, toStartOfTimeline: boolean, removed, data): void => { if (this.unmounted) return; // ignore events for other rooms or the notification timeline set @@ -1167,7 +1167,7 @@ export class RoomView extends React.Component { } }; - private onEventDecrypted = (ev: MatrixEvent) => { + private onEventDecrypted = (ev: MatrixEvent): void => { if (!this.state.room || !this.state.matrixClientIsReady) return; // not ready at all if (ev.getRoomId() !== this.state.room.roomId) return; // not for us this.updateVisibleDecryptionFailures(); @@ -1175,7 +1175,7 @@ export class RoomView extends React.Component { this.handleEffects(ev); }; - private handleEffects = (ev: MatrixEvent) => { + private handleEffects = (ev: MatrixEvent): void => { const notifState = this.context.roomNotificationStateStore.getRoomState(this.state.room); if (!notifState.isUnread) return; @@ -1189,19 +1189,19 @@ export class RoomView extends React.Component { }); }; - private onRoomName = (room: Room) => { + private onRoomName = (room: Room): void => { if (this.state.room && room.roomId == this.state.room.roomId) { this.forceUpdate(); } }; - private onKeyBackupStatus = () => { + private onKeyBackupStatus = (): void => { // Key backup status changes affect whether the in-room recovery // reminder is displayed. this.forceUpdate(); }; - public canResetTimeline = () => { + public canResetTimeline = (): boolean => { if (!this.messagePanel) { return true; } @@ -1216,7 +1216,7 @@ export class RoomView extends React.Component { // called when state.room is first initialised (either at initial load, // after a successful peek, or after we join the room). - private onRoomLoaded = (room: Room) => { + private onRoomLoaded = (room: Room): void => { if (this.unmounted) return; // Attach a widget store listener only when we get a room this.context.widgetLayoutStore.on(WidgetLayoutStore.emissionForRoom(room), this.onWidgetLayoutChange); @@ -1251,17 +1251,17 @@ export class RoomView extends React.Component { } }; - private getRoomTombstone(room = this.state.room) { + private getRoomTombstone(room = this.state.room): MatrixEvent | undefined { return room?.currentState.getStateEvents(EventType.RoomTombstone, ""); } - private async calculateRecommendedVersion(room: Room) { + private async calculateRecommendedVersion(room: Room): Promise { const upgradeRecommendation = await room.getRecommendedVersion(); if (this.unmounted) return; this.setState({ upgradeRecommendation }); } - private async loadMembersIfJoined(room: Room) { + private async loadMembersIfJoined(room: Room): Promise { // lazy load members if enabled if (this.context.client.hasLazyLoadMembersEnabled()) { if (room && room.getMyMembership() === "join") { @@ -1280,14 +1280,14 @@ export class RoomView extends React.Component { } } - private calculatePeekRules(room: Room) { + private calculatePeekRules(room: Room): void { const historyVisibility = room.currentState.getStateEvents(EventType.RoomHistoryVisibility, ""); this.setState({ canPeek: historyVisibility?.getContent().history_visibility === HistoryVisibility.WorldReadable, }); } - private updatePreviewUrlVisibility({ roomId }: Room) { + private updatePreviewUrlVisibility({ roomId }: Room): void { // URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit const key = this.context.client.isRoomEncrypted(roomId) ? "urlPreviewsEnabled_e2ee" : "urlPreviewsEnabled"; this.setState({ @@ -1295,7 +1295,7 @@ export class RoomView extends React.Component { }); } - private onRoom = (room: Room) => { + private onRoom = (room: Room): void => { if (!room || room.roomId !== this.state.roomId) { return; } @@ -1318,7 +1318,7 @@ export class RoomView extends React.Component { ); }; - private onDeviceVerificationChanged = (userId: string) => { + private onDeviceVerificationChanged = (userId: string): void => { const room = this.state.room; if (!room?.currentState.getMember(userId)) { return; @@ -1326,7 +1326,7 @@ export class RoomView extends React.Component { this.updateE2EStatus(room); }; - private onUserVerificationChanged = (userId: string) => { + private onUserVerificationChanged = (userId: string): void => { const room = this.state.room; if (!room || !room.currentState.getMember(userId)) { return; @@ -1334,14 +1334,14 @@ export class RoomView extends React.Component { this.updateE2EStatus(room); }; - private onCrossSigningKeysChanged = () => { + private onCrossSigningKeysChanged = (): void => { const room = this.state.room; if (room) { this.updateE2EStatus(room); } }; - private async updateE2EStatus(room: Room) { + private async updateE2EStatus(room: Room): Promise { if (!this.context.client.isRoomEncrypted(room.roomId)) return; // If crypto is not currently enabled, we aren't tracking devices at all, @@ -1357,13 +1357,13 @@ export class RoomView extends React.Component { this.setState({ e2eStatus }); } - private onUrlPreviewsEnabledChange = () => { + private onUrlPreviewsEnabledChange = (): void => { if (this.state.room) { this.updatePreviewUrlVisibility(this.state.room); } }; - private onRoomStateEvents = (ev: MatrixEvent, state: RoomState) => { + private onRoomStateEvents = (ev: MatrixEvent, state: RoomState): void => { // ignore if we don't have a room yet if (!this.state.room || this.state.room.roomId !== state.roomId) return; @@ -1377,7 +1377,7 @@ export class RoomView extends React.Component { } }; - private onRoomStateUpdate = (state: RoomState) => { + private onRoomStateUpdate = (state: RoomState): void => { // ignore members in other rooms if (state.roomId !== this.state.room?.roomId) { return; @@ -1386,7 +1386,7 @@ export class RoomView extends React.Component { this.updateRoomMembers(); }; - private onMyMembership = (room: Room, membership: string, oldMembership: string) => { + private onMyMembership = (room: Room, membership: string, oldMembership: string): void => { if (room.roomId === this.state.roomId) { this.forceUpdate(); this.loadMembersIfJoined(room); @@ -1394,7 +1394,7 @@ export class RoomView extends React.Component { } }; - private updatePermissions(room: Room) { + private updatePermissions(room: Room): void { if (room) { const me = this.context.client.getUserId(); const canReact = @@ -1420,7 +1420,7 @@ export class RoomView extends React.Component { { leading: true, trailing: true }, ); - private checkDesktopNotifications() { + private checkDesktopNotifications(): void { const memberCount = this.state.room.getJoinedMemberCount() + this.state.room.getInvitedMemberCount(); // if they are not alone prompt the user about notifications so they don't miss replies if (memberCount > 1 && Notifier.shouldShowPrompt()) { @@ -1428,7 +1428,7 @@ export class RoomView extends React.Component { } } - private updateDMState() { + private updateDMState(): void { const room = this.state.room; if (room.getMyMembership() != "join") { return; @@ -1439,7 +1439,7 @@ export class RoomView extends React.Component { } } - private onInviteClick = () => { + private onInviteClick = (): void => { // open the room inviter dis.dispatch({ action: "view_invite", @@ -1447,7 +1447,7 @@ export class RoomView extends React.Component { }); }; - private onJoinButtonClicked = () => { + private onJoinButtonClicked = (): void => { // If the user is a ROU, allow them to transition to a PWLU if (this.context.client?.isGuest()) { // Join this room once the user has registered and logged in @@ -1489,7 +1489,7 @@ export class RoomView extends React.Component { { leading: false, trailing: true }, ); - private onMessageListScroll = () => { + private onMessageListScroll = (): void => { if (this.messagePanel.isAtEndOfLiveTimeline()) { this.setState({ numUnreadMessages: 0, @@ -1504,7 +1504,7 @@ export class RoomView extends React.Component { this.updateVisibleDecryptionFailures(); }; - private resetJumpToEvent = (eventId?: string) => { + private resetJumpToEvent = (eventId?: string): void => { if ( this.state.initialEventId && this.state.initialEventScrollIntoView && @@ -1523,7 +1523,7 @@ export class RoomView extends React.Component { } }; - private injectSticker(url: string, info: object, text: string, threadId: string | null) { + private injectSticker(url: string, info: object, text: string, threadId: string | null): void { if (this.context.client.isGuest()) { dis.dispatch({ action: "require_registration" }); return; @@ -1539,7 +1539,7 @@ export class RoomView extends React.Component { }); } - private onSearch = (term: string, scope: SearchScope) => { + private onSearch = (term: string, scope: SearchScope): void => { const roomId = scope === SearchScope.Room ? this.state.room.roomId : undefined; debuglog("sending search request"); const abortController = new AbortController(); @@ -1569,21 +1569,21 @@ export class RoomView extends React.Component { }); }; - private onAppsClick = () => { + private onAppsClick = (): void => { dis.dispatch({ action: "appsDrawer", show: !this.state.showApps, }); }; - private onForgetClick = () => { + private onForgetClick = (): void => { dis.dispatch({ action: "forget_room", room_id: this.state.room.roomId, }); }; - private onRejectButtonClicked = () => { + private onRejectButtonClicked = (): void => { this.setState({ rejecting: true, }); @@ -1611,7 +1611,7 @@ export class RoomView extends React.Component { ); }; - private onRejectAndIgnoreClick = async () => { + private onRejectAndIgnoreClick = async (): Promise => { this.setState({ rejecting: true, }); @@ -1644,7 +1644,7 @@ export class RoomView extends React.Component { } }; - private onRejectThreepidInviteButtonClicked = () => { + private onRejectThreepidInviteButtonClicked = (): void => { // We can reject 3pid invites in the same way that we accept them, // using /leave rather than /join. In the short term though, we // just ignore them. @@ -1652,7 +1652,7 @@ export class RoomView extends React.Component { dis.fire(Action.ViewRoomDirectory); }; - private onSearchClick = () => { + private onSearchClick = (): void => { this.setState({ timelineRenderingType: this.state.timelineRenderingType === TimelineRenderingType.Search @@ -1674,7 +1674,7 @@ export class RoomView extends React.Component { }; // jump down to the bottom of this room, where new events are arriving - private jumpToLiveTimeline = () => { + private jumpToLiveTimeline = (): void => { if (this.state.initialEventId && this.state.isInitialEventHighlighted) { // If we were viewing a highlighted event, firing view_room without // an event will take care of both clearing the URL fragment and @@ -1692,18 +1692,18 @@ export class RoomView extends React.Component { }; // jump up to wherever our read marker is - private jumpToReadMarker = () => { + private jumpToReadMarker = (): void => { this.messagePanel.jumpToReadMarker(); }; // update the read marker to match the read-receipt - private forgetReadMarker = (ev) => { + private forgetReadMarker = (ev): void => { ev.stopPropagation(); this.messagePanel.forgetReadMarker(); }; // decide whether or not the top 'unread messages' bar should be shown - private updateTopUnreadMessagesBar = () => { + private updateTopUnreadMessagesBar = (): void => { if (!this.messagePanel) { return; } @@ -1754,12 +1754,12 @@ export class RoomView extends React.Component { }; } - private onStatusBarVisible = () => { + private onStatusBarVisible = (): void => { if (this.unmounted || this.state.statusBarVisible) return; this.setState({ statusBarVisible: true }); }; - private onStatusBarHidden = () => { + private onStatusBarHidden = (): void => { // This is currently not desired as it is annoying if it keeps expanding and collapsing if (this.unmounted || !this.state.statusBarVisible) return; this.setState({ statusBarVisible: false }); @@ -1770,7 +1770,7 @@ export class RoomView extends React.Component { * * We pass it down to the scroll panel. */ - public handleScrollKey = (ev) => { + public handleScrollKey = (ev): void => { let panel: ScrollPanel | TimelinePanel; if (this.searchResultsPanel.current) { panel = this.searchResultsPanel.current; @@ -1793,24 +1793,24 @@ export class RoomView extends React.Component { // this has to be a proper method rather than an unnamed function, // otherwise react calls it with null on each update. - private gatherTimelinePanelRef = (r) => { + private gatherTimelinePanelRef = (r): void => { this.messagePanel = r; }; - private getOldRoom() { + private getOldRoom(): Room | null { const createEvent = this.state.room.currentState.getStateEvents(EventType.RoomCreate, ""); if (!createEvent || !createEvent.getContent()["predecessor"]) return null; return this.context.client.getRoom(createEvent.getContent()["predecessor"]["room_id"]); } - public getHiddenHighlightCount() { + public getHiddenHighlightCount(): number { const oldRoom = this.getOldRoom(); if (!oldRoom) return 0; return oldRoom.getUnreadNotificationCount(NotificationCountType.Highlight); } - public onHiddenHighlightsClick = () => { + public onHiddenHighlightsClick = (): void => { const oldRoom = this.getOldRoom(); if (!oldRoom) return; dis.dispatch({ @@ -1826,7 +1826,7 @@ export class RoomView extends React.Component { }); } - private onFileDrop = (dataTransfer: DataTransfer) => + private onFileDrop = (dataTransfer: DataTransfer): Promise => ContentMessages.sharedInstance().sendContentListToRoom( Array.from(dataTransfer.files), this.state.room?.roomId ?? this.state.roomId, @@ -1869,7 +1869,7 @@ export class RoomView extends React.Component { ); } - public render() { + public render(): JSX.Element { if (this.state.room instanceof LocalRoom) { if (this.state.room.state === LocalRoomState.CREATING) { return this.renderLocalRoomCreateLoader(); diff --git a/src/components/structures/ScrollPanel.tsx b/src/components/structures/ScrollPanel.tsx index 66676666df..f51cba66a3 100644 --- a/src/components/structures/ScrollPanel.tsx +++ b/src/components/structures/ScrollPanel.tsx @@ -35,7 +35,7 @@ const UNFILL_REQUEST_DEBOUNCE_MS = 200; // much while the content loads. const PAGE_SIZE = 400; -const debuglog = (...args: any[]) => { +const debuglog = (...args: any[]): void => { if (SettingsStore.getValue("debug_scroll_panel")) { logger.log.call(console, "ScrollPanel debuglog:", ...args); } @@ -227,14 +227,14 @@ export default class ScrollPanel extends React.Component { this.props.resizeNotifier?.removeListener("middlePanelResizedNoisy", this.onResize); } - private onScroll = (ev: Event | React.UIEvent): void => { + private onScroll = (ev: Event): void => { // skip scroll events caused by resizing if (this.props.resizeNotifier && this.props.resizeNotifier.isResizing) return; debuglog("onScroll called past resize gate; scroll node top:", this.getScrollNode().scrollTop); this.scrollTimeout.restart(); this.saveScrollState(); this.updatePreventShrinking(); - this.props.onScroll?.(ev as Event); + this.props.onScroll?.(ev); // noinspection JSIgnoredPromiseFromCall this.checkFillState(); }; @@ -587,7 +587,7 @@ export default class ScrollPanel extends React.Component { * Scroll up/down in response to a scroll key * @param {object} ev the keyboard event */ - public handleScrollKey = (ev: KeyboardEvent) => { + public handleScrollKey = (ev: KeyboardEvent): void => { const roomAction = getKeyBindingsManager().getRoomAction(ev); switch (roomAction) { case KeyBindingAction.ScrollUp: @@ -853,7 +853,7 @@ export default class ScrollPanel extends React.Component { return this.divScroll; } - private collectScroll = (divScroll: HTMLDivElement) => { + private collectScroll = (divScroll: HTMLDivElement): void => { this.divScroll = divScroll; }; diff --git a/src/components/structures/SpaceHierarchy.tsx b/src/components/structures/SpaceHierarchy.tsx index 13674347aa..af6f298382 100644 --- a/src/components/structures/SpaceHierarchy.tsx +++ b/src/components/structures/SpaceHierarchy.tsx @@ -114,12 +114,12 @@ const Tile: React.FC = ({ const [onFocus, isActive, ref] = useRovingTabIndex(); const [busy, setBusy] = useState(false); - const onPreviewClick = (ev: ButtonEvent) => { + const onPreviewClick = (ev: ButtonEvent): void => { ev.preventDefault(); ev.stopPropagation(); onViewRoomClick(); }; - const onJoinClick = async (ev: ButtonEvent) => { + const onJoinClick = async (ev: ButtonEvent): Promise => { setBusy(true); ev.preventDefault(); ev.stopPropagation(); @@ -271,7 +271,7 @@ const Tile: React.FC = ({ ); if (showChildren) { - const onChildrenKeyDown = (e) => { + const onChildrenKeyDown = (e): void => { const action = getKeyBindingsManager().getAccessibilityAction(e); switch (action) { case KeyBindingAction.ArrowLeft: @@ -439,7 +439,7 @@ const toLocalRoom = (cli: MatrixClient, room: IHierarchyRoom): IHierarchyRoom => return room; }; -export const HierarchyLevel = ({ +export const HierarchyLevel: React.FC = ({ root, roomSet, hierarchy, @@ -448,7 +448,7 @@ export const HierarchyLevel = ({ onViewRoomClick, onJoinRoomClick, onToggleClick, -}: IHierarchyLevelProps) => { +}) => { const cli = useContext(MatrixClientContext); const space = cli.getRoom(root.room_id); const hasPermissions = space?.currentState.maySendStateEvent(EventType.SpaceChild, cli.getUserId()); @@ -553,7 +553,7 @@ export const useRoomHierarchy = ( }); const loadMore = useCallback( - async (pageSize?: number) => { + async (pageSize?: number): Promise => { if (hierarchy.loading || !hierarchy.canLoadMore || hierarchy.noSupport || error) return; await hierarchy.load(pageSize).catch(setError); setRooms(hierarchy.rooms); @@ -578,8 +578,8 @@ export const useRoomHierarchy = ( }; }; -const useIntersectionObserver = (callback: () => void) => { - const handleObserver = (entries: IntersectionObserverEntry[]) => { +const useIntersectionObserver = (callback: () => void): ((element: HTMLDivElement) => void) => { + const handleObserver = (entries: IntersectionObserverEntry[]): void => { const target = entries[0]; if (target.isIntersecting) { callback(); @@ -610,7 +610,7 @@ interface IManageButtonsProps { setError: Dispatch>; } -const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageButtonsProps) => { +const ManageButtons: React.FC = ({ hierarchy, selected, setSelected, setError }) => { const cli = useContext(MatrixClientContext); const [removing, setRemoving] = useState(false); @@ -645,7 +645,7 @@ const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageBu <>