From 84128f2a6fb202ac8da579f008e5c5e010eb671e Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Mon, 29 Jul 2024 18:51:00 +0100 Subject: [PATCH 01/20] Remove default comment. --- assets/js/googlesitekit/notifications/register-defaults.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/assets/js/googlesitekit/notifications/register-defaults.js b/assets/js/googlesitekit/notifications/register-defaults.js index 82e944618c9..bfb022b0cb8 100644 --- a/assets/js/googlesitekit/notifications/register-defaults.js +++ b/assets/js/googlesitekit/notifications/register-defaults.js @@ -30,8 +30,6 @@ import { NOTIFICATION_AREAS } from './datastore/constants'; * @param {Object} notificationsAPI Notifications API. */ export function registerDefaults( notificationsAPI ) { - // TODO: This file and the below code is pure scaffolding and for test QA purposes. - // It will be modified in issue #8976 that registers the first refactored notification. notificationsAPI.registerNotification( 'gathering-data-notification', { Component() { return

TODO: Use a valid notification component here.

; From a51db656221418ce19169bd8e6406514b288c585 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Thu, 1 Aug 2024 14:22:03 +0100 Subject: [PATCH 02/20] Move gathering data notification check to notification registration. --- .../notifications/register-defaults.js | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/assets/js/googlesitekit/notifications/register-defaults.js b/assets/js/googlesitekit/notifications/register-defaults.js index bfb022b0cb8..89980f64e32 100644 --- a/assets/js/googlesitekit/notifications/register-defaults.js +++ b/assets/js/googlesitekit/notifications/register-defaults.js @@ -21,6 +21,10 @@ import { VIEW_CONTEXT_MAIN_DASHBOARD_VIEW_ONLY, } from '../constants'; import { NOTIFICATION_AREAS } from './datastore/constants'; +import { CORE_USER } from '../datastore/user/constants'; +import { CORE_MODULES } from '../modules/datastore/constants'; +import { MODULES_ANALYTICS_4 } from '../../modules/analytics-4/datastore/constants'; +import { MODULES_SEARCH_CONSOLE } from '../../modules/search-console/datastore/constants'; /** * Registers notifications not specific to any one particular module. @@ -40,7 +44,60 @@ export function registerDefaults( notificationsAPI ) { VIEW_CONTEXT_MAIN_DASHBOARD, VIEW_CONTEXT_MAIN_DASHBOARD_VIEW_ONLY, ], - checkRequirements: () => false, + checkRequirements: ( { select } ) => { + const isAnalyticsConnected = + select( CORE_MODULES ).isModuleConnected( 'analytics-4' ); + + const canViewSharedAnalytics = + select( CORE_USER ).canViewSharedModule( 'analytics-4' ); + const canViewSharedSearchConsole = + select( CORE_USER ).canViewSharedModule( 'search-console' ); + + const showRecoverableAnalytics = () => { + const recoverableModules = + select( CORE_MODULES ).getRecoverableModules(); + + if ( recoverableModules === undefined ) { + return undefined; + } + + return Object.keys( recoverableModules ).includes( + 'analytics-4' + ); + }; + const showRecoverableSearchConsole = () => { + const recoverableModules = + select( CORE_MODULES ).getRecoverableModules(); + + if ( recoverableModules === undefined ) { + return undefined; + } + + return Object.keys( recoverableModules ).includes( + 'search-console' + ); + }; + + const analyticsGatheringData = + isAnalyticsConnected && + canViewSharedAnalytics && + false === showRecoverableAnalytics + ? select( MODULES_ANALYTICS_4 ).isGatheringData() + : false; + const searchConsoleGatheringData = + canViewSharedSearchConsole && + false === showRecoverableSearchConsole && + select( MODULES_SEARCH_CONSOLE ).isGatheringData(); + + if ( + analyticsGatheringData === undefined || + searchConsoleGatheringData === undefined + ) { + return false; + } + + return analyticsGatheringData || searchConsoleGatheringData; + }, isDismissible: true, } ); } From 0858770d9d4ca9fc8e2e23fa90808a0281e1d5d5 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Thu, 1 Aug 2024 16:02:17 +0100 Subject: [PATCH 03/20] Add a reusable constant for view only contexts. --- assets/js/googlesitekit/constants.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/assets/js/googlesitekit/constants.js b/assets/js/googlesitekit/constants.js index 4a839c7615a..e8c64cfcfaa 100644 --- a/assets/js/googlesitekit/constants.js +++ b/assets/js/googlesitekit/constants.js @@ -52,3 +52,11 @@ export const SITE_KIT_VIEW_CONTEXTS = [ VIEW_CONTEXT_SETTINGS, VIEW_CONTEXT_MODULE_SETUP, ]; + +// Site Kit view-only contexts +export const SITE_KIT_VIEW_ONLY_CONTEXTS = [ + VIEW_CONTEXT_MAIN_DASHBOARD_VIEW_ONLY, + VIEW_CONTEXT_ENTITY_DASHBOARD_VIEW_ONLY, + VIEW_CONTEXT_ADMIN_BAR_VIEW_ONLY, + VIEW_CONTEXT_WP_DASHBOARD_VIEW_ONLY, +]; From 2726f72a036fb0275959c1bdd8dc6f0a6e414432 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Thu, 1 Aug 2024 16:03:24 +0100 Subject: [PATCH 04/20] Check view only when computing gathering data logic. --- .../notifications/datastore/notifications.js | 5 ++- .../notifications/register-defaults.js | 34 ++++++++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/assets/js/googlesitekit/notifications/datastore/notifications.js b/assets/js/googlesitekit/notifications/datastore/notifications.js index d8ee7050a6d..95cd95839da 100644 --- a/assets/js/googlesitekit/notifications/datastore/notifications.js +++ b/assets/js/googlesitekit/notifications/datastore/notifications.js @@ -219,7 +219,10 @@ export const resolvers = { filteredNotifications.map( async ( { checkRequirements } ) => { if ( typeof checkRequirements === 'function' ) { try { - return await checkRequirements( registry ); + return await checkRequirements( + registry, + viewContext + ); } catch ( e ) { return false; // Prevent `Promise.all()` from being rejected for a single failed promise. } diff --git a/assets/js/googlesitekit/notifications/register-defaults.js b/assets/js/googlesitekit/notifications/register-defaults.js index 89980f64e32..cd576286555 100644 --- a/assets/js/googlesitekit/notifications/register-defaults.js +++ b/assets/js/googlesitekit/notifications/register-defaults.js @@ -17,6 +17,7 @@ */ import { + SITE_KIT_VIEW_ONLY_CONTEXTS, VIEW_CONTEXT_MAIN_DASHBOARD, VIEW_CONTEXT_MAIN_DASHBOARD_VIEW_ONLY, } from '../constants'; @@ -44,16 +45,35 @@ export function registerDefaults( notificationsAPI ) { VIEW_CONTEXT_MAIN_DASHBOARD, VIEW_CONTEXT_MAIN_DASHBOARD_VIEW_ONLY, ], - checkRequirements: ( { select } ) => { + checkRequirements: ( { select }, viewContext ) => { + const viewOnly = + SITE_KIT_VIEW_ONLY_CONTEXTS.includes( viewContext ); + const isAnalyticsConnected = select( CORE_MODULES ).isModuleConnected( 'analytics-4' ); - const canViewSharedAnalytics = - select( CORE_USER ).canViewSharedModule( 'analytics-4' ); - const canViewSharedSearchConsole = - select( CORE_USER ).canViewSharedModule( 'search-console' ); + const canViewSharedAnalytics = () => { + if ( ! viewOnly ) { + return true; + } + + return select( CORE_USER ).canViewSharedModule( 'analytics-4' ); + }; + const canViewSharedSearchConsole = () => { + if ( ! viewOnly ) { + return true; + } + + return select( CORE_USER ).canViewSharedModule( + 'search-console' + ); + }; const showRecoverableAnalytics = () => { + if ( ! viewOnly ) { + return false; + } + const recoverableModules = select( CORE_MODULES ).getRecoverableModules(); @@ -66,6 +86,10 @@ export function registerDefaults( notificationsAPI ) { ); }; const showRecoverableSearchConsole = () => { + if ( ! viewOnly ) { + return false; + } + const recoverableModules = select( CORE_MODULES ).getRecoverableModules(); From d8efce3c6ca5850740482115c408b2839cc04327 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Thu, 1 Aug 2024 17:33:12 +0100 Subject: [PATCH 05/20] Add a reusable hook to compute gathering and zero data for modules. --- assets/js/hooks/useModuleGatheringZeroData.js | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 assets/js/hooks/useModuleGatheringZeroData.js diff --git a/assets/js/hooks/useModuleGatheringZeroData.js b/assets/js/hooks/useModuleGatheringZeroData.js new file mode 100644 index 00000000000..3f3cf831464 --- /dev/null +++ b/assets/js/hooks/useModuleGatheringZeroData.js @@ -0,0 +1,135 @@ +/** + * `useModuleGatheringZeroData` hook. + * + * Site Kit by Google, Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Internal dependencies + */ +import { useInViewSelect, useSelect } from 'googlesitekit-data'; +import { CORE_MODULES } from '../googlesitekit/modules/datastore/constants'; +import { CORE_USER } from '../googlesitekit/datastore/user/constants'; +import { MODULES_ANALYTICS_4 } from '../modules/analytics-4/datastore/constants'; +import { MODULES_SEARCH_CONSOLE } from '../modules/search-console/datastore/constants'; +import useViewOnly from './useViewOnly'; + +/** + * Determines if either Search Console or Analytics is in gathering or zero data states. + * + * @since n.e.x.t + * + * @return {Object} Individual boolean|undefined values for Gathering and Zero data states for both modules. + */ +export default function useModuleGatheringZeroData() { + const viewOnly = useViewOnly(); + + const isAnalyticsConnected = useSelect( ( select ) => + select( CORE_MODULES ).isModuleConnected( 'analytics-4' ) + ); + + const canViewSharedAnalytics = useSelect( ( select ) => { + if ( ! viewOnly ) { + return true; + } + + return select( CORE_USER ).canViewSharedModule( 'analytics-4' ); + } ); + const canViewSharedSearchConsole = useSelect( ( select ) => { + if ( ! viewOnly ) { + return true; + } + + return select( CORE_USER ).canViewSharedModule( 'search-console' ); + } ); + + const showRecoverableAnalytics = useSelect( ( select ) => { + if ( ! viewOnly ) { + return false; + } + + const recoverableModules = + select( CORE_MODULES ).getRecoverableModules(); + + if ( recoverableModules === undefined ) { + return undefined; + } + + return Object.keys( recoverableModules ).includes( 'analytics-4' ); + } ); + const showRecoverableSearchConsole = useSelect( ( select ) => { + if ( ! viewOnly ) { + return false; + } + + const recoverableModules = + select( CORE_MODULES ).getRecoverableModules(); + + if ( recoverableModules === undefined ) { + return undefined; + } + + return Object.keys( recoverableModules ).includes( 'search-console' ); + } ); + + const analyticsGatheringData = useInViewSelect( + ( select ) => + isAnalyticsConnected && + canViewSharedAnalytics && + false === showRecoverableAnalytics + ? select( MODULES_ANALYTICS_4 ).isGatheringData() + : false, + [ + isAnalyticsConnected, + canViewSharedAnalytics, + showRecoverableAnalytics, + ] + ); + const searchConsoleGatheringData = useInViewSelect( + ( select ) => + canViewSharedSearchConsole && + false === showRecoverableSearchConsole && + select( MODULES_SEARCH_CONSOLE ).isGatheringData(), + [ canViewSharedSearchConsole, showRecoverableSearchConsole ] + ); + + const analyticsHasZeroData = useInViewSelect( + ( select ) => + isAnalyticsConnected && + canViewSharedAnalytics && + false === showRecoverableAnalytics + ? select( MODULES_ANALYTICS_4 ).hasZeroData() + : false, + [ + isAnalyticsConnected, + canViewSharedAnalytics, + showRecoverableAnalytics, + ] + ); + const searchConsoleHasZeroData = useInViewSelect( + ( select ) => + canViewSharedSearchConsole && + false === showRecoverableSearchConsole && + select( MODULES_SEARCH_CONSOLE ).hasZeroData(), + [ canViewSharedSearchConsole, showRecoverableSearchConsole ] + ); + + return { + analyticsGatheringData, + searchConsoleGatheringData, + analyticsHasZeroData, + searchConsoleHasZeroData, + }; +} From b1eaf711b3d6b2a878a22e61e798ff2e2552f864 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Thu, 1 Aug 2024 17:34:40 +0100 Subject: [PATCH 06/20] Make gathering data notification component standalone & sufficient. --- .../GatheringDataNotification.js | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/assets/js/components/notifications/ZeroDataStateNotifications/GatheringDataNotification.js b/assets/js/components/notifications/ZeroDataStateNotifications/GatheringDataNotification.js index eb1ae700d90..b72417ca56f 100644 --- a/assets/js/components/notifications/ZeroDataStateNotifications/GatheringDataNotification.js +++ b/assets/js/components/notifications/ZeroDataStateNotifications/GatheringDataNotification.js @@ -16,11 +16,6 @@ * limitations under the License. */ -/** - * External dependencies - */ -import PropTypes from 'prop-types'; - /** * WordPress dependencies */ @@ -36,11 +31,9 @@ import GatheringDataIcon from '../../../../svg/graphics/zero-state-red.svg'; import { CORE_SITE } from '../../../googlesitekit/datastore/site/constants'; import { DAY_IN_SECONDS, trackEvent } from '../../../util'; import useViewContext from '../../../hooks/useViewContext'; +import useModuleGatheringZeroData from '../../../hooks/useModuleGatheringZeroData'; -export default function GatheringDataNotification( { - title, - gatheringDataWaitTimeInHours, -} ) { +export default function GatheringDataNotification() { const viewContext = useViewContext(); const eventCategory = `${ viewContext }_gathering-data-notification`; const handleOnView = useCallback( () => { @@ -57,6 +50,32 @@ export default function GatheringDataNotification( { select( CORE_SITE ).getAdminURL( 'googlesitekit-settings' ) ); + const { analyticsGatheringData, searchConsoleGatheringData } = + useModuleGatheringZeroData(); + + let gatheringDataTitle; + // Analytics requires up to 72 hours to gather data. + let gatheringDataWaitTimeInHours = 72; + if ( analyticsGatheringData && searchConsoleGatheringData ) { + gatheringDataTitle = __( + 'Search Console and Analytics are gathering data', + 'google-site-kit' + ); + } else if ( analyticsGatheringData ) { + gatheringDataTitle = __( + 'Analytics is gathering data', + 'google-site-kit' + ); + } else if ( searchConsoleGatheringData ) { + // If only Search Console is gathering data, show a lower wait + // time, since it only requires 48 hours. + gatheringDataWaitTimeInHours = 48; + gatheringDataTitle = __( + 'Search Console is gathering data', + 'google-site-kit' + ); + } + if ( ! gatheringDataWaitTimeInHours ) { return null; } @@ -64,7 +83,7 @@ export default function GatheringDataNotification( { return ( ); } - -GatheringDataNotification.propTypes = { - title: PropTypes.string, - gatheringDataWaitTimeInHours: PropTypes.number, -}; From af3f159c22d75bbcdf1245a9e46100d43e88e7e4 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Fri, 2 Aug 2024 15:28:11 +0100 Subject: [PATCH 07/20] Move the Gathering Data Notification as a standalone component. --- .../GatheringDataNotification.js | 12 ++++++------ .../ZeroDataStateNotifications/index.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) rename assets/js/components/notifications/{ZeroDataStateNotifications => }/GatheringDataNotification.js (89%) diff --git a/assets/js/components/notifications/ZeroDataStateNotifications/GatheringDataNotification.js b/assets/js/components/notifications/GatheringDataNotification.js similarity index 89% rename from assets/js/components/notifications/ZeroDataStateNotifications/GatheringDataNotification.js rename to assets/js/components/notifications/GatheringDataNotification.js index b72417ca56f..dd656e2741a 100644 --- a/assets/js/components/notifications/ZeroDataStateNotifications/GatheringDataNotification.js +++ b/assets/js/components/notifications/GatheringDataNotification.js @@ -26,12 +26,12 @@ import { useCallback } from '@wordpress/element'; * Internal dependencies */ import { useSelect } from 'googlesitekit-data'; -import BannerNotification from '../BannerNotification'; -import GatheringDataIcon from '../../../../svg/graphics/zero-state-red.svg'; -import { CORE_SITE } from '../../../googlesitekit/datastore/site/constants'; -import { DAY_IN_SECONDS, trackEvent } from '../../../util'; -import useViewContext from '../../../hooks/useViewContext'; -import useModuleGatheringZeroData from '../../../hooks/useModuleGatheringZeroData'; +import BannerNotification from './BannerNotification'; +import GatheringDataIcon from '../../../svg/graphics/zero-state-red.svg'; +import { CORE_SITE } from '../../googlesitekit/datastore/site/constants'; +import { DAY_IN_SECONDS, trackEvent } from '../../util'; +import useViewContext from '../../hooks/useViewContext'; +import useModuleGatheringZeroData from '../../hooks/useModuleGatheringZeroData'; export default function GatheringDataNotification() { const viewContext = useViewContext(); diff --git a/assets/js/components/notifications/ZeroDataStateNotifications/index.js b/assets/js/components/notifications/ZeroDataStateNotifications/index.js index ccf462b89f9..fde83faf998 100644 --- a/assets/js/components/notifications/ZeroDataStateNotifications/index.js +++ b/assets/js/components/notifications/ZeroDataStateNotifications/index.js @@ -30,7 +30,7 @@ import { CORE_MODULES } from '../../../googlesitekit/modules/datastore/constants import useViewOnly from '../../../hooks/useViewOnly'; import { MODULES_ANALYTICS_4 } from '../../../modules/analytics-4/datastore/constants'; import { MODULES_SEARCH_CONSOLE } from '../../../modules/search-console/datastore/constants'; -import GatheringDataNotification from './GatheringDataNotification'; +import GatheringDataNotification from '../GatheringDataNotification'; import ZeroDataNotification from './ZeroDataNotification'; export default function ZeroDataStateNotifications() { From b0f6e71b8964a2835b0af9dd6c26fa8f0a2d4255 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Sun, 4 Aug 2024 20:40:18 +0530 Subject: [PATCH 08/20] Register the new GatheringDataNotification standalone component. --- .../googlesitekit/notifications/register-defaults.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/assets/js/googlesitekit/notifications/register-defaults.js b/assets/js/googlesitekit/notifications/register-defaults.js index cd576286555..cecaba401fa 100644 --- a/assets/js/googlesitekit/notifications/register-defaults.js +++ b/assets/js/googlesitekit/notifications/register-defaults.js @@ -18,6 +18,8 @@ import { SITE_KIT_VIEW_ONLY_CONTEXTS, + VIEW_CONTEXT_ENTITY_DASHBOARD, + VIEW_CONTEXT_ENTITY_DASHBOARD_VIEW_ONLY, VIEW_CONTEXT_MAIN_DASHBOARD, VIEW_CONTEXT_MAIN_DASHBOARD_VIEW_ONLY, } from '../constants'; @@ -26,6 +28,7 @@ import { CORE_USER } from '../datastore/user/constants'; import { CORE_MODULES } from '../modules/datastore/constants'; import { MODULES_ANALYTICS_4 } from '../../modules/analytics-4/datastore/constants'; import { MODULES_SEARCH_CONSOLE } from '../../modules/search-console/datastore/constants'; +import GatheringDataNotification from '../../components/notifications/GatheringDataNotification'; /** * Registers notifications not specific to any one particular module. @@ -36,14 +39,14 @@ import { MODULES_SEARCH_CONSOLE } from '../../modules/search-console/datastore/c */ export function registerDefaults( notificationsAPI ) { notificationsAPI.registerNotification( 'gathering-data-notification', { - Component() { - return

TODO: Use a valid notification component here.

; - }, - priority: 100, + Component: GatheringDataNotification, + priority: 300, areaSlug: NOTIFICATION_AREAS.BANNERS_ABOVE_NAV, viewContexts: [ VIEW_CONTEXT_MAIN_DASHBOARD, VIEW_CONTEXT_MAIN_DASHBOARD_VIEW_ONLY, + VIEW_CONTEXT_ENTITY_DASHBOARD, + VIEW_CONTEXT_ENTITY_DASHBOARD_VIEW_ONLY, ], checkRequirements: ( { select }, viewContext ) => { const viewOnly = From cea797d995cd89c0d5bfaa84710326f789a281e4 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Sun, 4 Aug 2024 20:41:04 +0530 Subject: [PATCH 09/20] Make ZeroDataNotification standalone in its checks. --- .../ZeroDataStateNotifications/ZeroDataNotification.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/assets/js/components/notifications/ZeroDataStateNotifications/ZeroDataNotification.js b/assets/js/components/notifications/ZeroDataStateNotifications/ZeroDataNotification.js index afb2535f4c2..eb634f7221a 100644 --- a/assets/js/components/notifications/ZeroDataStateNotifications/ZeroDataNotification.js +++ b/assets/js/components/notifications/ZeroDataStateNotifications/ZeroDataNotification.js @@ -31,6 +31,7 @@ import BannerNotification from '../BannerNotification'; import ZeroStateIcon from '../../../../svg/graphics/zero-state-blue.svg'; import { DAY_IN_SECONDS, trackEvent } from '../../../util'; import useViewContext from '../../../hooks/useViewContext'; +import useModuleGatheringZeroData from '../../../hooks/useModuleGatheringZeroData'; export default function ZeroDataNotification() { const viewContext = useViewContext(); @@ -54,6 +55,13 @@ export default function ZeroDataNotification() { ); } ); + const { analyticsHasZeroData, searchConsoleHasZeroData } = + useModuleGatheringZeroData(); + + if ( ! analyticsHasZeroData && ! searchConsoleHasZeroData ) { + return null; + } + return ( Date: Sun, 4 Aug 2024 20:54:05 +0530 Subject: [PATCH 10/20] Add notifications component to render the first queued notification. --- .../components/notifications/Notifications.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 assets/js/components/notifications/Notifications.js diff --git a/assets/js/components/notifications/Notifications.js b/assets/js/components/notifications/Notifications.js new file mode 100644 index 00000000000..1087b9cb10b --- /dev/null +++ b/assets/js/components/notifications/Notifications.js @@ -0,0 +1,41 @@ +/** + * Notifications component. + * + * Site Kit by Google, Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Internal dependencies + */ +import Data from 'googlesitekit-data'; +import { CORE_NOTIFICATIONS } from '../../googlesitekit/notifications/datastore/constants'; +const { useSelect } = Data; + +export default function Notifications( { viewContext, areaSlug } ) { + const queuedNotifications = useSelect( ( select ) => + select( CORE_NOTIFICATIONS ).getQueuedNotifications( viewContext ) + ); + + if ( + queuedNotifications?.[ 0 ] === undefined || + queuedNotifications?.[ 0 ]?.areaSlug !== areaSlug + ) { + return null; + } + + const { Component: ActiveNotification } = queuedNotifications[ 0 ]; + + return ; +} From 9ccd86a528734490f02c5e3d872cddf01ae3d6e7 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Sun, 4 Aug 2024 20:54:49 +0530 Subject: [PATCH 11/20] Move the ZeroDataNotification as a standalone component. --- .../ZeroDataNotification.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) rename assets/js/components/notifications/{ZeroDataStateNotifications => }/ZeroDataNotification.js (85%) diff --git a/assets/js/components/notifications/ZeroDataStateNotifications/ZeroDataNotification.js b/assets/js/components/notifications/ZeroDataNotification.js similarity index 85% rename from assets/js/components/notifications/ZeroDataStateNotifications/ZeroDataNotification.js rename to assets/js/components/notifications/ZeroDataNotification.js index eb634f7221a..e6ee91403cb 100644 --- a/assets/js/components/notifications/ZeroDataStateNotifications/ZeroDataNotification.js +++ b/assets/js/components/notifications/ZeroDataNotification.js @@ -26,12 +26,12 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import { CORE_SITE } from '../../../googlesitekit/datastore/site/constants'; -import BannerNotification from '../BannerNotification'; -import ZeroStateIcon from '../../../../svg/graphics/zero-state-blue.svg'; -import { DAY_IN_SECONDS, trackEvent } from '../../../util'; -import useViewContext from '../../../hooks/useViewContext'; -import useModuleGatheringZeroData from '../../../hooks/useModuleGatheringZeroData'; +import { CORE_SITE } from '../../googlesitekit/datastore/site/constants'; +import BannerNotification from './BannerNotification'; +import ZeroStateIcon from '../../../svg/graphics/zero-state-blue.svg'; +import { DAY_IN_SECONDS, trackEvent } from '../../util'; +import useViewContext from '../../hooks/useViewContext'; +import useModuleGatheringZeroData from '../../hooks/useModuleGatheringZeroData'; export default function ZeroDataNotification() { const viewContext = useViewContext(); From 3149f6f54a27fe9979b5a662b2fa603737f7b7c7 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Mon, 5 Aug 2024 00:34:22 +0530 Subject: [PATCH 12/20] Fix checkRequirements to return bools/promises instead of functions. --- .../notifications/register-defaults.js | 44 ++++++------------- 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/assets/js/googlesitekit/notifications/register-defaults.js b/assets/js/googlesitekit/notifications/register-defaults.js index cecaba401fa..df864c3cedc 100644 --- a/assets/js/googlesitekit/notifications/register-defaults.js +++ b/assets/js/googlesitekit/notifications/register-defaults.js @@ -48,31 +48,22 @@ export function registerDefaults( notificationsAPI ) { VIEW_CONTEXT_ENTITY_DASHBOARD, VIEW_CONTEXT_ENTITY_DASHBOARD_VIEW_ONLY, ], - checkRequirements: ( { select }, viewContext ) => { + checkRequirements: ( { select, resolveSelect }, viewContext ) => { const viewOnly = SITE_KIT_VIEW_ONLY_CONTEXTS.includes( viewContext ); const isAnalyticsConnected = select( CORE_MODULES ).isModuleConnected( 'analytics-4' ); - const canViewSharedAnalytics = () => { - if ( ! viewOnly ) { - return true; - } - - return select( CORE_USER ).canViewSharedModule( 'analytics-4' ); - }; - const canViewSharedSearchConsole = () => { - if ( ! viewOnly ) { - return true; - } + const canViewSharedAnalytics = ! viewOnly + ? true + : select( CORE_USER ).canViewSharedModule( 'analytics-4' ); - return select( CORE_USER ).canViewSharedModule( - 'search-console' - ); - }; + const canViewSharedSearchConsole = ! viewOnly + ? true + : select( CORE_USER ).canViewSharedModule( 'search-console' ); - const showRecoverableAnalytics = () => { + const showRecoverableAnalytics = ( () => { if ( ! viewOnly ) { return false; } @@ -87,8 +78,8 @@ export function registerDefaults( notificationsAPI ) { return Object.keys( recoverableModules ).includes( 'analytics-4' ); - }; - const showRecoverableSearchConsole = () => { + } )(); + const showRecoverableSearchConsole = ( () => { if ( ! viewOnly ) { return false; } @@ -103,28 +94,21 @@ export function registerDefaults( notificationsAPI ) { return Object.keys( recoverableModules ).includes( 'search-console' ); - }; + } )(); const analyticsGatheringData = isAnalyticsConnected && canViewSharedAnalytics && false === showRecoverableAnalytics - ? select( MODULES_ANALYTICS_4 ).isGatheringData() + ? resolveSelect( MODULES_ANALYTICS_4 ).isGatheringData() : false; const searchConsoleGatheringData = canViewSharedSearchConsole && false === showRecoverableSearchConsole && - select( MODULES_SEARCH_CONSOLE ).isGatheringData(); - - if ( - analyticsGatheringData === undefined || - searchConsoleGatheringData === undefined - ) { - return false; - } + resolveSelect( MODULES_SEARCH_CONSOLE ).isGatheringData(); return analyticsGatheringData || searchConsoleGatheringData; }, - isDismissible: true, + isDismissible: false, } ); } From b303e6511aa66a4895966fb4cfc5f48694186419 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Mon, 5 Aug 2024 00:39:40 +0530 Subject: [PATCH 13/20] Fix priority of ZeroDataNotification. --- .../notifications/BannerNotifications.js | 26 ++++++++++++++++--- .../EntityBannerNotifications.js | 17 ++++++++++-- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/assets/js/components/notifications/BannerNotifications.js b/assets/js/components/notifications/BannerNotifications.js index 9844dbf7b82..11bd0fc7e7e 100644 --- a/assets/js/components/notifications/BannerNotifications.js +++ b/assets/js/components/notifications/BannerNotifications.js @@ -38,16 +38,20 @@ import ModuleRecoveryAlert from '../dashboard-sharing/ModuleRecoveryAlert'; import AdSenseAlerts from './AdSenseAlerts'; import EnhancedMeasurementActivationBanner from '../../modules/analytics-4/components/dashboard/EnhancedMeasurementActivationBanner'; import useViewOnly from '../../hooks/useViewOnly'; -import ZeroDataStateNotifications from './ZeroDataStateNotifications'; +import useViewContext from '../../hooks/useViewContext'; +import ZeroDataNotification from './ZeroDataNotification'; import EnableAutoUpdateBannerNotification from './EnableAutoUpdateBannerNotification'; import GoogleTagIDMismatchNotification from './GoogleTagIDMismatchNotification'; import WebDataStreamNotAvailableNotification from './WebDataStreamNotAvailableNotification'; import AdBlockingRecoverySetupSuccessBannerNotification from './AdBlockingRecoverySetupSuccessBannerNotification'; import { CORE_UI } from '../../googlesitekit/datastore/ui/constants'; import { UI_KEY_KEY_METRICS_SETUP_CTA_RENDERED } from '../KeyMetrics/KeyMetricsSetupCTARenderedEffect'; +import { NOTIFICATION_AREAS } from '../../googlesitekit/notifications/datastore/constants'; +import Notifications from './Notifications'; export default function BannerNotifications() { const viewOnly = useViewOnly(); + const viewContext = useViewContext(); const isAuthenticated = useSelect( ( select ) => select( CORE_USER ).isAuthenticated() @@ -90,7 +94,15 @@ export default function BannerNotifications() { const [ slug ] = useQueryArg( 'slug' ); if ( viewOnly ) { - return ; + return ( + + + + + ); } return ( @@ -117,7 +129,15 @@ export default function BannerNotifications() { ) } - + + { /* Temporary hack to give priority to the `GatheringDataNotification` component queued by `Notifications`. + This happens because `hasZeroData` selectors return true within `ZeroDataNotification` even if a module is + still gathering data. `ZeroDataNotification` should be refactored next which will make `Notifications` + the last component to be rendered. */ } + ); } diff --git a/assets/js/components/notifications/EntityBannerNotifications.js b/assets/js/components/notifications/EntityBannerNotifications.js index ebc075fd3a3..cf6776f207e 100644 --- a/assets/js/components/notifications/EntityBannerNotifications.js +++ b/assets/js/components/notifications/EntityBannerNotifications.js @@ -24,12 +24,25 @@ import { Fragment } from '@wordpress/element'; /** * Internal dependencies */ -import ZeroDataNotifications from './ZeroDataStateNotifications'; +import ZeroDataNotification from './ZeroDataNotification'; +import Notifications from './Notifications'; +import useViewContext from '../../hooks/useViewContext'; +import { NOTIFICATION_AREAS } from '../../googlesitekit/notifications/datastore/constants'; export default function EntityBannerNotifications() { + const viewContext = useViewContext(); + return ( - + + { /* Temporary hack to give priority to the `GatheringDataNotification` component queued by `Notifications`. + This happens because `hasZeroData` selectors return true within `ZeroDataNotification` even if a module is + still gathering data. `ZeroDataNotification` should be refactored next which will make `Notifications` + the last component to be rendered. */ } + ); } From 74b60a95768283ba1ef5bdd0efab48d849b61f83 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Mon, 5 Aug 2024 01:06:19 +0530 Subject: [PATCH 14/20] Add new story for GatheringDataNotification. --- .../GatheringDataNotification.stories.js | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 assets/js/components/notifications/GatheringDataNotification.stories.js diff --git a/assets/js/components/notifications/GatheringDataNotification.stories.js b/assets/js/components/notifications/GatheringDataNotification.stories.js new file mode 100644 index 00000000000..c81022cfdba --- /dev/null +++ b/assets/js/components/notifications/GatheringDataNotification.stories.js @@ -0,0 +1,101 @@ +/** + * GatheringDataNotification Component Stories. + * + * Site Kit by Google, Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Internal dependencies + */ +import { provideModules } from '../../../../tests/js/utils'; +import WithRegistrySetup from '../../../../tests/js/WithRegistrySetup'; +import { MODULES_ANALYTICS_4 } from '../../modules/analytics-4/datastore/constants'; +import { MODULES_SEARCH_CONSOLE } from '../../modules/search-console/datastore/constants'; +import GatheringDataNotification from './GatheringDataNotification'; + +function Template( { setupRegistry } ) { + return ( + + + + ); +} + +export const AnalyticsGatheringData = Template.bind( {} ); +AnalyticsGatheringData.storyName = 'Analytics Gathering Data'; +AnalyticsGatheringData.args = { + setupRegistry: ( registry ) => { + registry + .dispatch( MODULES_SEARCH_CONSOLE ) + .receiveIsGatheringData( false ); + registry.dispatch( MODULES_ANALYTICS_4 ).receiveIsGatheringData( true ); + }, +}; + +export const SearchConsoleGatheringData = Template.bind( {} ); +SearchConsoleGatheringData.storyName = 'Search Console Gathering Data'; +SearchConsoleGatheringData.args = { + setupRegistry: ( registry ) => { + registry + .dispatch( MODULES_SEARCH_CONSOLE ) + .receiveIsGatheringData( true ); + registry + .dispatch( MODULES_ANALYTICS_4 ) + .receiveIsGatheringData( false ); + }, +}; + +export const SearchConsoleAndAnalyticsGatheringData = Template.bind( {} ); +SearchConsoleAndAnalyticsGatheringData.storyName = + 'Search Console And Analytics Gathering Data'; +SearchConsoleAndAnalyticsGatheringData.args = { + setupRegistry: ( registry ) => { + registry + .dispatch( MODULES_SEARCH_CONSOLE ) + .receiveIsGatheringData( true ); + registry.dispatch( MODULES_ANALYTICS_4 ).receiveIsGatheringData( true ); + }, +}; + +export default { + title: 'Components/Notifications/GatheringDataNotification', + decorators: [ + ( Story, { args } ) => { + const setupRegistry = ( registry ) => { + provideModules( registry, [ + { + active: true, + connected: true, + slug: 'search-console', + }, + { + active: true, + connected: true, + slug: 'analytics-4', + }, + ] ); + + // Call story-specific setup. + args.setupRegistry( registry ); + }; + + return ( + + + + ); + }, + ], +}; From be62887953bc15c7e44fcb5bcc2c7b1189335ade Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Mon, 5 Aug 2024 01:18:34 +0530 Subject: [PATCH 15/20] Add new story for ZeroDataNotification. --- .../ZeroDataNotification.stories.js | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 assets/js/components/notifications/ZeroDataNotification.stories.js diff --git a/assets/js/components/notifications/ZeroDataNotification.stories.js b/assets/js/components/notifications/ZeroDataNotification.stories.js new file mode 100644 index 00000000000..1f2d2ba305c --- /dev/null +++ b/assets/js/components/notifications/ZeroDataNotification.stories.js @@ -0,0 +1,33 @@ +/** + * ZeroDataNotification Component Stories. + * + * Site Kit by Google, Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Internal dependencies + */ +import ZeroDataNotification from './ZeroDataNotification'; + +function Template( {} ) { + return ; +} + +export const Default = Template.bind( {} ); +Default.storyName = 'ZeroDataNotification'; + +export default { + title: 'Components/Notifications/ZeroDataNotification', +}; From fb4a6834338d4aec2d104df75d3771964e6842a2 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Mon, 5 Aug 2024 01:19:25 +0530 Subject: [PATCH 16/20] Remove ZeroDataNotifications combined component. --- .../ZeroDataStateNotifications/index.js | 182 ------------------ 1 file changed, 182 deletions(-) delete mode 100644 assets/js/components/notifications/ZeroDataStateNotifications/index.js diff --git a/assets/js/components/notifications/ZeroDataStateNotifications/index.js b/assets/js/components/notifications/ZeroDataStateNotifications/index.js deleted file mode 100644 index fde83faf998..00000000000 --- a/assets/js/components/notifications/ZeroDataStateNotifications/index.js +++ /dev/null @@ -1,182 +0,0 @@ -/** - * ZeroDataStateNotifications component. - * - * Site Kit by Google, Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; - -/** - * Internal dependencies - */ -import { useSelect, useInViewSelect } from 'googlesitekit-data'; -import { CORE_USER } from '../../../googlesitekit/datastore/user/constants'; -import { CORE_MODULES } from '../../../googlesitekit/modules/datastore/constants'; -import useViewOnly from '../../../hooks/useViewOnly'; -import { MODULES_ANALYTICS_4 } from '../../../modules/analytics-4/datastore/constants'; -import { MODULES_SEARCH_CONSOLE } from '../../../modules/search-console/datastore/constants'; -import GatheringDataNotification from '../GatheringDataNotification'; -import ZeroDataNotification from './ZeroDataNotification'; - -export default function ZeroDataStateNotifications() { - const viewOnly = useViewOnly(); - - const isAnalyticsConnected = useSelect( ( select ) => - select( CORE_MODULES ).isModuleConnected( 'analytics-4' ) - ); - const canViewSharedAnalytics = useSelect( ( select ) => { - if ( ! viewOnly ) { - return true; - } - - return select( CORE_USER ).canViewSharedModule( 'analytics-4' ); - } ); - const canViewSharedSearchConsole = useSelect( ( select ) => { - if ( ! viewOnly ) { - return true; - } - - return select( CORE_USER ).canViewSharedModule( 'search-console' ); - } ); - const showRecoverableAnalytics = useSelect( ( select ) => { - if ( ! viewOnly ) { - return false; - } - - const recoverableModules = - select( CORE_MODULES ).getRecoverableModules(); - - if ( recoverableModules === undefined ) { - return undefined; - } - - return Object.keys( recoverableModules ).includes( 'analytics-4' ); - } ); - const showRecoverableSearchConsole = useSelect( ( select ) => { - if ( ! viewOnly ) { - return false; - } - - const recoverableModules = - select( CORE_MODULES ).getRecoverableModules(); - - if ( recoverableModules === undefined ) { - return undefined; - } - - return Object.keys( recoverableModules ).includes( 'search-console' ); - } ); - - const analyticsGatheringData = useInViewSelect( - ( select ) => - isAnalyticsConnected && - canViewSharedAnalytics && - false === showRecoverableAnalytics - ? select( MODULES_ANALYTICS_4 ).isGatheringData() - : false, - [ - isAnalyticsConnected, - canViewSharedAnalytics, - showRecoverableAnalytics, - ] - ); - const searchConsoleGatheringData = useInViewSelect( - ( select ) => - canViewSharedSearchConsole && - false === showRecoverableSearchConsole && - select( MODULES_SEARCH_CONSOLE ).isGatheringData(), - [ canViewSharedSearchConsole, showRecoverableSearchConsole ] - ); - const analyticsHasZeroData = useInViewSelect( - ( select ) => - isAnalyticsConnected && - canViewSharedAnalytics && - false === showRecoverableAnalytics - ? select( MODULES_ANALYTICS_4 ).hasZeroData() - : false, - [ - isAnalyticsConnected, - canViewSharedAnalytics, - showRecoverableAnalytics, - ] - ); - const searchConsoleHasZeroData = useInViewSelect( - ( select ) => - canViewSharedSearchConsole && - false === showRecoverableSearchConsole && - select( MODULES_SEARCH_CONSOLE ).hasZeroData(), - [ canViewSharedSearchConsole, showRecoverableSearchConsole ] - ); - - // If any of the checks for gathering data or zero data states have - // not finished loading, we don't show any notifications. This - // prevents one notification from briefly showing while the other - // notification loads and then replaces the first one. - // See: https://github.com/google/site-kit-wp/issues/5008 - if ( - analyticsGatheringData === undefined || - searchConsoleGatheringData === undefined || - analyticsHasZeroData === undefined || - searchConsoleHasZeroData === undefined - ) { - return null; - } - - if ( - ! analyticsGatheringData && - ! searchConsoleGatheringData && - ! analyticsHasZeroData && - ! searchConsoleHasZeroData - ) { - return null; - } - - let gatheringDataTitle; - // Analytics requires up to 72 hours to gather data. - let gatheringDataWaitTimeInHours = 72; - if ( analyticsGatheringData && searchConsoleGatheringData ) { - gatheringDataTitle = __( - 'Search Console and Analytics are gathering data', - 'google-site-kit' - ); - } else if ( analyticsGatheringData ) { - gatheringDataTitle = __( - 'Analytics is gathering data', - 'google-site-kit' - ); - } else if ( searchConsoleGatheringData ) { - // If only Search Console is gathering data, show a lower wait - // time, since it only requires 48 hours. - gatheringDataWaitTimeInHours = 48; - gatheringDataTitle = __( - 'Search Console is gathering data', - 'google-site-kit' - ); - } - - if ( analyticsGatheringData || searchConsoleGatheringData ) { - return ( - - ); - } - - return ; -} From 664c986a937c1ad9a81fa98990813bdb8fdb1f90 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Mon, 5 Aug 2024 01:19:49 +0530 Subject: [PATCH 17/20] Remove old ZeroDataNotifications stories. --- .../index.stories.js | 229 ------------------ 1 file changed, 229 deletions(-) delete mode 100644 assets/js/components/notifications/ZeroDataStateNotifications/index.stories.js diff --git a/assets/js/components/notifications/ZeroDataStateNotifications/index.stories.js b/assets/js/components/notifications/ZeroDataStateNotifications/index.stories.js deleted file mode 100644 index f6d98f0c51e..00000000000 --- a/assets/js/components/notifications/ZeroDataStateNotifications/index.stories.js +++ /dev/null @@ -1,229 +0,0 @@ -/** - * ZeroDataStateNotifications Component Stories. - * - * Site Kit by Google, Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Internal dependencies - */ -import { - provideModules, - provideSiteInfo, - provideUserAuthentication, -} from '../../../../../tests/js/utils'; -import WithRegistrySetup from '../../../../../tests/js/WithRegistrySetup'; -import { CORE_USER } from '../../../googlesitekit/datastore/user/constants'; -import { MODULES_ANALYTICS_4 } from '../../../modules/analytics-4/datastore/constants'; -import { provideAnalytics4MockReport } from '../../../modules/analytics-4/utils/data-mock'; -import { MODULES_SEARCH_CONSOLE } from '../../../modules/search-console/datastore/constants'; -import { provideSearchConsoleMockReport } from '../../../modules/search-console/util/data-mock'; -import ZeroDataStateNotifications from './'; - -const searchConsoleArgs = { - startDate: '2021-08-18', - endDate: '2021-10-12', - dimensions: 'date', -}; - -const analyticsArgs = [ - { - startDate: '2020-12-31', - endDate: '2021-01-27', - compareStartDate: '2020-12-03', - compareEndDate: '2020-12-30', - metrics: [ - { - name: 'totalUsers', - }, - ], - dimensionFilters: { - sessionDefaultChannelGrouping: [ 'Organic Search' ], - }, - }, - { - startDate: '2020-12-31', - endDate: '2021-01-27', - compareStartDate: '2020-12-03', - compareEndDate: '2020-12-30', - dimensions: [ - { - name: 'date', - }, - ], - limit: 10, - metrics: [ - { - name: 'averageSessionDuration', - }, - ], - }, - { - startDate: '2020-12-31', - endDate: '2021-01-27', - compareStartDate: '2020-12-03', - compareEndDate: '2020-12-30', - metrics: [ { name: 'totalUsers' } ], - dimensions: [ 'date' ], - orderby: [ - { - dimension: { - dimensionName: 'date', - }, - }, - ], - }, - { - startDate: '2020-12-31', - endDate: '2021-01-27', - dimensions: [ 'pagePath' ], - metrics: [ - { - name: 'screenPageViews', - }, - ], - orderby: [ - { - metric: { - metricName: 'screenPageViews', - }, - desc: true, - }, - ], - limit: 5, - }, -]; - -function Template( { setupRegistry } ) { - return ( - - - - ); -} - -export const NoNotificationsAvailable = Template.bind( {} ); -NoNotificationsAvailable.storyName = 'No Notifications Available'; -NoNotificationsAvailable.args = { - setupRegistry: ( registry ) => { - provideSearchConsoleMockReport( registry, searchConsoleArgs ); - - for ( const options of analyticsArgs ) { - provideAnalytics4MockReport( registry, options ); - } - }, -}; - -export const AnalyticsGatheringData = Template.bind( {} ); -AnalyticsGatheringData.storyName = 'Analytics Gathering Data'; -AnalyticsGatheringData.args = { - setupRegistry: ( registry ) => { - provideSearchConsoleMockReport( registry, searchConsoleArgs ); - - registry.dispatch( MODULES_ANALYTICS_4 ).receiveIsGatheringData( true ); - }, -}; - -export const SearchConsoleGatheringData = Template.bind( {} ); -SearchConsoleGatheringData.storyName = 'Search Console Gathering Data'; -SearchConsoleGatheringData.args = { - setupRegistry: ( registry ) => { - registry.dispatch( CORE_USER ).setReferenceDate( '2021-01-28' ); - - registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetSettings( { - propertyCreateTime: 1662715085968, - } ); - - registry.dispatch( MODULES_SEARCH_CONSOLE ).receiveGetReport( [], { - options: searchConsoleArgs, - } ); - - for ( const options of analyticsArgs ) { - provideAnalytics4MockReport( registry, options ); - } - }, -}; - -export const SearchConsoleAndAnalyticsGatheringData = Template.bind( {} ); -SearchConsoleAndAnalyticsGatheringData.storyName = - 'Search Console And Analytics Gathering Data'; -SearchConsoleAndAnalyticsGatheringData.args = { - setupRegistry: ( registry ) => { - registry - .dispatch( MODULES_SEARCH_CONSOLE ) - .receiveGetReport( [], { options: searchConsoleArgs } ); - registry.dispatch( MODULES_ANALYTICS_4 ).receiveIsGatheringData( true ); - }, -}; - -export const ZeroDataState = Template.bind( {} ); -ZeroDataState.storyName = 'Zero Data State'; -ZeroDataState.args = { - setupRegistry: ( registry ) => { - registry.dispatch( MODULES_SEARCH_CONSOLE ).receiveGetReport( - [ - { - clicks: 0, - ctr: 0, - impressions: 0, - keys: [ '2021-08-18' ], - position: 0, - }, - ], - { - options: searchConsoleArgs, - } - ); - - registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetSettings( { - propertyCreateTime: 1662715085968, - } ); - }, -}; - -export default { - title: 'Components/ZeroDataStateNotifications', - decorators: [ - ( Story, { args } ) => { - const setupRegistry = ( registry ) => { - provideSiteInfo( registry ); - provideUserAuthentication( registry ); - registry.dispatch( CORE_USER ).setReferenceDate( '2021-10-13' ); - - provideModules( registry, [ - { - active: true, - connected: true, - slug: 'search-console', - }, - { - active: true, - connected: true, - slug: 'analytics-4', - }, - ] ); - - // Call story-specific setup. - args.setupRegistry( registry ); - }; - - return ( - - - - ); - }, - ], -}; From 39f349e57b99af5645516b640b28171a91ff7654 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Mon, 5 Aug 2024 01:50:56 +0530 Subject: [PATCH 18/20] Fix existing BannerNotifications tests. --- .../js/components/notifications/BannerNotifications.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/assets/js/components/notifications/BannerNotifications.test.js b/assets/js/components/notifications/BannerNotifications.test.js index 60415d1f677..86d5d1f8c7b 100644 --- a/assets/js/components/notifications/BannerNotifications.test.js +++ b/assets/js/components/notifications/BannerNotifications.test.js @@ -37,6 +37,7 @@ import { mockLocation } from '../../../../tests/js/mock-browser-utils'; import BannerNotifications from './BannerNotifications'; import Header from '../Header'; import { MODULES_ANALYTICS_4 } from '../../modules/analytics-4/datastore/constants'; +import { VIEW_CONTEXT_MAIN_DASHBOARD } from '../../googlesitekit/constants'; describe( 'BannerNotifications', () => { mockLocation(); @@ -94,6 +95,7 @@ describe( 'BannerNotifications', () => { registry.dispatch( CORE_USER ).receiveGetSurvey( { survey: null } ); registry.dispatch( CORE_SITE ).receiveGetNotifications( [] ); registry.dispatch( CORE_USER ).receiveNonces( [] ); + registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetSettings( [] ); registry .dispatch( MODULES_ANALYTICS_4 ) .receiveHasMismatchGoogleTagID( false ); @@ -107,6 +109,7 @@ describe( 'BannerNotifications', () => { , { registry, + viewContext: VIEW_CONTEXT_MAIN_DASHBOARD, } ); @@ -127,6 +130,7 @@ describe( 'BannerNotifications', () => { , { registry, + viewContext: VIEW_CONTEXT_MAIN_DASHBOARD, } ); @@ -157,6 +161,7 @@ describe( 'BannerNotifications', () => {
} />, { registry, + viewContext: VIEW_CONTEXT_MAIN_DASHBOARD, } ); @@ -193,6 +198,7 @@ describe( 'BannerNotifications', () => { , { registry, + viewContext: VIEW_CONTEXT_MAIN_DASHBOARD, } ); From f9251af320eaa4c8729531d03d02f1636ef13864 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Wed, 7 Aug 2024 02:40:30 +0530 Subject: [PATCH 19/20] Ensure the ZeroDataNotification does not render in gathering data state. --- .../notifications/ZeroDataNotification.js | 14 +++++++++++-- .../ZeroDataNotification.stories.js | 21 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/assets/js/components/notifications/ZeroDataNotification.js b/assets/js/components/notifications/ZeroDataNotification.js index d1acb68956c..355d02bd576 100644 --- a/assets/js/components/notifications/ZeroDataNotification.js +++ b/assets/js/components/notifications/ZeroDataNotification.js @@ -55,8 +55,18 @@ export default function ZeroDataNotification() { ); } ); - const { analyticsHasZeroData, searchConsoleHasZeroData } = - useModuleGatheringZeroData(); + const { + analyticsGatheringData, + searchConsoleGatheringData, + analyticsHasZeroData, + searchConsoleHasZeroData, + } = useModuleGatheringZeroData(); + + // Ensure this notification is only rendered if any module is not in the + // gathering data state which would trigger the now standalone GatheringDataNotification. + if ( analyticsGatheringData || searchConsoleGatheringData ) { + return null; + } if ( ! analyticsHasZeroData && ! searchConsoleHasZeroData ) { return null; diff --git a/assets/js/components/notifications/ZeroDataNotification.stories.js b/assets/js/components/notifications/ZeroDataNotification.stories.js index 1f2d2ba305c..9220032d15d 100644 --- a/assets/js/components/notifications/ZeroDataNotification.stories.js +++ b/assets/js/components/notifications/ZeroDataNotification.stories.js @@ -19,6 +19,9 @@ /** * Internal dependencies */ +import WithRegistrySetup from '../../../../tests/js/WithRegistrySetup'; +import { MODULES_ANALYTICS_4 } from '../../modules/analytics-4/datastore/constants'; +import { MODULES_SEARCH_CONSOLE } from '../../modules/search-console/datastore/constants'; import ZeroDataNotification from './ZeroDataNotification'; function Template( {} ) { @@ -30,4 +33,22 @@ Default.storyName = 'ZeroDataNotification'; export default { title: 'Components/Notifications/ZeroDataNotification', + decorators: [ + ( Story ) => { + const setupRegistry = ( registry ) => { + registry + .dispatch( MODULES_SEARCH_CONSOLE ) + .receiveIsGatheringData( false ); + registry + .dispatch( MODULES_ANALYTICS_4 ) + .receiveIsGatheringData( false ); + }; + + return ( + + + + ); + }, + ], }; From 00f3f12c7ce8381603bb4612747a3d13bbf1a808 Mon Sep 17 00:00:00 2001 From: Jimmy Madon Date: Wed, 7 Aug 2024 03:43:54 +0530 Subject: [PATCH 20/20] Fix tests that were returning false positives for ZeroDataNotification. --- .../notifications/BannerNotifications.test.js | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/assets/js/components/notifications/BannerNotifications.test.js b/assets/js/components/notifications/BannerNotifications.test.js index 86d5d1f8c7b..212d45eaf48 100644 --- a/assets/js/components/notifications/BannerNotifications.test.js +++ b/assets/js/components/notifications/BannerNotifications.test.js @@ -20,6 +20,7 @@ * Internal dependencies */ import { + act, createTestRegistry, muteFetch, provideModules, @@ -38,6 +39,10 @@ import BannerNotifications from './BannerNotifications'; import Header from '../Header'; import { MODULES_ANALYTICS_4 } from '../../modules/analytics-4/datastore/constants'; import { VIEW_CONTEXT_MAIN_DASHBOARD } from '../../googlesitekit/constants'; +import { + CORE_NOTIFICATIONS, + NOTIFICATION_AREAS, +} from '../../googlesitekit/notifications/datastore/constants'; describe( 'BannerNotifications', () => { mockLocation(); @@ -142,6 +147,23 @@ describe( 'BannerNotifications', () => { } ); it( 'prioritizes errors over alerts and regular notifications', async () => { + // Trigger the gathering data notification using the new registration process + act( () => { + registry + .dispatch( CORE_NOTIFICATIONS ) + .registerNotification( 'gathering-data-notification', { + Component() { + return ( +
+ Test notification! +
+ ); + }, + areaSlug: NOTIFICATION_AREAS.BANNERS_ABOVE_NAV, + viewContexts: [ VIEW_CONTEXT_MAIN_DASHBOARD ], + } ); + } ); + // Trigger the error notification. provideUserAuthentication( registry, { unsatisfiedScopes: [ @@ -183,6 +205,23 @@ describe( 'BannerNotifications', () => { } ); it( 'prioritizes alerts over regular notifications', async () => { + // Trigger the gathering data notification using the new registration process + act( () => { + registry + .dispatch( CORE_NOTIFICATIONS ) + .registerNotification( 'gathering-data-notification', { + Component() { + return ( +
+ Test notification! +
+ ); + }, + areaSlug: NOTIFICATION_AREAS.BANNERS_ABOVE_NAV, + viewContexts: [ VIEW_CONTEXT_MAIN_DASHBOARD ], + } ); + } ); + // Ensure setup completed notification is added. global.location.href = 'http://example.com/wp-admin/admin.php?notification=authentication_success';