This commit is contained in:
2026-07-02 15:54:39 -06:00
commit 9883323161
17470 changed files with 4470592 additions and 0 deletions
@@ -0,0 +1,251 @@
<?php
namespace Vrts\Features;
use Vrts\Core\Utilities\Url_Helpers;
use Vrts\List_Tables\Test_Runs_List_Table;
use Vrts\List_Tables\Test_Runs_Queue_List_Table;
use Vrts\Models\Alert;
use Vrts\Models\Test;
use Vrts\Models\Test_Run;
use Vrts\Services\Test_Run_Service;
class Test_Runs_Page {
/**
* Constructor.
*/
public function __construct() {
add_action( 'admin_init', [ $this, 'remove_admin_notices' ], 99 );
add_action( 'admin_menu', [ $this, 'add_submenu_page' ] );
add_action( 'admin_body_class', [ $this, 'add_body_class' ] );
}
/**
* Remove admin notices.
*/
public function remove_admin_notices() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here.
if ( isset( $_GET['page'] ) && 'vrts-runs' === $_GET['page'] && isset( $_GET['run_id'] ) ) {
remove_all_actions( 'admin_notices' );
}
}
/**
* Add submenu.
*/
public function add_submenu_page() {
$count = Alert::get_total_items_grouped_by_test_run();
$submenu_page = add_submenu_page(
'vrts',
__( 'Runs', 'visual-regression-tests' ),
$count ? esc_html__( 'Runs', 'visual-regression-tests' ) . '&nbsp;<span class="update-plugins" title="' . esc_attr( $count ) . '">' . esc_html( $count ) . '</span>' : esc_html__( 'Runs', 'visual-regression-tests' ),
'manage_options',
'vrts-runs',
[ $this, 'render_page' ],
1
);
//phpcs:ignore WordPress.Security.NonceVerification.Recommended -- It's ok.
if ( ! isset( $_GET['run_id'] ) ) {
add_action( 'load-' . $submenu_page, [ $this, 'screen_option' ] );
add_action( 'load-' . $submenu_page, [ $this, 'init_notifications' ] );
}
}
/**
* Add screen options.
*/
public function screen_option() {
// Set Screen Option.
$option = 'per_page';
$args = [
'default' => 20,
'option' => 'vrts_test_runs_per_page',
];
// screen_option are user meta.
add_screen_option( $option, $args );
}
/**
* Add body class.
*
* @param string $classes Body classes.
*/
public function add_body_class( $classes ) {
//phpcs:ignore WordPress.Security.NonceVerification.Recommended -- It's ok.
if ( isset( $_GET['run_id'] ) ) {
$classes .= ' vrts-test-run-wrap';
}
return $classes;
}
/**
* Render page
*/
public function render_page() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- It's ok.
$run_id = intval( $_GET['run_id'] ?? 0 );
$run = Test_Run::get_item( $run_id );
if ( $run ) {
$tests = $this->prepare_tests( maybe_unserialize( $run->tests ) );
$alerts = $this->prepare_alerts( $run_id, $tests );
list($alert_id, $alert) = $this->get_alert( $alerts );
$test = $alert ? Test::get_item_by_post_id( $alert->post_id ) : null;
$is_receipt = 'receipt' === $alert_id;
list( $current_pagination, $prev_alert_id, $next_alert_id ) = $this->get_pagination( $alerts, $alert_id );
vrts()->component('test-run-page', [
'run' => $run,
'alerts' => $alerts,
'alert' => $alert,
'is_receipt' => $is_receipt,
'pagination' => [
'prev_alert_id' => $prev_alert_id,
'next_alert_id' => $next_alert_id,
'current' => $current_pagination,
'total' => count( $alerts ),
],
'tests' => $tests,
'test_settings' => [
'test_id' => isset( $test->id ) ? $test->id : null,
'hide_css_selectors' => isset( $test->hide_css_selectors ) ? $test->hide_css_selectors : null,
],
]);
} else {
vrts()->component('test-runs-page', [
// phpcs:ignore WordPress.Security.NonceVerification.Missing -- It's ok.
'search_query' => sanitize_text_field( wp_unslash( $_POST['s'] ?? '' ) ),
'list_table' => new Test_Runs_List_Table(),
'list_queue_table' => new Test_Runs_Queue_List_Table(),
]);
}//end if
}
/**
* Prepare alerts.
*
* @param array $tests Tests.
*/
private function prepare_tests( $tests ) {
if ( is_array( $tests ) && count( $tests ) > 0 && ! is_array( $tests[0] ) ) {
$tests = array_map( function ( $test ) {
$test = (int) $test;
$post_id = Test::get_post_id( $test );
return [
'id' => $test,
'post_id' => $post_id,
'post_title' => get_the_title( $post_id ),
'permalink' => get_permalink( $post_id ),
];
}, $tests );
}
usort( $tests, function ( $a, $b ) {
return $a['id'] > $b['id'] ? -1 : 1;
} );
return $tests;
}
/**
* Prepare alerts.
*
* @param int $run_id Run ID.
* @param array $tests Tests.
*/
private function prepare_alerts( $run_id, $tests ) {
$alerts = Alert::get_items_by_test_run( $run_id );
$alerts_by_post_id = [];
foreach ( $alerts as $alert ) {
$alerts_by_post_id[ $alert->post_id ][] = $alert;
}
$sorted_alerts = [];
foreach ( $tests as $test ) {
if ( isset( $alerts_by_post_id[ $test['post_id'] ] ) ) {
$sorted_alerts = array_merge( $sorted_alerts, $alerts_by_post_id[ $test['post_id'] ] );
unset( $alerts_by_post_id[ $test['post_id'] ] );
}
}
$remaining_alerts = array_values( $alerts_by_post_id );
usort( $remaining_alerts, function ( $a, $b ) {
return $a[0]->post_id > $b[0]->post_id ? -1 : 1;
} );
foreach ( $remaining_alerts as $remaining_alert ) {
$sorted_alerts = array_merge( $sorted_alerts, $remaining_alert );
}
return $sorted_alerts;
}
/**
* Get pagination.
*
* @param array $alerts Alerts.
* @param int $alert_id Alert ID.
*/
private function get_pagination( $alerts, $alert_id ) {
if ( 'receipt' === $alert_id ) {
$current_pagination = count( $alerts );
$prev_alert_id = $alerts[ count( $alerts ) - 1 ]->id ?? 0;
$next_alert_id = 0;
} else {
$current_index = ( array_keys( array_filter( $alerts, function ( $alert ) use ( $alert_id ) {
return $alert->id === $alert_id;
} ) )[0] ?? 0 );
$prev_alert_id = $alerts[ $current_index - 1 ]->id ?? 0;
$next_alert_id = $alerts[ $current_index + 1 ]->id ?? 0;
$current_pagination = $current_index + 1;
if ( ! $next_alert_id ) {
$next_alert_id = 'receipt';
}
}
return [ $current_pagination, $prev_alert_id, $next_alert_id ];
}
/**
* Get alert.
*
* @param array $alerts Alerts.
*/
private function get_alert( $alerts ) {
$first_alert_id = isset( $alerts[0] ) ? $alerts[0]->id : 0;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here.
$alert_id = sanitize_text_field( wp_unslash( $_GET['alert_id'] ?? $first_alert_id ) );
if ( 'receipt' === $alert_id ) {
return [ 'receipt', null ];
}
$alert = Alert::get_item( $alert_id );
if ( ! $alert ) {
$alert_id = $first_alert_id;
$alert = Alert::get_item( $alert_id );
}
return [ $alert_id, $alert ];
}
/**
* Init notifications.
*/
public function init_notifications() {
if ( ! Service::is_connected() ) {
add_action( 'admin_notices', [ $this, 'render_notification_connection_failed' ] );
}
}
/**
* Render connection_failed Notification.
*/
public function render_notification_connection_failed() {
Admin_Notices::render_notification( 'connection_failed' );
}
}