From c27b82a43763b44b0b2a2929b9cde588260581b4 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 10 Jul 2023 18:26:56 +0200 Subject: [PATCH] Add `forward_to_domains` parameter to `POST /api/v1/reports` (#25866) --- app/controllers/api/v1/reports_controller.rb | 2 +- .../mastodon/features/report/comment.jsx | 150 +++++++++++------- .../features/ui/components/report_modal.jsx | 34 ++-- .../styles/mastodon/components.scss | 1 + app/services/report_service.rb | 22 ++- spec/services/report_service_spec.rb | 24 ++- 6 files changed, 153 insertions(+), 80 deletions(-) diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index 8ff6c8fe5c..300c9faa3f 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -23,6 +23,6 @@ class Api::V1::ReportsController < Api::BaseController end def report_params - params.permit(:account_id, :comment, :category, :forward, status_ids: [], rule_ids: []) + params.permit(:account_id, :comment, :category, :forward, forward_to_domains: [], status_ids: [], rule_ids: []) end end diff --git a/app/javascript/mastodon/features/report/comment.jsx b/app/javascript/mastodon/features/report/comment.jsx index 4888b76bcb..98ac4caa0a 100644 --- a/app/javascript/mastodon/features/report/comment.jsx +++ b/app/javascript/mastodon/features/report/comment.jsx @@ -1,87 +1,121 @@ import PropTypes from 'prop-types'; -import { PureComponent } from 'react'; +import { useCallback, useEffect, useRef } from 'react'; -import { injectIntl, defineMessages, FormattedMessage } from 'react-intl'; +import { useIntl, defineMessages, FormattedMessage } from 'react-intl'; + +import { OrderedSet, List as ImmutableList } from 'immutable'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import { shallowEqual } from 'react-redux'; +import { createSelector } from 'reselect'; import Toggle from 'react-toggle'; +import { fetchAccount } from 'mastodon/actions/accounts'; import Button from 'mastodon/components/button'; +import { useAppDispatch, useAppSelector } from 'mastodon/store'; const messages = defineMessages({ placeholder: { id: 'report.placeholder', defaultMessage: 'Type or paste additional comments' }, }); -class Comment extends PureComponent { +const selectRepliedToAccountIds = createSelector( + [ + (state) => state.get('statuses'), + (_, statusIds) => statusIds, + ], + (statusesMap, statusIds) => statusIds.map((statusId) => statusesMap.getIn([statusId, 'in_reply_to_account_id'])), + { + resultEqualityCheck: shallowEqual, + } +); - static propTypes = { - onSubmit: PropTypes.func.isRequired, - comment: PropTypes.string.isRequired, - onChangeComment: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - isSubmitting: PropTypes.bool, - forward: PropTypes.bool, - isRemote: PropTypes.bool, - domain: PropTypes.string, - onChangeForward: PropTypes.func.isRequired, - }; +const Comment = ({ comment, domain, statusIds, isRemote, isSubmitting, selectedDomains, onSubmit, onChangeComment, onToggleDomain }) => { + const intl = useIntl(); - handleClick = () => { - const { onSubmit } = this.props; - onSubmit(); - }; + const dispatch = useAppDispatch(); + const loadedRef = useRef(false); - handleChange = e => { - const { onChangeComment } = this.props; - onChangeComment(e.target.value); - }; + const handleClick = useCallback(() => onSubmit(), [onSubmit]); + const handleChange = useCallback((e) => onChangeComment(e.target.value), [onChangeComment]); + const handleToggleDomain = useCallback(e => onToggleDomain(e.target.value, e.target.checked), [onToggleDomain]); - handleKeyDown = e => { + const handleKeyDown = useCallback((e) => { if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) { - this.handleClick(); + handleClick(); } - }; + }, [handleClick]); - handleForwardChange = e => { - const { onChangeForward } = this.props; - onChangeForward(e.target.checked); - }; + // Memoize accountIds since we don't want it to trigger `useEffect` on each render + const accountIds = useAppSelector((state) => domain ? selectRepliedToAccountIds(state, statusIds) : ImmutableList()); - render () { - const { comment, isRemote, forward, domain, isSubmitting, intl } = this.props; + // While we could memoize `availableDomains`, it is pretty inexpensive to recompute + const accountsMap = useAppSelector((state) => state.get('accounts')); + const availableDomains = domain ? OrderedSet([domain]).union(accountIds.map((accountId) => accountsMap.getIn([accountId, 'acct'], '').split('@')[1]).filter(domain => !!domain)) : OrderedSet(); - return ( - <> -

+ useEffect(() => { + if (loadedRef.current) { + return; + } -