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

Request scope only if it's needed #9840

Merged
merged 27 commits into from
Feb 21, 2025

Conversation

nfmohit
Copy link
Collaborator

@nfmohit nfmohit commented Dec 8, 2024

Summary

Addresses issue:

Relevant technical choices

[Updated by @techanvil] This PR required a substantial deviation from the IB, because the IB assumes that we'll always want to create the new/returning audiences if they don't exist, whereas in fact we need to first check to see if the selection can be populated from the existing audiences (including user defined and defaults) and only if we don't have an initial selection will we want to create the new/returning audiences.

PR Author Checklist

  • My code is tested and passes existing unit tests.
  • My code has an appropriate set of unit tests which all pass.
  • My code is backward-compatible with WordPress 5.2 and PHP 7.4.
  • My code follows the WordPress coding standards.
  • My code has proper inline documentation.
  • I have added a QA Brief on the issue linked above.
  • I have signed the Contributor License Agreement (see https://cla.developers.google.com/).

Do not alter or remove anything below. The following sections will be managed by moderators only.

Code Reviewer Checklist

  • Run the code.
  • Ensure the acceptance criteria are satisfied.
  • Reassess the implementation with the IB.
  • Ensure no unrelated changes are included.
  • Ensure CI checks pass.
  • Check Storybook where applicable.
  • Ensure there is a QA Brief.
  • Ensure there are no unexpected significant changes to file sizes.

Merge Reviewer Checklist

  • Ensure the PR has the correct target branch.
  • Double-check that the PR is okay to be merged.
  • Ensure the corresponding issue has a ZenHub release assigned.
  • Add a changelog message to the issue.

Copy link

github-actions bot commented Dec 8, 2024

Build files for 9a03b2a have been deleted.

Copy link

github-actions bot commented Dec 8, 2024

Size Change: +1.3 kB (+0.06%)

Total Size: 2.03 MB

Filename Size Change
./dist/assets/js/googlesitekit-main-dashboard-********************.js 165 kB +314 B (+0.19%)
./dist/assets/js/googlesitekit-modules-analytics-4-********************.js 193 kB +401 B (+0.21%)
./dist/assets/js/googlesitekit-settings-********************.js 129 kB +291 B (+0.23%)
./dist/assets/js/googlesitekit-widgets-********************.js 105 kB +292 B (+0.28%)
ℹ️ View Unchanged
Filename Size
./dist/assets/css/googlesitekit-admin-css-********************.min.css 63 kB
./dist/assets/css/googlesitekit-adminbar-css-********************.min.css 11.8 kB
./dist/assets/css/googlesitekit-authorize-application-css-********************.min.css 846 B
./dist/assets/css/googlesitekit-wp-dashboard-css-********************.min.css 8.48 kB
./dist/assets/js/33-********************.js 2.76 kB
./dist/assets/js/34-********************.js 2.25 kB
./dist/assets/js/35-********************.js 3.64 kB
./dist/assets/js/36-********************.js 935 B
./dist/assets/js/37-********************.js 892 B
./dist/assets/js/38-********************.js 1.61 kB
./dist/assets/js/39-********************.js 1.57 kB
./dist/assets/js/40-********************.js 1.61 kB
./dist/assets/js/41-********************.js 1.59 kB
./dist/assets/js/42-********************.js 1.83 kB
./dist/assets/js/43-********************.js 3.12 kB
./dist/assets/js/analytics-advanced-tracking-********************.js 901 B
./dist/assets/js/blocks/googlesitekit-reader-revenue-manager-block-editor.js 478 B
./dist/assets/js/blocks/sign-in-with-google/editor-styles.css 75 B
./dist/assets/js/blocks/sign-in-with-google/editor-styles.js 490 B
./dist/assets/js/blocks/sign-in-with-google/index.js 18 kB
./dist/assets/js/googlesitekit-activation-********************.js 23.8 kB
./dist/assets/js/googlesitekit-ad-blocking-recovery-********************.js 54.4 kB
./dist/assets/js/googlesitekit-adminbar-********************.js 34.9 kB
./dist/assets/js/googlesitekit-api-********************.js 10.1 kB
./dist/assets/js/googlesitekit-components-gm2-********************.js 6.46 kB
./dist/assets/js/googlesitekit-components-gm3-********************.js 10.1 kB
./dist/assets/js/googlesitekit-consent-mode-********************.js 25.6 kB
./dist/assets/js/googlesitekit-data-********************.js 2.37 kB
./dist/assets/js/googlesitekit-datastore-forms-********************.js 8.96 kB
./dist/assets/js/googlesitekit-datastore-location-********************.js 2.08 kB
./dist/assets/js/googlesitekit-datastore-site-********************.js 20.5 kB
./dist/assets/js/googlesitekit-datastore-ui-********************.js 10 kB
./dist/assets/js/googlesitekit-datastore-user-********************.js 28.4 kB
./dist/assets/js/googlesitekit-entity-dashboard-********************.js 84.9 kB
./dist/assets/js/googlesitekit-events-provider-contact-form-7-********************.js 646 B
./dist/assets/js/googlesitekit-events-provider-easy-digital-downloads-********************.js 624 B
./dist/assets/js/googlesitekit-events-provider-mailchimp-********************.js 630 B
./dist/assets/js/googlesitekit-events-provider-ninja-forms-********************.js 712 B
./dist/assets/js/googlesitekit-events-provider-optin-monster-********************.js 675 B
./dist/assets/js/googlesitekit-events-provider-popup-maker-********************.js 634 B
./dist/assets/js/googlesitekit-events-provider-woocommerce-********************.js 657 B
./dist/assets/js/googlesitekit-events-provider-wpforms-********************.js 633 B
./dist/assets/js/googlesitekit-i18n-********************.js 3.93 kB
./dist/assets/js/googlesitekit-metric-selection-********************.js 52.2 kB
./dist/assets/js/googlesitekit-modules-********************.js 22.4 kB
./dist/assets/js/googlesitekit-modules-ads-********************.js 36.4 kB
./dist/assets/js/googlesitekit-modules-adsense-********************.js 117 kB
./dist/assets/js/googlesitekit-modules-pagespeed-insights-********************.js 22.8 kB
./dist/assets/js/googlesitekit-modules-reader-revenue-manager-********************.js 44.7 kB
./dist/assets/js/googlesitekit-modules-search-console-********************.js 69.5 kB
./dist/assets/js/googlesitekit-modules-sign-in-with-google-********************.js 32.7 kB
./dist/assets/js/googlesitekit-modules-tagmanager-********************.js 32.3 kB
./dist/assets/js/googlesitekit-notifications-********************.js 43.6 kB
./dist/assets/js/googlesitekit-polyfills-********************.js 378 B
./dist/assets/js/googlesitekit-splash-********************.js 69 kB
./dist/assets/js/googlesitekit-user-input-********************.js 44 kB
./dist/assets/js/googlesitekit-vendor-********************.js 325 kB
./dist/assets/js/googlesitekit-wp-dashboard-********************.js 63.3 kB
./dist/assets/js/runtime-********************.js 1.4 kB

compressed-size-action

Copy link
Collaborator

@aaemnnosttv aaemnnosttv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @techanvil – I have a few questions and minor feedback to address.

The main question I have is: how much simpler would this be if we let the scope be requested in response to the request made which requires it rather than attempting to determine if it's needed beforehand?

Comment on lines +108 to +111
invalidateResolution( 'getQueuedNotifications', [
viewContext,
NOTIFICATION_GROUPS.DEFAULT,
] );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why invalidate the default queue? I'd expect this should invalidate the setup CTA resolution, but I'm not entirely sure why it would invalidate this for either.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this was introduced as part of the banner notification refactor as a way to show the CTA immediately. We do have an issue in IB to address this in a more elegant way: #9453

Copy link
Collaborator

@aaemnnosttv aaemnnosttv Feb 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes; what I mean is that this invalidates the default group, but the CTA is registered with other setup CTAs in their respective group:

[ AUDIENCE_SEGMENTATION_SETUP_CTA_NOTIFICATION ]: {
Component: AudienceSegmentationSetupCTAWidget,
priority: 10,
areaSlug: NOTIFICATION_AREAS.BANNERS_BELOW_NAV,
groupID: NOTIFICATION_GROUPS.SETUP_CTAS,

Edit: actually, this is about showing the setup success banner right away – which is in the default group – so that makes sense. I missed that detail in your response initially 👍

return { error: syncError };
}
const availableAudiences =
select( MODULES_ANALYTICS_4 ).getAvailableAudiences();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this not be resolve-selected instead?

Copy link
Collaborator

@techanvil techanvil Feb 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's just a module setting and it'll be set and resolved by the time we get here as we're always syncing the audiences beforehand (the sync is moved to maybeEnableAudienceGroup() but the current order of events with regard to the sync is retained).

*/
*enableAudienceGroupMain( failedSiteKitAudienceSlugs ) {
*getSelectionFromExistingAudiences() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid introducing actions that start with get* (other than resolvers). Maybe determine would be a better verb in this case? I'm open to other ideas.

Looking at the description, I'd also prefer to avoid retrieve* actions (I see we already have one) as it's easy to confuse with the common receive* convention we have.

Finally, it seems a bit unintuitive that this gets "selected audiences" but returns "configured audiences". I'd simplify it to just "audiences".

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid introducing actions that start with get* (other than resolvers). Maybe determine would be a better verb in this case? I'm open to other ideas.

Looking at the description, I'd also prefer to avoid retrieve* actions (I see we already have one) as it's easy to confuse with the common receive* convention we have.

Fair point on get* and retrieve* actions. Actually, taking another look at these, I've realised that they shouldn't really be actions - they can simply be helper functions. They were only introduced when refactoring the actions that call them, and were added as more actions but this was unnecessary; there's no intention for them to be used as actions in the wider codebase. They are returning values so the get* prefix is appropriate when they are helper functions. I've refactored actions to helpers accordingly.

Finally, it seems a bit unintuitive that this gets "selected audiences" but returns "configured audiences". I'd simplify it to just "audiences".

I take your point on the selected/configured audiences ambiguity, but just stripping it to "audiences" removes the specificity. I've changed it to use the term "configured audiences", please see what you think.

*
* @return {Object} Object with `needsScope` or `error`.
*/
*needsAnalytics4EditScope() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also has a name closer to what I'd expect to be a selector. Actions should be named using verbs.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I've renamed it to determineNeedForAnalytics4EditScope(). Happy to change it to something else if you have a better suggestion!

Comment on lines +104 to +106
setValues( AUDIENCE_SEGMENTATION_SETUP_FORM, {
autoSubmit: false,
} );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this to be set as soon as the autosubmit is invoked from the effect? This is how we do it in many other places and avoids potentially duplicate invocations in some cases.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm hesitant to do this, as it will be changing the current logic which has otherwise been retained despite the refactor.

It's worth noting that the autoSubmit value is used in a number of conditions that relate to showing the Setup CTA banner and the OAuth error modal. It's also set back to false in a number of places. Changing the timing of resetting autoSubmit could easily introduce a bug that would be hard to spot.

I'd rather not risk introducing a bug here and would prefer to leave this as it is. If we do want to revisit the autoSubmit logic, I think this would be best tackled in another issue. Please let me know if you'd like me to create one.

Usage, for reference:

Set to true:

const onEnableGroups = useCallback( async () => {
setIsSaving( true );
const { error, needsScope, failedSiteKitAudienceSlugs } =
await maybeEnableAudienceGroup();
if ( needsScope ) {
setValues( AUDIENCE_SEGMENTATION_SETUP_FORM, {
autoSubmit: true,
} );

Use in a condition:

if ( hasAnalytics4EditScope && autoSubmit ) {
onEnableGroups();
}

const hasOAuthError = autoSubmit && setupErrorCode === 'access_denied';

if ( hideCTABanner && ! hasOAuthError && ! showErrorModal ) {
return null;
}

{ ( showErrorModal || hasOAuthError ) && (
<AudienceErrorModal
hasOAuthError={ hasOAuthError }
apiErrors={ apiErrors.length ? apiErrors : failedAudiences }
onRetry={ onEnableGroups }
inProgress={ isSaving }
onCancel={
hasOAuthError
? onCancel
: () => setShowErrorModal( false )
}
trackEventCategory={ `${ viewContext }_audiences-setup` }
/>
) }

const hasOAuthError = autoSubmit && setupErrorCode === 'access_denied';

{ ( showErrorModal || hasOAuthError ) && (
<AudienceErrorModal
hasOAuthError={ hasOAuthError }
apiErrors={ apiErrors.length ? apiErrors : failedAudiences }
onRetry={ onEnableGroups }
inProgress={ isSaving }
onCancel={
hasOAuthError
? onCancel
: () => setShowErrorModal( false )
}
/>
) }

Set to false:

setValues( AUDIENCE_SEGMENTATION_SETUP_FORM, {
autoSubmit: false,
} );

const onCancel = useCallback( () => {
setValues( AUDIENCE_SEGMENTATION_SETUP_FORM, {
autoSubmit: false,
} );

const onCancel = () => {
setValues( AUDIENCE_SEGMENTATION_SETUP_FORM, {
autoSubmit: false,
} );

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the comprehensive response. We can leave it for now, but I think it's worth revisiting to apply consistently and in a way where it isn't possible to auto-submit consecutively more than once (a bug we've had before elsewhere). IMO, it should be disabled in the effect before it invokes the submit action, e.g.

if ( hasAnalytics4EditScope && autoSubmit ) {
onEnableGroups();
}

Perhaps we should encapsulate this behavior with some kind of core infra to avoid re-implementing it a little differently in each scenario.

Comment on lines +125 to +126
const { error, needsScope, failedSiteKitAudienceSlugs } =
await maybeEnableAudienceGroup();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if this error is a permission scope error? It seems like we may be making a significant effort to avoid letting this happen naturally.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like, as things stand, we'd try to show two modals: the Audience Segmentation generic error modal, and the Additional Permissions Required modal.

As I've mentioned in my other comment, we have gone to a significant effort to avoid the default behaviour, but this was by design from the outset. It's also worth noting that much of the error handling is there to support the AS error modals, so it's not the case that it's all there to accommodate the suppression of the Additional Permissions Required modal.

@techanvil
Copy link
Collaborator

Hey @aaemnnosttv! Thanks for the feedback on this one. To address this question:

The main question I have is: how much simpler would this be if we let the scope be requested in response to the request made which requires it rather than attempting to determine if it's needed beforehand?

The problem with taking the suggested approach would be that it would be at odds with the agreed UX design. We made a clear decision not to show the Additional Permissions Required modal, and instead to simply require the edit scope by default when actioning the setup CTA.

This is complimentary to the design where we have the new error modal displayed for a OAuth error, as well as for permission errors that may still occur in an edge case, and the catch all / generic error modal.

If we simply let the missing scope be determined by the request being made, AFAIK the only way to automatically handle this is to let the Additional Permissions Required modal be shown. We could do this but it would certainly be reversing a decision that's been made and so we should check in with Mariya and/or Sigal before considering this option.

I actually think that showing the Additional Permissions Required modal as well as potentially showing the error modal would not be a great UX, and could itself introduce a bit of additional complexity. We'd need to refactor the current logic, taking care to cover all the various happy and unhappy paths, and making sure it all works with the automatic missing scope handling and the existing modal error handling. This might not be so simple, as we'd want to ensure the Additional Permissions Required wouldn't show up at the same time as another error modal. We could end up with something simpler at the end of it, but it's definitely going to add a lot of additional complexity to get us to that point from where we are now. Plus, we'd be showing the extra modal so our simpler code would be at the expense of a more complicated UX which is what we wanted to avoid from the outset.

My opinion is that we should not go down this path, what we've got works according to the design and might not actually be much more complicated than it would be if we did allow the scope to be requested in response to a given request.

@aaemnnosttv
Copy link
Collaborator

Hey @techanvil - a quick response to your thoughts here and then we should be able to wrap this one up :)

The problem with taking the suggested approach would be that it would be at odds with the agreed UX design. We made a clear decision not to show the Additional Permissions Required modal, and instead to simply require the edit scope by default when actioning the setup CTA.
If we simply let the missing scope be determined by the request being made, AFAIK the only way to automatically handle this is to let the Additional Permissions Required modal be shown. We could do this but it would certainly be reversing a decision that's been made and so we should check in with Mariya and/or Sigal before considering this option.
I actually think that showing the Additional Permissions Required modal as well as potentially showing the error modal would not be a great UX, and could itself introduce a bit of additional complexity.

Yeah, I understand it was an intentional decision, and I'm not suggesting we change that. I didn't mean to say that we'd necessarily show the permissions modal, but let the error response handle the need on demand, at which point I think we could follow the connectURL it contains automatically without showing the modal (although I realize that is triggered automatically). It just seems like there is a lot happening to foresee this need where I think we may be able to handle it a bit more elegantly.

We can discuss this more outside of this issue, as it is out of scope here anyways.

Copy link
Collaborator

@aaemnnosttv aaemnnosttv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @techanvil – LGTM!

@aaemnnosttv aaemnnosttv merged commit 76e630c into develop Feb 21, 2025
28 of 31 checks passed
@aaemnnosttv aaemnnosttv deleted the enhancement/#9595-groups-edit-scope branch February 21, 2025 16:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants