+
-
+
diff --git a/app/javascript/mastodon/features/status/components/detailed_status.jsx b/app/javascript/mastodon/features/status/components/detailed_status.jsx
index 2f097ba57e..6bd016332b 100644
--- a/app/javascript/mastodon/features/status/components/detailed_status.jsx
+++ b/app/javascript/mastodon/features/status/components/detailed_status.jsx
@@ -137,6 +137,7 @@ class DetailedStatus extends ImmutablePureComponent {
let reblogIcon = 'retweet';
let favouriteLink = '';
let emojiReactionsLink = '';
+ let statusReferencesLink = '';
let edited = '';
if (this.props.measureHeight) {
@@ -310,6 +311,26 @@ class DetailedStatus extends ImmutablePureComponent {
);
}
+ if (this.context.router) {
+ statusReferencesLink = (
+
+
+
+
+
+
+ );
+ } else {
+ statusReferencesLink = (
+
+
+
+
+
+
+ );
+ }
+
if (status.get('edited_at')) {
edited = (
<>
@@ -347,7 +368,7 @@ class DetailedStatus extends ImmutablePureComponent {
- {edited}{visibilityLink}{searchabilityLink}{applicationLink}{reblogLink} · {favouriteLink} · {emojiReactionsLink}
+ {edited}{visibilityLink}{searchabilityLink}{applicationLink}{reblogLink} · {favouriteLink} · {emojiReactionsLink} - {statusReferencesLink}
diff --git a/app/javascript/mastodon/features/status_references/index.jsx b/app/javascript/mastodon/features/status_references/index.jsx
new file mode 100644
index 0000000000..00e200f42e
--- /dev/null
+++ b/app/javascript/mastodon/features/status_references/index.jsx
@@ -0,0 +1,95 @@
+import PropTypes from 'prop-types';
+
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+
+import { Helmet } from 'react-helmet';
+
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import ImmutablePureComponent from 'react-immutable-pure-component';
+import { connect } from 'react-redux';
+
+import { fetchStatusReferences } from 'mastodon/actions/interactions';
+import ColumnHeader from 'mastodon/components/column_header';
+import { Icon } from 'mastodon/components/icon';
+import LoadingIndicator from 'mastodon/components/loading_indicator';
+import ScrollableList from 'mastodon/components/scrollable_list';
+import StatusContainer from 'mastodon/containers/status_container';
+import Column from 'mastodon/features/ui/components/column';
+
+const messages = defineMessages({
+ refresh: { id: 'refresh', defaultMessage: 'Refresh' },
+});
+
+const mapStateToProps = (state, props) => ({
+ accountIds: state.getIn(['user_lists', 'referred_by', props.params.statusId]),
+});
+
+class StatusReferences extends ImmutablePureComponent {
+
+ static propTypes = {
+ params: PropTypes.object.isRequired,
+ dispatch: PropTypes.func.isRequired,
+ accountIds: ImmutablePropTypes.list,
+ multiColumn: PropTypes.bool,
+ intl: PropTypes.object.isRequired,
+ };
+
+ UNSAFE_componentWillMount () {
+ if (!this.props.accountIds) {
+ this.props.dispatch(fetchStatusReferences(this.props.params.statusId));
+ }
+ }
+
+ UNSAFE_componentWillReceiveProps (nextProps) {
+ if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {
+ this.props.dispatch(fetchStatusReferences(nextProps.params.statusId));
+ }
+ }
+
+ handleRefresh = () => {
+ this.props.dispatch(fetchStatusReferences(this.props.params.statusId));
+ };
+
+ render () {
+ const { intl, accountIds, multiColumn } = this.props;
+
+ if (!accountIds) {
+ return (
+
+
+
+ );
+ }
+
+ const emptyMessage =
;
+
+ return (
+
+
+ )}
+ />
+
+
+ {accountIds.map(id =>
+ ,
+ )}
+
+
+
+
+
+
+ );
+ }
+
+}
+
+export default connect(mapStateToProps)(injectIntl(StatusReferences));
diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx
index b765ee568b..73ba5c1a42 100644
--- a/app/javascript/mastodon/features/ui/index.jsx
+++ b/app/javascript/mastodon/features/ui/index.jsx
@@ -46,6 +46,7 @@ import {
Reblogs,
Favourites,
EmojiReactions,
+ StatusReferences,
DirectTimeline,
HashtagTimeline,
Notifications,
@@ -221,6 +222,7 @@ class SwitchingColumnsArea extends PureComponent {
+
{/* Legacy routes, cannot be easily factored with other routes because they share a param name */}
@@ -229,6 +231,7 @@ class SwitchingColumnsArea extends PureComponent {
+
diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js
index a10991026a..be6027464c 100644
--- a/app/javascript/mastodon/features/ui/util/async-components.js
+++ b/app/javascript/mastodon/features/ui/util/async-components.js
@@ -82,6 +82,10 @@ export function EmojiReactions () {
return import(/* webpackChunkName: "features/emoji_reactions" */'../../emoji_reactions');
}
+export function StatusReferences () {
+ return import(/* webpackChunkName: "features/status_references" */'../../status_references');
+}
+
export function FollowRequests () {
return import(/* webpackChunkName: "features/follow_requests" */'../../follow_requests');
}
diff --git a/app/javascript/mastodon/reducers/user_lists.js b/app/javascript/mastodon/reducers/user_lists.js
index e731b619c0..99d91dbc77 100644
--- a/app/javascript/mastodon/reducers/user_lists.js
+++ b/app/javascript/mastodon/reducers/user_lists.js
@@ -48,6 +48,7 @@ import {
REBLOGS_FETCH_SUCCESS,
FAVOURITES_FETCH_SUCCESS,
EMOJI_REACTIONS_FETCH_SUCCESS,
+ STATUS_REFERENCES_FETCH_SUCCESS,
} from '../actions/interactions';
import {
MUTES_FETCH_REQUEST,
@@ -75,6 +76,7 @@ const initialState = ImmutableMap({
reblogged_by: initialListState,
favourited_by: initialListState,
emoji_reactioned_by: initialListState,
+ referred_by: initialListState,
follow_requests: initialListState,
blocks: initialListState,
mutes: initialListState,
@@ -141,6 +143,8 @@ export default function userLists(state = initialState, action) {
return state.setIn(['favourited_by', action.id], ImmutableList(action.accounts.map(item => item.id)));
case EMOJI_REACTIONS_FETCH_SUCCESS:
return state.setIn(['emoji_reactioned_by', action.id], ImmutableList(action.accounts));
+ case STATUS_REFERENCES_FETCH_SUCCESS:
+ return state.setIn(['referred_by', action.id], ImmutableList(action.statuses.map(item => item.id)));
case NOTIFICATIONS_UPDATE:
return action.notification.type === 'follow_request' ? normalizeFollowRequest(state, action.notification) : state;
case FOLLOW_REQUESTS_FETCH_SUCCESS:
diff --git a/config/routes/api.rb b/config/routes/api.rb
index 57543be8fb..9f01253d8c 100644
--- a/config/routes/api.rb
+++ b/config/routes/api.rb
@@ -12,6 +12,7 @@ namespace :api, format: false do
resources :favourited_by, controller: :favourited_by_accounts, only: :index
resources :emoji_reactioned_by, controller: :emoji_reactioned_by_accounts, only: :index
resources :emoji_reactioned_by_slim, controller: :emoji_reactioned_by_accounts_slim, only: :index
+ resources :referred_by, controller: :referred_by_statuses, only: :index
resource :reblog, only: :create
post :unreblog, to: 'reblogs#destroy'