* Change design of federation pages in admin UI * Fix query performance in instance media attachments measure * Fix reblogs being included in instance languages dimensionclosed-social-glitch-2
@ -0,0 +1,35 @@ | |||
# frozen_string_literal: true | |||
class Admin::Metrics::Dimension::InstanceAccountsDimension < Admin::Metrics::Dimension::BaseDimension | |||
include LanguagesHelper | |||
def self.with_params? | |||
true | |||
end | |||
def key | |||
'instance_accounts' | |||
end | |||
protected | |||
def perform_query | |||
sql = <<-SQL.squish | |||
SELECT accounts.username, count(follows.*) AS value | |||
FROM accounts | |||
LEFT JOIN follows ON follows.target_account_id = accounts.id | |||
WHERE accounts.domain = $1 | |||
GROUP BY accounts.id, follows.target_account_id | |||
ORDER BY value DESC | |||
LIMIT $2 | |||
SQL | |||
rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, params[:domain]], [nil, @limit]]) | |||
rows.map { |row| { key: row['username'], human_key: row['username'], value: row['value'].to_s } } | |||
end | |||
def params | |||
@params.permit(:domain) | |||
end | |||
end |
@ -0,0 +1,37 @@ | |||
# frozen_string_literal: true | |||
class Admin::Metrics::Dimension::InstanceLanguagesDimension < Admin::Metrics::Dimension::BaseDimension | |||
include LanguagesHelper | |||
def self.with_params? | |||
true | |||
end | |||
def key | |||
'instance_languages' | |||
end | |||
protected | |||
def perform_query | |||
sql = <<-SQL.squish | |||
SELECT COALESCE(statuses.language, 'und') AS language, count(*) AS value | |||
FROM statuses | |||
INNER JOIN accounts ON accounts.id = statuses.account_id | |||
WHERE accounts.domain = $1 | |||
AND statuses.id BETWEEN $2 AND $3 | |||
AND statuses.reblog_of_id IS NULL | |||
GROUP BY COALESCE(statuses.language, 'und') | |||
ORDER BY count(*) DESC | |||
LIMIT $4 | |||
SQL | |||
rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, params[:domain]], [nil, Mastodon::Snowflake.id_at(@start_at, with_random: false)], [nil, Mastodon::Snowflake.id_at(@end_at, with_random: false)], [nil, @limit]]) | |||
rows.map { |row| { key: row['language'], human_key: standard_locale_name(row['language']), value: row['value'].to_s } } | |||
end | |||
def params | |||
@params.permit(:domain) | |||
end | |||
end |
@ -0,0 +1,58 @@ | |||
# frozen_string_literal: true | |||
class Admin::Metrics::Measure::InstanceAccountsMeasure < Admin::Metrics::Measure::BaseMeasure | |||
def self.with_params? | |||
true | |||
end | |||
def key | |||
'instance_accounts' | |||
end | |||
def total_in_time_range? | |||
false | |||
end | |||
protected | |||
def perform_total_query | |||
Account.where(domain: params[:domain]).count | |||
end | |||
def perform_previous_total_query | |||
nil | |||
end | |||
def perform_data_query | |||
sql = <<-SQL.squish | |||
SELECT axis.*, ( | |||
WITH new_accounts AS ( | |||
SELECT accounts.id | |||
FROM accounts | |||
WHERE date_trunc('day', accounts.created_at)::date = axis.period | |||
AND accounts.domain = $3::text | |||
) | |||
SELECT count(*) FROM new_accounts | |||
) AS value | |||
FROM ( | |||
SELECT generate_series(date_trunc('day', $1::timestamp)::date, date_trunc('day', $2::timestamp)::date, interval '1 day') AS period | |||
) AS axis | |||
SQL | |||
rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, params[:domain]]]) | |||
rows.map { |row| { date: row['period'], value: row['value'].to_s } } | |||
end | |||
def time_period | |||
(@start_at.to_date..@end_at.to_date) | |||
end | |||
def previous_time_period | |||
((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period)) | |||
end | |||
def params | |||
@params.permit(:domain) | |||
end | |||
end |
@ -0,0 +1,59 @@ | |||
# frozen_string_literal: true | |||
class Admin::Metrics::Measure::InstanceFollowersMeasure < Admin::Metrics::Measure::BaseMeasure | |||
def self.with_params? | |||
true | |||
end | |||
def key | |||
'instance_followers' | |||
end | |||
def total_in_time_range? | |||
false | |||
end | |||
protected | |||
def perform_total_query | |||
Follow.joins(:account).merge(Account.where(domain: params[:domain])).count | |||
end | |||
def perform_previous_total_query | |||
nil | |||
end | |||
def perform_data_query | |||
sql = <<-SQL.squish | |||
SELECT axis.*, ( | |||
WITH new_followers AS ( | |||
SELECT follows.id | |||
FROM follows | |||
INNER JOIN accounts ON follows.account_id = accounts.id | |||
WHERE date_trunc('day', follows.created_at)::date = axis.period | |||
AND accounts.domain = $3::text | |||
) | |||
SELECT count(*) FROM new_followers | |||
) AS value | |||
FROM ( | |||
SELECT generate_series(date_trunc('day', $1::timestamp)::date, date_trunc('day', $2::timestamp)::date, interval '1 day') AS period | |||
) AS axis | |||
SQL | |||
rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, params[:domain]]]) | |||
rows.map { |row| { date: row['period'], value: row['value'].to_s } } | |||
end | |||
def time_period | |||
(@start_at.to_date..@end_at.to_date) | |||
end | |||
def previous_time_period | |||
((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period)) | |||
end | |||
def params | |||
@params.permit(:domain) | |||
end | |||
end |
@ -0,0 +1,59 @@ | |||
# frozen_string_literal: true | |||
class Admin::Metrics::Measure::InstanceFollowsMeasure < Admin::Metrics::Measure::BaseMeasure | |||
def self.with_params? | |||
true | |||
end | |||
def key | |||
'instance_follows' | |||
end | |||
def total_in_time_range? | |||
false | |||
end | |||
protected | |||
def perform_total_query | |||
Follow.joins(:target_account).merge(Account.where(domain: params[:domain])).count | |||
end | |||
def perform_previous_total_query | |||
nil | |||
end | |||
def perform_data_query | |||
sql = <<-SQL.squish | |||
SELECT axis.*, ( | |||
WITH new_follows AS ( | |||
SELECT follows.id | |||
FROM follows | |||
INNER JOIN accounts ON follows.target_account_id = accounts.id | |||
WHERE date_trunc('day', follows.created_at)::date = axis.period | |||
AND accounts.domain = $3::text | |||
) | |||
SELECT count(*) FROM new_follows | |||
) AS value | |||
FROM ( | |||
SELECT generate_series(date_trunc('day', $1::timestamp)::date, date_trunc('day', $2::timestamp)::date, interval '1 day') AS period | |||
) AS axis | |||
SQL | |||
rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, params[:domain]]]) | |||
rows.map { |row| { date: row['period'], value: row['value'].to_s } } | |||
end | |||
def time_period | |||
(@start_at.to_date..@end_at.to_date) | |||
end | |||
def previous_time_period | |||
((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period)) | |||
end | |||
def params | |||
@params.permit(:domain) | |||
end | |||
end |
@ -0,0 +1,69 @@ | |||
# frozen_string_literal: true | |||
class Admin::Metrics::Measure::InstanceMediaAttachmentsMeasure < Admin::Metrics::Measure::BaseMeasure | |||
include ActionView::Helpers::NumberHelper | |||
def self.with_params? | |||
true | |||
end | |||
def key | |||
'instance_media_attachments' | |||
end | |||
def unit | |||
'bytes' | |||
end | |||
def value_to_human_value(value) | |||
number_to_human_size(value) | |||
end | |||
def total_in_time_range? | |||
false | |||
end | |||
protected | |||
def perform_total_query | |||
MediaAttachment.joins(:account).merge(Account.where(domain: params[:domain])).sum('COALESCE(file_file_size, 0) + COALESCE(thumbnail_file_size, 0)') | |||
end | |||
def perform_previous_total_query | |||
nil | |||
end | |||
def perform_data_query | |||
sql = <<-SQL.squish | |||
SELECT axis.*, ( | |||
WITH new_media_attachments AS ( | |||
SELECT COALESCE(media_attachments.file_file_size, 0) + COALESCE(media_attachments.thumbnail_file_size, 0) AS size | |||
FROM media_attachments | |||
INNER JOIN accounts ON accounts.id = media_attachments.account_id | |||
WHERE date_trunc('day', media_attachments.created_at)::date = axis.period | |||
AND accounts.domain = $3::text | |||
) | |||
SELECT SUM(size) FROM new_media_attachments | |||
) AS value | |||
FROM ( | |||
SELECT generate_series(date_trunc('day', $1::timestamp)::date, date_trunc('day', $2::timestamp)::date, interval '1 day') AS period | |||
) AS axis | |||
SQL | |||
rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, params[:domain]]]) | |||
rows.map { |row| { date: row['period'], value: row['value'].to_s } } | |||
end | |||
def time_period | |||
(@start_at.to_date..@end_at.to_date) | |||
end | |||
def previous_time_period | |||
((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period)) | |||
end | |||
def params | |||
@params.permit(:domain) | |||
end | |||
end |
@ -0,0 +1,59 @@ | |||
# frozen_string_literal: true | |||
class Admin::Metrics::Measure::InstanceReportsMeasure < Admin::Metrics::Measure::BaseMeasure | |||
def self.with_params? | |||
true | |||
end | |||
def key | |||
'instance_reports' | |||
end | |||
def total_in_time_range? | |||
false | |||
end | |||
protected | |||
def perform_total_query | |||
Report.where(target_account: Account.where(domain: params[:domain])).count | |||
end | |||
def perform_previous_total_query | |||
nil | |||
end | |||
def perform_data_query | |||
sql = <<-SQL.squish | |||
SELECT axis.*, ( | |||
WITH new_reports AS ( | |||
SELECT reports.id | |||
FROM reports | |||
INNER JOIN accounts ON accounts.id = reports.target_account_id | |||
WHERE date_trunc('day', reports.created_at)::date = axis.period | |||
AND accounts.domain = $3::text | |||
) | |||
SELECT count(*) FROM new_reports | |||
) AS value | |||
FROM ( | |||
SELECT generate_series(date_trunc('day', $1::timestamp)::date, date_trunc('day', $2::timestamp)::date, interval '1 day') AS period | |||
) AS axis | |||
SQL | |||
rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, params[:domain]]]) | |||
rows.map { |row| { date: row['period'], value: row['value'].to_s } } | |||
end | |||
def time_period | |||
(@start_at.to_date..@end_at.to_date) | |||
end | |||
def previous_time_period | |||
((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period)) | |||
end | |||
def params | |||
@params.permit(:domain) | |||
end | |||
end |
@ -0,0 +1,60 @@ | |||
# frozen_string_literal: true | |||
class Admin::Metrics::Measure::InstanceStatusesMeasure < Admin::Metrics::Measure::BaseMeasure | |||
def self.with_params? | |||
true | |||
end | |||
def key | |||
'instance_statuses' | |||
end | |||
def total_in_time_range? | |||
false | |||
end | |||
protected | |||
def perform_total_query | |||
Status.joins(:account).merge(Account.where(domain: params[:domain])).count | |||
end | |||
def perform_previous_total_query | |||
nil | |||
end | |||
def perform_data_query | |||
sql = <<-SQL.squish | |||
SELECT axis.*, ( | |||
WITH new_statuses AS ( | |||
SELECT statuses.id | |||
FROM statuses | |||
INNER JOIN accounts ON accounts.id = statuses.account_id | |||
WHERE statuses.id BETWEEN $3 AND $4 | |||
AND accounts.domain = $5::text | |||
AND date_trunc('day', statuses.created_at)::date = axis.period | |||
) | |||
SELECT count(*) FROM new_statuses | |||
) AS value | |||
FROM ( | |||
SELECT generate_series(date_trunc('day', $1::timestamp)::date, date_trunc('day', $2::timestamp)::date, interval '1 day') AS period | |||
) AS axis | |||
SQL | |||
rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, Mastodon::Snowflake.id_at(@start_at, with_random: false)], [nil, Mastodon::Snowflake.id_at(@end_at, with_random: false)], [nil, params[:domain]]]) | |||
rows.map { |row| { date: row['period'], value: row['value'].to_s } } | |||
end | |||
def time_period | |||
(@start_at.to_date..@end_at.to_date) | |||
end | |||
def previous_time_period | |||
((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period)) | |||
end | |||
def params | |||
@params.permit(:domain) | |||
end | |||
end |
@ -1,12 +1,20 @@ | |||
# frozen_string_literal: true | |||
class REST::Admin::MeasureSerializer < ActiveModel::Serializer | |||
attributes :key, :total, :previous_total, :data | |||
attributes :key, :unit, :total | |||
attribute :human_value, if: -> { object.respond_to?(:value_to_human_value) } | |||
attribute :previous_total, if: -> { object.total_in_time_range? } | |||
attribute :data | |||
def total | |||
object.total.to_s | |||
end | |||
def human_value | |||
object.value_to_human_value(object.total) | |||
end | |||
def previous_total | |||
object.previous_total.to_s | |||
end | |||
@ -1,25 +0,0 @@ | |||
- content_for :page_title do | |||
= t('admin.domain_blocks.show.title', domain: @domain_block.domain) | |||
- if @domain_block.private_comment.present? | |||
.speech-bubble | |||
.speech-bubble__bubble | |||
= simple_format(h(@domain_block.private_comment)) | |||
.speech-bubble__owner= t 'admin.instances.private_comment' | |||
- if @domain_block.public_comment.present? | |||
.speech-bubble | |||
.speech-bubble__bubble | |||
= simple_format(h(@domain_block.public_comment)) | |||
.speech-bubble__owner= t 'admin.instances.public_comment' | |||
= simple_form_for @domain_block, url: admin_domain_block_path(@domain_block), method: :delete do |f| | |||
- unless (@domain_block.noop?) | |||
%p= t(".retroactive.#{@domain_block.severity}") | |||
%p.hint= t(:affected_accounts, | |||
scope: [:admin, :domain_blocks, :show], | |||
count: @domain_block.affected_accounts_count) | |||
.actions | |||
= f.button :button, t('.undo'), type: :submit |
@ -1,2 +0,0 @@ | |||
%li.negative-hint | |||
= l(exhausted_deliveries_days) |
@ -1,33 +1,15 @@ | |||
.directory__tag | |||
= link_to admin_instance_path(instance) do | |||
%h4 | |||
= fa_icon 'warning fw' if instance.failing? | |||
= instance.domain | |||
%small | |||
- if instance.domain_block | |||
- first_item = true | |||
- if !instance.domain_block.noop? | |||
= t("admin.domain_blocks.severity.#{instance.domain_block.severity}") | |||
- first_item = false | |||
- unless instance.domain_block.suspend? | |||
- if instance.domain_block.reject_media? | |||
- unless first_item | |||
• | |||
= t('admin.domain_blocks.rejecting_media') | |||
- first_item = false | |||
- if instance.domain_block.reject_reports? | |||
- unless first_item | |||
• | |||
= t('admin.domain_blocks.rejecting_reports') | |||
- elsif whitelist_mode? | |||
= instance.domain_block.policies.map { |policy| t(policy, scope: 'admin.instances.content_policies.policies') }.join(' • ') | |||
- elsif instance.domain_allow | |||
= t('admin.accounts.whitelisted') | |||
- else | |||
= t('admin.accounts.no_limits_imposed') | |||
- if instance.failure_days | |||
= ' / ' | |||
%span.negative-hint | |||
= t('admin.instances.delivery.warning_message', count: instance.failure_days) | |||
- if instance.unavailable_domain | |||
= ' / ' | |||
%span.negative-hint | |||
= t('admin.instances.delivery.unavailable_message') | |||
.trends__item__current{ title: t('admin.instances.known_accounts', count: instance.accounts_count) }= friendly_number_to_human instance.accounts_count |
@ -1,88 +1,95 @@ | |||
- content_for :page_title do | |||
= @instance.domain | |||
.filters | |||
.back-link | |||
= link_to admin_instances_path() do | |||
%i.fa.fa-chevron-left.fa-fw | |||
= t('admin.instances.back_to_all') | |||
= link_to admin_instances_path(limited: 1) do | |||
%i.fa.fa-chevron-left.fa-fw | |||
= t('admin.instances.back_to_limited') | |||
= link_to admin_instances_path(warning: 1) do | |||
%i.fa.fa-chevron-left.fa-fw | |||
= t('admin.instances.back_to_warning') | |||
.dashboard__counters | |||
%div | |||
= link_to admin_accounts_path(origin: 'remote', by_domain: @instance.domain) do | |||
.dashboard__counters__num= number_with_delimiter @instance.accounts_count | |||
.dashboard__counters__label= t 'admin.accounts.title' | |||
%div | |||
= link_to admin_reports_path(by_target_domain: @instance.domain) do | |||
.dashboard__counters__num= number_with_delimiter @instance.reports_count | |||
.dashboard__counters__label= t 'admin.instances.total_reported' | |||
%div | |||
%div | |||
.dashboard__counters__num= number_to_human_size @instance.media_storage | |||
.dashboard__counters__label= t 'admin.instances.total_storage' | |||
%div | |||
%div | |||
.dashboard__counters__num= number_with_delimiter @instance.following_count | |||
.dashboard__counters__label= t 'admin.instances.total_followed_by_them' | |||
%div | |||
%div | |||
.dashboard__counters__num= number_with_delimiter @instance.followers_count | |||
.dashboard__counters__label= t 'admin.instances.total_followed_by_us' | |||
%div | |||
%div | |||
.dashboard__counters__num= number_with_delimiter @instance.blocks_count | |||
.dashboard__counters__label= t 'admin.instances.total_blocked_by_us' | |||
%div | |||
%div | |||
.dashboard__counters__num | |||
- if @instance.delivery_failure_tracker.available? | |||
= fa_icon 'check' | |||
- else | |||
= fa_icon 'times' | |||
.dashboard__counters__label= t 'admin.instances.delivery_available' | |||
- if @instance.private_comment.present? | |||
.speech-bubble | |||
.speech-bubble__bubble | |||
= simple_format(h(@instance.private_comment)) | |||
.speech-bubble__owner= t 'admin.instances.private_comment' | |||
- if @instance.public_comment.present? | |||
.speech-bubble | |||
.speech-bubble__bubble | |||
= simple_format(h(@instance.public_comment)) | |||
.speech-bubble__owner= t 'admin.instances.public_comment' | |||
- unless @exhausted_deliveries_days.empty? | |||
%h4= t 'admin.instances.delivery_error_days' | |||
%ul | |||
= render partial: 'exhausted_deliveries_days', collection: @exhausted_deliveries_days | |||
%p.hint | |||
= t 'admin.instances.delivery_error_hint', count: DeliveryFailureTracker::FAILURE_DAYS_THRESHOLD | |||
- content_for :header_tags do | |||
= javascript_pack_tag 'admin', async: true, crossorigin: 'anonymous' | |||
- content_for :heading_actions do | |||
= l(@time_period.first) | |||
= ' - ' | |||
= l(@time_period.last) | |||
%p | |||
= fa_icon 'info fw' | |||
= t('admin.instances.totals_time_period_hint_html') | |||
.dashboard | |||
.dashboard__item | |||
= react_admin_component :counter, measure: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_accounts_measure'), href: admin_accounts_path(origin: 'remote', by_domain: @instance.domain) | |||
.dashboard__item | |||
= react_admin_component :counter, measure: 'instance_statuses', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_statuses_measure') | |||
.dashboard__item | |||
= react_admin_component :counter, measure: 'instance_media_attachments', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_media_attachments_measure') | |||
.dashboard__item | |||
= react_admin_component :counter, measure: 'instance_follows', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_follows_measure') | |||
.dashboard__item | |||
= react_admin_component :counter, measure: 'instance_followers', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_followers_measure') | |||
.dashboard__item | |||
= react_admin_component :counter, measure: 'instance_reports', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_reports_measure'), href: admin_reports_path(by_target_domain: @instance.domain) | |||
.dashboard__item | |||
= react_admin_component :dimension, dimension: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_accounts_dimension') | |||
.dashboard__item | |||
= react_admin_component :dimension, dimension: 'instance_languages', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_languages_dimension') | |||
%hr.spacer/ | |||
%div.action-buttons | |||
%div | |||
- if @instance.domain_allow | |||
= link_to t('admin.domain_allows.undo'), admin_domain_allow_path(@instance.domain_allow), class: 'button button--destructive', data: { confirm: t('admin.accounts.are_you_sure'), method: :delete } | |||
- elsif @instance.domain_block | |||
= link_to t('admin.domain_blocks.edit'), edit_admin_domain_block_path(@instance.domain_block), class: 'button' | |||
= link_to t('admin.domain_blocks.undo'), admin_domain_block_path(@instance.domain_block), class: 'button' | |||
- else | |||
= link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @instance.domain), class: 'button' | |||
- if @instance.delivery_failure_tracker.available? | |||
- unless @exhausted_deliveries_days.empty? | |||
= link_to t('admin.instances.delivery.clear'), clear_delivery_errors_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }, class: 'button' | |||
= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }, class: 'button' | |||
%h3= t('admin.instances.content_policies.title') | |||
- if whitelist_mode? | |||
%p= t('admin.instances.content_policies.limited_federation_mode_description_html') | |||
- if @instance.domain_allow | |||
= link_to t('admin.domain_allows.undo'), admin_domain_allow_path(@instance.domain_allow), class: 'button button--destructive', data: { confirm: t('admin.accounts.are_you_sure'), method: :delete } | |||
- else | |||
= link_to t('admin.domain_allows.add_new'), admin_domain_allows_path(domain_allow: { domain: @instance.domain }), class: 'button', method: :post | |||
- else | |||
%p= t('admin.instances.content_policies.description_html') | |||
- if @instance.domain_block | |||
.table-wrapper | |||
%table.table.horizontal-table | |||
%tbody | |||
%tr | |||
%th= t('admin.instances.content_policies.comment') | |||
%td= @instance.domain_block.private_comment | |||
%tr | |||
%th= t('admin.instances.content_policies.reason') | |||
%td= @instance.domain_block.public_comment | |||
%tr | |||
%th= t('admin.instances.content_policies.policy') | |||
%td= @instance.domain_block.policies.map { |policy| t(policy, scope: 'admin.instances.content_policies.policies') }.join(' • ') | |||
= link_to t('admin.domain_blocks.edit'), edit_admin_domain_block_path(@instance.domain_block), class: 'button' | |||
= link_to t('admin.domain_blocks.undo'), admin_domain_block_path(@instance.domain_block), class: 'button', data: { confirm: t('admin.accounts.are_you_sure'), method: :delete } | |||
- else | |||
= link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @instance.domain), class: 'button' | |||
%hr.spacer/ | |||
%h3= t('admin.instances.availability.title') | |||
%p | |||
= t('admin.instances.availability.description_html', count: DeliveryFailureTracker::FAILURE_DAYS_THRESHOLD) | |||
.availability-indicator | |||
%ul.availability-indicator__graphic | |||
- @instance.availability_over_days(14).each do |(date, failing)| | |||
%li.availability-indicator__graphic__item{ class: failing ? 'negative' : 'neutral', title: l(date) } | |||
.availability-indicator__hint | |||
- if @instance.unavailable? | |||
%span.negative-hint | |||
= t('admin.instances.availability.failure_threshold_reached', date: l(@instance.unavailable_domain.created_at.to_date)) | |||
= link_to t('admin.instances.delivery.restart'), restart_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } | |||
- elsif @instance.exhausted_deliveries_days.empty? | |||
%span.positive-hint | |||
= t('admin.instances.availability.no_failures_recorded') | |||
= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } | |||
- else | |||
= link_to t('admin.instances.delivery.restart'), restart_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }, class: 'button' | |||
- if !@instance.delivery_failure_tracker.available? || @instance.accounts_count.zero? || @instance.domain_block&.suspend? | |||
= link_to t('admin.instances.purge'), admin_instance_path(@instance), data: { confirm: t('admin.instances.confirm_purge'), method: :delete }, class: 'button' | |||
%span.negative-hint | |||
= t('admin.instances.availability.failures_recorded', count: @instance.delivery_failure_tracker.days) | |||
= link_to t('admin.instances.delivery.clear'), clear_delivery_errors_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } unless @instance.exhausted_deliveries_days.empty? | |||
- if @instance.unavailable? | |||
%p= t('admin.instances.purge_description_html') | |||
= link_to t('admin.instances.purge'), admin_instance_path(@instance), data: { confirm: t('admin.instances.confirm_purge'), method: :delete }, class: 'button button--destructive' |