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;
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
},
|
||||
} );
|
||||
Reference in New Issue
Block a user