Skip to content

Commit

Permalink
Merge branch 'develop' into enhancement/5047-remove-ud-ff.
Browse files Browse the repository at this point in the history
  • Loading branch information
asvinb committed Jun 3, 2022
2 parents 34c12c5 + 1fdff53 commit 34c7c53
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 141 deletions.
9 changes: 7 additions & 2 deletions assets/js/components/dashboard-sharing/UserRoleSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,20 @@ export default function UserRoleSelect( { moduleSlug, isLocked = false } ) {

const toggleEditMode = useCallback( () => {
if ( editMode ) {
if ( ! isEqual( [ ...sharedRoles ].sort(), initialSharedRoles ) ) {
if (
! isEqual(
[ ...( sharedRoles || [] ) ].sort(),
initialSharedRoles
)
) {
trackEvent(
`${ viewContext }_sharing`,
'change_shared_roles',
moduleSlug
);
}
} else {
setInitialSharedRoles( [ ...sharedRoles ].sort() );
setInitialSharedRoles( [ ...( sharedRoles || [] ) ].sort() );
}

setEditMode( ! editMode );
Expand Down
30 changes: 29 additions & 1 deletion assets/js/googlesitekit/datastore/user/permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ export const selectors = {
}

// Return an array of module slugs for modules that are
// sharable and the user has the "read shared module data"
// shareable and the user has the "read shared module data"
// capability for.
return Object.values( modules ).reduce( ( moduleSlugs, module ) => {
const hasCapability = select( CORE_USER ).hasCapability(
Expand Down Expand Up @@ -231,6 +231,34 @@ export const selectors = {
return undefined;
}
),

/**
* Checks if the specified module is shareable and viewable by the current user.
*
* @since n.e.x.t
*
* @param {Object} state Data store's state.
* @param {string} moduleSlug Module slug to check.
* @return {(boolean|undefined)} `true` if the module is shareable and viewable by the current user. `false` if the module does not exist, is not shareable or not viewable by the current user. `undefined` if state is not loaded yet.
*/
canViewSharedModule: createRegistrySelector(
( select ) => ( state, moduleSlug ) => {
const module = select( CORE_MODULES ).getModule( moduleSlug );

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

if ( module === null || ! module.shareable ) {
return false;
}

return select( CORE_USER ).hasCapability(
PERMISSION_READ_SHARED_MODULE_DATA,
module.slug
);
}
),
};

export default {
Expand Down
101 changes: 101 additions & 0 deletions assets/js/googlesitekit/datastore/user/permissions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
} from '../../../../../tests/js/utils';
import { CORE_USER, PERMISSION_MANAGE_OPTIONS } from './constants';
import FIXTURES from '../../modules/datastore/__fixtures__';
import { CORE_MODULES } from '../../modules/datastore/constants';

describe( 'core/user authentication', () => {
const capabilitiesBaseVar = '_googlesitekitUserData';
Expand Down Expand Up @@ -252,5 +253,105 @@ describe( 'core/user authentication', () => {
] );
} );
} );

describe( 'canViewSharedModule', () => {
it( 'should return undefined if modules are not loaded', () => {
fetchMock.getOnce(
/^\/google-site-kit\/v1\/core\/modules\/data\/list/,
{ body: FIXTURES, status: 200 }
);

const canViewSharedModule = registry
.select( CORE_USER )
.canViewSharedModule( 'search-console' );

expect( canViewSharedModule ).toBeUndefined();
} );

it( 'should return FALSE if the module does not exist', () => {
registry
.dispatch( CORE_MODULES )
.receiveGetModules( [
{ slug: 'search-console', name: 'Search Console' },
] );

const canViewSharedModule = registry
.select( CORE_USER )
.canViewSharedModule( 'invalid-module' );

expect( canViewSharedModule ).toBe( false );
} );

it( 'should return FALSE if the module is not shared', () => {
registry.dispatch( CORE_MODULES ).receiveGetModules( [
{
slug: 'search-console',
name: 'Search Console',
shareable: false,
},
] );

const canViewSharedModule = registry
.select( CORE_USER )
.canViewSharedModule( 'search-console' );

expect( canViewSharedModule ).toBe( false );
} );

it( 'should return undefined if the capabilities are not loaded', () => {
registry.dispatch( CORE_MODULES ).receiveGetModules( [
{
slug: 'search-console',
name: 'Search Console',
shareable: true,
},
] );
global[ capabilitiesBaseVar ] = undefined;

const canViewSharedModule = registry
.select( CORE_USER )
.canViewSharedModule( 'search-console' );

expect( console ).toHaveErroredWith(
'Could not load core/user permissions.'
);

expect( canViewSharedModule ).toBeUndefined();
} );

it( 'should return FALSE if the module is shared but the user does not have the view permission', () => {
registry.dispatch( CORE_MODULES ).receiveGetModules( [
{
slug: 'search-console',
name: 'Search Console',
shareable: true,
},
] );
global[ capabilitiesBaseVar ] = capabilities;

const canViewSharedModule = registry
.select( CORE_USER )
.canViewSharedModule( 'search-console' );

expect( canViewSharedModule ).toBe( false );
} );

it( 'should return TRUE if the module is shared and the user has the view permission', () => {
registry.dispatch( CORE_MODULES ).receiveGetModules( [
{
slug: 'search-console',
name: 'Search Console',
shareable: true,
},
] );
global[ capabilitiesBaseVar ] = capabilitiesWithPermission;

const canViewSharedModule = registry
.select( CORE_USER )
.canViewSharedModule( 'search-console' );

expect( canViewSharedModule ).toBe( true );
} );
} );
} );
} );
12 changes: 5 additions & 7 deletions assets/js/googlesitekit/modules/create-info-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,12 @@ const { createRegistrySelector } = Data;
* @param {string} slug Slug of the module that the store is for.
* @param {Object} args Arguments to configure the store.
* @param {number} args.storeName Store name to use.
* @param {string} [args.adminPage] Optional. Store admin page. Default is 'googlesitekit-dashboard'.
* @param {boolean} [args.requiresSetup] Optional. Store flag, for requires setup. Default is 'true'.
* @return {Object} The info store object.
*/
export const createInfoStore = (
slug,
{
storeName = undefined,
adminPage = 'googlesitekit-dashboard',
requiresSetup = true,
} = {}
{ storeName = undefined, requiresSetup = true } = {}
) => {
invariant( storeName, 'storeName is required.' );

Expand All @@ -76,7 +71,10 @@ export const createInfoStore = (
*/
getAdminScreenURL: createRegistrySelector(
( select ) => ( state, queryArgs ) => {
return select( CORE_SITE ).getAdminURL( adminPage, queryArgs );
return select( CORE_SITE ).getAdminURL(
'googlesitekit-dashboard',
queryArgs
);
}
),

Expand Down
24 changes: 0 additions & 24 deletions assets/js/googlesitekit/modules/create-info-store.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,30 +87,6 @@ describe( 'createInfoStore store', () => {
} );
} );

// It uses `adminPage` when provided.
it( 'returns adminPage url when `adminPage` is provided', () => {
registry.dispatch( CORE_SITE ).receiveSiteInfo( {
adminURL: 'http://example.com/wp-admin/',
} );
const { STORE_NAME, ...store } = createInfoStore( MODULE_SLUG, {
storeName: TEST_STORE_NAME,
adminPage: 'test-admin-page',
} );
registry.registerStore( STORE_NAME, store );

const adminSreenURL = registry
.select( STORE_NAME )
.getAdminScreenURL();

const { origin, pathname } = new URL( adminSreenURL );
expect( origin + pathname ).toEqual(
'http://example.com/wp-admin/admin.php'
);
expect( adminSreenURL ).toMatchQueryParameters( {
page: 'test-admin-page',
} );
} );

// It adds extra query parameters if provided.
it( 'adds extra query parameters to the adminScreenURL when provided', () => {
registry.dispatch( CORE_SITE ).receiveSiteInfo( {
Expand Down
3 changes: 0 additions & 3 deletions assets/js/googlesitekit/modules/create-module-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ import { createValidationSelector } from '../data/utils';
* @param {number} args.storeName Store name to use.
* @param {Array} [args.settingSlugs] Optional. If the module store should support settings, this needs to be a list of the slugs that are part of the module and handled by the module's 'modules/{slug}/data/settings' API endpoint. Default is undefined.
* @param {Array} [args.ownedSettingsSlugs] Optional. List of "owned settings" for this module, if they exist.
* @param {string} [args.adminPage] Optional. Store admin page. Default is 'googlesitekit-dashboard'.
* @param {boolean} [args.requiresSetup] Optional. Store flag for requires setup. Default is 'true'.
* @param {Function} [args.submitChanges] Optional. Submit settings changes handler.
* @param {Function} [args.rollbackChanges] Optional. Rollbacks settings changes handler.
Expand All @@ -68,7 +67,6 @@ export function createModuleStore( slug, args = {} ) {
storeName,
settingSlugs,
ownedSettingsSlugs = undefined,
adminPage = 'googlesitekit-dashboard',
requiresSetup = true,
submitChanges,
rollbackChanges,
Expand All @@ -90,7 +88,6 @@ export function createModuleStore( slug, args = {} ) {

const infoStore = createInfoStore( slug, {
storeName,
adminPage,
requiresSetup,
} );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import {
BREAKPOINT_SMALL,
useBreakpoint,
} from '../../../../../hooks/useBreakpoint';
import useViewOnly from '../../../../../hooks/useViewOnly';
import { CORE_USER } from '../../../../../googlesitekit/datastore/user/constants';
const { useSelect, useInViewSelect } = Data;

function getDatapointAndChange( [ report ], selectedStat, divider = 1 ) {
Expand Down Expand Up @@ -85,6 +87,16 @@ const Overview = ( {
const zeroDataStatesEnabled = useFeature( 'zeroDataStates' );
const breakpoint = useBreakpoint();

const viewOnly = useViewOnly();

const canViewSharedAnalytics = useSelect( ( select ) => {
if ( ! viewOnly ) {
return true;
}

return select( CORE_USER ).canViewSharedModule( 'analytics' );
} );

const analyticsModuleConnected = useSelect( ( select ) =>
select( CORE_MODULES ).isModuleConnected( 'analytics' )
);
Expand Down Expand Up @@ -151,11 +163,15 @@ const Overview = ( {
}

const showAnalytics =
( analyticsModuleConnected &&
( canViewSharedAnalytics &&
analyticsModuleConnected &&
! isAnalyticsGatheringData &&
! zeroDataStatesEnabled &&
! error ) ||
( analyticsModuleConnected && zeroDataStatesEnabled && ! error );
( canViewSharedAnalytics &&
analyticsModuleConnected &&
zeroDataStatesEnabled &&
! error );

const showGoalsCTA =
showAnalytics &&
Expand Down Expand Up @@ -236,7 +252,8 @@ const Overview = ( {
</Cell>
) }

{ ( ! analyticsModuleConnected || ! analyticsModuleActive ) &&
{ canViewSharedAnalytics &&
( ! analyticsModuleConnected || ! analyticsModuleActive ) &&
! isNavigatingToReauthURL && (
<Cell { ...halfCellProps }>
{ zeroDataStatesEnabled &&
Expand All @@ -252,16 +269,19 @@ const Overview = ( {
</Cell>
) }

{ analyticsModuleActiveAndConnected && error && (
<Cell { ...halfCellProps }>
<WidgetReportError
moduleSlug="analytics"
error={ error }
/>
</Cell>
) }
{ canViewSharedAnalytics &&
analyticsModuleActiveAndConnected &&
error && (
<Cell { ...halfCellProps }>
<WidgetReportError
moduleSlug="analytics"
error={ error }
/>
</Cell>
) }

{ isAnalyticsGatheringData &&
{ canViewSharedAnalytics &&
isAnalyticsGatheringData &&
! error &&
! zeroDataStatesEnabled && (
<Cell { ...halfCellProps }>
Expand Down
Loading

0 comments on commit 34c7c53

Please sign in to comment.