Merge branch 'kb_development' into kb_migration

This commit is contained in:
KMY 2023-05-31 12:32:34 +09:00
commit 45d56fce78
14 changed files with 84 additions and 38 deletions

View file

@ -1,16 +1,20 @@
import { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import { injectIntl, defineMessages } from 'react-intl';
import { IconButton } from '../../../components/icon_button';
import Overlay from 'react-overlays/Overlay';
import { supportsPassiveEvents } from 'detect-passive-events';
import classNames from 'classnames';
import { supportsPassiveEvents } from 'detect-passive-events';
import Overlay from 'react-overlays/Overlay';
import { IconButton } from '../../../components/icon_button';
const messages = defineMessages({
add_expiration: { id: 'status.expiration.add', defaultMessage: 'Set status expiration' },
});
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
class ExpirationDropdownMenu extends PureComponent {
@ -25,6 +29,7 @@ class ExpirationDropdownMenu extends PureComponent {
handleDocumentClick = e => {
if (this.node && !this.node.contains(e.target)) {
this.props.onClose();
e.stopPropagation();
}
};
@ -82,13 +87,13 @@ class ExpirationDropdownMenu extends PureComponent {
};
componentDidMount () {
document.addEventListener('click', this.handleDocumentClick, false);
document.addEventListener('click', this.handleDocumentClick, { capture: true });
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
if (this.focusedItem) this.focusedItem.focus({ preventScroll: true });
}
componentWillUnmount () {
document.removeEventListener('click', this.handleDocumentClick, false);
document.removeEventListener('click', this.handleDocumentClick, { capture: true });
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);
}

View file

@ -1,11 +1,16 @@
import { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import { injectIntl, defineMessages } from 'react-intl';
import { IconButton } from '../../../components/icon_button';
import Overlay from 'react-overlays/Overlay';
import { supportsPassiveEvents } from 'detect-passive-events';
import classNames from 'classnames';
import { Icon } from 'mastodon/components/icon';
import { supportsPassiveEvents } from 'detect-passive-events';
import Overlay from 'react-overlays/Overlay';
import { Icon } from 'mastodon/components/icon';
import { IconButton } from '../../../components/icon_button';
const messages = defineMessages({
public_short: { id: 'searchability.public.short', defaultMessage: 'Public' },
@ -19,7 +24,7 @@ const messages = defineMessages({
change_searchability: { id: 'searchability.change', defaultMessage: 'Set status searchability' },
});
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
class SearchabilityDropdownMenu extends PureComponent {
@ -34,6 +39,7 @@ class SearchabilityDropdownMenu extends PureComponent {
handleDocumentClick = e => {
if (this.node && !this.node.contains(e.target)) {
this.props.onClose();
e.stopPropagation();
}
};
@ -91,13 +97,13 @@ class SearchabilityDropdownMenu extends PureComponent {
};
componentDidMount () {
document.addEventListener('click', this.handleDocumentClick, false);
document.addEventListener('click', this.handleDocumentClick, { capture: true });
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
if (this.focusedItem) this.focusedItem.focus({ preventScroll: true });
}
componentWillUnmount () {
document.removeEventListener('click', this.handleDocumentClick, false);
document.removeEventListener('click', this.handleDocumentClick, { capture: true });
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);
}

View file

@ -1,7 +1,8 @@
import { connect } from 'react-redux';
import ExpirationDropdown from '../components/expiration_dropdown';
import { openModal, closeModal } from '../../../actions/modal';
import { isUserTouching } from '../../../is_mobile';
import ExpirationDropdown from '../components/expiration_dropdown';
const mapStateToProps = state => ({
value: state.getIn(['compose', 'privacy']),
@ -16,8 +17,14 @@ const mapDispatchToProps = (dispatch, { onPickExpiration }) => ({
},
isUserTouching,
onModalOpen: props => dispatch(openModal('ACTIONS', props)),
onModalClose: () => dispatch(closeModal()),
onModalOpen: props => dispatch(openModal({
modalType: 'ACTIONS',
modalProps: props,
})),
onModalClose: () => dispatch(closeModal({
modalType: undefined,
ignoreFocus: false,
})),
});

View file

@ -1,8 +1,9 @@
import { connect } from 'react-redux';
import SearchabilityDropdown from '../components/searchability_dropdown';
import { changeComposeSearchability } from '../../../actions/compose';
import { openModal, closeModal } from '../../../actions/modal';
import { isUserTouching } from '../../../is_mobile';
import SearchabilityDropdown from '../components/searchability_dropdown';
const mapStateToProps = state => ({
value: state.getIn(['compose', 'searchability']),
@ -15,8 +16,14 @@ const mapDispatchToProps = dispatch => ({
},
isUserTouching,
onModalOpen: props => dispatch(openModal('ACTIONS', props)),
onModalClose: () => dispatch(closeModal()),
onModalOpen: props => dispatch(openModal({
modalType: 'ACTIONS',
modalProps: props,
})),
onModalClose: () => dispatch(closeModal({
modalType: undefined,
ignoreFocus: false,
})),
});

View file

@ -128,10 +128,18 @@ class Onboarding extends ImmutablePureComponent {
<p className='onboarding__lead'><FormattedMessage id='onboarding.start.skip' defaultMessage='Want to skip right ahead?' /></p>
<div className='onboarding__links'>
<Link to='/explore' className='onboarding__link'>
<Link to='/explore' onClick={this.handleClose} className='onboarding__link'>
<ArrowSmallRight />
<FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage="See what's trending" />
</Link>
<Link to='/public/local' onClick={this.handleClose} className='onboarding__link'>
<ArrowSmallRight />
<FormattedMessage id='onboarding.actions.go_to_local_timeline' defaultMessage='See posts from local' />
</Link>
<Link to='/home' onClick={this.handleClose} className='onboarding__link'>
<ArrowSmallRight />
<FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='See home' />
</Link>
</div>
<div className='onboarding__footer'>

View file

@ -16,6 +16,7 @@ import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
import { updateReactionDeck } from 'mastodon/actions/reaction_deck';
import Button from 'mastodon/components/button';
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 Column from 'mastodon/features/ui/components/column';
@ -129,16 +130,18 @@ class ReactionDeck extends ImmutablePureComponent {
<DragDropContext onDragEnd={this.handleReorder}>
<StrictModeDroppable droppableId='deckitems'>
{(provided) => (
<div className='deckitems' {...provided.droppableProps} ref={provided.innerRef}>
<div className='deckitems reaction_deck_container' {...provided.droppableProps} ref={provided.innerRef}>
{deck.map((emoji, index) => (
<Draggable key={index} draggableId={'' + index} index={index}>
{(provided2) => (
<div ref={provided2.innerRef} {...provided2.draggableProps} {...provided2.dragHandleProps}>
<div className='reaction_deck_container__row' ref={provided2.innerRef} {...provided2.draggableProps}>
<Icon id='bars' className='handle' {...provided2.dragHandleProps} />
<ReactionEmoji emojiMap={emojiMap}
emoji={emoji.get('name')}
index={index}
onChange={this.handleChange}
onRemove={this.handleRemove}
className='reaction_emoji'
/>
</div>
)}

View file

@ -459,6 +459,7 @@
"onboarding.actions.close": "今後この画面を表示しない",
"onboarding.actions.go_to_explore": "話題をさがす",
"onboarding.actions.go_to_home": "タイムラインに移動",
"onboarding.actions.go_to_local_timeline": "ローカルの投稿を見る",
"onboarding.compose.template": "#Mastodon はじめました",
"onboarding.follows.empty": "おすすめに表示できるアカウントはまだありません。検索や「見つける」を活用して、ほかのアカウントを探してみましょう。",
"onboarding.follows.lead": "自分の手でタイムラインを作ってみましょう。フォローを増やせば、タイムラインはより賑やかでおもしろいものになります。最初のフォローの参考になりそうなアカウントをいくつか表示しています。気になったものがあれば、ここからフォローしてみましょう。フォローはいつでも解除して大丈夫です。",
@ -468,7 +469,7 @@
"onboarding.share.next_steps": "次のステップに進む:",
"onboarding.share.title": "プロフィールをシェアする",
"onboarding.start.lead": "Mastodon アカウントの準備ができました。次のステップに進みましょう:",
"onboarding.start.skip": "チュートリアルをスキップ",
"onboarding.start.skip": "下のどれかをクリックしてチュートリアルを終了",
"onboarding.start.title": "はじめに",
"onboarding.steps.follow_people.body": "タイムラインを充実させましょう。",
"onboarding.steps.follow_people.title": "最初の{count, plural, other {#人}}をフォローする",

View file

@ -7544,11 +7544,25 @@ noscript {
}
}
.reaction_deck_container {
&__row {
display: flex;
height: 32px;
margin: 8px 16px 12px 4px;
.handle {
font-size: 24px;
}
.reaction_deck__emoji {
flex: 1;
}
}
}
.reaction_deck__emoji {
&__wrapper {
display: flex;
margin: 8px 16px 8px 4px;
height: 32px;
.emojione {
min-width: 24px;

View file

@ -42,7 +42,7 @@ class StatusEdit < ApplicationRecord
default_scope { order(id: :asc) }
delegate :local?, :application, :edited?, :edited_at,
delegate :local?, :application, :edited?, :edited_at, :language,
:discarded?, :visibility, to: :status
def emojis

View file

@ -74,6 +74,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
max_characters_per_option: PollValidator::MAX_OPTION_CHARS,
min_expiration: PollValidator::MIN_EXPIRATION,
max_expiration: PollValidator::MAX_EXPIRATION,
allow_image: true,
},
translation: {

View file

@ -84,6 +84,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer
max_characters_per_option: PollValidator::MAX_OPTION_CHARS,
min_expiration: PollValidator::MIN_EXPIRATION,
max_expiration: PollValidator::MAX_EXPIRATION,
allow_image: true,
},
emoji_reactions: {

View file

@ -17,7 +17,7 @@ module AccountScope
end
def scope_account_local_followers(account)
account.followers_for_local_distribution.select(:id).reorder(nil)
account.followers_for_local_distribution.or(Account.where(id: account.id)).select(:id).reorder(nil)
end
def scope_status_mentioned(status)

View file

@ -121,7 +121,7 @@ class FanOutOnWriteService < BaseService
antennas = Antenna.available_stls
antennas = antennas.where(account_id: Account.without_suspended.joins(:user).select('accounts.id').where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago))
antennas = antennas.where(account: @account.followers).or(antennas.where(account: @account)).where.not(list_id: 0) if !@account.domain.nil? || [:public, :public_unlisted, :login].exclude?(@status.visibility.to_sym)
antennas = antennas.where(account: @account.followers).or(antennas.where(account: @account)).where.not(list_id: 0) if !@account.domain.nil? || @status.reblog? || [:public, :public_unlisted, :login].exclude?(@status.visibility.to_sym)
collection = AntennaCollection.new(@status, @options[:update])

View file

@ -6,20 +6,13 @@ class DeliveryEmojiReactionWorker
include Lockable
include AccountScope
def perform(payload_json, status_id, my_account_id = nil)
redis.publish("timeline:#{my_account_id}", payload_json) if my_account_id.present? && !Account.find(my_account_id)&.user&.setting_stop_emoji_reaction_streaming
def perform(payload_json, status_id, _my_account_id = nil)
status = Status.find(status_id.to_i)
if status.present?
scope_status(status).includes(:user).find_each do |account|
redis.publish("timeline:#{account.id}", payload_json) if !account.user&.setting_stop_emoji_reaction_streaming && redis.exists?("subscribed:timeline:#{account.id}")
end
if [:public, :unlisted, :public_unlisted, :login].exclude?(status.visibility.to_sym) && status.account_id != my_account_id &&
redis.exists?("subscribed:timeline:#{status.account_id}") && !status.account.user&.setting_stop_emoji_reaction_streaming
redis.publish("timeline:#{status.account_id}", payload_json)
end
end
true