Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow module details link to be overridden in the module store. #9937

Merged
merged 5 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions assets/js/components/settings/SettingsActiveModule/Footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
*/
import PropTypes from 'prop-types';
import { useHistory, useParams } from 'react-router-dom';
import { isEmpty } from 'lodash';

/**
* WordPress dependencies
Expand All @@ -42,7 +41,6 @@ import Link from '../../Link';
import { trackEvent } from '../../../util';
import { clearCache } from '../../../googlesitekit/api/cache';
import { CORE_UI } from '../../../googlesitekit/datastore/ui/constants';
import { CORE_USER } from '../../../googlesitekit/datastore/user/constants';
import useViewContext from '../../../hooks/useViewContext';

export default function Footer( props ) {
Expand Down Expand Up @@ -80,12 +78,9 @@ export default function Footer( props ) {
select( CORE_UI ).getValue( isSavingKey )
);

const moduleHomepage = useSelect( ( select ) => {
if ( ! module || isEmpty( module.homepage ) ) {
return undefined;
}
return select( CORE_USER ).getAccountChooserURL( module.homepage );
} );
const moduleHomepage = useSelect( ( select ) =>
select( CORE_MODULES ).getDetailsLinkURL( slug )
);

const { submitChanges } = useDispatch( CORE_MODULES );
const { clearErrors } = useDispatch( module?.storeName ) || {};
Expand Down
40 changes: 40 additions & 0 deletions assets/js/googlesitekit/modules/datastore/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,46 @@ const baseSelectors = {
getRecoveredModules( state ) {
return state.recoveredModules;
},

/**
* Gets the details link URL for a module.
*
* Returns the module homepage by default. This can be overwritten by a
* custom selector of the same name in the module store implementation.
*
* @since n.e.x.t
*
* @param {Object} state Data store's state.
* @param {string} slug Module slug.
* @return {(string|null|undefined)} Details link URL; `null` if module is not available, or does not have a homepage. `undefined` if data is still loading.
*/
getDetailsLinkURL: createRegistrySelector(
( select ) => ( state, slug ) => {
const module = select( CORE_MODULES ).getModule( slug );

if ( module === undefined ) {
return undefined;
}

if ( module === null ) {
return null;
}

const storeName = select( CORE_MODULES ).getModuleStoreName( slug );

const { getDetailsLinkURL } = select( storeName ) || {};

if ( typeof getDetailsLinkURL === 'function' ) {
return getDetailsLinkURL();
}

if ( ! module.homepage ) {
return null;
}

return select( CORE_USER ).getAccountChooserURL( module.homepage );
}
),
};

const store = combineStores(
Expand Down
91 changes: 91 additions & 0 deletions assets/js/googlesitekit/modules/datastore/modules.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
* Internal dependencies
*/
import API from 'googlesitekit-api';
import Modules from 'googlesitekit-modules';
import { combineStores } from 'googlesitekit-data';
import {
createTestRegistry,
muteFetch,
Expand Down Expand Up @@ -2186,5 +2188,94 @@ describe( 'core/modules modules', () => {
await waitForDefaultTimeouts();
} );
} );

describe( 'getDetailsLinkURL', () => {
it( 'should return null if module is not found', () => {
registry.dispatch( CORE_MODULES ).receiveGetModules( FIXTURES );

expect(
registry
.select( CORE_MODULES )
.getDetailsLinkURL( 'unregistered-module' )
).toBeNull();
} );

it( 'should return null if module does not define homepage', () => {
registry.dispatch( CORE_MODULES ).receiveGetModules( [
{
slug: 'search-console',
name: 'Search Console',
active: true,
connected: true,
},
] );

expect(
registry
.select( CORE_MODULES )
.getDetailsLinkURL( 'search-console' )
).toBeNull();
} );

it( 'should return module homepage', () => {
registry.dispatch( CORE_MODULES ).receiveGetModules( [
{
slug: 'search-console',
name: 'Search Console',
homepage: 'https://example.com',
active: true,
connected: true,
},
] );
registry
.dispatch( CORE_USER )
.receiveUserInfo( { email: '[email protected]' } );

expect(
registry
.select( CORE_MODULES )
.getDetailsLinkURL( 'search-console' )
).toBe(
'https://accounts.google.com/accountchooser?continue=https%3A%2F%2Fexample.com&Email=test%40example.com'
);
} );

it( 'should be overridden by module defined selector', () => {
const slug = 'test-module';
const moduleStoreName = `test/${ slug }`;

registry.registerStore(
moduleStoreName,
combineStores(
Modules.createModuleStore( slug, {
storeName: moduleStoreName,
} ),
{
selectors: {
getDetailsLinkURL: () =>
'https://example.com/custom-link',
},
}
)
);

registry
.dispatch( CORE_MODULES )
.registerModule( slug, { storeName: moduleStoreName } );

registry.dispatch( CORE_MODULES ).receiveGetModules( [
{
slug,
name: 'Test Module',
active: true,
connected: true,
},
] );

expect(
registry.select( CORE_MODULES ).getDetailsLinkURL( slug )
).toBe( 'https://example.com/custom-link' );
} );
} );
} );
} );
12 changes: 12 additions & 0 deletions assets/js/modules/adsense/datastore/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,18 @@ export const selectors = {
return select( MODULES_ADSENSE ).getServiceURL( { path, query } );
}
),

/**
* Overrides the details link URL for this module.
*
* @since n.e.x.t
*
* @return {(string|undefined)} AdSense account sites list URL (or `undefined` if not loaded).
*/
getDetailsLinkURL: createRegistrySelector(
( select ) => () =>
select( MODULES_ADSENSE ).getServiceAccountManageSitesURL()
),
};

const store = {
Expand Down
Loading