Create action for installing and activate plugins (https://github.com/woocommerce/woocommerce-admin/pull/4473)
* Add installAndActivatePlugins method to plugin store * Use new install/actiate method in Plugins component * Refactor benefits page to use await * Refactor business details page to use new install method * Replace Plugins component in Jetpack CTA * Format and throw errors in plugin data store * Add generic response handling function * Add default error messages to plugin API
This commit is contained in:
parent
2aa59bc8e6
commit
046f6c8bd4
|
@ -6,36 +6,45 @@ import { compose } from '@wordpress/compose';
|
||||||
import { Button } from '@wordpress/components';
|
import { Button } from '@wordpress/components';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { withDispatch, withSelect } from '@wordpress/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WooCommerce dependencies
|
* WooCommerce dependencies
|
||||||
*/
|
*/
|
||||||
import { H, Plugins } from '@woocommerce/components';
|
import { H } from '@woocommerce/components';
|
||||||
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
||||||
import { PLUGINS_STORE_NAME, useUserPreferences } from '@woocommerce/data';
|
import { PLUGINS_STORE_NAME, useUserPreferences } from '@woocommerce/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import withSelect from 'wc-api/with-select';
|
|
||||||
import Connect from 'dashboard/components/connect';
|
import Connect from 'dashboard/components/connect';
|
||||||
import { recordEvent } from 'lib/tracks';
|
import { recordEvent } from 'lib/tracks';
|
||||||
|
import { createNoticesFromResponse } from 'lib/notices';
|
||||||
|
|
||||||
function InstallJetpackCta( {
|
function InstallJetpackCta( {
|
||||||
isJetpackInstalled,
|
isJetpackInstalled,
|
||||||
isJetpackActivated,
|
isJetpackActivated,
|
||||||
isJetpackConnected,
|
isJetpackConnected,
|
||||||
|
installAndActivatePlugins,
|
||||||
|
isInstalling,
|
||||||
} ) {
|
} ) {
|
||||||
const { updateUserPreferences, ...userPrefs } = useUserPreferences();
|
const { updateUserPreferences, ...userPrefs } = useUserPreferences();
|
||||||
const [ isInstalling, setIsInstalling ] = useState( false );
|
|
||||||
const [ isConnecting, setIsConnecting ] = useState( false );
|
const [ isConnecting, setIsConnecting ] = useState( false );
|
||||||
const [ isDismissed, setIsDismissed ] = useState(
|
const [ isDismissed, setIsDismissed ] = useState(
|
||||||
( userPrefs.homepage_stats || {} ).installJetpackDismissed
|
( userPrefs.homepage_stats || {} ).installJetpackDismissed
|
||||||
);
|
);
|
||||||
|
|
||||||
function install() {
|
async function install() {
|
||||||
setIsInstalling( true );
|
|
||||||
recordEvent( 'statsoverview_install_jetpack' );
|
recordEvent( 'statsoverview_install_jetpack' );
|
||||||
|
|
||||||
|
installAndActivatePlugins( [ 'jetpack' ] )
|
||||||
|
.then( () => {
|
||||||
|
setIsConnecting( ! isJetpackConnected );
|
||||||
|
} )
|
||||||
|
.catch( ( error ) => {
|
||||||
|
createNoticesFromResponse( error );
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
function dismiss() {
|
function dismiss() {
|
||||||
|
@ -53,22 +62,6 @@ function InstallJetpackCta( {
|
||||||
recordEvent( 'statsoverview_dismiss_install_jetpack' );
|
recordEvent( 'statsoverview_dismiss_install_jetpack' );
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPluginInstaller() {
|
|
||||||
return (
|
|
||||||
<Plugins
|
|
||||||
autoInstall
|
|
||||||
onComplete={ () => {
|
|
||||||
setIsInstalling( false );
|
|
||||||
setIsConnecting( ! isJetpackConnected );
|
|
||||||
} }
|
|
||||||
onError={ () => {
|
|
||||||
setIsInstalling( false );
|
|
||||||
} }
|
|
||||||
pluginSlugs={ [ 'jetpack' ] }
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getConnector() {
|
function getConnector() {
|
||||||
return (
|
return (
|
||||||
<Connect
|
<Connect
|
||||||
|
@ -124,7 +117,6 @@ function InstallJetpackCta( {
|
||||||
</Button>
|
</Button>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
{ isInstalling && getPluginInstaller() }
|
|
||||||
{ isConnecting && getConnector() }
|
{ isConnecting && getConnector() }
|
||||||
</article>
|
</article>
|
||||||
);
|
);
|
||||||
|
@ -141,14 +133,25 @@ export default compose(
|
||||||
withSelect( ( select ) => {
|
withSelect( ( select ) => {
|
||||||
const {
|
const {
|
||||||
isJetpackConnected,
|
isJetpackConnected,
|
||||||
|
isPluginsRequesting,
|
||||||
getInstalledPlugins,
|
getInstalledPlugins,
|
||||||
getActivePlugins,
|
getActivePlugins,
|
||||||
} = select( PLUGINS_STORE_NAME );
|
} = select( PLUGINS_STORE_NAME );
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
isInstalling:
|
||||||
|
isPluginsRequesting( 'installPlugins' ) ||
|
||||||
|
isPluginsRequesting( 'activatePlugins' ),
|
||||||
isJetpackInstalled: getInstalledPlugins().includes( 'jetpack' ),
|
isJetpackInstalled: getInstalledPlugins().includes( 'jetpack' ),
|
||||||
isJetpackActivated: getActivePlugins().includes( 'jetpack' ),
|
isJetpackActivated: getActivePlugins().includes( 'jetpack' ),
|
||||||
isJetpackConnected: isJetpackConnected(),
|
isJetpackConnected: isJetpackConnected(),
|
||||||
};
|
};
|
||||||
|
} ),
|
||||||
|
withDispatch( ( dispatch ) => {
|
||||||
|
const { installAndActivatePlugins } = dispatch( PLUGINS_STORE_NAME );
|
||||||
|
|
||||||
|
return {
|
||||||
|
installAndActivatePlugins,
|
||||||
|
};
|
||||||
} )
|
} )
|
||||||
)( InstallJetpackCta );
|
)( InstallJetpackCta );
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { dispatch } from '@wordpress/data';
|
||||||
|
|
||||||
|
export function createNoticesFromResponse( response ) {
|
||||||
|
const { createNotice } = dispatch( 'core/notices' );
|
||||||
|
|
||||||
|
if ( response.error_data && response.errors && Object.keys( response.errors ).length ) {
|
||||||
|
// Loop over multi-error responses.
|
||||||
|
Object.keys( response.errors ).forEach( errorKey => {
|
||||||
|
createNotice( 'error', response.errors[ errorKey ].join( ' ' ) );
|
||||||
|
} );
|
||||||
|
} else if ( response.message ) {
|
||||||
|
// Handle generic messages.
|
||||||
|
createNotice( response.code ? 'error' : 'success', response.message );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { dispatch } from '@wordpress/data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { createNoticesFromResponse } from '../../notices';
|
||||||
|
|
||||||
|
jest.mock( '@wordpress/data', () => ( {
|
||||||
|
dispatch: jest.fn().mockReturnValue( {
|
||||||
|
createNotice: jest.fn(),
|
||||||
|
} ),
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
describe( 'createNoticesFromResponse', () => {
|
||||||
|
beforeEach( () => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
} );
|
||||||
|
|
||||||
|
const { createNotice } = dispatch( 'core/notices' );
|
||||||
|
|
||||||
|
test( 'should create notice based on message when no errors exist', () => {
|
||||||
|
const response = { message: 'Generic response message' };
|
||||||
|
|
||||||
|
createNoticesFromResponse( response );
|
||||||
|
expect( createNotice ).toHaveBeenCalledWith(
|
||||||
|
'success',
|
||||||
|
response.message,
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
|
||||||
|
test( 'should create an error notice when an error code and message exists', () => {
|
||||||
|
const response = { code: 'invalid_code', message: 'Error message' };
|
||||||
|
|
||||||
|
createNoticesFromResponse( response );
|
||||||
|
expect( createNotice ).toHaveBeenCalledWith(
|
||||||
|
'error',
|
||||||
|
response.message,
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
|
||||||
|
test( 'should create error messages for each item', () => {
|
||||||
|
const response = { errors: {
|
||||||
|
item1: [
|
||||||
|
'Item1 - Error 1.',
|
||||||
|
'Item1 - Error 2.',
|
||||||
|
],
|
||||||
|
item2: [
|
||||||
|
'Item2 - Error 1.',
|
||||||
|
]
|
||||||
|
}, error_data: [] };
|
||||||
|
|
||||||
|
createNoticesFromResponse( response );
|
||||||
|
expect( createNotice ).toHaveBeenCalledTimes(2);
|
||||||
|
const call1 = createNotice.mock.calls[0];
|
||||||
|
const call2 = createNotice.mock.calls[1];
|
||||||
|
expect( call1 ).toEqual( [ 'error', response.errors.item1.join( ' ' ) ] );
|
||||||
|
expect( call2 ).toEqual( [ 'error', response.errors.item2[0] ] );
|
||||||
|
} );
|
||||||
|
|
||||||
|
test( 'should not call createNotice when no message or errors exist', () => {
|
||||||
|
const response = { data: {} };
|
||||||
|
|
||||||
|
createNoticesFromResponse( response );
|
||||||
|
expect( createNotice ).not.toHaveBeenCalled();
|
||||||
|
} );
|
||||||
|
} );
|
|
@ -11,7 +11,7 @@ import { filter } from 'lodash';
|
||||||
/**
|
/**
|
||||||
* WooCommerce dependencies
|
* WooCommerce dependencies
|
||||||
*/
|
*/
|
||||||
import { Card, H, Plugins } from '@woocommerce/components';
|
import { Card, H } from '@woocommerce/components';
|
||||||
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
||||||
import {
|
import {
|
||||||
pluginNames,
|
pluginNames,
|
||||||
|
@ -24,6 +24,7 @@ import {
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import Connect from 'dashboard/components/connect';
|
import Connect from 'dashboard/components/connect';
|
||||||
|
import { createNoticesFromResponse } from 'lib/notices';
|
||||||
import Logo from './logo';
|
import Logo from './logo';
|
||||||
import ManagementIcon from './images/management';
|
import ManagementIcon from './images/management';
|
||||||
import SalesTaxIcon from './images/sales_tax';
|
import SalesTaxIcon from './images/sales_tax';
|
||||||
|
@ -34,10 +35,6 @@ import { recordEvent } from 'lib/tracks';
|
||||||
class Benefits extends Component {
|
class Benefits extends Component {
|
||||||
constructor( props ) {
|
constructor( props ) {
|
||||||
super( props );
|
super( props );
|
||||||
this.state = {
|
|
||||||
isConnecting: false,
|
|
||||||
isInstalling: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.isJetpackActive = props.activePlugins.includes( 'jetpack' );
|
this.isJetpackActive = props.activePlugins.includes( 'jetpack' );
|
||||||
this.isWcsActive = props.activePlugins.includes(
|
this.isWcsActive = props.activePlugins.includes(
|
||||||
|
@ -59,26 +56,6 @@ class Benefits extends Component {
|
||||||
this.skipPluginInstall = this.skipPluginInstall.bind( this );
|
this.skipPluginInstall = this.skipPluginInstall.bind( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate( prevProps, prevState ) {
|
|
||||||
const { goToNextStep } = this.props;
|
|
||||||
|
|
||||||
// No longer pending or updating profile items, go to next step.
|
|
||||||
if (
|
|
||||||
! this.isPending() &&
|
|
||||||
( prevProps.isRequesting ||
|
|
||||||
prevState.isConnecting ||
|
|
||||||
prevState.isInstalling )
|
|
||||||
) {
|
|
||||||
goToNextStep();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isPending() {
|
|
||||||
const { isConnecting, isInstalling } = this.state;
|
|
||||||
const { isRequesting } = this.props;
|
|
||||||
return isConnecting || isInstalling || isRequesting;
|
|
||||||
}
|
|
||||||
|
|
||||||
async skipPluginInstall() {
|
async skipPluginInstall() {
|
||||||
const {
|
const {
|
||||||
createNotice,
|
createNotice,
|
||||||
|
@ -108,21 +85,46 @@ class Benefits extends Component {
|
||||||
goToNextStep();
|
goToNextStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
startPluginInstall() {
|
async startPluginInstall() {
|
||||||
const { updateProfileItems, updateOptions } = this.props;
|
const {
|
||||||
|
createNotice,
|
||||||
this.setState( { isInstalling: true } );
|
goToNextStep,
|
||||||
|
installAndActivatePlugins,
|
||||||
updateOptions( {
|
isJetpackConnected,
|
||||||
woocommerce_setup_jetpack_opted_in: true,
|
updateProfileItems,
|
||||||
} );
|
updateOptions,
|
||||||
|
} = this.props;
|
||||||
const plugins = this.isJetpackActive ? 'installed-wcs' : 'installed';
|
const plugins = this.isJetpackActive ? 'installed-wcs' : 'installed';
|
||||||
|
|
||||||
recordEvent( 'storeprofiler_install_plugins', {
|
recordEvent( 'storeprofiler_install_plugins', {
|
||||||
install: true,
|
install: true,
|
||||||
plugins,
|
plugins,
|
||||||
} );
|
} );
|
||||||
updateProfileItems( { plugins } );
|
|
||||||
|
await Promise.all( [
|
||||||
|
installAndActivatePlugins( this.pluginsToInstall ),
|
||||||
|
updateProfileItems( { plugins } ),
|
||||||
|
updateOptions( {
|
||||||
|
woocommerce_setup_jetpack_opted_in: true,
|
||||||
|
} ),
|
||||||
|
] ).catch( ( pluginError, profileError ) => {
|
||||||
|
if ( pluginError ) {
|
||||||
|
createNoticesFromResponse( pluginError );
|
||||||
|
}
|
||||||
|
if ( profileError ) {
|
||||||
|
createNotice(
|
||||||
|
'error',
|
||||||
|
__(
|
||||||
|
'There was a problem updating your preferences.',
|
||||||
|
'woocommerce-admin'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
if ( isJetpackConnected ) {
|
||||||
|
goToNextStep();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBenefit( benefit ) {
|
renderBenefit( benefit ) {
|
||||||
|
@ -200,12 +202,22 @@ class Benefits extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isConnecting, isInstalling } = this.state;
|
const {
|
||||||
const { isJetpackConnected, isRequesting } = this.props;
|
activePlugins,
|
||||||
|
goToNextStep,
|
||||||
|
isJetpackConnected,
|
||||||
|
isInstallingActivating,
|
||||||
|
isRequesting,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
const pluginNamesString = this.pluginsToInstall
|
const pluginNamesString = this.pluginsToInstall
|
||||||
.map( ( pluginSlug ) => pluginNames[ pluginSlug ] )
|
.map( ( pluginSlug ) => pluginNames[ pluginSlug ] )
|
||||||
.join( ' ' + __( 'and', 'woocommerce-admin' ) + ' ' );
|
.join( ' ' + __( 'and', 'woocommerce-admin' ) + ' ' );
|
||||||
|
const pluginsRemaining = this.pluginsToInstall.filter(
|
||||||
|
( plugin ) => ! activePlugins.includes( plugin )
|
||||||
|
);
|
||||||
|
const isInstallAction =
|
||||||
|
isInstallingActivating || ! pluginsRemaining.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="woocommerce-profile-wizard__benefits-card">
|
<Card className="woocommerce-profile-wizard__benefits-card">
|
||||||
|
@ -222,10 +234,8 @@ class Benefits extends Component {
|
||||||
<div className="woocommerce-profile-wizard__card-actions">
|
<div className="woocommerce-profile-wizard__card-actions">
|
||||||
<Button
|
<Button
|
||||||
isPrimary
|
isPrimary
|
||||||
isBusy={
|
isBusy={ isInstallAction }
|
||||||
this.isPending() && ( isInstalling || isConnecting )
|
disabled={ isRequesting || isInstallAction }
|
||||||
}
|
|
||||||
disabled={ this.isPending() }
|
|
||||||
onClick={ this.startPluginInstall }
|
onClick={ this.startPluginInstall }
|
||||||
className="woocommerce-profile-wizard__continue"
|
className="woocommerce-profile-wizard__continue"
|
||||||
>
|
>
|
||||||
|
@ -233,36 +243,18 @@ class Benefits extends Component {
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
isSecondary
|
isSecondary
|
||||||
isBusy={
|
isBusy={ isRequesting && ! isInstallAction }
|
||||||
this.isPending() && ! isInstalling && ! isConnecting
|
disabled={ isRequesting || isInstallAction }
|
||||||
}
|
|
||||||
disabled={ this.isPending() }
|
|
||||||
className="woocommerce-profile-wizard__skip"
|
className="woocommerce-profile-wizard__skip"
|
||||||
onClick={ this.skipPluginInstall }
|
onClick={ this.skipPluginInstall }
|
||||||
>
|
>
|
||||||
{ __( 'No thanks', 'woocommerce-admin' ) }
|
{ __( 'No thanks', 'woocommerce-admin' ) }
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{ isInstalling && (
|
|
||||||
<Plugins
|
|
||||||
autoInstall
|
|
||||||
onComplete={ () =>
|
|
||||||
this.setState( {
|
|
||||||
isInstalling: false,
|
|
||||||
isConnecting: ! isJetpackConnected,
|
|
||||||
} )
|
|
||||||
}
|
|
||||||
onError={ () =>
|
|
||||||
this.setState( {
|
|
||||||
isInstalling: false,
|
|
||||||
} )
|
|
||||||
}
|
|
||||||
pluginSlugs={ this.pluginsToInstall }
|
|
||||||
/>
|
|
||||||
) }
|
|
||||||
|
|
||||||
{ /* Make sure we're finished requesting since this will auto redirect us. */ }
|
{ /* Make sure we're finished requesting since this will auto redirect us. */ }
|
||||||
{ isConnecting && ! isJetpackConnected && ! isRequesting && (
|
{ ! isJetpackConnected &&
|
||||||
|
! isRequesting &&
|
||||||
|
! pluginsRemaining.length && (
|
||||||
<Connect
|
<Connect
|
||||||
autoConnect
|
autoConnect
|
||||||
onConnect={ () => {
|
onConnect={ () => {
|
||||||
|
@ -270,9 +262,7 @@ class Benefits extends Component {
|
||||||
'storeprofiler_jetpack_connect_redirect'
|
'storeprofiler_jetpack_connect_redirect'
|
||||||
);
|
);
|
||||||
} }
|
} }
|
||||||
onError={ () =>
|
onError={ () => goToNextStep() }
|
||||||
this.setState( { isConnecting: false } )
|
|
||||||
}
|
|
||||||
redirectUrl={ getAdminLink(
|
redirectUrl={ getAdminLink(
|
||||||
'admin.php?page=wc-admin&reset_profiler=0'
|
'admin.php?page=wc-admin&reset_profiler=0'
|
||||||
) }
|
) }
|
||||||
|
@ -308,31 +298,35 @@ export default compose(
|
||||||
isOnboardingRequesting,
|
isOnboardingRequesting,
|
||||||
} = select( ONBOARDING_STORE_NAME );
|
} = select( ONBOARDING_STORE_NAME );
|
||||||
|
|
||||||
const { getActivePlugins, isJetpackConnected } = select(
|
const {
|
||||||
PLUGINS_STORE_NAME
|
getActivePlugins,
|
||||||
);
|
isJetpackConnected,
|
||||||
|
isPluginsRequesting,
|
||||||
const isProfileItemsError = Boolean(
|
} = select( PLUGINS_STORE_NAME );
|
||||||
getOnboardingError( 'updateProfileItems' )
|
|
||||||
);
|
|
||||||
const activePlugins = getActivePlugins();
|
|
||||||
const profileItems = getProfileItems();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
activePlugins,
|
activePlugins: getActivePlugins(),
|
||||||
isProfileItemsError,
|
isProfileItemsError: Boolean(
|
||||||
profileItems,
|
getOnboardingError( 'updateProfileItems' )
|
||||||
|
),
|
||||||
|
profileItems: getProfileItems(),
|
||||||
isJetpackConnected: isJetpackConnected(),
|
isJetpackConnected: isJetpackConnected(),
|
||||||
isRequesting: isOnboardingRequesting( 'updateProfileItems' ),
|
isRequesting: isOnboardingRequesting( 'updateProfileItems' ),
|
||||||
|
isInstallingActivating:
|
||||||
|
isPluginsRequesting( 'installPlugins' ) ||
|
||||||
|
isPluginsRequesting( 'activatePlugins' ) ||
|
||||||
|
isPluginsRequesting( 'getJetpackConnectUrl' ),
|
||||||
};
|
};
|
||||||
} ),
|
} ),
|
||||||
withDispatch( ( dispatch ) => {
|
withDispatch( ( dispatch ) => {
|
||||||
|
const { installAndActivatePlugins } = dispatch( PLUGINS_STORE_NAME );
|
||||||
const { updateProfileItems } = dispatch( ONBOARDING_STORE_NAME );
|
const { updateProfileItems } = dispatch( ONBOARDING_STORE_NAME );
|
||||||
const { updateOptions } = dispatch( OPTIONS_STORE_NAME );
|
const { updateOptions } = dispatch( OPTIONS_STORE_NAME );
|
||||||
const { createNotice } = dispatch( 'core/notices' );
|
const { createNotice } = dispatch( 'core/notices' );
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createNotice,
|
createNotice,
|
||||||
|
installAndActivatePlugins,
|
||||||
updateProfileItems,
|
updateProfileItems,
|
||||||
updateOptions,
|
updateOptions,
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,12 @@ import { keys, get, pickBy } from 'lodash';
|
||||||
*/
|
*/
|
||||||
import { formatValue } from '@woocommerce/number';
|
import { formatValue } from '@woocommerce/number';
|
||||||
import { getSetting } from '@woocommerce/wc-admin-settings';
|
import { getSetting } from '@woocommerce/wc-admin-settings';
|
||||||
import { ONBOARDING_STORE_NAME, pluginNames, SETTINGS_STORE_NAME } from '@woocommerce/data';
|
import {
|
||||||
|
ONBOARDING_STORE_NAME,
|
||||||
|
PLUGINS_STORE_NAME,
|
||||||
|
pluginNames,
|
||||||
|
SETTINGS_STORE_NAME,
|
||||||
|
} from '@woocommerce/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
@ -24,12 +29,11 @@ import {
|
||||||
SelectControl,
|
SelectControl,
|
||||||
Form,
|
Form,
|
||||||
TextControl,
|
TextControl,
|
||||||
Plugins,
|
|
||||||
} from '@woocommerce/components';
|
} from '@woocommerce/components';
|
||||||
import withWCApiSelect from 'wc-api/with-select';
|
|
||||||
import { recordEvent } from 'lib/tracks';
|
import { recordEvent } from 'lib/tracks';
|
||||||
import { getCurrencyRegion } from 'dashboard/utils';
|
import { getCurrencyRegion } from 'dashboard/utils';
|
||||||
import { CurrencyContext } from 'lib/currency-context';
|
import { CurrencyContext } from 'lib/currency-context';
|
||||||
|
import { createNoticesFromResponse } from 'lib/notices';
|
||||||
|
|
||||||
const wcAdminAssetUrl = getSetting( 'wcAdminAssetUrl', '' );
|
const wcAdminAssetUrl = getSetting( 'wcAdminAssetUrl', '' );
|
||||||
|
|
||||||
|
@ -60,12 +64,6 @@ class BusinessDetails extends Component {
|
||||||
: true,
|
: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.state = {
|
|
||||||
installExtensions: false,
|
|
||||||
isInstallingExtensions: false,
|
|
||||||
extensionInstallError: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.extensions = [
|
this.extensions = [
|
||||||
'facebook-for-woocommerce',
|
'facebook-for-woocommerce',
|
||||||
'mailchimp-for-woocommerce',
|
'mailchimp-for-woocommerce',
|
||||||
|
@ -82,7 +80,7 @@ class BusinessDetails extends Component {
|
||||||
const {
|
const {
|
||||||
createNotice,
|
createNotice,
|
||||||
goToNextStep,
|
goToNextStep,
|
||||||
isError,
|
installAndActivatePlugins,
|
||||||
updateProfileItems,
|
updateProfileItems,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const {
|
const {
|
||||||
|
@ -125,19 +123,8 @@ class BusinessDetails extends Component {
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
await updateProfileItems( updates );
|
const promises = [
|
||||||
|
updateProfileItems( updates ).catch( () => {
|
||||||
if ( ! isError ) {
|
|
||||||
if ( businessExtensions.length === 0 ) {
|
|
||||||
goToNextStep();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState( {
|
|
||||||
installExtensions: true,
|
|
||||||
isInstallingExtensions: true,
|
|
||||||
} );
|
|
||||||
} else {
|
|
||||||
createNotice(
|
createNotice(
|
||||||
'error',
|
'error',
|
||||||
__(
|
__(
|
||||||
|
@ -145,7 +132,29 @@ class BusinessDetails extends Component {
|
||||||
'woocommerce-admin'
|
'woocommerce-admin'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
throw new Error();
|
||||||
|
} ),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ( businessExtensions.length ) {
|
||||||
|
promises.push(
|
||||||
|
installAndActivatePlugins( businessExtensions )
|
||||||
|
.then( ( response ) => {
|
||||||
|
createNoticesFromResponse( response );
|
||||||
|
} )
|
||||||
|
.catch( ( error ) => {
|
||||||
|
this.setState( {
|
||||||
|
hasInstallActivateError: true,
|
||||||
|
} );
|
||||||
|
createNoticesFromResponse( error );
|
||||||
|
throw new Error();
|
||||||
|
} )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Promise.all( promises ).then( () => {
|
||||||
|
goToNextStep();
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
validate( values ) {
|
validate( values ) {
|
||||||
|
@ -274,7 +283,7 @@ class BusinessDetails extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBusinessExtensionHelpText( values ) {
|
renderBusinessExtensionHelpText( values ) {
|
||||||
const { isInstallingExtensions } = this.state;
|
const { isInstallingActivating } = this.props;
|
||||||
const extensions = this.getBusinessExtensions( values );
|
const extensions = this.getBusinessExtensions( values );
|
||||||
|
|
||||||
if ( extensions.length === 0 ) {
|
if ( extensions.length === 0 ) {
|
||||||
|
@ -287,7 +296,7 @@ class BusinessDetails extends Component {
|
||||||
} )
|
} )
|
||||||
.join( ', ' );
|
.join( ', ' );
|
||||||
|
|
||||||
if ( isInstallingExtensions ) {
|
if ( isInstallingActivating ) {
|
||||||
return (
|
return (
|
||||||
<p>
|
<p>
|
||||||
{ sprintf(
|
{ sprintf(
|
||||||
|
@ -319,9 +328,6 @@ class BusinessDetails extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBusinessExtensions( values, getInputProps ) {
|
renderBusinessExtensions( values, getInputProps ) {
|
||||||
const { installExtensions, extensionInstallError } = this.state;
|
|
||||||
const { goToNextStep } = this.props;
|
|
||||||
const extensionsToInstall = this.getBusinessExtensions( values );
|
|
||||||
const extensionBenefits = [
|
const extensionBenefits = [
|
||||||
{
|
{
|
||||||
slug: 'facebook-for-woocommerce',
|
slug: 'facebook-for-woocommerce',
|
||||||
|
@ -382,33 +388,16 @@ class BusinessDetails extends Component {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) ) }
|
) ) }
|
||||||
|
|
||||||
{ installExtensions && (
|
|
||||||
<div className="woocommerce-profile-wizard__card-actions">
|
|
||||||
<Plugins
|
|
||||||
onComplete={ () => {
|
|
||||||
goToNextStep();
|
|
||||||
} }
|
|
||||||
onSkip={ () => {
|
|
||||||
goToNextStep();
|
|
||||||
} }
|
|
||||||
onError={ () => {
|
|
||||||
this.setState( {
|
|
||||||
extensionInstallError: true,
|
|
||||||
isInstallingExtensions: false,
|
|
||||||
} );
|
|
||||||
} }
|
|
||||||
autoInstall={ ! extensionInstallError }
|
|
||||||
pluginSlugs={ extensionsToInstall }
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) }
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isInstallingExtensions, extensionInstallError } = this.state;
|
const {
|
||||||
|
goToNextStep,
|
||||||
|
isInstallingActivating,
|
||||||
|
hasInstallActivateError,
|
||||||
|
} = this.props;
|
||||||
const { formatCurrency } = this.context;
|
const { formatCurrency } = this.context;
|
||||||
const productCountOptions = [
|
const productCountOptions = [
|
||||||
{
|
{
|
||||||
|
@ -662,20 +651,35 @@ class BusinessDetails extends Component {
|
||||||
getInputProps
|
getInputProps
|
||||||
) }
|
) }
|
||||||
|
|
||||||
{ ! extensionInstallError && (
|
<div className="woocommerce-profile-wizard__card-actions">
|
||||||
<Button
|
<Button
|
||||||
isPrimary
|
isPrimary
|
||||||
className="woocommerce-profile-wizard__continue"
|
className="woocommerce-profile-wizard__continue"
|
||||||
onClick={ handleSubmit }
|
onClick={ handleSubmit }
|
||||||
disabled={ ! isValidForm }
|
disabled={ ! isValidForm }
|
||||||
isBusy={ isInstallingExtensions }
|
isBusy={ isInstallingActivating }
|
||||||
|
>
|
||||||
|
{ ! hasInstallActivateError
|
||||||
|
? __(
|
||||||
|
'Continue',
|
||||||
|
'woocommerce-admin'
|
||||||
|
)
|
||||||
|
: __(
|
||||||
|
'Retry',
|
||||||
|
'woocommerce-admin'
|
||||||
|
) }
|
||||||
|
</Button>
|
||||||
|
{ hasInstallActivateError && (
|
||||||
|
<Button
|
||||||
|
onClick={ () => goToNextStep() }
|
||||||
>
|
>
|
||||||
{ __(
|
{ __(
|
||||||
'Continue',
|
'Continue without installing',
|
||||||
'woocommerce-admin'
|
'woocommerce-admin'
|
||||||
) }
|
) }
|
||||||
</Button>
|
</Button>
|
||||||
) }
|
) }
|
||||||
|
</div>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
@ -692,37 +696,43 @@ class BusinessDetails extends Component {
|
||||||
BusinessDetails.contextType = CurrencyContext;
|
BusinessDetails.contextType = CurrencyContext;
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
withWCApiSelect( ( select ) => {
|
|
||||||
const { getProfileItems, getOnboardingError } = select( ONBOARDING_STORE_NAME );
|
|
||||||
|
|
||||||
return {
|
|
||||||
isError: Boolean( getOnboardingError( 'updateProfileItems' ) ),
|
|
||||||
profileItems: getProfileItems(),
|
|
||||||
};
|
|
||||||
} ),
|
|
||||||
withSelect( ( select ) => {
|
withSelect( ( select ) => {
|
||||||
const {
|
const {
|
||||||
getSettings,
|
getSettings,
|
||||||
getSettingsError,
|
getSettingsError,
|
||||||
isGetSettingsRequesting,
|
isGetSettingsRequesting,
|
||||||
} = select( SETTINGS_STORE_NAME );
|
} = select( SETTINGS_STORE_NAME );
|
||||||
|
const { getProfileItems, getOnboardingError } = select(
|
||||||
|
ONBOARDING_STORE_NAME
|
||||||
|
);
|
||||||
|
const { getPluginsError, isPluginsRequesting } = select(
|
||||||
|
PLUGINS_STORE_NAME
|
||||||
|
);
|
||||||
const { general: settings = {} } = getSettings( 'general' );
|
const { general: settings = {} } = getSettings( 'general' );
|
||||||
const isSettingsError = Boolean( getSettingsError( 'general' ) );
|
|
||||||
const isSettingsRequesting = isGetSettingsRequesting( 'general' );
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isSettingsError,
|
hasInstallActivateError:
|
||||||
isSettingsRequesting,
|
getPluginsError( 'installPlugins' ) ||
|
||||||
|
getPluginsError( 'activatePlugins' ),
|
||||||
|
isError: Boolean( getOnboardingError( 'updateProfileItems' ) ),
|
||||||
|
profileItems: getProfileItems(),
|
||||||
|
isSettingsError: Boolean( getSettingsError( 'general' ) ),
|
||||||
|
isSettingsRequesting: isGetSettingsRequesting( 'general' ),
|
||||||
settings,
|
settings,
|
||||||
|
isInstallingActivating:
|
||||||
|
isPluginsRequesting( 'installPlugins' ) ||
|
||||||
|
isPluginsRequesting( 'activatePlugins' ) ||
|
||||||
|
isPluginsRequesting( 'getJetpackConnectUrl' ),
|
||||||
};
|
};
|
||||||
} ),
|
} ),
|
||||||
withDispatch( ( dispatch ) => {
|
withDispatch( ( dispatch ) => {
|
||||||
const { updateProfileItems } = dispatch( ONBOARDING_STORE_NAME );
|
const { updateProfileItems } = dispatch( ONBOARDING_STORE_NAME );
|
||||||
|
const { installAndActivatePlugins } = dispatch( PLUGINS_STORE_NAME );
|
||||||
const { createNotice } = dispatch( 'core/notices' );
|
const { createNotice } = dispatch( 'core/notices' );
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createNotice,
|
createNotice,
|
||||||
|
installAndActivatePlugins,
|
||||||
updateProfileItems,
|
updateProfileItems,
|
||||||
};
|
};
|
||||||
} )
|
} )
|
||||||
|
|
|
@ -11,7 +11,8 @@ import { withSelect, withDispatch } from '@wordpress/data';
|
||||||
/**
|
/**
|
||||||
* WooCommerce dependencies
|
* WooCommerce dependencies
|
||||||
*/
|
*/
|
||||||
import { pluginNames, PLUGINS_STORE_NAME } from '@woocommerce/data';
|
import { createNoticesFromResponse } from 'lib/notices';
|
||||||
|
import { PLUGINS_STORE_NAME } from '@woocommerce/data';
|
||||||
|
|
||||||
export class Plugins extends Component {
|
export class Plugins extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -41,9 +42,8 @@ export class Plugins extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
installAndActivatePlugins,
|
||||||
isRequesting,
|
isRequesting,
|
||||||
installPlugins,
|
|
||||||
activatePlugins,
|
|
||||||
pluginSlugs,
|
pluginSlugs,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
@ -52,60 +52,26 @@ export class Plugins extends Component {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const installs = await installPlugins( pluginSlugs );
|
installAndActivatePlugins( pluginSlugs )
|
||||||
|
.then( ( response ) => {
|
||||||
if ( installs.errors && Object.keys( installs.errors.errors ).length ) {
|
createNoticesFromResponse( response );
|
||||||
this.handleErrors( installs.errors );
|
this.handleSuccess( response.data.activated );
|
||||||
return;
|
} )
|
||||||
}
|
.catch( ( error ) => {
|
||||||
|
createNoticesFromResponse( error );
|
||||||
const activations = await activatePlugins( pluginSlugs );
|
this.handleErrors( error.errors );
|
||||||
|
} );
|
||||||
if ( activations.success && activations.data.activated ) {
|
|
||||||
this.handleSuccess( activations.data.activated );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( activations.errors ) {
|
|
||||||
this.handleErrors( activations.errors );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleErrors( errors ) {
|
handleErrors( errors ) {
|
||||||
const { onError, createNotice } = this.props;
|
const { onError } = this.props;
|
||||||
const { errors: pluginErrors } = errors;
|
|
||||||
|
|
||||||
if ( pluginErrors ) {
|
|
||||||
Object.keys( pluginErrors ).forEach( ( plugin ) => {
|
|
||||||
createNotice(
|
|
||||||
'error',
|
|
||||||
// Replace the slug with a plugin name if a constant exists.
|
|
||||||
pluginNames[ plugin ]
|
|
||||||
? pluginErrors[ plugin ][ 0 ].replace(
|
|
||||||
`\`${ plugin }\``,
|
|
||||||
pluginNames[ plugin ]
|
|
||||||
)
|
|
||||||
: pluginErrors[ plugin ][ 0 ]
|
|
||||||
);
|
|
||||||
} );
|
|
||||||
} else if ( errors.message ) {
|
|
||||||
createNotice( 'error', errors.message );
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState( { hasErrors: true } );
|
this.setState( { hasErrors: true } );
|
||||||
onError( errors );
|
onError( errors );
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSuccess( activePlugins ) {
|
handleSuccess( activePlugins ) {
|
||||||
const { createNotice, onComplete } = this.props;
|
const { onComplete } = this.props;
|
||||||
|
|
||||||
createNotice(
|
|
||||||
'success',
|
|
||||||
__(
|
|
||||||
'Plugins were successfully installed and activated.',
|
|
||||||
'woocommerce-admin'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
onComplete( activePlugins );
|
onComplete( activePlugins );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,15 +187,10 @@ export default compose(
|
||||||
};
|
};
|
||||||
} ),
|
} ),
|
||||||
withDispatch( ( dispatch ) => {
|
withDispatch( ( dispatch ) => {
|
||||||
const { createNotice } = dispatch( 'core/notices' );
|
const { installAndActivatePlugins } = dispatch( PLUGINS_STORE_NAME );
|
||||||
const { activatePlugins, installPlugins } = dispatch(
|
|
||||||
PLUGINS_STORE_NAME
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
activatePlugins,
|
installAndActivatePlugins,
|
||||||
createNotice,
|
|
||||||
installPlugins,
|
|
||||||
};
|
};
|
||||||
} )
|
} )
|
||||||
)( Plugins );
|
)( Plugins );
|
||||||
|
|
|
@ -46,16 +46,12 @@ describe( 'Rendering', () => {
|
||||||
|
|
||||||
describe( 'Installing and activating', () => {
|
describe( 'Installing and activating', () => {
|
||||||
let pluginsWrapper;
|
let pluginsWrapper;
|
||||||
const installPlugins = jest.fn().mockReturnValue( {
|
const installAndActivatePlugins = jest.fn().mockResolvedValue( {
|
||||||
success: true,
|
|
||||||
} );
|
|
||||||
const activatePlugins = jest.fn().mockReturnValue( {
|
|
||||||
success: true,
|
success: true,
|
||||||
data: {
|
data: {
|
||||||
activated: [ 'jetpack' ],
|
activated: [ 'jetpack' ],
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
const createNotice = jest.fn();
|
|
||||||
const onComplete = jest.fn();
|
const onComplete = jest.fn();
|
||||||
|
|
||||||
beforeEach( () => {
|
beforeEach( () => {
|
||||||
|
@ -63,40 +59,23 @@ describe( 'Installing and activating', () => {
|
||||||
<Plugins
|
<Plugins
|
||||||
pluginSlugs={ [ 'jetpack' ] }
|
pluginSlugs={ [ 'jetpack' ] }
|
||||||
onComplete={ onComplete }
|
onComplete={ onComplete }
|
||||||
installPlugins={ installPlugins }
|
installAndActivatePlugins={ installAndActivatePlugins }
|
||||||
activatePlugins={ activatePlugins }
|
|
||||||
createNotice={ createNotice }
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'should call installPlugins', async () => {
|
it( 'should call installAndActivatePlugins', async () => {
|
||||||
const installButton = pluginsWrapper.find( Button ).at( 0 );
|
const installButton = pluginsWrapper.find( Button ).at( 0 );
|
||||||
installButton.simulate( 'click' );
|
installButton.simulate( 'click' );
|
||||||
|
|
||||||
expect( installPlugins ).toHaveBeenCalledWith( [ 'jetpack' ] );
|
expect( installAndActivatePlugins ).toHaveBeenCalledWith( [ 'jetpack' ] );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'should call activatePlugin', async () => {
|
|
||||||
const installButton = pluginsWrapper.find( Button ).at( 0 );
|
|
||||||
installButton.simulate( 'click' );
|
|
||||||
|
|
||||||
expect( activatePlugins ).toHaveBeenCalledWith( [ 'jetpack' ] );
|
|
||||||
} );
|
|
||||||
it( 'should create a success notice', async () => {
|
|
||||||
const installButton = pluginsWrapper.find( Button ).at( 0 );
|
|
||||||
installButton.simulate( 'click' );
|
|
||||||
|
|
||||||
expect( createNotice ).toHaveBeenCalledWith(
|
|
||||||
'success',
|
|
||||||
'Plugins were successfully installed and activated.'
|
|
||||||
);
|
|
||||||
} );
|
|
||||||
it( 'should call the onComplete callback', async () => {
|
it( 'should call the onComplete callback', async () => {
|
||||||
const installButton = pluginsWrapper.find( Button ).at( 0 );
|
const installButton = pluginsWrapper.find( Button ).at( 0 );
|
||||||
installButton.simulate( 'click' );
|
installButton.simulate( 'click' );
|
||||||
|
|
||||||
expect( onComplete ).toHaveBeenCalledWith( [ 'jetpack' ] );
|
await expect( onComplete ).toHaveBeenCalledWith( [ 'jetpack' ] );
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
@ -107,43 +86,28 @@ describe( 'Installing and activating errors', () => {
|
||||||
'failed-plugin': [ 'error message' ],
|
'failed-plugin': [ 'error message' ],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const installPlugins = jest.fn().mockReturnValue( {
|
const installAndActivatePlugins = jest.fn().mockRejectedValue( {
|
||||||
errors,
|
errors,
|
||||||
} );
|
} );
|
||||||
const activatePlugins = jest.fn().mockReturnValue( {
|
const onComplete = jest.fn();
|
||||||
success: false,
|
|
||||||
} );
|
|
||||||
const createNotice = jest.fn();
|
|
||||||
const onError = jest.fn();
|
const onError = jest.fn();
|
||||||
|
|
||||||
beforeEach( () => {
|
beforeEach( () => {
|
||||||
pluginsWrapper = shallow(
|
pluginsWrapper = shallow(
|
||||||
<Plugins
|
<Plugins
|
||||||
pluginSlugs={ [ 'jetpack' ] }
|
pluginSlugs={ [ 'jetpack' ] }
|
||||||
onComplete={ () => {} }
|
onComplete={ onComplete }
|
||||||
installPlugins={ installPlugins }
|
installAndActivatePlugins={ installAndActivatePlugins }
|
||||||
activatePlugins={ activatePlugins }
|
|
||||||
createNotice={ createNotice }
|
|
||||||
onError={ onError }
|
onError={ onError }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'should not call activatePlugin on install error', async () => {
|
it( 'should not call onComplete on install error', async () => {
|
||||||
const installButton = pluginsWrapper.find( Button ).at( 0 );
|
const installButton = pluginsWrapper.find( Button ).at( 0 );
|
||||||
installButton.simulate( 'click' );
|
installButton.simulate( 'click' );
|
||||||
|
|
||||||
expect( activatePlugins ).not.toHaveBeenCalled();
|
expect( onComplete ).not.toHaveBeenCalled();
|
||||||
} );
|
|
||||||
|
|
||||||
it( 'should create an error notice', async () => {
|
|
||||||
const installButton = pluginsWrapper.find( Button ).at( 0 );
|
|
||||||
installButton.simulate( 'click' );
|
|
||||||
|
|
||||||
expect( createNotice ).toHaveBeenCalledWith(
|
|
||||||
'error',
|
|
||||||
errors.errors[ 'failed-plugin' ][ 0 ]
|
|
||||||
);
|
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'should call the onError callback', async () => {
|
it( 'should call the onError callback', async () => {
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
/**
|
/**
|
||||||
* External Dependencies
|
* External Dependencies
|
||||||
*/
|
*/
|
||||||
|
import { apiFetch, dispatch } from '@wordpress/data-controls';
|
||||||
import { apiFetch } from '@wordpress/data-controls';
|
|
||||||
import { __ } from '@wordpress/i18n';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal Dependencies
|
* Internal Dependencies
|
||||||
*/
|
*/
|
||||||
|
import { pluginNames, STORE_NAME } from './constants';
|
||||||
import TYPES from './action-types';
|
import TYPES from './action-types';
|
||||||
import { WC_ADMIN_NAMESPACE } from '../constants';
|
import { WC_ADMIN_NAMESPACE } from '../constants';
|
||||||
|
|
||||||
|
@ -68,16 +67,12 @@ export function* installPlugins( plugins ) {
|
||||||
data: { plugins: plugins.join( ',' ) },
|
data: { plugins: plugins.join( ',' ) },
|
||||||
} );
|
} );
|
||||||
|
|
||||||
if ( ! results ) {
|
if ( results.data.installed.length ) {
|
||||||
throw new Error();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( results.success && results.data.installed ) {
|
|
||||||
yield updateInstalledPlugins( results.data.installed );
|
yield updateInstalledPlugins( results.data.installed );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( Object.keys( results.errors.errors ).length ) {
|
if ( Object.keys( results.errors.errors ).length ) {
|
||||||
yield setError( 'installPlugins', results.errors );
|
throw results.errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield setIsRequesting( 'installPlugins', false );
|
yield setIsRequesting( 'installPlugins', false );
|
||||||
|
@ -85,16 +80,7 @@ export function* installPlugins( plugins ) {
|
||||||
return results;
|
return results;
|
||||||
} catch ( error ) {
|
} catch ( error ) {
|
||||||
yield setError( 'installPlugins', error );
|
yield setError( 'installPlugins', error );
|
||||||
yield setIsRequesting( 'installPlugins', false );
|
throw formatErrors( error );
|
||||||
|
|
||||||
return {
|
|
||||||
errors: {
|
|
||||||
message: __(
|
|
||||||
'Something went wrong while trying to install your plugins.',
|
|
||||||
'woocommerce-admin'
|
|
||||||
),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,24 +94,47 @@ export function* activatePlugins( plugins ) {
|
||||||
data: { plugins: plugins.join( ',' ) },
|
data: { plugins: plugins.join( ',' ) },
|
||||||
} );
|
} );
|
||||||
|
|
||||||
if ( results.success && results.data.activated ) {
|
if ( results.data.activated.length ) {
|
||||||
yield updateActivePlugins( results.data.activated );
|
yield updateActivePlugins( results.data.activated );
|
||||||
yield setIsRequesting( 'activatePlugins', false );
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error();
|
if ( Object.keys( results.errors.errors ).length ) {
|
||||||
|
throw results.errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield setIsRequesting( 'activatePlugins', false );
|
||||||
|
|
||||||
|
return results;
|
||||||
} catch ( error ) {
|
} catch ( error ) {
|
||||||
yield setError( 'activatePlugins', error );
|
yield setError( 'activatePlugins', error );
|
||||||
yield setIsRequesting( 'activatePlugins', false );
|
throw formatErrors( error );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
export function* installAndActivatePlugins( plugins ) {
|
||||||
errors: {
|
try {
|
||||||
message: __(
|
yield dispatch( STORE_NAME, 'installPlugins', plugins );
|
||||||
'Something went wrong while trying to activate your plugins.',
|
const activations = yield dispatch( STORE_NAME, 'activatePlugins', plugins );
|
||||||
'woocommerce-admin'
|
return activations;
|
||||||
),
|
} catch ( error ) {
|
||||||
}
|
throw error;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatErrors( response ) {
|
||||||
|
if ( response.errors ) {
|
||||||
|
// Replace the slug with a plugin name if a constant exists.
|
||||||
|
Object.keys( response.errors ).forEach( plugin => {
|
||||||
|
response.errors[ plugin ] = response.errors[ plugin ].map( pluginError => {
|
||||||
|
return pluginNames[ plugin ]
|
||||||
|
? pluginError.replace(
|
||||||
|
`\`${ plugin }\``,
|
||||||
|
pluginNames[ plugin ]
|
||||||
|
)
|
||||||
|
: pluginError;
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
|
@ -234,7 +234,7 @@ class Plugins extends \WC_REST_Data_Controller {
|
||||||
$errors->add(
|
$errors->add(
|
||||||
$plugin,
|
$plugin,
|
||||||
/* translators: %s: plugin slug (example: woocommerce-services) */
|
/* translators: %s: plugin slug (example: woocommerce-services) */
|
||||||
sprintf( __( 'The requested plugin `%s`. is not in the list of allowed plugins.', 'woocommerce-admin' ), $slug )
|
sprintf( __( 'The requested plugin `%s` is not in the list of allowed plugins.', 'woocommerce-admin' ), $slug )
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -315,6 +315,9 @@ class Plugins extends \WC_REST_Data_Controller {
|
||||||
),
|
),
|
||||||
'errors' => $errors,
|
'errors' => $errors,
|
||||||
'success' => count( $errors->errors ) === 0,
|
'success' => count( $errors->errors ) === 0,
|
||||||
|
'message' => count( $errors->errors ) === 0
|
||||||
|
? __( 'Plugins were successfully installed.', 'woocommerce-admin' )
|
||||||
|
: __( 'There was a problem installing some of the requested plugins.', 'woocommerce-admin' ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,6 +425,9 @@ class Plugins extends \WC_REST_Data_Controller {
|
||||||
),
|
),
|
||||||
'errors' => $errors,
|
'errors' => $errors,
|
||||||
'success' => count( $errors->errors ) === 0,
|
'success' => count( $errors->errors ) === 0,
|
||||||
|
'message' => count( $errors->errors ) === 0
|
||||||
|
? __( 'Plugins were successfully activated.', 'woocommerce-admin' )
|
||||||
|
: __( 'There was a problem activating some of the requested plugins.', 'woocommerce-admin' ),
|
||||||
) );
|
) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue