diff --git a/plugins/woocommerce-beta-tester/api/api.php b/plugins/woocommerce-beta-tester/api/api.php
index 2f8a0c9de77..6bb18ac9cd5 100644
--- a/plugins/woocommerce-beta-tester/api/api.php
+++ b/plugins/woocommerce-beta-tester/api/api.php
@@ -59,3 +59,4 @@ require 'rest-api-filters/class-wca-test-helper-rest-api-filters.php';
require 'rest-api-filters/hook.php';
require 'live-branches/manifest.php';
require 'tools/set-block-template-logging-threshold.php';
+require 'remote-spec-validator/class-wca-test-helper-remote-spec-validator.php';
\ No newline at end of file
diff --git a/plugins/woocommerce-beta-tester/api/remote-spec-validator/class-wca-test-helper-remote-spec-validator.php b/plugins/woocommerce-beta-tester/api/remote-spec-validator/class-wca-test-helper-remote-spec-validator.php
new file mode 100644
index 00000000000..d0b00a4c50f
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/api/remote-spec-validator/class-wca-test-helper-remote-spec-validator.php
@@ -0,0 +1,34 @@
+ 'POST',
+ 'args' => array(
+ 'spec' => array(
+ 'description' => 'The remote spec to validate.',
+ 'type' => 'string',
+ 'required' => true,
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ )
+);
+
+/**
+ * @param WP_REST_Request $request The full request data.
+ */
+function wca_test_helper_validate_remote_spec( $request ) {
+ $spec = json_decode( $request->get_param( 'spec' ) );
+ $rule_evaluator = new RuleEvaluator();
+ $result = [
+ 'valid' => $rule_evaluator->evaluate( $spec ),
+ ];
+
+ return new WP_REST_RESPONSE( $result, 200 );
+}
diff --git a/plugins/woocommerce-beta-tester/changelog/add-remote-spec-rule-validator b/plugins/woocommerce-beta-tester/changelog/add-remote-spec-rule-validator
new file mode 100644
index 00000000000..0f732d54c8e
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/changelog/add-remote-spec-rule-validator
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add Remote Spec Rule validator
\ No newline at end of file
diff --git a/plugins/woocommerce-beta-tester/composer.lock b/plugins/woocommerce-beta-tester/composer.lock
index 1a608c200b2..f7876fed498 100644
--- a/plugins/woocommerce-beta-tester/composer.lock
+++ b/plugins/woocommerce-beta-tester/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "e1ae720be342a5fd2aa3cbac6514537d",
+ "content-hash": "b373f29961b944cda3ae2f767107523c",
"packages": [
{
"name": "composer/installers",
diff --git a/plugins/woocommerce-beta-tester/plugin.php b/plugins/woocommerce-beta-tester/plugin.php
index 810c1bfb1cd..60ffe6283f3 100644
--- a/plugins/woocommerce-beta-tester/plugin.php
+++ b/plugins/woocommerce-beta-tester/plugin.php
@@ -12,6 +12,7 @@ add_action( 'admin_menu', function() {
} );
add_action( 'wp_loaded', function() {
+ require_once __DIR__ . '/vendor/autoload.php';
require( 'api/api.php' );
} );
@@ -24,4 +25,4 @@ add_filter( 'woocommerce_admin_get_feature_config', function( $feature_config )
}
}
return $feature_config;
-} );
\ No newline at end of file
+} );
diff --git a/plugins/woocommerce-beta-tester/src/app/app.js b/plugins/woocommerce-beta-tester/src/app/app.js
index 44e52fe4d3e..699bba2e7e3 100644
--- a/plugins/woocommerce-beta-tester/src/app/app.js
+++ b/plugins/woocommerce-beta-tester/src/app/app.js
@@ -13,6 +13,7 @@ import { default as Options } from '../options';
import { default as Experiments } from '../experiments';
import { default as Features } from '../features';
import { default as RestAPIFilters } from '../rest-api-filters';
+import RemoteSpecValidator from '../remote-spec-validator';
const tabs = applyFilters( 'woocommerce_admin_test_helper_tabs', [
{
@@ -45,6 +46,11 @@ const tabs = applyFilters( 'woocommerce_admin_test_helper_tabs', [
title: 'REST API FIlters',
content: ,
},
+ {
+ name: 'remote-spec-validator',
+ title: 'Remote Spec Rule Validator',
+ content: ,
+ },
] );
export function App() {
diff --git a/plugins/woocommerce-beta-tester/src/index.scss b/plugins/woocommerce-beta-tester/src/index.scss
index ffd37268e99..7a6dc32fec1 100644
--- a/plugins/woocommerce-beta-tester/src/index.scss
+++ b/plugins/woocommerce-beta-tester/src/index.scss
@@ -173,3 +173,14 @@ form.rest-api-filter-new-form {
margin-top: 10px;
}
}
+
+#wc-admin-test-helper-remote-spec-validator {
+ textarea {
+ width: 100%;
+ height: 300px;
+ }
+
+ .btn-validate {
+ float: right;
+ }
+}
\ No newline at end of file
diff --git a/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/action-types.js b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/action-types.js
new file mode 100644
index 00000000000..b6df3ed6b71
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/action-types.js
@@ -0,0 +1,6 @@
+const TYPES = {
+ VALIDATE: 'VALIDATE',
+ SET_MESSAGE: 'SET_MESSAGE',
+};
+
+export default TYPES;
diff --git a/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/actions.js b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/actions.js
new file mode 100644
index 00000000000..c94b5941da9
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/actions.js
@@ -0,0 +1,52 @@
+/**
+ * External dependencies
+ */
+import { apiFetch } from '@wordpress/data-controls';
+
+/**
+ * Internal dependencies
+ */
+import TYPES from './action-types';
+import { API_NAMESPACE } from './constants';
+
+export function* validate( jsonString ) {
+ try {
+ const response = yield apiFetch( {
+ method: 'POST',
+ path: `${ API_NAMESPACE }/remote-spec-validator/validate`,
+ headers: { 'content-type': 'application/json' },
+ data: {
+ spec: JSON.stringify( JSON.parse( jsonString ) ),
+ },
+ } );
+ if ( response.valid ) {
+ yield {
+ type: TYPES.SET_MESSAGE,
+ message: {
+ type: 'notice notice-success',
+ text: 'Validation passed',
+ },
+ };
+ } else {
+ yield {
+ type: TYPES.SET_MESSAGE,
+ message: {
+ type: 'error',
+ text: 'Validation failed',
+ },
+ };
+ }
+ } catch {
+ throw new Error();
+ }
+}
+
+export function setMessage( type, text ) {
+ return {
+ type: TYPES.SET_MESSAGE,
+ message: {
+ type,
+ text,
+ },
+ };
+}
diff --git a/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/constants.js b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/constants.js
new file mode 100644
index 00000000000..2b5793ddc2c
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/constants.js
@@ -0,0 +1,2 @@
+export const STORE_KEY = 'wc-admin-helper/remote-spec-validator';
+export const API_NAMESPACE = '/wc-admin-test-helper';
diff --git a/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/index.js b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/index.js
new file mode 100644
index 00000000000..e476479ea88
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/index.js
@@ -0,0 +1,22 @@
+/**
+ * External dependencies
+ */
+import { registerStore } from '@wordpress/data';
+import { controls } from '@wordpress/data-controls';
+
+/**
+ * Internal dependencies
+ */
+import * as actions from './actions';
+import * as resolvers from './resolvers';
+import * as selectors from './selectors';
+import reducer from './reducer';
+import { STORE_KEY } from './constants';
+
+export default registerStore( STORE_KEY, {
+ actions,
+ selectors,
+ resolvers,
+ controls,
+ reducer,
+} );
diff --git a/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/reducer.js b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/reducer.js
new file mode 100644
index 00000000000..ec265f924cb
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/reducer.js
@@ -0,0 +1,25 @@
+/**
+ * Internal dependencies
+ */
+import TYPES from './action-types';
+
+const DEFAULT_STATE = {
+ message: {
+ type: null,
+ text: null,
+ },
+};
+
+const reducer = ( state = DEFAULT_STATE, action ) => {
+ switch ( action.type ) {
+ case TYPES.SET_MESSAGE:
+ return {
+ ...state,
+ message: action.message,
+ };
+ default:
+ return state;
+ }
+};
+
+export default reducer;
diff --git a/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/resolvers.js b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/resolvers.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/selectors.js b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/selectors.js
new file mode 100644
index 00000000000..8fc8bbdff3c
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/src/remote-spec-validator/data/selectors.js
@@ -0,0 +1,3 @@
+export function getMessage( state ) {
+ return state.message;
+}
diff --git a/plugins/woocommerce-beta-tester/src/remote-spec-validator/index.js b/plugins/woocommerce-beta-tester/src/remote-spec-validator/index.js
new file mode 100644
index 00000000000..c5066e36b78
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/src/remote-spec-validator/index.js
@@ -0,0 +1,74 @@
+/**
+ * External dependencies
+ */
+import { withDispatch, withSelect } from '@wordpress/data';
+import { compose } from '@wordpress/compose';
+import { useState } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import { STORE_KEY } from './data/constants';
+import './data';
+
+function RemoteSpecValidator( { validate, message, setMessage } ) {
+ const exampleText = JSON.stringify(
+ [
+ {
+ type: 'plugin_version',
+ plugin: 'woocommerce',
+ version: '6.5.0-dev',
+ operator: '>=',
+ },
+ ],
+ null,
+ 4
+ );
+ const [ spec, setSpec ] = useState( exampleText );
+ return (
+ <>
+
Paste your Remote Spec rule and click Validate button.
+
+ >
+ );
+}
+
+export default compose(
+ withSelect( ( select ) => {
+ const { getMessage } = select( STORE_KEY );
+ return {
+ message: getMessage(),
+ };
+ } ),
+ withDispatch( ( dispatch ) => {
+ const { validate, setMessage } = dispatch( STORE_KEY );
+
+ return {
+ validate,
+ setMessage,
+ };
+ } )
+)( RemoteSpecValidator );