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,156 @@
import { __, sprintf } from '@wordpress/i18n';
import { select } from '@wordpress/data';
import DOMPurify from 'dompurify';
const NotificationNewTestAdded = ( {} ) => {
return (
<>
<div className="vrts-metabox-notice vrts-metabox-notice-is-success">
<p>
<strong>
{ __(
'You have added a new test',
'visual-regression-tests'
) }
</strong>
</p>
<p
dangerouslySetInnerHTML={ {
__html: DOMPurify.sanitize(
sprintf(
/* translators: %s name of the page */
__(
'The Visual Regression Test for the page %s has been added!',
'visual-regression-tests'
),
'<strong>' +
select(
'core/editor'
).getEditedPostAttribute( 'title' ) +
'</strong>'
)
),
} }
></p>
</div>
</>
);
};
const NotificationUnlockMoreTests = ( {
upgradeUrl = '',
remainingTests = 0,
totalTests = 0,
} ) => {
return (
<>
<div className="vrts-metabox-notice vrts-metabox-notice-is-info">
<p>
<strong>
{ __( 'Unlock more tests', 'visual-regression-tests' ) }
</strong>
</p>
<p
dangerouslySetInnerHTML={ {
__html: DOMPurify.sanitize(
sprintf(
'%1$s %2$s',
sprintf(
/* translators: %1$s, %2$s: number of tests. */
__(
'Good work! You have added %1$s of %2$s available tests.',
'visual-regression-tests'
),
totalTests - remainingTests,
totalTests
),
sprintf(
/* translators: %1$s, %2$s: link wrapper. */
__(
'Upgrade %1$shere%2$s to add more tests to your website!',
'visual-regression-tests'
),
`<a href="${ upgradeUrl }" target="_blank">`,
'</a>'
)
)
),
} }
></p>
</div>
</>
);
};
const NotificationUpgradeRequired = ( { upgradeUrl = '' } ) => {
return (
<>
<div className="vrts-metabox-notice vrts-metabox-notice-is-error">
<p>
<strong>
{ __(
'Ready for an Upgrade?',
'visual-regression-tests'
) }
</strong>
</p>
<p
dangerouslySetInnerHTML={ {
__html: DOMPurify.sanitize(
sprintf(
'%1$s <a href="%2$s" target="_blank" title="%3$s">%3$s</a>',
__(
'Looks like you need a bigger plan to add more tests.',
'visual-regression-tests'
),
upgradeUrl,
__( 'Upgrade here!', 'visual-regression-tests' )
)
),
} }
></p>
</div>
</>
);
};
const NotificationConnectionFailed = ( { pluginUrl = '' } ) => {
return (
<>
<div className="vrts-metabox-notice vrts-metabox-notice-is-error">
<p>
<strong>
{ __( 'Connection failed', 'visual-regression-tests' ) }
</strong>
</p>
<p>
{ __(
'Something went wrong while trying to connect to the external service.',
'visual-regression-tests'
) }
</p>
<p
dangerouslySetInnerHTML={ {
__html: DOMPurify.sanitize(
sprintf(
'<a href="%1$s" title="%2$s">%2$s</a>',
pluginUrl,
__(
'Go to plugin page',
'visual-regression-tests'
)
)
),
} }
></p>
</div>
</>
);
};
export {
NotificationNewTestAdded,
NotificationUnlockMoreTests,
NotificationUpgradeRequired,
NotificationConnectionFailed,
};
@@ -0,0 +1,257 @@
// Native
import { Flex, Icon, ToggleControl } from '@wordpress/components';
import { useState, useEffect, useRef } from '@wordpress/element';
import { select, subscribe } from '@wordpress/data';
import { info as infoIcon } from '@wordpress/icons';
import { __, sprintf } from '@wordpress/i18n';
// Custom
import {
NotificationNewTestAdded,
NotificationUnlockMoreTests,
NotificationUpgradeRequired,
NotificationConnectionFailed,
} from 'editor/components/metabox-notifications';
import Settings from 'editor/components/settings';
import apiFetch from '@wordpress/api-fetch';
const Metabox = () => {
const upgradeUrl = window.vrts_editor_vars.upgrade_url;
const pluginUrl = window.vrts_editor_vars.plugin_url;
const testStatus = window.vrts_editor_vars.test_status;
const screenshot = window.vrts_editor_vars.screenshot;
const postId = select( 'core/editor' ).getCurrentPostId();
const [ postStatus, setPostStatus ] = useState(
select( 'core/editor' ).getEditedPostAttribute( 'status' )
);
const [ loading, setLoading ] = useState( true );
const [ disabled, setDisabled ] = useState( true );
const [ test, setTest ] = useState( {} );
const [ credits, setCredits ] = useState( {} );
const [ newTest, setNewTest ] = useState( false );
async function createTest() {
setLoading( true );
try {
const response = await apiFetch( {
path: `/vrts/v1/tests/post/${ postId }`,
method: 'POST',
} );
setTest( response );
if ( test.service_test_id ) {
setCredits( {
...credits,
remaining_tests: credits.remaining_tests - 1,
} );
}
} catch ( error ) {
console.log( error ); // eslint-disable-line no-console
}
setLoading( false );
setNewTest( true );
}
async function deleteTest() {
setLoading( true );
try {
const previousServiceTestId = test.service_test_id;
const response = await apiFetch( {
path: `/vrts/v1/tests/post/${ postId }`,
method: 'DELETE',
} );
setTest( response || {} );
setNewTest( false );
if ( previousServiceTestId ) {
setCredits( {
...credits,
remaining_tests: credits.remaining_tests + 1,
} );
}
} catch ( error ) {
console.log( error ); // eslint-disable-line no-console
}
setLoading( false );
}
useEffect( () => {
if ( 'auto-draft' === postStatus ) {
setDisabled( true );
} else {
setDisabled( false );
}
}, [ postStatus ] );
useEffect( () => {
setLoading( true );
async function fetchAndSetTest() {
try {
const response = await apiFetch( {
path: `/vrts/v1/tests/post/${ postId }`,
} );
setTest( response );
} catch ( error ) {
console.log( error ); // eslint-disable-line no-console
}
setLoading( false );
}
fetchAndSetTest();
}, [ postStatus, postId ] );
useEffect( () => {
async function fetchAndSetCredits() {
try {
const response = await apiFetch( {
path: `/vrts/v1/tests`,
} );
setCredits( response );
} catch ( error ) {
console.log( error ); // eslint-disable-line no-console
}
}
setLoading( true );
fetchAndSetCredits();
}, [ postStatus ] );
const wasSavingPost = useRef( select( 'core/editor' ).isSavingPost() );
useEffect( () => {
subscribe( () => {
const newPostStatus =
select( 'core/editor' ).getEditedPostAttribute( 'status' );
const isSavingPost = select( 'core/editor' ).isSavingPost();
if (
wasSavingPost.current &&
! isSavingPost &&
newPostStatus !== postStatus
) {
setPostStatus( newPostStatus );
}
wasSavingPost.current = isSavingPost;
} );
}, [ postStatus ] );
let metaboxNotification = null;
if ( true === newTest ) {
metaboxNotification = <NotificationNewTestAdded />;
} else if ( credits.remaining_tests === 1 ) {
metaboxNotification = (
<NotificationUnlockMoreTests
upgradeUrl={ upgradeUrl }
remainingTests={ credits.remaining_tests }
totalTests={ credits.total_tests }
/>
);
} else if ( credits.remaining_tests === 0 ) {
metaboxNotification = (
<NotificationUpgradeRequired upgradeUrl={ upgradeUrl } />
);
}
const isConnected = window.vrts_editor_vars.is_connected;
if ( ! isConnected ) {
return <NotificationConnectionFailed pluginUrl={ pluginUrl } />;
}
return (
<>
<Flex gap={ 3 } style={ { marginBottom: 12 } }>
<ToggleControl
label={ __( 'Add to VRTs', 'visual-regression-tests' ) }
checked={ test.id ? true : false }
onChange={ test.id ? deleteTest : createTest }
disabled={
disabled ||
loading ||
( credits.remaining_tests === 0 && ! test.id )
}
__nextHasNoMarginBottom={ true }
/>
<span className="vrts-tooltip">
<span className="vrts-tooltip-icon">
<Icon icon={ infoIcon } size="20" />
</span>
<span className="vrts-tooltip-content">
<span
className="vrts-tooltip-content-inner"
dangerouslySetInnerHTML={ {
__html: sprintf(
// translators: %1$s, %2$s: link wrapper.
__(
'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="' + pluginUrl + '">',
'</a>'
),
} }
></span>
</span>
</span>
</Flex>
{ metaboxNotification }
{ test.id && (
<>
<div className="vrts-testing-status-wrapper">
<p className="vrts-testing-status">
<span>
{ __(
'Test Status',
'visual-regression-tests'
) }
</span>
<strong>
<span
className={ `vrts-testing-status--${ testStatus.class }` }
>
{ testStatus.text }
</span>
</strong>
</p>
<p
className="vrts-testing-status-info"
dangerouslySetInnerHTML={ {
// This is safe because the content is sanitized in PHP.
__html: testStatus.instructions,
} }
/>
</div>
<div className="vrts-testing-status-wrapper">
<p className="vrts-testing-status">
<span>
{ __( 'Snapshot', 'visual-regression-tests' ) }
</span>
<span
className="vrts-testing-status-info"
dangerouslySetInnerHTML={ {
// This is safe because the content is sanitized in PHP.
__html: [ 'paused', 'waiting' ].includes(
screenshot.status
)
? screenshot.text
: screenshot.instructions,
} }
/>
</p>
<figure
className="figure"
dangerouslySetInnerHTML={ {
// This is safe because the content is sanitized in PHP.
__html: screenshot.screenshot,
} }
/>
</div>
</>
) }
{ test.id && (
<>
<Settings test={ test } setTest={ setTest } />
</>
) }
</>
);
};
export default Metabox;
@@ -0,0 +1,68 @@
import { __, sprintf } from '@wordpress/i18n';
import { Icon, TextareaControl } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { info as infoIcon } from '@wordpress/icons';
import { dispatch } from '@wordpress/data';
const Settings = ( { test = {} } ) => {
const [ testState, setTestState ] = useState( {
hide_css_selectors: '',
...test,
} );
const updateTest = ( value ) => {
const updatedTest = { ...testState, hide_css_selectors: value };
test.hide_css_selectors = value;
setTestState( updatedTest );
return dispatch( 'core/editor' ).editPost( {
vrts: { hide_css_selectors: value },
} );
};
return (
<>
<div className="settings">
<p className="settings-title">
{ __(
'Hide elements from VRTs',
'visual-regression-tests'
) }
<span className="vrts-tooltip">
<span className="vrts-tooltip-icon">
<Icon icon={ infoIcon } size="20" />
</span>
<span className="vrts-tooltip-content">
<span
className="vrts-tooltip-content-inner"
dangerouslySetInnerHTML={ {
__html: sprintf(
/* translators: %1$s, %2$s: link wrapper. */
__(
'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>
</p>
<TextareaControl
placeholder={ __(
'e.g.: .lottie, #ads',
'visual-regression-tests'
) }
value={ testState.hide_css_selectors }
onChange={ ( value ) => {
updateTest( value );
} }
/>
</div>
</>
);
};
export default Settings;
@@ -0,0 +1,59 @@
// Native
import { registerPlugin } from '@wordpress/plugins';
import {
PluginSidebar,
PluginSidebarMoreMenuItem,
PluginDocumentSettingPanel,
} from '@wordpress/edit-post';
import { PanelBody } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { createElement } from '@wordpress/element';
// Custom
import Metabox from 'editor/components/metabox';
const vrtsLogoIcon = createElement(
'svg',
{ width: 20, height: 20, viewBox: '0 0 20 20' },
createElement( 'path', {
d: 'M10.66 19a8.906 8.906 0 0 0 4.914-1.903H10.66V19zm0-3.194h6.254a9.27 9.27 0 0 0 1.236-1.935h-7.49v1.935zm0-3.226h7.992c.188-.63.305-1.279.348-1.936h-8.34v1.936zm7.992-5.16H10.66v1.936H19a8.772 8.772 0 0 0-.348-1.936zm-1.738-3.226H10.66V6.13h7.49v-.001a9.365 9.365 0 0 0-1.236-1.935zM10.66 1v1.904h4.914A8.913 8.913 0 0 0 10.66 1zM1 10a9.047 9.047 0 0 0 2.423 6.145 9.018 9.018 0 0 0 5.949 2.854V1a9.016 9.016 0 0 0-5.949 2.854A9.049 9.049 0 0 0 1 10z',
} )
);
const pluginName = window.vrts_editor_vars.plugin_name;
registerPlugin( 'visual-regression-tests-plugin-sidebar', {
render: () => {
return (
<>
<PluginDocumentSettingPanel
className="vrts_post_options_metabox"
name="visual-regression-tests-document-setting-panel"
title={ pluginName }
icon={ vrtsLogoIcon }
>
<Metabox />
</PluginDocumentSettingPanel>
<PluginSidebarMoreMenuItem
target="visual-regression-tests-sidebar"
icon={ vrtsLogoIcon }
>
{ pluginName }
</PluginSidebarMoreMenuItem>
<PluginSidebar
className="vrts_post_options_metabox"
name="visual-regression-tests-sidebar"
title={ pluginName }
icon={ vrtsLogoIcon }
>
<PanelBody
title={ __( 'Options', 'visual-regression-tests' ) }
intialOpen={ true }
>
<Metabox />
</PanelBody>
</PluginSidebar>
</>
);
},
} );