Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - app/models/user.rb - app/serializers/initial_state_serializer.rb - app/views/admin/dashboard/index.html.haml - config/locales/simple_form.en.yml
This commit is contained in:
@ -28,10 +28,13 @@ module Admin
|
||||
@pam_enabled = ENV['PAM_ENABLED'] == 'true'
|
||||
@hidden_service = ENV['ALLOW_ACCESS_TO_HIDDEN_SERVICE'] == 'true'
|
||||
@trending_hashtags = TrendingTags.get(10, filtered: false)
|
||||
@authorized_fetch = authorized_fetch_mode?
|
||||
@whitelist_enabled = whitelist_mode?
|
||||
@profile_directory = Setting.profile_directory
|
||||
@timeline_preview = Setting.timeline_preview
|
||||
@keybase_integration = Setting.enable_keybase
|
||||
@spam_check_enabled = Setting.spam_check_enabled
|
||||
@trends_enabled = Setting.trends
|
||||
end
|
||||
|
||||
private
|
||||
@ -41,7 +44,13 @@ module Admin
|
||||
end
|
||||
|
||||
def redis_info
|
||||
@redis_info ||= Redis.current.info
|
||||
@redis_info ||= begin
|
||||
if Redis.current.is_a?(Redis::Namespace)
|
||||
Redis.current.redis.info
|
||||
else
|
||||
Redis.current.info
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -17,7 +17,7 @@ module Admin
|
||||
authorize @tag, :update?
|
||||
|
||||
if @tag.update(tag_params.merge(reviewed_at: Time.now.utc))
|
||||
redirect_to admin_tag_path(@tag.id)
|
||||
redirect_to admin_tag_path(@tag.id), notice: I18n.t('admin.tags.updated_msg')
|
||||
else
|
||||
render :show
|
||||
end
|
||||
|
@ -30,7 +30,7 @@ class DirectoriesController < ApplicationController
|
||||
end
|
||||
|
||||
def set_tag
|
||||
@tag = Tag.discoverable.find_by!(name: params[:id].downcase)
|
||||
@tag = Tag.discoverable.find_normalized!(params[:id])
|
||||
end
|
||||
|
||||
def set_tags
|
||||
|
@ -58,6 +58,7 @@ class Settings::PreferencesController < Settings::BaseController
|
||||
:setting_default_content_type,
|
||||
:setting_use_blurhash,
|
||||
:setting_use_pending_items,
|
||||
:setting_trends,
|
||||
notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag),
|
||||
interactions: %i(must_be_follower must_be_following must_be_following_dm)
|
||||
)
|
||||
|
@ -48,7 +48,7 @@ class TagsController < ApplicationController
|
||||
private
|
||||
|
||||
def set_tag
|
||||
@tag = Tag.find_normalized!(params[:id])
|
||||
@tag = Tag.usable.find_normalized!(params[:id])
|
||||
end
|
||||
|
||||
def set_body_classes
|
||||
|
32
app/javascript/mastodon/actions/trends.js
Normal file
32
app/javascript/mastodon/actions/trends.js
Normal file
@ -0,0 +1,32 @@
|
||||
import api from '../api';
|
||||
|
||||
export const TRENDS_FETCH_REQUEST = 'TRENDS_FETCH_REQUEST';
|
||||
export const TRENDS_FETCH_SUCCESS = 'TRENDS_FETCH_SUCCESS';
|
||||
export const TRENDS_FETCH_FAIL = 'TRENDS_FETCH_FAIL';
|
||||
|
||||
export const fetchTrends = () => (dispatch, getState) => {
|
||||
dispatch(fetchTrendsRequest());
|
||||
|
||||
api(getState)
|
||||
.get('/api/v1/trends')
|
||||
.then(({ data }) => dispatch(fetchTrendsSuccess(data)))
|
||||
.catch(err => dispatch(fetchTrendsFail(err)));
|
||||
};
|
||||
|
||||
export const fetchTrendsRequest = () => ({
|
||||
type: TRENDS_FETCH_REQUEST,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const fetchTrendsSuccess = trends => ({
|
||||
type: TRENDS_FETCH_SUCCESS,
|
||||
trends,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const fetchTrendsFail = error => ({
|
||||
type: TRENDS_FETCH_FAIL,
|
||||
error,
|
||||
skipLoading: true,
|
||||
skipAlert: true,
|
||||
});
|
@ -112,7 +112,7 @@ export default class StatusContent extends React.PureComponent {
|
||||
}
|
||||
|
||||
onHashtagClick = (hashtag, e) => {
|
||||
hashtag = hashtag.replace(/^#/, '').toLowerCase();
|
||||
hashtag = hashtag.replace(/^#/, '');
|
||||
|
||||
if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
|
@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import Hashtag from 'mastodon/components/hashtag';
|
||||
|
||||
export default class Trends extends ImmutablePureComponent {
|
||||
|
||||
static defaultProps = {
|
||||
loading: false,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
trends: ImmutablePropTypes.list,
|
||||
fetchTrends: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
this.props.fetchTrends();
|
||||
this.refreshInterval = setInterval(() => this.props.fetchTrends(), 36000);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (this.refreshInterval) {
|
||||
clearInterval(this.refreshInterval);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { trends } = this.props;
|
||||
|
||||
if (!trends || trends.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='getting-started__trends'>
|
||||
{trends.take(3).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { fetchTrends } from '../../../actions/trends';
|
||||
import Trends from '../components/trends';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
trends: state.getIn(['trends', 'items']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
fetchTrends: () => dispatch(fetchTrends()),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Trends);
|
@ -7,12 +7,13 @@ import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { me, profile_directory } from '../../initial_state';
|
||||
import { me, profile_directory, showTrends } from '../../initial_state';
|
||||
import { fetchFollowRequests } from 'mastodon/actions/accounts';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import NavigationBar from '../compose/components/navigation_bar';
|
||||
import Icon from 'mastodon/components/icon';
|
||||
import LinkFooter from 'mastodon/features/ui/components/link_footer';
|
||||
import TrendsContainer from './containers/trends_container';
|
||||
|
||||
const messages = defineMessages({
|
||||
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
|
||||
@ -168,6 +169,8 @@ class GettingStarted extends ImmutablePureComponent {
|
||||
|
||||
<LinkFooter withHotkeys={multiColumn} />
|
||||
</div>
|
||||
|
||||
{multiColumn && showTrends && <TrendsContainer />}
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ import React from 'react';
|
||||
import { NavLink, withRouter } from 'react-router-dom';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import Icon from 'mastodon/components/icon';
|
||||
import { profile_directory } from 'mastodon/initial_state';
|
||||
import { profile_directory, showTrends } from 'mastodon/initial_state';
|
||||
import NotificationsCounterIcon from './notifications_counter_icon';
|
||||
import FollowRequestsNavLink from './follow_requests_nav_link';
|
||||
import ListPanel from './list_panel';
|
||||
import TrendsContainer from 'mastodon/features/getting_started/containers/trends_container';
|
||||
|
||||
const NavigationPanel = () => (
|
||||
<div className='navigation-panel'>
|
||||
@ -25,6 +26,9 @@ const NavigationPanel = () => (
|
||||
<a className='column-link column-link--transparent' href='/settings/preferences'><Icon className='column-link__icon' id='cog' fixedWidth /><FormattedMessage id='navigation_bar.preferences' defaultMessage='Preferences' /></a>
|
||||
<a className='column-link column-link--transparent' href='/relationships'><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='navigation_bar.follows_and_followers' defaultMessage='Follows and followers' /></a>
|
||||
{!!profile_directory && <a className='column-link column-link--transparent' href='/explore'><Icon className='column-link__icon' id='address-book-o' fixedWidth /><FormattedMessage id='navigation_bar.profile_directory' defaultMessage='Profile directory' /></a>}
|
||||
|
||||
{showTrends && <div className='flex-spacer' />}
|
||||
{showTrends && <TrendsContainer />}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -23,5 +23,6 @@ export const isStaff = getMeta('is_staff');
|
||||
export const forceSingleColumn = !getMeta('advanced_layout');
|
||||
export const useBlurhash = getMeta('use_blurhash');
|
||||
export const usePendingItems = getMeta('use_pending_items');
|
||||
export const showTrends = getMeta('trends');
|
||||
|
||||
export default initialState;
|
||||
|
@ -31,6 +31,7 @@ import conversations from './conversations';
|
||||
import suggestions from './suggestions';
|
||||
import polls from './polls';
|
||||
import identity_proofs from './identity_proofs';
|
||||
import trends from './trends';
|
||||
|
||||
const reducers = {
|
||||
dropdown_menu,
|
||||
@ -65,6 +66,7 @@ const reducers = {
|
||||
conversations,
|
||||
suggestions,
|
||||
polls,
|
||||
trends,
|
||||
};
|
||||
|
||||
export default combineReducers(reducers);
|
||||
|
@ -12,6 +12,10 @@ const initialState = ImmutableMap({
|
||||
|
||||
skinTone: 1,
|
||||
|
||||
trends: ImmutableMap({
|
||||
show: true,
|
||||
}),
|
||||
|
||||
home: ImmutableMap({
|
||||
shows: ImmutableMap({
|
||||
reblog: true,
|
||||
|
23
app/javascript/mastodon/reducers/trends.js
Normal file
23
app/javascript/mastodon/reducers/trends.js
Normal file
@ -0,0 +1,23 @@
|
||||
import { TRENDS_FETCH_REQUEST, TRENDS_FETCH_SUCCESS, TRENDS_FETCH_FAIL } from '../actions/trends';
|
||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
items: ImmutableList(),
|
||||
isLoading: false,
|
||||
});
|
||||
|
||||
export default function trendsReducer(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case TRENDS_FETCH_REQUEST:
|
||||
return state.set('isLoading', true);
|
||||
case TRENDS_FETCH_SUCCESS:
|
||||
return state.withMutations(map => {
|
||||
map.set('items', fromJS(action.trends));
|
||||
map.set('isLoading', false);
|
||||
});
|
||||
case TRENDS_FETCH_FAIL:
|
||||
return state.set('isLoading', false);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
@ -2212,7 +2212,6 @@ a.account__display-name {
|
||||
}
|
||||
|
||||
.getting-started__wrapper,
|
||||
.getting-started__trends,
|
||||
.search {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
@ -2319,13 +2318,24 @@ a.account__display-name {
|
||||
margin-bottom: 10px;
|
||||
height: calc(100% - 20px);
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
& > a {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
hr {
|
||||
flex: 0 0 auto;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
border-top: 1px solid lighten($ui-base-color, 4%);
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.flex-spacer {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer__pager {
|
||||
@ -2717,8 +2727,10 @@ a.account__display-name {
|
||||
}
|
||||
|
||||
&__trends {
|
||||
background: $ui-base-color;
|
||||
flex: 0 1 auto;
|
||||
opacity: 1;
|
||||
animation: fade 150ms linear;
|
||||
margin-top: 10px;
|
||||
|
||||
@media screen and (max-height: 810px) {
|
||||
.trends__item:nth-child(3) {
|
||||
@ -2735,11 +2747,15 @@ a.account__display-name {
|
||||
@media screen and (max-height: 670px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__scrollable {
|
||||
max-height: 100%;
|
||||
overflow-y: auto;
|
||||
.trends__item {
|
||||
border-bottom: 0;
|
||||
padding: 10px;
|
||||
|
||||
&__current {
|
||||
color: $darker-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5968,7 +5984,8 @@ noscript {
|
||||
font-size: 24px;
|
||||
line-height: 36px;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
text-align: right;
|
||||
padding-right: 15px;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
@ -5976,7 +5993,12 @@ noscript {
|
||||
flex: 0 0 auto;
|
||||
width: 50px;
|
||||
|
||||
path {
|
||||
path:first-child {
|
||||
fill: rgba($highlight-text-color, 0.25) !important;
|
||||
fill-opacity: 1 !important;
|
||||
}
|
||||
|
||||
path:last-child {
|
||||
stroke: lighten($highlight-text-color, 6%) !important;
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +324,8 @@
|
||||
&.active h4 {
|
||||
&,
|
||||
.fa,
|
||||
small {
|
||||
small,
|
||||
.trends__item__current {
|
||||
color: $primary-text-color;
|
||||
}
|
||||
}
|
||||
@ -337,6 +338,10 @@
|
||||
&.active .avatar-stack .account__avatar {
|
||||
border-color: $ui-highlight-color;
|
||||
}
|
||||
|
||||
.trends__item__current {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,7 +380,7 @@ class Formatter
|
||||
end
|
||||
|
||||
def hashtag_html(tag)
|
||||
"<a href=\"#{encode(tag_url(tag.downcase))}\" class=\"mention hashtag\" rel=\"tag\">#<span>#{encode(tag)}</span></a>"
|
||||
"<a href=\"#{encode(tag_url(tag))}\" class=\"mention hashtag\" rel=\"tag\">#<span>#{encode(tag)}</span></a>"
|
||||
end
|
||||
|
||||
def mention_html(account)
|
||||
|
@ -40,6 +40,7 @@ class UserSettingsDecorator
|
||||
user.settings['default_content_type']= default_content_type_preference if change?('setting_default_content_type')
|
||||
user.settings['use_blurhash'] = use_blurhash_preference if change?('setting_use_blurhash')
|
||||
user.settings['use_pending_items'] = use_pending_items_preference if change?('setting_use_pending_items')
|
||||
user.settings['trends'] = trends_preference if change?('setting_trends')
|
||||
end
|
||||
|
||||
def merged_notification_emails
|
||||
@ -142,6 +143,10 @@ class UserSettingsDecorator
|
||||
boolean_cast_setting 'setting_use_pending_items'
|
||||
end
|
||||
|
||||
def trends_preference
|
||||
boolean_cast_setting 'setting_trends'
|
||||
end
|
||||
|
||||
def boolean_cast_setting(key)
|
||||
ActiveModel::Type::Boolean.new.cast(settings[key])
|
||||
end
|
||||
|
@ -231,17 +231,7 @@ class Account < ApplicationRecord
|
||||
end
|
||||
|
||||
def tags_as_strings=(tag_names)
|
||||
tag_names.map! { |name| name.mb_chars.downcase.to_s }
|
||||
tag_names.uniq!
|
||||
|
||||
# Existing hashtags
|
||||
hashtags_map = Tag.where(name: tag_names).each_with_object({}) { |tag, h| h[tag.name] = tag }
|
||||
|
||||
# Initialize not yet existing hashtags
|
||||
tag_names.each do |name|
|
||||
next if hashtags_map.key?(name)
|
||||
hashtags_map[name] = Tag.new(name: name)
|
||||
end
|
||||
hashtags_map = Tag.find_or_create_by_names(tag_names).each_with_object({}) { |tag, h| h[tag.name] = tag }
|
||||
|
||||
# Remove hashtags that are to be deleted
|
||||
tags.each do |tag|
|
||||
|
@ -23,7 +23,7 @@ class FeaturedTag < ApplicationRecord
|
||||
validate :validate_featured_tags_limit, on: :create
|
||||
|
||||
def name=(str)
|
||||
self.tag = Tag.find_or_initialize_by(name: str.strip.delete('#').mb_chars.downcase.to_s)
|
||||
self.tag = Tag.find_or_create_by_names(str.strip)&.first
|
||||
end
|
||||
|
||||
def increment(timestamp)
|
||||
|
@ -35,6 +35,7 @@ class Form::AdminSettings
|
||||
show_reblogs_in_public_timelines
|
||||
show_replies_in_public_timelines
|
||||
spam_check_enabled
|
||||
trends
|
||||
).freeze
|
||||
|
||||
BOOLEAN_KEYS = %i(
|
||||
@ -51,6 +52,7 @@ class Form::AdminSettings
|
||||
show_reblogs_in_public_timelines
|
||||
show_replies_in_public_timelines
|
||||
spam_check_enabled
|
||||
trends
|
||||
).freeze
|
||||
|
||||
UPLOAD_KEYS = %i(
|
||||
|
@ -31,7 +31,8 @@ class Tag < ApplicationRecord
|
||||
|
||||
scope :reviewed, -> { where.not(reviewed_at: nil) }
|
||||
scope :pending_review, -> { where(reviewed_at: nil).where.not(requested_review_at: nil) }
|
||||
scope :discoverable, -> { where.not(listable: false).joins(:account_tag_stat).where(AccountTagStat.arel_table[:accounts_count].gt(0)).order(Arel.sql('account_tag_stats.accounts_count desc')) }
|
||||
scope :usable, -> { where(usable: [true, nil]) }
|
||||
scope :discoverable, -> { where(listable: [true, nil]).joins(:account_tag_stat).where(AccountTagStat.arel_table[:accounts_count].gt(0)).order(Arel.sql('account_tag_stats.accounts_count desc')) }
|
||||
scope :most_used, ->(account) { joins(:statuses).where(statuses: { account: account }).group(:id).order(Arel.sql('count(*) desc')) }
|
||||
|
||||
delegate :accounts_count,
|
||||
|
@ -66,6 +66,10 @@ class TrendingTags
|
||||
end
|
||||
|
||||
def request_review!(tag)
|
||||
return unless Setting.trends
|
||||
|
||||
tag.touch(:requested_review_at)
|
||||
|
||||
User.staff.includes(:account).find_each { |u| AdminMailer.new_trending_tag(u.account, tag).deliver_later! if u.allows_trending_tag_emails? }
|
||||
end
|
||||
end
|
||||
|
@ -107,7 +107,9 @@ class User < ApplicationRecord
|
||||
delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :favourite_modal, :delete_modal,
|
||||
:reduce_motion, :system_font_ui, :noindex, :flavour, :skin, :display_media, :hide_network, :hide_followers_count,
|
||||
:expand_spoilers, :default_language, :aggregate_reblogs, :show_application,
|
||||
:advanced_layout, :default_content_type, :use_blurhash, :use_pending_items, :use_pending_items, to: :settings, prefix: :setting, allow_nil: false
|
||||
:advanced_layout, :use_blurhash, :use_pending_items, :trends,
|
||||
:default_content_type,
|
||||
to: :settings, prefix: :setting, allow_nil: false
|
||||
|
||||
attr_reader :invite_code
|
||||
attr_writer :external
|
||||
|
@ -34,6 +34,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
||||
invites_enabled: Setting.min_invite_role == 'user',
|
||||
mascot: instance_presenter.mascot&.file&.url,
|
||||
profile_directory: Setting.profile_directory,
|
||||
trends: Setting.trends,
|
||||
}
|
||||
|
||||
if object.current_account
|
||||
@ -50,6 +51,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
||||
store[:use_blurhash] = object.current_account.user.setting_use_blurhash
|
||||
store[:use_pending_items] = object.current_account.user.setting_use_pending_items
|
||||
store[:is_staff] = object.current_account.user.staff?
|
||||
store[:trends] = Setting.trends && object.current_account.user.setting_trends
|
||||
store[:default_content_type] = object.current_account.user.setting_default_content_type
|
||||
end
|
||||
|
||||
|
@ -81,8 +81,8 @@ class BatchedRemoveStatusService < BaseService
|
||||
end
|
||||
|
||||
@tags[status.id].each do |hashtag|
|
||||
redis.publish("timeline:hashtag:#{hashtag}", payload)
|
||||
redis.publish("timeline:hashtag:#{hashtag}:local", payload) if status.local?
|
||||
redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}", payload)
|
||||
redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}:local", payload) if status.local?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -77,8 +77,8 @@ class FanOutOnWriteService < BaseService
|
||||
Rails.logger.debug "Delivering status #{status.id} to hashtags"
|
||||
|
||||
status.tags.pluck(:name).each do |hashtag|
|
||||
Redis.current.publish("timeline:hashtag:#{hashtag}", @payload)
|
||||
Redis.current.publish("timeline:hashtag:#{hashtag}:local", @payload) if status.local?
|
||||
Redis.current.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}", @payload)
|
||||
Redis.current.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}:local", @payload) if status.local?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -126,8 +126,8 @@ class RemoveStatusService < BaseService
|
||||
return unless @status.public_visibility?
|
||||
|
||||
@tags.each do |hashtag|
|
||||
redis.publish("timeline:hashtag:#{hashtag}", @payload)
|
||||
redis.publish("timeline:hashtag:#{hashtag}:local", @payload) if @status.local?
|
||||
redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}", @payload)
|
||||
redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}:local", @payload) if @status.local?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -51,6 +51,8 @@
|
||||
= feature_hint(link_to(t('admin.dashboard.feature_timeline_preview'), edit_admin_settings_path), @timeline_preview)
|
||||
%li
|
||||
= feature_hint(link_to(t('admin.dashboard.keybase'), edit_admin_settings_path), @keybase_integration)
|
||||
%li
|
||||
= feature_hint(link_to(t('admin.dashboard.trends'), edit_admin_settings_path), @trends_enabled)
|
||||
%li
|
||||
= feature_hint(link_to(t('admin.dashboard.feature_relay'), admin_relays_path), @relay_enabled)
|
||||
%li
|
||||
@ -92,6 +94,10 @@
|
||||
= feature_hint(t('admin.dashboard.search'), @search_enabled)
|
||||
%li
|
||||
= feature_hint(t('admin.dashboard.single_user_mode'), @single_user_mode)
|
||||
%li
|
||||
= feature_hint(t('admin.dashboard.authorized_fetch_mode'), @authorized_fetch)
|
||||
%li
|
||||
= feature_hint(t('admin.dashboard.whitelist_mode'), @whitelist_mode)
|
||||
%li
|
||||
= feature_hint('LDAP', @ldap_enabled)
|
||||
%li
|
||||
|
@ -68,6 +68,9 @@
|
||||
.fields-group
|
||||
= f.input :profile_directory, as: :boolean, wrapper: :with_label, label: t('admin.settings.profile_directory.title'), hint: t('admin.settings.profile_directory.desc_html')
|
||||
|
||||
.fields-group
|
||||
= f.input :trends, as: :boolean, wrapper: :with_label, label: t('admin.settings.trends.title'), hint: t('admin.settings.trends.desc_html')
|
||||
|
||||
.fields-group
|
||||
= f.input :hide_followers_count, as: :boolean, wrapper: :with_label, label: t('admin.settings.hide_followers_count.title'), hint: t('admin.settings.hide_followers_count.desc_html')
|
||||
|
||||
|
@ -22,6 +22,11 @@
|
||||
= f.input :setting_reduce_motion, as: :boolean, wrapper: :with_label
|
||||
= f.input :setting_system_font_ui, as: :boolean, wrapper: :with_label
|
||||
|
||||
%h4= t 'appearance.discovery'
|
||||
|
||||
.fields-group
|
||||
= f.input :setting_trends, as: :boolean, wrapper: :with_label
|
||||
|
||||
%h4= t 'appearance.confirmation_dialogs'
|
||||
|
||||
.fields-group
|
||||
|
Reference in New Issue
Block a user