Fix Layout Controller forwarding arrays from the URL query string. (#38593)

* Revert part of "Remove `qs` dependency from `woocommerce-admin` (#35128)"

This reverts Layout- and Filter-related changes from commit 00c151f9aa, reversing
changes made to eef417fe39.

Removes the fix (keeping the test) from https://github.com/woocommerce/woocommerce/pull/38542 as it's not needed for `qs`

Fixes https://github.com/woocommerce/woocommerce/issues/38582.

* Simplify the use of query params in `ProductTour`

* Add changelog entry
This commit is contained in:
Tomek Wytrębowicz 2023-06-05 09:55:20 +02:00 committed by GitHub
parent ac85cc2c59
commit f569f333a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 74 additions and 50 deletions

View File

@ -21,6 +21,7 @@ import {
defaultTableDateFormat, defaultTableDateFormat,
getCurrentDates, getCurrentDates,
} from '@woocommerce/date'; } from '@woocommerce/date';
import { stringify } from 'qs';
import { CurrencyContext } from '@woocommerce/currency'; import { CurrencyContext } from '@woocommerce/currency';
/** /**
@ -309,7 +310,7 @@ const formatProps = memoize(
[ [
isError, isError,
isRequesting, isRequesting,
new URLSearchParams( tableQuery ).toString(), stringify( tableQuery ),
get( revenueData, [ 'totalResults' ], 0 ), get( revenueData, [ 'totalResults' ], 0 ),
get( revenueData, [ 'data', 'intervals' ], EMPTY_ARRAY ).length, get( revenueData, [ 'data', 'intervals' ], EMPTY_ARRAY ).length,
dateType, dateType,

View File

@ -8,6 +8,7 @@ import {
LayoutContextProvider, LayoutContextProvider,
getLayoutContextValue, getLayoutContextValue,
} from '@woocommerce/admin-layout'; } from '@woocommerce/admin-layout';
import QueryString, { parse } from 'qs';
/** /**
* Internal dependencies * Internal dependencies
@ -20,8 +21,10 @@ import './style.scss';
type QueryParams = EmbeddedBodyProps; type QueryParams = EmbeddedBodyProps;
function isWPPage( params: URLSearchParams ): boolean { function isWPPage(
return params.get( 'page' ) !== null; params: QueryParams | QueryString.ParsedQs
): params is QueryParams {
return ( params as QueryParams ).page !== undefined;
} }
const EMBEDDED_BODY_COMPONENT_LIST: React.ElementType[] = [ const EMBEDDED_BODY_COMPONENT_LIST: React.ElementType[] = [
@ -41,10 +44,10 @@ export const EmbeddedBodyLayout = () => {
triggerExitPageCesSurvey(); triggerExitPageCesSurvey();
}, [] ); }, [] );
const query = new URLSearchParams( location.search ); const query = parse( location.search.substring( 1 ) );
let queryParams: QueryParams = { page: '', tab: '' }; let queryParams: QueryParams = { page: '', tab: '' };
if ( isWPPage( query ) ) { if ( isWPPage( query ) ) {
queryParams = Object.fromEntries( query ) as QueryParams; queryParams = query;
} }
/** /**
* Filter an array of body components for WooCommerce non-react pages. * Filter an array of body components for WooCommerce non-react pages.

View File

@ -293,10 +293,8 @@ export const ProductTour = () => {
recordEvent( 'walkthrough_product_enable_button_click' ); recordEvent( 'walkthrough_product_enable_button_click' );
} ); } );
const query = Object.fromEntries( const query = new URLSearchParams( window.location.search );
new URLSearchParams( window.location.search ) if ( query.get( 'tutorial' ) === 'true' ) {
);
if ( query && query.tutorial === 'true' ) {
const intervalId = waitUntilElementTopNotChange( const intervalId = waitUntilElementTopNotChange(
tourConfig.steps[ 0 ].referenceElements?.desktop || '', tourConfig.steps[ 0 ].referenceElements?.desktop || '',
() => { () => {

View File

@ -3,6 +3,7 @@
*/ */
import { Suspense, lazy } from '@wordpress/element'; import { Suspense, lazy } from '@wordpress/element';
import { useRef, useEffect } from 'react'; import { useRef, useEffect } from 'react';
import { parse, stringify } from 'qs';
import { find, isEqual, last, omit } from 'lodash'; import { find, isEqual, last, omit } from 'lodash';
import { applyFilters } from '@wordpress/hooks'; import { applyFilters } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
@ -429,28 +430,18 @@ export const Controller = ( { ...props } ) => {
*/ */
export function updateLinkHref( item, nextQuery, excludedScreens ) { export function updateLinkHref( item, nextQuery, excludedScreens ) {
if ( isWCAdmin( item.href ) ) { if ( isWCAdmin( item.href ) ) {
// If we accept a full HTMLAnchorElement, then we should be able to use `.search`.
// const query = new URLSearchParams( item.search );
// but to remain backward compatible, we support any object with `href` property.
const search = last( item.href.split( '?' ) ); const search = last( item.href.split( '?' ) );
let query = new URLSearchParams( search ); const query = parse( search );
const path = query.get( 'path' ) || 'homescreen'; const path = query.path || 'homescreen';
const screen = getScreenFromPath( path ); const screen = getScreenFromPath( path );
if ( ! excludedScreens.includes( screen ) ) { const isExcludedScreen = excludedScreens.includes( screen );
query = new URLSearchParams( {
...Object.fromEntries( query ),
...nextQuery,
} );
}
// Remove undefined keys.
for ( const [ key, value ] of Array.from( query.entries() ) ) {
if ( value === 'undefined' || value === undefined ) {
query.delete( key );
}
}
const href = 'admin.php?' + query.toString(); const href =
'admin.php?' +
stringify(
Object.assign( query, isExcludedScreen ? {} : nextQuery )
);
// Replace the href so you can see the url on hover. // Replace the href so you can see the url on hover.
item.href = href; item.href = href;

View File

@ -188,9 +188,7 @@ function _Layout( {
const { breadcrumbs, layout = { header: true, footer: true } } = page; const { breadcrumbs, layout = { header: true, footer: true } } = page;
const { header: showHeader = true, footer: showFooter = true } = layout; const { header: showHeader = true, footer: showFooter = true } = layout;
const query = Object.fromEntries( const query = getQuery();
new URLSearchParams( location && location.search )
);
return ( return (
<LayoutContextProvider <LayoutContextProvider

View File

@ -92,6 +92,7 @@
"history": "^5.3.0", "history": "^5.3.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"memize": "^1.1.0", "memize": "^1.1.0",
"qs": "^6.10.3",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Fix Layout Controller forwarding arrays from the URL query string.

View File

@ -2579,6 +2579,9 @@ importers:
memize: memize:
specifier: ^1.1.0 specifier: ^1.1.0
version: 1.1.0 version: 1.1.0
qs:
specifier: ^6.10.3
version: 6.10.3
react: react:
specifier: ^17.0.2 specifier: ^17.0.2
version: 17.0.2 version: 17.0.2
@ -3100,7 +3103,7 @@ importers:
version: link:../../packages/js/eslint-plugin version: link:../../packages/js/eslint-plugin
'@wordpress/prettier-config': '@wordpress/prettier-config':
specifier: 2.17.0 specifier: 2.17.0
version: 2.17.0(wp-prettier@2.8.5) version: 2.17.0(wp-prettier@2.6.2)
'@wordpress/scripts': '@wordpress/scripts':
specifier: ^26.4.0 specifier: ^26.4.0
version: 26.4.0(@types/node@16.18.21)(acorn@8.8.1)(react-dom@17.0.2)(react@17.0.2)(typescript@4.9.5) version: 26.4.0(@types/node@16.18.21)(acorn@8.8.1)(react-dom@17.0.2)(react@17.0.2)(typescript@4.9.5)
@ -3109,7 +3112,7 @@ importers:
version: 8.32.0 version: 8.32.0
prettier: prettier:
specifier: npm:wp-prettier@^2.6.2 specifier: npm:wp-prettier@^2.6.2
version: /wp-prettier@2.8.5 version: /wp-prettier@2.6.2
ts-loader: ts-loader:
specifier: ^9.4.1 specifier: ^9.4.1
version: 9.4.1(typescript@4.9.5)(webpack@5.76.3) version: 9.4.1(typescript@4.9.5)(webpack@5.76.3)
@ -3906,7 +3909,7 @@ packages:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
'@babel/core': 7.21.3 '@babel/core': 7.21.3
'@jridgewell/trace-mapping': 0.3.16 '@jridgewell/trace-mapping': 0.3.17
commander: 4.1.1 commander: 4.1.1
convert-source-map: 1.8.0 convert-source-map: 1.8.0
fs-readdir-recursive: 1.1.0 fs-readdir-recursive: 1.1.0
@ -4897,7 +4900,7 @@ packages:
'@babel/core': ^7.13.0 '@babel/core': ^7.13.0
dependencies: dependencies:
'@babel/core': 7.17.8 '@babel/core': 7.17.8
'@babel/helper-plugin-utils': 7.20.2 '@babel/helper-plugin-utils': 7.21.5
'@babel/helper-skip-transparent-expression-wrappers': 7.18.9 '@babel/helper-skip-transparent-expression-wrappers': 7.18.9
'@babel/plugin-proposal-optional-chaining': 7.18.9(@babel/core@7.17.8) '@babel/plugin-proposal-optional-chaining': 7.18.9(@babel/core@7.17.8)
dev: true dev: true
@ -4909,7 +4912,7 @@ packages:
'@babel/core': ^7.13.0 '@babel/core': ^7.13.0
dependencies: dependencies:
'@babel/core': 7.21.3 '@babel/core': 7.21.3
'@babel/helper-plugin-utils': 7.20.2 '@babel/helper-plugin-utils': 7.21.5
'@babel/helper-skip-transparent-expression-wrappers': 7.18.9 '@babel/helper-skip-transparent-expression-wrappers': 7.18.9
'@babel/plugin-proposal-optional-chaining': 7.18.9(@babel/core@7.21.3) '@babel/plugin-proposal-optional-chaining': 7.18.9(@babel/core@7.21.3)
@ -4990,7 +4993,7 @@ packages:
dependencies: dependencies:
'@babel/core': 7.17.8 '@babel/core': 7.17.8
'@babel/helper-environment-visitor': 7.18.9 '@babel/helper-environment-visitor': 7.18.9
'@babel/helper-plugin-utils': 7.20.2 '@babel/helper-plugin-utils': 7.21.5
'@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.17.8) '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.17.8)
'@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.17.8) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.17.8)
transitivePeerDependencies: transitivePeerDependencies:
@ -5005,7 +5008,7 @@ packages:
dependencies: dependencies:
'@babel/core': 7.21.3 '@babel/core': 7.21.3
'@babel/helper-environment-visitor': 7.18.9 '@babel/helper-environment-visitor': 7.18.9
'@babel/helper-plugin-utils': 7.20.2 '@babel/helper-plugin-utils': 7.21.5
'@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.21.3) '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.21.3)
'@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.21.3) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.21.3)
transitivePeerDependencies: transitivePeerDependencies:
@ -6106,7 +6109,7 @@ packages:
'@babel/core': 7.17.8 '@babel/core': 7.17.8
'@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-annotate-as-pure': 7.18.6
'@babel/helper-create-class-features-plugin': 7.19.0(@babel/core@7.17.8) '@babel/helper-create-class-features-plugin': 7.19.0(@babel/core@7.17.8)
'@babel/helper-plugin-utils': 7.20.2 '@babel/helper-plugin-utils': 7.21.5
'@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.17.8) '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.17.8)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -6121,7 +6124,7 @@ packages:
'@babel/core': 7.21.3 '@babel/core': 7.21.3
'@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-annotate-as-pure': 7.18.6
'@babel/helper-create-class-features-plugin': 7.19.0(@babel/core@7.21.3) '@babel/helper-create-class-features-plugin': 7.19.0(@babel/core@7.21.3)
'@babel/helper-plugin-utils': 7.20.2 '@babel/helper-plugin-utils': 7.21.5
'@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.21.3) '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.21.3)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -6549,6 +6552,15 @@ packages:
'@babel/helper-plugin-utils': 7.20.2 '@babel/helper-plugin-utils': 7.20.2
dev: true dev: true
/@babel/plugin-syntax-jsx@7.18.6(@babel/core@7.17.8):
resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.17.8
'@babel/helper-plugin-utils': 7.21.5
/@babel/plugin-syntax-jsx@7.18.6(@babel/core@7.21.3): /@babel/plugin-syntax-jsx@7.18.6(@babel/core@7.21.3):
resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==} resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@ -6575,6 +6587,7 @@ packages:
dependencies: dependencies:
'@babel/core': 7.17.8 '@babel/core': 7.17.8
'@babel/helper-plugin-utils': 7.21.5 '@babel/helper-plugin-utils': 7.21.5
dev: true
/@babel/plugin-syntax-jsx@7.21.4(@babel/core@7.21.3): /@babel/plugin-syntax-jsx@7.21.4(@babel/core@7.21.3):
resolution: {integrity: sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==} resolution: {integrity: sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==}
@ -8087,7 +8100,7 @@ packages:
dependencies: dependencies:
'@babel/core': 7.17.8 '@babel/core': 7.17.8
'@babel/helper-module-transforms': 7.21.2 '@babel/helper-module-transforms': 7.21.2
'@babel/helper-plugin-utils': 7.20.2 '@babel/helper-plugin-utils': 7.21.5
'@babel/helper-simple-access': 7.20.2 '@babel/helper-simple-access': 7.20.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -8101,7 +8114,7 @@ packages:
dependencies: dependencies:
'@babel/core': 7.21.3 '@babel/core': 7.21.3
'@babel/helper-module-transforms': 7.21.2 '@babel/helper-module-transforms': 7.21.2
'@babel/helper-plugin-utils': 7.20.2 '@babel/helper-plugin-utils': 7.21.5
'@babel/helper-simple-access': 7.20.2 '@babel/helper-simple-access': 7.20.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -8823,9 +8836,9 @@ packages:
'@babel/core': 7.21.3 '@babel/core': 7.21.3
'@babel/helper-annotate-as-pure': 7.16.7 '@babel/helper-annotate-as-pure': 7.16.7
'@babel/helper-module-imports': 7.16.7 '@babel/helper-module-imports': 7.16.7
'@babel/helper-plugin-utils': 7.21.5 '@babel/helper-plugin-utils': 7.18.9
'@babel/plugin-syntax-jsx': 7.16.7(@babel/core@7.21.3) '@babel/plugin-syntax-jsx': 7.16.7(@babel/core@7.21.3)
'@babel/types': 7.22.4 '@babel/types': 7.17.0
dev: true dev: true
/@babel/plugin-transform-react-jsx@7.19.0(@babel/core@7.17.8): /@babel/plugin-transform-react-jsx@7.19.0(@babel/core@7.17.8):
@ -10333,8 +10346,8 @@ packages:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
'@babel/core': 7.21.3 '@babel/core': 7.21.3
'@babel/helper-plugin-utils': 7.20.2 '@babel/helper-plugin-utils': 7.21.5
'@babel/helper-validator-option': 7.18.6 '@babel/helper-validator-option': 7.21.0
'@babel/plugin-transform-react-display-name': 7.16.7(@babel/core@7.21.3) '@babel/plugin-transform-react-display-name': 7.16.7(@babel/core@7.21.3)
'@babel/plugin-transform-react-jsx': 7.19.0(@babel/core@7.21.3) '@babel/plugin-transform-react-jsx': 7.19.0(@babel/core@7.21.3)
'@babel/plugin-transform-react-jsx-development': 7.16.7(@babel/core@7.21.3) '@babel/plugin-transform-react-jsx-development': 7.16.7(@babel/core@7.21.3)
@ -10635,8 +10648,8 @@ packages:
'@babel/core': ^7.0.0 '@babel/core': ^7.0.0
dependencies: dependencies:
'@babel/core': 7.17.8 '@babel/core': 7.17.8
'@babel/helper-module-imports': 7.21.4 '@babel/helper-module-imports': 7.18.6
'@babel/plugin-syntax-jsx': 7.21.4(@babel/core@7.17.8) '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.17.8)
'@babel/runtime': 7.21.0 '@babel/runtime': 7.21.0
'@emotion/hash': 0.9.0 '@emotion/hash': 0.9.0
'@emotion/memoize': 0.8.0 '@emotion/memoize': 0.8.0
@ -12121,6 +12134,7 @@ packages:
dependencies: dependencies:
'@jridgewell/resolve-uri': 3.1.0 '@jridgewell/resolve-uri': 3.1.0
'@jridgewell/sourcemap-codec': 1.4.14 '@jridgewell/sourcemap-codec': 1.4.14
dev: true
/@jridgewell/trace-mapping@0.3.17: /@jridgewell/trace-mapping@0.3.17:
resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==}
@ -19947,6 +19961,15 @@ packages:
prettier: /wp-prettier@2.2.1-beta-1 prettier: /wp-prettier@2.2.1-beta-1
dev: true dev: true
/@wordpress/prettier-config@2.17.0(wp-prettier@2.6.2):
resolution: {integrity: sha512-g4TEQIRDwNW/O8cAf895YV8a3eFfJr7RNLjqu70r8JFH4jmt2clJNu/9nxRburBxJZwqQnykrnDUz0HvXSbcsA==}
engines: {node: '>=14'}
peerDependencies:
prettier: '>=2'
dependencies:
prettier: /wp-prettier@2.6.2
dev: true
/@wordpress/prettier-config@2.17.0(wp-prettier@2.8.5): /@wordpress/prettier-config@2.17.0(wp-prettier@2.8.5):
resolution: {integrity: sha512-g4TEQIRDwNW/O8cAf895YV8a3eFfJr7RNLjqu70r8JFH4jmt2clJNu/9nxRburBxJZwqQnykrnDUz0HvXSbcsA==} resolution: {integrity: sha512-g4TEQIRDwNW/O8cAf895YV8a3eFfJr7RNLjqu70r8JFH4jmt2clJNu/9nxRburBxJZwqQnykrnDUz0HvXSbcsA==}
engines: {node: '>=14'} engines: {node: '>=14'}
@ -21421,8 +21444,8 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.1.0 postcss: ^8.1.0
dependencies: dependencies:
browserslist: 4.21.4 browserslist: 4.20.2
caniuse-lite: 1.0.30001418 caniuse-lite: 1.0.30001352
fraction.js: 4.2.0 fraction.js: 4.2.0
normalize-range: 0.1.2 normalize-range: 0.1.2
picocolors: 1.0.0 picocolors: 1.0.0
@ -22987,7 +23010,6 @@ packages:
escalade: 3.1.1 escalade: 3.1.1
node-releases: 2.0.6 node-releases: 2.0.6
picocolors: 1.0.0 picocolors: 1.0.0
dev: true
/browserslist@4.20.4: /browserslist@4.20.4:
resolution: {integrity: sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw==} resolution: {integrity: sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw==}
@ -45124,6 +45146,12 @@ packages:
hasBin: true hasBin: true
dev: true dev: true
/wp-prettier@2.6.2:
resolution: {integrity: sha512-AV33EzqiFJ3fj+mPlKABN59YFPReLkDxQnj067Z3uEOeRQf3g05WprL0RDuqM7UBhSRo9W1rMSC2KvZmjE5UOA==}
engines: {node: '>=10.13.0'}
hasBin: true
dev: true
/wp-prettier@2.8.5: /wp-prettier@2.8.5:
resolution: {integrity: sha512-gkphzYtVksWV6D7/V530bTehKkhrABUru/Gy4reOLOHJoKH4i9lcE1SxqU2VDxC3gCOx/Nk9alZmWk6xL/IBCw==} resolution: {integrity: sha512-gkphzYtVksWV6D7/V530bTehKkhrABUru/Gy4reOLOHJoKH4i9lcE1SxqU2VDxC3gCOx/Nk9alZmWk6xL/IBCw==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}