initial
This commit is contained in:
+156
@@ -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;
|
||||
Reference in New Issue
Block a user