From d434f1aec70d5bffa2e7ee2a915d721258f8cc35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Tr=C3=A4nklein?= Date: Thu, 31 Oct 2024 10:26:51 +0100 Subject: [PATCH 1/6] fix(Runs): do not clear alerts on extra notification --- includes/services/class-test-run-service.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/includes/services/class-test-run-service.php b/includes/services/class-test-run-service.php index 9c3a2b0..7af81a3 100644 --- a/includes/services/class-test-run-service.php +++ b/includes/services/class-test-run-service.php @@ -5,6 +5,7 @@ use Vrts\Core\Utilities\Url_Helpers; use Vrts\Features\Service; use Vrts\Features\Subscription; +use Vrts\Models\Alert; use Vrts\Models\Test; use Vrts\Models\Test_Run; use Vrts\Services\Email_Service; @@ -23,11 +24,13 @@ public function update_run_from_api_data( $data ) { $test_run = Test_Run::get_by_service_test_run_id( $run_id ); $test_run_just_finished = false; - $alert_ids = []; + $alert_ids = $test_run ? maybe_unserialize( $test_run->alerts ) : []; if ( $test_run && empty( $test_run->finished_at ) && ! empty( $data['finished_at'] ) ) { $test_run_just_finished = true; $alert_ids = $this->update_tests_and_create_alerts( $data['comparisons'], $test_run ); + } elseif ( $test_run && ! empty( $test_run->finished_at ) ) { + $alert_ids = ! empty( $alert_ids ) ? $alert_ids : array_column(Alert::get_items_by_test_run( $test_run->id ), 'id'); } $test_ids = empty( $data['comparison_schedule_ids'] ) ? [] : array_map(function( $test ) { From 37632e6e22a822aa13ad97952b77e0321ea2efba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Tr=C3=A4nklein?= Date: Wed, 6 Nov 2024 10:48:38 +0100 Subject: [PATCH 2/6] feat: do no save alerts to test runs table --- .../list-tables/class-test-runs-list-table.php | 15 +++------------ includes/models/class-test-run.php | 12 ++++++++---- includes/services/class-test-run-service.php | 4 ---- includes/tables/class-test-runs-table.php | 11 +++++++++-- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/includes/list-tables/class-test-runs-list-table.php b/includes/list-tables/class-test-runs-list-table.php index 31e1dbb..e53bc27 100644 --- a/includes/list-tables/class-test-runs-list-table.php +++ b/includes/list-tables/class-test-runs-list-table.php @@ -160,14 +160,6 @@ public function prepare_items() { ]; $this->items = Test_Run::get_items( $args ); - $test_run_ids = wp_list_pluck( $this->items, 'id' ); - $alert_counts = []; - foreach ( Alert::get_unread_count_by_test_run_ids( $test_run_ids ) as $alert_count ) { - $alert_counts[ $alert_count->test_run_id ] = $alert_count->count; - } - foreach ( $this->items as $item ) { - $item->alerts_count = $alert_counts[ $item->id ] ?? 0; - } $total_items = 0; if ( null !== $args['filter_status'] ) { @@ -198,7 +190,7 @@ public function single_row( $item ) { class="" data-test-run-id="id ); ?>" data-test-run-new="" - alerts_count > 0 ? 'data-has-alerts' : ''; ?> + unread_alerts_count > 0 ? 'data-has-alerts' : ''; ?> > single_row_columns( $item ); ?> @@ -324,11 +316,10 @@ public function column_trigger( $item ) { * @return string */ public function column_status( $item ) { - $alerts_count = count( maybe_unserialize( $item->alerts ) ?? [] ); $tests_count = count( maybe_unserialize( $item->tests ) ?? [] ); - if ( $alerts_count > 0 ) { + if ( $item->alerts_count > 0 ) { $status_class = 'paused'; - $status_text = esc_html__( 'Changes detected ', 'visual-regression-tests' ) . sprintf( '(%s)', $alerts_count ); + $status_text = esc_html__( 'Changes detected ', 'visual-regression-tests' ) . sprintf( '(%s)', $item->alerts_count ); } else { $status_class = 'running'; diff --git a/includes/models/class-test-run.php b/includes/models/class-test-run.php index cb40afb..1899177 100644 --- a/includes/models/class-test-run.php +++ b/includes/models/class-test-run.php @@ -42,7 +42,7 @@ public static function get_items( $args = [], $return_count = false ) { if ( isset( $args['filter_status'] ) && null !== $args['filter_status'] ) { if ( 'changes-detected' === $args['filter_status'] ) { - $where .= ' AND alerts IS NOT NULL'; + $where .= ' AND alerts_count > 0'; } } @@ -82,7 +82,8 @@ public static function get_items( $args = [], $return_count = false ) { runs.id, $run_title, runs.tests, - runs.alerts, + SUM( IF( alerts.id IS NOT NULL, 1, 0 ) ) as alerts_count, + SUM( IF( alerts.id IS NOT NULL and alerts.alert_state = 0, 1, 0 ) ) as unread_alerts_count, runs.trigger, runs.trigger_notes, runs.trigger_meta, @@ -90,6 +91,9 @@ public static function get_items( $args = [], $return_count = false ) { runs.scheduled_at, runs.finished_at FROM $test_runs_table as runs + LEFT JOIN $alerts_table as alerts + ON runs.id = alerts.test_run_id + GROUP BY runs.id ) runs $where $orderby @@ -372,7 +376,7 @@ public static function get_calculated_status( $test_run ) { $test_run = self::get_item( $test_run ); } - $has_alerts = ! empty( maybe_unserialize( $test_run->alerts ) ); + $has_alerts = ( $test_run->alerts_count ?? 0 ) > 0; if ( $has_alerts ) { return 'has-alerts'; @@ -440,7 +444,7 @@ public static function get_status_data( $test_run ) { switch ( $test_run_status ) { case 'has-alerts': - $alerts_count = count( maybe_unserialize( $test_run->alerts ) ); + $alerts_count = $test_run->alerts_count; $class = 'paused'; $text = esc_html__( 'Changes detected', 'visual-regression-tests' ); $instructions = Date_Time_Helpers::get_formatted_relative_date_time( $test_run->finished_at ); diff --git a/includes/services/class-test-run-service.php b/includes/services/class-test-run-service.php index 7af81a3..0b35581 100644 --- a/includes/services/class-test-run-service.php +++ b/includes/services/class-test-run-service.php @@ -24,13 +24,10 @@ public function update_run_from_api_data( $data ) { $test_run = Test_Run::get_by_service_test_run_id( $run_id ); $test_run_just_finished = false; - $alert_ids = $test_run ? maybe_unserialize( $test_run->alerts ) : []; if ( $test_run && empty( $test_run->finished_at ) && ! empty( $data['finished_at'] ) ) { $test_run_just_finished = true; $alert_ids = $this->update_tests_and_create_alerts( $data['comparisons'], $test_run ); - } elseif ( $test_run && ! empty( $test_run->finished_at ) ) { - $alert_ids = ! empty( $alert_ids ) ? $alert_ids : array_column(Alert::get_items_by_test_run( $test_run->id ), 'id'); } $test_ids = empty( $data['comparison_schedule_ids'] ) ? [] : array_map(function( $test ) { @@ -44,7 +41,6 @@ public function update_run_from_api_data( $data ) { $test_run_id = $this->create_test_run( $data['run_id'], [ 'tests' => maybe_serialize( $test_ids ), - 'alerts' => ! empty( $alert_ids ) ? maybe_serialize( $alert_ids ) : null, 'started_at' => $data['started_at'], 'finished_at' => $data['finished_at'], 'scheduled_at' => $data['scheduled_at'], diff --git a/includes/tables/class-test-runs-table.php b/includes/tables/class-test-runs-table.php index e307c71..eb0cd00 100644 --- a/includes/tables/class-test-runs-table.php +++ b/includes/tables/class-test-runs-table.php @@ -4,7 +4,7 @@ class Test_Runs_Table { - const DB_VERSION = '1.0'; + const DB_VERSION = '1.1'; const TABLE_NAME = 'vrts_test_runs'; /** @@ -32,7 +32,6 @@ public static function install_table() { id bigint(20) unsigned NOT NULL AUTO_INCREMENT, service_test_run_id varchar(40), tests text, - alerts text default NULL, `trigger` varchar(20), trigger_notes text, trigger_meta text default NULL, @@ -117,6 +116,10 @@ public static function create_runs_from_alerts() { return "('" . implode( "','", array_map( 'esc_sql', $run ) ) . "')"; }, $test_runs)); + // add alerts column to test_runs table. + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.SchemaChange + $wpdb->query( "ALTER TABLE {$runs_table} ADD COLUMN alerts text;" ); + // insert all test runs with single query. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $wpdb->query( "INSERT INTO {$runs_table} (tests, alerts, `trigger`, started_at, finished_at) VALUES " . $test_runs_values . ';' ); @@ -125,6 +128,10 @@ public static function create_runs_from_alerts() { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $wpdb->query( "UPDATE {$alerts_table} a JOIN {$runs_table} r ON r.alerts LIKE CONCAT('%\"', a.id, '\"%') SET a.test_run_id = r.id;" ); + // remove alerts column from test_runs table. + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.SchemaChange + $wpdb->query( "ALTER TABLE {$runs_table} DROP COLUMN alerts;" ); + return true; } } From 86a9659516fca70d8303071fe944beb5713306a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harun=20Ba=C5=A1i=C4=87?= Date: Wed, 6 Nov 2024 12:25:36 +0100 Subject: [PATCH 3/6] fix(TestRun): sticky heading z-index issue --- components/test-run-alerts/_style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/test-run-alerts/_style.scss b/components/test-run-alerts/_style.scss index 72eaf45..f9356fe 100644 --- a/components/test-run-alerts/_style.scss +++ b/components/test-run-alerts/_style.scss @@ -30,7 +30,7 @@ padding: 0 20px; position: sticky; top: -0.1px; - z-index: 1; + z-index: 3; } &-link { From e07dc600a9ea4d72fb3829a45d057dc88133029e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harun=20Ba=C5=A1i=C4=87?= Date: Wed, 6 Nov 2024 12:27:01 +0100 Subject: [PATCH 4/6] fix(Helpers): deprecated notice --- includes/core/utilities/class-image-helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/utilities/class-image-helpers.php b/includes/core/utilities/class-image-helpers.php index 38df4dc..1407bab 100644 --- a/includes/core/utilities/class-image-helpers.php +++ b/includes/core/utilities/class-image-helpers.php @@ -45,7 +45,7 @@ public static function alert_image_aspect_ratio( $alert ) { * @return string */ public static function get_screenshot_url( $object, $type, $size = 'full' ) { - $property = "${type}_screenshot_url"; + $property = "{$type}_screenshot_url"; if ( ! property_exists( $object, $property ) ) { return ''; From 6c3c3bc33d2a9377c7591156b89e4b62ea65f759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harun=20Ba=C5=A1i=C4=87?= Date: Wed, 6 Nov 2024 12:27:34 +0100 Subject: [PATCH 5/6] fix(Onboarding): use correct navigation selectors --- includes/features/class-onboarding.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/features/class-onboarding.php b/includes/features/class-onboarding.php index ba8a7bc..d63759e 100644 --- a/includes/features/class-onboarding.php +++ b/includes/features/class-onboarding.php @@ -112,7 +112,7 @@ public function get_onboardings() { 'description' => wp_kses_post( __( 'Starting from tomorrow, your Test will run daily, ensuring consistent monitoring of your page.', 'visual-regression-tests' ) ), ], [ - 'element' => '.vrts_navigation_item a[href$="admin.php?page=vrts-settings"]', + 'element' => '.vrts-admin-header__navigation-link[href$="admin.php?page=vrts-settings"]', 'title' => wp_kses_post( __( '🛠️ Fine-tune your setup', 'visual-regression-tests' ) ), 'description' => wp_kses_post( __( 'Further customize your Test configuration and plugin settings for an optimized experience.', 'visual-regression-tests' ) ), ], @@ -137,7 +137,7 @@ public function get_onboardings() { [ 'side' => 'bottom', 'align' => 'center', - 'element' => '.vrts_navigation_item a[href$="admin.php?page=vrts-runs"]', + 'element' => '.vrts-admin-header__navigation-link[href$="admin.php?page=vrts-runs"]', 'title' => wp_kses_post( __( '🚀 Meet the new Runs!', 'visual-regression-tests' ) ), 'description' => wp_kses_post( __( 'Alerts are now bundled into Runs. Get a single report for each daily test, manual test, API trigger, or new: WordPress & plugin update (Pro)!', 'visual-regression-tests' ) ), ], From 46722302b31e322b1a5f0d4b9175e30a8149be7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Tr=C3=A4nklein?= Date: Thu, 7 Nov 2024 11:39:30 +0100 Subject: [PATCH 6/6] feat(Runs): convert temporary alerts column to bigint --- includes/tables/class-test-runs-table.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/includes/tables/class-test-runs-table.php b/includes/tables/class-test-runs-table.php index eb0cd00..bb31e39 100644 --- a/includes/tables/class-test-runs-table.php +++ b/includes/tables/class-test-runs-table.php @@ -105,7 +105,7 @@ public static function create_runs_from_alerts() { 'permalink' => get_permalink( $alert->post_id ), ], ] ), - 'alerts' => maybe_serialize( [ $alert->id ] ), + 'alert_id' => $alert->id, 'trigger' => 'legacy', 'started_at' => $alert->finished_at, 'finished_at' => $alert->finished_at, @@ -116,21 +116,21 @@ public static function create_runs_from_alerts() { return "('" . implode( "','", array_map( 'esc_sql', $run ) ) . "')"; }, $test_runs)); - // add alerts column to test_runs table. + // add alert_id column to test_runs table. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.SchemaChange - $wpdb->query( "ALTER TABLE {$runs_table} ADD COLUMN alerts text;" ); + $wpdb->query( "ALTER TABLE {$runs_table} ADD COLUMN alert_id bigint(20) unsigned;" ); // insert all test runs with single query. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared - $wpdb->query( "INSERT INTO {$runs_table} (tests, alerts, `trigger`, started_at, finished_at) VALUES " . $test_runs_values . ';' ); + $wpdb->query( "INSERT INTO {$runs_table} (tests, alert_id, `trigger`, started_at, finished_at) VALUES " . $test_runs_values . ';' ); - // update test_run_id in alerts table from newly created test runs based on alerts column. + // update test_run_id in alerts table from newly created test runs based on alert_id column. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared - $wpdb->query( "UPDATE {$alerts_table} a JOIN {$runs_table} r ON r.alerts LIKE CONCAT('%\"', a.id, '\"%') SET a.test_run_id = r.id;" ); + $wpdb->query( "UPDATE {$alerts_table} a JOIN {$runs_table} r ON r.alert_id = a.id SET a.test_run_id = r.id;" ); - // remove alerts column from test_runs table. + // remove alert_id column from test_runs table. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.SchemaChange - $wpdb->query( "ALTER TABLE {$runs_table} DROP COLUMN alerts;" ); + $wpdb->query( "ALTER TABLE {$runs_table} DROP COLUMN alert_id;" ); return true; }