forked from cybrespace/mastodon
Add quick links to the admin interface in the WebUI (#8545)
* Allow to show a specific status in the admin interface * Let the front-end know the current account is a moderator * Add admin links to status and account menus If the current logged-in user is an admin, add quick links to the admin interface in account and toot dropdown menu. Suggestion by @ashkitten * Use @statuses.first instead of @statuses[0]
This commit is contained in:
parent
1512af2811
commit
6f9a7bd02c
|
@ -22,6 +22,15 @@ module Admin
|
||||||
@form = Form::StatusBatch.new
|
@form = Form::StatusBatch.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
authorize :status, :index?
|
||||||
|
|
||||||
|
@statuses = @account.statuses.where(id: params[:id])
|
||||||
|
authorize @statuses.first, :show?
|
||||||
|
|
||||||
|
@form = Form::StatusBatch.new
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
authorize :status, :update?
|
authorize :status, :update?
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import IconButton from './icon_button';
|
||||||
import DropdownMenuContainer from '../containers/dropdown_menu_container';
|
import DropdownMenuContainer from '../containers/dropdown_menu_container';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { me } from '../initial_state';
|
import { me, isStaff } from '../initial_state';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
||||||
|
@ -30,6 +30,8 @@ const messages = defineMessages({
|
||||||
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
|
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
|
||||||
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
|
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
|
||||||
embed: { id: 'status.embed', defaultMessage: 'Embed' },
|
embed: { id: 'status.embed', defaultMessage: 'Embed' },
|
||||||
|
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
|
||||||
|
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const obfuscatedCount = count => {
|
const obfuscatedCount = count => {
|
||||||
|
@ -182,6 +184,11 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
||||||
menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
||||||
menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
|
menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
|
||||||
|
if (isStaff) {
|
||||||
|
menu.push(null);
|
||||||
|
menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });
|
||||||
|
menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.get('visibility') === 'direct') {
|
if (status.get('visibility') === 'direct') {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
||||||
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
|
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
|
||||||
import { NavLink } from 'react-router-dom';
|
import { NavLink } from 'react-router-dom';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import { me } from '../../../initial_state';
|
import { me, isStaff } from '../../../initial_state';
|
||||||
import { shortNumberFormat } from '../../../utils/numbers';
|
import { shortNumberFormat } from '../../../utils/numbers';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
@ -35,6 +35,7 @@ const messages = defineMessages({
|
||||||
endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' },
|
endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' },
|
||||||
unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' },
|
unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' },
|
||||||
add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' },
|
add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' },
|
||||||
|
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
|
||||||
});
|
});
|
||||||
|
|
||||||
export default @injectIntl
|
export default @injectIntl
|
||||||
|
@ -151,6 +152,11 @@ class ActionBar extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (account.get('id') !== me && isStaff) {
|
||||||
|
menu.push(null);
|
||||||
|
menu.push({ text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), href: `/admin/accounts/${account.get('id')}` });
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{extraInfo}
|
{extraInfo}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import IconButton from '../../../components/icon_button';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
|
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import { me } from '../../../initial_state';
|
import { me, isStaff } from '../../../initial_state';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
||||||
|
@ -26,6 +26,8 @@ const messages = defineMessages({
|
||||||
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
|
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
|
||||||
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
|
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
|
||||||
embed: { id: 'status.embed', defaultMessage: 'Embed' },
|
embed: { id: 'status.embed', defaultMessage: 'Embed' },
|
||||||
|
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
|
||||||
|
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' },
|
||||||
});
|
});
|
||||||
|
|
||||||
export default @injectIntl
|
export default @injectIntl
|
||||||
|
@ -145,6 +147,11 @@ class ActionBar extends React.PureComponent {
|
||||||
menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
||||||
menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
||||||
menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
|
menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
|
||||||
|
if (isStaff) {
|
||||||
|
menu.push(null);
|
||||||
|
menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });
|
||||||
|
menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const shareButton = ('share' in navigator) && status.get('visibility') === 'public' && (
|
const shareButton = ('share' in navigator) && status.get('visibility') === 'public' && (
|
||||||
|
|
|
@ -16,5 +16,6 @@ export const invitesEnabled = getMeta('invites_enabled');
|
||||||
export const version = getMeta('version');
|
export const version = getMeta('version');
|
||||||
export const mascot = getMeta('mascot');
|
export const mascot = getMeta('mascot');
|
||||||
export const profile_directory = getMeta('profile_directory');
|
export const profile_directory = getMeta('profile_directory');
|
||||||
|
export const isStaff = getMeta('is_staff');
|
||||||
|
|
||||||
export default initialState;
|
export default initialState;
|
||||||
|
|
|
@ -29,6 +29,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
||||||
store[:display_media] = object.current_account.user.setting_display_media
|
store[:display_media] = object.current_account.user.setting_display_media
|
||||||
store[:expand_spoilers] = object.current_account.user.setting_expand_spoilers
|
store[:expand_spoilers] = object.current_account.user.setting_expand_spoilers
|
||||||
store[:reduce_motion] = object.current_account.user.setting_reduce_motion
|
store[:reduce_motion] = object.current_account.user.setting_reduce_motion
|
||||||
|
store[:is_staff] = object.current_account.user.staff?
|
||||||
end
|
end
|
||||||
|
|
||||||
store
|
store
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
- content_for :page_title do
|
||||||
|
= t('admin.statuses.title')
|
||||||
|
\-
|
||||||
|
= "@#{@account.acct}"
|
||||||
|
|
||||||
|
.filters
|
||||||
|
.back-link{ style: 'flex: 1 1 auto; text-align: right' }
|
||||||
|
= link_to admin_account_path(@account.id) do
|
||||||
|
%i.fa.fa-chevron-left.fa-fw
|
||||||
|
= t('admin.statuses.back_to_account')
|
||||||
|
|
||||||
|
%hr.spacer/
|
||||||
|
|
||||||
|
= form_for(@form, url: admin_account_statuses_path(@account.id)) do |f|
|
||||||
|
= hidden_field_tag :page, params[:page]
|
||||||
|
= hidden_field_tag :media, params[:media]
|
||||||
|
|
||||||
|
.batch-table
|
||||||
|
.batch-table__toolbar
|
||||||
|
%label.batch-table__toolbar__select.batch-checkbox-all
|
||||||
|
= check_box_tag :batch_checkbox_all, nil, false
|
||||||
|
.batch-table__toolbar__actions
|
||||||
|
= f.button safe_join([fa_icon('eye-slash'), t('admin.statuses.batch.nsfw_on')]), name: :nsfw_on, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
|
||||||
|
= f.button safe_join([fa_icon('eye'), t('admin.statuses.batch.nsfw_off')]), name: :nsfw_off, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
|
||||||
|
= f.button safe_join([fa_icon('trash'), t('admin.statuses.batch.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
|
||||||
|
.batch-table__body
|
||||||
|
= render partial: 'admin/reports/status', collection: @statuses, locals: { f: f }
|
|
@ -192,7 +192,7 @@ Rails.application.routes.draw do
|
||||||
resource :change_email, only: [:show, :update]
|
resource :change_email, only: [:show, :update]
|
||||||
resource :reset, only: [:create]
|
resource :reset, only: [:create]
|
||||||
resource :action, only: [:new, :create], controller: 'account_actions'
|
resource :action, only: [:new, :create], controller: 'account_actions'
|
||||||
resources :statuses, only: [:index, :create, :update, :destroy]
|
resources :statuses, only: [:index, :show, :create, :update, :destroy]
|
||||||
resources :followers, only: [:index]
|
resources :followers, only: [:index]
|
||||||
|
|
||||||
resource :confirmation, only: [:create] do
|
resource :confirmation, only: [:create] do
|
||||||
|
|
Loading…
Reference in New Issue