This commit is contained in:
2026-07-02 15:54:39 -06:00
commit 9883323161
17470 changed files with 4470592 additions and 0 deletions
@@ -0,0 +1,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 );