diff --git a/.eslintrc.js b/.eslintrc.js index 9e965791b0..cbac530d6f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -104,7 +104,6 @@ module.exports = { 'react/jsx-equals-spacing': 'error', 'react/jsx-no-bind': 'error', 'react/jsx-no-target-blank': 'off', - 'react/no-deprecated': 'off', 'react/no-unknown-property': 'off', 'react/self-closing-comp': 'error', diff --git a/app/javascript/mastodon/components/autosuggest_input.jsx b/app/javascript/mastodon/components/autosuggest_input.jsx index a68e2a01b4..218faabb79 100644 --- a/app/javascript/mastodon/components/autosuggest_input.jsx +++ b/app/javascript/mastodon/components/autosuggest_input.jsx @@ -154,7 +154,7 @@ export default class AutosuggestInput extends ImmutablePureComponent { this.input.focus(); }; - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) { this.setState({ suggestionsHidden: false }); } diff --git a/app/javascript/mastodon/components/autosuggest_textarea.jsx b/app/javascript/mastodon/components/autosuggest_textarea.jsx index a627bc1ec2..50cc24b002 100644 --- a/app/javascript/mastodon/components/autosuggest_textarea.jsx +++ b/app/javascript/mastodon/components/autosuggest_textarea.jsx @@ -153,7 +153,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { this.textarea.focus(); }; - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) { this.setState({ suggestionsHidden: false }); } diff --git a/app/javascript/mastodon/components/logo.jsx b/app/javascript/mastodon/components/logo.tsx similarity index 75% rename from app/javascript/mastodon/components/logo.jsx rename to app/javascript/mastodon/components/logo.tsx index 60e8f40b23..c3f409947a 100644 --- a/app/javascript/mastodon/components/logo.jsx +++ b/app/javascript/mastodon/components/logo.tsx @@ -1,15 +1,13 @@ import React from 'react'; import logo from 'mastodon/../images/logo.svg'; -export const WordmarkLogo = () => ( +export const WordmarkLogo: React.FC = () => ( Mastodon ); -export const SymbolLogo = () => ( +export const SymbolLogo: React.FC = () => ( Mastodon ); - -export default WordmarkLogo; diff --git a/app/javascript/mastodon/components/media_gallery.jsx b/app/javascript/mastodon/components/media_gallery.jsx index 6bb3826408..564d6e7d55 100644 --- a/app/javascript/mastodon/components/media_gallery.jsx +++ b/app/javascript/mastodon/components/media_gallery.jsx @@ -241,7 +241,7 @@ class MediaGallery extends React.PureComponent { window.removeEventListener('resize', this.handleResize); } - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { if (!is(nextProps.media, this.props.media) && nextProps.visible === undefined) { this.setState({ visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all' }); } else if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) { diff --git a/app/javascript/mastodon/components/modal_root.jsx b/app/javascript/mastodon/components/modal_root.jsx index c0525c2217..7671d2725d 100644 --- a/app/javascript/mastodon/components/modal_root.jsx +++ b/app/javascript/mastodon/components/modal_root.jsx @@ -57,7 +57,7 @@ export default class ModalRoot extends React.PureComponent { this.history = this.context.router ? this.context.router.history : createBrowserHistory(); } - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { if (!!nextProps.children && !this.props.children) { this.activeElement = document.activeElement; diff --git a/app/javascript/mastodon/features/account/components/account_note.jsx b/app/javascript/mastodon/features/account/components/account_note.jsx index 5201ebd4dc..9a81b0aee2 100644 --- a/app/javascript/mastodon/features/account/components/account_note.jsx +++ b/app/javascript/mastodon/features/account/components/account_note.jsx @@ -22,7 +22,7 @@ class InlineAlert extends React.PureComponent { static TRANSITION_DELAY = 200; - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { if (!this.props.show && nextProps.show) { this.setState({ mountMessage: true }); } else if (this.props.show && !nextProps.show) { @@ -58,11 +58,11 @@ class AccountNote extends ImmutablePureComponent { saved: false, }; - componentWillMount () { + UNSAFE_componentWillMount () { this._reset(); } - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { const accountWillChange = !is(this.props.account, nextProps.account); const newState = {}; diff --git a/app/javascript/mastodon/features/audio/index.jsx b/app/javascript/mastodon/features/audio/index.jsx index 56e913ae3a..5ed02d9378 100644 --- a/app/javascript/mastodon/features/audio/index.jsx +++ b/app/javascript/mastodon/features/audio/index.jsx @@ -136,7 +136,7 @@ class Audio extends React.PureComponent { } } - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) { this.setState({ revealed: nextProps.visible }); } diff --git a/app/javascript/mastodon/features/blocks/index.jsx b/app/javascript/mastodon/features/blocks/index.jsx index 38616ba844..da28f12d79 100644 --- a/app/javascript/mastodon/features/blocks/index.jsx +++ b/app/javascript/mastodon/features/blocks/index.jsx @@ -34,7 +34,7 @@ class Blocks extends ImmutablePureComponent { multiColumn: PropTypes.bool, }; - componentWillMount () { + UNSAFE_componentWillMount () { this.props.dispatch(fetchBlocks()); } diff --git a/app/javascript/mastodon/features/bookmarked_statuses/index.jsx b/app/javascript/mastodon/features/bookmarked_statuses/index.jsx index 46fff856e4..1ffe7e768d 100644 --- a/app/javascript/mastodon/features/bookmarked_statuses/index.jsx +++ b/app/javascript/mastodon/features/bookmarked_statuses/index.jsx @@ -34,7 +34,7 @@ class Bookmarks extends ImmutablePureComponent { isLoading: PropTypes.bool, }; - componentWillMount () { + UNSAFE_componentWillMount () { this.props.dispatch(fetchBookmarkedStatuses()); } diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.jsx b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.jsx index d428b2c4be..0b792418ff 100644 --- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.jsx +++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.jsx @@ -59,7 +59,7 @@ class ModifierPickerMenu extends React.PureComponent { this.props.onSelect(e.currentTarget.getAttribute('data-index') * 1); }; - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { if (nextProps.active) { this.attachListeners(); } else { diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx b/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx index dcc442a93b..82c738d9dd 100644 --- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx +++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx @@ -214,7 +214,7 @@ class PrivacyDropdown extends React.PureComponent { this.props.onChange(value); }; - componentWillMount () { + UNSAFE_componentWillMount () { const { intl: { formatMessage } } = this.props; this.options = [ diff --git a/app/javascript/mastodon/features/domain_blocks/index.jsx b/app/javascript/mastodon/features/domain_blocks/index.jsx index 0c22aa2396..6a9f6e4cf5 100644 --- a/app/javascript/mastodon/features/domain_blocks/index.jsx +++ b/app/javascript/mastodon/features/domain_blocks/index.jsx @@ -34,7 +34,7 @@ class Blocks extends ImmutablePureComponent { multiColumn: PropTypes.bool, }; - componentWillMount () { + UNSAFE_componentWillMount () { this.props.dispatch(fetchDomainBlocks()); } diff --git a/app/javascript/mastodon/features/favourited_statuses/index.jsx b/app/javascript/mastodon/features/favourited_statuses/index.jsx index 2cbf002919..161297114d 100644 --- a/app/javascript/mastodon/features/favourited_statuses/index.jsx +++ b/app/javascript/mastodon/features/favourited_statuses/index.jsx @@ -34,7 +34,7 @@ class Favourites extends ImmutablePureComponent { isLoading: PropTypes.bool, }; - componentWillMount () { + UNSAFE_componentWillMount () { this.props.dispatch(fetchFavouritedStatuses()); } diff --git a/app/javascript/mastodon/features/favourites/index.jsx b/app/javascript/mastodon/features/favourites/index.jsx index 4a8c1deb6f..ed210dad5b 100644 --- a/app/javascript/mastodon/features/favourites/index.jsx +++ b/app/javascript/mastodon/features/favourites/index.jsx @@ -31,13 +31,13 @@ class Favourites extends ImmutablePureComponent { intl: PropTypes.object.isRequired, }; - componentWillMount () { + UNSAFE_componentWillMount () { if (!this.props.accountIds) { this.props.dispatch(fetchFavourites(this.props.params.statusId)); } } - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { this.props.dispatch(fetchFavourites(nextProps.params.statusId)); } diff --git a/app/javascript/mastodon/features/follow_requests/index.jsx b/app/javascript/mastodon/features/follow_requests/index.jsx index a8875bbd31..779bc473e4 100644 --- a/app/javascript/mastodon/features/follow_requests/index.jsx +++ b/app/javascript/mastodon/features/follow_requests/index.jsx @@ -39,7 +39,7 @@ class FollowRequests extends ImmutablePureComponent { multiColumn: PropTypes.bool, }; - componentWillMount () { + UNSAFE_componentWillMount () { this.props.dispatch(fetchFollowRequests()); } diff --git a/app/javascript/mastodon/features/list_timeline/index.jsx b/app/javascript/mastodon/features/list_timeline/index.jsx index c93305341a..e1408d8efb 100644 --- a/app/javascript/mastodon/features/list_timeline/index.jsx +++ b/app/javascript/mastodon/features/list_timeline/index.jsx @@ -76,7 +76,7 @@ class ListTimeline extends React.PureComponent { this.disconnect = dispatch(connectListStream(id)); } - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { const { dispatch } = this.props; const { id } = nextProps.params; diff --git a/app/javascript/mastodon/features/lists/index.jsx b/app/javascript/mastodon/features/lists/index.jsx index afd645a308..232b0c2d5a 100644 --- a/app/javascript/mastodon/features/lists/index.jsx +++ b/app/javascript/mastodon/features/lists/index.jsx @@ -42,7 +42,7 @@ class Lists extends ImmutablePureComponent { multiColumn: PropTypes.bool, }; - componentWillMount () { + UNSAFE_componentWillMount () { this.props.dispatch(fetchLists()); } diff --git a/app/javascript/mastodon/features/mutes/index.jsx b/app/javascript/mastodon/features/mutes/index.jsx index 5c05d2f700..078d8779ec 100644 --- a/app/javascript/mastodon/features/mutes/index.jsx +++ b/app/javascript/mastodon/features/mutes/index.jsx @@ -35,7 +35,7 @@ class Mutes extends ImmutablePureComponent { multiColumn: PropTypes.bool, }; - componentWillMount () { + UNSAFE_componentWillMount () { this.props.dispatch(fetchMutes()); } diff --git a/app/javascript/mastodon/features/notifications/index.jsx b/app/javascript/mastodon/features/notifications/index.jsx index 8a31c5db6c..8b77374c40 100644 --- a/app/javascript/mastodon/features/notifications/index.jsx +++ b/app/javascript/mastodon/features/notifications/index.jsx @@ -93,7 +93,7 @@ class Notifications extends React.PureComponent { trackScroll: true, }; - componentWillMount() { + UNSAFE_componentWillMount() { this.props.dispatch(mountNotifications()); } diff --git a/app/javascript/mastodon/features/pinned_statuses/index.jsx b/app/javascript/mastodon/features/pinned_statuses/index.jsx index 24a0b6d2e3..e58ce2bb89 100644 --- a/app/javascript/mastodon/features/pinned_statuses/index.jsx +++ b/app/javascript/mastodon/features/pinned_statuses/index.jsx @@ -29,7 +29,7 @@ class PinnedStatuses extends ImmutablePureComponent { multiColumn: PropTypes.bool, }; - componentWillMount () { + UNSAFE_componentWillMount () { this.props.dispatch(fetchPinnedStatuses()); } diff --git a/app/javascript/mastodon/features/reblogs/index.jsx b/app/javascript/mastodon/features/reblogs/index.jsx index fb503f40f1..757ef0dd0e 100644 --- a/app/javascript/mastodon/features/reblogs/index.jsx +++ b/app/javascript/mastodon/features/reblogs/index.jsx @@ -31,13 +31,13 @@ class Reblogs extends ImmutablePureComponent { intl: PropTypes.object.isRequired, }; - componentWillMount () { + UNSAFE_componentWillMount () { if (!this.props.accountIds) { this.props.dispatch(fetchReblogs(this.props.params.statusId)); } } - componentWillReceiveProps(nextProps) { + UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { this.props.dispatch(fetchReblogs(nextProps.params.statusId)); } diff --git a/app/javascript/mastodon/features/status/components/card.jsx b/app/javascript/mastodon/features/status/components/card.jsx index 1d5edfc173..bc02665311 100644 --- a/app/javascript/mastodon/features/status/components/card.jsx +++ b/app/javascript/mastodon/features/status/components/card.jsx @@ -66,7 +66,7 @@ export default class Card extends React.PureComponent { revealed: !this.props.sensitive, }; - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { if (!Immutable.is(this.props.card, nextProps.card)) { this.setState({ embedded: false, previewLoaded: false }); } diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index 9a244c8be1..7a14761c44 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -209,7 +209,7 @@ class Status extends ImmutablePureComponent { loadedStatusId: undefined, }; - componentWillMount () { + UNSAFE_componentWillMount () { this.props.dispatch(fetchStatus(this.props.params.statusId)); } @@ -217,7 +217,7 @@ class Status extends ImmutablePureComponent { attachFullscreenListener(this.onFullScreenChange); } - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { this._scrolledIntoView = false; this.props.dispatch(fetchStatus(nextProps.params.statusId)); diff --git a/app/javascript/mastodon/features/ui/components/bundle.jsx b/app/javascript/mastodon/features/ui/components/bundle.jsx index 1b10a218b6..c1e837b16e 100644 --- a/app/javascript/mastodon/features/ui/components/bundle.jsx +++ b/app/javascript/mastodon/features/ui/components/bundle.jsx @@ -33,11 +33,11 @@ class Bundle extends React.PureComponent { forceRender: false, }; - componentWillMount() { + UNSAFE_componentWillMount() { this.load(this.props); } - componentWillReceiveProps(nextProps) { + UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.fetchComponent !== this.props.fetchComponent) { this.load(nextProps); } diff --git a/app/javascript/mastodon/features/ui/components/columns_area.jsx b/app/javascript/mastodon/features/ui/components/columns_area.jsx index 1ce14b4c5b..346f44bf09 100644 --- a/app/javascript/mastodon/features/ui/components/columns_area.jsx +++ b/app/javascript/mastodon/features/ui/components/columns_area.jsx @@ -78,7 +78,7 @@ export default class ColumnsArea extends ImmutablePureComponent { this.isRtlLayout = document.getElementsByTagName('body')[0].classList.contains('rtl'); } - componentWillUpdate(nextProps) { + UNSAFE_componentWillUpdate(nextProps) { if (this.props.singleColumn !== nextProps.singleColumn && nextProps.singleColumn) { this.node.removeEventListener('wheel', this.handleWheel); } diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx index ee1a83cc60..b62d216ae9 100644 --- a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx +++ b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl } from 'react-intl'; import { Link } from 'react-router-dom'; -import Logo from 'mastodon/components/logo'; +import { WordmarkLogo } from 'mastodon/components/logo'; import { timelinePreview, showTrends } from 'mastodon/initial_state'; import ColumnLink from './column_link'; import DisabledAccountBanner from './disabled_account_banner'; @@ -46,7 +46,7 @@ class NavigationPanel extends React.Component { return (
- +
diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index 5bbd94c268..df6a1b3fa2 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -126,7 +126,7 @@ class SwitchingColumnsArea extends React.PureComponent { mobile: PropTypes.bool, }; - componentWillMount () { + UNSAFE_componentWillMount () { if (this.props.mobile) { document.body.classList.toggle('layout-single-column', true); document.body.classList.toggle('layout-multiple-columns', false); diff --git a/app/javascript/mastodon/features/video/index.jsx b/app/javascript/mastodon/features/video/index.jsx index 8b57cf3d10..3d9d1aec6c 100644 --- a/app/javascript/mastodon/features/video/index.jsx +++ b/app/javascript/mastodon/features/video/index.jsx @@ -370,7 +370,7 @@ class Video extends React.PureComponent { } } - componentWillReceiveProps (nextProps) { + UNSAFE_componentWillReceiveProps (nextProps) { if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) { this.setState({ revealed: nextProps.visible }); } diff --git a/app/javascript/mastodon/store/index.ts b/app/javascript/mastodon/store/index.ts index 6c3e963d9e..f7e1be6b7b 100644 --- a/app/javascript/mastodon/store/index.ts +++ b/app/javascript/mastodon/store/index.ts @@ -8,7 +8,21 @@ import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; export const store = configureStore({ reducer: rootReducer, middleware: (getDefaultMiddleware) => - getDefaultMiddleware() + getDefaultMiddleware({ + // In development, Redux Toolkit enables 2 default middlewares to detect + // common issues with states. Unfortunately, our use of ImmutableJS for state + // triggers both, so lets disable them until our state is fully refactored + + // https://redux-toolkit.js.org/api/serializabilityMiddleware + // This checks recursively that every values in the state are serializable in JSON + // Which is not the case, as we use ImmutableJS structures, but also File objects + serializableCheck: false, + + // https://redux-toolkit.js.org/api/immutabilityMiddleware + // This checks recursively if every value in the state is immutable (ie, a JS primitive type) + // But this is not the case, as our Root State is an ImmutableJS map, which is an object + immutableCheck: false, + }) .concat( loadingBarMiddleware({ promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'],