Skip to content

Commit

Permalink
Merge pull request #5900 from ampproject/fix/5772-delayed-validation-…
Browse files Browse the repository at this point in the history
…error-count-display

Delay showing the unreviewed counts of validated URLs and errors; remove 'At a Glance' widget
  • Loading branch information
westonruter committed Feb 23, 2021
2 parents 4a91d53 + f1005a9 commit f2af134
Show file tree
Hide file tree
Showing 17 changed files with 558 additions and 134 deletions.
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
"plugin:import/recommended",
"plugin:eslint-comments/recommended"
],
"env": {
"browser": true
},
"rules": {
"block-scoped-var": "error",
"complexity": ["error", { "max": 20 } ],
Expand Down
2 changes: 2 additions & 0 deletions .phpstorm.meta.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
'admin.options_menu' => \AmpProject\AmpWP\Admin\OptionsMenu::class,
'admin.polyfills' => \AmpProject\AmpWP\Admin\Polyfills::class,
'admin.paired_browsing' => \AmpProject\AmpWP\Admin\PairedBrowsing::class,
'admin.validation_counts' => \AmpProject\AmpWP\Admin\ValidationCounts::class,
'amp_slug_customization_watcher' => \AmpProject\AmpWP\AmpSlugCustomizationWatcher::class,
'css_transient_cache.ajax_handler' => \AmpProject\AmpWP\Admin\ReenableCssTransientCachingAjaxAction::class,
'css_transient_cache.monitor' => \AmpProject\AmpWP\BackgroundTask\MonitorCssTransientCaching::class,
Expand All @@ -33,6 +34,7 @@
'plugin_suppression' => \AmpProject\AmpWP\PluginSuppression::class,
'reader_theme_loader' => \AmpProject\AmpWP\ReaderThemeLoader::class,
'rest.options_controller' => \AmpProject\AmpWP\OptionsRESTController::class,
'rest.validation_counts_controller' => \AmpProject\AmpWP\Validation\ValidationCountsRestController::class,
'server_timing' => \AmpProject\AmpWP\Instrumentation\ServerTiming::class,
'site_health_integration' => \AmpProject\AmpWP\Admin\SiteHealth::class,
'validated_url_stylesheet_gc' => \AmpProject\AmpWP\BackgroundTask\ValidatedUrlStylesheetDataGarbageCollection::class,
Expand Down
2 changes: 1 addition & 1 deletion assets/js/amp-service-worker-runtime-precaching.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global self, caches, URLS */
/* global URLS */
// See AMP_Service_Workers::add_amp_runtime_caching() and <https://github.com/ampproject/amp-by-example/blob/a4d798cac6a534e0c46e78944a2718a8dab3c057/boilerplate-generator/templates/files/serviceworkerJs.js#L9-L22>.
{
self.addEventListener( 'install', ( event ) => {
Expand Down
95 changes: 95 additions & 0 deletions assets/src/amp-validation/counts/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import domReady from '@wordpress/dom-ready';

/**
* Internal dependencies
*/
import './style.css';

/**
* Updates a menu item with its count.
*
* If the count is not a number or is `0`, the element that contains the count is instead removed (as it would be no longer relevant).
*
* @param {HTMLElement} itemEl Menu item element.
* @param {number} count Count to set.
*/
function updateMenuItem( itemEl, count ) {
if ( isNaN( count ) || count === 0 ) {
itemEl.parentNode.parentNode.removeChild( itemEl.parentNode );
} else {
itemEl.classList.remove( 'loading' );
itemEl.textContent = count.toLocaleString();
}
}

/**
* Updates the 'Validated URLs' and 'Error Index' menu items with their respective unreviewed count.
*
* @param {Object} counts Counts for menu items.
* @param {number} counts.validated_urls Unreviewed validated URLs count.
* @param {number} counts.errors Unreviewed validation errors count.
*/
function updateMenuItemCounts( counts ) {
const { validated_urls: newValidatedUrlCount, errors: newErrorCount } = counts;

const errorCountEl = document.getElementById( 'new-error-index-count' );
if ( errorCountEl ) {
updateMenuItem( errorCountEl, newErrorCount );
}

const validatedUrlsCountEl = document.getElementById( 'new-validation-url-count' );
if ( validatedUrlsCountEl ) {
updateMenuItem( validatedUrlsCountEl, newValidatedUrlCount );
}
}

/**
* Fetches the validation counts only when the AMP submenu is open for the first time.
*
* @param {HTMLElement} root AMP submenu item.
*/
function createObserver( root ) {
// IntersectionObserver is not available in IE11, so just hide the counts entirely for that browser.
if ( ! ( 'IntersectionObserver' in window ) ) {
updateMenuItemCounts( { validated_urls: 0, errors: 0 } );
return;
}

const target = root.querySelector( 'ul' );

const observer = new IntersectionObserver( ( [ entry ] ) => {
if ( ! entry || ! entry.isIntersecting ) {
return;
}

observer.unobserve( target );

apiFetch( { path: '/amp/v1/unreviewed-validation-counts' } ).then( ( counts ) => {
updateMenuItemCounts( counts );
} ).catch( ( error ) => {
updateMenuItemCounts( { validated_urls: 0, errors: 0 } );

const message = error?.message || __( 'An unknown error occurred while retrieving the validation counts', 'amp' );
// eslint-disable-next-line no-console
console.error( `[AMP Plugin] ${ message }` );
} );
}, { root } );

observer.observe( target );
}

domReady( () => {
const ampMenuItem = document.getElementById( 'toplevel_page_amp-options' );

// Bail if the AMP submenu is not in the DOM.
if ( ! ampMenuItem ) {
return;
}

createObserver( ampMenuItem );
} );
24 changes: 24 additions & 0 deletions assets/src/amp-validation/counts/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@keyframes rotate-forever {

0% {
transform: rotate(0deg);
}

100% {
transform: rotate(360deg);
}
}

#toplevel_page_amp-options > ul > li span.loading {
animation-duration: 0.75s;
animation-iteration-count: infinite;
animation-name: rotate-forever;
animation-timing-function: linear;
height: 4px;
width: 4px;
border: 2px solid #fff;
border-right-color: transparent;
border-top-color: transparent;
border-radius: 50%;
display: inline-block;
}
81 changes: 3 additions & 78 deletions includes/validation/class-amp-validated-url-post-type.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
* @package AMP
*/

use AmpProject\AmpWP\DevTools\UserAccess;
use AmpProject\AmpWP\Admin\OptionsMenu;
use AmpProject\AmpWP\Icon;
use AmpProject\AmpWP\PluginRegistry;
use AmpProject\AmpWP\Option;
use AmpProject\AmpWP\QueryVar;
use AmpProject\AmpWP\Services;
Expand Down Expand Up @@ -270,13 +268,6 @@ public static function handle_plugin_update( $old_version ) {
public static function add_admin_hooks() {
add_action( 'admin_enqueue_scripts', [ __CLASS__, 'enqueue_post_list_screen_scripts' ] );

$dev_tools_user_access = Services::get( 'dev_tools.user_access' );

if ( $dev_tools_user_access->is_user_enabled() ) {
add_filter( 'dashboard_glance_items', [ __CLASS__, 'filter_dashboard_glance_items' ] );
add_action( 'rightnow_end', [ __CLASS__, 'print_dashboard_glance_styles' ] );
}

// Edit post screen hooks.
add_action( 'admin_enqueue_scripts', [ __CLASS__, 'enqueue_edit_post_screen_scripts' ] );
add_action( 'add_meta_boxes', [ __CLASS__, 'add_meta_boxes' ], PHP_INT_MAX );
Expand Down Expand Up @@ -490,11 +481,8 @@ public static function update_validated_url_menu_item() {
$menu_name_label = get_post_type_object( self::POST_TYPE_SLUG )->labels->menu_name;
$submenu_item[0] = $menu_name_label;

// Display the count of new validation errors next to the label, if there are any.
$new_validation_error_url_count = self::get_validation_error_urls_count();
if ( 0 < $new_validation_error_url_count ) {
$submenu_item[0] .= ' <span class="awaiting-mod"><span class="new-validation-error-urls-count">' . esc_html( number_format_i18n( $new_validation_error_url_count ) ) . '</span></span>';
}
// Append markup to display a loading spinner while the unreviewed count is being fetched.
$submenu_item[0] .= ' <span class="awaiting-mod"><span id="new-validation-url-count" class="loading"></span></span>';
break;
}
}
Expand All @@ -507,7 +495,7 @@ public static function update_validated_url_menu_item() {
*
* @return int Count of new validation error URLs.
*/
protected static function get_validation_error_urls_count() {
public static function get_validation_error_urls_count() {
$count = get_transient( static::NEW_VALIDATION_ERROR_URLS_COUNT_TRANSIENT );
if ( false !== $count ) {
// Handle case where integer stored in transient gets returned as string when persistent object cache is not
Expand Down Expand Up @@ -2937,69 +2925,6 @@ public static function get_recheck_url( $url_or_post ) {
);
}

/**
* Filter At a Glance items add AMP Validation Errors.
*
* @param array $items At a glance items.
* @return array Items.
*/
public static function filter_dashboard_glance_items( $items ) {
$count = self::get_validation_error_urls_count();

if ( 0 !== $count ) {
$items[] = sprintf(
'<a class="amp-validation-errors" href="%s">%s</a>',
esc_url(
admin_url(
add_query_arg(
[
'post_type' => self::POST_TYPE_SLUG,
AMP_Validation_Error_Taxonomy::VALIDATION_ERROR_STATUS_QUERY_VAR => [
AMP_Validation_Error_Taxonomy::VALIDATION_ERROR_NEW_REJECTED_STATUS,
AMP_Validation_Error_Taxonomy::VALIDATION_ERROR_NEW_ACCEPTED_STATUS,
],
],
'edit.php'
)
)
),
esc_html(
sprintf(
/* translators: %s is the validation error count */
_n(
'%s URL w/ new AMP errors',
'%s URLs w/ new AMP errors',
$count,
'amp'
),
number_format_i18n( $count )
)
)
);
}
return $items;
}

/**
* Print styles for the At a Glance widget.
*/
public static function print_dashboard_glance_styles() {
?>
<style>
#dashboard_right_now .amp-validation-errors {
color: #a00;
}
#dashboard_right_now .amp-validation-errors:before {
content: "\f534";
}
#dashboard_right_now .amp-validation-errors:hover {
color: #dc3232;
border: none;
}
</style>
<?php
}

/**
* Filters the document title on the single URL page at /wp-admin/post.php.
*
Expand Down
10 changes: 2 additions & 8 deletions includes/validation/class-amp-validation-error-taxonomy.php
Original file line number Diff line number Diff line change
Expand Up @@ -1741,14 +1741,8 @@ public static function filter_tag_row_actions( $actions, WP_Term $tag ) {
*/
public static function add_admin_menu_validation_error_item() {
$menu_item_label = esc_html__( 'Error Index', 'amp' );
$new_error_count = self::get_validation_error_count(
[
'group' => [ self::VALIDATION_ERROR_NEW_REJECTED_STATUS, self::VALIDATION_ERROR_NEW_ACCEPTED_STATUS ],
]
);
if ( $new_error_count ) {
$menu_item_label .= ' <span class="awaiting-mod"><span class="pending-count">' . esc_html( number_format_i18n( $new_error_count ) ) . '</span></span>';
}
// Append markup to display a loading spinner while the unreviewed count is being fetched.
$menu_item_label .= ' <span class="awaiting-mod"><span id="new-error-index-count" class="loading"></span></span>';

$post_menu_slug = 'edit.php?post_type=' . AMP_Validated_URL_Post_Type::POST_TYPE_SLUG;
$term_menu_slug = 'edit-tags.php?taxonomy=' . self::TAXONOMY_SLUG . '&post_type=' . AMP_Validated_URL_Post_Type::POST_TYPE_SLUG;
Expand Down
82 changes: 82 additions & 0 deletions src/Admin/ValidationCounts.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php
/**
* Class ValidatedUrlCounts.
*
* @package AmpProject\AmpWP
*/

namespace AmpProject\AmpWP\Admin;

use AmpProject\AmpWP\Infrastructure\Conditional;
use AmpProject\AmpWP\Infrastructure\Delayed;
use AmpProject\AmpWP\Infrastructure\Registerable;
use AmpProject\AmpWP\Infrastructure\Service;
use AmpProject\AmpWP\Services;

/**
* Loads assets necessary to retrieve and show the unreviewed counts for validated URLs and validation errors in
* the AMP admin menu.
*
* @since 2.1
* @internal
*/
final class ValidationCounts implements Service, Registerable, Conditional, Delayed {

/**
* Assets handle.
*
* @var string
*/
const ASSETS_HANDLE = 'amp-validation-counts';

/**
* Get the action to use for registering the service.
*
* @return string Registration action to use.
*/
public static function get_registration_action() {
return 'admin_enqueue_scripts';
}

/**
* Check whether the conditional object is currently needed.
*
* @return bool Whether the conditional object is needed.
*/
public static function is_needed() {
$dev_tools_user_access = Services::get( 'dev_tools.user_access' );
return $dev_tools_user_access->is_user_enabled();
}

/**
* Runs on instantiation.
*/
public function register() {
$this->enqueue_scripts();
}

/**
* Enqueue admin assets.
*/
public function enqueue_scripts() {
$asset_file = AMP__DIR__ . '/assets/js/' . self::ASSETS_HANDLE . '.asset.php';
$asset = require $asset_file;
$dependencies = $asset['dependencies'];
$version = $asset['version'];

wp_enqueue_script(
self::ASSETS_HANDLE,
amp_get_asset_url( 'js/' . self::ASSETS_HANDLE . '.js' ),
$dependencies,
$version,
true
);

wp_enqueue_style(
self::ASSETS_HANDLE,
amp_get_asset_url( 'css/' . self::ASSETS_HANDLE . '.css' ),
false,
$version
);
}
}
2 changes: 2 additions & 0 deletions src/AmpWpPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ final class AmpWpPlugin extends ServiceBasedPlugin {
'admin.options_menu' => Admin\OptionsMenu::class,
'admin.polyfills' => Admin\Polyfills::class,
'admin.paired_browsing' => Admin\PairedBrowsing::class,
'admin.validation_counts' => Admin\ValidationCounts::class,
'amp_slug_customization_watcher' => AmpSlugCustomizationWatcher::class,
'css_transient_cache.ajax_handler' => Admin\ReenableCssTransientCachingAjaxAction::class,
'css_transient_cache.monitor' => BackgroundTask\MonitorCssTransientCaching::class,
Expand All @@ -84,6 +85,7 @@ final class AmpWpPlugin extends ServiceBasedPlugin {
'plugin_suppression' => PluginSuppression::class,
'reader_theme_loader' => ReaderThemeLoader::class,
'rest.options_controller' => OptionsRESTController::class,
'rest.validation_counts_controller' => Validation\ValidationCountsRestController::class,
'server_timing' => Instrumentation\ServerTiming::class,
'site_health_integration' => Admin\SiteHealth::class,
'validated_url_stylesheet_gc' => BackgroundTask\ValidatedUrlStylesheetDataGarbageCollection::class,
Expand Down
2 changes: 0 additions & 2 deletions src/DevTools/UserAccess.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ final class UserAccess implements Service, Registerable {

/**
* Runs on instantiation.
*
* @action rest_api_init
*/
public function register() {
add_action( 'rest_api_init', [ $this, 'register_rest_field' ] );
Expand Down
Loading

0 comments on commit f2af134

Please sign in to comment.