Implement `background-toggle` setup for Enhanced measurement
- Dominant language
- JavaScript
- Stars
- 1.4k
- Forks
- 383
- Avg merge
- 4d 14h
- Merged PRs (30d)
- 77
Description
## Feature Description
Not every feature in the hub is a service to connect. Some are a switch on a service the user has already connected: there's nothing to configure and nowhere to send them, so the right experience is that the feature is simply turned on where they clicked, on the hub. Enhanced measurement is the simplest of these — a single Analytics setting.
There's one complication. Site Kit's connection to Analytics may be read-only, in which case changing that setting needs the user's permission from Google first. That means a trip out to Google's permission screen and back, and when they land back on the hub the switch should be thrown for them — having already said yes twice, they shouldn't have to click the call to action a third time.
This issue establishes that handling — enabling in place, the permission trip and the resumption on return, and reporting a failed save — and uses it to drive Enhanced measurement. Visitor groups is enabled in place too, but it's a small setup rather than one setting and brings its own UI for it, so it builds on this handling in #13344.
For reference, see the [`background-toggle` — enable in place](https://docs.google.com/document/d/1sLWcimi6eZqbK4YXVCZtO0ZrfrDV7Ub218Hu_vpwmyI/edit?tab=t.0#heading=h.q8l6vebw4hp9) and [Returning to the hub](https://docs.google.com/document/d/1sLWcimi6eZqbK4YXVCZtO0ZrfrDV7Ub218Hu_vpwmyI/edit?tab=t.0#heading=h.yl5go7548bwn) sections in the design doc.
---------------
_Do not alter or remove anything below. The following sections will be managed by moderators only._
## Acceptance criteria
- Enhanced measurement is turned on from its card's CTA (#13322) without the user leaving the hub. The CTA shows its in-progress state while the change is saved.
- Where Site Kit doesn't have permission to change the Analytics property's settings, clicking the CTA takes the user to Google's permission screen. Granting permission returns them to the hub, on the tab they started from (#13338), where enabling continues on its own — they don't have to click the CTA again.
- If the permission isn't granted, Enhanced measurement isn't enabled and its card is left as it was.
- If the setting can't be saved, the failure is reported in the feature's place in the list as *"Enhanced measurement setup failed"* (#13339), and its **Retry** attempts the save again.
- Enhanced measurement is turned on from the detail panel's CTA (#13330) exactly as from the card: the panel closes and everything above happens in the list behind it.
- Enhanced measurement counts as set up once it's on for the site's Analytics stream, so from that point the hub stops listing the feature.
- The confirmation the user sees when a feature is enabled in place is covered by #13346.
- Site Kit's existing ways of enabling enhanced measurement — in the Analytics setup flow and from the dashboard — are unchanged, as is the setting itself.
## Implementation Brief
- [ ] In `assets/js/googlesitekit/datastore/feature-discovery/types.ts`:
- Update `FeatureSetup.activate`'s signature to `( registry: WPDataRegistry ) => Promise< { error?: WPError } >`.
- [ ] In `assets/js/googlesitekit/datastore/feature-discovery/features.ts`:
- Extend the `setupFeature( slug )` generator (added in #13322, given its `setup-flow` handling in #13338) with a branch for `feature.setup.type === FEATURE_SETUP_TYPES.BACKGROUND_TOGGLE`: `yield commonActions.await( feature.setup.activate( registry ) )`, returning `{ error }` when the routine reports one, otherwise `{}`.
- [ ] In `assets/js/modules/analytics-4/features/index.ts` (registered in #13247 `enhanced-measurement` entry — its copy, `prerequisiteModules: [ MODULE_SLUG_ANALYTICS_4 ]`, and `ctaLabel` already live there):
- Add `setup.isEnabled`, resolving `propertyID`/`webDataStreamID` from `MODULES_ANALYTICS_4`'s saved settings and returning `select( MODULES_ANALYTICS_4 ).isEnhancedMeasurementStreamEnabled( propertyID, webDataStreamID )`. Return `undefined` while either ID or the setting is still loading, matching `isFeatureConnected()`'s existing loading contract — don't resolve to `false` prematurely.
- Add `setup.activate`, an async function taking the registry.
- Read `hasScope( EDIT_SCOPE )` via `select( CORE_USER )`.
- Where the scope is missing: call `setPendingSetup( 'enhanced-measurement', getCurrentFeatureDiscoveryTab() )` (`@/js/googlesitekit/feature-discovery/pending-setup`, #13338) so the hub tab survives the round trip, set `FORM_SETUP`'s `autoSubmit` value via `CORE_FORMS` (as `EnhancedMeasurementActivationBanner` already does for the dashboard banner), then `dispatch( CORE_USER ).setPermissionScopeError( { code: ERROR_CODE_MISSING_REQUIRED_SCOPE, message: …, data: { status: 403, scopes: [ EDIT_SCOPE ], skipModal: true, redirectURL: global.location.href } } )` and return `{}`
- Where the scope is present: `dispatch( MODULES_ANALYTICS_4 ).setEnhancedMeasurementStreamEnabled( { propertyID, webDataStreamID, enabled: true } )`, then `dispatch( MODULES_ANALYTICS_4 ).updateEnhancedMeasurementSettings( propertyID, webDataStreamID )`; return `{ error }` on failure, else `{}`.
- `redirectURL` is simply the hub's current URL (as the dashboard banner uses `global.location.href`).
- [ ] In `assets/js/components/feature-discovery/FeatureCTA.tsx` (added in #13322):
- On mount, where `feature.setup.type === FEATURE_SETUP_TYPES.BACKGROUND_TOGGLE`, read the pending-setup record the hub already consumed and held for the session on load (#13338's `consumePendingSetup()`, called once at the hub shell's mount). Where its `featureSlug` matches this card's `slug`, set `isBusy` and re-dispatch `setupFeature( slug )` automatically.
- On a `setupFeature( slug )` call resolving with `{ error }`, hold it in local state and surface it via the shared `FeatureSetupErrorNotice` (#13339) in the card's slot; its Retry re-dispatches `setupFeature( slug )` the same way, and dismissing it clears the local error and restores the card.
- No separate handling is needed for the in-place success state: once `activate()` succeeds, `isEnabled` (above) flips and `isFeatureConnected( 'enhanced-measurement' )` becomes `true`, so `getAvailableFeatures()` drops the feature and the confirmation itself is `#13346`'s `FeatureSuccessNotice`, reacting to that same flip.
### Test Coverage
- Add unit test coverage for the `setupFeature()` `BACKGROUND_TOGGLE` branch in `features.test.ts`: it calls `activate()` and surfaces `{ error }` correctly, without referencing any specific feature.
- Add unit test coverage for the `enhanced-measurement` catalog entry's `isEnabled` and `activate`, covering: scope present (save success and save failure), scope missing (permission error dispatched, `autoSubmit` and pending-setup written, hub URL used as `redirectURL`), and `isEnabled`'s loading/connected/not-connected states.
- Extend `FeatureCTA` test coverage for the `background-toggle` type: busy state while `activate()` runs, the automatic resume when a matching pending-setup record is held on mount, and the error notice + retry path.
- Fix any failing tests.
## QA Brief
-
## Changelog entry
-
Contributor guide
Research direction
Start with the setupFeature branch in assets/js/googlesitekit/datastore/feature-discovery/features.ts and its tests in features.test.ts, then read the enhanced-measurement entry in assets/js/modules/analytics-4/features/index.ts. Review FeatureCTA.tsx and its tests for pending-setup resume and error handling. Done means the listed activation, permission-return, failure, retry, and loading-state tests pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, typescript, wordpress
- Domain
- authentication, frontend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100