From fd3a45e3482e86dad3c1dfc069144864c4ff0b0b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 9 Feb 2022 01:17:07 +0100 Subject: Add edit history to web UI (#17390) * Add edit history to web UI * Change history reducer to store items per status * Fix missing loading prop --- app/javascript/styles/mastodon/components.scss | 228 ++++++++++++++++++------- 1 file changed, 164 insertions(+), 64 deletions(-) (limited to 'app/javascript/styles') diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 02b3473a9..591f2fad1 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1889,8 +1889,47 @@ a.account__display-name { box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); z-index: 9999; - ul { - list-style: none; + &__text-button { + display: inline; + color: inherit; + background: transparent; + border: 0; + margin: 0; + padding: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; + + &:focus { + outline: 1px dotted; + } + } + + &__container { + &__header { + border-bottom: 1px solid darken($ui-secondary-color, 8%); + padding: 4px 14px; + padding-bottom: 8px; + font-size: 13px; + line-height: 18px; + color: $inverted-text-color; + } + + &__list { + list-style: none; + + &--scrollable { + max-height: 300px; + overflow-y: scroll; + } + } + + &--loading { + display: flex; + align-items: center; + justify-content: center; + padding: 30px 45px; + } } &.left { @@ -1946,18 +1985,29 @@ a.account__display-name { } .dropdown-menu__item { - a { - font-size: 13px; - line-height: 18px; + font-size: 13px; + line-height: 18px; + display: block; + color: $inverted-text-color; + + a, + button { + font-family: inherit; + font-size: inherit; + line-height: inherit; display: block; + width: 100%; padding: 4px 14px; + border: 0; + margin: 0; box-sizing: border-box; text-decoration: none; background: $ui-secondary-color; - color: $inverted-text-color; + color: inherit; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + text-align: inherit; &:focus, &:hover, @@ -1969,6 +2019,42 @@ a.account__display-name { } } +.dropdown-menu__item--text { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding: 4px 14px; +} + +.dropdown-menu__item.edited-timestamp__history__item { + border-bottom: 1px solid darken($ui-secondary-color, 8%); + + &:last-child { + border-bottom: 0; + } + + &.dropdown-menu__item--text, + a, + button { + padding: 8px 14px; + } +} + +.inline-account { + display: inline-flex; + align-items: center; + vertical-align: top; + + .account__avatar { + margin-right: 5px; + border-radius: 50%; + } + + strong { + font-weight: 600; + } +} + .dropdown--active .dropdown__content { display: block; line-height: 18px; @@ -3631,36 +3717,48 @@ a.status-card.compact:hover { top: 50%; left: 50%; transform: translate(-50%, -50%); + display: flex; + align-items: center; + justify-content: center; +} - span { - display: block; - float: left; - transform: translateX(-50%); - margin: 82px 0 0 50%; - white-space: nowrap; +.circular-progress { + color: lighten($ui-base-color, 26%); + animation: 1.4s linear 0s infinite normal none running simple-rotate; + + circle { + stroke: currentColor; + stroke-dasharray: 80px, 200px; + stroke-dashoffset: 0; + animation: circular-progress 1.4s ease-in-out infinite; } } -.loading-indicator__figure { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 42px; - height: 42px; - box-sizing: border-box; - background-color: transparent; - border: 0 solid lighten($ui-base-color, 26%); - border-width: 6px; - border-radius: 50%; -} +@keyframes circular-progress { + 0% { + stroke-dasharray: 1px, 200px; + stroke-dashoffset: 0; + } -.no-reduce-motion .loading-indicator span { - animation: loader-label 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1); + 50% { + stroke-dasharray: 100px, 200px; + stroke-dashoffset: -15px; + } + + 100% { + stroke-dasharray: 100px, 200px; + stroke-dashoffset: -125px; + } } -.no-reduce-motion .loading-indicator__figure { - animation: loader-figure 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1); +@keyframes simple-rotate { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } } @keyframes spring-rotate-in { @@ -3707,40 +3805,6 @@ a.status-card.compact:hover { } } -@keyframes loader-figure { - 0% { - width: 0; - height: 0; - background-color: lighten($ui-base-color, 26%); - } - - 29% { - background-color: lighten($ui-base-color, 26%); - } - - 30% { - width: 42px; - height: 42px; - background-color: transparent; - border-width: 21px; - opacity: 1; - } - - 100% { - width: 42px; - height: 42px; - border-width: 0; - opacity: 0; - background-color: transparent; - } -} - -@keyframes loader-label { - 0% { opacity: 0.25; } - 30% { opacity: 1; } - 100% { opacity: 0.25; } -} - .video-error-cover { align-items: center; background: $base-overlay-background; @@ -4940,7 +5004,8 @@ a.status-card.compact:hover { .report-modal, .actions-modal, .mute-modal, -.block-modal { +.block-modal, +.compare-history-modal { background: lighten($ui-secondary-color, 8%); color: $inverted-text-color; border-radius: 8px; @@ -5342,6 +5407,41 @@ a.status-card.compact:hover { } } +.compare-history-modal { + .report-modal__target { + border-bottom: 1px solid $ui-secondary-color; + } + + &__container { + padding: 30px; + pointer-events: all; + } + + .status__content { + color: $inverted-text-color; + font-size: 19px; + line-height: 24px; + + .emojione { + width: 24px; + height: 24px; + margin: -1px 0 0; + } + + a { + color: $highlight-text-color; + } + + hr { + height: 0.25rem; + padding: 0; + background-color: $ui-secondary-color; + border: 0; + margin: 20px 0; + } + } +} + .loading-bar { background-color: $highlight-text-color; height: 3px; -- cgit From d0fcf07436d158bcac2617d076a83d0aa49c39e6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 11 Feb 2022 21:51:57 +0100 Subject: Change actions in reports to require only one click (#17487) --- .../admin/reports/actions_controller.rb | 50 +++++++++++++++++++ app/javascript/styles/mastodon/admin.scss | 37 +++++++++++++- app/models/admin/status_batch_action.rb | 12 ++++- app/views/admin/reports/_actions.html.haml | 27 ++++++++++ app/views/admin/reports/show.html.haml | 57 +++++++++------------- config/locales/en.yml | 9 +++- config/routes.rb | 2 + 7 files changed, 156 insertions(+), 38 deletions(-) create mode 100644 app/controllers/admin/reports/actions_controller.rb create mode 100644 app/views/admin/reports/_actions.html.haml (limited to 'app/javascript/styles') diff --git a/app/controllers/admin/reports/actions_controller.rb b/app/controllers/admin/reports/actions_controller.rb new file mode 100644 index 000000000..05a4fb63d --- /dev/null +++ b/app/controllers/admin/reports/actions_controller.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +class Admin::Reports::ActionsController < Admin::BaseController + before_action :set_report + + def create + authorize @report, :show? + + case action_from_button + when 'delete' + status_batch_action = Admin::StatusBatchAction.new( + type: action_from_button, + status_ids: @report.status_ids, + current_account: current_account, + report_id: @report.id, + send_email_notification: !@report.spam? + ) + + status_batch_action.save! + when 'silence', 'suspend' + account_action = Admin::AccountAction.new( + type: action_from_button, + report_id: @report.id, + target_account: @report.target_account, + current_account: current_account, + send_email_notification: !@report.spam? + ) + + account_action.save! + end + + redirect_to admin_reports_path + end + + private + + def set_report + @report = Report.find(params[:report_id]) + end + + def action_from_button + if params[:delete] + 'delete' + elsif params[:silence] + 'silence' + elsif params[:suspend] + 'suspend' + end + end +end diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index c20762fba..21669dded 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -1394,8 +1394,9 @@ a.sparkline { } &__button { + box-sizing: border-box; flex: 0 0 auto; - width: 100px; + width: 200px; padding: 15px; padding-right: 0; @@ -1411,4 +1412,38 @@ a.sparkline { color: $dark-text-color; } } + + @media screen and (max-width: 800px) { + border: 0; + + &__item { + flex-direction: column; + border: 0; + + &__button { + width: 100%; + padding: 15px 0; + } + + &__description { + padding: 0; + padding-bottom: 15px; + } + } + } +} + +.section-skip-link { + float: right; + + a { + color: $ui-highlight-color; + text-decoration: none; + + &:hover, + &:focus, + &:active { + text-decoration: underline; + } + } } diff --git a/app/models/admin/status_batch_action.rb b/app/models/admin/status_batch_action.rb index 85822214b..40f60f379 100644 --- a/app/models/admin/status_batch_action.rb +++ b/app/models/admin/status_batch_action.rb @@ -8,6 +8,12 @@ class Admin::StatusBatchAction attr_accessor :current_account, :type, :status_ids, :report_id + attr_reader :send_email_notification + + def send_email_notification=(value) + @send_email_notification = ActiveModel::Type::Boolean.new.cast(value) + end + def save! process_action! end @@ -55,7 +61,7 @@ class Admin::StatusBatchAction statuses.each { |status| Tombstone.find_or_create_by(uri: status.uri, account: status.account, by_moderator: true) } unless target_account.local? end - UserMailer.warning(target_account.user, @warning).deliver_later! if target_account.local? + UserMailer.warning(target_account.user, @warning).deliver_later! if warnable? RemovalWorker.push_bulk(status_ids) { |status_id| [status_id, { 'preserve' => target_account.local?, 'immediate' => !target_account.local? }] } end @@ -82,6 +88,10 @@ class Admin::StatusBatchAction !report.nil? end + def warnable? + send_email_notification && target_account.local? + end + def target_account @target_account ||= statuses.first.account end diff --git a/app/views/admin/reports/_actions.html.haml b/app/views/admin/reports/_actions.html.haml new file mode 100644 index 000000000..f3162b325 --- /dev/null +++ b/app/views/admin/reports/_actions.html.haml @@ -0,0 +1,27 @@ += form_tag admin_report_actions_path(@report), method: :post do + .report-actions + .report-actions__item + .report-actions__item__button + = link_to t('admin.reports.mark_as_resolved'), resolve_admin_report_path(@report), method: :post, class: 'button' + .report-actions__item__description + = t('admin.reports.actions.resolve_description_html') + .report-actions__item + .report-actions__item__button + = button_tag t('admin.reports.delete_and_resolve'), name: :delete, class: 'button button--destructive' + .report-actions__item__description + = t('admin.reports.actions.delete_description_html') + .report-actions__item + .report-actions__item__button + = button_tag t('admin.accounts.silence'), name: :silence, class: 'button button--destructive' + .report-actions__item__description + = t('admin.reports.actions.silence_description_html') + .report-actions__item + .report-actions__item__button + = button_tag t('admin.accounts.suspend'), name: :suspend, class: 'button button--destructive' + .report-actions__item__description + = t('admin.reports.actions.suspend_description_html') + .report-actions__item + .report-actions__item__button + = link_to t('admin.accounts.custom'), new_admin_account_action_path(@report.target_account_id, report_id: @report.id), class: 'button' + .report-actions__item__description + = t('admin.reports.actions.other_description_html') diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml index 4f513dd39..02c46e384 100644 --- a/app/views/admin/reports/show.html.haml +++ b/app/views/admin/reports/show.html.haml @@ -124,24 +124,30 @@ - if @report.comment.present? %p= t('admin.reports.comment_description_html', name: content_tag(:strong, @report.account.username, class: 'username')) - .report-notes__item - = image_tag @report.account.avatar.url, class: 'report-notes__item__avatar' - - .report-notes__item__header - %span.username - = link_to display_name(@report.account), admin_account_path(@report.account_id) - %time{ datetime: @report.created_at.iso8601, title: l(@report.created_at) } - - if @report.created_at.today? - = t('admin.report_notes.today_at', time: l(@report.created_at, format: :time)) - - else - = l @report.created_at.to_date + .report-notes + .report-notes__item + = image_tag @report.account.avatar.url, class: 'report-notes__item__avatar' + + .report-notes__item__header + %span.username + = link_to display_name(@report.account), admin_account_path(@report.account_id) + %time{ datetime: @report.created_at.iso8601, title: l(@report.created_at) } + - if @report.created_at.today? + = t('admin.report_notes.today_at', time: l(@report.created_at, format: :time)) + - else + = l @report.created_at.to_date - .report-notes__item__content - = simple_format(h(@report.comment)) + .report-notes__item__content + = simple_format(h(@report.comment)) %hr.spacer/ -%h3= t 'admin.reports.statuses' +%h3 + = t 'admin.reports.statuses' + %small.section-skip-link + = link_to '#actions' do + = fa_icon 'angle-double-down' + = t('admin.reports.skip_to_actions') %p = t 'admin.reports.statuses_description_html' @@ -156,8 +162,6 @@ .batch-table__toolbar__actions - if !@statuses.empty? && @report.unresolved? = f.button safe_join([fa_icon('times'), t('admin.statuses.batch.remove_from_report')]), name: :remove_from_report, class: 'table-action-link', type: :submit - = f.button safe_join([fa_icon('trash'), t('admin.reports.delete_and_resolve')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } - - else .batch-table__body - if @statuses.empty? = nothing_here 'nothing-here--under-tabs' @@ -167,24 +171,9 @@ - if @report.unresolved? %hr.spacer/ - %p= t 'admin.reports.actions_description_html' - - .report-actions - .report-actions__item - .report-actions__item__button - = link_to t('admin.accounts.silence'), new_admin_account_action_path(@report.target_account_id, type: 'silence', report_id: @report.id), class: 'button button--destructive' - .report-actions__item__description - = t('admin.reports.actions.silence_description_html') - .report-actions__item - .report-actions__item__button - = link_to t('admin.accounts.perform_full_suspension'), new_admin_account_action_path(@report.target_account_id, report_id: @report.id, type: 'suspend'), class: 'button button--destructive' - .report-actions__item__description - = t('admin.reports.actions.suspend_description_html') - .report-actions__item - .report-actions__item__button - = link_to t('admin.accounts.custom'), new_admin_account_action_path(@report.target_account_id, report_id: @report.id), class: 'button' - .report-actions__item__description - = t('admin.reports.actions.other_description_html') + %p#actions= t 'admin.reports.actions_description_html' + + = render partial: 'admin/reports/actions' - unless @action_logs.empty? %hr.spacer/ diff --git a/config/locales/en.yml b/config/locales/en.yml index ccaff84b4..0a9f66827 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -206,6 +206,7 @@ en: statuses: Posts strikes: Previous strikes subscribe: Subscribe + suspend: Suspend suspended: Suspended suspension_irreversible: The data of this account has been irreversibly deleted. You can unsuspend the account to make it usable but it will not recover any data it previously had. suspension_reversible_hint_html: The account has been suspended, and the data will be fully removed on %{date}. Until then, the account can be restored without any ill effects. If you wish to remove all of the account's data immediately, you can do so below. @@ -560,10 +561,12 @@ en: action_log: Audit log action_taken_by: Action taken by actions: + delete_description_html: The reported posts will be deleted and a strike will be recorded to help you escalate on future infractions by the same account. other_description_html: See more options for controlling the account's behaviour and customize communication to the reported account. + resolve_description_html: No action will be taken against the reported account, no strike recorded, and the report will be closed. silence_description_html: The profile will be visible only to those who already follow it or manually look it up, severely limiting its reach. Can always be reverted. suspend_description_html: The profile and all its contents will become inaccessible until it is eventually deleted. Interacting with the account will be impossible. Reversible within 30 days. - actions_description_html: 'If removing the offending content above is insufficient:' + actions_description_html: Decide which action to take to resolve this report. If you take a punitive action against the reported account, an e-mail notification will be sent to them, except when the Spam category is selected. add_to_report: Add more to report are_you_sure: Are you sure? assign_to_self: Assign to me @@ -575,7 +578,7 @@ en: none: None comment_description_html: 'To provide more information, %{name} wrote:' created_at: Reported - delete_and_resolve: Delete and resolve + delete_and_resolve: Delete posts forwarded: Forwarded forwarded_to: Forwarded to %{domain} mark_as_resolved: Mark as resolved @@ -589,12 +592,14 @@ en: placeholder: Describe what actions have been taken, or any other related updates... title: Notes notes_description_html: View and leave notes to other moderators and your future self + quick_actions_description_html: 'Take a quick action or scroll down to see reported content:' reopen: Reopen report report: 'Report #%{id}' reported_account: Reported account reported_by: Reported by resolved: Resolved resolved_msg: Report successfully resolved! + skip_to_actions: Skip to actions status: Status statuses: Reported content statuses_description_html: Offending content will be cited in communication with the reported account diff --git a/config/routes.rb b/config/routes.rb index 670bebce2..5edb36519 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -225,6 +225,8 @@ Rails.application.routes.draw do resources :rules resources :reports, only: [:index, :show] do + resources :actions, only: [:create], controller: 'reports/actions' + member do post :assign_to_self post :unassign -- cgit From e848d281d55a3c753f6dc8d9f32a3d7eb9b9a2ff Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 12 Feb 2022 01:08:23 +0100 Subject: Fix layout of the report page on smaller screens in admin UI (#17523) Fix #17491 --- app/javascript/styles/mastodon/admin.scss | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'app/javascript/styles') diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index 21669dded..546de1640 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -1187,6 +1187,10 @@ a.sparkline { } } } + + @media screen and (max-width: 930px) { + grid-template-columns: minmax(0, 1fr); + } } .account-card { -- cgit