/
githubmirror
/
wp-calypso
Обзор
Документация
Войти
/
githubmirror
/
wp-calypso
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
trunk
client/sites/controller.tsx
229 строк
7 KB
Steven Dufresne
Track admin-bar redirects to the hosting dashboard with a bumpStat counter (#112685)
20 июл 2026, 12:12
Не верифицирован
20 июл 2026, 12:12
9840c97
Код
Авторство
О чём код?
import page from '@automattic/calypso-router'; import { siteLaunchStatusGroupValues } from '@automattic/sites'; import { Global, css } from '@emotion/react'; import { removeQueryArgs } from '@wordpress/url'; import i18n from 'i18n-calypso'; import AsyncLoad from 'calypso/components/async-load'; import ResurrectedWelcomeModalGate from 'calypso/components/resurrected-welcome-modal'; import { dashboardLink } from 'calypso/dashboard/utils/link'; import { bumpStat } from 'calypso/lib/analytics/mc'; import PageViewTracker from 'calypso/lib/analytics/page-view-tracker'; import { hasDashboardOptIn } from 'calypso/state/dashboard/selectors'; import { removeNotice, successNotice } from 'calypso/state/notices/actions'; import { fetchPreferences } from 'calypso/state/preferences/actions'; import { hasReceivedRemotePreferences } from 'calypso/state/preferences/selectors'; import { setAllSitesSelected } from 'calypso/state/ui/actions'; import { getSelectedSite } from 'calypso/state/ui/selectors'; import SitesDashboard from './components/sites-dashboard'; import { areHostingFeaturesSupported } from './hosting/features'; import type { Context, Context as PageJSContext } from '@automattic/calypso-router'; import type { CalypsoDispatch, IAppState } from 'calypso/state/types'; const loadTrackResurrections = () => import( /* webpackChunkName: "async-load-calypso-lib-analytics-track-resurrections" */ 'calypso/lib/analytics/track-resurrections' ); const getStatusFilterValue = ( status?: string ) => { return siteLaunchStatusGroupValues.find( ( value ) => value === status ); }; function getQueryParams( context: Context ) { return { page: context.query.page ? parseInt( context.query.page ) : undefined, perPage: context.query[ 'per-page' ] ? parseInt( context.query[ 'per-page' ] ) : undefined, search: context.query.search, status: context.query.status, siteType: context.query.siteType, }; } export function sanitizeQueryParameters( context: PageJSContext, next: () => void ) { if ( context.pathname.startsWith( '/p2s' ) ) { context.query.siteType = 'p2'; } /** * We need a base case because `page.replace` triggers a re-render for every middleware * in the route. */ if ( context.query.status === undefined ) { return next(); } const status = context.query.status.trim(); if ( status === '' ) { context.page.replace( removeQueryArgs( context.canonicalPath, 'status' ) ); return; } const chosenStatus = getStatusFilterValue( status ); if ( ! chosenStatus ) { context.page.replace( removeQueryArgs( context.canonicalPath, 'status' ) ); return; } context.query.status = chosenStatus; next(); } export function sitesDashboard( context: Context, next: () => void ) { const sitesDashboardGlobalStyles = css` body.is-group-sites-dashboard { background: var( --color-main-background, #fcfcfc ); .layout__content { // Add border around everything overflow: hidden; min-height: 100vh; padding: calc( var( --masterbar-height ) + 16px ) 16px 16px calc( var( --sidebar-width-max ) ); @media only screen and ( max-width: 781px ) { padding: calc( var( --masterbar-height ) + 24px ) 24px 24px calc( var( --sidebar-width-max ) ); } } .layout__secondary .global-sidebar { border: none; } } body.is-group-sites-dashboard.rtl .layout__content { padding: calc( var( --masterbar-height ) + 16px ) calc( var( --sidebar-width-max ) ) 16px 16px; @media only screen and ( max-width: 781px ) { padding: calc( var( --masterbar-height ) + 24px ) calc( var( --sidebar-width-max ) ) 24px 24px; } } // Update body margin to account for the sidebar width @media only screen and ( min-width: 782px ) { div.layout.is-global-sidebar-visible { .layout__primary > main { background: var( --color-surface ); border-radius: 8px; height: calc( 100vh - 32px ); overflow: auto; } } } @media only screen and ( max-width: 781px ) { div.layout.is-global-sidebar-visible { .layout__primary { overflow-x: auto; } } } `; context.primary = ( <> <Global styles={ sitesDashboardGlobalStyles } /> <PageViewTracker path="/sites" title="Sites Management Page" delay={ 500 } /> <ResurrectedWelcomeModalGate /> <AsyncLoad require={ loadTrackResurrections } placeholder={ null } /> <SitesDashboard queryParams={ getQueryParams( context ) } /> </> ); // By definition, Sites Dashboard does not select any one specific site context.store.dispatch( setAllSitesSelected() ); next(); } export function siteDashboard( feature: string | undefined ) { return ( context: Context, next: () => void ) => { context.primary = ( <SitesDashboard initialSiteFeature={ feature } selectedSiteFeaturePreview={ context.primary } queryParams={ getQueryParams( context ) } isOnlyLayoutView={ context.inSiteContext } /> ); next(); }; } export function maybeRemoveCheckoutSuccessNotice( context: PageJSContext, next: () => void ) { if ( context.query[ 'new-site' ] ) { // `?new-site` shows a site creation notice and we don't want to show a double notice, // so hide the checkout success notice if it's there. context.store.dispatch( removeNotice( 'checkout-thank-you-success' ) ); } next(); } // Helper thunk that ensures that the user preferences has been fetched into Redux state before we // continue working with it. const waitForPrefs = () => async ( dispatch: CalypsoDispatch, getState: () => IAppState ) => { if ( hasReceivedRemotePreferences( getState() ) ) { return; } try { await dispatch( fetchPreferences() ); } catch { // if the fetching of preferences fails, return gracefully and proceed to the next landing page candidate } }; // The wp-admin admin bar does not know about user preferences and so may use the // origin_admin_bar query param to indicate that Calypso should take the user's // preference into account (without the query param, users can still navigate to // `/sites` manually, meaning the old dashboard is still accessible when the user // is specifically trying to go there). export const maybeRedirectToDashboard = ( context: PageJSContext, next: () => void ) => { const originAdminBar = context.query[ 'origin_admin_bar' ]; if ( originAdminBar !== 'wpcom' ) { return next(); } const { dispatch, getState } = context.store; dispatch( waitForPrefs() ).finally( () => { if ( hasDashboardOptIn( getState() ) ) { bumpStat( 'dashboard-redirect', 'site-list' ); window.location.replace( dashboardLink( '/sites' ) ); return; } context.page.replace( removeQueryArgs( context.canonicalPath, 'origin_admin_bar' ) ); next(); } ); }; export function redirectToHostingFeaturesIfNotAtomic( context: PageJSContext, next: () => void ) { const state = context.store.getState(); const site = getSelectedSite( state ); if ( ! areHostingFeaturesSupported( site ) ) { return page.redirect( `/hosting-features/${ site?.slug }` ); } next(); } export function showHostingFeaturesNoticeIfPresent( context: PageJSContext, next: () => void ) { // Update the url and show the notice after a redirect if ( context.query && context.query.hosting_features === 'activated' ) { context.store.dispatch( successNotice( i18n.translate( 'Hosting features activated successfully!' ), { displayOnNextPage: true, } ) ); // Remove query param without triggering a re-render window.history.replaceState( null, '', removeQueryArgs( window.location.href, 'hosting_features' ) ); } next(); }