initial
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
@import "@wordpress/base-styles/mixins";
|
||||
@import "@wordpress/base-styles/breakpoints";
|
||||
@import "@wordpress/base-styles/variables";
|
||||
@import "@wordpress/base-styles/default-custom-properties";
|
||||
|
||||
.vrts-admin-header {
|
||||
box-sizing: border-box;
|
||||
background: $white;
|
||||
border-bottom: 1px solid $light-gray-500;
|
||||
margin-left: -20px;
|
||||
padding-left: 20px;
|
||||
padding-top: 0;
|
||||
height: 54px;
|
||||
display: flex;
|
||||
gap: 25px;
|
||||
|
||||
@media (max-width: $break-small) {
|
||||
height: calc(54px + 46px);
|
||||
padding-top: 46px;
|
||||
}
|
||||
|
||||
@media (max-width: $break-medium) {
|
||||
margin-left: -10px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
+ #wpbody {
|
||||
|
||||
@media (max-width: 600px) {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__logo {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
|
||||
&-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
svg {
|
||||
|
||||
path {
|
||||
fill: $gray-700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-text {
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
|
||||
@media (max-width: $break-medium) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__navigation {
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
|
||||
@media (max-width: $break-medium) {
|
||||
gap: 20px;
|
||||
overflow: auto;
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-item {
|
||||
display: flex;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-link {
|
||||
position: relative;
|
||||
padding: 16px 20px;
|
||||
text-decoration: none;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background: var(--vrts-admin-theme-color);
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
[aria-current="true"] & {
|
||||
border-bottom-color: var(--vrts-admin-theme-color);
|
||||
font-weight: 600;
|
||||
|
||||
&::after {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--vrts-admin-theme-color);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: inset 0 0 0 2px var(--vrts-admin-theme-color);
|
||||
}
|
||||
|
||||
// required to match the color scheme
|
||||
&:not(:hover):not(:focus) {
|
||||
color: $gray-text;
|
||||
}
|
||||
}
|
||||
|
||||
&-button {
|
||||
align-self: center;
|
||||
border: 1px solid var(--vrts-admin-theme-color);
|
||||
border-radius: 50px;
|
||||
padding: 8px 14px;
|
||||
margin-left: 20px;
|
||||
color: var(--vrts-admin-theme-color);
|
||||
text-decoration: none;
|
||||
|
||||
&::after {
|
||||
content: attr(title);
|
||||
position: relative;
|
||||
display: block;
|
||||
font-weight: 700;
|
||||
height: 1px;
|
||||
color: transparent;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
[aria-current="true"] & {
|
||||
border: 1px solid var(--vrts-admin-theme-color);
|
||||
background: rgba(var(--vrts-admin-theme-color--rgb), 0.1);
|
||||
font-weight: initial;
|
||||
}
|
||||
|
||||
@media (max-width: $break-medium) {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 2px var(--vrts-admin-theme-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.update-plugins {
|
||||
background-color: $alert-red;
|
||||
border-radius: 9px;
|
||||
box-sizing: border-box;
|
||||
color: $white;
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
height: 18px;
|
||||
line-height: 1.6;
|
||||
margin: 0 0 -1px 0;
|
||||
min-width: 18px;
|
||||
padding: 0 5px;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
|
||||
&::after {
|
||||
display: block;
|
||||
content: attr(title);
|
||||
font-weight: 700;
|
||||
height: 1px;
|
||||
color: transparent;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<nav class="vrts-admin-header">
|
||||
<a class="vrts-admin-header__logo" href="<?php echo esc_url( Url_Helpers::get_page_url( 'tests' ) ); ?>">
|
||||
<span class="vrts-admin-header__logo-icon"><?php vrts()->logo(); ?></span>
|
||||
<h2 class="vrts-admin-header__logo-text"><?php echo esc_html( $data['plugin_name'] ); ?></h2>
|
||||
</a>
|
||||
<ul class="vrts-admin-header__navigation">
|
||||
<?php
|
||||
$allowed_html_into_text = [
|
||||
'span' => [
|
||||
'class' => [],
|
||||
'title' => [],
|
||||
],
|
||||
];
|
||||
$allowed_html_into_title = [];
|
||||
foreach ( $data['menu_items'] as $menu_item ) {
|
||||
printf(
|
||||
'<li class="vrts-admin-header__navigation-item" aria-current="%1$s"><a class="vrts-admin-header__navigation-%5$s" href="%2$s" title="%3$s">%4$s</a></li>',
|
||||
! empty( $menu_item['is_active'] ) ? 'true' : 'false',
|
||||
esc_url( $menu_item['url'] ),
|
||||
wp_kses( $menu_item['text'], $allowed_html_into_title ),
|
||||
wp_kses( $menu_item['text'], $allowed_html_into_text ),
|
||||
esc_attr( strpos( $menu_item['url'], 'vrts-upgrade' ) !== false ? 'button' : 'link' )
|
||||
);
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</nav>
|
||||
@@ -0,0 +1,27 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
|
||||
.vrts-notice {
|
||||
padding-bottom: 0.75em;
|
||||
|
||||
p,
|
||||
form {
|
||||
display: inline;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.admin-notice-button {
|
||||
border: 0;
|
||||
margin-bottom: 2px;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
min-height: 19px;
|
||||
line-height: 1;
|
||||
border-radius: 0;
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
switch ( $data['view'] ) {
|
||||
case 'connection_failed':
|
||||
$template = __DIR__ . '/views/admin-notification-connection-failed.php';
|
||||
break;
|
||||
|
||||
case 'get_started':
|
||||
$template = __DIR__ . '/views/admin-notification-get-started.php';
|
||||
break;
|
||||
|
||||
case 'new_test_added':
|
||||
$template = __DIR__ . '/views/admin-notification-new-test-added.php';
|
||||
break;
|
||||
|
||||
case 'new_test_failed':
|
||||
$template = __DIR__ . '/views/admin-notification-new-test-failed.php';
|
||||
break;
|
||||
|
||||
case 'new_tests_added':
|
||||
$template = __DIR__ . '/views/admin-notification-new-tests-added.php';
|
||||
break;
|
||||
|
||||
case 'plugin_activated':
|
||||
$template = __DIR__ . '/views/admin-notification-plugin-activated.php';
|
||||
break;
|
||||
|
||||
case 'settings_saved':
|
||||
$template = __DIR__ . '/views/admin-notification-settings-saved.php';
|
||||
break;
|
||||
|
||||
case 'license_added':
|
||||
$template = __DIR__ . '/views/admin-notification-license-added.php';
|
||||
break;
|
||||
|
||||
case 'license_not_added':
|
||||
$template = __DIR__ . '/views/admin-notification-license-not-added.php';
|
||||
break;
|
||||
|
||||
case 'test_disabled':
|
||||
$template = __DIR__ . '/views/admin-notification-test-disabled.php';
|
||||
break;
|
||||
|
||||
case 'test_started':
|
||||
$template = __DIR__ . '/views/admin-notification-test-started.php';
|
||||
break;
|
||||
|
||||
case 'test_failed':
|
||||
$template = __DIR__ . '/views/admin-notification-test-failed.php';
|
||||
break;
|
||||
|
||||
case 'unlock_more_tests':
|
||||
$template = __DIR__ . '/views/admin-notification-unlock-more-tests.php';
|
||||
break;
|
||||
|
||||
default:
|
||||
$template = '';
|
||||
break;
|
||||
}//end switch
|
||||
|
||||
if ( file_exists( $template ) ) {
|
||||
include $template;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/* global jQuery, ajaxurl */
|
||||
|
||||
import 'scripts/relative-time-element';
|
||||
|
||||
jQuery( document ).ready( function ( $ ) {
|
||||
$( document ).on( 'click', '.vrts-notice .notice-dismiss', ( event ) => {
|
||||
if ( ajaxurl ) {
|
||||
const nonce =
|
||||
event.target.parentElement.querySelector( '#_wpnonce' ).value;
|
||||
const view = event.target.parentElement.dataset.view;
|
||||
|
||||
const data = {
|
||||
action: 'vrts_admin_notice_dismiss',
|
||||
url: ajaxurl,
|
||||
security: nonce,
|
||||
view,
|
||||
};
|
||||
|
||||
$.ajax( {
|
||||
type: 'POST',
|
||||
url: ajaxurl,
|
||||
data,
|
||||
} );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<div class="vrts-notice notice notice-error" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<h3><?php esc_html_e( 'Connection failed', 'visual-regression-tests' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Something went wrong while trying to connect to the external service.', 'visual-regression-tests' ); ?></p>
|
||||
<form id="form-retry-connection" method="post">
|
||||
<?php wp_nonce_field( 'vrts_retry_connection_nonce' ); ?>
|
||||
<?php submit_button( esc_attr__( 'Retry connection', 'visual-regression-tests' ), 'admin-notice-button', 'submit_retry_connection', false ); ?>
|
||||
</form>
|
||||
</div>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<div class="vrts-notice notice notice-info is-dismissible" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Let’s get started!', 'visual-regression-tests' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Click “Add New“ to create a Visual Regression Test for your Website and find issues before others do.', 'visual-regression-tests' ); ?></p>
|
||||
</div>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<div class="vrts-notice notice notice-success" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'License activated!', 'visual-regression-tests' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Enjoy your upgraded features for seamless visual testing.', 'visual-regression-tests' ); ?></p>
|
||||
</div>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<div class="vrts-notice notice notice-error" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Invalid License Key', 'visual-regression-tests' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %1$s, %2$s: link wrapper. */
|
||||
esc_html__( 'We could not verify the license key you entered. Please check for typos and try again. If the issue persists, %1$scontact us%2$s for assistance. We’re here to help!', 'visual-regression-tests' ),
|
||||
'<a href="https://vrts.app/contact/" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<div class="vrts-notice notice notice-success" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Test added successfully', 'visual-regression-tests' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: the title of the page. */
|
||||
esc_html__( 'Tests will be run for the following page: %s', 'visual-regression-tests' ),
|
||||
esc_html( $data['page_title'] )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<div class="vrts-notice notice notice-error is-dismissable" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<h3><?php esc_html_e( 'Ready for an Upgrade?', 'visual-regression-tests' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
'%1$s <a href="%2$s" title="%3$s">%3$s</a>',
|
||||
esc_html__( 'Looks like you need a bigger plan to add more tests.', 'visual-regression-tests' ),
|
||||
esc_url( Url_Helpers::get_page_url( 'upgrade' ) ),
|
||||
esc_html__( 'Upgrade here!', 'visual-regression-tests' )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<div class="vrts-notice notice notice-success" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Tests added successfully', 'visual-regression-tests' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: the title of the page. */
|
||||
esc_html__( 'Tests will be run for the following pages: %s', 'visual-regression-tests' ),
|
||||
esc_html( $data['page_titles'] )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<div class="notice updated is-dismissible" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'VRTs Plugin successfully activated!', 'visual-regression-tests' ); ?></strong>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %1$s, %2$s and %3$s, %4$s: link wrapper. */
|
||||
esc_html__( 'Start to %1$sconfigure tests%2$s, or check the customization options in the %3$splugin settings%4$s.', 'visual-regression-tests' ),
|
||||
'<a href="' . esc_url( Url_Helpers::get_page_url( 'tests' ) ) . '">',
|
||||
'</a>',
|
||||
'<a href="' . esc_url( Url_Helpers::get_page_url( 'settings' ) ) . '">',
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<div class="vrts-notice notice notice-success" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Settings saved', 'visual-regression-tests' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Changes have been saved successfully.', 'visual-regression-tests' ); ?></p>
|
||||
</div>
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<div class="vrts-notice notice notice-error" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Test disabled successfully', 'visual-regression-tests' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: the title of the page. */
|
||||
esc_html__( 'No more tests will be run for the following page: %s', 'visual-regression-tests' ),
|
||||
esc_html( $data['page_title'] )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<form id="form-undo-test" method="post">
|
||||
<input type="hidden" name="post_id" value="<?php echo esc_attr( $data['post_id'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_page_tests_nonce' ); ?>
|
||||
<?php submit_button( esc_attr__( 'Undo', 'visual-regression-tests' ), 'admin-notice-button', 'submit_add_new_test', false ); ?>
|
||||
</form>
|
||||
</div>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<div class="vrts-notice notice notice-error" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Test couldn’t be started', 'visual-regression-tests' ); ?></h3>
|
||||
<p><?php esc_html_e( 'A Test is already in progress. Please wait for the current Test to finish, then try again.', 'visual-regression-tests' ); ?></p>
|
||||
</div>
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<div class="vrts-notice notice notice-info" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Testing has started 🚀', 'visual-regression-tests' ); ?></h3>
|
||||
<p><?php esc_html_e( 'New screenshots are being taken and compared with the previous version.', 'visual-regression-tests' ); ?></p><br>
|
||||
<p><?php esc_html_e( 'This may take a moment. You’ll receive an email if any visual changes are detected.', 'visual-regression-tests' ); ?></p>
|
||||
</div>
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<div class="vrts-notice notice notice-info" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<h3><?php esc_html_e( 'Unlock more tests', 'visual-regression-tests' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
'%s %s',
|
||||
sprintf(
|
||||
/* translators: %1$s, %2$s: number of tests. */
|
||||
esc_html__( 'Good work! You have added %1$s of %2$s available tests.', 'visual-regression-tests' ),
|
||||
intval( $data['total_tests'] ) - intval( $data['remaining_tests'] ),
|
||||
intval( $data['total_tests'] )
|
||||
),
|
||||
sprintf(
|
||||
/* translators: %1$s, %2$s: link wrapper. */
|
||||
esc_html__( 'Upgrade %1$shere%2$s to add more tests to your website!', 'visual-regression-tests' ),
|
||||
'<a href="' . esc_url( Url_Helpers::get_page_url( 'upgrade' ) ) . '">',
|
||||
'</a>'
|
||||
)
|
||||
)
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,129 @@
|
||||
.vrts-alert-actions {
|
||||
display: block;
|
||||
position: relative;
|
||||
|
||||
&__trigger {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
padding: 0.5rem;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
content: "";
|
||||
background: #f6f7f7;
|
||||
border-radius: 2px;
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-visible,
|
||||
&[aria-expanded="true"] {
|
||||
|
||||
&::before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__dropdown {
|
||||
position: absolute;
|
||||
top: calc(100% - 5px);
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border: 1px solid #c3c4c7;
|
||||
box-shadow: 0 3px 28px 0 rgba(0, 0, 0, 0.15);
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
min-width: 200px;
|
||||
transform: translateY(-4px);
|
||||
will-change: transform, opacity, visibility;
|
||||
transition: all 0.15s;
|
||||
|
||||
&[aria-hidden="false"] {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__dropdown-action {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
white-space: nowrap;
|
||||
padding: 12px 15px;
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: color 0.2s;
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
color: var(--vrts-admin-theme-color);
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
&__modal {
|
||||
|
||||
.vrts-modal__content {
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
.vrts-modal__content-inner {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
&-action {
|
||||
margin-top: 10px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
&-action-success {
|
||||
color: #00a32a;
|
||||
font-size: 0.75rem;
|
||||
margin-left: 0.5rem;
|
||||
display: none;
|
||||
|
||||
&.is-active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
margin: 0;
|
||||
display: none;
|
||||
|
||||
&.is-active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
border-color: #ccc;
|
||||
}
|
||||
|
||||
.description {
|
||||
color: #757575;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<vrts-alert-actions class="vrts-alert-actions">
|
||||
<button type="button" data-vrts-dropdown-open class="vrts-alert-actions__trigger" aria-expanded="false" aria-controls="vrts-alert-actions-dropdown">
|
||||
<?php vrts()->icon( 'more-horizontal' ); ?>
|
||||
</button>
|
||||
<div id="vrts-alert-actions-dropdown" class="vrts-alert-actions__dropdown" aria-hidden="true">
|
||||
<button data-vrts-loading="false" data-vrts-action-state="<?php echo esc_attr( $data['alert']->is_false_positive ? 'secondary' : 'primary' ); ?>" data-vrts-alert-id="<?php echo esc_attr( $data['alert']->id ); ?>" data-vrts-alert-action="false-positive" class="vrts-alert-actions__dropdown-action vrts-action-button">
|
||||
<span class="vrts-action-button__icons">
|
||||
<span class="vrts-action-button__icon" data-vrts-action-state-primary><?php vrts()->icon( 'flag-outline' ); ?></span>
|
||||
<span class="vrts-action-button__icon" data-vrts-action-state-secondary><?php vrts()->icon( 'flag' ); ?></span>
|
||||
<span class="vrts-action-button__spinner"><?php vrts()->icon( 'spinner' ); ?></span>
|
||||
</span>
|
||||
<span class="vrts-action-button__info" data-vrts-action-state-primary><?php esc_html_e( 'Flag as false positive', 'visual-regression-tests' ); ?></span>
|
||||
<span class="vrts-action-button__info" data-vrts-action-state-secondary><?php esc_html_e( 'Unflag as false positive', 'visual-regression-tests' ); ?></span>
|
||||
</button>
|
||||
<button data-vrts-loading="false" data-vrts-action-state="<?php echo esc_attr( $data['alert']->alert_state ? 'secondary' : 'primary' ); ?>" data-vrts-alert-id="<?php echo esc_attr( $data['alert']->id ); ?>" data-vrts-alert-action="read-status" class="vrts-alert-actions__dropdown-action vrts-action-button">
|
||||
<span class="vrts-action-button__icons">
|
||||
<span class="vrts-action-button__icon" data-vrts-action-state-secondary><?php vrts()->icon( 'email-unread' ); ?></span>
|
||||
<span class="vrts-action-button__icon" data-vrts-action-state-primary><?php vrts()->icon( 'email-read' ); ?></span>
|
||||
<span class="vrts-action-button__spinner"><?php vrts()->icon( 'spinner' ); ?></span>
|
||||
</span>
|
||||
<span class="vrts-action-button__info" data-vrts-action-state-primary><?php esc_html_e( 'Mark as read', 'visual-regression-tests' ); ?></span>
|
||||
<span class="vrts-action-button__info" data-vrts-action-state-secondary><?php esc_html_e( 'Mark as unread', 'visual-regression-tests' ); ?></span>
|
||||
</button>
|
||||
<button type="button" class="vrts-alert-actions__dropdown-action" data-a11y-dialog-show="vrts-modal-hide-elements">
|
||||
<?php vrts()->icon( 'hidden' ); ?>
|
||||
<?php esc_html_e( 'Hide elements', 'visual-regression-tests' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<vrts-modal id="vrts-modal-hide-elements" class="vrts-modal vrts-alert-actions__modal" aria-hidden="true">
|
||||
<div class="vrts-modal__overlay" data-a11y-dialog-hide></div>
|
||||
<div class="vrts-modal__content" role="document">
|
||||
<button type="button" class="vrts-modal__close" data-a11y-dialog-hide aria-label="<?php esc_attr_e( 'Close', 'visual-regression-tests' ); ?>"></button>
|
||||
<h2 class="vrts-modal__title">
|
||||
<?php vrts()->icon( 'hidden' ); ?>
|
||||
<?php esc_html_e( 'Hide elements', 'visual-regression-tests' ); ?>
|
||||
</h2>
|
||||
<div class="vrts-modal__content-inner">
|
||||
<form data-vrts-hide-elements-form action="<?php echo esc_url( Url_Helpers::get_page_url( 'runs' ) ); ?>" method="put">
|
||||
<input type="hidden" name="post_id" value="<?php echo esc_attr( $data['alert']->post_id ); ?>">
|
||||
<input type="hidden" name="test_id" value="<?php echo esc_attr( $data['test_settings']['test_id'] ); ?>">
|
||||
<textarea class="widefat" name="hide_css_selectors" placeholder="<?php esc_html_e( 'e.g.: .lottie, #ads', 'visual-regression-tests' ); ?>" rows="4"><?php echo esc_html( $data['test_settings']['hide_css_selectors'] ); ?></textarea>
|
||||
<p class="description"><?php esc_html_e( 'Hide elements on snapshots to exclude them from comparisons.', 'visual-regression-tests' ); ?></p>
|
||||
<div class="vrts-alert-actions__modal-action">
|
||||
<button type="submit" class="button button-primary"><?php esc_html_e( 'Save Changes', 'visual-regression-tests' ); ?></button>
|
||||
<span class="spinner"></span>
|
||||
<span class="vrts-alert-actions__modal-action-success"><?php esc_html_e( 'Saved successfully.', 'visual-regression-tests' ); ?></span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</vrts-modal>
|
||||
</vrts-alert-actions>
|
||||
@@ -0,0 +1,198 @@
|
||||
import Dropdown from '../../assets/scripts/dropdown';
|
||||
|
||||
class VrtsAlertActions extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.dropdown = null;
|
||||
this.setAsReadTimeout = null;
|
||||
this.resolveElements();
|
||||
this.bindFunctions();
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$actionButtons = this.querySelectorAll(
|
||||
'[data-vrts-alert-action]'
|
||||
);
|
||||
this.$hideElementsForm = this.querySelector(
|
||||
'[data-vrts-hide-elements-form]'
|
||||
);
|
||||
this.$hideElementsModal = document.getElementById(
|
||||
'vrts-modal-hide-elements'
|
||||
);
|
||||
this.$spinner = this.querySelector( '.spinner' );
|
||||
this.$success = this.querySelector(
|
||||
'.vrts-alert-actions__modal-action-success'
|
||||
);
|
||||
}
|
||||
|
||||
bindFunctions() {
|
||||
this.onActionClick = this.onActionClick.bind( this );
|
||||
this.onHideElementsFormSubmit =
|
||||
this.onHideElementsFormSubmit.bind( this );
|
||||
this.onHideElementsModalClose =
|
||||
this.onHideElementsModalClose.bind( this );
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$actionButtons.forEach( ( item ) => {
|
||||
item.addEventListener( 'click', this.onActionClick );
|
||||
} );
|
||||
this.$hideElementsForm.addEventListener(
|
||||
'submit',
|
||||
this.onHideElementsFormSubmit
|
||||
);
|
||||
this.$hideElementsModal.addEventListener(
|
||||
'hide',
|
||||
this.onHideElementsModalClose
|
||||
);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.dropdown = Dropdown( this );
|
||||
this.setAsReadOnView();
|
||||
}
|
||||
|
||||
setAsReadOnView() {
|
||||
this.$actionButtons.forEach( ( action ) => {
|
||||
const isReadStatusAction =
|
||||
action.getAttribute( 'data-vrts-alert-action' ) ===
|
||||
'read-status';
|
||||
const isUnread =
|
||||
action.getAttribute( 'data-vrts-action-state' ) === 'primary';
|
||||
|
||||
if ( isReadStatusAction && isUnread ) {
|
||||
this.setAsReadTimeout = setTimeout( () => {
|
||||
action.click();
|
||||
}, 1000 );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
onHideElementsFormSubmit( e ) {
|
||||
e.preventDefault();
|
||||
const $form = e.currentTarget;
|
||||
const formData = new window.FormData( $form );
|
||||
const postId = formData.get( 'post_id' );
|
||||
|
||||
this.$spinner.classList.add( 'is-active' );
|
||||
this.$success.classList.remove( 'is-active' );
|
||||
|
||||
fetch( `${ window.vrts_admin_vars.rest_url }/tests/post/${ postId }`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-WP-Nonce': window.vrts_admin_vars.rest_nonce,
|
||||
},
|
||||
body: new URLSearchParams( formData ),
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
return response.json();
|
||||
} )
|
||||
.then( () => {
|
||||
this.$spinner.classList.remove( 'is-active' );
|
||||
this.$success.classList.add( 'is-active' );
|
||||
} );
|
||||
}
|
||||
|
||||
onHideElementsModalClose() {
|
||||
this.$success.classList.remove( 'is-active' );
|
||||
}
|
||||
|
||||
onActionClick( e ) {
|
||||
const $el = e.currentTarget;
|
||||
const isLoading = $el.getAttribute( 'data-vrts-loading' ) === 'true';
|
||||
const state = $el.getAttribute( 'data-vrts-action-state' );
|
||||
const isPrimary = state === 'primary';
|
||||
|
||||
if ( isLoading ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const action = $el.getAttribute( 'data-vrts-alert-action' );
|
||||
const id = $el.getAttribute( 'data-vrts-alert-id' );
|
||||
|
||||
this.handleAction( action, $el, id, isPrimary );
|
||||
}
|
||||
|
||||
handleAction( action, $el, id, shouldSetAction ) {
|
||||
const restEndpoint = `${ window.vrts_admin_vars.rest_url }/alerts/${ id }/${ action }`;
|
||||
const method = shouldSetAction ? 'POST' : 'DELETE';
|
||||
|
||||
let loadingElapsedTime = 0;
|
||||
let interval = null;
|
||||
|
||||
const timeout = setTimeout( () => {
|
||||
$el.setAttribute( 'data-vrts-loading', 'true' );
|
||||
const loadingStartTime = window.Date.now();
|
||||
interval = setInterval( () => {
|
||||
loadingElapsedTime = window.Date.now() - loadingStartTime;
|
||||
}, 50 );
|
||||
}, 200 );
|
||||
|
||||
fetch( restEndpoint, {
|
||||
method,
|
||||
headers: {
|
||||
'X-WP-Nonce': window.vrts_admin_vars.rest_nonce,
|
||||
},
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
return response.json();
|
||||
} )
|
||||
.then( () => {
|
||||
const loadingTimeoutTime =
|
||||
loadingElapsedTime > 0
|
||||
? Math.abs( loadingElapsedTime - 400 )
|
||||
: 0;
|
||||
|
||||
setTimeout( () => {
|
||||
$el.setAttribute( 'data-vrts-loading', 'false' );
|
||||
|
||||
$el.setAttribute(
|
||||
'data-vrts-action-state',
|
||||
shouldSetAction ? 'secondary' : 'primary'
|
||||
);
|
||||
|
||||
const $alert = document.getElementById(
|
||||
`vrts-alert-${ id }`
|
||||
);
|
||||
|
||||
if ( $alert ) {
|
||||
if ( 'false-positive' === action ) {
|
||||
$alert.setAttribute(
|
||||
'data-vrts-false-positive',
|
||||
shouldSetAction ? 'true' : 'false'
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'read-status' === action ) {
|
||||
$alert.setAttribute(
|
||||
'data-vrts-state',
|
||||
shouldSetAction ? 'read' : 'unread'
|
||||
);
|
||||
}
|
||||
}
|
||||
}, loadingTimeoutTime );
|
||||
|
||||
clearTimeout( timeout );
|
||||
clearInterval( interval );
|
||||
} );
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.dropdown?.();
|
||||
clearTimeout( this.setAsReadTimeout );
|
||||
this.$actionButtons?.forEach( ( item ) => {
|
||||
item.removeEventListener( 'click', this.onActionClick );
|
||||
} );
|
||||
this.$hideElementsForm?.removeEventListener(
|
||||
'submit',
|
||||
this.onHideElementsFormSubmit
|
||||
);
|
||||
this.$hideElementsModal?.removeEventListener(
|
||||
'hide',
|
||||
this.onHideElementsModalClose
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-alert-actions', VrtsAlertActions );
|
||||
@@ -0,0 +1,300 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
@import "@wordpress/base-styles/breakpoints";
|
||||
|
||||
.vrts-comparisons {
|
||||
--vrts-comparisons-slider-position: 50%;
|
||||
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
border-top: 0;
|
||||
margin-bottom: 0;
|
||||
|
||||
&__header {
|
||||
background-color: $white;
|
||||
z-index: 1;
|
||||
gap: 1rem;
|
||||
|
||||
&:has(vrts-modal:not([aria-hidden="true"])) {
|
||||
z-index: 999999;
|
||||
}
|
||||
|
||||
@media (min-width: 850px) {
|
||||
position: sticky;
|
||||
top: calc(62px + var(--wp-admin--admin-bar--height));
|
||||
|
||||
[data-vrts-fullscreen="true"] & {
|
||||
top: 62px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
display: -webkit-box;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
max-block-size: calc(13px * 1.4);
|
||||
white-space: initial;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
&__info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 0.25rem;
|
||||
z-index: 1;
|
||||
|
||||
> *:not(:last-child) {
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
right: -0.5px;
|
||||
content: "";
|
||||
display: block;
|
||||
width: 1px;
|
||||
height: 1rem;
|
||||
background: $gray-10;
|
||||
margin-left: 0.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__difference {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #b32d2e;
|
||||
padding-right: 0.75rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__expand-button {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
@media (max-width: 667px) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
content: "";
|
||||
background: #f6f7f7;
|
||||
border-radius: 2px;
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
|
||||
&::before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 14px;
|
||||
width: auto;
|
||||
|
||||
&:last-child {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-vrts-fullscreen="true"] & {
|
||||
|
||||
svg:first-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
svg:last-child {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, max-content));
|
||||
justify-content: center;
|
||||
gap: 0.25rem;
|
||||
padding: 15px;
|
||||
|
||||
@container (max-width: 600px) {
|
||||
gap: 0;
|
||||
grid-template-columns: repeat(2, minmax(0, max-content));
|
||||
}
|
||||
|
||||
&-container {
|
||||
container-type: inline-size;
|
||||
}
|
||||
}
|
||||
|
||||
&__figure {
|
||||
margin: 0;
|
||||
position: relative;
|
||||
border: solid 1px #{$gray-lighten-20};
|
||||
min-height: 100px;
|
||||
|
||||
&-image {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@container (max-width: 600px) {
|
||||
|
||||
&[data-vrts-comparisons-slot="comparison"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__diff-inidicator {
|
||||
box-sizing: border-box;
|
||||
background: #f0f0f1;
|
||||
border-block: 1px solid transparent;
|
||||
height: 100%;
|
||||
image-rendering: pixelated;
|
||||
width: 4px;
|
||||
|
||||
@container (max-width: 600px) {
|
||||
margin-left: -9.5px;
|
||||
}
|
||||
}
|
||||
|
||||
&__slider {
|
||||
--vrts-comparisons-slider-height: 100%;
|
||||
|
||||
position: relative;
|
||||
display: grid;
|
||||
align-items: start;
|
||||
border: solid 1px #{$gray-lighten-20};
|
||||
overflow: clip;
|
||||
|
||||
.vrts-comparisons__figure {
|
||||
grid-column: 1 / 1;
|
||||
grid-row: 1 / 1;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
[data-vrts-comparisons-slot="base"] {
|
||||
clip-path: inset(0 calc(100% - var(--vrts-comparisons-slider-position)) 0 0);
|
||||
}
|
||||
|
||||
[data-vrts-comparisons-slot="target"] {
|
||||
clip-path: inset(0 0 0 var(--vrts-comparisons-slider-position));
|
||||
}
|
||||
|
||||
&:has(input:focus-visible) {
|
||||
|
||||
.vrts-comparisons__slider-handle svg {
|
||||
outline: 2px solid var(--vrts-admin-theme-color);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__slider-handle {
|
||||
--vrts-comparisons-offset: calc(62px + 42px);
|
||||
--vrts-comparisons-handle-size: 32px;
|
||||
--vrts-comparisons-handle-offest: 20px;
|
||||
--vrts-comparisons-slider-centered: calc(100% / var(--vrts-comparisons-slider-aspect-ratio) / 2 - var(--vrts-comparisons-handle-size) / 2);
|
||||
--vrts-comparisons-viewport-centered: calc(((100vh - var(--wp-admin--admin-bar--height) - 56px - 15px - var(--vrts-comparisons-offset)) / 2 - var(--vrts-comparisons-handle-size) / 2) + 15%);
|
||||
|
||||
box-sizing: border-box;
|
||||
position: sticky;
|
||||
top: calc((var(--vrts-comparisons-handle-size) / 2) + 10%);
|
||||
width: 100%;
|
||||
height: calc(var(--vrts-comparisons-handle-size) + 10px);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
grid-column: 1 / 1;
|
||||
grid-row: 1 / 1;
|
||||
margin-block: var(--vrts-comparisons-handle-offest);
|
||||
margin-block-start: max(var(--vrts-comparisons-handle-offest), min(var(--vrts-comparisons-slider-centered), var(--vrts-comparisons-viewport-centered)));
|
||||
|
||||
@media (min-width: 851px) {
|
||||
top: calc(var(--wp-admin--admin-bar--height) + var(--vrts-comparisons-offset) + (var(--vrts-comparisons-handle-size) / 2) + 10%);
|
||||
}
|
||||
|
||||
[data-vrts-fullscreen="true"] & {
|
||||
top: calc(var(--vrts-comparisons-offset) + (var(--vrts-comparisons-handle-size) / 2) + 10%);
|
||||
}
|
||||
|
||||
svg { // stylelint-disable-line no-descending-specificity
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(var(--vrts-comparisons-slider-position) - (var(--vrts-comparisons-handle-size) / 2));
|
||||
width: var(--vrts-comparisons-handle-size);
|
||||
height: var(--vrts-comparisons-handle-size);
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
border: 1px solid var(--vrts-admin-theme-color);
|
||||
color: var(--vrts-admin-theme-color);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
&__slider-divider {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(var(--vrts-comparisons-slider-position) - 0.5px);
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
background: var(--vrts-admin-theme-color);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
&__slider-divider-clone {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(var(--vrts-comparisons-slider-position) - 0.5px);
|
||||
width: 0;
|
||||
height: 100%;
|
||||
border-left: 1px dashed #c3c4c7;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
&__slider-control {
|
||||
appearance: none;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0;
|
||||
|
||||
&::-webkit-slider-runnable-track {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
appearance: none;
|
||||
height: 100%;
|
||||
width: 56px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Image_Helpers;
|
||||
|
||||
?>
|
||||
|
||||
<vrts-comparisons class="vrts-comparisons postbox">
|
||||
<div class="vrts-comparisons__header postbox-header">
|
||||
<div class="vrts-comparisons__title"><?php echo esc_html( get_the_title( $data['alert']->post_id ) ); ?></div>
|
||||
<div class="vrts-comparisons__info">
|
||||
<div class="vrts-comparisons__difference">
|
||||
<?php /* translators: %s: the count of pixels with a visual difference. */ ?>
|
||||
<?php echo esc_html( sprintf( __( '%spx Difference', 'visual-regression-tests' ), esc_html( number_format_i18n( ceil( $data['alert']->differences ) ) ) ) ); ?>
|
||||
</div>
|
||||
<button type="button" title="<?php esc_html_e( 'Expand', 'visual-regression-tests' ); ?>" class="vrts-comparisons__expand-button" data-vrts-fullscreen-open>
|
||||
<?php vrts()->icon( 'expand' ); ?>
|
||||
<?php vrts()->icon( 'compress' ); ?>
|
||||
</button>
|
||||
<?php vrts()->component( 'alert-actions', $data ); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="vrts-comparisons__content-container">
|
||||
<div class="vrts-comparisons__content">
|
||||
<figure class="vrts-comparisons__figure" data-vrts-comparisons-slot="comparison">
|
||||
<img class="vrts-comparisons__figure-image" <?php echo wp_kses_post( Image_Helpers::alert_image_hwstring( $data['alert'] ) ); ?> crossorigin="anonymous" src="<?php echo esc_url( Image_Helpers::get_screenshot_url( $data['alert'], 'comparison' ) ); ?>" alt="<?php esc_attr_e( 'Difference', 'visual-regression-tests' ); ?>" />
|
||||
<span class="vrts-comparisons__slider-divider-clone"></span>
|
||||
</figure>
|
||||
<canvas class="vrts-comparisons__diff-inidicator" data-vrts-comparisons-diff-inidicator></canvas>
|
||||
<div class="vrts-comparisons__slider" style="--vrts-comparisons-slider-aspect-ratio: <?php echo esc_attr( Image_Helpers::alert_image_aspect_ratio( $data['alert'] ) ); ?>">
|
||||
<figure class="vrts-comparisons__figure" data-vrts-comparisons-slot="base">
|
||||
<img class="vrts-comparisons__figure-image" <?php echo wp_kses_post( Image_Helpers::alert_image_hwstring( $data['alert'] ) ); ?> crossorigin="anonymous" src="<?php echo esc_url( Image_Helpers::get_screenshot_url( $data['alert'], 'base' ) ); ?>" alt="<?php esc_attr_e( 'Snapshot', 'visual-regression-tests' ); ?>" />
|
||||
</figure>
|
||||
<figure class="vrts-comparisons__figure" data-vrts-comparisons-slot="target">
|
||||
<img class="vrts-comparisons__figure-image" <?php echo wp_kses_post( Image_Helpers::alert_image_hwstring( $data['alert'] ) ); ?> crossorigin="anonymous" src="<?php echo esc_url( Image_Helpers::get_screenshot_url( $data['alert'], 'target' ) ); ?>" alt="<?php esc_attr_e( 'Screenshot', 'visual-regression-tests' ); ?>" />
|
||||
</figure>
|
||||
<span class="vrts-comparisons__slider-divider"></span>
|
||||
<div class="vrts-comparisons__slider-handle">
|
||||
<?php vrts()->icon( 'grip-dots' ); ?>
|
||||
</div>
|
||||
<input type="range" step="0.078125" class="vrts-comparisons__slider-control" data-vrts-comparisons-slider-control>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="vrts-gradient-loader"></span>
|
||||
</vrts-comparisons>
|
||||
@@ -0,0 +1,163 @@
|
||||
class VrtsComparisons extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.resolveElements();
|
||||
this.bindFunctions();
|
||||
this.bindEvents();
|
||||
this.init();
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$content = document.querySelector( '[data-vrts-fullscreen]' );
|
||||
this.$fullscreen = this.querySelector( '[data-vrts-fullscreen-open]' );
|
||||
this.$control = this.querySelector(
|
||||
'[data-vrts-comparisons-slider-control]'
|
||||
);
|
||||
this.$diffIndicator = this.querySelector(
|
||||
'[data-vrts-comparisons-diff-inidicator]'
|
||||
);
|
||||
this.$comparison = this.querySelector(
|
||||
'[data-vrts-comparisons-slot="comparison"] img'
|
||||
);
|
||||
}
|
||||
|
||||
bindFunctions() {
|
||||
this.onFullscreenToggle = this.onFullscreenToggle.bind( this );
|
||||
this.onControlChange = this.onControlChange.bind( this );
|
||||
this.onFullScreenChange = this.onFullScreenChange.bind( this );
|
||||
this.onLoadComparison = this.onLoadComparison.bind( this );
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$fullscreen.addEventListener( 'click', this.onFullscreenToggle );
|
||||
this.$control.addEventListener( 'input', this.onControlChange );
|
||||
document.addEventListener(
|
||||
'fullscreenchange',
|
||||
this.onFullScreenChange
|
||||
);
|
||||
}
|
||||
|
||||
init() {
|
||||
this.worker = new window.Worker(
|
||||
new URL( 'worker.js', import.meta.url )
|
||||
);
|
||||
this.worker.onmessage = this.onWorkerMessage.bind( this );
|
||||
if ( this.$comparison.complete ) {
|
||||
this.onLoadComparison();
|
||||
} else {
|
||||
this.$comparison.onload = this.onLoadComparison;
|
||||
}
|
||||
}
|
||||
|
||||
onLoadComparison() {
|
||||
const imageData = this.createOffscreenCanvarImageData(
|
||||
this.$comparison
|
||||
);
|
||||
this.worker.postMessage( {
|
||||
action: 'analyzeImage',
|
||||
imageData,
|
||||
} );
|
||||
}
|
||||
|
||||
createOffscreenCanvarImageData( image ) {
|
||||
const canvas = new window.OffscreenCanvas(
|
||||
image.naturalWidth,
|
||||
image.naturalHeight
|
||||
);
|
||||
const ctx = canvas.getContext( '2d' );
|
||||
ctx.drawImage( image, 0, 0 );
|
||||
return ctx.getImageData( 0, 0, canvas.width, canvas.height );
|
||||
}
|
||||
|
||||
requestFullscreen( element ) {
|
||||
if ( element.requestFullscreen ) {
|
||||
element.requestFullscreen();
|
||||
} else if ( element.webkitRequestFullscreen ) {
|
||||
element.webkitRequestFullscreen();
|
||||
} else if ( element.msRequestFullscreen ) {
|
||||
element.msRequestFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
exitFullscreen() {
|
||||
if ( document.exitFullscreen ) {
|
||||
document.exitFullscreen();
|
||||
} else if ( document.webkitExitFullscreen ) {
|
||||
document.webkitExitFullscreen();
|
||||
} else if ( document.msExitFullscreen ) {
|
||||
document.msExitFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
getFullscreenElement() {
|
||||
return (
|
||||
document.fullscreenElement ||
|
||||
document.webkitFullscreenElement ||
|
||||
document.msFullscreenElement
|
||||
);
|
||||
}
|
||||
|
||||
onFullscreenToggle( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
if ( this.getFullscreenElement() === this.$content ) {
|
||||
this.exitFullscreen();
|
||||
} else {
|
||||
this.requestFullscreen( this.$content );
|
||||
}
|
||||
}
|
||||
|
||||
onFullScreenChange() {
|
||||
this.$content.setAttribute(
|
||||
'data-vrts-fullscreen',
|
||||
this.getFullscreenElement() === this.$content
|
||||
);
|
||||
}
|
||||
|
||||
onControlChange( e ) {
|
||||
this.style.setProperty(
|
||||
'--vrts-comparisons-slider-position',
|
||||
`${ e.target.value }%`
|
||||
);
|
||||
}
|
||||
|
||||
onWorkerMessage( e ) {
|
||||
if ( e.data?.action === 'analyzedImage' ) {
|
||||
this.highlightPixels( e.data.coloredPixels );
|
||||
}
|
||||
}
|
||||
|
||||
highlightPixels( pixels ) {
|
||||
const ctx = this.$diffIndicator.getContext( '2d' );
|
||||
this.$diffIndicator.width = this.$comparison.naturalWidth;
|
||||
this.$diffIndicator.height = this.$comparison.naturalHeight;
|
||||
ctx.clearRect(
|
||||
0,
|
||||
0,
|
||||
this.$comparison.naturalWidth,
|
||||
this.$comparison.naturalHeight
|
||||
);
|
||||
ctx.fillStyle = '#cc1818';
|
||||
pixels.forEach( ( y ) => {
|
||||
ctx.fillRect( 0, y - 2, ctx.canvas.width, 3 );
|
||||
} );
|
||||
}
|
||||
|
||||
connectedCallback() {}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.$fullscreen?.removeEventListener(
|
||||
'click',
|
||||
this.onFullscreenToggle
|
||||
);
|
||||
this.$control?.removeEventListener( 'input', this.onControlChange );
|
||||
document.removeEventListener(
|
||||
'fullscreenchange',
|
||||
this.onFullScreenChange
|
||||
);
|
||||
this.worker?.terminate();
|
||||
this.worker = null;
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-comparisons', VrtsComparisons );
|
||||
@@ -0,0 +1,30 @@
|
||||
/* global self */
|
||||
function getColoredPixelsWithLimit( imageData, xLimit, direction = 'left' ) {
|
||||
const coloredPixels = new Set();
|
||||
for ( let i = 0; i < imageData.data.length; i += 4 ) {
|
||||
const r = imageData.data[ i ];
|
||||
const g = imageData.data[ i + 1 ];
|
||||
const b = imageData.data[ i + 2 ];
|
||||
const a = imageData.data[ i + 3 ];
|
||||
if ( r === 255 && g === 0 && b === 0 && a === 255 ) {
|
||||
const x = ( i / 4 ) % imageData.width;
|
||||
if ( direction === 'left' ? x < xLimit : x > xLimit ) {
|
||||
// push x and y coordinates
|
||||
coloredPixels.add( Math.floor( i / 4 / imageData.width ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
return Array.from( coloredPixels );
|
||||
}
|
||||
|
||||
self.onmessage = function ( e ) {
|
||||
if ( e.data?.action === 'analyzeImage' ) {
|
||||
const { imageData } = e.data;
|
||||
const coloredPixels = getColoredPixelsWithLimit(
|
||||
imageData,
|
||||
0,
|
||||
'right'
|
||||
);
|
||||
self.postMessage( { action: 'analyzedImage', coloredPixels } );
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Date_Time_Helpers;
|
||||
use Vrts\Core\Utilities\String_Helpers;
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
use Vrts\Models\Test_Run;
|
||||
|
||||
?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html lang="en" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Title</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="x-apple-disable-message-reformatting" />
|
||||
<meta content="telephone=no" name="format-detection">
|
||||
|
||||
<!--[if !mso]><!-->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<!--<![endif]-->
|
||||
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
<o:AllowPNG />
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
|
||||
<style>
|
||||
table,
|
||||
tr,
|
||||
td {
|
||||
border-collapse: separate;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--[if mso]>
|
||||
<style type="text/css">
|
||||
v\:* {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
}
|
||||
o\:* {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
}
|
||||
w\:* {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
}
|
||||
.ExternalClass {
|
||||
width: 100%;
|
||||
}
|
||||
table {
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
}
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
.ReadMsgBody {
|
||||
width: 100%;
|
||||
}
|
||||
a {
|
||||
background: transparent !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
li {
|
||||
text-align: -webkit-match-parent;
|
||||
display: list-item;
|
||||
text-indent: -1em;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
margin-left: 1em !important;
|
||||
}
|
||||
|
||||
p {
|
||||
text-indent: 0;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body style="width:100%;height:100%;padding:0;Margin:0">
|
||||
<table border="0" cellspacing="0" width="100%" bgcolor="#ffffff" style="background-color: #ffffff; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td style="padding: 20px;">
|
||||
<p style="font-size: 14px; line-height: 16px; color: #2C3338; display: block; mso-line-height-rule: exactly"><?php esc_html_e( 'Howdy 👋', 'visual-regression-tests' ); ?></p>
|
||||
<p style="font-size: 14px; line-height: 16px; color: #2C3338; display: block; mso-line-height-rule: exactly; margin: 0"><?php esc_html_e( "We've detected visual changes on your website.", 'visual-regression-tests' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0" cellspacing="0" bgcolor="#ffffff" style="background-color: #ffffff; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td width="1"></td>
|
||||
<td width="280" style="padding: 0 20px;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" role="presentation" style="width: 100%; border-spacing: 0; background-color: #F6F7FB;">
|
||||
<tr><td style="padding: 0 15px;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" role="presentation" style="width: 100%; border-spacing: 0; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px dashed #c3c4c7; padding: 12px 0">
|
||||
<center>
|
||||
<table cellpadding="0" cellspacing="0" border="0" style="border-spacing: 0; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td width="22" style="padding-right: 8px;">
|
||||
<img width="22" height="22" src="<?php echo esc_url( vrts()->get_plugin_url( 'assets/images/vrts-logo.png' ) ); ?>" alt="Logo">
|
||||
</td>
|
||||
<td width="100">
|
||||
<p style="font-size: 16px; line-height: 20px; color: #2C3338; display: block; margin: 0; mso-line-height-rule: exactly;"><strong><?php esc_html_e( 'VRTs Plugin', 'visual-regression-tests' ); ?></strong></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
<table cellpadding="0" cellspacing="0" border="0" style="width: 100%; border-spacing: 0; padding-top: 10px; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td style="text-align: center">
|
||||
<p style="font-size: 14px; line-height: 20px; color: #2C3338; display: block; margin: 0; mso-line-height-rule: exactly"><?php esc_html_e( 'Test Receipt', 'visual-regression-tests' ); ?></p>
|
||||
<a style="font-size: 11px; line-height: 16px; display: block; padding-top: 4px; mso-line-height-rule: exactly" href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php echo esc_html( home_url( '/' ) ); ?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border-bottom: 1px dashed #c3c4c7; padding: 12px 0; text-align: center;">
|
||||
<p style="font-size: 11px; line-height: 16px; color: #2C3338; display: block; margin: 0; mso-line-height-rule: exactly">
|
||||
<span style="padding-right: 10px">
|
||||
<?php
|
||||
// translators: %s: the run number.
|
||||
printf( esc_html__( 'Run #%s', 'visual-regression-tests' ), esc_html( $data['run']->id ) );
|
||||
?>
|
||||
</span>
|
||||
<?php echo wp_kses( Date_Time_Helpers::get_formatted_date_time( $data['run']->finished_at ), [ 'time' => [ 'datetime' => true ] ] ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border-bottom: 1px dashed #c3c4c7; padding: 12px 0;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" style="width: 100%; border-spacing: 0; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<th style="font-size: 12px; padding-bottom: 4px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly; text-align: left;">Pages</th>
|
||||
<th style="font-size: 12px; padding-bottom: 4px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly; text-align: right;">Difference</th>
|
||||
</tr>
|
||||
<?php
|
||||
|
||||
foreach ( $data['tests'] as $test ) :
|
||||
$alert = array_values( array_filter( $data['alerts'], static function( $alert ) use ( $test ) {
|
||||
return $alert->post_id === $test['post_id'];
|
||||
} ) );
|
||||
$difference = $alert ? ceil( $alert[0]->differences ) : 0;
|
||||
?>
|
||||
<tr>
|
||||
<td style="padding-top: 2px; padding-bottom: 2px; vertical-align: top; font-size: 12px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly; text-align: left;">
|
||||
<?php if ( $test['permalink'] ) : ?>
|
||||
<a style="color: #2C3338; text-decoration: none" href="<?php echo esc_url( $test['permalink'] ); ?>"><?php echo esc_html( String_Helpers::truncate( Url_Helpers::make_relative( $test['permalink'] ), 30 ) ); ?></a>
|
||||
<?php else : ?>
|
||||
N/A
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td style="padding-top: 2px; padding-bottom: 2px; vertical-align: top; font-size: 12px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly; text-align: right;">
|
||||
<?php $difference_url = $difference ? Url_Helpers::get_alert_page( $alert[0]->id, $data['run']->id ) : Url_Helpers::get_alerts_page( $data['run']->id ); ?>
|
||||
<a style="color: #2C3338; text-decoration: none" href="<?php echo esc_url( $difference_url ); ?>">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s. Test run receipt diff in pixels */
|
||||
esc_html_x( '%spx', 'test run receipt difference', 'visual-regression-tests' ),
|
||||
esc_html( number_format_i18n( $difference ) )
|
||||
);
|
||||
?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border-bottom: 1px dashed #c3c4c7; padding: 12px 0;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" style="width: 100%; border-spacing: 0; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<th style="font-size: 14px; padding-bottom: 4px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly; text-align: left;">Total</th>
|
||||
<th style="font-size: 14px; padding-bottom: 4px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly; text-align: right;">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s. Number of tests */
|
||||
esc_html( _n( '%s Test', '%s Tests', count( $data['tests'] ), 'visual-regression-tests' ) ), count( $data['tests'] )
|
||||
); ?>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-top: 2px; padding-bottom: 2px; vertical-align: top; font-size: 12px; line-height: 16px; color: #4ab866; mso-line-height-rule: exactly; text-align: left;"><?php esc_html_e( 'Passed', 'visual-regression-tests' ); ?></td>
|
||||
<td style="padding-top: 2px; padding-bottom: 2px; vertical-align: top; font-size: 12px; line-height: 16px; color: #4ab866; mso-line-height-rule: exactly; text-align: right;"><?php echo esc_html( count( $data['tests'] ) - count( $data['alerts'] ) ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-top: 2px; padding-bottom: 2px; vertical-align: top; font-size: 12px; line-height: 16px; color: #b32d2e; mso-line-height-rule: exactly; text-align: left;"><?php esc_html_e( 'Changes Detected', 'visual-regression-tests' ); ?></td>
|
||||
<td style="padding-top: 2px; padding-bottom: 2px; vertical-align: top; font-size: 12px; line-height: 16px; color: #b32d2e; mso-line-height-rule: exactly; text-align: right;"><?php echo esc_html( count( $data['alerts'] ) ); ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border-bottom: 1px dashed #c3c4c7; padding: 12px 0; font-size: 11px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly;">
|
||||
<table>
|
||||
<tr>
|
||||
<td><?php esc_html_e( 'Trigger', 'visual-regression-tests' ); ?></td>
|
||||
<td style="padding-left: 5px;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" role="presentation" bgcolor="#f0e8f8" width="100.00%" style="border-radius: 100px; background-color: <?php echo Test_Run::get_trigger_background_color( $data['run'] ); ?>; width: 100%; border-spacing: 0; border-collapse: separate; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<p style="font-size: 12px; font-weight: 400; line-height: 16px; color: <?php echo Test_Run::get_trigger_text_color( $data['run'] ); ?>; mso-line-height-alt: 16px; margin: 0; padding: 4px 10px"><?php echo esc_html( Test_Run::get_trigger_title( $data['run'] ) ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php
|
||||
$trigger_note = Test_Run::get_trigger_note( $data['run'] );
|
||||
if ( ! empty( $trigger_note ) ) : ?>
|
||||
<span style="color: #757575;">
|
||||
<?php echo esc_html( $trigger_note ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-top: 12px; padding-bottom: 8px; text-align: center">
|
||||
<p style="font-size: 13px; line-height: 16px; text-transform: uppercase; color: #2C3338; display: block; margin: 0; mso-line-height-rule: exactly"><strong><?php esc_html_e( 'Test Completed!', 'visual-regression-tests' ); ?></strong></p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="1" style="padding-bottom: 12px;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" role="presentation" bgcolor="#1954ed" width="100.00%" style="border-radius: 2px; background-color: #1954ed; width: 100%; border-spacing: 0; border-collapse: separate; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td align="center" valign="middle" style="padding: 8px 24px;">
|
||||
<a href="<?php echo Url_Helpers::get_test_run_page( $data['run'] ); ?>" style="font-size: 14px; font-weight: 600; color: white; margin: 0; padding: 0; line-height: 20px; mso-line-height-alt: 20px; text-decoration: none; display: block;"><?php esc_html_e( 'View Details', 'visual-regression-tests' ); ?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0" cellspacing="0" width="100%" bgcolor="#ffffff" style="background-color: #ffffff; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td style="padding: 20px 20px;">
|
||||
<p style="font-size: 14px; line-height: 16px; color: #2C3338; display: block; mso-line-height-rule: exactly; margin: 0"><?php esc_html_e( 'Your VRTs squad! 🚀', 'visual-regression-tests' ); ?></p>
|
||||
<p style="font-size: 14px; line-height: 16px; color: #2C3338; display: block; mso-line-height-rule: exactly">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: Home URL */
|
||||
wp_kses_post( 'This alert was sent by the VRTs plugin on %s.', 'visual-regression-tests' ),
|
||||
'<a href="' . esc_url( home_url() ) .'">' . esc_html( home_url() ) . '</a>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
|
||||
#vrts_post_options_metabox { // stylelint-disable-line selector-id-pattern
|
||||
|
||||
figcaption {
|
||||
|
||||
> :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
> :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.figure {
|
||||
margin: 0;
|
||||
|
||||
&-link {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&-title {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
&-image {
|
||||
aspect-ratio: 16/9;
|
||||
border: solid 1px #bfbfbf;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center top;
|
||||
}
|
||||
|
||||
.howto {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-testing-status {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0;
|
||||
|
||||
&--paused {
|
||||
color: $alert-red;
|
||||
}
|
||||
|
||||
&--waiting {
|
||||
color: #f97b06;
|
||||
}
|
||||
|
||||
&--running {
|
||||
color: $alert-green;
|
||||
}
|
||||
|
||||
&-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
margin: 1.5rem 0;
|
||||
|
||||
> * {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dashicons {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 5px;
|
||||
font-size: 0.75rem;
|
||||
color: $gray-700;
|
||||
}
|
||||
}
|
||||
|
||||
.settings {
|
||||
|
||||
&-title {
|
||||
margin-bottom: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
if ( ! $data['is_connected'] ) {
|
||||
include_once __DIR__ . '/metabox-notifications/metabox-notification-connection-failed.php';
|
||||
return;
|
||||
}
|
||||
?>
|
||||
|
||||
<?php wp_nonce_field( $data['nonce'], $data['nonce'] ); ?>
|
||||
<p class="vrts-testing-toogle">
|
||||
<?php if ( 0 === intval( $data['remaining_tests'] ) && ! $data['run_tests_checked'] ) { ?>
|
||||
<input class="widefat" type="checkbox" id="<?php echo esc_attr( $data['field_test_status_key'] ); ?>" value="0" disabled />
|
||||
<?php } else { ?>
|
||||
<input class="widefat" type="checkbox" name="<?php echo esc_attr( $data['field_test_status_key'] ); ?>" id="<?php echo esc_attr( $data['field_test_status_key'] ); ?>" <?php checked( $data['run_tests_checked'] ); ?> value="1" />
|
||||
<?php } ?>
|
||||
<label for="<?php echo esc_attr( $data['field_test_status_key'] ); ?>"><strong><?php esc_html_e( 'Add to VRTs', 'visual-regression-tests' ); ?></strong></label>
|
||||
<span class="vrts-tooltip">
|
||||
<span class="vrts-tooltip-icon dashicons dashicons-info-outline"></span>
|
||||
<span class="vrts-tooltip-content">
|
||||
<span class="vrts-tooltip-content-inner">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %1$s, %2$s: link wrapper. */
|
||||
wp_kses_post( __( 'Add this page to your Visual Regression Tests for consistent checks to ensure no visual changes go unnoticed. Explore the %1$sTests page%2$s in the VRTs plugin for an overview of all tests and their status.', 'visual-regression-tests' ) ),
|
||||
'<a href="' . esc_url( $data['plugin_url'] ) . '">',
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<?php
|
||||
|
||||
// Notification: New Test added.
|
||||
if ( true === $data['is_new_test'] ) {
|
||||
include_once __DIR__ . '/metabox-notifications/metabox-notification-new-test-added.php';
|
||||
} elseif ( 1 === intval( $data['remaining_tests'] ) ) {
|
||||
// Notification: Unlock more tests.
|
||||
include_once __DIR__ . '/metabox-notifications/metabox-notification-unlock-more-tests.php';
|
||||
} elseif ( 0 === intval( $data['remaining_tests'] ) ) {
|
||||
// Notification: Unlock more tests.
|
||||
include_once __DIR__ . '/metabox-notifications/metabox-notification-upgrade-required.php';
|
||||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
// Display details only when "Run Tests" checkbox is active.
|
||||
if ( $data['run_tests_checked'] ) {
|
||||
$test_status = $data['test_status'];
|
||||
$screenshot = $data['screenshot'];
|
||||
?>
|
||||
<div class="vrts-testing-status-wrapper">
|
||||
<p class="vrts-testing-status">
|
||||
<span><?php esc_html_e( 'Test Status', 'visual-regression-tests' ); ?></span>
|
||||
<strong class="vrts-testing-status--<?php echo esc_attr( $test_status['class'] ); ?>"><?php echo wp_kses_post( $test_status['text'] ); ?></strong>
|
||||
</p>
|
||||
<p class="vrts-testing-status-info">
|
||||
<?php echo wp_kses_post( $test_status['instructions'] ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="vrts-testing-status-wrapper">
|
||||
<p class="vrts-testing-status">
|
||||
<span><?php esc_html_e( 'Snapshot', 'visual-regression-tests' ); ?></span>
|
||||
<span class="vrts-testing-status-info">
|
||||
<?php
|
||||
$text = in_array( $screenshot['status'], [ 'paused', 'waiting' ], true ) ? $screenshot['text'] : $screenshot['instructions'];
|
||||
echo wp_kses_post( $text );
|
||||
?>
|
||||
</span>
|
||||
</p>
|
||||
<figure class="figure">
|
||||
<?php echo wp_kses_post( $screenshot['screenshot'] ); ?>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="settings">
|
||||
<input name="test_id" type="hidden" value="<?php echo esc_html( $data['test_settings']['test_id'] ); ?>"/>
|
||||
<label for="vrts-hide-css-selectors" class="settings-title">
|
||||
<span><?php esc_html_e( 'Hide elements from VRTs', 'visual-regression-tests' ); ?></span>
|
||||
<span class="vrts-tooltip">
|
||||
<span class="vrts-tooltip-icon dashicons dashicons-info-outline"></span>
|
||||
<span class="vrts-tooltip-content">
|
||||
<span class="vrts-tooltip-content-inner">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %1$s, %2$s: link wrapper. */
|
||||
esc_html__( 'Exclude elements on this page: Add %1$sCSS selectors%2$s (as comma separated list) to exclude elements from VRTs when a new snapshot gets created.', 'visual-regression-tests' ),
|
||||
'<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<textarea id="vrts-hide-css-selectors" name="hide_css_selectors" placeholder="<?php esc_html_e( 'e.g.: .lottie, #ads', 'visual-regression-tests' ); ?>" rows="4"><?php echo esc_html( $data['test_settings']['hide_css_selectors'] ); ?></textarea>
|
||||
</div>
|
||||
<?php }//end if
|
||||
?>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<div class="vrts-metabox-notice vrts-metabox-notice-is-error">
|
||||
<p><strong><?php esc_html_e( 'Connection failed', 'visual-regression-tests' ); ?></strong></p>
|
||||
<p><?php esc_html_e( 'Something went wrong while trying to connect to the external service.', 'visual-regression-tests' ); ?></p>
|
||||
<p><a href="<?php echo esc_attr( Url_Helpers::get_page_url( 'tests' ) ); ?>"><?php esc_html_e( 'Go to plugin page', 'visual-regression-tests' ); ?></a></p>
|
||||
</div>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<div class="vrts-metabox-notice vrts-metabox-notice-is-success">
|
||||
<p><strong><?php esc_html_e( 'You have added a new test', 'visual-regression-tests' ); ?></strong></p>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: page title. */
|
||||
esc_html__( 'The Visual Regression Test for the page %s has been added!', 'visual-regression-tests' ),
|
||||
'<strong>' . esc_html( get_the_title( $data['post_id'] ) ) . '</strong>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<div class="vrts-metabox-notice vrts-metabox-notice-is-info">
|
||||
<p><strong><?php esc_html_e( 'Unlock more tests', 'visual-regression-tests' ); ?></strong></p>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
'%s %s',
|
||||
sprintf(
|
||||
/* translators: %1$s, %2$s: number of tests. */
|
||||
esc_html__( 'Good work! You have added %1$s of %2$s available tests.', 'visual-regression-tests' ),
|
||||
intval( $data['total_tests'] ) - intval( $data['remaining_tests'] ),
|
||||
intval( $data['total_tests'] )
|
||||
),
|
||||
sprintf(
|
||||
/* translators: %1$s, %2$s: link wrapper. */
|
||||
esc_html__( 'Upgrade %1$shere%2$s to add more tests to your website!', 'visual-regression-tests' ),
|
||||
'<a href="' . esc_url( Url_Helpers::get_page_url( 'upgrade' ) ) . '" target="_blank">',
|
||||
'</a>'
|
||||
)
|
||||
)
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<div class="vrts-metabox-notice vrts-metabox-notice-is-error">
|
||||
<p><strong><?php esc_html_e( 'Ready for an Upgrade?', 'visual-regression-tests' ); ?></strong></p>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
'%1$s <a href="%2$s" target="_blank" title="%3$s">%3$s</a>',
|
||||
esc_html__( 'Looks like you need a bigger plan to add more tests.', 'visual-regression-tests' ),
|
||||
esc_url( Url_Helpers::get_page_url( 'upgrade' ) ),
|
||||
esc_html__( 'Upgrade here!', 'visual-regression-tests' )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,83 @@
|
||||
.vrts-modal {
|
||||
animation: vrts-fade-in 200ms both;
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
outline: 0;
|
||||
z-index: 9999999999;
|
||||
|
||||
&[aria-hidden="true"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&,
|
||||
&__overlay {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&__overlay {
|
||||
background-color: rgba(44, 51, 56, 0.35);
|
||||
}
|
||||
|
||||
&__content {
|
||||
animation: vrts-fade-in 300ms both, vrts-slide-up 300ms both;
|
||||
background-color: #fff;
|
||||
box-shadow: 2px 2px 8px 4px rgba(30, 30, 30, 0.12);
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: auto;
|
||||
max-height: min(calc(100vh - 40px), 620px);
|
||||
min-width: 250px;
|
||||
max-width: 345px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
z-index: 99999;
|
||||
|
||||
&-inner {
|
||||
flex: 1 1 auto;
|
||||
overflow: auto;
|
||||
padding: 10px 15px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&__close {
|
||||
all: unset;
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 7px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
display: block !important;
|
||||
background-image: url('data:image/svg+xml,<svg width="11" height="10" viewBox="0 0 11 10" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.2564 1.41L6.71644 4.95L10.2564 8.49L8.84645 9.9L5.30645 6.37L1.77644 9.9L0.356445 8.48L3.88645 4.95L0.356445 1.42L1.77644 0L5.30645 3.53L8.84645 0L10.2564 1.41Z" fill="%23757575"/></svg>'); // stylelint-disable-line
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
border-radius: 3px;
|
||||
font-size: 0;
|
||||
z-index: 1;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: #f6f7f7;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--vrts-admin-theme-color);
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin: 0;
|
||||
padding: 15px 45px 0 15px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import A11yDialog from 'a11y-dialog';
|
||||
|
||||
class VrtsModal extends window.HTMLElement {
|
||||
connectedCallback() {
|
||||
this.modal = new A11yDialog( this );
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.modal.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-modal', VrtsModal );
|
||||
@@ -0,0 +1,66 @@
|
||||
.vrts-settings {
|
||||
display: block;
|
||||
|
||||
h1 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
form h2 {
|
||||
font-weight: 400;
|
||||
font-size: 20px;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
margin-top: 0.75rem;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
fieldset {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
input {
|
||||
|
||||
&[readonly] {
|
||||
border-color: #8c8f94;
|
||||
background-color: #fff;
|
||||
color: #2c3338;
|
||||
}
|
||||
}
|
||||
|
||||
.form-table {
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 0 24px 24px 0;
|
||||
}
|
||||
|
||||
td fieldset label {
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&__pro-label {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 11px;
|
||||
line-height: 1;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
color: #fff;
|
||||
background: #757575;
|
||||
border-radius: 35px;
|
||||
}
|
||||
|
||||
&__modal {
|
||||
|
||||
&-info {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<vrts-settings class="wrap vrts-settings">
|
||||
<h1><?php echo esc_html( $data['title'] ); ?></h1>
|
||||
<form method="post" action="options.php">
|
||||
<?php
|
||||
settings_fields( $data['settings_fields'] );
|
||||
do_settings_sections( $data['settings_sections'] );
|
||||
submit_button();
|
||||
?>
|
||||
</form>
|
||||
<vrts-modal id="vrts-modal-pro-settings" class="vrts-modal vrts-settings__modal" aria-hidden="true">
|
||||
<div class="vrts-modal__overlay" data-a11y-dialog-hide></div>
|
||||
<div class="vrts-modal__content" role="document">
|
||||
<button type="button" class="vrts-modal__close" data-a11y-dialog-hide aria-label="<?php esc_attr_e( 'Close', 'visual-regression-tests' ); ?>"></button>
|
||||
<h2 class="vrts-modal__title">
|
||||
<?php esc_html_e( '🚀 Go Pro for more testing power!', 'visual-regression-tests' ); ?>
|
||||
</h2>
|
||||
<div class="vrts-modal__content-inner">
|
||||
<p class="vrts-settings__modal-info"><?php esc_html_e( 'Upgrade your plan and unlock automatic testing after updates, plus more tools like manual testing to keep your sites running smoothly.', 'visual-regression-tests' ); ?></p>
|
||||
<a href="<?php echo esc_url( Url_Helpers::get_page_url( 'upgrade' ) ); ?>" class="button button-primary vrts-settings__modal-link"><?php esc_html_e( 'Unlock Now', 'visual-regression-tests' ); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</vrts-modal>
|
||||
</vrts-settings>
|
||||
@@ -0,0 +1,36 @@
|
||||
class VrtsSettings extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.resolveElements();
|
||||
this.bindFunctions();
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$proSettingsCheckboxes = this.querySelectorAll(
|
||||
'[data-a11y-dialog-show] input[type="checkbox"]'
|
||||
);
|
||||
}
|
||||
|
||||
bindFunctions() {
|
||||
this.onCheckboxChange = this.onCheckboxChange.bind( this );
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$proSettingsCheckboxes?.forEach( ( item ) => {
|
||||
item.addEventListener( 'change', this.onCheckboxChange );
|
||||
} );
|
||||
}
|
||||
|
||||
onCheckboxChange( e ) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.checked = ! e.currentTarget.checked;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.$proSettingsCheckboxes?.forEach( ( item ) => {
|
||||
item.removeEventListener( 'change', this.onCheckboxChange );
|
||||
} );
|
||||
}
|
||||
}
|
||||
window.customElements.define( 'vrts-settings', VrtsSettings );
|
||||
@@ -0,0 +1,206 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
|
||||
.vrts-test-run-alerts {
|
||||
|
||||
&__heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #f0f0f1;
|
||||
padding: 0;
|
||||
height: 62px;
|
||||
overflow: hidden;
|
||||
transition: box-shadow 0.2s;
|
||||
|
||||
&[data-is-sticky="true"] {
|
||||
box-shadow: 0 1px 0 0 $gray-10;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
> * {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
@media (min-width: 851px) {
|
||||
padding: 0 20px;
|
||||
position: sticky;
|
||||
top: -0.1px;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
&-link {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
min-height: 30px;
|
||||
transition: color 0.2s;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: -15px;
|
||||
right: -15px;
|
||||
bottom: -5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $blue-50;
|
||||
}
|
||||
|
||||
&--button {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__list {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
padding: 0 10px 10px 10px;
|
||||
margin: 0 -10px;
|
||||
overflow-x: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
@media (min-width: 851px) {
|
||||
flex-direction: column;
|
||||
overflow: visible;
|
||||
padding: 0 20px;
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__card {
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
border: 1px solid $gray-10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 0 auto;
|
||||
transition: all 0.1s;
|
||||
box-shadow: inset 0 0 0 1px transparent;
|
||||
width: 60%;
|
||||
|
||||
@media (min-width: 480px) {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
@media (min-width: 851px) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:has([data-vrts-state="read"]) {
|
||||
background: #f6f7f9;
|
||||
}
|
||||
|
||||
&:has(:hover),
|
||||
&:has([data-vrts-current="true"]) {
|
||||
border-color: var(--vrts-admin-theme-color);
|
||||
box-shadow: inset 0 0 0 1px var(--vrts-admin-theme-color);
|
||||
}
|
||||
|
||||
&:has([data-vrts-current="false"]:focus-visible) {
|
||||
border-color: $gray-20;
|
||||
box-shadow: inset 0 0 0 1px $gray-20;
|
||||
}
|
||||
|
||||
&-link {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
padding: 10px 10px 0 10px;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-figure {
|
||||
position: relative;
|
||||
background: #f6f7f7;
|
||||
border: 1px solid $gray-5;
|
||||
aspect-ratio: 1 / 1.15;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-flag {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
visibility: hidden;
|
||||
|
||||
[data-vrts-false-positive="true"] & {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
&-image {
|
||||
position: absolute;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
&-title-inner,
|
||||
&-path {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3125rem;
|
||||
color: $gray-70;
|
||||
font-weight: 700;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 4px;
|
||||
text-decoration: none;
|
||||
|
||||
[data-vrts-state="read"] & {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
[data-vrts-state="unread"] &::after {
|
||||
content: "";
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: var(--vrts-admin-theme-color);
|
||||
border-radius: 50%;
|
||||
flex: 0 0 auto;
|
||||
margin-top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
&-path {
|
||||
padding: 10px;
|
||||
margin-top: -10px;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid $gray-20;
|
||||
outline-offset: -8px;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Models\Alert;
|
||||
use Vrts\Core\Utilities\Image_Helpers;
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
$unread_alerts = Alert::get_unread_count_by_test_run_ids( $data['run']->id );
|
||||
$unread_count = $unread_alerts[0]->count ?? 0;
|
||||
$unred_runs_count = Alert::get_total_items_grouped_by_test_run();
|
||||
$current_alert_id = isset( $data['alert']->id ) ? $data['alert']->id : 0;
|
||||
|
||||
?>
|
||||
<vrts-test-run-alerts
|
||||
class="vrts-test-run-alerts"
|
||||
data-vrts-current-alert="<?php echo esc_attr( $current_alert_id ? $current_alert_id : 'false' ); ?>"
|
||||
data-vrts-unread-runs="<?php echo esc_attr( $unred_runs_count ); ?>">
|
||||
<div class="vrts-test-run-alerts__heading">
|
||||
<a href="<?php echo esc_url( Url_Helpers::get_page_url( 'runs' ) ); ?>" class="vrts-test-run-alerts__heading-link">
|
||||
<?php vrts()->icon( 'chevron-left' ); ?>
|
||||
<?php esc_html_e( 'All Runs', 'visual-regression-tests' ); ?>
|
||||
</a>
|
||||
<?php if ( $data['alerts'] ) : ?>
|
||||
<button data-vrts-loading="false" data-vrts-action-state="<?php echo esc_attr( $unread_count > 0 ? 'primary' : 'secondary' ); ?>" data-vrts-test-run-id="<?php echo esc_attr( $data['run']->id ); ?>" data-vrts-test-run-action="read-status" class="vrts-test-run-alerts__heading-link vrts-test-run-alerts__heading-link--button vrts-action-button">
|
||||
<span class="vrts-action-button__icons">
|
||||
<span class="vrts-action-button__icon" data-vrts-action-state-secondary><?php vrts()->icon( 'email-unread' ); ?></span>
|
||||
<span class="vrts-action-button__icon" data-vrts-action-state-primary><?php vrts()->icon( 'email-read' ); ?></span>
|
||||
<span class="vrts-action-button__spinner"><?php vrts()->icon( 'spinner' ); ?></span>
|
||||
</span>
|
||||
<span class="vrts-action-button__info" data-vrts-action-state-primary><?php esc_html_e( 'Mark all as read', 'visual-regression-tests' ); ?></span>
|
||||
<span class="vrts-action-button__info" data-vrts-action-state-secondary><?php esc_html_e( 'Mark all as unread', 'visual-regression-tests' ); ?></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if ( $data['alerts'] ) : ?>
|
||||
<div class="vrts-test-run-alerts__list">
|
||||
<?php
|
||||
foreach ( $data['alerts'] as $alert ) :
|
||||
$test = null;
|
||||
foreach ( $data['tests'] as $some_test ) {
|
||||
if ( $some_test['post_id'] === $alert->post_id ) {
|
||||
$test = $some_test;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$alert_link = add_query_arg( [
|
||||
'run_id' => $data['run']->id,
|
||||
'alert_id' => $alert->id,
|
||||
], Url_Helpers::get_page_url( 'runs' ) );
|
||||
|
||||
$alert_permalink = '';
|
||||
$alert_post_title = '';
|
||||
if ( $test ) {
|
||||
$alert_permalink = $test['permalink'];
|
||||
$alert_post_title = $test['post_title'];
|
||||
}
|
||||
if ( ! $alert_permalink ) {
|
||||
$alert_permalink = get_permalink( $alert->post_id );
|
||||
}
|
||||
if ( ! $alert_post_title ) {
|
||||
$alert_post_title = get_the_title( $alert->post_id ) ?: 'N/A';
|
||||
}
|
||||
$alert_relative_permalink = Url_Helpers::make_relative( $alert_permalink );
|
||||
|
||||
?>
|
||||
<div class="vrts-test-run-alerts__card">
|
||||
<a
|
||||
id="vrts-alert-<?php echo esc_attr( $alert->id ); ?>"
|
||||
href="<?php echo esc_url( $alert_link ); ?>"
|
||||
class="vrts-test-run-alerts__card-link"
|
||||
data-vrts-alert="<?php echo esc_attr( $alert->id ); ?>"
|
||||
data-vrts-current="<?php echo esc_attr( $current_alert_id === $alert->id ? 'true' : 'false' ); ?>"
|
||||
data-vrts-state="<?php echo esc_attr( intval( $alert->alert_state ) === 0 ? 'unread' : 'read' ); ?>"
|
||||
data-vrts-false-positive="<?php echo esc_attr( $alert->is_false_positive ? 'true' : 'false' ); ?>">
|
||||
<figure class="vrts-test-run-alerts__card-figure">
|
||||
<img class="vrts-test-run-alerts__card-image" src="<?php echo esc_url( Image_Helpers::get_screenshot_url( $alert, 'comparison', 'preview' ) ); ?>" alt="<?php esc_attr_e( 'Difference', 'visual-regression-tests' ); ?>">
|
||||
<span class="vrts-test-run-alerts__card-flag"><?php vrts()->icon( 'flag' ); ?></span>
|
||||
</figure>
|
||||
<span class="vrts-test-run-alerts__card-title">
|
||||
<span class="vrts-test-run-alerts__card-title-inner"><?php echo esc_html( $alert_post_title ); ?></span>
|
||||
</span>
|
||||
</a>
|
||||
<a href="<?php echo esc_url( get_permalink( $alert->post_id ) ); ?>" target="_blank" class="vrts-test-run-alerts__card-path"><?php echo esc_html( $alert_relative_permalink ); ?></a>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php vrts()->component( 'test-run-receipt', $data ); ?>
|
||||
<script>
|
||||
const urlParams = new URLSearchParams( window.location.search );
|
||||
const currentAlertId = urlParams.get( 'alert_id' );
|
||||
|
||||
if ( currentAlertId ) {
|
||||
const $sidebar = document.querySelector(
|
||||
'.vrts-test-run-page__sidebar'
|
||||
);
|
||||
|
||||
let $alert = document.getElementById(
|
||||
`vrts-alert-${ currentAlertId }`
|
||||
);
|
||||
|
||||
let offsetTop = 0;
|
||||
|
||||
while ( $alert && $alert !== $sidebar ) {
|
||||
offsetTop += $alert.offsetTop;
|
||||
$alert = $alert.offsetParent;
|
||||
}
|
||||
|
||||
if ( $alert ) {
|
||||
$sidebar.scrollTo( {
|
||||
left: 0,
|
||||
top: offsetTop - 82,
|
||||
} );
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</vrts-test-run-alerts>
|
||||
@@ -0,0 +1,297 @@
|
||||
class VrtsTestRunAlerts extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.resolveElements();
|
||||
this.bindFunctions();
|
||||
this.bindEvents();
|
||||
this.unreadAlerts = new Set();
|
||||
this.initialUnreadAlerts = 0;
|
||||
this.unreadRuns = parseInt(
|
||||
this.getAttribute( 'data-vrts-unread-runs' ),
|
||||
10
|
||||
);
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$heading = this.querySelector( '.vrts-test-run-alerts__heading' );
|
||||
this.$alerts = this.querySelectorAll( '[data-vrts-alert]' );
|
||||
this.$actionButtons = this.querySelectorAll(
|
||||
'[data-vrts-test-run-action]'
|
||||
);
|
||||
|
||||
this.$runsMenuItems = [
|
||||
document.querySelector(
|
||||
'.vrts-admin-header [href*="page=vrts-runs"]'
|
||||
),
|
||||
document.querySelector(
|
||||
'#adminmenu .menu-top[href*="page=vrts"] .wp-menu-name'
|
||||
),
|
||||
document.querySelector(
|
||||
'#adminmenu .wp-submenu a[href*="page=vrts-runs"]'
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
bindFunctions() {
|
||||
this.handleAlertClick = this.handleAlertClick.bind( this );
|
||||
this.handleActionClick = this.handleActionClick.bind( this );
|
||||
this.updateRunsCount = this.updateRunsCount.bind( this );
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$alerts?.forEach( ( item ) => {
|
||||
item.addEventListener( 'click', this.handleAlertClick );
|
||||
} );
|
||||
this.$actionButtons?.forEach( ( item ) => {
|
||||
item.addEventListener( 'click', this.handleActionClick );
|
||||
} );
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.checkHeadingSticky();
|
||||
this.checkReadStatusChange();
|
||||
|
||||
this.$alerts.forEach( ( item ) => {
|
||||
const isUnread =
|
||||
item.getAttribute( 'data-vrts-state' ) === 'unread';
|
||||
if ( isUnread ) {
|
||||
this.unreadAlerts.add( item.getAttribute( 'data-vrts-alert' ) );
|
||||
}
|
||||
} );
|
||||
|
||||
this.initialUnreadAlerts = this.unreadAlerts.size;
|
||||
}
|
||||
|
||||
checkHeadingSticky() {
|
||||
const checkIsSticky = ( entries ) => {
|
||||
const isSticky = ! entries[ 0 ].isIntersecting;
|
||||
this.$heading.setAttribute( 'data-is-sticky', isSticky );
|
||||
};
|
||||
|
||||
const observer = new window.IntersectionObserver( checkIsSticky, {
|
||||
root: document,
|
||||
threshold: [ 1 ],
|
||||
} );
|
||||
|
||||
observer.observe( this.$heading );
|
||||
}
|
||||
|
||||
checkReadStatusChange() {
|
||||
const observer = new window.MutationObserver( ( mutations ) => {
|
||||
mutations.forEach( ( mutation ) => {
|
||||
if (
|
||||
mutation.type === 'attributes' &&
|
||||
mutation.attributeName === 'data-vrts-state'
|
||||
) {
|
||||
const id =
|
||||
mutation.target.getAttribute( 'data-vrts-alert' );
|
||||
const state =
|
||||
mutation.target.getAttribute( 'data-vrts-state' );
|
||||
|
||||
if ( id === 'receipt' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'unread' === state ) {
|
||||
this.unreadAlerts.add( id );
|
||||
} else {
|
||||
this.unreadAlerts.delete( id );
|
||||
}
|
||||
|
||||
this.querySelector(
|
||||
'[data-vrts-test-run-action="read-status"]'
|
||||
).setAttribute(
|
||||
'data-vrts-action-state',
|
||||
this.unreadAlerts.size > 0 ? 'primary' : 'secondary'
|
||||
);
|
||||
|
||||
this.updateRunsCount( this.unreadAlerts.size );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
this.$alerts.forEach( ( item ) => {
|
||||
observer.observe( item, {
|
||||
attributes: true,
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
updateRunsCount( unreadAlerts ) {
|
||||
let unreadRuns = this.unreadRuns;
|
||||
|
||||
if ( unreadAlerts > 0 && this.initialUnreadAlerts === 0 ) {
|
||||
unreadRuns += 1;
|
||||
} else if ( unreadAlerts === 0 && this.initialUnreadAlerts > 0 ) {
|
||||
unreadRuns -= 1;
|
||||
}
|
||||
|
||||
this.$runsMenuItems.forEach( ( item ) => {
|
||||
if ( item ) {
|
||||
item.querySelector( '.update-plugins' )?.remove();
|
||||
item.textContent = item.textContent.replace( /\u00A0/g, '' );
|
||||
|
||||
if ( unreadRuns > 0 ) {
|
||||
const $count = document.createElement( 'span' );
|
||||
const nbsp = document.createTextNode( '\u00A0' );
|
||||
$count.classList.add( 'update-plugins' );
|
||||
$count.textContent = unreadRuns;
|
||||
|
||||
item.appendChild( nbsp );
|
||||
item.appendChild( $count );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
handleAlertClick( e ) {
|
||||
e.preventDefault();
|
||||
const $el = e.currentTarget;
|
||||
const isCurrent = $el.getAttribute( 'data-vrts-current' ) === 'true';
|
||||
|
||||
if ( isCurrent ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const href = $el.getAttribute( 'href' );
|
||||
const $content =
|
||||
document.querySelector( 'vrts-comparisons' ) ||
|
||||
document.querySelector( 'vrts-test-run-success' );
|
||||
const $pagination = document.querySelector(
|
||||
'vrts-test-run-pagination'
|
||||
);
|
||||
|
||||
this.$alerts.forEach( ( item ) => {
|
||||
item.setAttribute( 'data-vrts-current', 'false' );
|
||||
} );
|
||||
|
||||
$el.setAttribute( 'data-vrts-current', 'true' );
|
||||
|
||||
const timeout = setTimeout( () => {
|
||||
$content.setAttribute( 'data-vrts-loading', 'true' );
|
||||
}, 200 );
|
||||
|
||||
fetch( href )
|
||||
.then( ( response ) => {
|
||||
return response.text();
|
||||
} )
|
||||
.then( ( data ) => {
|
||||
const parser = new window.DOMParser();
|
||||
const $html = parser.parseFromString( data, 'text/html' );
|
||||
|
||||
const $newContent =
|
||||
$html.querySelector( 'vrts-comparisons' ) ||
|
||||
$html.querySelector( 'vrts-test-run-success' );
|
||||
const $newPagination = $html.querySelector(
|
||||
'vrts-test-run-pagination'
|
||||
);
|
||||
|
||||
window.history.replaceState( {}, '', href );
|
||||
|
||||
this.scrollTo( $content.offsetTop - 62 );
|
||||
|
||||
if ( $newContent ) {
|
||||
$content.replaceWith( $newContent );
|
||||
}
|
||||
|
||||
if ( $newPagination ) {
|
||||
$pagination.replaceWith( $newPagination );
|
||||
}
|
||||
|
||||
clearTimeout( timeout );
|
||||
} );
|
||||
}
|
||||
|
||||
handleActionClick( e ) {
|
||||
const $el = e.currentTarget;
|
||||
const isLoading = $el.getAttribute( 'data-vrts-loading' ) === 'true';
|
||||
const state = $el.getAttribute( 'data-vrts-action-state' );
|
||||
const isPrimary = state === 'primary';
|
||||
|
||||
if ( isLoading ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const action = $el.getAttribute( 'data-vrts-test-run-action' );
|
||||
const id = $el.getAttribute( 'data-vrts-test-run-id' );
|
||||
|
||||
this.handleAction( action, $el, id, isPrimary );
|
||||
}
|
||||
|
||||
handleAction( action, $el, id, shouldSetAction ) {
|
||||
const restEndpoint = `${ window.vrts_admin_vars.rest_url }/test-runs/${ id }/${ action }`;
|
||||
const method = shouldSetAction ? 'POST' : 'DELETE';
|
||||
|
||||
let loadingElapsedTime = 0;
|
||||
let interval = null;
|
||||
|
||||
const timeout = setTimeout( () => {
|
||||
$el.setAttribute( 'data-vrts-loading', 'true' );
|
||||
const loadingStartTime = window.Date.now();
|
||||
interval = setInterval( () => {
|
||||
loadingElapsedTime = window.Date.now() - loadingStartTime;
|
||||
}, 50 );
|
||||
}, 200 );
|
||||
|
||||
fetch( restEndpoint, {
|
||||
method,
|
||||
headers: {
|
||||
'X-WP-Nonce': window.vrts_admin_vars.rest_nonce,
|
||||
},
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
return response.json();
|
||||
} )
|
||||
.then( () => {
|
||||
const loadingTimeoutTime =
|
||||
loadingElapsedTime > 0
|
||||
? Math.abs( loadingElapsedTime - 400 )
|
||||
: 0;
|
||||
|
||||
setTimeout( () => {
|
||||
$el.setAttribute( 'data-vrts-loading', 'false' );
|
||||
$el.setAttribute(
|
||||
'data-vrts-action-state',
|
||||
shouldSetAction ? 'secondary' : 'primary'
|
||||
);
|
||||
|
||||
const $alerts =
|
||||
document.querySelectorAll( '[data-vrts-alert]' );
|
||||
|
||||
$alerts.forEach( ( item ) => {
|
||||
item.setAttribute(
|
||||
'data-vrts-state',
|
||||
shouldSetAction ? 'read' : 'unread'
|
||||
);
|
||||
} );
|
||||
}, loadingTimeoutTime );
|
||||
|
||||
clearTimeout( timeout );
|
||||
clearInterval( interval );
|
||||
} );
|
||||
}
|
||||
|
||||
scrollTo( offset ) {
|
||||
const $el =
|
||||
document.fullscreenElement ||
|
||||
document.webkitFullscreenElement ||
|
||||
document.msFullscreenElement ||
|
||||
window;
|
||||
|
||||
$el.scrollTo( {
|
||||
top: offset,
|
||||
behavior: 'smooth',
|
||||
} );
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.$alerts?.forEach( ( item ) => {
|
||||
item.removeEventListener( 'click', this.handleAlertClick );
|
||||
} );
|
||||
this.$actionButtons?.forEach( ( item ) => {
|
||||
item.removeEventListener( 'click', this.handleActionClick );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-test-run-alerts', VrtsTestRunAlerts );
|
||||
@@ -0,0 +1,44 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
|
||||
.vrts-test-run-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
@media (max-width: 700px) {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
> * {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
min-width: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:not(:last-child)::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 1px;
|
||||
height: 1rem;
|
||||
background: $gray-10;
|
||||
}
|
||||
}
|
||||
|
||||
&__trigger {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.vrts-test-run-trigger-notes {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
display: -webkit-box;
|
||||
color: $gray-40;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
max-block-size: calc(13px * 1.4);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: initial;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Date_Time_Helpers;
|
||||
use Vrts\Models\Test_Run;
|
||||
|
||||
$trigger_note = Test_Run::get_trigger_note( $data );
|
||||
|
||||
?>
|
||||
<div class="vrts-test-run-info">
|
||||
<strong>
|
||||
<?php
|
||||
// translators: %s: the run number.
|
||||
printf( esc_html__( 'Run #%s', 'visual-regression-tests' ), esc_html( $data->id ) );
|
||||
?>
|
||||
</strong>
|
||||
<?php echo wp_kses( Date_Time_Helpers::get_formatted_relative_date_time( $data->finished_at ), [ 'time' => [ 'datetime' => true ] ] ); ?>
|
||||
<span class="vrts-test-run-info__trigger">
|
||||
<span class="vrts-test-run-trigger vrts-test-run-trigger--<?php echo esc_attr( $data->trigger ); ?>">
|
||||
<?php echo esc_html( Test_Run::get_trigger_title( $data ) ); ?>
|
||||
</span>
|
||||
<?php if ( ! empty( $trigger_note ) ) : ?>
|
||||
<span class="vrts-test-run-trigger-notes" title="<?php echo esc_attr( $trigger_note ); ?>">
|
||||
<?php echo esc_html( $trigger_note ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
</div>
|
||||
@@ -0,0 +1,128 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
@import "@wordpress/base-styles/mixins";
|
||||
@import "@wordpress/base-styles/breakpoints";
|
||||
@import "@wordpress/base-styles/variables";
|
||||
@import "@wordpress/base-styles/default-custom-properties";
|
||||
|
||||
.vrts-test-run-wrap {
|
||||
|
||||
#wpfooter {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#wpbody-content {
|
||||
padding-bottom: 0;
|
||||
|
||||
@media (min-width: 851px) {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-test-run-page {
|
||||
--vrts-test-run-page-offset: 54px; // our header height
|
||||
|
||||
display: flex;
|
||||
margin-right: 10px;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
|
||||
@media (min-width: 851px) {
|
||||
gap: 20px;
|
||||
flex-direction: row;
|
||||
margin-left: -20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
&__sidebar {
|
||||
order: 2;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: linear-gradient(to right, #{$gray-10} 1px, transparent 1px);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: $gray-20;
|
||||
}
|
||||
|
||||
@media (min-width: 851px) {
|
||||
order: -1;
|
||||
width: 280px;
|
||||
position: sticky;
|
||||
top: var(--wp-admin--admin-bar--height);
|
||||
height: calc(100vh - var(--wp-admin--admin-bar--height) - var(--vrts-test-run-page-offset));
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
flex: 1;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 20px;
|
||||
|
||||
&[data-vrts-fullscreen="true"] {
|
||||
overflow: auto;
|
||||
padding: 0 20px 20px 20px;
|
||||
background-color: #f0f0f1;
|
||||
}
|
||||
|
||||
@media (min-width: 851px) {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
&-heading {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
column-gap: 2rem;
|
||||
row-gap: 1rem;
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid $gray-10;
|
||||
|
||||
@media (min-width: 851px) {
|
||||
box-sizing: border-box;
|
||||
flex-wrap: nowrap;
|
||||
position: sticky;
|
||||
top: var(--wp-admin--admin-bar--height);
|
||||
height: 62px;
|
||||
padding: 0;
|
||||
background: #f0f0f1;
|
||||
z-index: 1;
|
||||
|
||||
[data-vrts-fullscreen="true"] & {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-navigation-info {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.25rem;
|
||||
margin-top: 1rem;
|
||||
color: #757575;
|
||||
|
||||
@media (min-width: 851px) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
svg {
|
||||
color: $gray-70;
|
||||
background: $gray-5;
|
||||
border-radius: 3px;
|
||||
padding: 5px;
|
||||
width: 0.75rem;
|
||||
height: 0.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<vrts-test-run-page class="vrts-test-run-page">
|
||||
<div class="vrts-test-run-page__sidebar">
|
||||
<?php vrts()->component( 'test-run-alerts', $data ); ?>
|
||||
</div>
|
||||
<div class="vrts-test-run-page__content" data-vrts-fullscreen="false">
|
||||
<div class="vrts-test-run-page__content-heading">
|
||||
<?php vrts()->component( 'test-run-info', $data['run'] ); ?>
|
||||
<?php
|
||||
vrts()->component( 'test-run-pagination', [
|
||||
'run' => $data['run'],
|
||||
'pagination' => $data['pagination'],
|
||||
'is_receipt' => $data['is_receipt'],
|
||||
] );
|
||||
?>
|
||||
</div>
|
||||
<?php if ( $data['alerts'] && ! $data['is_receipt'] ) : ?>
|
||||
<?php
|
||||
vrts()->component( 'comparisons', [
|
||||
'alert' => $data['alert'],
|
||||
'test_settings' => $data['test_settings'],
|
||||
] );
|
||||
?>
|
||||
<div class="vrts-test-run-page__content-navigation-info">
|
||||
<?php esc_html_e( 'Navigate with arrow keys', 'visual-regression-tests' ); ?>
|
||||
<?php vrts()->icon( 'arrow-up' ); ?>
|
||||
<?php vrts()->icon( 'arrow-down' ); ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<?php
|
||||
vrts()->component( 'test-run-success', [
|
||||
'run' => $data['run'],
|
||||
'is_receipt' => $data['is_receipt'],
|
||||
] );
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</vrts-test-run-page>
|
||||
@@ -0,0 +1,50 @@
|
||||
class VrtsTestRunPage extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.bindFunctions();
|
||||
this.bindEvents();
|
||||
this.isScrolling = false;
|
||||
}
|
||||
|
||||
bindFunctions() {
|
||||
this.onScroll = this.onScroll.bind( this );
|
||||
this.setOffset = this.setOffset.bind( this );
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
document.addEventListener( 'scroll', this.onScroll );
|
||||
}
|
||||
|
||||
onScroll() {
|
||||
if ( ! this.isScrolling ) {
|
||||
this.isScrolling = true;
|
||||
window.requestAnimationFrame( this.setOffset );
|
||||
}
|
||||
}
|
||||
|
||||
setOffset() {
|
||||
const offset = Math.max( 0, this.offset - window.scrollY );
|
||||
|
||||
this.style.setProperty(
|
||||
'--vrts-test-run-page-offset',
|
||||
`${ offset }px`
|
||||
);
|
||||
|
||||
this.isScrolling = false;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
const rect = this.getBoundingClientRect();
|
||||
const adminBarHeight =
|
||||
document.getElementById( 'wpadminbar' ).offsetHeight;
|
||||
this.offset = rect.top + window.scrollY - adminBarHeight;
|
||||
|
||||
this.setOffset();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
document.removeEventListener( 'scroll', this.onScroll );
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-test-run-page', VrtsTestRunPage );
|
||||
@@ -0,0 +1,22 @@
|
||||
.vrts-test-run-pagination {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
align-items: center;
|
||||
|
||||
&__text {
|
||||
white-space: nowrap;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
vertical-align: baseline;
|
||||
min-width: 30px;
|
||||
min-height: 30px;
|
||||
margin: 0;
|
||||
padding: 0 4px;
|
||||
font-size: 16px;
|
||||
line-height: 1.625;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
// don't show pagination if there is no previous or next alert.
|
||||
if ( 0 === $data['pagination']['total'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<vrts-test-run-pagination class="vrts-test-run-pagination">
|
||||
<span class="screen-reader-text"><?php esc_html_e( 'Current Page', 'visual-regression-tests' ); ?></span>
|
||||
<span class="vrts-test-run-pagination__text">
|
||||
<?php
|
||||
if ( $data['is_receipt'] ) {
|
||||
esc_html_e( 'Test Receipt', 'visual-regression-tests' );
|
||||
} else {
|
||||
printf(
|
||||
/* translators: %d: pages. */
|
||||
esc_html_x( 'Alert %1$d of %2$d', 'e.g. Alert 1 of 2', 'visual-regression-tests' ),
|
||||
esc_html( $data['pagination']['current'] ),
|
||||
esc_html( $data['pagination']['total'] )
|
||||
);
|
||||
}
|
||||
?>
|
||||
</span>
|
||||
<a data-vrts-pagination="prev" data-vrts-alert-id="<?php echo esc_attr( $data['pagination']['prev_alert_id'] ); ?>" class="button <?php echo ( 0 === $data['pagination']['prev_alert_id'] ) ? 'button-disabled' : ''; ?>"
|
||||
<?php echo ( 0 !== $data['pagination']['prev_alert_id'] ) ? 'href="' . esc_url( Url_Helpers::get_alert_page( $data['pagination']['prev_alert_id'], $data['run']->id ) ) . '"' : ''; ?>>
|
||||
<span class="screen-reader-text"><?php esc_html_e( 'Previous alert', 'visual-regression-tests' ); ?></span>
|
||||
<span aria-hidden="true">‹</span>
|
||||
</a>
|
||||
<a data-vrts-pagination="next" data-vrts-alert-id="<?php echo esc_attr( $data['pagination']['next_alert_id'] ); ?>" class="button <?php echo ( 0 === $data['pagination']['next_alert_id'] ) ? 'button-disabled' : ''; ?>"
|
||||
<?php echo ( 0 !== $data['pagination']['next_alert_id'] ) ? 'href="' . esc_url( Url_Helpers::get_alert_page( $data['pagination']['next_alert_id'], $data['run']->id ) ) . '"' : ''; ?>>
|
||||
<span class="screen-reader-text"><?php esc_html_e( 'Next alert', 'visual-regression-tests' ); ?></span>
|
||||
<span aria-hidden="true">›</span>
|
||||
</a>
|
||||
</vrts-test-run-pagination>
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
class VrtsTestRunPagination extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.resolveElements();
|
||||
this.bindFunctions();
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$alerts = document.querySelectorAll( '[data-vrts-alert]' );
|
||||
this.$buttons = this.querySelectorAll( '.button' );
|
||||
}
|
||||
|
||||
bindFunctions() {
|
||||
this.handleClick = this.handleClick.bind( this );
|
||||
this.handleKeyDown = this.handleKeyDown.bind( this );
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$buttons?.forEach( ( item ) => {
|
||||
item.addEventListener( 'click', this.handleClick );
|
||||
} );
|
||||
|
||||
document.addEventListener( 'keydown', this.handleKeyDown );
|
||||
}
|
||||
|
||||
handleClick( e ) {
|
||||
e.preventDefault();
|
||||
const $el = e.currentTarget;
|
||||
const nextAlertId = $el.getAttribute( 'data-vrts-alert-id' );
|
||||
let $nextAlert = document.getElementById(
|
||||
`vrts-alert-${ nextAlertId }`
|
||||
);
|
||||
|
||||
if ( ! $nextAlert ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const href = $el.getAttribute( 'href' );
|
||||
const $content =
|
||||
document.querySelector( 'vrts-comparisons' ) ||
|
||||
document.querySelector( 'vrts-test-run-success' );
|
||||
const $sidebar = document.querySelector(
|
||||
'.vrts-test-run-page__sidebar'
|
||||
);
|
||||
|
||||
this.$alerts.forEach( ( item ) => {
|
||||
item.setAttribute( 'data-vrts-current', 'false' );
|
||||
} );
|
||||
|
||||
$nextAlert.setAttribute( 'data-vrts-current', 'true' );
|
||||
|
||||
let loadingElapsedTime = 0;
|
||||
let interval = null;
|
||||
|
||||
const timeout = setTimeout( () => {
|
||||
$content.setAttribute( 'data-vrts-loading', 'true' );
|
||||
const loadingStartTime = window.Date.now();
|
||||
interval = setInterval( () => {
|
||||
loadingElapsedTime = window.Date.now() - loadingStartTime;
|
||||
}, 50 );
|
||||
}, 200 );
|
||||
|
||||
let offsetTop = 0;
|
||||
|
||||
while ( $nextAlert && $nextAlert !== $sidebar ) {
|
||||
offsetTop += $nextAlert.offsetTop;
|
||||
$nextAlert = $nextAlert.offsetParent;
|
||||
}
|
||||
|
||||
$sidebar.scrollTo( {
|
||||
top: offsetTop - 82,
|
||||
behavior: 'smooth',
|
||||
} );
|
||||
|
||||
fetch( href )
|
||||
.then( ( response ) => {
|
||||
return response.text();
|
||||
} )
|
||||
.then( ( data ) => {
|
||||
const parser = new window.DOMParser();
|
||||
const $html = parser.parseFromString( data, 'text/html' );
|
||||
|
||||
const $newContent =
|
||||
$html.querySelector( 'vrts-comparisons' ) ||
|
||||
$html.querySelector( 'vrts-test-run-success' );
|
||||
const $newPagination = $html.querySelector(
|
||||
'vrts-test-run-pagination'
|
||||
);
|
||||
|
||||
window.history.replaceState( {}, '', href );
|
||||
|
||||
this.scrollTo( $content.offsetTop - 62 );
|
||||
|
||||
const loadingTimeoutTime =
|
||||
loadingElapsedTime > 0
|
||||
? Math.abs( loadingElapsedTime - 400 )
|
||||
: 0;
|
||||
|
||||
setTimeout( () => {
|
||||
if ( $newContent ) {
|
||||
$content.replaceWith( $newContent );
|
||||
}
|
||||
|
||||
if ( $newPagination ) {
|
||||
this.replaceWith( $newPagination );
|
||||
}
|
||||
}, loadingTimeoutTime );
|
||||
|
||||
clearTimeout( timeout );
|
||||
clearInterval( interval );
|
||||
} );
|
||||
}
|
||||
|
||||
handleKeyDown( e ) {
|
||||
if ( e.key === 'ArrowUp' ) {
|
||||
e.preventDefault();
|
||||
this.querySelector( '[data-vrts-pagination="prev"]' ).click();
|
||||
}
|
||||
|
||||
if ( e.key === 'ArrowDown' ) {
|
||||
e.preventDefault();
|
||||
this.querySelector( '[data-vrts-pagination="next"]' ).click();
|
||||
}
|
||||
}
|
||||
|
||||
scrollTo( offset ) {
|
||||
const $el =
|
||||
document.fullscreenElement ||
|
||||
document.webkitFullscreenElement ||
|
||||
document.msFullscreenElement ||
|
||||
window;
|
||||
|
||||
$el.scrollTo( {
|
||||
top: offset,
|
||||
behavior: 'smooth',
|
||||
} );
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.$buttons?.forEach( ( item ) => {
|
||||
item.removeEventListener( 'click', this.handleClick );
|
||||
} );
|
||||
|
||||
document.removeEventListener( 'keydown', this.handleKeyDown );
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define(
|
||||
'vrts-test-run-pagination',
|
||||
VrtsTestRunPagination
|
||||
);
|
||||
@@ -0,0 +1,205 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
|
||||
.vrts-test-run-receipt {
|
||||
position: relative;
|
||||
padding: 0 12px;
|
||||
margin: 30px auto 30px auto;
|
||||
background-color: #f6f7fb;
|
||||
box-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.07);
|
||||
max-width: 280px;
|
||||
transition: box-shadow 0.2s;
|
||||
|
||||
@media (min-width: 851px) {
|
||||
max-width: 100%;
|
||||
margin: 8px 20px 20px;
|
||||
}
|
||||
|
||||
&:has(.vrts-test-run-receipt__link:hover),
|
||||
&:has(.vrts-test-run-receipt__link:focus-visible) {
|
||||
box-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
--vrts-test-run-receipt-mask: radial-gradient(10px at top, #0000 97%, #000) 50% / 18.5px 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 100%;
|
||||
content: "";
|
||||
mask: var(--vrts-test-run-receipt-mask);
|
||||
display: block;
|
||||
height: 10px;
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
&::after {
|
||||
--vrts-test-run-receipt-mask: radial-gradient(10px at bottom, #0000 97%, #000) 50% / 18.5px 100%;
|
||||
bottom: -10px;
|
||||
}
|
||||
|
||||
> * {
|
||||
padding: 12px 0;
|
||||
|
||||
&:where(:not(:last-child)) {
|
||||
border-bottom: 1px dashed #c3c4c7;
|
||||
}
|
||||
}
|
||||
|
||||
> svg {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&__link {
|
||||
display: block;
|
||||
border: none;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding-top: 20px;
|
||||
|
||||
&-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
justify-content: center;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
|
||||
svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
path {
|
||||
fill: #2c3338;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-info {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
gap: 2px;
|
||||
|
||||
a {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
column-gap: 10px;
|
||||
justify-content: center;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
&__pages-status,
|
||||
&__total {
|
||||
line-height: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
|
||||
&-heading,
|
||||
&-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
&-heading {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
&-row {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
a {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
display: -webkit-box;
|
||||
color: inherit;
|
||||
max-block-size: 16px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-decoration: none;
|
||||
white-space: initial;
|
||||
word-break: break-all;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__total {
|
||||
border-top: 1px dashed #c3c4c7;
|
||||
margin-top: 2px;
|
||||
|
||||
&-heading {
|
||||
font-size: 14px;
|
||||
|
||||
> :first-child {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
&-row {
|
||||
font-size: 12px;
|
||||
|
||||
&--success {
|
||||
color: #4ab866;
|
||||
}
|
||||
|
||||
&--failed {
|
||||
color: #b32d2e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__trigger {
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
|
||||
.vrts-test-run-trigger {
|
||||
font-size: inherit;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&-notes {
|
||||
color: #757575;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Date_Time_Helpers;
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
use Vrts\Models\Test_Run;
|
||||
|
||||
$trigger_note = Test_Run::get_trigger_note( $data['run'] );
|
||||
|
||||
?>
|
||||
|
||||
<div class="vrts-test-run-receipt">
|
||||
<?php if ( $data['alerts'] ) : ?>
|
||||
<a id="vrts-alert-receipt" class="vrts-test-run-receipt__link" data-vrts-alert="receipt" href="<?php echo esc_url( Url_Helpers::get_alert_page( 'receipt', $data['run']->id ) ); ?>"></a>
|
||||
<?php endif; ?>
|
||||
<div class="vrts-test-run-receipt__header">
|
||||
<div class="vrts-test-run-receipt__header-logo">
|
||||
<?php vrts()->logo(); ?>
|
||||
<?php esc_html_e( 'VRTs Plugin', 'visual-regression-tests' ); ?>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__header-info">
|
||||
<?php esc_html_e( 'Test Receipt', 'visual-regression-tests' ); ?>
|
||||
<a href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php echo esc_html( home_url( '/' ) ); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__info">
|
||||
<?php
|
||||
// translators: %s: the run number.
|
||||
printf( esc_html__( 'Run #%s', 'visual-regression-tests' ), esc_html( $data['run']->id ) );
|
||||
?>
|
||||
<?php echo wp_kses( Date_Time_Helpers::get_formatted_relative_date_time( $data['run']->finished_at ), [ 'time' => [ 'datetime' => true ] ] ); ?>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__pages-status">
|
||||
<div class="vrts-test-run-receipt__pages-status-heading">
|
||||
<span><?php esc_html_e( 'Page', 'visual-regression-tests' ); ?></span>
|
||||
<span><?php esc_html_e( 'Difference', 'visual-regression-tests' ); ?></span>
|
||||
</div>
|
||||
<?php
|
||||
foreach ( $data['tests'] as $test ) :
|
||||
$alert = array_values( array_filter( $data['alerts'], static function ( $alert ) use ( $test ) {
|
||||
return $alert->post_id === $test['post_id'];
|
||||
} ) );
|
||||
$difference = $alert ? ceil( $alert[0]->differences ) : 0;
|
||||
?>
|
||||
<div class="vrts-test-run-receipt__pages-status-row">
|
||||
<?php if ( $test['permalink'] ) : ?>
|
||||
<a href="<?php echo esc_url( $test['permalink'] ); ?>"><?php echo esc_html( Url_Helpers::make_relative( $test['permalink'] ) ); ?></a>
|
||||
<?php else : ?>
|
||||
N/A
|
||||
<?php endif; ?>
|
||||
<span>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s. Test run receipt diff in pixels */
|
||||
esc_html_x( '%spx', 'test run receipt difference', 'visual-regression-tests' ),
|
||||
esc_html( number_format_i18n( $difference ) )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__total">
|
||||
<div class="vrts-test-run-receipt__total-heading">
|
||||
<span><?php esc_html_e( 'Total', 'visual-regression-tests' ); ?></span>
|
||||
<span>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s. Number of tests */
|
||||
esc_html( _n( '%s Test', '%s Tests', count( $data['tests'] ), 'visual-regression-tests' ) ), count( $data['tests'] )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__total-row vrts-test-run-receipt__total-row--success">
|
||||
<span><?php esc_html_e( 'Passed', 'visual-regression-tests' ); ?></span>
|
||||
<span>
|
||||
<?php
|
||||
$passed_tests_count = count( $data['tests'] ) - count( $data['alerts'] );
|
||||
printf(
|
||||
/* translators: %s. Number of tests */
|
||||
esc_html( _n( '%s Test', '%s Tests', $passed_tests_count, 'visual-regression-tests' ) ), esc_html( $passed_tests_count )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__total-row vrts-test-run-receipt__total-row--failed">
|
||||
<span><?php esc_html_e( 'Changes detected', 'visual-regression-tests' ); ?></span>
|
||||
<span>
|
||||
<?php
|
||||
$changed_detected_count = count( $data['alerts'] );
|
||||
printf(
|
||||
/* translators: %s. Number of tests */
|
||||
esc_html( _n( '%s Test', '%s Tests', $changed_detected_count, 'visual-regression-tests' ) ), esc_html( $changed_detected_count )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__trigger">
|
||||
<?php esc_html_e( 'Trigger', 'visual-regression-tests' ); ?>
|
||||
<span class="vrts-test-run-trigger vrts-test-run-trigger--<?php echo esc_attr( $data['run']->trigger ); ?>">
|
||||
<?php echo esc_html( Test_Run::get_trigger_title( $data['run'] ) ); ?>
|
||||
</span>
|
||||
<?php if ( ! empty( $trigger_note ) ) : ?>
|
||||
<span class="vrts-test-run-receipt__trigger-notes" title="<?php echo esc_attr( $trigger_note ); ?>">
|
||||
<?php echo esc_html( $trigger_note ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__footer">
|
||||
<?php esc_html_e( 'Test Completed!', 'visual-regression-tests' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,60 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
|
||||
.vrts-test-run-success {
|
||||
display: block;
|
||||
padding: max(50px, 8%) 20px;
|
||||
border-top: 0;
|
||||
overflow: hidden;
|
||||
|
||||
&__inner {
|
||||
margin-bottom: 1.5rem;
|
||||
max-width: 600px;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
&__lottie-player {
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
aspect-ratio: 10 / 8;
|
||||
margin-top: calc(100% / (10 / 8) * 0.3 * -1);
|
||||
|
||||
svg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
text-align: center;
|
||||
margin-top: calc(100% / (10 / 8) * 0.3 * -1);
|
||||
|
||||
> p {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 2rem auto 0 auto;
|
||||
max-width: 350px;
|
||||
text-wrap: balance;
|
||||
|
||||
p,
|
||||
cite {
|
||||
color: $gray-50;
|
||||
margin: 5px;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
cite {
|
||||
color: $gray-700;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
$quotes = [
|
||||
[
|
||||
'quote' => __( 'Change is inevitable – except from a vending machine.', 'visual-regression-tests' ),
|
||||
'author' => 'Robert C. Gallagher',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'It’s not what happens to you, but how you react to it that matters.', 'visual-regression-tests' ),
|
||||
'author' => 'Epictetus',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Every success story is a tale of constant adaptation, revision, and change.', 'visual-regression-tests' ),
|
||||
'author' => 'Richard Branson',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Change is hard at first, messy in the middle and gorgeous at the end.', 'visual-regression-tests' ),
|
||||
'author' => 'Robin Sharma',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Without deviation from the norm, progress is not possible.', 'visual-regression-tests' ),
|
||||
'author' => 'Frank Zappa',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Perfection is not attainable, but if we chase perfection we can catch excellence.', 'visual-regression-tests' ),
|
||||
'author' => 'Vince Lombardi',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'It’s the little details that are vital. Little things make big things happen.', 'visual-regression-tests' ),
|
||||
'author' => 'John Wooden',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'It is not the strongest of the species that survive, nor the most intelligent. It is the one that is most adaptable to change.', 'visual-regression-tests' ),
|
||||
'author' => 'Charles Darwin',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Attention to detail is not about perfection. It’s about excellence, about constant improvement.', 'visual-regression-tests' ),
|
||||
'author' => 'Chris Denny',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The difference between something good and something great is attention to detail.', 'visual-regression-tests' ),
|
||||
'author' => 'Charles R Swindoll',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Details make perfection, and perfection is not a detail.', 'visual-regression-tests' ),
|
||||
'author' => 'Leonardo da Vinci',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Not everything that is faced can be changed, but nothing can be changed until it is faced.', 'visual-regression-tests' ),
|
||||
'author' => 'James Baldwin',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Small deeds done are better than great deeds planned.', 'visual-regression-tests' ),
|
||||
'author' => 'Peter Marshall',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Great things are not done by impulse, but by a series of small things brought together.', 'visual-regression-tests' ),
|
||||
'author' => 'Vincent Van Gogh',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Success is the sum of small efforts, repeated day in and day out.', 'visual-regression-tests' ),
|
||||
'author' => 'Robert Collier',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'To improve is to change; to be perfect is to change often.', 'visual-regression-tests' ),
|
||||
'author' => 'Winston Churchill',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The details are not the details. They make the design.', 'visual-regression-tests' ),
|
||||
'author' => 'Charles Eames',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'God is in the details.', 'visual-regression-tests' ),
|
||||
'author' => 'Ludwig Mies van der Rohe',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Excellence is the gradual result of always striving to do better.', 'visual-regression-tests' ),
|
||||
'author' => 'Pat Riley',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The world is changed by your example, not by your opinion.', 'visual-regression-tests' ),
|
||||
'author' => 'Paulo Coelho',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Doing the little things can make a big difference.', 'visual-regression-tests' ),
|
||||
'author' => 'Yogi Berra',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Tiny tweaks can lead to big changes.', 'visual-regression-tests' ),
|
||||
'author' => 'Amy Cuddy',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Life is a series of natural and spontaneous changes. Don’t resist them—that only creates sorrow. Let reality be reality.', 'visual-regression-tests' ),
|
||||
'author' => 'Lao Tzu',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'A bend in the road is not the end of the road… unless you fail to make the turn.', 'visual-regression-tests' ),
|
||||
'author' => 'Helen Keller',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The only way to make sense out of change is to plunge into it, move with it, and join the dance.', 'visual-regression-tests' ),
|
||||
'author' => 'Alan Watts',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Change is the only constant in life.', 'visual-regression-tests' ),
|
||||
'author' => 'Heraclitus',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The art of life lies in a constant readjustment to our surroundings.', 'visual-regression-tests' ),
|
||||
'author' => 'Okakura Kakuzō',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Adaptability is about the powerful difference between adapting to cope and adapting to win.', 'visual-regression-tests' ),
|
||||
'author' => 'Max McKeown',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The pessimist complains about the wind; the optimist expects it to change; the realist adjusts the sails.', 'visual-regression-tests' ),
|
||||
'author' => 'William Arthur Ward',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The world hates change, yet it is the only thing that has brought progress.', 'visual-regression-tests' ),
|
||||
'author' => 'Charles Kettering',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Change is inevitable. Change is constant.', 'visual-regression-tests' ),
|
||||
'author' => 'Benjamin Disraeli',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'You must welcome change as the rule but not as your ruler.', 'visual-regression-tests' ),
|
||||
'author' => 'Denis Waitley',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Change is the process by which the future invades our lives.', 'visual-regression-tests' ),
|
||||
'author' => 'Alvin Toffler',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Don’t fear failure. Fear being in the exact same place next year as you are today.', 'visual-regression-tests' ),
|
||||
'author' => 'Michael Hyatt',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Sometimes good things fall apart so better things can fall together.', 'visual-regression-tests' ),
|
||||
'author' => 'Marilyn Monroe',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Change starts when someone sees the next step.', 'visual-regression-tests' ),
|
||||
'author' => 'William Drayton',
|
||||
],
|
||||
];
|
||||
|
||||
mt_srand( $data['run']->id ); // phpcs:ignore WordPress.WP.AlternativeFunctions.rand_seeding_mt_srand -- It's ok.
|
||||
$random_quote = $quotes[ array_rand( $quotes ) ];
|
||||
|
||||
?>
|
||||
|
||||
<vrts-test-run-success class="vrts-test-run-success postbox">
|
||||
<div class="vrts-test-run-success__inner">
|
||||
<div class="vrts-test-run-success__lottie-player" vrts-lottie-player></div>
|
||||
<div class="vrts-test-run-success__content">
|
||||
<?php if ( $data['is_receipt'] ) : ?>
|
||||
<p><?php esc_html_e( 'Nice work – no more Alerts left to review!', 'visual-regression-tests' ); ?></p>
|
||||
<blockquote>
|
||||
<p>"<?php echo esc_html( $random_quote['quote'] ); ?>"</p>
|
||||
<cite>— <?php echo esc_html( $random_quote['author'] ); ?></cite>
|
||||
</blockquote>
|
||||
<?php else : ?>
|
||||
<p><?php esc_html_e( 'Smooth sailing – no changes found!', 'visual-regression-tests' ); ?></p>
|
||||
<p><?php esc_html_e( "You're good to go.", 'visual-regression-tests' ); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<span class="vrts-gradient-loader"></span>
|
||||
</vrts-test-run-success>
|
||||
@@ -0,0 +1,32 @@
|
||||
import lottie from 'lottie-web/build/player/lottie_light';
|
||||
|
||||
class VrtsTestRunSuccess extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.resolveElements();
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$lottiePlayer = this.querySelector( '[vrts-lottie-player]' );
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.lottieAnimation = lottie.loadAnimation( {
|
||||
path: `${ window.vrts_admin_vars.pluginUrl }/assets/animations/success-check.json`,
|
||||
container: this.$lottiePlayer,
|
||||
renderer: 'svg',
|
||||
loop: false,
|
||||
autoplay: true,
|
||||
} );
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.lottieAnimation.destroy();
|
||||
}
|
||||
|
||||
loaAnimation() {
|
||||
this.$lottiePlayer.play();
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-test-run-success', VrtsTestRunSuccess );
|
||||
@@ -0,0 +1,183 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
@import "@wordpress/base-styles/breakpoints";
|
||||
|
||||
.vrts-test-runs-page {
|
||||
display: block;
|
||||
|
||||
.tablenav.top {
|
||||
clear: none;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-test-runs-list-table {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.check-column {
|
||||
text-align: center;
|
||||
padding: 10px 0 0 10px !important;
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
.column-status {
|
||||
|
||||
@media screen and (max-width: 782px) {
|
||||
padding-bottom: 8px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-runs-status {
|
||||
|
||||
&--passed {
|
||||
color: $alert-green;
|
||||
}
|
||||
|
||||
&--scheduled {
|
||||
color: #f97b06;
|
||||
}
|
||||
|
||||
&--has-alerts {
|
||||
color: $alert-red;
|
||||
}
|
||||
|
||||
&--running {
|
||||
animation: vrts-rotate 1.5s linear infinite;
|
||||
color: $blue-50;
|
||||
}
|
||||
}
|
||||
|
||||
.row-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3125rem;
|
||||
color: $blue-50;
|
||||
line-height: 1;
|
||||
padding: 3px 0;
|
||||
|
||||
&:where(a)::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -38px;
|
||||
width: 100vw;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
[data-vrts-test-run-status="running"] .row-title {
|
||||
color: #f97b06;
|
||||
}
|
||||
|
||||
[data-vrts-test-run-status="scheduled"] .row-title {
|
||||
color: $gray-70;
|
||||
}
|
||||
|
||||
.row-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
visibility: hidden;
|
||||
|
||||
> *:not(:first-child)::before {
|
||||
content: " | ";
|
||||
}
|
||||
}
|
||||
|
||||
tr {
|
||||
|
||||
&[data-has-alerts] {
|
||||
|
||||
.row-title,
|
||||
.vrts-test-run-trigger,
|
||||
.vrts-testing-status-wrapper > *:first-child {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.row-title::after {
|
||||
content: "";
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: var(--vrts-admin-theme-color);
|
||||
border-radius: 50%;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.test-run-highlighted {
|
||||
animation: vrts-color-highlight 2s ease;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
.row-actions {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-test-run-view-alerts {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-test-runs-list-queue-table {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
thead,
|
||||
tfoot {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.subsubsub:has(+ &) {
|
||||
float: none;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
// .vrts-test-run-details {
|
||||
// display: none;
|
||||
|
||||
// [data-vrts-test-run-details="visible"] & {
|
||||
// display: block;
|
||||
// }
|
||||
|
||||
// .vrts-test-run-details-section {
|
||||
// margin: 15px 0;
|
||||
|
||||
// &:first-child {
|
||||
// margin-top: 25px;
|
||||
// }
|
||||
|
||||
// &-title {
|
||||
// border-bottom: 1px solid $gray-5;
|
||||
// color: $alert-red;
|
||||
// display: flex;
|
||||
// flex-wrap: wrap;
|
||||
// font-weight: 600;
|
||||
// gap: 10px;
|
||||
// justify-content: space-between;
|
||||
// margin-bottom: 10px;
|
||||
// padding-bottom: 10px;
|
||||
// }
|
||||
|
||||
// &--passed {
|
||||
|
||||
// .vrts-test-run-details-section-title {
|
||||
// color: $alert-green;
|
||||
// }
|
||||
// }
|
||||
|
||||
// ul {
|
||||
// margin: 0;
|
||||
// margin-left: 1rem;
|
||||
// list-style: outside;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .button {
|
||||
// margin-bottom: 4px;
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Features\Admin_Notices;
|
||||
use Vrts\Services\Manual_Test_Service;
|
||||
|
||||
?>
|
||||
<vrts-test-runs-page class="wrap vrts-list-table-page vrts-test-runs-page">
|
||||
<h1 class="wp-heading-inline">
|
||||
<?php esc_html_e( 'Runs', 'visual-regression-tests' ); ?>
|
||||
</h1>
|
||||
|
||||
<hr class="wp-header-end">
|
||||
|
||||
<?php
|
||||
$list_table = $data['list_queue_table'];
|
||||
$list_table->prepare_items();
|
||||
$list_table->views();
|
||||
$list_table->display();
|
||||
?>
|
||||
|
||||
<form method="post">
|
||||
<?php
|
||||
$list_table = $data['list_table'];
|
||||
$list_table->prepare_items();
|
||||
$list_table->views();
|
||||
$list_table->display();
|
||||
|
||||
if ( $list_table->has_items() ) {
|
||||
$list_table->inline_edit();
|
||||
}
|
||||
?>
|
||||
</form>
|
||||
<?php
|
||||
$vrts_manual_test_service = new Manual_Test_Service();
|
||||
$test_status = $vrts_manual_test_service->get_option();
|
||||
if ( $test_status ) {
|
||||
$vrts_manual_test_service->delete_option();
|
||||
if ( '1' === $test_status ) {
|
||||
Admin_Notices::render_notification( 'test_started', false, [] );
|
||||
} elseif ( '2' === $test_status ) {
|
||||
Admin_Notices::render_notification( 'test_failed', false, [] );
|
||||
}
|
||||
}
|
||||
?>
|
||||
</vrts-test-runs-page>
|
||||
@@ -0,0 +1,53 @@
|
||||
class VrtsTestRunsPage extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.resolveElements();
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$runsListTable = this.querySelector(
|
||||
'form .vrts-test-runs-list-table'
|
||||
);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.highlightNewTestRuns();
|
||||
}
|
||||
|
||||
highlightNewTestRuns() {
|
||||
const testRunIds = new Set(
|
||||
JSON.parse(
|
||||
window.localStorage.getItem( 'vrtsNewTestRuns' ) || '[]'
|
||||
)
|
||||
);
|
||||
|
||||
const rows = this.$runsListTable.querySelectorAll(
|
||||
'tr[data-test-run-id]'
|
||||
);
|
||||
|
||||
let staggerTimeout = 0;
|
||||
|
||||
rows.forEach( ( row ) => {
|
||||
const testRunId = row.getAttribute( 'data-test-run-id' );
|
||||
|
||||
if ( row.getAttribute( 'data-test-run-new' ) === 'true' ) {
|
||||
if ( ! testRunIds.has( testRunId ) ) {
|
||||
testRunIds.add( testRunId );
|
||||
setTimeout( () => {
|
||||
row.classList.add( 'test-run-highlighted' );
|
||||
}, staggerTimeout );
|
||||
staggerTimeout += 200;
|
||||
}
|
||||
} else if ( testRunIds.has( testRunId ) ) {
|
||||
testRunIds.delete( testRunId );
|
||||
}
|
||||
} );
|
||||
|
||||
window.localStorage.setItem(
|
||||
'vrtsNewTestRuns',
|
||||
JSON.stringify( [ ...testRunIds ] )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-test-runs-page', VrtsTestRunsPage );
|
||||
@@ -0,0 +1,93 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
@import "@wordpress/base-styles/breakpoints";
|
||||
|
||||
.page-title-actions {
|
||||
list-style: none;
|
||||
display: inline-flex;
|
||||
padding: 0 0 4px;
|
||||
margin: 0;
|
||||
gap: 1ch;
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.vrts-page-title-action {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
min-height: 32px;
|
||||
line-height: 2.30769231;
|
||||
padding: 0 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts_tests_page_wp_link {
|
||||
|
||||
@media (max-width: $break-mobile) {
|
||||
margin-top: -250px !important;
|
||||
max-height: 80vh;
|
||||
}
|
||||
|
||||
.link-url-field,
|
||||
.link-search-field {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.link-search-wrapper {
|
||||
position: relative;
|
||||
|
||||
.spinner {
|
||||
position: absolute;
|
||||
right: 40px;
|
||||
top: 4px;
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-tests--active {
|
||||
pointer-events: none;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
#link-options {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#wplink-link-existing-content {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
#wp-link .query-results {
|
||||
top: 80px;
|
||||
max-height: calc(100% - 90px);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.item {
|
||||
|
||||
&-permalink {
|
||||
font-size: 0.66rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-list-table-page {
|
||||
|
||||
.quick-edit-row-test {
|
||||
|
||||
label {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.inline-edit-col {
|
||||
max-width: 485px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
switch ( $data['action'] ) {
|
||||
default:
|
||||
$template = __DIR__ . '/views/tests-page-list.php';
|
||||
break;
|
||||
}
|
||||
|
||||
if ( file_exists( $template ) ) {
|
||||
include $template;
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
/* global jQuery, ajaxurl, inlineEditTest */
|
||||
|
||||
document
|
||||
.getElementById( 'show-modal-add-new' )
|
||||
?.addEventListener( 'click', () => {
|
||||
window.wpLink.open( 'input_hidden_internal_url' );
|
||||
} );
|
||||
|
||||
window.wp = window.wp || {};
|
||||
( function ( $, wp ) {
|
||||
window.inlineEditTest = {
|
||||
/**
|
||||
* Initializes the inline and bulk post editor.
|
||||
*
|
||||
* Binds event handlers to the Escape key to close the inline editor
|
||||
* and to the save and close buttons. Changes DOM to be ready for inline
|
||||
* editing. Adds event handler to bulk edit.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditTest
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
init() {
|
||||
const t = this,
|
||||
qeRow = $( '#inline-edit' );
|
||||
|
||||
t.type = 'test';
|
||||
// Test ID prefix.
|
||||
t.what = '#test-';
|
||||
|
||||
/**
|
||||
* Binds the Escape key to revert the changes and close the quick editor.
|
||||
*
|
||||
* @return {boolean} The result of revert.
|
||||
*/
|
||||
qeRow.on( 'keyup', function ( e ) {
|
||||
// Revert changes if Escape key is pressed.
|
||||
if ( e.which === 27 ) {
|
||||
return inlineEditTest.revert();
|
||||
}
|
||||
} );
|
||||
|
||||
/**
|
||||
* Reverts changes and close the quick editor if the cancel button is clicked.
|
||||
*
|
||||
* @return {boolean} The result of revert.
|
||||
*/
|
||||
$( '.cancel', qeRow ).on( 'click', function () {
|
||||
return inlineEditTest.revert();
|
||||
} );
|
||||
|
||||
/**
|
||||
* Saves changes in the quick editor if the save(named: update) button is clicked.
|
||||
*
|
||||
* @return {boolean} The result of save.
|
||||
*/
|
||||
$( '.save', qeRow ).on( 'click', function () {
|
||||
return inlineEditTest.save( this );
|
||||
} );
|
||||
|
||||
/**
|
||||
* If Enter is pressed, and the target is not the cancel button, save the post.
|
||||
*
|
||||
* @return {boolean} The result of save.
|
||||
*/
|
||||
$( 'td', qeRow ).on( 'keydown', function ( e ) {
|
||||
if (
|
||||
e.which === 13 &&
|
||||
! e.shiftKey &&
|
||||
! $( e.target ).hasClass( 'cancel' )
|
||||
) {
|
||||
return inlineEditTest.save( this );
|
||||
}
|
||||
} );
|
||||
|
||||
/**
|
||||
* Binds click event to the .editinline button which opens the quick editor.
|
||||
*/
|
||||
$( '#the-list' ).on( 'click', '.editinline', function () {
|
||||
$( this ).attr( 'aria-expanded', 'true' );
|
||||
inlineEditTest.edit( this );
|
||||
} );
|
||||
|
||||
/**
|
||||
* Adds onclick events to the apply buttons.
|
||||
*/
|
||||
$( '#doaction' ).on( 'click', function ( e ) {
|
||||
t.whichBulkButtonId = $( this ).attr( 'id' );
|
||||
const n = t.whichBulkButtonId.substr( 2 );
|
||||
|
||||
if ( 'edit' === $( 'select[name="' + n + '"]' ).val() ) {
|
||||
e.preventDefault();
|
||||
} else if (
|
||||
$( 'form#posts-filter tr.inline-editor' ).length > 0
|
||||
) {
|
||||
t.revert();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the quick edit window, hiding it when it's active and showing it when
|
||||
* inactive.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditTest
|
||||
*
|
||||
* @param {Object} el Element within a post table row.
|
||||
*/
|
||||
toggle( el ) {
|
||||
const t = this;
|
||||
// eslint-disable-next-line
|
||||
$( t.what + t.getId( el ) ).css( 'display' ) === 'none'
|
||||
? t.revert()
|
||||
: t.edit( el );
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a quick edit window for the post that has been clicked.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditTest
|
||||
*
|
||||
* @param {number|Object} id The ID of the clicked post or an element within a post
|
||||
* table row.
|
||||
* @return {boolean} Always returns false at the end of execution.
|
||||
*/
|
||||
edit( id ) {
|
||||
const t = this;
|
||||
t.revert();
|
||||
|
||||
if ( typeof id === 'object' ) {
|
||||
id = t.getId( id );
|
||||
}
|
||||
|
||||
// Add the new edit row with an extra blank row underneath to maintain zebra striping.
|
||||
const editRow = $( '#inline-edit' ).clone( true );
|
||||
$( 'td', editRow ).attr(
|
||||
'colspan',
|
||||
$( 'th:visible, td:visible', '.widefat:first thead' ).length
|
||||
);
|
||||
|
||||
// Remove the ID from the copied row and let the `for` attribute reference the hidden ID.
|
||||
$( 'td', editRow ).find( '#quick-edit-legend' ).removeAttr( 'id' );
|
||||
$( 'td', editRow )
|
||||
.find( 'p[id^="quick-edit-"]' )
|
||||
.removeAttr( 'id' );
|
||||
|
||||
$( t.what + id )
|
||||
.removeClass( 'is-expanded' )
|
||||
.hide()
|
||||
.after( editRow )
|
||||
.after( '<tr class="hidden"></tr>' );
|
||||
|
||||
// Populate fields in the quick edit window.
|
||||
const rowData = $( '#inline_' + id );
|
||||
const hideInputSelectorsText = $(
|
||||
'.hide_css_selectors',
|
||||
rowData
|
||||
).text();
|
||||
$( ':input[name="hide_css_selectors"]', editRow ).val(
|
||||
hideInputSelectorsText
|
||||
);
|
||||
|
||||
$( editRow )
|
||||
.attr( 'id', 'edit-' + id )
|
||||
.addClass( 'inline-editor' )
|
||||
.show();
|
||||
$( ':input[name="hide_css_selectors"]', editRow ).trigger(
|
||||
'focus'
|
||||
);
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves the changes made in the quick edit window to the post.
|
||||
* Ajax saving is only for Quick Edit and not for bulk edit.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @param {number} id The ID for the post that has been changed.
|
||||
* @return {boolean} False, so the form does not submit when pressing
|
||||
* Enter on a focused field.
|
||||
*/
|
||||
save( id ) {
|
||||
if ( typeof id === 'object' ) {
|
||||
id = this.getId( id );
|
||||
}
|
||||
|
||||
$( 'table.widefat .spinner' ).addClass( 'is-active' );
|
||||
|
||||
const params = {
|
||||
action: 'vrts_test_quick_edit_save',
|
||||
test_id: id,
|
||||
hide_css_selectors: $(
|
||||
'#edit-' + id + ' [name="hide_css_selectors"]'
|
||||
).val(),
|
||||
nonce: $( '#_vrts_test_quick_edit_nonce' ).val(),
|
||||
};
|
||||
|
||||
// Make Ajax request
|
||||
$.post(
|
||||
ajaxurl,
|
||||
params,
|
||||
function ( response ) {
|
||||
$( 'table.widefat .spinner' ).removeClass( 'is-active' );
|
||||
|
||||
// Work with the response.
|
||||
response = $.parseJSON( response );
|
||||
|
||||
if ( ! response.success ) {
|
||||
const $errorNotice = $(
|
||||
'#edit-' + id + ' .inline-edit-save .notice-error'
|
||||
);
|
||||
$errorNotice.removeClass( 'hidden' );
|
||||
$errorNotice.text( response.message );
|
||||
wp.a11y.speak( response.message );
|
||||
return;
|
||||
}
|
||||
|
||||
$( '#inline_' + id + ' .hide_css_selectors' ).text(
|
||||
response.hide_css_selectors
|
||||
);
|
||||
|
||||
// Hide the quick edit window.
|
||||
const $tableWideFat = $( '.widefat' );
|
||||
id = $( '.inline-editor', $tableWideFat ).attr( 'id' );
|
||||
|
||||
if ( id ) {
|
||||
$( '.spinner', $tableWideFat ).removeClass(
|
||||
'is-active'
|
||||
);
|
||||
|
||||
// Remove both the inline-editor and its hidden tr siblings.
|
||||
$( '#' + id )
|
||||
.siblings( 'tr.hidden' )
|
||||
.addBack()
|
||||
.remove();
|
||||
id = id.substr( id.lastIndexOf( '-' ) + 1 );
|
||||
|
||||
// Show the post row and move focus back to the Quick Edit button.
|
||||
$( '#test-' + id )
|
||||
.fadeIn( 400 )
|
||||
.find( '.editinline' )
|
||||
.attr( 'aria-expanded', 'false' )
|
||||
.trigger( 'focus' );
|
||||
}
|
||||
|
||||
wp.a11y.speak( response.message );
|
||||
|
||||
// Update the snapshot column in the table and set the status of the snapshot.
|
||||
const snapshotStatus = response.snapshot_status;
|
||||
const $snapshotColumn = $(
|
||||
'#test-' + id + ' .base_screenshot_date'
|
||||
);
|
||||
if (
|
||||
null !== snapshotStatus &&
|
||||
undefined !== snapshotStatus &&
|
||||
'' !== snapshotStatus
|
||||
) {
|
||||
$snapshotColumn.text( snapshotStatus );
|
||||
}
|
||||
},
|
||||
'html'
|
||||
);
|
||||
|
||||
// Prevent submitting the form when pressing Enter on a focused field.
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Hides and empties the Quick Edit and/or Bulk Edit windows.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditTest
|
||||
*
|
||||
* @return {boolean} Always returns false.
|
||||
*/
|
||||
revert() {
|
||||
const $tableWideFat = $( '.widefat' );
|
||||
let id = $( '.inline-editor', $tableWideFat ).attr( 'id' );
|
||||
|
||||
if ( id ) {
|
||||
$( '.spinner', $tableWideFat ).removeClass( 'is-active' );
|
||||
|
||||
// Remove both the inline-editor and its hidden tr siblings.
|
||||
$( '#' + id )
|
||||
.siblings( 'tr.hidden' )
|
||||
.addBack()
|
||||
.remove();
|
||||
id = id.substr( id.lastIndexOf( '-' ) + 1 );
|
||||
|
||||
// Show the post row and move focus back to the Quick Edit button.
|
||||
$( this.what + id )
|
||||
.show()
|
||||
.find( '.editinline' )
|
||||
.attr( 'aria-expanded', 'false' )
|
||||
.trigger( 'focus' );
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the ID for a the post that you want to quick edit from the row in the quick
|
||||
* edit table.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditTest
|
||||
*
|
||||
* @param {Object} o DOM row object to get the ID for.
|
||||
* @return {string} The post ID extracted from the table row in the object.
|
||||
*/
|
||||
getId( o ) {
|
||||
const id = $( o ).closest( 'tr' ).attr( 'id' ),
|
||||
parts = id.split( '-' );
|
||||
return parts[ parts.length - 1 ];
|
||||
},
|
||||
};
|
||||
|
||||
$( function () {
|
||||
if ( $( '.vrts-list-table-page' ).length ) {
|
||||
inlineEditTest.init();
|
||||
}
|
||||
} );
|
||||
} )( jQuery, window.wp );
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Features\Admin_Notices;
|
||||
use Vrts\Features\Subscription;
|
||||
use Vrts\Services\Manual_Test_Service;
|
||||
|
||||
?>
|
||||
|
||||
<div class="wrap vrts-list-table-page">
|
||||
<h1 class="wp-heading-inline">
|
||||
<?php esc_html_e( 'Tests', 'visual-regression-tests' ); ?>
|
||||
</h1>
|
||||
|
||||
<menu class="page-title-actions">
|
||||
<li>
|
||||
<button type="button" class="vrts-page-title-action button-primary"
|
||||
id="<?php echo ( ! $data['is_connected'] || intval( $data['remaining_tests'] ) === 0 ) ? 'modal-add-new-disabled' : 'show-modal-add-new'; ?>"
|
||||
<?php echo ( ! $data['is_connected'] || intval( $data['remaining_tests'] ) === 0 ) ? ' disabled' : ''; ?>>
|
||||
<?php esc_html_e( 'Add New', 'visual-regression-tests' ); ?>
|
||||
</button>
|
||||
</li>
|
||||
<?php if ( Subscription::get_subscription_status() ) : ?>
|
||||
<li>
|
||||
<form method="post" id="form-run-manual-tests">
|
||||
<?php wp_nonce_field( 'submit_run_manual_tests', '_wpnonce' ); ?>
|
||||
<input type="submit" name="submit_run_manual_tests" value="<?php esc_attr_e( 'Run All Tests', 'visual-regression-tests' ); ?>"
|
||||
class="vrts-page-title-action button-secondary"
|
||||
id="<?php echo ( ! $data['is_connected'] || ! $data['running_tests_count'] ) ? 'run-manual-tests-disabled' : 'run-manual-tests'; ?>"
|
||||
<?php echo ( ! $data['is_connected'] || ! $data['running_tests_count'] ) ? ' disabled' : ''; ?>
|
||||
>
|
||||
</form>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</menu>
|
||||
|
||||
<?php if ( isset( $data['search_query'] ) && '' !== $data['search_query'] ) { ?>
|
||||
<span class="subtitle">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: search query. */
|
||||
esc_html__( 'Search results for: %s', 'visual-regression-tests' ),
|
||||
'<strong>' . esc_html( $data['search_query'] ) . '</strong>'
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
<?php } ?>
|
||||
|
||||
<hr class="wp-header-end">
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" name="page" value="vrts-tests_list_table">
|
||||
|
||||
<?php
|
||||
$list_table = $data['list_table'];
|
||||
$list_table->prepare_items();
|
||||
$list_table->views();
|
||||
$list_table->search_box( esc_attr__( 'Search', 'visual-regression-tests' ), 'search_id' );
|
||||
$list_table->display();
|
||||
|
||||
if ( $list_table->has_items() ) {
|
||||
$list_table->inline_edit();
|
||||
}
|
||||
|
||||
$vrts_manual_test_service = new Manual_Test_Service();
|
||||
$test_status = $vrts_manual_test_service->get_option();
|
||||
if ( $test_status ) {
|
||||
$vrts_manual_test_service->delete_option();
|
||||
if ( '1' === $test_status ) {
|
||||
Admin_Notices::render_notification( 'test_started', false, [] );
|
||||
} elseif ( '2' === $test_status ) {
|
||||
Admin_Notices::render_notification( 'test_failed', false, [] );
|
||||
}
|
||||
}
|
||||
?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="wp-link-backdrop" style="display: none"></div>
|
||||
<div id="wp-link-wrap" class="wp-core-ui vrts_tests_page_wp_link" style="display: none" role="dialog" aria-labelledby="link-modal-title">
|
||||
<form id="wp-link" tabindex="-1" method="post">
|
||||
<?php wp_nonce_field( 'internal-linking', '_ajax_linking_nonce', false ); ?>
|
||||
<?php wp_nonce_field( 'vrts_page_tests_nonce' ); ?>
|
||||
<h1 id="link-modal-title"><?php esc_html_e( 'Add New Test', 'visual-regression-tests' ); ?></h1>
|
||||
<button type="button" id="wp-link-close"><span class="screen-reader-text"><?php esc_html_e( 'Close', 'visual-regression-tests' ); ?></span></button>
|
||||
<div id="link-selector">
|
||||
<div id="link-options">
|
||||
<p class="howto" id="wplink-enter-url"><?php esc_html_e( 'Destination URL', 'visual-regression-tests' ); ?></p>
|
||||
<div>
|
||||
<input id="wp-link-url" class="link-url-field" type="text" aria-describedby="wplink-enter-url" name="internal_url" readonly />
|
||||
<input id="wp-link-id" type="hidden" name="post_id" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="howto" id="wplink-link-existing-content"><?php esc_html_e( 'Search', 'visual-regression-tests' ); ?></p>
|
||||
<div id="search-panel">
|
||||
<div class="link-search-wrapper">
|
||||
<input type="search" id="wp-link-search" class="link-search-field" autocomplete="off" aria-describedby="wplink-link-existing-content" />
|
||||
<span class="spinner"></span>
|
||||
</div>
|
||||
<div id="search-results" class="query-results" tabindex="0">
|
||||
<ul></ul>
|
||||
<div class="river-waiting">
|
||||
<span class="spinner"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="most-recent-results" class="query-results" tabindex="0">
|
||||
<div class="query-notice" id="query-notice-message">
|
||||
<em class="query-notice-default"><?php esc_html_e( 'No search term specified. Showing recent items.', 'visual-regression-tests' ); ?></em>
|
||||
<em class="query-notice-hint screen-reader-text"><?php esc_html_e( 'Search or use up and down arrow keys to select an item.', 'visual-regression-tests' ); ?></em>
|
||||
</div>
|
||||
<ul></ul>
|
||||
<div class="river-waiting">
|
||||
<span class="spinner"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="submitbox">
|
||||
<div id="wp-link-cancel">
|
||||
<button type="button" class="button"><?php esc_html_e( 'Cancel', 'visual-regression-tests' ); ?></button>
|
||||
</div>
|
||||
<div id="wp-link-update">
|
||||
<?php
|
||||
submit_button(
|
||||
__( 'Add New Test', 'visual-regression-tests' ),
|
||||
'button button-primary',
|
||||
'submit_add_new_test',
|
||||
false,
|
||||
[ 'id' => 'wp-link-submit' ]
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,6 @@
|
||||
.vrts_upgrade_page {
|
||||
|
||||
iframe {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="wrap vrts_upgrade_page">
|
||||
<iframe
|
||||
src="https://vrts.app/pricing-embedded/?current-tier=<?php echo rawurlencode( esc_attr( $data['tier_id'] ) ); ?>"
|
||||
title="<?php echo esc_html( $data['title'] ); ?>"
|
||||
loading="lazy"
|
||||
width="100%"
|
||||
id="vrts_upgrade_iframe">
|
||||
</iframe>
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
import iFrameResize from 'iframe-resizer/js/iframeResizer';
|
||||
|
||||
const isVrtsUpgradePage = document.querySelector( '.vrts_upgrade_page' );
|
||||
|
||||
if ( isVrtsUpgradePage ) {
|
||||
iFrameResize(
|
||||
{
|
||||
checkOrigin: false,
|
||||
heightCalculationMethod: 'taggedElement',
|
||||
},
|
||||
'#vrts_upgrade_iframe'
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user