Add phrase confirmation to domain block dialog
This commit is contained in:
parent
c297bf5471
commit
695f9a7d08
18 changed files with 137 additions and 29 deletions
|
@ -96,6 +96,7 @@ class Settings::PreferencesController < Settings::BaseController
|
|||
:setting_default_search_searchability,
|
||||
:setting_show_reload_button,
|
||||
:setting_default_column_width,
|
||||
:setting_confirm_domain_block,
|
||||
notification_emails: %i(follow follow_request reblog favourite emoji_reaction status_reference mention digest report pending_account trending_tag),
|
||||
interactions: %i(must_be_follower must_be_following must_be_following_dm must_be_dm_to_send_email must_be_following_reference)
|
||||
)
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { blockDomain, unblockDomain } from '../actions/domain_blocks';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { unblockDomain } from '../actions/domain_blocks';
|
||||
import Domain from '../components/domain';
|
||||
import { openModal } from '../actions/modal';
|
||||
|
||||
const messages = defineMessages({
|
||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Block entire domain' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const mapStateToProps = () => ({});
|
||||
|
@ -15,18 +8,10 @@ const makeMapStateToProps = () => {
|
|||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
onBlockDomain (domain) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
||||
onConfirm: () => dispatch(blockDomain(domain)),
|
||||
}));
|
||||
},
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onUnblockDomain (domain) {
|
||||
dispatch(unblockDomain(domain));
|
||||
},
|
||||
});
|
||||
|
||||
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Domain));
|
||||
export default connect(makeMapStateToProps, mapDispatchToProps)(Domain);
|
||||
|
|
|
@ -52,7 +52,7 @@ import { initReport } from '../actions/reports';
|
|||
import { openModal } from '../actions/modal';
|
||||
import { deployPictureInPicture } from '../actions/picture_in_picture';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { boostModal, deleteModal, unfollowModal, unsubscribeModal } from '../initial_state';
|
||||
import { boostModal, deleteModal, unfollowModal, unsubscribeModal, confirmDomainBlock } from '../initial_state';
|
||||
import { showAlertForError } from '../actions/alerts';
|
||||
|
||||
import { createSelector } from 'reselect';
|
||||
|
@ -68,6 +68,7 @@ const messages = defineMessages({
|
|||
quoteConfirm: { id: 'confirmations.quote.confirm', defaultMessage: 'Quote' },
|
||||
quoteMessage: { id: 'confirmations.quote.message', defaultMessage: 'Quoting now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
|
||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
||||
blockDomainPassphrase: { id: 'confirmations.domain_block.passphrase', defaultMessage: 'block' },
|
||||
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
||||
unsubscribeConfirm: { id: 'confirmations.unsubscribe.confirm', defaultMessage: 'Unsubscribe' },
|
||||
});
|
||||
|
@ -254,6 +255,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
||||
onConfirm: () => dispatch(blockDomain(domain)),
|
||||
passphrase: confirmDomainBlock && intl.formatMessage(messages.blockDomainPassphrase),
|
||||
destructive: true,
|
||||
}));
|
||||
},
|
||||
|
||||
|
|
|
@ -22,13 +22,14 @@ import { initReport } from '../../../actions/reports';
|
|||
import { openModal } from '../../../actions/modal';
|
||||
import { blockDomain, unblockDomain } from '../../../actions/domain_blocks';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { unfollowModal, unsubscribeModal } from '../../../initial_state';
|
||||
import { unfollowModal, unsubscribeModal, confirmDomainBlock } from '../../../initial_state';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
|
||||
const messages = defineMessages({
|
||||
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
||||
unsubscribeConfirm: { id: 'confirmations.unsubscribe.confirm', defaultMessage: 'Unsubscribe' },
|
||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
||||
blockDomainPassphrase: { id: 'confirmations.domain_block.passphrase', defaultMessage: 'block' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
|
@ -146,6 +147,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
||||
onConfirm: () => dispatch(blockDomain(domain)),
|
||||
passphrase: confirmDomainBlock && intl.formatMessage(messages.blockDomainPassphrase),
|
||||
destructive: true,
|
||||
}));
|
||||
},
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ import { openModal } from '../../actions/modal';
|
|||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { HotKeys } from 'react-hotkeys';
|
||||
import { boostModal, deleteModal, enableStatusReference } from '../../initial_state';
|
||||
import { boostModal, deleteModal, confirmDomainBlock, enableStatusReference } from '../../initial_state';
|
||||
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
|
||||
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
|
||||
import Icon from 'mastodon/components/icon';
|
||||
|
@ -82,6 +82,7 @@ const messages = defineMessages({
|
|||
quoteConfirm: { id: 'confirmations.quote.confirm', defaultMessage: 'Quote' },
|
||||
quoteMessage: { id: 'confirmations.quote.message', defaultMessage: 'Quoting now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
|
||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
||||
blockDomainPassphrase: { id: 'confirmations.domain_block.passphrase', defaultMessage: 'block' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
|
@ -430,6 +431,8 @@ class Status extends ImmutablePureComponent {
|
|||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||
confirm: this.props.intl.formatMessage(messages.blockDomainConfirm),
|
||||
onConfirm: () => this.props.dispatch(blockDomain(domain)),
|
||||
passphrase: confirmDomainBlock && this.props.intl.formatMessage(messages.blockDomainPassphrase),
|
||||
destructive: true,
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||
import Button from '../../../components/button';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export default @injectIntl
|
||||
class ConfirmationModal extends React.PureComponent {
|
||||
|
@ -14,6 +15,8 @@ class ConfirmationModal extends React.PureComponent {
|
|||
secondary: PropTypes.string,
|
||||
onSecondary: PropTypes.func,
|
||||
closeWhenConfirm: PropTypes.bool,
|
||||
destructive: PropTypes.bool,
|
||||
passphrase: PropTypes.string,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
@ -21,15 +24,30 @@ class ConfirmationModal extends React.PureComponent {
|
|||
closeWhenConfirm: true,
|
||||
};
|
||||
|
||||
state = {
|
||||
passphrase: '',
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.button.focus();
|
||||
if (this.props.passphrase) {
|
||||
this.passphraseInput.focus();
|
||||
} else {
|
||||
this.button.focus();
|
||||
}
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
if (this.props.closeWhenConfirm) {
|
||||
this.props.onClose();
|
||||
const { passphrase, closeWhenConfirm, onClose, onConfirm } = this.props;
|
||||
|
||||
if (passphrase && this.state.passphrase !== passphrase) {
|
||||
this.passphraseInput.focus();
|
||||
return;
|
||||
}
|
||||
this.props.onConfirm();
|
||||
|
||||
if (closeWhenConfirm) {
|
||||
onClose();
|
||||
}
|
||||
onConfirm();
|
||||
}
|
||||
|
||||
handleSecondary = () => {
|
||||
|
@ -41,12 +59,20 @@ class ConfirmationModal extends React.PureComponent {
|
|||
this.props.onClose();
|
||||
}
|
||||
|
||||
handleChange = (e) => {
|
||||
this.setState({ passphrase: e.target.value });
|
||||
}
|
||||
|
||||
setRef = (c) => {
|
||||
this.button = c;
|
||||
}
|
||||
|
||||
setPassphraseRef = (c) => {
|
||||
this.passphraseInput = c;
|
||||
}
|
||||
|
||||
render () {
|
||||
const { message, confirm, secondary } = this.props;
|
||||
const { message, confirm, secondary, destructive, passphrase } = this.props;
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal confirmation-modal'>
|
||||
|
@ -54,6 +80,15 @@ class ConfirmationModal extends React.PureComponent {
|
|||
{message}
|
||||
</div>
|
||||
|
||||
{passphrase && (
|
||||
<div className='confirmation-modal__passphrase'>
|
||||
<div className='passphrase__label'>
|
||||
<FormattedMessage id='confirmations.passphrase' defaultMessage='Please type "{passphrase}" to confirm' values={{ passphrase: <strong>{passphrase}</strong> }} />,
|
||||
</div>
|
||||
<input type='text' className={classNames('passphrase__input', { invalid: this.state.passphrase !== passphrase })} onChange={this.handleChange} ref={this.setPassphraseRef} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='confirmation-modal__action-bar'>
|
||||
<Button onClick={this.handleCancel} className='confirmation-modal__cancel-button'>
|
||||
<FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
|
||||
|
@ -61,7 +96,7 @@ class ConfirmationModal extends React.PureComponent {
|
|||
{secondary !== undefined && (
|
||||
<Button text={secondary} onClick={this.handleSecondary} className='confirmation-modal__secondary-button' />
|
||||
)}
|
||||
<Button text={confirm} onClick={this.handleClick} ref={this.setRef} />
|
||||
<Button text={confirm} className={classNames({ 'always-destructive': destructive })} onClick={this.handleClick} disabled={passphrase && this.state.passphrase !== passphrase} ref={this.setRef} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -31,6 +31,7 @@ export const showTrends = getMeta('trends');
|
|||
export const title = getMeta('title');
|
||||
export const cropImages = getMeta('crop_images');
|
||||
export const disableSwiping = getMeta('disable_swiping');
|
||||
export const confirmDomainBlock = getMeta('confirm_domain_block');
|
||||
export const show_follow_button_on_timeline = getMeta('show_follow_button_on_timeline');
|
||||
export const show_subscribe_button_on_timeline = getMeta('show_subscribe_button_on_timeline');
|
||||
export const show_followed_by = getMeta('show_followed_by');
|
||||
|
|
|
@ -185,11 +185,13 @@
|
|||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
||||
"confirmations.domain_block.confirm": "Block entire domain",
|
||||
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
|
||||
"confirmations.domain_block.passphrase": "block",
|
||||
"confirmations.logout.confirm": "Log out",
|
||||
"confirmations.logout.message": "Are you sure you want to log out?",
|
||||
"confirmations.mute.confirm": "Mute",
|
||||
"confirmations.mute.explanation": "This will hide posts from them and posts mentioning them, but it will still allow them to see your posts and follow you.",
|
||||
"confirmations.mute.message": "Are you sure you want to mute {name}?",
|
||||
"confirmations.passphrase": "Please type \"{passphrase}\" to confirm",
|
||||
"confirmations.post_reference.confirm": "Post",
|
||||
"confirmations.post_reference.message": "It contains references, do you want to post it?",
|
||||
"confirmations.quote.confirm": "Quote",
|
||||
|
|
|
@ -185,11 +185,13 @@
|
|||
"confirmations.delete_list.message": "本当にこのリストを完全に削除しますか?",
|
||||
"confirmations.domain_block.confirm": "ドメイン全体をブロック",
|
||||
"confirmations.domain_block.message": "本当に{domain}全体を非表示にしますか? 多くの場合は個別にブロックやミュートするだけで充分であり、また好ましいです。公開タイムラインにそのドメインのコンテンツが表示されなくなり、通知も届かなくなります。そのドメインのフォロワーはアンフォローされます。",
|
||||
"confirmations.domain_block.passphrase": "ブロック",
|
||||
"confirmations.logout.confirm": "ログアウト",
|
||||
"confirmations.logout.message": "本当にログアウトしますか?",
|
||||
"confirmations.mute.confirm": "ミュート",
|
||||
"confirmations.mute.explanation": "これにより相手の投稿と返信は見えなくなりますが、相手はあなたをフォローし続け投稿を見ることができます。",
|
||||
"confirmations.mute.message": "本当に{name}さんをミュートしますか?",
|
||||
"confirmations.passphrase": "確認のため \"{passphrase}\" と入力してください",
|
||||
"confirmations.post_reference.confirm": "投稿",
|
||||
"confirmations.post_reference.message": "参照を含んでいますが、投稿しますか?",
|
||||
"confirmations.quote.confirm": "引用",
|
||||
|
|
|
@ -382,6 +382,14 @@ html {
|
|||
border: 1px solid lighten($ui-base-color, 8%);
|
||||
}
|
||||
|
||||
.confirmation-modal__passphrase .passphrase__input {
|
||||
border: 1px solid lighten($ui-base-color, 8%);
|
||||
|
||||
&.invalid {
|
||||
background-color: darken($error-value-color, 35%);
|
||||
}
|
||||
}
|
||||
|
||||
.reactions-bar__item {
|
||||
&:hover:enabled,
|
||||
&:focus:enabled,
|
||||
|
|
|
@ -84,6 +84,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.always-destructive {
|
||||
background-color: $error-red;
|
||||
|
||||
&:disabled,
|
||||
&.disabled {
|
||||
background-color: $ui-primary-color;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled,
|
||||
&.disabled {
|
||||
background-color: $ui-primary-color;
|
||||
|
@ -5747,6 +5757,51 @@ a.status-card.compact:hover {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.confirmation-modal__passphrase {
|
||||
text-align: center;
|
||||
padding: 0 30px 30px;
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
|
||||
.passphrase__label {
|
||||
flex: 1 1 auto;
|
||||
|
||||
strong {
|
||||
font-weight: 500;
|
||||
|
||||
@each $lang in $cjk-langs {
|
||||
&:lang(#{$lang}) {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.passphrase__input {
|
||||
flex: 1 1 auto;
|
||||
min-width: 50%;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
margin: 0;
|
||||
color: $inverted-text-color;
|
||||
background: $simple-background-color;
|
||||
font-family: inherit;
|
||||
font-size: 16px;
|
||||
resize: vertical;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
border-radius: 4px;
|
||||
|
||||
&.invalid {
|
||||
background-color: lighten($error-value-color, 35%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block-modal,
|
||||
.mute-modal {
|
||||
&__explanation {
|
||||
|
|
|
@ -57,6 +57,7 @@ class UserSettingsDecorator
|
|||
user.settings['use_pending_items'] = use_pending_items_preference if change?('setting_use_pending_items')
|
||||
user.settings['trends'] = trends_preference if change?('setting_trends')
|
||||
user.settings['crop_images'] = crop_images_preference if change?('setting_crop_images')
|
||||
user.settings['confirm_domain_block'] = confirm_domain_block_preference if change?('setting_confirm_domain_block')
|
||||
user.settings['show_follow_button_on_timeline'] = show_follow_button_on_timeline_preference if change?('setting_show_follow_button_on_timeline')
|
||||
user.settings['show_subscribe_button_on_timeline'] = show_subscribe_button_on_timeline_preference if change?('setting_show_subscribe_button_on_timeline')
|
||||
user.settings['show_followed_by'] = show_followed_by_preference if change?('setting_show_followed_by')
|
||||
|
@ -90,7 +91,7 @@ class UserSettingsDecorator
|
|||
user.settings['default_search_searchability'] = default_search_searchability_preference if change?('setting_default_search_searchability')
|
||||
user.settings['show_reload_button'] = show_reload_button_preference if change?('setting_show_reload_button')
|
||||
user.settings['default_column_width'] = default_column_width_preference if change?('setting_default_column_width')
|
||||
end
|
||||
end
|
||||
|
||||
def merged_notification_emails
|
||||
user.settings['notification_emails'].merge coerced_settings('notification_emails').to_h
|
||||
|
@ -204,6 +205,10 @@ end
|
|||
boolean_cast_setting 'setting_crop_images'
|
||||
end
|
||||
|
||||
def confirm_domain_block_preference
|
||||
boolean_cast_setting 'setting_confirm_domain_block'
|
||||
end
|
||||
|
||||
def show_follow_button_on_timeline_preference
|
||||
boolean_cast_setting 'setting_show_follow_button_on_timeline'
|
||||
end
|
||||
|
|
|
@ -125,7 +125,7 @@ class User < ApplicationRecord
|
|||
:reduce_motion, :system_font_ui, :noindex, :theme, :display_media, :hide_network,
|
||||
:expand_spoilers, :default_language, :aggregate_reblogs, :show_application,
|
||||
:advanced_layout, :use_blurhash, :use_pending_items, :trends, :crop_images,
|
||||
:disable_swiping,
|
||||
:disable_swiping, :confirm_domain_block,
|
||||
:show_follow_button_on_timeline, :show_subscribe_button_on_timeline, :show_target,
|
||||
:show_follow_button_on_timeline, :show_subscribe_button_on_timeline, :show_followed_by, :show_target,
|
||||
:follow_button_to_list_adder, :show_navigation_panel, :show_quote_button, :show_bookmark_button,
|
||||
|
|
|
@ -42,6 +42,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||
store[:is_staff] = object.current_account.user.staff?
|
||||
store[:trends] = Setting.trends && object.current_account.user.setting_trends
|
||||
store[:crop_images] = object.current_account.user.setting_crop_images
|
||||
store[:confirm_domain_block] = object.current_account.user.setting_confirm_domain_block
|
||||
store[:show_follow_button_on_timeline] = object.current_account.user.setting_show_follow_button_on_timeline
|
||||
store[:show_subscribe_button_on_timeline] = object.current_account.user.setting_show_subscribe_button_on_timeline
|
||||
store[:show_followed_by] = object.current_account.user.setting_show_followed_by
|
||||
|
|
|
@ -98,6 +98,7 @@
|
|||
= f.input :setting_unsubscribe_modal, as: :boolean, wrapper: :with_label, fedibird_features: true
|
||||
= f.input :setting_boost_modal, as: :boolean, wrapper: :with_label
|
||||
= f.input :setting_delete_modal, as: :boolean, wrapper: :with_label
|
||||
= f.input :setting_confirm_domain_block, as: :boolean, wrapper: :with_label
|
||||
= f.input :setting_post_reference_modal, as: :boolean, wrapper: :with_label, fedibird_features: true
|
||||
= f.input :setting_add_reference_modal, as: :boolean, wrapper: :with_label, fedibird_features: true
|
||||
= f.input :setting_unselect_reference_modal, as: :boolean, wrapper: :with_label, fedibird_features: true
|
||||
|
|
|
@ -220,6 +220,7 @@ en:
|
|||
setting_auto_play_gif: Auto-play animated GIFs
|
||||
setting_boost_modal: Show confirmation dialog before boosting
|
||||
setting_compact_reaction: Compact display of reaction
|
||||
setting_confirm_domain_block: Require domain input for domain block
|
||||
setting_confirm_follow_from_bot: Require follow requests from bot
|
||||
setting_content_emoji_reaction_size: Emoji reaction size
|
||||
setting_content_font_size: Content font size
|
||||
|
|
|
@ -220,6 +220,7 @@ ja:
|
|||
setting_auto_play_gif: アニメーションGIFを自動再生する
|
||||
setting_boost_modal: ブーストする前に確認ダイアログを表示する
|
||||
setting_compact_reaction: リアクションをコンパクトに表示
|
||||
setting_confirm_domain_block: ドメインブロックにドメイン入力を要求する
|
||||
setting_confirm_follow_from_bot: Bot承認制アカウントにする
|
||||
setting_content_emoji_reaction_size: 投稿の絵文字リアクションのサイズ
|
||||
setting_content_font_size: 投稿のフォントサイズ
|
||||
|
|
|
@ -42,6 +42,7 @@ defaults: &defaults
|
|||
trends: true
|
||||
trendable_by_default: false
|
||||
crop_images: true
|
||||
confirm_domain_block: true
|
||||
show_follow_button_on_timeline: false
|
||||
show_subscribe_button_on_timeline: false
|
||||
show_followed_by: false
|
||||
|
|
Loading…
Reference in a new issue