A feature tab to toggle features

This commit is contained in:
Lourens Schep 2022-03-15 11:09:40 -03:00
parent 83392f2526
commit 46cba23313
12 changed files with 294 additions and 0 deletions

View File

@ -36,3 +36,4 @@ require( 'tools/delete-all-products.php');
require( 'tools/disable-wc-email.php' );
require( 'tools/trigger-update-callbacks.php' );
require( 'tracks/tracks-debug-log.php' );
require( 'features/features.php' );

59
api/features/features.php Normal file
View File

@ -0,0 +1,59 @@
<?php
use Automattic\WooCommerce\Admin\Features\Features;
const OPTION_NAME_PREFIX = 'wc_admin_helper_feature_values';
register_woocommerce_admin_test_helper_rest_route(
'/features/(?P<feature_name>[a-z0-9_\-]+)/toggle',
'toggle_feature',
array(
'methods' => 'POST',
)
);
register_woocommerce_admin_test_helper_rest_route(
'/features',
'get_features',
array(
'methods' => 'GET',
)
);
register_woocommerce_admin_test_helper_rest_route(
'/features/reset',
'reset_features',
array(
'methods' => 'POST',
)
);
function toggle_feature( $request ) {
$features = get_features();
$custom_feature_values = get_option( OPTION_NAME_PREFIX, array() );
$feature_name = $request->get_param( 'feature_name' );
if ( ! isset( $features[$feature_name ]) ) {
return new WP_REST_Response( $features, 204 );
}
if ( isset( $custom_feature_values[$feature_name] ) ) {
unset( $custom_feature_values[$feature_name] );
} else {
$custom_feature_values[$feature_name] = ! $features[ $feature_name ];
}
update_option(OPTION_NAME_PREFIX, $custom_feature_values );
return new WP_REST_Response( get_features(), 200 );
}
function reset_features() {
delete_option( OPTION_NAME_PREFIX );
return new WP_REST_Response( get_features(), 200 );
}
function get_features() {
if ( function_exists( 'wc_admin_get_feature_config' ) ) {
return apply_filters( 'woocommerce_admin_get_feature_config', wc_admin_get_feature_config() );
}
return array();
}

View File

@ -14,3 +14,13 @@ add_action( 'admin_menu', function() {
add_action( 'wp_loaded', function() {
require( 'api/api.php' );
} );
add_filter( 'woocommerce_admin_get_feature_config', function( $feature_config ) {
$custom_feature_values = get_option( 'wc_admin_helper_feature_values', array() );
foreach ( $custom_feature_values as $feature => $value ) {
if ( isset( $feature_config[$feature] ) ) {
$feature_config[$feature] = $value;
}
}
return $feature_config;
} );

View File

@ -11,6 +11,7 @@ import { AdminNotes } from '../admin-notes';
import { default as Tools } from '../tools';
import { default as Options } from '../options';
import { default as Experiments } from '../experiments';
import { default as Features } from '../features';
const tabs = applyFilters('woocommerce_admin_test_helper_tabs', [
{
@ -33,6 +34,11 @@ const tabs = applyFilters('woocommerce_admin_test_helper_tabs', [
title: 'Experiments',
content: <Experiments />,
},
{
name: 'features',
title: 'Features',
content: <Features />,
},
]);
export function App() {

View File

@ -0,0 +1,7 @@
const TYPES = {
TOGGLE_FEATURE: 'TOGGLE_FEATURE',
SET_FEATURES: 'SET_FEATURES',
SET_MODIFIED_FEATURES: 'SET_MODIFIED_FEATURES',
};
export default TYPES;

View File

@ -0,0 +1,51 @@
/**
* External dependencies
*/
import { apiFetch } from '@wordpress/data-controls';
/**
* Internal dependencies
*/
import TYPES from './action-types';
import { API_NAMESPACE } from './constants';
export function* resetModifiedFeatures() {
try {
const response = yield apiFetch({
path: `${API_NAMESPACE}/features/reset`,
method: 'POST',
});
yield setModifiedFeatures([]);
yield setFeatures(response);
} catch (error) {
throw new Error();
}
}
export function* toggleFeature(featureName) {
try {
const response = yield apiFetch({
method: 'POST',
path: API_NAMESPACE + '/features/' + featureName + '/toggle',
headers: { 'content-type': 'application/json' },
});
return yield setFeatures(response);
} catch (error) {
throw new Error();
}
}
export function setFeatures(features) {
return {
type: TYPES.SET_FEATURES,
features,
};
}
export function setModifiedFeatures(modifiedFeatures) {
return {
type: TYPES.SET_MODIFIED_FEATURES,
modifiedFeatures,
};
}

View File

@ -0,0 +1,3 @@
export const STORE_KEY = 'wc-admin-helper/features';
export const OPTION_NAME_PREFIX = 'wc_admin_helper_feature_values';
export const API_NAMESPACE = '/wc-admin-test-helper';

View File

@ -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,
} );

View File

@ -0,0 +1,28 @@
/**
* Internal dependencies
*/
import TYPES from './action-types';
const DEFAULT_STATE = {
features: {},
modifiedFeatures: [],
};
const reducer = (state = DEFAULT_STATE, action) => {
switch (action.type) {
case TYPES.SET_MODIFIED_FEATURES:
return {
...state,
modifiedFeatures: action.modifiedFeatures,
};
case TYPES.SET_FEATURES:
return {
...state,
features: action.features,
};
default:
return state;
}
};
export default reducer;

View File

@ -0,0 +1,34 @@
/**
* External dependencies
*/
import { apiFetch } from '@wordpress/data-controls';
/**
* Internal dependencies
*/
import { setFeatures, setModifiedFeatures } from './actions';
import { API_NAMESPACE, OPTION_NAME_PREFIX } from './constants';
export function* getModifiedFeatures() {
try {
const response = yield apiFetch({
path: `${API_NAMESPACE}/options?search=` + OPTION_NAME_PREFIX,
});
yield setModifiedFeatures(Object.keys(response));
} catch (error) {
throw new Error();
}
}
export function* getFeatures() {
try {
const response = yield apiFetch({
path: `${API_NAMESPACE}/features`,
});
yield setFeatures(response);
} catch (error) {
throw new Error();
}
}

View File

@ -0,0 +1,7 @@
export function getFeatures(state) {
return state.features;
}
export function getModifiedFeatures(state) {
return state.modifiedFeatures;
}

66
src/features/index.js Normal file
View File

@ -0,0 +1,66 @@
/**
* External dependencies
*/
import { useDispatch, useSelect } from '@wordpress/data';
import { Button } from '@wordpress/components';
/**
* Internal dependencies
*/
import { STORE_KEY } from './data/constants';
import './data';
function Features() {
const { features = {}, modifiedFeatures = [] } = useSelect((select) => {
const { getFeatures, getModifiedFeatures } = select(STORE_KEY);
return {
features: getFeatures(),
modifiedFeatures: getModifiedFeatures(),
};
});
const { toggleFeature, resetModifiedFeatures } = useDispatch(STORE_KEY);
return (
<div id="wc-admin-test-helper-features">
<h2>Features</h2>
<Button
disabled={modifiedFeatures.length === 0}
onClick={() => resetModifiedFeatures()}
>
Reset to defaults
</Button>
<table className="features wp-list-table striped table-view-list widefat">
<thead>
<tr>
<th>Feature Name</th>
<th>Enabled?</th>
<th>Toggle</th>
</tr>
</thead>
<tbody>
{Object.keys(features).map((feature_name) => {
return (
<tr key={feature_name}>
<td className="feature-name">{feature_name}</td>
<td>{features[feature_name].toString()}</td>
<td>
<Button
onClick={() => {
toggleFeature(feature_name);
}}
isPrimary
>
Toggle
</Button>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
export default Features;