Use new PR 2462 for reactions
This commit is contained in:
commit
10ad23fdb4
@ -70,7 +70,6 @@ export const defaultMediaVisibility = (status, settings) => {
|
|||||||
class Status extends ImmutablePureComponent {
|
class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
router: PropTypes.object,
|
|
||||||
identity: PropTypes.object,
|
identity: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -788,6 +787,9 @@ class Status extends ImmutablePureComponent {
|
|||||||
muted,
|
muted,
|
||||||
}, 'focusable');
|
}, 'focusable');
|
||||||
|
|
||||||
|
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
|
||||||
|
contentMedia.push(hashtagBar);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers}>
|
<HotKeys handlers={handlers}>
|
||||||
<div
|
<div
|
||||||
@ -837,6 +839,16 @@ class Status extends ImmutablePureComponent {
|
|||||||
disabled={!history}
|
disabled={!history}
|
||||||
tagLinks={settings.get('tag_misleading_links')}
|
tagLinks={settings.get('tag_misleading_links')}
|
||||||
rewriteMentions={settings.get('rewrite_mentions')}
|
rewriteMentions={settings.get('rewrite_mentions')}
|
||||||
|
{...statusContentProps}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<StatusReactions
|
||||||
|
statusId={status.get('id')}
|
||||||
|
reactions={status.get('reactions')}
|
||||||
|
numVisible={visibleReactions}
|
||||||
|
addReaction={this.props.onReactionAdd}
|
||||||
|
removeReaction={this.props.onReactionRemove}
|
||||||
|
canReact={this.context.identity.signedIn}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<StatusReactions
|
<StatusReactions
|
||||||
|
@ -9,6 +9,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
|
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
|
||||||
|
import EmojiPickerDropdown from 'flavours/glitch/features/compose/containers/emoji_picker_dropdown_container';
|
||||||
import { me, maxReactions } from 'flavours/glitch/initial_state';
|
import { me, maxReactions } from 'flavours/glitch/initial_state';
|
||||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions';
|
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions';
|
||||||
import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links';
|
import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links';
|
||||||
@ -341,7 +342,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
? <EmojiPickerDropdown className='status__action-bar-button' onPickEmoji={this.handleEmojiPick} button={reactButton} disabled={!canReact} />
|
? <EmojiPickerDropdown className='status__action-bar-button' onPickEmoji={this.handleEmojiPick} button={reactButton} disabled={!canReact} />
|
||||||
: reactButton
|
: reactButton
|
||||||
}
|
}
|
||||||
<IconButton className='status__action-bar-button bookmark-icon' disabled={anonymousAccess} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />
|
<IconButton className='status__action-bar-button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />
|
||||||
|
|
||||||
{filterButton}
|
{filterButton}
|
||||||
|
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import { autoPlayGif, reduceMotion } from '../initial_state';
|
|
||||||
import spring from 'react-motion/lib/spring';
|
|
||||||
import TransitionMotion from 'react-motion/lib/TransitionMotion';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
|
import TransitionMotion from 'react-motion/lib/TransitionMotion';
|
||||||
|
import spring from 'react-motion/lib/spring';
|
||||||
|
|
||||||
import { unicodeMapping } from '../features/emoji/emoji_unicode_mapping_light';
|
import { unicodeMapping } from '../features/emoji/emoji_unicode_mapping_light';
|
||||||
import { AnimatedNumber } from './animated_number';
|
import { autoPlayGif, reduceMotion } from '../initial_state';
|
||||||
import { assetHost } from '../utils/config';
|
import { assetHost } from '../utils/config';
|
||||||
|
|
||||||
|
import { AnimatedNumber } from './animated_number';
|
||||||
|
|
||||||
export default class StatusReactions extends ImmutablePureComponent {
|
export default class StatusReactions extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -10,6 +10,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||||||
|
|
||||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
|
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
|
||||||
|
import EmojiPickerDropdown from 'flavours/glitch/features/compose/containers/emoji_picker_dropdown_container';
|
||||||
import { me, maxReactions } from 'flavours/glitch/initial_state';
|
import { me, maxReactions } from 'flavours/glitch/initial_state';
|
||||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions';
|
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions';
|
||||||
import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links';
|
import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links';
|
||||||
@ -88,7 +89,7 @@ class ActionBar extends PureComponent {
|
|||||||
|
|
||||||
handleEmojiPick = data => {
|
handleEmojiPick = data => {
|
||||||
this.props.onReactionAdd(this.props.status.get('id'), data.native.replace(/:/g, ''), data.imageUrl);
|
this.props.onReactionAdd(this.props.status.get('id'), data.native.replace(/:/g, ''), data.imageUrl);
|
||||||
}
|
};
|
||||||
|
|
||||||
handleBookmarkClick = (e) => {
|
handleBookmarkClick = (e) => {
|
||||||
this.props.onBookmark(this.props.status, e);
|
this.props.onBookmark(this.props.status, e);
|
||||||
@ -149,7 +150,7 @@ class ActionBar extends PureComponent {
|
|||||||
navigator.clipboard.writeText(url);
|
navigator.clipboard.writeText(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleNoOp = () => {} // hack for reaction add button
|
handleNoOp = () => {}; // hack for reaction add button
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { status, intl } = this.props;
|
const { status, intl } = this.props;
|
||||||
|
@ -13,6 +13,7 @@ import AttachmentList from 'flavours/glitch/components/attachment_list';
|
|||||||
import { Avatar } from 'flavours/glitch/components/avatar';
|
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||||
import { DisplayName } from 'flavours/glitch/components/display_name';
|
import { DisplayName } from 'flavours/glitch/components/display_name';
|
||||||
import EditedTimestamp from 'flavours/glitch/components/edited_timestamp';
|
import EditedTimestamp from 'flavours/glitch/components/edited_timestamp';
|
||||||
|
import { getHashtagBarForStatus } from 'flavours/glitch/components/hashtag_bar';
|
||||||
import { Icon } from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import MediaGallery from 'flavours/glitch/components/media_gallery';
|
import MediaGallery from 'flavours/glitch/components/media_gallery';
|
||||||
import PictureInPicturePlaceholder from 'flavours/glitch/components/picture_in_picture_placeholder';
|
import PictureInPicturePlaceholder from 'flavours/glitch/components/picture_in_picture_placeholder';
|
||||||
@ -31,7 +32,6 @@ import Card from './card';
|
|||||||
class DetailedStatus extends ImmutablePureComponent {
|
class DetailedStatus extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
router: PropTypes.object,
|
|
||||||
identity: PropTypes.object,
|
identity: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -311,6 +311,9 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
|
||||||
|
contentMedia.push(hashtagBar);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={outerStyle}>
|
<div style={outerStyle}>
|
||||||
<div ref={this.setRef} className={classNames('detailed-status', `detailed-status-${status.get('visibility')}`, { compact })} data-status-by={status.getIn(['account', 'acct'])}>
|
<div ref={this.setRef} className={classNames('detailed-status', `detailed-status-${status.get('visibility')}`, { compact })} data-status-by={status.getIn(['account', 'acct'])}>
|
||||||
@ -333,6 +336,15 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||||||
tagLinks={settings.get('tag_misleading_links')}
|
tagLinks={settings.get('tag_misleading_links')}
|
||||||
rewriteMentions={settings.get('rewrite_mentions')}
|
rewriteMentions={settings.get('rewrite_mentions')}
|
||||||
disabled
|
disabled
|
||||||
|
{...statusContentProps}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<StatusReactions
|
||||||
|
statusId={status.get('id')}
|
||||||
|
reactions={status.get('reactions')}
|
||||||
|
addReaction={this.props.onReactionAdd}
|
||||||
|
removeReaction={this.props.onReactionRemove}
|
||||||
|
canReact={this.context.identity.signedIn}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<StatusReactions
|
<StatusReactions
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
* @property {boolean} limited_federation_mode
|
* @property {boolean} limited_federation_mode
|
||||||
* @property {string} locale
|
* @property {string} locale
|
||||||
* @property {string | null} mascot
|
* @property {string | null} mascot
|
||||||
|
* @property {number} max_reactions
|
||||||
* @property {string=} me
|
* @property {string=} me
|
||||||
* @property {string=} moved_to_account_id
|
* @property {string=} moved_to_account_id
|
||||||
* @property {string=} owner
|
* @property {string=} owner
|
||||||
|
@ -191,6 +191,7 @@
|
|||||||
"status.react": "React",
|
"status.react": "React",
|
||||||
"status.sensitive_toggle": "Click to view",
|
"status.sensitive_toggle": "Click to view",
|
||||||
"status.uncollapse": "Uncollapse",
|
"status.uncollapse": "Uncollapse",
|
||||||
|
"tooltips.reactions": "Reactions",
|
||||||
"web_app_crash.change_your_settings": "Change your {settings}",
|
"web_app_crash.change_your_settings": "Change your {settings}",
|
||||||
"web_app_crash.content": "You could try any of the following:",
|
"web_app_crash.content": "You could try any of the following:",
|
||||||
"web_app_crash.debug_info": "Debug information",
|
"web_app_crash.debug_info": "Debug information",
|
||||||
|
@ -62,6 +62,7 @@ const initialState = ImmutableMap({
|
|||||||
follow: true,
|
follow: true,
|
||||||
follow_request: false,
|
follow_request: false,
|
||||||
favourite: true,
|
favourite: true,
|
||||||
|
reaction: true,
|
||||||
reblog: true,
|
reblog: true,
|
||||||
reaction: true,
|
reaction: true,
|
||||||
mention: true,
|
mention: true,
|
||||||
@ -76,6 +77,7 @@ const initialState = ImmutableMap({
|
|||||||
follow: true,
|
follow: true,
|
||||||
follow_request: false,
|
follow_request: false,
|
||||||
favourite: true,
|
favourite: true,
|
||||||
|
reaction: true,
|
||||||
reblog: true,
|
reblog: true,
|
||||||
reaction: true,
|
reaction: true,
|
||||||
mention: true,
|
mention: true,
|
||||||
|
@ -18,6 +18,11 @@ import {
|
|||||||
REACTION_REMOVE_REQUEST,
|
REACTION_REMOVE_REQUEST,
|
||||||
UNBOOKMARK_REQUEST,
|
UNBOOKMARK_REQUEST,
|
||||||
UNBOOKMARK_FAIL,
|
UNBOOKMARK_FAIL,
|
||||||
|
REACTION_UPDATE,
|
||||||
|
REACTION_ADD_FAIL,
|
||||||
|
REACTION_REMOVE_FAIL,
|
||||||
|
REACTION_ADD_REQUEST,
|
||||||
|
REACTION_REMOVE_REQUEST,
|
||||||
} from 'flavours/glitch/actions/interactions';
|
} from 'flavours/glitch/actions/interactions';
|
||||||
import {
|
import {
|
||||||
STATUS_MUTE_SUCCESS,
|
STATUS_MUTE_SUCCESS,
|
||||||
@ -50,6 +55,43 @@ const deleteStatus = (state, id, references) => {
|
|||||||
return state.delete(id);
|
return state.delete(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateReaction = (state, id, name, updater) => state.update(
|
||||||
|
id,
|
||||||
|
status => status.update(
|
||||||
|
'reactions',
|
||||||
|
reactions => {
|
||||||
|
const index = reactions.findIndex(reaction => reaction.get('name') === name);
|
||||||
|
if (index > -1) {
|
||||||
|
return reactions.update(index, reaction => updater(reaction));
|
||||||
|
} else {
|
||||||
|
return reactions.push(updater(fromJS({ name, count: 0 })));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateReactionCount = (state, reaction) => updateReaction(state, reaction.status_id, reaction.name, x => x.set('count', reaction.count));
|
||||||
|
|
||||||
|
// The url parameter is only used when adding a new custom emoji reaction
|
||||||
|
// (one that wasn't in the reactions list before) because we don't have its
|
||||||
|
// URL yet. In all other cases, it's undefined.
|
||||||
|
const addReaction = (state, id, name, url) => updateReaction(
|
||||||
|
state,
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
x => x.set('me', true)
|
||||||
|
.update('count', n => n + 1)
|
||||||
|
.update('url', old => old ? old : url)
|
||||||
|
.update('static_url', old => old ? old : url),
|
||||||
|
);
|
||||||
|
|
||||||
|
const removeReaction = (state, id, name) => updateReaction(
|
||||||
|
state,
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
x => x.set('me', false).update('count', n => n - 1),
|
||||||
|
);
|
||||||
|
|
||||||
const statusTranslateSuccess = (state, id, translation) => {
|
const statusTranslateSuccess = (state, id, translation) => {
|
||||||
return state.withMutations(map => {
|
return state.withMutations(map => {
|
||||||
map.setIn([id, 'translation'], fromJS(normalizeStatusTranslation(translation, map.get(id))));
|
map.setIn([id, 'translation'], fromJS(normalizeStatusTranslation(translation, map.get(id))));
|
||||||
|
BIN
app/javascript/images/mailer/icon_add.png
Normal file
BIN
app/javascript/images/mailer/icon_add.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
@ -32,6 +32,7 @@ import { RelativeTimestamp } from './relative_timestamp';
|
|||||||
import StatusActionBar from './status_action_bar';
|
import StatusActionBar from './status_action_bar';
|
||||||
import StatusReactions from './status_reactions';
|
import StatusReactions from './status_reactions';
|
||||||
import StatusContent from './status_content';
|
import StatusContent from './status_content';
|
||||||
|
import StatusReactions from './status_reactions';
|
||||||
import { VisibilityIcon } from './visibility_icon';
|
import { VisibilityIcon } from './visibility_icon';
|
||||||
|
|
||||||
const domParser = new DOMParser();
|
const domParser = new DOMParser();
|
||||||
@ -80,7 +81,6 @@ const messages = defineMessages({
|
|||||||
class Status extends ImmutablePureComponent {
|
class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
router: PropTypes.object,
|
|
||||||
identity: PropTypes.object,
|
identity: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
|
||||||
import { ReactComponent as BookmarkIcon } from '@material-symbols/svg-600/outlined/bookmark-fill.svg';
|
import { ReactComponent as BookmarkIcon } from '@material-symbols/svg-600/outlined/bookmark-fill.svg';
|
||||||
import { ReactComponent as BookmarkBorderIcon } from '@material-symbols/svg-600/outlined/bookmark.svg';
|
import { ReactComponent as BookmarkBorderIcon } from '@material-symbols/svg-600/outlined/bookmark.svg';
|
||||||
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
|
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
|
||||||
@ -24,6 +25,7 @@ import EmojiPickerDropdown from '../features/compose/containers/emoji_picker_dro
|
|||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||||
|
|
||||||
import DropdownMenuContainer from '../containers/dropdown_menu_container';
|
import DropdownMenuContainer from '../containers/dropdown_menu_container';
|
||||||
|
import EmojiPickerDropdown from '../features/compose/containers/emoji_picker_dropdown_container';
|
||||||
import { me, maxReactions } from '../initial_state';
|
import { me, maxReactions } from '../initial_state';
|
||||||
|
|
||||||
import { IconButton } from './icon_button';
|
import { IconButton } from './icon_button';
|
||||||
@ -147,7 +149,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
|
|
||||||
handleEmojiPick = data => {
|
handleEmojiPick = data => {
|
||||||
this.props.onReactionAdd(this.props.status.get('id'), data.native.replace(/:/g, ''), data.imageUrl);
|
this.props.onReactionAdd(this.props.status.get('id'), data.native.replace(/:/g, ''), data.imageUrl);
|
||||||
}
|
};
|
||||||
|
|
||||||
handleReblogClick = e => {
|
handleReblogClick = e => {
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.context.identity;
|
||||||
@ -252,7 +254,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
this.props.onFilter();
|
this.props.onFilter();
|
||||||
};
|
};
|
||||||
|
|
||||||
handleNoOp = () => {} // hack for reaction add button
|
handleNoOp = () => {}; // hack for reaction add button
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { status, relationship, intl, withDismiss, withCounters, scrollKey } = this.props;
|
const { status, relationship, intl, withDismiss, withCounters, scrollKey } = this.props;
|
||||||
@ -396,6 +398,17 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const isReply = status.get('in_reply_to_account_id') === status.getIn(['account', 'id']);
|
const isReply = status.get('in_reply_to_account_id') === status.getIn(['account', 'id']);
|
||||||
|
const canReact = signedIn && status.get('reactions').filter(r => r.get('count') > 0 && r.get('me')).size < maxReactions;
|
||||||
|
const reactButton = (
|
||||||
|
<IconButton
|
||||||
|
className='status__action-bar-button'
|
||||||
|
onClick={this.handleNoOp} // EmojiPickerDropdown handles that
|
||||||
|
title={intl.formatMessage(messages.react)}
|
||||||
|
disabled={!canReact}
|
||||||
|
icon='plus'
|
||||||
|
iconComponent={AddIcon}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='status__action-bar'>
|
<div className='status__action-bar'>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
<<<<<<< HEAD
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
@ -10,6 +11,25 @@ import { unicodeMapping } from '../features/emoji/emoji_unicode_mapping_light';
|
|||||||
import { AnimatedNumber } from './animated_number';
|
import { AnimatedNumber } from './animated_number';
|
||||||
import { assetHost } from '../utils/config';
|
import { assetHost } from '../utils/config';
|
||||||
|
|
||||||
|
=======
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
|
import TransitionMotion from 'react-motion/lib/TransitionMotion';
|
||||||
|
import spring from 'react-motion/lib/spring';
|
||||||
|
|
||||||
|
import { unicodeMapping } from '../features/emoji/emoji_unicode_mapping_light';
|
||||||
|
import { autoPlayGif, reduceMotion } from '../initial_state';
|
||||||
|
import { assetHost } from '../utils/config';
|
||||||
|
|
||||||
|
import { AnimatedNumber } from './animated_number';
|
||||||
|
|
||||||
|
>>>>>>> pr2462
|
||||||
export default class StatusReactions extends ImmutablePureComponent {
|
export default class StatusReactions extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -9,6 +9,7 @@ import { withRouter } from 'react-router-dom';
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
|
||||||
import { ReactComponent as BookmarkIcon } from '@material-symbols/svg-600/outlined/bookmark-fill.svg';
|
import { ReactComponent as BookmarkIcon } from '@material-symbols/svg-600/outlined/bookmark-fill.svg';
|
||||||
import { ReactComponent as BookmarkBorderIcon } from '@material-symbols/svg-600/outlined/bookmark.svg';
|
import { ReactComponent as BookmarkBorderIcon } from '@material-symbols/svg-600/outlined/bookmark.svg';
|
||||||
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
|
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
|
||||||
@ -23,8 +24,13 @@ import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
|||||||
|
|
||||||
import { IconButton } from '../../../components/icon_button';
|
import { IconButton } from '../../../components/icon_button';
|
||||||
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
|
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
|
||||||
|
<<<<<<< HEAD
|
||||||
import EmojiPickerDropdown from '../../compose/containers/emoji_picker_dropdown_container';
|
import EmojiPickerDropdown from '../../compose/containers/emoji_picker_dropdown_container';
|
||||||
import { me, maxReactions } from '../../../initial_state';
|
import { me, maxReactions } from '../../../initial_state';
|
||||||
|
=======
|
||||||
|
import { me, maxReactions } from '../../../initial_state';
|
||||||
|
import EmojiPickerDropdown from '../../compose/containers/emoji_picker_dropdown_container';
|
||||||
|
>>>>>>> pr2462
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
||||||
@ -111,7 +117,11 @@ class ActionBar extends PureComponent {
|
|||||||
|
|
||||||
handleEmojiPick = data => {
|
handleEmojiPick = data => {
|
||||||
this.props.onReactionAdd(this.props.status.get('id'), data.native.replace(/:/g, ''));
|
this.props.onReactionAdd(this.props.status.get('id'), data.native.replace(/:/g, ''));
|
||||||
|
<<<<<<< HEAD
|
||||||
}
|
}
|
||||||
|
=======
|
||||||
|
};
|
||||||
|
>>>>>>> pr2462
|
||||||
|
|
||||||
handleBookmarkClick = (e) => {
|
handleBookmarkClick = (e) => {
|
||||||
this.props.onBookmark(this.props.status, e);
|
this.props.onBookmark(this.props.status, e);
|
||||||
@ -200,7 +210,11 @@ class ActionBar extends PureComponent {
|
|||||||
navigator.clipboard.writeText(url);
|
navigator.clipboard.writeText(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
handleNoOp = () => {} // hack for reaction add button
|
handleNoOp = () => {} // hack for reaction add button
|
||||||
|
=======
|
||||||
|
handleNoOp = () => {}; // hack for reaction add button
|
||||||
|
>>>>>>> pr2462
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { status, relationship, intl } = this.props;
|
const { status, relationship, intl } = this.props;
|
||||||
@ -295,6 +309,10 @@ class ActionBar extends PureComponent {
|
|||||||
title={intl.formatMessage(messages.react)}
|
title={intl.formatMessage(messages.react)}
|
||||||
disabled={!canReact}
|
disabled={!canReact}
|
||||||
icon='plus'
|
icon='plus'
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
iconComponent={AddIcon}
|
||||||
|
>>>>>>> pr2462
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ import Card from './card';
|
|||||||
class DetailedStatus extends ImmutablePureComponent {
|
class DetailedStatus extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
router: PropTypes.object,
|
|
||||||
identity: PropTypes.object,
|
identity: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -326,6 +325,14 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||||||
|
|
||||||
{expanded && hashtagBar}
|
{expanded && hashtagBar}
|
||||||
|
|
||||||
|
<StatusReactions
|
||||||
|
statusId={status.get('id')}
|
||||||
|
reactions={status.get('reactions')}
|
||||||
|
addReaction={this.props.onReactionAdd}
|
||||||
|
removeReaction={this.props.onReactionRemove}
|
||||||
|
canReact={this.context.identity.signedIn}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className='detailed-status__meta'>
|
<div className='detailed-status__meta'>
|
||||||
<a className='detailed-status__datetime' href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} target='_blank' rel='noopener noreferrer'>
|
<a className='detailed-status__datetime' href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} target='_blank' rel='noopener noreferrer'>
|
||||||
<FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
|
<FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
|
||||||
|
@ -431,6 +431,7 @@
|
|||||||
"notification.mention": "{name} mentioned you",
|
"notification.mention": "{name} mentioned you",
|
||||||
"notification.own_poll": "Your poll has ended",
|
"notification.own_poll": "Your poll has ended",
|
||||||
"notification.poll": "A poll you have voted in has ended",
|
"notification.poll": "A poll you have voted in has ended",
|
||||||
|
"notification.reaction": "{name} reacted to your post",
|
||||||
"notification.reblog": "{name} boosted your post",
|
"notification.reblog": "{name} boosted your post",
|
||||||
"notification.status": "{name} just posted",
|
"notification.status": "{name} just posted",
|
||||||
"notification.update": "{name} edited a post",
|
"notification.update": "{name} edited a post",
|
||||||
@ -449,6 +450,7 @@
|
|||||||
"notifications.column_settings.mention": "Mentions:",
|
"notifications.column_settings.mention": "Mentions:",
|
||||||
"notifications.column_settings.poll": "Poll results:",
|
"notifications.column_settings.poll": "Poll results:",
|
||||||
"notifications.column_settings.push": "Push notifications",
|
"notifications.column_settings.push": "Push notifications",
|
||||||
|
"notifications.column_settings.reaction": "Reactions:",
|
||||||
"notifications.column_settings.reblog": "Boosts:",
|
"notifications.column_settings.reblog": "Boosts:",
|
||||||
"notifications.column_settings.show": "Show in column",
|
"notifications.column_settings.show": "Show in column",
|
||||||
"notifications.column_settings.sound": "Play sound",
|
"notifications.column_settings.sound": "Play sound",
|
||||||
@ -651,6 +653,7 @@
|
|||||||
"status.pin": "Pin on profile",
|
"status.pin": "Pin on profile",
|
||||||
"status.pinned": "Pinned post",
|
"status.pinned": "Pinned post",
|
||||||
"status.read_more": "Read more",
|
"status.read_more": "Read more",
|
||||||
|
"status.react": "React",
|
||||||
"status.reblog": "Boost",
|
"status.reblog": "Boost",
|
||||||
"status.reblog_private": "Boost with original visibility",
|
"status.reblog_private": "Boost with original visibility",
|
||||||
"status.reblogged_by": "{name} boosted",
|
"status.reblogged_by": "{name} boosted",
|
||||||
@ -689,6 +692,7 @@
|
|||||||
"timeline_hint.resources.followers": "Followers",
|
"timeline_hint.resources.followers": "Followers",
|
||||||
"timeline_hint.resources.follows": "Follows",
|
"timeline_hint.resources.follows": "Follows",
|
||||||
"timeline_hint.resources.statuses": "Older posts",
|
"timeline_hint.resources.statuses": "Older posts",
|
||||||
|
"tooltips.reactions": "Reactions",
|
||||||
"trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {{days} days}}",
|
"trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {{days} days}}",
|
||||||
"trends.trending_now": "Trending now",
|
"trends.trending_now": "Trending now",
|
||||||
"tooltips.reactions": "Reactions",
|
"tooltips.reactions": "Reactions",
|
||||||
|
@ -57,6 +57,7 @@ const initialState = ImmutableMap({
|
|||||||
follow: true,
|
follow: true,
|
||||||
follow_request: false,
|
follow_request: false,
|
||||||
favourite: true,
|
favourite: true,
|
||||||
|
reaction: true,
|
||||||
reblog: true,
|
reblog: true,
|
||||||
reaction: true,
|
reaction: true,
|
||||||
mention: true,
|
mention: true,
|
||||||
@ -71,6 +72,7 @@ const initialState = ImmutableMap({
|
|||||||
follow: true,
|
follow: true,
|
||||||
follow_request: false,
|
follow_request: false,
|
||||||
favourite: true,
|
favourite: true,
|
||||||
|
reaction: true,
|
||||||
reblog: true,
|
reblog: true,
|
||||||
reaction: true,
|
reaction: true,
|
||||||
mention: true,
|
mention: true,
|
||||||
|
@ -20,6 +20,11 @@ import {
|
|||||||
REACTION_REMOVE_REQUEST,
|
REACTION_REMOVE_REQUEST,
|
||||||
UNBOOKMARK_REQUEST,
|
UNBOOKMARK_REQUEST,
|
||||||
UNBOOKMARK_FAIL,
|
UNBOOKMARK_FAIL,
|
||||||
|
REACTION_UPDATE,
|
||||||
|
REACTION_ADD_FAIL,
|
||||||
|
REACTION_REMOVE_FAIL,
|
||||||
|
REACTION_ADD_REQUEST,
|
||||||
|
REACTION_REMOVE_REQUEST,
|
||||||
} from '../actions/interactions';
|
} from '../actions/interactions';
|
||||||
import {
|
import {
|
||||||
STATUS_MUTE_SUCCESS,
|
STATUS_MUTE_SUCCESS,
|
||||||
@ -47,6 +52,43 @@ const deleteStatus = (state, id, references) => {
|
|||||||
return state.delete(id);
|
return state.delete(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateReaction = (state, id, name, updater) => state.update(
|
||||||
|
id,
|
||||||
|
status => status.update(
|
||||||
|
'reactions',
|
||||||
|
reactions => {
|
||||||
|
const index = reactions.findIndex(reaction => reaction.get('name') === name);
|
||||||
|
if (index > -1) {
|
||||||
|
return reactions.update(index, reaction => updater(reaction));
|
||||||
|
} else {
|
||||||
|
return reactions.push(updater(fromJS({ name, count: 0 })));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateReactionCount = (state, reaction) => updateReaction(state, reaction.status_id, reaction.name, x => x.set('count', reaction.count));
|
||||||
|
|
||||||
|
// The url parameter is only used when adding a new custom emoji reaction
|
||||||
|
// (one that wasn't in the reactions list before) because we don't have its
|
||||||
|
// URL yet. In all other cases, it's undefined.
|
||||||
|
const addReaction = (state, id, name, url) => updateReaction(
|
||||||
|
state,
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
x => x.set('me', true)
|
||||||
|
.update('count', n => n + 1)
|
||||||
|
.update('url', old => old ? old : url)
|
||||||
|
.update('static_url', old => old ? old : url),
|
||||||
|
);
|
||||||
|
|
||||||
|
const removeReaction = (state, id, name) => updateReaction(
|
||||||
|
state,
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
x => x.set('me', false).update('count', n => n - 1),
|
||||||
|
);
|
||||||
|
|
||||||
const statusTranslateSuccess = (state, id, translation) => {
|
const statusTranslateSuccess = (state, id, translation) => {
|
||||||
return state.withMutations(map => {
|
return state.withMutations(map => {
|
||||||
map.setIn([id, 'translation'], fromJS(normalizeStatusTranslation(translation, map.get(id))));
|
map.setIn([id, 'translation'], fromJS(normalizeStatusTranslation(translation, map.get(id))));
|
||||||
|
@ -6,8 +6,8 @@ class NotificationMailer < ApplicationMailer
|
|||||||
:routing
|
:routing
|
||||||
|
|
||||||
before_action :process_params
|
before_action :process_params
|
||||||
before_action :set_status, only: [:mention, :favourite, :reblog]
|
before_action :set_status, only: [:mention, :favourite, :reaction, :reblog]
|
||||||
before_action :set_account, only: [:follow, :favourite, :reblog, :follow_request]
|
before_action :set_account, only: [:follow, :favourite, :reaction, :reblog, :follow_request]
|
||||||
after_action :set_list_headers!
|
after_action :set_list_headers!
|
||||||
|
|
||||||
default to: -> { email_address_with_name(@user.email, @me.username) }
|
default to: -> { email_address_with_name(@user.email, @me.username) }
|
||||||
@ -38,6 +38,15 @@ class NotificationMailer < ApplicationMailer
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reaction
|
||||||
|
return unless @user.functional? && @status.present?
|
||||||
|
|
||||||
|
locale_for_account(@me) do
|
||||||
|
thread_by_conversation(@status.conversation)
|
||||||
|
mail subject: default_i18n_subject(name: @account.acct)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def reblog
|
def reblog
|
||||||
return unless @user.functional? && @status.present?
|
return unless @user.functional? && @status.present?
|
||||||
|
|
||||||
|
@ -22,6 +22,10 @@ class StatusReaction < ApplicationRecord
|
|||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
validates_with StatusReactionValidator
|
validates_with StatusReactionValidator
|
||||||
|
|
||||||
|
before_validation do
|
||||||
|
self.status = status.reblog if status&.reblog?
|
||||||
|
end
|
||||||
|
|
||||||
before_validation :set_custom_emoji
|
before_validation :set_custom_emoji
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -45,6 +45,7 @@ class UserSettings
|
|||||||
setting :follow, default: true
|
setting :follow, default: true
|
||||||
setting :reblog, default: false
|
setting :reblog, default: false
|
||||||
setting :favourite, default: false
|
setting :favourite, default: false
|
||||||
|
setting :reaction, default: false
|
||||||
setting :mention, default: true
|
setting :mention, default: true
|
||||||
setting :follow_request, default: true
|
setting :follow_request, default: true
|
||||||
setting :report, default: true
|
setting :report, default: true
|
||||||
|
45
app/views/notification_mailer/reaction.html.haml
Normal file
45
app/views/notification_mailer/reaction.html.haml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||||
|
%tbody
|
||||||
|
%tr
|
||||||
|
%td.email-body
|
||||||
|
.email-container
|
||||||
|
%table.content-section{ cellspacing: 0, cellpadding: 0 }
|
||||||
|
%tbody
|
||||||
|
%tr
|
||||||
|
%td.content-cell.hero
|
||||||
|
.email-row
|
||||||
|
.col-6
|
||||||
|
%table.column{ cellspacing: 0, cellpadding: 0 }
|
||||||
|
%tbody
|
||||||
|
%tr
|
||||||
|
%td.column-cell.text-center.padded
|
||||||
|
%table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }
|
||||||
|
%tbody
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
= image_tag full_pack_url('media/images/mailer/icon_add.png'), alt: ''
|
||||||
|
|
||||||
|
%h1= t 'notification_mailer.reaction.title'
|
||||||
|
%p.lead= t('notification_mailer.reaction.body', name: @account.pretty_acct)
|
||||||
|
|
||||||
|
= render 'status', status: @status, time_zone: @me.user_time_zone
|
||||||
|
|
||||||
|
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||||
|
%tbody
|
||||||
|
%tr
|
||||||
|
%td.email-body
|
||||||
|
.email-container
|
||||||
|
%table.content-section{ cellspacing: 0, cellpadding: 0 }
|
||||||
|
%tbody
|
||||||
|
%tr
|
||||||
|
%td.content-cell.content-start.border-top
|
||||||
|
%table.column{ cellspacing: 0, cellpadding: 0 }
|
||||||
|
%tbody
|
||||||
|
%tr
|
||||||
|
%td.column-cell.button-cell
|
||||||
|
%table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }
|
||||||
|
%tbody
|
||||||
|
%tr
|
||||||
|
%td.button-primary
|
||||||
|
= link_to web_url("@#{@status.account.pretty_acct}/#{@status.id}") do
|
||||||
|
%span= t 'application_mailer.view_status'
|
5
app/views/notification_mailer/reaction.text.erb
Normal file
5
app/views/notification_mailer/reaction.text.erb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<%= raw t('application_mailer.salutation', name: display_name(@me)) %>
|
||||||
|
|
||||||
|
<%= raw t('notification_mailer.reaction.body', name: @account.pretty_acct) %>
|
||||||
|
|
||||||
|
<%= render 'status', status: @status %>
|
@ -36,8 +36,6 @@
|
|||||||
= ff.input :'web.use_system_font', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_system_font_ui')
|
= ff.input :'web.use_system_font', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_system_font_ui')
|
||||||
= ff.input :'web.use_system_emoji_font', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_system_emoji_font'), glitch_only: true
|
= ff.input :'web.use_system_emoji_font', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_system_emoji_font'), glitch_only: true
|
||||||
|
|
||||||
%h4= t 'appearance.toot_layout'
|
|
||||||
|
|
||||||
.fields-group.fields-row__column.fields-row__column-6
|
.fields-group.fields-row__column.fields-row__column-6
|
||||||
= ff.input :'visible_reactions', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_visible_reactions'), input_html: { type: 'number', min: '0', data: { default: '6' } }, hint: false
|
= ff.input :'visible_reactions', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_visible_reactions'), input_html: { type: 'number', min: '0', data: { default: '6' } }, hint: false
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
= ff.input :'notification_emails.follow_request', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.follow_request')
|
= ff.input :'notification_emails.follow_request', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.follow_request')
|
||||||
= ff.input :'notification_emails.reblog', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.reblog')
|
= ff.input :'notification_emails.reblog', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.reblog')
|
||||||
= ff.input :'notification_emails.favourite', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.favourite')
|
= ff.input :'notification_emails.favourite', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.favourite')
|
||||||
|
= ff.input :'notification_emails.reaction', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.reaction')
|
||||||
= ff.input :'notification_emails.mention', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.mention')
|
= ff.input :'notification_emails.mention', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.mention')
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
|
@ -22,6 +22,7 @@ en:
|
|||||||
setting_system_emoji_font: Use system's default font for emojis (applies to Glitch flavour only)
|
setting_system_emoji_font: Use system's default font for emojis (applies to Glitch flavour only)
|
||||||
setting_visible_reactions: Number of visible emoji reactions
|
setting_visible_reactions: Number of visible emoji reactions
|
||||||
notification_emails:
|
notification_emails:
|
||||||
|
reaction: Someone reacted to your post
|
||||||
trending_link: New trending link requires review
|
trending_link: New trending link requires review
|
||||||
trending_status: New trending post requires review
|
trending_status: New trending post requires review
|
||||||
trending_tag: New trending tag requires review
|
trending_tag: New trending tag requires review
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class FixForeignKeysStatusReactions < ActiveRecord::Migration[6.1]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def change
|
||||||
|
# Fixes an oversight in a previous version of the CreateStatusReactions migration
|
||||||
|
remove_foreign_key :status_reactions, :accounts
|
||||||
|
add_foreign_key :status_reactions, :accounts, on_delete: :cascade, validate: false
|
||||||
|
validate_foreign_key :status_reactions, :accounts
|
||||||
|
remove_foreign_key :status_reactions, :statuses
|
||||||
|
add_foreign_key :status_reactions, :statuses, on_delete: :cascade, validate: false
|
||||||
|
validate_foreign_key :status_reactions, :statuses
|
||||||
|
remove_foreign_key :status_reactions, :custom_emojis
|
||||||
|
add_foreign_key :status_reactions, :custom_emojis, on_delete: :cascade, validate: false
|
||||||
|
validate_foreign_key :status_reactions, :custom_emojis
|
||||||
|
end
|
||||||
|
end
|
@ -947,7 +947,6 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_07_150100) do
|
|||||||
t.datetime "created_at", precision: 6, null: false
|
t.datetime "created_at", precision: 6, null: false
|
||||||
t.datetime "updated_at", precision: 6, null: false
|
t.datetime "updated_at", precision: 6, null: false
|
||||||
t.index ["account_id", "status_id", "name"], name: "index_status_reactions_on_account_id_and_status_id", unique: true
|
t.index ["account_id", "status_id", "name"], name: "index_status_reactions_on_account_id_and_status_id", unique: true
|
||||||
t.index ["account_id"], name: "index_status_reactions_on_account_id"
|
|
||||||
t.index ["custom_emoji_id"], name: "index_status_reactions_on_custom_emoji_id"
|
t.index ["custom_emoji_id"], name: "index_status_reactions_on_custom_emoji_id"
|
||||||
t.index ["status_id"], name: "index_status_reactions_on_status_id"
|
t.index ["status_id"], name: "index_status_reactions_on_status_id"
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user